/***************************************************/ /*! \class DelayA \brief STK allpass interpolating delay line class. This class implements a fractional-length digital delay-line using a first-order allpass filter. If the delay and maximum length are not specified during instantiation, a fixed maximum length of 4095 and a delay of zero is set. An allpass filter has unity magnitude gain but variable phase delay properties, making it useful in achieving fractional delays without affecting a signal's frequency magnitude response. In order to achieve a maximally flat phase delay response, the minimum delay possible in this implementation is limited to a value of 0.5. by Perry R. Cook and Gary P. Scavone, 1995--2017. */ /***************************************************/ #include "DelayA.h" namespace stk { DelayA :: DelayA( StkFloat delay, unsigned long maxDelay ) { if ( delay < 0.5 ) { oStream_ << "DelayA::DelayA: delay must be >= 0.5!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( delay > (StkFloat) maxDelay ) { oStream_ << "DelayA::DelayA: maxDelay must be > than delay argument!"; handleError( StkError::FUNCTION_ARGUMENT ); } // Writing before reading allows delays from 0 to length-1. if ( maxDelay + 1 > inputs_.size() ) inputs_.resize( maxDelay + 1, 1, 0.0 ); inPoint_ = 0; this->setDelay( delay ); apInput_ = 0.0; doNextOut_ = true; } DelayA :: ~DelayA() { } void DelayA :: clear() { for ( unsigned int i=0; i length ) { // The value is too big. oStream_ << "DelayA::setDelay: argument (" << delay << ") greater than maximum!"; handleError( StkError::WARNING ); return; } if ( delay < 0.5 ) { oStream_ << "DelayA::setDelay: argument (" << delay << ") less than 0.5 not possible!"; handleError( StkError::WARNING ); } StkFloat outPointer = inPoint_ - delay + 1.0; // outPoint chases inpoint delay_ = delay; while ( outPointer < 0 ) outPointer += length; // modulo maximum length outPoint_ = (long) outPointer; // integer part if ( outPoint_ == length ) outPoint_ = 0; alpha_ = 1.0 + outPoint_ - outPointer; // fractional part if ( alpha_ < 0.5 ) { // The optimal range for alpha is about 0.5 - 1.5 in order to // achieve the flattest phase delay response. outPoint_ += 1; if ( outPoint_ >= length ) outPoint_ -= length; alpha_ += (StkFloat) 1.0; } coeff_ = (1.0 - alpha_) / (1.0 + alpha_); // coefficient for allpass } StkFloat DelayA :: tapOut( unsigned long tapDelay ) { long tap = inPoint_ - tapDelay - 1; while ( tap < 0 ) // Check for wraparound. tap += inputs_.size(); return inputs_[tap]; } void DelayA :: tapIn( StkFloat value, unsigned long tapDelay ) { long tap = inPoint_ - tapDelay - 1; while ( tap < 0 ) // Check for wraparound. tap += inputs_.size(); inputs_[tap] = value; } } // stk namespace