annotate hackday/CannamMidiFileLoader.cpp @ 36:5a1b0c6fa1fb

Added class to read in the csv Annotation file, then write out the respective difference between the performed piece as followed here, and the annotation of RWC by Ewert and Muller
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 15 Dec 2011 02:28:49 +0000
parents 9a70d9abdc8b
children
rev   line source
andrew@24 1 /*
andrew@24 2 * CannamMidiFileLoader.cpp
andrew@24 3 * midi-score-follower
andrew@24 4 *
andrew@24 5 * Created by Andrew on 19/08/2011.
andrew@24 6 * Copyright 2011 QMUL. All rights reserved.
andrew@24 7 *
andrew@24 8 */
andrew@24 9
andrew@24 10 #include "MIDIFileReader.h"
andrew@24 11 #include "CannamMidiFileLoader.h"
andrew@24 12
andrew@24 13 CannamMidiFileLoader::CannamMidiFileLoader(){
andrew@24 14 chopBeginning = true;
andrew@31 15 firstTickTime = 0;
andrew@24 16 }
andrew@24 17
andrew@24 18 int CannamMidiFileLoader::loadFile(std::string& filename, midiEventHolder& myMidiEvents){
andrew@24 19
andrew@24 20 noteOnIndex = 0;
andrew@31 21 firstTickTime = 0;
andrew@24 22 myMidiEvents.clearAllEvents();
andrew@24 23
andrew@31 24
andrew@24 25 setTempoFromMidiValue(500000, myMidiEvents);//default is 120bpm
andrew@24 26 myMidiEvents.pulsesPerQuarternote = 240;//default
andrew@31 27 //myMidiEvents.measureVector.push_back(0);
andrew@24 28 //int main(int argc, char **argv)
andrew@24 29 //{
andrew@24 30 // if (argc != 2) {
andrew@24 31 // cerr << "Usage: midifile <file.mid>" << endl;
andrew@24 32 // return 1;
andrew@24 33 // }
andrew@24 34
andrew@24 35 // std::string filename = midiFileName;//argv[1];
andrew@24 36
andrew@24 37 MIDIFileReader fr(filename);
andrew@24 38
andrew@24 39 if (!fr.isOK()) {
andrew@24 40 std::cerr << "Error: " << fr.getError().c_str() << std::endl;
andrew@24 41 return 1;
andrew@24 42 }
andrew@24 43
andrew@24 44 MIDIComposition c = fr.load();
andrew@24 45
andrew@24 46 switch (fr.getFormat()) {
andrew@24 47 case MIDI_SINGLE_TRACK_FILE: cout << "Format: MIDI Single Track File" << endl; break;
andrew@24 48 case MIDI_SIMULTANEOUS_TRACK_FILE: cout << "Format: MIDI Simultaneous Track File" << endl; break;
andrew@24 49 case MIDI_SEQUENTIAL_TRACK_FILE: cout << "Format: MIDI Sequential Track File" << endl; break;
andrew@24 50 default: cout << "Format: Unknown MIDI file format?" << endl; break;
andrew@24 51 }
andrew@24 52
andrew@24 53 cout << "Tracks: " << c.size() << endl;
andrew@24 54
andrew@24 55 int td = fr.getTimingDivision();
andrew@24 56 if (td < 32768) {
andrew@24 57 if (printMidiInfo)
andrew@24 58 cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl;
andrew@24 59 myMidiEvents.pulsesPerQuarternote = fr.getTimingDivision();
andrew@25 60 ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4;//default setting
andrew@25 61
andrew@24 62 } else {
andrew@24 63 int frames = 256 - (td >> 8);
andrew@24 64 int subframes = td & 0xff;
andrew@24 65 if (printMidiInfo)
andrew@24 66 cout << "SMPTE timing: " << frames << " fps, " << subframes << " subframes" << endl;
andrew@24 67 }
andrew@24 68
andrew@24 69 for (MIDIComposition::const_iterator i = c.begin(); i != c.end(); ++i) {
andrew@24 70 if (printMidiInfo)
andrew@24 71 cout << "Start of track: " << i->first+1 << endl;
andrew@24 72
andrew@24 73 for (MIDITrack::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
andrew@24 74
andrew@24 75 unsigned int t = j->getTime();
andrew@24 76 int ch = j->getChannelNumber();
andrew@24 77
andrew@24 78 if (j->isMeta()) {
andrew@24 79 int code = j->getMetaEventCode();
andrew@24 80 string name;
andrew@24 81 bool printable = true;
andrew@24 82 switch (code) {
andrew@24 83
andrew@24 84 case MIDI_END_OF_TRACK:
andrew@24 85 cout << t << ": End of track" << endl;
andrew@24 86 break;
andrew@24 87
andrew@24 88 case MIDI_TEXT_EVENT: name = "Text"; break;
andrew@24 89 case MIDI_COPYRIGHT_NOTICE: name = "Copyright"; break;
andrew@24 90 case MIDI_TRACK_NAME: name = "Track name"; break;
andrew@24 91 case MIDI_INSTRUMENT_NAME: name = "Instrument name"; break;
andrew@24 92 case MIDI_LYRIC: name = "Lyric"; break;
andrew@24 93 case MIDI_TEXT_MARKER: name = "Text marker"; break;
andrew@24 94 case MIDI_SEQUENCE_NUMBER: name = "Sequence number"; printable = false; break;
andrew@24 95 case MIDI_CHANNEL_PREFIX_OR_PORT: name = "Channel prefix or port"; printable = false; break;
andrew@24 96 case MIDI_CUE_POINT: name = "Cue point"; break;
andrew@24 97 case MIDI_CHANNEL_PREFIX: name = "Channel prefix"; printable = false; break;
andrew@24 98 case MIDI_SEQUENCER_SPECIFIC: name = "Sequencer specific"; printable = false; break;
andrew@24 99 case MIDI_SMPTE_OFFSET: name = "SMPTE offset"; printable = false; break;
andrew@24 100
andrew@24 101 case MIDI_SET_TEMPO:
andrew@24 102 {
andrew@24 103 int m0 = j->getMetaMessage()[0];
andrew@24 104 int m1 = j->getMetaMessage()[1];
andrew@24 105 int m2 = j->getMetaMessage()[2];
andrew@24 106 long tempo = (((m0 << 8) + m1) << 8) + m2;
andrew@31 107 //if (printMidiInfo)
andrew@24 108 cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl;
andrew@24 109 setTempoFromMidiValue(tempo, myMidiEvents);
andrew@31 110 DoubleVector tmp;
andrew@31 111
andrew@31 112
andrew@31 113 double lastTickInMillis = 0;
andrew@31 114 double millisTimeNow = lastTickInMillis;
andrew@31 115 int tickInterval = 0;
andrew@31 116 if (myMidiEvents.periodValues.size() > 0){
andrew@31 117 lastTickInMillis = myMidiEvents.periodValues[myMidiEvents.periodValues.size()-1][2];
andrew@31 118 tickInterval = (t - firstTickTime) - myMidiEvents.periodValues[myMidiEvents.periodValues.size()-1][0];
andrew@31 119 millisTimeNow = lastTickInMillis + (myMidiEvents.periodValues[myMidiEvents.periodValues.size()-1][1]*tickInterval);
andrew@31 120
andrew@31 121 }
andrew@31 122
andrew@31 123 if (!chopBeginning)
andrew@31 124 tmp.push_back(t);
andrew@31 125 else
andrew@31 126 tmp.push_back(t - firstTickTime);
andrew@31 127
andrew@31 128 tmp.push_back(60000000.0 / double(tempo));
andrew@31 129 tmp.push_back(millisTimeNow);
andrew@31 130 myMidiEvents.periodValues.push_back(tmp);
andrew@31 131
andrew@31 132 printf("tick[%i]: TEMPO period %f : time now %f\n", t, 60000000.0 / double(tempo), millisTimeNow);
andrew@31 133 //printf("period double is %f\n", myMidiEvents.period);
andrew@25 134
andrew@24 135 }
andrew@24 136 break;
andrew@24 137
andrew@24 138 case MIDI_TIME_SIGNATURE:
andrew@24 139 {
andrew@24 140 int numerator = j->getMetaMessage()[0];
andrew@24 141 int denominator = 1 << (int)j->getMetaMessage()[1];
andrew@25 142
andrew@25 143 newTimeSignature(t, numerator, denominator, myMidiEvents);
andrew@25 144
andrew@25 145 //if (printMidiInfo)
andrew@24 146 cout << t << ": Time signature: " << numerator << "/" << denominator << endl;
andrew@31 147 printf(" ticks %i Time signature: %i by %i \n", t, numerator , denominator );
andrew@24 148 }
andrew@24 149
andrew@24 150 case MIDI_KEY_SIGNATURE:
andrew@24 151 {
andrew@24 152 int accidentals = j->getMetaMessage()[0];
andrew@24 153 int isMinor = j->getMetaMessage()[1];
andrew@24 154 bool isSharp = accidentals < 0 ? false : true;
andrew@24 155 accidentals = accidentals < 0 ? -accidentals : accidentals;
andrew@24 156 if (printMidiInfo)
andrew@24 157 cout << t << ": Key signature: " << accidentals << " "
andrew@24 158 << (isSharp ?
andrew@24 159 (accidentals > 1 ? "sharps" : "sharp") :
andrew@24 160 (accidentals > 1 ? "flats" : "flat"))
andrew@24 161 << (isMinor ? ", minor" : ", major") << endl;
andrew@24 162 }
andrew@24 163
andrew@24 164 }
andrew@24 165
andrew@24 166
andrew@24 167 if (name != "") {
andrew@24 168 if (printable) {
andrew@24 169 cout << t << ": File meta event: code " << code
andrew@24 170 << ": " << name << ": \"" << j->getMetaMessage()
andrew@24 171 << "\"" << endl;
andrew@24 172 } else {
andrew@24 173 cout << t << ": File meta event: code " << code
andrew@24 174 << ": " << name << ": ";
andrew@24 175 for (int k = 0; k < j->getMetaMessage().length(); ++k) {
andrew@24 176 cout << (int)j->getMetaMessage()[k] << " ";
andrew@24 177 }
andrew@24 178 }
andrew@24 179 }
andrew@24 180 continue;
andrew@24 181 }
andrew@24 182
andrew@24 183 switch (j->getMessageType()) {
andrew@24 184
andrew@24 185 case MIDI_NOTE_ON:
andrew@24 186 if (printMidiInfo)
andrew@24 187 cout << t << ": Note: channel " << ch
andrew@24 188 << " duration " << j->getDuration()
andrew@24 189 << " pitch " << j->getPitch()
andrew@24 190 << " velocity " << j->getVelocity()
andrew@24 191 << "event time " << myMidiEvents.getEventTimeMillis(t) << endl;
andrew@24 192
andrew@24 193
andrew@31 194 if (noteOnIndex == 0 || t < firstTickTime){
andrew@31 195 //easier just to pick the minimum
andrew@24 196 firstTickTime = t;
andrew@31 197 printf("FIRST TICK TIME %i\n", firstTickTime);
andrew@24 198 }
andrew@24 199
andrew@24 200 noteOnIndex++;
andrew@24 201
andrew@24 202 v.clear();
andrew@24 203
andrew@31 204 // printf("note on at %i\n", t);
andrew@31 205
andrew@24 206 if (!chopBeginning)
andrew@24 207 v.push_back(t);
andrew@24 208 else
andrew@24 209 v.push_back(t - firstTickTime);
andrew@24 210
andrew@24 211 v.push_back(j->getPitch());
andrew@24 212 v.push_back(j->getVelocity());
andrew@24 213 v.push_back(j->getDuration());
andrew@24 214 myMidiEvents.recordedNoteOnMatrix.push_back(v);
andrew@24 215
andrew@24 216 myMidiEvents.noteOnMatches.push_back(false);
andrew@24 217
andrew@24 218 break;
andrew@24 219
andrew@24 220 case MIDI_POLY_AFTERTOUCH:
andrew@24 221 if (printMidiInfo)
andrew@24 222 cout << t << ": Polyphonic aftertouch: channel " << ch
andrew@24 223 << " pitch " << j->getPitch()
andrew@24 224 << " pressure " << j->getData2() << endl;
andrew@24 225 break;
andrew@24 226
andrew@24 227 case MIDI_CTRL_CHANGE:
andrew@24 228 {
andrew@24 229 int controller = j->getData1();
andrew@24 230 string name;
andrew@24 231 switch (controller) {
andrew@24 232 case MIDI_CONTROLLER_BANK_MSB: name = "Bank select MSB"; break;
andrew@24 233 case MIDI_CONTROLLER_VOLUME: name = "Volume"; break;
andrew@24 234 case MIDI_CONTROLLER_BANK_LSB: name = "Bank select LSB"; break;
andrew@24 235 case MIDI_CONTROLLER_MODULATION: name = "Modulation wheel"; break;
andrew@24 236 case MIDI_CONTROLLER_PAN: name = "Pan"; break;
andrew@24 237 case MIDI_CONTROLLER_SUSTAIN: name = "Sustain"; break;
andrew@24 238 case MIDI_CONTROLLER_RESONANCE: name = "Resonance"; break;
andrew@24 239 case MIDI_CONTROLLER_RELEASE: name = "Release"; break;
andrew@24 240 case MIDI_CONTROLLER_ATTACK: name = "Attack"; break;
andrew@24 241 case MIDI_CONTROLLER_FILTER: name = "Filter"; break;
andrew@24 242 case MIDI_CONTROLLER_REVERB: name = "Reverb"; break;
andrew@24 243 case MIDI_CONTROLLER_CHORUS: name = "Chorus"; break;
andrew@24 244 case MIDI_CONTROLLER_NRPN_1: name = "NRPN 1"; break;
andrew@24 245 case MIDI_CONTROLLER_NRPN_2: name = "NRPN 2"; break;
andrew@24 246 case MIDI_CONTROLLER_RPN_1: name = "RPN 1"; break;
andrew@24 247 case MIDI_CONTROLLER_RPN_2: name = "RPN 2"; break;
andrew@24 248 case MIDI_CONTROLLER_SOUNDS_OFF: name = "All sounds off"; break;
andrew@24 249 case MIDI_CONTROLLER_RESET: name = "Reset"; break;
andrew@24 250 case MIDI_CONTROLLER_LOCAL: name = "Local"; break;
andrew@24 251 case MIDI_CONTROLLER_ALL_NOTES_OFF: name = "All notes off"; break;
andrew@24 252 }
andrew@24 253 if (printMidiInfo)
andrew@24 254 cout << t << ": Controller change: channel " << ch
andrew@24 255 << " controller " << j->getData1();
andrew@24 256 if (name != "") cout << " (" << name << ")";
andrew@24 257 cout << " value " << j->getData2() << endl;
andrew@24 258 }
andrew@24 259 break;
andrew@24 260
andrew@24 261 case MIDI_PROG_CHANGE:
andrew@24 262 if (printMidiInfo)
andrew@24 263 cout << t << ": Program change: channel " << ch
andrew@24 264 << " program " << j->getData1() << endl;
andrew@24 265 break;
andrew@24 266
andrew@24 267 case MIDI_CHNL_AFTERTOUCH:
andrew@24 268 if (printMidiInfo)
andrew@24 269 cout << t << ": Channel aftertouch: channel " << ch
andrew@24 270 << " pressure " << j->getData1() << endl;
andrew@24 271 break;
andrew@24 272
andrew@24 273 case MIDI_PITCH_BEND:
andrew@24 274 if (printMidiInfo)
andrew@24 275 cout << t << ": Pitch bend: channel " << ch
andrew@24 276 << " value " << (int)j->getData2() * 128 + (int)j->getData1() << endl;
andrew@24 277 break;
andrew@24 278
andrew@24 279 case MIDI_SYSTEM_EXCLUSIVE:
andrew@24 280 if (printMidiInfo)
andrew@24 281 cout << t << ": System exclusive: code "
andrew@24 282 << (int)j->getMessageType() << " message length " <<
andrew@24 283 j->getMetaMessage().length() << endl;
andrew@24 284 break;
andrew@24 285
andrew@24 286
andrew@24 287 }
andrew@24 288
andrew@24 289
andrew@24 290 }
andrew@24 291
andrew@24 292
andrew@24 293 }
andrew@24 294 if (printMidiInfo)
andrew@24 295 myMidiEvents.printRecordedEvents();
andrew@24 296
andrew@25 297 //printMeasuresSoFar(myMidiEvents);
andrew@25 298
andrew@25 299 if (myMidiEvents.recordedNoteOnMatrix.size() > 0){
andrew@25 300
andrew@25 301 printf("END FILE MEASURE UPDATE\n");
andrew@25 302 updateMeasureToTickPosition(myMidiEvents.recordedNoteOnMatrix[myMidiEvents.recordedNoteOnMatrix.size()-1][0], myMidiEvents);
andrew@25 303 // printMeasuresSoFar(myMidiEvents);
andrew@25 304 }
andrew@25 305
andrew@24 306 // printf("|||||||||||||||||||||| \n\n\n\n\n\n\n");
andrew@24 307 myMidiEvents.reorderMatrixFromNoteTimes(myMidiEvents.recordedNoteOnMatrix);
andrew@24 308 myMidiEvents.correctTiming(myMidiEvents.recordedNoteOnMatrix);
andrew@24 309 myMidiEvents.doublecheckOrder(myMidiEvents.recordedNoteOnMatrix);
andrew@24 310
andrew@24 311 createEventTiming(myMidiEvents);
andrew@25 312
andrew@31 313 printf("BEFORE DOING MEASURE UPDATE\n first tick pos is %i\n", firstTickTime);
andrew@31 314 // printMeasuresSoFar(myMidiEvents);
andrew@31 315 if (chopBeginning)
andrew@31 316 correctMeasuresTiming(myMidiEvents);
andrew@31 317
andrew@24 318 if (printMidiInfo)
andrew@25 319 myMidiEvents.printRecordedEvents();
andrew@25 320
andrew@30 321 printf("Duration of MIDI file is %f \n", myMidiEvents.recordedEventTimes[myMidiEvents.recordedEventTimes.size()-1]);
andrew@30 322
andrew@25 323 //printMeasuresSoFar(myMidiEvents);
andrew@24 324
andrew@24 325 }//end cannam midi main
andrew@24 326
andrew@24 327
andrew@24 328 void CannamMidiFileLoader::createEventTiming( midiEventHolder& myMidiEvents){
andrew@24 329
andrew@24 330 long t;
andrew@24 331 t = myMidiEvents.recordedNoteOnMatrix[0][0];
andrew@24 332 firstNoteTime = myMidiEvents.getEventTimeMillis(t);
andrew@24 333
andrew@24 334 for (int i = 0; i < myMidiEvents.recordedNoteOnMatrix.size();i++){
andrew@24 335 t = myMidiEvents.recordedNoteOnMatrix[i][0];
andrew@24 336
andrew@24 337 if (!chopBeginning)
andrew@24 338 myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t));
andrew@24 339 else {
andrew@24 340 myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t) - firstNoteTime);
andrew@24 341
andrew@24 342 }
andrew@24 343 }
andrew@24 344
andrew@24 345 }
andrew@24 346
andrew@24 347 void CannamMidiFileLoader::setTempoFromMidiValue(long tempo, midiEventHolder& myMidiEvents){
andrew@24 348 myMidiEvents.tempo = 60000000.0 / double(tempo);
andrew@24 349 myMidiEvents.period = double(tempo)/1000.0;
andrew@24 350 myMidiEvents.ticksFactor = myMidiEvents.pulsesPerQuarternote / myMidiEvents.period;
andrew@24 351 }
andrew@24 352
andrew@24 353
andrew@25 354 void CannamMidiFileLoader::newTimeSignature(int ticks, int numerator, int denominator, midiEventHolder& myMidiEvents){
andrew@24 355
andrew@25 356 updateMeasureToTickPosition(ticks, myMidiEvents);
andrew@25 357
andrew@25 358 ticksPerMeasure = myMidiEvents.pulsesPerQuarternote * 4 * numerator / denominator;
andrew@25 359
andrew@25 360 }
andrew@25 361
andrew@25 362 void CannamMidiFileLoader::updateMeasureToTickPosition(int ticks, midiEventHolder& myMidiEvents){
andrew@25 363 printf("update measure at tick pos %i at tpm %i\n", ticks, ticksPerMeasure);
andrew@25 364
andrew@25 365 int measureVectorSize = myMidiEvents.measureVector.size();
andrew@25 366 int lastMeasurePosition = 0;
andrew@31 367 // if (chopBeginning)
andrew@31 368 // lastMeasurePosition = -1*firstTickTime;
andrew@25 369
andrew@25 370 if (measureVectorSize > 0)
andrew@25 371 lastMeasurePosition = myMidiEvents.measureVector[measureVectorSize-1];
andrew@31 372
andrew@25 373
andrew@25 374 while (lastMeasurePosition < ticks){
andrew@25 375 //update
andrew@25 376 lastMeasurePosition += ticksPerMeasure;
andrew@25 377 myMidiEvents.measureVector.push_back(lastMeasurePosition);
andrew@27 378 // cout << "MEASURE " << myMidiEvents.measureVector.size()-1 << " is " << lastMeasurePosition << endl;
andrew@27 379 // printf("MEASURE %i is %i \n", (int)myMidiEvents.measureVector.size()-1 , lastMeasurePosition);
andrew@25 380 }
andrew@25 381 }
andrew@25 382
andrew@25 383
andrew@31 384 void CannamMidiFileLoader::correctMeasuresTiming(midiEventHolder& myMidiEvents){
andrew@31 385 //correct measures
andrew@31 386 for (int i = 0;i <myMidiEvents.measureVector.size();i++){
andrew@31 387 myMidiEvents.measureVector[i] -= firstTickTime;
andrew@31 388 }
andrew@31 389 printf("AFTER DOING MEASURE UPDATE\n");
andrew@31 390 printMeasuresSoFar(myMidiEvents);
andrew@31 391 }
andrew@31 392
andrew@25 393 void CannamMidiFileLoader::printMeasuresSoFar(midiEventHolder& myMidiEvents){
andrew@25 394 for (int i = 0;i < myMidiEvents.measureVector.size();i++){
andrew@25 395 printf("measure [%i] at %i\n", i, myMidiEvents.measureVector[i]);
andrew@25 396 }
andrew@25 397 }