Krotos Modules 3
Loading...
Searching...
No Matches
AudioSampleCircularBuffer.cpp
Go to the documentation of this file.
1namespace krotos
2{
3 AudioSampleCircularBuffer::AudioSampleCircularBuffer(const int numSamples, const long sampleRate) noexcept
4 : m_head(0), m_useInterpolation(true), m_size(numSamples), m_sizeAsFloat(static_cast<float>(numSamples)),
5 m_sizeMultiple(numSamples * BUFFER_MULTIPLE_FOR_NEG_MODULUS_CALC),
6 m_sizeMultipleAsFloat(static_cast<float>(m_sizeMultiple))
7 {
8 m_circularDelayBuffer = std::make_unique<AudioSampleBuffer>(1, numSamples);
9
10 if (numSamples < sampleRate)
11 {
12 // if the buffer is short set the read position to be the last sample of the delay line.
13 m_readPosition = float(numSamples);
14 }
15 else
16 {
17 // set the read position to be one seconds worth of samples (at the default rate) inside the buffer.
18 m_readPosition = float(m_size - sampleRate);
19 }
20
21 // NOTE! The length of the buffer should really be updated to reflect the current sample rate.
22 // The best place to do this seems to be in prepareToPlay().
23
24 m_circularDelayBuffer->clear();
25 }
26
27 void AudioSampleCircularBuffer::setSize(int numSamples) noexcept
28 {
29 m_circularDelayBuffer->setSize(1, numSamples);
30 m_circularDelayBuffer->clear();
31 }
32
34 {
35 FloatVectorOperations::fill(m_circularDelayBuffer->getWritePointer(0), 0.0f,
36 m_circularDelayBuffer->getNumSamples());
37 m_head = 0;
38 }
39
40 // set the read position - if it moves outside the bounds of the buffer reset it to 0 (to make the buffer circular)
42 {
43 m_readPosition = m_head - index;
44 m_readPosition = wrapFloatValue(m_readPosition);
45 }
46
47 // set the read position - if it moves outside the bounds of the buffer reset it to 0 (to make the buffer circular)
53
54 // copy a block of samples into the buffer
55 void AudioSampleCircularBuffer::copySamples(AudioSampleBuffer& source, int numSamples) noexcept
56 {
57 // if the number of samples will fit inside the buffer without overrunning then just copy them in, and increment
58 // m_head and tail:
59 float* bufferPointer = m_circularDelayBuffer->getWritePointer(0);
60
61 if ((m_head + numSamples) < m_size)
62 {
63 FloatVectorOperations::fill(bufferPointer + m_head, 0.0f, numSamples);
64 m_circularDelayBuffer->copyFrom(0, m_head, source, 0, 0, numSamples);
65 m_head += numSamples;
66 }
67
68 // otherwise we need to copy some samples into the end of the buffer and the remaining samples into the start
69 // (to make the buffer circular)
70 else
71 {
72 int numSamplesToReadToEnd = m_size - m_head;
73
74 int numSamplesToReadToStart = numSamples - numSamplesToReadToEnd;
75
76 FloatVectorOperations::fill(bufferPointer + m_head, 0.0f, numSamplesToReadToEnd);
77 FloatVectorOperations::fill(bufferPointer, 0.0f, numSamplesToReadToStart);
78
79 m_circularDelayBuffer->copyFrom(0, m_head, source, 0, 0, numSamplesToReadToEnd);
80 m_circularDelayBuffer->copyFrom(0, 0, source, 0, numSamplesToReadToEnd, numSamplesToReadToStart);
81
82 // we also need to check if the m_head is at zero so we know if we need to manually set the poisition of
83 // tail to the end of the buffer
84 m_head = (m_head + numSamples) - m_size;
85 }
86 }
87
88 // copy a sample into the buffer
89 void AudioSampleCircularBuffer::copySample(float source) noexcept
90 {
91 m_circularDelayBuffer->setSample(0, m_head, source);
92
93 m_head++;
94
95 if (m_head >= m_size)
96 {
97 m_head = m_head - m_size;
98 }
99 }
100
101 void AudioSampleCircularBuffer::addSample(int indexOffset, float newSample) noexcept
102 {
103 m_circularDelayBuffer->addSample(0, static_cast<int>(wrapFloatValue(float(indexOffset))), newSample);
104 }
105
107 {
108 index = static_cast<int>(val);
109 mu = val - static_cast<float>(index);
110 nmu = 1.0f - mu;
111 }
112
114 {
115 float retVal = input - static_cast<float>(static_cast<int>(input));
116 jassert((retVal >= 0.0f) && (retVal <= 1.0f));
117 return retVal;
118 }
119
120 float AudioSampleCircularBuffer::getSample(float sampleToRead) noexcept
121 {
122 MU sampleIndex1(wrapFloatValue(sampleToRead));
123
124 int sampleIndex2 = sampleIndex1.index + 1;
125 if (sampleIndex2 >= m_size)
126 sampleIndex2 -= m_size;
127
128 const float* delayBufferData = m_circularDelayBuffer->getReadPointer(0);
129 float y1 = delayBufferData[sampleIndex1.index];
130 float y2 = delayBufferData[sampleIndex2];
131
132 float retVal{0.0f};
133
134 switch (m_interpolationType)
135 {
137 retVal = y1 * sampleIndex1.nmu + y2 * sampleIndex1.mu;
138 break;
139 }
140
141 // Interpolation method from http://paulbourke.net/miscellaneous/interpolation/
143 float mu2 = (1.0f - cosf(sampleIndex1.mu * juce::MathConstants<float>::pi)) / 2;
144 retVal = y1 * (1.0f - mu2) + y2 * mu2;
145 break;
146 }
147
148 // Interpolation method from http://paulbourke.net/miscellaneous/interpolation/
149 case InterpolationType::cubic: // This is the dodgy one which sounds bad
150 {
151 int sampleIndex0 = sampleIndex1.index - 1;
152 if (sampleIndex0 < 0)
153 sampleIndex0 += m_size;
154 int sampleIndex3 = sampleIndex2 + 1;
155 if (sampleIndex3 >= m_size)
156 sampleIndex3 -= m_size;
157 float y0 = delayBufferData[sampleIndex0];
158 float y3 = delayBufferData[sampleIndex3];
159 float mu2 = sampleIndex1.mu * sampleIndex1.mu;
160
161 float a0 = y3 - y2 - y0 + y1;
162 float a1 = y0 - y1 - a0;
163 float a2 = y2 - y0;
164 float a3 = y1;
165 retVal = a0 * sampleIndex1.mu * mu2 + a1 * mu2 + a2 * sampleIndex1.mu + a3;
166 break;
167 }
168
169 // Interpolation method from http://paulbourke.net/miscellaneous/interpolation/
171 int sampleIndex0 = sampleIndex1.index - 1;
172 if (sampleIndex0 < 0)
173 sampleIndex0 += m_size;
174 int sampleIndex3 = sampleIndex2 + 1;
175 if (sampleIndex3 >= m_size)
176 sampleIndex3 -= m_size;
177 float y0 = delayBufferData[sampleIndex0];
178 float y3 = delayBufferData[sampleIndex3];
179 float mu2 = sampleIndex1.mu * sampleIndex1.mu;
180
181 float a0 = -0.5f * y0 + 1.5f * y1 - 1.5f * y2 + 0.5f * y3;
182 float a1 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3;
183 float a2 = -0.5f * y0 + 0.5f * y2;
184 float a3 = y1;
185 retVal = a0 * sampleIndex1.mu * mu2 + a1 * mu2 + a2 * sampleIndex1.mu + a3;
186 break;
187 }
188 }
189
190 return retVal;
191 }
192} // namespace krotos
creates and stores the fractional part of a float and its inverse
Definition AudioSampleCircularBuffer.h:17
MU(float val)
Definition AudioSampleCircularBuffer.cpp:106
float mu
Definition AudioSampleCircularBuffer.h:20
int index
Definition AudioSampleCircularBuffer.h:21
float nmu
Definition AudioSampleCircularBuffer.h:20
float getSample(float sampleToRead) noexcept
Definition AudioSampleCircularBuffer.cpp:120
void setReadPosition(float sample) noexcept
Definition AudioSampleCircularBuffer.cpp:41
std::unique_ptr< juce::AudioSampleBuffer > m_circularDelayBuffer
Definition AudioSampleCircularBuffer.h:79
InterpolationType m_interpolationType
Definition AudioSampleCircularBuffer.h:87
void copySamples(juce::AudioSampleBuffer &source, int numSamples) noexcept
Definition AudioSampleCircularBuffer.cpp:55
void fillWithZeroes()
Definition AudioSampleCircularBuffer.cpp:33
void setSize(int numSamples) noexcept
Definition AudioSampleCircularBuffer.cpp:27
@ cubic3d
Definition AudioSampleCircularBuffer.h:35
@ linear
Definition AudioSampleCircularBuffer.h:33
@ cubic
Definition AudioSampleCircularBuffer.h:32
@ cosine
Definition AudioSampleCircularBuffer.h:34
float m_readPosition
Definition AudioSampleCircularBuffer.h:77
float fract(float input)
returns the fractional part of a float
Definition AudioSampleCircularBuffer.cpp:113
float wrapFloatValue(float valueToWrap) noexcept
Definition AudioSampleCircularBuffer.h:63
AudioSampleCircularBuffer(int numSamples, long sampleRate) noexcept
Definition AudioSampleCircularBuffer.cpp:3
void incrementReadPosition() noexcept
Definition AudioSampleCircularBuffer.cpp:48
void copySample(float source) noexcept
Definition AudioSampleCircularBuffer.cpp:89
void addSample(int indexOffset, float newSample) noexcept
Definition AudioSampleCircularBuffer.cpp:101
const int m_size
Definition AudioSampleCircularBuffer.h:82
int m_head
Definition AudioSampleCircularBuffer.h:76
Definition AirAbsorptionFilter.cpp:2