1 /***************************************************/
2 /*! \class DelayA
3     \brief STK allpass interpolating delay line class.
4 
5     This Delay subclass implements a fractional-length digital
6     delay-line using a first-order allpass filter.  A fixed maximum
7     length of 4095 and a delay of 0.5 is set using the default
8     constructor.  Alternatively, the delay and maximum length can be
9     set during instantiation with an overloaded constructor.
10 
11     An allpass filter has unity magnitude gain but variable phase
12     delay properties, making it useful in achieving fractional delays
13     without affecting a signal's frequency magnitude response.  In
14     order to achieve a maximally flat phase delay response, the
15     minimum delay possible in this implementation is limited to a
16     value of 0.5.
17 
18     by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
19 */
20 /***************************************************/
21 
22 #include "DelayA.h"
23 
24 using namespace Nyq;
25 
DelayA()26 DelayA :: DelayA() : Delay()
27 {
28   this->setDelay( 0.5 );
29   apInput_ = 0.0;
30   doNextOut_ = true;
31 }
32 
DelayA(StkFloat delay,unsigned long maxDelay)33 DelayA :: DelayA(StkFloat delay, unsigned long maxDelay)
34 {
35   if ( delay < 0.0 || maxDelay < 1 ) {
36     errorString_ << "DelayA::DelayA: delay must be >= 0.0, maxDelay must be > 0!";
37     handleError( StkError::FUNCTION_ARGUMENT );
38   }
39 
40   if ( delay > (StkFloat) maxDelay ) {
41     errorString_ << "DelayA::DelayA: maxDelay must be > than delay argument!";
42     handleError( StkError::FUNCTION_ARGUMENT );
43   }
44 
45   // Writing before reading allows delays from 0 to length-1.
46   if ( maxDelay > inputs_.size()-1 ) {
47     inputs_.resize( maxDelay+1 );
48     this->clear();
49   }
50 
51   inPoint_ = 0;
52   this->setDelay(delay);
53   apInput_ = 0.0;
54   doNextOut_ = true;
55 }
56 
~DelayA()57 DelayA :: ~DelayA()
58 {
59 }
60 
clear()61 void DelayA :: clear()
62 {
63   Delay::clear();
64   apInput_ = 0.0;
65 }
66 
setDelay(StkFloat delay)67 void DelayA :: setDelay(StkFloat delay)
68 {
69   StkFloat outPointer;
70   unsigned long length = inputs_.size();
71 
72   if ( delay > inputs_.size() - 1 ) { // The value is too big.
73     errorString_ << "DelayA::setDelay: argument (" << delay << ") too big ... setting to maximum!";
74     handleError( StkError::WARNING );
75 
76     // Force delay to maxLength
77     outPointer = inPoint_ + 1.0;
78     delay_ = length - 1;
79   }
80   else if (delay < 0.5) {
81     errorString_ << "DelayA::setDelay: argument (" << delay << ") less than 0.5 not possible!";
82     handleError( StkError::WARNING );
83 
84     outPointer = inPoint_ + 0.4999999999;
85     delay_ = 0.5;
86   }
87   else {
88     outPointer = inPoint_ - delay + 1.0;     // outPoint chases inpoint
89     delay_ = delay;
90   }
91 
92   if (outPointer < 0)
93     outPointer += length;  // modulo maximum length
94 
95   outPoint_ = (long) outPointer;         // integer part
96   if ( outPoint_ == length ) outPoint_ = 0;
97   alpha_ = 1.0 + outPoint_ - outPointer; // fractional part
98 
99   if (alpha_ < 0.5) {
100     // The optimal range for alpha is about 0.5 - 1.5 in order to
101     // achieve the flattest phase delay response.
102     outPoint_ += 1;
103     if (outPoint_ >= length) outPoint_ -= length;
104     alpha_ += (StkFloat) 1.0;
105   }
106 
107   coeff_ = ((StkFloat) 1.0 - alpha_) /
108     ((StkFloat) 1.0 + alpha_);         // coefficient for all pass
109 }
110 
getDelay(void) const111 StkFloat DelayA :: getDelay(void) const
112 {
113   return delay_;
114 }
115 
nextOut(void)116 StkFloat DelayA :: nextOut(void)
117 {
118   if ( doNextOut_ ) {
119     // Do allpass interpolation delay.
120     nextOutput_ = -coeff_ * outputs_[0];
121     nextOutput_ += apInput_ + (coeff_ * inputs_[outPoint_]);
122     doNextOut_ = false;
123   }
124 
125   return nextOutput_;
126 }
127 
computeSample(StkFloat input)128 StkFloat DelayA :: computeSample( StkFloat input )
129 {
130   inputs_[inPoint_++] = input;
131 
132   // Increment input pointer modulo length.
133   if (inPoint_ == inputs_.size())
134     inPoint_ = 0;
135 
136   outputs_[0] = nextOut();
137   doNextOut_ = true;
138 
139   // Save the allpass input and increment modulo length.
140   apInput_ = inputs_[outPoint_++];
141   if (outPoint_ == inputs_.size())
142     outPoint_ = 0;
143 
144   return outputs_[0];
145 }
146