//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sun May 20 16:30:59 PDT 2001
// Last Modified: Sun May 20 16:31:02 PDT 2001
// Filename: ...sig/examples/all/markana.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/markana.cpp
// Syntax: C++; museinfo
//
// Description: Measure the root of a previously marked region of music.
//
#include "humdrum.h"
#include <string.h>
#include <math.h>
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
void printAnalysis(HumdrumFile& infile,
Array<int>& givenrootanalysis,
Array<double>& durations,
Array<int>& automaticrootanalysis,
Array<double>& rootscores);
void generateAnalysis(HumdrumFile& infile,
Array<int>& givenrootanalysis,
Array<double>& durations,
Array<int>& automaticrootanalysis,
Array<double>& rootscores);
void printErrors(Array<int>& given,
Array<int>& automatic);
// global variables
Options options; // database for command-line arguments
int debugQ = 0; // used with the --debug option
int appendQ = 0; // used with the -a option
int errorQ = 0; // used with the -e option
double delta = -4; // used with the --delta option
double lambda = -3; // used with the --lambda option
double alpha = 0.578; // used with the --alpha option
int weightsQ = 0; // used with the -w option
int octave = 3; // used with the --octave option
int algorithm = 0; // used with the --algorithm option
Array<double> parameters; // used with --alpha, --delta, --lambda
///////////////////////////////////////////////////////////////////////////
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<int> automaticrootanalysis;
Array<int> givenrootanalysis;
Array<double> rootscores;
Array<double> durations;
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));
}
generateAnalysis(infile, givenrootanalysis, durations,
automaticrootanalysis, rootscores);
if (errorQ) {
printErrors(givenrootanalysis, automaticrootanalysis);
} else {
printAnalysis(infile, givenrootanalysis, durations,
automaticrootanalysis, rootscores);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printErrors --
//
void printErrors(Array& given, Array& automatic) {
int i;
char buffer[64] = {0};
for (i=0; i<given.getSize(); i++) {
if (given[i] < 0) {
continue;
}
if ((given[i] % 40) != (automatic[i] % 40)) {
cout << "On line: " << i+1 << ":\tgiven = "
<< Convert::base40ToKern(buffer, (given[i] % 40) + 2 + 3 * 40)
<< "\tautomatic = ";
cout << Convert::base40ToKern(buffer, (automatic[i] % 40) + 2 + 3 * 40)
<< "\n";
}
}
}
//////////////////////////////
//
// printAnalysis -- display the analysis results.
//
void printAnalysis(HumdrumFile& infile,
Array<int>& given,
Array<double>& durations,
Array<int>& automatic,
Array<double>& rootscores) {
char buffer[64] = {0};
int i;
for (i=0; i<infile.getNumLines(); i++) {
switch (infile[i].getType()) {
case E_humrec_none:
case E_humrec_empty:
case E_humrec_global_comment:
case E_humrec_bibliography:
cout << infile[i] << "\n";
break;
case E_humrec_data_comment:
cout << infile[i] << "\t!\n";
break;
case E_humrec_data_kern_measure:
cout << infile[i] << "\t" << infile[i][0] << "\n";
break;
case E_humrec_interpretation:
cout << infile[i];
if (strncmp(infile[i][0], "**", 2) == 0) {
cout << "\t**root";
} else if (infile[i].equalFieldsQ()) {
if (strchr(infile[i][0], '+') != NULL ||
strchr(infile[i][0], '^') != NULL ||
strcmp(infile[i][0], "*x") == 0) {
cout << "\t*";
} else {
cout << "\t" << infile[i][0];
}
} else {
cout << "\t*";
}
cout << "\n";
break;
case E_humrec_data:
cout << infile[i] << "\t";
if (automatic[i] == -1) {
cout << ".";
} else if (automatic[i] < 0) {
cout << Convert::durationToKernRhythm(buffer, durations[i]);
cout << "r";
} else {
cout << Convert::durationToKernRhythm(buffer, durations[i]);
cout << Convert::base40ToKern(buffer, (automatic[i]+2)%40 +
octave * 40);
}
cout << "\n";
break;
default:
break;
}
}
}
//////////////////////////////
//
// generateAnalysis -- analyze the roots of the chords
//
void generateAnalysis(HumdrumFile& infile,
Array<int>& givenrootanalysis,
Array<double>& durations,
Array<int>& automaticrootanalysis,
Array<double>& rootscores) {
infile.analyzeRhythm("4"); // force the beat to be quarter notes for now
automaticrootanalysis.setSize(infile.getNumLines());
durations.setSize(infile.getNumLines());
givenrootanalysis.setSize(infile.getNumLines());
rootscores.setSize(infile.getNumLines());
automaticrootanalysis.allowGrowth(0);
durations.allowGrowth(0);
givenrootanalysis.allowGrowth(0);
rootscores.allowGrowth(0);
automaticrootanalysis.setAll(-1);
givenrootanalysis.setAll(-1);
durations.setAll(-1);
rootscores.setAll(-1);
Array<double> scores(40);
int i, j;
int spines;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() == E_humrec_data) {
spines = infile[i].getFieldCount();
j=0;
while (j<spines) {
if (strcmp(infile[i].getExInterp(j), "**root") == 0) {
if (strcmp(infile[i][j], ".") == 0) {
break;
} else if (strchr(infile[i][j], 'r') != NULL) {
givenrootanalysis[i] = -1000;
automaticrootanalysis[i] = -1000;
rootscores[i] = -1000;
durations[i] = Convert::kernToDuration(infile[i][j]);
} else {
givenrootanalysis[i] = Convert::kernToBase40(infile[i][j])-2;
durations[i] = Convert::kernToDuration(infile[i][j]);
automaticrootanalysis[i] =
infile.measureChordRoot(scores, parameters,
infile[i].getAbsBeat(),
infile[i].getAbsBeat()+durations[i]-0.01, algorithm);
rootscores[i] = scores[automaticrootanalysis[i]];
}
break;
}
j++;
}
}
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("a|append=b", "append analysis to data in output");
opts.define("delta=d:-4.0", "empirical rhythm value 1");
opts.define("lambda=d:-3.0", "empirical rhythm value 2");
opts.define("alpha=d:0.578", "scale factor for the x-pitch space axis");
opts.define("o|octave=i:3", "octave number of bass line");
opts.define("w|weights=b", "display parallel spine of scores next to roots");
opts.define("e|errors|error=b", "display only root errors and where occur");
opts.define("g|algorithm=i:0", "use a specific chord algorithm");
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, May 2000" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 20 May 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);
}
debugQ = opts.getBoolean("debug");
appendQ = opts.getBoolean("append");
errorQ = opts.getBoolean("error");
algorithm = opts.getInteger("algorithm");
delta = opts.getDouble("delta");
lambda = opts.getDouble("lambda");
alpha = opts.getDouble("alpha");
parameters.setSize(3);
parameters.allowGrowth(0);
parameters[0] = alpha;
parameters[1] = delta;
parameters[2] = lambda;
octave = opts.getInteger("octave");
weightsQ = opts.getBoolean("weights");
}
//////////////////////////////
//
// example -- example usage of the markana program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the markana program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
// md5sum: 4be90626fa4bb440e750ad612bb66dad markana.cpp [20050403]