//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Fri May 4 17:04:43 PDT 2001
// Last Modified: Fri May 4 17:04:48 PDT 2001
// Filename: ...sig/examples/all/kern2cmn.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/kern2cmn.cpp
// Syntax: C++; museinfo
// Reference: http://www-ccrma.stanford.edu/CCRMA/Software/cmn/cmn-manual/cmn.html
//
// Description: Converts kern data into the format used in CMN,
// a LISP program that genrates PostScript musical scores.
//
// Note: Not completed
//
#include "humdrum.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <math.h>
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
void convertToCMN(HumdrumFile& infile);
void processTrack(HumdrumFile& infile, int track);
void convertKernNoteToDM(HumdrumFile& infile, int line, int spine, int track);
void printNote(int base40);
void printRest(double duration);
void printCMNDuration(double duration);
int parseInterpretation(HumdrumFile& infile, int line, int track);
void printPitchClass(int note);
void getNoteArray(Array<int>& notes, HumdrumFile& infile, int line, int spine);
// user interface variables
Options options; // database for command-line arguments
// other variables:
int key = -1; // for storing the key (base 40 number)
int nameinit = 0;
char name[128] = {0};
int bar = 0; // bar number
int mode = -1; // for storing the mode (0 = major, 1 = minor)
float metronome = -1.0; //
int start = -1;
int terminus = -1;
///////////////////////////////////////////////////////////////////////////
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();
Array<double> absbeat;
Array<int> pitch;
Array<int> testset;
Array<double> duration;
Array<double> level;
Array<double> coef;
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));
}
infile.analyzeRhythm();
cout << "(cmn\n";
convertToCMN(infile);
cout << ")\n";
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// convertToCMN -- convert kern spines into CMN format.
//
void convertToCMN(HumdrumFile& infile) {
for (int i=infile.getMaxTracks()-1; i>= 0; i--) {
// set global state variables to uninitialized
key = -1;
nameinit = 0;
name[0] = '\0';
mode = -1;
metronome = -1;
bar = 0;
processTrack(infile, i+1);
}
}
//////////////////////////////
//
// processTrack -- print out the specified track
//
void processTrack(HumdrumFile& infile, int track) {
int status;
int i, j;
for (i=0; i<infile.getNumLines(); i++) {
if (start > i && track != infile.getMaxTracks()) {
// skip over global comments after the first time:
i = start;
}
if (terminus < i && terminus != -1 && track != 1) {
// skip over global comments after the first time:
break;
}
switch (infile[i].getType()) {
case E_humrec_data:
for (j=0; j<infile[i].getFieldCount(); j++) {
if (infile[i].getPrimaryTrack(j) == track) {
convertKernNoteToDM(infile, i, j, track);
break; // don't process second part of split track
}
}
break;
case E_humrec_bibliography:
cout << ";;;" << (char*)&infile[i][0][3] << "\n";
break;
case E_humrec_global_comment:
cout << ";;" << (char*)&infile[i][0][2] << "\n";
break;
case E_humrec_data_comment:
for (j=0; j<infile[i].getFieldCount(); j++) {
if (infile[i].getPrimaryTrack(j) == track) {
cout << ";" << (char*)&infile[i][j][1] << "\n";
break; // don't process second part of split track
}
}
break;
case E_humrec_data_measure:
break;
case E_humrec_interpretation:
status = parseInterpretation(infile, i, track);
if (status == 0) {
return;
}
default: ;
}
}
}
//////////////////////////////
//
// parseInterpretation --
//
int parseInterpretation(HumdrumFile& infile, int line, int track) {
int i;
int status = 2;
int length = 0;
if ((terminus == -1) && (strcmp(infile[line][0], "*-") == 0)) {
terminus = line;
}
if (strcmp(infile[line][0], "*-") == 0) {
cout << "\n";
}
for (i=0; i<infile[line].getFieldCount(); i++) {
if (infile[line].getPrimaryTrack(i) == track) {
length = strlen(infile[line][i]);
if (strncmp(infile[line][i], "**", 2) == 0) {
if (start == -1) {
start = line;
}
if (strcmp(infile[line][i], "**kern") != 0) {
// don't translate non-musical data.
return 2;
} else {
status = 1;
}
} else if (infile[line][i][0] == '*' &&
infile[line][i][length-1] == ':') {
key = Convert::kernToBase40(infile[line][i]);
if (isupper(infile[line][i][1])) {
cout << " " << (char)tolower(infile[line][i][1]) << "-major\n";
} else if (islower(infile[line][i][1])) {
cout << " " << infile[line][i][1] << "-minor\n";
}
} else if (strncmp(infile[line][i], "*I", 2) == 0) {
if (islower(infile[line][i][2])) {
strcpy(name, &infile[line][i][2]);
}
} else if (strncmp(infile[line][i], "*MM", 3) == 0) {
sscanf(infile[line][i], "*MM%f", &metronome);
} else if (strncmp(infile[line][i], "*M", 2) == 0) {
int metertop;
int meterbottom;
sscanf(infile[line][i], "*M%d/%d", &metertop, &meterbottom);
cout << " (meter " << metertop << " " << meterbottom << ")\n";
} else if (strcmp(infile[line][i], "*clefG2") == 0) {
cout << " treble\n";
} else if (strcmp(infile[line][i], "*clefF4") == 0) {
cout << " bass\n";
}
if (strcmp(infile[line][i], "**kern") == 0) {
cout << " staff\n";
}
}
}
return status;
}
//////////////////////////////
//
// convertKernNoteToDM --
//
void convertKernNoteToDM(HumdrumFile& infile, int line, int spine, int track) {
const char* element = infile[line][spine];
double duration;
Array<int> notes;
if (strcmp(element, ".") == 0) {
return;
}
if (infile[line].getExInterpNum(spine) != E_KERN_EXINT) {
return;
}
if (infile[line].getBeat() == 1.0) {
bar++;
cout << "\n (bar " << bar << ") ";
}
duration = Convert::kernToDuration(infile[line][spine]);
if (strchr(element, 'r') != NULL) {
cout << " ";
printRest(duration);
return;
}
getNoteArray(notes, infile, line, spine);
int notecount = notes.getSize();
cout << " (";
for (int i=0; i<notecount; i++){
printNote(notes[i]);
if (i < notecount - 1) {
cout << " ";
}
}
cout << " ";
printCMNDuration(duration);
if (strchr(infile[line][spine], '[') != NULL) {
cout << " begin-tie";
} else if (strchr(infile[line][spine], ']') != NULL) {
cout << " end-tie";
} else if (strchr(infile[line][spine], '_') != NULL) {
}
cout << ")";
}
//////////////////////////////
//
// printRest --
//
void printRest(double duration) {
if (fabs(duration - 4.0) < 0.001) {
cout << "whole-rest";
} else if (fabs(duration - 2.0) < 0.001) {
cout << "half-rest";
} else if (fabs(duration - 1.0) < 0.001) {
cout << "quarter-rest";
} else if (fabs(duration - 0.5) < 0.001) {
cout << "eighth-rest";
} else if (fabs(duration - 0.25) < 0.001) {
cout << "sixteenth-rest";
} else if (fabs(duration - 0.125) < 0.001) {
cout << "thirty-second-rest";
}
}
//////////////////////////////
//
// getNoteArray --
//
void getNoteArray(Array& notes, HumdrumFile& infile, int line, int spine){
int notecount = infile[line].getTokenCount(spine);
char buffer[128] = {0};
notes.setSize(0);
int note;
notes.allowGrowth(1);
for (int i=0; i<notecount; i++) {
infile[line].getToken(buffer, spine, i, 128);
note = Convert::kernToBase40(buffer);
notes.append(note);
}
notes.allowGrowth(0);
}
//////////////////////////////
//
// printCMNDuration --
//
void printCMNDuration(double duration) {
char buffer[128] = {0};
Convert::durationToKernRhythm(buffer, duration);
if (strcmp(buffer, "8") == 0) {
cout << "e";
} else if (strcmp(buffer, "8.") == 0) {
cout << "e.";
} else if (strcmp(buffer, "16") == 0) {
cout << "s";
} else if (strcmp(buffer, "16.") == 0) {
cout << "s.";
} else if (strcmp(buffer, "4") == 0) {
cout << "q";
} else if (strcmp(buffer, "4.") == 0) {
cout << "q.";
} else if (strcmp(buffer, "2") == 0) {
cout << "h";
} else if (strcmp(buffer, "2.") == 0) {
cout << "h.";
} else if (strcmp(buffer, "1") == 0) {
cout << "w";
} else if (strcmp(buffer, "1.") == 0) {
cout << "w.";
}
}
//////////////////////////////
//
// printPitchClass --
//
void printPitchClass(int base40) {
switch ((base40 % 40) - 2) {
case -2: cout << "cff"; break; case -1: cout << "cf"; break;
case 0: cout << "c"; break; case 1: cout << "cs"; break;
case 2: cout << "css"; break; case 3: cout << "x"; break;
case 4: cout << "dff"; break; case 5: cout << "df"; break;
case 6: cout << "d"; break; case 7: cout << "ds"; break;
case 8: cout << "dss"; break; case 9: cout << "x"; break;
case 10: cout << "eff"; break; case 11: cout << "ef"; break;
case 12: cout << "e"; break; case 13: cout << "es"; break;
case 14: cout << "ess"; break; case 15: cout << "fff"; break;
case 16: cout << "ff"; break; case 17: cout << "f"; break;
case 18: cout << "fs"; break; case 19: cout << "fss"; break;
case 20: cout << "x"; break; case 21: cout << "gff"; break;
case 22: cout << "gf"; break; case 23: cout << "g"; break;
case 24: cout << "gs"; break; case 25: cout << "gss"; break;
case 26: cout << "x"; break; case 27: cout << "aff"; break;
case 28: cout << "af"; break; case 29: cout << "a"; break;
case 30: cout << "as"; break; case 31: cout << "ass"; break;
case 32: cout << "x"; break; case 33: cout << "bff"; break;
case 34: cout << "bf"; break; case 35: cout << "b"; break;
case 36: cout << "bs"; break; case 37: cout << "bss"; break;
default: cout << "x";
}
}
//////////////////////////////
//
// printNote --
//
void printNote(int base40) {
printPitchClass(base40);
cout << base40/40; // the octave number
}
//////////////////////////////
//
// 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, April 2001" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 28 April 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);
}
}
//////////////////////////////
//
// example -- example usage of the kern2dm program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the quality program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
// md5sum: 7cd8a48eb583b3469648b762ea66e627 kern2cmn.cpp [20050403]