-
Notifications
You must be signed in to change notification settings - Fork 0
/
MidiFile.h
315 lines (268 loc) · 14.7 KB
/
MidiFile.h
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Fri Nov 26 14:12:01 PST 1999
// Last Modified: Mon Jan 18 20:54:04 PST 2021 Added readSmf().
// Filename: midifile/include/MidiFile.h
// Website: http://midifile.sapp.org
// Syntax: C++11
// vim: ts=3 noexpandtab
//
// Description: A class that can read/write Standard MIDI files.
// MIDI data is stored by track in an array.
//
#ifndef _MIDIFILE_H_INCLUDED
#define _MIDIFILE_H_INCLUDED
#include "MidiEventList.h"
#include <vector>
#include <string>
#include <istream>
#include <fstream>
#define TIME_STATE_DELTA 0
#define TIME_STATE_ABSOLUTE 1
#define TRACK_STATE_SPLIT 0
#define TRACK_STATE_JOINED 1
namespace smf {
class _TickTime {
public:
int tick;
double seconds;
};
class MidiFile {
public:
MidiFile (void);
MidiFile (const std::string& filename);
MidiFile (std::istream& input);
MidiFile (const MidiFile& other);
MidiFile (MidiFile&& other);
~MidiFile ();
MidiFile& operator= (const MidiFile& other);
MidiFile& operator= (MidiFile&& other);
// Reading/writing functions:
// Auto-detected SMF or ASCII-encoded SMF (decoded with Binasc class):
bool read (const std::string& filename);
bool read (std::istream& instream);
// Only allow Standard MIDI File input:
bool readSmf (const std::string& filename);
bool readSmf (std::istream& instream);
bool write (const std::string& filename);
bool write (std::ostream& out);
bool writeHex (const std::string& filename,
int width = 25);
bool writeHex (std::ostream& out,
int width = 25);
bool writeBinasc (const std::string& filename);
bool writeBinasc (std::ostream& out);
bool writeBinascWithComments (const std::string& filename);
bool writeBinascWithComments (std::ostream& out);
bool status (void) const;
// track-related functions:
const MidiEventList& operator[] (int aTrack) const;
MidiEventList& operator[] (int aTrack);
int getTrackCount (void) const;
int getNumTracks (void) const;
int size (void) const;
void removeEmpties (void);
// tick-related functions:
void makeDeltaTicks (void);
void deltaTicks (void);
void makeAbsoluteTicks (void);
void absoluteTicks (void);
int getTickState (void) const;
bool isDeltaTicks (void) const;
bool isAbsoluteTicks (void) const;
// join/split track functionality:
void joinTracks (void);
void splitTracks (void);
void splitTracksByChannel (void);
int getTrackState (void) const;
int hasJoinedTracks (void) const;
int hasSplitTracks (void) const;
int getSplitTrack (int track, int index) const;
int getSplitTrack (int index) const;
// track sorting funcionality:
void sortTrack (int track);
void sortTracks (void);
void markSequence (void);
void markSequence (int track, int sequence = 1);
void clearSequence (void);
void clearSequence (int track);
// track manipulation functionality:
int addTrack (void);
int addTrack (int count);
int addTracks (int count);
void deleteTrack (int aTrack);
void mergeTracks (int aTrack1, int aTrack2);
int getTrackCountAsType1 (void);
// ticks-per-quarter related functions:
void setMillisecondTicks (void);
int getTicksPerQuarterNote (void) const;
int getTPQ (void) const;
void setTicksPerQuarterNote (int ticks);
void setTPQ (int ticks);
// physical-time analysis functions:
void doTimeAnalysis (void);
double getTimeInSeconds (int aTrack, int anIndex);
double getTimeInSeconds (int tickvalue);
double getAbsoluteTickTime (double starttime);
int getFileDurationInTicks (void);
double getFileDurationInQuarters (void);
double getFileDurationInSeconds (void);
// note-analysis functions:
int linkNotePairs (void);
int linkEventPairs (void);
void clearLinks (void);
// filename functions:
void setFilename (const std::string& aname);
const char* getFilename (void) const;
// event functionality:
MidiEvent* addEvent (int aTrack, int aTick,
std::vector<uchar>& midiData);
MidiEvent* addEvent (MidiEvent& mfevent);
MidiEvent* addEvent (int aTrack, MidiEvent& mfevent);
MidiEvent& getEvent (int aTrack, int anIndex);
const MidiEvent& getEvent (int aTrack, int anIndex) const;
int getEventCount (int aTrack) const;
int getNumEvents (int aTrack) const;
void allocateEvents (int track, int aSize);
void erase (void);
void clear (void);
void clear_no_deallocate (void);
// MIDI message adding convenience functions:
MidiEvent* addNoteOn (int aTrack, int aTick,
int aChannel, int key,
int vel);
MidiEvent* addNoteOff (int aTrack, int aTick,
int aChannel, int key,
int vel);
MidiEvent* addNoteOff (int aTrack, int aTick,
int aChannel, int key);
MidiEvent* addController (int aTrack, int aTick,
int aChannel, int num,
int value);
MidiEvent* addPatchChange (int aTrack, int aTick,
int aChannel, int patchnum);
MidiEvent* addTimbre (int aTrack, int aTick,
int aChannel, int patchnum);
MidiEvent* addPitchBend (int aTrack, int aTick,
int aChannel, double amount);
// RPN settings:
void setPitchBendRange (int aTrack, int aTick,
int aChannel, double range);
// Controller message adding convenience functions:
MidiEvent* addSustain (int aTrack, int aTick,
int aChannel, int value);
MidiEvent* addSustainPedal (int aTrack, int aTick,
int aChannel, int value);
MidiEvent* addSustainOn (int aTrack, int aTick,
int aChannel);
MidiEvent* addSustainPedalOn (int aTrack, int aTick,
int aChannel);
MidiEvent* addSustainOff (int aTrack, int aTick,
int aChannel);
MidiEvent* addSustainPedalOff (int aTrack, int aTick,
int aChannel);
// Meta-event adding convenience functions:
MidiEvent* addMetaEvent (int aTrack, int aTick,
int aType,
std::vector<uchar>& metaData);
MidiEvent* addMetaEvent (int aTrack, int aTick,
int aType,
const std::string& metaData);
MidiEvent* addText (int aTrack, int aTick,
const std::string& text);
MidiEvent* addCopyright (int aTrack, int aTick,
const std::string& text);
MidiEvent* addTrackName (int aTrack, int aTick,
const std::string& name);
MidiEvent* addInstrumentName (int aTrack, int aTick,
const std::string& name);
MidiEvent* addLyric (int aTrack, int aTick,
const std::string& text);
MidiEvent* addMarker (int aTrack, int aTick,
const std::string& text);
MidiEvent* addCue (int aTrack, int aTick,
const std::string& text);
MidiEvent* addTempo (int aTrack, int aTick,
double aTempo);
MidiEvent* addTimeSignature (int aTrack, int aTick,
int top, int bottom,
int clocksPerClick = 24,
int num32dsPerQuarter = 8);
MidiEvent* addCompoundTimeSignature(int aTrack, int aTick,
int top, int bottom,
int clocksPerClick = 36,
int num32dsPerQuarter = 8);
uchar readByte (std::istream& input);
// static functions:
static ushort readLittleEndian2Bytes (std::istream& input);
static ulong readLittleEndian4Bytes (std::istream& input);
static std::ostream& writeLittleEndianUShort (std::ostream& out,
ushort value);
static std::ostream& writeBigEndianUShort (std::ostream& out,
ushort value);
static std::ostream& writeLittleEndianShort (std::ostream& out,
short value);
static std::ostream& writeBigEndianShort (std::ostream& out,
short value);
static std::ostream& writeLittleEndianULong (std::ostream& out,
ulong value);
static std::ostream& writeBigEndianULong (std::ostream& out,
ulong value);
static std::ostream& writeLittleEndianLong (std::ostream& out,
long value);
static std::ostream& writeBigEndianLong (std::ostream& out,
long value);
static std::ostream& writeLittleEndianFloat (std::ostream& out,
float value);
static std::ostream& writeBigEndianFloat (std::ostream& out,
float value);
static std::ostream& writeLittleEndianDouble (std::ostream& out,
double value);
static std::ostream& writeBigEndianDouble (std::ostream& out,
double value);
protected:
// m_events == Lists of MidiEvents for each MIDI file track.
std::vector<MidiEventList*> m_events;
// m_ticksPerQuarterNote == A value for the MIDI file header
// which represents the number of ticks in a quarter note
// that are used as units for the delta times for MIDI events
// in MIDI file track data.
int m_ticksPerQuarterNote = 120;
// m_theTrackState == state variable for whether the tracks
// are joined or split.
int m_theTrackState = TRACK_STATE_SPLIT;
// m_theTimeState == state variable for whether the MidiEvent::tick
// variable contain absolute ticks since the start of the file's
// time, or delta ticks since the last MIDI event in the track.
int m_theTimeState = TIME_STATE_ABSOLUTE;
// m_readFileName == the filename of the last file read into
// the object.
std::string m_readFileName;
// m_timemapvalid ==
bool m_timemapvalid = false;
// m_timemap ==
std::vector<_TickTime> m_timemap;
// m_rwstatus == True if last read was successful, false if a problem.
bool m_rwstatus = true;
// m_linkedEventQ == True if link analysis has been done.
bool m_linkedEventsQ = false;
private:
int extractMidiData (std::istream& inputfile,
std::vector<uchar>& array,
uchar& runningCommand);
ulong readVLValue (std::istream& inputfile);
ulong unpackVLV (uchar a = 0, uchar b = 0,
uchar c = 0, uchar d = 0,
uchar e = 0);
void writeVLValue (long aValue,
std::vector<uchar>& data);
int makeVLV (uchar *buffer, int number);
static int ticksearch (const void* A, const void* B);
static int secondsearch (const void* A, const void* B);
void buildTimeMap (void);
double linearTickInterpolationAtSecond (double seconds);
double linearSecondInterpolationAtTick (int ticktime);
};
} // end of namespace smf
std::ostream& operator<<(std::ostream& out, smf::MidiFile& aMidiFile);
#endif /* _MIDIFILE_H_INCLUDED */