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 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 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 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 ptc dataMSB dataLSB data dataIncr dataDecr nrpnMSB nrpnLSB nrpn rpnMSB rpnLSB rpn allSoundOff allNotesOff resetAllControllers localControl omni mono poly 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() sxMasterTuning() sxMasterTuningF() sxMasterTuningA() sxTuningDumpRequest sxNoteTuning sxNoteTuningF sxNoteTuningHZ sxScaleTuning1 sxScaleTuning1F sxScaleTuning2 sxScaleTuning2F sxScaleTuning sxScaleTuningF

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 channel information for the subsequent chained calls; same as the MIDI-Out's ch(),

sxId()

mtrk.sxId(id) - set 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 MIDI or RMI 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 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...

player()

smf.player(), syx.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