// // Programmer: Craig Stuart Sapp Creation Date: // Mon Jan 26 08:53:14 PST 2004 // Last Modified: Fri Apr 9 19:02:18 PDT 2004 (rhythmic feature extraction) // Last Modified: Mon Apr 12 14:05:52 PDT 2004 (adding more rhythm features) // Last Modified: Fri Apr 16 18:01:03 PDT 2004 (added directory processing) // Last Modified: Sun Aug 8 18:44:36 PDT 2004 (added more rhythm features) // Last Modified: Thu Oct 30 10:38:19 PST 2008 (closedir fix for OSX) // Last Modified: Wed Jul 1 16:11:07 PDT 2009 (added polyphonic extraction) // Filename: ...museinfo/examples/all/themebuilderx.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/themebuilderx.cpp // Syntax: C++; museinfo // // Description: Converts Humdrum files into themefinder search index records. // // Classical Thema index order: // is: [Zz] { # : % } j J M // // Meaning of the tracer symbols: // [Zz] = major/minor key // { = 12-tone interval // # = pitch refined contour // : = pitch gross contour // % = scale degree // } = musical interval // j = 12-tone pitch // J = absolute pitch // M = metric description // Added rhythmic markers: // ~ = duration gross contour // ^ = duration refined contour // ! = duration (IOI) // & = beat level // @ = metric gross contour // ` = metric refined contour // ' = metric level // #include "humdrum.h" #ifndef OLDCPP #include #include using namespace std; #else #include #include #endif // includes needed for file/directory processing: #include #include #include #include class ISTN { public: char *istn; char *filename; ISTN(void) { istn = NULL; filename = NULL; } ISTN(ISTN& anISTN) { int len; if (anISTN.istn == NULL) { istn = NULL; } else { len = strlen(anISTN.istn); istn = new char[len+1]; strcpy(istn, anISTN.istn); } if (anISTN.filename == NULL) { filename = NULL; } else { len = strlen(anISTN.filename); filename = new char[len+1]; strcpy(filename, anISTN.filename); } } void print(void) { if (istn != NULL) { cout << istn; } else { cout << "."; } cout << "\t"; if (filename != NULL) { cout << filename; } else { cout << "."; } cout << "\n"; } int is_valid(void) { if (filename == NULL) return 0; if (istn == NULL) return 0; return 1; } void setFilename(const char* string) { if (filename != NULL) { delete [] filename; } filename = new char[strlen(string)+1]; strcpy(filename, string); } void setIstn(const char* string) { if (istn != NULL) { delete [] istn; } istn = new char[strlen(string)+1]; strcpy(istn, string); } ISTN& operator=(ISTN& anISTN) { if (this == &anISTN) return *this; clear(); int len; if (anISTN.istn == NULL) { istn = NULL; } else { len = strlen(anISTN.istn); istn = new char[len+1]; strcpy(istn, anISTN.istn); } if (anISTN.filename == NULL) { filename = NULL; } else { len = strlen(anISTN.filename); filename = new char[len+1]; strcpy(filename, anISTN.filename); } return *this; } ~ISTN() { clear(); } void clear(void) { if (istn != NULL) delete [] istn; if (filename != NULL) delete [] filename; istn = NULL; filename = NULL; } }; // function declarations: void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); void createIndex (HumdrumFile& hfile, const char* filename); void createIndexEnding (HumdrumFile& hfile, int index); void extractPitchSequence (Array& pitches, HumdrumFile& hfile, int track); void extractDurationSequence(Array& durations, HumdrumFile& hfile, int track); void extractMetricSequence (Array& metriclevel, HumdrumFile& hfile, int track); void getKey (HumdrumFile& hfile, int& mode, int& tonic); void printKey (int mode, int tonic); void printMeter (HumdrumFile& hfile); // pitch sequence printing: void printPitch (Array& pitches); void printGrossContour (Array& pitches); void printRefinedContour (Array& pitches); void print12toneInterval (Array& pitches); void print12tonePitch (Array& pitches); void printScaleDegree (Array& pitches, int tonic); void printMusicalInterval (Array& pitches); // rhythm sequence printing: void printGrossContourRhythm (Array& durations); void printRefinedContourRhythm(Array& durations); void printMetricLevel (Array& levels); void printMetricRefinedContour (Array& levels); void printMetricGrossContour (Array& levels); void printBeatLevel (Array& levels); void printDuration (Array& levels); void extractFeatureSet (const char* features); int is_directory (const char* path); int is_file (const char* path); void processArgument (const char* path); void fillIstnDatabase (Array& istndatabase, const char* istnfile); const char* getIstn (const char* filename); // User interface variables: Options options; int debugQ = 0; // used with --debug option int polyQ = 0; // used with --poly option int rhythmQ = 0; // used with -r option int pitchQ = 1; // used with -p option int extraQ = 1; // used with -E option int limitQ = 0; // used with -l option int limit = 20; // used with -l option int istnQ = 0; // used with --istn option const char* istnfile= ""; // used with --istn option Array istndatabase; // used with --istn option #define PSTATESIZE 128 int pstate[PSTATESIZE] = {0}; // true for printing of particular feature #define pHumdrumFormat 0 //pitch printing states: #define pPitch 1 #define pGrossContour 2 #define pRefinedContour 3 #define p12toneInterval 4 #define p12tonePitch 5 #define pScaleDegree 6 #define pMusicalInterval 7 // rhythm printing states: #define pDurationGrossContour 8 #define pDurationRefinedContour 9 #define pDuration 10 #define pBeat 11 #define pMetricLevel 12 #define pMetricRefinedContour 13 #define pMetricGrossContour 14 ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { checkOptions(options, argc, argv); // process the command-line options int i; int numinputs = options.getArgCount(); HumdrumFile hfile; for (i=0; id_name, ".", 1) == 0) { entry = readdir(dir); continue; } fullname = new char[strlen(path) + 1 + strlen(entry->d_name) + 1]; strcpy(fullname, path); strcat(fullname, "/"); strcat(fullname, entry->d_name); processArgument(fullname); entry = readdir(dir); } } if (dir != NULL) { closedir(dir); } } ////////////////////////////// // // is_file -- returns true if the string is a file. // int is_file(const char* path) { struct stat filestat; stat(path, &filestat); return S_ISREG(filestat.st_mode); } ////////////////////////////// // // is_directory -- returns true if the string is a directory. // int is_directory(const char* path) { struct stat filestat; stat(path, &filestat); return S_ISDIR(filestat.st_mode); } ////////////////////////////// // // getIstn -- // const char* getIstn(const char* filename) { int i; const char* output = NULL; for (i=0; i pitches; Array durations; Array metriclevels; extractPitchSequence(pitches, hfile, index); int mode = 0; int tonic = 2; getKey(hfile, mode, tonic); if (extraQ) { cout << '\t'; printKey(mode, tonic); } if (pstate[p12toneInterval]) { cout << '\t'; print12toneInterval(pitches); } if (pstate[pRefinedContour]) { cout << '\t'; printRefinedContour(pitches); } if (pstate[pGrossContour]) { cout << '\t'; printGrossContour(pitches); } if (pstate[pScaleDegree]) { cout << '\t'; printScaleDegree(pitches, tonic); } if (pstate[pMusicalInterval]) { cout << '\t'; printMusicalInterval(pitches); } if (pstate[p12tonePitch]) { cout << '\t'; print12tonePitch(pitches); } if (pstate[pPitch]) { cout << '\t'; printPitch(pitches); } if (extraQ) { cout << '\t'; printMeter(hfile); } if (rhythmQ) { extractDurationSequence(durations, hfile, index); extractMetricSequence(metriclevels, hfile, index); if (pstate[pDurationGrossContour]) { cout << '\t'; printGrossContourRhythm(durations); } if (pstate[pDurationRefinedContour]) { cout << '\t'; printRefinedContourRhythm(durations); } if (pstate[pDuration]) { cout << '\t'; printDuration(durations); } if (pstate[pBeat]) { cout << '\t'; printBeatLevel(metriclevels); } if (pstate[pMetricLevel]) { cout << '\t'; printMetricLevel(metriclevels); } if (pstate[pMetricRefinedContour]) { cout << '\t'; printMetricRefinedContour(metriclevels); } if (pstate[pMetricGrossContour]) { cout << '\t'; printMetricGrossContour(metriclevels); } } } ////////////////////////////// // // printGrossContourRhythm -- // void printGrossContourRhythm(Array& durations) { int i; cout << "~"; for (i=1; i 0) { cout << '>'; } else if (durations[i] - durations[i-1] < 0) { cout << '<'; } else { cout << '='; } } } ////////////////////////////// // // printRefinedContourRhythm -- // void printRefinedContourRhythm(Array& durations) { int i; cout << "^"; double value; for (i=1; i 2.0) { cout << "]"; } else if (value > 1.0) { cout << ">"; } else if (value == 1.0) { cout << "="; } else if (value >= 0.5) { cout << "<"; } else if (value < 0.5) { cout << "["; } else { cout << "X"; } } } } /* Old definition (a ratio between adjacent notes) void printRefinedContourRhythm(Array& durations) { int i; cout << "^"; double value; int ivalue; for (i=1; i& durations) { int i; int j; int k; int len; char buffer[128] = {0}; cout << "!"; int count; for (i=0; i 0 && (buffer[0] == 'q')) { count = (int)durations[i]; for (j=0; j 0) { Convert::durationToKernRhythm(buffer, durations[i]-count); } len = strlen(buffer); for (k=0; k& levels) { int i; cout << "\'"; double value; int ivalue; for (i=0; i 0) { cout << "p"; } else if (ivalue < 0) { cout << "m"; ivalue = -ivalue; } cout << ivalue << " "; } } ////////////////////////////// // // printMetricRefinedContour -- // void printMetricRefinedContour(Array& levels) { int i; cout << "`"; double value; int ivalue; double bvalue; int bivalue; int zvalue; for (i=1; i 1) { cout << "H"; } else if (zvalue == 1) { cout << "h"; } else if (zvalue == 0) { cout << "S"; } else if (zvalue == -1) { cout << "w"; } else if (zvalue < -1) { cout << "W"; } else { cout << "x"; } } } ////////////////////////////// // // printMetricGrossContour -- // void printMetricGrossContour(Array& levels) { int i; cout << "@"; double value; int ivalue; double bvalue; int bivalue; int zvalue; for (i=1; i 0) { cout << "H"; } else if (zvalue < 0) { cout << "W"; } else { cout << "S"; } } } ////////////////////////////// // // printBeatLevel -- // void printBeatLevel(Array& levels) { int i; cout << "&"; double value; int ivalue; for (i=0; i= 0) { cout << 1; } else { cout << 0; } } } ////////////////////////////// // // printMusicalInterval -- // void printMusicalInterval(Array& pitches) { cout << '}'; // print the musical interval identification marker int octave; int interval; int degree; int direction; int i; for (i=1; i& pitches, int tonic) { cout << '%'; // print the scale-degree identification marker int i; for (i=0; i& pitches) { int i; cout << '#'; // print the refined-contour identification marker for (i=1; i pitches[i-1]) { if (pitches[i] - pitches[i-1] < 9) { cout << 'u'; } else { cout << 'U'; } } else { cout << 's'; } } } ////////////////////////////// // // printGrossContour -- // void printGrossContour(Array& pitches) { int i; cout << ':'; // print the gross-contour identification marker for (i=1; i pitches[i-1]) { cout << 'U'; } else { cout << 'S'; } } } ////////////////////////////// // // printPitch -- // void printPitch(Array& pitches) { int i; int j; char buffer[128] = {0}; cout << 'J'; // print the pitch identification marker for (i=0; i& metriclevels, HumdrumFile& hfile, int track) { Array metlev; hfile.analyzeMetricLevel(metlev); int i, j; metriclevels.setSize(metlev.getSize()); metriclevels.setSize(1000); metriclevels.setSize(0); metriclevels.allowGrowth(); double level; for (i=0; i& durations, HumdrumFile& hfile, int track) { durations.setSize(10000); durations.setSize(0); durations.allowGrowth(); double dur = 0; int i, j; int pitch; for (i=0; i 10000)) { // ignore rests and other strange things break; } dur = hfile.getTiedDuration(i, j); durations.append(dur); if (limitQ) { if (durations.getSize() >= limit) { return; } } break; } break; default: break; } } } ////////////////////////////// // // extractPitchSequence -- // restrictions: // (1) **kern data expected is track being searched // (2) chords will be ignored, only first note in chord will be processed. // void extractPitchSequence(Array& pitches, HumdrumFile& hfile, int track) { pitches.setSize(10000); pitches.setGrowth(10000); pitches.setSize(0); pitches.allowGrowth(); int pitch = 0; int i, j; for (i=0; i 10000)) { // ignore rests and other strange things break; } pitches.append(pitch); if (limitQ) { if (pitches.getSize() >= limit) { return; } } break; } break; default: break; } } } ////////////////////////////// // // checkOptions -- // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("debug=b", "print debug information"); opts.define("poly=b", "create poliphonic"); opts.define("E|no-extra=b", "do nto print extra information"); opts.define("r|rhythm=b", "extract rhythm information"); opts.define("p|pitch=b", "extract pitch information"); opts.define("P|not-pitch=b", "do not extract pitch information"); opts.define("a|all=b", "extract all possible musical features"); opts.define("H|humdrum=b", "format output as a humdrum file"); opts.define("f|features=s", "extract the list of features"); opts.define("t|istn|translate=s", "translation file which contains istn values"); opts.define("l|limit=i:20", "limit the number of extracted features"); 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, Jan 2004" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 26 Jan 2004" << 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); } debugQ = opts.getBoolean("debug"); polyQ = opts.getBoolean("poly"); rhythmQ = opts.getBoolean("rhythm"); pitchQ = 1; extraQ = !opts.getBoolean("no-extra"); limitQ = opts.getBoolean("limit"); limit = opts.getInteger("limit"); istnQ = opts.getBoolean("istn"); istnfile = opts.getString("istn"); if (istnQ) { fillIstnDatabase(istndatabase, istnfile); } if (rhythmQ) { pitchQ = opts.getBoolean("pitch"); } if (opts.getBoolean("all")) { rhythmQ = 1; pitchQ = 1; } if (options.getBoolean("not-pitch")) { pitchQ = 0; } if (!opts.getBoolean("humdrum")) { pstate[pHumdrumFormat] = 1; } if (opts.getBoolean("features")) { extractFeatureSet(opts.getString("features")); } else { // set up the printing options. pstate[pGrossContour] = pitchQ; pstate[pRefinedContour] = pitchQ; pstate[p12toneInterval] = pitchQ; pstate[p12tonePitch] = pitchQ; pstate[pScaleDegree] = pitchQ; pstate[pMusicalInterval] = pitchQ; pstate[pPitch] = pitchQ; pstate[pDurationGrossContour] = rhythmQ; pstate[pDurationRefinedContour] = rhythmQ; pstate[pDuration] = rhythmQ; pstate[pBeat] = rhythmQ; pstate[pMetricLevel] = rhythmQ; pstate[pMetricRefinedContour] = rhythmQ; pstate[pMetricGrossContour] = rhythmQ; } } ////////////////////////////// // // extractFeatureSet -- // // Pitch Abbreviations // P = Pitch // GC, PGC = GrossContour // RC, PRC = RefinedContour // 12I = 12toneInterval // 12P = 12tonePitch // SD, S, D = ScaleDegree // MI, I = MusicalInterval // Rhythm Abbreviations: // RGC = RhythmGrossContour // RRC = RhythmRefinedContour // IOI = Duration // BLV = BeatLevel // MLV = Metric Level // MLI = Metric Interval // void extractFeatureSet(const char* features) { char *buffer; int length = strlen(features); buffer = new char[length+1]; int i; for (i=0; i& istndatabase, const char* istnfile) { HumdrumFile infile; infile.read(istnfile); int i, j; ISTN entry; istndatabase.setSize(infile.getNumLines()); istndatabase.setSize(0); for (i=0; i