Skip to content

Commit

Permalink
umpTempo() and umpTimeSignature()
Browse files Browse the repository at this point in the history
  • Loading branch information
jazz-soft committed Jul 2, 2023
1 parent 1c6241b commit 838ce10
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
63 changes: 61 additions & 2 deletions javascript/JZZ.js
Original file line number Diff line number Diff line change
Expand Up @@ -2923,6 +2923,33 @@
umpStartClip: function() { return [0xf0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; },
umpEndClip: function() { return [0xf0, 0x21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; },
};
var _helperGN = {
umpTempo: function(g, n) { return [0xd0 + g, 0x10, 0, 0, n >> 24, (n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff, 0, 0, 0, 0, 0, 0, 0, 0]; },
umpBPM: function(g, n) { return _helperGN.umpTempo(g, Math.round(6000000000 / n)); },
umpTimeSignature: function(g, a, b) {
var nn, cc, dd;
var m = ('' + a ).match(/^\s*(\d+)\s*\/\s*(\d+)\s*$/);
if (m) {
nn = parseInt(m[1]);
cc = parseInt(m[2]);
if (nn > 0 && nn < 0x100 && cc > 0 && !(cc & (cc - 1))) {
dd = 0;
for (cc >>= 1; cc; cc >>= 1) dd++;
return [0xd0 + g, 0x10, 0, 1, nn, dd, cc, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
}
else if (a == parseInt(a) && b == parseInt(b)) {
if (a > 0 && a < 0x100 && b > 0 && !(b & (b - 1))) {
nn = a;
dd = 0;
cc = b;
for (cc >>= 1; cc; cc >>= 1) dd++;
return [0xd0 + g, 0x10, 0, 1, nn, dd, cc, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
}
throw RangeError('Wrong time signature ' + a + (typeof b == 'undefined' ? '' : '/' + b));
},
};
var _helperGC = {
};

Expand All @@ -2943,7 +2970,7 @@
UMP[name] = function() {
var args = Array.prototype.slice.call(arguments);
if (typeof this._gr != 'undefined') args = [this._gr].concat(args);
return new UMP([0x10 + args[0]].concat(func.apply(this, args.slice(1)), [0, 0]).slice(0, 4));
return new UMP(func.apply(this, args));
};
}
function _umpseqstat(n, i) { return n == 1 ? 0 : i == 0 ? 0x10 : i == n - 1 ? 0x30 : 0x20; }
Expand All @@ -2968,13 +2995,39 @@
return new UMP([0x20 + args[0]].concat(func.apply(this, args.slice(1)), [0]).slice(0, 4));
};
}
function _copyHelperM1N(name, func) {
UMP[name] = function() {
var args = Array.prototype.slice.call(arguments);
if (typeof this._gr != 'undefined') args = [this._gr].concat(args);
return new UMP([0x10 + args[0]].concat(func.apply(this, args.slice(1)), [0, 0]).slice(0, 4));
};
}
_for(_helperNN, function(n) { _copyHelperNN(n, _helperNN[n]); });
_for(_helperGC, function(n) { _copyHelperGC(n, _helperGC[n]); });
_for(_helperMPE, function(n) { _copyHelperM1(n, _helperMPE[n]); });
_for(_helperCH, function(n) { _copyHelperM1(n, _helperCH[n]); });
_for(_helperNC, function(n) { _copyHelperGN(n, _helperNC[n]); });
_for(_helperNC, function(n) { _copyHelperM1N(n, _helperNC[n]); });
_for(_helperGN, function(n) { _copyHelperGN(n, _helperGN[n]); });
_for(_helperSX, function(n) { _copyHelperSX(n, _helperSX[n]); });

UMP.prototype.getTempo = function() {
if (this.isTempo()) return (this[4] << 24) + (this[5] << 16) + (this[6] << 8) + this[7];
};
UMP.prototype.getBPM = function() {
var n = this.getTempo();
if (n) return Math.round(6000000000 / n);
};
UMP.prototype.getTimeSignature = function() {
if (this.isTimeSignature()) return [this[4], 1 << this[5]];
};

UMP.prototype.isTempo = function() {
return (this[0] >> 4) == 13 && (this[1] >> 4) == 1 && this[2] == 0 && this[3] == 0;
};
UMP.prototype.isTimeSignature = function() {
return (this[0] >> 4) == 13 && (this[1] >> 4) == 1 && this[2] == 0 && this[3] == 1;
};

UMP.prototype.toString = MIDI.prototype.toString;
UMP.prototype._str = function() {
var t = this._string();
Expand All @@ -2989,6 +3042,12 @@
s = ['NOOP', 'JR Clock', 'JR Timestamp', 'Ticks Per Quarter Note', 'Delta Ticks'][n];
return s;
}
if (this[0] == 0xd0) {
if (this[2] == 0) {
if (this[3] == 0) return 'Tempo ' + this.getBPM() + ' BPM';
if (this[3] == 1) return 'Time Signature ' + this.getTimeSignature().join('/');
}
}
if (this[0] == 0xf0) {
s = { 0x20: 'Start of Clip', 0x21: 'End of Clip' }[this[1]];
return s;
Expand Down
29 changes: 29 additions & 0 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,35 @@ describe('UMP messages', function() {
it('umpEndClip', function() {
assert.equal(JZZ.UMP.umpEndClip().toString(), 'f0210000 00000000 00000000 00000000 -- End of Clip');
});
it('umpTempo', function() {
var s = 'd0100000 02faf080 00000000 00000000 -- Tempo 120 BPM';
var msg = JZZ.UMP.umpBPM(0, 120);
assert.equal(msg.isTempo(), true);
assert.equal(msg.isTimeSignature(), false);
assert.equal(msg.getTempo(), 50000000);
assert.equal(msg.getBPM(), 120);
assert.equal(typeof msg.getTimeSignature(), 'undefined');
assert.equal(msg.toString(), s);
assert.equal(JZZ.UMP.gr(0).umpBPM(120).toString(), s);
});
it('umpTimeSignature', function() {
var s = 'd0100001 03020000 00000000 00000000 -- Time Signature 3/4';
var msg = JZZ.UMP.umpTimeSignature(0, '3/4');
assert.equal(msg.isTimeSignature(), true);
assert.equal(msg.isTempo(), false);
assert.equal(typeof msg.getBPM(), 'undefined');
assert.equal(msg.toString(), s);
assert.equal(JZZ.UMP.umpTimeSignature(0, 3, 4).toString(), s);
assert.equal(JZZ.UMP.gr(0).umpTimeSignature(3, 4).toString(), s);
assert.throws(function() { JZZ.UMP.gr(0).umpTimeSignature('1/5'); });
assert.throws(function() { JZZ.UMP.gr(0).umpTimeSignature(4, 3); });
assert.throws(function() { JZZ.UMP.gr(0).umpTimeSignature(); });
});

it('unknown', function() {
assert.equal(JZZ.UMP([0xd0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).toString(), 'd0000500 00000000 00000000 00000000');
assert.equal(JZZ.UMP([0xd0, 0x10, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).toString(), 'd0100005 00000000 00000000 00000000');
});
});

describe('SMF events', function() {
Expand Down

0 comments on commit 838ce10

Please sign in to comment.