1 /***************************************************/
2 /*! \class DelayL
3     \brief STK linear interpolating delay line class.
4 
5     This Delay subclass implements a fractional-
6     length digital delay-line using first-order
7     linear interpolation.  A fixed maximum length
8     of 4095 and a delay of zero is set using the
9     default constructor.  Alternatively, the
10     delay and maximum length can be set during
11     instantiation with an overloaded constructor.
12 
13     Linear interpolation is an efficient technique
14     for achieving fractional delay lengths, though
15     it does introduce high-frequency signal
16     attenuation to varying degrees depending on the
17     fractional delay setting.  The use of higher
18     order Lagrange interpolators can typically
19     improve (minimize) this attenuation characteristic.
20 
21     by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
22 */
23 /***************************************************/
24 
25 #include "DelayL.h"
26 
27 using namespace Nyq;
28 
DelayL()29 DelayL :: DelayL() : Delay()
30 {
31   doNextOut_ = true;
32 }
33 
DelayL(StkFloat delay,unsigned long maxDelay)34 DelayL :: DelayL(StkFloat delay, unsigned long maxDelay)
35 {
36   if ( delay < 0.0 || maxDelay < 1 ) {
37     errorString_ << "DelayL::DelayL: delay must be >= 0.0, maxDelay must be > 0!";
38     handleError( StkError::FUNCTION_ARGUMENT );
39   }
40 
41   if ( delay > (StkFloat) maxDelay ) {
42     errorString_ << "DelayL::DelayL: maxDelay must be > than delay argument!";
43     handleError( StkError::FUNCTION_ARGUMENT );
44   }
45 
46   // Writing before reading allows delays from 0 to length-1.
47   if ( maxDelay > inputs_.size()-1 ) {
48     inputs_.resize( maxDelay+1 );
49     this->clear();
50   }
51 
52   inPoint_ = 0;
53   this->setDelay(delay);
54   doNextOut_ = true;
55 }
56 
~DelayL()57 DelayL :: ~DelayL()
58 {
59 }
60 
setDelay(StkFloat delay)61 void DelayL :: setDelay(StkFloat delay)
62 {
63   StkFloat outPointer;
64 
65   if ( delay > inputs_.size() - 1 ) { // The value is too big.
66     errorString_ << "DelayL::setDelay: argument (" << delay << ") too big ... setting to maximum!";
67     handleError( StkError::WARNING );
68 
69     // Force delay to maxLength
70     outPointer = inPoint_ + 1.0;
71     delay_ = inputs_.size() - 1;
72   }
73   else if (delay < 0 ) {
74     errorString_ << "DelayL::setDelay: argument (" << delay << ") less than zero ... setting to zero!";
75     handleError( StkError::WARNING );
76 
77     outPointer = inPoint_;
78     delay_ = 0;
79   }
80   else {
81     outPointer = inPoint_ - delay;  // read chases write
82     delay_ = delay;
83   }
84 
85   while (outPointer < 0)
86     outPointer += inputs_.size(); // modulo maximum length
87 
88   outPoint_ = (long) outPointer;   // integer part
89   if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
90   alpha_ = outPointer - outPoint_; // fractional part
91   omAlpha_ = (StkFloat) 1.0 - alpha_;
92 }
93 
getDelay(void) const94 StkFloat DelayL :: getDelay(void) const
95 {
96   return delay_;
97 }
98 
nextOut(void)99 StkFloat DelayL :: nextOut(void)
100 {
101   if ( doNextOut_ ) {
102     // First 1/2 of interpolation
103     nextOutput_ = inputs_[outPoint_] * omAlpha_;
104     // Second 1/2 of interpolation
105     if (outPoint_+1 < inputs_.size())
106       nextOutput_ += inputs_[outPoint_+1] * alpha_;
107     else
108       nextOutput_ += inputs_[0] * alpha_;
109     doNextOut_ = false;
110   }
111 
112   return nextOutput_;
113 }
114 
computeSample(StkFloat input)115 StkFloat DelayL :: computeSample( StkFloat input )
116 {
117   inputs_[inPoint_++] = input;
118 
119   // Increment input pointer modulo length.
120   if (inPoint_ == inputs_.size())
121     inPoint_ = 0;
122 
123   outputs_[0] = nextOut();
124   doNextOut_ = true;
125 
126   // Increment output pointer modulo length.
127   if (++outPoint_ == inputs_.size())
128     outPoint_ = 0;
129 
130   return outputs_[0];
131 }
132 
133