Jazz-Soft.net
We make it sound!
Home » Documentation » JZZ.js » JZZ.MIDI.SMF

JZZ.MIDI.SMF - Standard MIDI Files
( reading / writing / playing )

Usage

// in Node.js:
var JZZ = require('jzz');
require('jzz-midi-smf')(JZZ);
// or in HTML:
<script src="JZZ.js"></script>
<script src="JZZ.midi.SMF.js"></script>

Construction

(works with or without the new keyword)

JZZ.MIDI.SMF() - create a new SMF (MIDI File) object with the default settings: type = 1, ppqn = 96.

JZZ.MIDI.SMF(type) - create MIDI File of requested type; valid values for type are 0, 1, or 2; default timing: ppqn = 96.

JZZ.MIDI.SMF(type, ppqn) - create MIDI File with PPQN timing; ppqn - number of pulses (ticks) per quarter note.

JZZ.MIDI.SMF(type, fps, ppf) - create MIDI File with SMPTE timing; fps - number of frames per second; ppf - number of pulses (ticks) per frame.

JZZ.MIDI.SMF(smf) - copy-constructor, where smf is another SMF object.

JZZ.MIDI.SMF(syx) - create from a JZZ.MIDI.SYX object.

JZZ.MIDI.SMF(data) - create from binary data; data - the contents of a MIDI or RMI file as a String, Buffer, ArrayBuffer, Int8Array or Uint8Array.

toString()

smf.toString() convert MIDI file to human-readable string.

NOTE: in most JavaScript realizations, console.log() does not automatically call this function.

dump()

smf.dump(rmi) - export MIDI File in .MID(.KAR) format if rmi evaluates to false, or in .RMI format otherwie; returns a String of bytes.

toBuffer()

smf.toBuffer(rmi) - as above; returns a Buffer object.

toArrayBuffer()

smf.toArrayBuffer(rmi) - as above; returns an ArrayBuffer object.

toInt8Array()

smf.toInt8Array(rmi) - as above; returns an Int8Array object.

toUint8Array()

smf.toUint8Array(rmi) - as above; returns a Uint8Array object.

NOTE: depending on the System/JavaScript version, some Array/Buffer types above may be not available.

Array attributes

SMF object is subclassed from JavaScript Array and inherits all its functions and attributes like push(), length, operator [], etc...

It contains data chunks and MIDI tracks.

Chunk

(works with or without the new keyword)

JZZ.MIDI.SMF.Chunk(type, data) - create an arbitrary Chunk object; type - chunk name, a 4-byte String; data - chunk contents, a String of bytes.

Chunks of non-MTrk types are ignored by most MIDI software.

MTrk

(works with or without the new keyword)

JZZ.MIDI.SMF.MTrk() - create a new MIDI Track.

As well as SMF, MTrk object is also subclassed from JavaScript Array and inherits all its functions and attributes. It contains MIDI events.

add()

mtrk.add(time, midi) - add MIDI event to the track; time - the event time in MIDI ticks; midi - a MIDI message or a Standard MIDI File Meta Event.

Example

var smf = new JZZ.MIDI.SMF(0, 96);
smf.push(new JZZ.MIDI.SMF.MTrk());

smf[0].add(0, JZZ.MIDI.smfBPM(120)) // tempo 120 bpm
      .add(96, JZZ.MIDI.noteOn(0, 'C6', 127))
      .add(96, JZZ.MIDI.noteOn(0, 'Eb6', 127))
      .add(96, JZZ.MIDI.noteOn(0, 'G6', 127))
      .add(192, JZZ.MIDI.noteOff(0, 'C6'))
      .add(192, JZZ.MIDI.noteOff(0, 'Eb6'))
      .add(192, JZZ.MIDI.noteOff(0, 'G6'))
      .add(288, JZZ.MIDI.smfEndOfTrack());

require('fs').writeFileSync('out.mid', smf.dump(), 'binary');

tick()

mtrk.tick(time) - return a "timed reference" to the track;

unlike in the MIDI-Out's wait(), the time is set in MIDI ticks.

send()

mtrk.send(midi) - add MIDI event at the "current" tick; similar to the MIDI-Out's send(),

Helpers

For each helper name, mtrk.helper(...) is equivalent to mtrk.send(JZZ.MIDI.helper(...)).

MIDI 1.0 messages:

noteOn noteOff aftertouch program pressure pitchBend pitchBendF control bankMSB bankLSB bank modMSB modLSB mod modF breathMSB breathLSB breath breathF footMSB footLSB foot footF portamentoMSB portamentoLSB portamentoTime portamentoTimeF volumeMSB volumeLSB volume volumeF balanceMSB balanceLSB balance balanceF panMSB panLSB pan panF expressionMSB expressionLSB expression expressionF damper portamento sostenuto soft legato hold2 soundVariation filterResonance releaseTime attackTime brightness decayTime vibratoRate vibratoDepth vibratoDelay ptc dataMSB dataLSB data dataF dataIncr dataDecr nrpnMSB nrpnLSB nrpn rpnMSB rpnLSB rpn allSoundOff allNotesOff resetAllControllers localControl omni mono poly mode1 mode2 mode3 mode4 mtc songPosition songSelect tune clock start continue stop active rpnPitchBendRange rpnPitchBendRangeF rpnFineTuning rpnFineTuningF rpnCoarseTuning rpnCoarseTuningF rpnTuning rpnTuningF rpnTuningA rpnSelectTuningProgram rpnSelectTuningBank rpnSelectTuning rpnModulationDepthRange rpnModulationDepthRangeF rpnNull sxIdRequest sxFullFrame sxMasterVolume sxMasterVolumeF sxMasterFineTuning sxMasterFineTuningF sxMasterCoarseTuning sxMasterCoarseTuningF sxMasterTranspose sxMasterTransposeF sxMasterTuning sxMasterTuningF sxMasterTuningA sxTuningDumpRequest sxNoteTuning sxNoteTuningF sxNoteTuningHZ sxScaleTuning1 sxScaleTuning1F sxScaleTuning2 sxScaleTuning2F sxScaleTuning sxScaleTuningF sxGM sxGS sxXG sxMidiSoft gsMasterVolume gsMasterVolumeF gsMasterFineTuning gsMasterFineTuningF gsMasterCoarseTuning gsMasterCoarseTuningF gsMasterTranspose gsMasterTransposeF gsMasterTuningF gsMasterTuningA gsOctaveTuning gsOctaveTuningF gsScaleTuning gsScaleTuningF xgMasterVolume xgMasterVolumeF xgMasterFineTuning xgMasterFineTuningF xgMasterCoarseTuning xgMasterCoarseTuningF xgMasterTranspose xgMasterTransposeF xgMasterTuningF xgMasterTuningA xgOctaveTuning xgOctaveTuningF xgScaleTuning xgScaleTuningF

SMF meta events:

smf smfSeqNumber smfText smfCopyright smfSeqName smfInstrName smfLyric smfMarker smfCuePoint smfProgName smfDevName smfChannelPrefix smfEndOfTrack smfTempo smfBPM smfSMPTE smfTimeSignature smfKeySignature smfMetaEvent

note()

mtrk.note(c, n, v, t) is equivalent to mtrk.noteOn(c, n, v).tick(t).noteOff(c, n) if t > 0, and to mtrk.noteOn(c, n, v) otherwise.

ch()

mtrk.ch(chan) - set the channel information for the subsequent chained calls; same as the MIDI-Out's ch(),

sxId()

mtrk.sxId(id) - set the default SysEx ID for the subsequent chained calls; same as the MIDI-Out's sxId(),

Example

// the calls from the example above can be rewritten shorter:
smf[0].smfBPM(120).ch(0) // subsequent calls will apply to channel 0
      .tick(96).noteOn('C6', 127).noteOn('Eb6', 127).noteOn('G6', 127)
      .tick(96).noteOff('C6').noteOff('Eb6').noteOff('G6')
      .tick(96).smfEndOfTrack();
// or
smf[0].smfBPM(120).ch(0)
      .tick(96).note('C6', 127, 96).note('Eb6', 127, 96).note('G6', 127, 96)
      .tick(192).smfEndOfTrack();

SYX files

.syx file is a binary file with the contents of one or more SysEx messages.
It is normally used to dump and store MIDI instrument data.

JZZ.MIDI.SYX constructors work with or without the new keyword:

JZZ.MIDI.SYX(msg) - create a MIDI message; msg must be a SysEx message or a corresponding array of bytes.

JZZ.MIDI.SYX(syx) - copy-constructor, where syx is another SYX object.

JZZ.MIDI.SYX(smf) - create from a JZZ.MIDI.SMF object; Throws if the MIDI file contains any non-SysEx MIDI message; Ignores SMF meta events.

JZZ.MIDI.SYX(data) - create from binary data; data - the contents of a SYX file as a String, Buffer, ArrayBuffer, Int8Array or Uint8Array.

toString()

syx.toString() convert SYX file to human-readable string.

NOTE: in most JavaScript realizations, console.log() does not automatically call this function.

dump()

syx.dump() - export SYX File as a String of bytes.

toBuffer()

syx.toBuffer() - as above; returns a Buffer object.

toArrayBuffer()

syx.toArrayBuffer() - as above; returns an ArrayBuffer object.

toInt8Array()

syx.toInt8Array() - as above; returns an Int8Array object.

toUint8Array()

syx.toUint8Array() - as above; returns a Uint8Array object.

NOTE: depending on the System/JavaScript version, some Array/Buffer types above may be not available.

add(), send(), etc...

syx.add(msg), syx.send(msg) - add MIDI message; See the example below.

All the helper functions can be also used as well as ch() and sxId(), however, all non-SysEx messages will be ignored.

Example

// the calls below produce identical SYX objects:
var syx1 = new JZZ.MIDI.SYX(JZZ.MIDI.sxIdRequest());
var syx2 = JZZ.MIDI.SYX([0xf0, 0x7e, 0x7f, 0x06, 0x01]);
var syx3 = JZZ.MIDI.SYX(syx2);
var syx4 = JZZ.MIDI.SYX(); syx4.add(JZZ.MIDI.sxIdRequest());
var syx5 = JZZ.MIDI.SYX(); syx5.add([0xf0, 0x7e, 0x7f, 0x06, 0x01]);
var syx6 = new JZZ.MIDI.SYX(); syx6.sxIdRequest();
// etc...

MIDI 2.0 Clip files

JZZ.MIDI.Clip constructors work with or without the new keyword:

JZZ.MIDI.Clip(clip) - copy-constructor, where clip is another Clip object.

JZZ.MIDI.Clip(data) - create from binary data; data - the contents of a MIDI 2.0 Clip file as a String, Buffer, ArrayBuffer, Int8Array or Uint8Array.

toString()

clip.toString() convert Clip file to human-readable string.

NOTE: in most JavaScript realizations, console.log() does not automatically call this function.

dump()

clip.dump() - export Clip File as a String of bytes.

toBuffer()

clip.toBuffer() - as above; returns a Buffer object.

toArrayBuffer()

clip.toArrayBuffer() - as above; returns an ArrayBuffer object.

toInt8Array()

clip.toInt8Array() - as above; returns an Int8Array object.

toUint8Array()

clip.toUint8Array() - as above; returns a Uint8Array object.

NOTE: depending on the System/JavaScript version, some Array/Buffer types above may be not available.

add()

clip.add(time, midi) - add MIDI event to the clip; time - the event time in MIDI ticks; midi - a MIDI 2.0 message.

tick()

clip.tick(time) - return a "timed reference" to the clip.

send()

clip.send(midi) - add MIDI 2.0 event at the "current" tick; sending a Delta Clock message is equivalent to calling the clip.tick() function.

Helpers

For each helper name, clip.helper(...) is equivalent to clip.send(JZZ.MIDI2.helper(...)).

All MIDI 1.0 helpers require group as an additional first parameter and produce MIDI 1.0 messages wrapped into Universal MIDI Packages (UMP).

Additional MIDI 2.0 messages:

noop umpClock umpTimestamp umpTicksPQN umpDelta umpNoteOn umpNoteOff umpProgram umpPressure umpPressureF umpPnPressure umpPnPressureF umpAftertouch umpAftertouchF umpPitchBend umpPitchBendF umpPnPitchBend umpPnPitchBendF umpRPN umpPnRPN umpNRPN umpPnNRPN umpControl umpTempo umpBPM umpTimeSignature umpCustomText umpMetadata umpCMetadata umpProjectName umpCProjectName umpCompositionName umpCCompositionName umpClipName umpCClipName umpCopyright umpCCopyright umpComposerName umpCComposerName umpLyricistName umpCLyricistName umpArrangerName umpCArrangerName umpPublisherName umpCPublisherName umpPerformerName umpCPerformerName umpAccPerformerName umpCAccPerformerName umpRecordingDate umpCRecordingDate umpRecordingLocation umpCRecordingLocation umpText umpCText umpLyrics umpCLyrics umpLyricsLanguage umpLyricsLanguage umpRuby umpCRuby umpRubyLanguage umpCRubyLanguage

gr()

clip.gr(chan) - set the group information for the subsequent chained calls; same as the MIDI-Out's gr(),

ch()

clip.ch(chan) - set the channel information for the subsequent chained calls; same as the MIDI-Out's ch(),

sxId()

clip.sxId(id) - set the default SysEx ID for the subsequent chained calls; same as the MIDI-Out's sxId(),

MIDI Player

smf.player(), syx.player(), clip.player() - create the Player object.

Player is subclassed from MIDI-In and inherits all its methods, in particular, connect() and disconnect().

Messages (including the SMF Meta Events) sent to the Player via send() or helper functions, will be redirected to the output;

SMF Tempo Meta Events (smfTempo, smfBPM) will also affect the playback tempo if MIDI file is PPQN-timed (most common case).

play()

player.play() - start playback.

stop()

player.stop() - stop playback.

pause()

player.pause() - pause playback.

resume()

player.resume() - resume playback.

loop()

player.loop(value) - set / unset the loop.

value - if integer - set the loop counter to value; otherwise if true - set the loop to infinity; if false - unset the loop.

speed()

player.speed(x) - slow down (0.0 < x < 1.0) or speed up (x > 1.0) playback.

x - ratio to the default playback speed;

If called without paramener, returns the current payback speed.

type()

player.type() - return the type of the MIDI file (0, 1 or 0).

tracks()

player.tracks() - return the number of MIDI tracks in the file.

duration()

player.duration() - return the MIDI file duration in MIDI ticks.

durationMS()

player.durationMS() - return the MIDI file duration in milliseconds.

position()

player.position() - return the current MIDI file position in MIDI ticks.

positionMS()

player.positionMS() - return the current MIDI file position in milliseconds.

jump()

player.jump(pos) - jump to the specified position in MIDI ticks.

pos - position in MIDI ticks.

jumpMS()

player.jumpMS(pos) - jump to the specified position in milliseconds.

pos - position in milliseconds.

tick2ms()

player.tick2ms(t) - convert the position in MIDI ticks into milliseconds.

t - position in MIDI ticks.

ms2tick()

player.ms2tick(t) - convert the position in milliseconds into MIDI ticks.

t - position in milliseconds.

User hook

player.onEnd() - called when the end of the MIDI file is reached.

Example

var data = require('fs').readFileSync('test.mid', 'binary');
var smf = new JZZ.MIDI.SMF(data);

var player = smf.player();
player.onEnd = function() { console.log('Done!'); };

JZZ().or('Cannot start MIDI engine!').openMidiOut().or('Cannot open MIDI Out!').and(function() {
  player.connect(this);
  player.play();
});

See also