comparison hackday/CannamMidiFileLoader.cpp @ 24:5a11b19906c7

hackday code is added.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Sat, 03 Dec 2011 17:19:43 +0000
parents
children 2a025ea7c793
comparison
equal deleted inserted replaced
23:032edf186a68 24:5a11b19906c7
1 /*
2 * CannamMidiFileLoader.cpp
3 * midi-score-follower
4 *
5 * Created by Andrew on 19/08/2011.
6 * Copyright 2011 QMUL. All rights reserved.
7 *
8 */
9
10 #include "MIDIFileReader.h"
11 #include "CannamMidiFileLoader.h"
12
13 CannamMidiFileLoader::CannamMidiFileLoader(){
14 chopBeginning = true;
15 }
16
17 int CannamMidiFileLoader::loadFile(std::string& filename, midiEventHolder& myMidiEvents){
18
19 noteOnIndex = 0;
20 myMidiEvents.clearAllEvents();
21
22 setTempoFromMidiValue(500000, myMidiEvents);//default is 120bpm
23 myMidiEvents.pulsesPerQuarternote = 240;//default
24
25 //int main(int argc, char **argv)
26 //{
27 // if (argc != 2) {
28 // cerr << "Usage: midifile <file.mid>" << endl;
29 // return 1;
30 // }
31
32 // std::string filename = midiFileName;//argv[1];
33
34 MIDIFileReader fr(filename);
35
36 if (!fr.isOK()) {
37 std::cerr << "Error: " << fr.getError().c_str() << std::endl;
38 return 1;
39 }
40
41 MIDIComposition c = fr.load();
42
43 switch (fr.getFormat()) {
44 case MIDI_SINGLE_TRACK_FILE: cout << "Format: MIDI Single Track File" << endl; break;
45 case MIDI_SIMULTANEOUS_TRACK_FILE: cout << "Format: MIDI Simultaneous Track File" << endl; break;
46 case MIDI_SEQUENTIAL_TRACK_FILE: cout << "Format: MIDI Sequential Track File" << endl; break;
47 default: cout << "Format: Unknown MIDI file format?" << endl; break;
48 }
49
50 cout << "Tracks: " << c.size() << endl;
51
52 int td = fr.getTimingDivision();
53 if (td < 32768) {
54 if (printMidiInfo)
55 cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl;
56 myMidiEvents.pulsesPerQuarternote = fr.getTimingDivision();
57 } else {
58 int frames = 256 - (td >> 8);
59 int subframes = td & 0xff;
60 if (printMidiInfo)
61 cout << "SMPTE timing: " << frames << " fps, " << subframes << " subframes" << endl;
62 }
63
64 for (MIDIComposition::const_iterator i = c.begin(); i != c.end(); ++i) {
65 if (printMidiInfo)
66 cout << "Start of track: " << i->first+1 << endl;
67
68 for (MIDITrack::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
69
70 unsigned int t = j->getTime();
71 int ch = j->getChannelNumber();
72
73 if (j->isMeta()) {
74 int code = j->getMetaEventCode();
75 string name;
76 bool printable = true;
77 switch (code) {
78
79 case MIDI_END_OF_TRACK:
80 cout << t << ": End of track" << endl;
81 break;
82
83 case MIDI_TEXT_EVENT: name = "Text"; break;
84 case MIDI_COPYRIGHT_NOTICE: name = "Copyright"; break;
85 case MIDI_TRACK_NAME: name = "Track name"; break;
86 case MIDI_INSTRUMENT_NAME: name = "Instrument name"; break;
87 case MIDI_LYRIC: name = "Lyric"; break;
88 case MIDI_TEXT_MARKER: name = "Text marker"; break;
89 case MIDI_SEQUENCE_NUMBER: name = "Sequence number"; printable = false; break;
90 case MIDI_CHANNEL_PREFIX_OR_PORT: name = "Channel prefix or port"; printable = false; break;
91 case MIDI_CUE_POINT: name = "Cue point"; break;
92 case MIDI_CHANNEL_PREFIX: name = "Channel prefix"; printable = false; break;
93 case MIDI_SEQUENCER_SPECIFIC: name = "Sequencer specific"; printable = false; break;
94 case MIDI_SMPTE_OFFSET: name = "SMPTE offset"; printable = false; break;
95
96 case MIDI_SET_TEMPO:
97 {
98 int m0 = j->getMetaMessage()[0];
99 int m1 = j->getMetaMessage()[1];
100 int m2 = j->getMetaMessage()[2];
101 long tempo = (((m0 << 8) + m1) << 8) + m2;
102 if (printMidiInfo)
103 cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl;
104 setTempoFromMidiValue(tempo, myMidiEvents);
105
106
107 printf("period double is %f\n", myMidiEvents.period);
108 }
109 break;
110
111 case MIDI_TIME_SIGNATURE:
112 {
113 int numerator = j->getMetaMessage()[0];
114 int denominator = 1 << (int)j->getMetaMessage()[1];
115 if (printMidiInfo)
116 cout << t << ": Time signature: " << numerator << "/" << denominator << endl;
117 }
118
119 case MIDI_KEY_SIGNATURE:
120 {
121 int accidentals = j->getMetaMessage()[0];
122 int isMinor = j->getMetaMessage()[1];
123 bool isSharp = accidentals < 0 ? false : true;
124 accidentals = accidentals < 0 ? -accidentals : accidentals;
125 if (printMidiInfo)
126 cout << t << ": Key signature: " << accidentals << " "
127 << (isSharp ?
128 (accidentals > 1 ? "sharps" : "sharp") :
129 (accidentals > 1 ? "flats" : "flat"))
130 << (isMinor ? ", minor" : ", major") << endl;
131 }
132
133 }
134
135
136 if (name != "") {
137 if (printable) {
138 cout << t << ": File meta event: code " << code
139 << ": " << name << ": \"" << j->getMetaMessage()
140 << "\"" << endl;
141 } else {
142 cout << t << ": File meta event: code " << code
143 << ": " << name << ": ";
144 for (int k = 0; k < j->getMetaMessage().length(); ++k) {
145 cout << (int)j->getMetaMessage()[k] << " ";
146 }
147 }
148 }
149 continue;
150 }
151
152 switch (j->getMessageType()) {
153
154 case MIDI_NOTE_ON:
155 if (printMidiInfo)
156 cout << t << ": Note: channel " << ch
157 << " duration " << j->getDuration()
158 << " pitch " << j->getPitch()
159 << " velocity " << j->getVelocity()
160 << "event time " << myMidiEvents.getEventTimeMillis(t) << endl;
161
162
163 if (noteOnIndex == 0){
164 firstTickTime = t;
165 }
166
167 noteOnIndex++;
168
169 v.clear();
170
171 if (!chopBeginning)
172 v.push_back(t);
173 else
174 v.push_back(t - firstTickTime);
175
176 v.push_back(j->getPitch());
177 v.push_back(j->getVelocity());
178 v.push_back(j->getDuration());
179 myMidiEvents.recordedNoteOnMatrix.push_back(v);
180
181 myMidiEvents.noteOnMatches.push_back(false);
182
183 break;
184
185 case MIDI_POLY_AFTERTOUCH:
186 if (printMidiInfo)
187 cout << t << ": Polyphonic aftertouch: channel " << ch
188 << " pitch " << j->getPitch()
189 << " pressure " << j->getData2() << endl;
190 break;
191
192 case MIDI_CTRL_CHANGE:
193 {
194 int controller = j->getData1();
195 string name;
196 switch (controller) {
197 case MIDI_CONTROLLER_BANK_MSB: name = "Bank select MSB"; break;
198 case MIDI_CONTROLLER_VOLUME: name = "Volume"; break;
199 case MIDI_CONTROLLER_BANK_LSB: name = "Bank select LSB"; break;
200 case MIDI_CONTROLLER_MODULATION: name = "Modulation wheel"; break;
201 case MIDI_CONTROLLER_PAN: name = "Pan"; break;
202 case MIDI_CONTROLLER_SUSTAIN: name = "Sustain"; break;
203 case MIDI_CONTROLLER_RESONANCE: name = "Resonance"; break;
204 case MIDI_CONTROLLER_RELEASE: name = "Release"; break;
205 case MIDI_CONTROLLER_ATTACK: name = "Attack"; break;
206 case MIDI_CONTROLLER_FILTER: name = "Filter"; break;
207 case MIDI_CONTROLLER_REVERB: name = "Reverb"; break;
208 case MIDI_CONTROLLER_CHORUS: name = "Chorus"; break;
209 case MIDI_CONTROLLER_NRPN_1: name = "NRPN 1"; break;
210 case MIDI_CONTROLLER_NRPN_2: name = "NRPN 2"; break;
211 case MIDI_CONTROLLER_RPN_1: name = "RPN 1"; break;
212 case MIDI_CONTROLLER_RPN_2: name = "RPN 2"; break;
213 case MIDI_CONTROLLER_SOUNDS_OFF: name = "All sounds off"; break;
214 case MIDI_CONTROLLER_RESET: name = "Reset"; break;
215 case MIDI_CONTROLLER_LOCAL: name = "Local"; break;
216 case MIDI_CONTROLLER_ALL_NOTES_OFF: name = "All notes off"; break;
217 }
218 if (printMidiInfo)
219 cout << t << ": Controller change: channel " << ch
220 << " controller " << j->getData1();
221 if (name != "") cout << " (" << name << ")";
222 cout << " value " << j->getData2() << endl;
223 }
224 break;
225
226 case MIDI_PROG_CHANGE:
227 if (printMidiInfo)
228 cout << t << ": Program change: channel " << ch
229 << " program " << j->getData1() << endl;
230 break;
231
232 case MIDI_CHNL_AFTERTOUCH:
233 if (printMidiInfo)
234 cout << t << ": Channel aftertouch: channel " << ch
235 << " pressure " << j->getData1() << endl;
236 break;
237
238 case MIDI_PITCH_BEND:
239 if (printMidiInfo)
240 cout << t << ": Pitch bend: channel " << ch
241 << " value " << (int)j->getData2() * 128 + (int)j->getData1() << endl;
242 break;
243
244 case MIDI_SYSTEM_EXCLUSIVE:
245 if (printMidiInfo)
246 cout << t << ": System exclusive: code "
247 << (int)j->getMessageType() << " message length " <<
248 j->getMetaMessage().length() << endl;
249 break;
250
251
252 }
253
254
255 }
256
257
258 }
259 if (printMidiInfo)
260 myMidiEvents.printRecordedEvents();
261
262 // printf("|||||||||||||||||||||| \n\n\n\n\n\n\n");
263 myMidiEvents.reorderMatrixFromNoteTimes(myMidiEvents.recordedNoteOnMatrix);
264 myMidiEvents.correctTiming(myMidiEvents.recordedNoteOnMatrix);
265 myMidiEvents.doublecheckOrder(myMidiEvents.recordedNoteOnMatrix);
266
267 createEventTiming(myMidiEvents);
268
269 if (printMidiInfo)
270 myMidiEvents.printRecordedEvents();
271
272 }//end cannam midi main
273
274
275 void CannamMidiFileLoader::createEventTiming( midiEventHolder& myMidiEvents){
276
277 long t;
278 t = myMidiEvents.recordedNoteOnMatrix[0][0];
279 firstNoteTime = myMidiEvents.getEventTimeMillis(t);
280
281 for (int i = 0; i < myMidiEvents.recordedNoteOnMatrix.size();i++){
282 t = myMidiEvents.recordedNoteOnMatrix[i][0];
283
284 if (!chopBeginning)
285 myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t));
286 else {
287 myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t) - firstNoteTime);
288
289 }
290 }
291
292 }
293
294 void CannamMidiFileLoader::setTempoFromMidiValue(long tempo, midiEventHolder& myMidiEvents){
295 myMidiEvents.tempo = 60000000.0 / double(tempo);
296 myMidiEvents.period = double(tempo)/1000.0;
297 myMidiEvents.ticksFactor = myMidiEvents.pulsesPerQuarternote / myMidiEvents.period;
298 }
299
300
301