// // Programmer: Craig Stuart Sapp // Creation Date: Sun Oct 24 10:39:47 PDT 1999 // Last Modified: Sat Nov 25 20:17:58 PST 2000 (added instrument selection) // Last Modified: Tue Feb 20 19:20:09 PST 2001 (add articulation interpretation) // Last Modified: Sat Aug 23 08:57:54 PDT 2003 (added *free/*strict control) // Last Modified: Wed Mar 24 19:56:04 PST 2004 (fixed initial *MM ignore) // Last Modified: Wed Apr 7 16:22:38 PDT 2004 (grace-note noteoff hack) // Last Modified: Tue Sep 7 03:31:49 PDT 2004 (added extra space at end) // Last Modified: Tue Sep 7 03:43:09 PDT 2004 (more grace-note noteoff fixing) // Last Modified: Tue Sep 7 20:58:38 PDT 2004 (initial dynamics processing) // Last Modified: Fri Sep 10 02:26:59 PDT 2004 (added padding option) // Last Modified: Fri Sep 10 19:46:53 PDT 2004 (added cresc. decresc. control) // Last Modified: Sun Sep 12 05:20:44 PDT 2004 (added human and metric volume) // Last Modified: Wed Mar 23 00:35:18 PST 2005 (added constant volume back) // Last Modified: Sat Dec 17 22:46:11 PST 2005 (added **time processing) // Filename: ...sig/examples/all/hum2mid.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/hum2mid.cpp // Syntax: C++; museinfo // // Description: Converts Humdrum **kern data into MIDI data in a // Standard MIDI File format. // #include "museinfo.h" #include #include #include // Dynamics to attack velocity conversions: // Set based on conversions to MIDI files made in Finale: // (Every 13 increments) #define DYN_FFFF 127 #define DYN_FFF 114 #define DYN_FF 101 #define DYN_F 88 #define DYN_MF 75 #define DYN_MP 62 #define DYN_P 49 #define DYN_PP 36 #define DYN_PPP 23 #define DYN_PPPP 10 // global variables: const char *outlocation = NULL; int trackcount = 0; // number of tracks in MIDI file int track = 0; // track number starting at 0 int offset = 0; // start-time offset in ticks int tempo = 60; // default tempo // user interface variables Options options; int storeCommentQ = 1; // used with -C option int storeTextQ = 1; // used with -T option int plusQ = 0; // used with --plus option int defaultvolume = 64; // used with -v option double tscaling = 1.0; // used with -s option int multitimbreQ = 1; // used with -c option int instrumentQ = 1; // used with -I option int fixedChannel = 0; // used with -c option int instrumentnumber = -1; // used with -f option int forcedQ = 0; // used with -f option int mine = 0; // used with -m option int shortenQ = 0; // used with -s option int shortenamount = 0; // used with -s option int plainQ = 0; // used with -p option int debugQ = 0; // used with --debug option int dynamicsQ = 1; // used with -D option int padQ = 1; // used with -P option int humanvolumeQ = 5; // used with --hv option int metricvolumeQ = 5; // used with --mv option int sforzando = 20; // used with --sf option int fixedvolumeQ = 0; // used with -v option int timeQ = 0; // used with --time option // function declarations: void assignTracks (HumdrumFile& infile, Array& trackchannel); double checkForTempo (HumdrumRecord& record); void checkOptions (Options& opts, int argc, char** argv); void example (void); int makeVLV (uchar *buffer, int number); void reviseInstrumentMidiNumbers(const char* string); int setMidiPlusVolume (const char* kernnote); void storeMetaText (MidiFile& mfile, int track, const char* string, int tick, int metaType = 1); void storeMidiData (HumdrumFile& infile, MidiFile& outfile); void storeInstrument (int ontick, MidiFile& mfile, HumdrumFile& infile, int i, int j, int pcQ); void usage (const char* command); void storeFreeNote (Array >& array,int ptrack,int midinote); void getDynamics (HumdrumFile& infile, Array >& dynamics, int defaultdynamic); void getDynamicAssignments(HumdrumFile& infile, Array& assignments); void getStaffValues (HumdrumFile& infile, int staffline, Array >& staffvalues); void getNewDynamics (Array& currentdynamic, Array& assignments, HumdrumFile& infile, int line, Array >& crescendos, Array >& accentuation); void processCrescDecresc(HumdrumFile& infile, Array >& dynamics, Array >& crescendos); void interpolateDynamics(HumdrumFile& infile, Array& dyn, Array& cresc); void generateInterpolation(HumdrumFile& infile, Array& dyn, Array& cresc, int startline, int stopline, int direction); int findtermination (Array& dyn, Array& cresc, int start); char adjustVolumeHuman (int startvol, int delta); char adjustVolumeMetric (int startvol, int delta, double metricpos); char applyAccentuation (int dynamic, int accent); int getMillisecondTime (HumdrumFile& infile, int line); int getFileDurationInMilliseconds(HumdrumFile& infile); int getMillisecondDuration(HumdrumFile& infile, int row, int col, int subcol); Array tracknamed; // for storing boolean if track is named Array trackchannel; // channel of each track ////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { // for humanizing processes #ifndef VISUAL srand48(time(NULL)); # else srand(time(NULL)); #endif HumdrumFile infile; MidiFile outfile; outfile.setTicksPerQuarterNote(120); // process the command-line options checkOptions(options, argc, argv); if (timeQ) { outfile.setMillisecondDelta(); } // figure out the number of input files to process int numinputs = options.getArgCount(); for (int i=0; i gmsysex; gmsysex.setSize(6); gmsysex[0] = 0xf0; // Start of SysEx gmsysex[1] = 0x7e; // Universal (reserved) ID number gmsysex[2] = 0x7f; // Device ID (general transmission) gmsysex[3] = 0x09; // Means 'This is a message about General MIDI' gmsysex[4] = 0x01; // Means 'Turn General MIDI On'. 02 means 'Off' gmsysex[5] = 0xf7; // End of SysEx outfile.addEvent(0, 0, gmsysex); } */ storeMidiData(infile, outfile); if (outlocation == NULL) { outfile.sortTracks(); cout << outfile; } else { outfile.sortTracks(); outfile.write(outlocation); } } return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // assignTracks -- give a track number for each spine in the input file // trying to place the same instruments into the same channels if // there are not enough channels to go around. // void assignTracks(HumdrumFile& infile, Array& trackchannel) { int i, j; Array instruments; // MIDI instruments indicated in track trackchannel.setSize(infile.getMaxTracks() + 1); instruments.setSize(trackchannel.getSize()); for (i=0; i 16) { // channel allocation is over quota: squash over-allocations: for (i=0; i 15) { trackchannel[i] = 0; } } } } } ////////////////////////////// // // checkForTempo -- // double checkForTempo(HumdrumRecord& record) { int i; float tempo = 60.0; for (i=0; i 127) { defaultvolume = 127; } tscaling = opts.getDouble("tempo-scaling"); if (tscaling < 0.001) { tscaling = 1.0; } else if (tscaling > 1000.0) { tscaling = 1.0; } instrumentQ = !opts.getBoolean("noinstrument"); if (opts.getBoolean("channel")) { multitimbreQ = 0; fixedChannel = opts.getInteger("channel") - 1; if (fixedChannel < 0) { fixedChannel = 0; } if (fixedChannel > 15) { fixedChannel = 15; } instrumentQ = 0; } else { multitimbreQ = 1; fixedChannel = -1; } if (opts.getBoolean("output")) { outlocation = opts.getString("output"); } else { outlocation = NULL; } forcedQ = opts.getBoolean("forceinstrument"); if (forcedQ) { instrumentnumber = opts.getInteger("forceinstrument"); if (instrumentnumber < 0 || instrumentnumber > 127) { instrumentnumber = 0; } } else { instrumentnumber = -1; } mine = opts.getInteger("min"); if (mine < 0) { mine = 0; } debugQ = opts.getBoolean("debug"); shortenQ = opts.getBoolean("shorten"); shortenamount = opts.getInteger("shorten"); padQ = !opts.getBoolean("nopad"); humanvolumeQ = opts.getInteger("humanvolume"); fixedvolumeQ = opts.getBoolean("volume"); timeQ = opts.getBoolean("time"); metricvolumeQ = opts.getInteger("metricvolume"); sforzando = opts.getInteger("sforzando"); } ////////////////////////////// // // example -- // void example(void) { } ////////////////////////////// // // storeMetaText -- // void storeMetaText(MidiFile& mfile, int track, const char* string, int tick, int metaType) { int i; int length = strlen(string); Array metadata; uchar size[23] = {0}; int lengthsize = makeVLV(size, length); metadata.setSize(2+lengthsize+length); metadata[0] = 0xff; metadata[1] = metaType; for (i=0; i= (1 << 28)) { cout << "Error: number too large to handle" << endl; exit(1); } buffer[0] = (value >> 21) & 0x7f; buffer[1] = (value >> 14) & 0x7f; buffer[2] = (value >> 7) & 0x7f; buffer[3] = (value >> 0) & 0x7f; int i; int flag = 0; int length = -1; for (i=0; i<3; i++) { if (buffer[i] != 0) { flag = 1; } if (flag) { buffer[i] |= 0x80; } if (length == -1 && buffer[i] >= 0x80) { length = 4-i; } } if (length == -1) { length = 1; } if (length < 4) { for (i=0; i mididata; int i, j, k; int ii; int tokencount = 0; char buffer1[1024] = {0}; int staccatoQ = 0; int accentQ = 0; int sforzandoQ = 0; int volume = defaultvolume; int ttempo; Array freeQ; freeQ.setSize(infile.getMaxTracks()); freeQ.setAll(0); Array > freenotestate; freenotestate.setSize(freeQ.getSize()); for (i=0; i > dynamics; getDynamics(infile, dynamics, defaultvolume); /* if (tscaling != 1.0) { ttempo = (int)(60 * tscaling); if (ttempo > 0) { mididata.setSize(6); mididata[0] = 0xff; mididata[1] = 0x51; mididata[2] = 3; ttempo = (int)(60000000.0 / ttempo + 0.5); mididata[3] = (uchar)((ttempo >> 16) & 0xff); mididata[4] = (uchar)((ttempo >> 8) & 0xff); mididata[5] = (uchar)(ttempo & 0xff); outfile.addEvent(0, 0 + offset, mididata); } } */ if (options.getBoolean("comment")) { storeMetaText(outfile, 0, options.getString("comment"), 0); } for (i=0; i 0) { // cout << "The tempo read was " << tempo << endl; ttempo = (int)(tempo * tscaling + 0.5); mididata.setSize(6); mididata[0] = 0xff; mididata[1] = 0x51; mididata[2] = 3; ttempo = (int)(60000000.0 / ttempo + 0.5); mididata[3] = (uchar)((ttempo >> 16) & 0xff); mididata[4] = (uchar)((ttempo >> 8) & 0xff); mididata[5] = (uchar)(ttempo & 0xff); if (timeQ) { ontick = getMillisecondTime(infile, i); } else { absbeat = infile.getAbsBeat(i); ontick = int(absbeat * outfile.getTicksPerQuarterNote()); } outfile.addEvent(0, ontick + offset, mididata); // outfile.addEvent(0, 10 + offset, mididata); tempo = -1; } for (j=0; j mididata; mididata.setSize(2); mididata[0] = 0xc0 | (0x0f & trackchannel[track]); mididata[1] = instrumentnumber; outfile.addEvent(track, ontick + offset, mididata); continue; } if (strncmp(infile[i][j], "*I", 2) == 0) { storeInstrument(ontick + offset, outfile, infile, i, j, instrumentQ); continue; } if (strcmp(infile[i][j], "*free") == 0) { freeQ[infile[i].getPrimaryTrack(j)-1] = 1; } else if (strcmp(infile[i][j], "*strict") == 0) { freeQ[infile[i].getPrimaryTrack(j)-1] = 0; // turn off any previous notes in the track // started during a free rhythm section ptrack = infile[i].getPrimaryTrack(j) - 1; for (ii=0; ii= 0) { mididata.setSize(3); mididata[0] = 0x80 | trackchannel[track]; mididata[1] = (uchar)freenotestate[ptrack][ii]; mididata[2] = 0; outfile.addEvent(track, ontick + offset + 1, mididata); // added 1 to the previous line for grace notes 7Apr2004 freenotestate[ptrack][ii] = -1; if (ii == freenotestate[ptrack].getSize() - 1) { // shrink-wrap the free note off array freenotestate[ptrack].setSize(ii); break; } } } } } } else if (infile[i].getType() == E_humrec_data) { for (j=0; j= 0) { mididata.setSize(3); mididata[0] = 0x80 | trackchannel[track]; mididata[1] = (uchar)freenotestate[ptrack][ii]; mididata[2] = 0; outfile.addEvent(track, ontick + offset, mididata); freenotestate[ptrack][ii] = -1; if (ii == freenotestate[ptrack].getSize() - 1) { // shrink-wrap the free note off array freenotestate[ptrack].setSize(ii); break; } } } } for (k=0; k 127) { volume = 127; } if (volume < 1) { volume = 1; } if (plusQ) { volume = setMidiPlusVolume(buffer1); } if (timeQ) { ontick = getMillisecondTime(infile, i); offtick = (int)(ontick + duration + 0.5); } else { absbeat = infile.getAbsBeat(i); ontick = int(absbeat * outfile.getTicksPerQuarterNote()); offtick = int(duration * outfile.getTicksPerQuarterNote()) + ontick; } if (shortenQ) { offtick -= shortenamount; if (offtick - ontick < mine) { offtick = ontick + mine; } } // fix for grace note noteoffs (7 Sep 2004): if (timeQ) { if (offtick <= ontick) { offtick = ontick + 100; } } else { if (offtick <= ontick) { offtick = ontick + (int)(infile[i].getDuration() * outfile.getTicksPerQuarterNote()+0.5); } // in case the duration of the line is 0: if (offtick <= ontick) { offtick = ontick + 12; } } if (volume < 0) { volume = 1; } if (volume > 127) { volume = 127; } mididata.setSize(3); mididata[0] = 0x90 | trackchannel[track]; mididata[1] = midinote; mididata[2] = volume; if (fixedvolumeQ) { mididata[2] = defaultvolume; } outfile.addEvent(track, ontick + offset, mididata); if (freeQ[ptrack] == 0) { // don't specify the note off duration when rhythm is free. mididata[0] = 0x80 | trackchannel[track]; outfile.addEvent(track, offtick + offset, mididata); } else { // store the notes to be turned off later storeFreeNote(freenotestate, ptrack, midinote); } } } } } } // now add the end-of-track message to all tracks so that they // end at the same time. mididata.setSize(3); if (timeQ) { ontick = getFileDurationInMilliseconds(infile); ontick += 1000; } else { absbeat = infile.getAbsBeat(infile.getNumLines()-1); ontick = int(absbeat * outfile.getTicksPerQuarterNote()); // note that extra time is added so that the last note will not get // cut off by the MIDI player. ontick += 120; } // stupid Microsoft Media player (et al.) will still cut off early, // so add a dummy note-off at end as well... if (options.getBoolean("type0")) { outfile.joinTracks(); if (padQ) { mididata[0] = 0x90; mididata[1] = 0x00; mididata[2] = 0x00; outfile.addEvent(0, ontick-1+offset, mididata); } mididata[0] = 0xff; mididata[1] = 0x2f; mididata[2] = 0x00; outfile.addEvent(0, ontick+offset, mididata); } else { // type 1 MIDI file int trackcount = outfile.getNumTracks(); for (i=0; i >& array, int ptrack, int midinote) { int i; int loc = -1; for (i=0; i= 0) { array[ptrack][loc] = midinote; } else { array[ptrack].append(midinote); } } ////////////////////////////// // // reviseInstrumentMidiNumbers -- // void reviseInstrumentMidiNumbers(const char* string) { const char* spaces = " \t\n,:;"; char* buffer = new char[strlen(string) + 1]; strcpy(buffer, string); HumdrumInstrument x; char* pointer = buffer; pointer = strtok(buffer, spaces); int instnum = 0; while (pointer != NULL) { char* humdrumname = pointer; pointer = strtok(NULL, spaces); if (pointer == NULL) { break; } instnum = 0; sscanf(pointer, "%d", &instnum); if (instnum < 0 || instnum > 127) { continue; } x.setGM(humdrumname, instnum); pointer = strtok(NULL, spaces); } } ////////////////////////////// // // setMidiPlusVolume -- store slur and enharmonic spelling information. // based on definition in the book: // Beyond MIDI: The Handbook of Musical Codes. pp. 99-104. // int setMidiPlusVolume(const char* kernnote) { int output = 1 << 6; // check for slurs, but do not worry about separating multiple slurs if (strchr(kernnote, '(') != NULL) { // start of slur A output |= (1 << 2); } else if (strchr(kernnote, ')') != NULL) { // end of slur A output |= (1 << 4); } // set the accidental marking int base40class = Convert::kernToBase40(kernnote) % 40; int midinoteclass = Convert::kernToMidiNoteNumber(kernnote) % 12; int acheck = 0; switch (midinoteclass) { case 0: // C/Dbb/B# switch (base40class) { case 4: acheck = 1; break; // Dbb case 0: acheck = 2; break; // C case 36: acheck = 3; break; // B# default: acheck = 0; } break; case 1: // C#/Db/B## switch (base40class) { case 5: acheck = 1; break; // Db case 1: acheck = 2; break; // C# case 37: acheck = 3; break; // B## default: acheck = 0; } break; case 2: // D/C##/Ebb switch (base40class) { case 10: acheck = 1; break; // Ebb case 6: acheck = 2; break; // D case 2: acheck = 3; break; // C## default: acheck = 0; } break; case 3: // D#/Eb/Fbb switch (base40class) { case 15: acheck = 1; break; // Fbb case 11: acheck = 2; break; // Eb case 7: acheck = 3; break; // D# default: acheck = 0; } break; case 4: // E/Fb/D## switch (base40class) { case 16: acheck = 1; break; // Fb case 12: acheck = 2; break; // E case 8: acheck = 3; break; // D## default: acheck = 0; } break; case 5: // F/E#/Gbb switch (base40class) { case 21: acheck = 1; break; // Gbb case 17: acheck = 2; break; // F case 13: acheck = 3; break; // E# default: acheck = 0; } break; case 6: // F#/Gb/E## switch (base40class) { case 22: acheck = 1; break; // Gb case 18: acheck = 2; break; // F# case 14: acheck = 3; break; // E## default: acheck = 0; } break; case 7: // G/Abb/F## switch (base40class) { case 27: acheck = 1; break; // Abb case 23: acheck = 2; break; // G case 19: acheck = 3; break; // F## default: acheck = 0; } break; case 8: // G#/Ab/F### switch (base40class) { case 28: acheck = 1; break; // Ab case 24: acheck = 2; break; // G# default: acheck = 0; // F### } break; case 9: // A/Bbb/G## switch (base40class) { case 33: acheck = 1; break; // Bbb case 29: acheck = 2; break; // A case 25: acheck = 3; break; // G## default: acheck = 0; } break; case 10: // Bb/A#/Cbb switch (base40class) { case 38: acheck = 1; break; // Cbb case 34: acheck = 2; break; // Bb case 30: acheck = 3; break; // A# default: acheck = 0; } break; case 11: // B/Cf/A## switch (base40class) { case 39: acheck = 1; break; // Cb case 35: acheck = 2; break; // B case 31: acheck = 3; break; // A## default: acheck = 0; } break; } output |= acheck; return output; } ////////////////////////////// // // storeInstrument -- // void storeInstrument(int ontick, MidiFile& mfile, HumdrumFile& infile, int i, int j, int pcQ) { static HumdrumInstrument huminst; int track = infile[i].getPrimaryTrack(j); const char* trackname = huminst.getName(infile[i][j]); int pc = huminst.getGM(infile[i][j]); if (forcedQ) { pc = instrumentnumber; } int channel = 0x0f & trackchannel[track]; // store the program change if requested: Array mididata; mididata.setSize(2); mididata[0] = 0xc0 | channel; mididata[1] = (uchar)pc; if (pcQ && pc >= 0 && !forcedQ) { mfile.addEvent(track, ontick + offset, mididata); } if (!tracknamed[track]) { tracknamed[track] = 1; storeMetaText(mfile, track, trackname, 0, 3); // Track Name } storeMetaText(mfile, track, trackname + offset, ontick, 4); // Inst. Name } ////////////////////////////// // // usage -- // void usage(const char* command) { } ////////////////////////////// // // getDynamics -- // void getDynamics(HumdrumFile& infile, Array >& dynamics, int defaultdynamic) { int maxtracks = infile.getMaxTracks(); Array currentdynamic; currentdynamic.setSize(maxtracks); currentdynamic.setAll(defaultdynamic); Array metlev; infile.analyzeMetricLevel(metlev); Array > crescendos; // -1=decrescendo, +1=crescendo, 0=none crescendos.setSize(maxtracks); Array > accentuation; // v = sf, sfz, fz, sffz accentuation.setSize(maxtracks); dynamics.setSize(maxtracks); int i; int j; for (i=0; i assignments; // dynamic data which controls kern data getDynamicAssignments(infile, assignments); for (i=0; i 1) { cout << "----------------------------------------------" << endl; cout << "Dynamics profile of file:" << endl; } for (i=0; i 1) { cout << (int)dynamics[j][i] << "\t"; } } if (dynamicsQ > 1) { cout << endl; } } if (dynamicsQ > 1) { cout << "----------------------------------------------" << endl; } } ////////////////////////////// // // applyAccentuation -- // char applyAccentuation(int dynamic, int accent) { switch (accent) { case 'v': dynamic += sforzando; break; } if (dynamic > 127) { dynamic = 127; } else if (dynamic <= 0) { dynamic = 1; } return (char)dynamic; } /////////////////////////////// // // adjustVolumeMetric -- adjust the attack volume based on the // metric position of the note (on the beat, off the beat, on // a metrically strong beat). // char adjustVolumeMetric(int startvol, int delta, double metricpos) { if (metricpos > 0.0) { startvol += delta; } else if (metricpos < 0) { startvol -= delta; } if (startvol <= 0) { startvol = 1; } else if (startvol > 127) { startvol = 127; } return (char)startvol; } //////////////////////////////// // // adjustVolumeHuman -- add a randomness to the volume // char adjustVolumeHuman(int startvol, int delta) { int randval; #ifndef VISUAL randval = lrand48() % (delta * 2 + 1) - delta; #else randval = rand() % (delta * 2 + 1) - delta; #endif startvol += randval; if (startvol <= 0) { startvol = 1; } if (startvol > 127) { startvol = 127; } return (char)startvol; } ////////////////////////////// // // processCrescDecresc -- adjust attack velocities based on the // crescendos and decrescendos found in the file. // void processCrescDecresc(HumdrumFile& infile, Array >& dynamics, Array >& crescendos) { int i; for (i=0; i& dyn, Array& cresc) { int direction = 0; int i; int ii; for (i=0; i 0) { direction = +1; } else if (cresc[i] < 0) { direction = -1; } else { direction = 0; } ii = findtermination(dyn, cresc, i); generateInterpolation(infile, dyn, cresc, i, ii, direction); // skip over calm water: i = ii - 1; } } } ////////////////////////////// // // generateInterpolation -- do the actual interpolation work. // void generateInterpolation(HumdrumFile& infile, Array& dyn, Array& cresc, int startline, int stopline, int direction) { double startbeat = infile[startline].getAbsBeat(); double stopbeat = infile[stopline].getAbsBeat(); if (startbeat == stopbeat) { // nothing to do return; } int startvel = dyn[startline]; int stopvel = dyn[stopline]; if (startvel < 0) startvel = -startvel; if (stopvel < 0) stopvel = -stopvel; if (stopvel == startvel) { if (direction > 0) { stopvel += 10; } else { stopvel -= 10; } } else if (stopvel>startvel && direction<0) { stopvel = startvel - 10; } else if (stopvel0) { stopvel = startvel + 10; } int i; double slope = (double)(stopvel-startvel)/(double)(stopbeat-startbeat); double currvel = 0.0; double currbeat = 0.0; for (i=startline+1; i 127.0) { currvel = 127.0; } if (currvel < 0.0) { currvel = 0.0; } dyn[i] = (char)(currvel+0.5); } } ////////////////////////////// // // findtermination -- // int findtermination(Array& dyn, Array& cresc, int start) { int i; for (i=start+1; i=dyn.getSize()) { i = dyn.getSize()-1; } return i; } ////////////////////////////// // // getNewDynamics -- // void getNewDynamics(Array& currentdynamic, Array& assignments, HumdrumFile& infile, int line, Array >& crescendos, Array >& accentuation) { if (infile[line].getType() != E_humrec_data) { return; } int i; int j; int k; int length; int track = -1; int dval = -1; int accent = 0; int cresval = 0; char buffer[2048] = {0}; for (i=0; i and < on the same line. if (strchr(infile[line][i], '<') != NULL) { cresval = +1; } else if (strchr(infile[line][i], '>') != NULL) { cresval = -1; } // look for accentuatnon if (strchr(infile[line][i], 'v') != NULL) { accent = 'v'; } if (dval > 0 || cresval !=0) { for (j=0; j 0) { currentdynamic[j] = -dval; } if (cresval != 0) { crescendos[j][line] = cresval; } if (accent != 0) { accentuation[j][line] = accent; } } } } } } ////////////////////////////// // // getDynamicAssignments -- // void getDynamicAssignments(HumdrumFile& infile, Array& assignments) { assignments.setSize(infile.getMaxTracks()); assignments.setAll(-1); // *staff assignment assumed to be all on one line, and before // any note data. int staffline = -1; int exinterp = -1; int i; int j; for (i=0; i=0; i--) { if (strcmp(infile[exinterp][i], "**dynam") == 0) { currdyn = i; } if (currdyn >= 0) { assignments[i] = infile[exinterp].getPrimaryTrack(currdyn)-1; } else { assignments[i] = -1; } } if (staffline == -1) { // there is no staff assignments in the file, so attach any // dynamics to the first **kern spine on the left. return; } // there is a *staff assignment line, so follow the directions found there Array > staffvalues; getStaffValues(infile, staffline, staffvalues); int k; // assignments.setSize(infile.getMaxTracks()); for (i=0; i 0) { if (!isdigit(cptr[0])) { break; } value = strtol(cptr, &newcptr, 10); staffvalues[i].append(value); cptr = newcptr; if (cptr[0] != '/') { break; } else { cptr = cptr + 1; } } } } } } ////////////////////////////// // // getMillisecondTime -- return the time in milliseconds found // on the current line in the file. // int getMillisecondTime(HumdrumFile& infile, int line) { double output = -100; int flag; int i; while ((line < infile.getNumLines()) && (infile[line].getType() != E_humrec_data)) { line++; } if (line >= infile.getNumLines() - 1) { return getFileDurationInMilliseconds(infile); } for (i=0; i= (stopbeat-0.0002)) { for (j=0; j 0) && (infile[lastdataline].getType() != E_humrec_data)) { lastdataline--; } double ctime = getMillisecondTime(infile, lastdataline); double cbeat = infile[lastdataline].getAbsBeat(); double nbeat = infile[infile.getNumLines()-1].getAbsBeat(); int preindex = -1; int i; for (i=lastdataline-1; i>=0; i--) { if (infile[i].getType() != E_humrec_data) { continue; } preindex = i; break; } if (preindex < 0) { return -1; } double pbeat = infile[preindex].getAbsBeat(); double ptime = -1.0; for (i=0; i> "; // cout << "<< DB2 = " << db2 << " >> "; // cout << "<< DT1 = " << dt1 << " >> "; return (int)(ctime + db2 * dt1 / db1 + 0.5); } // md5sum: 1417781a4db6339fea405d9e44627e85 hum2mid.cpp [20060502]