// // Programmer: Craig Stuart Sapp // Creation Date: Thu May 6 17:15:41 PDT 2000 // Last Modified: Fri May 5 11:45:28 PDT 2000 // Last Modified: Thu Jun 29 00:11:48 PDT 2000 // Last Modified: Thu Jun 29 00:11:48 PDT 2000 (updated to museinfo 1.1) // Last Modified: Thu Jun 29 00:11:48 PDT 2000 (added shorten options) // Filename: ...sig/doc/examples/all/hplay/hplay.cpp // Syntax: C++ // // Description: Play **kern entries in a Humdrum file through MIDI. // #include "synthImprov.h" #include "HumdrumFile.h" #include "Convert.h" #include /*----------------- beginning of improvization algorithms ---------------*/ double tempo = 120.0; // current metronome tempo SigTimer timer; // for playing the humdrum file EventBuffer eventBuffer; // for storing note offs when playing notes HumdrumFile data; // humdrum file to play int linenum = 0; // for keeping track of current line in file double tempoScale = 1.0; // for global adjustment of tempo int velocity = 64; // default velocity to play MIDI notes int echoTextQ = 1; // boolean for displaying input file int fileNumber = 1; // current file number being played int mine = 0; // used with the -m option int shortenQ = 0; // used with the -s option int shortenamount = 0; // used with the -s option // non-synthImprov function declarations: void checkOptions(void); void inputNewFile(void); void playdata(HumdrumFile& data, int& linenum, SigTimer& timer); void printInputLine(HumdrumRecord& record); void processNotes(HumdrumRecord& record); /*--------------------- maintenance algorithms --------------------------*/ void description(void) { printboxtop(); psl(" HPLAY -- by Craig Stuart Sapp " "-- 4 May 2000\n"); printboxbottom(); } void initialization(void) { checkOptions(); timer.setPeriod(500); timer.reset(); eventIdler.setPeriod(0); eventBuffer.setPollPeriod(10); } void finishup(void) { eventBuffer.off(); } /*-------------------- main loop algorithms -----------------------------*/ void mainloopalgorithms(void) { eventBuffer.checkPoll(); if (timer.expired()) { playdata(data, linenum, timer); if (linenum >= data.getNumLines()) { inputNewFile(); } } } /*-------------------- triggered algorithms -----------------------------*/ void keyboardchar(int key) { switch (key) { case ' ': // toggle display of file while playing echoTextQ = !echoTextQ; if (echoTextQ) { cout << "!! FILE DISPLAY TURNED ON" << endl; } else { cout << "!! FILE DISPLAY TURNED OFF" << endl; } break; case ',': // slow down tempo tempoScale *= 0.97; cout << "!! TEMPO SET TO " << (int)(tempo * tempoScale) << endl; break; case '<': tempoScale *= 0.93; cout << "!! TEMPO SET TO " << (int)(tempo * tempoScale) << endl; break; case '.': // speed up tempo tempoScale *= 1.03; cout << "!! TEMPO SET TO " << (int)(tempo * tempoScale) << endl; break; case '>': tempoScale *= 1.07; cout << "!! TEMPO SET TO " << (int)(tempo * tempoScale) << endl; break; case 's': // silence notes eventBuffer.off(); break; } } /*------------------ end improvization algorithms -----------------------*/ ////////////////////////////// // // checkOptions -- process command-line options and setup the // humdrum data to play. // void checkOptions(void) { options.define("t|tempo=d:120.0", "Base tempo"); options.define("c|tempo-scale=d:1.0", "Tempo scaling factor"); options.define("p|pause=d:1.0", "pause time in seconds between files"); options.define("q|quiet=b", "Turn off data echoing while playing"); options.define("v|velocity=i:64", "Default MIDI key velocity"); options.define("m|min=i:0", "minimum tick duration of notes"); options.define("s|shorten=i:0", "shortening tick value for note durations"); options.process(); velocity = options.getInteger("velocity"); tempoScale = options.getDouble("tempo-scale"); tempo = options.getDouble("tempo"); if (options.getBoolean("quiet")) { echoTextQ = 0; } if (options.getArgCount() < 1) { data.read(cin); } else { inputNewFile(); } mine = options.getInteger("min"); if (mine < 0) { mine = 0; } shortenQ = options.getBoolean("shorten"); shortenamount = options.getInteger("shorten"); } ////////////////////////////// // // inputNewFile -- load in a new Humdrum file. // void inputNewFile(void) { data.clear(); linenum = 0; int count = options.getArgCount(); if (fileNumber > count) { finishup(); exit(0); } data.read(options.getArg(fileNumber)); data.analyzeRhythm("4"); if (fileNumber > 1) { millisleep((float)(1000 * options.getDouble("pause"))); } fileNumber++; } ////////////////////////////// // // playdata -- play the next line of the humdrum file, update the // line number and the time for the next events to be read // from the file. // void playdata(HumdrumFile& data, int& linenum, SigTimer& timer) { double duration = 0; // duration of the current line; int type = data[linenum].getType(); while (linenum < data.getNumLines() && duration == 0.0) { duration = data[linenum].getDuration(); if (type == E_humrec_data) { processNotes(data[linenum]); } else if (type == E_humrec_interpretation) { if (strncmp(data[linenum][0], "*MM", 3) == 0) { tempo = atoi(&data[linenum][0][3]); } } if (echoTextQ) { printInputLine(data[linenum]); } if (duration > 0.0) { timer.setPeriod(60000 / tempo / tempoScale * duration); timer.reset(); } linenum++; if (linenum < data.getNumLines()) { type = data[linenum].getType(); } } } ////////////////////////////// // // printInputLine -- print the current line of the file, // omitting the duration field at the end of the line // void printInputLine(HumdrumRecord& record) { cout << record.getLine() << endl; } ////////////////////////////// // // processNotes -- play all kern notes in the current record and // return the shortest note duration. // void processNotes(HumdrumRecord& record) { NoteEvent note; int pitch = 0; double duration = 0.0; int staccatoQ = 0; int accentQ = 0; int sforzandoQ = 0; int i, j; int notecount = 0; char buffer[128] = {0}; for (i=0; i