JZZ.SMPTE is a helper class to simplify the work with the MIDI Time Code (MTC).
It takes care of frame-drops, generating and reading the full-frame sysex messages, generating and reading the quarter-frame MIDI messages in forvard and reverse directions.
JZZ.SMPTE() constructor works with or without the new keyword.
It takes a comma-separated list or an array of the following parameters: type, hour, minute, second, frame, quarter, where
type - SMPTE type (frames per second); can be 24 (24 fps, default), 25 (25 fps), 30 (30 fps), or 29.97 (30 fps, drop-frame).
hour, minute, second, frame - time from hours to fractions of second; omitted parameters will be set to zero.
quarter - the frame quarter number; from 0 (default) to 7 sic!. Used to generate the quarter-frame MIDI Time Code messages.
Constructor can also take another JZZ.SMPTE object to create its copy.
// the following code creates 4 identical SMPTE objects: 07:40:00:00, 30 fps, drop-frame var smpte0 = new JZZ.SMPTE(29.97, 7, 40); // using the "new" keyword var smpte1 = JZZ.SMPTE(29.97, 7, 40); // not using the "new" keyword var smpte2 = JZZ.SMPTE([29.97, 7, 40]); // take an array as the argument var smpte3 = JZZ.SMPTE(smpte1); // take another object as the argument
toString() return a string in the form hh:mm:ss:ff.
NOTE: in most JavaScript realizations, console.log() does not automatically call this function.
isFullFrame() - return true if it's a beginning of a new SMPTE frame, or false otherwise. A useful check if you want to emit a SMPTE clock event.
getType(), getHour(), getMinute(), getSecond(), getFrame(), getQuarter() - return the object's type, hour, minute, second, frame, quarter respectively.
setType(tt), setHour(hh), setMinute(mm), setSecond(ss), setFrame(ff), setQuarter(qq) - set the object's type, hour, minute, second, frame, quarter.
reset(...) - takes exactly the same parameters as the constructor above and sets all object fields accordingly.
incrFrame() - increase the time by one SMPTE frame.
decrFrame() - decrease the time by one SMPTE frame.
incrQF() - increase the time by a quarter-frame.
decrQF() - decrease the time by a quarter-frame.
Functions set***(), reset(), incr***(), decr***() return this, and, therefore, can be chained, e.g.: smpte.reset().setSecond(5).incrQF();.
The following JZZ.MIDI helpers produce MTC-related MIDI messages from a JZZ.SMPTE input:
JZZ.MIDI.mtc(smpte) creates a quarter-frame MIDI message.
JZZ.MIDI.sxFullFrame(smpte) creates a full-frame MIDI SysEx message. (Make sure the SysEx messages are enabled!)
read(msg) - read the quarter-frame or full-frame message and update the object accordingly. Returns true if that was a MIDI Time Code message, or false otherwise.
This example demonstrates how the slave clock picks up the current time from the master clock.
var master = JZZ.SMPTE(); // master clock var slave = JZZ.SMPTE(); // slave clock var sender = JZZ.Widget(); // sending port var receiver = JZZ.Widget(); // receiving port receiver._receive = function(msg) { if (slave.read(msg)) // print and consume the MTC messages console.log(master.toString(), ' ==> ', msg.toString(), ' ==> ', slave.toString()); else _emit(msg); // forward all other MIDI messages }; sender.connect(receiver); master.reset(24, 7, 39, 59); // 7:40 it arrives... for (var n = 0; n < 25; n++) { sender.mtc(master); master.incrQF(); }
It takes the full cycle of eight quarter-frames to get the clocks synchronized:
07:39:59:00 ==> f1 00 -- MIDI Time Code ==> 00:00:00:00 07:39:59:00 ==> f1 10 -- MIDI Time Code ==> 00:00:00:00 07:39:59:00 ==> f1 2b -- MIDI Time Code ==> 00:00:00:00 07:39:59:00 ==> f1 33 -- MIDI Time Code ==> 00:00:00:00 07:39:59:01 ==> f1 47 -- MIDI Time Code ==> 00:00:00:01 07:39:59:01 ==> f1 52 -- MIDI Time Code ==> 00:00:00:01 07:39:59:01 ==> f1 67 -- MIDI Time Code ==> 00:00:00:01 07:39:59:01 ==> f1 70 -- MIDI Time Code ==> 00:00:00:01 07:39:59:02 ==> f1 02 -- MIDI Time Code ==> 07:39:59:02 07:39:59:02 ==> f1 10 -- MIDI Time Code ==> 07:39:59:02 07:39:59:02 ==> f1 2b -- MIDI Time Code ==> 07:39:59:02 07:39:59:02 ==> f1 33 -- MIDI Time Code ==> 07:39:59:02 07:39:59:03 ==> f1 47 -- MIDI Time Code ==> 07:39:59:03 07:39:59:03 ==> f1 52 -- MIDI Time Code ==> 07:39:59:03 07:39:59:03 ==> f1 67 -- MIDI Time Code ==> 07:39:59:03 07:39:59:03 ==> f1 70 -- MIDI Time Code ==> 07:39:59:03 07:39:59:04 ==> f1 04 -- MIDI Time Code ==> 07:39:59:04 07:39:59:04 ==> f1 10 -- MIDI Time Code ==> 07:39:59:04 07:39:59:04 ==> f1 2b -- MIDI Time Code ==> 07:39:59:04 07:39:59:04 ==> f1 33 -- MIDI Time Code ==> 07:39:59:04 07:39:59:05 ==> f1 47 -- MIDI Time Code ==> 07:39:59:05 07:39:59:05 ==> f1 52 -- MIDI Time Code ==> 07:39:59:05 07:39:59:05 ==> f1 67 -- MIDI Time Code ==> 07:39:59:05 07:39:59:05 ==> f1 70 -- MIDI Time Code ==> 07:39:59:05 07:39:59:06 ==> f1 06 -- MIDI Time Code ==> 07:39:59:06
NOTE: sender and receiver in the above example are used just for illustration.
Instead of sender.mtc(master);, one could equally well write receiver.mtc(master); or slave.read(JZZ.MIDI.mtc(master));.