//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat May 23 21:08:48 PDT 1998
// Last Modified: Fri Jul 3 14:18:04 PDT 1998
// Filename: ...sig/examples/all/base40.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/base40.cpp
// Syntax: C++; museinfo
// Reference: http://www.ccarh.org/publications/reprints/base40
//
// Description: Converts **kern pitches into/from base 40 system.
//
#include "humdrum.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void processDataRecord(HumdrumRecord& line);
void processExclusiveInterp(HumdrumRecord& line);
void processTandemRecord(HumdrumRecord& line);
void splitstring(const char* line, char* front, char* basestring,
char* back, const char* markstart, const char* markend);
void kernsplit(const char* line, char* front, char* back,
const char* markstart, const char* markend);
// global variables
Options options; // database for command-line arguments
int octaveQ = 1; // boolean for keeping or removing octave info
int transpose = 0; // transposition value from command-line
int preserveQ = 0; // boolean for keeping extra kern info
int kernQ = 1; // boolean for converting **base40 to **kern
int cvalue = 2; // default pitch class for C
int noptionQ = 0; // for -n option: convert to specific key
int mode = 0; // for -n option
char newkey[32] = {0}; // for -n option
const char* markstart = ""; // start of base40 number marker
const char* markend = ""; // end of base40 number marker
///////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
// process the command-line options
checkOptions(options, argc, argv);
int numinputs = options.getArgCount();
HumdrumFile input;
for (int j=0; j<numinputs || j==0; j++) {
input.clear();
// if no command-line arguments read data file from standard input
if (numinputs < 1) {
input.read(cin);
} else {
input.read(options.getArg(j+1));
}
for (int i=0; i<input.getNumLines(); i++) {
switch (input[i].getType()) {
case E_humrec_none:
case E_humrec_empty:
case E_humrec_bibliography:
case E_humrec_global_comment:
case E_humrec_data_comment:
case E_humrec_interpretation:
if (strncmp(input[i][0], "**", 2) == 0) {
processExclusiveInterp(input[i]);
cout << input[i] << endl;
} else if (noptionQ) {
processTandemRecord(input[i]);
}
cout << input[i] << endl;
break;
case E_humrec_data_kern_measure:
cout << input[i] << endl;
break;
case E_humrec_data:
processDataRecord(input[i]);
cout << input[i] << endl;
break;
default:
break;
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("p|pitch-class=b", "show only base40 pitch classes");
opts.define("r|rhythm=b", "preserve **kern rhythms and other info");
opts.define("c|c-value=i:2", "base 40 pitch class value for C");
opts.define("t|transpose=i:0", "transposition interval");
opts.define("k|kern=b", "convert **base40 spines to **kern");
opts.define("n|newkey=s", "transpose **kern spines to newkey");
opts.define("s|start=s:a", "marker string start for **kern preserving");
opts.define("e|end=s:a", "marker string end for **kern preserving");
opts.define("author=b", "show the 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, April 2000" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 11 April 2000" << 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);
}
if (opts.getBoolean("pitch-class")) {
octaveQ = 0;
} else {
octaveQ = 1;
}
// get the transposition interval
transpose = opts.getInteger("transpose");
// get kern convertion option
kernQ = opts.getBoolean("kern");
// get the base40 marker start/stop strings
markstart = opts.getString("start");
markend = opts.getString("end");
// get boolean for keeping extra kern data.
preserveQ = opts.getBoolean("rhythm");
// get boolean for converting from base40 to kern
kernQ = opts.getBoolean("kern");
// get C value offset
cvalue = opts.getInteger("c-value");
cvalue -= 2;
if (opts.getBoolean("newkey")) {
noptionQ = 1;
transpose = 0;
strncpy(newkey, opts.getString("newkey"), 30);
if (isupper(newkey[0])) {
mode = 0; // Major
} else {
mode = 1; // Minor
}
int i = 0;
while (newkey[i] != '\0') {
if (newkey[i] == 's') {
newkey[i] = '#';
}
i++;
}
}
}
//////////////////////////////
//
// example -- example usage of the base40 program
//
void example(void) {
cout <<
" \n"
"no examples yet \n"
" \n"
<< endl;
}
//////////////////////////////
//
// kernsplit -- split up the kern into stuff before and stuff
// after a pitch value.
//
void kernsplit(const char* line, char* front, char* back,
const char* markstart, const char* markend) {
int length = strlen(line);
char *templine;
templine = new char[length+1];
strcpy(templine, line);
char* pointer;
pointer = strtok(templine, "abcdefgABCDEFG#-n");
if (pointer != NULL) {
strcpy(front, pointer);
} else {
front[0] = '\0';
}
pointer = strtok(NULL, "abcdefgABCDEFG#-n");
if (pointer != NULL) {
strcpy(back, pointer);
} else {
back[0] = '\0';
}
delete [] templine;
}
//////////////////////////////
//
// processDataRecord -- example usage of the base40 program
//
void processDataRecord(HumdrumRecord& line) {
int k;
int base40value;
static char buffer[1024] = {0};
static char pitchbuffer[128] = {0};
static char front[128] = {0};
static char back[128] = {0};
static char basestring[128] = {0};
if (kernQ) {
// converting from **base40 to **kern
for (k=0; k<line.getFieldCount(); k++) {
if (strcmp(line.getExInterp(k), "**base40") == 0) {
if (strcmp(line[k], ".") == 0) {
continue;
}
splitstring(line[k], front, basestring, back, markstart, markend);
base40value = atoi(basestring);
base40value += transpose - cvalue;
Convert::base40ToKern(pitchbuffer, base40value);
strcpy(buffer, front);
strcat(buffer, pitchbuffer);
strcat(buffer, back);
line.changeField(k, buffer);
}
}
} else if (noptionQ) {
//////////////////////////////////////////
} else {
// converting from **kern to **base40
for (k=0; k<line.getFieldCount(); k++) {
if (strcmp(line.getExInterp(k), "**kern") == 0) {
if (strcmp(line[k], ".") == 0) {
continue;
}
base40value = Convert::kernToBase40(line[k]);
base40value += transpose + cvalue;
if (preserveQ) {
kernsplit(line[k], front, back, markstart, markend);
if (base40value < -100) {
line.changeField(k, "r");
pitchbuffer[0] = 'r';
pitchbuffer[1] = '\0';
} else {
if (octaveQ == 0) {
base40value = base40value % 40;
}
sprintf(pitchbuffer, "%d", base40value);
}
sprintf(buffer, "%s%s%s%s%s", front, markstart,
pitchbuffer, markend, back);
line.changeField(k, buffer);
} else {
if (base40value < -100) {
line.changeField(k, "r");
} else {
if (octaveQ == 0) {
base40value = base40value % 40;
}
sprintf(buffer, "%d", base40value);
line.changeField(k, buffer);
}
}
}
}
}
}
//////////////////////////////
//
// processExclusiveInterp -- adjust the ** fields as necessary
//
void processExclusiveInterp(HumdrumRecord& line) {
int k;
if (kernQ) {
// converting from **base40 to **base40
for (k=0; k<line.getFieldCount(); k++) {
if (strcmp(line[k], "**base40") == 0) {
line.changeField(k, "**kern");
}
}
} else if (noptionQ) {
// do nothing, will keep **kern spines, but transpose them.
} else {
// converting from **kern to **base40
for (k=0; k<line.getFieldCount(); k++) {
if (strcmp(line[k], "**kern") == 0) {
line.changeField(k, "**base40");
}
}
}
}
//////////////////////////////
//
// processTandemRecord -- handle lines starting with *.
//
void processTandemRecord(HumdrumRecord& line) {
if (transpose != 0) {
return; // don't need to change this more than once
}
// find the first **kern spine
char oldkey[32] = {0};
char oldkeytemp[32] = {0};
char *tempointer = NULL;
int length = 0;
int k;
for (k=0; k<line.getFieldCount(); k++) {
if (strcmp("**kern", line.getExInterp(k)) == 0) {
strncpy(oldkey, line[k], 30);
break;
}
}
length = strlen(oldkey);
strcpy(oldkeytemp, oldkey);
tempointer = strtok(oldkeytemp, "*abcdefgABCDEFG#-:");
if (tempointer == NULL || strcmp(tempointer, "") == 0) {
// do nothing
} else {
return; // not the tandem interp that was wanted.
}
if (oldkey[length-1] != ':') {
return;
}
int base40note = Convert::kernToBase40(oldkey);
cout << "++++++++ Key value is: " << base40note << endl;
}
//////////////////////////////
//
// splitstring -- split the kern field into three sections:
// (1) before the pitch, (2) the pitch, and (3) after the pitch.
//
void splitstring(const char* line, char* front, char* basestring, char* back,
const char* markstart, const char* markend) {
int length = strlen(line);
char *templine;
templine = new char[length+1];
strcpy(templine, line);
int lengths = strlen(markstart);
int lengthe = strlen(markend);
char *startp, *endp;
startp = strstr(templine, markstart);
if (startp != NULL) {
endp = strstr(&startp[1], markend);
} else {
endp = NULL;
}
// if there is no marker to preserve kern
if (startp == NULL && endp == NULL) {
front[0] = '\0';
back[0] = '\0';
strcpy(basestring, line);
delete [] templine;
return;
}
// something weird may have happened, send all ouptut to middle string
if (startp == NULL || endp == NULL) {
front[0] = '\0';
back[0] = '\0';
strcpy(basestring, line);
delete [] templine;
return;
}
// both the start and the end marker were found so split up the
// string into three pieces
startp[0] = '\0';
endp[0] = '\0';
strcpy(front, templine);
strcpy(basestring, &startp[lengths]);
strcpy(back, &endp[lengthe]);
delete [] templine;
}
//////////////////////////////
//
// usage -- gives the usage statement for the quality program
//
void usage(const char* command) {
cout <<
"Extracts pitch information from <tt>**kern</tt> spines and converts them \n"
"to a base-40 representation which preserves interval qualities between \n"
"pitches. \n"
" \n"
"Usage: " << command << " [-r][-p] input \n"
" \n"
"Options: \n"
" -r = keep **kern rhythms and other kern information. \n"
" -p = convert to base40 pitch class, not asolute pitch. \n"
" -k = convert from **base40 to **kern \n"
" --options = list of all options, aliases and default values \n"
" \n"
<< endl;
}
// md5sum: 5a7991fedc79c13df19a5496dca855b0 base40.cpp [20050403]