DelayLine class and thanks Leslie Sanford

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

I was trying to create an interpolating delay line that did block processing, but I couldn't get the algorithm to sound just right. Leslie Sanford posted a DelayLine template class that is oh so easy to use and sounds cool, so I adapted the algorithm to this one. Thanks Leslie!

Notes:

-_timeZ is a slew limited version of the _time field to create pitch artifacts when you set _time, any advice on how to control this behavior to make it sound like a tape delay?

- I haven't got processMod() working yet. Anyone want to fill that in?

delayLine.h

Code: Select all

#ifndef DELAY_LINE_H
#define DELAY_LINE_H

class DelayLine
{
public:
   DelayLine(int bufferSize=8192);
   DelayLine(DelayLine const& copy);
   ~DelayLine();
   void process(float* buffer, int numSamples);
   void processMod(float* buffer, int numSamples, float* modBuffer, int numModSamples);
   void setTime(float time);
   void setFeedback(float feedback);
   void setBufferSize(int bufferSize);
   void clearBuffer();
   
private:
   float* _buffer;
   int _bufferSize;
   int _index;
   float _feedback;
   float _time;
   float _timeZ;
};
                 
#endif
DelayLine.cpp

Code: Select all

#include "DelayLine.h"

#include <iostream>

DelayLine::DelayLine(int bufferSize)
:  _bufferSize(bufferSize),
   _index(0.f),
   _time(0.5),
   _timeZ(0.5),
   _feedback(0.85)
{
   _buffer = new float[_bufferSize];
   memset(_buffer, 0.f, _bufferSize);
}

DelayLine::DelayLine(DelayLine const& copy)
{
   *this = copy;  // do a regular copy
   _buffer = new float[_bufferSize];  // obtain our own buffer
   memset(_buffer, 0.f, _bufferSize); // initialize it
}

DelayLine::~DelayLine()
{
   delete[] _buffer;
   _buffer = NULL;
}

void DelayLine::process(float* buffer, int numSamples)
{
   for (int sampleNumber = 0; sampleNumber < numSamples; sampleNumber++)
   {
      float i = _index - (_timeZ * _bufferSize);
      while (i < 0.f) i += _bufferSize;
      
      int x1 = (int)i;
      int x2 = (x1 + 1) % _bufferSize;
      float f = i - x1;
      float y1 = _buffer[x1];
      float y2 = _buffer[x2];
               
      float outputSample = (y2 - y1) * f + y1;
      
      _buffer[_index] = buffer[sampleNumber] + outputSample * _feedback;
      
      buffer[sampleNumber] = outputSample;
      
      _index = (_index + 1) % _bufferSize;
               
      _timeZ = 0.001 * _time + 0.999 * _timeZ;
   }
} 

void DelayLine::processMod(float* buffer, int numSamples, float* modBuffer, int numModSamples)
{
   // TODO
} 

void DelayLine::setTime(float time)
{
   _time = time;
}
void DelayLine::setFeedback(float feedback)
{
   _feedback = feedback;
}

void DelayLine::setBufferSize(int bufferSize)
{
   delete[] _buffer;
   _buffer = new float[bufferSize];
   memset(_buffer, 0.f, _bufferSize);
   _bufferSize = bufferSize;
}

usage (juce code snippets):

Code: Select all


class Plug ....
{
...
private:
   vector<DelayLine> _delays;
...
};

Plug::Plug(...)
{
...
   _delays.push_back(DelayLine());
   _delays.push_back(DelayLine());
...
}

void Plug::processBlock (AudioSampleBuffer& buffer, 
                                            MidiBuffer& midiMessages)
{

   int numSamples = buffer.getNumSamples();

   float* inputL;
   float* inputR;
    
   inputL = buffer.getSampleData(0);
   _delays.at(0).process(inputL, numSamples);
   
   if (buffer.getNumChannels() > 1) {
      inputR = buffer.getSampleData(1);
      _delays.at(1).process(inputR, numSamples);
   }

Post

asomers wrote:I was trying to create an interpolating delay line that did block processing, but I couldn't get the algorithm to sound just right. Leslie Sanford posted a DelayLine template class that is oh so easy to use and sounds cool, so I adapted the algorithm to this one. Thanks Leslie!
You're welcome! Glad my code was helpful. :)
Notes:

-_timeZ is a slew limited version of the _time field to create pitch artifacts when you set _time, any advice on how to control this behavior to make it sound like a tape delay?
I don't think I've ever solved this myself. I just took the same approach as you and slew limited the delay time. I get something that kinda sounds like my old Boss analog delay pedal when changing delay times, but not sure if it's anything like a real tape delay.
- I haven't got processMod() working yet. Anyone want to fill that in?
For modulating the delay time, I do pow(2, *modBuffer) on each sample (I use an optimized verion of pow so that it's not quite as expensive). I take the result of that and multiply the delay time with it. I think I may have used a scaler so that the modulation stays within a sensible range.

Post Reply

Return to “DSP and Plugin Development”