// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Sat Sep 20 06:35:45 PDT 2008 // Last Modified: Sat Sep 20 06:36:19 PDT 2008 // Filename: ...museinfo/examples/all/koto2xml.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/koto2xml.cpp // Syntax: C++; museinfo // // Description: Convert **koto data into MEI XML and MusicXML. // #include "humdrum.h" #define MEIXML 1 #define MUSICXML 2 // function declarations void printTabs(ostream& outstream, int count); void example(void); void usage(const char* command); void checkOptions(Options& opts, int argc, char* argv[]); void processHumdrumFile(HumdrumFile& infile, int outputType); // MEI XML functions: void printMeiXml(ostream& outstream, HumdrumFile& infile); void printMeiHeader(ostream& outstream, HumdrumFile& infile, int level); void printMeiWork(ostream& outstream, HumdrumFile& infile, int level); void printMeiKotoPart(ostream& outstream, HumdrumFile& infile, int spine, int level); void printMeiMeasure(ostream& outstream, HumdrumFile& infile, int spine, int start, int level); void printMeiNoteData(ostream& outstream, const char* string, int level); void printMeiChordData(ostream& outstream, HumdrumFile& infile, int spine, int line, int level); void printMeiPitch(ostream& outstream, int pitch); void printMeiRhythm(ostream& outstream, const char* data); // MusicXML functions: void printMusicXml(ostream& outstream, HumdrumFile& infile); // Shared functions: char* getTitle(char* buffer, int buffsize, HumdrumFile& infile); void printEncodedString(ostream& outstream, char* buffer); int checkForTune(int* mapping, HumdrumRecord& arecord, int spine); int getKotoString(const char* data); int getRhythm(const char* data); int getDots(const char* data); // User interface variables: Options options; int meiQ = 1; // default behavior int musicxmlQ = 0; // convert to MusicXML int STRINGMAPPING[21] = {0}; int main(int argc, char** argv) { HumdrumFile infile; // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process int numinputs = options.getArgCount(); for (int i=0; i<numinputs || i==0; i++) { infile.clear(); // if no command-line arguments read data file from standard input if (numinputs < 1) { infile.read(cin); } else { infile.read(options.getArg(i+1)); } processHumdrumFile(infile, MEIXML); } return 0; } //////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("debug=b", "trace input parsing"); opts.define("author=b", "author of the program"); opts.define("version=b", "compilation information"); opts.define("example=b", "example usage"); 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, Sep 2008" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: Sep 2008" << 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); } } ////////////////////////////// // // processHumdrumFile -- // void processHumdrumFile(HumdrumFile& infile, int outputType) { switch (outputType) { case MEIXML: printMeiXml(std::cout, infile); break; case MUSICXML: printMusicXml(std::cout, infile); break; } } ////////////////////////////// // // example -- example usage of the scrub program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // usage -- gives the usage statement for the scrub program // void usage(const char* command) { cout << " \n" << endl; } ////////////////////////////// // // printTabs -- // void printTabs(ostream& outstream, int count) { for (int i=0; i<count && i < 1000; i++) { // outstream << '\t'; outstream << " "; } } /////////////////////////////////////////////////////////////////////////// // // MEI XML functions // ////////////////////////////// // // printMeiXml -- // void printMeiXml(ostream& outstream, HumdrumFile& infile) { outstream << "<?xml version='1.0' encoding='UTF-8'?>" << "\n"; outstream << "<!DOCTYPE mei SYSTEM 'mei18bFull.dtd'"; outstream << '>' << '\n'; outstream << "<mei version='1.8b'>\n"; int level = 1; printMeiHeader(outstream, infile, level); printMeiWork(outstream, infile, level); outstream << "</mei>\n"; } ////////////////////////////// // // printMeiHeader -- // void printMeiHeader(ostream& outstream, HumdrumFile& infile, int level) { #define BUFFSIZE 10000 char buffer[BUFFSIZE]; printTabs(outstream, level); outstream << "<meihead>" << "\n"; printTabs(outstream, level+1); outstream << "<filedesc>" << "\n"; printTabs(outstream, level+2); outstream << "<titlestmt>" << "\n"; getTitle(buffer, BUFFSIZE, infile); if (strlen(buffer) == 0) { printTabs(outstream, level+3); outstream << "<title/>\n"; } else { printTabs(outstream, level+3); outstream << "<title>"; printEncodedString(outstream, buffer); outstream << "</title>\n"; } printTabs(outstream, level+2); outstream << "</titlestmt>" << "\n"; printTabs(outstream, level+2); outstream << "<pubstmt/>" << "\n"; printTabs(outstream, level+1); outstream << "</filedesc>" << "\n"; printTabs(outstream, level); outstream << "</meihead>" << "\n"; } ////////////////////////////// // // printMeiWork -- // void printMeiWork(ostream& outstream, HumdrumFile& infile, int level) { printTabs(outstream, level ); outstream << "<music>" << "\n"; printTabs(outstream, level+1); outstream << "<body>" << "\n"; printTabs(outstream, level+2); outstream << "<mdiv>" << "\n"; printTabs(outstream, level+3); outstream << "<score>" << "\n"; printTabs(outstream, level+4); outstream << "<staffgrp>" << "\n"; printTabs(outstream, level+5); outstream << "<staffdef n='1'/>" << "\n"; printTabs(outstream, level+4); outstream << "</staffgrp>" << "\n"; printMeiKotoPart(outstream, infile, 0, level+4); printTabs(outstream, level+3); outstream << "</score>" << "\n"; printTabs(outstream, level+2); outstream << "</mdiv>" << "\n"; printTabs(outstream, level+1); outstream << "</body>" << "\n"; printTabs(outstream, level ); outstream << "</music>" << "\n"; } ////////////////////////////// // // printMeiKotoPart -- // void printMeiKotoPart(ostream& outstream, HumdrumFile& infile, int spine, int level) { int i; for (i=0; i<infile.getNumLines(); i++) { switch (infile[i].getType()) { case E_humrec_interpretation: checkForTune(STRINGMAPPING, infile[i], spine); break; case E_humrec_data_measure: if (strncmp(infile[i][spine], "==", 2) != 0) { // online print measure if note a double-barline // probably check later to see if there is an end of file printMeiMeasure(outstream, infile, spine, i, level); } break; //default: // do nothing } } } ////////////////////////////// // // printMeiMeasure -- // void printMeiMeasure(ostream& outstream, HumdrumFile& infile, int spine, int start, int level) { int i; if (infile[start][spine][0] != '=') { std::cout << "ERROR: line does not have measure: " << infile[start][spine] << endl; exit(1); } static int measure = -1; int flag = sscanf(infile[start][spine], "=%d", &measure); if (flag != 1) { measure++; } printTabs(outstream, level); outstream << "<measure n='" << measure << "'>" << "\n"; printTabs(outstream, level+1); outstream << "<staff n='1'>" << "\n"; start++; for (i=start; i<infile.getNumLines(); i++) { if (infile[i].getType() == E_humrec_interpretation) { checkForTune(STRINGMAPPING, infile[i], spine); } else if (infile[i].getType() == E_humrec_data_measure) { break; } else if (infile[i].getType() == E_humrec_data) { printMeiChordData(outstream, infile, spine, i, level+2); } else { } } printTabs(outstream, level+1); outstream << "</staff>" << "\n"; printTabs(outstream, level); outstream << "</measure>" << "\n"; // perhaps return the new line here for processing next measure } ////////////////////////////// // // printMeiChordData -- // void printMeiChordData(ostream& outstream, HumdrumFile& infile, int spine, int line, int level) { int tokencount = infile[line].getTokenCount(spine); if (tokencount < 1) { return; } if (tokencount == 1) { // a single note printMeiNoteData(outstream, infile[line][spine], level); return; } // print chord printTabs(outstream, level); outstream << "<chord>" << "\n"; char buffer[1024]; int i; for (i=0; i<tokencount; i++) { infile[line].getToken(buffer, spine, i, 1024); printMeiNoteData(outstream, buffer, level+1); } printTabs(outstream, level); outstream << "</chord>" << "\n"; } ////////////////////////////// // // printMeiNoteData -- // void printMeiNoteData(ostream& outstream, const char* data, int level) { if (strcmp(data, ".") == 0) { // nothing to print return; } // WARNING: Have to deal with chords int string = getKotoString(data); printTabs(outstream, level); if (string == 0) { outstream << "<rest"; printMeiRhythm(outstream, data); outstream << "/>\n"; } else if (string == 14) { outstream << "<space"; printMeiRhythm(outstream, data); outstream << "/>\n"; } else if (string > 0) { outstream << "<note tab.string='" << string << "'"; printMeiPitch(outstream, STRINGMAPPING[string-1]); printMeiRhythm(outstream, data); outstream << "/>" << "\n"; } } ////////////////////////////// // // printMeiRhythm -- // void printMeiRhythm(ostream& outstream, const char* data) { int rhythm = getRhythm(data); int dots = getDots(data); outstream << " dur='" << rhythm << "'"; if (dots > 0) { outstream << " dots='" << dots << "'"; } } ////////////////////////////// // // printMeiPitch -- // void printMeiPitch(ostream& outstream, int pitch) { int octave = pitch / 40; int accidental = Convert::base40ToAccidental(pitch); int diatonic = Convert::base40ToDiatonic(pitch) % 7; if (diatonic < 0 || diatonic > 6) { std::cerr << "ERROR: invalid diatonic number: " << diatonic << " (" << pitch << ")" << endl; exit(1); } char Diatonic[7] = {'c', 'd', 'e', 'f', 'g', 'a', 'b'}; outstream << " pname='" << Diatonic[diatonic] << "'"; outstream << " oct='" << octave << "'"; if (accidental != 0) { outstream << " accid.ges='"; switch (accidental) { case 2: outstream << "ss"; break; case 1: outstream << "s"; break; case -1: outstream << "f"; break; case -2: outstream << "ff"; break; } outstream << "'"; } } /////////////////////////////////////////////////////////////////////////// // // MusicXML functions // void printMusicXml(ostream& outstream, HumdrumFile& infile) { // do nothing for now } /////////////////////////////////////////////////////////////////////////// // // Shared functions // ////////////////////////////// // // printEncodedString -- escape quote output string // < = < // > = > // & = & // ' = ' // " = " // void printEncodedString(ostream& outstream, char* buffer) { int i; int length = strlen(buffer); for (i=0; i<length; i++) { switch (buffer[i]) { case '<': outstream << "<"; break; case '>': outstream << ">"; break; case '&': outstream << "&"; break; case '\'': outstream << "&"; break; case '\"': outstream << "&"; break; default: outstream << buffer[i]; } } } ////////////////////////////// // // getTitle -- Return the first !!!OTL record in the file. // char* getTitle(char* buffer, int buffsize, HumdrumFile& infile) { int i, j; int length; int colon = -1; buffer[0] = 0; for (i=0; i<infile.getNumLines(); i++) { if (infile[i].getType() == E_humrec_bibliography) { if (strncmp(infile[i][0], "!!!OTL", 6) == 0) { length = strlen(infile[i][0]); for (j=6; j<length; j++) { if (infile[i][0][j] == ':') { colon = j+1; break; } } if (colon < 0) { return buffer; } while (j < length && (infile[i][0][colon] == ' ' || infile[i][0][colon] == '\n')) { colon++; } strncpy(buffer, &(infile[i][0][colon]), buffsize-1); } } } return buffer; } ////////////////////////////// // // checkForTune -- Look for tuning directive in data // int checkForTune(int* mapping, HumdrumRecord& arecord, int spine) { if (strncmp(arecord[spine], "*tune[", 6) != 0) { return 0; } char buffer[1024]; strncpy(buffer, &(arecord[spine][6]), 1023); char* ptr = strtok(buffer, ": \n\t]"); int counter = 0; while (ptr != NULL && counter < 21) { mapping[counter] = Convert::kernToBase40(ptr); // std::cout << "FOUND " << counter << " to be " << ptr << endl; counter++; ptr = strtok(NULL, ": \n\t]"); } // std::cout << "COUNTER = " << counter << endl; return counter; } ////////////////////////////// // // getKotoString -- // int getKotoString(const char* data) { int i; int length = strlen(data); for (i=0; i<length; i++) { switch (data[i]) { case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case '0': return 0; case '-': return 14; } } return -1; } ////////////////////////////// // // getRhythm -- return the numeric part of the rhythm (excluding // augmentation dots) // int getRhythm(const char* data) { double duration = Convert::kotoToDuration(data); char buffer[1024]; Convert::durationToKernRhythm(buffer, duration); int i; int length = strlen(buffer); int output = 0; for (i=0; i<length; i++) { if (isdigit(buffer[i])) { sscanf(&(buffer[i]), "%d", &output); break; } } return output; } ////////////////////////////// // // getDots -- return the number of augmentation dots in the rhythm. // int getDots(const char* data) { int i; int length = strlen(data); int output = 0; for (i=0; i<length; i++) { if (data[i] == '.') { output++; } } return output; } // md5sum: 7ec5706a9a636a3405f6aa95317dce7d koto2xml.cpp [20101226]