2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
20 ==============================================================================
26 //==============================================================================
28 A multi-channel buffer containing floating point audio samples.
32 template <typename Type
>
36 //==============================================================================
37 /** Creates an empty buffer with 0 channels and 0 length. */
38 AudioBuffer() noexcept
39 : channels (static_cast<Type
**> (preallocatedChannelSpace
))
43 //==============================================================================
44 /** Creates a buffer with a specified number of channels and samples.
46 The contents of the buffer will initially be undefined, so use clear() to
47 set all the samples to zero.
49 The buffer will allocate its memory internally, and this will be released
50 when the buffer is deleted. If the memory can't be allocated, this will
51 throw a std::bad_alloc exception.
53 AudioBuffer (int numChannelsToAllocate
,
54 int numSamplesToAllocate
)
55 : numChannels (numChannelsToAllocate
),
56 size (numSamplesToAllocate
)
58 jassert (size
>= 0 && numChannels
>= 0);
62 /** Creates a buffer using a pre-allocated block of memory.
64 Note that if the buffer is resized or its number of channels is changed, it
65 will re-allocate memory internally and copy the existing data to this new area,
66 so it will then stop directly addressing this memory.
68 @param dataToReferTo a pre-allocated array containing pointers to the data
69 for each channel that should be used by this buffer. The
70 buffer will only refer to this memory, it won't try to delete
71 it when the buffer is deleted or resized.
72 @param numChannelsToUse the number of channels to use - this must correspond to the
73 number of elements in the array passed in
74 @param numSamples the number of samples to use - this must correspond to the
75 size of the arrays passed in
77 AudioBuffer (Type
* const* dataToReferTo
,
80 : numChannels (numChannelsToUse
),
83 jassert (dataToReferTo
!= nullptr);
84 jassert (numChannelsToUse
>= 0 && numSamples
>= 0);
85 allocateChannels (dataToReferTo
, 0);
88 /** Creates a buffer using a pre-allocated block of memory.
90 Note that if the buffer is resized or its number of channels is changed, it
91 will re-allocate memory internally and copy the existing data to this new area,
92 so it will then stop directly addressing this memory.
94 @param dataToReferTo a pre-allocated array containing pointers to the data
95 for each channel that should be used by this buffer. The
96 buffer will only refer to this memory, it won't try to delete
97 it when the buffer is deleted or resized.
98 @param numChannelsToUse the number of channels to use - this must correspond to the
99 number of elements in the array passed in
100 @param startSample the offset within the arrays at which the data begins
101 @param numSamples the number of samples to use - this must correspond to the
102 size of the arrays passed in
104 AudioBuffer (Type
* const* dataToReferTo
,
105 int numChannelsToUse
,
108 : numChannels (numChannelsToUse
),
111 jassert (dataToReferTo
!= nullptr);
112 jassert (numChannelsToUse
>= 0 && startSample
>= 0 && numSamples
>= 0);
113 allocateChannels (dataToReferTo
, startSample
);
116 /** Copies another buffer.
118 This buffer will make its own copy of the other's data, unless the buffer was created
119 using an external data buffer, in which case both buffers will just point to the same
120 shared block of data.
122 AudioBuffer (const AudioBuffer
& other
)
123 : numChannels (other
.numChannels
),
125 allocatedBytes (other
.allocatedBytes
)
127 if (allocatedBytes
== 0)
129 allocateChannels (other
.channels
, 0);
141 for (int i
= 0; i
< numChannels
; ++i
)
142 FloatVectorOperations::copy (channels
[i
], other
.channels
[i
], size
);
147 /** Copies another buffer onto this one.
149 This buffer's size will be changed to that of the other buffer.
151 AudioBuffer
& operator= (const AudioBuffer
& other
)
155 setSize (other
.getNumChannels(), other
.getNumSamples(), false, false, false);
165 for (int i
= 0; i
< numChannels
; ++i
)
166 FloatVectorOperations::copy (channels
[i
], other
.channels
[i
], size
);
175 This will free any memory allocated by the buffer.
177 ~AudioBuffer() = default;
179 /** Move constructor. */
180 AudioBuffer (AudioBuffer
&& other
) noexcept
181 : numChannels (other
.numChannels
),
183 allocatedBytes (other
.allocatedBytes
),
184 allocatedData (std::move (other
.allocatedData
)),
185 isClear (other
.isClear
)
187 if (numChannels
< (int) numElementsInArray (preallocatedChannelSpace
))
189 channels
= preallocatedChannelSpace
;
191 for (int i
= 0; i
< numChannels
; ++i
)
192 preallocatedChannelSpace
[i
] = other
.channels
[i
];
196 channels
= other
.channels
;
199 other
.numChannels
= 0;
201 other
.allocatedBytes
= 0;
204 /** Move assignment. */
205 AudioBuffer
& operator= (AudioBuffer
&& other
) noexcept
207 numChannels
= other
.numChannels
;
209 allocatedBytes
= other
.allocatedBytes
;
210 allocatedData
= std::move (other
.allocatedData
);
211 isClear
= other
.isClear
;
213 if (numChannels
< (int) numElementsInArray (preallocatedChannelSpace
))
215 channels
= preallocatedChannelSpace
;
217 for (int i
= 0; i
< numChannels
; ++i
)
218 preallocatedChannelSpace
[i
] = other
.channels
[i
];
222 channels
= other
.channels
;
225 other
.numChannels
= 0;
227 other
.allocatedBytes
= 0;
231 //==============================================================================
232 /** Returns the number of channels of audio data that this buffer contains.
234 @see getNumSamples, getReadPointer, getWritePointer
236 int getNumChannels() const noexcept
{ return numChannels
; }
238 /** Returns the number of samples allocated in each of the buffer's channels.
240 @see getNumChannels, getReadPointer, getWritePointer
242 int getNumSamples() const noexcept
{ return size
; }
244 /** Returns a pointer to an array of read-only samples in one of the buffer's channels.
246 For speed, this doesn't check whether the channel number is out of range,
247 so be careful when using it!
249 If you need to write to the data, do NOT call this method and const_cast the
250 result! Instead, you must call getWritePointer so that the buffer knows you're
251 planning on modifying the data.
253 const Type
* getReadPointer (int channelNumber
) const noexcept
255 jassert (isPositiveAndBelow (channelNumber
, numChannels
));
256 return channels
[channelNumber
];
259 /** Returns a pointer to an array of read-only samples in one of the buffer's channels.
261 For speed, this doesn't check whether the channel number or index are out of range,
262 so be careful when using it!
264 If you need to write to the data, do NOT call this method and const_cast the
265 result! Instead, you must call getWritePointer so that the buffer knows you're
266 planning on modifying the data.
268 const Type
* getReadPointer (int channelNumber
, int sampleIndex
) const noexcept
270 jassert (isPositiveAndBelow (channelNumber
, numChannels
));
271 jassert (isPositiveAndBelow (sampleIndex
, size
));
272 return channels
[channelNumber
] + sampleIndex
;
275 /** Returns a writeable pointer to one of the buffer's channels.
277 For speed, this doesn't check whether the channel number is out of range,
278 so be careful when using it!
280 Note that if you're not planning on writing to the data, you should always
281 use getReadPointer instead.
283 This will mark the buffer as not cleared and the hasBeenCleared method will return
284 false after this call. If you retain this write pointer and write some data to
285 the buffer after calling its clear method, subsequent clear calls will do nothing.
286 To avoid this either call this method each time you need to write data, or use the
287 setNotClear method to force the internal cleared flag to false.
291 Type
* getWritePointer (int channelNumber
) noexcept
293 jassert (isPositiveAndBelow (channelNumber
, numChannels
));
295 return channels
[channelNumber
];
298 /** Returns a writeable pointer to one of the buffer's channels.
300 For speed, this doesn't check whether the channel number or index are out of range,
301 so be careful when using it!
303 Note that if you're not planning on writing to the data, you should
304 use getReadPointer instead.
306 This will mark the buffer as not cleared and the hasBeenCleared method will return
307 false after this call. If you retain this write pointer and write some data to
308 the buffer after calling its clear method, subsequent clear calls will do nothing.
309 To avoid this either call this method each time you need to write data, or use the
310 setNotClear method to force the internal cleared flag to false.
314 Type
* getWritePointer (int channelNumber
, int sampleIndex
) noexcept
316 jassert (isPositiveAndBelow (channelNumber
, numChannels
));
317 jassert (isPositiveAndBelow (sampleIndex
, size
));
319 return channels
[channelNumber
] + sampleIndex
;
322 /** Returns an array of pointers to the channels in the buffer.
324 Don't modify any of the pointers that are returned, and bear in mind that
325 these will become invalid if the buffer is resized.
327 const Type
** getArrayOfReadPointers() const noexcept
{ return const_cast<const Type
**> (channels
); }
329 /** Returns an array of pointers to the channels in the buffer.
331 Don't modify any of the pointers that are returned, and bear in mind that
332 these will become invalid if the buffer is resized.
334 This will mark the buffer as not cleared and the hasBeenCleared method will return
335 false after this call. If you retain this write pointer and write some data to
336 the buffer after calling its clear method, subsequent clear calls will do nothing.
337 To avoid this either call this method each time you need to write data, or use the
338 setNotClear method to force the internal cleared flag to false.
342 Type
** getArrayOfWritePointers() noexcept
{ isClear
= false; return channels
; }
344 //==============================================================================
345 /** Changes the buffer's size or number of channels.
347 This can expand or contract the buffer's length, and add or remove channels.
349 Note that if keepExistingContent and avoidReallocating are both true, then it will
350 only avoid reallocating if neither the channel count or length in samples increase.
352 If the required memory can't be allocated, this will throw a std::bad_alloc exception.
354 @param newNumChannels the new number of channels.
355 @param newNumSamples the new number of samples.
356 @param keepExistingContent if this is true, it will try to preserve as much of the
357 old data as it can in the new buffer.
358 @param clearExtraSpace if this is true, then any extra channels or space that is
359 allocated will be also be cleared. If false, then this space is left
361 @param avoidReallocating if this is true, then changing the buffer's size won't reduce the
362 amount of memory that is currently allocated (but it will still
363 increase it if the new size is bigger than the amount it currently has).
364 If this is false, then a new allocation will be done so that the buffer
365 uses takes up the minimum amount of memory that it needs.
367 void setSize (int newNumChannels
,
369 bool keepExistingContent
= false,
370 bool clearExtraSpace
= false,
371 bool avoidReallocating
= false)
373 jassert (newNumChannels
>= 0);
374 jassert (newNumSamples
>= 0);
376 if (newNumSamples
!= size
|| newNumChannels
!= numChannels
)
378 auto allocatedSamplesPerChannel
= ((size_t) newNumSamples
+ 3) & ~3u;
379 auto channelListSize
= ((static_cast<size_t> (1 + newNumChannels
) * sizeof (Type
*)) + 15) & ~15u;
380 auto newTotalBytes
= ((size_t) newNumChannels
* (size_t) allocatedSamplesPerChannel
* sizeof (Type
))
381 + channelListSize
+ 32;
383 if (keepExistingContent
)
385 if (avoidReallocating
&& newNumChannels
<= numChannels
&& newNumSamples
<= size
)
387 // no need to do any remapping in this case, as the channel pointers will remain correct!
391 HeapBlock
<char, true> newData
;
392 newData
.allocate (newTotalBytes
, clearExtraSpace
|| isClear
);
394 auto numSamplesToCopy
= (size_t) jmin (newNumSamples
, size
);
396 auto newChannels
= unalignedPointerCast
<Type
**> (newData
.get());
397 auto newChan
= unalignedPointerCast
<Type
*> (newData
+ channelListSize
);
399 for (int j
= 0; j
< newNumChannels
; ++j
)
401 newChannels
[j
] = newChan
;
402 newChan
+= allocatedSamplesPerChannel
;
407 auto numChansToCopy
= jmin (numChannels
, newNumChannels
);
409 for (int i
= 0; i
< numChansToCopy
; ++i
)
410 FloatVectorOperations::copy (newChannels
[i
], channels
[i
], (int) numSamplesToCopy
);
413 allocatedData
.swapWith (newData
);
414 allocatedBytes
= newTotalBytes
;
415 channels
= newChannels
;
420 if (avoidReallocating
&& allocatedBytes
>= newTotalBytes
)
422 if (clearExtraSpace
|| isClear
)
423 allocatedData
.clear (newTotalBytes
);
427 allocatedBytes
= newTotalBytes
;
428 allocatedData
.allocate (newTotalBytes
, clearExtraSpace
|| isClear
);
429 channels
= unalignedPointerCast
<Type
**> (allocatedData
.get());
432 auto* chan
= unalignedPointerCast
<Type
*> (allocatedData
+ channelListSize
);
434 for (int i
= 0; i
< newNumChannels
; ++i
)
437 chan
+= allocatedSamplesPerChannel
;
441 channels
[newNumChannels
] = nullptr;
442 size
= newNumSamples
;
443 numChannels
= newNumChannels
;
447 /** Makes this buffer point to a pre-allocated set of channel data arrays.
449 There's also a constructor that lets you specify arrays like this, but this
450 lets you change the channels dynamically.
452 Note that if the buffer is resized or its number of channels is changed, it
453 will re-allocate memory internally and copy the existing data to this new area,
454 so it will then stop directly addressing this memory.
456 The hasBeenCleared method will return false after this call.
458 @param dataToReferTo a pre-allocated array containing pointers to the data
459 for each channel that should be used by this buffer. The
460 buffer will only refer to this memory, it won't try to delete
461 it when the buffer is deleted or resized.
462 @param newNumChannels the number of channels to use - this must correspond to the
463 number of elements in the array passed in
464 @param newStartSample the offset within the arrays at which the data begins
465 @param newNumSamples the number of samples to use - this must correspond to the
466 size of the arrays passed in
468 void setDataToReferTo (Type
** dataToReferTo
,
473 jassert (dataToReferTo
!= nullptr);
474 jassert (newNumChannels
>= 0 && newNumSamples
>= 0);
476 if (allocatedBytes
!= 0)
479 allocatedData
.free();
482 numChannels
= newNumChannels
;
483 size
= newNumSamples
;
485 allocateChannels (dataToReferTo
, newStartSample
);
489 /** Makes this buffer point to a pre-allocated set of channel data arrays.
491 There's also a constructor that lets you specify arrays like this, but this
492 lets you change the channels dynamically.
494 Note that if the buffer is resized or its number of channels is changed, it
495 will re-allocate memory internally and copy the existing data to this new area,
496 so it will then stop directly addressing this memory.
498 The hasBeenCleared method will return false after this call.
500 @param dataToReferTo a pre-allocated array containing pointers to the data
501 for each channel that should be used by this buffer. The
502 buffer will only refer to this memory, it won't try to delete
503 it when the buffer is deleted or resized.
504 @param newNumChannels the number of channels to use - this must correspond to the
505 number of elements in the array passed in
506 @param newNumSamples the number of samples to use - this must correspond to the
507 size of the arrays passed in
509 void setDataToReferTo (Type
** dataToReferTo
,
513 setDataToReferTo (dataToReferTo
, newNumChannels
, 0, newNumSamples
);
516 /** Resizes this buffer to match the given one, and copies all of its content across.
518 The source buffer can contain a different floating point type, so this can be used to
519 convert between 32 and 64 bit float buffer types.
521 The hasBeenCleared method will return false after this call if the other buffer
524 template <typename OtherType
>
525 void makeCopyOf (const AudioBuffer
<OtherType
>& other
, bool avoidReallocating
= false)
527 setSize (other
.getNumChannels(), other
.getNumSamples(), false, false, avoidReallocating
);
529 if (other
.hasBeenCleared())
537 for (int chan
= 0; chan
< numChannels
; ++chan
)
539 auto* dest
= channels
[chan
];
540 auto* src
= other
.getReadPointer (chan
);
542 for (int i
= 0; i
< size
; ++i
)
543 dest
[i
] = static_cast<Type
> (src
[i
]);
548 //==============================================================================
549 /** Clears all the samples in all channels and marks the buffer as cleared.
551 This method will do nothing if the buffer has been marked as cleared (i.e. the
552 hasBeenCleared method returns true.)
554 @see hasBeenCleared, setNotClear
556 void clear() noexcept
560 for (int i
= 0; i
< numChannels
; ++i
)
561 FloatVectorOperations::clear (channels
[i
], size
);
567 /** Clears a specified region of all the channels.
569 This will mark the buffer as cleared if the entire buffer contents are cleared.
571 For speed, this doesn't check whether the channel and sample number
572 are in-range, so be careful!
574 This method will do nothing if the buffer has been marked as cleared (i.e. the
575 hasBeenCleared method returns true.)
577 @see hasBeenCleared, setNotClear
579 void clear (int startSample
, int numSamples
) noexcept
581 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
585 for (int i
= 0; i
< numChannels
; ++i
)
586 FloatVectorOperations::clear (channels
[i
] + startSample
, numSamples
);
588 isClear
= (startSample
== 0 && numSamples
== size
);
592 /** Clears a specified region of just one channel.
594 For speed, this doesn't check whether the channel and sample number
595 are in-range, so be careful!
597 This method will do nothing if the buffer has been marked as cleared (i.e. the
598 hasBeenCleared method returns true.)
600 @see hasBeenCleared, setNotClear
602 void clear (int channel
, int startSample
, int numSamples
) noexcept
604 jassert (isPositiveAndBelow (channel
, numChannels
));
605 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
608 FloatVectorOperations::clear (channels
[channel
] + startSample
, numSamples
);
611 /** Returns true if the buffer has been entirely cleared.
613 Note that this does not actually measure the contents of the buffer - it simply
614 returns a flag that is set when the buffer is cleared, and which is reset whenever
615 functions like getWritePointer are invoked. That means the method is quick, but it
616 may return false negatives when in fact the buffer is still empty.
618 bool hasBeenCleared() const noexcept
{ return isClear
; }
620 /** Forces the internal cleared flag of the buffer to false.
622 This may be useful in the case where you are holding on to a write pointer and call
623 the clear method before writing some data. You can then use this method to mark the
624 buffer as containing data so that subsequent clear calls will succeed. However a
625 better solution is to call getWritePointer each time you need to write data.
627 void setNotClear() noexcept
{ isClear
= false; }
629 //==============================================================================
630 /** Returns a sample from the buffer.
632 The channel and index are not checked - they are expected to be in-range. If not,
633 an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
636 Type
getSample (int channel
, int sampleIndex
) const noexcept
638 jassert (isPositiveAndBelow (channel
, numChannels
));
639 jassert (isPositiveAndBelow (sampleIndex
, size
));
640 return *(channels
[channel
] + sampleIndex
);
643 /** Sets a sample in the buffer.
645 The channel and index are not checked - they are expected to be in-range. If not,
646 an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
649 The hasBeenCleared method will return false after this call.
651 void setSample (int destChannel
, int destSample
, Type newValue
) noexcept
653 jassert (isPositiveAndBelow (destChannel
, numChannels
));
654 jassert (isPositiveAndBelow (destSample
, size
));
655 *(channels
[destChannel
] + destSample
) = newValue
;
659 /** Adds a value to a sample in the buffer.
661 The channel and index are not checked - they are expected to be in-range. If not,
662 an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
665 The hasBeenCleared method will return false after this call.
667 void addSample (int destChannel
, int destSample
, Type valueToAdd
) noexcept
669 jassert (isPositiveAndBelow (destChannel
, numChannels
));
670 jassert (isPositiveAndBelow (destSample
, size
));
671 *(channels
[destChannel
] + destSample
) += valueToAdd
;
675 /** Applies a gain multiple to a region of one channel.
677 For speed, this doesn't check whether the channel and sample number
678 are in-range, so be careful!
680 void applyGain (int channel
, int startSample
, int numSamples
, Type gain
) noexcept
682 jassert (isPositiveAndBelow (channel
, numChannels
));
683 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
685 if (gain
!= Type (1) && ! isClear
)
687 auto* d
= channels
[channel
] + startSample
;
690 FloatVectorOperations::clear (d
, numSamples
);
692 FloatVectorOperations::multiply (d
, gain
, numSamples
);
696 /** Applies a gain multiple to a region of all the channels.
698 For speed, this doesn't check whether the sample numbers
699 are in-range, so be careful!
701 void applyGain (int startSample
, int numSamples
, Type gain
) noexcept
703 for (int i
= 0; i
< numChannels
; ++i
)
704 applyGain (i
, startSample
, numSamples
, gain
);
707 /** Applies a gain multiple to all the audio data. */
708 void applyGain (Type gain
) noexcept
710 applyGain (0, size
, gain
);
713 /** Applies a range of gains to a region of a channel.
715 The gain that is applied to each sample will vary from
716 startGain on the first sample to endGain on the last Sample,
717 so it can be used to do basic fades.
719 For speed, this doesn't check whether the sample numbers
720 are in-range, so be careful!
722 void applyGainRamp (int channel
, int startSample
, int numSamples
,
723 Type startGain
, Type endGain
) noexcept
727 if (startGain
== endGain
)
729 applyGain (channel
, startSample
, numSamples
, startGain
);
733 jassert (isPositiveAndBelow (channel
, numChannels
));
734 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
736 const auto increment
= (endGain
- startGain
) / (float) numSamples
;
737 auto* d
= channels
[channel
] + startSample
;
739 while (--numSamples
>= 0)
742 startGain
+= increment
;
748 /** Applies a range of gains to a region of all channels.
750 The gain that is applied to each sample will vary from
751 startGain on the first sample to endGain on the last Sample,
752 so it can be used to do basic fades.
754 For speed, this doesn't check whether the sample numbers
755 are in-range, so be careful!
757 void applyGainRamp (int startSample
, int numSamples
,
758 Type startGain
, Type endGain
) noexcept
760 for (int i
= 0; i
< numChannels
; ++i
)
761 applyGainRamp (i
, startSample
, numSamples
, startGain
, endGain
);
764 /** Adds samples from another buffer to this one.
766 The hasBeenCleared method will return false after this call if samples have
769 @param destChannel the channel within this buffer to add the samples to
770 @param destStartSample the start sample within this buffer's channel
771 @param source the source buffer to add from
772 @param sourceChannel the channel within the source buffer to read from
773 @param sourceStartSample the offset within the source buffer's channel to start reading samples from
774 @param numSamples the number of samples to process
775 @param gainToApplyToSource an optional gain to apply to the source samples before they are
776 added to this buffer's samples
780 void addFrom (int destChannel
,
782 const AudioBuffer
& source
,
784 int sourceStartSample
,
786 Type gainToApplyToSource
= Type (1)) noexcept
788 jassert (&source
!= this
789 || sourceChannel
!= destChannel
790 || sourceStartSample
+ numSamples
<= destStartSample
791 || destStartSample
+ numSamples
<= sourceStartSample
);
792 jassert (isPositiveAndBelow (destChannel
, numChannels
));
793 jassert (destStartSample
>= 0 && numSamples
>= 0 && destStartSample
+ numSamples
<= size
);
794 jassert (isPositiveAndBelow (sourceChannel
, source
.numChannels
));
795 jassert (sourceStartSample
>= 0 && sourceStartSample
+ numSamples
<= source
.size
);
797 if (gainToApplyToSource
!= 0 && numSamples
> 0 && ! source
.isClear
)
799 auto* d
= channels
[destChannel
] + destStartSample
;
800 auto* s
= source
.channels
[sourceChannel
] + sourceStartSample
;
806 if (gainToApplyToSource
!= Type (1))
807 FloatVectorOperations::copyWithMultiply (d
, s
, gainToApplyToSource
, numSamples
);
809 FloatVectorOperations::copy (d
, s
, numSamples
);
813 if (gainToApplyToSource
!= Type (1))
814 FloatVectorOperations::addWithMultiply (d
, s
, gainToApplyToSource
, numSamples
);
816 FloatVectorOperations::add (d
, s
, numSamples
);
821 /** Adds samples from an array of floats to one of the channels.
823 The hasBeenCleared method will return false after this call if samples have
826 @param destChannel the channel within this buffer to add the samples to
827 @param destStartSample the start sample within this buffer's channel
828 @param source the source data to use
829 @param numSamples the number of samples to process
830 @param gainToApplyToSource an optional gain to apply to the source samples before they are
831 added to this buffer's samples
835 void addFrom (int destChannel
,
839 Type gainToApplyToSource
= Type (1)) noexcept
841 jassert (isPositiveAndBelow (destChannel
, numChannels
));
842 jassert (destStartSample
>= 0 && numSamples
>= 0 && destStartSample
+ numSamples
<= size
);
843 jassert (source
!= nullptr);
845 if (gainToApplyToSource
!= 0 && numSamples
> 0)
847 auto* d
= channels
[destChannel
] + destStartSample
;
853 if (gainToApplyToSource
!= Type (1))
854 FloatVectorOperations::copyWithMultiply (d
, source
, gainToApplyToSource
, numSamples
);
856 FloatVectorOperations::copy (d
, source
, numSamples
);
860 if (gainToApplyToSource
!= Type (1))
861 FloatVectorOperations::addWithMultiply (d
, source
, gainToApplyToSource
, numSamples
);
863 FloatVectorOperations::add (d
, source
, numSamples
);
869 /** Adds samples from an array of floats, applying a gain ramp to them.
871 The hasBeenCleared method will return false after this call if samples have
874 @param destChannel the channel within this buffer to add the samples to
875 @param destStartSample the start sample within this buffer's channel
876 @param source the source data to use
877 @param numSamples the number of samples to process
878 @param startGain the gain to apply to the first sample (this is multiplied with
879 the source samples before they are added to this buffer)
880 @param endGain the gain to apply to the final sample. The gain is linearly
881 interpolated between the first and last samples.
883 void addFromWithRamp (int destChannel
,
888 Type endGain
) noexcept
890 if (startGain
== endGain
)
892 addFrom (destChannel
, destStartSample
, source
, numSamples
, startGain
);
896 jassert (isPositiveAndBelow (destChannel
, numChannels
));
897 jassert (destStartSample
>= 0 && numSamples
>= 0 && destStartSample
+ numSamples
<= size
);
898 jassert (source
!= nullptr);
903 const auto increment
= (endGain
- startGain
) / numSamples
;
904 auto* d
= channels
[destChannel
] + destStartSample
;
906 while (--numSamples
>= 0)
908 *d
++ += startGain
* *source
++;
909 startGain
+= increment
;
915 /** Copies samples from another buffer to this one.
917 @param destChannel the channel within this buffer to copy the samples to
918 @param destStartSample the start sample within this buffer's channel
919 @param source the source buffer to read from
920 @param sourceChannel the channel within the source buffer to read from
921 @param sourceStartSample the offset within the source buffer's channel to start reading samples from
922 @param numSamples the number of samples to process
926 void copyFrom (int destChannel
,
928 const AudioBuffer
& source
,
930 int sourceStartSample
,
931 int numSamples
) noexcept
933 jassert (&source
!= this
934 || sourceChannel
!= destChannel
935 || sourceStartSample
+ numSamples
<= destStartSample
936 || destStartSample
+ numSamples
<= sourceStartSample
);
937 jassert (isPositiveAndBelow (destChannel
, numChannels
));
938 jassert (destStartSample
>= 0 && destStartSample
+ numSamples
<= size
);
939 jassert (isPositiveAndBelow (sourceChannel
, source
.numChannels
));
940 jassert (sourceStartSample
>= 0 && numSamples
>= 0 && sourceStartSample
+ numSamples
<= source
.size
);
947 FloatVectorOperations::clear (channels
[destChannel
] + destStartSample
, numSamples
);
952 FloatVectorOperations::copy (channels
[destChannel
] + destStartSample
,
953 source
.channels
[sourceChannel
] + sourceStartSample
,
959 /** Copies samples from an array of floats into one of the channels.
961 The hasBeenCleared method will return false after this call if samples have
964 @param destChannel the channel within this buffer to copy the samples to
965 @param destStartSample the start sample within this buffer's channel
966 @param source the source buffer to read from
967 @param numSamples the number of samples to process
971 void copyFrom (int destChannel
,
974 int numSamples
) noexcept
976 jassert (isPositiveAndBelow (destChannel
, numChannels
));
977 jassert (destStartSample
>= 0 && numSamples
>= 0 && destStartSample
+ numSamples
<= size
);
978 jassert (source
!= nullptr);
983 FloatVectorOperations::copy (channels
[destChannel
] + destStartSample
, source
, numSamples
);
987 /** Copies samples from an array of floats into one of the channels, applying a gain to it.
989 The hasBeenCleared method will return false after this call if samples have
992 @param destChannel the channel within this buffer to copy the samples to
993 @param destStartSample the start sample within this buffer's channel
994 @param source the source buffer to read from
995 @param numSamples the number of samples to process
996 @param gain the gain to apply
1000 void copyFrom (int destChannel
,
1001 int destStartSample
,
1006 jassert (isPositiveAndBelow (destChannel
, numChannels
));
1007 jassert (destStartSample
>= 0 && numSamples
>= 0 && destStartSample
+ numSamples
<= size
);
1008 jassert (source
!= nullptr);
1012 auto* d
= channels
[destChannel
] + destStartSample
;
1014 if (gain
!= Type (1))
1019 FloatVectorOperations::clear (d
, numSamples
);
1024 FloatVectorOperations::copyWithMultiply (d
, source
, gain
, numSamples
);
1030 FloatVectorOperations::copy (d
, source
, numSamples
);
1035 /** Copies samples from an array of floats into one of the channels, applying a gain ramp.
1037 The hasBeenCleared method will return false after this call if samples have
1040 @param destChannel the channel within this buffer to copy the samples to
1041 @param destStartSample the start sample within this buffer's channel
1042 @param source the source buffer to read from
1043 @param numSamples the number of samples to process
1044 @param startGain the gain to apply to the first sample (this is multiplied with
1045 the source samples before they are copied to this buffer)
1046 @param endGain the gain to apply to the final sample. The gain is linearly
1047 interpolated between the first and last samples.
1051 void copyFromWithRamp (int destChannel
,
1052 int destStartSample
,
1056 Type endGain
) noexcept
1058 if (startGain
== endGain
)
1060 copyFrom (destChannel
, destStartSample
, source
, numSamples
, startGain
);
1064 jassert (isPositiveAndBelow (destChannel
, numChannels
));
1065 jassert (destStartSample
>= 0 && numSamples
>= 0 && destStartSample
+ numSamples
<= size
);
1066 jassert (source
!= nullptr);
1071 const auto increment
= (endGain
- startGain
) / numSamples
;
1072 auto* d
= channels
[destChannel
] + destStartSample
;
1074 while (--numSamples
>= 0)
1076 *d
++ = startGain
* *source
++;
1077 startGain
+= increment
;
1083 /** Returns a Range indicating the lowest and highest sample values in a given section.
1085 @param channel the channel to read from
1086 @param startSample the start sample within the channel
1087 @param numSamples the number of samples to check
1089 Range
<Type
> findMinMax (int channel
, int startSample
, int numSamples
) const noexcept
1091 jassert (isPositiveAndBelow (channel
, numChannels
));
1092 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
1095 return { Type (0), Type (0) };
1097 return FloatVectorOperations::findMinAndMax (channels
[channel
] + startSample
, numSamples
);
1100 /** Finds the highest absolute sample value within a region of a channel. */
1101 Type
getMagnitude (int channel
, int startSample
, int numSamples
) const noexcept
1103 jassert (isPositiveAndBelow (channel
, numChannels
));
1104 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
1109 auto r
= findMinMax (channel
, startSample
, numSamples
);
1111 return jmax (r
.getStart(), -r
.getStart(), r
.getEnd(), -r
.getEnd());
1114 /** Finds the highest absolute sample value within a region on all channels. */
1115 Type
getMagnitude (int startSample
, int numSamples
) const noexcept
1120 for (int i
= 0; i
< numChannels
; ++i
)
1121 mag
= jmax (mag
, getMagnitude (i
, startSample
, numSamples
));
1126 /** Returns the root mean squared level for a region of a channel. */
1127 Type
getRMSLevel (int channel
, int startSample
, int numSamples
) const noexcept
1129 jassert (isPositiveAndBelow (channel
, numChannels
));
1130 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
1132 if (numSamples
<= 0 || channel
< 0 || channel
>= numChannels
|| isClear
)
1135 auto* data
= channels
[channel
] + startSample
;
1138 for (int i
= 0; i
< numSamples
; ++i
)
1140 auto sample
= data
[i
];
1141 sum
+= sample
* sample
;
1144 return static_cast<Type
> (std::sqrt (sum
/ numSamples
));
1147 /** Reverses a part of a channel. */
1148 void reverse (int channel
, int startSample
, int numSamples
) const noexcept
1150 jassert (isPositiveAndBelow (channel
, numChannels
));
1151 jassert (startSample
>= 0 && numSamples
>= 0 && startSample
+ numSamples
<= size
);
1154 std::reverse (channels
[channel
] + startSample
,
1155 channels
[channel
] + startSample
+ numSamples
);
1158 /** Reverses a part of the buffer. */
1159 void reverse (int startSample
, int numSamples
) const noexcept
1161 for (int i
= 0; i
< numChannels
; ++i
)
1162 reverse (i
, startSample
, numSamples
);
1165 //==============================================================================
1166 /** This allows templated code that takes an AudioBuffer to access its sample type. */
1167 using SampleType
= Type
;
1170 //==============================================================================
1173 #if (! JUCE_GCC || (__GNUC__ * 100 + __GNUC_MINOR__) >= 409)
1174 static_assert (alignof (Type
) <= maxAlignment
,
1175 "AudioBuffer cannot hold types with alignment requirements larger than that guaranteed by malloc");
1177 jassert (size
>= 0);
1179 auto channelListSize
= (size_t) (numChannels
+ 1) * sizeof (Type
*);
1180 auto requiredSampleAlignment
= std::alignment_of
<Type
>::value
;
1181 size_t alignmentOverflow
= channelListSize
% requiredSampleAlignment
;
1183 if (alignmentOverflow
!= 0)
1184 channelListSize
+= requiredSampleAlignment
- alignmentOverflow
;
1186 allocatedBytes
= (size_t) numChannels
* (size_t) size
* sizeof (Type
) + channelListSize
+ 32;
1187 allocatedData
.malloc (allocatedBytes
);
1188 channels
= unalignedPointerCast
<Type
**> (allocatedData
.get());
1189 auto chan
= unalignedPointerCast
<Type
*> (allocatedData
+ channelListSize
);
1191 for (int i
= 0; i
< numChannels
; ++i
)
1197 channels
[numChannels
] = nullptr;
1201 void allocateChannels (Type
* const* dataToReferTo
, int offset
)
1203 jassert (offset
>= 0);
1205 // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools)
1206 if (numChannels
< (int) numElementsInArray (preallocatedChannelSpace
))
1208 channels
= static_cast<Type
**> (preallocatedChannelSpace
);
1212 allocatedData
.malloc (numChannels
+ 1, sizeof (Type
*));
1213 channels
= unalignedPointerCast
<Type
**> (allocatedData
.get());
1216 for (int i
= 0; i
< numChannels
; ++i
)
1218 // you have to pass in the same number of valid pointers as numChannels
1219 jassert (dataToReferTo
[i
] != nullptr);
1220 channels
[i
] = dataToReferTo
[i
] + offset
;
1223 channels
[numChannels
] = nullptr;
1227 /* On iOS/arm7 the alignment of `double` is greater than the alignment of
1228 `std::max_align_t`, so we can't trust max_align_t. Instead, we query
1229 lots of primitive types and use the maximum alignment of all of them.
1231 static constexpr size_t getMaxAlignment() noexcept
1233 constexpr size_t alignments
[] { alignof (std::max_align_t
),
1237 alignof (long double),
1238 alignof (short int),
1241 alignof (long long int),
1246 alignof (wchar_t) };
1250 for (const auto elem
: alignments
)
1251 max
= jmax (max
, elem
);
1256 int numChannels
= 0, size
= 0;
1257 size_t allocatedBytes
= 0;
1259 HeapBlock
<char, true> allocatedData
;
1260 Type
* preallocatedChannelSpace
[32];
1261 bool isClear
= false;
1262 static constexpr size_t maxAlignment
= getMaxAlignment();
1264 JUCE_LEAK_DETECTOR (AudioBuffer
)
1267 //==============================================================================
1269 A multi-channel buffer of 32-bit floating point audio samples.
1271 This type is here for backwards compatibility with the older AudioSampleBuffer
1272 class, which was fixed for 32-bit data, but is otherwise the same as the new
1273 templated AudioBuffer class.
1277 using AudioSampleBuffer
= AudioBuffer
<float>;