Dynamic Audio Connections

jkoffman

Well-known member
Hi all,

Since my mixer object is a bit stalled for the moment, I'm looking to try out dynamically changeable connections to accomplish some of what I was going for. I know this is possible, I'm just not finding a ton of examples online, and I want to make sure I'm not going about this the wrong way.

I saw an example from an old forum post that defines connections at the start like this:

Code:
AudioConnection * DynamicPatchCord1;

Then in the setup the connection is created like this:
Code:
DynamicPatchCord1 = new AudioConnection(*input1, 0, *mixer1, 0);

then connects and disconnects them like this:

Code:
DynamicPatchCord1->connect();
DynamicPatchCord1->disconnect();

I have some questions (I know you're shocked). First off, can I define the connection initially like the gui does (in this case AudioConnection DynamicPatchCord1(input1, 0, mixer, 0), then connect/disconnect as needed? Or is it better to leave the definition of what the connection is to the code so it can be modified while the program runs?

I saw on another post a passing reference to .connect() and .disconnect(), but I haven't seen it used. Does anyone have any code that shows this method in use?

Thank you!
 
I just do "new AudioConnection(...), like you show. You don't have to call ->connect(). If you don't need it, just "delete". It disconnects.
Having them "pre-made" is a pain, as you need to give each a new name.

I just have an std::list of connections, add all of them to connect things, then delete them when done and make new ones.
Then you don't have to keep track of them and they don't use memory if not connected.

In the header:
std::list<AudioConnection*> _cords;

In CPP file:
void AudioBoard::setupMixers() {
// Connect 4 input mixers to 2 output mixers
_cords.push_back(new AudioConnection(_mixer1, 0, _outMixer1, 0));
_cords.push_back(new AudioConnection(_mixer1, 0, _outMixer2, 0));
_cords.push_back(new AudioConnection(_mixer2, 0, _outMixer1, 1));
_cords.push_back(new AudioConnection(_mixer2, 0, _outMixer2, 1));
_cords.push_back(new AudioConnection(_mixer3, 0, _outMixer1, 2));
_cords.push_back(new AudioConnection(_mixer3, 0, _outMixer2, 2));
_cords.push_back(new AudioConnection(_mixer4, 0, _outMixer1, 3));
_cords.push_back(new AudioConnection(_mixer4, 0, _outMixer2, 3));

// 2 (stereo) output mixers go to the audio output
_cords.push_back(new AudioConnection(_outMixer1, 0, _audioOutput, 0));
_cords.push_back(new AudioConnection(_outMixer2, 0, _audioOutput, 1));
}

To disconnect:
for(auto cord : _cords)
delete cord;
_cords.clear();

Then you can connect what you need again.
 
Hi Andy, thank you for the reply!

I understand what you're doing on a basic level, but I'm not that experienced with c++ so I'll need to study it a bit further.

In my case, I want to basically be able to select between one of two outputs connected to the input of another block. Do you think it would be better to create two connections (but disconnect them) so I can just connect/disconnect, or completely disconnect and reassign each time? Or does disconnect break the relationship anyway and I'd have to reassign each time?

Thank you!
 
Any way will work.
You define the connecting points when you create the connection and can only connect/disconnect later. You cannot change the points of an existing connection.
If you delete/create a new connection each time, like in my example, you can define new points and connect.

Spend a couple of hours on C++ basics, like constructor/destructor and new/delete, and it all will be clear.
You'll need it anyway.

You can do the same in .ino file, just define the "std::list<AudioConnection*> _cords;" at the top and add "#include <list>" before that.
 
In my case, I want to basically be able to select between one of two outputs connected to the input of another block.
You seem to be trying to solve a non-existent problem. Why don't you just use a Mixer block? That's what it's for.
 
Any way will work.
You define the connecting points when you create the connection and can only connect/disconnect later. You cannot change the points of an existing connection.
If you delete/create a new connection each time, like in my example, you can define new points and connect.

Interesting. I will do some experiments to see if I am allowed to have two connections that technically conflict, but aren't both active at the same time.


Spend a couple of hours on C++ basics, like constructor/destructor and new/delete, and it all will be clear.
You'll need it anyway.

You can do the same in .ino file, just define the "std::list<AudioConnection*> _cords;" at the top and add "#include <list>" before that.

That's my plan. I do have a bit extra time now....

Thank you!
 
You seem to be trying to solve a non-existent problem. Why don't you just use a Mixer block? That's what it's for.

In my attempt to simplify what I'm doing, I haven't fully explained the issue. The better analogy would be that I'm making a phase reverse. So it's two sources, and two destinations. sometimes I want 1-1 and 2-2, and sometimes it will be 1-2 and 2-1.

To do this with mixers will use two mixers for each input, and in my case that would mean like 10-12 mixers. I had been trying to make a mixer with 2 outputs so that I could eventually make a 2x2 audio router, but I haven't been able to get it to work without glitching. I'll keep plugging away at that, but for the moment I'm pretty stuck.

I think reconfiguring the connections between my blocks is a good alternative solution. I'm going to do some experiments today and see what I can do!
 
Hi, long time listener, first time poster. I've been having success with the type of code proposed above, but cannot do something similar with dynamic AudioStream instances. After deleting the connections, if I attempt to delete the streams, I get a variety of symptoms (audio dropping from a single channel, crashing) which prevent me from moving forward with my project. Looking at the core code, it appears that AudioStream instances are entered into a list:

Code:
			// add to a simple list, for update_all
			// TODO: replace with a proper data flow analysis in update_all
			if (first_update == NULL) {
				first_update = this;
			} else {
				AudioStream *p;
				for (p=first_update; p->next_update; p = p->next_update) ;
				p->next_update = this;
			}

and never removed. Presumably this is what is causing the effects I'm seeing, but I'm new to the core code and might be making some bad assumptions.

Is there some reason why it would be unsafe to remove AudioStream instances from that list if they are deleted? The utter lack of a destructor for the class seems conspicuous, but it's not obvious to me. Potential race condition with audio interrupt code? Although presumably creating new AudioStream objects would have the same potential race condition. Anyway, please let me know if any of that sounds familiar... and thanks a lot!
 
My answer in two words: forget it.

I've spent maybe a week trying to create/delete effects and connections between them dynamically and gave up. It works for 2 or 3 times, then the poor little thing (Teensy) pretends it's not there.
Memory leaks, stray pointers? Who cares. It just doesn't work.

Just yesterday I started to move it all back to static connections with connect/disconnect thing. Still working on it.
So, if you need to create and connect things (effects and connections) only once, you can use "new" for anything.
If you try to delete/new it more than twice - you are on your own.

To be honest, we get spoiled here. We think it it takes C++ syntax, it's as good as Linux. It's not.
Please prove me wrong.

Still, (I stand up and drink to that) Teensy is the best thing on this infected planet.
Can't wait for the 4.1
 
My answer in two words: forget it.

I've spent maybe a week trying to create/delete effects and connections between them dynamically and gave up. It works for 2 or 3 times, then the poor little thing (Teensy) pretends it's not there.
Memory leaks, stray pointers? Who cares. It just doesn't work.

Just yesterday I started to move it all back to static connections with connect/disconnect thing. Still working on it.
So, if you need to create and connect things (effects and connections) only once, you can use "new" for anything.
If you try to delete/new it more than twice - you are on your own.

To be honest, we get spoiled here. We think it it takes C++ syntax, it's as good as Linux. It's not.
Please prove me wrong.

Still, (I stand up and drink to that) Teensy is the best thing on this infected planet.
Can't wait for the 4.1

Hi,

Just to clarify, did you try modifying the core library AudioStream code at all in your investigations? That's where I'm going next before I admit defeat.

Thanks!
 
@sockmonkey
Didn't touch the library and not going to.
I just need to get by to make my guitar and keyboard effects thingy to work and start making it.
Maybe later I'll take a look at the whole audio library and see how it works.

If you find something there we can fix, please share.
 
@sockmonkey
Didn't touch the library and not going to.
I just need to get by to make my guitar and keyboard effects thingy to work and start making it.
Maybe later I'll take a look at the whole audio library and see how it works.

If you find something there we can fix, please share.

Got it, thanks for the clarification. I'll let you know how my experiments work out.
 
Dynamic AudioConnection objects are in the Teensyduino 1.57 beta (https://forum.pjrc.com/threads/70196-Teensyduino-1-57-Beta-1).

If you want dynamic AudioStream objects then you could look at https://forum.pjrc.com/threads/66840-Roadmap-quot-Dynamic-Updates-quot-any-effort-going-on. These are a bit further from getting rolled into Teensyduino, and given Paul already has 99 problems I suspect he isn’t anxious to add another (potential) one right now! But I’d very much welcome users to give it a go and report successes and issues, either on that thread or via GitHub.
 
Dynamic AudioConnection objects are in the Teensyduino 1.57 beta (https://forum.pjrc.com/threads/70196-Teensyduino-1-57-Beta-1).

If you want dynamic AudioStream objects then you could look at https://forum.pjrc.com/threads/66840-Roadmap-quot-Dynamic-Updates-quot-any-effort-going-on. These are a bit further from getting rolled into Teensyduino, and given Paul already has 99 problems I suspect he isn’t anxious to add another (potential) one right now! But I’d very much welcome users to give it a go and report successes and issues, either on that thread or via GitHub.

I didn't realize that this was being worked on officially. I did some work on this here:

https://github.com/jeremybernstein/cores

and

https://github.com/jeremybernstein/Audio

which has been in a hardware project for a while -- we've got hundreds of units in the wild and it seems to be working ok. If this is giving Paul headaches, I suspect that my solution is incomplete. However, for my practical purposes, it's working, so you might want to give it a shot and let me know if you can make it work for your project (or if you can improve it!)
 
Well, it's only "official" in that I've been a bit of a squeaky wheel on the subject, and I put a pull request in on Paul's repository, so it happens to be my code that's been adopted! As yet it doesn't seem to have caused any issues amongst the 1.57 beta users... The fully-dynamic audio objects could be another matter, of course - there's a lot of opportunity for mayhem there.
 
Well, it's only "official" in that I've been a bit of a squeaky wheel on the subject, and I put a pull request in on Paul's repository, so it happens to be my code that's been adopted! As yet it doesn't seem to have caused any issues amongst the 1.57 beta users... The fully-dynamic audio objects could be another matter, of course - there's a lot of opportunity for mayhem there.

I'm thrilled to see this stuff being merged into the official release, regardless of provenance (I tend to trust the code of others more than my own, so your code already has an implicit bonus as far as I'm concerned!).

My project requires dynamic audio objects -- it's a two channel tone generator, where each channel can dynamically switch between ca 40 different algorithms, each of which is essentially a complete Teensy patch. Like I said, I'm sure the solution is incomplete, but pragmatically, what I've done is working for us, and we haven't gotten reports of problems since release (over 6 months ago). It may be that we've just gotten lucky, though, or that our code is running in some fashion where the toxic edge cases don't appear. Anyway, I'll definitely keep an eye on progress in this area. Thanks so much!
 
I'm thrilled to see this stuff being merged into the official release, regardless of provenance (I tend to trust the code of others more than my own, so your code already has an implicit bonus as far as I'm concerned!).

My project requires dynamic audio objects -- it's a two channel tone generator, where each channel can dynamically switch between ca 40 different algorithms, each of which is essentially a complete Teensy patch. Like I said, I'm sure the solution is incomplete, but pragmatically, what I've done is working for us, and we haven't gotten reports of problems since release (over 6 months ago). It may be that we've just gotten lucky, though, or that our code is running in some fashion where the toxic edge cases don't appear. Anyway, I'll definitely keep an eye on progress in this area. Thanks so much!
Well, I'm not sure my code is much more trustworthy than the next person's, but that's what beta releases and GitHub issues are for...

If it's not proprietary, I'd be interested to see your approach to dynamic objects. You can find mine at https://github.com/h4yn0nnym0u5e/Audio/tree/features/dynamic-updates, and my AudioStream modifications in https://github.com/h4yn0nnym0u5e/cores/tree/feature/Audio/dynamic-updates. It should all be backward-compatible with the existing Teensy audio library. The only minor difference I'm aware of is that if you attempt to make multiple connections to an input, only the first succeeds, whereas with the original it's the last one; you shouldn't do it at all, of course, so unless Paul insists I'll leave it as-is. I've tried to keep up to date with the master branches from PJRC, but it'll probably need a bit of a campaign when TD 1.57 is officially released to get properly back in sync again.
 
Wow this is all great to hear and especially to wake up to see, thanks @h4yn0nnym0u5e :D

Guess I have my reading cut out for me!
 
Back
Top