Build a Light Theremin Using Maker Pi Pico and CircuitPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Build a Light Theremin Using Raspberry Pi Pico | |
# (Maker Pi Pico) and CircuitPython | |
# | |
# Raspberry Pi Pico | |
# - [Maker Pi Pico] https://my.cytron.io/p-maker-pi-pico?tracking=idris | |
# Grove - Light Sensor v1.2 | |
# - https://my.cytron.io/p-grove-light-sensor-v1.2?tracking=idris | |
# | |
# Update: | |
# 9 Feb 2021 - Tested with CircuitPython Pico 6.2.0-beta.1-127-ga10ce39ae | |
# | |
from time import sleep | |
from board import * | |
from digitalio import DigitalInOut, Direction, Pull | |
from analogio import AnalogIn | |
from pwmio import PWMOut | |
from pitches import tones | |
from neopixel_write import neopixel_write | |
sleep(1) | |
btn1 = DigitalInOut(GP20) | |
btn1.direction = Direction.INPUT | |
btn1.pull = Pull.UP | |
btn2 = DigitalInOut(GP21) | |
btn2.direction = Direction.INPUT | |
btn2.pull = Pull.UP | |
btn3 = DigitalInOut(GP22) | |
btn3.direction = Direction.INPUT | |
btn3.pull = Pull.UP | |
pixel_off = bytearray([0, 0, 0]) | |
pixel_red = bytearray([0, 20, 0]) | |
pixel_green = bytearray([20, 0, 0]) | |
pixel_blue = bytearray([0, 0, 20]) | |
rgb = DigitalInOut(GP28) | |
rgb.direction = Direction.OUTPUT | |
neopixel_write(rgb, pixel_off) | |
light = AnalogIn(GP27) | |
tempo = 1 | |
melody_start = ['c4', 'g4'] | |
rhythm_start = [8, 8] | |
def playTone(melody, rhythm): | |
for tone, length in zip(melody, rhythm): | |
beeper = PWMOut(GP18, variable_frequency=True) | |
if tones[tone] != 0: | |
beeper.duty_cycle = 2 ** 15 | |
beeper.frequency = tones[tone] | |
sleep(tempo / length) | |
beeper.deinit() | |
def map(x, in_min, in_max, out_min, out_max): | |
if x > in_max: | |
x = in_max | |
if x < in_min: | |
x = in_min | |
return (x-in_min) * (out_max-out_min) / (in_max-in_min) + out_min | |
playTone(melody_start, rhythm_start) | |
while btn1.value: | |
pass | |
notes_theremin = [ | |
'c3', 'cs3', 'd3', 'ds3', 'e3', 'f3', 'fs3', 'g3', 'gs3', 'a3', 'as3', 'b3', | |
'c4', 'cs4', 'd4', 'ds4', 'e4', 'f4', 'fs4', 'g4', 'gs4', 'a4', 'as4', 'b4', | |
'c5', 'cs5', 'd5', 'ds5', 'e5', 'f5', 'fs5', 'g5', 'gs5', 'a5', 'as5', 'b5', | |
'c6', 'cs6', 'd6', 'ds6', 'e6', 'f6', 'fs6', 'g6', 'gs6', 'a6', 'as6', 'b6', | |
] | |
enable_theremin = False | |
delay = 0.2 | |
while True: | |
if not btn1.value: | |
enable_theremin = not enable_theremin | |
if enable_theremin: | |
neopixel_write(rgb, pixel_green) | |
else: | |
neopixel_write(rgb, pixel_off) | |
sleep(1) | |
if enable_theremin: | |
light_ADC = light.value | |
note = int(map(light_ADC, 1000, 40000, 0, 47)) | |
print("ADC: {}\tMap: {}\t\tNote: {}".format(light_ADC, note, notes_theremin[note])) | |
beeper = PWMOut(GP18, variable_frequency=True) | |
beeper.duty_cycle = 2 ** 15 | |
beeper.frequency = tones[notes_theremin[note]] | |
sleep(delay) | |
beeper.deinit() | |
sleep(0.01) | |
if not btn2.value: | |
neopixel_write(rgb, pixel_green) | |
delay -= 0.01 | |
if delay < 0.1: | |
neopixel_write(rgb, pixel_red) | |
delay = 0.1 | |
elif not btn3.value: | |
neopixel_write(rgb, pixel_green) | |
delay += 0.01 | |
if delay > 0.2: | |
delay = 0.2 | |
neopixel_write(rgb, pixel_blue) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tones = { | |
'': 0, | |
'b0': 31, | |
'c1': 33, | |
'cs1': 35, | |
'd1': 37, | |
'ds1': 39, | |
'e1': 41, | |
'f1': 44, | |
'fs1': 46, | |
'g1': 49, | |
'gs1': 52, | |
'a1': 55, | |
'as1': 58, | |
'b1': 62, | |
'c2': 65, | |
'cs2': 69, | |
'd2': 73, | |
'ds2': 78, | |
'e2': 82, | |
'f2': 87, | |
'fs2': 93, | |
'g2': 98, | |
'gs2': 104, | |
'a2': 110, | |
'as2': 117, | |
'b2': 123, | |
'c3': 131, | |
'cs3': 139, | |
'd3': 147, | |
'ds3': 156, | |
'e3': 165, | |
'f3': 175, | |
'fs3': 185, | |
'g3': 196, | |
'gs3': 208, | |
'a3': 220, | |
'as3': 233, | |
'b3': 247, | |
'c4': 262, | |
'cs4': 277, | |
'd4': 294, | |
'ds4': 311, | |
'e4': 330, | |
'f4': 349, | |
'fs4': 370, | |
'g4': 392, | |
'gs4': 415, | |
'a4': 440, | |
'as4': 466, | |
'b4': 494, | |
'c5': 523, | |
'cs5': 554, | |
'd5': 587, | |
'ds5': 622, | |
'e5': 659, | |
'f5': 698, | |
'fs5': 740, | |
'g5': 784, | |
'gs5': 831, | |
'a5': 880, | |
'as5': 932, | |
'b5': 988, | |
'c6': 1047, | |
'cs6': 1109, | |
'd6': 1175, | |
'ds6': 1245, | |
'e6': 1319, | |
'f6': 1397, | |
'fs6': 1480, | |
'g6': 1568, | |
'gs6': 1661, | |
'a6': 1760, | |
'as6': 1865, | |
'b6': 1976, | |
'c7': 2093, | |
'cs7': 2217, | |
'd7': 2349, | |
'ds7': 2489, | |
'e7': 2637, | |
'f7': 2794, | |
'fs7': 2960, | |
'g7': 3136, | |
'gs7': 3322, | |
'a7': 3520, | |
'as7': 3729, | |
'b7': 3951, | |
'c8': 4186, | |
'cs8': 4435, | |
'd8': 4699, | |
'ds8': 4978, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment