diff --git a/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp b/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp index 2caf96e463..2ef57d8a37 100644 --- a/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp +++ b/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp @@ -858,45 +858,6 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WASAPIDeviceBase) }; -class SimpleAbstractQueue -{ -public: - SimpleAbstractQueue() = default; - - explicit SimpleAbstractQueue (int sizeIn) - : size (nextPowerOfTwo (sizeIn)) {} - - int getRemainingSpace() const { return size - numReadable; } - int getNumReadable() const { return numReadable; } - int getSize() const { return size; } - - std::array, 2> write (int num) - { - const auto startPos = (readPos + numReadable) & (size - 1); - const auto maxToWrite = jmin (getRemainingSpace(), num); - const auto firstBlockSize = jmin (maxToWrite, size - startPos); - - numReadable += maxToWrite; - - return { { { startPos, startPos + firstBlockSize }, { 0, maxToWrite - firstBlockSize } } }; - } - - std::array, 2> read (int num) - { - const auto startPos = readPos; - const auto maxToRead = jmin (numReadable, num); - const auto firstBlockSize = jmin (maxToRead, size - startPos); - - readPos = (startPos + maxToRead) & (size - 1); - numReadable -= maxToRead; - - return { { { startPos, startPos + firstBlockSize }, { 0, maxToRead - firstBlockSize } } }; - } - -private: - int size = 0, readPos = 0, numReadable = 0; -}; - //============================================================================== class WASAPIInputDevice : public WASAPIDeviceBase { @@ -923,7 +884,7 @@ public: closeClient(); captureClient = nullptr; reservoir.reset(); - queue = SimpleAbstractQueue(); + queue = SingleThreadedAbstractFifo(); } template @@ -945,7 +906,7 @@ public: { const auto reservoirSize = nextPowerOfTwo ((int) (actualBufferSize + (UINT32) userBufferSizeIn)); - queue = SimpleAbstractQueue (reservoirSize); + queue = SingleThreadedAbstractFifo (reservoirSize); reservoir.setSize ((size_t) (queue.getSize() * bytesPerFrame), true); xruns = 0; @@ -1036,7 +997,7 @@ public: ComSmartPtr captureClient; MemoryBlock reservoir; - SimpleAbstractQueue queue; + SingleThreadedAbstractFifo queue; int xruns = 0; std::unique_ptr converter; diff --git a/modules/juce_core/containers/juce_AbstractFifo.h b/modules/juce_core/containers/juce_AbstractFifo.h index 8e5c90db99..ddf78e1ce2 100644 --- a/modules/juce_core/containers/juce_AbstractFifo.h +++ b/modules/juce_core/containers/juce_AbstractFifo.h @@ -42,30 +42,24 @@ namespace juce { void addToFifo (const int* someData, int numItems) { - int start1, size1, start2, size2; - abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2); - - if (size1 > 0) - copySomeData (myBuffer + start1, someData, size1); + const auto scope = abstractFifo.write (numItems); - if (size2 > 0) - copySomeData (myBuffer + start2, someData + size1, size2); + if (scope.blockSize1 > 0) + copySomeData (myBuffer + scope.startIndex1, someData, scope.blockSize1); - abstractFifo.finishedWrite (size1 + size2); + if (scope.blockSize2 > 0) + copySomeData (myBuffer + scope.startIndex2, someData, scope.blockSize2); } void readFromFifo (int* someData, int numItems) { - int start1, size1, start2, size2; - abstractFifo.prepareToRead (numItems, start1, size1, start2, size2); - - if (size1 > 0) - copySomeData (someData, myBuffer + start1, size1); + const auto scope = abstractFifo.read (numItems); - if (size2 > 0) - copySomeData (someData + size1, myBuffer + start2, size2); + if (scope.blockSize1 > 0) + copySomeData (someData, myBuffer + scope.startIndex1, scope.blockSize1); - abstractFifo.finishedRead (size1 + size2); + if (scope.blockSize2 > 0) + copySomeData (someData + scope.blockSize1, myBuffer + scope.startIndex2, scope.blockSize2); } AbstractFifo abstractFifo { 1024 }; diff --git a/modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h b/modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h new file mode 100644 index 0000000000..2963161e73 --- /dev/null +++ b/modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h @@ -0,0 +1,126 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + Encapsulates the logic for a single-threaded FIFO. + + This might be useful for building buffers which can be written and read in + blocks of different sizes. For example, in an audio effect we might wish to + run some processing on fixed-size blocks of audio input, but the host may + provide input blocks of varying sizes. In this situation, we might want to + store the previous input in a buffer, and extract a fixed-size block + whenever there are enough samples available. The SingleThreadedAbstractFifo + implements logic suitable for this use-case. + + This class is quite similar to AbstractFifo, in that it only keeps track of + the current read/write locations. The user is responsible for providing the + actual buffer that will be read/written. + + The intended usage of this class is as follows: + - Create some backing storage in a vector, AudioBuffer etc. + - Construct a SingleThreadedAbstractFifo to manage the buffer, passing the + number of items in the buffer. + - Each time new input is ready, call write(), passing the number of items + you wish to write into the buffer. This function returns a pair of ranges + describing which indices in the backing storage should be written. + - Call getNumReadable() to find out how many items are ready to read from + the buffer. + - If there are enough items ready to read, call read(), passing the number + of items you require. This function returns a pair of ranges describing + which indices in the backing storage may be read. + + Unlike AbstractFifo, the SingleThreadedAbstractFifo is intended for use + from a single thread. It is not safe to call any non-const member function + of SingleThreadedAbstractFifo concurrently with any other member function. + + @see AbstractFifo + + @tags{Core} +*/ +class SingleThreadedAbstractFifo +{ +public: + /** Creates a SingleThreadedAbstractFifo with no size. */ + SingleThreadedAbstractFifo() = default; + + /** Creates a SingleThreadedAbstractFifo that can manage a buffer of the specified size. */ + explicit SingleThreadedAbstractFifo (int sizeIn) + : size (sizeIn) + { + // This class only works properly when the size is a power of two. + // Use nextPowerOfTwo() to find a good size, and ensure that your + // backing storage is the same size. + jassert (isPowerOfTwo (sizeIn)); + } + + /** Returns the number of unused elements present in the buffer. */ + int getRemainingSpace() const { return size - numReadable; } + + /** Returns the number of pending elements present in the buffer. */ + int getNumReadable() const { return numReadable; } + + /** Returns the size of the managed buffer. */ + int getSize() const { return size; } + + /** Returns two blocks in the buffer where new items may be written. + + Note that if the buffer is running low on free space, the sum of the lengths of + the returned ranges may be less than num! + */ + std::array, 2> write (int num) + { + const auto startPos = (readPos + numReadable) & (size - 1); + const auto maxToWrite = jmin (getRemainingSpace(), num); + const auto firstBlockSize = jmin (maxToWrite, size - startPos); + + numReadable += maxToWrite; + + return { { { startPos, startPos + firstBlockSize }, { 0, maxToWrite - firstBlockSize } } }; + } + + /** Returns two blocks in the buffer from which new items may be read. + + Note that if the buffer doesn't have the requested number of items available, + the sum of the lengths of the returned ranges may be less than num! + */ + std::array, 2> read (int num) + { + const auto startPos = readPos; + const auto maxToRead = jmin (numReadable, num); + const auto firstBlockSize = jmin (maxToRead, size - startPos); + + readPos = (startPos + maxToRead) & (size - 1); + numReadable -= maxToRead; + + return { { { startPos, startPos + firstBlockSize }, { 0, maxToRead - firstBlockSize } } }; + } + +private: + int size = 0, readPos = 0, numReadable = 0; +}; + + +} // namespace juce diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 97c86bcb40..777eb583b1 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -263,6 +263,7 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "containers/juce_SortedSet.h" #include "containers/juce_SparseSet.h" #include "containers/juce_AbstractFifo.h" +#include "containers/juce_SingleThreadedAbstractFifo.h" #include "text/juce_NewLine.h" #include "text/juce_StringPool.h" #include "text/juce_Identifier.h"