Jamoma API  0.6.0.a19
TTAudioGraphObject.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup audioGraphLibrary
4  *
5  * @brief Wraps an object from Jamoma DSP to function within AudioGraph
6  *
7  * @details The TTAudioGraphObjectBase wraps a Jamoma DSP object such that it is possible to build a dynamic graph of audio processing units. It is implemented as a #TTObjectBase so that it can receive dynamically bound messages,
8  * including notifications from other objects.
9  *
10  * @authors Timothy Place, Trond Lossius
11  *
12  * @copyright Copyright © 2010, Timothy Place @n
13  * This code is licensed under the terms of the "New BSD License" @n
14  * http://creativecommons.org/licenses/BSD/
15  */
16 
17 
18 #include "TTAudioGraphObject.h"
19 #include "TTAudioGraphInlet.h"
20 #include "TTAudioGraphOutlet.h"
21 
22 #define thisTTClass TTAudioGraphObjectBase
23 
24 TTMutexPtr TTAudioGraphObjectBase::sSharedMutex = NULL;
25 
26 
27 // Arguments
28 // 1. (required) The name of the Jamoma DSP object you want to wrap
29 // 2. (optional) Number of inlets, default = 1
30 // 3. (optional) Number of outlets, default = 1
31 
32 
33 TTObjectBasePtr TTAudioGraphObjectBase::instantiate(TTSymbol name, TTValue arguments)
34 {
35  return new TTAudioGraphObjectBase(arguments);
36 }
37 
38 extern "C" void TTAudioGraphObjectBase::registerClass()
39 {
40  TTClassRegister(TT("audio.object"), "audio, graph, wrapper", TTAudioGraphObjectBase::instantiate );
41 }
42 
43 
44 TTAudioGraphObjectBase :: TTAudioGraphObjectBase (const TTValue& arguments) :
45  TTGraphObjectBase(arguments),
47  mAudioFlags(kTTAudioGraphProcessor),
48  mInputSignals(1),
49  mOutputSignals(1),
50  mVectorSize(0),
51  mSampleStamp(-1)
52 {
53  TTSymbol wrappedObjectName = kTTSymEmpty;
54  TTUInt16 numInlets = 1;
55  TTUInt16 numOutlets = 1;
56 
57  addAttributeWithSetter(NumAudioInlets, kTypeUInt32);
58  addAttributeWithSetter(NumAudioOutlets, kTypeUInt32);
59 
60  TT_ASSERT(audiograph_correct_instantiation_arg_count, (arguments.size() > 0));
61 
62  wrappedObjectName = arguments[0];
63  if (arguments.size() > 1)
64  numInlets = arguments[1];
65  if (arguments.size() > 2)
66  numOutlets = arguments[2];
67 
68  setAttributeValue(TT("numAudioInlets"), numInlets);
69  setAttributeValue(TT("numAudioOutlets"), numOutlets);
70 
71  // if an object supports the 'setOwner' message, then we tell it that we want to become the owner
72  // this is particularly important for the dac object
73  TTValue v = TTPtr(this);
74  TTValue unusedReturnValue;
75  mKernel.send("setOwner", v, unusedReturnValue);
76 
77  if (!sSharedMutex)
78  sSharedMutex = new TTMutex(false);
79 }
80 
81 
82 TTAudioGraphObjectBase::~TTAudioGraphObjectBase()
83 {
84 }
85 
86 
88 {
89  // TODO: if the number of inlets or outlets changes on the fly then we will leak memory!
90  TTUInt16 inletCount = newNumInlets;
91 
92  mInputSignals.setStreamCount(inletCount);
93  mAudioInlets.resize(inletCount);
94  mNumAudioInlets = inletCount;
95  return kTTErrNone;
96 }
97 
98 
100 {
101  // TODO: if the number of inlets or outlets changes on the fly then we will leak memory!
102  TTUInt16 outletCount = newNumOutlets;
103 
104  mAudioOutlets.resize(outletCount);
105  mOutputSignals.setStreamCount(outletCount);
106  mNumAudioOutlets = outletCount;
107  return kTTErrNone;
108 }
109 
110 
112 {
113  if (valid && mAudioDescription.mClassName != kTTSymEmpty) {
115  mAudioDescription.mClassName = kTTSymEmpty;
116 
117  prepareDescription();
118 
119  for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++)
120  inlet->prepareDescriptions();
121  }
122 }
123 
124 
126 {
127  if (mAudioDescription.mClassName != kTTSymEmpty) { // a description for this object has already been created -- use it.
128  desc = mAudioDescription;
129  }
130  else { // create a new description for this object.
131  desc.mClassName = mKernel.name();
132  desc.mObjectInstance = mKernel;
133  desc.mNumInlets = mInlets.size();
134  desc.mNumOutlets = mOutlets.size();
135  desc.mAudioDescriptionsForInlets.clear();
136  desc.mID = desc.sIndex++;
137  mAudioDescription = desc;
138 
139  for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
140  TTAudioGraphDescriptionVector vector;
141 
142  inlet->getDescriptions(vector);
143  desc.mAudioDescriptionsForInlets.push_back(vector);
144  }
145 
146 // prepareDescription();
147  getDescription(desc.mControlDescription);
148  }
149 }
150 
151 
153 {
154  sSharedMutex->lock();
155  for_each(mAudioInlets.begin(), mAudioInlets.end(), std::mem_fun_ref(&TTAudioGraphInlet::reset));
156  sSharedMutex->unlock();
157  return kTTErrNone;
158 }
159 
160 
162 {
163  TTErr err;
164 
165  // it might seem like connections should not need the critical region:
166  // the vector gets a little longer and the new items might be ignored the first time
167  // it doesn't change the order or delete things or copy them around in the vector like a drop() does
168  // but:
169  // if the resize of the vector can't happen in-place, then the whole thing gets copied and the old one destroyed
170 
171  sSharedMutex->lock();
172 
173  if (toInletNumber+1 > (TTInt32) mAudioInlets.size())
174  setNumAudioInlets(toInletNumber+1);
175 
176  err = mAudioInlets[toInletNumber].connect(anObject, fromOutletNumber);
177  sSharedMutex->unlock();
178  return err;
179 }
180 
181 
183 {
185 
186  sSharedMutex->lock();
187  if (toInletNumber < mAudioInlets.size())
188  err = mAudioInlets[toInletNumber].drop(anObject, fromOutletNumber);
189  sSharedMutex->unlock();
190  return err;
191 }
192 
193 
195 {
196  lock();
198  TTAudioSignalPtr audioSignal;
199  TTUInt16 index = 0;
200 
202 
203  for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
204  inlet->preprocess(initData);
205  audioSignal = inlet->getBuffer(); // TODO: It seems like we can just cache this once when we init the graph, because the number of inlets cannot change on-the-fly
206  mInputSignals.setStream(index, audioSignal);
207  index++;
208  }
209 
210  index = 0;
211  for (TTAudioGraphOutletIter outlet = mAudioOutlets.begin(); outlet != mAudioOutlets.end(); outlet++) {
212  audioSignal = outlet->getBuffer();
213  mOutputSignals.setStream(index, audioSignal);
214  index++;
215  }
216 
218  if (mVectorSize != initData.vectorSize) {
219  mVectorSize = initData.vectorSize;
220  mOutputSignals.allocAllWithVectorSize(initData.vectorSize);
221  mInputSignals.setStreamCount(0);
222  }
223  }
224  }
225  unlock();
226  return kTTErrNone;
227 }
228 
229 
230 TTErr TTAudioGraphObjectBase::process(TTAudioSignalPtr& returnedSignal, TTUInt64 sampleStamp, TTUInt16 forOutletNumber)
231 {
232  lock();
233 
234  if (sampleStamp == mSampleStamp) // we have already processed this slice of time!
235  returnedSignal = &mOutputSignals.getSignal(forOutletNumber);
236  else {
237  mSampleStamp = sampleStamp; // update our notion of time and proceed
238 
239  switch (mStatus) {
240 
241  // we have not processed anything yet, so let's get started
244 
245  if (mAudioFlags & kTTAudioGraphGenerator) { // a generator (or no input)
247  }
248  else { // a processor
249  // zero our collected input samples
250 
251  // WE CANNOT DO THIS!!! IF THE INLET IS JUST A POINTER TO MEMORY IN ANOTHER OBJECT'S OUTLET
252  // THEN WE END UP CLEARING THAT OBJECT'S COMPUTED OUTPUT!!!
253  // INSTEAD, WE MOVE THE CLEARING INTO THE inlet->process() call
254  //mInputSignals->clearAll();
255 
256 
257  // pull (process, sum, and collect) all of our source audio
258  // for_each(mAudioInlets.begin(), mAudioInlets.end(), mem_fun_ref(&TTAudioGraphInlet::process));
259  for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
260  inlet->process(sampleStamp);
261  }
262 
263  // TEMPORARY -- DUPLICATING CODE FROM PREPROCESS
264  // If there is a change in the inlet/source configuration during processing, including channel counts, then the information cached at preprocess is WRONG!
265  // If there is feedback, then the problem gets compounded into future pulls on the graph!
266  int index = 0;
267  for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
268  TTAudioSignalPtr audioSignal = inlet->getBuffer(); // TODO: It seems like we can just cache this once when we init the graph, because the number of inlets cannot change on-the-fly
269  mInputSignals.setStream(index, audioSignal);
270  index++;
271  }
272 
274  // examples of non-adapting objects are join≈ and matrix≈
275  // non-adapting in this case means channel numbers -- vector sizes still adapt
276  mOutputSignals.matchNumChannels(mInputSignals);
277  }
278  mOutputSignals.allocAllWithVectorSize(mInputSignals.getVectorSize());
279 
280  // adapt ugen based on the input we are going to process
281  getUnitGenerator().adaptMaxChannelCount(mInputSignals.getMaxChannelCount());
282  getUnitGenerator().setSampleRate(mInputSignals.getSignal(0).getSampleRate());
283 
284  // finally, process the audio
286  }
287 
288  // These two lines should be equivalent
289  //returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
290  returnedSignal = &mOutputSignals.getSignal(forOutletNumber);
291 
293  break;
294 
295  // we already processed everything that needs to be processed, so just set the pointer
297  // These two lines should be equivalent
298  //returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
299  returnedSignal = &mOutputSignals.getSignal(forOutletNumber);
300  break;
301 
302  // to prevent feedback / infinite loops, we just hand back the last calculated output here
304  // These two lines should be equivalent
305  //returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
306  returnedSignal = &mOutputSignals.getSignal(forOutletNumber);
307  break;
308 
309  // we should never get here
310  default:
311  unlock();
312  return kTTErrGeneric;
313  }
314  }
315  unlock();
316  return kTTErrNone;
317 }
The TTGraphObjectBase wraps a TTDSP object such that it is possible to build a dynamic graph of audio...
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTErr unlock()
Unlock the object when thread-safe processing is no longer required.
Definition: TTObjectBase.h:530
An inappropriate value was specified for an attribute or variable.
Definition: TTBase.h:349
This node is currently processing audio.
Definition: TTAudioGraph.h:51
TTErr connectAudio(TTAudioGraphObjectBasePtr anObject, TTUInt16 fromOutletNumber=0, TTUInt16 toInletNumber=0)
Add a source to the list of objects from which to request audio.
TTErr adaptMaxChannelCount(const TTUInt16 aNewChannelCount)
Allocate neccessary memory and make configuration adjustments so the object is able to process additi...
Audio processing has not yet started for this node.
Definition: TTAudioGraph.h:50
TTUInt16 mVectorSize
The most recent vector size info passed from the terminal object during a preprocess.
std::uint64_t TTUInt64
64 bit unsigned integer
Definition: TTBase.h:180
void getAudioDescription(TTAudioGraphDescription &desc)
Describe this object as part of the action of describing a complete audio graph.
TTAudioGraphOutletVector mAudioOutlets
The outlets that processed audio sampled will be passed to.
size_type size() const noexcept
Return the number of elements.
void reset()
Reset the graph by dropping all connections to all sources in preparation of a rebuilding of all of t...
This object provides a description of a TTAudioGraphObject and its sources.
void prepareAudioDescription()
Prepare for a request to descibe all of the graph.
Defines a single 'outlet' from an individual AudioGraph object.
Base class for all first-class Jamoma objects.
Definition: TTObjectBase.h:109
This object is an audio generator, and do not expect audio input.
Definition: TTAudioGraph.h:73
TTGraphInletVector mInlets
The inlets through which we pull audio from sources.
TTErr dropAudio(TTAudioGraphObjectBasePtr anObject, TTUInt16 fromOutletNumber=0, TTUInt16 toInletNumber=0)
Drop a source from the list of objects from which to request audio.
Defines a single 'inlet' from an individual AudioGraph object.
TTErr setAttributeValue(const TTSymbol name, TTValue &value)
Set an attribute value for an object.
TTAudioGraphDescription mAudioDescription
Used to prevent feedback loops etc. when describing a graph.
TTBoolean valid
If the object isn't completely built, or is in the process of freeing, this will be false...
Definition: TTObjectBase.h:124
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
This node is an audio effect processor. It expects audio input that will be processed.
Definition: TTAudioGraph.h:72
TTAudioArray mInputSignals
The buffered input for processing audio with our object.
The current processing status of the node is unknown.
Definition: TTAudioGraph.h:49
TTSymbol name() const
Return the name of this class.
Definition: TTObject.cpp:129
TTErr setNumAudioOutlets(const TTValue &newNumOutlets)
Set the number of audio outlets.
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTUInt32 mNumAudioInlets
Attribute: The number of inputs for this object.
This object does not adapt its number of output channels to the number of input channels.
Definition: TTAudioGraph.h:74
TTUInt16 vectorSize
The global/recommended/initial vectorSize (which can be overriden during process) ...
Definition: TTAudioGraph.h:83
virtual TTErr preprocess(const TTAudioGraphPreprocessData &initData)
This method is called by an object about to process audio, prior to calling getAudioOutput().
The TTAudioSignal class represents N vectors of audio samples for M channels.
Definition: TTAudioSignal.h:57
This node has completed processing audio for now.
Definition: TTAudioGraph.h:52
TTAudioObject & getUnitGenerator()
...
Wraps an object from Jamoma DSP to function within AudioGraph.
TTUInt32 mNumAudioOutlets
Attribute: The number of outlets for this object.
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
static TTInt32 sIndex
Used for creating mID.
TTErr setNumAudioInlets(const TTValue &newNumInlets)
Set the number of audio inlets.
TTUInt64 mSampleStamp
The current time in samples, as determined from the pulling of this object.
TTErr resetAudio()
Clear the list of source objects from which this object will try to pull audio.
TTAudioArray mOutputSignals
The results of processing audio with our object, buffered for objects requesting it.
virtual TTErr process(TTAudioSignalPtr &returnedSignal, TTUInt64 sampleStamp, TTUInt16 forOutletNumber=0)
This method is required to be implemented by all objects except for those existing solely as a destin...
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
TTInt32 mID
An index number that uniquely identifies this instance.
The TTAudioGraphObjectBase wraps a TTDSP object such that it is possible to build a dynamic graph of ...
[doxygenAppendixC_bitmaskExample]
Definition: TTAudioGraph.h:81
#define addAttributeWithSetter(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom setter...
Definition: TTAttribute.h:47
32-bit unsigned integer, range is 0 through 4,294,967,295.
Definition: TTBase.h:278
TTAudioGraphInletVector mAudioInlets
The inlets through which we pull audio from sources.
TTObject mKernel
The actual TT object doing the processing.
No Error.
Definition: TTBase.h:343
TTGraphOutletVector mOutlets
The inlets through which we pull audio from sources.
TTErr drop(TTGraphObjectBasePtr anObject, TTUInt16 fromOutletNumber=0, TTUInt16 toInletNumber=0)
Drop a source from the list of objects from which to request audio.
TTErr lock()
Lock the object in order to ensure thread-safe processing.
Definition: TTObjectBase.h:520
TTErr setSampleRate(const TTUInt32 &newSampleRate)
Set the object's sample rate.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTAudioGraphProcessStatus mStatus
Used to enable correct processing of feedback loops, multiple destinations, etc.
static TTMutexPtr sSharedMutex
A critical region shared by all TTAudioGraphObjectBases to prevent changes to the graph while process...
TTUInt32 mAudioFlags
A bitmask of values defined in TTAudioGraphFlags.