//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Fri Apr 6 13:35:26 PDT 2001
// Last Modified: Mon May 21 20:20:14 PDT 2001
// Filename: ...sig/examples/all/croot2.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/croot2.cpp
// Syntax: C++; museinfo
//
// Description: determine the root of a chord in a given timespan.
//
#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>& rootanalysis,
Array<double>& rootscores);
void generateAnalysis(HumdrumFile& infile, Array<int>& rootanalysis,
Array<double>& rootscores);
// global variables
Options options; // database for command-line arguments
int debugQ = 0; // used with the --debug option
int rawQ = 0; // used with the --raw option
int appendQ = 0; // used with the -a option
int compoundQ = 1; // used with the -c option
int kernQ = 0; // used with the -k option
double rval = 1.0; // used with the -r option
double rlevel = 1.0; // used with the -r option
double duration = 1.0; // used with the -r option
double srhythm = 4.0; // used with the -r option
double delta = -4; // used with the --delta option
double lambda = -3; // used with the --lambda option
double sx = 0.578; // used with the --sx option
double sy = 1.0; // used with the --sx option
int octave = -1; // used with the -o option
int weightsQ = 0; // used with the -w option
int algorithm = 0; // used with the --algorithm option
double pickupfraction = 0.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();
Array<int> rootanalysis; // roots analysed at various times
Array<double> rootbeat; // absolute start beat of root
Array<double> rootscores; // score of best root
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, rootanalysis, rootscores);
printAnalysis(infile, rootanalysis, rootscores);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printAnalysis -- display the analysis results.
//
void printAnalysis(HumdrumFile& infile, Array<int>& rootanalysis,
Array<double>& rootscores) {
char buffer[1024] = {0};
int i;
int m;
if (rawQ) {
for (i=0; i<rootanalysis.getSize(); i++) {
if (rootanalysis[i] > 0) {
cout << "absbeat: " << pickupfraction + i * duration << "\t= "
<< Convert::base40ToKern(buffer, rootanalysis[i])
<< ",\tscore = " << rootscores[i] << endl;
} else {
cout << "absbeat: " << pickupfraction + i * duration << "\t= "
<< "rest"
<< "\tscore = " << 0 << endl;
}
}
return;
}
int j = 0;
double pos;
for (i=0; i<infile.getNumLines(); i++) {
pos = j * duration + pickupfraction; // next beat in analysis
switch (infile[i].getType()) {
case E_humrec_data:
if (infile[i].getAbsBeat() < pickupfraction) {
cout << infile[i].getLine();
cout << "\t";
cout << Convert::durationToKernRhythm(buffer, pickupfraction);
cout << "r";
if (weightsQ) {
cout << "\t0";
}
} else if (fabs(infile[i].getAbsBeat() - pos) < 0.01) {
cout << infile[i].getLine();
cout << "\t";
cout << Convert::durationToKernRhythm(buffer, duration);
if (rootanalysis[j] > 0) {
cout
<< Convert::base40ToKern(buffer, rootanalysis[j]);
} else {
cout << "r";
}
if (weightsQ) {
cout << "\t" << rootscores[j];
}
j++;
pos = j * duration + pickupfraction;
} else if (infile[i].getAbsBeat() < pos) {
cout << infile[i].getLine() << "\t.";
if (weightsQ) {
cout << "\t.";
}
} else {
while (pos < infile[i].getAbsBeat()) {
cout << "XXXNEWLINE: ";
cout << "\t";
cout << Convert::durationToKernRhythm(buffer, duration);
if (rootanalysis[j] > 0) {
cout
<< Convert::base40ToKern(buffer, rootanalysis[j]);
} else {
cout << "r";
}
if (weightsQ) {
cout << "\t" << rootscores[j];
}
j++;
pos = j * duration + pickupfraction; // next beat in analysis
}
}
cout << "\n";
break;
case E_humrec_data_measure:
if (infile[i].getAbsBeat() > pos) {
while (pos < infile[i].getAbsBeat()) {
for (m=0; m<infile[i].getFieldCount(); m++) {
cout << ".\t";
}
cout << "YYYNEWLINE: ";
cout << "\t";
cout << Convert::durationToKernRhythm(buffer, duration);
if (rootanalysis[j] > 0) {
cout
<< Convert::base40ToKern(buffer, rootanalysis[j]);
} else {
cout << "r";
}
if (weightsQ) {
cout << "\t" << rootscores[j];
}
cout << "\n";
j++;
pos = j * duration + pickupfraction;
}
}
cout << infile[i].getLine();
cout << "\t" << infile[i][0];
if (weightsQ) {
cout << "\t" << infile[i][0];
}
cout << "\n";
break;
case E_humrec_data_comment:
cout << infile[i].getLine();
if (infile[i].equalFieldsQ()) {
cout << "\t" << infile[i][0];
} else {
cout << "\t!";
}
if (weightsQ && infile[i].equalFieldsQ()) {
cout << "\t" << infile[i][0];
} else if (weightsQ) {
cout << "\t!";
}
cout << "\n";
break;
case E_humrec_data_interpretation:
cout << infile[i].getLine();
if (strncmp(infile[i][0], "**", 2) == 0) {
if (kernQ) {
cout << "\t**kern";
} else {
cout << "\t**root";
}
if (weightsQ) {
cout << "\t**weight";
}
cout << "\n";
} else {
if (infile[i].equalFieldsQ()) {
cout << "\t" << infile[i][0];
} else {
cout << "\t*";
}
if (weightsQ && infile[i].equalFieldsQ()) {
cout << "\t" << infile[i][0];
} else if (weightsQ) {
cout << "\t*";
}
cout << "\n";
}
break;
case E_humrec_global_comment:
case E_humrec_bibliography:
case E_humrec_none:
case E_humrec_empty:
default:
cout << infile[i].getLine() << "\n";
}
}
}
//////////////////////////////
//
// generateAnalysis -- analyze the roots of the chords
//
void generateAnalysis(HumdrumFile& infile, Array<int>& rootanalysis,
Array<double>& rootscores) {
Array<double> tonicscores(40);
infile.analyzeRhythm("4"); // force the beat to be quarter notes for now
double pickupoffset = infile.getPickupDuration();
double totalduration = infile.getTotalDuration();
double fraction = pickupoffset/duration - int(pickupoffset/duration);
pickupfraction = fraction * duration;
double startbeat;
if (fraction > 0.005) {
startbeat = pickupfraction;
} else {
startbeat = 0.0;
}
int size = int((totalduration - startbeat)/duration);
double currentbeat = 0.0;
double endbeat = 0.0;
int most = 0;
int nextroot = 0;
int lastroot = 0;
int i;
Array<double> parameters(3);
parameters[0] = sx;
parameters[1] = delta;
parameters[2] = lambda;
rootscores.setSize(size);
rootscores.setSize(0);
rootscores.allowGrowth(1);
rootanalysis.setSize(size);
rootanalysis.setSize(0);
rootanalysis.allowGrowth(1);
char buffer[128] = {0};
for (i=0; i<size; i++) {
currentbeat = startbeat + duration * i;
endbeat = currentbeat + duration - 0.01;
most = infile.measureChordRoot(tonicscores, parameters,
currentbeat, endbeat, algorithm, debugQ);
if (most >= 0) {
if (octave < 0) {
nextroot = (most + 2) % 40 + 80;
if (abs(nextroot + 40 - lastroot) < 13) {
nextroot += 40;
} else if (abs(nextroot - 40 - lastroot) < 13) {
nextroot -= 40;
}
} else {
nextroot = (most + 2) % 40 + 40 * octave;
}
Convert::base40ToKern(buffer, nextroot);
lastroot = nextroot;
} else {
nextroot = 0;
}
rootanalysis.append(nextroot);
if (most < 0) {
double zero = 0.0;
rootscores.append(zero);
} else {
rootscores.append(tonicscores[most]);
}
}
}
//////////////////////////////
//
// 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("raw=b", "raw display of output");
opts.define("C|compound=b", "don't try to use compound meters");
opts.define("r|rhythm=s:4", "rhythm to measure root at");
opts.define("delta=d:-4.0", "empirical rhythm value 1");
opts.define("lambda=d:-3.0", "empirical rhythm value 2");
opts.define("sx=d:0.578", "scale factor for the x-pitch space axis");
opts.define("sy=d:1.0", "scale factor for the y-pitch space axis");
opts.define("o|octave=i:-1", "octave number of bass line");
opts.define("w|weights=b", "display parallel spine of scores next to roots");
opts.define("g|algorithm=i:0", "controls which root algorithm to use");
opts.define("k|kern=b", "output root spine as **kern rather than **root");
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, Dec 2000" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 21 Mar 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");
rawQ = opts.getBoolean("raw");
if (opts.getBoolean("compound")) {
compoundQ = 0;
} else {
compoundQ = 0;
}
duration = Convert::kernToDuration(opts.getString("rhythm"));
srhythm = 4.0 / duration;
rlevel = log10(srhythm)/log10(2.0) - 2.0;
delta = opts.getDouble("delta");
lambda = opts.getDouble("lambda");
sx = opts.getDouble("sx");
sy = opts.getDouble("sy");
octave = opts.getInteger("octave");
weightsQ = opts.getBoolean("weights");
kernQ = opts.getBoolean("kern");
}
//////////////////////////////
//
// example -- example usage of the maxent 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: bcbdaca8d63f596f978634d8f67bd7ed croot2.cpp [20050403]