Ann Hell Scripting - I: Basic Commands
This document describes the basic commands for the Ann Hell Scripting language. These commands are those directly related with the music being generated, as notes and their appropriate properties and global song information as tempo and measure. Also, a global description of the AHS syntax is included here.
Ann Hell Ex Machina scripts consist of a sequence of commands and their possible arguments which run from the top to the bottom. Formatting and indentation can be used in a free-form way.
At any time, comments can be inserted in C language style as in the following example:
/* this is a C style comment, that spans multiple lines */
Whitespace separation is not mandatory and commands can be conveniently joined together if they are unambiguous.
T120 M4/4 o5 c4 d8 e& f4 g8 a&16 b& c'1
can also be written as
or, grouped by measures,
T120 M4/4 o5 c4d8e& f4g8a&16b& c'1
Script files can be included from each other by enclosing filenames between backticks, as in the example:
The referenced file will be inserted at that exact point.
Tempo is expressed in Beats Per Minute (bpm) as in the next example:
T120 /* sets tempo to 120 Beats Per Minute */
Obviously, tempo changes are global to all tracks. Though it's normally set at the beginning of a song, it can be used anywhere. You can use marks to be sure that tempo changes occur exactly where you want in all tracks (see documentation for marks). The tempo can be a non-integer number.
Measure is expressed as in standard music notation. For example:
M4/4 /* classic 4 quarter notes measure */
Measure settings are global to all tracks as tempo.
Letter is any from a to g for english notation notes in the currently selected octave, r for rests, or z for a zero-note, that allows setting the length for subsequent notes without doing anything more.
The alteration is optional, and is any of # (sharp) or & (flat). If not specified, natural note is assumed.
The octave is also optional, and is one or more ocurrencies of ' (one octave higher for each one) or , (one octave lower for each one). If none is specified, note is assumed to belong to the current octave.
a# /* A sharp */ g& /* G flat */ a /* normal A */ c' /* C, one octave above */ f#,, /* F sharp, two octaves below */
Optional, with the following syntax:
Figure is any of 1, 2, 4, 8, 16, 32, 64 measure partitions. Tuplet, if present, is a / followed by a numeric divisor (3 for triplets, etc.). Currently, only 3 or 5 tuplets are supported. Mult, if present, can be expressed as an * followed by a numeric multiplier of the figure meaning the final length is that times longer, or as a more music-standard series of dots, adding each one half the length.
If no length is present, the note length is inherited from the last one previously defined.
a4 // an A longing one beat r4. // a rest, longing one beat and a half g8/3 // a G, in triplets of eighths f1*6 // an F longing 6 complete 4/4 measures r4*1.5 // same as r4. z2 // sets note lengths to a half note (no note inserted)
Optional, can be expressed as a ~ followed by a real number ranging from 0 (silence) to 1 (full volume).
If no volume is specified, the full global one is used.
a4~0.8 // a quarter note of A at 80% of global volume
Measure marks help when writing music by asserting that measures last exactly what the metric says. They are the equivalent of measure bars in standard music notation and are expressed by the character |. Unlike in standard music, though, they are optional. Apart from checking, these marks do not modify the resulting music in any way.
This piece of music will trigger an error in the second mark, just before the c2, because it does not fall in a measure boundary.
M3/4 a4 b c | c1 | c2
Permanent octave changes
Permanent octave changing can be expressed as an absolute or relative change. Examples:
o2 /* sets octave number 2 (absolute) */ o+1 /* sets one octave higher (relative) */ o-2 /* sets two octaves lower (relative) */
Absolute octave numbers range from 0 to 10. Otherwise, for relative changes, a signed integer number can be used.
A complete note trip up can be done this way, using absolute and relative changes and blocks:
o0 z16 (cdefgab o+1)*10
Octaves can be out of range (the previous example will end with an invalid octave number of 11), but inserting a note after it will generate an error. This 'lazy error checking' is done purposely to allow block repetitions like this one; just change to a valid octave before inserting a new note.
Permanent volume changes
Permament volume can be expressed as an absolute or relative change. Examples:
v0.75 /* sets global volume to 0.75 (75%) */ v+0.1 /* increments current volume by 0.1 */ v-0.3 /* decrements current volume by 0.3 */
Absolute volume range from 0 (silence) to 1 (full volume).
Dynamic (random) volumes
(New in 1.0.10) If the volume command has two arguments separated by a comma, each note will be generated with a random value from within that range.
v0.2,0.8 /* next volumes will be from 0.2 to 0.8, randomly chosen */
Transposition is expressed as a negative or positive number of semitones. By default, each track has an initial transposition of 0. This is an example:
t5 /* transpose a fifth up */
Note that transpose, as octave changing, can lead to out-of-bound notes. No error will be reported until an invalid note is inserted.
The staccato is expressed as the partial time of the total note length that the note will really sound. By default, each track has an initial value of 0.8 (80%). Usual values range from 0.5 (staccato) to 1 (tenuto). For example:
s0.9 /* sets staccato to 90%: notes sound more tied together */
To form chords or more complicated sequences of polyphonic notes, groups can be used. They are enclosed by < and > and separated by semicolons. The group's duration is that of the longest of the parts.
The simplest example is a basic chord like this one:
<c1 ; e& ; g> /* a C minor chord for a whole 4/4 measure */
Each part of the group can contain more than one note:
// the classic bass drum, snare, close and open hat beat <c8rrr crrr ; rrdr rrdr ; g#g#g#a# g#g#g#a#>
By default, each part of a group start at exactly the same time. To implement strumming (as, for example, in guitar chords, where each note is played slightly after the previous one), the glissando command is used, with an argument expressed as a note length:
l16 <c;e;g> /* delay each chord note by a sixteenth */
Multipliers and tuplets can also be used (see the note length sections for more information).
To disable glissando, use a glissando command with a value of 0.
The arpeggiator allows the programming of automatic repetitions for each note, probably modifying some of its features. It's expressed by the x command followed by a comma separated list of repetition specifications with the following syntax:
Offset is a length specification (see Notes) and is the delay of the repetition after the start of the original note (it does NOT express the length of the repeated note; each arpeggiated note last the same as the original one). It can be zero for notes that sound at the same time as the original note.
Volume, if specified, is a ~ followed by a real number (see also Notes). This volume is multiplied by the original volume of the note. If none is specified, the note is repeated at its original volume.
Transpose, if specified, is a signed number of semitones to transpose the original note. If no transpose is specified, the pitch of the repeated note will be the same as the original.
Track, if specified, is a / followed by a track offset, meaning the note will be inserted that tracks after current one (and not in the current one).
An x command with no repetition specifications effectively disables the arpeggiator.
x4~0.6 // repeats each note a quarter later at 60% of vol. x4~0.6,2~0.4 // the same, but another repetition later at 40% x8-1,4-2,8*3-3 // 3 chromatic repetitions after each eighth x8-1,4-2,8*3-3/2 // the same, last note is inserted 2 tracks after x // disable arpeggiator
To create a mark, use
and, in tracks defined later, you can set the cursor at the mark by using
The mark name can use alphanumeric characters and hyphens. An error is generated if a move to mark command is used but the current track's cursor is already beyond that position (i.e. you cannot move 'backwards').
Marks can also be used for synchronization by using
if the track's cursor does not match that of the mark position, an error is returned reporting the difference in measures.
The START mark defines the starting point of subsequent tracks. By default, it's the very begining of the song. If it's defined, all next songs will start at this point.
The END mark is an automatic one that always points to the furthest time seen on a track. So, combining the START and END marks, it's possible to mix different songs to play one after the other, as in
/* first song */ `song1.ahs`
/* move to the furthest point */ @END
/* set start of new tracks there */ ^START
\ /* second song */ `song2.ahs`
Sometimes is useful to move back the internal 'cursor' of the song; for example, when a voice starts just a note before a mark (an anacrusa). The back command is implemented with the letter k followed by an optional note length specification.
/* this instrument is silent until a quarter before tutti */ @tutti
/* move back one quarter and play it */ k4 g
/* tutti really starts here */ c'1
The back command can also be used to implement rudimentary chords:
/* a C major chord, using backs (same as <c1;e;g>) */ c1kekg
Blocks are marked using pairs of parentheses. The closing one should be followed by a character indicating the operation to do with the block.
Blocks that should be repeated a defined number of times can be specified as
Where code can be anything, from notes to track information, and times the number of times the block will repeat.
Named blocks (patterns)
A block can be assigned a name to be later inserted. To name it:
Where code can be anything, from notes to track information, and name-of-the-block the name to be assigned. The name should not contain spaces. The block is not inserted where it's defined; to insert it, the following notation should be used:
So, for example:
(c16defgab)=scale // define a named block $scale $scale $scale // insert several times ($scale)*8 // blocks can be nested
Named blocks can be redefined anytime:
(($drumloop)*8)=phrase // valid even though drumloop is still undef (cdcdcdcd)=drumloop $phrase // drumloop resolved when inserting phrase (cdcccdcc)=drumloop $phrase // inserts now 8 copies of the new drumloop
Using blocks for random playing
Blocks can be used to select alternatives for random playing. These alternatives are defined inside a block and separated by a : (colon). This way, when inserting a block, one of the subblocks will be randomly selected.
/* play 4 whole note chords; they can be CM, FM or GM at random */ z1 (<c;e;g> : <c;f;a> : <d;g;b> )*4
/* if you want different weights, just do it by repeating */ /* this way, CM will be 50%, FM 25% and GM 25% */ (<c;e;g> : /* CM again */ <c;e;g> : <c;f;a> : <d;g;b> )=chords1
(New in 1.0.8). Alterations can be implemented with the A command. The argument to this command is a string specified up to seven alterations for the natural notes c, d, e, f, g, a and b, where each alteration can be # (sharp), & (flat) or - (natural). This command is useful to specify tonalities.
/* plays a natural C scale (C Major) */ c8defgab c1
/* sets the alterations to match the C Minor mode; flats on e, a and b, no change on the rest. From now on, all references to those notes will be altered */ A--&--&&
/* and now play a C Minor scale */ c8defgab c1
/* set now to G Major (notes not specified are naturals) */ A---# g8abcdef g1
/* set back to C Major */ A
Major and minor modes for classic tonalities are predefined as named blocks and implemented as alterations. The name is formed by the uppercase note, an optional modifier (# for sharp and & for flat, as always) and an M or m (for Major and minor):
/* set tonality to C Major */ $CM /* set tonality to B flat Major */ B&M /* set tonality to F sharp minor */ F#m
(New in 1.0.12) Source and data files are seeked from a number of directories or paths, as the ~/ahxmlib directory, for example. From the very start, the Ann Hell Scripting compiler always have supported the -L switch, to add more directories to that library path. Now, the L directive can also be used to do the same from a source file:
/* also search for files in /usr/share/sounds/sf2 */ L/usr/share/sounds/sf2
Command reference table
a Insert note A b Insert note B c Insert note C d Insert note D e Insert note E f Insert note F g Insert note G r Insert rest (silence) z Zero note (set length for future notes) o Set default octave t Set transpose s Set staccato v Set volume A Set alterations
< Start of group ; Group delimiter > End of group l Set glissando delay
( Start of block ) End of block * Block repetition if following ) = Named block assignment if following ) $ Named block insertion ` Include script
^ Set mark @ Move to mark ! Mark assertion
T Set tempo M Set measure
| Measure mark k Move back x Arpeggiator L Add to library path
Angel Ortega - http://triptico.com