140 lines
4.8 KiB
Python
Executable file
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)
|