My Delay class causes crashes

Hi!
I’m trying to implement a simple delay class. It seems to work, but when I pause the audio in my DAW it crashes - so I’m definitely doing something wrong!

Here’s the class:
delay.h

class Delay
{
public:
	void processSamples(float* inbuffer, int numSamples);
private:
	static const int bufferLength = 44100 * 2; // Buffer length in samples
	float buffer[bufferLength] = { 0 }; // Buffer of previous samples
	int bufferPointer = 0;  // Current position in buffer
	float delaySamp = 44100;  // Delay in samples
};

delay.cpp

#include "Delay.h"

// Processes the samples starting at pointer location inbuffer
void Delay::processSamples(float* inbuffer, int numSamples) {

	for (int i = 0; i < numSamples; i++) {
		buffer[bufferPointer] = inbuffer[i];
	
    	float frac = delaySamp - (int)delaySamp;
	inbuffer[i] = inbuffer[i] + (1-frac)*buffer[((bufferPointer - (int)delaySamp) + bufferLength) % bufferLength] + frac*buffer[((bufferPointer - (int)delaySamp - 1) + bufferLength) % bufferLength];

    bufferPointer++;
	if (bufferPointer >= bufferLength)
		bufferPointer = 0;
	}
}

And lastly how I do the processing in processBlock:

 for (int channel = 0; channel < totalNumInputChannels; ++channel)
    {
        auto* channelData = buffer.getWritePointer (channel);
        delaylr[channel].processSamples(channelData, buffer.getNumSamples());
    }

I’m not too sure what could be causing the crashing (especially as it seems to function for a while…).

(delaylr is an array of two Delay objects, one for the left and right channels. They’re made in the header for the plugin).

I’d love to hear any general comments too, on whether this is the best way to approach this.

Thanks for any help!

I am probably not the best qualified person to answer (still quite green myself), but have you tried debugging your plugin? i.e. compile a debug version of your application and attach it to your DAW.

Here’s how to do that in Xcode for instance:

In Xcode, click Product > Scheme > Edit Scheme…, then under Run select Other… from the Executable dropdown and locate the host app binary (e.g. Reaper.app). Make sure Debug executable is ticked.

Now when you build and run your plugin within Xcode it will automatically launch the host, and when your plug-in is loaded inside the host it will feed debugging information back to Xcode. In the debugger you should be able to see exactly what your app was doing when it crashed.

I muddled my way through my first plugin using alerts to “debug”, but using an actual debugger is light years more efficient, and I am sure that I am only scratching the surface of what’s possible.

That’s a really good idea. I’m not at all familiar with debugging like this, and it’s definitely a necessary skill. I’m using visual studio, but I’m sure the basic idea is the same so I’ll look into it!

On a slightly more general note; I’ve noticed the actual dsp classes (like the FIR one) are vastly more complicated than what I’m doing here (jasserts, using different buffer classes, blocking and stuff), and I’m wondering whether I should be trying to do these things also, or if that stuff isn’t desperately important?

There are always two ways to use a debugger, either attaching to a running process or start an executable. Both ways work. Attaching is easier, but it might already have crashed, before you got the chance to attach.

jasserts are very useful, they are a planned stop for the debugger. If you have a value, that you assume to have a certain value, you can put it in an jassert, and the debugger will halt here, if the value is not the expected (or in the expected range), so you can check, how your program ended up with that unwanted value.
The benefit is, that in a release build the jasserts are removed, so there is no performance loss.

In your case you could do:

auto readPos1 = ((bufferPointer - (int)delaySamp - 1) + bufferLength) % bufferLength;
auto readPos2 = ((bufferPointer - (int)delaySamp) + bufferLength) % bufferLength;
jassert (isPositiveAndBelow (readPos1, bufferLength));
jassert (isPositiveAndBelow (readPos2, bufferLength));
inbuffer[i] = inbuffer[i] + (1-frac)*buffer[readPos2] + frac*buffer[readPos1];

to make sure, that you don’t read outside the buffer…

Thanks for both your help! I got debugging up and running, and solved the issue.