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.

780 lines
34KB

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