// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Sat May 1 16:20:50 PDT 2004 // Last Modified: Sat May 1 16:20:52 PDT 2004 // Last Modified: Wed May 27 01:00:49 PDT 2009 (fixed out filename in cwd) // Filename: ...museinfo/examples/all/thememakerx.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/thememakerx.cpp // Syntax: C++; museinfo // // Description: Extract incipits from monophonic Humdrum files which contain // phrase markings (preferrably). // #include "humdrum.h" #ifndef OLDCPP #include <iostream> #include <fstream> using namespace std; #else #include <iostream.h> #include <fstream.h> #endif // includes needed for file/directory processing: #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <string.h> // function declarations: void checkOptions(Options& opts, int argc, char** argv); void example(void); void usage(const char* command); void createIncipit(HumdrumFile& hfile, const char* filename, const char* sourcebase, int limit); void extractPitchSequence(Array<int>& pitches, Array<int>& phrase, HumdrumFile& hfile); int is_directory (const char* path); int is_file (const char* path); void processArgument(const char* path); void createOutputName(char* outfile, const char* filename, const char* target, const char* sourcebase); void checkTargetDirectory(const char* outfile); void getPhrasesAndNoteLines(Array<int>& lines, Array<int>& phrase, HumdrumFile& hfile); int getEndingLine(Array<int>& lines, Array<int>& phrase, HumdrumFile& hfile, int limit); // User interface variables: Options options; int debugQ = 0; // used with --debug option int limitQ = 0; // used with -l option int limit = 30; // used with -l option int minval = 10; // used with -m option const char* target = "."; // used with -b option char sourcebase[2048] = {0}; ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { checkOptions(options, argc, argv); // process the command-line options int i; int numinputs = options.getArgCount(); HumdrumFile hfile; strcpy(sourcebase, "."); for (i=0; i<numinputs || i==0; i++) { hfile.clear(); // if no command-line arguments read data file from standard input if (numinputs < 1) { hfile.read(cin); createIncipit(hfile, "", sourcebase, limit); } else { if (is_directory(options.getArg(i+1))) { strcpy(sourcebase, options.getArg(i+1)); } processArgument(options.getArg(i+1)); } } return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // processArgument -- check if the argument is a file or a directory. // If a directory, then process all files/subdirectories in it. // void processArgument(const char* path) { HumdrumFile hfile; DIR* dir = NULL; char* fullname; struct dirent* entry; int namelen = 0; int valid = 0; if (is_file(path)) { namelen = strlen(path); valid = 0; if (strcmp(&(path[namelen-4]), ".krn") == 0) { valid = 1; } else if (strcmp(&(path[namelen-4]), ".KRN") == 0) { valid = 1; } if (!valid) { return; } hfile.read(path); createIncipit(hfile, path, sourcebase, limit); } else if (is_directory(path)) { dir = opendir(path); if (dir == NULL) { return; } entry = readdir(dir); while (entry != NULL) { if (strncmp(entry->d_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); } } closedir(dir); } ////////////////////////////// // // is_file -- returns true if the string is a file. // int is_file(const char* path) { struct stat filestat; if (stat(path, &filestat)) { return 0; } 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; if (stat(path, &filestat)) { return 0; } return S_ISDIR(filestat.st_mode); } ////////////////////////////// // // createIncipit -- // void createIncipit(HumdrumFile& hfile, const char* filename, const char* sourcebase, int limit) { char outfile[4096] = {0}; createOutputName(outfile, filename, target, sourcebase); cout << "creating incipit for: " << filename << "\toutput: " << outfile << endl; fstream output; output.open(outfile, ios::out); if (!output.is_open()) { cout << "Error opening file to write: " << outfile << endl; exit(1); } Array<int> lines; Array<int> phrase; getPhrasesAndNoteLines(lines, phrase, hfile); int endline = getEndingLine(lines, phrase, hfile, limit); int i; for (i=0; i<hfile.getNumLines(); i++) { switch (hfile[i].getType()) { case E_humrec_global_comment: if (i < endline) { output << hfile[i] << "\n"; } break; case E_humrec_bibliography: output << hfile[i] << "\n"; break; case E_humrec_data_comment: if (i < endline) { output << hfile[i][0] << "\n"; } break; case E_humrec_data_kern_measure: if (i < endline+1) { output << hfile[i][0] << "\n"; } break; case E_humrec_interpretation: if (i < endline) { if ((strcmp(hfile[i][0], "*v") != 0) && (strcmp(hfile[i][0], "*^") != 0) && (strcmp(hfile[i][0], "*x") != 0)) { output << hfile[i][0] << "\n"; } } break; case E_humrec_data: if (i < endline) { output << hfile[i][0] << "\n"; } break; case E_humrec_empty: case E_humrec_none: default: break; } if (i == endline) { output << "*-\n"; } } output.close(); } ////////////////////////////// // // getEndingLine -- // int getEndingLine(Array<int>& lines, Array<int>& phrase, HumdrumFile& hfile, int limit) { int i; int start = lines.getSize()-1; if (start > limit) { start = limit; } int phraseboundary = start; if (phrase[phraseboundary] <= 1) { if (phraseboundary < minval) { phraseboundary = limit; } if (phraseboundary >= lines.getSize()) { phraseboundary = lines.getSize()-1; } return lines[phraseboundary]; } for (i=start; i>=0; i--) { if (i>0 && (phrase[i] != phrase[i-1])) { phraseboundary = i; break; } } if (phraseboundary < minval) { phraseboundary = limit; } if (phraseboundary >= lines.getSize()) { phraseboundary = lines.getSize()-1; } return lines[phraseboundary]; } ////////////////////////////// // // getPhrasesAndNoteLines -- // void getPhrasesAndNoteLines(Array<int>& lines, Array<int>& phrase, HumdrumFile& hfile) { lines.setSize(hfile.getNumLines()); lines.setSize(0); phrase.setSize(hfile.getNumLines()); phrase.setSize(0); int pcount = 0; int i; for (i=0; i<hfile.getNumLines(); i++) { if (hfile[i].getType() != E_humrec_data) { continue; } if (strcmp(hfile[i][0], ".") == 0) { // ignore null tokens continue; } if (strchr(hfile[i][0], '{') != NULL) { pcount++; } if (strchr(hfile[i][0], 'r') != NULL) { // ignore rests continue; } if (strchr(hfile[i][0], ']') != NULL) { // ignore tie endings continue; } if (strchr(hfile[i][0], '_') != NULL) { // ignore tie continuations continue; } lines.append(i); phrase.append(pcount); } } ////////////////////////////// // // createOutputName -- // void createOutputName(char* outfile, const char* filename, const char* target, const char* sourcebase) { strcpy(outfile, target); strcat(outfile, "/"); char buffer[1024] = {0}; strcpy(buffer, filename); int len2 = strlen(buffer); char* dot = strrchr(buffer, '.'); if (len2 - (int)(dot - buffer) == 4) { strcpy(dot, ".thm"); } else { strcat(buffer, ".thm"); } char* ptr; ptr = strrchr(buffer, '/'); if (ptr) { strcat(outfile, ptr+1); } else { strcat(outfile, buffer); } checkTargetDirectory(outfile); } ////////////////////////////// // // checkTargetDirectory -- create the target directory if it does not // exist. // void checkTargetDirectory(const char* outfile) { char buffer[4096] = {0}; strncpy(buffer, outfile, 4000); char* end = strrchr(buffer, '/'); if (end == NULL) { return; } end[0] = '\0'; if (is_directory(buffer)) { return; } char fulldir[4096] = {0}; if (buffer[0] == '/') { strcpy(fulldir, "/"); } char* ptr = strtok(buffer, "/"); while (ptr != NULL) { strcat(fulldir, ptr); if (!is_directory(fulldir)) { cout << "Creating the directory: " << fulldir << endl; if (mkdir(fulldir, 0755)) { cout << "ERROR creating the directory: "<< fulldir << endl; exit(1); } } strcat(fulldir, "/"); ptr = strtok(NULL, "/"); } } ////////////////////////////// // // extractPitchSequence -- // restrictions: // (1) **kern data must be first column in file. // (2) chords will be ignored, only first note in chord will be processed. // void extractPitchSequence(Array<int>& pitches, HumdrumFile& hfile) { pitches.setSize(10000); pitches.setGrowth(10000); pitches.setSize(0); pitches.allowGrowth(); int pitch = 0; int i; for (i=0; i<hfile.getNumLines(); i++) { switch (hfile[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: case E_humrec_data_kern_measure: break; case E_humrec_data: if (strcmp(hfile[i][0], ".") == 0) { // ignore null tokens break; } if (strchr(hfile[i][0], '_') != NULL) { // ignore continuing ties break; } if (strchr(hfile[i][0], ']') != NULL) { // ignore ending ties break; } if (strchr(hfile[i][0], 'r') != NULL) { // ignore rests break; } pitch = Convert::kernToBase40(hfile[i][0]); if ((pitch < 0) || (pitch > 10000)) { // ignore rests and other strange things break; } pitches.append(pitch); if (limitQ) { if (pitches.getSize() >= limit) { return; } } break; default: break; } } } ////////////////////////////// // // checkOptions -- // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("debug=b", "print debug information"); opts.define("l|limit=i:30", "upper limit the number of extracted notes"); opts.define("m|min=i:10", "lower limit on number of extracted notes"); opts.define("t|target=s:.", "filename target base for recursive output"); 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, May 2004" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 1 May 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"); limitQ = opts.getBoolean("limit"); limit = opts.getInteger("limit"); minval = opts.getInteger("min"); target = opts.getString("target"); if (!is_directory(target)) { cout << "Error: target directory does not exist: " << target << endl; exit(1); } } ////////////////////////////// // // example -- // void example(void) { } ////////////////////////////// // // usage -- // void usage(const char* command) { } // md5sum: 607dbdf6817a432762d577e6e551c1c6 thememakerx.cpp [20090527]