Creating Larger Buffers and Playing Back From Them


#1

I need to create a buffer that is larger than the block buffer, fill it up from the smaller block buffers, do some processing, then send it out to be played.  Here is a crude diagram: 

 

This should be simple, however, everything I try crashes in AudioMulch.

LargerBuffer and PlaybackBuffer were created as private members of PluginProcessor.h:

 

Their size is set in prepareToPlay:

 

In processBlock, LargerBuffer is filled up with the smaller block buffers in until it is full, then the RMS is taken, and the LargerBuffer is copied to PlaybackBuffer. The crashing happens here with the PlaybackBuffer.copyFrom calls, as well as the buffer.copyFrom calls:

 

The crashing stops if copyFrom is replaced with the following highlighted line, however, this doesn't seem right.  

 

PlaybackBuffer must then be divided into block-sized portions for playback, and nothing prevents the crashing with those copyFrom calls:

 

In case it might be helpful, here is some of the crash info:

 

I've tried more things than I care to admit, can anyone shed some light on this?

 


#2

Hi Connor,

 

There are a couple of problems here. For a start, the first thing you're doing inside processBlock is you’re overwriting the input buffer with some of the contents of PlaybackBuffer. I imagine you probably want to do that right at the end of processBlock!

The code is failing because once sampleCounter reaches just below 44100 then you’ll be trying to copy data from beyond the end of the PlaybackBuffer. For example, if the blocksize is 256, then after 172 iterations the sample counter will be at 44032. At the next iteration you’ll be trying to read 256 samples from PlaybackBuffer, but starting at 44032. As the buffer is only 44100 samples long, you’ll be trying to read 188 samples past the end of the buffer.

You could fix this by making your buffers larger, e.g. 44100 + samplesPerBlock (though samplesPerBlock isn’t guaranteed forever, so you should add even more margin).

Now, with regards to replacing the copyFrom: when you use the copy constructor you’re actually creating a new variable on the stack which hides the member variable of the same name. Then that version of PlaybackBuffer goes out of scope at the end of the else statement. I’m not sure how that stops things from crashing – unless you’re changing something else in your code when you’re testing that.

There might be a few other things to figure out with regards to what happens when the buffer wraps around, but one step at a time J

 

Regards,
Andrew


#3

The most important thing to learn is not what you're doing with buffers or samples, but that when you have a "crash", it's not just a mysterious dead end - you can debug it and see what's going on. Unless you learn to do that, you're going to find C++ development very painful!

Also, this crash was probably preceded by a whole bunch of assertions that I put there to catch people doing silly things with AudioSampleBuffers - if you were running in a debugger, you'd have seen them and been given useful messages that would have saved you a lot of head-scratching.

TL;DR Learn your development tools!


#4

Yeah, if you treat it as a black box then it can all be very mysterious. If you can look inside the box and see what breaks, then it gets easier.

If you find it hard to debug this as a plugin then you can always create an audio application from the Introjucer. This would be OK for debugging your current issues, but not for figuring out how parameters work for instance. Note that in an audio app, prepareToPlay() is the same, but you'll need to put your processBlock() code inside getNextAudioBlock().

Having said that, it's far better to get the hang of debugging your plugin in a host. I use the JUCE plugin host as my first port of call for this.