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