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.

221 lines
9.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the juce_core module of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. or without fee is hereby granted, provided that the above copyright notice and this
  7. permission notice appear in all copies.
  8. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  9. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  10. NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  11. DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  12. IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. ------------------------------------------------------------------------------
  15. NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
  16. All other JUCE modules are covered by a dual GPL/commercial license, so if you are
  17. using any other modules, be sure to check that you also comply with their license.
  18. For more details, visit www.juce.com
  19. ==============================================================================
  20. */
  21. #ifndef JUCE_ABSTRACTFIFO_H_INCLUDED
  22. #define JUCE_ABSTRACTFIFO_H_INCLUDED
  23. //==============================================================================
  24. /**
  25. Encapsulates the logic required to implement a lock-free FIFO.
  26. This class handles the logic needed when building a single-reader, single-writer FIFO.
  27. It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
  28. its position and status when reading or writing to it.
  29. To use it, you can call prepareToWrite() to determine the position within your own buffer that
  30. an incoming block of data should be stored, and prepareToRead() to find out when the next
  31. outgoing block should be read from.
  32. e.g.
  33. @code
  34. class MyFifo
  35. {
  36. public:
  37. MyFifo() : abstractFifo (1024)
  38. {
  39. }
  40. void addToFifo (const int* someData, int numItems)
  41. {
  42. int start1, size1, start2, size2;
  43. abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
  44. if (size1 > 0)
  45. copySomeData (myBuffer + start1, someData, size1);
  46. if (size2 > 0)
  47. copySomeData (myBuffer + start2, someData + size1, size2);
  48. abstractFifo.finishedWrite (size1 + size2);
  49. }
  50. void readFromFifo (int* someData, int numItems)
  51. {
  52. int start1, size1, start2, size2;
  53. abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
  54. if (size1 > 0)
  55. copySomeData (someData, myBuffer + start1, size1);
  56. if (size2 > 0)
  57. copySomeData (someData + size1, myBuffer + start2, size2);
  58. abstractFifo.finishedRead (size1 + size2);
  59. }
  60. private:
  61. AbstractFifo abstractFifo;
  62. int myBuffer [1024];
  63. };
  64. @endcode
  65. */
  66. class JUCE_API AbstractFifo
  67. {
  68. public:
  69. //==============================================================================
  70. /** Creates a FIFO to manage a buffer with the specified capacity. */
  71. AbstractFifo (int capacity) noexcept;
  72. /** Destructor */
  73. ~AbstractFifo();
  74. //==============================================================================
  75. /** Returns the total size of the buffer being managed. */
  76. int getTotalSize() const noexcept;
  77. /** Returns the number of items that can currently be added to the buffer without it overflowing. */
  78. int getFreeSpace() const noexcept;
  79. /** Returns the number of items that can currently be read from the buffer. */
  80. int getNumReady() const noexcept;
  81. /** Clears the buffer positions, so that it appears empty. */
  82. void reset() noexcept;
  83. /** Changes the buffer's total size.
  84. Note that this isn't thread-safe, so don't call it if there's any danger that it
  85. might overlap with a call to any other method in this class!
  86. */
  87. void setTotalSize (int newSize) noexcept;
  88. //==============================================================================
  89. /** Returns the location within the buffer at which an incoming block of data should be written.
  90. Because the section of data that you want to add to the buffer may overlap the end
  91. and wrap around to the start, two blocks within your buffer are returned, and you
  92. should copy your data into the first one, with any remaining data spilling over into
  93. the second.
  94. If the number of items you ask for is too large to fit within the buffer's free space, then
  95. blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
  96. may decide to keep waiting and re-trying the method until there's enough space available.
  97. After calling this method, if you choose to write your data into the blocks returned, you
  98. must call finishedWrite() to tell the FIFO how much data you actually added.
  99. e.g.
  100. @code
  101. void addToFifo (const int* someData, int numItems)
  102. {
  103. int start1, size1, start2, size2;
  104. prepareToWrite (numItems, start1, size1, start2, size2);
  105. if (size1 > 0)
  106. copySomeData (myBuffer + start1, someData, size1);
  107. if (size2 > 0)
  108. copySomeData (myBuffer + start2, someData + size1, size2);
  109. finishedWrite (size1 + size2);
  110. }
  111. @endcode
  112. @param numToWrite indicates how many items you'd like to add to the buffer
  113. @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
  114. @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
  115. @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
  116. the first block should be written
  117. @param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
  118. @see finishedWrite
  119. */
  120. void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
  121. /** Called after writing from the FIFO, to indicate that this many items have been added.
  122. @see prepareToWrite
  123. */
  124. void finishedWrite (int numWritten) noexcept;
  125. /** Returns the location within the buffer from which the next block of data should be read.
  126. Because the section of data that you want to read from the buffer may overlap the end
  127. and wrap around to the start, two blocks within your buffer are returned, and you
  128. should read from both of them.
  129. If the number of items you ask for is greater than the amount of data available, then
  130. blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
  131. may decide to keep waiting and re-trying the method until there's enough data available.
  132. After calling this method, if you choose to read the data, you must call finishedRead() to
  133. tell the FIFO how much data you have consumed.
  134. e.g.
  135. @code
  136. void readFromFifo (int* someData, int numItems)
  137. {
  138. int start1, size1, start2, size2;
  139. prepareToRead (numSamples, start1, size1, start2, size2);
  140. if (size1 > 0)
  141. copySomeData (someData, myBuffer + start1, size1);
  142. if (size2 > 0)
  143. copySomeData (someData + size1, myBuffer + start2, size2);
  144. finishedRead (size1 + size2);
  145. }
  146. @endcode
  147. @param numWanted indicates how many items you'd like to add to the buffer
  148. @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
  149. @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
  150. @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
  151. the first block should be written
  152. @param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
  153. @see finishedRead
  154. */
  155. void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
  156. /** Called after reading from the FIFO, to indicate that this many items have now been consumed.
  157. @see prepareToRead
  158. */
  159. void finishedRead (int numRead) noexcept;
  160. private:
  161. //==============================================================================
  162. int bufferSize;
  163. Atomic <int> validStart, validEnd;
  164. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
  165. };
  166. #endif // JUCE_ABSTRACTFIFO_H_INCLUDED