Home

ALab Developer Tutorial

The very first thing to know about ALab is, that every object that can produce sound must be a subclass of AObject. The way an AObject provides its sound data differs from most other concepts. Usually a method calling for sound data would be coded like getValueAt(channel, position). This method would calculate the value at position and at audio channel channel. In ALab it is only possible to ask for the next value (method nextValue(channel, rate)). Depending on the samplerate the next value is calculated.
To ensure correct working of ALab it is neccessary to ask for values in a certain sequence. The lowest channel has to be called first, followed by higher channels and ending with the highest one. There are two abstract methods that must be implemented by a subclass of AObject: getValue(channel, rate) calculates the next value. copy() returns a copy of itself that returns exactly the same values and uses copies of the AObjects it uses (in fact, the copy method doesn't change much. To implement the copy method it is neccessary to build a constructor that can copy a class of its type. The copy method simply calls this constructor with itself).

ASilence, Diagram (all example java-files can be found in docs/tutorial/examples)

In this tutorial we will create new ALab modules, subclasses of AObject. The first module created silence the next module is an impuls generator. This oscillator will be a subclass of AWave that is a subclass of AObject and provides typical oscillator methods. Every AWave object has a certain frequency and phase. To calculate the next value we only need to know the current phase at each channel. This phase is calculated by the method nextPhase(channel, rate) and returns a value between -PI and PI. A new circle starts at 0. But it is also possible that the last phase was -0.01 and the current phase is 0.24, so the new circle doesn't start with zero. It is also possible that the phase is running backwards (negative frequency). To know, wheather a new circle started or not, we can use the method isZero(channel). This method returns true if a new circle started. Our impuls generator will return 1 every new circle and -1 if the phase changes from PI to -PI. To know when the phase changes, we remember the last phase and return -1 whenever the last and the current phase are different in sign and the method isZero() returns false.

Phase Diagram, AImpuls, Flow Diagram

The next module will not create sound, but change the values of any AObject. At first we simply take and store the given object and return its values if asked for any value. To do so, we have to build a constructor that uses an AObject as parameter. This AObject is copied and stored. We have to copy it, to ensure that this object is not used by any other object. If it would be used by another object the result would not be correct, because it is not possible in ALab to ask for any value two times. If we ask any AObject for values two times, the return values will be different, because always the next value is calculated.

AUseObject

Our module will be able to be modulated. Modulation always works this way in ALab: There is always one certain value (pan in our next example) that must be declared in the constructor. This value is of type double and has no limit in range (but can be limited to ensure correct working). Most modules work with such values in the range -1..1. There is only one value for all channels, but this value can be changed (modulated) for every channel (so it is possible to get different values for each channel). To modulate such a value, a modulator for this value must be defined (in our next example it is called panMod). Any AObject can be used as modulator and the values of this modulator are multiplied with the value to be modulated (nextObjValue()). If such a value is 5 (for all channels) and the modulator is 1 at channel zero (left) and -1 at channel one (right) than the value will be used as 5 (5x1=5) on left channel and -5 (5x-1=-5) at right channel. The range of the modulated values is between -value and value.

AUseMod

To understand our module we will look at a certain problem before: We have three sounds, a cow saying 'MUH', a chicken saying 'GACK-GACK' and a pig saying 'GRUNZ'. We have each of this sounds as one channel (mono) AObjects. We want this three sounds to be placed into a stereo (two channel) AObject. 'MUH' left, 'GACK-GACK' middle and 'GRUNZ' right in the stereo panorama. Our module APan will be able to do this. APan is always a stereo object and uses any AObject as input. The value pan tells the position in the stereo panorama. If the input AObject has n channels, the pan value modulator must also have n channels to take effect on all channels. In our example the pan modulator will use -1 for 'MUH', zero for 'GACK-GACK' and 1 for 'GRUNZ'. If the pan modulator has less channels, the pan value will be zero for these missing channels.

APan, APan(without docu), panorama

This is the end of the developer tutorial. If you did understand everything you will be able to build interesting new modules alone now. Try to avoid constructors that throw exceptions and cast all exceptions to AException. If you want to create complexer modules, you will probably need more informations. You can get these informations by studying the source code of ALab or you can send a mail to the support address.

Home