Delay code randomly crashing on Ableton startup


#1

I have a simple delay AU plugin I am trying to run in Ableton Live 9.7.2 on OSX 10.12.5.

I have tested the AU in the Plugin Host and it opens up fine. However, when I test loading it into Ableton, about 1/2 the time it will cause the program to crash. I ran my Ableton w/plugin in the debugger and this is the line it always crashes at:

const int numInputChannels = getNumInputChannels();
const int numOutputChannels = getNumOutputChannels();   
const int numSamples = buffer.getNumSamples();
const float delayFeedback = *feedBack;
int dpr, dpw;

delayReadPosition_ = (int)(delayWritePosition_ - (*delayLength * getSampleRate()) + delayBufferLen_) % delayBufferLen_;

float dryMix = (1.0-*dryWetPercent);
float wetMix = *dryWetPercent;

for (int channel = 0; channel < getTotalNumOutputChannels(); ++channel)
{
    
    dpr = delayReadPosition_;
    dpw = delayWritePosition_;
    
    float* const channelData = buffer.getWritePointer (channel);
    float* delayData = delayBuffer_.getWritePointer (jmin (channel, delayBuffer_.getNumChannels() - 1));


    for (int i = 0; i < numSamples; ++i)
    {
        const float in = channelData[i];
        float out = 0.0;
        out = (dryMix * in + wetMix * delayData[dpr]);
        // THIS IS THE PROBLEM LINE
        delayData[dpw] = in + (delayData[dpr] * delayFeedback);
        if (++dpr >= delayBufferLen_)
            dpr = 0;
        if (++dpw >= delayBufferLen_)
            dpw = 0;
        channelData[i] = out;
    }
}
delayReadPosition_ = dpr;
delayWritePosition_ = dpw;
for (int i = numInputChannels; i < numOutputChannels; ++i)
{
    buffer.clear (i, 0, buffer.getNumSamples());
}

this is all in my processBlock function.

        //delayData[dpw] = in + (delayData[dpr] * delayFeedback);

as soon I comment out this line, the plugin loads just fine.

Screenshot:

The ableton report is saying it’s a SEGFAULT of some kind.

Any idea why this would be happening? Let me know if more info needed.


#2

Your code is attempting to access memory that is, for some reason, not accessible to your code at that point. Can’t really tell exactly what as I don’t see all of your class.

I may be missing something, but delayFeedback - how is it getting the value of *feedback?


#3
OutputCollinDelayAudioProcessor::OutputCollinDelayAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
{
    addParameter (delayLength = new AudioParameterFloat ("length", "Time (ms)", 0.1, 1.0, 0.1));
    addParameter (feedBack = new AudioParameterFloat ("feedback", "Feedback", 0.0f, 1.0f, 0.5f));
    addParameter (dryWetPercent = new AudioParameterFloat ("wetDry", "Wet/Dry", 0.0f, 1.0f, 0.5f));
}

Feedback is an AudioParameterFloat that is a member of my AudioProcessor class.

It is accessed by the PluginEditor class.

#include "PluginProcessor.h"
#include "PluginEditor.h"

OutputCollinDelayAudioProcessorEditor::OutputCollinDelayAudioProcessorEditor (OutputCollinDelayAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
    
    processor.addMeterListener (*this);

    const OwnedArray<AudioProcessorParameter>& params = p.getParameters();
    
    for (int i = 0; i < params.size(); ++i)
    {
        if (const AudioParameterFloat* param = dynamic_cast<AudioParameterFloat*> (params[i]))
        {
            Slider* aSlider;
            
            paramSliders.add (aSlider = new Slider (param->name));
            aSlider->setRange (param->range.start, param->range.end);
            aSlider->setSliderStyle (Slider::LinearHorizontal);
            aSlider->setValue (*param);
            
            aSlider->addListener (this);
            addAndMakeVisible (aSlider);
            
            Label* aLabel;
            paramLabels.add (aLabel = new Label (param->name, param->name));
            addAndMakeVisible (aLabel);
        }
    }
    

    
    noParameterLabel.setJustificationType (Justification::horizontallyCentred | Justification::verticallyCentred);
    noParameterLabel.setFont (noParameterLabel.getFont().withStyle (Font::italic));
    
    setSize (kParamSliderWidth + kParamLabelWidth, jmax (1, kParamControlHeight * (paramSliders.size()+1)));
    
    if (paramSliders.size() == 0) {
        addAndMakeVisible (noParameterLabel);
    } else {
        startTimer (100);
    }
    
    for (auto& meter : meters)
        addAndMakeVisible (meter);
}

OutputCollinDelayAudioProcessorEditor::~OutputCollinDelayAudioProcessorEditor()
{
}

//==============================================================================

void OutputCollinDelayAudioProcessorEditor::paint (Graphics& g)
{
    g.fillRect (getLocalBounds());
}

void OutputCollinDelayAudioProcessorEditor::resized()
{
    Rectangle<int> r = getLocalBounds();
    noParameterLabel.setBounds (r);
    for (auto& meter : meters)
    {
        r.removeFromLeft (10);
        meter.setBounds (r.removeFromLeft (20));
    }
    
    for (int i = 0; i < paramSliders.size(); ++i)
    {
        Rectangle<int> paramBounds = r.removeFromTop (kParamControlHeight);
        Rectangle<int> labelBounds = paramBounds.removeFromLeft (kParamLabelWidth);
        
        paramLabels[i]->setBounds (labelBounds);
        paramSliders[i]->setBounds (paramBounds);
    }
}

void OutputCollinDelayAudioProcessorEditor::handleNewMeterValue (int channel, float value)
{
    meters[(size_t) channel].update (value);
}

//==============================================================================

void OutputCollinDelayAudioProcessorEditor::sliderValueChanged (Slider* slider)
{
    if (AudioParameterFloat* param = getParameterForSlider (slider))
        *param = (float) slider->getValue();
}

void OutputCollinDelayAudioProcessorEditor::sliderDragStarted (Slider* slider)
{
    if (AudioParameterFloat* param = getParameterForSlider (slider))
        param->beginChangeGesture();
}

void OutputCollinDelayAudioProcessorEditor::sliderDragEnded (Slider* slider)
{
    if (AudioParameterFloat* param = getParameterForSlider (slider))
        param->endChangeGesture();
}

void OutputCollinDelayAudioProcessorEditor::timerCallback()
{
    const OwnedArray<AudioProcessorParameter>& params = getAudioProcessor()->getParameters();
    
    for (int i = 0; i < params.size(); ++i)
    {
        if (const AudioParameterFloat* param = dynamic_cast<AudioParameterFloat*> (params[i]))
        {
            if (i < paramSliders.size())
                paramSliders[i]->setValue (*param);
        }
    }
    //outputAmp->setValue(processor.volumeParam->getActualValue(), dontSendNotification);
}

AudioParameterFloat* OutputCollinDelayAudioProcessorEditor::getParameterForSlider (Slider* slider)
{
    const OwnedArray<AudioProcessorParameter>& params = getAudioProcessor()->getParameters();
    return dynamic_cast<AudioParameterFloat*> (params[paramSliders.indexOf (slider)]);
}

#4

In the picture above, in my debugger it says feedbackDelay has a value of 0.5, so it looks like that’s fine


#5

I believe I have a solution. In my prepareToPlay function I wasn’t initializing my delayWritePosition_, so I changed it to init to 0 and I haven’t been seeing the problem since. Why that would happen randomly when I load in the Plugin from Ableton, I don’t know.


#6

Because sometimes you’re lucky and that memory location was already zero. This is actually quite likely since zeros are used all over the place in code. These bugs are sometimes hard to track for this reason.


#7

Have a look at your screen shot again dpw was 669839664 so you were trying to access this index of delayData. dpw is setting using delayWritePosition_ which as you’ve now recognised was uninitialised, always initialise built in types like this or you’re asking for trouble. I would suggest always doing this in a constructor as a habit.