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 };