//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Oct 24 10:08:24 PDT 2001
// Last Modified: Fri Mar 29 09:37:12 PST 2002 (fixed bib recs at end of data)
// Last Modified: Wed Jun 24 15:37:46 PDT 2009 (updated for GCC 4.4)
// Filename: ...sig/examples/all/hum2gmn.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/hum2gmn.cpp
// Syntax: C++; museinfo
//
// Description: Converts a Humdrum file into Guido Music Notation.
//
// Reference: http://www.salieri.org/GUIDO
// Reference: http://guidolib.sourceforge.net
//
// Status: Initial stages of development
//
// Things todo: beams
// articulations (except staccatos)
// ties
// lyrics
// multiple voices on a staff
// stem direction markers
// double barline encodings?
// tempo markings?
// etc.
//
// Things done: systems, notes, rhythms, slurs, clefs, time sigs, key sigs,
// grace notes, staccatos.
//
//
#include "humdrum.h"
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#ifndef OLDCPP
#include <iostream>
#else
#include <iostream.h>
#endif
#ifndef VISUAL
#include <time.h>
#endif
// function declarations:
void checkOptions(Options& opts, int argc, char** argv);
void example(void);
void convertToGMN(HumdrumFile& hfile);
void convertPartToGMN(HumdrumFile& hfile, int part, int startline);
void convertMeasureToGMN(HumdrumFile& hfile, int part, int line);
int convertInterpretationToGMN(HumdrumFile& hfile, int part, int line);
void convertNoteDataToGMN(HumdrumFile& hfile, int part, int line);
void convertNoteToGMN(const char* note, int graceQ);
void convertGlobalComment(HumdrumRecord& globalcomment);
void convertBibliography(HumdrumRecord& bibrec);
void processHeader(HumdrumFile& hfile);
void processFooter(HumdrumFile& hfile);
void print(const char* data);
void usage(const char* command);
int getPartSpine(HumdrumFile& hfile, int part, int line);
void resetGlobals(void);
void printTitleComposer(HumdrumFile& hfile);
// 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 quietQ = 0; // don't add extra information
// Global state information
int Goctave = -99; // for displaying octave after a note
double Gduration = -99.0; // for sticky rhythms
int Gnoteinit = 0; // for marking when the first note is written
char lastchar = '\0'; // last printed character in print stream
int Gline =0; // for error warnings
int Gpartinit = 0; // for identifying the first part in the file.
//////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
checkOptions(options, argc, argv); // process the command-line options
HumdrumFile hfile(options.getArg(1));
hfile.analyzeRhythm();
convertToGMN(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, Oct 2001" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 24 Oct 2001" << 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) {
}
//////////////////////////////
//
// convertToGMN --
//
void convertToGMN(HumdrumFile& hfile) {
// find the start of the data and count how many parts there are
int i, j;
int parts = 0;
Array<int> partspines;
partspines.setSize(100);
partspines.setSize(0);
partspines.allowGrowth();
int startline = 0;
for (i=0; i<hfile.getNumLines(); i++) {
if (strncmp(hfile[i][0], "**", 2) == 0) {
startline = i;
for (j=0; j<hfile[i].getFieldCount(); j++) {
if (strcmp(hfile[i].getExInterp(j), "**kern") == 0) {
parts++;
partspines.append(j);
}
}
break;
}
}
processHeader(hfile);
print("{ "); // print a system start
for (i=0; i<partspines.getSize(); i++) {
resetGlobals();
if (!reverseQ) {
convertPartToGMN(hfile, partspines[partspines.getSize()-1-i], startline);
} else {
convertPartToGMN(hfile, partspines[i], startline);
}
if (i < partspines.getSize() - 1) {
print(", ");
}
}
print("} \n"); // print a system end
processFooter(hfile);
if (quietQ == 0) {
print("\n\n");
print("% Converted with hum2gmn v1.0.1 on ");
#ifndef VISUAL
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
print(asctime(timeinfo));
#else
print("<time not available>");
#endif
print("\n");
}
}
//////////////////////////////
//
// convertPartToGMN --
//
void convertPartToGMN(HumdrumFile& hfile, int part, int startline) {
static int staffno = 1;
static char buffer[1024] = {0};
print("[ "); // beginning of part marker
sprintf(buffer, "\\staff<%d> ", staffno++);
print(buffer);
if (Gpartinit == 0) {
printTitleComposer(hfile);
print("\n\t\\systemFormat<dx=1.0cm> ");
print("\n\t\\barFormat<style=\"system\"> ");
print("\n\t\\set<autoEndBar=\"off\"> ");
}
int i;
int done = 0;
for (i=startline+1; i<hfile.getNumLines(); i++) {
Gline = i+1;
switch (hfile[i].getType()) {
case E_humrec_none:
case E_humrec_empty:
break;
case E_humrec_global_comment:
convertGlobalComment(hfile[i]);
break;
case E_humrec_bibliography:
if (Gpartinit == 0) {
convertBibliography(hfile[i]);
}
break;
case E_humrec_data_comment:
break;
case E_humrec_data_kern_measure:
convertMeasureToGMN(hfile, part, i);
break;
case E_humrec_interpretation:
done = convertInterpretationToGMN(hfile, part, i);
break;
case E_humrec_data:
if (Gnoteinit == 0) {
print("\n\t\t");
Gnoteinit = 1;
}
convertNoteDataToGMN(hfile, part, i);
break;
default:
break;
}
if (done) break;
}
print("\n] "); // end of part marker
Gpartinit = 1; // set to 1 after first voice has been processed
}
//////////////////////////////
//
// printTitleComposer -- print the title and composer if available
//
void printTitleComposer(HumdrumFile& hfile) {
int i;
const char *cptr;
char buffer[128] = {0};
int titleQ = 0;
for (i=0; i<hfile.getNumLines(); i++) {
if (hfile[i].getType() == E_humrec_bibliography) {
if (!titleQ && strncmp(hfile[i][0], "!!!OTL", 6) == 0) {
titleQ = 1;
cptr = strchr(hfile[i][0], ':');
if (cptr == NULL) {
continue;
}
cptr++;
while (cptr[0] == ' ') {
cptr++;
}
if (cptr[0] != '\0') {
print("\n\t\\title<\"");
} else {
continue;
}
while (cptr[0] != '\0') {
if (cptr[0] == '\"') {
print("\\\'");
} else {
buffer[0] = cptr[0];
buffer[1] = '\0';
print(buffer);
}
cptr++;
}
print("\">");
}
if (strncmp(hfile[i][0], "!!!COM", 6) == 0) {
cptr = strchr(hfile[i][0], ',');
if (cptr == NULL) {
cptr = strchr(hfile[i][0], ':');
}
if (cptr == NULL) {
continue;
}
cptr++;
while (cptr[0] == ' ') {
cptr++;
}
if (cptr[0] != '\0') {
print("\n\t\\composer<\"");
} else {
continue;
}
while (cptr[0] != '\0') {
if (cptr[0] == '\"') {
print("\\\'");
} else {
buffer[0] = cptr[0];
buffer[1] = '\0';
print(buffer);
}
cptr++;
}
cptr = strchr(hfile[i][0], ':');
if (cptr != NULL) {
cptr++;
while (cptr[0] == ' ') {
cptr++;
}
if (cptr[0] == '\0') {
print("\">");
continue;
}
print(" ");
while (cptr[0] != ',' && cptr[0] != '\0') {
if (cptr[0] == '\"') {
print("\\\'");
} else {
buffer[0] = cptr[0];
buffer[1] = '\0';
print(buffer);
}
cptr++;
}
}
print("\">");
}
}
}
}
//////////////////////////////
//
// getPartSpine -- get the spine number for the first
// occurance of the part in the given line.
//
int getPartSpine(HumdrumFile& hfile, int part, int line) {
int i;
int output = -1;
for (i=0; i<hfile[line].getFieldCount(); i++) {
if (part+1 == hfile[line].getPrimaryTrack(i)) {
output = i;
break;
}
}
return output;
}
//////////////////////////////
//
// convertMeasureToGMN -- convert **kern measure to GMN values.
//
void convertMeasureToGMN(HumdrumFile& hfile, int part, int line) {
char buffer[1024] = {0};
int spine = getPartSpine(hfile, part, line);
if (spine < 0) {
cerr << "Warning: invalid humdrum syntax at line " << line+1 << endl;
}
int length = strlen(hfile[line][spine]);
int repeatQ = 0;
int startrep = 0;
int endrep = 0;
if (strchr(hfile[line][spine], '-') != NULL) {
// don't display hidden measures
return;
}
if (strchr(hfile[line][spine], ':') != NULL) {
repeatQ = 1;
}
// process repeat signs
if (repeatQ) {
int i;
for (i=1; i<length; i++) {
if (hfile[line][spine][i] == ':') {
if (hfile[line][spine][i-1] == '|' || hfile[line][spine][i-1]=='!') {
startrep = 1;
} else {
endrep = 1;
}
}
}
if (endrep) {
print("\\repeatEnd ");
}
}
print("\n\t");
int measurenum = 0;
int measureQ = 0;
int count = sscanf(hfile[line][spine], "=%d", &measurenum);
if (count == 1) {
measureQ = 1;
}
int doubleQ = 0;
if (strncmp(hfile[line][spine], "==", 2) == 0) {
doubleQ = 1;
}
if (!repeatQ) {
if (doubleQ) {
print("\\endBar");
} else {
print("\\bar");
}
if (measureQ) {
sprintf(buffer, "<%d> ", measurenum);
print(buffer);
} else {
print(" ");
}
}
if (startrep) {
print("\\repeatBegin ");
}
}
//////////////////////////////
//
// convertInterpretationToGMN -- convert **kern interpretation to GMN values.
//
int convertInterpretationToGMN(HumdrumFile& hfile, int part, int line) {
static char buffer[1024] = {0};
int spine = getPartSpine(hfile, part, line);
if (spine < 0) {
cerr << "Warning: invalid humdrum syntax at line " << line+1 << endl;
return 0;
}
int length = strlen(hfile[line][spine]);
if (strcmp(hfile[line][spine], "*-") == 0) {
return 1;
}
// proces a clef
if (strncmp(hfile[line][spine], "*clef", 5) == 0) {
if (Gnoteinit == 0) {
print("\n\t");
}
char clef = 'x';
int ctype = -99;
if (length >= 5) {
clef = hfile[line][spine][5];
}
if (length >= 6 && isdigit(hfile[line][spine][6])) {
ctype = hfile[line][spine][6] - '0';
}
clef = tolower(clef);
if (ctype != 99) {
sprintf(buffer, "\\clef<\"%c%d\">", clef, ctype);
} else {
sprintf(buffer, "\\clef<\"%c\">", clef);
}
print(buffer);
print(" ");
return 0;
}
// proces a key signature
if ((strncmp(hfile[line][spine], "*k[", 3) == 0)
&& (hfile[line][spine][length-1] == ']')) {
if (Gnoteinit == 0) {
print("\n\t");
}
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;
}
sprintf(buffer, "\\key<%d>", keyinfo);
print(buffer);
print(" ");
return 0;
}
// process time signatures
if (strncmp(hfile[line][spine], "*M", 2) == 0 &&
strchr(hfile[line][spine], '/') != NULL) {
int top = 0;
int bottom = 0;
int flag = sscanf(hfile[line][spine], "*M%d/%d", &top, &bottom);
if (flag == 2) {
if (Gnoteinit == 0) {
print("\n\t");
}
sprintf(buffer, "\\meter<\"%d/%d\">", top, bottom);
print(buffer);
print(" ");
}
return 0;
}
return 0;
}
//////////////////////////////
//
// convertNoteDataToGMN -- Convert note data to GMN values.
//
void convertNoteDataToGMN(HumdrumFile& hfile, int part, int line) {
int i;
char kbuffer[1024] = {0};
int spine = getPartSpine(hfile, part, line);
int chordnotes = hfile[line].getTokenCount(spine);
// check to see if just a null token
if (strcmp(hfile[line][spine], ".") == 0) {
return;
}
// check for the start of a slur
if (strchr(hfile[line][spine], '(') != NULL) {
print("\\slur( ");
}
// check for the start of a tie
if (strchr(hfile[line][spine], '[') != NULL) {
print("\\tieBegin ");
}
// check to see if this is a grace note/chord
int graceQ = 0;
if (strchr(hfile[line][spine], 'q') != NULL) {
print("\\grace( ");
graceQ = 1;
}
// check for accidentals
int staccatoQ = 0;
if (strchr(hfile[line][spine], '\'') != NULL) {
print("\\stacc( ");
staccatoQ = 1;
}
if (chordnotes > 1) {
print("{");
}
for (i=0; i<chordnotes; i++) {
hfile[line].getToken(kbuffer, spine, i);
convertNoteToGMN(kbuffer, graceQ);
if (chordnotes > 1) {
if (i < chordnotes - 1) {
print(",");
}
} else {
print(" ");
}
}
if (chordnotes > 1) {
print("} ");
}
if (staccatoQ) {
print(") ");
}
if (graceQ) {
print(") ");
}
// check for the end of a tie
if (strchr(hfile[line][spine], ']') != NULL) {
print("\\tieEnd ");
}
// check for the end of a slur
if (strchr(hfile[line][spine], ')') != NULL) {
print(") ");
}
}
//////////////////////////////
//
// convertNoteToGMN -- convert a note to GMN format.
//
void convertNoteToGMN(const char* note, int graceQ) {
static char buffer[1024] = {0};
int octave = 0;
int base40 = 0;
int restQ = 0;
char name = 'x';
int length = strlen(note);
// get the accidentals
int accidental = 0;
int i;
for (i=0; i<length; i++) {
if (note[i] == '#') {
accidental++;
} else if (note[i] == '-') {
accidental--;
}
}
// process pitch
if (strchr(note, 'r') != NULL) {
restQ = 1;
name = '_';
} else { // process a real note
base40 = Convert::kernToBase40(note);
octave = (base40 / 40) - 3; // Middle C = C1 in Guido
Convert::base40ToKern(buffer, base40);
name = tolower(buffer[0]);
}
if (restQ) {
print("_");
} else {
sprintf(buffer, "%c", name);
print(buffer);
if (accidental > 0) {
for (i=0; i<accidental; i++) {
print("#");
}
} else if (accidental < 0) {
for (i=0; i<-accidental; i++) {
print("&");
}
}
if (octave != Goctave) {
sprintf(buffer, "%d", octave);
print(buffer);
Goctave = octave;
}
}
// process duration
double duration = Convert::kernToDuration(note);
Convert::durationToKernRhythm(buffer, duration);
if (duration == Gduration) {
// don't print duration, since it is alreay active.
} else {
Gduration = duration;
print("/");
print(buffer);
}
}
//////////////////////////////
//
// processFooter --
//
void processFooter(HumdrumFile& hfile) {
int i;
int start = 0;
for (i=hfile.getNumLines()-1; i>=0; i--) {
if (strcmp(hfile[i][0], "*-") == 0) {
start = i;
break;
}
}
if (start == 0) {
// already printed the header
return;
}
print("\n");
for (i=start; i<hfile.getNumLines(); i++) {
switch(hfile[i].getType()) {
case E_humrec_global_comment:
convertGlobalComment(hfile[i]);
break;
case E_humrec_bibliography:
convertBibliography(hfile[i]);
break;
}
}
}
/////////////////////////////
//
// processHeader -- print the header information in the file
//
void processHeader(HumdrumFile& hfile) {
int i;
int done = 0;
for (i=0; i<hfile.getNumLines(); i++) {
switch(hfile[i].getType()) {
case E_humrec_global_comment:
convertGlobalComment(hfile[i]);
break;
case E_humrec_bibliography:
convertBibliography(hfile[i]);
break;
case E_humrec_interpretation:
done = 1;
break;
}
if (done) break;
}
print("\n");
}
//////////////////////////////
//
// convertBibliography -- print a bibliographic record (!!! -> %%%)
//
void convertBibliography(HumdrumRecord& bibrec) {
if (lastchar != '\n') {
print("\n");
}
print("%%%");
print(&(bibrec.getLine()[3]));
print("\n");
}
//////////////////////////////
//
// convertBibliography -- print a bibliographic record (!!! -> %%%)
//
void convertGlobalComment(HumdrumRecord& globalcomment) {
if (lastchar != '\n') {
print("\n");
}
print("%%");
print(&(globalcomment.getLine()[2]));
print("\n");
}
//////////////////////////////
//
// print -- print the data
//
void print(const char* data) {
int length = strlen(data);
lastchar = data[length-1];
cout << data;
}
//////////////////////////////
//
// usage --
//
void usage(const char* command) {
}
//////////////////////////////
//
// resetGlobals -- global states for parsing into Guido notation
//
void resetGlobals(void) {
Goctave = -99;
Gduration = -99.0;
Gnoteinit = 0;
}
// md5sum: 86ef2895d810769328d903dd55105db3 hum2gmn.cpp [20090626]