The jsPlayCommand library is a JavaScript implementation of the
play
command from HyperTalk, which used a kind of notation
now known in the xTalk community as scripted music notation.
HyperTalk used sound resources, but with our Modern Technology™
* we can use MIDI!
You can play around with jsPlayCommand using the editor below. Load a preset song or enter your own using scripted music notation. The equivalent traditional music notation will appear above the text field as you type. Scroll down the page for a reference to scripted music notation. Then, hit the Play button to see how it sounds! You will have to either use Google Chrome or install Jazz-Soft.net Jazz-Plugin to be able to actually play the notes. Alternatively, you can click the Generate MIDI File button and download your creation as a standard MIDI file you can play anywhere!
Using Scripted Music Notation
Scripted music notation uses a sequence of note strings separated by
whitespace to represent a sequence of notes. Each note string representing
a sounded note is composed of four parts: a pitch, a duration,
a velocity, and an effect. A note string representing a rest
is composed of two parts: a duration and the letter r
.
-
The pitch is specified as a note name (
C
,D
,E
,F
,G
,A
,B
), followed by zero or moreb
or#
symbols (representing flats and sharps respectively), optionally followed by an octave number (00
,0
,1
,2
,3
,4
,5
,6
,7
,8
,9
) (where octave 4 is the octave starting with middle C and containing A440). Alternatively, the pitch may be given as the letterM
,N
, orP
followed by the MIDI value;M60
is equivalent toC4
andM69
is equivalent toA4
. If the note value or octave is not specified, the previous value is used. -
The duration is specified as one of the following letters,
followed by zero or more
:
symbols (which double the note value),.
symbols (to create a dotted note), or digits1
through9
(to create a tuplet note). (Note that a digit will create an individual note in a tuplet, not the whole tuplet.)
Alternatively, the duration may be given as the letterz
octuple whole note l
sextuple whole note i
quadruple whole note u
double whole note w
whole note h
half note q
quarter note e
eighth note s
16th note t
32nd note x
64th note o
128th note d
followed by the duration of the note in 64ths of a quarter note. If the duration is not specified, the previous value is used. -
The velocity is specified as one of the following strings, from
softest to loudest:
ppp
,pp
,p
,mpp
,mp
,m
,mf
,mff
,f
,ff
,fff
. Alternatively, the velocity may be given as the letterv
followed by the MIDI value from0
(completely silent) to127
(the loudest, equivalent tofff
). If the velocity is not specified, the previous value is used. -
The effect is specified as zero or more of the following symbols.
,
The note is counted for its full duration, but only played for half its duration (stoccato). *
The note keeps playing even after its duration is passed, until a !
is encountered (fermata).!
Stops a note started by *
after the specified duration has passed.+
The next note will start playing simultaneously with this note (chord).
Using jsPlayCommand
To use jsPlayCommand, embed the following script tags on your page:
<script type="text/javascript" src="http://www.kreativekorp.com/lib/jsPlayCommand/WebMIDIAPI.js"></script> <script type="text/javascript" src="http://www.kreativekorp.com/lib/jsPlayCommand/jsPlayCommand.js"></script>
Or, if you prefer to host it yourself, download jsPlayCommand.zip.
You may need to install Jazz-Soft.net Jazz-Plugin to be able to use jsPlayCommand (unless, of course, your browser already supports the Web MIDI API, currently found only in Chrome Canary).
Before jsPlayCommand can actually play any notes, it must be initialized using the following APIs:
jsPlayCommand.start(success, failure)
- Requests access to MIDI controllers and initializes jsPlayCommand. The success function is called if this completed successfully. Otherwise, the failure function is called.
jsPlayCommand.running()
-
Returns true if
jsPlayCommand.start()
has been called successfully. jsPlayCommand.stop()
- Resets jsPlayCommand to its uninitialized state.
Once jsPlayCommand is initialized, use one of the following APIs:
jsPlayCommand.play(instrument, notes)
jsPlayCommand.play(instrument, tempo, notes)
jsPlayCommand.play(channel, instrument, tempo, notes)
jsPlayCommand.play(bankSelect, channel, instrument, tempo, notes)
jsPlayCommand.play(output, bankSelect, channel, instrument, tempo, notes)
-
Plays a sequence of notes on a MIDI device. The sequence is played
asynchronously, so this API returns almost immediately. The parameters
to this API are:
- Output is one of the devices returned by
jsPlayCommand.outputs()
. -
BankSelect is the bank select mode,
which is one of the following:
jsPlayCommand.BANK_SELECT_GM
General MIDI mode. No bank select commands are sent. jsPlayCommand.BANK_SELECT_GS
GS mode. CC0 is used for bank select; CC32 is not used. jsPlayCommand.BANK_SELECT_XG
XG mode. CC32 is used for bank select; CC0 is not used. jsPlayCommand.BANK_SELECT_MMA
MMA or GM2 mode. CC0 is used for MSB; CC32 is used for LSB. - Channel is the MIDI channel number from 0 to 15.
-
Instrument is an integer, an object with a
bank
andinstrument
, or one of the following instrument names:
When matching an instrument name, case, whitespace, and punctuation are ignored, so0 Acoustic Grand Piano 1 Bright Acoustic Piano 2 Electric Grand Piano 3 Honky-Tonk Piano 4 Electric Piano 1 5 Electric Piano 2 6 Harpsichord 7 Clavi 8 Celesta 9 Glockenspiel 10 Music Box 11 Vibraphone 12 Marimba 13 Xylophone 14 Tubular Bells 15 Dulcimer 16 Drawbar Organ 17 Percussive Organ 18 Rock Organ 19 Church Organ 20 Reed Organ 21 Accordion 22 Harmonica 23 Tango Accordion 24 Acoustic Guitar (Nylon) 25 Acoustic Guitar (Steel) 26 Electric Guitar (Jazz) 27 Electric Guitar (Clean) 28 Electric Guitar (Muted) 29 Overdriven Guitar 30 Distortion Guitar 31 Guitar Harmonics 32 Acoustic Bass 33 Electric Bass (Finger) 34 Electric Bass (Pick) 35 Fretless Bass 36 Slap Bass 1 37 Slap Bass 2 38 Synth Bass 1 39 Synth Bass 2 40 Violin 41 Viola 42 Cello 43 Contrabass 44 Tremolo Strings 45 Pizzicato Strings 46 Orchestral Harp 47 Timpani 48 String Ensemble 1 49 String Ensemble 2 50 Synth Strings 1 51 Synth Strings 2 52 Choir Aahs 53 Voice Oohs 54 Synth Voice 55 Orchestra Hit 56 Trumpet 57 Trombone 58 Tuba 59 Muted Trumpet 60 French Horn 61 Brass Section 62 Synth Brass 1 63 Synth Brass 2 64 Soprano Sax 65 Alto Sax 66 Tenor Sax 67 Baritone Sax 68 Oboe 69 English Horn 70 Bassoon 71 Clarinet 72 Piccolo 73 Flute 74 Recorder 75 Pan Flute 76 Blown Bottle 77 Shakuhachi 78 Whistle 79 Ocarina 80 Lead 1 (Square) 81 Lead 2 (Sawtooth) 82 Lead 3 (Calliope) 83 Lead 4 (Chiff) 84 Lead 5 (Charang) 85 Lead 6 (Voice) 86 Lead 7 (Fifths) 87 Lead 8 (Bass + Lead) 88 Pad 1 (New Age) 89 Pad 2 (Warm) 90 Pad 3 (Polysynth) 91 Pad 4 (Choir) 92 Pad 5 (Bowed) 93 Pad 6 (Metallic) 94 Pad 7 (Halo) 95 Pad 8 (Sweep) 96 FX 1 (Rain) 97 FX 2 (Soundtrack) 98 FX 3 (Crystal) 99 FX 4 (Atmosphere) 100 FX 5 (Brightness) 101 FX 6 (Goblins) 102 FX 7 (Echoes) 103 FX 8 (Sci-Fi) 104 Sitar 105 Banjo 106 Shamisen 107 Koto 108 Kalimba 109 Bagpipe 110 Fiddle 111 Shanai 112 Tinkle Bell 113 Agogo 114 Steel Drums 115 Woodblock 116 Taiko Drum 117 Melodic Tom 118 Synth Drum 119 Reverse Cymbal 120 Guitar Fret Noise 121 Breath Noise 122 Seashore 123 Bird Tweet 124 Telephone Ring 125 Helicopter 126 Applause 127 Gunshot "Alto Sax"
," alto_sax "
, and"ALTO.SAX"
all map to instrument 65. - Tempo is the tempo of the note sequence in beats per minute.
- Notes is a sequence of notes in scripted music notation.
- Output is one of the devices returned by
jsPlayCommand.playMultiple(arguments)
jsPlayCommand.playMultiple(arguments, arguments)
jsPlayCommand.playMultiple(arguments, arguments, arguments,
...)
-
Executes several play commands in parallel. Even though the play
command is asynchronous, there is still a delay introduced by
processing arguments, parsing note strings, and so on; this ensures
that all the sequences passed in start playing at exactly the same time.
Each argument to this API is an array of arguments as given to
jsPlayCommand.play()
. If you need to pass in an array of arrays, as this demo does, usejsPlayCommand.playMultiple.apply(jsPlayCommand, arrays)
. jsPlayCommand.compile(instrument, notes)
jsPlayCommand.compile(instrument, tempo, notes)
jsPlayCommand.compile(channel, instrument, tempo, notes)
jsPlayCommand.compile(bankSelect, channel, instrument, tempo, notes)
jsPlayCommand.compile(trackName, bankSelect, channel, instrument, tempo, notes)
-
Compiles a sequence of notes into a MIDI file and returns the MIDI file
as an array of byte values. The parameters to this API are similar to
the parameters to
jsPlayCommand.play()
, except that a track name is given in place of an output device. This API will always work, independently of jsPlayCommand initialization or MIDI support. jsPlayCommand.compileMultiple(arguments)
jsPlayCommand.compileMultiple(arguments, arguments)
jsPlayCommand.compileMultiple(arguments, arguments, arguments,
...)
-
Compiles multiple sequences of notes into a MIDI file and returns the
MIDI file as an array of byte values. The parameters to this API are
similar to the parameters to
jsPlayCommand.playMultiple()
, except that track names are given in place of output devices. This API will always work, independently of jsPlayCommand initialization or MIDI support. jsPlayCommand.compileBase64(instrument, notes)
jsPlayCommand.compileBase64(instrument, tempo, notes)
jsPlayCommand.compileBase64(channel, instrument, tempo, notes)
jsPlayCommand.compileBase64(bankSelect, channel, instrument, tempo, notes)
jsPlayCommand.compileBase64(trackName, bankSelect, channel, instrument, tempo, notes)
-
Compiles a sequence of notes into a MIDI file and returns the MIDI file
as a base64-encoded string. The parameters to this API are similar to
the parameters to
jsPlayCommand.play()
, except that a track name is given in place of an output device. This API will always work, independently of jsPlayCommand initialization or MIDI support. jsPlayCommand.compileMultipleBase64(arguments)
jsPlayCommand.compileMultipleBase64(arguments, arguments)
jsPlayCommand.compileMultipleBase64(arguments, arguments, arguments,
...)
-
Compiles multiple sequences of notes into a MIDI file and returns the
MIDI file as a base64-encoded string. The parameters to this API are
similar to the parameters to
jsPlayCommand.playMultiple()
, except that track names are given in place of output devices. This API will always work, independently of jsPlayCommand initialization or MIDI support.
By default, jsPlayCommand uses the first output device it finds, does not use any bank select commands, and plays on channel 0 with instrument 0 at a tempo of 120 bpm, unless a play command specifies otherwise. These defaults can be changed with the following APIs:
jsPlayCommand.outputs()
- Returns a list of MIDI output devices where jsPlayCommand can send its output.
jsPlayCommand.getDefaultOutput()
jsPlayCommand.setDefaultOutput(output)
- Gets or sets the default MIDI output device.
jsPlayCommand.getDefaultBankSelect()
jsPlayCommand.setDefaultBankSelect(bankSelect)
-
Gets or sets the default bank select mode. This must be one of the following:
jsPlayCommand.BANK_SELECT_GM
General MIDI mode. No bank select commands are sent. jsPlayCommand.BANK_SELECT_GS
GS mode. CC0 is used for bank select; CC32 is not used. jsPlayCommand.BANK_SELECT_XG
XG mode. CC32 is used for bank select; CC0 is not used. jsPlayCommand.BANK_SELECT_MMA
MMA or GM2 mode. CC0 is used for MSB; CC32 is used for LSB. jsPlayCommand.getDefaultChannel()
jsPlayCommand.setDefaultChannel(channel)
- Gets or sets the default MIDI channel.
jsPlayCommand.getDefaultInstrument()
jsPlayCommand.setDefaultInstrument(instrument)
- Gets or sets the default instrument.
jsPlayCommand.getDefaultTempo()
jsPlayCommand.setDefaultTempo(tempo)
- Gets or sets the default tempo.
If you would like to play around with the API, there is a jsPlayCommand JSFiddle for you!
Additional Resources
HyperSound
is a soundfont recreation of the original three sampled sounds included
with HyperCard for use with the play
command.
The "harpsichord" sound is mapped to bank 73, instrument 6 (Harpsichord);
the "boing" sound is mapped to bank 73, instrument 103 (FX 8);
the "flute" sound is mapped to bank 73, instrument 73 (Flute).
(There is also a GM version with the same mappings in bank 0.)
jsPlayCommand recognizes these instruments in bank 73 as "HyperFlute",
"HyperBoing", and, naturally, "Hypsichord". You can load these in your
synthesizer and your play commands will sound just like they did in
HyperCard!
* MIDI (1982) is actually older than HyperTalk (1987). Neither is all that modern.