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.

167 lines
5.3KB

  1. /*!
  2. @file AudioUnitSDK/AUBuffer.h
  3. @copyright © 2000-2021 Apple Inc. All rights reserved.
  4. */
  5. #ifndef AudioUnitSDK_AUBuffer_h
  6. #define AudioUnitSDK_AUBuffer_h
  7. #include <AudioUnitSDK/AUUtility.h>
  8. #include <AudioToolbox/AudioUnit.h>
  9. #include <cstddef>
  10. #include <optional>
  11. namespace ausdk {
  12. /// struct created/destroyed by allocator. Do not attempt to manually create/destroy.
  13. struct AllocatedBuffer {
  14. const UInt32 mMaximumNumberBuffers;
  15. const UInt32 mMaximumBytesPerBuffer;
  16. const UInt32 mReservedA[2]; // NOLINT C-style array
  17. const UInt32 mHeaderSize;
  18. const UInt32 mBufferDataSize;
  19. const UInt32 mReservedB[2]; // NOLINT C-style array
  20. void* const mBufferData;
  21. void* const mReservedC;
  22. AudioBufferList mAudioBufferList;
  23. // opaque variable-length data may follow the AudioBufferList
  24. AudioBufferList& Prepare(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer);
  25. AudioBufferList& PrepareNull(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer);
  26. };
  27. /*!
  28. @class BufferAllocator
  29. @brief Class which allocates memory for internal audio buffers.
  30. To customize, create a subclass and install an instance into the global via set_instance().
  31. */
  32. class BufferAllocator {
  33. public:
  34. /// Obtain the global instance, creating it if necessary.
  35. static BufferAllocator& instance();
  36. /// A client may install a custom global instance via this method. Throws an exception if
  37. /// a default instance has already been created.
  38. static void set_instance(BufferAllocator& instance);
  39. BufferAllocator() = default;
  40. virtual ~BufferAllocator() = default;
  41. // Rule of 5
  42. BufferAllocator(const BufferAllocator&) = delete;
  43. BufferAllocator(BufferAllocator&&) = delete;
  44. BufferAllocator& operator=(const BufferAllocator&) = delete;
  45. BufferAllocator& operator=(BufferAllocator&&) = delete;
  46. // N.B. Must return zeroed memory aligned to at least 16 bytes.
  47. virtual AllocatedBuffer* Allocate(
  48. UInt32 numberBuffers, UInt32 maxBytesPerBuffer, UInt32 reservedFlags);
  49. virtual void Deallocate(AllocatedBuffer* allocatedBuffer);
  50. };
  51. /*!
  52. @class AUBufferList
  53. @brief Manages an `AudioBufferList` backed by allocated memory buffers.
  54. */
  55. class AUBufferList {
  56. enum class EPtrState { Invalid, ToMyMemory, ToExternalMemory };
  57. public:
  58. AUBufferList() = default;
  59. ~AUBufferList() { Deallocate(); }
  60. AUBufferList(const AUBufferList&) = delete;
  61. AUBufferList(AUBufferList&&) = delete;
  62. AUBufferList& operator=(const AUBufferList&) = delete;
  63. AUBufferList& operator=(AUBufferList&&) = delete;
  64. AudioBufferList& PrepareBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames);
  65. AudioBufferList& PrepareNullBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames);
  66. AudioBufferList& SetBufferList(const AudioBufferList& abl)
  67. {
  68. ausdk::ThrowExceptionIf(mAllocatedStreams < abl.mNumberBuffers, -1);
  69. mPtrState = EPtrState::ToExternalMemory;
  70. auto& myabl = mBuffers->mAudioBufferList;
  71. memcpy(&myabl, &abl,
  72. static_cast<size_t>(
  73. reinterpret_cast<const std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT
  74. reinterpret_cast<const std::byte*>(&abl))); // NOLINT
  75. return myabl;
  76. }
  77. void SetBuffer(UInt32 index, const AudioBuffer& ab)
  78. {
  79. auto& myabl = mBuffers->mAudioBufferList;
  80. ausdk::ThrowExceptionIf(
  81. mPtrState == EPtrState::Invalid || index >= myabl.mNumberBuffers, -1);
  82. mPtrState = EPtrState::ToExternalMemory;
  83. myabl.mBuffers[index] = ab; // NOLINT
  84. }
  85. void InvalidateBufferList() noexcept { mPtrState = EPtrState::Invalid; }
  86. [[nodiscard]] AudioBufferList& GetBufferList() const
  87. {
  88. ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1);
  89. return mBuffers->mAudioBufferList;
  90. }
  91. void CopyBufferListTo(AudioBufferList& abl) const
  92. {
  93. ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1);
  94. memcpy(&abl, &mBuffers->mAudioBufferList,
  95. static_cast<size_t>(
  96. reinterpret_cast<std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT
  97. reinterpret_cast<std::byte*>(&abl))); // NOLINT
  98. }
  99. void CopyBufferContentsTo(AudioBufferList& destabl) const
  100. {
  101. ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1);
  102. const auto& srcabl = mBuffers->mAudioBufferList;
  103. const AudioBuffer* srcbuf = srcabl.mBuffers; // NOLINT
  104. AudioBuffer* destbuf = destabl.mBuffers; // NOLINT
  105. for (UInt32 i = 0; i < destabl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) { // NOLINT
  106. if (i >=
  107. srcabl.mNumberBuffers) { // duplicate last source to additional outputs [4341137]
  108. --srcbuf; // NOLINT
  109. }
  110. if (destbuf->mData != srcbuf->mData) {
  111. memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
  112. }
  113. destbuf->mDataByteSize = srcbuf->mDataByteSize;
  114. }
  115. }
  116. void Allocate(const AudioStreamBasicDescription& format, UInt32 nFrames);
  117. void Deallocate();
  118. // AudioBufferList utilities
  119. static void ZeroBuffer(AudioBufferList& abl)
  120. {
  121. AudioBuffer* buf = abl.mBuffers; // NOLINT
  122. for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) { // NOLINT
  123. memset(buf->mData, 0, buf->mDataByteSize);
  124. }
  125. }
  126. [[nodiscard]] UInt32 GetAllocatedFrames() const noexcept { return mAllocatedFrames; }
  127. private:
  128. EPtrState mPtrState{ EPtrState::Invalid };
  129. AllocatedBuffer* mBuffers = nullptr; // only valid between Allocate and Deallocate
  130. UInt32 mAllocatedStreams{ 0 };
  131. UInt32 mAllocatedFrames{ 0 };
  132. };
  133. } // namespace ausdk
  134. #endif // AudioUnitSDK_AUBuffer_h