// // Programmer: Craig Stuart Sapp // Creation Date: Mon Oct 27 10:42:08 PST 2008 // Last Modified: Fri Jun 26 11:23:35 PDT 2009 converted from original version // Last Modified: Thu Jul 2 15:59:04 PDT 2009 intial PCRE implementation // Last Modified: Wed Aug 25 15:55:23 PDT 2010 made -t input case insensitive // Last Modified: Thu Aug 26 14:32:01 PDT 2010 add cleaning for pitch queries // Last Modified: Wed Sep 1 15:43:34 PDT 2010 added metric position // Last Modified: Thu Sep 2 17:40:01 PDT 2010 added feature linking // Last Modified: Fri Sep 3 13:31:22 PDT 2010 added --count feature // Last Modified: Wed Sep 8 19:24:08 PDT 2010 added --limit // Last Modified: Mon Nov 22 09:24:00 PST 2010 added -B // Last Modified: Wed Nov 24 17:59:20 PST 2010 fixed -p/--location interaction // Last Modified: Sun Nov 28 13:03:28 PST 2010 added -f option // Last Modified: Tue Jan 11 19:32:58 PST 2011 added --location2 option // Last Modified: Mon Jan 17 04:12:01 PST 2011 switched --loc and --loc2 // Last Midified: Tue Jan 18 08:16:26 PST 2011 added --overlap option // Last Midified: Sat Apr 2 18:01:12 PDT 2011 added L=long B=breve durations // Last Midified: Mon Nov 7 10:40:00 PST 2011 added + == # for pitch search // Last Midified: Mon Nov 12 17:09:30 PST 2012 added note offsets // Filename: ...museinfo/examples/all/themax.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/themax.cpp // Syntax: C++; museinfo // // Description: searches an index created by tindex. Themax // is a C++ implementation of the original thema command // which was written by David Huron in 1996/1998, and // modified with a few bug fixes during the implementation // of Themefinder.org by Craig Sapp (1999-2001). // // Classical themebuilder (AWK version of tindex) entry order: // fileid [Zz] { # : % } j J M // Additional rhythmic marks: // ~ ^ ! & @ ` ' // // 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 // // Options: // -a anchor to start (implemented) // -M major keys (implemented) // -m minor keys (implemented) // -t tonic (implemented) // -T meter (implemented) // // PITCH FEATURES: // // -i { 12-tone interval (implemented) // -c # refined contour (implemented) // -C : gross contour (implemented) // -d % scale degree (implemented) // -I } musical interval (implemented) // -P j 12-tone pitch class (implemented) // -p J pitch-class name (implemented) // -D diatonic pitch-class name(implemented) // // RHYTHM FEATURES: // // -u ; duration (IOI) (implemented) // -R ~ duration gross contour (implemented) // -r ^ duration refined contour (implemented) // -b & beat level (implemented) // -l = metric position (implemented) // -E @ metric gross contour (implemented) // -e ` metric refined contour (implemented) // -L ' metric level (implemented) // // Todo: Add --repeat option which allows for any repeated notes // between pitch features. // #include "humdrum.h" #include "PerlRegularExpression.h" #ifndef OLDCPP #include #include #include #include #define SSTREAM stringstream #define CSTRING str().c_str() using namespace std; #else #include #include #include #ifdef VISUAL #include /* for windows 95 */ #else #include #endif #define SSTREAM strstream #define CSTRING str() #endif // character markers in index file (as used in tindex) #define P_PITCH_CLASS_MARKER 'J' #define P_DIATONIC_INTERVAL_MARKER '}' #define P_SCALE_DEGREE_MARKER '%' #define P_12TONE_INTERVAL_MARKER '{' #define P_REFINED_CONTOUR_MARKER '#' #define P_GROSS_CONTOUR_MARKER ':' #define P_12TONE_PITCH_CLASS_MARKER 'j' #define R_DURATION_GROSS_CONTOUR_MARKER '~' #define R_DURATION_REFINED_CONTOUR_MARKER '^' #define R_DURATION_MARKER ';' #define R_BEAT_LEVEL_MARKER '&' #define R_METRIC_POSITION_MARKER '=' #define R_METRIC_LEVEL_MARKER '\'' #define R_METRIC_GROSS_CONTOUR_MARKER '@' #define R_METRIC_REFINED_CONTOUR_MARKER '`' // function declarations: void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); void appendString (Array& ss, const char* string); void appendToSearchString (Array& ss, const char* string, char marker, int anchor); void showCleanedParameters (void); int searchForMatches (const char* filename, Array& ss, PerlRegularExpression& re, int mcount); int searchForMatches (istream& inputfile, Array& ss, PerlRegularExpression& re, int mcount); void prepareInterval (Array& data); int checkLink (string& line, int offset); void getSimpleLocationINT (Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs, int featurewidth = 1); void getSimpleLocationFET (Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs, int featurewidth = 1); void getSeparatorLocationINT(Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs, char separator = ' '); void getSeparatorLocationFET(Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs, char separator = ' '); void getMusicalIntervalLocation(Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs); // void findIntersection (Array& aa, Array& bb); void processKernString (const char* string); void removeBoundaryCharacters(string& line); void getTargetEnds (Array& targetend, Array& target, string& line); void adjustForInterleavedQuery(Options& opts); void removeOverlappedMatches (Array& target, Array& targetend); // location2Q functions void getSeparatorLocationFETEnd(Array& positions, string& line, Array& feature, char searchanchor, Array& startlocs, char separator); int countElementsA(const char* str, int ending, char separator); void getSimpleLocationINTEnd(Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs, int featurewidth = 1); int countElementsB(const char* str, int ending, int width); void getMusicalIntervalLocationEnd(Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs); int countElementsC(const char* str, int ending); // user input sanitation functions: void cleanPpitchClass (Array& data); void cleanPmusicalInterval (Array& data); void cleanPscaleDegree (Array& data); void cleanPgrossContour (Array& data); void cleanPrefinedContour (Array& data); void cleanP12tonePitchClass(Array& data); void cleanP12toneInterval (Array& data); void cleanUpRangeSyntaxNoOutsideDigitsOrComma(Array& data); void cleanRbeatLevel (Array& data); void cleanRduration (Array& data); void cleanRgrossContour (Array& data); void cleanRrefinedContour (Array& data); void cleanRmgc (Array& data); void cleanRmrc (Array& data); void cleanRmetricLevel (Array& data); void cleanRmetricPosition (Array& data); // User interface variables: Options options; int showcleanQ = 0; // used with --cleaned int verboseQ = 0; // used with --verbose option int verbose2Q = 0; // used with --verbose2 option int cleanQ = 1; // used with --no-clean option int anchoredQ = 0; // used with -a option int keyfilterQ = 0; // used with -m -M and -t options int minorQ = 0; // used with -m option int majorQ = 0; // used with -M option int debugQ = 0; // used with --debug option int regexQ = 0; // used with --regex option int quietQ = 0; // used with -q option int boundaryQ = 1; // used with -B option int shortQ = 0; // used with --short option int tonicQ = 0; // used with -t option int diatonicQ = 0; // used with -D option // const char* tonicstring = ""; // used with -t option Array tonicstring; // used with -t option int meterQ = 0; // used with -T option const char* meterstring = ""; // used with -T option Array meterss; int totalQ = 0; // used with --total option int countQ = 0; // used with --count option int locationQ = 0; // used with --locstart option int location2Q = 0; // used with --loc option int printendQ = 0; // used with --overlap and --loc options int overlapQ = 0; // used with --overlap int notQ = 0; // used with --not option int unlinkQ = 0; // used with --unlink option int featureCount = 0; // used with --unlink option int smartQ = 0; // used with --smart option int kernQ = 0; // used with -k option const char* kernstring = ""; // used with -k option int limitQ = 0; // used with --limit option int limitval = 0; // used with --limit option Array filetag; // used with -f option int TOTALCOUNT = 0; // used for --total option, hack for some problem where count is // returning file count instead of match count. Array tonicss; // tonic search string // classical searches int P12toneintervalQ = 0; // used with -i option int PgrosscontourQ = 0; // used with -c option int PrefinedcontourQ = 0; // used with -C option int PscaledegreeQ = 0; // used with -d option int PmusicalintervalQ = 0; // used with -I option int P12tonepitchclassQ = 0; // used with -P option int PpitchclassQ = 0; // used with -p option Array P12toneinterval; // used with -i option Array Pgrosscontour; // used with -c option Array Prefinedcontour; // used with -C option Array Pscaledegree; // used with -d option Array Pmusicalinterval; // used with -I option Array P12tonepitchclass; // used with -P option Array Ppitchclass; // used with -p option // extended rhythm searches int RgrosscontourQ = 0; // used with -R option int RrefinedcontourQ = 0; // used with -r option int RdurationQ = 0; // used with -u option int RbeatlevelQ = 0; // used with -b option int RmetriclevelQ = 0; // used with -L option int RmetricpositionQ = 0; // used with -l option int RmetricrefinedcontourQ = 0; // used with -e option int RmetricgrosscontourQ = 0; // used with -E option Array Rgrosscontour; // used with -R option Array Rrefinedcontour; // used with -r option Array Rduration; // used with -u option Array Rbeatlevel; // used with -b option Array Rmetriclevel; // used with -L option Array Rmetricposition; // used with -l option Array Rmetricrefinedcontour; // used with -e option Array Rmetricgrosscontour; // used with -E option // final search feature strings for use with link checking Array xP12toneinterval; Array xPgrosscontour; Array xPrefinedcontour; Array xPscaledegree; Array xPmusicalinterval; Array xP12tonepitchclass; Array xPpitchclass; Array xRgrosscontour; Array xRrefinedcontour; Array xRduration; Array xRbeatlevel; Array xRmetriclevel; Array xRmetricposition; Array xRmetricrefinedcontour; Array xRmetricgrosscontour; ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { tonicstring.setSize(1); tonicstring[0] = '\0'; checkOptions(options, argc, argv); // process the command-line options Array searchstring; Array& ss = searchstring; ss.setSize(10000); ss.setGrowth(10000); ss.setSize(0); if (filetag.getSize() > 1) { PerlRegularExpression fre; // convert dots to literal dots (not regular expression dot) fre.sar(filetag, "\\.", "\\.", "g"); // convert starts to match anything except tabs or colon fre.sar(filetag, "\\*", "[^\\t:]*", "g"); appendString(ss, "^[^:\\t]*"); appendString(ss, filetag.getBase()); appendString(ss, "[:]?[^\\t]*\\t"); appendString(ss, ".*"); } // order of data in index file: // [Zz] = major/minor key ////////////////////////////////////////////////// tonicss.setSize(0); if (keyfilterQ) { tonicss.setSize(1); tonicss[0] = '\0'; tonicss.setSize(0); if (majorQ && !minorQ) { appendString(tonicss, "Z"); } else if (minorQ && !majorQ) { appendString(tonicss, "z"); } else { appendString(tonicss, "[Zz]"); } // place the tonic search next if given if (tonicQ) { appendString(tonicss, tonicstring.getBase()); } else { appendString(tonicss, "[^=]*"); } appendString(tonicss, "="); // place the end of key information marker: appendString(ss, tonicss.getBase()); appendString(ss, ".*"); } // { = 12-tone interval ////////////////////////////////////////////////// if (P12toneintervalQ) { if (cleanQ) { cleanP12toneInterval(P12toneinterval); } appendToSearchString(ss, P12toneinterval.getBase(), P_12TONE_INTERVAL_MARKER, anchoredQ); } // # = pitch refined contour ///////////////////////////////////////////// if (PrefinedcontourQ) { if (cleanQ) { cleanPrefinedContour(Prefinedcontour); } appendToSearchString(ss, Prefinedcontour.getBase(), P_REFINED_CONTOUR_MARKER, anchoredQ); } // : = pitch gross contour /////////////////////////////////////////////// if (PgrosscontourQ) { if (cleanQ) { cleanPgrossContour(Pgrosscontour); } appendToSearchString(ss, Pgrosscontour.getBase(), P_GROSS_CONTOUR_MARKER, anchoredQ); } // % = scale degree ////////////////////////////////////////////////////// if (PscaledegreeQ) { if (cleanQ) { cleanPscaleDegree(Pscaledegree); } appendToSearchString(ss, Pscaledegree.getBase(), P_SCALE_DEGREE_MARKER, anchoredQ); } // } = musical interval ////////////////////////////////////////////////// if (PmusicalintervalQ) { if (cleanQ) { cleanPmusicalInterval(Pmusicalinterval); } appendToSearchString(ss, Pmusicalinterval.getBase(), P_DIATONIC_INTERVAL_MARKER, anchoredQ); } // j = 12-tone pitch class /////////////////////////////////////////////// if (P12tonepitchclassQ) { if (cleanQ) { cleanP12tonePitchClass(P12tonepitchclass); } appendToSearchString(ss, P12tonepitchclass.getBase(), P_12TONE_PITCH_CLASS_MARKER, anchoredQ); } // J = pitch class name ////////////////////////////////////////////////// if (PpitchclassQ) { if (cleanQ) { cleanPpitchClass(Ppitchclass); } appendToSearchString(ss, Ppitchclass.getBase(), P_PITCH_CLASS_MARKER, anchoredQ); } // M = metric description //////////////////////////////////////////////// meterss.setSize(0); if (meterQ) { appendString(meterss, "M"); if (!std::isdigit(meterstring[0])) { appendString(meterss, "[^\\t]*?"); } appendString(meterss, meterstring); appendString(ss, meterss.getBase()); appendString(ss, ".*"); } // Added rhythmic markers: // ~ = duration gross contour /////////////////////////////////////////// if (RgrosscontourQ) { if (cleanQ) { cleanRgrossContour(Rgrosscontour); } appendToSearchString(ss, Rgrosscontour.getBase(), R_DURATION_GROSS_CONTOUR_MARKER, anchoredQ); } // ^ = duration refined contour ///////////////////////////////////////// if (RrefinedcontourQ) { if (cleanQ) { cleanRrefinedContour(Rrefinedcontour); } appendToSearchString(ss, Rrefinedcontour.getBase(), R_DURATION_REFINED_CONTOUR_MARKER, anchoredQ); } // ! = duration (IOI) /////////////////////////////////////////////////// if (RdurationQ) { if (cleanQ) { cleanRduration(Rduration); } appendToSearchString(ss, Rduration.getBase(), R_DURATION_MARKER, anchoredQ); } // & = beat level /////////////////////////////////////////////////////// if (RbeatlevelQ) { if (cleanQ) { cleanRbeatLevel(Rbeatlevel); } appendToSearchString(ss, Rbeatlevel.getBase(), R_BEAT_LEVEL_MARKER, anchoredQ); } // ' = metric level ///////////////////////////////////////////////////// if (RmetriclevelQ) { if (cleanQ) { cleanRmetricLevel(Rmetriclevel); } appendToSearchString(ss, Rmetriclevel.getBase(), R_METRIC_LEVEL_MARKER, anchoredQ); } // ` = metric refined contour /////////////////////////////////////////// if (RmetricrefinedcontourQ) { if (cleanQ) { cleanRmrc(Rmetricrefinedcontour); } appendToSearchString(ss, Rmetricrefinedcontour.getBase(), R_METRIC_REFINED_CONTOUR_MARKER, anchoredQ); } // @ = metric gross contour ///////////////////////////////////////////// if (RmetricgrosscontourQ) { if (cleanQ) { cleanRmgc(Rmetricgrosscontour); } appendToSearchString(ss, Rmetricgrosscontour.getBase(), R_METRIC_GROSS_CONTOUR_MARKER, anchoredQ); } // = = metric position /////////////////////////////////////////////////// if (RmetricpositionQ) { if (cleanQ) { cleanRmetricPosition(Rmetricposition); } appendToSearchString(ss, Rmetricposition.getBase(), R_METRIC_POSITION_MARKER, anchoredQ); } ////////////////////////////////////////////////////////////////////////////// if ((!quietQ) && (overlapQ) && (locationQ || location2Q)) { cout << "#OVERLAP" << endl; } // terminate the search string char ch = '\0'; ss.append(ch); ss.setSize(ss.getSize()-1); PerlRegularExpression pre; if (pre.search(ss, "\\.\\*$", "")) { ss.setSize(ss.getSize()-2); } ss.append(ch); ss.setSize(ss.getSize()-1); ss.append(ch); if (regexQ) { cout << ss.getBase() << endl; exit(0); } if (showcleanQ) { showCleanedParameters(); cout << "Final Regular Expression: " << ss.getBase() << endl; exit(0); } pre.initializeSearchAndStudy(ss.getBase()); int i; int totalcount = 0; if (options.getArgCount() == 0) { // standard input totalcount += searchForMatches(cin, ss, pre, totalcount); } else { for (i=1; i<=options.getArgCount(); i++) { totalcount += searchForMatches(options.getArgument(i).data(), ss, pre, totalcount); if (limitQ && (totalcount >= limitval)) { break; } } } if (totalQ) { if (TOTALCOUNT > 0) { cout << TOTALCOUNT << endl; } else { cout << totalcount << endl; } } return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // searchForMatches -- // int searchForMatches(const char* filename, Array& ss, PerlRegularExpression& pre, int mcount) { ifstream inputfile; inputfile.open(filename); if (!inputfile.is_open()) { return 0; } int count = searchForMatches(inputfile, ss, pre, mcount); inputfile.close(); return count; } ////////////////////////////// // // searchForMatches -- Should be merged with above function. // int searchForMatches(istream& inputfile, Array& ss, PerlRegularExpression& pre, int mcount) { PerlRegularExpression blanktest; PerlRegularExpression messagetest; PerlRegularExpression noteoffsettest; noteoffsettest.initializeSearchAndStudy("[^\\t]+;(\\d+)\\t"); string line; int offset = 1; int state; int i; int counter = 0; while (!inputfile.eof()) { getline(inputfile, line); if (!boundaryQ) { removeBoundaryCharacters(line); } if (blanktest.search(line.c_str(), "^\\s*$", "")) { continue; } // if (messagetest.search(line.c_str(), "^#", "")) { if (line.c_str()[0] == '#') { if (!quietQ) { // echo control messages in the index file. cout << line << "\n"; } continue; } state = pre.search(line.c_str()); if (!state) { continue; } if (noteoffsettest.search(line.c_str())) { offset = atoi(noteoffsettest.getSubmatch(1)); } else { offset = 1; } if (state && (!unlinkQ) && (!anchoredQ) && (featureCount > 1)) { state = checkLink(line, offset); } else if (state && (countQ || locationQ || location2Q)) { counter += checkLink(line, offset); mcount++; continue; } if ((state && !notQ) || (notQ && !state)) { counter++; mcount++; if (verboseQ) { cout << "Matches in " << endl; } if (totalQ) { continue; } if (shortQ && (!countQ && !locationQ && !location2Q)) { i = 0; while ((line.c_str()[i] != '\0') && (line.c_str()[i] != '\t')) { cout << line.c_str()[i]; i++; } cout << "\n"; } else if (!countQ && !locationQ && !location2Q) { cout << line << "\n"; } } if (limitQ && (mcount >= limitval)) { break; } } return counter; } ////////////////////////////// // // removeBoundaryCharcters -- Remove "R", "r", "R ", or "r " after // the first tab character in the string. // void removeBoundaryCharacters(string& line) { int tabind = line.find_first_of('\t'); if (tabind < 0) { // no tab character found return; } PerlRegularExpression pre; if (!pre.search(line.c_str(), "R ?", "gi")) { // no boundary markers to remove return; } Array pretab; pretab.setSize(tabind + 1); strncpy(pretab.getBase(), line.c_str(), tabind); pretab.last() = '\0'; Array posttab; int postlen = line.length() - tabind - 1; posttab.setSize(postlen + 1); strncpy(posttab.getBase(), line.c_str()+tabind+1, postlen); posttab.last() = '\0'; pre.sar(posttab, "R ?", "", "gi"); line = pretab.getBase(); line += posttab.getBase(); } ////////////////////////////// // // checkLink -- make sure that every search feature starts at the same // note number in the data. Returns the number of matches found // on the input line. // int checkLink(string& line, int offset) { Array target; target.setSize(0); Array temptarget; if (P12toneintervalQ) { getSimpleLocationINT(temptarget, line, P12toneinterval, P_12TONE_INTERVAL_MARKER, target, 2); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (PgrosscontourQ) { getSimpleLocationINT(temptarget, line, Pgrosscontour, P_GROSS_CONTOUR_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (PrefinedcontourQ) { getSimpleLocationINT(temptarget, line, Prefinedcontour, P_REFINED_CONTOUR_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (PscaledegreeQ) { getSimpleLocationFET(temptarget, line, Pscaledegree, P_SCALE_DEGREE_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (PmusicalintervalQ) { getMusicalIntervalLocation(temptarget, line, Pmusicalinterval, P_DIATONIC_INTERVAL_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (P12tonepitchclassQ) { getSimpleLocationFET(temptarget, line, P12tonepitchclass, P_12TONE_PITCH_CLASS_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (PpitchclassQ) { getSeparatorLocationFET(temptarget, line, Ppitchclass, P_PITCH_CLASS_MARKER, target, ' '); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RgrosscontourQ) { getSimpleLocationINT(temptarget, line, Rgrosscontour, R_DURATION_GROSS_CONTOUR_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RrefinedcontourQ) { getSimpleLocationINT(temptarget, line, Rrefinedcontour, R_DURATION_REFINED_CONTOUR_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RdurationQ) { getSeparatorLocationFET(temptarget, line, Rduration, R_DURATION_MARKER, target, ' '); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RbeatlevelQ) { getSimpleLocationFET(temptarget, line, Rbeatlevel, R_BEAT_LEVEL_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RmetriclevelQ) { getSeparatorLocationFET(temptarget, line, Rmetriclevel, R_METRIC_LEVEL_MARKER, target, ' '); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RmetricpositionQ) { getSeparatorLocationFET(temptarget, line, Rmetricposition, R_METRIC_POSITION_MARKER, target, ' '); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RmetricrefinedcontourQ) { getSimpleLocationINT(temptarget, line, Rmetricrefinedcontour, R_METRIC_REFINED_CONTOUR_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } if (RmetricgrosscontourQ) { getSimpleLocationINT(temptarget, line, Rmetricgrosscontour, R_METRIC_GROSS_CONTOUR_MARKER, target); if (temptarget.getSize() == 0) { return 0; } else { target = temptarget; } } // for use with --location Array targetend; targetend.setSize(0); if (location2Q) { getTargetEnds(targetend, target, line); } else { // not necessary, but doing to anyway targetend.setSize(target.getSize()); targetend.setAll(-1); } if (!overlapQ) { removeOverlappedMatches(target, targetend); } int offsettoggle = 0; int coloncount = 0; if ((location2Q || locationQ || countQ) && (target.getSize() > 0)) { int i = 0; const char* ptr = line.c_str(); while ((ptr[i] != '\0') && (ptr[i] != '\t')) { if (ptr[i] == ':') { coloncount++; } if ((coloncount >= 2) && (ptr[i] == ';')) { offsettoggle = 1; } if (offsettoggle == 0) { cout << ptr[i]; } i++; } if (countQ) { cout << '\t' << target.getSize(); TOTALCOUNT += target.getSize(); } else { // locationQ cout << '\t'; for (i=0; i& target, Array& targetend) { Array tstart; Array tend; tstart.setSize(target.getSize()); tstart.setSize(0); tend.setSize(targetend.getSize()); tend.setSize(0); int i; int emark = -1; for (i=0; i emark) { tstart.append(target[i]); tend.append(targetend[i]); if (targetend[i] > emark) { emark = targetend[i]; } } } if (target.getSize() == tstart.getSize()) { // no overlaps, so just return return; } // copied the unoverlapped matches target = tstart; targetend = tend; } ////////////////////////////// // // getTargetEnds -- return the ending point of a match which is the // highest note number from all searches which were done. // void getTargetEnds(Array& targetend, Array& target, string& line) { targetend.setSize(target.getSize()); targetend.setAll(-1); int i; Array temptarget; temptarget.setSize(targetend.getSize()); targetend.setGrowth(0); temptarget.setAll(-1); // ggg if (PgrosscontourQ) { getSimpleLocationINTEnd(temptarget, line, Pgrosscontour, P_GROSS_CONTOUR_MARKER, target, 1); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } if (PrefinedcontourQ) { getSimpleLocationINTEnd(temptarget, line, Prefinedcontour, P_REFINED_CONTOUR_MARKER, target, 1); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } if (PscaledegreeQ) { // getSimpleLocationFETEnd -> INTEnd for now. // check interaction with segmentation markers later... getSimpleLocationINTEnd(temptarget, line, Pscaledegree, P_SCALE_DEGREE_MARKER, target, 1); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (PmusicalintervalQ) { getMusicalIntervalLocationEnd(temptarget, line, Pmusicalinterval, P_DIATONIC_INTERVAL_MARKER, target); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } if (P12tonepitchclassQ) { // getSimpleLocationFETEnd -> INTEnd for now. // check interaction with segmentation markers later... getSimpleLocationINTEnd(temptarget, line, P12tonepitchclass, P_12TONE_PITCH_CLASS_MARKER, target, 1); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (P12toneintervalQ) { getSeparatorLocationFETEnd(temptarget, line, P12toneinterval, P_12TONE_INTERVAL_MARKER, target, ' '); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (PpitchclassQ) { getSeparatorLocationFETEnd(temptarget, line, Ppitchclass, P_PITCH_CLASS_MARKER, target, ' '); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (RgrosscontourQ) { getSimpleLocationINTEnd(temptarget, line, Rgrosscontour, R_DURATION_GROSS_CONTOUR_MARKER, target); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } if (RrefinedcontourQ) { getSimpleLocationINTEnd(temptarget, line, Rrefinedcontour, R_DURATION_REFINED_CONTOUR_MARKER, target); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } if (RdurationQ) { getSeparatorLocationFETEnd(temptarget, line, Rduration, R_DURATION_MARKER, target, ' '); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (RbeatlevelQ) { // getSimpleLocationFETEnd -> INTEnd for now. // check interaction with segmentation markers later... getSimpleLocationINTEnd(temptarget, line, Rbeatlevel, R_BEAT_LEVEL_MARKER, target); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (RmetriclevelQ) { getSeparatorLocationFETEnd(temptarget, line, Rmetriclevel, R_METRIC_LEVEL_MARKER, target, ' '); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (RmetricpositionQ) { getSeparatorLocationFETEnd(temptarget, line, Rmetricposition, R_METRIC_POSITION_MARKER, target, ' '); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]; } } } if (RmetricrefinedcontourQ) { getSimpleLocationINTEnd(temptarget, line, Rmetricrefinedcontour, R_METRIC_REFINED_CONTOUR_MARKER, target); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } if (RmetricgrosscontourQ) { getSimpleLocationINTEnd(temptarget, line, Rmetricgrosscontour, R_METRIC_GROSS_CONTOUR_MARKER, target); for (i=0; i targetend[i]) { targetend[i] = temptarget[i]+1; // +1 for interval to note } } } } ////////////////////////////// // // getMusicalIntervalLocationEnd -- // void getMusicalIntervalLocationEnd(Array& positions, string& line, Array& feature, char searchanchor, Array& startlocs) { PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); int i; Array newfeature; newfeature.setSize(feature.getSize() + 4); newfeature.setSize(0); appendString(newfeature, "("); appendString(newfeature, feature.getBase()); appendString(newfeature, ")"); // Check only locations specified by startlocs. // The positions in startlocs are presumed to be sorted. // This code probably will no longer work if "R" segmentations are // present in the data. PerlRegularExpression pokey; pokey.initializeSearchAndStudy(newfeature.getBase()); const char* str = line.c_str(); i = startindex; int starting; int ending; int pos; int tindex = 0; int tsize = startlocs.getSize(); // Check only locations specified by startlocs. // The positions in startlocs are presumed to be sorted. while ((str[i] != '\0') && (str[i] != '\t') && (tindex < tsize)) { // search for the ith start position, and then extract the end position pos = pokey.search(str+i); if (pos == 0) { break; } starting = pokey.getSubmatchStart(1); ending = pokey.getSubmatchEnd(1); positions[tindex] = startlocs[tindex] + countElementsC(str+i+starting, ending-starting); tindex++; i += pokey.getSubmatchStart(1); i++; } } ////////////////////////////// // // countElementsC -- Count the number of character segments separated // by the searchanchor, and stop when the ending point in the string // has been found (or excceeded). Used with // getMusicalIntervalLocationEnd(). // int countElementsC(const char* str, int ending) { int i; int output = 0; for (i=0; i& positions, string& line, Array& feature, char searchanchor, Array& startlocs, int featurewidth) { positions.setAll(-1); if (startlocs.getSize() == 0) { return; } PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); Array newfeature; newfeature.setSize(feature.getSize() + 4); newfeature.setSize(0); appendString(newfeature, "("); appendString(newfeature, feature.getBase()); appendString(newfeature, ")"); PerlRegularExpression pokey; pokey.initializeSearchAndStudy(newfeature.getBase()); const char* str = line.c_str(); int tsize = startlocs.getSize(); int i = startindex; int pos; // start index position of match (plus 1) int ending; int starting; int tindex = 0; // Check only locations specified by startlocs. // The positions in startlocs are presumed to be sorted. while ((str[i] != '\0') && (str[i] != '\t') && (tindex < tsize)) { // search for the ith start position, and then extract the end position pos = pokey.search(str+i); if (pos == 0) { break; } starting = pokey.getSubmatchStart(1); ending = pokey.getSubmatchEnd(1); positions[tindex] = startlocs[tindex] + countElementsB(str+i+starting, ending-starting, featurewidth); tindex++; i += pokey.getSubmatchStart(1); i += featurewidth; } } ////////////////////////////// // // countElementsB -- Count the number of character segments separated // by the searchanchor, and stop when the ending point in the string // has been found (or excceeded). Used with getSimpleLocationINTEnd(). int countElementsB(const char* str, int ending, int width) { int i; int output = 0; for (i=0; i& positions, string& line, Array& feature, char searchanchor, Array& startlocs, char separator) { positions.setAll(-1); if (startlocs.getSize() == 0) { return; } PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); int i; Array newfeature; newfeature.setSize(feature.getSize() + 4); newfeature.setSize(0); appendString(newfeature, "("); appendString(newfeature, feature.getBase()); appendString(newfeature, ")"); // Check only locations specified by startlocs. // The positions in startlocs are presumed to be sorted. PerlRegularExpression pokey; pokey.initializeSearchAndStudy(newfeature.getBase()); const char* str = line.c_str(); i = startindex; int pos; // start index position of match (plus 1) int ending; int starting; int tindex = 0; int tsize = startlocs.getSize(); while ((str[i] != '\0') && (str[i] != '\t') && (tindex < tsize)) { // search for the ith start position, and then extract the end position pos = pokey.search(str+i); if (pos == 0) { break; } starting = pokey.getSubmatchStart(1); ending = pokey.getSubmatchEnd(1); positions[tindex] = startlocs[tindex] + countElementsA(str+i+starting, ending-starting, separator); tindex++; i += pokey.getSubmatchStart(1); i++; } } ////////////////////////////// // // countElementsA -- Count the number of character segments separated // by the searchanchor, and stop when the ending point in the string // has been found (or excceeded). Used with getSeparatorLocationFETEnd(). // int countElementsA(const char* str, int ending, char separator) { int i; int output = 0; for (i=0; i& aa, Array& bb) { Array output(aa.getSize()); output.setSize(0); int aSize = aa.getSize(); int bSize = bb.getSize(); int aIndex = 0; int bIndex = 0; for (aIndex = 0; aIndex < aSize; aIndex++) { if (bb[bIndex] < aa[aIndex]) { do { bIndex++; if (bIndex >= bSize) { break; } } while (bb[bIndex] < aa[aIndex]); } if (bIndex >= bSize) { break; } if (bb[bIndex] == aa[aIndex]) { output.append(aa[aIndex]); } } aa = output; } */ ////////////////////////////// // // getMusicalIntervalLocation -- return the element number in the feature // list (offset from 1) on the given line in the specified feature, // when the features are sepearated by according to musical interval // feature format, such as: // }Xm2XM2P1xm2Xm2XM2xM2P1xM2P1P1P1P1xm3P1xm3xM3XM2XM2Xm2XP5P1XP4xm2xM2 // * * * * * * * * * * * * * * * * * * * * * * * * * // (checking for segmentation when a digits is preceded by a non-digit.) // // Do NOT Ignore "R *" markers when counting notes. Add one for each // occurence of a rest. Example test data to consider: // // -m2 F 1 // -M2 E 4 // +M2 D 4 // -M3 E 1. // +M2 C 2 // -M2 D 1 // C 1 // R R R (measure 125 of Jos0802d -- bassus part) // F L // R R R // -m3 F 1 // -M2 D 2 // +P4 C 2 // -m2 F 2. // -M3 E 4 // C L // R R R // +M2 D 2. // +m2 E 4 // +M2 F 2 // -P4 G 2 // +P4 D 2 // +M2 G 2. // void getMusicalIntervalLocation(Array& positions, string& line, Array& feature, char searchanchor, Array& checklocs) { positions.setSize(0); PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); int i; // If checklocs is non-zero, then only check the feature // at the given locations; otherwise, check every position. if (checklocs.getSize() == 0) { // check every location in feature for a match (allowing overlaps) PerlRegularExpression gumby; gumby.setAnchor(); gumby.initializeSearchAndStudy(feature.getBase()); PerlRegularExpression rest; rest.setAnchor(); rest.initializeSearchAndStudy("(R *)"); const char* str = line.c_str(); int location = -1; // need to start at -1 since first spot will increment i = startindex; while ((str[i] != '\0') && (str[i] != '\t')) { if (rest.search(str+i)) { i += rest.getSubmatchEnd(1) - rest.getSubmatchStart(1); // do increment location if (location >= 0) { // but don't increment if the R marker is at the front // of the sequence. location++; } // continue; // maybe this is needed? } if ((toupper(str[i]) == 'X') || ((str[i] == 'P') && (i>=1) && (toupper(str[i-1]) != 'X'))) { location++; } if ((i > 1) && (toupper(str[i]) == 'R') && (toupper(str[i-1]) == 'R')) { location++; } // cout << "I = " << i << "\t" << str[i] << str[i+1] << str[i+2] << str[i+3] << " LOCATION = " << location << endl; if (gumby.search(str+i)) { positions.append(location); } i++; } } else { // Check only locations specified by checklocs. // The positions in checklocs are presumed to be sorted. // This code probably will no longer work if "R" segmentations are // present in the data. PerlRegularExpression pokey; pokey.setAnchor(); pokey.initializeSearchAndStudy(feature.getBase()); const char* str = line.c_str(); int location = 0; i = startindex; int targetindex = 0; int tsize = checklocs.getSize(); while ((str[i] != '\0') && (str[i] != '\t') && (targetindex < tsize)) { // Increase the target location if it is smaller than // the current search location. if (checklocs[targetindex] < location) { targetindex++; continue; } // If a separator character is found, then increment location. if ((toupper(str[i]) == 'X') || ((str[i] == 'P') && (toupper(str[i-1]) != 'X'))) { location++; } if (location == checklocs[targetindex]) { if (pokey.search(str+i)) { positions.append(location); targetindex++; } } i++; } } if (verbose2Q) { cout << "ORIGINAL LINE: " << line << endl; cout << "\tCOUNT IS " << positions.getSize() << " FOR FEATURE SEARCH " << feature.getBase() << endl; cout << "\tMATCHES AT: "; int j; for (j=0; j& positions, string& line, Array& feature, char searchanchor, Array& checklocs, char separator) { positions.setSize(0); PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); int i; // If checklocs is non-zero, then only check the feature // at the given locations; otherwise, check every position. if (checklocs.getSize() == 0) { // check every location in feature for a match (allowing overlaps) PerlRegularExpression gumby; gumby.setAnchor(); gumby.initializeSearchAndStudy(feature.getBase()); // currently rest separator is either nothing or a space PerlRegularExpression rest; rest.setAnchor(); rest.initializeSearchAndStudy("(R *)"); const char* str = line.c_str(); int location = 0; i = startindex; while ((str[i] != '\0') && (str[i] != '\t')) { if (str[i] == separator) { i++; location++; continue; } if (rest.search(str+i)) { i += rest.getSubmatchEnd(1) - rest.getSubmatchStart(1); location++; continue; } if (gumby.search(str+i)) { positions.append(location); } i++; } } else { // Check only locations specified by checklocs. // The positions in checklocs are presumed to be sorted. PerlRegularExpression pokey; pokey.setAnchor(); pokey.initializeSearchAndStudy(feature.getBase()); const char* str = line.c_str(); int location = 0; i = startindex; int targetindex = 0; int tsize = checklocs.getSize(); while ((str[i] != '\0') && (str[i] != '\t') && (targetindex < tsize)) { // Increase the target location if it is smaller than // the current search location. if (checklocs[targetindex] < location) { targetindex++; continue; } // If a separator character is found, then increment location. if (str[i] == separator) { i++; location++; continue; } if (location == checklocs[targetindex]) { if (pokey.search(str+i)) { positions.append(location); targetindex++; } } i++; } } if (verbose2Q) { cout << "ORIGINAL LINE: " << line << endl; cout << "\tCOUNT IS " << positions.getSize() << " FOR FEATURE SEARCH " << feature.getBase() << endl; cout << "\tMATCHES AT: "; int j; for (j=0; j& positions, string& line, Array& feature, char searchanchor, Array& checklocs, char separator) { positions.setSize(checklocs.getSize()); positions.setSize(0); PerlRegularExpression pre; Array startmarker; startmarker.setSize(256); startmarker.setGrowth(10000); startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); // startindex is the first character in the search feature with // the full search index. Matches will be counted from this // position. int startindex = pre.getSubmatchEnd(1); int i, j; Array temppos(1000); temppos.setGrowth(100000); // If checklocs is non-zero, then only check the feature // at the given locations; otherwise, check every position. if (checklocs.getSize() == 0) { // check every location in feature for a match (allowing overlaps) PerlRegularExpression gumby; gumby.setAnchor(); gumby.initializeSearchAndStudy(feature.getBase()); // currently rest separator is either nothing or a space PerlRegularExpression rest; rest.setAnchor(); rest.initializeSearchAndStudy("(R *)"); const char* str = line.c_str(); int location = 0; i = startindex; while ((str[i] != '\0') && (str[i] != '\t')) { if (str[i] == separator) { i++; location++; continue; } if (rest.search(str+i)) { i += rest.getSubmatchEnd(1) - rest.getSubmatchStart(1); continue; } if (gumby.search(str+i)) { positions.append(location); } i++; } } else { // Check only locations specified by checklocs. // The positions in checklocs are presumed to be sorted. PerlRegularExpression pokey; pokey.setAnchor(); pokey.initializeSearchAndStudy(feature.getBase()); const char* str = line.c_str(); int location = 0; //int lastpos = 0; i = startindex; int targetindex = 0; int tsize = checklocs.getSize(); // currently rest separator is either nothing or a space PerlRegularExpression rest; rest.setAnchor(); rest.initializeSearchAndStudy("(R *)"); while ((str[i] != '\0') && (str[i] != '\t') && (targetindex < tsize)) { // Increase the target location if it is smaller than // the current search location. if (checklocs[targetindex] < location) { targetindex++; continue; } // If a separator character is found, then increment location. if (str[i] == separator) { i++; location++; continue; } if (rest.search(str+i)) { i += rest.getSubmatchEnd(1) - rest.getSubmatchStart(1); continue; } if (pokey.search(str+i)) { //for (j=lastpos; j& positions, string& line, Array& feature, char searchanchor, Array& checklocs, int featurewidth) { positions.setSize(0); PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); int i; // if checklocs is non-zero, then only check the feature // at the given locations; otherwise, check every position. if (checklocs.getSize() == 0) { // check every location in feature for a match (allowing overlaps) PerlRegularExpression gumby; gumby.setAnchor(); gumby.initializeSearchAndStudy(feature.getBase()); const char* str = line.c_str(); int location; int charloc = 0; i = startindex; while ((str[i] != '\0') && (str[i] != '\t')) { if (gumby.search(str+i)) { location = charloc / featurewidth; positions.append(location); } charloc++; i++; } } else { // check only locations specified by checklocs // The feature is presumed to be of equal length // to other features, and an end of string problem // will therefore not be checked. Only the start // of a feature will be checked (no partial // start features will be examined, but could be // added). PerlRegularExpression pokey; pokey.setAnchor(); pokey.initializeSearchAndStudy(feature.getBase()); const char* str = line.c_str() + startindex; for (i=0; i& positions, string& line, Array& feature, char searchanchor, Array& checklocs, int featurewidth) { positions.setSize(0); PerlRegularExpression pre; Array startmarker; startmarker.setSize(0); appendString(startmarker, "(\\t"); startmarker.append(searchanchor); appendString(startmarker, ")"); pre.search(line.c_str(), startmarker.getBase(), ""); int startindex = pre.getSubmatchEnd(1); int i; // if checklocs is non-zero, then only check the feature // at the given locations; otherwise, check every position. if (checklocs.getSize() == 0) { // check every location in feature for a match (allowing overlaps) PerlRegularExpression gumby; gumby.setAnchor(); gumby.initializeSearchAndStudy(feature.getBase()); // currently rest separator is either nothing or a space PerlRegularExpression rest; rest.setAnchor(); rest.initializeSearchAndStudy("R"); const char* str = line.c_str(); int location; int charloc = 0; i = startindex; while ((str[i] != '\0') && (str[i] != '\t')) { if (rest.search(str+i)) { i++; // don't increment charloc due to "R". continue; } if (gumby.search(str+i)) { location = charloc / featurewidth; positions.append(location); } charloc++; i++; } } else { // check only locations specified by checklocs // The feature is presumed to be of equal length // to other features, and an end of string problem // will therefore not be checked. Only the start // of a feature will be checked (no partial // start features will be examined, but could be // added). PerlRegularExpression pokey; pokey.setAnchor(); pokey.initializeSearchAndStudy(feature.getBase()); // this code will not work with segmentation markers, so have // to fix. Basically cannot speed up the search process, and // have to step through data. const char* str = line.c_str() + startindex; for (i=0; i 1) { cout << "tonic:\t\t" << tonicss.getBase() << endl; } if (P12toneinterval.getSize() > 1) { cout << "twelve-tone interval:\t" << P12toneinterval.getBase() << endl; } if (Pgrosscontour.getSize() > 1) { cout << "Pitch gross contour:\t" << Pgrosscontour.getBase() << endl; } if (Prefinedcontour.getSize() > 1) { cout << "Pitch refined contour:\t" << Prefinedcontour.getBase() << endl; } if (Pscaledegree.getSize() > 1) { cout << "Scale-degree:\t" << Pscaledegree.getBase() << endl; } if (Pmusicalinterval.getSize() > 1) { cout << "Interval:\t" << Pmusicalinterval.getBase() << endl; } if (P12tonepitchclass.getSize() > 1) { cout << "Twelve-tone pitch-class:\t" << P12tonepitchclass.getBase() << endl; } if (Ppitchclass.getSize() > 1) { cout << "Pitch-class:\t" << Ppitchclass.getBase() << endl; } if (meterss.getSize() > 1) { cout << "meter:\t\t" << meterss.getBase() << endl; } if (Rgrosscontour.getSize() > 1) { cout << "Rhythm gross contour:\t" << Rgrosscontour.getBase() << endl; } if (Rrefinedcontour.getSize() > 1) { cout << "Rhythm refined contour:\t" << Rrefinedcontour.getBase() << endl; } if (Rduration.getSize() > 1) { cout << "Duration:\t" << Rduration.getBase() << endl; } if (Rbeatlevel.getSize() > 1) { cout << "Beat level:\t" << Rbeatlevel.getBase() << endl; } if (Rmetriclevel.getSize() > 1) { cout << "Metric level:\t" << Rmetriclevel.getBase() << endl; } if (Rmetricrefinedcontour.getSize() > 1) { cout << "Metric refined contour:\t" << Rmetricrefinedcontour.getBase() << endl; } if (Rmetricgrosscontour.getSize() > 1) { cout << "Metric gross contour:\t" << Rmetricgrosscontour.getBase() << endl; } if (Rmetricposition.getSize() > 1) { cout << "Metric position:\t" << Rmetricposition.getBase() << endl; } } ////////////////////////////// // // appendToSearchString -- // void appendToSearchString(Array& ss, const char* string, char marker, int anchor) { char ch; // add back quote for certain markers switch (marker) { case '{': case '}': case '^': ch = '\\'; ss.append(ch); } ss.append(marker); char nullchar = '\0'; ss.append(nullchar); ss.setSize(ss.getSize()-1); // add [^\t]* if not anchored: // // if (!anchor) { // The ? causes problems when searching for P1 in -I option: // appendString(ss, "[^\\t]*?"); appendString(ss, "[^\\t]*"); } appendString(ss, string); // Moved to cleanPpitchClass: // // for pitch-class names, the next character after the search // // string must be a space or a tab to prevent accidentals // // from matching on natural-note search endings. // if (marker == P_PITCH_CLASS_MARKER) { // appendString(ss, "[ \\t]"); // } appendString(ss, ".*"); } ////////////////////////////// // // appendString -- // void appendString(Array& ss, const char* string) { int i; char ch; int length = strlen(string); for (i=0; i > tokens; PerlRegularExpression pre; pre.getTokens(tokens, "\\s+", opts.getString("query").data()); if (tokens.getSize() == 0) { return; } Array > featuretype; pre.getTokens(featuretype, ":", tokens[0].getBase()); if (featuretype.getSize() == 0) { return; } int featurecount = featuretype.getSize(); int seqcount = tokens.getSize()-1; SSTREAM *sptr[featurecount]; int i, j; for (i=0; i > feature; int maxfet = featurecount; for (i=0; i=]\n" " -R incipit : identify according to long/short/medium rhythm [LSM]\n" " -s : limit search to structural tones only\n" " -t tonic : limit search to themes in key of \"tonic\" (major or minor)\n" "\n" " Refer to reference manual for further details." <& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^UuDdRrEeSsHhwW=<>0-9,.{}()+*-]", "", "g"); pre.tr(data, "udHhWw=Eesr", "UDUUDDSSSSR"); } /////////////////////////////// // // cleanRmrc -- metric refined contour // void cleanRmrc(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^UuDdRrEeSsHhwW=<>0-9,.{}()+*-]", "", "g"); pre.tr(data, "HhWwEes=r", "UuDdSSSSR"); } /////////////////////////////// // // cleanRgrossContour -- // void cleanRgrossContour(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^RrSsLl=<>0-9,.{}()+*-]", "", "g"); pre.tr(data, "rSsLl", "R<<>>"); } /////////////////////////////// // // cleanRrefinedContour -- // void cleanRrefinedContour(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^\\]\\[RrSsLl=<>0-9,.{}()+*-]", "", "g"); pre.tr(data, "rsl", "R<>"); pre.sar(data, "\\]", "\\]", "g"); pre.sar(data, "\\[", "\\[", "g"); pre.sar(data, "S", "\\[", "g"); pre.sar(data, "L", "\\]", "g"); } ////////////////////////////// // // cleanRbeatLevel -- // void cleanRbeatLevel(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^Rr0-9,.{}()|*+?BbSs]", "", "g"); // convert B to 1 and S to 0 if they are used (derived from metric level) pre.tr(data, "rBbSs", "R1100"); // adjust meaning of dot so that it does not match to tab character: pre.sar(data, "\\.", "[^\\t]", "g"); } ////////////////////////////// // // cleanRDuration -- // work on allowing more regular expressions. // void cleanRduration(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^LlBb?Rr0-9Dd,.{}()|*+\\sxX]", "", "g"); // change dots into "d", and "x" into "X": pre.tr(data, "r.Dxlb", "RddXLB"); // convert "X" into the equivalent of regular-expression dot: pre.sar(data, "X", " \\d+d* ", "g"); // change spaces to single, adding one at end, removing // any from start pre.sar(data, "\\s+", " ", "g"); pre.sar(data, "^\\s+", "", ""); pre.sar(data, "\\s*$", " ", ""); // adjust for ? wildcard (more added later...) pre.sar(data, " ", " )(?:", "g"); pre.sar(data, "^", "(?:", ""); pre.sar(data, "$", ")", ""); pre.sar(data, "\\? \\)", " )?", "g"); pre.sar(data, "\\(\\?:\\)", "", "g"); // remove ending null case } ////////////////////////////// // // cleanRmetricLevel -- // void cleanRmetricLevel(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^Rr0-9,.{}()|*+\\s+-pmPM]", "", "g"); // change dots into "d": pre.tr(data, "r+-PMbs", "RpmpmBS"); pre.sar(data, "B", " B ", "g"); pre.sar(data, "S", " S ", "g"); // change spaces to single, adding one at end, removing // any from start pre.sar(data, "\\s+", " ", "g"); pre.sar(data, "^\\s+", "", ""); pre.sar(data, "\\s*$", " ", ""); // expand B and S markers pre.sar(data, "B", "(?:p\\d+|0)", "g"); pre.sar(data, "S", "m\\d+", "g"); } ////////////////////////////// // // cleanRmetricPosition -- // void cleanRmetricPosition(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^Rr0-9,.{}()|*+\\~\\^\\s+_\\- \\/]", "", "g"); // change dashes into underscores pre.tr(data, "r-", "R_"); // make sure underscores do not have any adjacent spaces: pre.sar(data, "\\s*_\\s*", "_", "g"); // make dots surrounded by spaces: pre.sar(data, "\\s*\\.\\s*", " . ", "g"); // change spaces to single space, adding one at end, removing // any from start pre.sar(data, "\\s+~\\s+", "~ ", "g"); // remove any spaces before ~ pre.sar(data, "\\s+\\^\\s+", "~ ", "g"); // remove any spaces before ^ pre.sar(data, "\\s+", " ", "g"); pre.sar(data, "^\\s+", "", ""); pre.sar(data, "\\s*$", " ", ""); // attach offbeat values to beats pre.sar(data, " (?=\\d+\\/\\d+)", "_", "g"); // expand ~ marker (which means beat and any possible subbeat) pre.sar(data, "\\~", "(?:_\\d+\\/\\d+)?", "g"); // expand ^ marker (which means any possible subbeat of a beat) pre.sar(data, "\\^", "_(?:\\d+\\/\\d+)?", "g"); // add "x" markers to starts of beats pre.sar(data, "\\s+", " x", "g"); pre.sar(data, "x$", "", ""); pre.sar(data, "^", "x", ""); // convert dots into form to match any beat position pre.sar(data, "\\.", "\\d+(_\\d+\\/\\d+)?", "g"); } ////////////////////////////// // // cleanPgrossContour -- // void cleanPgrossContour(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^?0-9/\\\\UuDdSsRr*+.{},()|=-]", "", "g"); // collapse alias chars pre.tr(data, "s=-", "SSS"); pre.tr(data, "/udr\\\\", "UUDRD"); // convert "." into [^\t] since tab characters should not match "." pre.sar(data, "\\.", "[^\\t]", "g"); } ////////////////////////////// // // cleanPrefinedContour -- // void cleanPrefinedContour(Array& data) { PerlRegularExpression pre; // remove invalid characters pre.sar(data, "[^?0-9UuDdSsRr*+.{},()|-]", "", "g"); // collapse alias chars pre.tr(data, "-sr", "SSR"); // convert "." into [^\t] since tab characters should not match "." pre.sar(data, "\\.", "[^\\t]", "g"); } ////////////////////////////// // // cleanPscaleDegree -- This function cleans user input so that it // can be used to search the data which is formatted in a particular way. // void cleanPscaleDegree(Array& data) { PerlRegularExpression pre; if (pre.search(data, "[a-x]", "i")) { // convert pitch names to scale degrees // remove all accidentals pre.sar(data, "( |-)?is", "", "gi"); // replace German sharp pre.sar(data, "( |-)?es", "", "gi"); // replace German flat pre.sar(data, "( |-)?sharp", "", "gi"); // replace acc names with syms pre.sar(data, "( |-)?flat", "", "gi"); // replace acc names with syms // convert solfege syllables into scale degrees. int solfege = 0; // true if using solfege syllables if (pre.sar(data, "ut|do", "1", "gi")) { solfege = 1; } if (pre.sar(data, "re", "2", "gi")) { solfege = 1; } if (pre.sar(data, "mi", "3", "gi")) { solfege = 1; } if (pre.sar(data, "sol?", "5", "gi")) { solfege = 1; } if (pre.sar(data, "la", "6", "gi")) { solfege = 1; } if (pre.sar(data, "[ts]i", "7", "gi")) { solfege = 1; } // if any other solfege syllables have been used, then convert // "fa" into F; otherwise, assume that "fa" means "F A"; if (solfege) { pre.sar(data, "fa", "4", "gi"); } // remove any plain accidentals pre.sar(data, "x", "", "gi"); pre.sar(data, "#", "", "gi"); pre.sar(data, "-", "", "gi"); // convert pitches to scale degrees as if they were in C major: pre.sar(data, "c", "1", "gi"); pre.sar(data, "d", "2", "gi"); pre.sar(data, "e", "3", "gi"); pre.sar(data, "f", "4", "gi"); pre.sar(data, "g", "5", "gi"); pre.sar(data, "a", "6", "gi"); pre.sar(data, "b", "7", "gi"); } // remove any characters which are not 1-7 pre.sar(data, "[^Rr1-7@+.]", "", "g"); pre.tr(data, "r@", "R+"); } ////////////////////////////// // // cleanP12toneInterval -- This function cleans user input so that it // can be used to search the data which is formatted in a particular way. // void cleanP12toneInterval(Array& data) { PerlRegularExpression pre; // place plus in front of any intervals which don't have signs pre.sar(data, "\\s(?=\\d)", " p", "g"); if (pre.search(data, "^\\d", "")) { pre.sar(data, "^", "p", ""); } // change plus and minus into "p" and "m" pre.tr(data, "PM+\\-r", "pmpmR"); // change any m0 to p0: pre.sar(data, "m0", "p0", "g"); // remove any disallowed characters pre.sar(data, "[^Rr0-9pm~\\[\\]]", "", "g"); // change tilde sign into [pm] which means either up or down. pre.sar(data, "~", "[pm]", "g"); } ////////////////////////////// // // cleanP12tonePitchClass -- This function cleans user input so that it // can be used to search the data which is formatted in a particular way. // void cleanP12tonePitchClass(Array& data) { PerlRegularExpression pre; // change lowercase to upper case // Y => A, Z => B. May use pitch classes in the future so // minimizing use of A and B in raw search from user. pre.tr(data, "yz", "YZ"); if (!pre.search(data, "[YZ]", "")) { // convert "10" and "11" to "A" and "B" if they are present in query pre.sar(data, "\\b10\\b", "Y", "g"); pre.sar(data, "\\b11\\b", "Z", "g"); } if (pre.search(data, "[a-x]", "i")) { // convert pitch names to 12-tone intervals, no triple sharps/flats // or higher allowed. pre.sar(data, "( |-)?is", "#", "gi"); // replace German sharp pre.sar(data, "( |-)?es", "-", "gi"); // replace German flat pre.sar(data, "( |-)?sharp", "#", "gi"); // replace acc names with syms pre.sar(data, "( |-)?flat", "-", "gi"); // replace acc names with syms // convert solfege syllables into English note names. int solfege = 0; // true if using solfege syllables if (pre.sar(data, "ut|do", "C", "gi")) { solfege = 1; } if (pre.sar(data, "re", "D", "gi")) { solfege = 1; } if (pre.sar(data, "mi", "E", "gi")) { solfege = 1; } if (pre.sar(data, "sol?", "G", "gi")) { solfege = 1; } if (pre.sar(data, "la", "A", "gi")) { solfege = 1; } if (pre.sar(data, "[ts]i", "B", "gi")) { solfege = 1; } // if any other solfege syllables have been used, then convert // "fa" into F; otherwise, assume that "fa" means "F A"; if (solfege) { pre.sar(data, "fa", "F", "gi"); } pre.sar(data, "x", "##", "gi"); pre.sar(data, "c##", "2", "gi"); pre.sar(data, "d##", "4", "gi"); pre.sar(data, "e##", "6", "gi"); pre.sar(data, "f##", "7", "gi"); pre.sar(data, "g##", "9", "gi"); pre.sar(data, "a##", "Z", "gi"); pre.sar(data, "b##", "1", "gi"); pre.sar(data, "c#", "1", "gi"); pre.sar(data, "d#", "3", "gi"); pre.sar(data, "e#", "5", "gi"); pre.sar(data, "f#", "6", "gi"); pre.sar(data, "g#", "8", "gi"); pre.sar(data, "a#", "Y", "gi"); pre.sar(data, "b#", "0", "gi"); pre.sar(data, "c--", "Y", "gi"); pre.sar(data, "d--", "0", "gi"); pre.sar(data, "e--", "2", "gi"); pre.sar(data, "f--", "3", "gi"); pre.sar(data, "g--", "5", "gi"); pre.sar(data, "a--", "7", "gi"); pre.sar(data, "b--", "9", "gi"); pre.sar(data, "c-", "Z", "gi"); pre.sar(data, "d-", "1", "gi"); pre.sar(data, "e-", "3", "gi"); pre.sar(data, "f-", "4", "gi"); pre.sar(data, "g-", "6", "gi"); pre.sar(data, "a-", "8", "gi"); pre.sar(data, "b-", "Y", "gi"); pre.sar(data, "c", "0", "gi"); pre.sar(data, "d", "2", "gi"); pre.sar(data, "e", "4", "gi"); pre.sar(data, "f", "5", "gi"); pre.sar(data, "g", "7", "gi"); pre.sar(data, "a", "9", "gi"); pre.sar(data, "b", "Z", "gi"); } // convert Y and Z symbols to A and B (pitches 10 and 11 in thema index pre.tr(data, "rYZ", "RAB"); // remove any characters which are invalid pre.sar(data, "[^RrAB0-9]", "", "g"); } ////////////////////////////// // // cleanPmusicalInterval -- based on processIntervalClassQuary in original // PERL interface. This function cleans user input so that it can be // used to search the data which is formatted in a particular way. // // Todo: add ^ and # wildcards. // void cleanPmusicalInterval(Array& data) { PerlRegularExpression pre; PerlRegularExpression pre2; Array > pieces; pieces.setSize(1000); pieces.setSize(0); pieces.setGrowth(100000); // remove invalid characters pre.sar(data, "[^Rr0-9\\+\\-MmPpAaDd\\.\\*\\? ]", "", "g"); // translate characters pre.tr(data, "\\*\\+\\-Dapr", "SXxdAPR"); // extract individual intervals from data string: const char* ptr; int index; // the following while loop should be improved, so that the second // long regular expression is not needed (in other words, increment // the pointer into the data for the start of the search so that // the match does not need to be destroyed once it is found. while (pre.search(data, "(S|R|\\*\\s*|\\.\\s*\\??|[Xx]?[PdmMA]?\\d+\\s*\\??|[Xx]?[PdmMA]\\s*\\??|[Xx]\\s*\\?\?)", "")) { ptr = pre.getSubmatch(1); if (pre2.search(ptr, "^\\s*$")) { continue; } index = pieces.getSize(); pieces.setSize(index+1); pieces[index].setSize(0); appendString(pieces[index], ptr); prepareInterval(pieces[index]); pre.sar(data, "(S|R|\\*\\s*|\\.\\s*\\??|[Xx]?[PdmMA]?\\d+\\s*\\??|[Xx]?[PdmMA]\\s*\\??|[Xx]\\s*\\?\?)", "", ""); } // prevent perfect unison from being mixed with P15, etc. pre.sar(data, "1(?!\\d)", "1(?!\\d)", "gi"); data.setSize(0); int i; for (i=0; i& data) { PerlRegularExpression pre; // rests are uninteresting to prepare if (pre.search(data, "R", "")) { return; } // * characters are handled later if (pre.search(data, "S", "")) { return; } // step 1: check to see which components are present pre.search(data, "([Xx])?([MmPAd])?([0-9]+)?(.*)", ""); Array direction; Array quality; Array ssize; Array other; direction.setSize(1); quality.setSize(1); ssize.setSize(1); other.setSize(1); direction[0] = '\0'; quality[0] = '\0'; ssize[0] = '\0'; other[0] = '\0'; direction.setSize(0); quality.setSize(0); ssize.setSize(0); other.setSize(0); appendString(direction, pre.getSubmatch(1)); appendString(quality, pre.getSubmatch(2)); appendString(ssize, pre.getSubmatch(3)); appendString(other, pre.getSubmatch(4)); if (strcmp(other.getBase(), ".") == 0) { data.setSize(0); appendString(data, "([Xx]?[mMPAd][1-9][0-9]?)"); return; } if (strcmp(other.getBase(), "*") == 0) { data.setSize(0); appendString(data, "([Xx]?[mMPAd][1-9][0-9]?)*"); return; } if (strcmp(direction.getBase(), "") == 0) { int isize = strtol(ssize.getBase(), NULL, 10); if ((strcmp(quality.getBase(), "P") == 0) && (isize == 1)) { // do not add an interval direction for P1 } else { direction.setSize(0); appendString(direction, "[Xx]?"); } } if (strcmp(quality.getBase(), "") == 0) { quality.setSize(0); appendString(quality, "[mMPAd]"); } if (strcmp(ssize.getBase(), "") == 0) { ssize.setSize(0); appendString(ssize, "[1-9][0-9]?"); } data.setSize(1); data[0] = '\0'; data.setSize(0); if (direction.getSize() > 0) { appendString(data, direction.getBase()); } if (quality.getSize() > 0) { appendString(data, quality.getBase()); } if (ssize.getSize() > 0) { appendString(data, ssize.getBase()); } PerlRegularExpression pre2; // Perfect unisons do not have a direction so remove if present pre2.sar(data, "[X|x]P1$", "P1", ""); if (other.getSize() > 0) { if (pre2.search(other, "\\?", "")) { Array tempdata; tempdata.setSize(0); appendString(tempdata, "("); appendString(tempdata, data.getBase()); appendString(tempdata, ")?"); data.setSize(0); appendString(data, tempdata.getBase()); } } if (pre.search(data, "(?& data) { PerlRegularExpression pre; pre.sar(data, "\\+", "#", "g"); // allow for + to mean sharp pre.sar(data, "( |-)?is", "#", "gi"); // replace German sharp pre.sar(data, "( |-)?es", "-", "gi"); // replace German flat pre.sar(data, "( |-)?sharp", "#", "gi"); // replace acc names with symbols pre.sar(data, "( |-)?flat", "-", "gi"); // replace acc names with symbols // convert solfege syllables into English note names. int solfege = 0; // true if using solfege syllables if (pre.sar(data, "ut|do", "C", "gi")) { solfege = 1; } if (pre.sar(data, "re", "D", "gi")) { solfege = 1; } if (pre.sar(data, "mi", "E", "gi")) { solfege = 1; } if (pre.sar(data, "sol?", "G", "gi")) { solfege = 1; } if (pre.sar(data, "la", "A", "gi")) { solfege = 1; } if (pre.sar(data, "[ts]i", "B", "gi")) { solfege = 1; } // if any other solfege syllables have been used, then convert // "fa" into F; otherwise, assume that "fa" means "F A"; if (solfege) { pre.sar(data, "fa", "F", "gi"); } // remove duplicate spaces pre.sar(data, "\\s+", " ", "g"); // adjust for aliases pre.tr(data, "\n\txa-hsSrmM-", " XA-H##Rbbb"); pre.tr(data, "@", "+"); // expand double sharps pre.sar(data, "X", "##", "gi"); // remove invalid chars pre.sar(data, "[^nA-HRb# H(){},.?+^*0-9]", "", "g"); // make sure {} operator has valid syntax cleanUpRangeSyntaxNoOutsideDigitsOrComma(data); // convert parentheses temporarily into letters and store // real regex operators in temporary letter values pre.sar(data, "\\(", "Q", "g"); pre.sar(data, "\\)", "q", "g"); pre.sar(data, "q\\*", "qS", "g"); pre.sar(data, "\\*", "S", "g"); pre.sar(data, "q\\+", "qP", "g"); pre.sar(data, "\\+", "P", "g"); pre.sar(data, "q\\?", "qN", "g"); // if a German B-natural is presents, map B->Bb and H->B if (pre.search(data.getBase(), "H")) { pre.sar(data, "B", "Bb", "gi"); // transmute German B pre.sar(data, "H", "B", "gi"); // transmute German H } // add spaces between notes pre.sar(data, "(?<=[^ ])(?=[A-GRQq{.])", " ", "g"); // change meaning of * which means match to zero or more notes. pre.sar(data, "\\*", "[YZ]*", "g"); // change meaning of "." which means any one pitch. pre.sar(data, "\\.", "[A-G][#-]*", "g"); // remove duplicate spaces again pre.sar(data, "\\s+", " ", "g"); // put parens around each note, then clean up: // remove any leading spaces pre.sar(data, "^\\s+", ""); // remove any trailing spaces pre.sar(data, "\\s+$", ""); // if the -D option is specified, then than means the // pitch names can contain any accidental (the search query // should not have any accidentals listed). if (diatonicQ) { pre.sar(data, "(?<=[A-G])(?![#nb-])", "^", "g"); } // remove natural sign (no longer needed after diatonic processing pre.sar(data, "n", "", "g"); // put a parenthesis at very beginning and very end of string pre.sar(data, "^", "(?:"); pre.sar(data, "$", ")"); // now put parentheses at each space separating a pitch. pre.sar(data, " ", ") (?:", "g"); // move "?" outside of parens pre.sar(data, "\\?\\) ", ")? ", "g"); pre.sar(data, "\\?\\)$", ")?" ); // fix the space/"?" association pre.sar(data, "\\)\\?\\s", " )?", "g"); // fix the space/"+" association pre.sar(data, "\\+\\)\\s", " )+", "g"); // change meaning of ^ which means any chromatic alteration of the note // (including no alteration), in other words search for diatonic part // with any chromatic alteration pre.sar(data, "\\^", "(?:#+|b+)?", "g"); // finalize change of * pre.sar(data, "Z", "\t", "g"); pre.sar(data, "Y", "^", "g"); pre.sar(data, "\\*\\) ", "*)", "g"); // change )( to ) ( pre.sar(data, "\\)\\(", ") (", "g"); // get rid of null notes pre.sar(data, "\\(\\)", "", "g"); // get rid of parentheses around {} operator pre.sar(data, "\\(\\?:\\{","{", "g"); pre.sar(data, "\\}\\)", "}", "g"); // get rid of space before {} operator pre.sar(data, " \\{", "{", "g"); pre.sar(data, "\\( ", "(", "g"); pre.sar(data, " \\)", ")", "g"); // convert Q and q back into parentheses pre.sar(data, "\\(\\?:Q\\) ", "(", "g"); pre.sar(data, "\\(\\?:q", "q", "g"); pre.sar(data, "(?<=q)\\) ?", "", "g"); pre.sar(data, "(?<=q[^ )])\\) ?","", "g"); pre.sar(data, "q", ")", "g"); // put regex operators back to normal: pre.sar(data, "S\\) ", ") (?:[A-G][#b]* )*?", "g"); pre.sar(data, "P\\) ", " )+?", "g"); pre.sar(data, "P\\)$", " ?)+?", "g"); pre.sar(data, "S\\)$", ") (?:[A-G][#b]* ?)*?", "g"); pre.sar(data, "N", "?", "g"); // fix a bug related to * operator: pre.sar(data, "\\(\\?:\\) ", "", "g"); // thema command adds the space later, so get rid of any at the end pre.sar(data, " $", ""); // added 10 Dec 2000 pre.sar(data, "^ +", ""); // moved from appendToSearchString [20101123] data.setSize(data.getSize() + strlen("[ \\t]")); strcat(data.getBase(), "[ \\t]"); } ////////////////////////////// // // cleanUpRangeSyntax: disallow digits or commas to exist // anywhere outside of the {} regular-expression operator. // void cleanUpRangeSyntaxNoOutsideDigitsOrComma(Array& data) { int i; int inside = 0; SSTREAM tempdata; for (i=0; i > tokens; PerlRegularExpression::getTokens(tokens, "\\s+", astring); PerlRegularExpression pre; Array tempc; int noteQ; Array sequence; sequence.setSize(tokens.getSize()); sequence.setSize(0); int i; for (i=0; i pitches; pitches.setSize(sequence.getSize()); Array durations; durations.setSize(sequence.getSize()); int pitchesq = 0; int dursq = 0; for (i=0; i 1000) || (pitches[i] < 0)) { pitches[i] = -1; } else { pitchesq = 1; } durations[i] = Convert::kernToDuration(tokens[sequence[i]].getBase()); if (durations[i] <= 0.0) { } else { dursq = 1; } } if (pitchesq) { PpitchclassQ = 1; // activate -p option } if (dursq) { RdurationQ = 1; // activate -u option } SSTREAM pitchseq; SSTREAM durseq; Array buffer(1024); for (i=0; i 0) { Convert::base40ToKern(buffer.getBase(), pitches[i]%40 + 3*40); pitchseq << buffer.getBase(); } else { pitchseq << "."; } if (i < sequence.getSize()-1) { pitchseq << ' '; } } if (dursq) { if (durations[i] > 0) { Convert::durationToKernRhythm(buffer.getBase(), durations[i]); if (pre.search(buffer.getBase(), "-")) { durseq << "x"; } else { durseq << buffer.getBase(); } } else { durseq << "x"; } if (i < sequence.getSize()-1) { durseq << ' '; } } } pitchseq << ends; durseq << ends; int plen = strlen(pitchseq.CSTRING); int dlen = strlen(durseq.CSTRING); Ppitchclass.setSize(plen+1); Rduration.setSize(dlen+1); strcpy(Ppitchclass.getBase(), pitchseq.CSTRING); strcpy(Rduration.getBase(), durseq.CSTRING); // cout << "PITCH SEQUENCE: " << Ppitchclass.getBase() << endl; // cout << "DRUATION SEQUENCE: " << Rduration.getBase() << endl; // exit(0); } // md5sum: 222f1914e4f03ab5801e0e219a9c41f4 themax.cpp [20160512]