//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Tue Jun 5 13:48:27 PDT 2001
// Last Modified: Tue Jun 5 13:48:29 PDT 2001
// Last Modified: Fri Feb 25 00:09:19 PST 2005 (balanced <measure> markers)
// Last Modified: Tue Dec 12 20:23:42 PST 2006 (handling > and < as text)
// Filename: ...sig/examples/all/hum2xml.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/hum2xml.cpp
// Syntax: C++; museinfo
//
// Description: Converts a Humdrum file into MusicXML.
//
#include "humdrum.h"
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#ifndef OLDCPP
#include <iostream>
#else
#include <iostream.h>
#endif
// function declarations:
void checkOptions(Options& opts, int argc, char** argv);
void example(void);
void convertToMusicXML(HumdrumFile& hfile);
int makePartList(HumdrumFile& hfile);
void makePart(HumdrumFile& hfile, int start, int spine,
int count);
void generatePartInfo(HumdrumFile& hfile, int start, int spine,
int count);
void convertDataToMusicXML(HumdrumFile& hfile, int line, int trace);
void convertMeasureToXML(HumdrumFile& hfile, int line, int spine);
void convertAttributeToXML(HumdrumFile& hfile, int line, int spine);
void convertNoteToXML(HumdrumFile& hfile, int line, int spine);
void pline(int level, char* string);
void usage(const char* command);
double convertNoteEntryToXML(HumdrumFile& hfile, int line, int spine,
const char* buffer, int chord, int vlevel);
void checkMeasure(void);
void printDurationType(const char* durstring);
void printDots(const char* durstring);
void adjustKey(int keyinfo);
void checkAccidentals(int diatonic, int alter, int chord);
void updateAccidentals(void);
void printGlobalComments(HumdrumFile& hfile, int direction);
void printGlobalComment(HumdrumFile& hfile, int line);
void printBibliography(HumdrumFile& hfile, int line);
void checkbackup(void);
void processTextUnderlay(HumdrumFile& hfile, int line, int spine);
void displayUnknownTextType(HumdrumFile& hfile, int line, int spine,
int verse);
void displayLyrics(HumdrumFile& hfile, int line, int spine,
int verse);
void displayHTMLText(const char* buffer);
void processBeams(HumdrumFile& hfile, int line, int spine,
const char* buffer, int vlevel);
// User interface variables:
Options options;
int debugQ = 0; // used with the --debug option
int cautionaryQ = 1; // used with the --nocaution option
int reverseQ = 0; // reverse the ordering of the parts
int lev = 0; // indentation level in output text
int minit = 0; // at start of each part: if measure is active
double smallestdur = 1.0; // smallest durational component in the music
int divisions = 1; // number of divisions per beat
int measurestate = 0; // 0 = measure is not open, 1 = measure open
int v1lastmeasure[7] = {0}; // for explicit accidentals ABCDEFG
int v1states[7] = {0}; // for explicit accidentals ABCDEFG
int v1key[7] = {0}; // for explicit accidentals ABCDEFG
int v1chord[7] = {0}; // for explicit accidentals ABCDEFG
int v1prechordstates[7] = {0}; // for explicit accidentals ABCDEFG
int direction = 0; // for <backup> <forward> commands
int beamlevel[128] = {0}; // for beaming information
int musicstart = 0; // for suppressing bars before music starts
// int attributes = 0; // for suppressing multiple attributes entries
//////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
// process the command-line options
checkOptions(options, argc, argv);
// figure out the number of input files to process
int numinputs = options.getArgCount();
HumdrumFile hfile;
for (int i=0; i<numinputs || i==0; i++) {
hfile.clear();
// if no command-line arguments read data file from standard input
if (numinputs < 1) {
hfile.read(cin);
} else {
hfile.read(options.getArg(i+1));
}
hfile.analyzeRhythm();
divisions = hfile.getMinTimeBase();
if (divisions % 4 == 0) {
divisions = divisions/4;
} else {
// don't know what this case may be
}
convertToMusicXML(hfile);
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// checkOptions --
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("debug=b", "print debug information");
opts.define("nocaution=b", "print cautionary accidentals");
opts.define("r|reverse=b", "reverse the order of the parts");
opts.define("author=b", "author of program");
opts.define("version=b", "compilation info");
opts.define("example=b", "example usages");
opts.define("h|help=b", "short description");
opts.process(argc, argv);
// handle basic options:
if (opts.getBoolean("author")) {
cout << "Written by Craig Stuart Sapp, "
<< "craig@ccrma.stanford.edu, May 1998" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 3 July 1998" << endl;
cout << "compiled: " << __DATE__ << endl;
cout << MUSEINFO_VERSION << endl;
exit(0);
} else if (opts.getBoolean("help")) {
usage(opts.getCommand());
exit(0);
} else if (opts.getBoolean("example")) {
example();
exit(0);
}
debugQ = opts.getBoolean("debug");
cautionaryQ = !opts.getBoolean("nocaution");
reverseQ = opts.getBoolean("reverse");
}
//////////////////////////////
//
// example --
//
void example(void) {
}
//////////////////////////////
//
// convertToMusicXML --
//
// MusicXML 0.6a header:
// <?xml version="1.0" standalone="no"?>
// <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 0.6a Partwise//EN" "//C:/Program Files/Finale 2003/Component Files/partwise.dtd">
//
// MusicXML 0.3 (alpha) header:
// <?xml version=\"1.0\" standalone=\"no\"?>
// <!DOCTYPE score-partwise SYSTEM \"/musicxml/partwise.dtd\">
// <!-- DOCTYPE score-partwise PUBLIC
// \"-//Recordare//DTD MusicXML 0.3 Partwise//EN\"
// \"http://www.musicxml.org/dtds/partwise.dtd\" -->
//
void convertToMusicXML(HumdrumFile& hfile) {
pline(lev, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
pline(lev, "<!DOCTYPE score-partwise PUBLIC \"-//Recordare//DTD MusicXML 0.6a Partwise//EN\" \"//C:/Program Files/Finale 2003/Component Files/partwise.dtd\">\n");
printGlobalComments(hfile, 1);
pline(lev, "<score-partwise>\n");
int count = makePartList(hfile);
int start = 0;
while (start < hfile.getNumLines() &&
strncmp(hfile[start][0], "**", 2) != 0) {
start++;
}
int i;
int gcount = 0;
if (!reverseQ) {
for (i=hfile[start].getFieldCount()-1; i>=0; i--) {
if (strcmp(hfile[start].getExInterp(i), "**kern") != 0) {
continue;
}
gcount++;
makePart(hfile, start, i, gcount);
count--;
}
} else {
// doing things in reverse order
for (i=0; i<hfile[start].getFieldCount(); i++) {
if (strcmp(hfile[start].getExInterp(i), "**kern") != 0) {
continue;
}
gcount++;
makePart(hfile, start, i, gcount);
count--;
}
}
lev = 0;
pline(lev, "</score-partwise>\n");
printGlobalComments(hfile, -1);
if (count != 0) {
cerr << "Error in generating parts: number of parts has changed" << endl;
}
}
//////////////////////////////
//
// printGlobalComments
//
void printGlobalComments(HumdrumFile& hfile, int direction) {
int start = 0;
int stop = hfile.getNumLines();
int i;
if (direction == 1) {
start = 0;
i = 0;
while (i < hfile.getNumLines()) {
if (strncmp(hfile[i][0], "**", 2) == 0) {
stop = i;
break;
}
i++;
}
} else {
stop = hfile.getNumLines() - 1;
i = stop;
while (i >= 0) {
if (strcmp(hfile[i][0], "*-") == 0) {
start = i;
break;
}
i--;
}
}
for (i=start; i<=stop; i++) {
switch (hfile[i].getType()) {
case E_humrec_global_comment:
printGlobalComment(hfile, i);
break;
case E_humrec_bibliography:
printBibliography(hfile, i);
break;
}
}
}
//////////////////////////////
//
// printGlobalComment --
//
void printGlobalComment(HumdrumFile& hfile, int line) {
pline(lev, "<!-- GCOMMENT value=\"");
cout << &(hfile[line][0][2]) << "\" -->\n";
}
//////////////////////////////
//
// printBibliography --
//
void printBibliography(HumdrumFile& hfile, int line) {
char buffer[1024] = {0};
strcpy(buffer, hfile[line][0]);
int i = 0;
while (buffer[i] != '\0') {
if (buffer[i] == ':') {
buffer[i] = '\0';
i++;
if (buffer[i] == ' ') {
buffer[i] = '\0';
i++;
}
break;
}
i++;
}
if (i == 0) return;
pline(lev, "<!-- INFO key=\"");
cout << &(buffer[3]) << "\" value=\"" << &(buffer[i]) << "\" -->\n";
}
//////////////////////////////
//
// makePart --
//
void makePart(HumdrumFile& hfile, int start, int spine, int count) {
cout << "\n";
pline(lev, "<part id=\"P");
cout << count << "\">\n";
lev++;
minit = 0;
musicstart = 0;
checkMeasure();
lev++;
pline(lev, "<attributes>\n");
// attributes = 1;
lev++;
pline(lev, "<divisions>");
cout << divisions << "</divisions>\n";
lev--;
pline(lev, "</attributes>\n"); // att
lev--; // att
int line = 0;
int trace = 0;
for (line = start+1; line < hfile.getNumLines(); line++) {
trace = 0;
if (strncmp(hfile[line][0], "!!", 2) == 0) {
continue;
}
if (hfile[line].getType() == E_humrec_empty) {
continue;
}
while (trace < hfile[line].getFieldCount() &&
spine+1 != hfile[line].getPrimaryTrack(trace)) {
trace++;
}
if (strcmp(hfile[line].getExInterp(trace), "**kern") != 0) {
continue;
}
if (trace < hfile[line].getFieldCount()) {
convertDataToMusicXML(hfile, line, trace);
} else {
cout << "Error on line " << line+1 << ": Spine error\n";
}
}
if (measurestate == 1) {
pline(lev, "</measure>\n");
measurestate = 0;
}
lev--;
pline(lev, "</part>\n");
}
//////////////////////////////
//
// convertDataToMusicXML --
//
void convertDataToMusicXML(HumdrumFile& hfile, int line, int trace) {
if (debugQ) {
cout << "DATA = " << hfile[line][trace] << " \n";
}
switch(hfile[line].getType()) {
case E_humrec_none:
case E_humrec_empty:
case E_humrec_global_comment:
case E_humrec_bibliography:
case E_humrec_data_comment:
break;
case E_humrec_data_kern_measure:
convertMeasureToXML(hfile, line, trace);
break;
case E_humrec_interpretation:
convertAttributeToXML(hfile, line, trace);
break;
case E_humrec_data:
musicstart = 1;
convertNoteToXML(hfile, line, trace);
break;
default:
break;
}
}
//////////////////////////////
//
// updateAccidentals -- restore accidentals at a measure boundary.
//
void updateAccidentals(void) {
// copy v1states to v1lastmeasure
// and fill v1states with v1key
int i;
for (i=0; i<7; i++) {
v1lastmeasure[i] = v1states[i];
v1states[i] = v1key[i];
}
}
//////////////////////////////
//
// convertMeasureToXML --
//
void convertMeasureToXML(HumdrumFile& hfile, int line, int spine) {
int measureno = -1;
if (!musicstart) {
return;
}
updateAccidentals();
const char *ptr;
if (strcmp(hfile[line][spine], "==") == 0
|| strcmp(hfile[line+1][0], "*-") == 0) {
checkbackup();
lev++;
pline(lev, "<barline>\n");
lev++;
pline(lev, "<bar-style>light-heavy</bar-style>\n");
lev--;
pline(lev, "</barline>\n");
lev--;
pline(lev, "</measure>\n");
measurestate = 0;
} else if ((ptr = strchr(hfile[line][spine], ':')) != NULL) {
if ((ptr+1)[0] == '|' || (ptr+1)[0] == '!') {
lev++;
pline(lev, "<barline>\n");
lev++;
if (strstr(hfile[line][spine], ":|!") != NULL) {
pline(lev, "<bar-style>light-heavy</bar-style>\n");
} else if (strstr(hfile[line][spine], ":||") != NULL) {
pline(lev, "<bar-style>light-light</bar-style>\n");
} else if (strstr(hfile[line][spine], ":!") != NULL) {
pline(lev, "<bar-style>heavy</bar-style>\n");
} else if (strstr(hfile[line][spine], ":|") != NULL) {
pline(lev, "<bar-style>light</bar-style>\n");
}
pline(lev, "<repeat direction=\"backward\"/>\n");
lev--;
pline(lev, "</barline>\n");
lev--;
}
} else if (strstr(hfile[line][spine], "||") != NULL) {
checkbackup();
lev++;
pline(lev, "<barline>\n");
lev++;
pline(lev, "<bar-style>light-light</bar-style>\n");
lev--;
pline(lev, "</barline>\n");
lev--;
}
if (strcmp(hfile[line+1][0], "*-") == 0) {
return;
}
checkbackup();
if (minit != 0) {
if (measurestate != 0) {
pline(lev, "</measure>\n");
measurestate = 0;
}
}
minit++;
if (sscanf(hfile[line][spine], "=%d", &measureno)) {
pline(lev, "<measure number=\"");
cout << minit << "\">\n";
measurestate = 1;
} else if (strncmp(hfile[line][spine], "=", 1) == 0) {
if (hfile.getTotalDuration() > hfile[line].getAbsBeat()) {
// don't start a new measure if we are at the end of the music
pline(lev, "<measure number=\"");
cout << minit << "\">\n";
measurestate = 1;
}
}
if ((ptr = strchr(hfile[line][spine], ':')) != NULL) {
if ((ptr-1)[0] == '|' || (ptr-1)[0] == '!') {
lev++;
pline(lev, "<barline>\n");
lev++;
if (strstr(hfile[line][spine], ":|!") != NULL) {
pline(lev, "<bar-style>light-heavy</bar-style>\n");
} else if (strstr(hfile[line][spine], ":||") != NULL) {
pline(lev, "<bar-style>light-light</bar-style>\n");
} else if (strstr(hfile[line][spine], ":!") != NULL) {
pline(lev, "<bar-style>heavy</bar-style>\n");
} else if (strstr(hfile[line][spine], ":|") != NULL) {
pline(lev, "<bar-style>light</bar-style>\n");
}
pline(lev, "<repeat direction=\"forward\"/>\n");
lev--;
pline(lev, "</barline>\n");
lev--;
}
}
}
//////////////////////////////
//
// checkMeasure --
//
void checkMeasure(void) {
if (minit == 0) {
minit++;
pline(lev, "<measure number=\"");
cout << minit << "\">\n";
measurestate = 1;
}
}
//////////////////////////////
//
// adjustKey -- replace the old key signature with a new one
//
void adjustKey(int keyinfo) {
int i;
for (i=0; i<7; i++) {
v1key[i] = 0;
}
if (keyinfo < 0) {
v1key['B' - 'A'] = -1;
if (keyinfo < -1) v1key['E' - 'A'] = -1;
if (keyinfo < -2) v1key['A' - 'A'] = -1;
if (keyinfo < -3) v1key['D' - 'A'] = -1;
if (keyinfo < -4) v1key['G' - 'A'] = -1;
if (keyinfo < -5) v1key['C' - 'A'] = -1;
if (keyinfo < -6) v1key['F' - 'A'] = -1;
}
if (keyinfo > 0) {
v1key['F' - 'A'] = 1;
if (keyinfo > 1) v1key['C' - 'A'] = 1;
if (keyinfo > 2) v1key['G' - 'A'] = 1;
if (keyinfo > 3) v1key['D' - 'A'] = 1;
if (keyinfo > 4) v1key['A' - 'A'] = 1;
if (keyinfo > 5) v1key['E' - 'A'] = 1;
if (keyinfo > 6) v1key['B' - 'A'] = 1;
}
// erase previous measure accidentals:
for (i=0; i<7; i++) {
v1lastmeasure[i] = v1key[i];
v1states[i] = v1key[i];
}
}
//////////////////////////////
//
// convertAttributeToXML --
//
void convertAttributeToXML(HumdrumFile& hfile, int line, int spine) {
int length = strlen(hfile[line][spine]);
if (strncmp(hfile[line][spine], "*M", 2) == 0 &&
strchr(hfile[line][spine], '/') != NULL) {
// meter marking
int top = 0;
int bottom = 0;
int flag = sscanf(hfile[line][spine], "*M%d/%d", &top, &bottom);
if (flag == 2) {
checkMeasure();
lev++;
// if (!attributes) {
pline(lev, "<attributes>\n");
lev++;
// attributes = 1;
// }
pline(lev, "<time>\n");
lev++;
pline(lev, "<beats>");
cout << top << "</beats>\n";
pline(lev, "<beat-type>");
cout << bottom << "</beat-type>\n";
lev--;
pline(lev, "</time>\n");
lev--;
pline(lev, "</attributes>\n"); // att
lev--; // att
}
} else if (strncmp(hfile[line][spine], "*k[", 3) == 0 &&
hfile[line][spine][length-1] == ']') {
// key signature
int pitch = 0;
if (length > 4) {
pitch = Convert::kernToBase40(&hfile[line][spine][length-3]);
pitch = pitch % 40;
} else {
pitch = E_muse_c;
}
int keyinfo = 0;
switch (pitch) {
case E_muse_c: keyinfo = 0; break;
case E_muse_fs: keyinfo = 1; break;
case E_muse_cs: keyinfo = 2; break;
case E_muse_gs: keyinfo = 3; break;
case E_muse_ds: keyinfo = 4; break;
case E_muse_as: keyinfo = 5; break;
case E_muse_es: keyinfo = 6; break;
case E_muse_bs: keyinfo = 7; break;
case E_muse_bf: keyinfo = -1; break;
case E_muse_ef: keyinfo = -2; break;
case E_muse_af: keyinfo = -3; break;
case E_muse_df: keyinfo = -4; break;
case E_muse_cf: keyinfo = -5; break;
case E_muse_gf: keyinfo = -6; break;
case E_muse_ff: keyinfo = -7; break;
}
adjustKey(keyinfo);
checkMeasure();
lev++;
// if (!attributes) {
pline(lev, "<attributes>\n");
lev++;
// attributes = 1;
// }
pline(lev, "<key>\n");
lev++;
pline(lev, "<fifths>");
cout << keyinfo << "</fifths>\n";
lev--;
pline(lev, "</key>\n");
lev--;
pline(lev, "</attributes>\n"); // att
lev--; // att
} else if (strcmp(hfile[line][spine], "*clefF4") == 0) {
checkMeasure();
lev++;
// if (!attributes) {
pline(lev, "<attributes>\n");
lev++;
// attributes = 1;
// }
pline(lev, "<clef>\n");
lev++;
pline(lev, "<sign>F</sign>\n");
pline(lev, "<line>4</line>\n");
lev--;
pline(lev, "</clef>\n");
lev--;
pline(lev, "</attributes>\n"); // att
lev--; // att
} else if (strcmp(hfile[line][spine], "*clefG2") == 0) {
checkMeasure();
lev++;
// if (!attributes) {
pline(lev, "<attributes>\n");
lev++;
// attributes = 1;
// }
pline(lev, "<clef>\n");
lev++;
pline(lev, "<sign>G</sign>\n");
pline(lev, "<line>2</line>\n");
lev--;
pline(lev, "</clef>\n");
lev--;
pline(lev, "</attributes>\n"); // att
lev--; // att
}
}
//////////////////////////////
//
// convertNoteToXML --
//
void convertNoteToXML(HumdrumFile& hfile, int line, int spine) {
static char buffer[128] = {0};
int i;
if (strcmp(hfile[line].getExInterp(spine), "**kern") != 0) {
return;
}
musicstart = 1;
// copy current accidentals into chord buffer
for (i=0; i<7; i++) {
v1chord[i] = v1lastmeasure[i];
v1prechordstates[i] = v1states[i];
}
lev++;
double cdur = 0;
int xdur = 0;
int tokencount = hfile[line].getTokenCount(spine);
for (i=0; i<tokencount; i++) {
hfile[line].getToken(buffer, spine, i);
cdur = convertNoteEntryToXML(hfile, line, spine, buffer, i, 0);
}
if ((spine+1 < hfile[line].getFieldCount()) &&
(hfile[line].getPrimaryTrack(spine) ==
hfile[line].getPrimaryTrack(spine+1))) {
xdur = (int)(cdur * divisions);
direction = xdur;
tokencount = hfile[line].getTokenCount(spine+1);
for (i=0; i<tokencount; i++) {
hfile[line].getToken(buffer, spine+1, i);
cdur = convertNoteEntryToXML(hfile, line, spine+1, buffer, i, 1);
}
xdur = (int)(cdur * divisions) -
(int)(divisions * hfile[line].getDuration());
direction += xdur;
}
lev--;
}
//////////////////////////////
//
// checkbackup --
//
void checkbackup(void) {
if (direction > 0) {
// backwards
pline(lev, "<backup>\n");
lev++;
pline(lev, "<duration>");
cout << direction << "</duration>\n";
lev--;
pline(lev, "</backup>\n");
} else if (direction < 0) {
// forwards
pline(lev, "<forward>\n");
lev++;
pline(lev, "<duration>");
cout << -direction << "</duration>\n";
lev--;
pline(lev, "</forward>\n");
}
direction = 0;
}
//////////////////////////////
//
// convertNoteEntryToXML --
//
double convertNoteEntryToXML(HumdrumFile& hfile, int line, int spine,
const char* buffer, int chord, int vlevel) {
double output = 0;
if (strcmp(buffer, ".") == 0) {
// nothing to do
return 0.0;
}
int explicitz = 0;
int altered = 0;
double duration = Convert::kernToDuration(buffer);
int pitch = Convert::kernToBase40(buffer);
char buff2[64] = {0};
if (pitch > 0) {
Convert::base40ToKern(buff2, pitch);
} else {
strcpy(buff2, "r");
}
if (strstr(buff2, "--") != NULL) {
} else if (strstr(buff2, "--") != NULL) {
altered = -2;
} else if (strstr(buff2, "##") != NULL) {
altered = 2;
} else if (strstr(buff2, "-") != NULL) {
altered = -1;
} else if (strstr(buff2, "#") != NULL) {
altered = 1;
} else if (strstr(buffer, "n") != NULL) {
altered = 0;
explicitz = 1;
} else {
altered = 0;
explicitz = 0;
}
char diapitch = toupper(buff2[0]);
int octave = 0;
if (pitch > 0) {
octave = pitch / 40;
}
if (debugQ) {
cout << "+++ processing note token: " << buffer << endl;
}
// if (attributes) {
// lev--;
// pline(lev, "</attributes>\n");
// lev--; // att
// attributes = 0;
// }
checkbackup();
pline(lev, "<note>\n");
lev++;
int grace = 0;
if (strchr(buffer, 'q') != NULL || strchr(buffer, 'Q') != NULL) {
grace = 1;
}
if (grace) {
pline(lev, "<grace/>\n");
}
if (chord) {
pline(lev, "<chord/>\n");
}
if (toupper(diapitch) != 'R') {
pline(lev, "<pitch>\n");
lev++;
pline(lev, "<step>");
cout << diapitch << "</step>\n";
if (altered != 0) {
pline(lev, "<alter>");
cout << altered << "</alter>\n";
}
pline(lev, "<octave>");
cout << octave << "</octave>\n";
lev--;
pline(lev, "</pitch>\n");
} else {
pline(lev, "<rest/>\n");
}
if (!grace) {
pline(lev, "<duration>");
cout << duration*divisions << "</duration>\n";
output = duration;
} else {
output = 0.0;
}
int tietype = 0;
if (strchr(buffer, '[') != NULL) {
tietype = 1;
} else if (strchr(buffer, '_') != NULL) {
tietype = 2;
} else if (strchr(buffer, ']') != NULL) {
tietype = 3;
}
switch (tietype) {
case 1:
pline(lev, "<tie type=\"start\"/>\n");
break;
case 2:
pline(lev, "<tie type=\"stop\"/>\n");
pline(lev, "<tie type=\"start\"/>\n");
break;
case 3:
pline(lev, "<tie type=\"stop\"/>\n");
break;
}
int vcase = 0;
if (strchr(hfile[line].getSpineInfo(spine), '(') == NULL) {
vcase = 0;
pline(lev, "<voice>1</voice>\n");
pline(lev, "<type>");
} else if (strchr(hfile[line].getSpineInfo(spine), 'a') != NULL) {
vcase = 1;
pline(lev, "<voice>1</voice>\n");
pline(lev, "<type>");
} else if (strchr(hfile[line].getSpineInfo(spine), 'b') != NULL) {
vcase = 2;
pline(lev, "<voice>2</voice>\n");
pline(lev, "<type>");
} else {
vcase = 3;
pline(lev, "<voice>1</voice>\n");
pline(lev, "<type>");
}
char durstring[32] = {0};
Convert::durationToKernRhythm(durstring, duration);
printDurationType(durstring);
cout << "</type>\n";
printDots(durstring);
/// WRITTEN ACCIDENTALS ////////////////////////////////////////////
if (toupper(buff2[0]) != 'R') {
if (strchr(buffer, 'n') != NULL) {
pline(lev, "<accidental>natural</accidental>\n");
v1states[toupper(buff2[0]) - 'A'] = 0;
v1lastmeasure[toupper(buff2[0]) - 'A'] = 0;
} else {
checkAccidentals(toupper(buff2[0]), altered, chord);
}
}
if (strchr(buffer, '/') != NULL) {
pline(lev, "<stem>up</stem>\n");
} else if (strchr(buffer, '\\') != NULL) {
pline(lev, "<stem>down</stem>\n");
} else if (vcase == 1) {
pline(lev, "<stem>down</stem>\n");
} else if (vcase == 2) {
if (strchr(buffer, '/') == NULL && strchr(buffer, '\\') == NULL) {
pline(lev, "<stem>up</stem>\n");
}
}
if (duration >= 1.0) {
// kill rogue beam marks.
beamlevel[vlevel] = 0;
}
if (!chord) {
processBeams(hfile, line, spine, buffer, vlevel);
}
/// WRITTEN TIES ///////////////////////////////////////////////////
if (tietype) {
pline(lev, "<notations>\n");
lev++;
switch (tietype) {
case 1:
pline(lev, "<tied type=\"start\"/>\n");
break;
case 2:
pline(lev, "<tied type=\"stop\"/>\n");
pline(lev, "<tied type=\"start\"/>\n");
break;
case 3:
pline(lev, "<tied type=\"stop\"/>\n");
break;
}
lev--;
pline(lev, "</notations>\n");
}
/// FERMATAS ///////////////////////////////////////////////////////
if (strchr(buffer, ';') != NULL) {
pline(lev, "<notations>\n");
lev++;
pline(lev, "<fermata type=\"upright\"/>\n");
lev--;
pline(lev, "</notations>\n");
}
/// ARTICULATIONS ////////////////////////////////////////////
if (strchr(buffer, '\'') != NULL) {
pline(lev, "<notations>\n");
lev++;
pline(lev, "<articulations>\n");
lev++;
pline(lev, "<staccato placement=\"above\"/>\n");
lev--;
pline(lev, "</articulations>\n");
lev--;
pline(lev, "</notations>\n");
}
if (strchr(buffer, '~') != NULL) {
pline(lev, "<notations>\n");
lev++;
pline(lev, "<articulations>\n");
lev++;
pline(lev, "<tenuto placement=\"above\"/>\n");
lev--;
pline(lev, "</articulations>\n");
lev--;
pline(lev, "</notations>\n");
}
if (strchr(buffer, '^') != NULL) {
pline(lev, "<notations>\n");
lev++;
pline(lev, "<articulations>\n");
lev++;
pline(lev, "<accent placement=\"above\"/>\n");
lev--;
pline(lev, "</articulations>\n");
lev--;
pline(lev, "</notations>\n");
}
/// LYRICS /////////////////////////////////////////////////////////
if (!chord) {
processTextUnderlay(hfile, line, spine);
}
lev--;
pline(lev, "</note>\n");
return output;
}
//////////////////////////////
//
// processBeams --
//
void processBeams(HumdrumFile& hfile, int line, int spine, const char* buffer,
int vlevel) {
int backhook = 0;
int forehook = 0;
int openbeam = 0;
int closebeam = 0;
int i=0;
int sum = 0;
int length = strlen(buffer);
for (i=0; i<length; i++) {
switch (buffer[i]) {
case 'k': backhook++; sum++; break;
case 'K': forehook++; sum++; break;
case 'L': openbeam++; sum++; break;
case 'J': closebeam++; sum++; break;
}
}
if (closebeam && openbeam) {
openbeam = 0;
}
if (forehook && backhook) {
if (openbeam) {
backhook = 0;
} else {
forehook = 0;
}
}
if (sum == 0) {
// there is nothing new to do
for (i=0; i<beamlevel[vlevel]; i++) {
pline(lev, "<beam number=\"");
cout << i+1 << "\">continue</beam>\n";
}
return;
}
// int totalcount = beamlevel[vlevel] + openbeam - closebeam +
// backhook + forehook;
int rcount = 0;
if (openbeam != 0) {
// add any new beams which are starting
// continue any old beams
for (i=0; i<beamlevel[vlevel]; i++) {
pline(lev, "<beam number=\"");
cout << i+1 << "\">continue</beam>\n";
rcount++;
}
// add new beams
for (i=0; i<openbeam; i++) {
pline(lev, "<beam number=\"");
cout << beamlevel[vlevel] + i + 1 << "\">begin</beam>\n";
rcount++;
}
beamlevel[vlevel] += openbeam;
// add any opening beam hook
for (i=0; i<forehook; i++) {
pline(lev, "<beam number=\"");
cout << beamlevel[vlevel] + i + 1 << "\">forward hook</beam>\n";
rcount++;
}
}
if (closebeam != 0) {
// close any old beams which are ending
// continue any old beams
for (i=0; i<beamlevel[vlevel] - closebeam - backhook; i++) {
pline(lev, "<beam number=\"");
cout << i+1 << "\">continue</beam>\n";
rcount++;
}
// close old beams
for (i=0; i<closebeam; i++) {
pline(lev, "<beam number=\"");
cout << beamlevel[vlevel] - closebeam + i + 1 << "\">end</beam>\n";
rcount++;
}
beamlevel[vlevel] -= closebeam;
// add any ending beam hook
for (i=0; i<backhook; i++) {
pline(lev, "<beam number=\"");
cout << beamlevel[vlevel] + closebeam + i + 1
<< "\">backward hook</beam>\n";
rcount++;
}
}
if (beamlevel[vlevel] < 0) {
beamlevel[vlevel] = 0;
}
}
//////////////////////////////
//
// processTextUnderlay --
//
void processTextUnderlay(HumdrumFile& hfile, int line, int spine) {
int fields = hfile[line].getFieldCount();
if (spine >= fields-1) {
return;
}
int tspine = spine+1;
int verse = 1;
while (tspine < fields &&
strcmp(hfile[line].getExInterp(tspine), "**kern") != 0) {
if (strcmp(hfile[line][tspine], ".") == 0) {
// ignore null tokens
} else if (strcmp(hfile[line].getExInterp(tspine), "**text") == 0) {
displayLyrics(hfile, line, tspine, verse);
} else {
displayUnknownTextType(hfile, line, tspine, verse);
}
tspine++;
verse++;
}
}
//////////////////////////////
//
// displayLyrics --
//
void displayLyrics(HumdrumFile& hfile, int line, int spine, int verse) {
displayUnknownTextType(hfile, line, spine, verse);
}
//////////////////////////////
//
// displayUnknownTextType --
//
void displayUnknownTextType(HumdrumFile& hfile, int line, int spine,
int verse) {
pline(lev, "<lyric number=\"");
cout << verse << "\" name=\"verse\">\n";
lev++;
pline(lev, "<syllabic>single</syllabic>\n");
pline(lev, "<text>");
displayHTMLText(hfile[line][spine]);
cout << "</text>\n";
lev--;
pline(lev, "</lyric>\n");
}
//////////////////////////////
//
// displayHTMLText --
//
void displayHTMLText(const char* buffer) {
int length = strlen(buffer);
for (int i=0; i<length; i++) {
switch (buffer[i]) {
case 'ä': cout << "ä"; break;
case 'ë': cout << "ë"; break;
case 'ï': cout << "ï"; break;
case 'ö': cout << "ö"; break;
case 'ü': cout << "ü"; break;
case '<': cout << "<"; break;
case '>': cout << ">"; break;
default: cout << buffer[i];
}
}
}
//////////////////////////////
//
// checkAccidentals --
//
void checkAccidentals(int diatonic, int alter, int chord) {
// if a note is different than the current state
// in the measure, then add an accidental to make
// sure that the note is played right
if (toupper(diatonic) == 'R') {
return;
}
if (!chord) {
diatonic = toupper(diatonic);
if (v1states[diatonic - 'A'] != alter) {
pline(lev, "<accidental>");
switch (alter) {
case 2: cout << "double-sharp"; break;
case 1: cout << "sharp"; break;
case 0: cout << "natural"; break;
case -1: cout << "flat"; break;
case -2: cout << "double-flat"; break;
}
cout << "</accidental>\n";
v1states[diatonic - 'A'] = alter;
v1lastmeasure[diatonic - 'A'] = alter;
} else if (cautionaryQ && v1lastmeasure[diatonic - 'A'] != alter) {
// if a cautionary accidental accross measure, then adjust here
pline(lev, "<accidental>");
switch (alter) {
case 2: cout << "double-sharp"; break;
case 1: cout << "sharp"; break;
case 0: cout << "natural"; break;
case -1: cout << "flat"; break;
case -2: cout << "double-flat"; break;
}
cout << "</accidental>\n";
v1states[diatonic - 'A'] = alter;
v1lastmeasure[diatonic - 'A'] = alter;
}
} else {
// note in a chord
diatonic = toupper(diatonic);
if (v1prechordstates[diatonic - 'A'] != alter) {
pline(lev, "<accidental>");
switch (alter) {
case 2: cout << "double-sharp"; break;
case 1: cout << "sharp"; break;
case 0: cout << "natural"; break;
case -1: cout << "flat"; break;
case -2: cout << "double-flat"; break;
}
cout << "</accidental>\n";
v1states[diatonic - 'A'] = alter;
v1lastmeasure[diatonic - 'A'] = alter;
} else if (cautionaryQ && v1chord[diatonic - 'A'] != alter) {
// if a cautionary accidental accross measure, then adjust here
pline(lev, "<accidental>");
switch (alter) {
case 2: cout << "double-sharp"; break;
case 1: cout << "sharp"; break;
case 0: cout << "natural"; break;
case -1: cout << "flat"; break;
case -2: cout << "double-flat"; break;
}
cout << "</accidental>\n";
v1states[diatonic - 'A'] = alter;
v1lastmeasure[diatonic - 'A'] = alter;
}
}
}
//////////////////////////////
//
// printDots --
//
void printDots(const char* durstring) {
int length = strlen(durstring);
int i;
for (i=0; i<length; i++) {
if (durstring[i] == '.') {
pline(lev, "<dot/>\n");
}
}
}
//////////////////////////////
//
// printDurationType --
//
void printDurationType(const char* durstring) {
char buffer[32] = {0};
int length = strlen(durstring);
strcpy(buffer, durstring);
for (int i=0; i<length; i++) {
if (buffer[i] == '.') {
buffer[i] = '\0';
}
}
int number = atoi(buffer);
if (number <= 1) {
cout << "whole";
} else if (number <= 2) {
cout << "half";
} else if (number <= 4) {
cout << "quarter";
} else if (number <= 8) {
cout << "eighth";
} else if (number <= 16) {
cout << "16th";
} else if (number <= 32) {
cout << "32nd";
} else if (number <= 64) {
cout << "64th";
} else if (number <= 128) {
cout << "128th";
} else if (number <= 256) {
cout << "256th";
} else if (number <= 512) {
cout << "512th";
} else if (number <= 1024) {
cout << "1024th";
} else if (number <= 2048) {
cout << "2048th";
} else if (number <= 4096) {
cout << "4096th";
} else {
cout << "UNKNOWN";
}
}
//////////////////////////////
//
// makePartList -- generate a list of the parts in the score
//
int makePartList(HumdrumFile& hfile) {
lev++;
pline(lev, "<part-list>\n");
lev++;
// find the start of the spine data and output a part for each
// spine
int i = 0;
int count = 0; // the number of **kern spines
int j = 0;
while (i<hfile.getNumLines() && hfile[i].getType() !=
E_humrec_interpretation) {
i++;
}
if (hfile[i].getType() == E_humrec_interpretation) {
if (strncmp("**", hfile[i][0], 2) != 0) {
cout << "Error on line " << i + 1 << " of file: No start of data"
<< endl;
}
} else {
cout << "Error: no data in file" << endl;
exit(1);
}
if (reverseQ) {
for (j=0; j<hfile[i].getFieldCount(); j++) {
if (strcmp(hfile[i].getExInterp(j), "**kern") != 0) {
continue;
}
count++;
generatePartInfo(hfile, i, j, count);
}
} else {
// doing parts in reverse order
for (j=hfile[i].getFieldCount()-1; j>=0; j--) {
if (strcmp(hfile[i].getExInterp(j), "**kern") != 0) {
continue;
}
count++;
generatePartInfo(hfile, i, j, count);
}
}
lev--;
pline(lev, "</part-list>\n");
return count;
}
//////////////////////////////
//
// generatePart --
//
void generatePartInfo(HumdrumFile& hfile, int start, int spine, int count) {
int i = start + 1;
int j = 0;
pline(lev, "<score-part id=\"P");
cout << count << "\">\n";
lev++;
int done = 0;
while (!done && i < hfile.getNumLines()) {
if (hfile[i].getType() == E_humrec_interpretation) {
for (j=0; j<hfile[i].getFieldCount(); j++) {
if (hfile[i].getPrimaryTrack(j) == spine + 1) {
if (strncmp(hfile[i][j], "*I", 2) == 0 &&
strncmp(hfile[i][j], "*IC", 3) != 0) {
done = 1;
break;
}
} else {
}
}
}
if (done) break;
i++;
}
if (done == 1) {
pline(lev, "<part-name>");
cout << &(hfile[i][j][2]) << "</part-name>\n";
} else {
pline(lev, "<part-name>XPart ");
cout << spine << "</part-name>\n";
}
lev--;
pline(lev, "</score-part>\n");
}
//////////////////////////////
//
// pline -- print a line of data
//
void pline(int level, char* string) {
for (int i=0; i<level; i++) {
cout << '\t';
}
cout << string;
}
//////////////////////////////
//
// usage --
//
void usage(const char* command) {
}
// md5sum: d016d84b6deab8d829822983f383c26a hum2xml.cpp [20050403]