//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sun Feb 11 15:15:53 PST 2001
// Last Modified: Sat Feb 17 09:52:27 PST 2001
// Last Modified: Fri Apr 6 14:54:35 PDT 2001 (added revised algorithm)
// Filename: ...sig/examples/all/keyscape.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/keyscape.cpp
// Syntax: C++; museinfo
//
// Description: generate a key landscape picture or numeric data.
//
#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 makeGrayscale(void);
void processMatrix(Array<ArrayInt>& matrix);
void printMatrix(Array<ArrayInt>& matrix);
void printTriangle(Array<ArrayInt>& matrix);
void printPPM(Array<ArrayInt>& matrix);
void printAveragePPM(Array<ArrayInt>& matrix);
// global variables
Options options; // database for command-line arguments
int debugQ = 0; // used with the --debug option
int compoundQ = 1; // used with the -c option
double empirical1 = -4; // used with the --e1 option
double empirical2 = -3; // used with the --e2 option
double sx = 0.578; // used with the --sx option
double sy = 1.0; // used with the --sx option
int ppmQ = 0; // used with the --ppm option
int ppmWidth = 1000; // used with the -m option
int ppmHeight = 500; // used with the -t option
int linearQ = 0; // used with the -l option
int monochromeQ = 0; // used with the -b option
int matrixQ = 0; // used with the -x option
int mirrorQ = 0; // used with the --mirror option
int maxdivisions = -1; // used with the -d option
int averageQ = 0; // used with the -a option
int algorithm = 0; // used with the -2 option
///////////////////////////////////////////////////////////////////////////
// Pitch to Color translations
int red[40] = {
0, 9, 18, 0, 63, 63, 63, 73, 82, 0, 218, 237, 255, 255, 255,
255, 255, 255, 218, 182, 0, 45, 54, 63, 63, 63, 0, 109, 118,
127, 145, 164, 0, 255, 255, 255, 255, 255, 73, 36
};
int green[40] = {
255, 246, 237, 0, 123, 109, 95, 86, 77, 0, 9, 4, 0, 18, 36, 218,
237, 255, 255, 255, 0, 209, 200, 191, 177, 164, 0, 50, 41, 31,
27, 22, 0, 91, 109, 127, 145, 164, 255, 255
};
int blue[40] = {
0, 36, 73, 0, 255, 255, 255, 255, 255, 0, 73, 36, 0, 0, 0, 0,
0, 0, 0, 0, 0, 182, 218, 255, 255, 255, 0, 255, 255, 255, 219,
182, 0, 0, 0, 0, 0, 0, 0, 0
};
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile; // input Humdrum Format file
Array<int> rhylev; // storage for metrical level analysis
Array<double> tonicscores; // storage for root scores
tonicscores.setSize(0);
Array<ArrayInt> matrix; // storage for root analysis results
// process the command-line options
checkOptions(options, argc, argv);
// figure out the number of input files to process
int numinputs = options.getArgCount();
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("4"); // force the beat to be quarter notes for now
infile.analyzeMetricLevel(rhylev);
double duration = infile.getTotalDuration();
int totalrows = (int)duration;
if (maxdivisions > 0 && totalrows > maxdivisions) {
totalrows = maxdivisions;
}
int j, k;
matrix.setSize(totalrows);
for (k=0; k<totalrows; k++) {
matrix[k].setSize(totalrows);
matrix[k].allowGrowth(0);
for (j=0; j<totalrows; j++) {
matrix[k][j] = -1;
}
}
double startbeat; // absolute start beat of analysis
double stopbeat; // absolute ending beat of analysis
for (j=0; j<totalrows; j++) {
for (k=0; k<=j; k++) {
startbeat = duration/(j+1) * k;
stopbeat = duration/(j+1) * (k+1);
matrix[j][k] = infile.analyzeChordProbabilityDur(tonicscores,
startbeat, stopbeat, rhylev, empirical1, empirical2, sx, sy);
}
}
if (matrixQ) {
printMatrix(matrix);
} else if (ppmQ) {
if (averageQ) {
printAveragePPM(matrix);
} else {
printPPM(matrix);
}
} else {
printTriangle(matrix);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printPPM --
//
void printPPM(Array& matrix) {
int row, column;
int maxrow = ppmHeight;
int maxcolumn = ppmWidth;
int size = matrix.getSize();
int i, j;
int root;
cout << "P3\n";
cout << maxcolumn << " " << maxrow << "\n";
cout << "255\n";
for (row=0; row<maxrow; row++) {
if (linearQ) {
i = (int)(size * (double)row/maxrow);
} else {
i = size - (int)(size *
log10((double)(maxrow-row))/log10((double)(maxrow+1))) - 1;
}
for (column=0; column<maxcolumn; column++) {
j = (int)(i * (double)column/maxcolumn);
root = matrix[i][j];
if (root >= 0) {
cout << red[root] << " "
<< green[root] << " "
<< blue[root] << " ";
} else {
cout << " 0 0 0 ";
}
}
cout << "\n";
}
}
//////////////////////////////
//
// printAveragePPM --
//
void printAveragePPM(Array& matrix) {
int row, column;
int maxrow = ppmHeight;
int maxcolumn = ppmWidth;
int size = matrix.getSize();
int i, j;
int root;
cout << "P3\n";
cout << maxcolumn << " " << maxrow << "\n";
cout << "255\n";
Array<double> redsum(maxcolumn);
Array<double> greensum(maxcolumn);
Array<double> bluesum(maxcolumn);
redsum.allowGrowth(0);
greensum.allowGrowth(0);
bluesum.allowGrowth(0);
redsum.zero();
greensum.zero();
bluesum.zero();
for (row=0; row<maxrow; row++) {
if (linearQ) {
i = (int)(size * (double)row/maxrow);
} else {
i = size - (int)(size * log10((double)(maxrow-row)) /
log10((double)(maxrow+1))) - 1;
}
for (column=0; column<maxcolumn; column++) {
j = (int)(i * (double)column/maxcolumn);
root = matrix[i][j];
if (root >= 0) {
redsum[column] += red[root];
greensum[column] += green[root];
bluesum[column] += blue[root];
}
}
}
for (i=0; i<redsum.getSize(); i++) {
redsum[i] /= maxrow;
greensum[i] /= maxrow;
bluesum[i] /= maxrow;
}
for (row=0; row<maxrow; row++) {
for (column=0; column<maxcolumn; column++) {
cout << (int)redsum[column] << " "
<< (int)greensum[column] << " "
<< (int)bluesum[column] << " ";
}
cout << "\n";
}
}
//////////////////////////////
//
// printTriangle --
//
void printTriangle(Array& matrix) {
int i, j;
int size = matrix.getSize();
for (i=0; i<size; i++) {
cout << i+1;
for (j=0; j<=i; j++) {
cout << "\t" << matrix[i][j];
}
cout << "\n";
}
}
//////////////////////////////
//
// printMatrix --
//
void printMatrix(Array& matrix) {
processMatrix(matrix);
int i, j;
int size = matrix.getSize();
for (i=0; i<size; i++) {
for (j=0; j<size; j++) {
cout << matrix[i][j];
if (j < size-1) {
cout << "\t";
}
}
cout << "\n";
}
}
//////////////////////////////
//
// processMatrix --
//
void processMatrix(Array& matrix) {
int i, j;
int size = matrix.getSize();
for (i=0; i<size; i++) {
for (j=0; j<i; j++) {
if (mirrorQ) {
matrix[i-j-1][i] = matrix[i][j];
} else {
matrix[j][i] = matrix[i][j];
}
}
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("C|compound=b", "don't try to use compound meters");
opts.define("r|rhythm=i:4", "rhythm to measure root at");
opts.define("e1|empirical1=d:-4", "empirical rhythm value 1");
opts.define("e2|empirical2=d:-3", "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("2=b", "0 = old algorithm, 1 = new algorithm");
opts.define("ppm=b", "generate a ppm graphic lanscape image");
opts.define("w|width=i:1000", "width of ppm image");
opts.define("t|height=i:500", "height of ppm image");
opts.define("l|linear=b", "linear plot instead of logarithmic");
opts.define("b|monochrome=b", "use black and white instead of color");
opts.define("x|matrix=b", "generate a matrix rather than a table");
opts.define("mirror=b","generate mirror matrix rather than cyclical matrix");
opts.define("d|divisions=i:-1", "the maximum number of divisions");
opts.define("a|average=b","generate average key picture");
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: 6 Dec 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("2")) {
algorithm = 1;
} else {
algorithm = 0;
}
debugQ = opts.getBoolean("debug");
if (opts.getBoolean("compound")) {
compoundQ = 0;
} else {
compoundQ = 0;
}
empirical1 = opts.getDouble("empirical1");
empirical2 = opts.getDouble("empirical2");
sx = opts.getDouble("sx");
sy = opts.getDouble("sy");
ppmQ = opts.getBoolean("ppm");
ppmWidth = opts.getInteger("width");
ppmHeight = opts.getInteger("height");
linearQ = opts.getBoolean("linear");
matrixQ = opts.getBoolean("matrix");
mirrorQ = opts.getBoolean("mirror");
maxdivisions = opts.getInteger("divisions");
averageQ = opts.getBoolean("average");
if (opts.getBoolean("monochrome")) {
makeGrayscale();
}
}
//////////////////////////////
//
// 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;
}
//////////////////////////////
//
// makeGrayscale --
//
void makeGrayscale(void) {
for (int i=0; i<40; i++) {
red[i] = (int)((i+1.0)/40.0);
green[i] = red[i];
blue[i] = red[i];
}
}
// md5sum: 6b9ff0e87377713fd0f1968347abfb40 keyscape.cpp [20080227]