Exercise: Theremin

2.14. Exercise: Theremin#

  1. Navigate to the MicroPython editor https://python.microbit.org/v/3. If you already have it open, then use that existing window or tab.

  2. Connect your micro:bit using the instructions on the previous page

  3. Enter the following code into the editor

from microbit import *

pitch = 0

sound = audio.SoundEffect(
    freq_start=pitch,
    freq_end=pitch,
    duration=60,
    vol_start=255,
    vol_end=255,
    waveform=audio.SoundEffect.WAVEFORM_SQUARE,
    fx=audio.SoundEffect.FX_NONE,
    shape=audio.SoundEffect.SHAPE_LINEAR,
)


def clip(val, min_val=-1200, max_val=1200):
    return min(max(val, min_val), max_val)


while True:
    x = accelerometer.get_x()

    pitch_new = int(scale(clip(x), from_=(-1200, 1200), to=(20, 400)))

    print(x, pitch_new)

    sound.freq_start = pitch
    sound.freq_end = pitch_new
    pitch = pitch_new

    audio.play(sound, wait=False)

    if button_a.is_pressed():
        speaker.off()
    elif button_b.is_pressed():
        speaker.on()

    sleep(50)

The code does the following:

  1. Create a new SoundEffect object

  2. Repeat forever:

    • Measure the x-axis of the accelerometer

    • Convert the acceleration into a pitch between 500 and 1000Hz

    • Set the sound effect’s starting pitch to the current value and the ending pitch to the new value

    • Play the sound effect

    • Check if any of the buttons are pressed to mute/unmute the speaker

    • Sleep for 100 milliseconds

  1. Flash the code to your micro:bit.

If you get stuck ask a peer or your teacher for help!

Question 1

Extend your code so that:

  • The z-axis controls the volume

Solution
from microbit import *

pitch = 0
volume = 0

sound = audio.SoundEffect(
    freq_start=pitch,
    freq_end=pitch,
    duration=60,
    vol_start=volume,
    vol_end=volume,
    waveform=audio.SoundEffect.WAVEFORM_SQUARE,
    fx=audio.SoundEffect.FX_NONE,
    shape=audio.SoundEffect.SHAPE_LINEAR
)

def clip(val, min_val=-1200, max_val=1200):
    return min( max(val, min_val), max_val)

while True:
    x, y, z = accelerometer.get_values()

    pitch_new = int(scale(clip(x), from_=(-1200, 1200), to=(20, 400)))
    volume_new = int(scale(clip(y), from_=(-1200, 1200), to=(0, 255)))

    print(x, pitch_new, y, volume_new)

    sound.freq_start = pitch
    sound.freq_end = pitch_new
    pitch = pitch_new

    sound.vol_start = volume
    sound.vol_end = volume_new
    volume = volume_new

    audio.play(sound, wait=False)

    if button_a.is_pressed():
        speaker.off()
    elif button_b.is_pressed():
        speaker.on()

    sleep(50)
Extension: Question 2

Make one or more of the following modifications:

  • The magnetomer controls the pitch

  • The buttons step up or down the frequency range of the theremin