Jamoma API  0.6.0.a19
Using Objects from the Jamoma API
Author
Jamoma, Timothy Place

Object Life Cycle

Creating and Destroying

To create an instance of a Jamoma object, create a TTObject. Internally this will look up the class in Jamoma’s registry of objects and create an instance.

An example below creates a stereo instance of an allpass filter, and two stereo audio signals. They are stereo because the argument given when instantiating these types of objects define the initial number of audio channels as two. You can safely ignore the fact that one of the variables is a TTAudioObjectPtr instead of a TTObjectPtr. TTAudioObject is simply a specialized version of TTObject for processing audio signals. TTAudio is also a specialized version of TTObject to represent the audio signals.

TTAudioObject myObject("allpass", 2);
TTAudio myAudioInput(2);
TTAudio myAudioOutput(2);

When you are all done using the objects, you need to release them. If you have allocated the objects on the stack, as we did in the example above, this is taken care of for you.

Retaining and Reference Counts

TTObject’s are reference counted. This means that you can create references to existing objects, and the object will not be freed until all references have been released. This is demonstrated in the following example:

TTObject* myObject = new TTObject(“noise”, 2);
TTObject* aReferenceToMyObject = new TTObject;
// reference count for internal instance inside myObject is now 1
aReferenceToMyObject = myObject;
// reference count for internal instance inside myObject is now 2
delete myObject;
// The myObject wrapper is deleted, but the internal object is not actually deleted
// reference count for internal instance inside myObject is now 1
delete aReferenceToMyObject;
// Now, because the reference count fell to zero, the internal object is deleted

Querying the Environment

As alluded to in section 3.1, Jamoma Foundation maintains a registry of available classes that may be instantiated by name. Some of these classes are implemented internally in the Jamoma libraries, and some are implemented externally as Jamoma Extensions. The registry does not differentiate between these, but simply provides a list of everything that is loaded in the system.

Getting All Class Names

To obtain a list of all class in the Foundation's registry, you call the TTObject::GetRegisteredClassNames() function as in the following example:

TTErr err;
TTValue classNames;
if (!err) {
// The classNames value now contains an array of TTSymbols,
// one for each class in the Jamoma registry.
// For example, we can print them all to console:
TTUInt16 numClassNames = classNames.size();
for (TTUInt16 i=0; i<numClassNames; i++) {
TTSymbol aClassName = classNames[i];
TTLogMessage("class name: %s", aClassName.c_str());
}
}

Searching For Classes Based on Tags

In addition to retrieving all class names, it is also useful to be able to retrieve a limited number of class names based on criteria that you specify. For example, you may wish to only list classes that generate their own audio. Or perhaps only those class which implement some sort of lowpass filter.

In this case we call TTObject::GetRegisteredClassNamesForTags(), and process the results in the same manner as we did for TTObject::GetRegisteredClassNames(). This is demonstrated in the example below:

TTErr err;
TTValue classNames;
TTValue searchTags;
searchTags.clear();
searchTags.append(TT("audio"));
searchTags.append(TT("filter"));
searchTags.append(TT("lowpass"));
err = TTGetRegisteredClassNamesForTags(classNames, searchTags);
if (!err) {
// The classNames value now contains an array of TTSymbols,
// one for each class in the Jamoma registry.
// For example, we can print them all to console:
TTUInt16 numClassNames = classNames.getSize();
for (TTUInt16 i=0; i<numClassNames; i++) {
TTSymbol aClassName = classNames[i];
TTLogMessage("class name: %s", aClassName.c_str());
}
}

For a list of common tags and what they mean in Jamoma see Appendix B. To get a list of all tags in use at any time, call TTObject::GetRegisteredTags().

Tag Searching and Instantiation in Action

Here is an example that searches based on tags for a lowpass filter using a Butterworth algorithm, and then creates an instance of that class.

// In this case there are multiple matches returned.
// Since more specific information was not provided,
// we just instantiate the first one.
TTErr err;
TTValue classNames;
TTValue searchTags;
TTAudioObject butterworthFilter;
searchTags.clear();
searchTags.append(TTSymbol("audio"));
searchTags.append(TTSymbol("filter"));
searchTags.append(TTSymbol("lowpass"));
searchTags.append(TTSymbol("butterworth"));
err = TTObject::GetRegisteredClassNamesForTags(classNames, searchTags);
if (!err) {
// for this example, we can just instantiate the first one in the list
butterworthFilter = TTAudioObject(classNames[0]);
}
// now do something with the filter.

Sending Messages

Having created an instance of an object, we must now do something with that object. We do things with objects by sending them messages. A message defines an action to be performed.

Given the Butterworth filter example in Tag Searching and Instantiation in Action, we can now send the filter the 'clear' message to zero its sample history

Note
The Butterworth filter is an IIR filter, meaning that it stores the results of previous calculations to perform future calculations. This feedback can sometimes get out of control, and thus the necessity for a 'clear' message.
butterworthFilter.send("clear");

Some messages, like the 'clear' message for the Butterworth filter, require no additional information to perform the requested action. Other messages, however, do require additional information. This information can be provided using an optional arguments to the send() method. Here are some samples:

TTValue returnValue;
TTValue dummy;
someObject.send("foo", 3.14, returnValue);
someObject.send("draw", "circle", returnValue);
// create a TTValue that holds a list and pass the TTValue
TTValue v(1.0, 2.0));
someObject.send("w", v, returnValue);
// when you send a message, it can return a value in the third argument.
TTErr err;
err = someObject->sendMessage("getContents", dummy, returnValue);
if (!err) {
// Assuming that someObject understands the message,
// this results in returnValue being set to contain something meaningful.
}
else if (err == kTTErrMethodNotFound) {
// The object didn't understand this message'
}
else {
// There was some other problem.
// Probably the object you sent the message to knows this message and is returning
// an error specific to the action you requested.
}

Setting and Getting Attributes

Sending messages is great for performing actions, however these actions do not represent the state of the object. The state of the object is represented as the object's 'attributes'.

Querying Objects for Available Messages and Attributes

Processing Audio

Not all objects can process audio, however, objects that have the tag ‘audio’ associated with them are able process audio. These objects derive from TTAudioObjectBase, a subclass of TTObjectBase which implements the “process” method.