Acoustic Research Tool (ART)  v0.10
Using the ART programmer's interface

Including the ART interface

Windows programmers can use the DLL. C++ programmers can include the ART.h file.

Using the DLL

If you are working on windows and not using C++, you can use a DLL. The DLL can be downloaded from the sourceforge site. If you prefer to compile the DLL by yourself, use the MakeARTDLL.bat make file script. Check the Delphi examples on source forge to find out how to use the DLL.

Including ART.h

When working in C++, simply include the ART.h file into your project. Don't forget to add all files of the ART package as dependencies. So far only compiling on Microsoft Visual C++ 6.0 has been tested, other compilers could work. We are still working on making the code portable to other compilers and platforms. Check out the source forge page if you want to get the source code.

Using the ART interface

Models - Prototypes - Elements - Circuits

It is important to grasp the difference between a model, a prototype and an element.

Models provide functions to prepare the calculation of their own acoustic properties. The data properties of a model are its physical features, like length, width or temperature. Other properties concern implementation details, like for which simulation domain and which wavetypes the model provides calculation functions. A model has to implement the ARTmodelInterface.

Prototypes (or "prototype models") are models, that are instantiated during the initialization of the ART root object. Each of these prototype models contains meaningful default values. Prototypes serve as templates to create other models of the same class during runtime. Theses clones are attached to elements (see below), which you can insert into circuits and use for calculation.

Elements are wrappers of models and can be used for simulation. Their properties, like input impedance or radiation impedance, are dependent on their place in a circuit. Elements contain their own model object (which is a clone of a prototype model).

Circuits are arrangements of acoustic elements. When simulating a musical instrument, you will have to build a circuit to represent that instrument closely. A circuit must contain one or more elements. So far elements can only be arranged in in a one dimensional way, branches (with the notable excepetion of tone holes) are not (yet) possible.

When calculation the impedance of a cylindrical tube, you would first create an element. When creating an element of type cylinder, the cylinder prototype is automatically cloned and the clone is attached to the element as its model. Then you would adapt the properties of the element's model, place the element into a circuit within the same simulator and evaluate the circuits impedance. When computing the impedance, the element will use the functions provided by its model.

Creating the simulator

First the user must create the ART root object. This object will contain all simulators and provides us with all prototypes. Then the user has to create a simulator for a certain wave type and a certain simulation domain. So far only frequency domain and multimodal waves are supported, so we will create a simulator for that and save a pointer to it:

P_ART_Simulator mySim = ARTCreateSimulator("MySimulator", "FrequencyDomain", "MultiModal");

Creating the elements

Elements are created from prototypes and placed into a simulator by the function ARTCreateElement. The prototypes need to provide functions for simulation in the simulator's domain and wavetype. We will create a cylinder and call it "Cyl", a cone called "Con" and a Bessel horn named "Bes", all in the simulator created before.

P_ART_Element Cyl = ARTCreateElement(mySim, "Cyl", "Cylinder");
P_ART_Element Con = ARTCreateElement(mySim, "Con", "Cone");
P_ART_Element Bes = ARTCreateElement(mySim, "Bes", "Besselhorn");

Customising the elements

To change the measurements and other parameters of the elements use the function ARTSetParameter. We well change the measurements of the cylinder to a 100 cm long tube with a radius of 1 cm. The cone will be 50 cm long, and have the same radius as the cylinder at the beginning and 1.5 times that radius at the end. The Bessel horn will be 20 cm long, have the same radius as the cone ending and bend to a radius of 12.5 cm at the end. The parameter flare, controlling the shape of the Bessel horn is set to 0.4.

ARTSetParameter(mySim, "Cyl.r = 1; Cyl.length = 100;");
ARTSetParameter(mySim, "Con.length = 50;");
ARTSetParameter(mySim, "Con.r1 = Cyl.r; Con.r2 = 1.5 * Con.r1;");
ARTSetParameter(mySim, "Bes.length = 20; Bes.r1 = Con.r2;");
ARTSetParameter(mySim, "Bes.r2 = 12.5; Bes.flare = 0.4;");

Building the instrument

The order in which the elements are added is important. The first element will be the element nearest to the mouth of the player. Use the functions ARTAppendReferenceBefore and ARTAppendReferenceAfter if you want to insert elements at a certain place. We will first create an instrument and then add our customised elements one by one.

P_ART_Circuit myIns = ARTCreateCircuit(mySim, "MyInstrument");
ARTAppendReference(myIns, Cyl);
ARTAppendReference(myIns, Con);
ARTAppendReference(myIns, Bes);

Calculating the instrument's impedance

Before calculating the impedance the frequency range and the number of modes have to be defined. The impedance is evaluated for discrete points within the range. The distance between these points is determined by the frequency step. We will set the range of the simulator to be from 50 Hz to 1800 Hz, with a frequency step of 5 Hz. We set the number of modes to 1.

ARTSetFrequencyRange(mySim, 50, 1800, 5);
ARTSetNModes(mySim, 1);

To calculate a circuit's impedance we simply use the function ARTInputImpedance. The impedance curve returned won't change if the arrangement is changed after the function is called. A new call ensures the impedance curve is up-to-date. The function returns a pointer to an object of class ARTdataContainer, which holds the data.

We will have the impedance of our instrument calculated and print it as numbers to the screen.

P_ART_Variant myImpCurve = ARTGetValue( ARTInputImpedance(myIns) );
for (int i=0; i<ARTGetLength(myImpCurve); i++)
{
T_ART_Tripl tri = ARTGetTriple(myImpCurve, i);
std::cout << tri.f << "Hz\t"
<< tri.re << "\t"
<< tri.im << "i\n";
}

Cleaning up

When you are done you must destroy all elements and simulators you create and also the ART root object:

ARTDestroyCircuit(mySim, myIns);
ARTDestroyElement(mySim, Cyl);
ARTDestroyElement(mySim, Con);
ARTDestroyElement(mySim, Bes);

Error handling

When errors are encountered, the interface either throws an exception as an object of the class ARTerror (when not using the DLL) or returns a bad value through a function (when using the DLL).

When not using the DLL, include critical operations in try/catch blocks, like this:

try
{
P_ART_Simulator mySim = ARTCreateSimulator("MySim", "FrequencyDomain", "MultiModal");
ARTCreateElement(mySim, "Zylinder1", "Cylinder");
ARTSetParameter(mySim, "Cyl.R = 10;"); //Error! There's no element called "Cyl"!
}
catch(ARTerror e)
{
string err = e.GetErrorMessage();
std::cout << err;
//Will print:
//"Error in function 'ARTSetParameter': An element of the specified name 'Cyl' does not exist."
}

Of course it does not harm to include all operations in try/catch blocks. At this stage of the project that can be useful for debugging. Note that most error messages so far are indeed rather for debugging and not meant for end-users.

See Also
ARTerror
ARTGetLastErrorMessage to find out more about error handling when using the DLL.

Technicalities

The dependency tree

When the impedance is evaluated, first all parameters it depends on are evaluated. If those parameters depend themselves on other parameters, they are evalauted before. All parameters are in a dependency tree, which the programme automatically follows to its principle elements, those that do not depend on any other parameter. In our example the dependency tree looks as follows:

dependencies.png

So when the impedance is queried, all other properties are evaluated first. Therefore the user never has to worry about evaluating other properties before calling ARTInputImpedance.

Properties keep track of their validity. As soon as a dependency of a property is changed, the property is marked for recalculation the next time it is needed.

Progress information and computation cost estimation

The user can specify a callback function, which will be called at regular intervals during the calculation process to communicate information about the progress. This function can also be used to abort the calculation. Before the calculation starts, the interface determines the cost of the computation in computation steps, that is parser or functionoid calls respectively. Since not all of these operations are of the same complexity the first thousand computation steps can be twice as fast as the following thousand.

@see ARTSetProgressFunction

Detailed description

Check the documentation of the ART interface for a detailed description of its functions.