// // Programmer: Craig Stuart Sapp // Creation Date: Sat Jun 30 11:52:06 PDT 2001 // Last Modified: Mon Feb 9 21:14:03 PST 2015 Updated for C++11. // Filename: ...sig/examples/all/midi2melody.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/midi2melody.cpp // Syntax: C++; museinfo // // Description: Converts a single melody MIDI file/track into an ASCII text // format with starting time and pitch. // #include "MidiFile.h" #include "Options.h" #include #include using namespace std; class Melody { public: double tick; double duration; int pitch; }; // user interface variables Options options; int track = 0; // used with the -t option // function declarations: void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); void convertToMelody (MidiFile& midifile, vector& melody); void printMelody (vector& melody, int tpq); void sortMelody (vector& melody); int notecompare (const void* a, const void* b); ////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { checkOptions(options, argc, argv); MidiFile midifile(options.getArg(1)); vector melody; convertToMelody(midifile, melody); sortMelody(melody); printMelody(melody, midifile.getTicksPerQuarterNote()); return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // sortMelody -- // void sortMelody(vector& melody) { qsort(melody.data(), melody.size(), sizeof(Melody), notecompare); } ////////////////////////////// // // printMelody -- // only print the highest voice if multiple notes played together. // void printMelody(vector& melody, int tpq) { int i; double delta = 0; if (melody.size() < 1) { return; } Melody temp; temp.tick = melody[melody.size()-1].tick + melody[melody.size()-1].duration; temp.pitch = 0; temp.duration = 0; melody.push_back(temp); for (i=0; i<(int)melody.size()-1; i++) { delta = melody[i+1].tick - melody[i].tick; if (delta == 0) { continue; } cout << (double)melody[i].tick/tpq << "\t" << melody[i].pitch // << "\t" << (double)melody[i].duration/tpq << "\n"; if (delta > melody[i].duration) { cout << (melody[i+1].tick - (delta - melody[i].duration))/(double)tpq << "\t" << 0 << "\n"; } } cout << (double)melody[melody.size()-1].tick/tpq << "\t" << 0 << "\n"; } ////////////////////////////// // // convertToMelody -- // void convertToMelody(MidiFile& midifile, vector& melody) { midifile.absoluteTicks(); if (track < 0 || track >= midifile.getNumTracks()) { cout << "Invalid track: " << track << " Maximum track is: " << midifile.getNumTracks() - 1 << endl; } int numEvents = midifile.getNumEvents(track); vector state(128); // for keeping track of the note states int i; for (i=0; i<128; i++) { state[i] = -1; } melody.reserve(numEvents); melody.clear(); Melody mtemp; int command; int pitch; int velocity; for (i=0; i bb.tick) { return 1; } else { // highest note comes first if (aa.pitch > bb.pitch) { return 1; } else if (aa.pitch < bb.pitch) { return -1; } else { return 0; } } }