picotouch/circuitpython/picotouch_aftertouch/code.py
2023-06-18 15:56:13 -07:00

140 lines
4.8 KiB
Python
Executable file

#
# picotouch_aftertouch.py -- Tiny capsense MIDI slider controller using Pico
# 28 Feb 2023 - @todbot / Tod Kurt - github.com/todbot/picotouch
#
# A touch-sensitive MIDI controller where pressing harder sends MIDI CC
#
# NOTE: This does not work very well.
#
# picotouch board
# ┌──────────────────────────────────────────────────────────────────────────────────────────┐
# │ .─. .─. .─. .─. .─. .─. .─. │
# │ ( 1 ) ( 3 ) ( 6 ) ( 8 ) ( 10) ( 13) ( 15) │
# │ `─' `─' `─' `─' `─' `─' `─' │
# │ .─. .─. .─. .─. .─. .─. .─. .─. .─. .─. │
# │ ( 0 ) ( 2 ) ( 4 ) ( 5 ) ( 7 ) ( 9 ) ( 11) ( 12) ( 14) ( 16) │
# │ `─' `─' `─' `─' `─' `─' `─' `─' `─' `─' │
# └──────────────────────────────────────────────────────────────────────────────────────────┘
#
# To use:
#
# 1. Install needed libraries:
# circup install adafruit_midi adafruit_debouncer adafruit_ticks
#
# 2. Copy over this file as code.py:
# cp code.py /Volumes/CIRCUITPY/code.py
#
# on Pico / RP2040, need 1M pull-down on each input
import time
import board, pwmio
import touchio
import digitalio
import usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.pitch_bend import PitchBend
from adafruit_midi.control_change import ControlChange
from adafruit_debouncer import Debouncer, Button
debug = False
octave = 4
midi_velocity = 100
midi_channel = 0 # 0-15
midi_cc_num = 1 # standard modwheel
touch_threshold_adjust = 10
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1])
touch_pins = (
board.GP0, board.GP1, board.GP2, board.GP3, board.GP4, board.GP5,
board.GP6, board.GP7, board.GP8, board.GP9, board.GP10, board.GP11,
board.GP12, board.GP13, board.GP14, board.GP15, board.GP16, board.GP17,
board.GP18, board.GP19, board.GP20, board.GP21,
board.GP22,
)
led = pwmio.PWMOut(board.LED, frequency=25000, duty_cycle=0)
# special keys that aren't notes
pitch_up_key = 22
pitch_dn_key = 21
mod_up_key = 19
mod_mid_key = 18
oct_up_key = 20
oct_dn_key = 17
time.sleep(1)
td_scale_factor = 18
def td_scale(v):
v = int( v*v ) >> td_scale_factor
return v
touchs = [] # for debug
touchpads = []
for pin in touch_pins:
touchin = touchio.TouchIn(pin)
touchin.threshold += touch_threshold_adjust
touchs.append(touchin)
touchpads.append( Debouncer(touchin) )
num_touchs = len(touchs)
notes_on = [0] * num_touchs # list of notes currently sounding
print("\n----------")
print("picotouch hello")
touchs_smooth = [0] * num_touchs
touchs_delta = [0] * num_touchs
touchs_start = [0] * num_touchs
sm_amount = 0.95
cc_sending_id = -1
key_down_time = time.monotonic()
while True:
for i in range(num_touchs):
touch = touchpads[i]
touch.update()
touchs_smooth[i] = touchs_smooth[i] * sm_amount + (1-sm_amount) * touchs[i].raw_value
touchs_delta[i] = touchs[i].raw_value - touchs[i].threshold; # + 200
#print("%+05x" % int(touchs_delta[i]), " ", end='')
if touch.rose:
led.duty_cycle = 65535
if debug: print('key press %2d' % i)
noteOn = NoteOn((12*octave) + i, midi_velocity)
notes_on[i] = noteOn
midi.send( noteOn, channel=midi_channel )
cc_sending_id = i
key_down_time = time.monotonic()
touchs_start[i] = touchs_smooth[i]
if touch.fell:
led.duty_cycle = 0
if debug: print("key release %2d" % i)
noteOn = notes_on[i]
notes_on[i] = 0
noteOn.velocity = 0 # noteOff == noteOn w/ zero velocity (as well as NoteOff)
midi.send( noteOn, channel=midi_channel )
cc_sending_id = -1
#print()
for i in range(num_touchs):
td = int(touchs_smooth[i]) - touchs[i].threshold
#td = int(touchs_smooth[i] - touchs_start[i])
if td > 0 and notes_on[i] and i == cc_sending_id and time.monotonic() - key_down_time > 0.4:
v = td_scale(td)
v = min(max( v, 0 ), 127 )
midi.send( ControlChange(midi_cc_num, v), channel=midi_channel)
led.duty_cycle = v * 512
print( "*" * (v//2), v,td)