//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// 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 <iostream>
#ifndef OLDCPP
#include <iostream>
#include <sstream>
#define SSTREAM stringstream
#define CSTRING str().c_str()
using namespace std;
#else
#include <iostream.h>
#ifdef VISUAL
#include <strstrea.h>
#else
#include <strstream.h>
#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; i<argc; i++) {
printToHumdrum(std::cout, argv[i]);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////
//
// printToHumdrum --
//
void printToHumdrum(ostream& out, const char* filename) {
TiXmlDocument doc(filename);
int status = doc.LoadFile();
HumdrumFile outfile;
if (status) {
convertToHumdrum(outfile, &doc);
} else {
cout << "Failed to load file " << filename << "\n";
exit(1);
}
out << outfile;
}
//////////////////////////////
//
// printHeaderInformation --
//
void printHeaderInformation(ostream& out, TiXmlNode* node, double& offset,
int& mtop, int& mbot, double& repeat, charstar& keyinfo) {
node = node->FirstChild();
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; i<length; i++) {
if (isdigit(string2[i])) {
count = sscanf(string2 + i, "%d", &octave);
if (count != 1) {
cerr << "ERROR in pitch octave" << endl;
exit(1);
}
string2[i] = '\0';
}
}
int diatonic;
switch (string2[0]) {
case 'A': case 'a': diatonic = 5; break;
case 'B': case 'b': diatonic = 6; break;
case 'C': case 'c': diatonic = 0; break;
case 'D': case 'd': diatonic = 1; break;
case 'E': case 'e': diatonic = 2; break;
case 'F': case 'f': diatonic = 3; break; // careful: f is also a flat
case 'G': case 'g': diatonic = 4; break;
default:
cerr << "ERROR IN DIATONIC PITCH NAME " << string2 << endl;
exit(1);
}
int accidentals = 0;
for (i=1; i<length; i++) {
if (string[i] == 's') {
accidentals++;
} else if (string[i] == 'f') {
accidentals--;
}
}
int output = 0;
switch (diatonic) {
case 0: output = 0; break;
case 1: output = 6; break;
case 2: output = 12; break;
case 3: output = 17; break;
case 4: output = 23; break;
case 5: output = 29; break;
case 6: output = 35; break;
}
output = output + 2 + accidentals;
return output + 40 * octave;
}
//////////////////////////////
//
// printKernNote --
//
void printKernNote(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;
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 <chorale> marker" << endl;
exit(1);
}
node = node->FirstChild();
if ((strcmp(node->Value(), "info") != 0)) {
cout << "ERROR did not find <info> 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 <satb> marker" << endl;
exit(1);
}
node = node->FirstChild();
if ((strcmp(node->Value(), "soprano") != 0)) {
cout << "ERROR did not find <soprano> 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 <satb> marker" << endl;
exit(1);
}
printHumdrumPart(altostream, node, STEMDOWN);
node = node->NextSibling();
if ((strcmp(node->Value(), "tenor") != 0)) {
cout << "ERROR did not find <satb> marker" << endl;
exit(1);
}
printHumdrumPart(tenorstream, node, STEMUP);
node = node->NextSibling();
if ((strcmp(node->Value(), "bass") != 0)) {
cout << "ERROR did not find <satb> marker" << endl;
exit(1);
}
printHumdrumPart(bassstream, node, STEMDOWN);
Array<HumdrumFile> 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<outfile.getNumLines(); i++) {
switch (outfile[i].getType()) {
case E_humrec_data_comment:
newout << outfile[i] << "\n";
break;
case E_humrec_data_kern_measure:
newout << outfile[i] << "\n";
break;
case E_humrec_interpretation:
if (strncmp(outfile[i][0], "**", 2) == 0) {
// (temporarily place two voices on each staff)
newout << "**kern\t**kern\n";
newout << "*^\t*^\n";
newout << "*clefF4\t*clefF4\t*clefG2\t*clefG2\n";
// check the next line of spine order changes
newout << "!tenor\t!bass\t!soprano\t!alto\n";
if (repeatQ) {
printAllSpines(newout, voices, "*>[A,A,B]");
printAllSpines(newout, voices, "*>norep[A,A,B]");
printAllSpines(newout, voices, "*>A");
}
printKeyInfo(newout, keyinfo, voices);
// print meter:
for (j=0; j<voices; j++) {
newout << "*M" << mtop << "/" << mbot;
if (j < voices - 1) {
newout << "\t";
}
}
newout << "\n";
printAllSpines(newout, voices, "*MM100");
} else if (strcmp(outfile[i][0], "*-") == 0) {
// (temporarily place two voices on each staff)
newout << "*v\t*v\t*\t*\n";
newout << "*\t*v\t*v\n";
newout << "*-\t*-\n";
} else {
newout << outfile[i] << "\n";
}
break;
case E_humrec_data:
absbeat = outfile[i].getAbsBeat();
if (repeatQ && (repeat-offset <= absbeat)) {
repeatQ = 0;
if (nextbartime <= absbeat) {
printbarline(newout, barcounter, voices, ":|!");
printAllSpines(newout, voices, "*>B");
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<int> noterow;
noterow.setSize(outfile.getNumLines());
noterow.setSize(0);
Array<double> durs;
durs.setSize(outfile.getNumLines());
durs.setSize(0);
double duration;
Array<int> beats;
beats.setSize(outfile.getNumLines());
beats.setSize(0);
int beat;
int i;
for (i=0; i<outfile.getNumLines(); i++) {
if (outfile[i].getType() != E_humrec_data) {
continue;
}
if (strcmp(outfile[i][spine], ".") == 0) {
continue;
}
if (strchr(outfile[i][spine], 'r') != NULL) {
continue;
}
duration = Convert::kernToDuration(outfile[i][spine]);
if (fabs(duration - 0.5) < 0.001) {
duration = 0.5;
}
if (fabs(duration - 0.25) < 0.001) {
duration = 0.25;
}
if (duration <= 0.0) {
continue;
}
beat = (int)(outfile[i].getAbsBeat() + 0.0001);
beats.append(beat);
durs.append(duration);
noterow.append(i);
}
char buffer1[1024] = {0};
char buffer2[1024] = {0};
char buffer3[1024] = {0};
for (i=0; i<beats.getSize(); i++) {
if (durs[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<outfile.getNumLines(); i++) {
if (outfile[i].getType() == E_humrec_data_measure) {
measureQ = 1;
} else if (measureQ && (outfile[i].getType() == E_humrec_data)) {
for (j=0; j<outfile[i].getFieldCount(); j++) {
if (strcmp(outfile[i][j], ".") == 0) {
fillNullToken(outfile, i, j);
}
}
measureQ = 0;
}
}
}
//////////////////////////////
//
// fillNullToken --
//
void fillNullToken(HumdrumFile& outfile, int line, int spine) {
int row = outfile[line].getDotLine(spine);
int col = outfile[line].getDotSpine(spine);
double dur = Convert::kernToDuration(outfile[row][col]);
double firstdur = outfile[line].getAbsBeat() - outfile[row].getAbsBeat();
double seconddur = dur - firstdur;
char rhythm1[1024] = {0};
Convert::durationToKernRhythm(rhythm1, firstdur);
char rhythm2[1024] = {0};
Convert::durationToKernRhythm(rhythm2, seconddur);
char oldstring[1024] = {0};
strcpy(oldstring, outfile[row][col]);
char newstring[1024] = {0};
makeNewToken(newstring, oldstring, rhythm1, TIESTART);
outfile[row].changeField(col, newstring);
makeNewToken(newstring, oldstring, rhythm2, TIEEND);
outfile[line].changeField(spine, newstring);
}
//////////////////////////////
//
// makeNewToken -- replace the old duration with a new one, and add
// tie start/end marks as needed. Assumes that the token is not
// a chord.
//
void makeNewToken(char* newstring, const char* oldstring, const char* rhythm,
int tiestate) {
char single[2] = {0};
single[1] = '\0';
newstring[0] = '\0';
int restQ = 0;
if (strchr(oldstring, 'r') != NULL) {
restQ = 1;
}
if (tiestate == TIESTART) {
if (!restQ) {
strcat(newstring, "[");
}
}
int rhythmfound = 0;
int i;
int tieprinted = 0;
int len = strlen(oldstring);
for (i=0; i<len; i++) {
if (isdigit(oldstring[i]) || (oldstring[i] == '.')) {
if (rhythmfound == 0) {
strcat(newstring, rhythm);
rhythmfound = 1;
}
} else if ((tiestate == TIEEND) && ((oldstring[i] == '/') ||
(oldstring[i] == '\\'))) {
if (!restQ) {
strcat(newstring, "]");
}
tieprinted = 1;
} else if ((tiestate == TIESTART) && (oldstring[i] == ';')) {
// don't do anything: suppress fermata on first of tied notes
} else {
single[0] = oldstring[i];
strcat(newstring, single);
}
}
if ((tieprinted == 0) && (tiestate == TIEEND)) {
if (!restQ) {
strcat(newstring, "]");
}
}
}
//////////////////////////////
//
// printKeyInfo --
//
void printKeyInfo(ostream& out, const char* keyinfo, int voices) {
char buffer[1024] = {0};
strcpy(buffer, keyinfo);
char* ptr1;
char* ptr2;
ptr1 = strtok(buffer, "-");
ptr2 = strtok(NULL, "-");
if ((ptr1 == NULL) || (ptr2 == NULL)) {
cerr << "ERROR in key " << keyinfo << endl;
exit(1);
}
int base40 = getBase40FromHokeyPitch(ptr1) % 40;
int octave = 3; // major by default
if (strcmp(ptr2, "Minor") == 0) {
octave = 4;
} else if (strcmp(ptr2, "Dorian") == 0) {
octave = 4;
} else if (strcmp(ptr2, "Phrygian") == 0) {
octave = 4;
} else if (strcmp(ptr2, "Locrian") == 0) {
octave = 4;
}
base40 = base40 + octave * 40;
char tempstring[1024] = {0};
char keyname[1024] = {0};
Convert::base40ToKern(tempstring, base40);
strcpy(keyname, "*");
strcat(keyname, tempstring);
strcat(keyname, ":");
int keynumber = 0;
if (strcmp(keyname, "*C-:") == 0) { keynumber = -7; }
else if (strcmp(keyname, "*G-:") == 0) { keynumber = -6; }
else if (strcmp(keyname, "*D-:") == 0) { keynumber = -5; }
else if (strcmp(keyname, "*A-:") == 0) { keynumber = -4; }
else if (strcmp(keyname, "*E-:") == 0) { keynumber = -3; }
else if (strcmp(keyname, "*B-:") == 0) { keynumber = -2; }
else if (strcmp(keyname, "*F:") == 0) { keynumber = -1; }
else if (strcmp(keyname, "*C:") == 0) { keynumber = 0; }
else if (strcmp(keyname, "*G:") == 0) { keynumber = +1; }
else if (strcmp(keyname, "*D:") == 0) { keynumber = +2; }
else if (strcmp(keyname, "*A:") == 0) { keynumber = +3; }
else if (strcmp(keyname, "*E:") == 0) { keynumber = +4; }
else if (strcmp(keyname, "*B:") == 0) { keynumber = +5; }
else if (strcmp(keyname, "*F#:") == 0) { keynumber = +6; }
else if (strcmp(keyname, "*C#:") == 0) { keynumber = +7; }
// minor keys
else if (strcmp(keyname, "*a-:") == 0) { keynumber = -7; }
else if (strcmp(keyname, "*e-:") == 0) { keynumber = -6; }
else if (strcmp(keyname, "*b-:") == 0) { keynumber = -5; }
else if (strcmp(keyname, "*f:") == 0) { keynumber = -4; }
else if (strcmp(keyname, "*c:") == 0) { keynumber = -3; }
else if (strcmp(keyname, "*g:") == 0) { keynumber = -2; }
else if (strcmp(keyname, "*d:") == 0) { keynumber = -1; }
else if (strcmp(keyname, "*a:") == 0) { keynumber = 0; }
else if (strcmp(keyname, "*e:") == 0) { keynumber = +1; }
else if (strcmp(keyname, "*b:") == 0) { keynumber = +2; }
else if (strcmp(keyname, "*f#:") == 0) { keynumber = +3; }
else if (strcmp(keyname, "*c#:") == 0) { keynumber = +4; }
else if (strcmp(keyname, "*g#:") == 0) { keynumber = +5; }
else if (strcmp(keyname, "*d#:") == 0) { keynumber = +6; }
else if (strcmp(keyname, "*a#:") == 0) { keynumber = +7; }
// adjust based on the mode
if (strcmp(ptr2, "Dorian") == 0) {
// add one sharp to the minor mode (e.g. one flat to natural for D Dorian)
keynumber++;
} else if (strcmp(ptr2, "Phrygian") == 0) {
// subtract one (E minor has one sharp, E phrygian has no sharps)
keynumber--;
} else if (strcmp(ptr2, "Lydian") == 0) {
// add a sharp
keynumber++;
} else if (strcmp(ptr2, "Mixolydian") == 0) {
// subtract a sharp
keynumber--;
} else if (strcmp(ptr2, "Locrian") == 0) {
// subtract 5 sharps
keynumber-=5;
}
// cerr << "BASE-40 " << base40 << endl;
// cerr << "KEY-NAME " << keyname << endl;
// cerr << "KEY-NUMBER " << keynumber << endl;
const char* keystring = Convert::keyNumberToKern(keynumber);
int i;
// first print the key signature
for (i=0; i<voices; i++) {
out << keystring;
if (i < voices - 1) {
out << "\t";
}
}
out << "\n";
// next print the key (major or minor part)
for (i=0; i<voices; i++) {
out << keyname;
if (i < voices - 1) {
out << "\t";
}
}
out << "\n";
if (strcmp(ptr2, "Dorian") == 0) {
printAllSpines(out, voices, "*KDor");
} else if (strcmp(ptr2, "Phrygian") == 0) {
printAllSpines(out, voices, "*KPhr");
} else if (strcmp(ptr2, "Lydian") == 0) {
printAllSpines(out, voices, "*KLyd");
} else if (strcmp(ptr2, "Mixolydian") == 0) {
printAllSpines(out, voices, "*KMix");
} else if (strcmp(ptr2, "Locrian") == 0) {
printAllSpines(out, voices, "*KLoc");
}
// finally print the mode if not major or minor
}
//////////////////////////////
//
// printAllSpines --
//
void printAllSpines(ostream& out, int voices, const char* string) {
int i;
for (i=0; i<voices; i++) {
out << string;
if (i < voices - 1) {
out << "\t";
}
}
out << "\n";
}
//////////////////////////////
//
// printbarline --
//
void printbarline(ostream& out, int barcounter, int voices,
const char* barstyle) {
char number[1024] = {0};
if (barcounter == -1) {
strcat(number, "1-");
} else if (barcounter > 0) {
sprintf(number, "%d", barcounter);
}
int i;
for (i=0; i<voices; i++) {
out << "=" << number << barstyle;
if (i < voices - 1) {
out << "\t";
}
}
out << "\n";
}
// md5sum: de629c4e12fae751a17b0b52551a4a3e hokey2humdrum.cpp [20081221]