Skip to content

Instantly share code, notes, and snippets.

@todbot
Last active November 8, 2024 16:20

Revisions

  1. todbot revised this gist Jul 24, 2024. No changes.
  2. todbot renamed this gist Jul 20, 2024. 1 changed file with 1 addition and 1 deletion.
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # trinkey_theramin_pitch_code.py -- Trinkey MIDI Theramin! with pitch control!
    # trinkey_theremin_pitch_code.py -- Trinkey MIDI Theremin! with pitch control!
    # 2021 @todbot
    # left antenna: pitch (by multiple MIDI notes, put your synth in legato mode)
    # right antenna: filter cutoff
  3. todbot revised this gist Aug 16, 2023. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion trinkey_theramin_pitch_code.py
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,8 @@
    # trinkey_theramin_pitch_code.py -- Trinkey MIDI Theramin! with pitch control!
    # 2021 @todbot
    # left antenna: pitch (by multiple MIDI notes, put your synth in legato mode)
    # left antenna: pitch (by multiple MIDI notes, put your synth in legato mode)
    # right antenna: filter cutoff
    # video demo in comment below
    #
    import time
    import board
  4. todbot revised this gist May 2, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions trinkey_theramin_pitch_code.py
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    # trinkey_theramin_pitch_code.py -- Trinkey MIDI Theramin! with pitch control!
    # 2021 @todbot
    # left antenna: pitch (by multiple MIDI notes, put your synth in legato mode)
    # right antenna: filter cutoff
    #
    import time
    import board
  5. todbot created this gist May 2, 2021.
    74 changes: 74 additions & 0 deletions trinkey_theramin_pitch_code.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,74 @@
    # trinkey_theramin_pitch_code.py -- Trinkey MIDI Theramin! with pitch control!
    # 2021 @todbot
    #
    import time
    import board
    import neopixel
    import touchio
    import usb_midi
    import adafruit_midi
    from adafruit_midi.note_on import NoteOn
    from adafruit_midi.control_change import ControlChange

    midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)
    leds = neopixel.NeoPixel(board.NEOPIXEL, 4, brightness=0.2, auto_write=True)

    # announce we're alive and wait for things to stabilize
    # before creating touch pins so their raw_value baseline are okay
    leds.fill(0xff00ff)
    time.sleep(1.0)
    leds.fill(0)

    touch1_pin = touchio.TouchIn(board.TOUCH1)
    touch2_pin = touchio.TouchIn(board.TOUCH2)

    # a litlte helper class for noise filtering
    class RunningAverage:
    def __init__(self,count):
    self.count = count
    self.i = 0
    self.buf = [0] * self.count
    def add_value(self,val):
    self.buf[self.i] = val
    self.i = (self.i + 1) % self.count
    def average(self):
    return sum(self.buf)/self.count

    base1 = int(touch1_pin.raw_value * 1.02)
    base2 = int(touch2_pin.raw_value * 1.02)

    avg1 = RunningAverage(8)
    avg2 = RunningAverage(8)

    note_on = False

    note_base = 48 # C3 in MIDI land
    note = note_base
    velocity = 64 # half

    while True:
    avg1.add_value( touch1_pin.raw_value )
    avg2.add_value( touch2_pin.raw_value )

    r = 0
    g = min(max(avg1.average()-base1, 0),255)
    b = min(max(avg2.average()-base2, 0),255)

    leds.fill( (r,g,b) )

    if g > 10: # hand present
    note_new = note_base + int(g/4)
    if note_new != note:
    print(time.monotonic(),"******* ON! ",note_new,note)
    midi.send(NoteOn(note_new, velocity)) # turn on new note
    midi.send(NoteOn(note,0)) # 0=off # turn off old note
    note = note_new # save new note

    else: # no hand, turn off note
    midi.send(NoteOn(note,0)) # 0=off

    if b > 10: # hand present
    midi.send(ControlChange( 74, 16+int(b/2.5))) # 74 = filter cutoff

    time.sleep(0.001)