Very Basic Usage of AudioProcessorGraph


#1

Hello,

I’m trying to figure out how to use AudioProcessorGraph.
I made simple plugin following this post.

Signal path is like this

Audio In —> myProcessor ------> Audio Out

private:

AudioProcessorGraph  myGraph_;
AudioProcessorGraph::AudioGraphIOProcessor*     ioProcIn_;
AudioProcessorGraph::AudioGraphIOProcessor*     ioProcOut_;
AudioProcessorGraph::AudioGraphIOProcessor*     ioProcMidiIn_;
AudioProcessorGraph::AudioGraphIOProcessor*     ioProcMidiOut_;

AudioProcessorGraph::Node::Ptr                  ioProcInNode_;
AudioProcessorGraph::Node::Ptr                  ioProcOutNode_;
AudioProcessorGraph::Node::Ptr                  ioProcMidiInNode_;
AudioProcessorGraph::Node::Ptr                  ioProcMidiOutNode_;

MyAudioProcessor* myProcessor;

constructor:
ioProcIn_ = new AudioProcessorGraph::AudioGraphIOProcessor
(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode);
ioProcOut_ = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode);
ioProcMidiIn_ = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);
ioProcInNode_ = myGraph_.addNode(ioProcIn_);
ioProcOutNode_ = myGraph_.addNode (ioProcOut_);
ioProcMidiInNode_ = myGraph_.addNode (ioProcMidiIn_);

    AudioProcessorGraph::Node* sbNode = myGraph_.addNode (myProcessor = new MyAudioProcessor());
    myProcessor->setNodeID (sbNode->nodeId);

prepareToPlay:

myGraph_.setPlayConfigDetails (getTotalNumInputChannels(), getTotalNumOutputChannels(), sampleRate, samplesPerBlock);
myGraph_.prepareToPlay (sampleRate, samplesPerBlock);

myGraph_.addConnection (myProcessor->getNodeID(), 0, ioProcOutNode_->nodeId, 0);
myGraph_.addConnection (myProcessor->getNodeID(), 1, ioProcOutNode_->nodeId, 1);

processBlock:
myGraph_.processBlock (buffer, midiMessages);

My plugin crashes immediately.

error log:

Thread 6 Crashed:: com.apple.audio.IOThread.client
0 com.roli.pluginhost 0x000000010502c35c void juce::AudioProcessorGraph::processAudio(juce::AudioBuffer&, juce::MidiBuffer&) + 332
1 com.yourcompany.AudioGraphTest 0x000000010d997845 juce::AudioProcessorGraph::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 37 (juce_AudioProcessorGraph.cpp:1496)
2 com.yourcompany.AudioGraphTest 0x000000010d93ee3a AudioGraphTestAudioProcessor::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 74 (PluginProcessor.cpp:185)
3 com.yourcompany.AudioGraphTest 0x000000010d93b776 void JuceVSTWrapper::internalProcessReplacing(float**, float**, int, JuceVSTWrapper::VstTempBuffers&) + 1302 (juce_VST_Wrapper.cpp:475)
4 com.yourcompany.AudioGraphTest 0x000000010d93b235 JuceVSTWrapper::processReplacing(float**, float**, int) + 149 (juce_VST_Wrapper.cpp:533)
5 com.yourcompany.AudioGraphTest 0x000000010d930fb3 JuceVSTWrapper::processReplacingCB(VstEffectInterface*, float**, float**, int) + 51 (juce_VST_Wrapper.cpp:538)
6 com.roli.pluginhost 0x00000001050879ac juce::VSTPluginInstance::invokeProcessFunction(juce::AudioBuffer&, int) + 124
7 com.roli.pluginhost 0x0000000105087582 void juce::VSTPluginInstance::processAudio(juce::AudioBuffer&, juce::MidiBuffer&) + 1186
8 com.roli.pluginhost 0x0000000105039f2e juce::VSTPluginInstance::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 126
9 com.roli.pluginhost 0x0000000105048da6 juce::GraphRenderingOps::ProcessBufferOp::callProcess(juce::AudioBuffer&, juce::MidiBuffer&) + 70
10 com.roli.pluginhost 0x0000000105048cfb void juce::GraphRenderingOps::ProcessBufferOp::perform(juce::AudioBuffer&, juce::OwnedArray<juce::MidiBuffer, juce::DummyCriticalSection> const&, int) + 267
11 com.roli.pluginhost 0x0000000105048986 juce::GraphRenderingOps::AudioGraphRenderingOpjuce::GraphRenderingOps::ProcessBufferOp::perform(juce::AudioBuffer&, juce::OwnedArray<juce::MidiBuffer, juce::DummyCriticalSection> const&, int) + 54
12 com.roli.pluginhost 0x000000010502c388 void juce::AudioProcessorGraph::processAudio(juce::AudioBuffer&, juce::MidiBuffer&) + 376
13 com.roli.pluginhost 0x0000000104ff9535 juce::AudioProcessorGraph::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 37
14 com.roli.pluginhost 0x00000001050b9fac juce::AudioProcessorPlayer::audioDeviceIOCallback(float const**, int, float**, int, int) + 1372
15 com.roli.pluginhost 0x0000000104fa4175 juce::AudioDeviceManager::audioDeviceIOCallbackInt(float const**, int, float**, int, int) + 693
16 com.roli.pluginhost 0x0000000104facaaf juce::AudioDeviceManager::CallbackHandler::audioDeviceIOCallback(float const**, int, float**, int, int) + 63
17 com.roli.pluginhost 0x0000000104fb5dfb juce::CoreAudioClasses::CoreAudioInternal::audioCallback(AudioBufferList const*, AudioBufferList*) + 475
18 com.roli.pluginhost 0x0000000104fb5c0b juce::CoreAudioClasses::CoreAudioInternal::audioIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*) + 59
19 com.apple.audio.CoreAudio 0x00007fffd32668ce HALC_ProxyIOContext::IOWorkLoop() + 5290
20 com.apple.audio.CoreAudio 0x00007fffd3265264 HALC_ProxyIOContext::IOThreadEntry(void*) + 128
21 com.apple.audio.CoreAudio 0x00007fffd3264fa3 HALB_IOThread::Entry(void*) + 75
22 libsystem_pthread.dylib 0x00007fffe90799af _pthread_body + 180
23 libsystem_pthread.dylib 0x00007fffe90798fb _pthread_start + 286
24 libsystem_pthread.dylib 0x00007fffe9079101 thread_start + 13

//==========================================================
Could anyone point me what is wrong?

Thank you for your help.


#2

Check out my post in the now deprecated thread:

Rail


#3

Thank you for your reply.

I just tried your code.
But I got some errors.

/JUCE/examples/PlugInSamples/MultiOutSynth/Source/MultiOutSynth.cpp:83:72: Only virtual member functions can be marked 'override'

It seems all those are related to setPreferredBusArrangement.

setPreferredBusArrangement is no longer available?
I’m on Projucer v4.3.1.

Thank you for your help.


#4

Yes, that code in JUCE is deprecated… but the code on how to integrate the AudioProcessorGraph is still the same… so there’s enough in there to show you what to do with a new 4.3.1 JUCE project

Rail


#5

Sorry I didn’t know the “deprecated” means.

I modified my code by referring to yours.
But still no luck.

AudioGraphTestAudioProcessor::AudioGraphTestAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       ),
#endif
:
myGraph_(new AudioProcessorGraph)
{
    myGraph_->setPlayConfigDetails (getTotalNumInputChannels(), getTotalNumOutputChannels(), 44100.0, 512);
    
    ioProcIn_         = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode);
    ioProcOut_        = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode);
    ioProcMidiIn_     = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);
    ioProcMidiOut_    = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);
    
    ioProcInNode_     = myGraph_->addNode (ioProcIn_);
    ioProcOutNode_    = myGraph_->addNode (ioProcOut_);
    ioProcMidiInNode_ = myGraph_->addNode (ioProcMidiIn_);
    ioProcMidiOutNode_= myGraph_->addNode (ioProcMidiOut_);
    
    myGraph_->addConnection (ioProcMidiInNode_->nodeId,  juce::AudioProcessorGraph::midiChannelIndex,
                             ioProcMidiOutNode_->nodeId, juce::AudioProcessorGraph::midiChannelIndex);
    
    myAudioProcessor_ = new MyAudioProcessor();
    myAudioProcessor_->setPlayConfigDetails (getTotalNumInputChannels(), getTotalNumOutputChannels(), 44100.0, 512);
    myAudioUnit_ = myGraph_->addNode(myAudioProcessor_);
    
    myGraph_->addConnection(ioProcInNode_->nodeId, 0, myAudioUnit_->nodeId, 0);
    myGraph_->addConnection(ioProcInNode_->nodeId, 1, myAudioUnit_->nodeId, 1);
    
    myGraph_->addConnection(myAudioUnit_->nodeId, 0, ioProcOutNode_->nodeId, 0);
    myGraph_->addConnection(myAudioUnit_->nodeId, 1, ioProcOutNode_->nodeId, 1);

}

AudioGraphTestAudioProcessor::~AudioGraphTestAudioProcessor(){}


void AudioGraphTestAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    ignoreUnused (samplesPerBlock);
    
    myGraph_->setRateAndBufferSizeDetails (sampleRate, samplesPerBlock);
    myGraph_->prepareToPlay (sampleRate, samplesPerBlock);
}

void AudioGraphTestAudioProcessor::releaseResources()
{
    myGraph_->releaseResources();
}

void AudioGraphTestAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    myGraph_->processBlock(buffer, midiMessages);
}

myGraph_->processBlock(buffer, midiMessages);

Is this OK?

If I do this, my plugin doesn’t crash.
myAudioProcessor_->processBlock(buffer, midiMessages);

But with this way AudioProcessorGraph doesn’t do anything.


#6

Instead of an AudioProcessor you’d need an AudioPluginInstance object if you’re trying to host a plugin

Rail


#7

My goal is handling my effect processors with AudioProcessorGraph.
So I need to figure out how to handle AudioProcessor with AudioProcessorGraph.

I tried to make very simple signal path with AudioProcessorGraph.

Inside of my plugin:
audio in —> myAudioProcessor ----> audio out

    myAudioProcessor_ = new MyAudioProcessor();
    myAudioProcessor_->setPlayConfigDetails (getTotalNumInputChannels(), getTotalNumOutputChannels(), 44100.0, 512);
    myAudioUnit_ = myGraph_->addNode(myAudioProcessor_);
    
    myGraph_->addConnection(ioProcInNode_->nodeId, 0, myAudioUnit_->nodeId, 0);
    myGraph_->addConnection(ioProcInNode_->nodeId, 1, myAudioUnit_->nodeId, 1);
    
    myGraph_->addConnection(myAudioUnit_->nodeId, 0, ioProcOutNode_->nodeId, 0);
    myGraph_->addConnection(myAudioUnit_->nodeId, 1, ioProcOutNode_->nodeId, 1);

Are these connections correct?
I tired to connect audio input of my plugin to audio input of myAudioProceeesor.
And audio out of myAudioProcessor to audio out of my plugin.


#8

What’s your myAudioProceeesor doing in it’s processBlock() ?

Rail


#9
void MyAudioProcessor::prepareToPlay (double sampleRate, int estimatedSamplesPerBlock)
{
    setPlayConfigDetails (2, 2, sampleRate, estimatedSamplesPerBlock);
    
}
void MyAudioProcessor::releaseResources(){}

void MyAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{

}

myAudioProcessor does nothing currently.


#10

It seems my connections have problem.

myGraph_	juce::ScopedPointer<juce::AudioProcessorGraph>	
object	juce::AudioProcessorGraph *	0x101729aa0	0x0000000101729aa0
juce::AudioProcessor	juce::AudioProcessor	
juce::AsyncUpdater	juce::AsyncUpdater	
nodes	juce::ReferenceCountedArray<juce::AudioProcessorGraph::Node, juce::DummyCriticalSection>	
connections	juce::OwnedArray<juce::AudioProcessorGraph::Connection, juce::DummyCriticalSection>	
data	juce::ArrayAllocationBase<juce::AudioProcessorGraph::Connection *, juce::DummyCriticalSection>	
elements	juce::HeapBlock<juce::AudioProcessorGraph::Connection *, false>	
data	juce::AudioProcessorGraph::Connection **	NULL	0x0000000000000000
*data	juce::AudioProcessorGraph::Connection *	NULL	
[1]	juce::AudioProcessorGraph::Connection *	NULL	
[2]	juce::AudioProcessorGraph::Connection *	NULL	
[3]	juce::AudioProcessorGraph::Connection *	NULL	
[4]	juce::AudioProcessorGraph::Connection *	NULL	
numAllocated	int	0
numUsed	int	0

Does this mean none of connections are available?


#11

I don’t know why but if I do following stuff in prepareToPlay rather than its constructor,
those connections become available,
But still my plugin crashes immediately.

void AudioGraphTestAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    ignoreUnused (samplesPerBlock);
    
    myGraph_->setPlayConfigDetails (getTotalNumInputChannels(), getTotalNumOutputChannels(), 44100.0, 512);
    
    ioProcIn_         = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode);
    ioProcOut_        = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode);
    ioProcMidiIn_     = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);
    ioProcMidiOut_    = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);
    
    ioProcInNode_     = myGraph_->addNode (ioProcIn_);
    ioProcOutNode_    = myGraph_->addNode (ioProcOut_);
    ioProcMidiInNode_ = myGraph_->addNode (ioProcMidiIn_);
    ioProcMidiOutNode_= myGraph_->addNode (ioProcMidiOut_);
    
    myGraph_->addConnection (ioProcMidiInNode_->nodeId,  juce::AudioProcessorGraph::midiChannelIndex,
                             ioProcMidiOutNode_->nodeId, juce::AudioProcessorGraph::midiChannelIndex);
    
    myAudioProcessor_ = new MyAudioProcessor();
    myAudioProcessor_->setPlayConfigDetails (getTotalNumInputChannels(), getTotalNumOutputChannels(), 44100.0, 512);
    myAudioUnit_ = myGraph_->addNode(myAudioProcessor_);
    
    myGraph_->setRateAndBufferSizeDetails (sampleRate, samplesPerBlock);
    myGraph_->prepareToPlay (sampleRate, samplesPerBlock);
    
    myGraph_->addConnection(ioProcInNode_->nodeId, 0, myAudioUnit_->nodeId, 0);
    myGraph_->addConnection(ioProcInNode_->nodeId, 1, myAudioUnit_->nodeId, 1);
    
    myGraph_->addConnection(myAudioUnit_->nodeId, 0, ioProcOutNode_->nodeId, 0);
    myGraph_->addConnection(myAudioUnit_->nodeId, 1, ioProcOutNode_->nodeId, 1);

}