Skip to content

Commit 865e47e

Browse files
committed
fixup filter example code
1 parent 1b552c2 commit 865e47e

10 files changed

+168
-158
lines changed

3_filters/code_filter_handmod.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
# 3_filters/code_filter_handmod.py
22
# part of todbot circuitpython synthio tutorial
33
# 10 Feb 2025 - @todbot / Tod Kurt
4+
#
45
import time
56
import synthio
67
from synth_setup import synth
7-
midi_note = 48
8+
midi_note = 48 # C2
89
filter_types = (synthio.FilterMode.LOW_PASS,
910
synthio.FilterMode.HIGH_PASS,
10-
synthio.FilterMode.NOTCH,
11-
)
11+
synthio.FilterMode.BAND_PASS,
12+
synthio.FilterMode.NOTCH)
1213
i=0 # which filter we're trying
1314
note = synthio.Note(synthio.midi_to_hz(midi_note))
1415
synth.press(note)
1516

1617
while True:
17-
print("selecting filter_type", filter_types[i])
18-
filter1 = synthio.Biquad(filter_types[i], frequency=3000, Q=1.2)
19-
note.filter = filter1
18+
print("selecting filter_type:\n ", filter_types[i])
19+
filter1 = synthio.Biquad(filter_types[i], frequency=4000, Q=1.2)
20+
note.filter = filter1 # set the filter for this note
2021

2122
while filter1.frequency > 250:
22-
print("changing filter frequency: %d" % filter1.frequency)
23+
print("filter frequency: %d" % filter1.frequency)
2324
filter1.frequency = filter1.frequency * 0.95 # do modulation by hand
24-
time.sleep(0.05)
25+
time.sleep(0.03)
2526
i = (i+1) % len(filter_types) # go to next filter type

3_filters/code_filter_knobmod.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44
#
55
import time, synthio
66
from synth_setup import synth, knobA, knobB
7-
midi_note = 60
8-
note = synthio.Note(synthio.midi_to_hz(midi_note))
7+
midi_notes = (43, 48, 55, 60)
8+
mi=0
9+
note = synthio.Note(synthio.midi_to_hz(midi_notes[mi]))
910
filter1 = synthio.Biquad(synthio.FilterMode.LOW_PASS, frequency=8000, Q=1.0)
1011
note.filter = filter1
1112
synth.press(note)
1213

1314
while True:
14-
filter1.frequency = (knobA.value / 65535) * 8000; # convert to 0-8000
15-
filter1.Q = (knobB.value / 65535) * 2; # convert to 0-2
16-
print("note freq: %4.2f filter freq: %6.2f Q: %1.2f" %
17-
(note.frequency, filter1.frequency, filter1.Q))
18-
time.sleep(0.05)
15+
for _ in range(20):
16+
filter1.frequency = (knobA.value / 65535) * 8000; # 0-8000
17+
filter1.Q = (knobB.value / 65535) * 2; # convert to 0-2
18+
print("note freq: %6.2f filter freq: %4d Q: %1.2f" %
19+
(note.frequency, filter1.frequency, filter1.Q))
20+
time.sleep(0.05)
21+
mi = (mi+1) % len(midi_notes) # go to next note
22+
note.frequency = synthio.midi_to_hz(midi_notes[mi])

3_filters/code_filter_lerp.py

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,42 @@
22
import time, random
33
import ulab.numpy as np
44
import synthio
5-
from synth_setup import synth
5+
from synth_setup import synth, knobA
66

7-
filter_attack_time = 1.3
8-
filter_release_time = 0.5
9-
filter_min_freq = 200
10-
filter_max_freq = 2000
7+
filter_attack_time = 0.1 # some example values to start out with
8+
filter_release_time = 0.6 # change them to see how it affects the sound
9+
filter_min_freq = 100
10+
filter_max_freq = 4000
1111

1212
# this LFO will automatically run the lerp position from 0 to 1 over a given timea
13-
lerp_pos = synthio.LFO(once=True, rate=1, waveform=np.array((0,32767), dtype=np.int16))
13+
lerp_pos = synthio.LFO(once=True, waveform=np.array((0,32767), dtype=np.int16))
1414

15-
# this MathOperation will then range from "start_val" to "end_val" over "lerp_time"
15+
# this MathOperation will range from "start_val" to "end_val" over "lerp_time"
1616
# where "start_val" is our starting frequency and "end_val" is our hold frequency)
17-
filter_env = synthio.Math(synthio.MathOperation.CONSTRAINED_LERP, 500, 2000, lerp_pos)
17+
filter_env = synthio.Math(synthio.MathOperation.CONSTRAINED_LERP,
18+
filter_min_freq, filter_max_freq, lerp_pos)
1819

20+
def set_filter_lerp(fstart, fend, ftime):
21+
filter_env.a = fstart
22+
filter_env.b = fend
23+
lerp_pos.rate = 1 / ftime
24+
lerp_pos.retrigger() # must make sure to retrigger the positioner
25+
26+
# nice little saw wave oscillator sounds better than default sqaure
1927
wave_saw = np.linspace(32000, -32000, num=128, dtype=np.int16)
2028

2129
while True:
22-
midi_note = random.randint(48,72)
30+
midi_note = 32 + int((knobA.value/65535)*32) #random.randint(48,60)
31+
print("playing note:", midi_note)
2332
note = synthio.Note(synthio.midi_to_hz(midi_note), waveform=wave_saw)
2433
note.filter = synthio.Biquad(synthio.FilterMode.LOW_PASS,
25-
frequency=filter_env, Q=1.8)
26-
# press the note
27-
# which means setting up the attack stage, the lerp and retriggering
28-
filter_env.a = filter_min_freq
29-
filter_env.b = filter_max_freq
30-
lerp_pos.rate = 1 / filter_attack_time
31-
lerp_pos.retrigger()
34+
frequency=filter_env, Q=1.8)
35+
# press the note, e.g. set up the attack lerp vals and retriggering
36+
set_filter_lerp(filter_min_freq, filter_max_freq, filter_attack_time)
3237
synth.press(note)
33-
time.sleep(1.5)
38+
time.sleep(filter_attack_time)
3439

35-
# release the note
36-
# which hmeans setting up the release stage, the lerp and retriggering
37-
filter_env.a = filter_max_freq
38-
filter_env.b = filter_min_freq
39-
lerp_pos.rate = 1 / filter_release_time
40-
lerp_pos.retrigger()
40+
# release the note, e.g. set up the release lerp vals and retriggering
41+
set_filter_lerp(filter_max_freq, filter_min_freq, filter_release_time)
4142
synth.release(note)
42-
time.sleep(1.0)
43+
time.sleep(filter_release_time)

3_filters/code_filter_lfoenv.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,40 @@
33
# 10 Feb 2025 - @todbot / Tod Kurt
44
import time, random, synthio
55
import ulab.numpy as np
6-
from synth_setup import synth, knobA, knobB
7-
6+
from synth_setup import synth
87
# extend the amplitude envelope release so we can hear the filter release
9-
synth.envelope = synthio.Envelope(attack_time=0.0, release_time=1.5)
10-
11-
# use a saw wave sound oscillator instead of square wave to hear the filter better
8+
synth.envelope = synthio.Envelope(attack_time=0.0, release_time=1.2)
9+
# use a saw wave oscillator instead of square wave to hear the filter better
1210
wave_saw = np.linspace(32000, -32000, num=128, dtype=np.int16)
13-
1411
# parameters for our filter "envelope"
15-
filt_attack_time = 1.0
16-
filt_release_time = 1.5
17-
filt_min_freq = 500
12+
filt_attack_time = 1.5
13+
filt_release_time = 0.75
14+
filt_min_freq = 100
1815
filt_max_freq = 2000
1916

2017
# LFO to use as the ramp up in frequency on key press
21-
filter_attack_lfo = synthio.LFO(once=True, rate=filt_attack_time,
22-
offset=min_freq, scale=max_freq,
18+
filter_attack_lfo = synthio.LFO(once=True, rate=1/filt_attack_time,
19+
offset=filt_min_freq, scale=filt_max_freq,
2320
waveform=np.array((0,32767), dtype=np.int16))
2421
# LFO to use to ramp down the frequency on key release
25-
filter_release_lfo = synthio.LFO(once=True, rate=filt_release_time,
26-
offset=min_freq, scale=max_freq,
22+
filter_release_lfo = synthio.LFO(once=True, rate=1/filt_release_time,
23+
offset=filt_min_freq, scale=filt_max_freq,
2724
waveform=np.array((32767,0), dtype=np.int16))
28-
2925
while True:
3026
midi_note = random.randint(48,72) # pick a new note to play
27+
print("filter up!")
3128
# press a note with attack filter
3229
note = synthio.Note(midi_note, waveform=wave_saw)
3330
note.filter = synthio.Biquad(synthio.FilterMode.LOW_PASS,
3431
frequency=filter_attack_lfo, Q=1.8)
3532
filter_attack_lfo.retrigger()
3633
synth.press(note) # trigger amp env and filter lfo
3734

38-
# wait for attack phase to complete, hold a bit, then
39-
time.sleep(1.0)
35+
time.sleep(filt_attack_time) # wait for note attack to finish, then
4036

41-
# release the note
42-
note.filter.frequency = filter_release_lfo
37+
note.filter.frequency = filter_release_lfo # release the note
4338
filter_release_lfo.retrigger()
4439
synth.release(note) # trigger amp env release
40+
print("filter down!")
4541

46-
# let the release happen
47-
time.sleep(1.0)
42+
time.sleep(filt_release_time) # let the release happen

3_filters/code_filter_lfomod.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
# 3_filters/code_filter_lfomod.py
2+
# part of todbot circuitpython synthio tutorial
3+
# 10 Feb 2025 - @todbot / Tod Kurt
4+
#
25
import time, synthio
36
import ulab.numpy as np
47
from synth_setup import synth, knobA, knobB
5-
midi_note = 60
6-
note = synthio.Note(synthio.midi_to_hz(midi_note))
7-
# make a custom waveform, a sawtooth wave, more on this later
8+
midi_notes = (43, 48, 55, 60) # a little arpeggio
9+
mi = 0 # which midi note to play
10+
note = synthio.Note(synthio.midi_to_hz(midi_notes[mi]))
11+
# make a custom sawtooth waveform, more on this later
812
note.waveform = np.linspace(32000, -32000, num=128, dtype=np.int16)
9-
10-
filter_lfo = synthio.LFO(rate=0.75, offset=4000, scale=3500)
11-
12-
filter1 = synthio.Biquad(synthio.FilterMode.LOW_PASS,
13-
frequency=filter_lfo, Q=1.5)
13+
# lfo to turn the filter frequency "knob" for us
14+
filter_lfo = synthio.LFO(rate=0.75, offset=4000, scale=3700)
15+
filter1 = synthio.Biquad(synthio.FilterMode.BAND_PASS,
16+
frequency=filter_lfo, Q=1.5)
1417
note.filter = filter1
1518
synth.press(note)
1619

1720
while True:
18-
print("note freq: %6.2f filter freq: %6.2f Q: %1.2f" %
19-
(note.frequency, filter1.frequency.value, filter1.Q))
20-
time.sleep(0.05)
21+
for _ in range(20):
22+
print("note freq: %6.2f filter freq: %4d Q: %1.2f" %
23+
(note.frequency, filter1.frequency.value, filter1.Q))
24+
filter_lfo.rate = (knobA.value/65535) * 20 # 0-20
25+
filter1.Q = (knobB.value/65535) * 2 # 0-2
26+
time.sleep(0.05)
27+
mi = (mi+1) % len(midi_notes) # go to next note
28+
note.frequency = synthio.midi_to_hz(midi_notes[mi])

3_filters/code_filter_tryout.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@
77
from synth_setup import synth
88

99
while True:
10-
midi_note = random.randint(48,72)
10+
midi_note = random.randint(36,60)
1111
print("playing note", midi_note)
1212
note = synthio.Note(synthio.midi_to_hz(midi_note))
1313
synth.press(note)
14-
# try out each filter
14+
# try out each filter by assigning to note.filter
1515
note.filter = synthio.Biquad(synthio.FilterMode.LOW_PASS, frequency=1000, Q=1.0)
1616
time.sleep(0.5)
1717
note.filter = synthio.Biquad(synthio.FilterMode.HIGH_PASS, frequency=1000, Q=1.0)
1818
time.sleep(0.5)
1919
note.filter = synthio.Biquad(synthio.FilterMode.BAND_PASS, frequency=1000, Q=1.0)
2020
time.sleep(0.5)
2121
synth.release(note)
22-
time.sleep(0.1)
22+
time.sleep(0.2)

README-2-Modulation.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,8 @@ and bends into the final pitch
569569

570570
Tomtom drums are pitched, so we can use lower MIDI note pitches playing sine
571571
waves for them. Bass drums are kinda like big toms, so we'll do the same for them.
572+
We'll talk more detail about custom oscillator waveforms in
573+
[Oscillators and Wavetables](README-4-Oscillators-Wavetables.md).
572574

573575
Also in this example is a quick way of doing a snare drum. Snare drums have
574576
little rattles on them that make a sizzling noise when they're struck. We can

0 commit comments

Comments
 (0)