Krotos Modules 3
Loading...
Searching...
No Matches
KrotosAudioBuffer.cpp
Go to the documentation of this file.
1#include "KrotosAudioBuffer.h"
2
3namespace krotos
4{
5 static const int START_SAMPLE{0};
6
8 KrotosAudioBuffer::KrotosAudioBuffer(int channels, int size) : AudioBuffer<float>(channels, size) { clear(); }
9 KrotosAudioBuffer::KrotosAudioBuffer(const AudioBuffer<float>& buffer, int numOfChannels)
10 : AudioBuffer<float>(buffer)
11 {
12 AudioBuffer<float>::setSize(numOfChannels, getNumSamples(), false, true, false);
13 clear(); // setSize should have cleared, but no harm in making sure
14 }
15
17
18 float KrotosAudioBuffer::getPeak(int channel) const { return getMagnitude(channel, START_SAMPLE, getNumSamples()); }
19
20 float KrotosAudioBuffer::getRMS(int channel) const
21 {
22 return AudioBuffer<float>::getRMSLevel(channel, START_SAMPLE, getNumSamples());
23 }
24
25 void KrotosAudioBuffer::setSize(int newNumChannels, int numSamples, bool keepExistingContent, bool clearExtraSpace,
26 bool avoidReallocating)
27 {
28 AudioBuffer<float>::setSize(newNumChannels, numSamples, keepExistingContent, clearExtraSpace,
29 avoidReallocating);
30 }
31
33 {
34 setSize(prototypeBuffer.getNumChannels(), prototypeBuffer.getNumSamples());
35 }
36
38 {
39 Random randomNumber;
40 for (int i = 0; i < getNumChannels(); ++i)
41 {
42 for (int sample = 0; sample < getNumSamples(); ++sample)
43 {
44 getWritePointer(i)[sample] = (randomNumber.nextFloat() - 0.5f) * 2;
45 }
46 }
47 }
48
50 {
51 if (state.isNotRamping())
52 return; // If we are not ramping up or down, then we return
53
54 float startValue = 0.0f;
55 float increment = 1.0f / static_cast<float>(getNumSamples());
56
57 if (state.isRampingDown())
58 {
59 startValue = 1.0f;
60 increment = -increment;
61 }
62
63 for (int i = 0; i < getNumChannels(); ++i)
64 {
65 float attenuation = startValue;
66 for (int sample = 0; sample < getNumSamples(); ++sample)
67 {
68 getWritePointer(i)[sample] *= attenuation;
69 attenuation += increment;
70 }
71 }
72 }
73
75 {
76 AudioBuffer<float> mono{1, this->getNumSamples()};
77 mono.clear();
78 for (int sourceChannel = 0; sourceChannel < this->getNumChannels(); sourceChannel++)
79 {
80 mono.addFrom(0, 0, this->getJuceAudioBuffer(), sourceChannel, 0, this->getNumSamples(),
81 1.0f / this->getNumChannels());
82 }
83
84 return KrotosAudioBuffer(mono);
85 }
86
88 {
89 return multiChannelBuffer.getMonoBuffer();
90 }
91 void KrotosAudioBuffer::setDataValid(bool state) { m_isDataValid = state; }
92
93 void KrotosAudioBuffer::copyFrom(int destChannel, const float* source, int numSamples)
94 {
95 AudioBuffer<float>::copyFrom(destChannel, START_SAMPLE, source, numSamples);
96 }
97
99 {
100 // Check that the source buffer matches our own dimensions
101 jassert(getNumSamples() == sourceBuffer.getNumSamples());
102 jassert((getNumChannels() == sourceBuffer.getNumChannels()) || (sourceBuffer.getNumChannels() == 1));
103
104 if (sourceBuffer.getNumChannels() == 1) // Mono gets copied to all dest channels
105 {
106 for (int i = 0; i < getNumChannels(); ++i)
107 {
108 copyFrom(i, sourceBuffer.getReadPointer(0), getNumSamples());
109 }
110 }
111 else
112 {
113 for (int i = 0; i < getNumChannels(); ++i)
114 {
115 copyFrom(i, sourceBuffer.getReadPointer(i), getNumSamples());
116 }
117 }
118
119 setDataValid(sourceBuffer.isDataValid());
120 }
121
122 void KrotosAudioBuffer::addFrom(int destChannel, const float* source, int numSamples)
123 {
124 AudioBuffer<float>::addFrom(destChannel, START_SAMPLE, source, numSamples);
125 }
126
128 {
129 if (!srcBuffer.isDataValid())
130 return;
131
132 // Check that the source buffer matches our own dimensions
133 jassert(getNumSamples() == srcBuffer.getNumSamples());
134 jassert((getNumChannels() == srcBuffer.getNumChannels()) || (srcBuffer.getNumChannels() == 1));
135
136 if (srcBuffer.getNumChannels() == 1) // Mono gets added to all dest channels
137 {
138 for (int channel = 0; channel < getNumChannels(); ++channel) // For every channel
139 {
140 // get read pointer from the first channel
141 const float* sourceSamples = srcBuffer.getReadPointer(0);
142 AudioBuffer<float>::addFrom(channel, START_SAMPLE, sourceSamples, srcBuffer.getNumSamples());
143 }
144 }
145 else
146 {
147 for (int channel = 0; channel < getNumChannels(); ++channel) // For every channel
148 {
149 const float* sourceSamples = srcBuffer.getReadPointer(channel);
150 AudioBuffer<float>::addFrom(channel, START_SAMPLE, sourceSamples, srcBuffer.getNumSamples());
151 }
152 }
153 }
154
156 {
158
159 //@TODO Very inefficient since addition of smoothed value - needs refactoring
160 for (int sample = 0; sample < getNumSamples(); ++sample) // For every sample
161 {
162 float wetFactor = wetDryValue.getSmoothedValue() / 100.0f;
163 float dryFactor = 1.0f - wetFactor;
164 for (int channel = 0; channel < getNumChannels(); ++channel) // For every channel
165 {
166 const float* sourceSamples = wetBuffer.getReadPointer(channel);
167 getWritePointer(channel)[sample] =
168 getReadPointer(channel)[sample] * wetFactor + sourceSamples[sample] * dryFactor;
169 }
170 }
171 }
172
174 {
175 for (int sample = 0; sample < getNumSamples(); ++sample) // For every sample
176 {
177 float gain = gainFactor.getSmoothedValue();
178 for (int channel = 0; channel < getNumChannels(); ++channel) // For every channel
179 {
180 getWritePointer(channel)[sample] *= gain;
181 }
182 }
183 }
184
185 bool KrotosAudioBuffer::processClamp(float clampValue)
186 {
187 bool wasClamped = false;
188 for (int channel = 0; channel < getNumChannels(); ++channel) // For every channel
189 {
190 for (int sample = 0; sample < getNumSamples(); ++sample) // For every sample
191 {
192 float val = getReadPointer(channel)[sample];
193 if (val > clampValue)
194 {
195 val = clampValue;
196 wasClamped = true;
197 }
198 else if (val < -clampValue)
199 {
200 val = -clampValue;
201 wasClamped = true;
202 }
203 getWritePointer(channel)[sample] = val;
204 }
205 }
206 return wasClamped;
207 }
208
209 void KrotosAudioBuffer::processGain(float gainFactor)
210 {
212
213 for (int sample = 0; sample < getNumSamples(); ++sample) // For every sample
214 {
215 for (int channel = 0; channel < getNumChannels(); ++channel) // For every channel
216 {
217 getWritePointer(channel)[sample] *= gainFactor;
218 }
219 }
220 }
221
223 {
225
226 if (getNumChannels() == 2)
227 {
228 for (int sample = 0; sample < getNumSamples(); ++sample) // For every sample
229 {
230 float gainFactorL = panValue.getSmoothedValue() * 2.0f;
231 float gainFactorR = 2.0f - gainFactorL;
232 getWritePointer(0)[sample] *= gainFactorR;
233 getWritePointer(1)[sample] *= gainFactorL;
234 }
235 }
236 else
237 {
240 jassert(false);
241 }
242 }
243
245
247 {
248 m_interpoltationType = newInterpolationType;
249 }
250
258 {
259 bool isStereo = false;
260 if (getNumChannels() > 1)
261 isStereo = true;
262 float scaling = 1.0f; // Start out unscaled
263 float increment = scaling / samples;
264 float* dataLeftChan = getWritePointer(0);
265 float* dataRightChan = dataLeftChan; // in case we are MONO, we will use the left channel data
266
267 if (isStereo) // are we >= STEREO ?
268 {
269 dataRightChan = getWritePointer(1); // if so, reference the right channel data
270 }
271
272 for (int i = 0; i < getNumSamples(); i++)
273 {
274 dataLeftChan[i] = startValue.left * scaling;
275 if (isStereo)
276 {
277 dataRightChan[i] = startValue.right * scaling;
278 }
279 scaling -= increment;
280 if (scaling < 0.0f)
281 scaling = 0.0f;
282 }
283
284 StereoSample retVal;
285 retVal.left = startValue.left * scaling;
286 retVal.right = startValue.right * scaling;
287 return retVal;
288 }
289
296 {
297 StereoSample retVal;
298
299 const float* dataLeftChan = getReadPointer(0);
300 const float* dataRightChan = dataLeftChan; // in case we are MONO, we will use the left channel data
301
302 if (getNumChannels() > 1) // are we >= STEREO ?
303 {
304 dataRightChan = getReadPointer(1); // if so, reference the right channel data
305 }
306
307 retVal.left = dataLeftChan[getNumSamples() - 1];
308 retVal.right = dataRightChan[getNumSamples() - 1];
309 return retVal;
310 }
311
319 {
320 StereoSample retVal;
321
322 // clamp the values to 0 -> bufferLength
323 if (index <= 0)
324 {
325 index = 0;
326 }
327 else if (index >= double(getNumSamples()))
328 {
329 index = double(getNumSamples()) - 1.0;
330 }
331
332 int integerPosition = (int)floor(index);
333 if (integerPosition >= getNumSamples() - 1 || integerPosition < 0)
334 {
335 // jassertfalse; // Playhead out of range
336 return retVal; // Quit with default sample value of 0,0 before we cause an access exception
337 }
338
339 const float* dataLeftChan = getReadPointer(0);
340 const float* dataRightChan = dataLeftChan; // in case we are MONO, we will use the left channel data
341
342 if (getNumChannels() > 1) // are we >= STEREO ?
343 {
344 dataRightChan = getReadPointer(1); // if so, reference the right channel data
345 }
346
347 switch (m_interpoltationType)
348 {
349 case InterpolationType::Linear: // simple linear interpolation
350 {
351 float alpha = float(index - double(integerPosition));
352 auto invAlpha = 1.0f - alpha;
353 retVal.left = dataLeftChan[integerPosition] * invAlpha + dataLeftChan[integerPosition + 1] * alpha;
354 retVal.right = dataRightChan[integerPosition] * invAlpha + dataRightChan[integerPosition + 1] * alpha;
355 break;
356 }
358 retVal.left = getCubicInterpolationSample(index, dataLeftChan);
359 retVal.right = getCubicInterpolationSample(index, dataRightChan);
360 break;
361 }
363 retVal.left = getCosineInterpolationSample(index, dataLeftChan);
364 retVal.right = getCosineInterpolationSample(index, dataRightChan);
365 break;
366 }
368 retVal.left = getCubic3dInterpolationSample(index, dataLeftChan);
369 retVal.right = getCubic3dInterpolationSample(index, dataRightChan);
370 break;
371 }
373 default: {
374 jassertfalse; // Unknown interpolation type
375 }
376 }
377
378 return retVal;
379 }
380
382 {
383 StereoSample val = getInterpolatedSample(playHead);
384 return (val.left + val.right) * 0.5f;
385 }
386
387 float KrotosAudioBuffer::getCubic3dInterpolationSample(double playhead, const float* buffer)
388 {
389 // Interpolation method from http://paulbourke.net/miscellaneous/interpolation/
390 int index = static_cast<int>(floor(playhead));
391 double mu = playhead - static_cast<double>(index);
392
393 int sampleIndex2 = index + 1;
394 if (sampleIndex2 >= getNumSamples())
395 {
396 sampleIndex2 = getNumSamples() - 1;
397 }
398
399 float y1 = buffer[index];
400 float y2 = buffer[sampleIndex2];
401
402 int sampleIndex0 = index - 1;
403 if (sampleIndex0 < 0)
404 sampleIndex0 = 0;
405 int sampleIndex3 = sampleIndex2 + 1;
406 if (sampleIndex3 >= getNumSamples())
407 {
408 sampleIndex3 = getNumSamples() - 1;
409 }
410 float y0 = buffer[sampleIndex0];
411 float y3 = buffer[sampleIndex3];
412 double mu2 = mu * mu;
413
414 float a0 = -0.5f * y0 + 1.5f * y1 - 1.5f * y2 + 0.5f * y3;
415 float a1 = y0 - 2.5f * y1 + 2 * y2 - 0.5f * y3;
416 float a2 = -0.5f * y0 + 0.5f * y2;
417 float a3 = y1;
418 return static_cast<float>(a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3);
419 }
420
421 float KrotosAudioBuffer::getCosineInterpolationSample(double playhead, const float* buffer)
422 {
423 // Interpolation method from http://paulbourke.net/miscellaneous/interpolation/
424 int index = static_cast<int>(floor(playhead));
425 double mu = playhead - static_cast<double>(index);
426
427 int sampleIndex2 = index + 1;
428 if (sampleIndex2 >= getNumSamples())
429 {
430 sampleIndex2 = getNumSamples() - 1;
431 }
432 float y1 = buffer[index];
433 float y2 = buffer[sampleIndex2];
434
435 float mu2 = (1.0f - cosf(static_cast<float>(mu) * juce::MathConstants<float>::pi)) / 2;
436 return y1 * (1.0f - mu2) + y2 * mu2;
437 }
438
439 float KrotosAudioBuffer::getCubicInterpolationSample(double playhead, const float* buffer)
440 {
441 // Cubic interpolation, for example, could go here
442 int y1index = static_cast<int>(floor(playhead));
443 int y2index = static_cast<int>(ceil(playhead));
444
445 if (y1index == y2index)
446 {
447 return buffer[y1index];
448 }
449
450 jassert(y1index >= 0);
451 jassert(y2index <= getNumSamples());
452
453 jassert((playhead != 0.0) && (y1index != y2index));
454
455 int y0index = y1index - 1;
456 int y3index = y2index + 1;
457
458 double mu = playhead - y1index;
459
460 jassert((mu >= 0) && (mu <= 1));
461
462 if (y0index == -1)
463 {
464 y0index = 0;
465 }
466
467 if (y2index >= getNumSamples())
468 {
469 y2index = getNumSamples() - 1;
470 y3index = getNumSamples() - 1;
471 }
472
473 else if (y3index >= getNumSamples())
474 {
475 y3index = getNumSamples() - 1;
476 }
477
478 jassert(y0index >= 0);
479 jassert(y1index >= 0);
480 jassert(y2index >= 0);
481 jassert(y3index >= 0);
482
483 jassert(y0index < getNumSamples());
484 jassert(y1index < getNumSamples());
485 jassert(y2index < getNumSamples());
486 jassert(y3index < getNumSamples());
487
488 double y0 = buffer[y0index];
489 double y1 = buffer[y1index];
490 double y2 = buffer[y2index];
491 double y3 = buffer[y3index];
492
493 double a0, a1, a2, a3, mu2;
494
495 mu2 = mu * mu;
496 a0 = y3 - y2 - y0 + y1;
497 a1 = y0 - y1 - a0;
498 a2 = y2 - y0;
499 a3 = y1;
500
501 return (static_cast<float>(a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3));
502 }
503
504 void KrotosAudioBuffer::setSampleRate(float sampleRate) { m_sampleRate = sampleRate; }
505
507
508 void KrotosAudioBuffer::setSourceSampleRate(float sampleRate) { m_sourceSampleRate = sampleRate; }
509
511
513 {
514 // This hardwired value should eventually be supplied from analyis of the sample, or from meta-data
515 // For now, sampled notes will be assumed to have a pitch of C4
516 return FREQ_Hz_NOTE_C4;
517 }
518
519 void KrotosAudioBuffer::reverse(int channel, int startSample, int numSamples)
520 {
521 std::reverse(getWritePointer(channel) + startSample, getWritePointer(channel) + startSample + numSamples);
522 }
523
525 void KrotosAudioBuffer::reverse(int startSample, int numSamples)
526 {
527 for (int i = 0; i < getNumChannels(); ++i)
528 {
529 reverse(i, startSample, numSamples);
530 }
531 }
532
533 juce::AudioBuffer<float>& KrotosAudioBuffer::getJuceAudioBuffer()
534 {
535 return dynamic_cast<AudioBuffer<float>&>(*this);
536 }
537
539 {
540 for (int channel = 0; channel < previousBuffer.getNumChannels(); channel++)
541 {
542 auto channelData = previousBuffer.getReadPointer(channel);
543 auto numOfSamples = previousBuffer.getNumSamples();
544
545 float multiplier = -1.0f;
546 const float increment = 2.0f / numOfSamples;
547 for (int i = 0; i < numOfSamples; i++)
548 {
549 const float newSample = (sqrt(0.5f * (1.f - multiplier)) * channelData[i]) +
550 (sqrt(0.5f * (1.f + multiplier)) * getReadPointer(channel)[i]);
551 getWritePointer(channel)[i] = newSample;
552 multiplier += increment;
553 }
554 }
555 }
556
558 {
559 float maxVal = 0;
560 for (int channel = 0; channel < getNumChannels(); channel++)
561 {
562 Range<float> range = findMinMax(channel, 0, getNumSamples());
563 if (fabs(range.getStart()) > maxVal)
564 maxVal = fabs(range.getStart());
565 if (fabs(range.getEnd()) > maxVal)
566 maxVal = fabs(range.getEnd());
567 }
568 return maxVal;
569 }
570
571 void KrotosAudioBuffer::normaliseTo(float scale) { applyGain(scale / findAbsMax()); }
572
573 const float KrotosAudioBuffer::FREQ_Hz_NOTE_C3{130.813705f};
574 const float KrotosAudioBuffer::FREQ_Hz_NOTE_D3{146.83f};
575 const float KrotosAudioBuffer::FREQ_Hz_NOTE_C4{261.63f};
576} // namespace krotos
Definition KrotosAudioBuffer.h:111
~KrotosAudioBuffer()
Definition KrotosAudioBuffer.cpp:16
float getRMS(int channel) const
Definition KrotosAudioBuffer.cpp:20
void setInterpolationType(InterpolationType newInterpolationType)
Definition KrotosAudioBuffer.cpp:246
juce::AudioBuffer< float > & getJuceAudioBuffer()
Definition KrotosAudioBuffer.cpp:533
StereoSample getLastSample()
Get the last stereo sample from the audio buffer.
Definition KrotosAudioBuffer.cpp:295
void processMute(MuteStateMachine &state)
Definition KrotosAudioBuffer.cpp:49
static const float FREQ_Hz_NOTE_D3
Definition KrotosAudioBuffer.h:219
float getCosineInterpolationSample(double playhead, const float *buffer)
Definition KrotosAudioBuffer.cpp:421
void processPan(SmoothedFloat &panValue)
Definition KrotosAudioBuffer.cpp:222
static const float FREQ_Hz_NOTE_C4
Definition KrotosAudioBuffer.h:220
float getSourceSampleRate(void)
Definition KrotosAudioBuffer.cpp:510
float getSampleRate(void)
Definition KrotosAudioBuffer.cpp:506
bool processClamp(float clampValue)
Definition KrotosAudioBuffer.cpp:185
float getCubic3dInterpolationSample(double playhead, const float *buffer)
Definition KrotosAudioBuffer.cpp:387
StereoSample getInterpolatedSample(double index)
Get a stereo sample from the audio buffer.
Definition KrotosAudioBuffer.cpp:318
void equalPowerCrossFadeFrom(const KrotosAudioBuffer &previousBuffer)
Definition KrotosAudioBuffer.cpp:538
float getInterpolatedSampleMono(float playHead)
Definition KrotosAudioBuffer.cpp:381
KrotosAudioBuffer getMonoBuffer()
Definition KrotosAudioBuffer.cpp:74
static const float FREQ_Hz_NOTE_C3
Definition KrotosAudioBuffer.h:218
float getCubicInterpolationSample(double playhead, const float *buffer)
Definition KrotosAudioBuffer.cpp:439
KrotosAudioBuffer()
Definition KrotosAudioBuffer.cpp:7
void processWetDry(KrotosAudioBuffer &wetBuffer, SmoothedFloat &wetDryValue)
Definition KrotosAudioBuffer.cpp:155
void fillWithNoise()
Definition KrotosAudioBuffer.cpp:37
float m_sampleRate
Definition KrotosAudioBuffer.h:213
void setSize(int newNumChannels, int numSamples, bool keepExistingContent=true, bool clearExtraSpace=true, bool avoidReallocating=true)
Definition KrotosAudioBuffer.cpp:25
void copyFrom(int destChannel, const float *source, int numSamples)
Definition KrotosAudioBuffer.cpp:93
void setSampleRate(float sampleRate)
Definition KrotosAudioBuffer.cpp:504
bool isDataValid() const
Definition KrotosAudioBuffer.cpp:244
void reverse(int channel, int startSample, int numSamples)
Definition KrotosAudioBuffer.cpp:519
InterpolationType m_interpoltationType
Definition KrotosAudioBuffer.h:212
void normaliseTo(float scale)
Definition KrotosAudioBuffer.cpp:571
StereoSample makeRamp(StereoSample startValue, int samples)
Create a ramp in the buffer.
Definition KrotosAudioBuffer.cpp:257
float findAbsMax()
Definition KrotosAudioBuffer.cpp:557
float getNativeNoteFrequency(void)
Definition KrotosAudioBuffer.cpp:512
InterpolationType
Definition KrotosAudioBuffer.h:120
@ NUM_TYPES
Definition KrotosAudioBuffer.h:125
@ Cosine
Definition KrotosAudioBuffer.h:123
@ Cubic3d
Definition KrotosAudioBuffer.h:124
@ Cubic
Definition KrotosAudioBuffer.h:122
@ Linear
Definition KrotosAudioBuffer.h:121
void setSourceSampleRate(float sampleRate)
Definition KrotosAudioBuffer.cpp:508
float m_sourceSampleRate
Definition KrotosAudioBuffer.h:214
float getPeak(int channel) const
Definition KrotosAudioBuffer.cpp:18
void setDataValid(bool state)
Definition KrotosAudioBuffer.cpp:91
void processGain(SmoothedFloat &gainFactor)
Definition KrotosAudioBuffer.cpp:173
void addFrom(int destChannel, const float *source, int numSamples)
Definition KrotosAudioBuffer.cpp:122
static KrotosAudioBuffer mixToMono(KrotosAudioBuffer &multiChannelBuffer)
Definition KrotosAudioBuffer.cpp:87
bool m_isDataValid
Definition KrotosAudioBuffer.h:210
Definition MuteStateMachine.h:6
bool isRampingDown()
Definition MuteStateMachine.h:61
bool isNotRamping()
Definition MuteStateMachine.h:56
Definition SmoothedFloat.h:6
float getSmoothedValue()
increments the value by the required increment and gets smootedValue
Definition SmoothedFloat.cpp:5
Definition KrotosAudioBuffer.h:16
float left
Definition KrotosAudioBuffer.h:107
float right
Definition KrotosAudioBuffer.h:107
Definition AirAbsorptionFilter.cpp:2
static const int START_SAMPLE
Definition KrotosAudioBuffer.cpp:5