//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Mon Jun 24 20:05:15 PDT 2002
// Last Modified: Sun Aug 25 17:47:13 PDT 2002
// Last Modified: Sat Nov 30 15:46:46 PST 2002 (added triad spectrum display)
// Filename: ...sig/examples/all/iwroot.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/iwroot.cpp
// Syntax: C++; museinfo
//
// Description: Determine the root of a pitch set according to
// different root-interval class sizes.
//
#define MYPI 3.141592653589793
#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 printScores(Array<double>& rootscores);
void printDistances(IntervalWeight& distances, int type);
int analyzeChromatic(Array<double>& rootscores, HumdrumFile& infile,
IntervalWeight& distances, int startline,
int stopline, int correct = -1,
int debugQ = 0);
double base40ToBase7(int pitch);
char base7pcToName(int value);
void identifyErrorsChromatic(HumdrumFile& infile, int type, int debugQ);
void generateDistances(IntervalWeight& distances, int type);
void printNotes(int correct, Array<int>& pitches);
void printNotes(int correct, Array<int>& pitches,
Array<double>& durations,
Array<double>& levels);
int intcompare(const void* a, const void* b);
int pdlcompare(const void* a, const void* b);
int doublecompare(const void* a, const void* b);
void setSortOrder(IntervalWeight& dist, Array<int>& index);
void getStartingWeights(IntervalWeight& weights,
HumdrumFile& weightfile);
double octavescaling(int pitch, double scaling);
double durationscaling(double duration);
double metricscaling(double metriclevel);
// global variables
Options options; // database for command-line arguments
int debugQ = 0; // used with --debug option
int appendQ = 0; // used with -a option
int rootQ = 0; // used with -R option
int errorsQ = 0; // used with -e option
double theta1 = 51.0; // used with -t option
double theta2 = 51.0; // used with -u option
int invertQ = 0; // used with -i option
int distanceQ = 0; // used with -d option
int notesQ = 0; // used with -n option
int transposeQ = 0; // used with -C option
int singleQ = 0; // used with -s option
int sortQ = 0; // used with -S option
int locationQ = 0; // used with -l option
int circularQ = 0; // used with -c option
double power = 1.0; // used with -p option
double circular = 0.0; // used with -c option
double offset = 0.0; // used with -o option
int weightQ = 0; // used with -w option
const char* weightFile = ""; // used with -w option
int verboseQ = 0; // used with -v option
int octaveQ = 0; // used with -o option
double octaveScale= 0.0; // used with -o option
int rhythmQ = 0; // used with -r option
double durationfactor=0.8; // used with --dfactor
double metricfactor=0.5; // used with --mfactor
int spectrumQ = 0; // used with --spectrum
const char* CurrentFile = ""; // current file being processed
int CurrentLine = 0; // current line in file being processed
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile;
// process the command-line options
checkOptions(options, argc, argv);
int i;
for (i=1; i<=options.getArgCount() || options.getArgCount()==0; i++) {
infile.clear();
// if no command-line arguments read data file from standard input
if (options.getArgCount() < 1) {
infile.read(cin);
} else {
CurrentFile = options.getArg(i);
infile.read(CurrentFile);
}
if (errorsQ) {
if (options.getBoolean("theta2")) {
identifyErrorsChromatic(infile, 2, debugQ);
} else if (circularQ) {
identifyErrorsChromatic(infile, 4, debugQ);
} else if (weightQ) {
identifyErrorsChromatic(infile, 0, debugQ);
} else {
identifyErrorsChromatic(infile, 1, debugQ);
}
} else if (distanceQ) {
IntervalWeight distances;
if (options.getBoolean("theta2")) {
generateDistances(distances, 2);
printDistances(distances, 2);
} else if (circularQ) {
generateDistances(distances, 4);
printDistances(distances, 4);
} else if (weightQ) {
generateDistances(distances, 0);
printDistances(distances, 0);
} else {
generateDistances(distances, 1);
printDistances(distances, 1);
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// generateDistances --
//
void generateDistances(IntervalWeight& distances, int type) {
switch (type) {
case 0: // read weight file
{
HumdrumFile infile(weightFile);
getStartingWeights(distances, infile);
}
break;
case 1:
distances.setChromatic1(theta1);
break;
case 2:
distances.setChromatic2(theta1, theta2);
break;
case 4:
distances.setCircular(theta1, circular);
break;
default:
cout << "Error: unknown type: " << type << endl;
exit(1);
}
int i;
if (power != 1.0) {
for (i=0; i<40; i++) {
distances[i] = pow(distances[i], power);
}
}
if (offset != 0.0) {
for (i=0; i<40; i++) {
distances[i] += offset;
}
}
}
//////////////////////////////
//
// identifyErrorsChromatic -- compare root scores value to root in
// humdrum file and print out errors.
//
void identifyErrorsChromatic(HumdrumFile& infile, int type, int debugQ) {
int oldline = 0;
int init = 0;
int best = 0; // best root according to algorithm
int correct = 0; // correct base40 root
int i;
int j;
// get interval distances:
IntervalWeight distances;
generateDistances(distances, type);
// go though the file and compare all chords to **root info:
Array<double> rootscores(40);
rootscores.setAll(0);
for (i=0; i<infile.getNumLines(); i++) {
CurrentLine = i+1;
if (!infile[i].isData()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (strcmp(infile[i].getExInterp(j), "**root") == 0) {
if (strcmp(infile[i][j], ".") == 0) {
break;
}
if (strchr(infile[i][j], '_') != NULL) { // cont. ties
break;
}
if (strchr(infile[i][j], ']') != NULL) { // tie ends
break;
}
if (init == 0) {
init = 1;
oldline = i;
correct = Convert::kernToBase40(infile[i][j]) % 40;
break;
}
best = analyzeChromatic(rootscores, infile, distances,
oldline, i-1, correct, debugQ);
if ((best >= 0) && (best+2 != correct)) {
char zbuffer[128] = {0};
cout << "Error on line " << oldline + 1
<< "\tcorrect="
<< Convert::base40ToKern(zbuffer, correct+4*40);
cout << "\tvalue="
<< Convert::base40ToKern(zbuffer, best+2+4*40) << endl;
}
oldline = i;
correct = Convert::kernToBase40(infile[i][j]) % 40;
break;
}
}
}
best = analyzeChromatic(rootscores, infile, distances, oldline,
i-1, correct, debugQ);
if ((best >= 0) && (best+2 != correct)) {
char zbuffer[128] = {0};
cout << "Error on line " << oldline + 1
<< "\tcorrect=" << Convert::base40ToKern(zbuffer, correct+4*40);
cout << "\tvalue=" << Convert::base40ToKern(zbuffer, best+2+4*40)
<< endl;
}
}
//////////////////////////////
//
// analyzeChromatic --
//
int analyzeChromatic(Array<double>& rootscores, HumdrumFile& infile,
IntervalWeight& distances, int startline, int stopline, int correct,
int debugQ) {
// extract note data
Array<double> absbeat;
Array<int> pitches;
Array<double> durations;
Array<double> levels;
infile.getNoteArray(absbeat, pitches, durations, levels, startline,
stopline);
if (pitches.getSize() == 0) {
// give up if there are no notes in the specified region
return -1;
}
if (notesQ) {
if (rhythmQ) {
printNotes(correct, pitches, durations, levels);
} else {
printNotes(correct, pitches);
}
}
char buffer[64] = {0};
if (debugQ) {
int i;
cout << "====================" << endl;
for (i=startline; i<=stopline; i++) {
cout << infile[i] << "\n";
}
cout << "--------------------" << endl;
cout << "Start line=" << startline+1
<< "\tEnd line=" << stopline+1 << endl;
for (i=0; i<pitches.getSize(); i++) {
cout << "pitch = "
<< Convert::base40ToKern(buffer, pitches[i]) << endl;
}
}
rootscores.setSize(40);
rootscores.setAll(0.0);
int i;
int j;
if (rhythmQ) {
if (octaveQ) {
for (i=0; i<rootscores.getSize(); i++) {
for (j=0; j<pitches.getSize(); j++) {
rootscores[i] += octavescaling(pitches[j], octaveScale) *
distances[(pitches[j]-i+400)%40] *
durationscaling(durations[j]) *
metricscaling(levels[j]);
}
}
} else {
for (i=0; i<rootscores.getSize(); i++) {
for (j=0; j<pitches.getSize(); j++) {
rootscores[i] += distances[(pitches[j]-i+400)%40] *
durationscaling(durations[j]) *
metricscaling(levels[j]);
}
}
}
} else {
if (octaveQ) {
for (i=0; i<rootscores.getSize(); i++) {
for (j=0; j<pitches.getSize(); j++) {
rootscores[i] += octavescaling(pitches[j], octaveScale) *
distances[(pitches[j]-i+400)%40];
}
}
} else {
for (i=0; i<rootscores.getSize(); i++) {
for (j=0; j<pitches.getSize(); j++) {
rootscores[i] += distances[(pitches[j]-i+400)%40];
}
}
}
}
int min = 0;
for (i=1; i<rootscores.getSize(); i++) {
if (rootscores[i] < rootscores[min]) {
min = i;
}
}
if (spectrumQ) {
cout << "======================\n";
for (i=0; i<rootscores.getSize(); i++) {
cout << Convert::base40ToKern(buffer, i+2+3*40)
<< "\t" << 1.0/rootscores[i] << "\n";
}
cout << "======================\n";
}
if (verboseQ) {
cout << "!! BEST ROOT = " << Convert::base40ToKern(buffer, min+2+3*40)
<< endl;
printScores(rootscores);
}
return min;
}
//////////////////////////////
//
// durationscaling -- scaling value from duration information
//
double durationscaling(double duration) {
if (duration <= 0.0) {
return 0.0;
}
double alpha = durationfactor;
double value = duration;
return pow(value, alpha);
}
//////////////////////////////
//
// metricscaling -- scaling value from metric level information
//
double metricscaling(double metriclevel) {
offset = 0.0;
metriclevel += offset;
if (metriclevel <= 0.0) {
return 0.0;
}
double alpha = metricfactor;
double value = metriclevel;
return pow(value, alpha);
}
//////////////////////////////
//
// octavescaling -- generate a octave weighting.
//
double octavescaling(int pitch, double scaling) {
int base12 = Convert::base40ToMidiNoteNumber(pitch);
return pow(2.0, (base12 - 60) * scaling);
}
////////////////////////////////
//
// printNotes -- print pitch classes and given root.
//
void printNotes(int correct, Array& pitches) {
Array<int> pc = pitches;
int i;
for (i=0; i<pc.getSize(); i++) {
if (pc[i] < 0) {
continue;
}
pc[i] = pc[i] % 40;
}
qsort(pc.getBase(), pc.getSize(), sizeof(int), intcompare);
char buffer[128] = {0};
if (locationQ) {
cout << CurrentFile << "\tline " << CurrentLine << "\t";
}
if (transposeQ && singleQ) {
// resort by length
for (i=0; i<pc.getSize(); i++) {
if (pc[i] < 0) {
continue;
}
pc[i] = (pc[i]-correct+2+400)%40;
}
qsort(pc.getBase(), pc.getSize(), sizeof(int), intcompare);
// remove duplicate pitch classes
for (i=1; i<pc.getSize(); i++) {
if (pc[i-1] == pc[i]) {
pc[i-1] = -1;
}
}
qsort(pc.getBase(), pc.getSize(), sizeof(int), intcompare);
cout << "R=" << Convert::base40ToKern(buffer, correct+3*40) << ":\t";
for (i=0; i<pc.getSize(); i++) {
if (pc[i] < 0) {
continue;
}
cout << Convert::base40ToKern(buffer, pc[i]+4*40);
if (i<pc.getSize()-1) {
cout << " ";
}
}
cout << "\n";
} else if (transposeQ) {
// resort by length
for (i=0; i<pc.getSize(); i++) {
if (pc[i] < 0) {
continue;
}
pc[i] = (pc[i]-correct+2+400)%40;
}
qsort(pc.getBase(), pc.getSize(), sizeof(int), intcompare);
cout << "R=" << Convert::base40ToKern(buffer, correct+3*40) << ":\t";
for (i=0; i<pc.getSize(); i++) {
cout << Convert::base40ToKern(buffer, pc[i]+4*40);
if (i<pc.getSize()-1) {
cout << " ";
}
}
cout << "\n";
} else {
cout << Convert::base40ToKern(buffer, correct+3*40) << ":\t";
for (i=0; i<pc.getSize(); i++) {
cout << Convert::base40ToKern(buffer, (pc[i]%40)+4*40);
if (i<pc.getSize()-1) {
cout << " ";
}
}
cout << "\n";
}
}
class PDL {
public:
int pitch;
double duration;
double level;
};
void printNotes(int correct, Array<int>& pitches,
Array<double>& durations, Array<double>& levels) {
Array<int> pc = pitches;
int i;
for (i=0; i<pc.getSize(); i++) {
if (pc[i] < 0) {
continue;
}
pc[i] = pc[i] % 40;
}
Array<PDL> pitchinfo;
pitchinfo.setSize(pc.getSize());
for (i=0; i<pc.getSize(); i++) {
pitchinfo[i].pitch = pc[i];
pitchinfo[i].duration = durations[i];
pitchinfo[i].level = levels[i];
}
// qsort(pc.getBase(), pc.getSize(), sizeof(int), intcompare);
qsort(pitchinfo.getBase(), pitchinfo.getSize(), sizeof(PDL), pdlcompare);
char buffer[128] = {0};
if (locationQ) {
cout << CurrentFile << "\tline " << CurrentLine << "\t";
}
if (transposeQ && singleQ) {
// resort by length
for (i=0; i<pitchinfo.getSize(); i++) {
if (pitchinfo[i].pitch < 0) {
continue;
}
pitchinfo[i].pitch = (pitchinfo[i].pitch-correct+2+400)%40;
}
qsort(pitchinfo.getBase(), pitchinfo.getSize(), sizeof(PDL), pdlcompare);
// remove duplicate pitch classes
for (i=1; i<pitchinfo.getSize(); i++) {
if (pitchinfo[i-1].pitch == pitchinfo[i].pitch) {
pitchinfo[i-1].pitch = -1;
}
}
// qsort(pc.getBase(), pc.getSize(), sizeof(int), intcompare);
qsort(pitchinfo.getBase(), pitchinfo.getSize(), sizeof(PDL), pdlcompare);
cout << "R=" << Convert::base40ToKern(buffer, correct+3*40) << ":\t";
for (i=0; i<pitchinfo.getSize(); i++) {
if (pitchinfo[i].pitch < 0) {
continue;
}
cout << Convert::base40ToKern(buffer, pitchinfo[i].pitch+4*40);
if (i<pitchinfo.getSize()-1) {
cout << " ";
}
}
cout << "\n";
} else if (transposeQ) {
// resort by length
for (i=0; i<pitchinfo.getSize(); i++) {
if (pitchinfo[i].pitch < 0) {
continue;
}
pitchinfo[i].pitch = (pitchinfo[i].pitch-correct+2+400)%40;
}
qsort(pitchinfo.getBase(), pitchinfo.getSize(), sizeof(PDL), pdlcompare);
cout << "R=" << Convert::base40ToKern(buffer, correct+3*40) << ":\t";
for (i=0; i<pitchinfo.getSize(); i++) {
cout << Convert::base40ToKern(buffer, pitchinfo[i].pitch+4*40);
cout << "(" << pitchinfo[i].duration << ","
<< pitchinfo[i].level << ")";
if (i<pitchinfo.getSize()-1) {
cout << " ";
}
}
cout << "\n";
} else {
cout << Convert::base40ToKern(buffer, correct+3*40) << ":\t";
for (i=0; i<pitchinfo.getSize(); i++) {
cout << Convert::base40ToKern(buffer, (pitchinfo[i].pitch%40)+4*40);
cout << "(" << pitchinfo[i].duration << ","
<< pitchinfo[i].level << ")";
if (i<pitchinfo.getSize()-1) {
cout << " ";
}
}
cout << "\n";
}
}
//////////////////////////////
//
// setSortOrder --
//
void setSortOrder(IntervalWeight& dist, Array& index) {
Array<int> used;
used.setSize(40);
used.allowGrowth(0);
used.setAll(0);
index.setSize(40);
index.setAll(10000);
int i, j;
Array<double> values;
values.setSize(40);
for (i=0; i<40; i++) {
values[i] = dist[i];
}
qsort(values.getBase(), values.getSize(), sizeof(double), doublecompare);
for (i=0; i<35; i++) {
for (j=0; j<40; j++) {
if ((values[i] == dist[j]) && (used[j] == 0)) {
used[j] = 1;
index[i] = j;
break;
}
}
}
}
//////////////////////////////
//
// printDistances --
//
void printDistances(IntervalWeight& distances, int type) {
int i;
char buffer[64] = {0};
switch (type) {
case 1:
cout << "!! theta: " << theta1 << "\n";
break;
case 2:
cout << "!! theta1: " << theta1 << "\n";
cout << "!! theta2: " << theta2 << "\n";
break;
case 4:
cout << "!! theta: " << theta1 << "\n";
cout << "!! scaling: " << circular << "\n";
break;
}
cout << "**kern\t**weight\n";
if (sortQ) {
Array<int> sorter(40);
setSortOrder(distances, sorter);
for (i=0; i<distances.getSize(); i++) {
if (sorter[i] > 40) {
continue;
}
cout << Convert::base40ToKern(buffer, sorter[i]+4*40);
cout << "\t" << distances[sorter[i]] << "\n";
}
} else {
for (i=0; i<distances.getSize(); i++) {
if (i==5 || i==11 || i==22 || i==28 || i==34) {
continue;
}
cout << Convert::base40ToKern(buffer, i+4*40);
cout << "\t" << distances[i] << "\n";
}
}
cout << "*-\t*-\n";
}
//////////////////////////////
//
// printScores --
//
void printScores(Array& rootscores) {
int i;
int findex;
char buffer[64] = {0};
for (i=0; i<rootscores.getSize(); i++) {
findex = (17 + i * 23) % 40;
Convert::base40ToKern(buffer, findex+4*40);
if (buffer[0] == '\0') {
continue;
}
cout << buffer << "\t" << i << "\t" << findex
<< "\t";
if (invertQ) {
cout << 1.0/rootscores[(findex-2+40)%40] << endl;
} else {
cout << rootscores[(findex-2+40)%40] << endl;
}
}
}
//////////////////////////////
//
// 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("i|invert=b", "invert scores");
opts.define("d|distance=b", "display interval distances");
opts.define("t|theta|theta1=d:51.0", "chromatic plane angle");
opts.define("u|theta2=d:51.0", "chromatic plane angle 2");
opts.define("e|errors=b", "identify root errors in the input file");
opts.define("n|notes=b", "display note set for each chord");
opts.define("l|location=b", "display file and line for note sets");
opts.define("C|transpose=b", "transpose note displays to C root");
opts.define("s|single=b", "note display single pitch class");
opts.define("S|sort=b", "sort display of note by weights");
opts.define("c|circular=d:0.1","use circular space");
opts.define("p|power=d:1.0", "power of space");
opts.define("f|offset=d:0.0", "space weights offset");
opts.define("o|octave=d:0.0", "octave scaling");
opts.define("w|weight=s", "interval weight file");
opts.define("v|verbose=b", "display individual scores for each chord");
opts.define("spectrum=b", "root spectrum listing");
opts.define("r|rhythm=b", "apply rhythm scaling");
opts.define("dfactor|durationfactor=d:0.8", "duration scaling factor");
opts.define("lfactor|mfactor|metricfactor=d:0.5", "metric scaling factor");
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, June 2002" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 18 June 2002" << 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");
errorsQ = opts.getBoolean("errors");
distanceQ = opts.getBoolean("distance");
notesQ = opts.getBoolean("notes");
transposeQ = opts.getBoolean("transpose");
singleQ = opts.getBoolean("single");
sortQ = opts.getBoolean("sort");
locationQ = opts.getBoolean("location");
appendQ = opts.getBoolean("append");
theta1 = opts.getDouble("theta");
theta2 = opts.getDouble("theta2");
invertQ = opts.getBoolean("invert");
circularQ = opts.getBoolean("circular");
circular = opts.getDouble("circular");
power = opts.getDouble("power");
offset = opts.getDouble("offset");
weightQ = opts.getBoolean("weight");
weightFile = opts.getString("weight");
verboseQ = opts.getBoolean("verbose");
spectrumQ = opts.getBoolean("spectrum");
octaveQ = opts.getBoolean("octave");
octaveScale= opts.getDouble("octave");
rhythmQ = opts.getBoolean("rhythm");
durationfactor = opts.getDouble("durationfactor");
metricfactor = opts.getDouble("metricfactor");
}
//////////////////////////////
//
// 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;
}
//////////////////////////////
//
// base40ToBase7 -- Convert pitch to diatonic pitch
// .0 = natural
// .1 = sharp
// .2 = double sharp
// .9 = flat
// .8 = double flat
//
double base40ToBase7(int pitch) {
int octave = pitch / 40;
if (octave < 0) {
// rest
return -1;
}
switch (pitch % 40) {
case 0: return octave * 7 + 0.9; // C--
case 1: return octave * 7 + 0.8; // C-
case 2: return octave * 7 + 0.0; // C
case 3: return octave * 7 + 0.1; // C#
case 4: return octave * 7 + 0.2; // C##
case 5: return -1; // X
case 6: return octave * 7 + 1.9; // D--
case 7: return octave * 7 + 1.8; // D-
case 8: return octave * 7 + 1.0; // D
case 9: return octave * 7 + 1.1; // D#
case 10: return octave * 7 + 1.2; // D##
case 11: return -1; // X
case 12: return octave * 7 + 2.9; // E--
case 13: return octave * 7 + 2.8; // E-
case 14: return octave * 7 + 2.0; // E
case 15: return octave * 7 + 2.1; // E#
case 16: return octave * 7 + 2.2; // E##
case 17: return octave * 7 + 3.9; // F--
case 18: return octave * 7 + 3.8; // F-
case 19: return octave * 7 + 3.0; // F
case 20: return octave * 7 + 3.1; // F#
case 21: return octave * 7 + 3.2; // F##
case 22: return -1; // X
case 23: return octave * 7 + 4.9; // G--
case 24: return octave * 7 + 4.8; // G-
case 25: return octave * 7 + 4.0; // G
case 26: return octave * 7 + 4.1; // G#
case 27: return octave * 7 + 4.2; // G##
case 28: return -1; // X
case 29: return octave * 7 + 5.9; // A--
case 30: return octave * 7 + 5.8; // A-
case 31: return octave * 7 + 5.0; // A
case 32: return octave * 7 + 5.1; // A#
case 33: return octave * 7 + 5.2; // A##
case 34: return -1; // X
case 35: return octave * 7 + 6.9; // B--
case 36: return octave * 7 + 6.8; // B-
case 37: return octave * 7 + 6.0; // B
case 38: return octave * 7 + 6.1; // B#
case 39: return octave * 7 + 6.2; // B##
}
return -1;
}
//////////////////////////////
//
// base7pcToName -- base 7 pitch class name: C D E F G A B
//
char base7pcToName(int value) {
value = (value + 70) % 7;
switch (value) {
case 0: return 'C';
case 1: return 'D';
case 2: return 'E';
case 3: return 'F';
case 4: return 'G';
case 5: return 'A';
case 6: return 'B';
default: return 'X';
}
return 'X';
}
//////////////////////////////
//
// intcompare -- compare two integers for ordering
//
int intcompare(const void* a, const void* b) {
if (*((int*)a) < *((int*)b)) {
return -1;
} else if (*((int*)a) > *((int*)b)) {
return 1;
} else {
return 0;
}
}
//////////////////////////////
//
// pdlcompare -- compare two pitches for ordering in PDL structure
//
int pdlcompare(const void* a, const void* b) {
PDL& A = *((PDL*)a);
PDL& B = *((PDL*)b);
if (A.pitch < B.pitch) {
return -1;
} else if (A.pitch > B.pitch) {
return +1;
}
// pitches are the same, so sort by duration
if (A.duration < B.duration) {
return -1;
} else if (A.duration > B.duration) {
return +1;
}
// durations are the same, so sort by metric level
if (A.level < B.level) {
return -1;
} else if (A.level > B.level) {
return +1;
}
// notes are identical
return 0;
}
//////////////////////////////
//
// doublecompare -- compare two doubles for ordering
//
int doublecompare(const void* a, const void* b) {
if (*((double*)a) < *((double*)b)) {
return -1;
} else if (*((double*)a) > *((double*)b)) {
return 1;
} else {
return 0;
}
}
//////////////////////////////
//
// getStartingWeights --
//
void getStartingWeights(IntervalWeight& weights, HumdrumFile& weightfile) {
weights.setAll(100000);
int i, j;
int root;
double weight;
for (i=0; i<weightfile.getNumLines(); i++) {
root = -1;
weight = 10000;
if (!weightfile[i].isData()) {
continue;
}
for (j=0; j<weightfile[i].getFieldCount(); j++) {
if (strcmp("**kern", weightfile[i].getExInterp(j)) == 0) {
root = Convert::kernToBase40(weightfile[i][j]) % 40;
} else if (strcmp("**weight", weightfile[i].getExInterp(j)) == 0) {
weight = strtod(weightfile[i][j], NULL);
}
}
if (root >= 0) {
weights[root] = weight;
}
}
}
// md5sum: 1c40094e93425238fda57be67493bd5a iwroot.cpp [20050403]