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()26DelayA :: DelayA() : Delay() 27 { 28 this->setDelay( 0.5 ); 29 apInput_ = 0.0; 30 doNextOut_ = true; 31 } 32 DelayA(StkFloat delay,unsigned long maxDelay)33DelayA :: 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()57DelayA :: ~DelayA() 58 { 59 } 60 clear()61void DelayA :: clear() 62 { 63 Delay::clear(); 64 apInput_ = 0.0; 65 } 66 setDelay(StkFloat delay)67void 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) const111StkFloat DelayA :: getDelay(void) const 112 { 113 return delay_; 114 } 115 nextOut(void)116StkFloat 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)128StkFloat 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