void appendMidi(MidiFile& outfile, const char* filename, double seconds, int initQ) { MidiFile infile(filename); infile.joinTracks(); infile.deltaTicks(); int i; int tpq; int count; MidiEvent anevent; if (initQ == 0) { outfile.joinTracks(); count = infile.getEventCount(0); // don't include end-of-track meta event count--; tpq = infile.getTicksPerQuarterNote(); outfile.setTicksPerQuarterNote(tpq); for (i=0; i<count; i++) { anevent = infile.getEvent(0,i); // storing as a type-0 file, so remove track information anevent.track = 0; outfile.addEvent(anevent); } return; } // presuming constant tpq for different files. tpq = outfile.getTicksPerQuarterNote(); if (seconds > 0.0) { // insert a tempo marking of 120, and then a pause related to how // long in second to wait until next MIDI file contents. // micro-seconds per quarter note is last three bytes of meta message // If quarter note is 120 bpm, that is 0.5 seconds or 500000 usec. // In hex 500000 is 07 a1 20 // Tempo meta event: ff 51 03 07 a1 20 vector<uchar> bpm120; bpm120.resize(3); bpm120[0] = 0x07; bpm120[1] = 0xa1; bpm120[2] = 0x20; outfile.addMetaEvent(0, 0, 0x51, bpm120); infile.getEvent(0,0).tick = int(seconds * 2 * tpq + 0.5); } count = infile.getEventCount(0); // don't include end-of-track meta event count--; for (i=0; i<count; i++) { anevent = infile.getEvent(0,i); anevent.track = 0; outfile.addEvent(anevent); } }
void createMidiFile(MidiFile& midifile, HumdrumFile& infile) { Array<int> millitimes; Array<double> velocities; Array<int> keynum; Array<int> track; millitimes.setSize(infile.getNumLines()); velocities.setSize(infile.getNumLines()); keynum.setSize(infile.getNumLines()); track.setSize(infile.getNumLines()); millitimes.setSize(0); velocities.setSize(0); keynum.setSize(0); track.setSize(0); int intval; double floatval; double dmax = -100000; double dmin = +100000; int i; for (i=0; i<infile.getNumLines(); i++) { if (!infile[i].isData()) { continue; } sscanf(infile[i][0], "%lf", &floatval); intval = int(floatval * 1000.0 + 0.5); millitimes.append(intval); sscanf(infile[i][1], "%lf", &floatval); velocities.append(floatval); if (floatval < dmin) { dmin = floatval; } if (floatval > dmax) { dmax = floatval; } intval = getMIDIKeyNum(infile[i][2]); keynum.append(intval); intval = getTrackNumber(infile[i][2]); track.append(intval); } millitimes.allowGrowth(0); velocities.allowGrowth(0); keynum.allowGrowth(0); track.allowGrowth(0); // normalize the dynamics data into the range from 0 to 1 double diff = dmax - dmin; for (i=0; i<velocities.getSize(); i++) { if (diff > 0.0) { velocities[i] = (velocities[i] - dmin) / diff; } else { velocities[i] = 0.5; } } // now ready to write the data to the MIDI file: midifile.setMillisecondDelta(); // SMPTE 25 frames & 40 subframes midifile.absoluteTime(); // Time values inserted are absolute midifile.addTrack(2); // Right and Left hands Array<uchar> event; event.setSize(3); int intdur = int(duration * 1000.0 + 0.5); int lasttime = 0; int dyndiff = maxdyn - mindyn; int vel; for (i=0; i<millitimes.getSize(); i++) { if ((keynum[i] <= 10) || (keynum[i] > 127)) { continue; } vel = int(velocities[i] * dyndiff + mindyn + 0.5); if (vel < 1) { vel = 1; } if (vel > 127) { vel = 127; } event[0] = 0x90; // note-on event[1] = keynum[i]; event[2] = vel; midifile.addEvent(track[i], millitimes[i], event); event[2] = 0; lasttime = millitimes[i] + intdur; midifile.addEvent(track[i], lasttime, event); } // write the end of track marker event[0] = 0xff; event[1] = 0x2f; event[2] = 0; for (i=0; i<midifile.getTrackCount(); i++) { if (i>0) { // have to lengthen the last note in track due to bugs // in various MIDI playback programs which clip // the last chord of a file midifile.getEvent(i, midifile.getNumEvents(i)-1).time += 1500; } midifile.addEvent(i, lasttime+2000, event); } // add comments from header for (i=0; i<infile.getNumLines() && i<lasttime; i++) { if (infile[i].isBibliographic() || infile[i].isGlobalComment()) { // 0x01 is a text event midifile.addMetaEvent(0, i, 0x01, infile[i].getLine()); } } // sort the ontimes and offtimes so they are in correct time order: midifile.sortTracks(); }