view src/CannamMidiFileLoader.cpp @ 5:195907bb8bb7

added purple where notes have been seen - lets you see what updates have been used. Also the chopping of midi files to the beginning was introduced recently, so when they load, you chop any white space at the beginning, then use first note to launch.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Fri, 19 Aug 2011 16:38:30 +0100
parents 4a8e6a6cd224
children df9c838d0b8f
line wrap: on
line source
/*
 *  CannamMidiFileLoader.cpp
 *  midi-score-follower
 *
 *  Created by Andrew on 19/08/2011.
 *  Copyright 2011 QMUL. All rights reserved.
 *
 */

#include "MIDIFileReader.h"
#include "CannamMidiFileLoader.h"

CannamMidiFileLoader::CannamMidiFileLoader(){
	chopBeginning = true;
}

int CannamMidiFileLoader::loadFile(std::string& filename, midiEventHolder& myMidiEvents){
		
		noteOnIndex = 0;
		myMidiEvents.clearAllEvents();
		
		//int main(int argc, char **argv)
		//{
		//	if (argc != 2) {
		//		cerr << "Usage: midifile <file.mid>" << endl;
		//		return 1;
		//	}
		
	//	std::string filename = midiFileName;//argv[1];
		
		MIDIFileReader fr(filename);
	
		if (!fr.isOK()) {
			std::cerr << "Error: " << fr.getError().c_str() << std::endl;
			return 1;
		}
		
		MIDIComposition c = fr.load();
		
		switch (fr.getFormat()) {
			case MIDI_SINGLE_TRACK_FILE: cout << "Format: MIDI Single Track File" << endl; break;
			case MIDI_SIMULTANEOUS_TRACK_FILE: cout << "Format: MIDI Simultaneous Track File" << endl; break;
			case MIDI_SEQUENTIAL_TRACK_FILE: cout << "Format: MIDI Sequential Track File" << endl; break;
			default: cout << "Format: Unknown MIDI file format?" << endl; break;
		}
		
		cout << "Tracks: " << c.size() << endl;
		
		int td = fr.getTimingDivision();
		if (td < 32768) {
			cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl;
			
			myMidiEvents.pulsesPerQuarternote = fr.getTimingDivision();
		} else {
			int frames = 256 - (td >> 8);
			int subframes = td & 0xff;
			cout << "SMPTE timing: " << frames << " fps, " << subframes << " subframes" << endl;
		}
		
		for (MIDIComposition::const_iterator i = c.begin(); i != c.end(); ++i) {
			
			cout << "Start of track: " << i->first+1 << endl;
			
			for (MIDITrack::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
				
				unsigned int t = j->getTime();
				int ch = j->getChannelNumber();
				
				if (j->isMeta()) {
					int code = j->getMetaEventCode();
					string name;
					bool printable = true;
					switch (code) {
							
						case MIDI_END_OF_TRACK:
							cout << t << ": End of track" << endl;
							break;
							
						case MIDI_TEXT_EVENT: name = "Text"; break;
						case MIDI_COPYRIGHT_NOTICE: name = "Copyright"; break;
						case MIDI_TRACK_NAME: name = "Track name"; break;
						case MIDI_INSTRUMENT_NAME: name = "Instrument name"; break;
						case MIDI_LYRIC: name = "Lyric"; break;
						case MIDI_TEXT_MARKER: name = "Text marker"; break;
						case MIDI_SEQUENCE_NUMBER: name = "Sequence number"; printable = false; break;
						case MIDI_CHANNEL_PREFIX_OR_PORT: name = "Channel prefix or port"; printable = false; break;
						case MIDI_CUE_POINT: name = "Cue point"; break;
						case MIDI_CHANNEL_PREFIX: name = "Channel prefix"; printable = false; break;
						case MIDI_SEQUENCER_SPECIFIC: name = "Sequencer specific"; printable = false; break;
						case MIDI_SMPTE_OFFSET: name = "SMPTE offset"; printable = false; break;
							
						case MIDI_SET_TEMPO:
						{
							int m0 = j->getMetaMessage()[0];
							int m1 = j->getMetaMessage()[1];
							int m2 = j->getMetaMessage()[2];
							long tempo = (((m0 << 8) + m1) << 8) + m2;
							
							cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl;
							myMidiEvents.tempo = 60000000.0 / double(tempo);
							myMidiEvents.period = double(tempo)/1000.0;
							
							printf("period double is %f\n", myMidiEvents.period);
						}
							break;
							
						case MIDI_TIME_SIGNATURE:
						{
							int numerator = j->getMetaMessage()[0];
							int denominator = 1 << (int)j->getMetaMessage()[1];
							
							cout << t << ": Time signature: " << numerator << "/" << denominator << endl;
						}
							
						case MIDI_KEY_SIGNATURE:
						{
							int accidentals = j->getMetaMessage()[0];
							int isMinor = j->getMetaMessage()[1];
							bool isSharp = accidentals < 0 ? false : true;
							accidentals = accidentals < 0 ? -accidentals : accidentals;
							cout << t << ": Key signature: " << accidentals << " "
							<< (isSharp ?
								(accidentals > 1 ? "sharps" : "sharp") :
								(accidentals > 1 ? "flats" : "flat"))
							<< (isMinor ? ", minor" : ", major") << endl;
						}
							
					}
					
					
					if (name != "") {
						if (printable) {
							cout << t << ": File meta event: code " << code
							<< ": " << name << ": \"" << j->getMetaMessage()
							<< "\"" << endl;
						} else {
							cout << t << ": File meta event: code " << code
							<< ": " << name << ": ";
							for (int k = 0; k < j->getMetaMessage().length(); ++k) {
								cout << (int)j->getMetaMessage()[k] << " ";
							}
						}
					}
					continue;
				}
				
				switch (j->getMessageType()) {
						
					case MIDI_NOTE_ON:
				/*		cout << t << ": Note: channel " << ch
						<< " duration " << j->getDuration()
						<< " pitch " << j->getPitch()
						<< " velocity " << j->getVelocity() 
						<< "event time " << myMidiEvents.getEventTimeMillis(t) << endl;
				*/
						
						if (noteOnIndex == 0){
							firstNoteTime = myMidiEvents.getEventTimeMillis(t);
							firstTickTime = t;
						}
						
						noteOnIndex++;
						
						v.clear();
						
						if (!chopBeginning)
							v.push_back(t);
						else
							v.push_back(t - firstTickTime);
						
						v.push_back(j->getPitch());
						v.push_back(j->getVelocity());
						v.push_back(j->getDuration());
						myMidiEvents.recordedNoteOnMatrix.push_back(v);
						
						if (!chopBeginning)
						myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t));
						else {
						myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t) - firstNoteTime);
					//		printf("chopping beginning %f \n", myMidiEvents.getEventTimeMillis(t) - firstNoteTime);
						}
						
						myMidiEvents.noteOnMatches.push_back(false);
						
						break;
						
					case MIDI_POLY_AFTERTOUCH:
						cout << t << ": Polyphonic aftertouch: channel " << ch
						<< " pitch " << j->getPitch()
						<< " pressure " << j->getData2() << endl;
						break;
						
					case MIDI_CTRL_CHANGE:
					{
						int controller = j->getData1();
						string name;
						switch (controller) {
							case MIDI_CONTROLLER_BANK_MSB: name = "Bank select MSB"; break;
							case MIDI_CONTROLLER_VOLUME: name = "Volume"; break;
							case MIDI_CONTROLLER_BANK_LSB: name = "Bank select LSB"; break;
							case MIDI_CONTROLLER_MODULATION: name = "Modulation wheel"; break;
							case MIDI_CONTROLLER_PAN: name = "Pan"; break;
							case MIDI_CONTROLLER_SUSTAIN: name = "Sustain"; break;
							case MIDI_CONTROLLER_RESONANCE: name = "Resonance"; break;
							case MIDI_CONTROLLER_RELEASE: name = "Release"; break;
							case MIDI_CONTROLLER_ATTACK: name = "Attack"; break;
							case MIDI_CONTROLLER_FILTER: name = "Filter"; break;
							case MIDI_CONTROLLER_REVERB: name = "Reverb"; break;
							case MIDI_CONTROLLER_CHORUS: name = "Chorus"; break;
							case MIDI_CONTROLLER_NRPN_1: name = "NRPN 1"; break;
							case MIDI_CONTROLLER_NRPN_2: name = "NRPN 2"; break;
							case MIDI_CONTROLLER_RPN_1: name = "RPN 1"; break;
							case MIDI_CONTROLLER_RPN_2: name = "RPN 2"; break;
							case MIDI_CONTROLLER_SOUNDS_OFF: name = "All sounds off"; break;
							case MIDI_CONTROLLER_RESET: name = "Reset"; break;
							case MIDI_CONTROLLER_LOCAL: name = "Local"; break;
							case MIDI_CONTROLLER_ALL_NOTES_OFF: name = "All notes off"; break;
						}
						cout << t << ": Controller change: channel " << ch
						<< " controller " << j->getData1();
						if (name != "") cout << " (" << name << ")";
						cout << " value " << j->getData2() << endl;
					}
						break;
						
					case MIDI_PROG_CHANGE:
						cout << t << ": Program change: channel " << ch
						<< " program " << j->getData1() << endl;
						break;
						
					case MIDI_CHNL_AFTERTOUCH:
						cout << t << ": Channel aftertouch: channel " << ch
						<< " pressure " << j->getData1() << endl;
						break;
						
					case MIDI_PITCH_BEND:
						cout << t << ": Pitch bend: channel " << ch
						<< " value " << (int)j->getData2() * 128 + (int)j->getData1() << endl;
						break;
						
					case MIDI_SYSTEM_EXCLUSIVE:
						cout << t << ": System exclusive: code "
						<< (int)j->getMessageType() << " message length " <<
						j->getMetaMessage().length() << endl;
						break;
						
						
				}
				
				
			}
			
			
		}
		
		
		
		
}//end cannam midi main