One reason multi-tap delays are interesting is that they can create a rhythmic feel that can synchronize with the tempo of a song. When the feedback larger than zero, the signal that appears at a tap repeats at an interval equal to the total delay line length, and this interval is the same for ALL taps. A multi-tap delay is NOT equivalent to multiple basic delay units in parallel.
The code allows for the total delay time, feedback multiplier, delay times for each of the four taps, the mix level for the four taps, and the level of the non-delayed input signal in the constructor.
See also:
Please do not redistribute this code. In the event that it contains a bug, this will ensure that it can be fixed without the buggy copies floating around indefinitely.
Last Modified: 6/28/98
/*********************************************************
FourTapDelay.h - A 4-tap delay unit
Copyright (c) 1998, Scott Lehman, slehman@harmony-central.com
This code may be used and modified freely provided that credit
is given to the author in any public release. Any derivative
programs must be distributed freely and/or the modified source
code made publicly available. All code is provided AS IS and
without warranty of any kind.
*********************************************************/
#ifndef FOUR_TAP_DELAY_H
#define FOUR_TAP_DELAY_H
#include "Processor.h"
class FourTapDelay : public Processor {
public:
FourTapDelay(float totalTime, float feedback,
float tap1Time, float tap1Mix,
float tap2Time, float tap2Mix,
float tap3Time, float tap3Mix,
float tap4Time, float tap4Mix,
float dryMix);
void Initialize(void);
void Process(void);
void Cleanup(void);
~FourTapDelay(){;}
private:
float totalDelayTime, feedbackGain; // delayTime is in milliseconds
float * outputSignal, * inputSignal;
float tap1DelayTime, tap1Level, tap2DelayTime, tap2Level;
float tap3DelayTime, tap3Level, tap4DelayTime, tap4Level;
float delayLineOutput, dryLevel;
float * delayLineStart, * delayLineEnd, * writePtr;
float * tap1Ptr, * tap2Ptr, * tap3Ptr, * tap4Ptr;
int i;
FourTapDelay(void){};
FourTapDelay(FourTapDelay&){};
};
#endif
|
/*********************************************************
FourTapDelay.cpp - A 4-tap delay unit
Copyright (c) 1998, Scott Lehman, slehman@harmony-central.com
This code may be used and modified freely provided that credit
is given to the author in any public release. Any derivative
programs must be distributed freely and/or the modified source
code made publicly available. All code is provided AS IS and
without warranty of any kind.
*********************************************************/
#include "FourTapDelay.h"
// ************ Delay(float, float, float, float) ***********
// time - total length of delayline, in milliseconds
// feedback - feedback gain, from 0 to 1 (or .9999...)
// tap#Time - the delay time for the specified tap, in milliseconds
// tap#Mix - the level of the tap that is passed to the output
// dryMix - level of input signal passed directly to output, from 0 to 1
FourTapDelay :: FourTapDelay (float time, float feedback,
float tap1Time, float tap1Mix,
float tap2Time, float tap2Mix,
float tap3Time, float tap3Mix,
float tap4Time, float tap4Mix,
float dryMix) {
SetNumInputs(1);
SetNumOutputs(1);
totalDelayTime = time;
feedbackGain = feedback;
tap1DelayTime = tap1Time;
tap1Level = tap1Mix;
tap2DelayTime = tap2Time;
tap2Level = tap2Mix;
tap3DelayTime = tap3Time;
tap3Level = tap3Mix;
tap4DelayTime = tap4Time;
tap4Level = tap4Mix;
dryLevel = dryMix;
return;
}
// ****************** Initialize(void) *******************
void FourTapDelay :: Initialize(void)
{
//Double check that input/output buffers are there
if (inputs[0] == NULL)
ModuleError("Buffer in Delay input not assigned");
if (outputs[0] == NULL)
ModuleError("Buffer in Delay output not assigned");
//compute required buffer size for desired delay and allocate for it
int bufferLength = (int)(totalDelayTime*samplingRate/1000);
if(bufferLength <= 0)
ModuleError("Delay buffer length is non-positive");
delayLineStart = new float[bufferLength];
if (delayLineStart == NULL)
ModuleError("Couldn't allocate buffer in Delay");
//set up pointers for delay line
delayLineEnd = delayLineStart + bufferLength;
writePtr = delayLineStart;
//zero out the buffer (silence)
do {
*writePtr = (float)0.0;
}
while (++writePtr < delayLineEnd);
//reset read pointer to start of delayline
writePtr = delayLineStart;
//set pointers for each of the taps
tap1Ptr = delayLineStart + bufferLength - (int)(tap1DelayTime*samplingRate/1000);
tap2Ptr = delayLineStart + bufferLength - (int)(tap2DelayTime*samplingRate/1000);
tap3Ptr = delayLineStart + bufferLength - (int)(tap3DelayTime*samplingRate/1000);
tap4Ptr = delayLineStart + bufferLength - (int)(tap4DelayTime*samplingRate/1000);
//only one in and out. Assign to new pointers for simplicity
outputSignal = outputs[0];
inputSignal = inputs[0];
return;
}
// ******************** Process(void) ******************
void FourTapDelay:: Process()
{
for (i=0; i<frameLength; i++) { //for each sample...
//get delayed sample - doesn't go to output, but may be written back
delayLineOutput = *writePtr;
//weight the delayed sample and the current input to create the output
outputSignal[i] = dryLevel * inputSignal[i] +
tap1Level * (*tap1Ptr) +
tap2Level * (*tap2Ptr) +
tap3Level * (*tap3Ptr) +
tap4Level * (*tap4Ptr);
//write the input sample and any feedback to delayline
*writePtr = inputSignal[i] +
feedbackGain * delayLineOutput;
//increment buffer index and wrap if necesary
if (++writePtr >= delayLineEnd)
writePtr = delayLineStart;
if (++tap1Ptr >= delayLineEnd)
tap1Ptr = delayLineStart;
if (++tap2Ptr >= delayLineEnd)
tap2Ptr = delayLineStart;
if (++tap3Ptr >= delayLineEnd)
tap3Ptr = delayLineStart;
if (++tap4Ptr >= delayLineEnd)
tap4Ptr = delayLineStart;
}
return;
}
// ********************** Cleanup(void) *******************
void FourTapDelay :: Cleanup(void)
{
//Free memory allocated during initialization
delete [] delayLineStart;
}
|