Multi-channel playback error

Hi all,

I seem to have a problem with some multi-channel audio playback and I can’t seem to figure out why this goes wrong.

My scenario is as follows:

  1. I scan a directory for .wav files and load the directory path into a vector list
  2. I randomly pick paths from the vector list and load them in one of the eight channels
  3. When the sample is done, I randomly select another path to play in the channel that has finished

All runs pretty well, but the app crashes occasionally and I don’t have any idea why exactly. It seems to crash when I load a new sample.

The playback code: http://yoeran.nl/clipboard/audioOut.cpp
Sample selection: http://yoeran.nl/clipboard/samplePlayback.cpp
Sample class: http://yoeran.nl/clipboard/Sample.cpp
Error log: http://yoeran.nl/clipboard/Error%20log%201.log

Can anyone point me in a direction on how to fix the crashing? I can’t make sense of the error log.
Thanks in advance!

It’s difficult to tell without seeing a bit more of your code (like the .h files) but I’m guessing it’s because in Sample::play(), you’re dereferencing your myData pointer without checking if it’s NULL first. That’d be this line :

  
  
short* buffer = (short *)myData  
  

So (again, guessing) it seems that the crash happens because:

  1. Your sample finishes
  2. You delete the sample’s data
  3. You load new sample data

And, in between steps 2 and 3, Sample::play() happens and tries to access data that doesn’t exist yet. There’s a couple ways around this. The simplest fix seems like it would be to use your isPlaying bool to indicate if myData is ready. So, change :

  
  
void Sample::load(string tmpPath) {  
    myPath = tmpPath;  
    isPlaying = true;  
	read();  
}  
  

to

  
  
void Sample::load(string tmpPath) {  
    myPath = tmpPath;  
    isPlaying = false;  
	read();  
    isPlaying = true;  
}  
  

Or, check if myData is != NULL before doing anything in play(). You’ll probably also want to write 0’s in play() if myData isn’t ready, but that’s up to you.

Thanks a lot admsyn! That makes complete sense!
I’m not able to test it at the moment, but I will post an update once I did.

No problem! Just FYI here’s a couple things you’ll probably need to know when doing the sort of thing you’re doing.

About the error log, these are the important bits:

Exception Type: EXC_BAD_ACCESS (SIGSEGV)

Basically, this means your program tried to access memory that wasn’t valid (it can mean other things too, but it’s almost always a case of reading from pointers that point to bad data).

Crashed Thread: 2

This tells you that your program crashed on thread 2 (ok that one was obvious). But, that tells you to take a look at thread 2’s stack trace, which looks like:

Thread 2 Crashed:
0 com.yourcompany.openFrameworks 0x00005979 Sample::play(double) + 121
1 com.yourcompany.openFrameworks 0x00004da6 testApp::audioOut(float*, int, int) + 342
2 com.yourcompany.openFrameworks 0x00004f69 non-virtual thunk to testApp::audioOut(float*, int, int) + 41
3 com.yourcompany.openFrameworks 0x001853b4 ofRtAudioSoundStream::rtAudioCallback(void*, void*, unsigned int, double, unsigned int, void*) + 292

The top of the trace shows you that the program crashed in Sample::play(double), which should give you enough info to start figuring out your problem.

The other thing is that (if the problem is actually the issue I mentioned) you should look into what a mutex is and why you’d want to use one. OpenFrameworks comes with one called ofMutex that’s quite easy to use. The reason in this case is that you’re sharing data between two threads: the “main” thread which is doing your sample loading, and another thread which is controlling audio playback.