Text Editor
Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide.
Alternatively, you can use any text editor that saves simple text files.
Download the Project Bundle
Your project will use a specific set of CircuitPython libraries, and the code.py file. To get everything you need, click on the Download Project Bundle button below, and uncompress the .zip file.
Connect your computer to the board via a known good USB power+data cable. A new flash drive should show up as CIRCUITPY.
Drag the contents of the uncompressed bundle directory onto your board CIRCUITPY drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.
# SPDX-FileCopyrightText: Copyright (c) 2023 john park for Adafruit Industries
#
# SPDX-License-Identifier: MIT
''' Faderwave Synthesizer
use 16 faders to create the single cycle waveform
rotary encoder adjusts other synth parameters
audio output: line level over 3.5mm TRS
optional CV output via DAC '''
import board
import busio
import ulab.numpy as np
import rotaryio
from digitalio import DigitalInOut, Pull
import displayio
import fourwire
from adafruit_display_text import label
from adafruit_display_shapes.rect import Rect
import terminalio
import synthio
import audiomixer
from adafruit_debouncer import Debouncer
import adafruit_ads7830.ads7830 as ADC
from adafruit_ads7830.analog_in import AnalogIn
import adafruit_displayio_ssd1306
import adafruit_ad569x
import usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff
displayio.release_displays()
DEBUG = False # turn on print debugging messages
ITSY_TYPE = 0 # Pick your ItsyBitsy: 0=M4, 1=RP2040
# neopixel setup for RP2040 only
if ITSY_TYPE == 1:
import neopixel
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3)
pixel.fill(0x004444)
i2c = busio.I2C(board.SCL, board.SDA, frequency=1_000_000)
midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], in_channel=0)
NUM_FADERS = 16
num_oscs = 1 # how many oscillators for each note to start
detune = 0.000 # how much to detune the oscillators
volume = 0.6 # mixer volume
lpf_freq = 12000 # user Low Pass Filter frequency setting
lpf_basef = 500 # filter lowest frequency
lpf_resonance = 0.1 # filter q
faders_pos = [0] * NUM_FADERS
last_faders_pos = [0] * NUM_FADERS
# Initialize ADS7830
adc_a = ADC.ADS7830(i2c, address=0x48) # default address 0x48
adc_b = ADC.ADS7830(i2c, address=0x49) # A0 jumper 0x49, A1 0x4A
faders = [] # list for fader objects on first ADC
for fdr in range(8): # add first group to list
faders.append(AnalogIn(adc_a, fdr))
for fdr in range(8): # add second group
faders.append(AnalogIn(adc_b, fdr))
# Initialize AD5693R for CV out
dac = adafruit_ad569x.Adafruit_AD569x(i2c)
dac.gain = True
dac.value = faders[0].value # set dac out to the slider level
# Rotary encoder setup
ENC_A = board.D9
ENC_B = board.D10
ENC_SW = board.D7
button_in = DigitalInOut(ENC_SW) # defaults to input
button_in.pull = Pull.UP # turn on internal pull-up resistor
button = Debouncer(button_in)
encoder = rotaryio.IncrementalEncoder(ENC_A, ENC_B)
encoder_pos = encoder.position
last_encoder_pos = encoder.position
# display setup
OLED_RST = board.D13
OLED_DC = board.D12
OLED_CS = board.D11
spi = board.SPI()
display_bus = fourwire.FourWire(spi, command=OLED_DC, chip_select=OLED_CS,
reset=OLED_RST, baudrate=30_000_000)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)
# Create display group
group = displayio.Group()
# Set the font for the text label
font = terminalio.FONT
# Create text label
title = label.Label(font, x=2, y=4, text=("FADERWAVE SYNTHESIZER"), color=0xffffff)
group.append(title)
column_x = (8, 60, 100)
row_y = (22, 34, 46, 58)
midi_lbl_rect = Rect(column_x[2]-3, row_y[0]-5, 28, 10, fill=0xffffff)
group.append(midi_lbl_rect)
midi_lbl = label.Label(font, x=column_x[2], y=row_y[0], text="MIDI", color=0x000000)
group.append(midi_lbl)
midi_rect = Rect(column_x[2]-3, row_y[1]-5, 28, 10, fill=0xffffff)
group.append(midi_rect)
midi_counter_lbl = label.Label(font, x=column_x[2]+8, y=row_y[1], text='-', color=0x000000)
group.append(midi_counter_lbl)
# Create menu selector
menu_sel = 0
menu_sel_txt = label.Label(font, text=(">"), color=0xffffff)
menu_sel_txt.x = column_x[0]-10
menu_sel_txt.y = row_y[menu_sel]
group.append(menu_sel_txt)
# Create detune text
det_txt_a = label.Label(font, text=("Detune "), color=0xffffff)
det_txt_a.x = column_x[0]
det_txt_a.y = row_y[0]
group.append(det_txt_a)
det_txt_b = label.Label(font, text=(str(detune)), color=0xffffff)
det_txt_b.x = column_x[1]
det_txt_b.y = row_y[0]
group.append(det_txt_b)
# Create number of oscs text
num_oscs_txt_a = label.Label(font, text=("Num Oscs "), color=0xffffff)
num_oscs_txt_a.x = column_x[0]
num_oscs_txt_a.y = row_y[1]
group.append(num_oscs_txt_a)
num_oscs_txt_b = label.Label(font, text=(str(num_oscs)), color=0xffffff)
num_oscs_txt_b.x = column_x[1]
num_oscs_txt_b.y = row_y[1]
group.append(num_oscs_txt_b)
# Create volume text
vol_txt_a = label.Label(font, text=("Volume "), color=0xffffff)
vol_txt_a.x = column_x[0]
vol_txt_a.y = row_y[2]
group.append(vol_txt_a)
vol_txt_b = label.Label(font, text=(str(volume)), color=0xffffff)
vol_txt_b.x = column_x[1]
vol_txt_b.y = row_y[2]
group.append(vol_txt_b)
# Create lpf frequency text
lpf_txt_a = label.Label(font, text=("LPF "), color=0xffffff)
lpf_txt_a.x = column_x[0]
lpf_txt_a.y = row_y[3]
group.append(lpf_txt_a)
lpf_txt_b = label.Label(font, text=(str(lpf_freq)), color=0xffffff)
lpf_txt_b.x = column_x[1]
lpf_txt_b.y = row_y[3]
group.append(lpf_txt_b)
# Show the display group
display.root_group = group
# Synthio setup
if ITSY_TYPE == 0:
import audioio
audio = audioio.AudioOut(left_channel=board.A0, right_channel=board.A1) # M4 built-in DAC
if ITSY_TYPE == 1:
import audiopwmio
audio = audiopwmio.PWMAudioOut(board.A1)
# if using I2S amp:
# audio = audiobusio.I2SOut(bit_clock=board.MOSI, word_select=board.MISO, data=board.SCK)
mixer = audiomixer.Mixer(channel_count=2, sample_rate=44100, buffer_size=4096)
synth = synthio.Synthesizer(channel_count=2, sample_rate=44100)
audio.play(mixer)
mixer.voice[0].play(synth)
mixer.voice[0].level = 0.75
wave_user = np.array([0]*NUM_FADERS, dtype=np.int16)
amp_env = synthio.Envelope(attack_time=0.3, attack_level=1, sustain_level=0.65, release_time=0.3)
def faders_to_wave():
for j in range(NUM_FADERS):
wave_user[j] = int(map_range(faders_pos[j], 0, 127, -32768, 32767))
notes_pressed = {} # which notes being pressed. key=midi note, val=note object
def note_on(n):
voices = [] # holds our currently sounding voices ('Notes' in synthio speak)
fo = synthio.midi_to_hz(n)
lpf = synth.low_pass_filter(lpf_freq, lpf_resonance)
for k in range(num_oscs):
f = fo * (1 + k*detune)
voices.append(synthio.Note(frequency=f, filter=lpf, envelope=amp_env, waveform=wave_user))
synth.press(voices)
note_off(n) # help to prevent double note_on for same note which can get stuck
notes_pressed[n] = voices
def note_off(n):
note = notes_pressed.get(n, None)
if note:
synth.release(note)
# simple range mapper, like Arduino map()
def map_range(s, a1, a2, b1, b2):
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
notes_on = 0
print("Welcome to Faderwave")
while True:
# get midi messages
msg = midi.receive()
if isinstance(msg, NoteOn) and msg.velocity != 0:
note_on(msg.note)
notes_on = notes_on + 1
if DEBUG:
print("MIDI notes on: ", msg.note, " Polyphony:", " "*notes_on, notes_on)
midi_counter_lbl.text = str(msg.note)
elif isinstance(msg, NoteOff) or (isinstance(msg, NoteOn) and msg.velocity == 0):
note_off(msg.note)
notes_on = notes_on - 1
if DEBUG:
print("MIDI notes off:", msg.note, " Polyphony:", " "*notes_on, notes_on)
midi_counter_lbl.text = "-"
# check faders
for i in range(len(faders)):
faders_pos[i] = faders[i].value//512
if faders_pos[i] is not last_faders_pos[i]:
faders_to_wave()
last_faders_pos[i] = faders_pos[i]
if DEBUG:
print("fader", [i], faders_pos[i])
# send out a DAC value based on fader 0
# if i == 1:
# dac.value = faders[1].value
# check encoder button
button.update()
if button.fell:
menu_sel = (menu_sel+1) % 4
menu_sel_txt.y = row_y[menu_sel]
# check encoder
encoder_pos = encoder.position
if encoder_pos > last_encoder_pos:
delta = encoder_pos - last_encoder_pos
if menu_sel == 0:
detune = detune + (delta * 0.001)
detune = min(max(detune, -0.030), 0.030)
formatted_detune = str("{:.3f}".format(detune))
det_txt_b.text = formatted_detune
elif menu_sel == 1:
num_oscs = num_oscs + delta
num_oscs = min(max(num_oscs, 1), 5)
formatted_num_oscs = str(num_oscs)
num_oscs_txt_b.text = formatted_num_oscs
elif menu_sel == 2:
volume = volume + (delta * 0.01)
volume = min(max(volume, 0.00), 1.00)
mixer.voice[0].level = volume
formatted_volume = str("{:.2f}".format(volume))
vol_txt_b.text = formatted_volume
elif menu_sel == 3:
lpf_freq = lpf_freq + (delta * 1000)
lpf_freq = min(max(lpf_freq, 1000), 20_000)
formatted_lpf = str(lpf_freq)
lpf_txt_b.text = formatted_lpf
last_encoder_pos = encoder.position
if encoder_pos < last_encoder_pos:
delta = last_encoder_pos - encoder_pos
if menu_sel == 0:
detune = detune - (delta * 0.001)
detune = min(max(detune, -0.030), 0.030)
formatted_detune = str("{:.3f}".format(detune))
det_txt_b.text = formatted_detune
elif menu_sel == 1:
num_oscs = num_oscs - delta
num_oscs = min(max(num_oscs, 1), 8)
formatted_num_oscs = str(num_oscs)
num_oscs_txt_b.text = formatted_num_oscs
elif menu_sel == 2:
volume = volume - (delta * 0.01)
volume = min(max(volume, 0.00), 1.00)
mixer.voice[0].level = volume
formatted_volume = str("{:.2f}".format(volume))
vol_txt_b.text = formatted_volume
elif menu_sel == 3:
lpf_freq = lpf_freq - (delta * 1000)
lpf_freq = min(max(lpf_freq, 1000), 20_000)
formatted_lpf = str(lpf_freq)
lpf_txt_b.text = formatted_lpf
last_encoder_pos = encoder.position
import board import busio import ulab.numpy as np import rotaryio from digitalio import DigitalInOut, Pull import displayio from adafruit_display_text import label from adafruit_display_shapes.rect import Rect import terminalio import synthio import audiomixer from adafruit_debouncer import Debouncer import adafruit_ads7830.ads7830 as ADC from adafruit_ads7830.analog_in import AnalogIn import adafruit_displayio_ssd1306 import adafruit_ad569x import usb_midi import adafruit_midi from adafruit_midi.note_on import NoteOn from adafruit_midi.note_off import NoteOff
Setup and Constants
First some setup, including user constants for DEBUG and ITSY_TYPE. Also to release the display before setting it up for use.
displayio.release_displays()
DEBUG = False # turn on print debugging messages
ITSY_TYPE = 0 # Pick your ItsyBitsy: 0=M4, 1=RP2040
# neopixel setup for RP2040 only
if ITSY_TYPE == 1:
import neopixel
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3)
pixel.fill(0x004444)
I2C, MIDI, Synthio, and Driver Setup
-
busio.I2Cinitializes one I2C bus on the STEMMA QT port pins -
adafruit_midiis set up for USB MIDI input - Initial
synthiosettings are established to define parameters for the synthesizer, such as the number of faders, initial number of oscillators, detune amount, volume, and low-pass filter settings.
i2c = busio.I2C(board.SCL, board.SDA, frequency=1_000_000) midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], in_channel=0) NUM_FADERS = 16 num_oscs = 1 # how many oscillators for each note to start detune = 0.000 # how much to detune the oscillators volume = 0.6 # mixer volume lpf_freq = 12000 # user Low Pass Filter frequency setting lpf_basef = 500 # filter lowest frequency lpf_resonance = 0.1 # filter q faders_pos = [0] * NUM_FADERS last_faders_pos = [0] * NUM_FADERS
Fader Initialization
Initializes the ADC for reading values from faders. Creates a list of AnalogIn objects representing the faders.
adc_a = ADC.ADS7830(i2c, address=0x48) # default address 0x48
adc_b = ADC.ADS7830(i2c, address=0x49) # A0 jumper 0x49, A1 0x4A
faders = [] # list for fader objects on first ADC
for fdr in range(8): # add first group to list
faders.append(AnalogIn(adc_a, fdr))
for fdr in range(8): # add second group
faders.append(AnalogIn(adc_b, fdr))
# Initialize AD5693R for CV out dac = adafruit_ad569x.Adafruit_AD569x(i2c) dac.gain = True dac.value = faders[0].value # set dac out to the slider level
ENC_A = board.D9 ENC_B = board.D10 ENC_SW = board.D7 button_in = DigitalInOut(ENC_SW) # defaults to input button_in.pull = Pull.UP # turn on internal pull-up resistor button = Debouncer(button_in) encoder = rotaryio.IncrementalEncoder(ENC_A, ENC_B) encoder_pos = encoder.position last_encoder_pos = encoder.position
OLED Display Setup
Now to set up the OLED display using the SSD1306 driver and initialize the displayio group.
OLED_RST = board.D13
OLED_DC = board.D12
OLED_CS = board.D11
spi = board.SPI()
display_bus = fourwire.FourWire(spi, command=OLED_DC, chip_select=OLED_CS,
reset=OLED_RST, baudrate=30_000_000)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)
Screen Elements
Here all of the various screen elements are created, including text labels, selector cursor, and value fields.
group = displayio.Group()
# Set the font for the text label
font = terminalio.FONT
# Create text label
title = label.Label(font, x=2, y=4, text=("FADERWAVE SYNTHESIZER"), color=0xffffff)
group.append(title)
column_x = (8, 60, 100)
row_y = (22, 34, 46, 58)
midi_lbl_rect = Rect(column_x[2]-3, row_y[0]-5, 28, 10, fill=0xffffff)
group.append(midi_lbl_rect)
midi_lbl = label.Label(font, x=column_x[2], y=row_y[0], text="MIDI", color=0x000000)
group.append(midi_lbl)
midi_rect = Rect(column_x[2]-3, row_y[1]-5, 28, 10, fill=0xffffff)
group.append(midi_rect)
midi_counter_lbl = label.Label(font, x=column_x[2]+8, y=row_y[1], text='-', color=0x000000)
group.append(midi_counter_lbl)
# Create menu selector
menu_sel = 0
menu_sel_txt = label.Label(font, text=(">"), color=0xffffff)
menu_sel_txt.x = column_x[0]-10
menu_sel_txt.y = row_y[menu_sel]
group.append(menu_sel_txt)
# Create detune text
det_txt_a = label.Label(font, text=("Detune "), color=0xffffff)
det_txt_a.x = column_x[0]
det_txt_a.y = row_y[0]
group.append(det_txt_a)
det_txt_b = label.Label(font, text=(str(detune)), color=0xffffff)
det_txt_b.x = column_x[1]
det_txt_b.y = row_y[0]
group.append(det_txt_b)
# Create number of oscs text
num_oscs_txt_a = label.Label(font, text=("Num Oscs "), color=0xffffff)
num_oscs_txt_a.x = column_x[0]
num_oscs_txt_a.y = row_y[1]
group.append(num_oscs_txt_a)
num_oscs_txt_b = label.Label(font, text=(str(num_oscs)), color=0xffffff)
num_oscs_txt_b.x = column_x[1]
num_oscs_txt_b.y = row_y[1]
group.append(num_oscs_txt_b)
# Create volume text
vol_txt_a = label.Label(font, text=("Volume "), color=0xffffff)
vol_txt_a.x = column_x[0]
vol_txt_a.y = row_y[2]
group.append(vol_txt_a)
vol_txt_b = label.Label(font, text=(str(volume)), color=0xffffff)
vol_txt_b.x = column_x[1]
vol_txt_b.y = row_y[2]
group.append(vol_txt_b)
# Create lpf frequency text
lpf_txt_a = label.Label(font, text=("LPF "), color=0xffffff)
lpf_txt_a.x = column_x[0]
lpf_txt_a.y = row_y[3]
group.append(lpf_txt_a)
lpf_txt_b = label.Label(font, text=(str(lpf_freq)), color=0xffffff)
lpf_txt_b.x = column_x[1]
lpf_txt_b.y = row_y[3]
group.append(lpf_txt_b)
# Show the display group
display.root_group = group
synthio Setup
Next: set up synthio. This can work with different audio output types depending on the ItsyBitsy board you use. I also set up a mixer object and the wave_user object that is the single-cycle waveform you'll be editing on the fly with the faders.
# Synthio setup
if ITSY_TYPE == 0:
import audioio
audio = audioio.AudioOut(left_channel=board.A0, right_channel=board.A1) # M4 built-in DAC
if ITSY_TYPE == 1:
import audiopwmio
audio = audiopwmio.PWMAudioOut(board.A1)
# if using I2S amp:
# audio = audiobusio.I2SOut(bit_clock=board.MOSI, word_select=board.MISO, data=board.SCK)
mixer = audiomixer.Mixer(channel_count=2, sample_rate=44100, buffer_size=4096)
synth = synthio.Synthesizer(channel_count=2, sample_rate=44100)
audio.play(mixer)
mixer.voice[0].play(synth)
mixer.voice[0].level = 0.75
wave_user = np.array([0]*NUM_FADERS, dtype=np.int16)
amp_env = synthio.Envelope(attack_time=0.3, attack_level=1, sustain_level=0.65, release_time=0.3)
Functions
We'll create a number of functions to call during play.
faders_to_wave() remaps the fader positions to the wavetable array points. This is the key to the whole thing!
note_on() and note_off() are called when MIDI messages for note on/off are received.
def faders_to_wave():
for j in range(NUM_FADERS):
wave_user[j] = int(map_range(faders_pos[j], 0, 127, -32768, 32767))
notes_pressed = {} # which notes being pressed. key=midi note, val=note object
def note_on(n):
voices = [] # holds our currently sounding voices ('Notes' in synthio speak)
fo = synthio.midi_to_hz(n)
lpf = synth.low_pass_filter(lpf_freq, lpf_resonance)
for k in range(num_oscs):
f = fo * (1 + k*detune)
voices.append(synthio.Note(frequency=f, filter=lpf, envelope=amp_env, waveform=wave_user))
synth.press(voices)
note_off(n) # help to prevent double note_on for same note which can get stuck
notes_pressed[n] = voices
def note_off(n):
note = notes_pressed.get(n, None)
if note:
synth.release(note)
# simple range mapper, like Arduino map()
def map_range(s, a1, a2, b1, b2):
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
Main Loop
The main loop continuously checks for MIDI messages, updates the synthesizer state based on input, and adjusts parameters using faders and the rotary encoder.
MIDI Input Handling (note_on and note_off):
- Processes MIDI messages, triggers note on/off events, and updates a counter label on the display.
Fader Handling (faders_to_wave):
- Reads values from faders and updates a waveform array. Also, sends out a DAC value based on the first fader.
Encoder Handling:
- Monitors the rotary encoder and adjusts parameters based on the selected menu.
Display Updates:
- Updates the OLED display with the current values of parameters like detune, number of oscillators, volume, and LPF frequency.
Synthio Operation:
- Creates a waveform based on the fader values and triggers note events based on MIDI input.
Hardware Interaction:
- Manages hardware components such as DAC, NeoPixel, and the display.
Debugging Output:
- If
DEBUGis set toTrue, it prints debugging messages, including MIDI notes on/off and polyphony information.
Display Output:
- If you are not seeing output on the TFT try adding a small delay and lowering the SPI baudrate to 6MHz.
spi = board.SPI()
time.sleep(0.5) # Brief delay for the SPI bus to stabilize
display_bus = fourwire.FourWire(
spi,
command=OLED_DC,
chip_select=OLED_CS,
reset=OLED_RST,
baudrate=6_000_000 # Lowered from 30_000_000
)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)
msg = midi.receive()
if isinstance(msg, NoteOn) and msg.velocity != 0:
note_on(msg.note)
notes_on = notes_on + 1
if DEBUG:
print("MIDI notes on: ", msg.note, " Polyphony:", " "*notes_on, notes_on)
midi_counter_lbl.text=str(msg.note)
elif isinstance(msg, NoteOff) or (isinstance(msg, NoteOn) and msg.velocity == 0):
note_off(msg.note)
notes_on = notes_on - 1
if DEBUG:
print("MIDI notes off:", msg.note, " Polyphony:", " "*notes_on, notes_on)
midi_counter_lbl.text="-"
# check faders
for i in range(len(faders)):
faders_pos[i] = faders[i].value//512
if faders_pos[i] is not last_faders_pos[i]:
faders_to_wave()
last_faders_pos[i] = faders_pos[i]
if DEBUG:
print("fader", [i], faders_pos[i])
# send out a DAC value based on fader 0
# if i == 1:
# dac.value = faders[1].value
# check encoder button
button.update()
if button.fell:
menu_sel = (menu_sel+1) % 4
menu_sel_txt.y = row_y[menu_sel]
# check encoder
encoder_pos = encoder.position
if encoder_pos > last_encoder_pos:
delta = encoder_pos - last_encoder_pos
if menu_sel == 0:
detune = detune + (delta * 0.001)
detune = min(max(detune, -0.030), 0.030)
formatted_detune = str("{:.3f}".format(detune))
det_txt_b.text = formatted_detune
elif menu_sel == 1:
num_oscs = num_oscs + delta
num_oscs = min(max(num_oscs, 1), 5)
formatted_num_oscs = str(num_oscs)
num_oscs_txt_b.text = formatted_num_oscs
elif menu_sel == 2:
volume = volume + (delta * 0.01)
volume = min(max(volume, 0.00), 1.00)
mixer.voice[0].level = volume
formatted_volume = str("{:.2f}".format(volume))
vol_txt_b.text = formatted_volume
elif menu_sel == 3:
lpf_freq = lpf_freq + (delta * 1000)
lpf_freq = min(max(lpf_freq, 1000), 20_000)
formatted_lpf = str(lpf_freq)
lpf_txt_b.text = formatted_lpf
last_encoder_pos = encoder.position
if encoder_pos < last_encoder_pos:
delta = last_encoder_pos - encoder_pos
if menu_sel == 0:
detune = detune - (delta * 0.001)
detune = min(max(detune, -0.030), 0.030)
formatted_detune = str("{:.3f}".format(detune))
det_txt_b.text = formatted_detune
elif menu_sel == 1:
num_oscs = num_oscs - delta
num_oscs = min(max(num_oscs, 1), 8)
formatted_num_oscs = str(num_oscs)
num_oscs_txt_b.text = formatted_num_oscs
elif menu_sel == 2:
volume = volume - (delta * 0.01)
volume = min(max(volume, 0.00), 1.00)
mixer.voice[0].level = volume
formatted_volume = str("{:.2f}".format(volume))
vol_txt_b.text = formatted_volume
elif menu_sel == 3:
lpf_freq = lpf_freq - (delta * 1000)
lpf_freq = min(max(lpf_freq, 1000), 20_000)
formatted_lpf = str(lpf_freq)
lpf_txt_b.text = formatted_lpf
last_encoder_pos = encoder.position
Page last edited February 14, 2025
Text editor powered by tinymce.