OpenShot Library | libopenshot-audio 0.2.0
juce_AudioSampleBuffer.h
1
2/** @weakgroup juce_audio_basics-buffers
3 * @{
4 */
5/*
6 ==============================================================================
7
8 This file is part of the JUCE library.
9 Copyright (c) 2017 - ROLI Ltd.
10
11 JUCE is an open source library subject to commercial or open-source
12 licensing.
13
14 The code included in this file is provided under the terms of the ISC license
15 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16 To use, copy, modify, and/or distribute this software for any purpose with or
17 without fee is hereby granted provided that the above copyright notice and
18 this permission notice appear in all copies.
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
30//==============================================================================
31/**
32 A multi-channel buffer containing floating point audio samples.
33
34 @tags{Audio}
35*/
36template <typename Type>
38{
39public:
40 //==============================================================================
41 /** Creates an empty buffer with 0 channels and 0 length. */
43 : channels (static_cast<Type**> (preallocatedChannelSpace))
44 {
45 }
46
47 //==============================================================================
48 /** Creates a buffer with a specified number of channels and samples.
49
50 The contents of the buffer will initially be undefined, so use clear() to
51 set all the samples to zero.
52
53 The buffer will allocate its memory internally, and this will be released
54 when the buffer is deleted. If the memory can't be allocated, this will
55 throw a std::bad_alloc exception.
56 */
59 : numChannels (numChannelsToAllocate),
61 {
62 jassert (size >= 0 && numChannels >= 0);
63 allocateData();
64 }
65
66 /** Creates a buffer using a pre-allocated block of memory.
67
68 Note that if the buffer is resized or its number of channels is changed, it
69 will re-allocate memory internally and copy the existing data to this new area,
70 so it will then stop directly addressing this memory.
71
72 @param dataToReferTo a pre-allocated array containing pointers to the data
73 for each channel that should be used by this buffer. The
74 buffer will only refer to this memory, it won't try to delete
75 it when the buffer is deleted or resized.
76 @param numChannelsToUse the number of channels to use - this must correspond to the
77 number of elements in the array passed in
78 @param numSamples the number of samples to use - this must correspond to the
79 size of the arrays passed in
80 */
83 int numSamples)
84 : numChannels (numChannelsToUse),
85 size (numSamples)
86 {
87 jassert (dataToReferTo != nullptr);
88 jassert (numChannelsToUse >= 0 && numSamples >= 0);
89 allocateChannels (dataToReferTo, 0);
90 }
91
92 /** Creates a buffer using a pre-allocated block of memory.
93
94 Note that if the buffer is resized or its number of channels is changed, it
95 will re-allocate memory internally and copy the existing data to this new area,
96 so it will then stop directly addressing this memory.
97
98 @param dataToReferTo a pre-allocated array containing pointers to the data
99 for each channel that should be used by this buffer. The
100 buffer will only refer to this memory, it won't try to delete
101 it when the buffer is deleted or resized.
102 @param numChannelsToUse the number of channels to use - this must correspond to the
103 number of elements in the array passed in
104 @param startSample the offset within the arrays at which the data begins
105 @param numSamples the number of samples to use - this must correspond to the
106 size of the arrays passed in
107 */
110 int startSample,
111 int numSamples)
112 : numChannels (numChannelsToUse),
113 size (numSamples)
114 {
115 jassert (dataToReferTo != nullptr);
116 jassert (numChannelsToUse >= 0 && startSample >= 0 && numSamples >= 0);
117 allocateChannels (dataToReferTo, startSample);
118 }
119
120 /** Copies another buffer.
121
122 This buffer will make its own copy of the other's data, unless the buffer was created
123 using an external data buffer, in which case boths buffers will just point to the same
124 shared block of data.
125 */
127 : numChannels (other.numChannels),
128 size (other.size),
129 allocatedBytes (other.allocatedBytes)
130 {
131 if (allocatedBytes == 0)
132 {
133 allocateChannels (other.channels, 0);
134 }
135 else
136 {
137 allocateData();
138
139 if (other.isClear)
140 {
141 clear();
142 }
143 else
144 {
145 for (int i = 0; i < numChannels; ++i)
146 FloatVectorOperations::copy (channels[i], other.channels[i], size);
147 }
148 }
149 }
150
151 /** Copies another buffer onto this one.
152 This buffer's size will be changed to that of the other buffer.
153 */
155 {
156 if (this != &other)
157 {
158 setSize (other.getNumChannels(), other.getNumSamples(), false, false, false);
159
160 if (other.isClear)
161 {
162 clear();
163 }
164 else
165 {
166 isClear = false;
167
168 for (int i = 0; i < numChannels; ++i)
169 FloatVectorOperations::copy (channels[i], other.channels[i], size);
170 }
171 }
172
173 return *this;
174 }
175
176 /** Destructor.
177 This will free any memory allocated by the buffer.
178 */
179 ~AudioBuffer() = default;
180
181 /** Move constructor */
183 : numChannels (other.numChannels),
184 size (other.size),
185 allocatedBytes (other.allocatedBytes),
186 allocatedData (std::move (other.allocatedData)),
187 isClear (other.isClear)
188 {
189 if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
190 {
191 channels = preallocatedChannelSpace;
192
193 for (int i = 0; i < numChannels; ++i)
194 preallocatedChannelSpace[i] = other.channels[i];
195 }
196 else
197 {
198 channels = other.channels;
199 }
200
201 other.numChannels = 0;
202 other.size = 0;
203 other.allocatedBytes = 0;
204 }
205
206 /** Move assignment */
208 {
209 numChannels = other.numChannels;
210 size = other.size;
211 allocatedBytes = other.allocatedBytes;
212 allocatedData = std::move (other.allocatedData);
213 isClear = other.isClear;
214
215 if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
216 {
217 channels = preallocatedChannelSpace;
218
219 for (int i = 0; i < numChannels; ++i)
220 preallocatedChannelSpace[i] = other.channels[i];
221 }
222 else
223 {
224 channels = other.channels;
225 }
226
227 other.numChannels = 0;
228 other.size = 0;
229 other.allocatedBytes = 0;
230 return *this;
231 }
232
233 //==============================================================================
234 /** Returns the number of channels of audio data that this buffer contains.
235 @see getNumSamples, getReadPointer, getWritePointer
236 */
237 int getNumChannels() const noexcept { return numChannels; }
238
239 /** Returns the number of samples allocated in each of the buffer's channels.
240 @see getNumChannels, getReadPointer, getWritePointer
241 */
242 int getNumSamples() const noexcept { return size; }
243
244 /** Returns a pointer to an array of read-only samples in one of the buffer's channels.
245 For speed, this doesn't check whether the channel number is out of range,
246 so be careful when using it!
247 If you need to write to the data, do NOT call this method and const_cast the
248 result! Instead, you must call getWritePointer so that the buffer knows you're
249 planning on modifying the data.
250 */
251 const Type* getReadPointer (int channelNumber) const noexcept
252 {
253 jassert (isPositiveAndBelow (channelNumber, numChannels));
254 return channels[channelNumber];
255 }
256
257 /** Returns a pointer to an array of read-only samples in one of the buffer's channels.
258 For speed, this doesn't check whether the channel number or index are out of range,
259 so be careful when using it!
260 If you need to write to the data, do NOT call this method and const_cast the
261 result! Instead, you must call getWritePointer so that the buffer knows you're
262 planning on modifying the data.
263 */
264 const Type* getReadPointer (int channelNumber, int sampleIndex) const noexcept
265 {
266 jassert (isPositiveAndBelow (channelNumber, numChannels));
267 jassert (isPositiveAndBelow (sampleIndex, size));
268 return channels[channelNumber] + sampleIndex;
269 }
270
271 /** Returns a writeable pointer to one of the buffer's channels.
272 For speed, this doesn't check whether the channel number is out of range,
273 so be careful when using it!
274 Note that if you're not planning on writing to the data, you should always
275 use getReadPointer instead.
276 */
277 Type* getWritePointer (int channelNumber) noexcept
278 {
279 jassert (isPositiveAndBelow (channelNumber, numChannels));
280 isClear = false;
281 return channels[channelNumber];
282 }
283
284 /** Returns a writeable pointer to one of the buffer's channels.
285 For speed, this doesn't check whether the channel number or index are out of range,
286 so be careful when using it!
287 Note that if you're not planning on writing to the data, you should
288 use getReadPointer instead.
289 */
290 Type* getWritePointer (int channelNumber, int sampleIndex) noexcept
291 {
292 jassert (isPositiveAndBelow (channelNumber, numChannels));
293 jassert (isPositiveAndBelow (sampleIndex, size));
294 isClear = false;
295 return channels[channelNumber] + sampleIndex;
296 }
297
298 /** Returns an array of pointers to the channels in the buffer.
299
300 Don't modify any of the pointers that are returned, and bear in mind that
301 these will become invalid if the buffer is resized.
302 */
303 const Type** getArrayOfReadPointers() const noexcept { return const_cast<const Type**> (channels); }
304
305 /** Returns an array of pointers to the channels in the buffer.
306
307 Don't modify any of the pointers that are returned, and bear in mind that
308 these will become invalid if the buffer is resized.
309 */
310 Type** getArrayOfWritePointers() noexcept { isClear = false; return channels; }
311
312 //==============================================================================
313 /** Changes the buffer's size or number of channels.
314
315 This can expand or contract the buffer's length, and add or remove channels.
316
317 If keepExistingContent is true, it will try to preserve as much of the
318 old data as it can in the new buffer.
319
320 If clearExtraSpace is true, then any extra channels or space that is
321 allocated will be also be cleared. If false, then this space is left
322 uninitialised.
323
324 If avoidReallocating is true, then changing the buffer's size won't reduce the
325 amount of memory that is currently allocated (but it will still increase it if
326 the new size is bigger than the amount it currently has). If this is false, then
327 a new allocation will be done so that the buffer uses takes up the minimum amount
328 of memory that it needs.
329
330 Note that if keepExistingContent and avoidReallocating are both true, then it will
331 only avoid reallocating if neither the channel count or length in samples increase.
332
333 If the required memory can't be allocated, this will throw a std::bad_alloc exception.
334 */
336 int newNumSamples,
337 bool keepExistingContent = false,
338 bool clearExtraSpace = false,
339 bool avoidReallocating = false)
340 {
341 jassert (newNumChannels >= 0);
342 jassert (newNumSamples >= 0);
343
344 if (newNumSamples != size || newNumChannels != numChannels)
345 {
347 auto channelListSize = ((sizeof (Type*) * (size_t) (newNumChannels + 1)) + 15) & ~15u;
348 auto newTotalBytes = ((size_t) newNumChannels * (size_t) allocatedSamplesPerChannel * sizeof (Type))
349 + channelListSize + 32;
350
352 {
353 if (avoidReallocating && newNumChannels <= numChannels && newNumSamples <= size)
354 {
355 // no need to do any remapping in this case, as the channel pointers will remain correct!
356 }
357 else
358 {
360 newData.allocate (newTotalBytes, clearExtraSpace || isClear);
361
362 auto numSamplesToCopy = (size_t) jmin (newNumSamples, size);
363
364 auto newChannels = reinterpret_cast<Type**> (newData.get());
365 auto newChan = reinterpret_cast<Type*> (newData + channelListSize);
366
367 for (int j = 0; j < newNumChannels; ++j)
368 {
371 }
372
373 if (! isClear)
374 {
375 auto numChansToCopy = jmin (numChannels, newNumChannels);
376
377 for (int i = 0; i < numChansToCopy; ++i)
379 }
380
381 allocatedData.swapWith (newData);
382 allocatedBytes = newTotalBytes;
383 channels = newChannels;
384 }
385 }
386 else
387 {
388 if (avoidReallocating && allocatedBytes >= newTotalBytes)
389 {
390 if (clearExtraSpace || isClear)
391 allocatedData.clear (newTotalBytes);
392 }
393 else
394 {
395 allocatedBytes = newTotalBytes;
396 allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear);
397 channels = reinterpret_cast<Type**> (allocatedData.get());
398 }
399
400 auto* chan = reinterpret_cast<Type*> (allocatedData + channelListSize);
401
402 for (int i = 0; i < newNumChannels; ++i)
403 {
404 channels[i] = chan;
406 }
407 }
408
409 channels[newNumChannels] = nullptr;
410 size = newNumSamples;
411 numChannels = newNumChannels;
412 }
413 }
414
415 /** Makes this buffer point to a pre-allocated set of channel data arrays.
416
417 There's also a constructor that lets you specify arrays like this, but this
418 lets you change the channels dynamically.
419
420 Note that if the buffer is resized or its number of channels is changed, it
421 will re-allocate memory internally and copy the existing data to this new area,
422 so it will then stop directly addressing this memory.
423
424 @param dataToReferTo a pre-allocated array containing pointers to the data
425 for each channel that should be used by this buffer. The
426 buffer will only refer to this memory, it won't try to delete
427 it when the buffer is deleted or resized.
428 @param newNumChannels the number of channels to use - this must correspond to the
429 number of elements in the array passed in
430 @param newStartSample the offset within the arrays at which the data begins
431 @param newNumSamples the number of samples to use - this must correspond to the
432 size of the arrays passed in
433 */
435 int newNumChannels,
436 int newStartSample,
437 int newNumSamples)
438 {
439 jassert (dataToReferTo != nullptr);
440 jassert (newNumChannels >= 0 && newNumSamples >= 0);
441
442 if (allocatedBytes != 0)
443 {
444 allocatedBytes = 0;
445 allocatedData.free();
446 }
447
448 numChannels = newNumChannels;
449 size = newNumSamples;
450
451 allocateChannels (dataToReferTo, newStartSample);
452 jassert (! isClear);
453 }
454
455 /** Makes this buffer point to a pre-allocated set of channel data arrays.
456
457 There's also a constructor that lets you specify arrays like this, but this
458 lets you change the channels dynamically.
459
460 Note that if the buffer is resized or its number of channels is changed, it
461 will re-allocate memory internally and copy the existing data to this new area,
462 so it will then stop directly addressing this memory.
463
464 @param dataToReferTo a pre-allocated array containing pointers to the data
465 for each channel that should be used by this buffer. The
466 buffer will only refer to this memory, it won't try to delete
467 it when the buffer is deleted or resized.
468 @param newNumChannels the number of channels to use - this must correspond to the
469 number of elements in the array passed in
470 @param newNumSamples the number of samples to use - this must correspond to the
471 size of the arrays passed in
472 */
479
480 /** Resizes this buffer to match the given one, and copies all of its content across.
481 The source buffer can contain a different floating point type, so this can be used to
482 convert between 32 and 64 bit float buffer types.
483 */
484 template <typename OtherType>
486 {
487 setSize (other.getNumChannels(), other.getNumSamples(), false, false, avoidReallocating);
488
489 if (other.hasBeenCleared())
490 {
491 clear();
492 }
493 else
494 {
495 isClear = false;
496
497 for (int chan = 0; chan < numChannels; ++chan)
498 {
499 auto* dest = channels[chan];
500 auto* src = other.getReadPointer (chan);
501
502 for (int i = 0; i < size; ++i)
503 dest[i] = static_cast<Type> (src[i]);
504 }
505 }
506 }
507
508 //==============================================================================
509 /** Clears all the samples in all channels. */
511 {
512 if (! isClear)
513 {
514 for (int i = 0; i < numChannels; ++i)
515 FloatVectorOperations::clear (channels[i], size);
516
517 isClear = true;
518 }
519 }
520
521 /** Clears a specified region of all the channels.
522
523 For speed, this doesn't check whether the channel and sample number
524 are in-range, so be careful!
525 */
526 void clear (int startSample, int numSamples) noexcept
527 {
528 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
529
530 if (! isClear)
531 {
532 if (startSample == 0 && numSamples == size)
533 isClear = true;
534
535 for (int i = 0; i < numChannels; ++i)
536 FloatVectorOperations::clear (channels[i] + startSample, numSamples);
537 }
538 }
539
540 /** Clears a specified region of just one channel.
541
542 For speed, this doesn't check whether the channel and sample number
543 are in-range, so be careful!
544 */
545 void clear (int channel, int startSample, int numSamples) noexcept
546 {
547 jassert (isPositiveAndBelow (channel, numChannels));
548 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
549
550 if (! isClear)
551 FloatVectorOperations::clear (channels[channel] + startSample, numSamples);
552 }
553
554 /** Returns true if the buffer has been entirely cleared.
555 Note that this does not actually measure the contents of the buffer - it simply
556 returns a flag that is set when the buffer is cleared, and which is reset whenever
557 functions like getWritePointer() are invoked. That means the method does not take
558 any time, but it may return false negatives when in fact the buffer is still empty.
559 */
560 bool hasBeenCleared() const noexcept { return isClear; }
561
562 //==============================================================================
563 /** Returns a sample from the buffer.
564 The channel and index are not checked - they are expected to be in-range. If not,
565 an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
566 territory.
567 */
568 Type getSample (int channel, int sampleIndex) const noexcept
569 {
570 jassert (isPositiveAndBelow (channel, numChannels));
571 jassert (isPositiveAndBelow (sampleIndex, size));
572 return *(channels[channel] + sampleIndex);
573 }
574
575 /** Sets a sample in the buffer.
576 The channel and index are not checked - they are expected to be in-range. If not,
577 an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
578 territory.
579 */
580 void setSample (int destChannel, int destSample, Type newValue) noexcept
581 {
582 jassert (isPositiveAndBelow (destChannel, numChannels));
583 jassert (isPositiveAndBelow (destSample, size));
584 *(channels[destChannel] + destSample) = newValue;
585 isClear = false;
586 }
587
588 /** Adds a value to a sample in the buffer.
589 The channel and index are not checked - they are expected to be in-range. If not,
590 an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
591 territory.
592 */
593 void addSample (int destChannel, int destSample, Type valueToAdd) noexcept
594 {
595 jassert (isPositiveAndBelow (destChannel, numChannels));
596 jassert (isPositiveAndBelow (destSample, size));
597 *(channels[destChannel] + destSample) += valueToAdd;
598 isClear = false;
599 }
600
601 /** Applies a gain multiple to a region of one channel.
602
603 For speed, this doesn't check whether the channel and sample number
604 are in-range, so be careful!
605 */
606 void applyGain (int channel, int startSample, int numSamples, Type gain) noexcept
607 {
608 jassert (isPositiveAndBelow (channel, numChannels));
609 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
610
611 if (gain != Type (1) && ! isClear)
612 {
613 auto* d = channels[channel] + startSample;
614
615 if (gain == Type())
616 FloatVectorOperations::clear (d, numSamples);
617 else
618 FloatVectorOperations::multiply (d, gain, numSamples);
619 }
620 }
621
622 /** Applies a gain multiple to a region of all the channels.
623
624 For speed, this doesn't check whether the sample numbers
625 are in-range, so be careful!
626 */
627 void applyGain (int startSample, int numSamples, Type gain) noexcept
628 {
629 for (int i = 0; i < numChannels; ++i)
630 applyGain (i, startSample, numSamples, gain);
631 }
632
633 /** Applies a gain multiple to all the audio data. */
634 void applyGain (Type gain) noexcept
635 {
636 applyGain (0, size, gain);
637 }
638
639 /** Applies a range of gains to a region of a channel.
640
641 The gain that is applied to each sample will vary from
642 startGain on the first sample to endGain on the last Sample,
643 so it can be used to do basic fades.
644
645 For speed, this doesn't check whether the sample numbers
646 are in-range, so be careful!
647 */
648 void applyGainRamp (int channel, int startSample, int numSamples,
649 Type startGain, Type endGain) noexcept
650 {
651 if (! isClear)
652 {
653 if (startGain == endGain)
654 {
655 applyGain (channel, startSample, numSamples, startGain);
656 }
657 else
658 {
659 jassert (isPositiveAndBelow (channel, numChannels));
660 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
661
662 const auto increment = (endGain - startGain) / (float) numSamples;
663 auto* d = channels[channel] + startSample;
664
665 while (--numSamples >= 0)
666 {
667 *d++ *= startGain;
669 }
670 }
671 }
672 }
673
674 /** Applies a range of gains to a region of all channels.
675
676 The gain that is applied to each sample will vary from
677 startGain on the first sample to endGain on the last Sample,
678 so it can be used to do basic fades.
679
680 For speed, this doesn't check whether the sample numbers
681 are in-range, so be careful!
682 */
683 void applyGainRamp (int startSample, int numSamples,
684 Type startGain, Type endGain) noexcept
685 {
686 for (int i = 0; i < numChannels; ++i)
687 applyGainRamp (i, startSample, numSamples, startGain, endGain);
688 }
689
690 /** Adds samples from another buffer to this one.
691
692 @param destChannel the channel within this buffer to add the samples to
693 @param destStartSample the start sample within this buffer's channel
694 @param source the source buffer to add from
695 @param sourceChannel the channel within the source buffer to read from
696 @param sourceStartSample the offset within the source buffer's channel to start reading samples from
697 @param numSamples the number of samples to process
698 @param gainToApplyToSource an optional gain to apply to the source samples before they are
699 added to this buffer's samples
700
701 @see copyFrom
702 */
704 int destStartSample,
705 const AudioBuffer& source,
706 int sourceChannel,
708 int numSamples,
709 Type gainToApplyToSource = Type (1)) noexcept
710 {
711 jassert (&source != this || sourceChannel != destChannel);
712 jassert (isPositiveAndBelow (destChannel, numChannels));
713 jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size);
714 jassert (isPositiveAndBelow (sourceChannel, source.numChannels));
715 jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size);
716
717 if (gainToApplyToSource != 0 && numSamples > 0 && ! source.isClear)
718 {
719 auto* d = channels[destChannel] + destStartSample;
720 auto* s = source.channels[sourceChannel] + sourceStartSample;
721
722 if (isClear)
723 {
724 isClear = false;
725
726 if (gainToApplyToSource != Type (1))
728 else
729 FloatVectorOperations::copy (d, s, numSamples);
730 }
731 else
732 {
733 if (gainToApplyToSource != Type (1))
735 else
736 FloatVectorOperations::add (d, s, numSamples);
737 }
738 }
739 }
740
741 /** Adds samples from an array of floats to one of the channels.
742
743 @param destChannel the channel within this buffer to add the samples to
744 @param destStartSample the start sample within this buffer's channel
745 @param source the source data to use
746 @param numSamples the number of samples to process
747 @param gainToApplyToSource an optional gain to apply to the source samples before they are
748 added to this buffer's samples
749
750 @see copyFrom
751 */
753 int destStartSample,
754 const Type* source,
755 int numSamples,
756 Type gainToApplyToSource = Type (1)) noexcept
757 {
758 jassert (isPositiveAndBelow (destChannel, numChannels));
759 jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size);
760 jassert (source != nullptr);
761
762 if (gainToApplyToSource != 0 && numSamples > 0)
763 {
764 auto* d = channels[destChannel] + destStartSample;
765
766 if (isClear)
767 {
768 isClear = false;
769
770 if (gainToApplyToSource != Type (1))
772 else
773 FloatVectorOperations::copy (d, source, numSamples);
774 }
775 else
776 {
777 if (gainToApplyToSource != Type (1))
779 else
780 FloatVectorOperations::add (d, source, numSamples);
781 }
782 }
783 }
784
785
786 /** Adds samples from an array of floats, applying a gain ramp to them.
787
788 @param destChannel the channel within this buffer to add the samples to
789 @param destStartSample the start sample within this buffer's channel
790 @param source the source data to use
791 @param numSamples the number of samples to process
792 @param startGain the gain to apply to the first sample (this is multiplied with
793 the source samples before they are added to this buffer)
794 @param endGain the gain to apply to the final sample. The gain is linearly
795 interpolated between the first and last samples.
796 */
798 int destStartSample,
799 const Type* source,
800 int numSamples,
801 Type startGain,
802 Type endGain) noexcept
803 {
804 if (startGain == endGain)
805 {
806 addFrom (destChannel, destStartSample, source, numSamples, startGain);
807 }
808 else
809 {
810 jassert (isPositiveAndBelow (destChannel, numChannels));
811 jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size);
812 jassert (source != nullptr);
813
814 if (numSamples > 0)
815 {
816 isClear = false;
817 const auto increment = (endGain - startGain) / numSamples;
818 auto* d = channels[destChannel] + destStartSample;
819
820 while (--numSamples >= 0)
821 {
822 *d++ += startGain * *source++;
824 }
825 }
826 }
827 }
828
829 /** Copies samples from another buffer to this one.
830
831 @param destChannel the channel within this buffer to copy the samples to
832 @param destStartSample the start sample within this buffer's channel
833 @param source the source buffer to read from
834 @param sourceChannel the channel within the source buffer to read from
835 @param sourceStartSample the offset within the source buffer's channel to start reading samples from
836 @param numSamples the number of samples to process
837
838 @see addFrom
839 */
841 int destStartSample,
842 const AudioBuffer& source,
843 int sourceChannel,
845 int numSamples) noexcept
846 {
847 jassert (&source != this || sourceChannel != destChannel);
848 jassert (isPositiveAndBelow (destChannel, numChannels));
849 jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
850 jassert (isPositiveAndBelow (sourceChannel, source.numChannels));
851 jassert (sourceStartSample >= 0 && numSamples >= 0 && sourceStartSample + numSamples <= source.size);
852
853 if (numSamples > 0)
854 {
855 if (source.isClear)
856 {
857 if (! isClear)
859 }
860 else
861 {
862 isClear = false;
864 source.channels[sourceChannel] + sourceStartSample,
865 numSamples);
866 }
867 }
868 }
869
870 /** Copies samples from an array of floats into one of the channels.
871
872 @param destChannel the channel within this buffer to copy the samples to
873 @param destStartSample the start sample within this buffer's channel
874 @param source the source buffer to read from
875 @param numSamples the number of samples to process
876
877 @see addFrom
878 */
880 int destStartSample,
881 const Type* source,
882 int numSamples) noexcept
883 {
884 jassert (isPositiveAndBelow (destChannel, numChannels));
885 jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size);
886 jassert (source != nullptr);
887
888 if (numSamples > 0)
889 {
890 isClear = false;
891 FloatVectorOperations::copy (channels[destChannel] + destStartSample, source, numSamples);
892 }
893 }
894
895 /** Copies samples from an array of floats into one of the channels, applying a gain to it.
896
897 @param destChannel the channel within this buffer to copy the samples to
898 @param destStartSample the start sample within this buffer's channel
899 @param source the source buffer to read from
900 @param numSamples the number of samples to process
901 @param gain the gain to apply
902
903 @see addFrom
904 */
906 int destStartSample,
907 const Type* source,
908 int numSamples,
909 Type gain) noexcept
910 {
911 jassert (isPositiveAndBelow (destChannel, numChannels));
912 jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size);
913 jassert (source != nullptr);
914
915 if (numSamples > 0)
916 {
917 auto* d = channels[destChannel] + destStartSample;
918
919 if (gain != Type (1))
920 {
921 if (gain == Type())
922 {
923 if (! isClear)
924 FloatVectorOperations::clear (d, numSamples);
925 }
926 else
927 {
928 isClear = false;
929 FloatVectorOperations::copyWithMultiply (d, source, gain, numSamples);
930 }
931 }
932 else
933 {
934 isClear = false;
935 FloatVectorOperations::copy (d, source, numSamples);
936 }
937 }
938 }
939
940 /** Copies samples from an array of floats into one of the channels, applying a gain ramp.
941
942 @param destChannel the channel within this buffer to copy the samples to
943 @param destStartSample the start sample within this buffer's channel
944 @param source the source buffer to read from
945 @param numSamples the number of samples to process
946 @param startGain the gain to apply to the first sample (this is multiplied with
947 the source samples before they are copied to this buffer)
948 @param endGain the gain to apply to the final sample. The gain is linearly
949 interpolated between the first and last samples.
950
951 @see addFrom
952 */
954 int destStartSample,
955 const Type* source,
956 int numSamples,
957 Type startGain,
958 Type endGain) noexcept
959 {
960 if (startGain == endGain)
961 {
962 copyFrom (destChannel, destStartSample, source, numSamples, startGain);
963 }
964 else
965 {
966 jassert (isPositiveAndBelow (destChannel, numChannels));
967 jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size);
968 jassert (source != nullptr);
969
970 if (numSamples > 0)
971 {
972 isClear = false;
973 const auto increment = (endGain - startGain) / numSamples;
974 auto* d = channels[destChannel] + destStartSample;
975
976 while (--numSamples >= 0)
977 {
978 *d++ = startGain * *source++;
980 }
981 }
982 }
983 }
984
985 /** Returns a Range indicating the lowest and highest sample values in a given section.
986
987 @param channel the channel to read from
988 @param startSample the start sample within the channel
989 @param numSamples the number of samples to check
990 */
991 Range<Type> findMinMax (int channel, int startSample, int numSamples) const noexcept
992 {
993 jassert (isPositiveAndBelow (channel, numChannels));
994 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
995
996 if (isClear)
997 return { Type (0), Type (0) };
998
999 return FloatVectorOperations::findMinAndMax (channels[channel] + startSample, numSamples);
1000 }
1001
1002 /** Finds the highest absolute sample value within a region of a channel. */
1003 Type getMagnitude (int channel, int startSample, int numSamples) const noexcept
1004 {
1005 jassert (isPositiveAndBelow (channel, numChannels));
1006 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
1007
1008 if (isClear)
1009 return Type (0);
1010
1011 auto r = findMinMax (channel, startSample, numSamples);
1012
1013 return jmax (r.getStart(), -r.getStart(), r.getEnd(), -r.getEnd());
1014 }
1015
1016 /** Finds the highest absolute sample value within a region on all channels. */
1017 Type getMagnitude (int startSample, int numSamples) const noexcept
1018 {
1019 Type mag (0);
1020
1021 if (! isClear)
1022 for (int i = 0; i < numChannels; ++i)
1023 mag = jmax (mag, getMagnitude (i, startSample, numSamples));
1024
1025 return mag;
1026 }
1027
1028 /** Returns the root mean squared level for a region of a channel. */
1029 Type getRMSLevel (int channel, int startSample, int numSamples) const noexcept
1030 {
1031 jassert (isPositiveAndBelow (channel, numChannels));
1032 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
1033
1034 if (numSamples <= 0 || channel < 0 || channel >= numChannels || isClear)
1035 return Type (0);
1036
1037 auto* data = channels[channel] + startSample;
1038 double sum = 0.0;
1039
1040 for (int i = 0; i < numSamples; ++i)
1041 {
1042 auto sample = data[i];
1043 sum += sample * sample;
1044 }
1045
1046 return static_cast<Type> (std::sqrt (sum / numSamples));
1047 }
1048
1049 /** Reverses a part of a channel. */
1050 void reverse (int channel, int startSample, int numSamples) const noexcept
1051 {
1052 jassert (isPositiveAndBelow (channel, numChannels));
1053 jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
1054
1055 if (! isClear)
1056 std::reverse (channels[channel] + startSample,
1057 channels[channel] + startSample + numSamples);
1058 }
1059
1060 /** Reverses a part of the buffer. */
1061 void reverse (int startSample, int numSamples) const noexcept
1062 {
1063 for (int i = 0; i < numChannels; ++i)
1064 reverse (i, startSample, numSamples);
1065 }
1066
1067 //==============================================================================
1068 /** This allows templated code that takes an AudioBuffer to access its sample type. */
1069 using SampleType = Type;
1070
1071private:
1072 //==============================================================================
1073 int numChannels = 0, size = 0;
1074 size_t allocatedBytes = 0;
1075 Type** channels;
1076 HeapBlock<char, true> allocatedData;
1077 Type* preallocatedChannelSpace[32];
1078 bool isClear = false;
1079
1080 void allocateData()
1081 {
1082 jassert (size >= 0);
1083 auto channelListSize = sizeof (Type*) * (size_t) (numChannels + 1);
1084 allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (Type) + channelListSize + 32;
1085 allocatedData.malloc (allocatedBytes);
1086 channels = reinterpret_cast<Type**> (allocatedData.get());
1087 auto chan = reinterpret_cast<Type*> (allocatedData + channelListSize);
1088
1089 for (int i = 0; i < numChannels; ++i)
1090 {
1091 channels[i] = chan;
1092 chan += size;
1093 }
1094
1095 channels[numChannels] = nullptr;
1096 isClear = false;
1097 }
1098
1099 void allocateChannels (Type* const* dataToReferTo, int offset)
1100 {
1101 jassert (offset >= 0);
1102
1103 // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools)
1104 if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
1105 {
1106 channels = static_cast<Type**> (preallocatedChannelSpace);
1107 }
1108 else
1109 {
1110 allocatedData.malloc (numChannels + 1, sizeof (Type*));
1111 channels = reinterpret_cast<Type**> (allocatedData.get());
1112 }
1113
1114 for (int i = 0; i < numChannels; ++i)
1115 {
1116 // you have to pass in the same number of valid pointers as numChannels
1117 jassert (dataToReferTo[i] != nullptr);
1118 channels[i] = dataToReferTo[i] + offset;
1119 }
1120
1121 channels[numChannels] = nullptr;
1122 isClear = false;
1123 }
1124
1125 JUCE_LEAK_DETECTOR (AudioBuffer)
1126};
1127
1128//==============================================================================
1129/**
1130 A multi-channel buffer of 32-bit floating point audio samples.
1131
1132 This type is here for backwards compatibility with the older AudioSampleBuffer
1133 class, which was fixed for 32-bit data, but is otherwise the same as the new
1134 templated AudioBuffer class.
1135
1136 @see AudioBuffer
1137*/
1138using AudioSampleBuffer = AudioBuffer<float>;
1139
1140} // namespace juce
1141
1142/** @}*/
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:60
int size() const noexcept
Returns the current number of elements in the array.
Definition juce_Array.h:219
A multi-channel buffer containing floating point audio samples.
AudioBuffer(Type *const *dataToReferTo, int numChannelsToUse, int startSample, int numSamples)
Creates a buffer using a pre-allocated block of memory.
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
Changes the buffer's size or number of channels.
Type getMagnitude(int channel, int startSample, int numSamples) const noexcept
Finds the highest absolute sample value within a region of a channel.
AudioBuffer(Type *const *dataToReferTo, int numChannelsToUse, int numSamples)
Creates a buffer using a pre-allocated block of memory.
Type getSample(int channel, int sampleIndex) const noexcept
Returns a sample from the buffer.
void applyGain(Type gain) noexcept
Applies a gain multiple to all the audio data.
Range< Type > findMinMax(int channel, int startSample, int numSamples) const noexcept
Returns a Range indicating the lowest and highest sample values in a given section.
AudioBuffer(const AudioBuffer &other)
Copies another buffer.
const Type * getReadPointer(int channelNumber, int sampleIndex) const noexcept
Returns a pointer to an array of read-only samples in one of the buffer's channels.
void makeCopyOf(const AudioBuffer< OtherType > &other, bool avoidReallocating=false)
Resizes this buffer to match the given one, and copies all of its content across.
void applyGain(int startSample, int numSamples, Type gain) noexcept
Applies a gain multiple to a region of all the channels.
void setDataToReferTo(Type **dataToReferTo, int newNumChannels, int newNumSamples)
Makes this buffer point to a pre-allocated set of channel data arrays.
void copyFromWithRamp(int destChannel, int destStartSample, const Type *source, int numSamples, Type startGain, Type endGain) noexcept
Copies samples from an array of floats into one of the channels, applying a gain ramp.
void addSample(int destChannel, int destSample, Type valueToAdd) noexcept
Adds a value to a sample in the buffer.
Type getRMSLevel(int channel, int startSample, int numSamples) const noexcept
Returns the root mean squared level for a region of a channel.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
void copyFrom(int destChannel, int destStartSample, const Type *source, int numSamples) noexcept
Copies samples from an array of floats into one of the channels.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
Type * getWritePointer(int channelNumber, int sampleIndex) noexcept
Returns a writeable pointer to one of the buffer's channels.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
void clear() noexcept
Clears all the samples in all channels.
void clear(int channel, int startSample, int numSamples) noexcept
Clears a specified region of just one channel.
void copyFrom(int destChannel, int destStartSample, const Type *source, int numSamples, Type gain) noexcept
Copies samples from an array of floats into one of the channels, applying a gain to it.
~AudioBuffer()=default
Destructor.
void applyGainRamp(int channel, int startSample, int numSamples, Type startGain, Type endGain) noexcept
Applies a range of gains to a region of a channel.
void setDataToReferTo(Type **dataToReferTo, int newNumChannels, int newStartSample, int newNumSamples)
Makes this buffer point to a pre-allocated set of channel data arrays.
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
Copies samples from another buffer to this one.
void reverse(int startSample, int numSamples) const noexcept
Reverses a part of the buffer.
void addFromWithRamp(int destChannel, int destStartSample, const Type *source, int numSamples, Type startGain, Type endGain) noexcept
Adds samples from an array of floats, applying a gain ramp to them.
Type getMagnitude(int startSample, int numSamples) const noexcept
Finds the highest absolute sample value within a region on all channels.
void reverse(int channel, int startSample, int numSamples) const noexcept
Reverses a part of a channel.
void setSample(int destChannel, int destSample, Type newValue) noexcept
Sets a sample in the buffer.
void addFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples, Type gainToApplyToSource=Type(1)) noexcept
Adds samples from another buffer to this one.
bool hasBeenCleared() const noexcept
Returns true if the buffer has been entirely cleared.
const Type * getReadPointer(int channelNumber) const noexcept
Returns a pointer to an array of read-only samples in one of the buffer's channels.
AudioBuffer & operator=(const AudioBuffer &other)
Copies another buffer onto this one.
AudioBuffer(AudioBuffer &&other) noexcept
Move constructor.
Type SampleType
This allows templated code that takes an AudioBuffer to access its sample type.
AudioBuffer() noexcept
Creates an empty buffer with 0 channels and 0 length.
void clear(int startSample, int numSamples) noexcept
Clears a specified region of all the channels.
const Type ** getArrayOfReadPointers() const noexcept
Returns an array of pointers to the channels in the buffer.
AudioBuffer(int numChannelsToAllocate, int numSamplesToAllocate)
Creates a buffer with a specified number of channels and samples.
void addFrom(int destChannel, int destStartSample, const Type *source, int numSamples, Type gainToApplyToSource=Type(1)) noexcept
Adds samples from an array of floats to one of the channels.
void applyGainRamp(int startSample, int numSamples, Type startGain, Type endGain) noexcept
Applies a range of gains to a region of all channels.
Type ** getArrayOfWritePointers() noexcept
Returns an array of pointers to the channels in the buffer.
void applyGain(int channel, int startSample, int numSamples, Type gain) noexcept
Applies a gain multiple to a region of one channel.
static void JUCE_CALLTYPE multiply(float *dest, const float *src, int numValues) noexcept
Multiplies the destination values by the source values.
static void JUCE_CALLTYPE clear(float *dest, int numValues) noexcept
Clears a vector of floats.
static void JUCE_CALLTYPE copyWithMultiply(float *dest, const float *src, float multiplier, int numValues) noexcept
Copies a vector of floats, multiplying each value by a given multiplier.
static void JUCE_CALLTYPE copy(float *dest, const float *src, int numValues) noexcept
Copies a vector of floats.
static void JUCE_CALLTYPE addWithMultiply(float *dest, const float *src, float multiplier, int numValues) noexcept
Multiplies each source value by the given multiplier, then adds it to the destination value.
static Range< float > JUCE_CALLTYPE findMinAndMax(const float *src, int numValues) noexcept
Finds the minimum and maximum values in the given array.
static void JUCE_CALLTYPE add(float *dest, float amountToAdd, int numValues) noexcept
Adds a fixed value to the destination values.
void clear(SizeType numElements) noexcept
This fills the block with zeros, up to the number of elements specified.
void swapWith(HeapBlock< ElementType, otherBlockThrows > &other) noexcept
Swaps this object's data with the data of another HeapBlock.
ElementType * get() const noexcept
Returns a raw pointer to the allocated data.
void allocate(SizeType newNumElements, bool initialiseToZero)
Allocates a specified amount of memory and optionally clears it.
void free() noexcept
Frees any currently-allocated data.