fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).
This commit is contained in:
316
modules/juce_core/containers/juce_AbstractFifo.h
Normal file
316
modules/juce_core/containers/juce_AbstractFifo.h
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
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 required to implement a lock-free FIFO.
|
||||
|
||||
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||
|
||||
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||
its position and status when reading or writing to it.
|
||||
|
||||
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||
outgoing block should be read from.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
class MyFifo
|
||||
{
|
||||
public:
|
||||
MyFifo() : abstractFifo (1024)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
abstractFifo.finishedWrite (size1 + size2);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
abstractFifo.finishedRead (size1 + size2);
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo abstractFifo;
|
||||
int myBuffer [1024];
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API AbstractFifo
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||
AbstractFifo (int capacity) noexcept;
|
||||
|
||||
/** Destructor */
|
||||
~AbstractFifo();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total size of the buffer being managed. */
|
||||
int getTotalSize() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||
int getFreeSpace() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be read from the buffer. */
|
||||
int getNumReady() const noexcept;
|
||||
|
||||
/** Clears the buffer positions, so that it appears empty. */
|
||||
void reset() noexcept;
|
||||
|
||||
/** Changes the buffer's total size.
|
||||
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||
might overlap with a call to any other method in this class!
|
||||
*/
|
||||
void setTotalSize (int newSize) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||
|
||||
Because the section of data that you want to add to the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should copy your data into the first one, with any remaining data spilling over into
|
||||
the second.
|
||||
|
||||
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough space available.
|
||||
|
||||
After calling this method, if you choose to write your data into the blocks returned, you
|
||||
must call finishedWrite() to tell the FIFO how much data you actually added.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedWrite
|
||||
*/
|
||||
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after writing from the FIFO, to indicate that this many items have been added.
|
||||
@see prepareToWrite
|
||||
*/
|
||||
void finishedWrite (int numWritten) noexcept;
|
||||
|
||||
/** Returns the location within the buffer from which the next block of data should be read.
|
||||
|
||||
Because the section of data that you want to read from the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should read from both of them.
|
||||
|
||||
If the number of items you ask for is greater than the amount of data available, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough data available.
|
||||
|
||||
After calling this method, if you choose to read the data, you must call finishedRead() to
|
||||
tell the FIFO how much data you have consumed.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numWanted indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedRead
|
||||
*/
|
||||
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||
@see prepareToRead
|
||||
*/
|
||||
void finishedRead (int numRead) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
|
||||
private:
|
||||
enum class ReadOrWrite
|
||||
{
|
||||
read,
|
||||
write
|
||||
};
|
||||
|
||||
public:
|
||||
/** Class for a scoped reader/writer */
|
||||
template <ReadOrWrite mode>
|
||||
class ScopedReadWrite final
|
||||
{
|
||||
public:
|
||||
/** Construct an unassigned reader/writer. Doesn't do anything upon destruction. */
|
||||
ScopedReadWrite() = default;
|
||||
|
||||
/** Construct a reader/writer and immediately call prepareRead/prepareWrite
|
||||
on the abstractFifo which was passed in.
|
||||
This object will hold a pointer back to the fifo, so make sure that
|
||||
the fifo outlives this object.
|
||||
*/
|
||||
ScopedReadWrite (AbstractFifo&, int num) noexcept;
|
||||
|
||||
ScopedReadWrite (const ScopedReadWrite&) = delete;
|
||||
ScopedReadWrite (ScopedReadWrite&&) noexcept;
|
||||
|
||||
ScopedReadWrite& operator= (const ScopedReadWrite&) = delete;
|
||||
ScopedReadWrite& operator= (ScopedReadWrite&&) noexcept;
|
||||
|
||||
/** Calls finishedRead or finishedWrite if this is a non-null scoped
|
||||
reader/writer.
|
||||
*/
|
||||
~ScopedReadWrite() noexcept;
|
||||
|
||||
/** Calls the passed function with each index that was deemed valid
|
||||
for the current read/write operation.
|
||||
*/
|
||||
template <typename FunctionToApply>
|
||||
void forEach (FunctionToApply&& func) const
|
||||
{
|
||||
for (auto i = startIndex1, e = startIndex1 + blockSize1; i != e; ++i) func (i);
|
||||
for (auto i = startIndex2, e = startIndex2 + blockSize2; i != e; ++i) func (i);
|
||||
}
|
||||
|
||||
int startIndex1, blockSize1, startIndex2, blockSize2;
|
||||
|
||||
private:
|
||||
void prepare (AbstractFifo&, int) noexcept;
|
||||
static void finish (AbstractFifo&, int) noexcept;
|
||||
void swap (ScopedReadWrite&) noexcept;
|
||||
|
||||
AbstractFifo* fifo = nullptr;
|
||||
};
|
||||
|
||||
using ScopedRead = ScopedReadWrite<ReadOrWrite::read>;
|
||||
using ScopedWrite = ScopedReadWrite<ReadOrWrite::write>;
|
||||
|
||||
/** Replaces prepareToRead/finishedRead with a single function.
|
||||
This function returns an object which contains the start indices and
|
||||
block sizes, and also automatically finishes the read operation when
|
||||
it goes out of scope.
|
||||
@code
|
||||
{
|
||||
auto readHandle = fifo.read (4);
|
||||
|
||||
for (auto i = 0; i != readHandle.blockSize1; ++i)
|
||||
{
|
||||
// read the item at index readHandle.startIndex1 + i
|
||||
}
|
||||
|
||||
for (auto i = 0; i != readHandle.blockSize2; ++i)
|
||||
{
|
||||
// read the item at index readHandle.startIndex2 + i
|
||||
}
|
||||
} // readHandle goes out of scope here, finishing the read operation
|
||||
@endcode
|
||||
*/
|
||||
ScopedRead read (int numToRead) noexcept { return { *this, numToRead }; }
|
||||
|
||||
/** Replaces prepareToWrite/finishedWrite with a single function.
|
||||
This function returns an object which contains the start indices and
|
||||
block sizes, and also automatically finishes the write operation when
|
||||
it goes out of scope.
|
||||
@code
|
||||
{
|
||||
auto writeHandle = fifo.write (5);
|
||||
|
||||
for (auto i = 0; i != writeHandle.blockSize1; ++i)
|
||||
{
|
||||
// write the item at index writeHandle.startIndex1 + i
|
||||
}
|
||||
|
||||
for (auto i = 0; i != writeHandle.blockSize2; ++i)
|
||||
{
|
||||
// write the item at index writeHandle.startIndex2 + i
|
||||
}
|
||||
} // writeHandle goes out of scope here, finishing the write operation
|
||||
@endcode
|
||||
*/
|
||||
ScopedWrite write (int numToWrite) noexcept { return { *this, numToWrite }; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int bufferSize;
|
||||
Atomic<int> validStart, validEnd;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
|
||||
};
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user