-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathenginefilterdelay.h
123 lines (107 loc) · 4.34 KB
/
enginefilterdelay.h
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
121
122
123
#pragma once
#include "engine/engineobject.h"
#include "util/assert.h"
#include "util/sample.h"
template<unsigned int SIZE>
class EngineFilterDelay : public EngineObjectConstIn {
public:
EngineFilterDelay()
: m_delaySamples(0),
m_oldDelaySamples(0),
m_delayPos(0),
m_doStart(false) {
// Set the current buffers to 0
memset(m_buf, 0, sizeof(m_buf));
}
virtual ~EngineFilterDelay() {};
void pauseFilter() {
// Set the current buffers to 0
if (!m_doStart) {
memset(m_buf, 0, sizeof(m_buf));
m_oldDelaySamples = 0;
m_doStart = true;
}
}
void setDelay(unsigned int delaySamples) {
m_delaySamples = delaySamples;
}
virtual void process(const CSAMPLE* pIn, CSAMPLE* pOutput,
const int iBufferSize) {
if (m_oldDelaySamples == m_delaySamples) {
int delaySourcePos = (m_delayPos + SIZE - m_delaySamples) % SIZE;
VERIFY_OR_DEBUG_ASSERT(delaySourcePos >= 0) {
SampleUtil::copy(pOutput, pIn, iBufferSize);
return;
}
VERIFY_OR_DEBUG_ASSERT(delaySourcePos <= static_cast<int>(SIZE)) {
SampleUtil::copy(pOutput, pIn, iBufferSize);
return;
}
for (int i = 0; i < iBufferSize; ++i) {
// put sample into delay buffer:
m_buf[m_delayPos] = pIn[i];
m_delayPos = (m_delayPos + 1) % SIZE;
// Take delayed sample from delay buffer and copy it to dest buffer:
pOutput[i] = m_buf[delaySourcePos];
delaySourcePos = (delaySourcePos + 1) % SIZE;
}
} else {
int delaySourcePos = (m_delayPos + SIZE - m_delaySamples + iBufferSize / 2) % SIZE;
int oldDelaySourcePos = (m_delayPos + SIZE - m_oldDelaySamples) % SIZE;
VERIFY_OR_DEBUG_ASSERT(delaySourcePos >= 0) {
SampleUtil::copy(pOutput, pIn, iBufferSize);
return;
}
VERIFY_OR_DEBUG_ASSERT(delaySourcePos <= static_cast<int>(SIZE)) {
SampleUtil::copy(pOutput, pIn, iBufferSize);
return;
}
VERIFY_OR_DEBUG_ASSERT(oldDelaySourcePos >= 0) {
SampleUtil::copy(pOutput, pIn, iBufferSize);
return;
}
VERIFY_OR_DEBUG_ASSERT(oldDelaySourcePos <= static_cast<int>(SIZE)) {
SampleUtil::copy(pOutput, pIn, iBufferSize);
return;
}
double cross_mix = 0.0;
double cross_inc = 2 / static_cast<double>(iBufferSize);
for (int i = 0; i < iBufferSize; ++i) {
// put sample into delay buffer:
m_buf[m_delayPos] = pIn[i];
m_delayPos = (m_delayPos + 1) % SIZE;
// Take delayed sample from delay buffer and copy it to dest buffer:
if (i < iBufferSize / 2) {
// only ramp the second half of the buffer, because we do
// the same in the IIR filter to wait for settling
pOutput[i] = m_buf[oldDelaySourcePos];
} else {
pOutput[i] = static_cast<CSAMPLE>(m_buf[oldDelaySourcePos] * (1.0 - cross_mix));
pOutput[i] += static_cast<CSAMPLE>(m_buf[delaySourcePos] * cross_mix);
delaySourcePos = (delaySourcePos + 1) % SIZE;
cross_mix += cross_inc;
}
oldDelaySourcePos = (oldDelaySourcePos + 1) % SIZE;
}
m_oldDelaySamples = m_delaySamples;
}
m_doStart = false;
}
// this is can be used instead off a final process() call before pause
// It fades to dry or 0 according to the m_startFromDry parameter
// it is an alternative for using pauseFillter() calls
void processAndPauseFilter(const CSAMPLE* pIn, CSAMPLE* pOutput,
const int iBufferSize) {
int oldDelay = m_delaySamples;
m_delaySamples = 0;
process(pIn, pOutput, iBufferSize);
m_delaySamples = oldDelay;
pauseFilter();
}
protected:
int m_delaySamples;
int m_oldDelaySamples;
int m_delayPos;
CSAMPLE m_buf[SIZE];
bool m_doStart;
};