Tympan / Tympan_Library

Arduino/Teensy Library for Tympan Open Source Hearing Aid
MIT License
122 stars 32 forks source link

Dynamic Audio Connections #81

Open chipaudette opened 1 week ago

chipaudette commented 1 week ago

The core Teensy Audio library supports dynamic audio connections. The Tympan Library does not. We should extend it to support dynamic audio connections.

There are two levels of "dynamic" that we could envisioned supporting:

Note: The Teensy library supports dynamic AudioConnection but not dynamic AudioStream. Given this, it seems like we ought to be able to get dynamic AudioConnection_F32 to work, but dynamic AudioStream_F32 is probably harder.

chipaudette commented 1 week ago

I made a branch of the Tympan_Library and tried to implement the full dynamic behavior -- both dynamic AudioConnection_F32 and dynamic AudioStream_F32. https://github.com/Tympan/Tympan_Library/tree/feature_createDestroyAudioStreamInstances. (*see note at bottom)

Unfortunately, this exploration took a lot of changes that might not be advisable. Here are a few examples:

I started a Teensy forum post to see if there is appetite for me to submit a pull request to Teensy: https://forum.pjrc.com/index.php?threads/destructor-for-audiostream.75797/

(Note: If you try to use this branch, the branch includes AudioStream_cores_Teensy4.h and AudioStream_cores_Teensy4.cpp. You need to copy these files to C:\Users\Chip\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.59.0\cores\teensy4 and then rename them to AudioStream.h and AudioStream.cpp so that you replace the original files that should already exist there. You'll probably want to back up those original files.)

chipaudette commented 1 week ago

Prior to the ability to dynamic connections, one had to instantiate all the possibly-desired audio pathways. One would then use switches and mixers to route audio blocks around to the different audio paths. It would look like this:

image

One question is whether all of the AudioPaths are running their calculations, even though we only want one active a time. Are we burning up CPU?

The answer is, no, generally not. The savior is that most audio processing elements (ie, AudioStream instances) have the behavior that they look for incoming blocks of audio. If there are no incoming blocks, they do no processing. So, by using the AudioSwitch to only route audio blocks to the desired audio path, only that audio path does any work. The other audio paths just sit idle. Nice!

The one situation where (I think) this breaks down is when you have something that generates its own audio. So, if you're using an AudioSynthWaveform_F32 to make a sine wave, it'll make a sine wave. It doesn't need to look for an in-coming block of audio, so it doesn't know that its been cut off as part of an inactive audio path. For these cases, one should use the enable or active flag (as applicable) which is part of many of the AudioStream child classes.

AudioPathSwitching.pptx

chipaudette commented 1 week ago

Out of nowhere, the Teensy folks are starting to build toward a new Teensy software release. This doesn't happen very often. Now is our chance to get the destructor into Teensy Cores!

I've offered this Pull Request: https://github.com/PaulStoffregen/cores/pull/755

chipaudette commented 1 week ago

I've been making an example that does the switching instead of create/destroy. It turns out that we don't need the initial switch. Instead, we can simply de-activate all of the processing blocks that we don't want and only activate the blocks of the one AudioPath that we desire.

So, it'd look like this:

multipath

AudioPathSwitching.pptx

chipaudette commented 1 week ago

@cab-creare-com I have a working example using my own AudioPath objects.

The example is in Tympan_Sandbox: https://github.com/Tympan/Tympan_Sandbox/tree/master/OpenHearing/TestSwitchedConnections

It's currently set to RevE, but you can easily switch it to any of the revisions (D/E/F) just by changing the "myTympan" line.

Once compiled and uploaded, you control it via the Serial Monitor. Use the menu (send an 'h') to switch between:

Chip