File size: 6,977 Bytes
9e60a92 |
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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
/**
* This is the base type for MIDI files. It contains all the "metadata" and information.
* It extends to:
* - BasicMIDI, which contains the actual track data of the MIDI file. Essentially the MIDI file itself.
* - MIDIData, which contains all properties that MIDI does, except for tracks and the embedded soundfont.
* MIDIData is the "shell" of the file which is available on the main thread at all times, containing the metadata.
*/
class MIDISequenceData
{
/**
* The time division of the sequence, representing the number of ticks per beat.
* @type {number}
*/
timeDivision = 0;
/**
* The duration of the sequence, in seconds.
* @type {number}
*/
duration = 0;
/**
* The tempo changes in the sequence, ordered from the last change to the first.
* Each change is represented by an object with a tick position and a tempo value in beats per minute.
* @type {{ticks: number, tempo: number}[]}
*/
tempoChanges = [{ ticks: 0, tempo: 120 }];
/**
* A string containing the copyright information for the MIDI sequence if detected.
* @type {string}
*/
copyright = "";
/**
* The number of tracks in the MIDI sequence.
* @type {number}
*/
tracksAmount = 0;
/**
* The track names in the MIDI file, an empty string if not set.
* @type {string[]}
*/
trackNames = [];
/**
* An array containing the lyrics of the sequence, stored as binary chunks (Uint8Array).
* @type {Uint8Array[]}
*/
lyrics = [];
/**
* An array of tick positions where lyrics events occur in the sequence.
* @type {number[]}
*/
lyricsTicks = [];
/**
* The tick position of the first note-on event in the MIDI sequence.
* @type {number}
*/
firstNoteOn = 0;
/**
* The MIDI key range used in the sequence, represented by a minimum and maximum note value.
* @type {{min: number, max: number}}
*/
keyRange = { min: 0, max: 127 };
/**
* The tick position of the last voice event (such as note-on, note-off, or control change) in the sequence.
* @type {number}
*/
lastVoiceEventTick = 0;
/**
* An array of MIDI port numbers used by each track in the sequence.
* @type {number[]}
*/
midiPorts = [0];
/**
* An array of channel offsets for each MIDI port, using the SpessaSynth method.
* @type {number[]}
*/
midiPortChannelOffsets = [0];
/**
* A list of sets, where each set contains the MIDI channels used by each track in the sequence.
* @type {Set<number>[]}
*/
usedChannelsOnTrack = [];
/**
* The loop points (in ticks) of the sequence, including both start and end points.
* @type {{start: number, end: number}}
*/
loop = { start: 0, end: 0 };
/**
* The name of the MIDI sequence.
* @type {string}
*/
midiName = "";
/**
* A boolean indicating if the sequence's name is the same as the file name.
* @type {boolean}
*/
midiNameUsesFileName = false;
/**
* The file name of the MIDI sequence, if provided during parsing.
* @type {string}
*/
fileName = "";
/**
* The raw, encoded MIDI name, represented as a Uint8Array.
* Useful when the MIDI file uses a different code page.
* @type {Uint8Array}
*/
rawMidiName;
/**
* The format of the MIDI file, which can be 0, 1, or 2, indicating the type of the MIDI file.
* @type {number}
*/
format = 0;
/**
* The RMID (Resource-Interchangeable MIDI) info data, if the file is RMID formatted.
* Otherwise, this field is undefined.
* Chunk type (e.g. "INAM"): Chunk data as a binary array.
* @type {Object<string, IndexedByteArray>}
*/
RMIDInfo = {};
/**
* The bank offset used for RMID files.
* @type {number}
*/
bankOffset = 0;
/**
* If the MIDI file is a Soft Karaoke file (.kar), this flag is set to true.
* https://www.mixagesoftware.com/en/midikit/help/HTML/karaoke_formats.html
* @type {boolean}
*/
isKaraokeFile = false;
/**
* Indicates if this file is a Multi-Port MIDI file.
* @type {boolean}
*/
isMultiPort = false;
/**
* Converts ticks to time in seconds
* @param ticks {number} time in MIDI ticks
* @returns {number} time in seconds
*/
MIDIticksToSeconds(ticks)
{
let totalSeconds = 0;
while (ticks > 0)
{
// tempo changes are reversed, so the first element is the last tempo change
// and the last element is the first tempo change
// (always at tick 0 and tempo 120)
// find the last tempo change that has occurred
let tempo = this.tempoChanges.find(v => v.ticks < ticks);
// calculate the difference and tempo time
let timeSinceLastTempo = ticks - tempo.ticks;
totalSeconds += (timeSinceLastTempo * 60) / (tempo.tempo * this.timeDivision);
ticks -= timeSinceLastTempo;
}
return totalSeconds;
}
/**
* INTERNAL USE ONLY!
* DO NOT USE IN SPESSASYNTH_LIB
* @param sequence {MIDISequenceData}
* @protected
*/
_copyFromSequence(sequence)
{
// properties can be assigned
this.midiName = sequence.midiName;
this.midiNameUsesFileName = sequence.midiNameUsesFileName;
this.fileName = sequence.fileName;
this.timeDivision = sequence.timeDivision;
this.duration = sequence.duration;
this.copyright = sequence.copyright;
this.tracksAmount = sequence.tracksAmount;
this.firstNoteOn = sequence.firstNoteOn;
this.lastVoiceEventTick = sequence.lastVoiceEventTick;
this.format = sequence.format;
this.bankOffset = sequence.bankOffset;
this.isKaraokeFile = sequence.isKaraokeFile;
this.isMultiPort = sequence.isMultiPort;
// copying arrays
this.tempoChanges = [...sequence.tempoChanges];
this.lyrics = sequence.lyrics.map(arr => new Uint8Array(arr));
this.lyricsTicks = [...sequence.lyricsTicks];
this.midiPorts = [...sequence.midiPorts];
this.trackNames = [...sequence.trackNames];
this.midiPortChannelOffsets = [...sequence.midiPortChannelOffsets];
this.usedChannelsOnTrack = sequence.usedChannelsOnTrack.map(set => new Set(set));
this.rawMidiName = sequence.rawMidiName ? new Uint8Array(sequence.rawMidiName) : undefined;
// copying objects
this.loop = { ...sequence.loop };
this.keyRange = { ...sequence.keyRange };
this.RMIDInfo = { ...sequence.RMIDInfo };
}
}
export { MIDISequenceData }; |