Chris@301
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@301
|
2
|
Chris@301
|
3 /*
|
Chris@301
|
4 Sonic Visualiser
|
Chris@301
|
5 An audio file viewer and annotation editor.
|
Chris@301
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@301
|
7
|
Chris@301
|
8 This program is free software; you can redistribute it and/or
|
Chris@301
|
9 modify it under the terms of the GNU General Public License as
|
Chris@301
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@301
|
11 License, or (at your option) any later version. See the file
|
Chris@301
|
12 COPYING included with this distribution for more information.
|
Chris@301
|
13 */
|
Chris@301
|
14
|
Chris@301
|
15
|
Chris@301
|
16 /*
|
Chris@301
|
17 This is a modified version of a source file from the
|
Chris@301
|
18 Rosegarden MIDI and audio sequencer and notation editor.
|
Chris@301
|
19 This file copyright 2000-2006 Richard Bown and Chris Cannam.
|
Chris@301
|
20 */
|
Chris@301
|
21
|
Chris@1581
|
22 #ifndef SV_MIDI_EVENT_H
|
Chris@1581
|
23 #define SV_MIDI_EVENT_H
|
Chris@301
|
24
|
Chris@301
|
25 #include <QString>
|
Chris@301
|
26 #include <string>
|
Chris@301
|
27 #include <iostream>
|
Chris@1038
|
28 #include <stdexcept>
|
Chris@1038
|
29
|
Chris@687
|
30 #include "base/Debug.h"
|
Chris@301
|
31
|
Chris@301
|
32 typedef unsigned char MIDIByte;
|
Chris@301
|
33
|
Chris@301
|
34 namespace MIDIConstants
|
Chris@301
|
35 {
|
Chris@301
|
36 static const char *const MIDI_FILE_HEADER = "MThd";
|
Chris@301
|
37 static const char *const MIDI_TRACK_HEADER = "MTrk";
|
Chris@301
|
38
|
Chris@301
|
39 static const MIDIByte MIDI_STATUS_BYTE_MASK = 0x80;
|
Chris@301
|
40 static const MIDIByte MIDI_MESSAGE_TYPE_MASK = 0xF0;
|
Chris@301
|
41 static const MIDIByte MIDI_CHANNEL_NUM_MASK = 0x0F;
|
Chris@301
|
42
|
Chris@301
|
43 static const MIDIByte MIDI_NOTE_OFF = 0x80;
|
Chris@301
|
44 static const MIDIByte MIDI_NOTE_ON = 0x90;
|
Chris@301
|
45 static const MIDIByte MIDI_POLY_AFTERTOUCH = 0xA0;
|
Chris@301
|
46 static const MIDIByte MIDI_CTRL_CHANGE = 0xB0;
|
Chris@301
|
47 static const MIDIByte MIDI_PROG_CHANGE = 0xC0;
|
Chris@301
|
48 static const MIDIByte MIDI_CHNL_AFTERTOUCH = 0xD0;
|
Chris@301
|
49 static const MIDIByte MIDI_PITCH_BEND = 0xE0;
|
Chris@301
|
50 static const MIDIByte MIDI_SELECT_CHNL_MODE = 0xB0;
|
Chris@301
|
51 static const MIDIByte MIDI_SYSTEM_EXCLUSIVE = 0xF0;
|
Chris@301
|
52 static const MIDIByte MIDI_TC_QUARTER_FRAME = 0xF1;
|
Chris@301
|
53 static const MIDIByte MIDI_SONG_POSITION_PTR = 0xF2;
|
Chris@301
|
54 static const MIDIByte MIDI_SONG_SELECT = 0xF3;
|
Chris@301
|
55 static const MIDIByte MIDI_TUNE_REQUEST = 0xF6;
|
Chris@301
|
56 static const MIDIByte MIDI_END_OF_EXCLUSIVE = 0xF7;
|
Chris@301
|
57 static const MIDIByte MIDI_TIMING_CLOCK = 0xF8;
|
Chris@301
|
58 static const MIDIByte MIDI_START = 0xFA;
|
Chris@301
|
59 static const MIDIByte MIDI_CONTINUE = 0xFB;
|
Chris@301
|
60 static const MIDIByte MIDI_STOP = 0xFC;
|
Chris@301
|
61 static const MIDIByte MIDI_ACTIVE_SENSING = 0xFE;
|
Chris@301
|
62 static const MIDIByte MIDI_SYSTEM_RESET = 0xFF;
|
Chris@301
|
63 static const MIDIByte MIDI_SYSEX_NONCOMMERCIAL = 0x7D;
|
Chris@301
|
64 static const MIDIByte MIDI_SYSEX_NON_RT = 0x7E;
|
Chris@301
|
65 static const MIDIByte MIDI_SYSEX_RT = 0x7F;
|
Chris@301
|
66 static const MIDIByte MIDI_SYSEX_RT_COMMAND = 0x06;
|
Chris@301
|
67 static const MIDIByte MIDI_SYSEX_RT_RESPONSE = 0x07;
|
Chris@301
|
68 static const MIDIByte MIDI_MMC_STOP = 0x01;
|
Chris@301
|
69 static const MIDIByte MIDI_MMC_PLAY = 0x02;
|
Chris@301
|
70 static const MIDIByte MIDI_MMC_DEFERRED_PLAY = 0x03;
|
Chris@301
|
71 static const MIDIByte MIDI_MMC_FAST_FORWARD = 0x04;
|
Chris@301
|
72 static const MIDIByte MIDI_MMC_REWIND = 0x05;
|
Chris@301
|
73 static const MIDIByte MIDI_MMC_RECORD_STROBE = 0x06;
|
Chris@301
|
74 static const MIDIByte MIDI_MMC_RECORD_EXIT = 0x07;
|
Chris@301
|
75 static const MIDIByte MIDI_MMC_RECORD_PAUSE = 0x08;
|
Chris@301
|
76 static const MIDIByte MIDI_MMC_PAUSE = 0x08;
|
Chris@301
|
77 static const MIDIByte MIDI_MMC_EJECT = 0x0A;
|
Chris@301
|
78 static const MIDIByte MIDI_MMC_LOCATE = 0x44;
|
Chris@301
|
79 static const MIDIByte MIDI_FILE_META_EVENT = 0xFF;
|
Chris@301
|
80 static const MIDIByte MIDI_SEQUENCE_NUMBER = 0x00;
|
Chris@301
|
81 static const MIDIByte MIDI_TEXT_EVENT = 0x01;
|
Chris@301
|
82 static const MIDIByte MIDI_COPYRIGHT_NOTICE = 0x02;
|
Chris@301
|
83 static const MIDIByte MIDI_TRACK_NAME = 0x03;
|
Chris@301
|
84 static const MIDIByte MIDI_INSTRUMENT_NAME = 0x04;
|
Chris@301
|
85 static const MIDIByte MIDI_LYRIC = 0x05;
|
Chris@301
|
86 static const MIDIByte MIDI_TEXT_MARKER = 0x06;
|
Chris@301
|
87 static const MIDIByte MIDI_CUE_POINT = 0x07;
|
Chris@301
|
88 static const MIDIByte MIDI_CHANNEL_PREFIX = 0x20;
|
Chris@301
|
89 static const MIDIByte MIDI_CHANNEL_PREFIX_OR_PORT = 0x21;
|
Chris@301
|
90 static const MIDIByte MIDI_END_OF_TRACK = 0x2F;
|
Chris@301
|
91 static const MIDIByte MIDI_SET_TEMPO = 0x51;
|
Chris@301
|
92 static const MIDIByte MIDI_SMPTE_OFFSET = 0x54;
|
Chris@301
|
93 static const MIDIByte MIDI_TIME_SIGNATURE = 0x58;
|
Chris@301
|
94 static const MIDIByte MIDI_KEY_SIGNATURE = 0x59;
|
Chris@301
|
95 static const MIDIByte MIDI_SEQUENCER_SPECIFIC = 0x7F;
|
Chris@301
|
96 static const MIDIByte MIDI_CONTROLLER_BANK_MSB = 0x00;
|
Chris@301
|
97 static const MIDIByte MIDI_CONTROLLER_VOLUME = 0x07;
|
Chris@301
|
98 static const MIDIByte MIDI_CONTROLLER_BANK_LSB = 0x20;
|
Chris@301
|
99 static const MIDIByte MIDI_CONTROLLER_MODULATION = 0x01;
|
Chris@301
|
100 static const MIDIByte MIDI_CONTROLLER_PAN = 0x0A;
|
Chris@301
|
101 static const MIDIByte MIDI_CONTROLLER_SUSTAIN = 0x40;
|
Chris@301
|
102 static const MIDIByte MIDI_CONTROLLER_RESONANCE = 0x47;
|
Chris@301
|
103 static const MIDIByte MIDI_CONTROLLER_RELEASE = 0x48;
|
Chris@301
|
104 static const MIDIByte MIDI_CONTROLLER_ATTACK = 0x49;
|
Chris@301
|
105 static const MIDIByte MIDI_CONTROLLER_FILTER = 0x4A;
|
Chris@301
|
106 static const MIDIByte MIDI_CONTROLLER_REVERB = 0x5B;
|
Chris@301
|
107 static const MIDIByte MIDI_CONTROLLER_CHORUS = 0x5D;
|
Chris@301
|
108 static const MIDIByte MIDI_CONTROLLER_NRPN_1 = 0x62;
|
Chris@301
|
109 static const MIDIByte MIDI_CONTROLLER_NRPN_2 = 0x63;
|
Chris@301
|
110 static const MIDIByte MIDI_CONTROLLER_RPN_1 = 0x64;
|
Chris@301
|
111 static const MIDIByte MIDI_CONTROLLER_RPN_2 = 0x65;
|
Chris@301
|
112 static const MIDIByte MIDI_CONTROLLER_SOUNDS_OFF = 0x78;
|
Chris@301
|
113 static const MIDIByte MIDI_CONTROLLER_RESET = 0x79;
|
Chris@301
|
114 static const MIDIByte MIDI_CONTROLLER_LOCAL = 0x7A;
|
Chris@301
|
115 static const MIDIByte MIDI_CONTROLLER_ALL_NOTES_OFF = 0x7B;
|
Chris@301
|
116 static const MIDIByte MIDI_PERCUSSION_CHANNEL = 9;
|
Chris@301
|
117 }
|
Chris@301
|
118
|
Chris@301
|
119 class MIDIEvent
|
Chris@301
|
120 {
|
Chris@301
|
121 public:
|
Chris@301
|
122 MIDIEvent(unsigned long deltaTime,
|
Chris@1038
|
123 int eventCode,
|
Chris@1038
|
124 int data1 = 0,
|
Chris@1038
|
125 int data2 = 0) :
|
Chris@1429
|
126 m_deltaTime(deltaTime),
|
Chris@1429
|
127 m_duration(0),
|
Chris@1429
|
128 m_metaEventCode(0)
|
Chris@1038
|
129 {
|
Chris@1038
|
130 if (eventCode < 0 || eventCode > 0xff ||
|
Chris@1038
|
131 data1 < 0 || data1 > 0xff ||
|
Chris@1038
|
132 data2 < 0 || data2 > 0xff) {
|
Chris@1038
|
133 throw std::domain_error("not all args within byte range");
|
Chris@1038
|
134 }
|
Chris@1038
|
135 m_eventCode = MIDIByte(eventCode);
|
Chris@1038
|
136 m_data1 = MIDIByte(data1);
|
Chris@1038
|
137 m_data2 = MIDIByte(data2);
|
Chris@1038
|
138 }
|
Chris@301
|
139
|
Chris@301
|
140 MIDIEvent(unsigned long deltaTime,
|
Chris@301
|
141 MIDIByte eventCode,
|
Chris@301
|
142 MIDIByte metaEventCode,
|
Chris@301
|
143 const std::string &metaMessage) :
|
Chris@1429
|
144 m_deltaTime(deltaTime),
|
Chris@1429
|
145 m_duration(0),
|
Chris@1429
|
146 m_eventCode(eventCode),
|
Chris@1429
|
147 m_data1(0),
|
Chris@1429
|
148 m_data2(0),
|
Chris@1429
|
149 m_metaEventCode(metaEventCode),
|
Chris@1429
|
150 m_metaMessage(metaMessage)
|
Chris@301
|
151 { }
|
Chris@301
|
152
|
Chris@301
|
153 MIDIEvent(unsigned long deltaTime,
|
Chris@301
|
154 MIDIByte eventCode,
|
Chris@301
|
155 const std::string &sysEx) :
|
Chris@1429
|
156 m_deltaTime(deltaTime),
|
Chris@1429
|
157 m_duration(0),
|
Chris@1429
|
158 m_eventCode(eventCode),
|
Chris@1429
|
159 m_data1(0),
|
Chris@1429
|
160 m_data2(0),
|
Chris@1429
|
161 m_metaEventCode(0),
|
Chris@1429
|
162 m_metaMessage(sysEx)
|
Chris@301
|
163 { }
|
Chris@301
|
164
|
Chris@1733
|
165 MIDIEvent(const MIDIEvent &) =default;
|
Chris@1733
|
166 MIDIEvent& operator=(const MIDIEvent &) =default;
|
Chris@1733
|
167
|
Chris@301
|
168 ~MIDIEvent() { }
|
Chris@301
|
169
|
Chris@301
|
170 void setTime(const unsigned long &time) { m_deltaTime = time; }
|
Chris@301
|
171 void setDuration(const unsigned long& duration) { m_duration = duration;}
|
Chris@301
|
172 unsigned long addTime(const unsigned long &time) {
|
Chris@1429
|
173 m_deltaTime += time;
|
Chris@1429
|
174 return m_deltaTime;
|
Chris@301
|
175 }
|
Chris@301
|
176
|
Chris@301
|
177 MIDIByte getMessageType() const
|
Chris@301
|
178 { return (m_eventCode & MIDIConstants::MIDI_MESSAGE_TYPE_MASK); }
|
Chris@301
|
179
|
Chris@301
|
180 MIDIByte getChannelNumber() const
|
Chris@301
|
181 { return (m_eventCode & MIDIConstants::MIDI_CHANNEL_NUM_MASK); }
|
Chris@301
|
182
|
Chris@301
|
183 unsigned long getTime() const { return m_deltaTime; }
|
Chris@301
|
184 unsigned long getDuration() const { return m_duration; }
|
Chris@301
|
185
|
Chris@301
|
186 MIDIByte getPitch() const { return m_data1; }
|
Chris@301
|
187 MIDIByte getVelocity() const { return m_data2; }
|
Chris@301
|
188 MIDIByte getData1() const { return m_data1; }
|
Chris@301
|
189 MIDIByte getData2() const { return m_data2; }
|
Chris@301
|
190 MIDIByte getEventCode() const { return m_eventCode; }
|
Chris@301
|
191
|
Chris@301
|
192 bool isMeta() const { return (m_eventCode == MIDIConstants::MIDI_FILE_META_EVENT); }
|
Chris@301
|
193
|
Chris@301
|
194 MIDIByte getMetaEventCode() const { return m_metaEventCode; }
|
Chris@301
|
195 std::string getMetaMessage() const { return m_metaMessage; }
|
Chris@301
|
196 void setMetaMessage(const std::string &meta) { m_metaMessage = meta; }
|
Chris@301
|
197
|
Chris@301
|
198 friend bool operator<(const MIDIEvent &a, const MIDIEvent &b);
|
Chris@301
|
199
|
Chris@301
|
200 private:
|
Chris@301
|
201 unsigned long m_deltaTime;
|
Chris@301
|
202 unsigned long m_duration;
|
Chris@301
|
203 MIDIByte m_eventCode;
|
Chris@301
|
204 MIDIByte m_data1; // or Note
|
Chris@301
|
205 MIDIByte m_data2; // or Velocity
|
Chris@301
|
206 MIDIByte m_metaEventCode;
|
Chris@301
|
207 std::string m_metaMessage;
|
Chris@301
|
208 };
|
Chris@301
|
209
|
Chris@301
|
210 // Comparator for sorting
|
Chris@301
|
211 //
|
Chris@301
|
212 struct MIDIEventCmp
|
Chris@301
|
213 {
|
Chris@301
|
214 bool operator()(const MIDIEvent &mE1, const MIDIEvent &mE2) const
|
Chris@301
|
215 { return mE1.getTime() < mE2.getTime(); }
|
Chris@301
|
216
|
Chris@301
|
217 bool operator()(const MIDIEvent *mE1, const MIDIEvent *mE2) const
|
Chris@301
|
218 { return mE1->getTime() < mE2->getTime(); }
|
Chris@301
|
219 };
|
Chris@301
|
220
|
Chris@301
|
221 class MIDIException : virtual public std::exception
|
Chris@301
|
222 {
|
Chris@301
|
223 public:
|
Chris@301
|
224 MIDIException(QString message) throw() : m_message(message) {
|
Chris@301
|
225 std::cerr << "WARNING: MIDI exception: "
|
Chris@1429
|
226 << message.toLocal8Bit().data() << std::endl;
|
Chris@301
|
227 }
|
Chris@301
|
228 virtual ~MIDIException() throw() { }
|
Chris@301
|
229
|
Chris@1580
|
230 const char *what() const throw() override {
|
Chris@1429
|
231 return m_message.toLocal8Bit().data();
|
Chris@301
|
232 }
|
Chris@301
|
233
|
Chris@301
|
234 protected:
|
Chris@301
|
235 QString m_message;
|
Chris@301
|
236 };
|
Chris@301
|
237
|
Chris@301
|
238 #endif
|