From b43bf8bbc1ba36056f222c7d9ba20ef9389fb411 Mon Sep 17 00:00:00 2001 From: Peter Hanappe Date: Mon, 22 Mar 2004 09:24:56 +0000 Subject: [PATCH] Adding Markus' LADSPA design document, Antoine's Xtra API doc, and a memo on midi timing --- fluidsynth/doc/FluidSynth-LADSPA.pdf | Bin 0 -> 104518 bytes fluidsynth/doc/midi_time.txt | 48 ++ fluidsynth/doc/xtrafluid.txt | 907 +++++++++++++++++++++++++++ 3 files changed, 955 insertions(+) create mode 100644 fluidsynth/doc/FluidSynth-LADSPA.pdf create mode 100644 fluidsynth/doc/midi_time.txt create mode 100644 fluidsynth/doc/xtrafluid.txt diff --git a/fluidsynth/doc/FluidSynth-LADSPA.pdf b/fluidsynth/doc/FluidSynth-LADSPA.pdf new file mode 100644 index 0000000000000000000000000000000000000000..432f3d67ed5129a1ff57b4a6191ee0263a4411a2 GIT binary patch literal 104518 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 literal 0 HcmV?d00001 diff --git a/fluidsynth/doc/midi_time.txt b/fluidsynth/doc/midi_time.txt new file mode 100644 index 00000000..dbc5f162 --- /dev/null +++ b/fluidsynth/doc/midi_time.txt @@ -0,0 +1,48 @@ + + +I use this document as a memo to understand timing in MIDI files. [PH] + +- MIDI Quarter Note: There is the MIDI quarter note. For those of you + who are interested in the music notation of a MIDI file, beware, a + MIDI quarter note in NOT necessarily equal to a notated quarter + note. + +- MIDI Clock: There are *24* MIDI clocks in a MIDI quarter note (this + is forced upon you) + +- MIDI Tempo: There are miditempo x 24th of a micro-second in a MIDI + clock. The value of miditempo is given by the SetTempo meta-event. + +- Division: A MIDI quarter note is split into N divisions. The value + of divisions can be found in the midifile header (MThd chunk). + +- Delta-time: The time between one event and the next is called + delta-time. The MIDI event delta-times are specified in divisions. + + +* How long is a MIDI Clock? + + midi-clock = miditempo * 1e-6 / 24 sec + +* How long is a MIDI Quarter Note? + + quarter-note = 24 midi-clocks + = 24 * miditempo * 1e-6 / 24 sec + = miditempo * 1e-6 sec + +* How long is a Division (a "tick" or "delta-time")? + + 1 delta-time = 1 tick = quarter-note / divisions + = miditempo / divisions / 1e6 sec + = miditempo / divisions / 1000 msec + + +To handle music notation, two more concepts are introduced: + +- There are *Nm* MIDI clocks in a metronome ticks +- There are *N32* notated 32nd notes in a MIDI quarter note + +Nm and N32 can be found in the TimeSignature meta event + + + diff --git a/fluidsynth/doc/xtrafluid.txt b/fluidsynth/doc/xtrafluid.txt new file mode 100644 index 00000000..4fb8f23f --- /dev/null +++ b/fluidsynth/doc/xtrafluid.txt @@ -0,0 +1,907 @@ +Xtra iiwu +Version 2.7 +October 2002 + + +--- Introduction +The iiwu Xtra integrates the iiwusynth synthesizer into Director. + +The iiwusynth software synthesizer has been designed by Peter Hanappe, +and is available under the LGPL licence. It emulates in software the +SoundFont 2.01 Specifications (http://www.soundfont.com) designed by +Creative Labs (SoundBlaster maker). It is basically a small, fast and +robust wavetable synthesizer, with a MIDI-like interface and +integrated sequencer. For more information on the iiwu synthesizer : +http://www.iiwu.org/iiwusynth + +The iiwu Xtra has been developped as part of the "infiniteCD Author" +project managed by Antoine Schmitt and Hyptique, with support from the +PRIAM funds from the French government. + +For more information on the infiniteCD Author project : +http://www.infiniteCD.org/ +http://www.hyptique.com/ +http://www.gratin.org/as/ + + +--- Licencing + +The Version 2.7 of the iiwu Xtra is beta. Do not distribute without +permission. Eventually, the Xtra will be part of the iiwu project, +and thus will conform to the LGPL licence. + + +--- Release notes +Version 2.0.1 : first beta version - October 2002 +Version 2.0.1 : first beta version - October 2002 +Version 2.5 : second beta - November 2002 +Version 2.6 : third beta - November 2002 +Version 2.7 : fourth beta - November 2002 + + +--- Technical Requirements +OS: +- Macintosh >= MacOS8.6.1 < MacOSX +- Windows >= 95 +Director 8.5.1 +Sound Card + + +--- Installation +Drop the folder "iiwuXtraFolder" into the Xtras folder of Director. + + +----------------- +--- Documentation +----------------- + +- Calls + +All function calls are done using lingo's call syntax: + +object.func(args...) +or +func(object, args...) + +Where object is the instance of the Xtra created with the 'new' +method. All functions return either a value, which can be 0 (zero), +meaning that the function executed without errors, either a negative +number, meaning that an error occurred. If an error occured, the +function 'getError' returns a human-readable string describing the +error. + +- Instances + +Many instances of the Xtra may coexist at the same time. +Instances are created with the 'new' function, and deleted by assigning +the lingo variable to VOID, as usual for Xtra instances. + +- SoundFont file, stack, presets + +A SoundFont bank is typically stored in a file, called a SoundFont +file, of extension .sf2. In the following documentation, we will refer +to the SoundFont file or SoundFont bank by the term +'SoundFont'. Please note that the term 'bank' will always refer to a +MIDI bank, not a SoundFont bank. + +A SoundFont has a name and contains 'presets'. A preset represents a +way to play a sound, as a combination of sample data and parameters on +how to play it. The preset is the fundamental sound object of the +SoundFont format. + +A preset has a name, and is defined uniquely by a MIDI bank number and +a preset number in the bank. The MIDI bank number ranges from 0 to +16383 and the preset number from 0 to 127. Thus a SoundFont file may +contain up to 128x16384=2097152 presets. + +SoundFont files may be loaded in the synthesizer, using the +'loadSoundFont' function, thus making its presets available for +playing. A SoundFont may be unloaded using the 'unloadSoundFont' +function. + +If more than one SoundFont file is loaded, the SoundFonts are stacked +in the synthesizer : when a preset is requested by the 'programChange' +function, it is looked up in all succcessive SoundFonts, from first to +last, until the preset with the right preset number and bank number is +found. The SoundFont stack may be examined but not changed : the +SoundFonts are stacked in inverse loading order: the last loaded +SoundFont is the first searched. + +A special SoundFont is maintained by the synthesizer, corresponding to +user-defined presets, built from user-provided samples. These presets +are defined using the 'loadSample' and 'loadSoundMember' +functions. This user SoundFont is inserted in the SoundFont stack at +the first call of one of these functions. All subsequent calls to one +of these functions will insert the created preset in the same user +SoundFont. + +- Channels + +According to the MIDI format and protocol, the synthesizer has a fixed +number of channels. This is the maximum number of presets that may be +playing at the same time. At all times, one given channel plays at +most one preset (but can play many notes from this preset). A preset +is associated to a channel using the 'programChange' function. The +number of channels of the synthesizer is defined at init time using +the 'new' function. A given preset may be associated to many +channels. + + +----------------- +-- Initialization +----------------- + +new(Xtra"iiwusynth") +new(Xtra"iiwusynth", plist initParams) +----------------- + +ex : iiwuObj = new(Xtra "iiwusynth", [#channels: 32]) + +Creates a new instance of the iiwu Xtra. +The optional initParams argument is a propert-list +of key-value paris defining initialization parameters. + +Only one key is currently defined: + +- #channels : int > 0 : the number of channels allocated by the +synthesizer. If omitted, the default number of channels is set to 64. +Version 2.0.1 : This is not implemented yet : the number of channels is always 64. + +To destroy the synthesizer, simply set its variable to VOID. + +Returns an error code (unable to create, hardware error, bad arguments). + + +getChannelsCount(object me) +----------------- + +ex : nbchan = getChannelsCount(iiwuObj) + +Returns the number of channels of the synthesizer. By default, there are 64 channels. + +Returns an error code (no synth). + + +getMasterGain(object me) +----------------- + +ex : gain = getMasterGain(iiwuObj) + +Returns the master gain of the synthesizer. By default the gain is 1.0 (full volume). +The gain is between 0.0 and 2.0. +Returns an error code (no synth). + + +setMasterGain(object me, float gain) +----------------- + +ex : setMasterGain(iiwuObj, 0.5) + +Sets the master gain of the synthesizer. By default the gain is 1.0. +The gain should between 0.0 and 2.0. +Gains superior to 1.0 (full volume, no attenuation) should be handled +carefully, as distortion may happen. +Returns an error code (no synth). + + +----------------- +-- Reverb/Chorus +----------------- + +setReverb(object me) +setReverb(object me, int onOrOff) +----------------- + +ex : setReverb(iiwuObj) +ex : setReverb(iiwuObj, FALSE) + +Sets the reverb module of the synthesizer on or off. + +Returns an error code (no synth, bad arguments). + + +getReverb(object me) +----------------- + +ex : revOn = getReverb(iiwuObj) + +Return 1 of the reverb module is on (default), 0 if it is off. + +Returns an error code (no synth, bad arguments). + + +setReverbProp(object me, symbol prop, float value) +----------------- + +ex : setReverbProp(iiwuObj, #roomsize, 0.9) +ex : setReverbProp(iiwuObj, #level, 0.2) + +Sets the value of a property of the reverb module. +Accepted properties are: +- #level : the level of the reverb (0.0 = no reverb, 1.0 = full reverb). +- #roomsize : the size of the room. 0.0 means a very small room, 1.0 means outerspace. +- #width : the spatial width of the reverb. 0.0 means a very narrow reverb, 1.0 a wide one. +- #damping : how much power is lost at each reverberation. 1.0 : mostly lost, 0.0 : full reverberation. + +All values are between 0.0 and 1.0. + +Returns an error code (no synth, bad arguments). + + +getReverbProp(object me, symbol prop) +----------------- + +ex : roomsiz = getReverbProp(iiwuObj, #roomsize) +ex : damping = getReverbProp(iiwuObj, #damping) + +Returns the float value of the given property of the reverb module. Accepted properties are listed above. +Returns an error code (no synth, bad arguments). + + +setChorus(object me) +setChorus(object me, int onOrOff) +----------------- + +ex : setChorus(iiwuObj) +ex : setChorus(iiwuObj, FALSE) + +Sets the chorus module of the synthesizer on or off. + +Returns an error code (no synth, bad arguments). + + +getChorus(object me) +----------------- + +ex : chorusOn = getChorus(iiwuObj) + +Return 1 of the chorus module is on (default), 0 if it is off. + +Returns an error code (no synth, bad arguments). + + +setChorusProp(object me, symbol prop, float value) +----------------- + +ex : setChorusProp(iiwuObj, #number, 3) +ex : setChorusProp(iiwuObj, #level, 0.2) + +Sets the value of a property of the chorus module. +Accepted properties are: +- #level : the level of the chorus. Min is 0.0, maximum accepted is 10.0. +- #number : the number of secondary voices. Maximum is 99. +- #modulation : the amplitude of the frequency modulation, in Hz. Min is 0.29, max is 5.0. +- #delay : the maximum delay between secondary voices, in ms. Min is 0, maximum is 100.0. + +Returns an error code (no synth, bad arguments). + + +getChorusProp(object me, symbol prop) +----------------- + +ex : number = getChorusProp(iiwuObj, #number) +ex : modulation = getChorusProp(iiwuObj, #modulation) + +Returns the float value of the given property of the chorus module. Accepted properties are listed above. +Returns an error code (no synth, bad arguments). + +----------------- +-- Sound Data +----------------- + +loadSoundFont(object me, string filePath) +----------------- + +ex : soundFontID = loadSoundFont(iiwuObj, the moviePath & "MySoundFonts.sf2") + +Loads a SoundFonts file in the synthesizer and places it at the top of +the SoundFont stack : it will be the first searched when looking for a +preset. + +The path is absolute, and should be expressed with the local file +system conventions. + +The loaded soundFont will be of type #file. + +Returns an ID, an interger uniquely idenfiying the SoundFont in the stack, or an error +code (no synth, no file, bad file format, not enough +memory). + + +createSoundFont(object me) +createSoundFont(object me, string name) +----------------- + +ex : soundFontID = createSoundFont(iiwuObj) +ex : soundFontID = createSoundFont(iiwuObj, "mysoundfont in memory") + +Creates an empty SoundFont in memory (type #ram) and places it at the top of +the SoundFont stack : it will be the first searched when looking for a +preset. + +The returned soundFontID can be used in the #soundFont property of the loadSampleFile or +loadSampleMember functions. + +The created soundFont can be removed from memory, using the unloadSoundFont function. + +The 'name' argument is optional and defaults to EMPTY (the empty string). + +Returns an ID, an interger uniquely idenfiying the SoundFont in the stack, or an error +code (no synth, no file, bad file format, not enough +memory). + + +unloadSoundFont(object me) +unloadSoundFont(object me, int soundFontID) +----------------- + +ex : unloadSoundFont(iiwuObj, 1) +ex : unloadSoundFont(iiwuObj) + +Unloads the SoundFont of the given ID of the SoundFont stack. +The soundFontID argument is optional, and defaults to the first searched +SoundFont (the last loaded). + +All types of soundFonts can be unloaded from memory. + +Returns an error code (no synth, bad ID). + + +reloadSoundFont(object me) +reloadSoundFont(object me, int soundFontID) +----------------- + +ex : reloadSoundFont(iiwuObj, 1) +ex : reloadSoundFont(iiwuObj) + +Version 2.0.1 : Not Yet Implemented. + +Reloads the SoundFont of the given ID of the SoundFont stack. +The soundFontID argument is optional, and defaults to the first searched +SoundFont (the last loaded). +This is useful when a soundFont is known to have changed outside +the synthesizer. +Only SoundFonts of type #file can be reloaded. + +Returns an error code (no synth, bad ID). + + +getSoundFontsStack(object me) +----------------- + +ex : aList = getSoundFontsStack(iiwuObj) + +Returns a lingo list containing all the IDs of the SoundFonts in the stack, sorted from first searched to last searched (last loded to first loaded). +May return an error code (no synth). + + +getSoundFontInfo(object me) +getSoundFontInfo(object me, int soundFontID) +----------------- + +ex : nam = getSoundFontInfo(iiwuObj) + +Returns information about the SoundFont of the given soundFontID of the SoundFont stack. +The soundFontID argument is optional, and defaults to the first searched +SoundFont (the last loaded). + +The information is returned in the form of a lingo property-list, +containing key-value pairs describing the SoundFont: its name, and +info about its presets (name, preset number and bank number): + +[ + #name:"SoundFontName", + #type:#file or #ram, + #presets: + [ + [#name:"preset1Name", #bank:preset1bankNb, #number:preset1Number], + [#name:"preset2Name", #bank:preset2bankNb, #number:preset2Number], + ... + ] +] +(More information may be added in future versions of the Xtra) + +Can return an error code (no synth, bad soundFontID). + + +loadSampleFile(object me, string filePath, plist presetInfo) +loadSampleFile(object me, string filePath, int number) +----------------- + +Version 2.0.1 : Not Yet Implemented. + +ex : loadSampleFile(iiwuObj, the moviePath&"MidPiano.aiff", +[#name:"piano", #bank:0, #number:1, #rootKey:60, #keyrange:[50, 70]]) + +ex : loadSampleFile(iiwuObj, the moviePath&"Piano.aiff", [#number:2]) +ex : loadSampleFile(iiwuObj, the moviePath&"Piano.aiff", 2) + +Loads a sample file from filePath and creates a preset from it. This +is a simple way of creating a preset from a specific sample. + +The 'filePath' is absolute, and should be expressed with the local +file system conventions. Accepted sample formats are : wav, and aiff. + +The preset is added to a ram (memory) SoundFont (type #ram). +This SoundFont is either specified using the #soundFont property (see below), +either the highest soundfont in the stack is used if it is a ram soundfont, +either it is created on the fly in memory, in which case it is placed at the top +of the SoundFont stack of the synthesizer. + +The preset is created according to the 'presetInfo' +lingo property-list. This plist is a combination of key-value pairs +describing the preset. The following keys are taken into account: + +- #number : integer, mandatory. Between 0 and 127 : the preset number in the bank + If this preset number (and bank if set) was already in use, the sample is added + to the already preset samples of this preset. This is a handy way to define + a keyRange for a preset. + +- #bank : integer, optional (default = 0). Between 0 and 16383: the number + of the MIDI bank that will be assigned to the preset. + +- #soundFont : integer, optional. Specifies the soundFontID of the SoundFont + in which the preset will be created. If specified, it should be a + soundFont of type #ram. If not specified, the first soundfont on the stack + will be used if it is of type #ram. If not, a new SoundFont + is created on the fly. + +- #name : string : the name of the preset - optional + +- #rootKey : int between 0 and 127 : the key at which the sample will + be played 'as is' - optional : if omitted, 60 (middle-C) is used. + +- #keyRangeStart : integer, optional (default = 0). + Defines the first of two keys between which the sample should be + played (the comparison is inclusive). + If a noteon asks for a key outside this range, the sample is not + played. If omitted, the whole range [0, 127] is used. + +- #keyRangeEnd : integer, optional (default = 127). See keyRangeStart. + +- #loop : boolean, optional. Specifies that the sample should be played +as a loop. Default is FALSE. + +- #attack : float, optional (default = 0.0). Duration, in milliseconds of +the attack phase of the sound, i.e. the time for the sample to reach peak volume +after a noteon is issued. + +- #decay : float, optional (default = 0.0). Duration, in milliseconds of +the decay phase of the sound, i.e. the time for the sample to reach sustain volume +after the attack. + +- #sustainlevel : float, optional (default = 0.0). Level, in dB relative to the +peak level, of the sustain level. A sustainlevel of 0 means the same level than +the peak level. A sustainlevel of 10 mean peak-10dB, which is very low. +A sustainlevel of 100dB conventionnaly means full attenuation. + +- #release : float, optional (default = 0.0). Duration, in milliseconds of +the release phase of the sound, i.e. the time for the sample to reach silence +after a noteoff. + +Note that in one preset, two different samples may be used for two +different key ranges. + +example : + +loadSampleFile(iiwuObj, the moviePath&"PianoLo.aiff", [#name:"piano", +#bank:0, #number:1, #rootKey:30, #keyrange:[0, 60]]) + +loadSampleFile(iiwuObj, the moviePath&"PianoHi.aiff", [#name:"piano", +#bank:0, #number:1, #rootKey:90, #keyrange:[61, 127]]) + +This example defines two samples for two ranges of the same preset. + +A preset may not be unloaded ; only the whole user SoundFont may be +unloaded from the SoundFont stack, using the 'unloadSoundFont' +function. + +Returns the soundFontID of the SoundFont to which the sample has been added, +or an error code (no synth, no file, bad file format, not enough +memory, bad bank number, bad preset number, bad key). + + +loadSampleMember(object me, obj member, plist presetInfo) +----------------- +ex : loadSampleMember(iiwuObj, member(3), [#name:"piano", #bank:0, #number:1]) + +Version 2.0.1 : Not Yet Implemented. + +Loads a sample from the given Director sound cast member and creates a +preset from it. + +The preset is created according to the 'presetInfo' lingo +property-list. (see above for details on the presetInfo format). + +Returns the soundFontID of the SoundFont to which the sample has been added, +or an error code (no synth, no member, bad member format, not enough memory, +bad bank number, bad preset number, bad key, not a user soundFont). + + + +----------------- +-- Event sequencer +----------------- + +Introduction +----------------- + +- Sequencer + +The API functions for playing music is derived from the MIDI +protocol. This protocol defines the use of a number of presets for +every synthesizer object. Application communicate with a preset in a +synthesizer over a channel. The communication is event based (MIDI +events). The API of the music functions (discussed below) can be +thought of as sending an event over a channel to a preset. + +The music API functions includes the optional use of a sequencer. A +sequencer is an object that assures the delivery of an event at a +future time. To use the sequencer object, the events have to specify a +time property. Two property key values can be used: + +- #date: specifies the time on an absolute time axis (the creation + time of the synthesizer is used as time zero), + +- #delay: specifies the time relative to the sequencer's current time. + +The time is measured in 'ticks'. A 'tick' is an arbitrary unit that +can be set by the application. See the sequencer API below. + +- Event destinations + +The API includes the use of several synthesizer objects. The property +key '#dest' indicates the destination of the event. The destination +value is the name of the synthesizer object. If no destination is +specified, the event will be sent to the first known destination which +is the default synthesizer. + +- Event sources + +Events can also specify an event source. This is useful when the +sender of an event wants to cancel some time the event later. To use +this feature, the event simply contains the key '#source' with a string +as value. + +- Callbacks + +Lingo objects can ask the sequencer to schedule a callback function at +a precise time. The callback is the name of a Lingo handler. The movie +will have to call the poll function of the xtra regularly to receive +the callbacks. + + +- Sequencer API + +The following functions address the sequencer directly. + +setTimeUnit(object me, float ticksPerSecond) +----------------- +ex. setTimeUnit(iiwuObj, 10.0) -- 1 tick equals 100 millisecond + +Sets the tick unit of the sequencer. +ticksPerSecond is a float > 0. + +Returns a error indication (bad initialization). + + +getTimeUnit(object me) +----------------- +ex. getTimeUnit(iiwuObj) + +Returns the tick unit of the sequencer or an error indication (bad +initialization). +By default, the tick value is 1000.0 (1 tick = 1 millisecond). + + +getTime(object me) +----------------- +ex. getTime(iiwuObj) + +Returns the time in tick from the start of the synthesizer, in tick units +of the sequencer or an error indication (bad initialization). + + +getDestinations(object me) +----------------- +ex. getDestinations(iiwuObj) + +Returns a list with all the names of possible event destinations. + + +removeEvents(object me, plist filter) +----------------- +ex. removeEvents(iiwuObj, [#dest: "iiwusynth", #source: "DrumMachine"]) +ex. removeEvents(iiwuObj, [#source: "DrumMachine", #type: #note]) + +Removes events that are queued for sending in the sequencer. The +function takes property list as argument. The property list defines +the events that should be filtered. Currently, any of the three +following keys can be used: + +- #source: remove the events for the specified source (if not specified, +removes all source) +- #dest: remove the events sent by the specified destination (if not +specified, removes all destination) +- #type: remove the events according to this event type (if not +specified, removes all events) + +Possible event types are: + +- #note +- #noteon +- #noteoff +- #allsoundsoff +- #allnotesoff +- #programchange +- #controlchange: includes all controlChange events (pitchbend, modulation, + sustain, pan, volume, reverbsend, chorussend) +- #pitchbend +- #modulation +- #sustain +- #pan +- #volume +- #reverbsend +- #chorussend +- #callback + +Returns an error code (no sequencer, invalid argument). + + + +scheduleCallback(object me, plist callbackInfo) +----------------- +ex. scheduleCallback(iiwuObj, [#delay: 1200, #handler:"updateDrumMachine", #args: [1,2,3]]) +ex. scheduleCallback(iiwuObj, [#delay: 1200, #source:"drumMachine", #handler:"updateDrumMachine"]) + +Schedules a callback event. When the event is reached, the lingo handler defined in +the 'callbackInfo' propertylist is called back. Note that the callback happens during +idle time. + +The 'callbackInfo' propertylist has the following possible properties: + +- #handler, string, mandatory. It is the lingo handler that will be called. +- #args, a lingo list, optional. This list contains the arguments of the handler. +The scheduleCallback function retains a pointer to this list but does not copy it, +according to the lingo tradition. The lingo eventually executed is equivalent +to "handler(args[1], args[2], ...)". If the first argument is a child object, +the corresponding handler will be called on that object. +- #delay/#date : integer, optional. Specifies the time of the callback. Defaults to #delay:0 +- #source : optional. Specifies the source. Useful for removing callbacks. +- #dest : optional. Specifies the destination. + +To remove a scheduled callback, use removeEvents: +ex : removeEvents(iiwuObj, [#source: "drumMachine", #type: #callback]) +ex : removeEvents(iiwuObj, [#type: #callback]) + +Returns an error code (no sequencer, invalid argument). + + + + + +----------------- +-- Playing music +----------------- + +Most event functions accept an optional property list that describes +the sequencing of the event. This is indicated by the 'seq' argument +in the functions below. The following properties are recognized: + +- #date: the absolute time of the event +- #delay: the time of the event relative to current time +- #source: the event source +- #dest: the event destination + +#date and #delay should not be specified together. + + +programChange(object me, int channel, plist presetInfo, plist seq) +programChange(object me, int channel, int presetNumber, plist seq) +----------------- + +ex : programChange(iiwuObj, 1, [#bank:1, #number:3]) +ex : programChange(iiwuObj, 1, 3) + +Assigns the given preset of the SoundFont stack to the given channel +of the synthethizer. + +The preset may be defined using a property-list defining its MIDI bank +number and its preset number, using specific keys: + +- #bank : int between 0 and 16383: the number of the MIDI bank of the + preset - optional : if #bank is not present, 0 is the default. + +- #number : int between 0 and 127 : the preset number in the bank - + mandatory. + +The preset may also be defined by a unique int, wich is treated as +the preset number, assuming that the MIDI bank is 0 (zero). + +In all cases, the preset is looked up in the SoundFont stack, starting +from the first SoundFont up the stack, until a corresponding preset is +found. The found preset is assigned to the channel. The maximum +number of channels are defined using the 'new' method. + +If a preset was previoulsy assigned to that channel, it is forgotten, +but all noteon finish normally. + +Returns an error code (no synth, no SoundFonts, bad +channel, bad preset definition). + + +getProgram(object me, int channel) +----------------- + +ex : getProgram(iiwuObj, 0) + +Returns information about the preset assigned to the channel. The +information is of the form : [#name:"presetName", #bank:presetBankNb, +#number:presetNumber] The maximum number of channels are defined using +the 'new' method. + +May return an error code (no synth, no preset +assigned, bad channel number) + + +note(object me, int channel, int key, float vel, int dur, plist seq) +----------------- + +ex : note(iiwuObj, 1, 38, 1.0, 1000) + +Plays a note, using the specified 'channel' and 'key', with the +specified velocity (strength). The duration 'dur' of the note is +specified in ticks. + +0.0 <= vel <= 1.0 (automatically limited if smaller or greater) +0 <= key <= 127 + +The maximum number of channels are defined using the 'new' method. + +Returns an error code (no synth, no SoundFonts, bad +channel, no preset assigned, bad key, bad vel). + + +noteon(object me, int channel, int key, float vel, plist seq) +----------------- + +ex : noteon(iiwuObj, 1, 38, 1.0) + +Starts a note, using the specified 'channel' and 'key', with the +specified velocity (strength). + +0.0 <= vel <= 1.0 (automatically limited if smaller or greater) +0 <= key <= 127 + +The maximum number of channels are defined using the 'new' method. + +Returns an error code (no synth, no SoundFonts, bad +channel, no preset assigned, bad key, bad vel). + + +noteoff(object me, int channel, int key, plist seq) +----------------- +ex : noteoff(iiwuObj, 1) + +Stops all playing notes on the given 'channel' and the given 'key'. + +The maximum number of channels are defined using the 'new' method. + +Returns an error code (no synth, no SoundFonts, bad +channel, no preset assigned). + + +controlChange(object me, int channel, plist controlParams, plist seq) +----------------- +ex: +controlChange(obj, 1, [#pitchbend: 1.0, #sustain:1]) +controlChange(obj, 1, [#pan: -0.2, #sustain:1, #volume:0.5, #reverbsend:1.0]) + +This function allow to change some control parameters of the given +channel. The effect is immediate and allows for continuous +modification of a sound. + +The 'controlParams' is a lingo property-list of key-value pairs, with +the key describing the control parameter to affect, and the value +specifying the amount of the change. For some keys, the value is not +taken into account. The list of currently implemented keys is the +following : + +- #pitchbend: float between -1.0 an 1.0: sets the pitchbend level + 0.0 means no pitchbend. + The pitchrange may be configured in the preset (for + loaded SoundFonts), but the default range corresponds to 4 steps + (one step = one semi-tone), so a value of -1.0 means two steps down, + and a value of 1.0 means two steps up. + +- #pan: float between -1.0 an 1.0: sets the pan level. + -1.0 is all sound on left channel, 1.0 is all sound on right channel + 0.0 is sound in center. + +- #volume: float between 0.0 an 1.0: sets the volume level. + 0.0 is silence, 1.0 is full volume. + +- #reverbsend: float between 0.0 an 1.0. Sets the volume of the auxiliary + output send to the reverb module. 0.0 is no signal, 1.0 is full + volume. + +- #chorussend: float between 0.0 an 1.0. Sets the volume of the auxiliary + output send to the chorus module. 0.0 is no signal, 1.0 is full + volume. + +- #sustain: int = 0 or 1: sets or removes the sustain from the + channel. + +- #modulation: float between 0.0 an 1.0. Amplitude modulation. + Vibrato. + +Returns an error code (no synth, no SoundFonts, bad +channel, no preset assigned, unknown controlKey, bad controlValue). + + +getControl(object me, int channel, symbol ctrl) +----------------- +ex. getControl(iiwuObj, 1, #volume) + +Returns the value of a controller. + + +getControls(object me, int channel) +----------------- +ex. getControls(iiwuObj, 1) + +Returns a property list with the values of all controllers in the +form: [#pan: 0.4, #sustain:1, #volume:0.8, #reverbsend:1.0, ...] + + +allsoundsoff(object me, int channel, plist seq) +----------------- + +Instantly stops all sound on the channel. The optional argument is +the sequencer information. Returns an error code (no sequencer). + + +allnotesoff(object me, int channel, plist seq) +----------------- + +Sends a noteoff to all currently playing notes on the channel. The +optional argument is the sequencer information. Returns an error code +(no sequencer). + + + +--------------------------- +-- Debug and maintenance +--------------------------- + +debug(object me, string logFile) +----------------- + +ex : debug(iiwuObj, the moviePath&"logfile") + +Sets the debug mode of the Xtra. +If a logFile is provided, debug is set. +If VOID is provided, debug is turned off. +If debug is on, a log of all actions and errors is written in the logFile. + +Returns an error code (cannot open/create log file). + + +getError(object me) +----------------- +ex : lastError = getError(iiwuObj) + +returns a human readable string describing the last error that occured +in the Xtra. + + +getCPUUsage(object me) +----------------- +ex : aPercent = getCPUusage(iiwuObj) + +returns a float representing the estimation of the percentage of CPU +used by the synthesizer, or an error code (no synth). + +------------------------------- +------------------------------- +-------------------------------