You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
""" Demonstrates a couple of issues in CircuitPython audio: 8-bit WAV playing fails with RuntimeError, and RawSample playback does not clear .playing flag at end. Test system is RP2040 Pico. Occurs with both audiopwmio and audiobusio.I2S; example shows just audiopwmio for simplicity."""importarrayimporttimeimportboardimportaudiocoreimportaudiopwmioaudio=audiopwmio.PWMAudioOut(board.GP22)
defplay(filename, usebuf, message):
""" Play requested WAV file, can use standard buffer or allocate a larger (1K) working buffer. 16-bit WAV plays OK. 8-bit WAV fails (regardless of buffer selection) at audio.play() with: "RuntimeError: Internal audio buffer too small" """print(message, end="")
file=open(filename, 'rb')
ifusebuf:
print(" w/custom buffer")
data=audiocore.WaveFile(file, bytearray(1024))
else:
print(" w/standard buffer")
data=audiocore.WaveFile(file)
audio.play(data)
whileaudio.playing:
passplay("hello16.wav", False, "16-bit WAV")
play("hello16.wav", True, "16-bit WAV")
play("hello8.wav", False, "8-bit WAV") # FAILSplay("hello8.wav", True, "8-bit WAV") # FAILSprint("8-bit WAV 'manually' via RawSample")
file=open('hello8.wav', 'rb')
file.seek(40, 0)
lw=file.read(4)
length=lw[0] + (lw[1] <<8) + (lw[2] <<16) + (lw[3] <<24)
raw=array.array("h", range(length))
foriinrange(length):
raw[i] =file.read(1)[0] *257-32768data=audiocore.RawSample(raw, sample_rate=8000)
# This DOES play through once...audio.play(data)
whileaudio.playing:
pass# ...but this line is never reached:print("HELLO!")
# (Have tried explicitly setting loop=False, makes no difference)
Behavior
For 8-bit WAVs:
RuntimeError: Internal audio buffer too small
For RawSample workaround:
Audio plays but .playing flag never clears, code can’t block correctly.
Description
16-bit WAVs play as expected, only 8-bit WAVs encounter the RuntimeError. This occurs whether using the standard audio buffer or when allocating a larger bytearray.
Trying to work around the bug via RawSample presents a different issue. Audio plays through once correctly, but the .playing flag is never cleared; code can’t block correctly.
Aside from the above, super happy to see the progress happening in CircuitPython audio, e.g. MP3 looping works great where it didn’t used to. Thank you!
The text was updated successfully, but these errors were encountered:
PR #8436 fixes the first bug (8-bit WAV playback on RP2040).
The second bug is a bit beyond me but I can see where it’s happening in ports/raspberrypi/audio_dma.c, in audio_dma_load_next_block(). RawSample audio playback is single-buffered, it just plays straight from the array in one pass. Double-buffered audio makes multiple calls through audiosample_get_buffer() and audio_dma_convert_samples() to determine when there’s no more data to read and to play back; a combination of GET_BUFFER_DONE and 0, respectively. Single-buffering returns GET_BUFFER_DONE and the source buffer size on a single call, but there is no subsequent invocation of this function that gets a 0 for the latter value.
ANYWAY, I need to move on to other things but am leaving notes here. With WAV playback fixed, the workaround (and its associated bug) wouldn’t have occurred. But, in principle, it’s still a bug. The typical use case for RawSample playback is looped playback of a waveform and this would not be encountered, but there can still be situations where single-pass RawSamples might be used.
The aforementioned PR is for RP2040. I have not dug out other hardware nor gone through other ports to see if the same bug(s) lurk there or if this is specific to the RP2040 DMA code, but probably will test/check eventually as it’s relevant to a guide in progress.
Additionally, I have not gone through other ports to see if the 8- to 16-bit expansion is performed correctly everywhere…but it’s a super common misunderstanding, e.g. seen before in the analogio.AnalogIn() range that I think was addressed from CP 8.0 forward. Myself or someone might make a pass through all audio-related code for N to >N bit conversion and make sure it’s not simply a left-shift, but a duplication of most-significant bits into the empty least-significant bits to avoid unwanted DC offset in the output waveform.
PaintYourDragon
changed the title
Two audio playback bugs
Two audio playback bugs (UPDATE: one)
Sep 30, 2023
CircuitPython version
Code/REPL
Behavior
For 8-bit WAVs:
RuntimeError: Internal audio buffer too small
For RawSample workaround:
Audio plays but .playing flag never clears, code can’t block correctly.
Description
16-bit WAVs play as expected, only 8-bit WAVs encounter the RuntimeError. This occurs whether using the standard audio buffer or when allocating a larger bytearray.
Trying to work around the bug via RawSample presents a different issue. Audio plays through once correctly, but the .playing flag is never cleared; code can’t block correctly.
Additional information
WAVs used by example code can be retrieved here:
https://www.dropbox.com/scl/fo/22rduhyy1rdzcd3m9d638/h?rlkey=a7fpsbcsw8747ki9u6yr58jz8&dl=0
(Have tested with different 8-bit WAVs, same issue)
Aside from the above, super happy to see the progress happening in CircuitPython audio, e.g. MP3 looping works great where it didn’t used to. Thank you!
The text was updated successfully, but these errors were encountered: