1 /***************************************************/
2 /*! \class DelayA
3     \brief STK allpass interpolating delay line class.
4 
5     This class implements a fractional-length digital delay-line using
6     a first-order allpass filter.  If the delay and maximum length are
7     not specified during instantiation, a fixed maximum length of 4095
8     and a delay of zero is set.
9 
10     An allpass filter has unity magnitude gain but variable phase
11     delay properties, making it useful in achieving fractional delays
12     without affecting a signal's frequency magnitude response.  In
13     order to achieve a maximally flat phase delay response, the
14     minimum delay possible in this implementation is limited to a
15     value of 0.5.
16 
17     by Perry R. Cook and Gary P. Scavone, 1995--2021.
18 */
19 /***************************************************/
20 
21 #include "DelayA.h"
22 
23 namespace stk {
24 
DelayA(StkFloat delay,unsigned long maxDelay)25 DelayA :: DelayA( StkFloat delay, unsigned long maxDelay )
26 {
27   if ( delay < 0.5 ) {
28     oStream_ << "DelayA::DelayA: delay must be >= 0.5!";
29     handleError( StkError::FUNCTION_ARGUMENT );
30   }
31 
32   if ( delay > (StkFloat) maxDelay ) {
33     oStream_ << "DelayA::DelayA: maxDelay must be > than delay argument!";
34     handleError( StkError::FUNCTION_ARGUMENT );
35   }
36 
37   // Writing before reading allows delays from 0 to length-1.
38   if ( maxDelay + 1 > inputs_.size() )
39     inputs_.resize( maxDelay + 1, 1, 0.0 );
40 
41   inPoint_ = 0;
42   this->setDelay( delay );
43   apInput_ = 0.0;
44   doNextOut_ = true;
45 }
46 
~DelayA()47 DelayA :: ~DelayA()
48 {
49 }
50 
clear()51 void DelayA :: clear()
52 {
53   for ( unsigned int i=0; i<inputs_.size(); i++ )
54     inputs_[i] = 0.0;
55   lastFrame_[0] = 0.0;
56   apInput_ = 0.0;
57 }
58 
setMaximumDelay(unsigned long delay)59 void DelayA :: setMaximumDelay( unsigned long delay )
60 {
61   if ( delay < inputs_.size() ) return;
62   inputs_.resize(delay + 1, 1, 0.0);
63 }
64 
setDelay(StkFloat delay)65 void DelayA :: setDelay( StkFloat delay )
66 {
67   unsigned long length = inputs_.size();
68   if ( delay + 1 > length ) { // The value is too big.
69     oStream_ << "DelayA::setDelay: argument (" << delay << ") greater than maximum!";
70     handleError( StkError::WARNING ); return;
71   }
72 
73   if ( delay < 0.5 ) {
74     oStream_ << "DelayA::setDelay: argument (" << delay << ") less than 0.5 not possible!";
75     handleError( StkError::WARNING );
76   }
77 
78   StkFloat outPointer = inPoint_ - delay + 1.0;     // outPoint chases inpoint
79   delay_ = delay;
80 
81   while ( outPointer < 0 )
82     outPointer += length;  // modulo maximum length
83 
84   outPoint_ = (long) outPointer;         // integer part
85   if ( outPoint_ == length ) outPoint_ = 0;
86   alpha_ = 1.0 + outPoint_ - outPointer; // fractional part
87 
88   if ( alpha_ < 0.5 ) {
89     // The optimal range for alpha is about 0.5 - 1.5 in order to
90     // achieve the flattest phase delay response.
91     outPoint_ += 1;
92     if ( outPoint_ >= length ) outPoint_ -= length;
93     alpha_ += (StkFloat) 1.0;
94   }
95 
96   coeff_ = (1.0 - alpha_) / (1.0 + alpha_);  // coefficient for allpass
97 }
98 
tapOut(unsigned long tapDelay)99 StkFloat DelayA :: tapOut( unsigned long tapDelay )
100 {
101   long tap = inPoint_ - tapDelay - 1;
102   while ( tap < 0 ) // Check for wraparound.
103     tap += inputs_.size();
104 
105   return inputs_[tap];
106 }
107 
tapIn(StkFloat value,unsigned long tapDelay)108 void DelayA :: tapIn( StkFloat value, unsigned long tapDelay )
109 {
110   long tap = inPoint_ - tapDelay - 1;
111   while ( tap < 0 ) // Check for wraparound.
112     tap += inputs_.size();
113 
114   inputs_[tap] = value;
115 }
116 
117 } // stk namespace
118