Using Scripts with Composition Engine
The advantage of using scripts with the composition engine is the ability to take advantage of the complete compositional rhythmic, metric, and harmonic environment provided by an ArtSong Project. This includes the ability to change chords and scales, map pitches to the underlying chords or scales, to read and change the metric strength at various time points, and read and change the base duration unit for all generated events during the composition process.
Successfully using scripts with the composition engines requires familiarity with the sequence of events during the algorithmic composition process. Please see Running Scripts.
Script algorithms are processed in normal project component hierarchical order. The script will be compiled and executed during the scripting component’s composition ‘initialization’ phase.
After the script’s MAIN code section is executed the script’s composition initializer function is called:
(Pascal) procedure BeforeCompose(Start, End)
(Basic) SUB BeforeCompose(Start, End)
After the script algorithm has been initialized the remaining components will be initialized in project hierarchical order. Please note that if track events are being generated from a script these events could end up being erased as each track is initialized.
At each time step during the algorithmic composition process the scripts Compose function will be called:
(Pascal) procedure Compose(Time)
(Basic) SUB Compose(Time)
After the composition process has reached the end time the script’s composition cleanup function is called:
(Pascal) procedure AfterCompose(EndTime)
(Basic) SUB AfterCompose(EndTime)
Example 11 – Using the ‘Engine.Generate’ property
During the normal pre-composition initialization phase existing track events are cleared in preparation for new events. This behavior can be canceled by setting the ‘Engine.Generate’ property to false; tracks will not be automatically cleared nor will they generate events.
Do this…
Set the default project view to ‘Project Editor’ and create a new blank project.
Select the top ‘Composition’ component in the Component Pane and click on either the Basic or Pascal algorithm on the ‘General’ Tab of the Algorithms Palette to add an instance of the algorithm to the project.
Select the Algorithm in the Component Pane and open its ‘property editor’ by right-clicking and selecting the ‘Property Editor…’ from the pop-up menu.
Enter the following line in the code window (you can ignore the comments):
(Pascal)
var note, time, duration, n;
this.clearall();
engine.generate := false;
for n = 0 to 19 do
begin
time = n * EIGHTH_NOTE;
duration := randomrange(1,5) * QUARTER_NOTE;
note := this.track[0].addnote(time, duration);
note.pitch := randomrange(C4, C6);
note.volume := randomrange(20, 110);
end;
this.play(0, 24 * EIGHTH_NOTE);
(Basic)
DIM note, time, duration, n
this.clearall()
engine.generate = false
FOR n = 0 TO 19
time = n * EIGHTH_NOTE
duration = randomrange(1,5) * QUARTER_NOTE
note = this.track[0].addnote(time, duration)
note.pitch = randomrange(C4, C6)
note.volume = randomrange(20, 110)
NEXT
this.play(0, 24 * EIGHTH_NOTE)
Close the algorithm property editor.
Clicking the ‘Compose’ button to compile and execute the scripts and begin the composition process.
How it works…
You should get approximately the same results as in Example 3.
Had the ‘engine.generate = false’ not been included the script would have cleared the track and generated the notes but the notes would have been erased again during the track’s initialization phase. Try it!
Example 12 – Using the Composition Environment
In this example we will use the script ‘Compose(t)’ function’s to generate notes at various composition times ‘t’ and map the note pitches to an underlying scale – in this instance pitches will be mapped to the default scale defined by the key signature specified in the composition component.
The ‘Compose(t)’ function, when it exists, is called by the composition engine at each incremental time step during the composition process. The composition engine sets the value of the argument ‘t’ in the function to the current composition time before calling the function; time increments may or may not be uniform.
Do this…
Set the default project view to ‘Project Editor’ and create a new blank project.
Select the top ‘Composition’ component in the Component Pane and click on either the Pascal algorithm on the ‘General’ Tab of the Algorithms Palette to add an instance of the Pascal algorithm to the project.
Select the Algorithm in the Component Pane and open its ‘property editor’ by right-clicking and selecting the ‘Property Editor…’ from the pop-up menu.
Enter the following line in the code window (you can ignore the comments):
(Pascal)
// this example has both a MAIN and PROCEDURE section
// the main section, which is executed immediately is // used to initialize a variable to keep track of note // generation and occurrence times
var lasttime; // variable used just to
// prevent note overlaps
// this procedure is called by the composition
// engine; the argument ‘t’ contains the
// current composition time
procedure compose(t)
var dur, pit;
begin
// check for another note that might be occurring
if(t >= lasttime) then
begin
// if no overlap with last note we generate
// a new note event
pit := RandomRange(32, 96);
dur := 30 * RandomRange(1,16);
// update lasttime
lasttime := lasttime + dur;
// often we will want to ensure that generated
// pitches adhere to the
// underlying scale or chord….
// the following ensures that pitch
//is in underlying scale
this.track[0].addnote(t, dur).pitch :=
engine.scalepitch(pit);
// alternatively the following ensures
// that pitch is in underlying chord
// this.track[0].addnote(t, dur).pitch :=
// engine.chordpitch(pit);
end;
end;
»
|