MANX started its life in 1993 as support software for the Metallophone Project of the Dutch Forth Users Group. The metallophone project -- two relay-driven xylophones controlled by a computer programmed in Forth -- was a big promotional success at a local computer fair. The host computer interpreted specially formatted text files filled with score information. Appropriate output commands actuated relays to generate the wanted notes.
In the months after the fair MANX development continued. The current release 1.0 is not exclusively for metallophones anymore. The program is able to read and write standard MIDI (Musical Instruments Digital Interface) files, with special instrument drivers taking care of I/O details. At this moment MANX has drivers for metallophones, the PC speaker, and GM (General MIDI) synthesizers or soundcards that support MIDI.
The user interface of MANX is the regular Forth environment, enhanced with a number of special purpose music language words. This music language aims to be complete in the sense that a user should be able to translate anything written down in conventional scores to MANX commands. But of course there is more, much, much more. A short list of features:
cis3
) or index (e.g. 42)
/4 /8.
, but also 3 \196
for special applications
126 /4 MM
{ c2 e2 gis3 }
and arpeggio's {arp c2 e2 g3 }
Acoustic-Grand-Piano, Orchestral-Harp, Bass-Drum-1
)
reverb sustain chorus pitchbend
)
MANX is written for a 32-bit ANS Forth, but in version 1.0 a lot of non-standard extensions are used. Therefore it is advised to use iForth 1.0 for DOS, Windows NT or Linux (all require an IBM-PC compatible with '386+'387 or better and at least 4 Mbytes of RAM).
Future versions of MANX may become standard ANS Forth with clearly bordered hardware dependencies. MANX is ported to non-IBM computers.
MIDIRW.FRT
are able to analyze the contents of standard
MIDI files version 1.0 (1988). A 'decompilation' of the information is
written to the terminal or to an ASCII text file.
MIDI files can also be played back on the available sound hardware, given
a suitable driver. MIDIRW
comes with drivers for the PC-speaker, for a
network of metallophones, and for a GM (General MIDI) synthesizer. As most
PC soundcards have MIDI drivers, a soundcard can also be used as an output
device. Note that some cards come with a Windows MIDI driver and do not
support MS-DOS. In that case you need to use iForth for Windows NT or Linux.
The most important application of MIDIRW
is to support MANX. In this
capacity, MIDIRW
allows MANX to write full-featured MIDI type 1
(multiple track) files. There are no restrictions.
[Sequence / track name] Militaire : 0 [Text] Schubert, Trois Marches Militaires, no. 1. Transcription: A. Nijhof, 7 nov 93 : 0 [Text] Copyright (C) 1994 : 0 [Text] MANX Midi Productions : 0 [Text] All Rights Reserved : 0 [Sequence / track name] Player0 : 0 [Sequence / track name] Player1 : 0 [Sequence / track name] Player2 : 0 [Sequence / track name] Percussion : 0 [Sequence / track name] Player3 : 0 [Sequence / track name] Player4 : 0 [Sequence / track name] Player5 : 0 [Sequence / track name] Player6 : 0 okIt is seen that militair.mid contains 8 tracks.
A far more detailed report is generated by entering: DUMP-MIDI ( "input" "output" -- ). Below is an excerpt of the file d.txt, a file generated by entering DUMP-MIDI drums3.mid d.txt :
Chunk type: MThd Length: 6 bytes. Header format: 1, multiple tracks vertical. Number of tracks: 9 Division: relative; 576 PPQN Track #0 ======== Chunk type: MTrk Length: 134 bytes. : 0 [Sequence / track name] Drums3 : 0 [Text] Just some drum patterns part III : 0 [Text] Copyright (C) 1994 : 0 [Text] MANX Midi Productions : 0 [Text] All Rights Reserved : 0 [Time signature] 4 /4 24 MIDI messages per metronome beat, 8 /32 notes per quarter note. : 0 [tempo] 266666 microseconds per quarter note. : 0 [End of Track] Track #1 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player0 : 0 channel 0 [control change] msb main volume := 127 : 0 channel 0 [control change] msb pan := 34 : 0 channel 0 [control change] external effects depth := 63 : 0 channel 0 [control change] chorus depth := 0 : 0 channel 0 [control change] msb (Roland) bank select := 0 : 0 channel 0 [program change] Rhodes-Piano : 0 channel 0 [control change] modus, reset all controls := 0 : 0 channel 0 [pitchbend] value 0 : 0 channel 0 [control change] msb modulation := 0 : 0 [End of Track] Track #2 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player1 : 0 channel 1 [control change] msb main volume := 127 : 0 channel 1 [control change] msb pan := 94 : 0 channel 1 [control change] external effects depth := 63 : 0 channel 1 [control change] chorus depth := 0 : 0 channel 1 [control change] msb (Roland) bank select := 0 : 0 channel 1 [program change] Rhodes-Piano : 0 channel 1 [control change] modus, reset all controls := 0 : 0 channel 1 [pitchbend] value 0 : 0 channel 1 [control change] msb modulation := 0 : 0 [End of Track] Track #3 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player2 : 0 channel 2 [control change] msb main volume := 127 : 0 channel 2 [control change] msb pan := 63 : 0 channel 2 [control change] external effects depth := 63 : 0 channel 2 [control change] chorus depth := 0 : 0 channel 2 [control change] msb (Roland) bank select := 0 : 0 channel 2 [program change] Rhodes-Piano : 0 channel 2 [control change] modus, reset all controls := 0 : 0 channel 2 [pitchbend] value 0 : 0 channel 2 [control change] msb modulation := 0 : 0 [End of Track] Track #4 ======== Chunk type: MTrk Length: 2124 bytes. : 0 [Sequence / track name] Percussion : 0 channel 9 [control change] msb main volume := 127 : 0 channel 9 [control change] msb pan := 63 : 0 channel 9 [control change] external effects depth := 63 : 0 channel 9 [control change] chorus depth := 0 : 0 channel 9 [control change] msb (Roland) bank select := 0 : 0 channel 9 [program change] Acoustic-Grand-Piano : 0 channel 9 [control change] modus, reset all controls := 0 : 0 channel 9 [pitchbend] value 0 : 0 channel 9 [control change] msb modulation := 0 : 1 channel 9 [control change] external effects depth := 63 : 0 channel 9 [program change] Hammond-Organ : 0 [tempo] 266666 microseconds per quarter note. : 2304 channel 9 [note on] Bass-Drum-1 velocity 127 : 0 channel 9 [note on] Closed-Hi-Hat velocity 127 : 0 channel 9 [note on] Ride-Cymbal-2 velocity 127 : 504 channel 9 [note off] Bass-Drum-1 velocity 127 : 0 channel 9 [note off] Closed-Hi-Hat velocity 127 : 0 channel 9 [note off] Ride-Cymbal-2 velocity 127 : 72 channel 9 [note on] Closed-Hi-Hat velocity 127 : 0 channel 9 [note on] Ride-Cymbal-2 velocity 127 [ etcetera, for a long long time ... ] : 9 channel 9 [note on] Closed-Hi-Hat velocity 127 : 63 channel 9 [note off] Closed-Hi-Hat velocity 127 : 9 channel 9 [note on] Closed-Hi-Hat velocity 127 : 63 channel 9 [note off] Closed-Hi-Hat velocity 127 : 0 [End of Track] Track #5 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player3 : 0 channel 3 [control change] msb main volume := 127 : 0 channel 3 [control change] msb pan := 63 : 0 channel 3 [control change] external effects depth := 63 : 0 channel 3 [control change] chorus depth := 0 : 0 channel 3 [control change] msb (Roland) bank select := 0 : 0 channel 3 [program change] Rhodes-Piano : 0 channel 3 [control change] modus, reset all controls := 0 : 0 channel 3 [pitchbend] value 0 : 0 channel 3 [control change] msb modulation := 0 : 0 [End of Track] Track #6 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player4 : 0 channel 4 [control change] msb main volume := 127 : 0 channel 4 [control change] msb pan := 63 : 0 channel 4 [control change] external effects depth := 63 : 0 channel 4 [control change] chorus depth := 0 : 0 channel 4 [control change] msb (Roland) bank select := 0 : 0 channel 4 [program change] Rhodes-Piano : 0 channel 4 [control change] modus, reset all controls := 0 : 0 channel 4 [pitchbend] value 0 : 0 channel 4 [control change] msb modulation := 0 : 0 [End of Track] Track #7 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player5 : 0 channel 5 [control change] msb main volume := 127 : 0 channel 5 [control change] msb pan := 63 : 0 channel 5 [control change] external effects depth := 63 : 0 channel 5 [control change] chorus depth := 0 : 0 channel 5 [control change] msb (Roland) bank select := 0 : 0 channel 5 [program change] Rhodes-Piano : 0 channel 5 [control change] modus, reset all controls := 0 : 0 channel 5 [pitchbend] value 0 : 0 channel 5 [control change] msb modulation := 0 : 0 [End of Track] Track #8 ======== Chunk type: MTrk Length: 50 bytes. : 0 [Sequence / track name] Player6 : 0 channel 6 [control change] msb main volume := 127 : 0 channel 6 [control change] msb pan := 63 : 0 channel 6 [control change] external effects depth := 63 : 0 channel 6 [control change] chorus depth := 0 : 0 channel 6 [control change] msb (Roland) bank select := 0 : 0 channel 6 [program change] Rhodes-Piano : 0 channel 6 [control change] modus, reset all controls := 0 : 0 channel 6 [pitchbend] value 0 : 0 channel 6 [control change] msb modulation := 0 : 0 [End of Track]The experimental word .TRACK-SCORE ( u "inputfile" --- ) tries to translate the MIDI note events in track u of inputfile to a set of MANX commands. It is only moderately successful as the following dump shows:
FORTH> 1 .TRACK-SCORE ziep.mid 1153 \2304 rest /8 d3 /8 d3 /4 g3 /16 g3 432 \2304 rest /8 g3 /8 a3 /16 b3 432 \2304 rest /4 g3 /8 a3 /8 a3 72 \2304 a3 216 \2304 rest 72 \2304 a3 216 \2304 rest /8 b3 /8 a3 /4 g3For reference, here is the original score, ZIEP.SCO :
Player0 PART | 3 /4 MEASURE Legato Mezzo-Forte Whistle reprogram 50 pan 50 portatime true portamento /2 rest /8 d3 d3 | /4 g3 [.] [>] g3 /8 g3 a3 | 2 /4 MEASURE /4 [.] [>] b3 g3 | 3 /4 MEASURE /8 a3 a3 [>] [.] a3 [.] a3 b3 a3 | false portamento /4 [>] g3 /2 rest ||
CLEAR-MIX resets the memory-array in which MIX accumulates the tracks. MIX reads the specified track from the specified file and sorts it into the memory-array. Use PLAY-MIX to hear the result. The word NMIX is more efficient than MIX when multiple tracks must be read. Note that NMIX automatically executes CLEAR-MIX.
Of course it is also possible to play a complete file all at once. However,
some professional MIDI products write files that contain several variants of
the same musical score, presumably to enable the material to be played
over low-fi soundcards but also on high-end GM synthesizers. Consequently
MIDIRW
has extra PLAY-xx words that select the correct tracks from these
files.
The easiest word to use is PLAY-FULL ( "name" -- ). It will work for most Public Domain material that records the percussion on channel 9 (unless you changed #pch in the config.frt file). PLAY-FULL also works for any MANX file.
PLAY-WP ( "name" -- ) plays WordPerfect Presentations 2.0 MIDI-files.
PLAY-SESSIONl ( "name" -- ) is meant for MIDI-files generated with the SESSION program which is bundled with the PRO-AUDIO Spectrum16 soundcard. Plays the low-quality tracks. Likewise PLAY-SESSIONh ( "name" -- ) plays the high-quality tracks.
It is possible to change the replay speed of all of the above PLAY-xx words by setting the DVALUE replay-speed appropriately (see the glossary).
Two additional commands with primarily educational value are the words MPRINTING-ON and MPRINTING-OFF. Using these, all events are dumped to the screen as they are played.
MIDIRW
is redirected to memory-arrays ('tracks', one for each player).
MANX requests are passed to a set of MIDIRW
deferred words which translate
the requests to time-stamped MIDI events. In the next passes, these requests
are read from the arrays, formatted as a type 1 MIDI file and written to
disk. The file is written multiple times as on the first write the MIDI header
information fields are not yet correctly filled in.
Note that a musical score is quite ambiguous and leaves a lot of opportunity for a human being to interpret the notes as he or she sees fit. This ambiguity is lost once conversion to a computer readable format has taken place. An example is the directive 'as fast as possible' which I found in Emerson, Lake and Palmer's ELP songbook.
MANX accepts a set of predefined music commands. However, it is just an extension of Forth and all the power of this language is available for additional manipulation. Especially, MANX is still user-extensible.
All of MANX's commands work equally well for compilation and direct execution at the terminal. Some commands have to be entered in pairs, however (e.g. PART || ). There is a debugging mode, toggled with PRINTING-ON and PRINTING-OFF , which shows in plain text what a compiled sequence is doing.
Actually MANX can be used in three modes. In the first mode one experiments at a terminal, typing the needed commands and writing colon definitions interactively. This mode is entered by typing TERMINAL. When MANX is in the wrong mode (when .STAT and .MIDI-STATUS show one of the words RECORDING PLAYING MIXING or OFF after the text 'Vectors : ' on the first line of their output) it will refuse to execute some commands. In most cases MANX will sense that you want TERMINAL mode, but especially when compiling fails it may get confused.
The second mode is typing the commands into an ASCII text file with a special format. This file (with the extension .SCO) is included just like any regular .FRT file. When the word SCORE ( "name" -- ) is used, executing name plays back the score, but only the PART that corresponds to the Player that is currently active (only one, not a group).
The third mode works from the same file used for the second mode.
That file is converted to a completely standard MIDI file by the word
BUILD-MIDI ( "name" -- ). All the tools from MIDIRW.FRT
can then be
used to playback and manipulate this file. Note especially that the output
file is directly readable by MIDI sequencing or scoring utility programs.
Example:
I-AM-PLAYER0 Flute reprogram c2 c3 ( play c2 c3 on flute) I-AM-PLAYER1 Voice-Oohs reprogram c2 ( sing c2 ) I-AM-PLAYER0 c1 ( c1 on flute again )Also, after entering I-AM-PLAYER0 and including a .SCO file, only the text in the PART reading Player0 PART ... || is compiled, all other PARTs are ignored (see the paragraph 'Player Names' below for the word Player0).
The players Conductor ( I-AM-CONDUCTOR ) and Percussion ( I-AM-PERCUSSION ) are special in that their PART can contain special commands.
Table 1. The available player names. Future versions of MANX may support up to 16 players (16 is the MIDI limit). I-AM-CONDUCTOR I-AM-PERCUSSION I-AM-PLAYER0 I-AM-PLAYER1 I-AM-PLAYER2 I-AM-PLAYER3 I-AM-PLAYER4 I-AM-PLAYER5 I-AM-PLAYER6
Table 2. Identifying a player. Conductor Percussion Player0 Player1 Player2 Player3 Player4 Player5 Player6
The word | ( "bar" ) breaks up the note data in a PART into manageable pieces. MANX does timing checks on bar boundaries, based on the data entered with MEASURE in the first bar of a new PART . The statement 4 /4 MEASURE informs MANX that each following bar counts a total of 4 quarter notes. A warning message will be issued for the second bar in below example (the words /4 c3 etc. are explained shortly):
Player0 PART | 3 /4 measure /4 c3 e3 g3 ( 3/4 ) | /4 c3 /4 g3 /8 c3 e3 g3 || ( 2/4 + 3/8)It is possible to duplicate a bar using n DUPLICATES (duplicate the last entered bar n times) or DUPLICATE (duplicate the last entered bar only once). To replay just any of the previous bars you must define a label before that bar, using the word L: ( "name" -- ). After that, name (which is actually a CONSTANT ) can be used with REDO to replay the bar. To REDO a continguous range of bars, label the first and last or last+1 bar of the range ( with \0 ), then enter BIS ( u1 u2 -- ) or ENCORE ( u1 u2 -- ).
The end of the PART is signalled with the word || .
Pitch words, and thus note names as duration is implicit, are in Table 3. MANX also understands the American notation, e.g. A#0 for ais0 and Eb3 for es3 (for other languages: please call MANX). Note that because of the MIDI standard, es3 and dis3 are exact equivalents.
Table 3. The following list declares all valid MANX pitch/note names. The notation a0 .. a9 means a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 . a0 .. a9 ais0 .. ais9 as0 .. as9 b0 .. b9 bes0 .. bes9 bis0 .. bis9 c0 .. c9 ces0 .. ces9 cis0 .. cis9 d0 .. d9 des0 .. des9 dis0 .. dis9 e0 .. e9 eis0 .. eis9 es0 .. es9 f0 .. f9 fes0 .. fes9 fis0 .. fis9 g0 .. g9 ges0 .. ges9 gis0 .. gis9 A#0 .. A#9 Ab0 .. Ab9 Bb0 .. Bb9 B#0 .. B#9 Cb0 .. Cb9 C#0 .. C#9 Db0 .. Db9 D#0 .. D#9 E#0 .. E#9 Eb0 .. Eb9 F#0 .. F#9 Fb0 .. Fb9 Gb0 .. Gb9 G#0 .. G#9A very important element of music is silence. This element is only characterized by its duration, so we need a special name for it: rest. A rest defaults to the last entered duration, like a normal note.
To specify the duration of a note or a rest the words in tables 4 and 5 are used. A special case is handled with WHOLE, which specifies a duration equal to a full bar ( 4 /4 MEASURE WHOLE REST is equal to 4 /4 MEASURE /1 REST ).
Table 4. MANX fixed note durations. /4 means quarter note. /1 /1. /2 /2. /3 /3. /4 /4. /5 /6 /6. /7 /8 /8. /9 /9. /10 /11 /12 /12. /13 /14 /15 /16 /16. /17 /24 /24. /32 /32. /48 /48. /64 /64. /96 /96. /128 /128. /192 /192.
Table 5. MANX variable note durations. 3 \4 means 3 quarter note. \1 \2 \3 \4 \6 \8 \9 \12 \16 \24 \32 \48 \64 \128 \192 \384 \480 \960 \2304Another important characteristic of music is tempo, the speed at which notes are played. MANX uses the word MM ( u -- ) to specify tempo. When the current note duration is a quarter ( /4 ) 120 MM sets a metronome value of 120 quarter notes per minute.
Occasionally, it is necessary to "squeeze" a number of notes into a specified time slot. In a conventional score we might find "play these five sixteenth notes while the other instrument plays a quarter note". To handle this situation MANX has the << ( u1 u2 -- ) and >> words, to arbitrarily "stretch" time.
The present tempo can be saved with \TEMP and restored with /TEMP.
The most important task of the Conductor is to control the timing of the SCORE , with the word +TEMPO ( mul div -- ). Typically, a Conductor PART only contains a MEASURE command and a series of rests to take it to the place where a +TEMPO or VOLUME! command is wanted.
A ritardando or acceleration is accomplished with the words RITARD ( time delta -- ) and ACCEL ( time delta -- ). To accelerate the music 'by a little bit' over a time period of 7 quarter notes, enter: 7 /4 10 ACCEL . The actual response curve of RITARD and ACCEL can be edited. It is complementary.
The words CHORD and ARPEGGIO take the list build by the last { or {ARP and play it as a chord or arpeggio. Note that a list build with { can be used with ARPEGGIO and a list build with {ARP works with CHORD . However, a list containing TIE commands should not be used with either CHORD or ARPEGGIO.
An infrequently used feature is the possibility to have several lists active, using the words CHORD0 .. CHORD9 with the revectoring word SET.
In addition to this we can pick from a series of standard musical terms to set an absolute loudness: Fortissimo, Forte, Mezzo-forte, Mezzo-piano, Piano and Pianissimo . The previous paragraph already introduced the word VOLUME!.
The loudness of one single note, PNOTE or chord is raised with [>] and lowered with [v] (Executing these word multiple times will increase the effect). By using \Forte \Pianissimo etc. the loudness of the next note or chord is set in an absolute sense.
And then we have the important articulation issue. The available articulation commands are shown in Table 6. Articulation means sounding a note for only a given percentage of its formal duration.
Table 6. Articulation commands available in MANX Legato (8/8) or L8 Tenuto (7/8) or L7 Portato (6/8) or L6 Non-Legato (5/8) or L5 Staccato (2/8) or L2 Staccatissimo (1/8) or L1 Non-standard names and possibilities are: L4 (4/8) L3 (3/8) L0 fixed time (see /l0)See also the words [.] and [-] which lower and raise the articulation index for the following note or PNOTE. Articulation is set to an absolute value for the following NOTE, PNOTE or chord with \L0 \L1 .. \L8. The words TRUE sustain keep all following notes in their sustain phase until FALSE sustain is executed. Articulation can be saved and restored with \ART and /ART respectively.
When the hardware allows it, a few 'technological enhancements' are possible. See Table 7 for a list.
Table 7. Hardware related expression commands. chorus ( u -- ) chorus effect (phasing) reverb ( u -- ) reverberation (hall) pan ( u -- ) move in stereo sound field pitchbend ( n -- ) 'bend' the string i.e. change the pitch portamento ( F -- ) enable glissando's portatime ( u -- ) set length of glissando sostenuto ( F -- ) enable sostenuto reprogram ( u -- ) choose a different timbre vibrato-depth ( u -- ) set vibrato depth vibrato-rate ( u -- ) set vibrato rate vibrato-delay ( u -- ) set vibrato delay tvf-cutoff ( u -- ) set voltage controlled filter cutoff freq. tvf-resonance ( u -- ) set voltage controlled filter resonance env-attack ( u -- ) set envelope attack (filter and amplitude) env-decay ( u -- ) set envelope decay (filter and amplitude) env-release ( u -- ) set envelope release (filter and amplitude)The word reprogram ( u -- ) allows a choice out of over at least 150 different instruments or timbres to be made (see
MIDIRW.DOC
)Tangentially related to articulation are the three words of the TIE class: tie- -tie- and -tie . These words keep only the specified note in its sustain phase. Consult the Glossary for their special behavior when { or {ARP is encountered.
MIDIRW.FRT
( Brush-Swirl Brush-Slap Brush-Tap Concert-Cymbal1
Concert-Cymbal2 Timpani-F1 etcetera).Instead of the slightly inelegant BECOMES one may define new words of the plok class using PNOTE ( u1 "name" -- ). This creates a new word name that, when executed, 'hits' the percussion instrument corresponding to the constant u1 (see above).
The word HIT ( u1 -- ), a basic component of PNOTE , is separately available and is useful for an occasional percussive slap here and there.
With MCOMMENTS-ON one instructs MANX to generate bar numbers and put them in the MIDI output file. In this mode the word CMT is available. It is used to embed user comments in the output stream. These comments and bar numbers are printed to the terminal screen. This works in mode 0, 1 en 2. It is, however, a MANX specific feature and other sequencing software will ignore the strings.
The current metronome value (in quarter notes per minute) is printed when typing .MM .
The word .STAT prints information about MANX's state, e.g. MIDI status, song name, general song info, metronome, current part, current program ...
The word .WHO prints the network statistics, e.g. who is conductor, the serial port that is used, ensemble or solo.
The maximum number of bars allowed by the hardware (memory limitations) is returned with /bars .
To play a note not by its name but by its index, use PERFORM-NOTE ( u -- ). The index u is found by applying N? to a note or pnote.
N? ( "name" -- u ) inspects the note name and extracts the index u suitable for use with PERFORM-NOTE.
When using L0, or when the sound output is done with the metallophone network, the content of /l0 specifies the pulse width in milliseconds of all following notes (until another articulation command is found or force-metallo? is turned off).
100 /4 MM ( set metronome to 100 quarter notes per minute) SCORE Ziep ( This will be the Forth name of the piece) \ Enter a non-printing comment which will be embedded in the MIDI file. INFO" Old Dutch traditional, using portamento" Player0 PART \ there will be only one player. Its notes start \ here and stop when '||' is encountered. | 3 /4 MEASURE \ First bar. Set up for a 3/4 beat. Legato \ no pause between notes Mezzo-Forte \ Not too loud Whistle reprogram \ Play the slide whistle 50 pan \ sound comes from front stage 50 portatime \ set a time for notes to slide \ to the next one (portamento) true portamento \ enable portamento /2 rest /8 d3 d3 \ the notes in bar 0 | /4 g3 \ bar 1 [.] [>] g3 \ the note g3 is played short \ (equivalent to L2), and \ emphasized (30% louder). /8 g3 a3 | 2 /4 MEASURE /4 [.] [>] b3 g3 \ bar 2 | 3 /4 MEASURE /8 a3 a3 \ bar 3 [>] [.] a3 [.] a3 b3 a3 | false portamento \ bar 4. Turn portamento off. /4 [>] g3 /2 rest || \ This ends player0's part.This file has a part for Player0 only, so if the current player is not Player0 nothing happens when you type ZIEP . You can find out the current player by entering .STAT . If the player is set wrong, type I-AM-PLAYER0 FORGET ziep INCLUDE ziep.sco. After this, entering
ZIEP
will play a very simple melody on your sound hardware.The command to convert ZIEP.SCO to a MIDI file with name ZIEP.MID is BUILD-MIDI ziep. In this case it doesn't matter what the current player is, all parts are converted automatically. The resultant binary file can be played back by entering PLAY-FULL ziep.mid. Optionally you can set the replay speed: 150 100 TO replay-speed plays the file 50% faster than the metronome value in the text ( 100 /4 MM ) specifies it. Instead of PRINTING-ON you must now use MPRINTING-ON to get a simultaneous listing of the events. An alternative is entering MCOMMENTS-ON , which will print the bars currently executed at the top of the screen, plus any comments you have put in the text using CMT (note that MCOMMENTS-ON must also be executed before you build the MIDI file). This display is useful for a complicated score where you suspect bars have been lost or misplaced when entering the text. For best results, the word "|" must be used for bars that contain DUPLICATE DUPLICATES BIS ENCORE or REDO statements.
126 /4 MM SCORE Bart-113 INFO" BARTOK, Bulgarian Rhythm, Mikrokosmos 113. Transcription: Albert Nijhof, Oct 24, 93" Player0 PART | 7 /8 measure true sustain \ notes are sustained as long as the instrument \ allows. When no instrument is set explicitly, \ it defaults to electric piano. whole rest \ equivalent to 7 /8 rest \ Define a label with name m1 L: m1 | /8 rest bes2 rest gis2 rest bes2 gis2 | m1 redo \ the code in this bar re-executes the code of \ the bar labelled m1 . L: m3 | m1 redo L: m4 | /8 a2 d2 gis2 d2 a2 d2 gis2 | 39 duplicates \ re-execute the code of the previous bar (m4) \ 39 times. | m1 .. m3 bis \ re-execute the bars between \ m1 and m3 (inclusive) | /4 rest 5 \8 tie- { a2 a3 } \ play a two note chord. The tie- \ command acts on both notes and says \ that a note must be held in its \ sustain phase. | whole -tie- chord \ equivalent to 7 /8 -tie- { a2 a3 } \ or whole { -tie- a2 -tie- a3 } etc. | 5 \8 -tie chord \ finally we may turn off the notes in \ the chord ( a2 and a3 ) /4 rest false sustain || Player1 PART | 7 /8 measure whole rest Acoustic-Guitar-(nylon) reprogram L: m1 | /8 bes2 rest gis2 rest bes2 /4 rest | m1 redo L: m3 | m1 redo L: m4 | /4 rest e3 a3 /8 b3 | /4 a3 d4 a3 /8 e3 | /4 f3 5 \8 tie- d3 \ we create sustained note d3 ... | whole -tie- d3 | 5 \8 -tie d3 \ turn of the sustained d3 /4 rest | /4 a3 e4 dis4 /8 e4 | /4 f4 e4 cis4 /8 g3 | /4 a3 5 \8 tie- c4 | whole -tie- c4 | 5 \8 -tie c4 /4 rest | /4 g4 f4 e4 /8 f4 | /4 e4 b3 cis4 /8 bes3 | /4 c4 5 \8 tie- g3 | whole -tie- g3 | 5 \8 -tie g3 /4 rest | /4 f3 e3 a3 /8 b3 | /4 cis4 b3 a3 /8 e3 | /4 f3 5 \8 tie- d3 | whole -tie- d3 L: m23 | 5 \8 -tie d3 /4 rest | m4 .. m23 bis | m1 .. m3 bis | /4 { cis3 cis4 } rest rest /8 rest | whole rest | duplicate \ equivalent to whole rest , re-execute the \ previous bar. ||This file has two parts, but MANX will only play one PART at the time. A typical command sequence to hear the parts after one another is:
PRINTING-ON I-am-Player0 INCLUDE bart-113.sco bart-113 FORGET bart-113 I-am-Player1 INCLUDE bart-113.sco bart-113The use of labels in the text makes it possible to hear a specific bar played. You can enter
m4 REDO
to hear just bar m4
, or m4 .. m23 BIS
to hear
the bars between m4 and m23 inclusive. When you start experimenting in this
way you will notice that MANX stops playing as soon as you touch just any
key. Also note that replaying just a small part of the score may leave you
with an instrument playing a set of tied notes at full blast. The word SILENCE
will kill these notes instantly.
Although labels are used for bars to be REDOne, a bar that does not have a
label can be specified by putting its internal index number on the data stack.
Bars are numbered sequentially, starting at bar 0. For the above example
m4 REDO
can also be expressed as 4 REDO
.
To hear both parts simultaneously you are supposed to use BUILD-MIDI bart-113 .
Please watch out for words marked IMMEDIATE in the glossary: BIS ENCORE REDO SET BECOMES N? PART | || DUPLICATE DUPLICATES L: { {ARP. Of this set you would not normally want to compile BIS ENCORE REDO PART | || DUPLICATE DUPLICATES and L:, but BECOMES N? { and {ARP are very useful at times.
CASESENSITIVE ON \ Define a few chords. : `A { a3 cis4 e4 } ; : `Am { a3 c4 e4 } ; : `A7 { a3 cis4 e4 g4 } ; : `Am7 { a3 c4 e4 g4 } ; : `AM7 { e3 gis3 cis4 } ; : `Adim7 { fis3 a3 c4 dis4 } ; : `B { fis3 b3 dis4 } ; : `Bm { fis3 b3 d4 } ; : `B7 { fis3 a3 b3 dis4 } ; : `Bm7 { fis3 a3 b3 d4 } ; : `BM7 { fis3 ais3 dis4 } ; : `Bdim7 { f3 gis3 b3 d4 } ; : `C { e3 g3 c4 } ; : `Cm { es3 g3 c4 } ; : `C7 { e3 g3 ais3 c4 } ; : `Cm7 { es3 g3 ais3 c4 } ; : `CM7 { c3 e3 g3 b3 } ; : `Cdim7 { dis3 fis3 a3 c4 } ; : `D { fis3 a3 d4 } ; : `Dm { f3 a3 d4 } ; : `D7 { fis3 a3 c4 d4 } ; : `Dm7 { f3 a3 c4 d4 } ; : `DM7 { d3 fis3 a3 cis4 } ; : `Ddim7 { f3 gis3 c3 d4 } ; : `E { gis3 b3 e4 } ; : `Em { g3 b3 e4 } ; : `E7 { gis3 b3 d4 e4 } ; : `Em7 { g3 b3 d4 e4 } ; : `EM7 { e3 gis3 b3 es4 } ; : `Edim7 { g3 bes3 cis4 e4 } ; : `F { f3 a3 c4 } ; : `Fm { f3 as3 c4 } ; : `F7 { f3 a3 c4 dis4 } ; : `Fm7 { f3 as3 c4 dis4 } ; : `FM7 { f3 a3 c4 e4 } ; : `Fdim7 { f3 as3 b4 d4 } ; : `G { g3 b4 d4 } ; : `Gm { g3 bes4 d4 } ; : `G7 { g3 b4 d4 f4 } ; : `Gm7 { g3 bes4 d4 f4 } ; : `GM7 { ges3 b4 d4 } ; : `Gdim7 { g3 bes4 des4 e4 } ; \ a defining word that build words that play a random chord in a certain key. : :chord CREATE DOES> 6 CHOOSE SWAP []CELL @ EXECUTE ; :chord achord ' `A , ' `Am , ' `A7 , ' `Am7 , ' `AM7 , ' `Adim7 , :chord bchord ' `B , ' `Bm , ' `B7 , ' `Bm7 , ' `BM7 , ' `Bdim7 , :chord cchord ' `C , ' `Cm , ' `C7 , ' `Cm7 , ' `CM7 , ' `Cdim7 , :chord dchord ' `D , ' `Dm , ' `D7 , ' `Dm7 , ' `DM7 , ' `Ddim7 , :chord echord ' `E , ' `Em , ' `E7 , ' `Em7 , ' `EM7 , ' `Edim7 , :chord fchord ' `F , ' `Fm , ' `F7 , ' `Fm7 , ' `FM7 , ' `Fdim7 , :chord gchord ' `G , ' `Gm , ' `G7 , ' `Gm7 , ' `GM7 , ' `Gdim7 , \ Play a random chord from a selection of 7 : AnyChord 7 CHOOSE EXEC: achord bchord cchord dchord echord fchord gchord ; \ Choose a random position on the stereo sound stage : ASpot #100 CHOOSE pan ; \ Choose a random reverberation level : ADepth #100 CHOOSE reverb ; \ Play a random chord, in a random key, at a random position, \ at a random distance from the listener. : SomeChord ASpot ADepth AnyChord ; #90 /4 MM SCORE Chords INFO" Random Cubed" Player0 PART | 4 /4 MEASURE WHOLE rest Choir-Aahs reprogram Mezzo-piano -1 TO octave L: m1 | /2 SomeChord ARPEGGIO \ like CHORD , but arpeggiate the notes. | 7 DUPLICATES | Breath-Noise reprogram /32 32 0 DO SomeChord LOOP \ Play 32 chords, length /32 BANK0 Marimba reprogram L: m9 | /2 `C7 ARPEGGIO | Voice-Oohs reprogram m1 .. m9 BIS || Player1 PART | 4 /4 MEASURE WHOLE rest Pad-2-(warm) reprogram 50 pan Forte L: m1 | 12 /4 10 DIMIN \ start diminuendo, 'a little bit' over 3 bars /8 8 0 DO `C7 LOOP \ play 8 chords | DUPLICATE | /8 8 0 DO `Em7 LOOP \ the diminuendo stops here | Piano DUPLICATE \ go to a known volume | 12 /4 10 CRESC \ a crescendo over 3 bars. /8 8 0 DO `Gdim7 LOOP | /8 8 0 DO `GM7 LOOP | /8 8 0 DO `Gdim7 LOOP | Forte DUPLICATE \ ... known volume | Helicopter reprogram /1 SomeChord Choir-Aahs Piano reprogram L: m9 | /4 4 0 DO `Cdim7 LOOP | m1 .. m9 BIS || CASESENSITIVE OFF
MIDIRW
comes with ready-to-use drivers for the PC-speaker, for a metallophone,
and for any machine that understands the MIDI-protocol -- effectively all
modern sound cards and GM synthesizers. However, even if your hardware is
special, it is still possible to use it with some minor programming. This
section shows how to write driver programs (or words) that interface the
routines in MIDIRW.FRT
to an actual instrument.
First of all, write a driver file. Choose one of the files PCSPEAKER, BRASS,
ALUMINIUM or SYNTH as a template. Your new driver file must contain the set
of 8 words in the table below. The term "event" is defined in DOC ENDDOC
blocks in MIDIRW.FRT
. Briefly, an event is a 32-bit word containing all
information your driver needs to fullfil MIDIRW
's requests:
Event bits: 31..24 23..16 15..8 7..0 Meaning: 0 [chan#] [velocity] [note#]The channel# addresses one of 16 sub-units. This field can be ignored although you should be aware of the fact that
MIDIRW
thinks that it can talk to a
percussion unit on channel #pch (9 or 15 is standard MIDI practice).The velocity is a 7-bit number that is commonly interpreted as the loudness with which the instrument sounds.
The note# addresses one of 128 notes on the wanted chan# (C-2 to C9).
The protocol is loosely based on the MIDI specification, so you can read
up on that subject if the documentation in MIDIRW.FRT
is not sufficient.
Table 8. MIDI base-level implementation words in driver files. :NOTE-ON ( event -- ) Start making the sound (attack phase). Note that a special :NOTE-ON request can be made that actually means :NOTE-OFF , and that a :NOTE-ON can specify one of sixteen sub-units, one of them being a percussion instrument. :NOTE-OFF ( event -- ) Shut off the sound (release phase). :CONTROL ( event -- ) Respond to requests to change a parameter of the current sound (vibrato, reverb, volume etc.) It is acceptable to just do a DROP and return. :REPROGRAM ( event -- ) Respond to requests to change the current timbre (e.g. acoustic piano, guitar etc.) It is acceptable to just do a DROP and return. :PITCHBEND ( event -- ) Change the frequency of the currently sounding note. It is acceptable to just do a DROP and return. :CAFTERTOUCH ( event -- ) Respond to requests to change the volume of the indicated sub-unit. It is acceptable to just do a DROP and return. :PAFTERTOUCH ( event -- ) Respond to requests to change the volume of the indicated note on the indicated sub-unit. It is acceptable to just do a DROP and return. :SYSEX ( event -- ) Respond to a sequencer specific request, here a special MANX command to set non-registered parameter numbers in a synth. It is acceptable to just do a DROP and return. :LOUDNESS ( event -- ) Respond to requests to change the general volume of the indicated sub-unit. It is acceptable to just do a DROP and return, however, do not throw away the '0' message: in this case the indicated sub-unit should be shut off and re-initialized.After writing the driver code you revector the deferred word SET-LOUDNESS to a meaningful routine (acceptable is
' :LOUDNESS IS SET-LOUDNESS
)
and define two words that inform MIDIRW
about the driver's capabilities
drivermax#n This is a CONSTANT or VALUE that tellsThat is all programming that is required. Next make the new driver available toMIDIRW
how many notes your instrument can play simultaneously. devoffsb This is a VALUE that contains the offset between the noteMIDIRW
asks for (say c2) and the actual note you want to hear (say d3). This offset is 0 for a full-featured instrument, but sometimes you will want to shift the notesMIDIRW
is sending to a range your instrument can handle. Install devoffsb in devoffs with the following Forth sequence: 'OF devoffsb IS devoffs .
MIDIRW
by writing a configuration file (look at SPEAKER.CFG), and
by making sure there is a NEEDS -yourdriver
in MIDIRW.FRT
. Copy yourdriver.CFG
to CONFIG.FRT and load MIDIRW.FRT
or MANX.FRT
.
Possible problems with this scheme are that the synchronization points are too few and timing gets 'peristaltic'. Also, the danger exists that complete bars ar missed by some of the machines.
The scheme was tried out and it actually works well in practice. However, we do not recommend it for any serious work. If your application is critical, extend MANX to be able to receive time-stamped MIDI clock messages inside its TIMER words. The clock messages should be broadcasted and received by interrupt driven serial port routines.
To get all of this to work, connect the machines using a serial cable. At
present only two machines are supported, so a standard cable is used. Edit the
CONFIG.FRT files on the machines so that one of them is Conductor. ( TRUE =: I'm-Conductor and FALSE =: I'm-Conductor ).
Make sure that the VALUE com#
is
set to the correct value for the serial port that you are about to use. Also
make sure that both machines initialize their serial ports with INIT-SR
(DEFS.FRT) after they have loaded MANX.FRT . When you enter ENSEMBLE the
two machines will synchronize before playing a bar from their PART's. SOLO
reverts back to the old unsynchronized situation. In ENSEMBLE mode you may
press any key to break a possible deadlock.
That is all there is to it.
iForth needs a '386+387 pair, or a '486 or higher. iForth for MS-DOS runs in protected mode. The used DOS-extender, GO32, is not very smart and strange errors or very slow operation will be experienced when the amount of memory is less than two Megabytes (we recommend 4 Mbytes for DOS and 8 MBytes for Windows).
Please install the MANX program files in a separate directory (suggested is /dfwforth/examples/manx) and the *.sco and *.mid files in a sub-directory thereof (suggested is /dfwforth/examples/manx/music).
Depending on the sound hardware you have available, one of the *.cfg files is renamed to CONFIG.FRT . What works on any machine is using the PC-speaker for output by entering the following command on the DOS command line: COPY pcspeaker.cfg config.frt.
The intended use of MANX is to drive a full GM synthesizer box through a MPU-401 compatible interface: COPY synth.cfg config.frt. In this case the file synth.frt may need some editing to set up the correct IRQ and port numbers. MANX under Linux bypasses the device driver and talks to the interface directly. Windows MANX just uses WIN32 calls.
Using MANX with a simple soundcard has its limitations. Sometimes DOS MIDI drivers for these cards are not available, forcing you to use Windows with its MIDI-mapper software. But even in that case interactive use of the sound hardware is possible, you don't need to generate a *.MID file first.