55 use 16 faders to create the single cycle waveform
66 rotary encoder adjusts other synth parameters
77 audio output: line level over 3.5mm TRS
8- CV output via DAC '''
8+ optional CV output via DAC '''
99
1010import board
1111import busio
1212import ulab .numpy as np
1313import rotaryio
14- import neopixel
1514from digitalio import DigitalInOut , Pull
1615import displayio
1716from adafruit_display_text import label
17+ from adafruit_display_shapes .rect import Rect
1818import terminalio
1919import synthio
2020import audiomixer
3030
3131displayio .release_displays ()
3232
33+ DEBUG = False # turn on print debugging messages
3334ITSY_TYPE = 0 # Pick your ItsyBitsy: 0=M4, 1=RP2040
3435
3536# neopixel setup for RP2040 only
3637if ITSY_TYPE == 1 :
38+ import neopixel
3739 pixel = neopixel .NeoPixel (board .NEOPIXEL , 1 , brightness = 0.3 )
3840 pixel .fill (0x004444 )
3941
4244midi = adafruit_midi .MIDI (midi_in = usb_midi .ports [0 ], in_channel = 0 )
4345
4446NUM_FADERS = 16
45- num_oscs = 2 # how many oscillators for each note
46- detune = 0.003 # how much to detune the oscillators
47+ num_oscs = 1 # how many oscillators for each note to start
48+ detune = 0.000 # how much to detune the oscillators
4749volume = 0.6 # mixer volume
4850lpf_freq = 12000 # user Low Pass Filter frequency setting
4951lpf_basef = 500 # filter lowest frequency
5456
5557# Initialize ADS7830
5658adc_a = ADC .ADS7830 (i2c , address = 0x48 ) # default address 0x48
57- adc_b = ADC .ADS7830 (i2c , address = 0x4A ) # A0 jumper 0x49, A1 0x4A
59+ adc_b = ADC .ADS7830 (i2c , address = 0x49 ) # A0 jumper 0x49, A1 0x4A
5860
5961faders = [] # list for fader objects on first ADC
6062for fdr in range (8 ): # add first group to list
9294
9395# Create display group
9496group = displayio .Group ()
95- # Create background rectangle
96- # bg_rect = Rect(0, 0, display.width, display.height, fill=0x0)
97- # group.append(bg_rect)
97+
9898# Set the font for the text label
9999font = terminalio .FONT
100100
101101# Create text label
102- title = label .Label (font , x = 2 , y = 4 , text = ("Faderwave Synthesizer " ), color = 0xffffff )
102+ title = label .Label (font , x = 2 , y = 4 , text = ("FADERWAVE SYNTHESIZER " ), color = 0xffffff )
103103group .append (title )
104104
105- title2 = label . Label ( font , x = 2 , y = 10 , text = ( "---------------------" ), color = 0xffffff )
106- group . append ( title2 )
105+ column_x = ( 8 , 60 , 100 )
106+ row_y = ( 22 , 34 , 46 , 58 )
107107
108- column_x = (20 , 90 )
109- row_y = (22 , 34 , 48 , 60 )
108+ midi_lbl_rect = Rect (column_x [2 ]- 3 , row_y [0 ]- 5 , 28 , 10 , fill = 0xffffff )
109+ group .append (midi_lbl_rect )
110+ midi_lbl = label .Label (font , x = column_x [2 ], y = row_y [0 ], text = "MIDI" , color = 0x000000 )
111+ group .append (midi_lbl )
112+ midi_rect = Rect (column_x [2 ]- 3 , row_y [1 ]- 5 , 28 , 10 , fill = 0xffffff )
113+ group .append (midi_rect )
114+ midi_counter_lbl = label .Label (font , x = column_x [2 ]+ 8 , y = row_y [1 ], text = '-' , color = 0x000000 )
115+ group .append (midi_counter_lbl )
110116
111117# Create menu selector
112118menu_sel = 0
113- menu_sel_txt = label .Label (font , text = ("- >" ), color = 0xffffff )
114- menu_sel_txt .x = column_x [0 ]- 16
119+ menu_sel_txt = label .Label (font , text = (">" ), color = 0xffffff )
120+ menu_sel_txt .x = column_x [0 ]- 10
115121menu_sel_txt .y = row_y [menu_sel ]
116122group .append (menu_sel_txt )
117123
118124# Create detune text
119- det_txt_a = label .Label (font , text = ("Detune..... " ), color = 0xffffff )
125+ det_txt_a = label .Label (font , text = ("Detune " ), color = 0xffffff )
120126det_txt_a .x = column_x [0 ]
121127det_txt_a .y = row_y [0 ]
122128group .append (det_txt_a )
123129
124- det_txt_b = label .Label (font , text = (str (0.003 )), color = 0xffffff )
130+ det_txt_b = label .Label (font , text = (str (detune )), color = 0xffffff )
125131det_txt_b .x = column_x [1 ]
126132det_txt_b .y = row_y [0 ]
127133group .append (det_txt_b )
128134
129135# Create number of oscs text
130- num_oscs_txt_a = label .Label (font , text = ("Num Oscs... " ), color = 0xffffff )
136+ num_oscs_txt_a = label .Label (font , text = ("Num Oscs " ), color = 0xffffff )
131137num_oscs_txt_a .x = column_x [0 ]
132138num_oscs_txt_a .y = row_y [1 ]
133139group .append (num_oscs_txt_a )
138144group .append (num_oscs_txt_b )
139145
140146# Create volume text
141- vol_txt_a = label .Label (font , text = ("Volume..... " ), color = 0xffffff )
147+ vol_txt_a = label .Label (font , text = ("Volume " ), color = 0xffffff )
142148vol_txt_a .x = column_x [0 ]
143149vol_txt_a .y = row_y [2 ]
144150group .append (vol_txt_a )
148154vol_txt_b .y = row_y [2 ]
149155group .append (vol_txt_b )
150156
151-
152157# Create lpf frequency text
153- lpf_txt_a = label .Label (font , text = ("LPF........ " ), color = 0xffffff )
158+ lpf_txt_a = label .Label (font , text = ("LPF " ), color = 0xffffff )
154159lpf_txt_a .x = column_x [0 ]
155160lpf_txt_a .y = row_y [3 ]
156161group .append (lpf_txt_a )
160165lpf_txt_b .y = row_y [3 ]
161166group .append (lpf_txt_b )
162167
163-
164168# Show the display group
165169display .root_group = group
166170
185189
186190def faders_to_wave ():
187191 for j in range (NUM_FADERS ):
188- wave_user [j ] = int (map_range (faders_pos [j ], 0 , 255 , - 32768 , 32767 ))
192+ wave_user [j ] = int (map_range (faders_pos [j ], 0 , 127 , - 32768 , 32767 ))
189193
190194notes_pressed = {} # which notes being pressed. key=midi note, val=note object
191195
@@ -198,6 +202,7 @@ def note_on(n):
198202 f = fo * (1 + k * detune )
199203 voices .append (synthio .Note (frequency = f , filter = lpf , envelope = amp_env , waveform = wave_user ))
200204 synth .press (voices )
205+ note_off (n ) # help to prevent double note_on for same note which can get stuck
201206 notes_pressed [n ] = voices
202207
203208def note_off (n ):
@@ -209,25 +214,39 @@ def note_off(n):
209214def map_range (s , a1 , a2 , b1 , b2 ):
210215 return b1 + ((s - a1 ) * (b2 - b1 ) / (a2 - a1 ))
211216
217+ notes_on = 0
218+
219+ print ("Welcome to Faderwave" )
220+
212221
213222while True :
214223 # get midi messages
215224 msg = midi .receive ()
216225 if isinstance (msg , NoteOn ) and msg .velocity != 0 :
217226 note_on (msg .note )
218- elif isinstance (msg , NoteOff ) or isinstance (msg , NoteOn ) and msg .velocity == 0 :
227+ notes_on = notes_on + 1
228+ if DEBUG :
229+ print ("MIDI notes on: " , msg .note , " Polyphony:" , " " * notes_on , notes_on )
230+ midi_counter_lbl .text = str (msg .note )
231+ elif isinstance (msg , NoteOff ) or (isinstance (msg , NoteOn ) and msg .velocity == 0 ):
219232 note_off (msg .note )
233+ notes_on = notes_on - 1
234+ if DEBUG :
235+ print ("MIDI notes off:" , msg .note , " Polyphony:" , " " * notes_on , notes_on )
236+ midi_counter_lbl .text = "-"
220237
221238 # check faders
222239 for i in range (len (faders )):
223- faders_pos [i ] = faders [i ].value // 256
240+ faders_pos [i ] = faders [i ].value // 512
224241 if faders_pos [i ] is not last_faders_pos [i ]:
225242 faders_to_wave ()
226243 last_faders_pos [i ] = faders_pos [i ]
244+ if DEBUG :
245+ print ("fader" , [i ], faders_pos [i ])
227246
228247 # send out a DAC value based on fader 0
229- if i == 0 :
230- dac .value = faders [0 ].value
248+ # if i == 1 :
249+ # dac.value = faders[1 ].value
231250
232251 # check encoder button
233252 button .update ()
@@ -247,7 +266,7 @@ def map_range(s, a1, a2, b1, b2):
247266
248267 elif menu_sel == 1 :
249268 num_oscs = num_oscs + delta
250- num_oscs = min (max (num_oscs , 1 ), 8 )
269+ num_oscs = min (max (num_oscs , 1 ), 5 )
251270 formatted_num_oscs = str (num_oscs )
252271 num_oscs_txt_b .text = formatted_num_oscs
253272
0 commit comments