Difficulty with multiple instances of ofxAudioUnitFileplayer

Hello forum,

I am working on a project currently involving 13 ofxAudioUnitFileplayer objects all playing simultaneously in sync. While they are all playing, only about 4 - 8 of them have their volume turned up above 0.0 at the same time. My problem is that when I run the program, some of the files are not playing. Stranger still, each time I run the program, different files are not playing. Sometimes, if I’m lucky, there are all playing. So, I found that between 0 and 4 tracks are not playing. I nterestingly, if I only use 7 ofxAudioUnitFilePlayer objects, I no longer have a problem.

Here’s how I’m setting up my signal chain:

First I have a object which handles groups of 3 tracks

  
trackStrip::trackStrip(string file1, string file2, string file3){  
    track1.setFile(ofToDataPath(file1));  
    track2.setFile(ofToDataPath(file2));  
    track3.setFile(ofToDataPath(file3));  
      
    mixer.setInputBusCount(3);  
    track1.connectTo(mixer, 0);  
    track2.connectTo(mixer, 1);  
    track3.connectTo(mixer, 2);  
      
    mixer >> tap;  
}  
  
void trackStrip::start() {  
    track1.loop();  
    track2.loop();  
    track3.loop();  
}  
  

then in my testApp.cpp

  
bg_track.setFile(ofToDataPath("audio/bg_track.wav"));  
  
    trackStrip *kick = new trackStrip("audio/kick_1.wav", "audio/kick_2.wav", "audio/kick_3.wav");  
    trackStrips.push_back(kick);  
      
    trackStrip *snare = new trackStrip("audio/snare_1.wav", "audio/snare_2.wav", "audio/snare_3.wav");  
    trackStrips.push_back(snare);  
      
    trackStrip *hats = new trackStrip("audio/hats_1.wav", "audio/hats_2.wav", "audio/hats_3.wav");  
    trackStrips.push_back(hats);  
      
    trackStrip *perc = new trackStrip("audio/perc_1.wav", "audio/perc_2.wav", "audio/perc_3.wav");  
    trackStrips.push_back(perc);  
  
    mainMixer.setInputBusCount(4);  
      
    bg_track.connectTo(mainMixer, 0);  
    trackStrips[0]->tap.connectTo(mainMixer, 1);  
    trackStrips[1]->tap.connectTo(mainMixer, 2);  
    trackStrips[2]->tap.connectTo(mainMixer, 3);  
    trackStrips[3]->tap.connectTo(mainMixer, 4);  
      
    mainMixer.setInputVolume(0.5, 0);  
    mainMixer >> output;  
    output.start();  
  
    bg_track.loop();  
            for (int i = 0; i < trackStrips.size(); i++) {  
                trackStrips[i]->start();  
            }  
  
  

I never receive an error from the setFile function and after this part of setFile()

  
AudioFileGetProperty(_fileID[0],  
	                     kAudioFilePropertyAudioDataPacketCount,  
	                     &dataSize,  
	                     &numPackets);  

is called, all tracks have an equal and appropriate amount of packets.

Finally I tried to set a breakpoint in the render function in the base class ofxAudioUnit to see if some of the ofxAudioUnitFilePlayer’s were not streaming audio data. However, whenever I hit the breakpoint, it would have been called by a ofxAudioUnitTap object. So I used a dynamic cast with an if statement to so that I could break only if the render function was being called by an instance of an ofxAudioUnitFilePlayer object like this:

  
OSStatus debug = AudioUnitRender(*_unit, ioActionFlags, inTimeStamp,  
						   inOutputBusNumber, inNumberFrames, ioData);  
      
    ofxAudioUnitFilePlayer* filePlayer = dynamic_cast<ofxAudioUnitFilePlayer*>(this);  
    if (filePlayer) {  
        cout << "is fileplayer"; //breakpoint here  
    }  
      
    return debug;  

and the breakpoint was never triggered. So now I’m realizing how little a really understand about audio units!

Has anyone run into problems like this when using multiple ofxAudioUnitFilePlayer objects? Could there be a built in limit to the number of them that can run simultaneously?

Any audio insight is greatly appreciated,
Jason

i have use the ofxAudioUnit addon and saw similar problems.
i remember setting them to .loop() and .play() at the end of setup

not sure if that really helps.

Are you suggesting that I called both loop() and play() for each track? Currently I am only calling loop().

According to the implementation, loop() is calling play()

  
// ----------------------------------------------------------  
void ofxAudioUnitFilePlayer::loop(unsigned int timesToLoop, uint64_t startTime)  
// ----------------------------------------------------------  
{  
	_region.mLoopCount = timesToLoop;  
	play(startTime);  
}  

thanks,
Jason

yes setting play seemed to solve it for me.

did you ever try to have more then 2 output channels on the mixer?

mixer.connectTo(output);

currently i only get one stereo output and can use mixer.setPan() -1 to 1 to direct sounds.

s

Hi Stephan,

Can you show a me a code sample of how you used loop() and play() in conjunction?

As for multiple output channels from a ofxAudioUnitMixer, I think the answer lies in the comments of “example-3-busses” that comes with ofxAudioUnit

  
//	A "bus" is basically a pathway for an audio stream to flow  
//	through. This is NOT the same as a channel. For example,  
//	you can have audio with 2 channels (ie. stereo) flowing  
//	through 1 bus. You could also have 5.1 channel audio flowing  
//	through a single bus.  
	  
//	Your output unit expects a single stereo bus of audio to send to  
//	the speakers. If you want to have more than a single instrument  
//	creating sound, you'll need to mix several busses down into  
//	one. This is what the ofxAudioUnitMixer is for.  
	  
//	The ofxAudioUnitMixer has a variable amount of input busses  
//	and one output bus. You can set the relative volume of each  
//	bus in order to get a good mix between your sound sources.  

i based my app on the busses example.
so what i did is simply call
source1.play();
source1.loop();

Wow, that makes no sense but it actually works! Also that’s not how it’s coded in the busses example, unless you have a different version than me. Here’s what I have in “example-3-busses”:

  
  
//	Start each of the loops at the same time so that they're in sync  
	  
	source1.loop();  
	source2.loop();  
	source3.loop();  
  

The other strange thing is that for less than 7 tracks, just calling loop() works fine. What could be different about more than 7 tracks? Why would you need to call play() and then loop() which itself calls play()?

I’d love to hear a comment from admsyn…

i am currently running 7 stereo usb device each playing 60 sounds. and i do see the same thing even when calling loop and play together.

i tried setting all sounds to play when pressing a key, but that did restart all and miss some.
i tried selectively starting those sounds one by one that had a flat wave form. this did start those sounds.

we should look for a way to check if a file is playing. if not have the app run the play function again. but i am not sure how to get core audio to give us this info.

a work around is to check the height or area of the wave polyline and if it is == 0 then apply play().

cout<<"wave area "<<waves.getBoundingBox().height <<endl;