forked from thestk/stk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPRCRev.cpp
More file actions
120 lines (99 loc) · 3.35 KB
/
PRCRev.cpp
File metadata and controls
120 lines (99 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/***************************************************/
/*! \class PRCRev
\brief Perry's simple reverberator class.
This class is based on some of the famous
Stanford/CCRMA reverbs (NRev, KipRev), which
were based on the Chowning/Moorer/Schroeder
reverberators using networks of simple allpass
and comb delay filters. This class implements
two series allpass units and two parallel comb
filters.
by Perry R. Cook and Gary P. Scavone, 1995--2021.
*/
/***************************************************/
#include "PRCRev.h"
#include <cmath>
namespace stk {
PRCRev :: PRCRev( StkFloat T60 )
{
if ( T60 <= 0.0 ) {
oStream_ << "PRCRev::PRCRev: argument (" << T60 << ") must be positive!";
handleError( StkError::FUNCTION_ARGUMENT );
}
lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
// Delay lengths for 44100 Hz sample rate.
int lengths[4]= {341, 613, 1557, 2137};
double scaler = Stk::sampleRate() / 44100.0;
// Scale the delay lengths if necessary.
int delay, i;
if ( scaler != 1.0 ) {
for (i=0; i<4; i++) {
delay = (int) floor(scaler * lengths[i]);
if ( (delay & 1) == 0) delay++;
while ( !this->isPrime(delay) ) delay += 2;
lengths[i] = delay;
}
}
for ( i=0; i<2; i++ ) {
allpassDelays_[i].setMaximumDelay( lengths[i] );
allpassDelays_[i].setDelay( lengths[i] );
combDelays_[i].setMaximumDelay( lengths[i+2] );
combDelays_[i].setDelay( lengths[i+2] );
}
this->setT60( T60 );
allpassCoefficient_ = 0.7;
effectMix_ = 0.5;
this->clear();
}
void PRCRev :: clear( void )
{
allpassDelays_[0].clear();
allpassDelays_[1].clear();
combDelays_[0].clear();
combDelays_[1].clear();
lastFrame_[0] = 0.0;
lastFrame_[1] = 0.0;
}
void PRCRev :: setT60( StkFloat T60 )
{
if ( T60 <= 0.0 ) {
oStream_ << "PRCRev::setT60: argument (" << T60 << ") must be positive!";
handleError( StkError::WARNING ); return;
}
combCoefficient_[0] = pow(10.0, (-3.0 * combDelays_[0].getDelay() / (T60 * Stk::sampleRate())));
combCoefficient_[1] = pow(10.0, (-3.0 * combDelays_[1].getDelay() / (T60 * Stk::sampleRate())));
}
StkFrames& PRCRev :: tick( StkFrames& frames, unsigned int channel )
{
#if defined(_STK_DEBUG_)
if ( channel >= frames.channels() - 1 ) {
oStream_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *samples = &frames[channel];
unsigned int hop = frames.channels();
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
*samples = tick( *samples );
*(samples+1) = lastFrame_[1];
}
return frames;
}
StkFrames& PRCRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
{
#if defined(_STK_DEBUG_)
if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
oStream_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *iSamples = &iFrames[iChannel];
StkFloat *oSamples = &oFrames[oChannel];
unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
*oSamples = tick( *iSamples );
*(oSamples+1) = lastFrame_[1];
}
return iFrames;
}
} // stk namespace