//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Dec 15 15:00:17 PST 2011
// Last Modified: Thu Dec 15 15:00:22 PST 2011
// Last Modified: Wed Jun 20 16:22:44 PDT 2012 Added instruments abbreviations
// Last Modified: Tue Aug 28 10:24:57 PDT 2012 Default metric bug fix
// Filename: ...sig/examples/all/jrpize.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/jrpize.cpp
// Syntax: C++; museinfo
//
// Description:
//
// Things this program does:
// (1) Add "l" markers on terminal and medial longs
// (2) Adds a RWG entry for terminal longs
// (3) Adds % RWG entry if "%" enhanced rhythmic values are used
// (4) default mensuration signs.
// (5) Section: text to !!section: comments and !!!OMD: records
//
// Things to add in the future:
// (a) automatic triplet brackets?
// (b) textual items.
// (c) mensuration sign exceptions.
//
#include "PerlRegularExpression.h"
#include "humdrum.h"
#ifndef OLDCPP
#include <sstream>
#define SSTREAM stringstream
#define CSTRING str().c_str()
using namespace std;
#else
#ifdef VISUAL
#include <strstrea.h> /* for windows 95 */
#else
#include <strstream.h>
#endif
#define SSTREAM strstream
#define CSTRING str()
#endif
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
int addTerminalLongs(HumdrumFile& infile);
int addTrackLongs(HumdrumFile& infile, int track);
void printOutput(HumdrumFile& infile, int terminalQ);
int hasEditorial(HumdrumFile& infile);
int hasEditorialRDF(HumdrumFile& infile);
int hasLongRDF(HumdrumFile& infile);
void handleMensuration(HumdrumFile& infile, int line);
void printAbbreviation(const char* fullname);
void checkAndPrintInstAbbr(HumdrumFile& infile, int line);
void checkAndPrintVox(HumdrumFile& infile, int line);
int hasSectionLabel(HumdrumFile& infile, int line);
void printSectionLabel(HumdrumFile& infile, int line);
void printDefaultKeyTimeMet(HumdrumFile& infile, int line);
void processMensuration(HumdrumFile& infile, int line);
char* getMensuration(char* buffer, HumdrumFile& infile,
int line, int spine);
char* convertMenIntoMet(char* buffer, const char* mensur);
void clearMensurationComment(HumdrumFile& infile, int line);
void setItem(Array<Array<char> >& anArray, int i,
const char* aString);
void printSectionInfo(void);
int wrongSideOfBarline(HumdrumFile& infile, int line);
int convertRscaleTextToInterpretation(HumdrumFile& infile, int line);
void processBarlineComment(HumdrumFile& infile);
void applyBarlineMarker(HumdrumFile& infile, int line, int column,
int barjump, int dashQ);
void makeBarlineInvisible(HumdrumFile& infile, int line, int track,
char addchar, int dashQ);
void printLabel(HumdrumFile& infile, int line);
void printDefaultLabelExpansion(HumdrumFile& infile, int line);
int hasDataBelow(HumdrumFile& infile, int line);
void turnOffAnyActiveRscales(HumdrumFile& infile, int line);
void mergeAdjacentNotes(HumdrumFile& infile, int line, int track);
void fixAccentedText(HumdrumRecord& aRecord);
void checkText(HumdrumRecord& aRecord, int index);
void checkForPrimaryMensurationNeed(HumdrumFile& infile, int line);
int cleanDefaultInterpretations(HumdrumFile& infile, int line);
void absorbMensurations(HumdrumFile& infile, int line);
// global variables
Options options; // database for command-line arguments
int hasTerminalLong = 0; // true if "l" marker added to data.
Array<Array<char> > Clef; // used for prevailing clef by voice
Array<Array<char> > Keysig; // used for prevailing key signature by voice
Array<Array<char> > Timesig; // used for prevailing time signature by voice
Array<Array<char> > Metsig; // used for prevailing meter signature by voice
Array<RationalNumber> Rscale; // used to turn off *rscale:
Array<char > Section; // used to flip on other side of measure line
char SectionLabel = 'A'-1;
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile;
Section.setSize(1);
Section[0] = '\0';
// process the command-line options
checkOptions(options, argc, argv);
// figure out the number of input files to process
int numinputs = options.getArgCount();
for (int i=0; i<numinputs || i==0; i++) {
infile.clear();
// if no command-line arguments read data file from standard input
if (numinputs < 1) {
infile.read(cin);
} else {
infile.read(options.getArg(i+1));
}
hasTerminalLong = addTerminalLongs(infile);
processBarlineComment(infile);
printOutput(infile, hasTerminalLong);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// processBarlineComment --
//
void processBarlineComment(HumdrumFile& infile) {
int i, j;
PerlRegularExpression pre;
PerlRegularExpression pre2;
PerlRegularExpression pre3;
int number;
int dashQ = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isLocalComment()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!pre.search(infile[i][j],
"!LO:TX:.*t=\\s*barline[s]:\\s*(\\d+[^:]*)", "i")) {
continue;
}
if (pre2.search(pre.getSubmatch(1), "/")) {
cerr << "ERROR: barlines directive has fraction: "
<< pre.getSubmatch() << " on line " << i+1 << endl;
exit(1);
}
if (pre3.search(infile[i][j], "dash", "i")) {
dashQ = 1;
}
number = atoi(pre.getSubmatch());
applyBarlineMarker(infile, i, j, number, dashQ);
infile[i].setToken(j, "!");
}
}
}
//////////////////////////////
//
// applyBarlineMarkers --
//
void applyBarlineMarker(HumdrumFile& infile, int line, int column,
int barjump, int dashQ) {
int i;
int visibleQ;
int barcount = 0;
int track = infile[line].getPrimaryTrack(column);
PerlRegularExpression pre;
for (i=line+1; i<infile.getNumLines(); i++) {
if (!infile[i].isMeasure()) {
continue;
}
// exit loop if end of music or section is found
if (pre.search(infile[i][0], "==")) { break; }
if (pre.search(infile[i][0], "\\|\\|")) { break; }
if (pre.search(infile[i][0], ":")) { break; }
barcount++;
visibleQ = !(barcount % barjump);
if (visibleQ) {
// or maybe make sure that barline is visible...
continue;
}
if (dashQ) {
makeBarlineInvisible(infile, i, track, '.', dashQ);
} else {
makeBarlineInvisible(infile, i, track, '-', dashQ);
}
}
}
//////////////////////////////
//
// makeBarlineInvisible --
//
void makeBarlineInvisible(HumdrumFile& infile, int line, int track,
char addchar, int dashQ) {
if (!infile[line].isMeasure()) {
return;
}
char charstring[2] = {0};
charstring[0] = addchar;
PerlRegularExpression pre;
char buffer[1024] = {0};
int j;
int t;
for (j=0; j<infile[line].getFieldCount(); j++) {
t = infile[line].getPrimaryTrack(j);
if (t != track) {
continue;
}
if (strchr(infile[line][j], addchar) != NULL) {
// already is invisible
continue;
}
strcpy(buffer, infile[line][j]);
strcat(buffer, charstring);
infile[line].setToken(j, buffer);
if (!dashQ) {
mergeAdjacentNotes(infile, line, t);
}
}
}
//////////////////////////////
//
// mergeAdjacentNotes --
//
void mergeAdjacentNotes(HumdrumFile& infile, int line, int track) {
int lasti = 0;
int lastj = 0;
int i, j;
int nexti = 0;
int nextj = 0;
int t;
for (i=line+1; i<infile.getNumLines(); i++) {
if (!infile[i].isData()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
t = infile[i].getPrimaryTrack(j);
if (t != track) {
continue;
}
if (strcmp(infile[i][j], ".") == 0) {
continue;
}
nexti = i;
nextj = j;
break;
}
if (nexti > 0) {
break;
}
}
for (i=line-1; i>0; i--) {
if (!infile[i].isData()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
t = infile[i].getPrimaryTrack(j);
if (t != track) {
continue;
}
if (strcmp(infile[i][j], ".") == 0) {
continue;
}
lasti = i;
lastj = j;
break;
}
if (lasti > 0) {
break;
}
}
if ((nexti == 0) || (lasti == 0)) {
return;
}
char buffer[1024] = {0};
PerlRegularExpression pre;
Array<char> buffer2;
if ((strchr(infile[lasti][lastj], 'r') != NULL) &&
(strchr(infile[nexti][nextj], 'r') != NULL) ) {
if ((strchr(infile[nexti][nextj], 'y') != NULL) &&
(strchr(infile[lasti][lastj], 'y') != NULL)) {
return;
}
strcpy(buffer, infile[nexti][nextj]);
strcat(buffer, "yy");
infile[nexti].setToken(nextj, buffer);
return;
}
if (strchr(infile[lasti][lastj], 'l') != NULL) {
// avoid terminal nulls
return;
}
if ((strchr(infile[lasti][lastj], '[') != NULL) &&
(strchr(infile[nexti][nextj], ']') != NULL) ) {
if ((strchr(infile[nexti][nextj], 'y') != NULL) &&
(strchr(infile[lasti][lastj], 'y') != NULL)) {
return;
}
// hide tie on first note
buffer2.setSize(strlen(infile[lasti][lastj]) + 1);
strcpy(buffer2.getBase(), infile[lasti][lastj]);
pre.sar(buffer2, "\\[", "[y", "g");
infile[lasti].setToken(lastj, buffer2.getBase());
// hide the entire second note
strcpy(buffer, infile[nexti][nextj]);
strcat(buffer, "yy");
infile[nexti].setToken(nextj, buffer);
}
}
//////////////////////////////
//
// addTerminalLongs -- place "l" marker on the last note of each voice
// (or chord in each voice). Also the last note befour any
// double barlines.
//
int addTerminalLongs(HumdrumFile& infile) {
int result = 0;
Array<int> ktracks;
infile.getTracksByExInterp(ktracks, "**kern");
int i;
for (i=0; i<ktracks.getSize(); i++) {
result |= addTrackLongs(infile, ktracks[i]);
}
return result;
}
//////////////////////////////
//
// addTrackLongs -- add long markers to a specific track.
//
int addTrackLongs(HumdrumFile& infile, int track) {
int i, j;
int ptrack;
int output = 0;
int addQ = 1;
char buffer[1024] = {0};
for (i=infile.getNumLines()-1; i>=0; i--) {
if (addQ == 0) {
if (infile[i].isMeasure()) {
for (j=0; j<infile[i].getFieldCount(); j++) {
ptrack = infile[i].getPrimaryTrack(j);
if (ptrack != track) {
continue;
}
if (strstr(infile[i][j], "||")) {
addQ = 1;
break;
}
}
}
continue;
}
if (!infile[i].isData()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
ptrack = infile[i].getPrimaryTrack(j);
if (ptrack != track) {
continue;
}
if (strchr(infile[i][j], '_') != NULL) {
continue;
}
if (strchr(infile[i][j], ']') != NULL) {
continue;
}
if (strchr(infile[i][j], 'r') != NULL) {
continue;
}
if (strcmp(infile[i][j], ".") == 0) {
continue;
}
if (strchr(infile[i][j], 'l') != NULL) {
// don't mark a note which is already marked.
addQ = 0; // clear the add state since already marked
continue;
}
// found a note which should be marked.
strcpy(buffer, infile[i][j]);
strcat(buffer, "l");
output = 1;
infile[i].changeField(j, buffer);
// disable addQ, but keep going on current line.
addQ = 0;
}
}
return output;
}
//////////////////////////////
//
// setItem --
//
void setItem(Array >& anArray, int i, const char* aString) {
anArray[i].setSize(strlen(aString)+1);
strcpy(anArray[i].getBase(), aString);
}
//////////////////////////////
//
// printSectionInfo --
//
void printSectionInfo(void) {
if (Section[0] == '\0') {
return;
}
cout << "!!section: " << Section << "\n";
cout << "!!!OMD:\t" << Section << "\n";
Section[0] = '\0';
Section.setSize(1);
}
//////////////////////////////
//
// convertRscaleTextToInterpretation --
//
int convertRscaleTextToInterpretation(HumdrumFile& infile, int line) {
if (!infile[line].isComment()) {
return 0;
}
int j;
char buffer[1024] = {0};
int hasRscale = 0;
PerlRegularExpression pre;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j],
"^!LO:TX:.*t=rscale:\\s*(\\d+[^:]*)", "i")) {
strcpy(buffer, "!rscale:");
strcat(buffer, pre.getSubmatch(1));
infile[line].setToken(j, buffer);
hasRscale = 1;
} else {
}
}
PerlRegularExpression pre2;
int track;
if (hasRscale) {
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j], "^!rscale:\\s*(.*)\\s*", "i")) {
track = infile[line].getPrimaryTrack(j);
cout << "*rscale:" << pre.getSubmatch(1);
if (pre2.search(pre.getSubmatch(), "(\\d+)/(\\d+)")) {
Rscale[track] = atoi(pre2.getSubmatch(1));
Rscale[track] /= atoi(pre2.getSubmatch(2));
} else {
Rscale[track] = atoi(pre2.getSubmatch(1));
}
infile[line].setToken(j, "!");
} else {
cout << "*";
}
if (j<infile[line].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
}
return hasRscale;
}
//////////////////////////////
//
// printDefaultLabelExpansion --
//
void printDefaultLabelExpansion(HumdrumFile& infile, int line) {
int i;
char label[2] = {0};
label[0] = ++SectionLabel;
char buffer[1024] = {0};
strcpy(buffer, "*>[");
strcat(buffer, label);
int count = 1;
PerlRegularExpression pre;
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isMeasure()) {
continue;
}
if (pre.search(infile[i][0], "\\|\\||==|:")) {
if (hasDataBelow(infile, i)) {
count++;
label[0]++;
strcat(buffer, ",");
strcat(buffer, label);
}
}
}
if (count <= 1) {
return;
}
strcat(buffer, "]");
int j;
for (j=0; j<infile[line].getFieldCount(); j++) {
cout << buffer;
if (j < infile[line].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
// print *>A label now
for (j=0; j<infile[line].getFieldCount(); j++) {
cout << "*>A";
if (j < infile[line].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// hasDataBelow -
//
int hasDataBelow(HumdrumFile& infile, int line) {
int i;
for (i=line+1; i<infile.getNumLines(); i++) {
if (infile[i].isData()) {
return 1;
}
}
return 0;
}
//////////////////////////////
//
// printOutput --
//
void printOutput(HumdrumFile& infile, int terminalQ) {
int firstBarline = 0;
int dataFoundQ = 0;
int i, j;
int editorialQ = hasEditorial(infile);
int insertedQ = 0;
int labelinitQ = 0;
int defaultPrinted = 0;
Rscale.setSize(infile.getMaxTracks()+1);
Rscale.setAll(1);
PerlRegularExpression pre;
Clef.setSize(infile.getMaxTracks()+1);
Keysig.setSize(infile.getMaxTracks()+1);
Timesig.setSize(infile.getMaxTracks()+1);
Metsig.setSize(infile.getMaxTracks()+1);
for (i=0; i<infile.getMaxTracks()+1; i++) {
setItem(Clef, i, "*");
setItem(Keysig, i, "*");
setItem(Timesig, i, "*");
setItem(Metsig, i, "*");
}
for (i=0; i<infile.getNumLines(); i++) {
if (defaultPrinted && infile[i].isData()) {
defaultPrinted = 0;
}
if ((defaultPrinted == 0) && infile[i].isInterpretation()) {
for (j=0; j<infile[i].getFieldCount(); j++) {
if (infile[i].isClef(j)) {
setItem(Clef, infile[i].getPrimaryTrack(j), infile[i][j]);
} else if (infile[i].isKeySig(j)) {
setItem(Keysig, infile[i].getPrimaryTrack(j), infile[i][j]);
} else if (infile[i].isTimeSig(j)) {
setItem(Timesig, infile[i].getPrimaryTrack(j), infile[i][j]);
} else if (infile[i].isMetSig(j)) {
setItem(Metsig, infile[i].getPrimaryTrack(j), infile[i][j]);
}
}
}
if ((dataFoundQ == 0) && (firstBarline == 0) && infile[i].isMeasure()) {
firstBarline = i;
continue;;
}
if (infile[i].isMeasure() && hasDataBelow(infile, i) &&
((strstr(infile[i][0], "||") != NULL) ||
(strstr(infile[i][0], ":") != NULL))) {
if ((i > 0) && (strcmp(infile[i-1][0], "!!LO:LB:i:g=z") != 0)) {
// printing line break provided that there is not one here already
// (this filters out extra linebreaks for repeated use of jrpize program)
cout << "!!LO:LB:i:g=z" << "\n";
}
}
if (infile[i].isMeasure() && ((strstr(infile[i][0], "||") != NULL) ||
(strstr(infile[i][0], ":") != NULL) ||
(strstr(infile[i][0], "==") != NULL))) {
turnOffAnyActiveRscales(infile, i);
}
if (infile[i].isInterpretation()) {
checkAndPrintVox(infile, i);
}
if ((labelinitQ == 0) && infile[i].isAllClef()) {
printDefaultLabelExpansion(infile, i);
}
convertRscaleTextToInterpretation(infile, i);
if (infile[i].isSpineManipulator() && (firstBarline > 0)) {
cout << infile[firstBarline] << "\n";
firstBarline = 0;
}
if (hasSectionLabel(infile, i)) {
printSectionLabel(infile, i);
continue;
}
if ((infile[i].isLocalComment() || infile[i].isData())
&& (dataFoundQ == 0) && (firstBarline > 0)) {
cout << infile[firstBarline] << "\n";
firstBarline = 0;
dataFoundQ = 1;
}
if (infile[i].isGlobalComment() || infile[i].isBibliographic()) {
// filter out line/page breaks from the MusicXML, they are
// not intended to be actual system breaks.
if (pre.search(infile[i][0], "break:original")) {
continue;
}
}
clearMensurationComment(infile, i);
if (infile[i].isNull()) {
continue;
}
fixAccentedText(infile[i]);
if (defaultPrinted) {
if (cleanDefaultInterpretations(infile, i)) {
continue;
}
}
cout << infile[i] << "\n";
if (infile[i].isMeasure()) {
if (Section[0] != '\0') {
printSectionInfo();
}
}
if (defaultPrinted == 0) {
if (infile[i].isAllTimeSig()) {
processMensuration(infile, i);
}
}
if (infile[i].isInterpretation()) {
checkAndPrintInstAbbr(infile, i);
}
if ((!insertedQ) && (strcmp(infile[i][0], "*-") == 0)) {
if (terminalQ && (!hasLongRDF(infile))) {
cout << "!!!RDF**kern: l=long note in original notation" << "\n";
}
if (editorialQ && (!hasEditorialRDF(infile))) {
cout << "!!!RDF**kern: i=editorial accidental" << "\n";
}
insertedQ = 1;
for (int ii=i+1; ii<infile.getNumLines(); ii++) {
cout << infile[ii] << "\n";
}
break;
}
// if (defaultPrinted == 0) {
// if (infile[i].isInterpretation()) {
// handleMensuration(infile, i);
// }
// }
if (infile[i].isMeasure() && ((strstr(infile[i][0], "||") != NULL) ||
(strstr(infile[i][0], ":") != NULL))) {
printLabel(infile, i);
printDefaultKeyTimeMet(infile, i);
defaultPrinted = 1;
}
}
}
//////////////////////////////
//
// cleanDefaultInterpretations --
//
int cleanDefaultInterpretations(HumdrumFile& infile, int line) {
if (!infile[line].isInterpretation()) {
return 0;
}
int j;
int leftcount = 0;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (strcmp(infile[line][j], "*") == 0) {
continue;
}
if (infile[line].isClef(j)) {
infile[line].changeField(j, "*");
} else if (infile[line].isKeySig(j)) {
infile[line].changeField(j, "*");
} else if (infile[line].isTimeSig(j)) {
infile[line].changeField(j, "*");
} else if (infile[line].isMetSig(j)) {
infile[line].changeField(j, "*");
} else {
leftcount++;
}
}
if (leftcount == 0) {
return 1;
} else {
return 0;
}
}
//////////////////////////////
//
// turnOffAnyActiveRscales --
//
void turnOffAnyActiveRscales(HumdrumFile& infile, int line) {
int j;
int track;
int hasRscale = 0;
for (j=0; j<infile[line].getFieldCount(); j++) {
track = infile[line].getPrimaryTrack(j);
if (Rscale[track] != 1) {
hasRscale = 1;
break;
}
}
if (hasRscale == 0) {
return;
}
for (j=0; j<infile[line].getFieldCount(); j++) {
track = infile[line].getPrimaryTrack(j);
if (Rscale[track] != 1) {
cout << "*rscale:1";
Rscale[track] = 1;
} else {
cout << "*";
}
if (j < infile[line].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// printLabel --
//
void printLabel(HumdrumFile& infile, int line) {
if (!infile[line].isMeasure()) {
return;
}
SectionLabel++;
int j;
for (j=0; j<infile[line].getFieldCount(); j++) {
cout << "*>" << SectionLabel;
if (j < infile[line].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// clearMensurationComment --
//
void clearMensurationComment(HumdrumFile& infile, int line) {
int j;
if (!infile[line].isLocalComment()) {
return;
}
PerlRegularExpression pre;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j],
"^!LO:TX:.*t=(\\s*all\\s*:\\s*)?[mM]en[A-Z0-9]", "")) {
infile[line].setToken(j, "!");
}
}
}
//////////////////////////////
//
// processMensuration -- Time signature just printed, so
// look for a metrical signature in each track, printing
// *met(C|) if time signature is 2/1 and there is no mensuration
// or
// *met(O) if time signature is 3/1 and there is no mensuration
//
void processMensuration(HumdrumFile& infile, int line) {
if (!infile[line].isInterpretation()) {
return;
}
char buffer[1024] = {0};
int j;
for (j=0; j<infile[line].getFieldCount(); j++) {
getMensuration(buffer, infile, line, j);
if (strcmp(buffer, "*ZZY") == 0) {
cout << "*Q";
} else {
cout << buffer;
}
setItem(Metsig, infile[line].getPrimaryTrack(j), buffer);
if (j < infile[line].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
checkForPrimaryMensurationNeed(infile, line);
}
//////////////////////////////
//
// absorbMensurations -- used by default mensuration processing
//
void absorbMensurations(HumdrumFile& infile, int line) {
char buffer[1024] = {0};
int i, j;
for (i=line; i<infile.getNumLines(); i++) {
if (infile[i].isData()) {
break;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
getMensuration(buffer, infile, i, j);
if (strlen(buffer) > 0) {
if (strcmp(buffer, "*ZZY") == 0) {
// no mensuration, handle default for meter elsewhere.
} else {
setItem(Metsig, infile[i].getPrimaryTrack(j), buffer);
}
}
}
}
}
//////////////////////////////
//
// checkForPrimaryMenurationNeed -- If all mensurations in **kern spines are
// not the same, then print the majority mensuration in a global comment.
//
void checkForPrimaryMensurationNeed(HumdrumFile& infile, int line) {
int i, j;
int track, lasttrack;
Array<int> tracks;
infile[line].getTracksByExInterp(tracks, "**kern");
if (tracks.getSize() <= 1) {
return;
}
int equalQ = 1;
for (i=1; i<tracks.getSize(); i++) {
track = tracks[i];
lasttrack = tracks[i-1];
if (strcmp(Metsig[track].getBase(), Metsig[lasttrack].getBase()) != 0) {
equalQ = 0;
break;
}
}
if (equalQ) {
// all mensurations are the same, so don't print a
// "!!primary-mensuration:" line.
return;
}
Array<int> counts;
counts.setSize(tracks.getSize());
counts.setAll(0);
int ti;
int tj;
for (i=0; i<tracks.getSize(); i++) {
ti = tracks[i];
for (j=0; j<tracks.getSize(); j++) {
tj = tracks[j];
if (strcmp(Metsig[ti].getBase(), Metsig[tj].getBase()) == 0) {
counts[tj]++;
break;
}
}
}
// find maximum count
int maxi = 0;
for (i=1; i<counts.getSize(); i++) {
if (counts[i] > counts[maxi]) {
maxi = i;
}
}
if (strcmp(Metsig[maxi].getBase(), "*") == 0) {
return;
}
if (strcmp(Metsig[maxi].getBase(), "") == 0) {
return;
}
// found the most common mensuration, so assume it is the
// primary mensuration:
cout << "!!primary-mensuration: " << Metsig[maxi].getBase()+1 << endl;
}
//////////////////////////////
//
// getMensuration --
//
char* getMensuration(char* buffer, HumdrumFile& infile, int line, int spine) {
strcpy(buffer, "*ZZY");
int foundDataQ = 0;
int i, j;
PerlRegularExpression pre;
if (!infile[line].isExInterp(spine, "**kern")) {
strcpy(buffer, "*");
return buffer;
}
int targettrack = infile[line].getPrimaryTrack(spine);
int tracki = 0;
int trackj = 0;
int mencount = 0;
int lasti = 0;
int lastj = 0;
int timesigi = 0;
int timesigj = 0;
int track;
for (i=line+1; i<infile.getNumLines(); i++) {
if (infile[i].isData()) {
foundDataQ = i;
break;
}
if (!infile[i].isLocalComment()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
continue;
}
if (strcmp(infile[i][j], "!") == 0) {
continue;
}
track = infile[i].getPrimaryTrack(j);
if (pre.search(infile[i][j],
"^!LO:TX:.*t=(\\s*all\\s*:\\s*)?[mM]en[A-Z0-9]", "")) {
mencount++;
lasti = i;
lastj = j;
if (track == targettrack) {
tracki = i;
trackj = j;
}
}
if (pre.search(infile[i][j], "^\\*M\\d+/\\d+")) {
if (track == targettrack) {
timesigi = i;
timesigj = j;
}
}
}
}
if (!foundDataQ) {
strcpy(buffer, "*ZZZ");
return buffer;
}
int ii = tracki;
int jj = trackj;
if (mencount == 1) {
ii = lasti;
jj = lastj;
}
if (pre.search(infile[ii][jj],
"^!LO:TX:.*t=(\\s*all\\s*:\\s*)?([Mm]en[^\\s]*)", "i")) {
if (infile[ii][jj][0] != '!') {
cerr << "Funny error on line " << ii+1 << " column " << jj+1 << endl;
cerr << infile[ii] << endl;
exit(1);
}
convertMenIntoMet(buffer, pre.getSubmatch(2));
if (mencount != 1) {
infile[ii].setToken(jj, "!");
}
return buffer;
}
if ((ii == 0) || (jj == 0)) {
// set a default mensuration since none found in data
if (pre.search(infile[line][spine], "^\\*M2/1$")) {
strcpy(buffer, "*met(C|)");
return buffer;
} else if (pre.search(infile[line][spine], "^\\*M3/1$")) {
strcpy(buffer, "*met(O)");
return buffer;
} else {
return buffer;
if (timesigi != 0) {
strcpy(buffer, "*met(___)");
} else {
strcpy(buffer, "*met(y)");
}
}
return buffer;
}
return buffer;
}
//////////////////////////////
//
// convertMenIntoMet --
//
char* convertMenIntoMet(char* buffer, const char* mensur) {
PerlRegularExpression pre;
if (pre.search(mensur, "MenCutC\\s*$", "i")) {
strcpy(buffer, "*met(C|)");
return buffer;
}
if (pre.search(mensur, "MenCircle\\s*$", "i")) {
strcpy(buffer, "*met(O)");
return buffer;
}
if (pre.search(mensur, "MenC3\\s*$", "i")) {
strcpy(buffer, "*met(C3)");
return buffer;
}
if (pre.search(mensur, "MenOover3\\s*$", "i")) {
strcpy(buffer, "*met(O/3)");
return buffer;
}
if (pre.search(mensur, "MenC\\s*$", "i")) {
strcpy(buffer, "*met(C)");
return buffer;
}
if (pre.search(mensur, "MenCircle2\\s*$", "i")) {
strcpy(buffer, "*met(O2)");
return buffer;
}
if (pre.search(mensur, "MenO2\\s*$", "i")) {
// not legal, but include in case of data error:
strcpy(buffer, "*met(O2)");
return buffer;
}
if (pre.search(mensur, "MenCutCircle\\s*$", "i")) {
strcpy(buffer, "*met(O|)");
return buffer;
}
if (pre.search(mensur, "MenCutC3\\s*$", "i")) {
strcpy(buffer, "*met(C|3)");
return buffer;
}
if (pre.search(mensur, "MenCircleDot\\s*$", "i")) {
strcpy(buffer, "*met(O.)");
return buffer;
}
if (pre.search(mensur, "MenC2\\s*$", "i")) {
strcpy(buffer, "*met(C2)");
return buffer;
}
if (pre.search(mensur, "MenCutC2\\s*$", "i")) {
strcpy(buffer, "*met(C|2)");
return buffer;
}
if (pre.search(mensur, "Men2\\s*$", "i")) {
strcpy(buffer, "*met(2)");
return buffer;
}
if (pre.search(mensur, "Men3\\s*$", "i")) {
strcpy(buffer, "*met(3)");
return buffer;
}
if (pre.search(mensur, "MenCDot\\s*$", "i")) {
strcpy(buffer, "*met(C.)");
return buffer;
}
if (pre.search(mensur, "Men3over2\\s*$", "i")) {
strcpy(buffer, "*met(3/2)");
return buffer;
}
if (pre.search(mensur, "MenCutCircle3\\s*$", "i")) {
strcpy(buffer, "*met(O|3)");
return buffer;
}
if (pre.search(mensur, "MenCutCircle3Over2\\s*$", "i")) {
strcpy(buffer, "*met(O|3/2)");
return buffer;
}
if (pre.search(mensur, "MenCircle3\\s*$", "i")) {
strcpy(buffer, "*met(O3)");
return buffer;
}
if (pre.search(mensur, "MenCutCOver3\\s*$", "i")) {
strcpy(buffer, "*met(C|/3)");
return buffer;
}
if (pre.search(mensur, "MenCutCOver2\\s*$", "i")) {
strcpy(buffer, "*met(C|/2)");
return buffer;
}
if (pre.search(mensur, "MenCircleOver3\\s*$", "i")) {
strcpy(buffer, "*met(O/3)");
return buffer;
}
if (pre.search(mensur, "MenCutCDot\\s*$", "i")) {
strcpy(buffer, "*met(C.|)");
return buffer;
}
cerr << "ERROR: unknown mensuration: " << mensur << endl;
exit(1);
}
//////////////////////////////
//
// printDefaultKeyTimeMet --
//
void printDefaultKeyTimeMet(HumdrumFile& infile, int line) {
if (!infile[line].isMeasure()) {
return;
}
absorbMensurations(infile, line);
int i, j;
int datafound = 0;
int hasMetsig = 0;
// search for new key,time,met data at the current
// location and store it before printing the default
// key,time,met.
for (i=line+1; i<infile.getNumLines(); i++) {
if (infile[i].isData()) {
datafound = 1;
break;
}
if (infile[i].isInterpretation()) {
for (j=0; j<infile[i].getFieldCount(); j++) {
if (infile[i].isClef(j)) {
setItem(Clef, infile[i].getPrimaryTrack(j), infile[i][j]);
} else if (infile[i].isKeySig(j)) {
setItem(Keysig, infile[i].getPrimaryTrack(j), infile[i][j]);
} else if (infile[i].isTimeSig(j)) {
setItem(Timesig, infile[i].getPrimaryTrack(j), infile[i][j]);
} else if (infile[i].isMetSig(j)) {
hasMetsig = 1;
}
}
}
}
int track;
// print the prevailing key,time,met information
for (j=0; j<infile[line].getFieldCount(); j++) {
track = infile[line].getPrimaryTrack(j);
cout << Clef[track];
if (j<infile[line].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
for (j=0; j<infile[line].getFieldCount(); j++) {
track = infile[line].getPrimaryTrack(j);
cout << Keysig[track];
if (j<infile[line].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
for (j=0; j<infile[line].getFieldCount(); j++) {
track = infile[line].getPrimaryTrack(j);
cout << Timesig[track];
if (j<infile[line].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
if (hasMetsig == 0) {
for (j=0; j<infile[line].getFieldCount(); j++) {
track = infile[line].getPrimaryTrack(j);
cout << Metsig[track];
if (j<infile[line].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
checkForPrimaryMensurationNeed(infile, line);
}
}
//////////////////////////////
//
// hasSectionLabel -- true if text start with [Ss]ection:
//
int hasSectionLabel(HumdrumFile& infile, int line) {
int j;
PerlRegularExpression pre;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j],
"^!LO:TX:.*t=\\s*[Ss][Ee][Cc][Tt][Ii][Oo][Nn]\\s*\\:\\s*([^:]*)\\s*$")) {
return 1;
}
}
return 0;
}
//////////////////////////////
//
// wrongSideOfBarline -- return true if current line is before a barline
// (true) or dataline (false)
//
int wrongSideOfBarline(HumdrumFile& infile, int line) {
int i;
for (i=line+1; i<infile.getNumLines(); i++) {
if (infile[i].isMeasure()) {
return 1;
} else if (infile[i].isData()) {
return 0;
}
}
return 0;
}
//////////////////////////////
//
// printSectionLabel --
//
void printSectionLabel(HumdrumFile& infile, int line) {
int other = 0;
int j;
Array<char> string;
PerlRegularExpression pre;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j],
"^!LO:TX:.*t=\\s*[Ss][Ee][Cc][Tt][Ii][Oo][Nn]\\s*\\:\\s*([^:]*)\\s*$")) {
string.setSize(strlen(pre.getSubmatch(1))+1);
strcpy(string.getBase(), pre.getSubmatch(1));
pre.sar(string, ":", ":", "g");
if (wrongSideOfBarline(infile, line)) {
Section.setSize(strlen(string.getBase()) + 1);
strcpy(Section.getBase(), string.getBase());
} else {
cout << "!!section: " << string << "\n";
cout << "!!!OMD: " << string << "\n";
}
infile[line].setToken(j, "!");
} else if (strcmp(infile[line][j], "!")) {
// do nothing
} else {
other = 1;
}
}
if (!infile[line].isNull()) {
cout << infile[line] << "\n";
}
}
//////////////////////////////
//
// checkAndPrintVox -- look for instrument names, and add an
// abbreviation underneath it.
//
void checkAndPrintVox(HumdrumFile& infile, int line) {
int j;
if (!infile[line].isInterpretation()) {
return;
}
PerlRegularExpression pre;
int hasInstrument = 0;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j], "^\\*I\"")) {
hasInstrument = 1;
break;
}
}
if (!hasInstrument) {
return;
}
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j], "^\\*I\"\\s*(.*)\\s*")) {
cout << "*Ivox";
} else {
cout << "*";
}
if (j<infile[line].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// checkAndPrintInstAbbr -- look for instrument names, and add an
// abbreviation underneath it.
//
void checkAndPrintInstAbbr(HumdrumFile& infile, int line) {
int j;
if (!infile[line].isInterpretation()) {
return;
}
PerlRegularExpression pre;
int hasInstrument = 0;
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j], "^\\*I\"")) {
hasInstrument = 1;
break;
}
}
if (!hasInstrument) {
return;
}
for (j=0; j<infile[line].getFieldCount(); j++) {
if (pre.search(infile[line][j], "^\\*I\"\\s*(.*)\\s*")) {
printAbbreviation(pre.getSubmatch(1));
} else {
cout << "*";
}
if (j<infile[line].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
}
////////////////////////////////////////
//
// printAbbreviation --
//
void printAbbreviation(const char* fullname) {
PerlRegularExpression pre;
if (pre.search(fullname, "^Superius", "i")) {
cout << "*I'S";
} else if (pre.search(fullname, "^Soprano", "i")) {
cout << "*I'S";
} else if (pre.search(fullname, "^Discantus", "i")) {
cout << "*I'D";
} else if (pre.search(fullname, "^Altus", "i")) {
cout << "*I'A";
} else if (pre.search(fullname, "^Alto", "i")) {
cout << "*I'A";
} else if (pre.search(fullname, "^Tenor", "i")) {
cout << "*I'T";
} else if (pre.search(fullname, "^Tenore", "i")) {
cout << "*I'T";
} else if (pre.search(fullname, "^Contratenor", "i")) {
cout << "*I'Ct";
} else if (pre.search(fullname, "^Contra", "i")) {
cout << "*I'C";
} else if (pre.search(fullname, "^Cantus", "i")) {
cout << "*I'Cn";
} else if (pre.search(fullname, "^Canto", "i")) {
cout << "*I'Cto";
} else if (pre.search(fullname, "^Quinto", "i")) {
cout << "*I'Qto";
} else if (pre.search(fullname, "^Bassus", "i")) {
cout << "*I'B";
} else if (pre.search(fullname, "^Bass", "i")) {
cout << "*I'B";
} else if (pre.search(fullname, "^Vagans", "i")) {
cout << "*I'V";
} else {
cout << "*I'XXX";
cerr << "WARNING: unknown instrument name: " << fullname << endl;
}
if (pre.search(fullname, "(\\d+[^\\s]*)")) {
cout << pre.getSubmatch(1);
}
return;
}
////////////////////////////////////////
//
// handleMensuration --
//
void handleMensuration(HumdrumFile& infile, int line) {
int& i = line;
int j;
PerlRegularExpression pre;
if (!infile[i].isInterpretation()) {
return;
}
if (i >= infile.getNumLines()-1) {
// should never get here, but just in case...
return;
}
int hasmeter = 0;
for (j=0; j<infile[i].getFieldCount(); j++) {
if (pre.search(infile[i][j], "^\\*M\\d")) {
hasmeter = 1;
break;
}
}
if (!hasmeter) {
return;
}
if (strncmp(infile[i+1][0], "*met(", 5) == 0) {
// don't add *met line if there already is one there.
return;
}
/* Mensuration added in another location now ... for (j=0; j<infile[i].getFieldCount(); j++) {
if (strcmp(infile[i][j], "*M2/1") == 0) {
cout << "*met(C|)x";
} else if (strcmp(infile[i][j], "*M3/1") == 0) {
cout << "*met(O)x";
} else {
if (infile[i].isExInterp(j, "**kern")) {
cout << "*met()x";
} else {
cout << "*";
}
}
if (j<infile[i].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
*/
}
//////////////////////////////
//
// hasLongRDF -- returns true if a bibliographic record starts with:
// !!!RDF**kern: l=long
//
int hasLongRDF(HumdrumFile& infile) {
int i;
PerlRegularExpression pre;
for (i=infile.getNumLines()-1; i>=0; i--) {
if (!infile[i].isBibliographic()) {
continue;
}
if (pre.search(infile[i][0],
"^!!!RDF\\*\\*kern\\s*:\\s*l\\s*=\\s*long", "i")) {
return 1;
}
}
return 0;
}
//////////////////////////////
//
// hadEditorial -- true if any **kern note has an "i" marker on it.
//
int hasEditorial(HumdrumFile& infile) {
int i, j;
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isData()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
continue;
}
if (strchr(infile[i][j], 'i') != NULL) {
return 1;
}
}
}
return 0;
}
//////////////////////////////
//
// hasEditorialRDF -- returns true if there is a bibliographic record
// starting with:
// !!!RDF**kern: i=edit
//
int hasEditorialRDF(HumdrumFile& infile) {
int i;
PerlRegularExpression pre;
for (i=infile.getNumLines()-1; i>=0; i--) {
if (!infile[i].isBibliographic()) {
continue;
}
if (pre.search(infile[i][0],
"^!!!RDF\\*\\*kern\\s*:\\s*i\\s*=\\s*edit", "i")) {
return 1;
}
}
return 0;
}
////////////////////
//
// fixAccentedText --
//
void fixAccentedText(HumdrumRecord& aRecord) {
int i;
for (i=0; i<aRecord.getFieldCount(); i++) {
if (!strcmp(aRecord[i], ".")) {
continue;
}
if (aRecord.isExInterp(i, "**text") || aRecord.isExInterp(i, "**silbe")) {
checkText(aRecord, i);
}
}
}
//////////////////////////////
//
// checkText --
//
void checkText(HumdrumRecord& aRecord, int index) {
PerlRegularExpression pre;
if (!pre.search(aRecord[index], "[^a-zA-Z0-9,. ='\"!@#$%^&*(){}\\|?/><-]")) {
return;
}
Array<char> text;
text.setSize(strlen(aRecord[index] + 1));
strcpy(text.getBase(), aRecord[index]);
pre.sar(text, "\xc5\xbd", "é", "g");
aRecord.setToken(index, text.getBase());
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("debug=b"); // determine bad input line num
opts.define("author=b"); // author of program
opts.define("version=b"); // compilation info
opts.define("example=b"); // example usages
opts.define("h|help=b"); // short description
opts.process(argc, argv);
// handle basic options:
if (opts.getBoolean("author")) {
cout << "Written by Craig Stuart Sapp, "
<< "craig@ccrma.stanford.edu, Dec 2011" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 15 Dec 2011" << 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);
}
}
//////////////////////////////
//
// example -- example usage of the quality program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the meter program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
// md5sum: bf3940a816bf4437a2dc40ac78561845 jrpize.cpp [20130206]