CircuitPython version and board name
Adafruit CircuitPython 10.3.0-alpha.2 on 2026-05-15; Raspberry Pi Pico 2 with rp2350a
Code/REPL
import audiobusio
import audiomixer
import board
import synthio
import time
FILTER = True
FILTER_BYPASS = False
audio = audiobusio.I2SOut(
bit_clock=board.GP20,
word_select=board.GP21,
data=board.GP22,
)
synth = synthio.Synthesizer(
sample_rate=44100,
channel_count=2,
)
if FILTER:
import audiofilters
effect_filter = audiofilters.Filter(
sample_rate=44100,
channel_count=2,
filter=None if FILTER_BYPASS else synthio.Biquad(
mode=synthio.FilterMode.LOW_PASS,
frequency=44100 / 2,
),
)
audio.play(effect_filter.play(synth))
else:
audio.play(synth)
synth.press(synthio.Note(
frequency=220,
panning=synthio.LFO(
rate=0.25,
),
amplitude=0.5,
))
Behavior
The stereo waveform graph above adheres to the following settings:
# Recording 1
FILTER = False
FILTER_BYPASS = True
# Recording 2
FILTER = True
FILTER_BYPASS = True
# Recording 3
FILTER = True
FILTER_BYPASS = False
Stereo audio data behaves normally until a synthio.Biquad object is provided which negatively impacts stereo imaging.
Description
A single biquad_filter_state struct is being created within filter_states for each synthio.Biquad assigned to the filter list in shared-module/audiofilters/Filter.c. This only accounts for a single channel of audio data, so each state is being shared across both left and right channels.
|
synthio_biquad_filter_samples(filter_obj, &self->filter_states[j], self->filter_buffer, n_samples); |
To fix this if channel_count=2, two biquad_filter_state structs should be created per synthio.Biquad and they should be used with synthio_biquad_filter_samples depending on the current channel of the sample.
Additional information
I wrote this module, so it's on me 😆
CircuitPython version and board name
Code/REPL
Behavior
The stereo waveform graph above adheres to the following settings:
Stereo audio data behaves normally until a
synthio.Biquadobject is provided which negatively impacts stereo imaging.Description
A single
biquad_filter_statestruct is being created withinfilter_statesfor eachsynthio.Biquadassigned to thefilterlist inshared-module/audiofilters/Filter.c. This only accounts for a single channel of audio data, so each state is being shared across both left and right channels.circuitpython/shared-module/audiofilters/Filter.c
Line 271 in 0ec323a
To fix this if
channel_count=2, twobiquad_filter_statestructs should be created persynthio.Biquadand they should be used withsynthio_biquad_filter_samplesdepending on the current channel of the sample.Additional information
I wrote this module, so it's on me 😆