Goto: [ Program Documentation ]
// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Thu Jun 22 17:16:28 PDT 2000 // Last Modified: Thu Jun 22 17:16:32 PDT 2000 // Last Modified: Thu Jun 29 21:21:31 PDT 2000 // Filename: ...sig/exmaples/all/vofun.cpp // Web Page: http://sig.sapp.org/examples/museinfo/humdrum/vofun.cpp // Syntax: C++; museinfo // Reference: http://dactyl.som.ohio-state.edu/Humdrum/representations/embel.rep.html // // Description: Analyzes **kern data for voice function analyses. // // #include "humdrum.h" #include <string.h> #include <stdlib.h> #include <ctype.h> #ifndef OLDCPP #include <iostream> #else #include <iostream.h> #endif // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void determineChordQuality(ChordQuality& cq, const HumdrumRecord& aRecord); void example(void); void prepareOutput(void); void processRecords(HumdrumFile& infile); void usage(const char* command); void doAnalysis(void); // global variables Options options; // database for command-line arguments char unknown[256] = {0}; // space for unknown chord simplification int chordinit; // for initializing chord detection function EnumerationEmbellish embellish; int spinecount = 0; // the number of **kern spines in the input Array<int> Line; // the translation between elements and // file line numbers. typedef Array<int> arrayint; Array<arrayint> Notes; // the input notes to be analyzed Array<arrayint> Functions; // the output functions Array<int> Inversion; // the inversion value for the harmony Array<int> Root; // the root value for the harmony in Base 40 Array<int> Quality; // the quality for the harmony HumdrumFile infile, outfile; /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { // initialize harmony tracking arrays Inversion.setSize(10000); Root.setSize(10000); Quality.setSize(10000); Line.setSize(10000); Notes.setSize(100); Functions.setSize(100); int k; for (k=0; k<100; k++) { Notes[k].setSize(10000); Notes[k].setSize(0); Notes[k].allowGrowth(); Functions[k].setSize(10000); Functions[k].setSize(0); Functions[k].allowGrowth(); } Inversion.setSize(0); Root.setSize(0); Quality.setSize(0); Line.setSize(0); Notes.setSize(0); Functions.setSize(0); Inversion.allowGrowth(); Root.allowGrowth(); Quality.allowGrowth(); Line.allowGrowth(); Notes.allowGrowth(); Functions.allowGrowth(); // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process int numinputs = options.getArgCount(); for (int i=0; i<numinputs || i==0; i++) { chordinit = 1; infile.clear(); outfile.clear(); // if no command-line arguments read data file from standard input if (numinputs < 1) { infile.read(cin); } else { infile.read(options.getArg(i+1)); } // analyze the input file according to command-line options processRecords(infile); doAnalysis(); prepareOutput(); outfile.write(cout); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // doAnalysis -- generate the voice function analysis // void doAnalysis(void) { // first mark the chord tones int i, j; for (i=0; i<Quality.getSize(); i++) { if (Quality[i] < 10000) { for (j=0; j<Functions.getSize(); j++) { Functions[j][i] = E_embel_ct; } } } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("t|type=b"); // show only chord type opts.define("i|inversion=b"); // show only chord inversion opts.define("r|root=b"); // show only chord root opts.define("a|assemble=b"); // assemble analysis with input opts.define("f|format=s:t:i:r"); // control display style opts.define("u|unknown=s:X"); // control display of unknowns opts.define("d|debug=b"); // determine bad input line num opts.define("author=b"); // 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, June 2000" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 22 June 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("root")) { ChordQuality::setDisplay("r"); } else if (opts.getBoolean("type")) { ChordQuality::setDisplay("t"); } else if (opts.getBoolean("inversion")) { ChordQuality::setDisplay("i"); } else { ChordQuality::setDisplay(opts.getString("format")); } Convert::chordType.setNullName(opts.getString("unknown")); Convert::chordInversion.setNullName(opts.getString("unknown")); Convert::kernPitchClass.setNullName(opts.getString("unknown")); strncpy(unknown, opts.getString("unknown"), 64); strcat(unknown, ":"); strncat(unknown, opts.getString("unknown"), 64); strcat(unknown, ":"); strncat(unknown, opts.getString("unknown"), 64); } ////////////////////////////// // // determineChordQuality -- extracts notes from humdrum data record // and sends them to a chord identifier. Notes from previous // records are remembered, and replace any null records in the // data. Rests are represented by some negative value // and will be ignored by the chord identifier. // void determineChordQuality(ChordQuality& cq, const HumdrumRecord& aRecord) { static SigCollection<int> lastnotes; // for keeping track of null record notes int i; if (chordinit) { chordinit = 0; lastnotes.setSize(aRecord.getFieldCount()); for (i=0; i<aRecord.getFieldCount(); i++) { lastnotes[i] = E_root_rest; } // remove non-kern spines from note list for (i=0; i<aRecord.getFieldCount(); i++) { if (aRecord.getExInterpNum(i) != E_KERN_EXINT) { lastnotes.setSize(lastnotes.getSize() - 1); } } } // determine chord notes and send to chord identifier SigCollection<int> currentNotes(lastnotes.getSize()); int count = 0; for (i=0; i<aRecord.getFieldCount(); i++) { if (aRecord.getExInterpNum(i) == E_KERN_EXINT) { if (strcmp(aRecord[i], ".") == 0) { currentNotes[count] = lastnotes[count]; } else { currentNotes[count] = Convert::kernToBase40(aRecord[i]); lastnotes[count] = currentNotes[count]; } count++; } } Convert::noteSetToChordQuality(cq, currentNotes); } ////////////////////////////// // // example -- example usage of the quality program // void example(void) { cout << " \n" "# example usage of the quality program. \n" "# analyze a Bach chorale for chord qualities: \n" " quality chor217.krn \n" " \n" "# display the chord analysis with original data: \n" " quality -a chor217.krn \n" " \n" "# display only the roots of chords: \n" " quality -r chor217.krn \n" " \n" << endl; } ////////////////////////////// // // prepareOutput -- generates the final output file which will be // sent to standard output. // void prepareOutput(void) { int i, j; for (i=0; i<Line.getSize(); i++) { cout << Line[i] << ":\t"; cout << "{"; for (j=0; j<Notes.getSize(); j++) { cout << Notes[j][i] << ":"; } cout << "}"; cout << "<"; for (j=0; j<Functions.getSize(); j++) { cout << Functions[j][i] << ":"; } cout << ">"; cout << "\ti=" << Inversion[i] << "\tr=" << Root[i] << "\tq=" << Quality[i] << "\n"; } char buffer[1024] = {0}; int k; j = 0; for (int i=0; i<infile.getNumLines(); i++) { switch (infile[i].getType()) { case E_humrec_data: buffer[0] = '\0'; for (k=0; k<spinecount; k++) { if (Notes[k][j] == -1) { strcat(buffer, "."); } else if (Functions[k][j] >= 0) { strcat(buffer, embellish.getName(Functions[k][j])); } else { strcat(buffer, "?"); } if (k < spinecount - 1) { strcat(buffer, "\t"); } } outfile.appendLine(buffer); j++; break; default: outfile.appendLine(infile[i]); } } } ////////////////////////////// // // processRecords -- looks at humdrum records and determines chord // quality // void processRecords(HumdrumFile& infile) { ChordQuality quality; HumdrumRecord currRecord; int i, j; for (i=0; i<infile.getNumLines(); i++) { if (options.getBoolean("debug")) { cout << "processing line " << (i+1) << " of input ..." << endl; } currRecord = infile[i]; switch (currRecord.getType()) { case E_humrec_none: case E_humrec_empty: case E_humrec_bibliography: case E_humrec_global_comment: break; case E_humrec_data_comment: if (currRecord.equalFieldsQ("**kern")) { currRecord.appendField(currRecord[0]); } else { currRecord.appendField("!"); } break; case E_humrec_data_interpretation: if (strncmp(currRecord[0], "**", 2) == 0) { spinecount = currRecord.getFieldCount(); Notes.setSize(spinecount); Functions.setSize(spinecount); } else if (currRecord.equalFieldsQ("**kern")) { currRecord.appendField(currRecord[0]); } else { currRecord.appendField("*"); } break; case E_humrec_data_kern_measure: if (currRecord.equalFieldsQ("**kern")) { currRecord.appendField(currRecord[0]); } else { currRecord.appendField("="); } break; case E_humrec_data: // handle null fields if (currRecord.equalFieldsQ("**kern", ".")) { currRecord.appendField("."); break; } determineChordQuality(quality, infile[i]); Line.append(i); for (j=0; j<infile[i].getFieldCount(); j++) { Notes[j].appendcopy(Convert::kernToBase40(infile[i][j])); Functions[j].appendcopy(-1); } Inversion.appendcopy(quality.getInversion()); Root.appendcopy(quality.getRoot()); Quality.appendcopy(quality.getType()); break; default: cerr << "Error on line " << (i+1) << " of input" << endl; exit(1); } } } ////////////////////////////// // // usage -- gives the usage statement for the quality program // void usage(const char* command) { cout << " \n" "Analyzes **kern data and generates a **qual spine which gives the chord \n" "quality of the **kern spines. Currently, input spines cannot split or \n" "join. \n" " \n" "Usage: " << command << " [-a][-i|-r|-t] [input1 [input2 ...]] \n" " \n" "Options: \n" " -a = assemble the **qual analysis spine with input data \n" " -i = displays the **qual chord inversion only \n" " -r = displays the **qual chord root only \n" " -t = displays the **qual chord type only \n" " --options = list of all options, aliases and default values \n" " \n" << endl; } // md5sum: 7db20031dd986c32cb490eaa28e84c1f chordtone.cpp [20090626]