Introduction: Xeramin - an Instrument That Is Shaken and Stirred-

Back in the year of 2014, while I was trying to fix my Theramin, I could not help but complain: “Gee! These discrete components are so expansive. Under the same budget, I can build a dozen Theramins with microcontroller and sensors.”

My idea was straight-forward: replacing the 2 antennas of a Theramin (one for tone and the other for volume) with equivalent sensors. That is, to…

    • Use a range detector, to detect the distance, and then translate to a tone.
    • Use another sensor to detect the gesture, to decide the volume.

      So, I set off to build a Theramin with microcontroller and sensors. But soon, I realized that I can build something different – an inversed Theramin. Such instrument would be portable and able to be played single-handed. I named it Xeramin; because I use an accelerometer for the volume part.

      An ultrasound ping sensor detects the distance from floor; while an accelerometer captures the g force when the device is shaken. These readings are processed by a microcontroller. And finally, a PWN tone was generated, filtered, and fed to a class-D amplifier. The final product is emitted by a speaker that is glued to a plastic bottle cap.

      These parts can be found in all sorts of “Arduino Starter Kit”. It was painless for me to create the prototype. However, after several attempts to make it sound better, I came to a conclusion: I should convert it to a MIDI instrument and hook it to a synthesizer. Then I left the project there for years.

      Recently, I came across Arduino Nano 33 BLE, an Arduino with built-in BLE and IMU funcionality. I thought: “This is it! I can definitely upgrade my Xeramin with it.”

      I am going to show you how to build a Xeramin with the latest Arduino parts. It is very easy and requires no pro tools at all. Here we go!

      Step 1: Prepare the Parts

      You will need...

        • A half-size breadboard
        • Arduino Nano 33 BLE with headers
        • VL53L0x breakout board
        • Grove-Mech keycap
        • A portable power source (9v battery x1 or 18650 battery x 2)
        • A computer to host MIDI synthesizer (we will use Raspberry Pi in this Instructable)

        The VL53L0x is a ToF laser range detector. We will hook it to Arduino via I2C. Any brand of breakout board will do.

        The Grove-Mech keycap is a mechanical button with LED. It will function both as a visual cue and as a “shut-up” button. If you can't get one, you can replace it with an ordinary push button and an Adafruit NeoPixel RGB LED.

        And for the power source… I did not hesitate to use a 9V battery. Given the low current and good efficiency of the regulator, it should not be too eco-unfriendly. An USB powerbank might refuse to power the device, unless it has "micro-current mode" (mode to charge earbuds at low current).

        Step 2: Wire Up Everything

        Because the needed wiring are so few, it can be built on a bread board without side effect except for durability issue. The keycap and battery case can be glued to the back of the breadboard, at whatever locations that you find comfortable.

        Regarding the position of the chips, I recommend to keep the VL53L0x near the wrist, while the IMU on Arduino board away from the wrist. This makes the reading of distance more stable during waving or shaking.

        Step 3: Program the Microcontroller

        I know, the code is a bit messy, especially the header part.

        Despite the readability issue, there are however, several constant variables that you definitely want to modify:

          • BLE device name: char const DEVICE_NAME[] = "Xeramin_R"; This will be the device name you see while connecting it to bluetooth central.Change it to avoid any confusion.
          • The MIDI channels that the device will use: byte const ch[] = {1, 2, 3, 10}; You might need to modify this to avoid collision; for example, if you plan to connect more than one device to the synthesizer. The code that I provided only use 3 channels, you can change int const SIZEOF_CH_ARR = 3; to use more or less.
          • If you wish to change the scale of notes, you can modify the byte const notes[] array, and int const NOTE_STEP_DIST = 88; , which determines how distance is translated to note.

          Step 4: Compile and Upload

          If your compiler split out error message like this, it is because the polymorphic functions in the Pololu VL53L0x library. This problem can be solved by changing writeReg16Bit and writeReg32Bit functions in VL53L0X.cpp (which can be found in the Arduino library folder) to explicit form, like this:

          // Write a 16-bit register
          void VL53L0X::writeReg16Bit(uint8_t reg, uint16_t value)
          {
            bus->beginTransmission(address);
            bus->write(reg);
            uint8_t val = value >> 8;
            bus->write(val); // value high byte
            val = value & 0xFF;
            bus->write(val); // value low byte
            last_status = bus->endTransmission();
          }
          
          // Write a 32-bit register
          void VL53L0X::writeReg32Bit(uint8_t reg, uint32_t value)
          {
            bus->beginTransmission(address);
            bus->write(reg);
            uint8_t val = value >> 24;
            bus->write(val); // value highest byte
            val = value >> 16;
            bus->write(val);
            val = value >> 8;
            bus->write(val);
            val = value & 0xFF;
            bus->write(val); // value lowest byte
            last_status = bus->endTransmission();
          }

          Then you should have no trouble uploading the codes to the board.

          Step 5: Setup QSynth on a Raspberry Pi

            This device has a critical flaw in terms of BLE communication: by using the ArduinoBLE library, it does not have the ability to reply to a pairing request.

            Sure, a BLE device can work without pairing. But this flaw makes it hard to connect to ordinary PCs or phones - unless you happen to have a device that is not picky about security. For example, my HUAWEI M5 android tablet + FluidSynth MIDI app connect to it without trouble.

            Luckily, manual pair-and-trust can be done easily on most Linux machines. I will demonstrate how to do it on a Raspberry Pi (3B/3B+/4B) running Raspbian. Other flavors of Linux will also work. But since MIDI is highly modular in Linux systems, it might not be easy for you to configure the synthesizer and audio drivers right.

            First, let us install some tools with good GUI interface to work with…

            sudo apt install qsynth qjackctl

            Next we run qsynth and do the setup, as shown in the images.

            Make sure that:

              • a soundfont is fed to qsynth
              • qsynth get enough buffer to work with, preferably >64kB * 8.
              • what you filled in the Audio Device field is valid; you can check your audio output hardware by...
                  aplay -l

                  Step 6: Earn the Trust Over BLE

                  We will use bluetoothctl to obtain the mac address and to grant access.

                  Power up Xeramins and put them near your Raspberry Pi. Call bluetoothctl from bash and execute...

                  scan on

                  The Xeramin devices will be listed, alone with their MAC addresses.

                  Then, use the following commands:

                  pair xx:xx:xx:xx:xx:xx
                  trust xx:xx:xx:xx:xx:xx

                  where the xx:xx:xx:xx:xx:xx is the MAC address of the Xeramin.

                  This should allow your Pi to trust and subscribe BLE service from Xeramin. Repeat this step if you have multiple Xeramins to connect to. Once the device is trusted, subscription to service will be done automatically later on.

                  Step 7: Tie Up the Data Stream

                  Next, we connect the MIDI input of qsynth to our device’s MIDI service by qjackctl. Note that it is under ALSA tag, instead of MIDI tag.

                  If nothing goes wrong, your Xeramin should be making sound when you shake it.

                  Step 8: Tune the Synth

                  Finally, setup the patch (instrument sound) for each channel in qsynth.

                  Due to the humming and ringing nature of Xeramin, some patches sound well (eg. Violin, Music box, Banjo) while some do not. It takes some time to play around and find out which patch works best for you. The assigned patches do not even have to be the same. For example, you can mix overdriven guitar with clean guitar to get something that is more like a... proper guitar?

                  If the sound is very clicky, you can try...

                  • lowering sampling rate
                  • a less memory consuming soundfont
                  • increasing buffer size (at the cost of latency)

                  Step 9: Shake It Up

                  Okay, that is pretty much all the steps.

                  Here is a quick introduction that shows you some basics about playing it.

                  Let's make some noise and have fun !

                  Arduino Contest

                  Participated in the
                  Arduino Contest