|
|
import { messageTypes } from "./midi_message.js"; |
|
|
import { writeVariableLengthQuantity } from "../utils/byte_functions/variable_length_quantity.js"; |
|
|
import { writeBytesAsUintBigEndian } from "../utils/byte_functions/big_endian.js"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function writeMIDI() |
|
|
{ |
|
|
const midi = this; |
|
|
if (!midi.tracks) |
|
|
{ |
|
|
throw new Error("MIDI has no tracks!"); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const binaryTrackData = []; |
|
|
for (const track of midi.tracks) |
|
|
{ |
|
|
const binaryTrack = []; |
|
|
let currentTick = 0; |
|
|
let runningByte = undefined; |
|
|
for (const event of track) |
|
|
{ |
|
|
|
|
|
const deltaTicks = event.ticks - currentTick; |
|
|
|
|
|
|
|
|
|
|
|
let messageData; |
|
|
|
|
|
if (event.messageStatusByte <= messageTypes.sequenceSpecific) |
|
|
{ |
|
|
|
|
|
|
|
|
messageData = [0xff, event.messageStatusByte, ...writeVariableLengthQuantity(event.messageData.length), ...event.messageData]; |
|
|
} |
|
|
else if (event.messageStatusByte === messageTypes.systemExclusive) |
|
|
{ |
|
|
|
|
|
|
|
|
messageData = [0xf0, ...writeVariableLengthQuantity(event.messageData.length), ...event.messageData]; |
|
|
} |
|
|
else |
|
|
{ |
|
|
|
|
|
messageData = []; |
|
|
if (runningByte !== event.messageStatusByte) |
|
|
{ |
|
|
|
|
|
runningByte = event.messageStatusByte; |
|
|
|
|
|
messageData.push(event.messageStatusByte); |
|
|
} |
|
|
|
|
|
messageData.push(...event.messageData); |
|
|
} |
|
|
|
|
|
binaryTrack.push(...writeVariableLengthQuantity(deltaTicks)); |
|
|
|
|
|
binaryTrack.push(...messageData); |
|
|
currentTick += deltaTicks; |
|
|
} |
|
|
binaryTrackData.push(new Uint8Array(binaryTrack)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function writeText(text, arr) |
|
|
{ |
|
|
for (let i = 0; i < text.length; i++) |
|
|
{ |
|
|
arr.push(text.charCodeAt(i)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const binaryData = []; |
|
|
|
|
|
writeText("MThd", binaryData); |
|
|
binaryData.push(...writeBytesAsUintBigEndian(6, 4)); |
|
|
binaryData.push(0, midi.format); |
|
|
binaryData.push(...writeBytesAsUintBigEndian(midi.tracksAmount, 2)); |
|
|
binaryData.push(...writeBytesAsUintBigEndian(midi.timeDivision, 2)); |
|
|
|
|
|
|
|
|
for (const track of binaryTrackData) |
|
|
{ |
|
|
|
|
|
writeText("MTrk", binaryData); |
|
|
binaryData.push(...writeBytesAsUintBigEndian(track.length, 4)); |
|
|
binaryData.push(...track); |
|
|
} |
|
|
return new Uint8Array(binaryData); |
|
|
} |