// // Programmer: Craig Stuart Sapp // Creation Date: Wed Dec 3 11:13:50 PST 2008 // Last Modified: Wed Dec 3 11:13:55 PST 2008 // Filename: ...museinfo/examples/all/hokey2humdrum.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/hokey2humdrum.cpp // Syntax: C++ // // Description: Convert Hokey XML data files into Humdrum files. // #include "humdrum.h" #define TIXML_USE_STL #include "tinyxml.h" #include #ifndef OLDCPP #include #include #define SSTREAM stringstream #define CSTRING str().c_str() using namespace std; #else #include #ifdef VISUAL #include #else #include #endif #define SSTREAM strstream #define CSTRING str() #endif typedef const char* charstar; void printToHumdrum (ostream& out, const char* filename); void convertToHumdrum (HumdrumFile& outfile, TiXmlNode* node); void printHeaderInformation (ostream& out, TiXmlNode* node, double& offset, int& mtop, int& mbot, double& repeat, charstar& keyinfo); void printHumdrumPart (ostream& out, TiXmlNode* node, int stem); void printKernNote (ostream& out, TiXmlNode* node, int stem); void printKernRest (ostream& out, TiXmlNode* node, int stem); int getBase40FromHokeyPitch (const char* string); double printRhythm (ostream& out, int dtop, int dbot); void printbarline (ostream& out, int barcounter, int voices, const char* barstyle); void printKeyInfo (ostream& out, const char* keyinfo, int voices); void printAllSpines (ostream& out, int voices, const char* string); void addTies (HumdrumFile& outfile); void fillNullToken (HumdrumFile& outfile, int line, int spine); void makeNewToken (char* newstring, const char* oldstring, const char* rhythm, int tiestate); void addBeaming (HumdrumFile& outfile, int spine); #define STEMDEFAULT 0 #define STEMUP 1 #define STEMDOWN 2 #define TIENONE 0 #define TIESTART 1 #define TIEEND 2 /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { int i; for (i=1; iFirstChild(); offset = 0; mtop = mbot = 0; const char* index = ""; const char* title = ""; const char* offsetT = ""; const char* repeatT = ""; int count; TiXmlText* textnode; while (node != NULL) { if (strcmp(node->Value(), "title") == 0) { textnode = node->FirstChild()->ToText(); title = textnode->Value(); } else if (strcmp(node->Value(), "index") == 0) { textnode = node->FirstChild()->ToText(); index = textnode->Value(); } else if (strcmp(node->Value(), "key") == 0) { textnode = node->FirstChild()->ToText(); keyinfo = textnode->Value(); } else if (strcmp(node->Value(), "start-time") == 0) { textnode = node->FirstChild()->ToText(); offsetT = textnode->Value(); } else if (strcmp(node->Value(), "repeat-time") == 0) { textnode = node->FirstChild()->ToText(); repeatT = textnode->Value(); } else if (strcmp(node->Value(), "meter") == 0) { textnode = node->FirstChild()->ToText(); count = sscanf(textnode->Value(), "%d/%d/", &mtop, &mbot); if (count != 2) { cerr << "ERROR in time signature " << textnode->Value() << endl; exit(1); } } node = node->NextSibling(); } if (title[0] != '\0') { out << "!!!COM:\t" << "Bach, Johann Sebastian" << "\n"; out << "!!!CDT:\t" << "1685/02/21/-1750/07/28/" << "\n"; out << "!!!OTL:\t" << title << "\n"; } if (index[0] != '\0') { out << "!!!ONM:\t" << index << "\n"; out << "!!!AGN:\t" << "chorale" << "\n"; } if (offsetT[0] != '\0') { int top = 0; int bot = 0; sscanf(offsetT, "%d/%d", &top, &bot); offset = (double)top / (double)bot * 4.0; } if (repeatT[0] != '\0') { int rtop = 0; int rbot = 0; sscanf(repeatT, "%d/%d", &rtop, &rbot); repeat = (double)rtop / (double)rbot * 4.0; } if ((mtop == 0) || (mbot == 0)) { cerr << "ERROR unspecified time signature" << endl; exit(1); } } ////////////////////////////// // // getHumdrumPart -- // void printHumdrumPart(ostream& out, TiXmlNode* node, int stem) { node = node->FirstChild(); out << "**kern\n"; while (node != NULL) { if (strcmp(node->Value(), "note") == 0) { printKernNote(out, node, stem); out << "\n"; } else if (strcmp(node->Value(), "rest") == 0) { printKernRest(out, node, stem); out << "\n"; } else { cerr << "Unknown ELEMENT <" << node->Value() << endl; exit(1); } node = node->NextSibling(); } out << "*-\n"; } /////////////////////////////// // // getBase40FromHokeyPitch -- // int getBase40FromHokeyPitch(const char* string) { int length = strlen(string); if (length == 0) { return 0; } int octave = 0; int count; int i; char string2[1024] = {0}; strcpy(string2, string); for (i=0; iFirstChild(); int dtop = 0; int dbot = 0; int base40 = 0; int count; int fermata = 0; int tiestart = 0; int tiecontinue = 0; int tieend = 0; double duration; while (node != NULL) { // cout << "ELEMENT " << node->Value() << endl; if (strcmp(node->Value(), "fermata") == 0) { fermata = 1; } else if (strcmp(node->Value(), "tiestart") == 0) { tiestart = 1; } else if (strcmp(node->Value(), "tiecontinue") == 0) { tiecontinue = 1; } else if (strcmp(node->Value(), "tieend") == 0) { tieend = 1; } else if (strcmp(node->Value(), "duration") == 0) { textnode = node->FirstChild()->ToText(); count = sscanf(textnode->Value(), "%d/%d", &dtop, &dbot); if (count != 2) { cerr << "Error parsing rhythm: " << textnode->Value() << endl; exit(1); } } else if (strcmp(node->Value(), "pitch") == 0) { textnode = node->FirstChild()->ToText(); base40 = getBase40FromHokeyPitch(textnode->Value()); } node = node->NextSibling(); } if (dtop == 0 || dbot == 0 || base40 == 0) { cerr << "SOME SORT OF ERROR" << endl; cerr << "dtop =\t" << dtop << endl; cerr << "dbot =\t" << dbot << endl; cerr << "base40 =\t" << base40 << endl; exit(1); } if (tiestart) { out << "["; } duration = printRhythm(out, dtop, dbot); char buffer[1024] = {0}; out << Convert::base40ToKern(buffer, base40); if (fermata) { out << ";"; } if (tiecontinue) { out << "_"; } else if (tieend) { out << "]"; } if (duration < 4.0) { // only print stem info if less than whole note if (stem == STEMUP) { out << "/"; } else if (stem == STEMDOWN) { out << "\\"; } } } ////////////////////////////// // // printRhythm -- // double printRhythm(ostream& out, int dtop, int dbot) { double duration = (double)dtop / (double) dbot; duration *= 4.0; char buffer[1024] = {0}; out << Convert::durationToKernRhythm(buffer, duration); return duration; } ////////////////////////////// // // printKernRest -- // void printKernRest(ostream& out, TiXmlNode* node, int stem) { TiXmlText* textnode; node = node->FirstChild(); int dtop = 0; int dbot = 0; int base40 = 0; int count; int fermata = 0; double duration; while (node != NULL) { // cout << "ELEMENT " << node->Value() << endl; if (strcmp(node->Value(), "fermata") == 0) { fermata = 1; } else if (strcmp(node->Value(), "duration") == 0) { textnode = node->FirstChild()->ToText(); count = sscanf(textnode->Value(), "%d/%d", &dtop, &dbot); if (count != 2) { cerr << "Error parsing rhythm: " << textnode->Value() << endl; exit(1); } } else if (strcmp(node->Value(), "pitch") == 0) { textnode = node->FirstChild()->ToText(); base40 = getBase40FromHokeyPitch(textnode->Value()); } node = node->NextSibling(); } if (dtop == 0 || dbot == 0 || base40 != 0) { cerr << "SOME SORT OF ERROR 2" << endl; cerr << "dtop =\t" << dtop << endl; cerr << "dbot =\t" << dbot << endl; cerr << "base40 =\t" << base40 << endl; exit(1); } duration = printRhythm(out, dtop, dbot); out << "r"; if (fermata) { out << ";"; } } /////////////////////////////// // // convertToHumdrum -- // void convertToHumdrum(HumdrumFile& outfile, TiXmlNode* node) { SSTREAM headerstream; // deal with printing it out later SSTREAM sopranostream; SSTREAM altostream; SSTREAM tenorstream; SSTREAM bassstream; if (node->Type() != TiXmlNode::DOCUMENT) { cout << "ERROR not at start of document" << endl; exit(1); } node = node->FirstChild(); if ((strcmp(node->Value(), "chorale") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } node = node->FirstChild(); if ((strcmp(node->Value(), "info") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } double offset = 0; // for keeping track of pickup-measures int mtop = 0; // top of timesignature; int mbot = 0; // bottom of timesignature; const char* keyinfo = ""; double repeat = 0; printHeaderInformation(headerstream, node, offset, mtop, mbot, repeat, keyinfo); node = node->NextSibling(); if ((strcmp(node->Value(), "satb") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } node = node->FirstChild(); if ((strcmp(node->Value(), "soprano") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } //printHumdrumPart(std::cout, node, STEMUP); printHumdrumPart(sopranostream, node, STEMUP); node = node->NextSibling(); if ((strcmp(node->Value(), "alto") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } printHumdrumPart(altostream, node, STEMDOWN); node = node->NextSibling(); if ((strcmp(node->Value(), "tenor") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } printHumdrumPart(tenorstream, node, STEMUP); node = node->NextSibling(); if ((strcmp(node->Value(), "bass") != 0)) { cout << "ERROR did not find marker" << endl; exit(1); } printHumdrumPart(bassstream, node, STEMDOWN); Array parts; parts.setSize(4); parts.allowGrowth(0); headerstream << ends; sopranostream << ends; altostream << ends; tenorstream << ends; bassstream << ends; // change order when making single part to a spine // look for "check the next line of spine order changes" below as well parts[3].read(altostream); parts[2].read(sopranostream); parts[1].read(bassstream); parts[0].read(tenorstream); outfile.clear(); HumdrumFile::assemble(outfile, 4, parts.getBase()); outfile.analyzeRhythm("4"); SSTREAM newout; int repeatQ = 0; if (repeat > 0) { repeatQ = 1; } int barcounter = 1; double bardur = 4.0 * mtop / mbot; double nextbartime = bardur - offset; if (nextbartime >= bardur) { nextbartime = 0; barcounter = -1; } double absbeat; newout << headerstream.CSTRING; int i, j; int voices = outfile.getMaxTracks(); for (i=0; i[A,A,B]"); printAllSpines(newout, voices, "*>norep[A,A,B]"); printAllSpines(newout, voices, "*>A"); } printKeyInfo(newout, keyinfo, voices); // print meter: for (j=0; jB"); barcounter = abs(barcounter); barcounter++; nextbartime += bardur; } else { printbarline(newout, -100, voices, ":|!"); printAllSpines(newout, voices, "*>B"); } } else if (nextbartime <= absbeat) { printbarline(newout, barcounter, voices, ""); barcounter = abs(barcounter); barcounter++; nextbartime += bardur; } newout << outfile[i] << "\n"; if (strcmp(outfile[i+1][0], "*-") == 0) { printbarline(newout, -100, voices, "="); } break; case E_humrec_none: case E_humrec_empty: case E_humrec_global_comment: case E_humrec_bibliography: default: newout << outfile[i] << "\n"; break; } } newout << "!!!hum2abc: -Q ''\n"; newout << "!!!title: @{ONM}. @{OTL}\n"; newout << ends; outfile.clear(); outfile.read(newout); outfile.analyzeRhythm("4"); addTies(outfile); outfile.analyzeRhythm("4"); addBeaming(outfile, 0); addBeaming(outfile, 1); addBeaming(outfile, 2); addBeaming(outfile, 3); } ////////////////////////////// // // addBeaming -- // void addBeaming(HumdrumFile& outfile, int spine) { Array noterow; noterow.setSize(outfile.getNumLines()); noterow.setSize(0); Array durs; durs.setSize(outfile.getNumLines()); durs.setSize(0); double duration; Array beats; beats.setSize(outfile.getNumLines()); beats.setSize(0); int beat; int i; for (i=0; i= 1.0) { continue; } if (i >= beats.getSize()-1) { continue; } if (beats[i] != beats[i+1]) { continue; } if (durs[i+1] >= 1.0) { continue; } if (strchr(outfile[noterow[i]][spine], 'L') != NULL) { continue; } if (strchr(outfile[noterow[i]][spine], 'J') != NULL) { continue; } if ((durs[i] == 0.5) && (durs[i+1] == 0.5)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+1]][spine]); strcat(buffer1, "L"); strcat(buffer2, "J"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+1]].changeField(spine, buffer2); continue; } if ((durs[i] == 0.75) && (durs[i+1] == 0.25)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+1]][spine]); strcat(buffer1, "L"); strcat(buffer2, "Jk"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+1]].changeField(spine, buffer2); continue; } if ((durs[i] == 0.25) && (durs[i+1] == 0.75)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+1]][spine]); strcat(buffer1, "LK"); strcat(buffer2, "J"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+1]].changeField(spine, buffer2); continue; } if (i >= beats.getSize()-2) { continue; } if ((beats[i] != beats[i+2]) || durs[i+2] >= 1.0) { if ((durs[i] == 0.25) && (durs[i+1] == 0.25)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+1]][spine]); strcat(buffer1, "LL"); strcat(buffer2, "JJ"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+1]].changeField(spine, buffer2); continue; } continue; } if ((durs[i] == 0.5) && (durs[i+1] == 0.25) && (durs[i+2] == 0.25)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+1]][spine]); strcpy(buffer3, outfile[noterow[i+2]][spine]); strcat(buffer1, "L"); strcat(buffer2, "L"); strcat(buffer3, "JJ"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+1]].changeField(spine, buffer2); outfile[noterow[i+2]].changeField(spine, buffer3); continue; } if ((durs[i] == 0.25) && (durs[i+1] == 0.25) && (durs[i+2] == 0.5)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+1]][spine]); strcpy(buffer3, outfile[noterow[i+2]][spine]); strcat(buffer1, "LL"); strcat(buffer2, "J"); strcat(buffer3, "J"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+1]].changeField(spine, buffer2); outfile[noterow[i+2]].changeField(spine, buffer3); continue; } if (i >= beats.getSize()-3) { continue; } if ((beats[i] != beats[i+3]) || durs[i+3] >= 1.0) { continue; } if ((durs[i] == 0.25) && (durs[i+1] == 0.25) && (durs[i+2] == 0.25) && (durs[i+3] == 0.25)) { strcpy(buffer1, outfile[noterow[i]][spine]); strcpy(buffer2, outfile[noterow[i+3]][spine]); strcat(buffer1, "LL"); strcat(buffer2, "JJ"); outfile[noterow[i]].changeField(spine, buffer1); outfile[noterow[i+3]].changeField(spine, buffer2); continue; } cout << "GOT HERE" << endl; } } ////////////////////////////// // // addTies -- // void addTies(HumdrumFile& outfile) { int i, j; int measureQ = 0; for (i=0; i 0) { sprintf(number, "%d", barcounter); } int i; for (i=0; i