//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat Aug 11 13:26:47 PDT 2012
// Last Modified: Sat Aug 11 13:26:51 PDT 2012
// Filename: ...sig/examples/all/scr2hum.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/score/scr2hum.cpp
// Syntax: C++; museinfo
//
// Description: Display staff information for a SCORE page file.
//
#include "ScorePageSet.h"
#include "Options.h"
#include "Convert.h"
#include "HumdrumFile.h"
#include "PerlRegularExpression.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// function declarations:
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
void makeBarline(ScorePageSet& work, int i,
HumdrumRecord& barline);
void setBarlineStyle(HumdrumRecord& barline, int staffidx,
ScoreRecord& arecord);
void printStartingBar(ScorePageSet& work, HumdrumRecord& barline,
HumdrumFile& newfile);
void printMeter(ScorePageSet& work, HumdrumRecord& meter,
HumdrumFile& newfile, int objidx, double hpos,
Array<int>& kernstart);
void printTempoNear(ScorePageSet& work, HumdrumRecord& tempoline, HumdrumFile& newfile,
int objidx, double hpos, Array<int>& kernstart);
void convertScoreMeterToKernMeter(char* buffer, ScoreRecord& srecord);
void printKeySignature(ScorePageSet& work, HumdrumRecord& keysigline,
HumdrumFile& newfile, int objidx, double hpos,
Array<int>& keysig, Array<int>& kernstart);
int convertScoreKeysigToKernKeysig(char* buffer, ScoreRecord& srecord);
void convertScoreClefToKernClef(char* buffer, ScoreRecord& srecord);
void printClef(ScorePageSet& work, HumdrumRecord& clefline,
HumdrumFile& newfile, int objidx, double hpos,
Array<Array<char> >& clefs,
Array<int>& kernstart);
void printTitle(ScorePageSet& work, HumdrumFile& newfile);
void printComposer(ScorePageSet& work, HumdrumFile& newfile);
void printInstruments(ScorePageSet& work, HumdrumFile& newfile,
HumdrumRecord& instruments,
Array<int>& kernstart);
void getInstrumentCode(Array<char>& code, Array<char>& name);
void getInstrumentAbbreviation(Array<char>& code, Array<char>& name);
int getPrettyScoreText(Array<char>& textdata, ScoreRecord& arecord);
int getPrettyScoreText(Array<char>& textdata);
void setHeaderRecord(HumdrumRecord& header, Array<int>& kernstart,
Array<int>& kerncount, Array<int>& dynamstart,
Array<int>& dynamcount, Array<int>& versestart,
Array<int>& versecount);
void setStaffAssignmentRecord(HumdrumRecord& staffassignment, Array<int>& kernstart,
Array<int>& kerncount, Array<int>& dynamstart,
Array<int>& dynamcount, Array<int>& versestart,
Array<int>& versecount);
void extractLyrics(ScorePageSet& work, int item,
HumdrumRecord& dataline, Array<int>& versestart,
Array<int>& versecount);
void getNoteVerseLinks(Array<int>& verses, ScorePageSet& work, int witem);
// interface variables:
Options options;
int verboseQ = 0; // used with -v option
int debugQ = 0; // used with --debug option
int invisibleQ = 1; // used with -I option
int stemQ = 1; // used with --no-stems
int plainQ = 0; // used with -p option
int htmlQ = 1;
int lyricsQ = 1; // used with -L option
int dynamQ = 0; // not used yet
//////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
checkOptions(options, argc, argv);
int i;
ScorePageSet work;
for (i=1; i<=options.getArgCount(); i++) {
work.appendRead(options.getArg(i), verboseQ);
}
work.analyzeContent();
char buffer[1024] = {0};
HumdrumFile newfile;
HumdrumRecord header;
HumdrumRecord staffassignment;
HumdrumRecord trailer;
HumdrumRecord barline;
HumdrumRecord dataline;
HumdrumRecord meterline;
HumdrumRecord tempoline;
HumdrumRecord keysigline;
HumdrumRecord clefline;
HumdrumRecord instruments;
int sysstaffcount = work.getSystemStaffCount();
int sysStaffIdx;
int versesum = 0;
Array<int> versecount(sysstaffcount);
versecount.setAll(0);
if (lyricsQ) {
for (i=0; i<versecount.getSize(); i++) {
versecount[i] = work.getVerseCount(i);
versesum += versecount[i];
}
}
// allow for dynamics later...
int dynamsum = 0;
Array<int> dynamcount(sysstaffcount);
dynamcount.setAll(0);
Array<int> dynamstart(sysstaffcount);
dynamstart.setAll(-1); // starting spine index for start of track's dynams
Array<int> versestart(sysstaffcount);
versestart.setAll(-1); // starting spine index for start of track's verses
int kernsum = sysstaffcount;
Array<int> kerncount(sysstaffcount);
kerncount.setAll(1); // not allowing spine splits for now...
Array<int> kernstart(sysstaffcount);
kernstart.setAll(-1); // starting spine index for start of track's notes
int allsum = versesum + dynamsum + kernsum;
int currtrack = 0;
for (i=0; i<sysstaffcount; i++) {
kernstart[i] = currtrack;
currtrack += kerncount[i];
if (dynamQ) {
dynamstart[i] = currtrack;
currtrack += dynamcount[i];
}
if (lyricsQ) {
versestart[i] = currtrack;
currtrack += versecount[i];
}
}
double lastAbsBeat = -1;
double absBeat = -1;
header.setSize(allsum);
staffassignment.setSize(allsum);
setHeaderRecord(header, kernstart, kerncount, dynamstart,
dynamcount, versestart, versecount);
setStaffAssignmentRecord(staffassignment, kernstart, kerncount,
dynamstart, dynamcount, versestart, versecount);
trailer.setSize(allsum);
trailer.setAllFields("*-");
barline.setSize(allsum);
barline.setAllFields("=");
dataline.setSize(allsum);
dataline.setAllFields(".");
meterline.setSize(allsum);
meterline.setAllFields(".");
tempoline.setSize(allsum);
tempoline.setAllFields(".");
keysigline.setSize(allsum);
keysigline.setAllFields(".");
clefline.setSize(allsum);
clefline.setAllFields(".");
instruments.setSize(allsum);
instruments.setAllFields("*");
double lastbarbeat = 0.0;
int emmitbarline = 0;
Array<int> keysig(sysstaffcount);
keysig.setAll(-100);
Array<Array<char> > clefs(allsum);
for (i=0; i<allsum; i++) {
clefs[i].setSize(1);
clefs[i][0] = '\0';
}
int dataQ = 0;
int p11;
printComposer(work, newfile);
printTitle(work, newfile);
newfile.appendLine(header);
newfile.appendLine(staffassignment);
printInstruments(work, newfile, instruments, kernstart);
char token[1024] = {0};
double hpos;
// the meter hpos needs to be reset each system, but doing that by
// resetting whenever a durational item is found.
double lastmeterhpos = -1;
double lastkeysighpos = -1;
double lastclefhpos = -1;
int stemdir = 0;
int haseditorial = 0;
for (i=0; i<work.getItemCount(); i++) {
absBeat = work.getItem(i).getAbsBeat();
hpos = work.getItem(i).getHpos();
if ((!invisibleQ) && (work.getItem(i).isRestItem() &&
(work.getItem(i).getValue(P6) == -1.0))) {
continue;
}
if (work.getItem(i).isBarlineItem() && (lastbarbeat != absBeat)) {
makeBarline(work, i, barline);
// newfile.appendLine(barline);
emmitbarline = 1;
if (!(dataline.equalFieldsQ() && (strcmp(dataline[0], ".") == 0))) {
newfile.appendLine(dataline);
dataline.setAllFields(".");
}
if (emmitbarline) {
if (work.isAtEnd(i)) {
barline.setAllFields("==");
}
if ((newfile.getNumLines() > 0) &&
(strncmp(newfile[newfile.getNumLines()-1][0], "=", 1) != 0)) {
newfile.appendLine(barline);
}
barline.setAllFields("=");
emmitbarline = 0;
}
lastbarbeat = absBeat;
}
if ((fabs(hpos - lastkeysighpos) > 0.01) &&
(work.getItem(i).isKeysigItem())) {
printKeySignature(work, keysigline, newfile, i, hpos, keysig,
kernstart);
lastkeysighpos = hpos;
}
// why is this after keysig?
if ((fabs(hpos - lastclefhpos) > 0.01) &&
(work.getItem(i).isClefItem())) {
printClef(work, clefline, newfile, i, hpos, clefs, kernstart);
lastclefhpos = hpos;
}
if ((fabs(hpos - lastmeterhpos) > 0.01) &&
(work.getItem(i).isMeterItem())) {
printMeter(work, meterline, newfile, i, hpos, kernstart);
printTempoNear(work, tempoline, newfile, i, hpos, kernstart);
lastmeterhpos = hpos;
}
if (!(work.getItem(i).hasDuration())) {
continue;
}
lastmeterhpos = -1;
lastkeysighpos = -1;
lastclefhpos = -1;
if (!dataQ) {
printStartingBar(work, barline, newfile);
dataQ = 1;
}
if ((absBeat != lastAbsBeat) && (lastAbsBeat >= 0)) {
if (!(dataline.equalFieldsQ() && (strcmp(dataline[0], ".") == 0))) {
newfile.appendLine(dataline);
}
if (emmitbarline) {
if (work.isAtEnd(i)) {
barline.setAllFields("==");
}
newfile.appendLine(barline);
emmitbarline = 0;
barline.setAllFields("=");
}
dataline.setAllFields(".");
}
lastAbsBeat = absBeat;
token[0] = '\0';
sysStaffIdx = work.getSystemStaffIndex(i);
if (work.getItem(i).hasTieStart()) {
strcat(token, "[");
}
Convert::durationToKernRhythm(buffer, work.getItem(i).getDuration());
strcat(token, buffer);
if (work.getItem(i).getPitch() <= 0) {
strcat(token, "r");
} else {
Convert::base40ToKern(buffer, work.getItem(i).getPitch());
strcat(token, buffer);
}
// if the note has a printed accidental which is predictable even if
// the printed accidental was there or not, then it is a cautionary
// accidental. The pitch analysis stage marks cautionary accidentals
// by setting the named parameter "cautionary" to non-zero (1).
if (work.getItem(i).hasCautionary()) {
strcat(token, "X");
}
// print articulations
p11 = work.getItem(i).getValue(P11);
if (abs(p11) == 1) { // editorial flat
if (strchr(token, '-') == NULL) {
strcat(token, "-");
}
strcat(token, "i");
haseditorial = 1;
} else if (abs(p11) == 2) { // editorial sharp
if (strchr(token, '#') == NULL) {
strcat(token, "#");
}
strcat(token, "i");
haseditorial = 1;
} else if (abs(p11) == 3) { // editorial natural
if (strchr(token, 'n') == NULL) {
strcat(token, "n");
}
strcat(token, "i");
haseditorial = 1;
} else if (abs(p11) == 14) {
// fermata
strcat(token, ";");
}
if (stemQ) {
stemdir = work.getItem(i).getStemDirection();
if (stemdir > 0) {
strcat(token, "/");
} else if (stemdir < 0) {
strcat(token, "\\");
}
}
if (work.getItem(i).hasTieEnd()) {
strcat(token, "]");
} else if (work.getItem(i).hasTieContinue()) {
strcat(token, "_");
}
dataline.changeField(kernstart[sysStaffIdx], token);
if (lyricsQ) {
extractLyrics(work, i, dataline, versestart, versecount);
}
}
if (emmitbarline) {
// no longer active
barline.setAllFields("==");
newfile.appendLine(barline);
emmitbarline = 0;
}
newfile.appendLine(trailer);
if (haseditorial) {
newfile.appendLine("!!!RDF**kern: i=editorial accidental");
}
cout << newfile;
return 0;
}
//////////////////////////////
//
// printStartingBar --
//
void printStartingBar(ScorePageSet& work, HumdrumRecord& barline,
HumdrumFile& newfile) {
// check to see if a pickup measure, if so, then don't print anything
// otherwise, print an invisible barline
// for now, just print an invisible barline all of the time.
barline.setAllFields("=-");
newfile.appendLine(barline);
}
//////////////////////////////
//
// makeBarline --
//
void makeBarline(ScorePageSet& work, int index, HumdrumRecord& barline) {
// just do a simple barline for now without any style adjustments
barline.setAllFields("=");
int i;
double absbeat = work.getAbsBeat(index);
for (i=index; i<work.getItemCount(); i++) {
if (work.getAbsBeat(i) != absbeat) {
break;
}
if (!work.getItem(i).isBarlineItem()) {
continue;
}
setBarlineStyle(barline, work.getSysStaffIndex(i), work.getItem(i));
}
for (i=index-1; i>=0; i--) {
if (work.getAbsBeat(i) != absbeat) {
break;
}
if (!work.getItem(i).isBarlineItem()) {
continue;
}
setBarlineStyle(barline, work.getSystemStaffIndex(i), work.getItem(i));
}
}
//////////////////////////////
//
// setBarlineStyle --
//
void setBarlineStyle(HumdrumRecord& barline, int staffidx, ScoreRecord& arecord) {
int partialQ = 0;
int barnum = -1;
if ((arecord.getValue(P10) > 3) && (arecord.getValue(P11) < 11)) {
partialQ = 1;
}
if (arecord.hasValue("barnum")) {
barnum = arecord.getValue("barnum");
}
char buffer[1024] = {0};
if (barnum >=0) {
sprintf(buffer, "=%d", barnum);
} else {
strcat(buffer, "=");
}
if (partialQ) {
strcat(buffer, "'");
}
barline.changeField(staffidx, buffer);
}
//////////////////////////////
//
// printClef --
//
void printClef(ScorePageSet& work, HumdrumRecord& clefline,
HumdrumFile& newfile, int objidx, double hpos,
Array<Array<char> >& clefs, Array<int>& kernstart) {
clefline.setAllFields("*");
int staffidx;
int i;
int foundQ = 0;
double h;
char buffer[1024] = {0};
for (i=objidx; i<work.getItemCount(); i++) {
if (!work.getItem(i).isClefItem()) {
continue;
}
h = work.getItem(i).getHpos();
if (h != hpos) {
continue;
}
staffidx = work.getItem(i).getSystemStaffIndex();
convertScoreClefToKernClef(buffer, work.getItem(i));
if (strcmp(clefs[staffidx].getBase(), buffer) == 0) {
// the new key signature is the same as the previous one
// so ignore the new key signature (since it is probably at
// the start of a new system).
continue;
} else {
clefs[staffidx].setSize(strlen(buffer)+1);
strcpy(clefs[staffidx].getBase(), buffer);
}
if (strcmp(buffer, "*") != 0) {
foundQ = 1;
}
clefline.changeField(kernstart[staffidx], buffer);
}
if (foundQ) {
newfile.appendLine(clefline);
}
}
//////////////////////////////
//
// printKeySignature --
//
void printKeySignature(ScorePageSet& work, HumdrumRecord& keysigline,
HumdrumFile& newfile, int objidx, double hpos, Array<int>& keysig,
Array<int>& kernstart) {
keysigline.setAllFields("*");
int staffidx;
int i;
int foundQ = 0;
double h;
int keystate;
char buffer[1024] = {0};
for (i=objidx; i<work.getItemCount(); i++) {
if (!work.getItem(i).isKeysigItem()) {
continue;
}
h = work.getItem(i).getHpos();
if (fabs(h - hpos) > 1.0) {
// if key sigantures are not vertically aligned enough, they will
// be printed on separte lines.
continue;
}
staffidx = work.getItem(i).getSystemStaffIndex();
keystate = convertScoreKeysigToKernKeysig(buffer, work.getItem(i));
if (keysig[staffidx] == keystate) {
// the new key signature is the same as the previous one
// so ignore the new key signature (since it is probably at
// the start of a new system).
continue;
} else {
keysig[staffidx] = keystate;
}
if (strcmp(buffer, "*") != 0) {
foundQ = 1;
}
keysigline.changeField(kernstart[staffidx], buffer);
}
if (foundQ) {
for (i=0; i<keysig.getSize(); i++) {
if ((keysig[i] < -7) && (strcmp(keysigline[kernstart[i]], "*") == 0)) {
keysigline.changeField(kernstart[i], "*k[]");
keysig[i] = 0;
}
}
newfile.appendLine(keysigline);
}
}
//////////////////////////////
//
// printTempoNear -- print a tempo marking in all **kern spines if one is found near
// the given hpos location on the staff.
//
void printTempoNear(ScorePageSet& work, HumdrumRecord& tempoline, HumdrumFile& newfile,
int objidx, double hpos, Array<int>& kernstart) {
int ssidx = work.getItem(objidx).getPageSystemIndex();
int tssidx;
int thpos;
ScoreRecord* srecord = NULL;
double limiting = 20.0; // maximum before/after search range on staff to look for tempo
double tempofound = -1;
double tempohpos = -1;
int i;
// search forward for a tempo indication on page
for (i=objidx; i<work.getObjectCount(); i++) {
srecord = &(work.getItem(i));
tssidx = srecord->getPageSystemIndex();
if (tssidx != ssidx) {
break;
}
thpos = srecord->getHpos();
if (fabs(thpos - hpos) > limiting) {
break;
}
if (!srecord->isTextItem()) {
continue;
}
if (srecord->getValue("tempo") > 0.0) {
tempofound = i;
tempohpos = thpos;
break;
}
}
// search backward for a tempo indication on page
for (i=objidx; i>=0; i--) {
srecord = &(work.getItem(i));
tssidx = srecord->getPageSystemIndex();
if (tssidx != ssidx) {
break;
}
thpos = srecord->getHpos();
if (fabs(thpos - hpos) > limiting) {
break;
}
if (!srecord->isTextItem()) {
continue;
}
if (srecord->getValue("tempo") > 0.0) {
if (fabs(thpos - hpos) < fabs(tempohpos - hpos)) {
tempofound = i;
tempohpos = thpos;
}
break;
}
}
if (tempofound <= 0) {
return;
}
char buffer[1024] = {0};
tempoline.setAllFields("*");
sprintf(buffer, "*MM%d", (int)work.getItem(tempofound).getValue("tempo"));
for (i=0; i<kernstart.getSize(); i++) {
tempoline.changeField(kernstart[i], buffer);
}
newfile.appendLine(tempoline);
}
//////////////////////////////
//
// printMeter --
//
void printMeter(ScorePageSet& work, HumdrumRecord& meter, HumdrumFile& newfile,
int objidx, double hpos, Array<int>& kernstart) {
meter.setAllFields("*");
int staffidx;
int i;
int foundQ = 0;
double h;
char buffer[1024] = {0};
for (i=objidx; i<work.getItemCount(); i++) {
if (!work.getItem(i).isMeterItem()) {
continue;
}
h = work.getItem(i).getHpos();
if (fabs(h - hpos) > 1.0) {
// if time sigantures are not vertically aligned enough, they will be printed on
// separte lines.
continue;
}
staffidx = work.getItem(i).getSystemStaffIndex();
convertScoreMeterToKernMeter(buffer, work.getItem(i));
if (strcmp(buffer, "*") != 0) {
foundQ = 1;
}
meter.changeField(kernstart[staffidx], buffer);
}
if (foundQ) {
newfile.appendLine(meter);
}
}
//////////////////////////////
//
// convertScoreClefToKernClef -- not dealing with all P4!=0 possibilities yet.
//
void convertScoreClefToKernClef(char* buffer, ScoreRecord& srecord) {
int p5int = srecord.getValue(P5);
double frac = srecord.getValue(P5) - p5int;
if (frac < 0) {
frac = -frac;
}
int octave = int(frac * 10.0 + 0.490);
int p4 = srecord.getValue(P4);
strcpy(buffer, "");
if (octave == 0) {
switch (p5int) {
case 0: strcpy(buffer, "*clefG2"); return;
case 1:
if (p4 == 0) {
strcpy(buffer, "*clefF4"); // bass clef
} else if (p4==-2) {
strcpy(buffer, "*clefF3"); // bariton clef
}
return;
case 2:
if (p4 == 0) {
strcpy(buffer, "*clefC3"); // alto clef
} else if (p4 == -4) {
strcpy(buffer, "*clefC1"); // soprano clef
} else if (p4 == -2) {
strcpy(buffer, "*clefC2"); // mezzo-soprano clef
}
return;
case 3: strcpy(buffer, "*clefC4"); return; // tenor clef
case 4: strcpy(buffer, "*clefX"); return;
}
} else {
switch (p5int) {
case 0:
strcpy(buffer, "*clefGv2"); // vocal tenor clef
return;
case 1:
strcpy(buffer, "*clefFv2"); // bass down clef
return;
}
}
}
//////////////////////////////
//
// convertScoreKeysigToKernKeysig --
//
int convertScoreKeysigToKernKeysig(char* buffer, ScoreRecord& srecord) {
int p5 = srecord.getValue(P5);
if ((p5 > 100) || (p5 <= -100)) {
// ignoring cancellation key signatures for now...
strcpy(buffer, "*");
return 0;
}
switch (p5) {
case 0: strcpy(buffer, "*k[]"); return 0;
case 1: strcpy(buffer, "*k[f#]"); return 1;
case 2: strcpy(buffer, "*k[f#c#]"); return 2;
case 3: strcpy(buffer, "*k[f#c#g#]"); return 3;
case 4: strcpy(buffer, "*k[f#c#g#d#]"); return 4;
case 5: strcpy(buffer, "*k[f#c#g#d#a#]"); return 5;
case 6: strcpy(buffer, "*k[f#c#g#d#a#e#]"); return 6;
case 7: strcpy(buffer, "*k[f#c#g#d#a#e#b#]"); return 7;
case -1: strcpy(buffer, "*k[b-]"); return -1;
case -2: strcpy(buffer, "*k[b-e-]"); return -2;
case -3: strcpy(buffer, "*k[b-e-a-]"); return -3;
case -4: strcpy(buffer, "*k[b-e-a-d-]"); return -4;
case -5: strcpy(buffer, "*k[b-e-a-d-g-]"); return -5;
case -6: strcpy(buffer, "*k[b-e-a-d-g-c-]"); return -6;
case -7: strcpy(buffer, "*k[b-e-a-d-g-c-f-]"); return -7;
}
// shouldn't get here
strcpy(buffer, "*");
return 0;
}
//////////////////////////////
//
// convertScoreMeterToKernMeter --
//
void convertScoreMeterToKernMeter(char* buffer, ScoreRecord& srecord) {
int p5 = srecord.getValue(P5);
int p6 = srecord.getValue(P6);
int p8 = srecord.getValue(P8);
int p9 = srecord.getValue(P9);
if (p8 != 0) {
if (p9 != 0) {
sprintf(buffer, "*M%d/%d/+%d/%d", p5, p6, p8, p9);
return;
} else {
sprintf(buffer, "*M%d+%d/%d", p5, p8, p6);
return;
}
}
if ((p5==99) && (p6==1)) {
strcpy(buffer, "*met(c)");
return;
}
if ((p5==98) && (p6==1)) {
strcpy(buffer, "*met(c|)");
return;
}
if ((p5!=0) && (p6!=0)) {
sprintf(buffer, "*M%d/%d", p5, p6);
return;
}
if ((p5==0) && (p6!=0)) {
sprintf(buffer, "*M%d", p6);
return;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("v|verbose=b", "verbose display of information");
opts.define("I|no-invisible=b", "do not dispay invisible rests");
opts.define("S|no-stems=b", "do not dispay note stems");
opts.define("p|plain=b", "display SCORE text as plain ASCII");
opts.define("L|no-lyrics=b", "do not display lyrcs");
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, Jul 2012" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 29 Jul 2012" << endl;
cout << "compiled: " << __DATE__ << endl;
exit(0);
} else if (opts.getBoolean("help")) {
usage(opts.getCommand());
exit(0);
} else if (opts.getBoolean("example")) {
example();
exit(0);
}
verboseQ = opts.getBoolean("verbose");
debugQ = opts.getBoolean("debug");
invisibleQ = !opts.getBoolean("no-invisible");
stemQ = !opts.getBoolean("no-stems");
plainQ = opts.getBoolean("plain");
lyricsQ = !opts.getBoolean("no-lyrics");
htmlQ = !plainQ;
}
//////////////////////////////
//
// 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;
}
//////////////////////////////
//
// printTitle --
//
void printTitle(ScorePageSet& work, HumdrumFile& newfile) {
Array<char> title;
work.getTitle(title);
getPrettyScoreText(title);
PerlRegularExpression pre;
char buffer[1024] = {0};
if (title.getSize() > 1) {
strcpy(buffer, "!!!OTL: ");
pre.sar(title, "_\\d\\d", "", "g");
strcat(buffer, title.getBase());
newfile.appendLine(buffer);
}
}
//////////////////////////////
//
// printComposer --
//
void printComposer(ScorePageSet& work, HumdrumFile& newfile) {
Array<char> composer;
work.getComposer(composer);
PerlRegularExpression pre;
pre.sar(composer, "^\\s+", "");
pre.sar(composer, "\\s+$", "");
pre.sar(composer, "\\s+", " ");
int spacecount = 0;
int commacount = 0;
int i;
for (i=0; i<composer.getSize(); i++) {
if (composer[i] == ' ') {
spacecount++;
} else if (composer[i] == ',') {
commacount++;
}
}
if ((spacecount == 1) && (commacount == 0)) {
pre.search(composer, "(.*) (.*)");
composer.increase();
strcpy(composer.getBase(), pre.getSubmatch(2));
strcat(composer.getBase(), ", ");
strcat(composer.getBase(), pre.getSubmatch(1));
}
char buffer[1024] = {0};
if (composer.getSize() > 1) {
pre.sar(composer, "_\\d\\d", "", "g");
if (pre.search(composer, "\\?\\s*$")) {
strcpy(buffer, "!!!COA: ");
pre.sar(composer, "\\?\\s*$", "");
} else {
strcpy(buffer, "!!!COM: ");
}
if (strcmp(composer.getBase(), "Guillaume Du Fay") == 0) {
strcat(buffer, "Du Fay, Guillaume");
} else {
strcat(buffer, composer.getBase());
}
newfile.appendLine(buffer);
if (pre.search(composer, "Du\\s*Fay", "i")) {
newfile.appendLine("!!!CDT: ~1397/08/05/-1474/11/27/");
}
}
}
//////////////////////////////
//
// printInstruments --
//
void printInstruments(ScorePageSet& work, HumdrumFile& newfile,
HumdrumRecord& instruments, Array<int>& kernstart) {
int staffcount = work.getSystemStaffCount();
instruments.setAllFields("*");
char buffer[1024] = {0};
Array<Array<char> > instrumentnames(staffcount);
Array<Array<char> > abbreviations(staffcount);
Array<Array<char> > instrumentcodes(staffcount);
int instrumentsQ = 0;
int i;
for (i=0; i<staffcount; i++) {
instrumentnames[i].setSize(1); instrumentnames[i][0] = '\0';
work.getInstrumentName(i, instrumentnames[i]);
if (instrumentnames[i].getSize() > 1) {
instrumentsQ = 1;
}
abbreviations[i].setSize(1); abbreviations[i][0] = '\0';
getInstrumentAbbreviation(abbreviations[i], instrumentnames[i]);
instrumentcodes[i].setSize(1); instrumentcodes[i][0] = '\0';
getInstrumentCode(instrumentcodes[i], instrumentnames[i]);
}
if (!instrumentsQ) {
return;
}
for (i=0; i<instrumentnames.getSize(); i++) {
if (instrumentnames[i].getSize() > 1) {
strcpy(buffer, "*I\"");
strcat(buffer, instrumentnames[i].getBase());
instruments.changeField(kernstart[i], buffer);
} else {
instruments.changeField(kernstart[i], "*");
}
}
newfile.appendLine(instruments);
for (i=0; i<abbreviations.getSize(); i++) {
if (abbreviations[i].getSize() > 1) {
strcpy(buffer, abbreviations[i].getBase());
instruments.changeField(kernstart[i], buffer);
} else {
instruments.changeField(kernstart[i], "*");
}
}
newfile.appendLine(instruments);
}
//////////////////////////////
//
// getInstrumentAbbreviation --
//
void getInstrumentAbbreviation(Array& code, Array& name) {
code.setSize(1);
code[0] = '\0';
char buffer[1024] = {0};
char buffer2[1024] = {0};
PerlRegularExpression pre;
if (pre.search(name, "^\\s$")) {
return;
} else if (pre.search(name, "^Superius", "i")) {
strcpy(buffer, "*I'S");
} else if (pre.search(name, "^Soprano", "i")) {
strcpy(buffer, "*I'S");
} else if (pre.search(name, "^Discantus", "i")) {
strcpy(buffer, "*I'D");
} else if (pre.search(name, "^Altus", "i")) {
strcpy(buffer, "*I'A");
} else if (pre.search(name, "^Alto", "i")) {
strcpy(buffer, "*I'A");
} else if (pre.search(name, "^Tenor", "i")) {
strcpy(buffer, "*I'T");
} else if (pre.search(name, "^Tenore", "i")) {
strcpy(buffer, "*I'T");
} else if (pre.search(name, "^Contratenor", "i")) {
strcpy(buffer, "*I'Ct");
} else if (pre.search(name, "^Contra", "i")) {
strcpy(buffer, "*I'C");
} else if (pre.search(name, "^Bassus", "i")) {
strcpy(buffer, "*I'B");
} else if (pre.search(name, "^Bass", "i")) {
strcpy(buffer, "*I'B");
} else if (pre.search(name, "^Vagans", "i")) {
strcpy(buffer, "*I'V");
} else if (pre.search(name, "^Cantus", "i")) {
strcpy(buffer, "*I'Ca");
} else {
// unknown instrument, put in a dummy
strcpy(buffer, "*I'XXX");
}
if (pre.search(name, "(\\d+)")) {
strcpy(buffer2, pre.getSubmatch(1));
strcat(buffer, buffer2);
}
int len = strlen(buffer);
code.setSize(len+1);
strcpy(code.getBase(), buffer);
}
//////////////////////////////
//
// getInstrumentCode --
//
void getInstrumentCode(Array& code, Array& name) {
}
//////////////////////////////
//
// getPrettyScoreText -- returns the number of charcters printed
//
int getPrettyScoreText(Array& textdata, ScoreRecord& arecord) {
arecord.getTextDataWithoutFonts(textdata);
return getPrettyScoreText(textdata);
}
//////////////////////////////
//
// getPrettyScoreText -- returns the number of charcters printed
//
int getPrettyScoreText(Array& textdata) {
if (plainQ) {
ScoreRecord::convertScoreTextToPlainText(textdata);
} else if (htmlQ) {
ScoreRecord::convertScoreTextToHtmlText(textdata);
}
return strlen(textdata.getBase());
}
//////////////////////////////
//
// setStaffAssignmentRecord --
//
void setStaffAssignmentRecord(HumdrumRecord& staffassignment, Array<int>& kernstart,
Array<int>& kerncount, Array<int>& dynamstart, Array<int>& dynamcount,
Array<int>& versestart, Array<int>& versecount) {
int current = 0;
int i, j;
int staffnum;
char buffer[1024] = {0};
for (i=0; i<kernstart.getSize(); i++) {
staffnum = kernstart.getSize() - i;
sprintf(buffer, "*staff%d", staffnum);
for (j=0; j<kerncount[i]; j++) {
staffassignment.changeField(current++, buffer);
}
for (j=0; j<dynamcount[i]; j++) {
staffassignment.changeField(current++, buffer);
}
for (j=0; j<versecount[i]; j++) {
staffassignment.changeField(current++, buffer);
}
}
}
//////////////////////////////
//
// setHeaderRecord -- assign exclusive interpretations for each column.
//
void setHeaderRecord(HumdrumRecord& header, Array<int>& kernstart,
Array<int>& kerncount, Array<int>& dynamstart, Array<int>& dynamcount,
Array<int>& versestart, Array<int>& versecount) {
int current = 0;
int i, j;
for (i=0; i<kernstart.getSize(); i++) {
for (j=0; j<kerncount[i]; j++) {
header.changeField(current++, "**kern");
}
for (j=0; j<dynamcount[i]; j++) {
header.changeField(current++, "**dynam");
}
for (j=0; j<versecount[i]; j++) {
header.changeField(current++, "**text");
}
}
}
//////////////////////////////
//
// extractLyrics --
//
void extractLyrics(ScorePageSet& work, int item, HumdrumRecord& dataline,
Array<int>& versestart, Array<int>& versecount) {
PerlRegularExpression pre;
int sysstaffidx = work.getSysStaffIndex(item);
int j;
Array<char> buffer;
Array<int> verses(versecount[sysstaffidx]);
verses.setAll(-1);
getNoteVerseLinks(verses, work, item);
for (j=0; j<verses.getSize(); j++) {
if (verses[j] < 0) {
dataline.changeField(versestart[sysstaffidx]+j, ".");
continue;
}
work.getItem(verses[j]).getTextDataWithoutFonts(buffer);
ScoreRecord::convertScoreTextToHtmlText(buffer);
if (strlen(buffer.getBase()) == 0) {
dataline.changeField(versestart[sysstaffidx]+j, ".");
} else {
// need to handle cases where text starts with Humdrum control
// charcters: * or !
if (!work.getItem(verses[j]).isWordStart()) {
pre.sar(buffer, "^", "-");
}
if (!work.getItem(verses[j]).isWordEnd()) {
pre.sar(buffer, "$", "-");
}
dataline.changeField(versestart[sysstaffidx]+j, buffer.getBase());
}
}
}
//////////////////////////////
//
// getNoteVerseLinks --
//
void getNoteVerseLinks(Array& verses, ScorePageSet& work, int witem) {
verses.setAll(-1);
int pageidx = work.getItemPage(witem);
ScorePage& page = work.getPage(pageidx);
int pitem = work.getItemPageIndex(witem);
double hpos = page.getItem(pitem).getHpos();
double nextnotehpos = page.getNextNotePositionOnStaff(pitem);
double prevnotehpos = page.getPreviousNotePositionOnStaff(pitem);
double nextcut = (hpos + nextnotehpos) / 2.0;
double prevcut = (hpos + prevnotehpos) / 2.0;
// Collect all verse syllables within 1/2 of the distance to the
// next/previous note/rest. Only taking the closest syllable from
// each verse, however (not all of them).
int versenum;
int sysidx = page.getSystemIndex(pitem);
int staffidx = page.getSystemStaffIndex(pitem);
int ssitem = page.getSystemStaffItemIndex(pitem);
double thpos;
ScoreRecord* srecord;
int i;
int pstaff = (int)page.getItem(pitem).getValue(P2);
int tstaff;
Array<int> backwarditem(verses.getSize());
backwarditem.setAll(-1);
Array<double> backwardhpos(verses.getSize());
backwardhpos.setAll(-1.0);
// search for lyric syllables to the left of a note.
for (i=ssitem-1; i>=0; i--) {
srecord = &(page.getSysStaffItem(sysidx, staffidx, i));
// check that the staff number has not changed; exit loop otherwise.
tstaff = (int)srecord->getValue(P2);
if (tstaff != pstaff) {
break;
}
// get horizontal position of item.
thpos = srecord->getHpos();
// if it is less than the cutoff horizontal position, exit the loop.
if (thpos < prevcut) {
break;
}
// ignore item if it is not a lyric syllable.
if (!srecord->isVerse()) {
continue;
}
// if there is an undefined verse number for some strange reason skip it:
versenum = srecord->getVerseIndex();
if (versenum < 0) {
continue;
}
// if the verse number is larger than expectd, skip over it as well:
if (versenum > verses.getSize()-1) {
// strange error
continue;
}
// only keep track of the closest syllable of each verse
if (backwarditem[versenum] < 0) {
backwarditem[versenum] = srecord->getSetIndex();
backwardhpos[versenum] = thpos;
}
}
Array<int> forwarditem(verses.getSize());
forwarditem.setAll(-1);
Array<double> forwardhpos(verses.getSize());
forwardhpos.setAll(-1.0);
// search for lyric syllables to the right of a note.
for (i=ssitem+1; i<page.getSysStaffItemCount(sysidx, staffidx); i++) {
srecord = &(page.getSysStaffItem(sysidx, staffidx, i));
// check that the staff number has not changed; exit otherwise.
tstaff = (int)srecord->getValue(P2);
if (tstaff != pstaff) {
break;
}
// get horizontal position of item.
thpos = srecord->getHpos();
// if it is greater than the cutoff horizontal position, exit the loop.
if (thpos > nextcut) {
break;
}
// ignore item if it is not a lyric syllable.
if (!srecord->isVerse()) {
continue;
}
// if there is an undefined verse number for some strange reason skip it:
versenum = srecord->getVerseIndex();
if (versenum < 0) {
continue;
}
// if the verse number is larger than expectd, skip over it as well:
if (versenum > verses.getSize()-1) {
// strange error: verse number larger than expected.
continue;
}
// only keep track of the closest syllable of each verse
if (forwarditem[versenum] < 0) {
forwarditem[versenum] = srecord->getSetIndex();
forwardhpos[versenum] = thpos;
}
}
double backdist;
double foredist;
for (i=0; i<verses.getSize(); i++) {
if ((backwarditem[i] < 0) && (forwarditem[i] > 0)) {
verses[i] = forwarditem[i];
continue;
} else if ((backwarditem[i] > 0) && (forwarditem[i] < 0)) {
verses[i] = backwarditem[i];
continue;
} else if ((backwarditem[i] < 0) && (forwarditem[i] < 0)) {
continue;
}
backdist = fabs(backwardhpos[i] - hpos);
foredist = fabs(forwardhpos[i] - hpos);
if (backdist < foredist) {
verses[i] = backwarditem[i];
} else {
verses[i] = forwarditem[i];
}
}
}
// md5sum: 513e0ca6f0325103ff902791bc811bbe scr2hum.cpp [20130206]