// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Sat May 23 21:08:48 PDT 1998 // Last Modified: Fri Jul 3 14:18:04 PDT 1998 // Filename: ...sig/examples/all/base12.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/base12.cpp // Syntax: C++; museinfo // Reference: http://www.ccarh.org/publications/reprints/base12 // // Description: Converts **kern pitches into/from base 12 system. // #include "humdrum.h" #include <stdio.h> #include <string.h> #include <ctype.h> // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void processDataRecord(HumdrumRecord& line); void processExclusiveInterp(HumdrumRecord& line); void processTandemRecord(HumdrumRecord& line); void splitstring(const char* line, char* front, char* basestring, char* back, const char* markstart, const char* markend); void kernsplit(const char* line, char* front, char* back, const char* markstart, const char* markend); // global variables Options options; // database for command-line arguments int octaveQ = 1; // boolean for keeping or removing octave info int transpose = 0; // transposition value from command-line int preserveQ = 0; // boolean for keeping extra kern info int kernQ = 1; // boolean for converting **base12 to **kern int cvalue = 2; // default pitch class for C int noptionQ = 0; // for -n option: convert to specific key int mode = 0; // for -n option char newkey[32] = {0}; // for -n option const char* markstart = ""; // start of base12 number marker const char* markend = ""; // end of base12 number marker /////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { // process the command-line options checkOptions(options, argc, argv); int numinputs = options.getArgCount(); HumdrumFile input; for (int j=0; j<numinputs || j==0; j++) { input.clear(); // if no command-line arguments read data file from standard input if (numinputs < 1) { input.read(cin); } else { input.read(options.getArg(j+1)); } for (int i=0; i<input.getNumLines(); i++) { switch (input[i].getType()) { case E_humrec_none: case E_humrec_empty: case E_humrec_bibliography: case E_humrec_global_comment: case E_humrec_data_comment: case E_humrec_interpretation: if (strncmp(input[i][0], "**", 2) == 0) { processExclusiveInterp(input[i]); cout << input[i] << endl; } else if (noptionQ) { processTandemRecord(input[i]); } cout << input[i] << endl; break; case E_humrec_data_kern_measure: cout << input[i] << endl; break; case E_humrec_data: processDataRecord(input[i]); cout << input[i] << endl; break; default: break; } } } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("p|pitch-class=b", "show only base12 pitch classes"); opts.define("r|rhythm=b", "preserve **kern rhythms and other info"); opts.define("c|c-value=i:2", "base 12 pitch class value for C"); opts.define("t|transpose=i:0", "transposition interval"); opts.define("k|kern=b", "convert **base12 spines to **kern"); opts.define("n|newkey=s", "transpose **kern spines to newkey"); opts.define("s|start=s:a", "marker string start for **kern preserving"); opts.define("e|end=s:a", "marker string end for **kern preserving"); opts.define("author=b", "show the author of program"); opts.define("version=b", "compilation info"); opts.define("example=b", "example usages"); opts.define("h|help=b", "short description"); opts.process(argc, argv); // handle basic options: if (opts.getBoolean("author")) { cout << "Written by Craig Stuart Sapp, " << "craig@ccrma.stanford.edu, April 2000" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 11 April 2000" << endl; cout << "compiled: " << __DATE__ << endl; cout << MUSEINFO_VERSION << endl; exit(0); } else if (opts.getBoolean("help")) { // usage(opts.getCommand()); exit(0); } else if (opts.getBoolean("example")) { // example(); exit(0); } if (opts.getBoolean("pitch-class")) { octaveQ = 0; } else { octaveQ = 1; } // get the transposition interval transpose = opts.getInteger("transpose"); // get kern convertion option kernQ = opts.getBoolean("kern"); // get the base12 marker start/stop strings markstart = opts.getString("start"); markend = opts.getString("end"); // get boolean for keeping extra kern data. preserveQ = opts.getBoolean("rhythm"); // get boolean for converting from base12 to kern kernQ = opts.getBoolean("kern"); // get C value offset cvalue = opts.getInteger("c-value"); cvalue -= 2; if (opts.getBoolean("newkey")) { noptionQ = 1; transpose = 0; strncpy(newkey, opts.getString("newkey"), 30); if (isupper(newkey[0])) { mode = 0; // Major } else { mode = 1; // Minor } int i = 0; while (newkey[i] != '\0') { if (newkey[i] == 's') { newkey[i] = '#'; } i++; } } } ////////////////////////////// // // example -- example usage of the base12 program // void example(void) { cout << " \n" "no examples yet \n" " \n" << endl; } ////////////////////////////// // // kernsplit -- split up the kern into stuff before and stuff // after a pitch value. // void kernsplit(const char* line, char* front, char* back, const char* markstart, const char* markend) { int length = strlen(line); char *templine; templine = new char[length+1]; strcpy(templine, line); char* pointer; pointer = strtok(templine, "abcdefgABCDEFG#-n"); if (pointer != NULL) { strcpy(front, pointer); } else { front[0] = '\0'; } pointer = strtok(NULL, "abcdefgABCDEFG#-n"); if (pointer != NULL) { strcpy(back, pointer); } else { back[0] = '\0'; } delete [] templine; } ////////////////////////////// // // processDataRecord -- example usage of the base12 program // void processDataRecord(HumdrumRecord& line) { int k; int base12value; static char buffer[1024] = {0}; static char pitchbuffer[128] = {0}; static char front[128] = {0}; static char back[128] = {0}; static char basestring[128] = {0}; if (kernQ) { // converting from **base12 to **kern for (k=0; k<line.getFieldCount(); k++) { if (strcmp(line.getExInterp(k), "**base12") == 0) { if (strcmp(line[k], ".") == 0) { continue; } splitstring(line[k], front, basestring, back, markstart, markend); base12value = atoi(basestring); base12value += transpose - cvalue; Convert::base12ToKern(pitchbuffer, base12value); strcpy(buffer, front); strcat(buffer, pitchbuffer); strcat(buffer, back); line.changeField(k, buffer); } } } else if (noptionQ) { ////////////////////////////////////////// } else { // converting from **kern to **base12 for (k=0; k<line.getFieldCount(); k++) { if (strcmp(line.getExInterp(k), "**kern") == 0) { if (strcmp(line[k], ".") == 0) { continue; } base12value = Convert::kernToMidiNoteNumber(line[k]); base12value += transpose + cvalue; if (preserveQ) { kernsplit(line[k], front, back, markstart, markend); if (base12value < -100) { line.changeField(k, "r"); pitchbuffer[0] = 'r'; pitchbuffer[1] = '\0'; } else { if (octaveQ == 0) { base12value = base12value % 12; } sprintf(pitchbuffer, "%d", base12value); } sprintf(buffer, "%s%s%s%s%s", front, markstart, pitchbuffer, markend, back); line.changeField(k, buffer); } else { if (base12value < -100) { line.changeField(k, "r"); } else { if (octaveQ == 0) { base12value = base12value % 12; } sprintf(buffer, "%d", base12value); line.changeField(k, buffer); } } } } } } ////////////////////////////// // // processExclusiveInterp -- adjust the ** fields as necessary // void processExclusiveInterp(HumdrumRecord& line) { int k; if (kernQ) { // converting from **base12 to **base12 for (k=0; k<line.getFieldCount(); k++) { if (strcmp(line[k], "**base12") == 0) { line.changeField(k, "**kern"); } } } else if (noptionQ) { // do nothing, will keep **kern spines, but transpose them. } else { // converting from **kern to **base12 for (k=0; k<line.getFieldCount(); k++) { if (strcmp(line[k], "**kern") == 0) { line.changeField(k, "**base12"); } } } } ////////////////////////////// // // processTandemRecord -- handle lines starting with *. // void processTandemRecord(HumdrumRecord& line) { if (transpose != 0) { return; // don't need to change this more than once } // find the first **kern spine char oldkey[32] = {0}; char oldkeytemp[32] = {0}; char *tempointer = NULL; int length = 0; int k; for (k=0; k<line.getFieldCount(); k++) { if (strcmp("**kern", line.getExInterp(k)) == 0) { strncpy(oldkey, line[k], 30); break; } } length = strlen(oldkey); strcpy(oldkeytemp, oldkey); tempointer = strtok(oldkeytemp, "*abcdefgABCDEFG#-:"); if (tempointer == NULL || strcmp(tempointer, "") == 0) { // do nothing } else { return; // not the tandem interp that was wanted. } if (oldkey[length-1] != ':') { return; } int base12note = Convert::kernToMidiNoteNumber(oldkey); cout << "++++++++ Key value is: " << base12note << endl; } ////////////////////////////// // // splitstring -- split the kern field into three sections: // (1) before the pitch, (2) the pitch, and (3) after the pitch. // void splitstring(const char* line, char* front, char* basestring, char* back, const char* markstart, const char* markend) { int length = strlen(line); char *templine; templine = new char[length+1]; strcpy(templine, line); int lengths = strlen(markstart); int lengthe = strlen(markend); char *startp, *endp; startp = strstr(templine, markstart); if (startp != NULL) { endp = strstr(&startp[1], markend); } else { endp = NULL; } // if there is no marker to preserve kern if (startp == NULL && endp == NULL) { front[0] = '\0'; back[0] = '\0'; strcpy(basestring, line); delete [] templine; return; } // something weird may have happened, send all ouptut to middle string if (startp == NULL || endp == NULL) { front[0] = '\0'; back[0] = '\0'; strcpy(basestring, line); delete [] templine; return; } // both the start and the end marker were found so split up the // string into three pieces startp[0] = '\0'; endp[0] = '\0'; strcpy(front, templine); strcpy(basestring, &startp[lengths]); strcpy(back, &endp[lengthe]); delete [] templine; } ////////////////////////////// // // usage -- gives the usage statement for the quality program // void usage(const char* command) { cout << "Extracts pitch information from <tt>**kern</tt> spines and converts them \n" "to a base-12 representation which preserves interval qualities between \n" "pitches. \n" " \n" "Usage: " << command << " [-r][-p] input \n" " \n" "Options: \n" " -r = keep **kern rhythms and other kern information. \n" " -p = convert to base12 pitch class, not asolute pitch. \n" " -k = convert from **base12 to **kern \n" " --options = list of all options, aliases and default values \n" " \n" << endl; } // md5sum: 4149c2ef57a5f9b7b1d88724ed331a08 base12.cpp [20050403]