@@ -1011,7 +1011,7 @@ static const uint32_t kAudioOutputPortOffset = MAX_PATCHBAY_PLUGINS*2; | |||||
static const uint32_t kMidiInputPortOffset = MAX_PATCHBAY_PLUGINS*3; | static const uint32_t kMidiInputPortOffset = MAX_PATCHBAY_PLUGINS*3; | ||||
static const uint32_t kMidiOutputPortOffset = MAX_PATCHBAY_PLUGINS*3+1; | static const uint32_t kMidiOutputPortOffset = MAX_PATCHBAY_PLUGINS*3+1; | ||||
static const uint kMidiChannelIndex = static_cast<uint>(AudioProcessorGraph::midiChannelIndex); | |||||
static const uint kMidiChannelIndex = static_cast<uint>(CarlaAudioProcessorGraph::midiChannelIndex); | |||||
static inline | static inline | ||||
bool adjustPatchbayPortIdForJuce(uint& portId) | bool adjustPatchbayPortIdForJuce(uint& portId) | ||||
@@ -1351,11 +1351,11 @@ private: | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Patchbay Graph | // Patchbay Graph | ||||
class NamedAudioGraphIOProcessor : public AudioProcessorGraph::AudioGraphIOProcessor | |||||
class NamedAudioGraphIOProcessor : public CarlaAudioProcessorGraph::AudioGraphIOProcessor | |||||
{ | { | ||||
public: | public: | ||||
NamedAudioGraphIOProcessor(const IODeviceType type) | NamedAudioGraphIOProcessor(const IODeviceType type) | ||||
: AudioProcessorGraph::AudioGraphIOProcessor(type) {} | |||||
: CarlaAudioProcessorGraph::AudioGraphIOProcessor(type) {} | |||||
const String getInputChannelName (int index) const override | const String getInputChannelName (int index) const override | ||||
{ | { | ||||
@@ -1431,7 +1431,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons | |||||
new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::audioInputNode)); | new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::audioInputNode)); | ||||
proc->setNames(false, channelNames); | proc->setNames(false, channelNames); | ||||
AudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
node->properties.set("isPlugin", false); | node->properties.set("isPlugin", false); | ||||
node->properties.set("isOutput", false); | node->properties.set("isOutput", false); | ||||
node->properties.set("isAudio", true); | node->properties.set("isAudio", true); | ||||
@@ -1445,7 +1445,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons | |||||
new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::audioOutputNode)); | new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::audioOutputNode)); | ||||
proc->setNames(true, channelNames); | proc->setNames(true, channelNames); | ||||
AudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
node->properties.set("isPlugin", false); | node->properties.set("isPlugin", false); | ||||
node->properties.set("isOutput", false); | node->properties.set("isOutput", false); | ||||
node->properties.set("isAudio", true); | node->properties.set("isAudio", true); | ||||
@@ -1457,7 +1457,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons | |||||
{ | { | ||||
NamedAudioGraphIOProcessor* const proc( | NamedAudioGraphIOProcessor* const proc( | ||||
new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::midiInputNode)); | new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::midiInputNode)); | ||||
AudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
node->properties.set("isPlugin", false); | node->properties.set("isPlugin", false); | ||||
node->properties.set("isOutput", false); | node->properties.set("isOutput", false); | ||||
node->properties.set("isAudio", false); | node->properties.set("isAudio", false); | ||||
@@ -1469,7 +1469,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons | |||||
{ | { | ||||
NamedAudioGraphIOProcessor* const proc( | NamedAudioGraphIOProcessor* const proc( | ||||
new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::midiOutputNode)); | new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::midiOutputNode)); | ||||
AudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.addNode(proc)); | |||||
node->properties.set("isPlugin", false); | node->properties.set("isPlugin", false); | ||||
node->properties.set("isOutput", true); | node->properties.set("isOutput", true); | ||||
node->properties.set("isAudio", false); | node->properties.set("isAudio", false); | ||||
@@ -1515,7 +1515,7 @@ void PatchbayGraph::addPlugin(CarlaPlugin* const plugin) | |||||
carla_debug("PatchbayGraph::addPlugin(%p)", plugin); | carla_debug("PatchbayGraph::addPlugin(%p)", plugin); | ||||
CarlaPluginInstance* const instance(new CarlaPluginInstance(kEngine, plugin)); | CarlaPluginInstance* const instance(new CarlaPluginInstance(kEngine, plugin)); | ||||
AudioProcessorGraph::Node* const node(graph.addNode(instance)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.addNode(instance)); | |||||
CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | ||||
plugin->setPatchbayNodeId(node->nodeId); | plugin->setPatchbayNodeId(node->nodeId); | ||||
@@ -1534,7 +1534,7 @@ void PatchbayGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* con | |||||
CARLA_SAFE_ASSERT_RETURN(oldPlugin != newPlugin,); | CARLA_SAFE_ASSERT_RETURN(oldPlugin != newPlugin,); | ||||
CARLA_SAFE_ASSERT_RETURN(oldPlugin->getId() == newPlugin->getId(),); | CARLA_SAFE_ASSERT_RETURN(oldPlugin->getId() == newPlugin->getId(),); | ||||
AudioProcessorGraph::Node* const oldNode(graph.getNodeForId(oldPlugin->getPatchbayNodeId())); | |||||
CarlaAudioProcessorGraph::Node* const oldNode(graph.getNodeForId(oldPlugin->getPatchbayNodeId())); | |||||
CARLA_SAFE_ASSERT_RETURN(oldNode != nullptr,); | CARLA_SAFE_ASSERT_RETURN(oldNode != nullptr,); | ||||
if (! usingExternal) | if (! usingExternal) | ||||
@@ -1548,7 +1548,7 @@ void PatchbayGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* con | |||||
graph.removeNode(oldNode->nodeId); | graph.removeNode(oldNode->nodeId); | ||||
CarlaPluginInstance* const instance(new CarlaPluginInstance(kEngine, newPlugin)); | CarlaPluginInstance* const instance(new CarlaPluginInstance(kEngine, newPlugin)); | ||||
AudioProcessorGraph::Node* const node(graph.addNode(instance)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.addNode(instance)); | |||||
CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | ||||
newPlugin->setPatchbayNodeId(node->nodeId); | newPlugin->setPatchbayNodeId(node->nodeId); | ||||
@@ -1565,7 +1565,7 @@ void PatchbayGraph::renamePlugin(CarlaPlugin* const plugin, const char* const ne | |||||
CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | ||||
carla_debug("PatchbayGraph::renamePlugin(%p)", plugin, newName); | carla_debug("PatchbayGraph::renamePlugin(%p)", plugin, newName); | ||||
AudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | ||||
if (! usingExternal) | if (! usingExternal) | ||||
@@ -1577,7 +1577,7 @@ void PatchbayGraph::removePlugin(CarlaPlugin* const plugin) | |||||
CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | ||||
carla_debug("PatchbayGraph::removePlugin(%p)", plugin); | carla_debug("PatchbayGraph::removePlugin(%p)", plugin); | ||||
AudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | ||||
if (! usingExternal) | if (! usingExternal) | ||||
@@ -1594,7 +1594,7 @@ void PatchbayGraph::removePlugin(CarlaPlugin* const plugin) | |||||
CarlaPlugin* const plugin2(kEngine->getPlugin(i)); | CarlaPlugin* const plugin2(kEngine->getPlugin(i)); | ||||
CARLA_SAFE_ASSERT_BREAK(plugin2 != nullptr); | CARLA_SAFE_ASSERT_BREAK(plugin2 != nullptr); | ||||
if (AudioProcessorGraph::Node* const node2 = graph.getNodeForId(plugin2->getPatchbayNodeId())) | |||||
if (CarlaAudioProcessorGraph::Node* const node2 = graph.getNodeForId(plugin2->getPatchbayNodeId())) | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_CONTINUE(node2->properties.getWithDefault("pluginId", -1) != juce::var(-1)); | CARLA_SAFE_ASSERT_CONTINUE(node2->properties.getWithDefault("pluginId", -1) != juce::var(-1)); | ||||
node2->properties.set("pluginId", static_cast<int>(i-1)); | node2->properties.set("pluginId", static_cast<int>(i-1)); | ||||
@@ -1613,7 +1613,7 @@ void PatchbayGraph::removeAllPlugins() | |||||
CarlaPlugin* const plugin(kEngine->getPlugin(i)); | CarlaPlugin* const plugin(kEngine->getPlugin(i)); | ||||
CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr); | ||||
AudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
CARLA_SAFE_ASSERT_CONTINUE(node != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(node != nullptr); | ||||
if (! usingExternal) | if (! usingExternal) | ||||
@@ -1744,7 +1744,7 @@ void PatchbayGraph::refresh(const char* const deviceName) | |||||
for (int i=0, count=graph.getNumNodes(); i<count; ++i) | for (int i=0, count=graph.getNumNodes(); i<count; ++i) | ||||
{ | { | ||||
AudioProcessorGraph::Node* const node(graph.getNode(i)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.getNode(i)); | |||||
CARLA_SAFE_ASSERT_CONTINUE(node != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(node != nullptr); | ||||
AudioProcessor* const proc(node->getProcessor()); | AudioProcessor* const proc(node->getProcessor()); | ||||
@@ -1764,7 +1764,7 @@ void PatchbayGraph::refresh(const char* const deviceName) | |||||
for (int i=0, count=graph.getNumConnections(); i<count; ++i) | for (int i=0, count=graph.getNumConnections(); i<count; ++i) | ||||
{ | { | ||||
const AudioProcessorGraph::Connection* const conn(graph.getConnection(i)); | |||||
const CarlaAudioProcessorGraph::Connection* const conn(graph.getConnection(i)); | |||||
CARLA_SAFE_ASSERT_CONTINUE(conn != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(conn != nullptr); | ||||
CARLA_SAFE_ASSERT_CONTINUE(conn->sourceChannelIndex >= 0); | CARLA_SAFE_ASSERT_CONTINUE(conn->sourceChannelIndex >= 0); | ||||
CARLA_SAFE_ASSERT_CONTINUE(conn->destChannelIndex >= 0); | CARLA_SAFE_ASSERT_CONTINUE(conn->destChannelIndex >= 0); | ||||
@@ -1813,10 +1813,10 @@ const char* const* PatchbayGraph::getConnections(const bool external) const | |||||
const ConnectionToId& connectionToId(it.getValue(fallback)); | const ConnectionToId& connectionToId(it.getValue(fallback)); | ||||
CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id > 0); | CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id > 0); | ||||
AudioProcessorGraph::Node* const nodeA(graph.getNodeForId(connectionToId.groupA)); | |||||
CarlaAudioProcessorGraph::Node* const nodeA(graph.getNodeForId(connectionToId.groupA)); | |||||
CARLA_SAFE_ASSERT_CONTINUE(nodeA != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(nodeA != nullptr); | ||||
AudioProcessorGraph::Node* const nodeB(graph.getNodeForId(connectionToId.groupB)); | |||||
CarlaAudioProcessorGraph::Node* const nodeB(graph.getNodeForId(connectionToId.groupB)); | |||||
CARLA_SAFE_ASSERT_CONTINUE(nodeB != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(nodeB != nullptr); | ||||
AudioProcessor* const procA(nodeA->getProcessor()); | AudioProcessor* const procA(nodeA->getProcessor()); | ||||
@@ -1853,7 +1853,7 @@ bool PatchbayGraph::getGroupAndPortIdFromFullName(const bool external, const cha | |||||
for (int i=0, count=graph.getNumNodes(); i<count; ++i) | for (int i=0, count=graph.getNumNodes(); i<count; ++i) | ||||
{ | { | ||||
AudioProcessorGraph::Node* const node(graph.getNode(i)); | |||||
CarlaAudioProcessorGraph::Node* const node(graph.getNode(i)); | |||||
CARLA_SAFE_ASSERT_CONTINUE(node != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(node != nullptr); | ||||
AudioProcessor* const proc(node->getProcessor()); | AudioProcessor* const proc(node->getProcessor()); | ||||
@@ -25,7 +25,12 @@ | |||||
#include "juce_audio_processors/juce_audio_processors.h" | #include "juce_audio_processors/juce_audio_processors.h" | ||||
using juce::AudioProcessorGraph; | |||||
#if 0 | |||||
typedef juce::AudioProcessorGraph CarlaAudioProcessorGraph; | |||||
#else | |||||
typedef juce::AudioProcessorGraphMultiThreaded CarlaAudioProcessorGraph; | |||||
#endif | |||||
using juce::AudioSampleBuffer; | using juce::AudioSampleBuffer; | ||||
using juce::MidiBuffer; | using juce::MidiBuffer; | ||||
@@ -147,7 +152,7 @@ struct RackGraph { | |||||
struct PatchbayGraph { | struct PatchbayGraph { | ||||
PatchbayConnectionList connections; | PatchbayConnectionList connections; | ||||
AudioProcessorGraph graph; | |||||
CarlaAudioProcessorGraph graph; | |||||
AudioSampleBuffer audioBuffer; | AudioSampleBuffer audioBuffer; | ||||
MidiBuffer midiBuffer; | MidiBuffer midiBuffer; | ||||
const uint32_t inputs; | const uint32_t inputs; | ||||
@@ -153,6 +153,7 @@ void AutoResizingNSViewComponentWithParent::timerCallback() | |||||
#include "processors/juce_AudioProcessorGraph.cpp" | #include "processors/juce_AudioProcessorGraph.cpp" | ||||
#include "processors/juce_GenericAudioProcessorEditor.cpp" | #include "processors/juce_GenericAudioProcessorEditor.cpp" | ||||
#include "processors/juce_PluginDescription.cpp" | #include "processors/juce_PluginDescription.cpp" | ||||
#include "processors/AudioProcessorGraphMultiThreaded.cpp" | |||||
#include "format_types/juce_LADSPAPluginFormat.cpp" | #include "format_types/juce_LADSPAPluginFormat.cpp" | ||||
#include "format_types/juce_VSTPluginFormat.cpp" | #include "format_types/juce_VSTPluginFormat.cpp" | ||||
#include "format_types/juce_VST3PluginFormat.cpp" | #include "format_types/juce_VST3PluginFormat.cpp" | ||||
@@ -83,6 +83,7 @@ class AudioProcessor; | |||||
#include "processors/juce_AudioPluginInstance.h" | #include "processors/juce_AudioPluginInstance.h" | ||||
#include "processors/juce_AudioProcessorGraph.h" | #include "processors/juce_AudioProcessorGraph.h" | ||||
#include "processors/juce_GenericAudioProcessorEditor.h" | #include "processors/juce_GenericAudioProcessorEditor.h" | ||||
#include "processors/AudioProcessorGraphMultiThreaded.h" | |||||
#include "format/juce_AudioPluginFormat.h" | #include "format/juce_AudioPluginFormat.h" | ||||
#include "format/juce_AudioPluginFormatManager.h" | #include "format/juce_AudioPluginFormatManager.h" | ||||
#include "scanning/juce_KnownPluginList.h" | #include "scanning/juce_KnownPluginList.h" | ||||
@@ -0,0 +1,484 @@ | |||||
/* | |||||
============================================================================== | |||||
AudioProcessorGraphMultiThreaded.h | |||||
Created: 26 Nov 2012 11:35:49am | |||||
Author: Christian | |||||
============================================================================== | |||||
*/ | |||||
#ifndef __AUDIOPROCESSORGRAPHMULTIMULTITHREADED_H_8E3C7DF3__ | |||||
#define __AUDIOPROCESSORGRAPHMULTIMULTITHREADED_H_8E3C7DF3__ | |||||
class AudioProcessorGraphMultiThreaded : public AudioProcessor, private AsyncUpdater | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
/** Creates an empty graph. */ | |||||
AudioProcessorGraphMultiThreaded(); | |||||
/** Destructor. | |||||
Any processor objects that have been added to the graph will also be deleted. | |||||
*/ | |||||
~AudioProcessorGraphMultiThreaded(); | |||||
void startAllThreads(); | |||||
void stopAllThreads(); | |||||
//============================================================================== | |||||
/** Represents a connection between two channels of two nodes in an AudioProcessorGraph. | |||||
To create a connection, use AudioProcessorGraph::addConnection(). | |||||
*/ | |||||
struct JUCE_API Connection | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
Connection (uint32 sourceNodeId, int sourceChannelIndex, | |||||
uint32 destNodeId, int destChannelIndex) noexcept; | |||||
//============================================================================== | |||||
/** The ID number of the node which is the input source for this connection. | |||||
@see AudioProcessorGraph::getNodeForId | |||||
*/ | |||||
uint32 sourceNodeId; | |||||
/** The index of the output channel of the source node from which this | |||||
connection takes its data. | |||||
If this value is the special number AudioProcessorGraph::midiChannelIndex, then | |||||
it is referring to the source node's midi output. Otherwise, it is the zero-based | |||||
index of an audio output channel in the source node. | |||||
*/ | |||||
int sourceChannelIndex; | |||||
/** The ID number of the node which is the destination for this connection. | |||||
@see AudioProcessorGraph::getNodeForId | |||||
*/ | |||||
uint32 destNodeId; | |||||
/** The index of the input channel of the destination node to which this | |||||
connection delivers its data. | |||||
If this value is the special number AudioProcessorGraph::midiChannelIndex, then | |||||
it is referring to the destination node's midi input. Otherwise, it is the zero-based | |||||
index of an audio input channel in the destination node. | |||||
*/ | |||||
int destChannelIndex; | |||||
private: | |||||
//============================================================================== | |||||
JUCE_LEAK_DETECTOR (Connection); | |||||
}; | |||||
//============================================================================== | |||||
/** Represents one of the nodes, or processors, in an AudioProcessorGraph. | |||||
To create a node, call AudioProcessorGraph::addNode(). | |||||
*/ | |||||
class JUCE_API Node : public ReferenceCountedObject | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
/** The ID number assigned to this node. | |||||
This is assigned by the graph that owns it, and can't be changed. | |||||
*/ | |||||
const uint32 nodeId; | |||||
Node (uint32 nodeId, AudioProcessor*, AudioProcessorGraphMultiThreaded& graph_) noexcept; | |||||
virtual ~Node() {}; | |||||
void prepare (double sampleRate, int blockSize); | |||||
void updateMyConnections(); | |||||
bool process(); | |||||
void reset(); | |||||
void unprepare(); | |||||
bool hasReachedNumberOfRequiredInputs(); | |||||
void clearRef() | |||||
{ | |||||
requiredInputs.clear(); | |||||
outputNodesToInform.clear(); | |||||
} | |||||
/** The actual processor object that this node represents. */ | |||||
AudioProcessor* getProcessor() const noexcept { return processor; } | |||||
/** A set of user-definable properties that are associated with this node. | |||||
This can be used to attach values to the node for whatever purpose seems | |||||
useful. For example, you might store an x and y position if your application | |||||
is displaying the nodes on-screen. | |||||
*/ | |||||
NamedValueSet properties; | |||||
//============================================================================== | |||||
/** A convenient typedef for referring to a pointer to a node object. */ | |||||
typedef ReferenceCountedObjectPtr <Node> Ptr; | |||||
void setParentGraph (AudioProcessorGraphMultiThreaded* graph) const; | |||||
int getNumRequiredInputs();; | |||||
bool isProcessingDone();; | |||||
private: | |||||
//============================================================================== | |||||
class NodeChannel | |||||
{ | |||||
public: | |||||
ScopedPointer<AudioProcessorGraphMultiThreaded::Connection> inputConnection; | |||||
Node::Ptr node; | |||||
}; | |||||
OwnedArray<NodeChannel> requiredInputs; | |||||
OwnedArray<NodeChannel> outputNodesToInform; | |||||
Atomic<int> numberOfProcessedInputs; | |||||
bool processingDone; | |||||
CriticalSection nodeLock; | |||||
const ScopedPointer<AudioProcessor> processor; | |||||
ScopedPointer<AudioSampleBuffer> buffer; | |||||
bool isPrepared; | |||||
AudioProcessorGraphMultiThreaded& graph; | |||||
MidiBuffer midiFakeBufferNotImplemented; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node); | |||||
}; | |||||
class WorkerThread : public Thread | |||||
{ | |||||
public: | |||||
WorkerThread(AudioProcessorGraphMultiThreaded& _graph) : | |||||
Thread("AudioProcessingThread"), | |||||
graph(_graph) {}; | |||||
virtual ~WorkerThread() {}; | |||||
void run() | |||||
{ | |||||
while (!threadShouldExit()) | |||||
{ | |||||
graph.processOneNode(false); | |||||
} | |||||
} | |||||
AudioProcessorGraphMultiThreaded& graph; | |||||
}; | |||||
void processOneNode(bool thisIsAudioCallbackThread); | |||||
//============================================================================== | |||||
/** Deletes all nodes and connections from this graph. | |||||
Any processor objects in the graph will be deleted. | |||||
*/ | |||||
void clear(); | |||||
/** Returns the number of nodes in the graph. */ | |||||
int getNumNodes() const; | |||||
/** Returns a pointer to one of the nodes in the graph. | |||||
This will return nullptr if the index is out of range. | |||||
@see getNodeForId | |||||
*/ | |||||
Node* getNode (const int index) const; | |||||
/** Searches the graph for a node with the given ID number and returns it. | |||||
If no such node was found, this returns nullptr. | |||||
@see getNode | |||||
*/ | |||||
Node* getNodeForId (const uint32 nodeId) const; | |||||
Node::Ptr getNodeRefPtrForId (const uint32 nodeId) const; | |||||
/** Adds a node to the graph. | |||||
This creates a new node in the graph, for the specified processor. Once you have | |||||
added a processor to the graph, the graph owns it and will delete it later when | |||||
it is no longer needed. | |||||
The optional nodeId parameter lets you specify an ID to use for the node, but | |||||
if the value is already in use, this new node will overwrite the old one. | |||||
If this succeeds, it returns a pointer to the newly-created node. | |||||
*/ | |||||
Node* addNode (AudioProcessor* newProcessor, uint32 nodeId = 0); | |||||
/** Deletes a node within the graph which has the specified ID. | |||||
This will also delete any connections that are attached to this node. | |||||
*/ | |||||
bool removeNode (uint32 nodeId); | |||||
//============================================================================== | |||||
/** Returns the number of connections in the graph. */ | |||||
int getNumConnections() const { return connections.size(); } | |||||
/** Returns a pointer to one of the connections in the graph. */ | |||||
const Connection* getConnection (int index) const { return connections [index]; } | |||||
/** Searches for a connection between some specified channels. | |||||
If no such connection is found, this returns nullptr. | |||||
*/ | |||||
const Connection* getConnectionBetween (uint32 sourceNodeId, | |||||
int sourceChannelIndex, | |||||
uint32 destNodeId, | |||||
int destChannelIndex) const; | |||||
int calculateInputConnections(uint32 nodeID) const; | |||||
/** Returns true if there is a connection between any of the channels of | |||||
two specified nodes. | |||||
*/ | |||||
bool isConnected (uint32 possibleSourceNodeId, | |||||
uint32 possibleDestNodeId) const; | |||||
/** Returns true if it would be legal to connect the specified points. */ | |||||
bool canConnect (uint32 sourceNodeId, int sourceChannelIndex, | |||||
uint32 destNodeId, int destChannelIndex) const; | |||||
/** Attempts to connect two specified channels of two nodes. | |||||
If this isn't allowed (e.g. because you're trying to connect a midi channel | |||||
to an audio one or other such nonsense), then it'll return false. | |||||
*/ | |||||
bool addConnection (uint32 sourceNodeId, int sourceChannelIndex, | |||||
uint32 destNodeId, int destChannelIndex); | |||||
/** Deletes the connection with the specified index. */ | |||||
void removeConnection (int index); | |||||
/** Deletes any connection between two specified points. | |||||
Returns true if a connection was actually deleted. | |||||
*/ | |||||
bool removeConnection (uint32 sourceNodeId, int sourceChannelIndex, | |||||
uint32 destNodeId, int destChannelIndex); | |||||
/** Removes all connections from the specified node. */ | |||||
bool disconnectNode (uint32 nodeId); | |||||
/** Returns true if the given connection's channel numbers map on to valid | |||||
channels at each end. | |||||
Even if a connection is valid when created, its status could change if | |||||
a node changes its channel config. | |||||
*/ | |||||
bool isConnectionLegal (const Connection* connection) const; | |||||
/** Performs a sanity checks of all the connections. | |||||
This might be useful if some of the processors are doing things like changing | |||||
their channel counts, which could render some connections obsolete. | |||||
*/ | |||||
bool removeIllegalConnections(); | |||||
//============================================================================== | |||||
/** A special number that represents the midi channel of a node. | |||||
This is used as a channel index value if you want to refer to the midi input | |||||
or output instead of an audio channel. | |||||
*/ | |||||
static const int midiChannelIndex; | |||||
//============================================================================== | |||||
/** A special type of AudioProcessor that can live inside an AudioProcessorGraph | |||||
in order to use the audio that comes into and out of the graph itself. | |||||
If you create an AudioGraphIOProcessor in "input" mode, it will act as a | |||||
node in the graph which delivers the audio that is coming into the parent | |||||
graph. This allows you to stream the data to other nodes and process the | |||||
incoming audio. | |||||
Likewise, one of these in "output" mode can be sent data which it will add to | |||||
the sum of data being sent to the graph's output. | |||||
@see AudioProcessorGraph | |||||
*/ | |||||
class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance | |||||
{ | |||||
public: | |||||
/** Specifies the mode in which this processor will operate. | |||||
*/ | |||||
enum IODeviceType | |||||
{ | |||||
audioInputNode, /**< In this mode, the processor has output channels | |||||
representing all the audio input channels that are | |||||
coming into its parent audio graph. */ | |||||
audioOutputNode, /**< In this mode, the processor has input channels | |||||
representing all the audio output channels that are | |||||
going out of its parent audio graph. */ | |||||
midiInputNode, /**< In this mode, the processor has a midi output which | |||||
delivers the same midi data that is arriving at its | |||||
parent graph. */ | |||||
midiOutputNode /**< In this mode, the processor has a midi input and | |||||
any data sent to it will be passed out of the parent | |||||
graph. */ | |||||
}; | |||||
//============================================================================== | |||||
/** Returns the mode of this processor. */ | |||||
IODeviceType getType() const { return type; } | |||||
/** Returns the parent graph to which this processor belongs, or nullptr if it | |||||
hasn't yet been added to one. */ | |||||
AudioProcessorGraphMultiThreaded* getParentGraph() const { return graph; } | |||||
/** True if this is an audio or midi input. */ | |||||
bool isInput() const; | |||||
/** True if this is an audio or midi output. */ | |||||
bool isOutput() const; | |||||
bool isAudioOutputNode() const; | |||||
//============================================================================== | |||||
AudioGraphIOProcessor (const IODeviceType type); | |||||
~AudioGraphIOProcessor(); | |||||
const String getName() const; | |||||
void fillInPluginDescription (PluginDescription&) const; | |||||
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); | |||||
void releaseResources(); | |||||
void processBlock (AudioSampleBuffer&, MidiBuffer&); | |||||
const String getInputChannelName (int channelIndex) const; | |||||
const String getOutputChannelName (int channelIndex) const; | |||||
bool isInputChannelStereoPair (int index) const; | |||||
bool isOutputChannelStereoPair (int index) const; | |||||
bool silenceInProducesSilenceOut() const; | |||||
bool acceptsMidi() const; | |||||
bool producesMidi() const; | |||||
bool hasEditor() const; | |||||
AudioProcessorEditor* createEditor(); | |||||
int getNumParameters(); | |||||
const String getParameterName (int); | |||||
float getParameter (int); | |||||
const String getParameterText (int); | |||||
void setParameter (int, float); | |||||
double getTailLengthSeconds() const;; | |||||
int getNumPrograms(); | |||||
int getCurrentProgram(); | |||||
void setCurrentProgram (int); | |||||
const String getProgramName (int); | |||||
void changeProgramName (int, const String&); | |||||
void getStateInformation (juce::MemoryBlock& destData); | |||||
void setStateInformation (const void* data, int sizeInBytes); | |||||
/** @internal */ | |||||
void setParentGraph (AudioProcessorGraphMultiThreaded*); | |||||
private: | |||||
const IODeviceType type; | |||||
AudioProcessorGraphMultiThreaded* graph; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioGraphIOProcessor); | |||||
}; | |||||
//============================================================================== | |||||
// AudioProcessor methods: | |||||
const String getName() const; | |||||
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); | |||||
void releaseResources(); | |||||
void processBlock (AudioSampleBuffer&, MidiBuffer&); | |||||
const String getInputChannelName (int channelIndex) const; | |||||
const String getOutputChannelName (int channelIndex) const; | |||||
bool isInputChannelStereoPair (int index) const; | |||||
bool isOutputChannelStereoPair (int index) const; | |||||
bool silenceInProducesSilenceOut() const; | |||||
bool acceptsMidi() const; | |||||
bool producesMidi() const; | |||||
bool hasEditor() const { return false; } | |||||
AudioProcessorEditor* createEditor() { return nullptr; } | |||||
int getNumParameters() { return 0; } | |||||
const String getParameterName (int) { return String::empty; } | |||||
float getParameter (int) { return 0; } | |||||
const String getParameterText (int) { return String::empty; } | |||||
void setParameter (int, float) { } | |||||
int getNumPrograms() { return 0; } | |||||
int getCurrentProgram() { return 0; } | |||||
void setCurrentProgram (int) { } | |||||
const String getProgramName (int) { return String::empty; } | |||||
void changeProgramName (int, const String&) { } | |||||
void getStateInformation (juce::MemoryBlock&); | |||||
void setStateInformation (const void* data, int sizeInBytes); | |||||
double getTailLengthSeconds() const;; | |||||
CriticalSection& getConfigurationLock() | |||||
{ | |||||
return reconfigurationLock; | |||||
} | |||||
bool nodeProcessingActive; | |||||
private: | |||||
//============================================================================== | |||||
Atomic<uint32> nextNodeIteritater; | |||||
int nothingHappenedCounter; // Is not atomic, because integrity isn't so important | |||||
WaitableEvent waitEvent; | |||||
ReferenceCountedArray <Node> nodes_original; | |||||
ReferenceCountedArray <Node> nodes_workingCopy; | |||||
OwnedArray <Connection> connections; | |||||
uint32 lastNodeId; | |||||
AudioSampleBuffer renderingBuffers; | |||||
OwnedArray <MidiBuffer> midiBuffers; | |||||
CriticalSection renderLock; | |||||
CriticalSection reconfigurationLock; | |||||
friend class AudioGraphIOProcessor; | |||||
AudioSampleBuffer* currentAudioInputBuffer; | |||||
AudioSampleBuffer currentAudioOutputBuffer; | |||||
MidiBuffer* currentMidiInputBuffer; | |||||
MidiBuffer currentMidiOutputBuffer; | |||||
void handleAsyncUpdate(); | |||||
void buildRenderingSequence(); | |||||
bool isAnInputTo (uint32 possibleInputId, uint32 possibleDestinationId, int recursionCheck) const; | |||||
OwnedArray<WorkerThread> workerThreads; | |||||
Node::Ptr outputNode; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorGraphMultiThreaded); | |||||
}; | |||||
#endif // __CK_AUDIOPROCESSORGRAPHMULTIPROCESSOR_H_8E3C7DF3__ |
@@ -34,6 +34,7 @@ namespace juce { | |||||
#include "juce_audio_processors/processors/juce_AudioChannelSet.cpp" | #include "juce_audio_processors/processors/juce_AudioChannelSet.cpp" | ||||
#include "juce_audio_processors/processors/juce_AudioProcessor.cpp" | #include "juce_audio_processors/processors/juce_AudioProcessor.cpp" | ||||
#include "juce_audio_processors/processors/juce_AudioProcessorGraph.cpp" | #include "juce_audio_processors/processors/juce_AudioProcessorGraph.cpp" | ||||
#include "juce_audio_processors/processors/AudioProcessorGraphMultiThreaded.cpp" | |||||
class JuceEventsThread : public Thread | class JuceEventsThread : public Thread | ||||
{ | { | ||||