1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
|
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace dsp
{
#ifndef DOXYGEN
namespace SampleTypeHelpers // Internal classes needed for handling sample type classes
{
template <typename T, bool = std::is_floating_point<T>::value>
struct ElementType
{
using Type = T;
};
template <typename T>
struct ElementType<T, false>
{
using Type = typename T::value_type;
};
}
#endif
//==============================================================================
/**
Minimal and lightweight data-structure which contains a list of pointers to
channels containing some kind of sample data.
This class doesn't own any of the data which it points to, it's simply a view
into data that is owned elsewhere. You can construct one from some raw data
that you've allocated yourself, or give it a HeapBlock to use, or give it
an AudioBuffer which it can refer to, but in all cases the user is
responsible for making sure that the data doesn't get deleted while there's
still an AudioBlock using it.
@tags{DSP}
*/
template <typename SampleType>
class AudioBlock
{
private:
template <typename OtherSampleType>
using MayUseConvertingConstructor =
std::enable_if_t<std::is_same<std::remove_const_t<SampleType>,
std::remove_const_t<OtherSampleType>>::value
&& std::is_const<SampleType>::value
&& ! std::is_const<OtherSampleType>::value,
int>;
public:
//==============================================================================
using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
//==============================================================================
/** Create a zero-sized AudioBlock. */
AudioBlock() noexcept = default;
/** Creates an AudioBlock from a pointer to an array of channels.
AudioBlock does not copy nor own the memory pointed to by dataToUse.
Therefore it is the user's responsibility to ensure that the memory is retained
throughout the life-time of the AudioBlock and released when no longer needed.
*/
constexpr AudioBlock (SampleType* const* channelData,
size_t numberOfChannels, size_t numberOfSamples) noexcept
: channels (channelData),
numChannels (static_cast<ChannelCountType> (numberOfChannels)),
numSamples (numberOfSamples)
{
}
/** Creates an AudioBlock from a pointer to an array of channels.
AudioBlock does not copy nor own the memory pointed to by dataToUse.
Therefore it is the user's responsibility to ensure that the memory is retained
throughout the life-time of the AudioBlock and released when no longer needed.
*/
constexpr AudioBlock (SampleType* const* channelData, size_t numberOfChannels,
size_t startSampleIndex, size_t numberOfSamples) noexcept
: channels (channelData),
numChannels (static_cast<ChannelCountType> (numberOfChannels)),
startSample (startSampleIndex),
numSamples (numberOfSamples)
{
}
/** Allocates a suitable amount of space in a HeapBlock, and initialises this object
to point into it.
The HeapBlock must of course not be freed or re-allocated while this object is still in
use, because it will be referencing its data.
*/
AudioBlock (HeapBlock<char>& heapBlockToUseForAllocation,
size_t numberOfChannels, size_t numberOfSamples,
size_t alignmentInBytes = defaultAlignment) noexcept
: numChannels (static_cast<ChannelCountType> (numberOfChannels)),
numSamples (numberOfSamples)
{
auto roundedUpNumSamples = (numberOfSamples + elementMask) & ~elementMask;
auto channelSize = sizeof (SampleType) * roundedUpNumSamples;
auto channelListBytes = sizeof (SampleType*) * numberOfChannels;
auto extraBytes = alignmentInBytes - 1;
heapBlockToUseForAllocation.malloc (channelListBytes + extraBytes + channelSize * numberOfChannels);
auto* chanArray = reinterpret_cast<SampleType**> (heapBlockToUseForAllocation.getData());
channels = chanArray;
auto* data = reinterpret_cast<SampleType*> (addBytesToPointer (chanArray, channelListBytes));
data = snapPointerToAlignment (data, alignmentInBytes);
for (ChannelCountType i = 0; i < numChannels; ++i)
{
chanArray[i] = data;
data += roundedUpNumSamples;
}
}
/** Creates an AudioBlock that points to the data in an AudioBuffer.
AudioBlock does not copy nor own the memory pointed to by dataToUse.
Therefore it is the user's responsibility to ensure that the buffer is retained
throughout the life-time of the AudioBlock without being modified.
*/
template <typename OtherSampleType>
constexpr AudioBlock (AudioBuffer<OtherSampleType>& buffer) noexcept
: channels (buffer.getArrayOfWritePointers()),
numChannels (static_cast<ChannelCountType> (buffer.getNumChannels())),
numSamples (static_cast<size_t> (buffer.getNumSamples()))
{
}
/** Creates an AudioBlock that points to the data in an AudioBuffer.
AudioBlock does not copy nor own the memory pointed to by dataToUse.
Therefore it is the user's responsibility to ensure that the buffer is retained
throughout the life-time of the AudioBlock without being modified.
*/
template <typename OtherSampleType>
AudioBlock (AudioBuffer<OtherSampleType>& buffer, size_t startSampleIndex) noexcept
: channels (buffer.getArrayOfWritePointers()),
numChannels (static_cast<ChannelCountType> (buffer.getNumChannels())),
startSample (startSampleIndex),
numSamples (static_cast<size_t> (buffer.getNumSamples()) - startSampleIndex)
{
jassert (startSample < static_cast<size_t> (buffer.getNumSamples()));
}
AudioBlock (const AudioBlock& other) noexcept = default;
AudioBlock& operator= (const AudioBlock& other) noexcept = default;
template <typename OtherSampleType, MayUseConvertingConstructor<OtherSampleType> = 0>
AudioBlock (const AudioBlock<OtherSampleType>& other) noexcept
: channels { other.channels },
numChannels { other.numChannels },
startSample { other.startSample },
numSamples { other.numSamples }
{
}
template <typename OtherSampleType, MayUseConvertingConstructor<OtherSampleType> = 0>
AudioBlock& operator= (const AudioBlock<OtherSampleType>& other) noexcept
{
AudioBlock blockCopy { other };
swap (blockCopy);
return *this;
}
void swap (AudioBlock& other) noexcept
{
std::swap (other.channels, channels);
std::swap (other.numChannels, numChannels);
std::swap (other.startSample, startSample);
std::swap (other.numSamples, numSamples);
}
//==============================================================================
template <typename OtherSampleType>
constexpr bool operator== (const AudioBlock<OtherSampleType>& other) const noexcept
{
return std::equal (channels,
channels + numChannels,
other.channels,
other.channels + other.numChannels)
&& startSample == other.startSample
&& numSamples == other.numSamples;
}
template <typename OtherSampleType>
constexpr bool operator!= (const AudioBlock<OtherSampleType>& other) const noexcept
{
return ! (*this == other);
}
//==============================================================================
/** Returns the number of channels referenced by this block. */
constexpr size_t getNumChannels() const noexcept { return static_cast<size_t> (numChannels); }
/** Returns the number of samples referenced by this block. */
constexpr size_t getNumSamples() const noexcept { return numSamples; }
/** Returns a raw pointer into one of the channels in this block. */
SampleType* getChannelPointer (size_t channel) const noexcept
{
jassert (channel < numChannels);
jassert (numSamples > 0);
return channels[channel] + startSample;
}
/** Returns an AudioBlock that represents one of the channels in this block. */
AudioBlock getSingleChannelBlock (size_t channel) const noexcept
{
jassert (channel < numChannels);
return AudioBlock (channels + channel, 1, startSample, numSamples);
}
/** Returns a subset of contiguous channels
@param channelStart First channel of the subset
@param numChannelsToUse Count of channels in the subset
*/
AudioBlock getSubsetChannelBlock (size_t channelStart, size_t numChannelsToUse) const noexcept
{
jassert (channelStart < numChannels);
jassert ((channelStart + numChannelsToUse) <= numChannels);
return AudioBlock (channels + channelStart, numChannelsToUse, startSample, numSamples);
}
/** Returns a sample from the buffer.
The channel and index are not checked - they are expected to be in-range. If not,
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
SampleType getSample (int channel, int sampleIndex) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (isPositiveAndBelow (sampleIndex, numSamples));
return channels[channel][(size_t) startSample + (size_t) sampleIndex];
}
/** Modifies a sample in the buffer.
The channel and index are not checked - they are expected to be in-range. If not,
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
void setSample (int destChannel, int destSample, SampleType newValue) const noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (isPositiveAndBelow (destSample, numSamples));
channels[destChannel][(size_t) startSample + (size_t) destSample] = newValue;
}
/** Adds a value to a sample in the buffer.
The channel and index are not checked - they are expected to be in-range. If not,
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
void addSample (int destChannel, int destSample, SampleType valueToAdd) const noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (isPositiveAndBelow (destSample, numSamples));
channels[destChannel][(size_t) startSample + (size_t) destSample] += valueToAdd;
}
//==============================================================================
/** Clears the memory referenced by this AudioBlock. */
AudioBlock& clear() noexcept { clearInternal(); return *this; }
const AudioBlock& clear() const noexcept { clearInternal(); return *this; }
/** Fills the memory referenced by this AudioBlock with value. */
AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) noexcept { fillInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) const noexcept { fillInternal (value); return *this; }
/** Copies the values in src to this block. */
template <typename OtherSampleType>
AudioBlock& copyFrom (const AudioBlock<OtherSampleType>& src) noexcept { copyFromInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& copyFrom (const AudioBlock<OtherSampleType>& src) const noexcept { copyFromInternal (src); return *this; }
/** Copy the values from an AudioBuffer to this block.
All indices and sizes are in this AudioBlock's units, i.e. if SampleType is a
SIMDRegister then incrementing srcPos by one will increase the sample position
in the AudioBuffer's units by a factor of SIMDRegister<SampleType>::SIMDNumElements.
*/
template <typename OtherNumericType>
AudioBlock& copyFrom (const AudioBuffer<OtherNumericType>& src,
size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max()) { copyFromInternal (src, srcPos, dstPos, numElements); return *this; }
template <typename OtherNumericType>
const AudioBlock& copyFrom (const AudioBuffer<OtherNumericType>& src,
size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max()) const { copyFromInternal (src, srcPos, dstPos, numElements); return *this; }
/** Copies the values from this block to an AudioBuffer.
All indices and sizes are in this AudioBlock's units, i.e. if SampleType is a
SIMDRegister then incrementing dstPos by one will increase the sample position
in the AudioBuffer's units by a factor of SIMDRegister<SampleType>::SIMDNumElements.
*/
void copyTo (AudioBuffer<typename std::remove_const<NumericType>::type>& dst, size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max()) const
{
auto dstlen = static_cast<size_t> (dst.getNumSamples()) / sizeFactor;
auto n = static_cast<int> (jmin (numSamples - srcPos, dstlen - dstPos, numElements) * sizeFactor);
auto maxChannels = jmin (static_cast<size_t> (dst.getNumChannels()), static_cast<size_t> (numChannels));
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (dst.getWritePointer (static_cast<int> (ch),
static_cast<int> (dstPos * sizeFactor)),
getDataPointer (ch) + (srcPos * sizeFactor),
n);
}
/** Move memory within this block from the position srcPos to the position dstPos.
If numElements is not specified then move will move the maximum amount of memory.
*/
AudioBlock& move (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) noexcept { moveInternal (srcPos, dstPos, numElements); return *this; }
const AudioBlock& move (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) const noexcept { moveInternal (srcPos, dstPos, numElements); return *this; }
//==============================================================================
/** Return a new AudioBlock pointing to a sub-block inside this block. This
function does not copy the memory and you must ensure that the original memory
pointed to by the receiver remains valid through-out the life-time of the
returned sub-block.
@param newOffset The index of an element inside the receiver which will
will become the first element of the return value.
@param newLength The number of elements of the newly created sub-block.
*/
AudioBlock getSubBlock (size_t newOffset, size_t newLength) const noexcept
{
jassert (newOffset < numSamples);
jassert (newOffset + newLength <= numSamples);
return AudioBlock (channels, numChannels, startSample + newOffset, newLength);
}
/** Return a new AudioBlock pointing to a sub-block inside this block. This
function does not copy the memory and you must ensure that the original memory
pointed to by the receiver remains valid through-out the life-time of the
returned sub-block.
@param newOffset The index of an element inside the block which will
will become the first element of the return value.
The return value will include all subsequent elements
of the receiver.
*/
AudioBlock getSubBlock (size_t newOffset) const noexcept
{
return getSubBlock (newOffset, getNumSamples() - newOffset);
}
//==============================================================================
/** Adds a fixed value to the elements in this block. */
AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) noexcept { addInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) const noexcept { addInternal (value); return *this; }
/** Adds the elements in the src block to the elements in this block. */
template <typename OtherSampleType>
AudioBlock& add (AudioBlock<OtherSampleType> src) noexcept { addInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& add (AudioBlock<OtherSampleType> src) const noexcept { addInternal (src); return *this; }
/** Adds a fixed value to each source value and replaces the contents of this block. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, NumericType value) noexcept { replaceWithSumOfInternal (src, value); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, NumericType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; }
/** Adds each source1 value to the corresponding source2 value and replaces the contents of this block. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithSumOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithSumOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithSumOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithSumOfInternal (src1, src2); return *this; }
//==============================================================================
/** Subtracts a fixed value from the elements in this block. */
AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) noexcept { subtractInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) const noexcept { subtractInternal (value); return *this; }
/** Subtracts the source values from the elements in this block. */
template <typename OtherSampleType>
AudioBlock& subtract (AudioBlock<OtherSampleType> src) noexcept { subtractInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& subtract (AudioBlock<OtherSampleType> src) const noexcept { subtractInternal (src); return *this; }
/** Subtracts a fixed value from each source value and replaces the contents of this block. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, NumericType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, NumericType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }
/** Subtracts each source2 value from the corresponding source1 value and replaces the contents of this block. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithDifferenceOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithDifferenceOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithDifferenceOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithDifferenceOfInternal (src1, src2); return *this; }
//==============================================================================
/** Multiplies the elements in this block by a fixed value. */
AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) noexcept { multiplyByInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) const noexcept { multiplyByInternal (value); return *this; }
/** Multiplies the elements in this block by the elements in the src block */
template <typename OtherSampleType>
AudioBlock& multiplyBy (AudioBlock<OtherSampleType> src) noexcept { multiplyByInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& multiplyBy (AudioBlock<OtherSampleType> src) const noexcept { multiplyByInternal (src); return *this; }
/** Replaces the elements in this block with the product of the elements in the source src block and a fixed value. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, NumericType value) noexcept { replaceWithProductOfInternal (src, value); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, NumericType value) const noexcept { replaceWithProductOfInternal (src, value); return *this; }
/** Replaces the elements in this block with the product of the elements in the src1 and scr2 blocks. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithProductOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithProductOfInternal (src1, src2); return *this; }
//==============================================================================
/** Multiplies each channels of this block by a smoothly changing value. */
template <typename SmoothingType>
AudioBlock& multiplyBy (SmoothedValue<SampleType, SmoothingType>& value) noexcept { multiplyByInternal (value); return *this; }
template <typename SmoothingType>
const AudioBlock& multiplyBy (SmoothedValue<SampleType, SmoothingType>& value) const noexcept { multiplyByInternal (value); return *this; }
/** Replaces each channel of this block with the product of the src block and a smoothed value. */
template <typename OtherSampleType, typename SmoothingType>
AudioBlock& replaceWithProductOf (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) noexcept { replaceWithProductOfInternal (src, value); return *this; }
template <typename OtherSampleType, typename SmoothingType>
const AudioBlock& replaceWithProductOf (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) const noexcept { replaceWithProductOfInternal (src, value); return *this; }
//==============================================================================
/** Multiplies each value in src by a fixed value and adds the result to this block. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, NumericType factor) noexcept { addProductOfInternal (src, factor); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, NumericType factor) const noexcept { addProductOfInternal (src, factor); return *this; }
/** Multiplies each value in srcA with the corresponding value in srcB and adds the result to this block. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& addProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { addProductOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& addProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { addProductOfInternal (src1, src2); return *this; }
//==============================================================================
/** Negates each value of this block. */
AudioBlock& negate() noexcept { negateInternal(); return *this; }
const AudioBlock& negate() const noexcept { negateInternal(); return *this; }
/** Replaces the contents of this block with the negative of the values in the src block. */
template <typename OtherSampleType>
AudioBlock& replaceWithNegativeOf (AudioBlock<OtherSampleType> src) noexcept { replaceWithNegativeOfInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& replaceWithNegativeOf (AudioBlock<OtherSampleType> src) const noexcept { replaceWithNegativeOfInternal (src); return *this; }
/** Replaces the contents of this block with the absolute values of the src block. */
template <typename OtherSampleType>
AudioBlock& replaceWithAbsoluteValueOf (AudioBlock<OtherSampleType> src) noexcept { replaceWithAbsoluteValueOfInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& replaceWithAbsoluteValueOf (AudioBlock<OtherSampleType> src) const noexcept { replaceWithAbsoluteValueOfInternal (src); return *this; }
//==============================================================================
/** Replaces each element of this block with the minimum of the corresponding element of the source arrays. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithMinOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithMinOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithMinOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithMinOfInternal (src1, src2); return *this; }
/** Replaces each element of this block with the maximum of the corresponding element of the source arrays. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithMaxOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithMaxOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithMaxOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithMaxOfInternal (src1, src2); return *this; }
//==============================================================================
/** Finds the minimum and maximum value of the buffer. */
Range<typename std::remove_const<NumericType>::type> findMinAndMax() const noexcept
{
if (numChannels == 0)
return {};
auto n = static_cast<int> (numSamples * sizeFactor);
auto minmax = FloatVectorOperations::findMinAndMax (getDataPointer (0), n);
for (size_t ch = 1; ch < numChannels; ++ch)
minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getDataPointer (ch), n));
return minmax;
}
//==============================================================================
// Convenient operator wrappers.
AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) noexcept { return add (value); }
const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) const noexcept { return add (value); }
AudioBlock& operator+= (AudioBlock src) noexcept { return add (src); }
const AudioBlock& operator+= (AudioBlock src) const noexcept { return add (src); }
AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType value) noexcept { return subtract (value); }
const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType value) const noexcept { return subtract (value); }
AudioBlock& operator-= (AudioBlock src) noexcept { return subtract (src); }
const AudioBlock& operator-= (AudioBlock src) const noexcept { return subtract (src); }
AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType value) noexcept { return multiplyBy (value); }
const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType value) const noexcept { return multiplyBy (value); }
AudioBlock& operator*= (AudioBlock src) noexcept { return multiplyBy (src); }
const AudioBlock& operator*= (AudioBlock src) const noexcept { return multiplyBy (src); }
template <typename SmoothingType>
AudioBlock& operator*= (SmoothedValue<SampleType, SmoothingType>& value) noexcept { return multiplyBy (value); }
template <typename SmoothingType>
const AudioBlock& operator*= (SmoothedValue<SampleType, SmoothingType>& value) const noexcept { return multiplyBy (value); }
//==============================================================================
// This class can only be used with floating point types
static_assert (std::is_same<std::remove_const_t<SampleType>, float>::value
|| std::is_same<std::remove_const_t<SampleType>, double>::value
#if JUCE_USE_SIMD
|| std::is_same<std::remove_const_t<SampleType>, SIMDRegister<float>>::value
|| std::is_same<std::remove_const_t<SampleType>, SIMDRegister<double>>::value
#endif
, "AudioBlock only supports single or double precision floating point types");
//==============================================================================
/** Applies a function to each value in an input block, putting the result into an output block.
The function supplied must take a SampleType as its parameter, and return a SampleType.
The two blocks must have the same number of channels and samples.
*/
template <typename Src1SampleType, typename Src2SampleType, typename FunctionType>
static void process (AudioBlock<Src1SampleType> inBlock, AudioBlock<Src2SampleType> outBlock, FunctionType&& function)
{
auto len = inBlock.getNumSamples();
auto numChans = inBlock.getNumChannels();
jassert (len == outBlock.getNumSamples());
jassert (numChans == outBlock.getNumChannels());
for (ChannelCountType c = 0; c < numChans; ++c)
{
auto* src = inBlock.getChannelPointer (c);
auto* dst = outBlock.getChannelPointer (c);
for (size_t i = 0; i < len; ++i)
dst[i] = function (src[i]);
}
}
private:
NumericType* getDataPointer (size_t channel) const noexcept
{
return reinterpret_cast<NumericType*> (getChannelPointer (channel));
}
//==============================================================================
void JUCE_VECTOR_CALLTYPE clearInternal() const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::clear (getDataPointer (ch), n);
}
void JUCE_VECTOR_CALLTYPE fillInternal (NumericType value) const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::fill (getDataPointer (ch), value, n);
}
template <typename OtherSampleType>
void copyFromInternal (const AudioBlock<OtherSampleType>& src) const noexcept
{
auto maxChannels = jmin (src.numChannels, numChannels);
auto n = static_cast<int> (jmin (src.numSamples * src.sizeFactor,
numSamples * sizeFactor));
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (getDataPointer (ch), src.getDataPointer (ch), n);
}
template <typename OtherNumericType>
void copyFromInternal (const AudioBuffer<OtherNumericType>& src, size_t srcPos, size_t dstPos, size_t numElements) const
{
auto srclen = static_cast<size_t> (src.getNumSamples()) / sizeFactor;
auto n = static_cast<int> (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor);
auto maxChannels = jmin (static_cast<size_t> (src.getNumChannels()), static_cast<size_t> (numChannels));
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (getDataPointer (ch) + (dstPos * sizeFactor),
src.getReadPointer (static_cast<int> (ch),
static_cast<int> (srcPos * sizeFactor)),
n);
}
void moveInternal (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) const noexcept
{
jassert (srcPos <= numSamples && dstPos <= numSamples);
auto len = jmin (numSamples - srcPos, numSamples - dstPos, numElements) * sizeof (SampleType);
if (len != 0)
for (size_t ch = 0; ch < numChannels; ++ch)
::memmove (getChannelPointer (ch) + dstPos,
getChannelPointer (ch) + srcPos, len);
}
//==============================================================================
void JUCE_VECTOR_CALLTYPE addInternal (NumericType value) const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getDataPointer (ch), value, n);
}
template <typename OtherSampleType>
void addInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getDataPointer (ch), src.getDataPointer (ch), n);
}
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock<OtherSampleType> src, NumericType value) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getDataPointer (ch), src.getDataPointer (ch), value, n);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithSumOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);
}
//==============================================================================
constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (NumericType value) const noexcept
{
addInternal (value * static_cast<NumericType> (-1.0));
}
template <typename OtherSampleType>
void subtractInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::subtract (getDataPointer (ch), src.getDataPointer (ch), n);
}
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock<OtherSampleType> src, NumericType value) const noexcept
{
replaceWithSumOfInternal (src, static_cast<NumericType> (-1.0) * value);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithDifferenceOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::subtract (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);
}
//==============================================================================
void JUCE_VECTOR_CALLTYPE multiplyByInternal (NumericType value) const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getDataPointer (ch), value, n);
}
template <typename OtherSampleType>
void multiplyByInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getDataPointer (ch), src.getDataPointer (ch), n);
}
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock<OtherSampleType> src, NumericType value) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getDataPointer (ch), src.getDataPointer (ch), value, n);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithProductOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);
}
template <typename SmoothingType>
void multiplyByInternal (SmoothedValue<SampleType, SmoothingType>& value) const noexcept
{
if (! value.isSmoothing())
{
multiplyByInternal (value.getTargetValue());
}
else
{
for (size_t i = 0; i < numSamples; ++i)
{
const auto scaler = value.getNextValue();
for (size_t ch = 0; ch < numChannels; ++ch)
getDataPointer (ch)[i] *= scaler;
}
}
}
template <typename OtherSampleType, typename SmoothingType>
void replaceWithProductOfInternal (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) const noexcept
{
jassert (numChannels == src.numChannels);
if (! value.isSmoothing())
{
replaceWithProductOfInternal (src, value.getTargetValue());
}
else
{
auto n = jmin (numSamples, src.numSamples) * sizeFactor;
for (size_t i = 0; i < n; ++i)
{
const auto scaler = value.getNextValue();
for (size_t ch = 0; ch < numChannels; ++ch)
getDataPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i];
}
}
}
//==============================================================================
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock<OtherSampleType> src, NumericType factor) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::addWithMultiply (getDataPointer (ch), src.getDataPointer (ch), factor, n);
}
template <typename Src1SampleType, typename Src2SampleType>
void addProductOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::addWithMultiply (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);
}
//==============================================================================
constexpr void negateInternal() const noexcept
{
multiplyByInternal (static_cast<NumericType> (-1.0));
}
template <typename OtherSampleType>
void replaceWithNegativeOfInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::negate (getDataPointer (ch), src.getDataPointer (ch), n);
}
template <typename OtherSampleType>
void replaceWithAbsoluteValueOfInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::abs (getDataPointer (ch), src.getDataPointer (ch), n);
}
//==============================================================================
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithMinOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::min (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithMaxOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::max (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);
}
//==============================================================================
using ChannelCountType = unsigned int;
//==============================================================================
static constexpr size_t sizeFactor = sizeof (SampleType) / sizeof (NumericType);
static constexpr size_t elementMask = sizeFactor - 1;
static constexpr size_t byteMask = (sizeFactor * sizeof (NumericType)) - 1;
#if JUCE_USE_SIMD
static constexpr size_t defaultAlignment = sizeof (SIMDRegister<NumericType>);
#else
static constexpr size_t defaultAlignment = sizeof (NumericType);
#endif
SampleType* const* channels;
ChannelCountType numChannels = 0;
size_t startSample = 0, numSamples = 0;
template <typename OtherSampleType>
friend class AudioBlock;
};
} // namespace dsp
} // namespace juce
|