-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMIDI.FileTrack.js
110 lines (103 loc) · 3.94 KB
/
MIDI.FileTrack.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// MIDIFileTrack : Read and edit a MIDI track chunk in a given ArrayBuffer
function MIDIFileTrack(buffer, start) {
var a;
var trackLength;
// no buffer, creating him
if(!buffer) {
a = new Uint8Array(12);
// Adding the empty track header (MTrk)
a[0] = 0x4D; a[1] = 0x54; a[2] = 0x72; a[3] = 0x6B;
// Adding the empty track size (4)
a[4] = 0x00; a[5] = 0x00; a[6] = 0x00; a[7] = 0x04;
// Adding the track end event
a[8] = 0x00; a[9] = 0xFF; a[10] = 0x2F; a[11] = 0x00;
// Saving the buffer
this.datas = new DataView(a.buffer, 0, MIDIFileTrack.HDR_LENGTH + 4);
// parsing the given buffer
} else {
if(!(buffer instanceof ArrayBuffer)) {
throw new Error('Invalid buffer received.');
}
// Buffer length must size at least like an empty track (8+3bytes)
if(12 > buffer.byteLength - start) {
throw new Error('Invalid MIDIFileTrack (0x' + start.toString(16) + ') :' +
' Buffer length must size at least 12bytes');
}
// Creating a temporary view to read the track header
this.datas = new DataView(buffer, start, MIDIFileTrack.HDR_LENGTH);
// Reading MIDI track header chunk
if(!(
'M' === String.fromCharCode(this.datas.getUint8(0)) &&
'T' === String.fromCharCode(this.datas.getUint8(1)) &&
'r' === String.fromCharCode(this.datas.getUint8(2)) &&
'k' === String.fromCharCode(this.datas.getUint8(3))
)) {
throw new Error('Invalid MIDIFileTrack (0x' + start.toString(16) + ') :' +
' MTrk prefix not found');
}
// Reading the track length
trackLength = this.getTrackLength();
if(buffer.byteLength - start < trackLength) {
throw new Error('Invalid MIDIFileTrack (0x' + start.toString(16) + ') :' +
' The track size exceed the buffer length.');
}
// Creating the final DataView
this.datas = new DataView(buffer, start, MIDIFileTrack.HDR_LENGTH + trackLength);
// Trying to find the end of track event
if(!(
0xFF === this.datas.getUint8(MIDIFileTrack.HDR_LENGTH + trackLength - 3) &&
0x2F === this.datas.getUint8(MIDIFileTrack.HDR_LENGTH + trackLength - 2) &&
0x00 === this.datas.getUint8(MIDIFileTrack.HDR_LENGTH + trackLength - 1)
)) {
throw new Error('Invalid MIDIFileTrack (0x' + start.toString(16) + ') :' +
' No track end event found at the expected index' +
' (' + (MIDIFileTrack.HDR_LENGTH + trackLength - 1).toString(16) + ').');
}
}
}
// Static constants
MIDIFileTrack.HDR_LENGTH = 8;
// Track length
MIDIFileTrack.prototype.getTrackLength = function() {
return this.datas.getUint32(4);
};
MIDIFileTrack.prototype.setTrackLength = function(trackLength) {
return this.datas.setUint32(4, trackLength);
};
// Read track contents
MIDIFileTrack.prototype.getTrackContent = function() {
return new DataView(this.datas.buffer,
this.datas.byteOffset + MIDIFileTrack.HDR_LENGTH,
this.datas.byteLength - MIDIFileTrack.HDR_LENGTH);
};
// Set track content
MIDIFileTrack.prototype.setTrackContent = function(dataView) {
var origin;
var destination;
var i;
var j;
// Calculating the track length
var trackLength = dataView.byteLength - dataView.byteOffset;
// Track length must size at least like an empty track (4bytes)
if(4 > trackLength) {
throw new Error('Invalid track length, must size at least 4bytes');
}
this.datas = new DataView(
new Uint8Array(MIDIFileTrack.HDR_LENGTH + trackLength).buffer);
// Adding the track header (MTrk)
this.datas.setUint8(0, 0x4D); // M
this.datas.setUint8(1, 0x54); // T
this.datas.setUint8(2, 0x72); // r
this.datas.setUint8(3, 0x6B); // k
// Adding the track size
this.datas.setUint32(4, trackLength);
// Copying the content
origin = new Uint8Array(dataView.buffer, dataView.byteOffset,
dataView.byteLength);
destination = new Uint8Array(this.datas.buffer,
MIDIFileTrack.HDR_LENGTH,
trackLength);
for(i = 0, j = origin.length; i < j; i++) {
destination[i] = origin[i];
}
};