Skip to content

synthio does not work on some ports #7837

@jepler

Description

@jepler

CircuitPython version

Adafruit CircuitPython 8.0.5 on 2023-03-31; Raspberry Pi Pico W with rp2040
Board ID:raspberry_pi_pico_w

Code/REPL

import board
import synthio
import audiobusio
lck_pin, bck_pin, dat_pin  = board.GP28, board.GP27, board.GP26
audio = audiobusio.I2SOut(bit_clock=bck_pin, word_select=lck_pin, data=dat_pin)
melody = synthio.MidiTrack(b"\0\x90H\0*\x80H\0\6\x90J\0*\x80J\0\6\x90L\0*\x80L\0\6\x90J\0" +
    b"*\x80J\0\6\x90H\0*\x80H\0\6\x90J\0*\x80J\0\6\x90L\0T\x80L\0" +
    b"\x0c\x90H\0T\x80H\0\x0c\x90H\0T\x80H\0", tempo=640)
audio.play(melody)

Behavior

A single repeating tone is heard on the audio output, instead of the tune.

Description

@todbot discovered during testing #7825 that the new code wasn't working. I tested the original synthio, and it also doesn't work. The underlying cause is probably the same thing (incomplete handling of the needs of the audio implementation).

Additional information

I think it's due to the "single buffer" flag being true. It affects rp2040 (and probably atmel-samd and maybe nrf?), boards that actually use the "single buffer" flag to change behavior.

synthio needs to be modified to be more like a WaveFile, returning false for its single buffer flag and alternately returning two different halves of its buffer.

Introducing an otherwise unneeded AudioMixer object may be a workaround, at least for MidiFile in 8.0.4:

import board
import synthio
import audiomixer
import audiobusio
lck_pin, bck_pin, dat_pin  = board.GP28, board.GP27, board.GP26
audio = audiobusio.I2SOut(bit_clock=bck_pin, word_select=lck_pin, data=dat_pin)
melody = synthio.MidiTrack(b"\0\x90H\0*\x80H\0\6\x90J\0*\x80J\0\6\x90L\0*\x80L\0\6\x90J\0" +
    b"*\x80J\0\6\x90H\0*\x80H\0\6\x90J\0*\x80J\0\6\x90L\0T\x80L\0" +
    b"\x0c\x90H\0T\x80H\0\x0c\x90H\0T\x80H\0", tempo=640)
mixer = audiomixer.Mixer(sample_rate=melody.sample_rate, channel_count=1)
audio.play(mixer)
mixer.voice[0].play(melody)

it appears a similar audiomixer workaround works in #7825. (weirdly in 8.0.5, it seemed to also work with the mixer.voice[].play call before the audio.play call, unless my testing wasn't with the code I intended; when "reset_buffer" is called on an audiomixer, as it is at the beginning of playback on rp2040 audio_dma_setup_playback) all samples are stopped.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions