Skip to content

audiowriter module#11106

Open
FoamyGuy wants to merge 8 commits into
adafruit:mainfrom
FoamyGuy:audiowriter
Open

audiowriter module#11106
FoamyGuy wants to merge 8 commits into
adafruit:mainfrom
FoamyGuy:audiowriter

Conversation

@FoamyGuy

@FoamyGuy FoamyGuy commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

This new module provides an audio sink that writes to a file. Its API is essentially a drop in replacement in code for where you would normally use AudioOut or one of the variations of it.

This allows saving audio generated from synthio and/or effects chains.

All of my testing has been on Metro RP2350. There are perhaps more ports or devices that this could be enabled on, right now I kept it only to rpi port and esp32s2. I left out the rest of the esp devices because they had audioio disabled, but maybe it would make more sense to have this depend on synthio and/or the audio effects flag since this writer functionality could be used with those even on ports that do not have other options for audio out theoretically.

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is only going to be files, maybe call it audiofilewriter? If not, are there other possible similar classes inside the module?

We also talked about having a more generalized audio sink: just a buffer or two that you could examine do what you want to with it. It would need to be pollable so you could tell when it was ready to examine. Perhaps that could be a "tee", so you could pass the audio on after changing it (assuming the code can keep up). Or it could just be a dead-end. (Is there a use for a /dev/null audio sink??)

@FoamyGuy

Copy link
Copy Markdown
Collaborator Author

audiofilewriter is probably better, I'll rename it to that. I don't have in mind any other kind of non-file writers for this module.

There are a few other sinks and other objects that would be cool I think, but in my mind they could live in their own modules instead of this one.

A /dev/null sink would be one solution to the problem presented here: https://forums.adafruit.com/viewtopic.php?t=224406. They had to use a dummy AudioOut in order to get synthio objects to work. A dummy would help in cases like this where the "real" output is getting routed elsewhere.

I do still think a more generalized buffer could be useful as well. Though I imagine it sitting within a chain instead of as a sink at the end of it. I think it could be used for audio reactive neopixels without a microphone. Audio generated by synthio and/or effects chains could pass thru a link in the chain that exposes the current data which could be analyzed with FFT and output to neopixels. The audio itself would continue through the chain to the sink that outputs it to wherever.

I think a splitter object is another that could be useful. Maybe the generalized buffer could be used for this. Right now it doesn't seem possible to take the same raw sample, pass it thru multiple different effects chains independently and then merge the results back together with audiomixer. Instead, once the raw sample passes through an effect chain link, the original version is gone. The original clean copy is unavailable to passed thru a different chain. A theoretical "splitter", I think the "tee" that you mention is the same, would allow the original raw source to get passed thru different effects independently rather than only serially.

Maybe one or both of the latter two could be done with the get_buffer() function that gets exposed by the AUIDIO_DEBUG build flag. I tried using that function to record to a file before implementing audiowriter but found that the recorded file was not clean, it had gaps in it. It warrants further investigation and testing with the other use-cases.

@FoamyGuy

Copy link
Copy Markdown
Collaborator Author

This is renamed to audiofilewriter.AudioFileWriter in the latest commit.

Comment on lines +37 to +39
//| :param int buffer_size: Size in bytes of the internal RAM ring that
//| decouples file-write latency from the source. Larger values tolerate
//| longer write stalls (e.g. a slow SD card) at the cost of RAM.

@dhalbert dhalbert Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code makes this a minimum of 512, but that's not documented. Maybe worth documenting. Also should it be a multiple of 512 or is any size >= 512 ok?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants