The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

873 lines
45KB

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