Processings with dynamic ports
From Clam
This page explain a technique to create processings that can be configured to have a different number of ports, multichannel processings so that the number of channels can be changed at configuration time. If you just need a fixed number of ports see Creating a minimal processing object.
Contents |
Defining dynamic ports
First of all, we have to decide the class of Ports that we want to use. In this example we will use the AudioInPort and AudioOutPort classes, so it's necessary the following includes. However you can decide another port type if you want.
...
#include <CLAM/AudioInPort.hxx>
#include <CLAM/AudioOutPort.hxx>
...
We'll use a vector of AudioInPort (or AudioOutPort) instead of an unique AudioInPort or AudioOutPort. That's because we want to work with dynamic port and we don't know the number of ports that we will need. So we can add this lines in the class declaration.
...
CLAM::AudioInPort _in; <--- OLD
CLAM::AudioOutPort _out; <--- OLD
typedef std::vector<CLAM::AudioOutPort*> OutPorts; <--- NEW
typedef std::vector<CLAM::AudioInPort*> InPorts; <--- NEW
OutPorts _outports; <--- NEW
InPorts _inports; <--- NEW
...
Initialization
In case we decide to have at least one port, we need to initialize the vector in the ConcreteConfigure() method. ( This code is for _inports vector, but it's the same for the _outports vector).
if(_inports.empty())
{ AudioInPort * port = new AudioInPort( "in1", this);
port->SetSize(BackendBufferSize());
port->SetHop( BackendBufferSize());
_inports.push_back( port );
}
Removing all ports
For removing all the ports we have to delete all the items and tell the ports that the vector of AudioPorts is clear.
if(!_outports.empty())
{
for(OutPorts::iterator itOutPorts=_outports.begin();itOutPorts!=_outports.end();itOutPorts++)
delete *itOutPorts;
}
_outports.clear();
// Delete ports from Processing (base class) register
GetOutPorts().Clear();
Keeping the port connections
If we want to increase or decrease the number of ports we can not remove all the ports because we will lose the port connections. The solution is delete or add the items that are completely necessary. So we have three cases.
First case: Maintaining the same ports
We don't have to put and remove anything.
if ( numberChannelsOut == _outports.size() )
return true;
Second case: To increase the number of ports
We have to create an AudioPort and insert it in the vector. The following code shows how to create as number of AudioInPort as number of channels. The condition is the number of channels has to be greater than the vector size.
std::string nameOutPort = "out";
if ( numberChannelsOut > _outports.size() )
{
for (int i=_outports.size()+1; i<= numberChannelsOut; i++)
{
std::ostringstream nameStream;
nameStream << nameOutPort << i;
AudioOutPort * port = new AudioOutPort( nameStream.str(), this);
port->SetSize( BackendBufferSize());
port->SetHop(BackendBufferSize());
_outports.push_back( port );
}
}
Third case: Deleting some items from the dynamic ports
The example below shows how to decrease in number of ports. We want to get a vector that will have as number of AudioPorts as number and channels, so we will delete the remaining items. The condition is that the vector size has to be greater than the number of channels.
if ( numberChannelsOut < _outports.size() )
{
for (unsigned i= numberChannelsOut; i<_outports.size(); i++)
delete _outports[i];
_outports.resize( numberChannelsOut );
}
Using the dynamic ports
Within the Do method we can read or write the AudioPorts. We create a CLAM::TData* array for save the buffer of each channel.
CLAM::TData* channels[_numberChannelsOut];
for (unsigned channel=0; channel<_numberChannelsOut; channel++)
channels[channel] = &_outports[channel]->GetAudio().GetBuffer()[0];
Then we can set the values that we want in the Audio Buffers.
const int portSize = _outports[0]->GetAudio().GetBuffer().Size();
for(int i=0; i< portSize; i++)
for(unsigned channel = 0; channel<_numberChannelsOut; channel++)
channels[channel][i] = value;
Finally, we have to call the Produce method for the AudioOutPorts and the Consume method for the AudioInPorts.
for (unsigned channel=0; channel<_numberChannelsOut; channel++)
_outports[channel]->Produce();
for (unsigned channel=0; channel<_numChannelsIn; channel++)
_inports[channel]->Consume();


