Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audible stepping when using synthio.LFO on audiodelays.Echo.delay_ms #10030

Open
relic-se opened this issue Feb 6, 2025 · 1 comment
Open
Milestone

Comments

@relic-se
Copy link

relic-se commented Feb 6, 2025

CircuitPython version and board name

Adafruit CircuitPython 9.2.4; Pimoroni Pico Plus2 with rp2350b

Code/REPL

import audiobusio
import audiodelays
import board, time
import synthio

SAMPLE_RATE = 48000
AMPLITUDE = 0.2
MIX = 1.0 # Would need to be 0.5 if #9994 is merged
TIME = 40
DEPTH = 8
RATE = 1.0
OCTAVE = -1

audio = audiobusio.I2SOut(
    bit_clock=board.GP0,
    word_select=board.GP1,
    data=board.GP2,
)

synth = synthio.Synthesizer(
    sample_rate=SAMPLE_RATE,
    channel_count=2,
)

effect = audiodelays.Echo(
    max_delay_ms=TIME,
    delay_ms=synthio.LFO(offset=TIME, scale=DEPTH, rate=RATE),
    decay=0.0,
    sample_rate=SAMPLE_RATE,
    channel_count=2,
    freq_shift=True,
)

effect.play(synth)
audio.play(effect)

# Chord
for i in range(3):
    synth.press(synthio.Note(
        frequency=synthio.midi_to_hz(65 + i * 4 + OCTAVE * 12),
        panning=synthio.LFO(rate=0.15 + i * 0.05),
        amplitude=AMPLITUDE,
    ))

while True:
    if effect.mix:
        effect.mix = 0.0
        print("Off")
    else:
        effect.mix = MIX
        print("On")
    time.sleep(2.0)

Behavior

There is audible stepping in the chorus effect.

Here's a recording of the above example: https://drive.google.com/file/d/13qotNTCFfkoQ_GuhENawpOw9rmh5oPoS/view?usp=drive_link

Description

No response

Additional information

The optimization at Echo.c#L313 prevents calling recalculate_delay at it's maximum rate of SYNTHIO_MAX_DUR and instead limits it to increments of sample_ms. For effects using larger delay lengths, this stepping isn't noticeable, but for effects which require a delay with a shorter delay length (ie: chorus, flanger), more granularity is required.

if (MICROPY_FLOAT_C_FUN(fabs)(self->current_delay_ms - f_delay_ms) >= self->sample_ms) {
recalculate_delay(self, f_delay_ms);
}

I'm thinking that a suitable solution is to check the difference by sample_ms / 256 when freq_shift=True (for the 8-bits of sub-resolution). That, or test the float equality using memcmp such as in the following function.

static int float_equal_or_update(
mp_float_t *cached,
mp_float_t new) {
// uses memcmp to avoid error about equality float comparison
if (memcmp(cached, &new, sizeof(mp_float_t))) {
*cached = new;
return false;
}
return true;
}

@relic-se relic-se added the bug label Feb 6, 2025
@relic-se
Copy link
Author

relic-se commented Feb 6, 2025

I've tested the proposed fix, and it doesn't appear to resolve the issue. I've also toyed around with a few other adjustments to no avail. Any ideas as to why this could be happening would be greatly appreciated.

@dhalbert dhalbert added this to the 9.x.x milestone Feb 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants