//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Jan 20 15:21:48 PST 2011
// Last Modified: Thu Jan 20 15:21:50 PST 2011
// Filename: ...sig/examples/all/chordmark.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/chordmark.cpp
// Syntax: C++; museinfo
//
// Description: Add marks to notes according to their triadic position
// in a chord.
//
#include <math.h>
#ifndef OLDCPP
#include <iostream>
#include <sstream>
#define SSTREAM stringstream
#define CSTRING str().c_str()
using namespace std;
#else
#include <iostream.h>
#ifdef VISUAL
#include <strstrea.h>
#else
#include <strstream.h>
#endif
#define SSTREAM strstream
#define CSTRING str()
#endif
#include "humdrum.h"
#include "PerlRegularExpression.h"
//////////////////////////////////////////////////////////////////////////
// function declarations:
void checkOptions(Options& opts, int argc, char** argv);
void example(void);
void usage(const char* command);
void chordmark(HumdrumFile& infile);
void printHexColor(double color);
void printChordMarkInfo(Array<char>& marklevel,
Array<Array<double> >& levelcolor,
Array<int>& markused);
int getRootTrack(HumdrumFile& infile);
void markToken(HumdrumFile& infile, int line, int col,
int root);
void printSubToken(ostream& out, const char* token, int root);
int updateRoot(HumdrumFile& infile, int line, int root,
int track);
// User interface variables:
Options options;
int debugQ = 0; // used with --debug option
Array<char> marklevel;
Array<int> markused;
Array<Array<double> > levelcolor;
//////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
HumdrumFile infile;
// initial processing of the command-line options
checkOptions(options, argc, argv);
if (options.getArgCount() < 1) {
infile.read(cin);
} else {
infile.read(options.getArg(1));
}
chordmark(infile);
cout << infile;
printChordMarkInfo(marklevel, levelcolor, markused);
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printChordMarkInfo --
//
void printChordMarkInfo(Array<char>& marklevel,
Array<Array<double> >& levelcolor, Array<int>& markused) {
int i;
for (i=0; i<marklevel.getSize(); i++) {
if (marklevel[i] && markused[i]) {
cout << "!!!RDF**kern: " << marklevel[i] << "= mark color=\"#";
printHexColor(levelcolor[i][0]);
printHexColor(levelcolor[i][1]);
printHexColor(levelcolor[i][2]);
cout << "\"";
switch (i) {
case 0: cout << ", root"; break;
case 2: cout << ", third"; break;
case 4: cout << ", fifth"; break;
case 6: cout << ", seventh"; break;
case 1: cout << ", ninth/second"; break;
case 3: cout << ", eleventh/fourth"; break;
case 5: cout << ", thirteenth/sixth"; break;
}
cout << endl;
}
}
}
//////////////////////////////
//
// printHexColor --
//
void printHexColor(double color) {
if (color > 1.0) {
color = 1.0;
}
if (color < 0.0) {
color = 0.0;
}
int icol = (int)(255 * color);
int digit1 = icol / 16;
int digit2 = icol % 16;
char buffer[32] = {0};
sprintf(buffer, "%x%x", digit1, digit2);
cout << buffer;
}
//////////////////////////////
//
// chordmark -- add an up/down stem on notes in **kern data which do not
// already have stem information.
//
void chordmark(HumdrumFile& infile) {
int roottrack = getRootTrack(infile);
int curroot = -1;
int i, j;
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isData()) {
continue;
}
curroot = updateRoot(infile, i, curroot, roottrack);
if (curroot < 0) {
// current root is inactive, so don't try to mark notes
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
continue;
}
markToken(infile, i, j, curroot);
}
}
}
//////////////////////////////
//
// markToken --
//
void markToken(HumdrumFile& infile, int line, int col, int root) {
int& i = line;
int& j = col;
if (strcmp(infile[i][j], ".") == 0) {
// don't mark null tokens
return;
}
if (strchr(infile[i][j], 'r') != NULL) {
// don't mark rests
return;
}
if (root < 0) {
// root is invalid
return;
}
SSTREAM newmark;
int k;
char buffer[128] = {0};
int tcount = infile[i].getTokenCount(j);
for (k=0; k<tcount; k++) {
infile[i].getToken(buffer, j, k, 100);
printSubToken(newmark, buffer, root);
if (k < tcount - 1) {
newmark << ' ';
}
}
infile[i].changeField(j, newmark.CSTRING);
}
//////////////////////////////
//
// printSubToken --
//
void printSubToken(ostream& out, const char* token, int root) {
int diatonic = Convert::kernToDiatonicPitch(token) % 7;
int position = ((diatonic + 70) - root) % 7;
out << token;
if (marklevel[position]) {
markused[position]++;
out << marklevel[position];
}
}
//////////////////////////////
//
// updateRoot --
//
int updateRoot(HumdrumFile& infile, int line, int root, int track) {
int& i = line;
int j;
for (j=0; j<infile[i].getFieldCount(); j++) {
if (track != infile[i].getPrimaryTrack(j)) {
continue;
}
if (strcmp(infile[i][j], ".") == 0) {
// nothing to update with
return root;
}
if (strchr(infile[i][j], 'R') != NULL) {
// rest, return root off marker
return -1;
}
return Convert::kernToDiatonicPitch(infile[i][j]) % 7;
}
return root;
}
//////////////////////////////
//
// getRootTrack --
//
int getRootTrack(HumdrumFile& infile) {
int i, j;
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isInterpretation()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (infile[i].isExInterp(j, "**root")) {
return infile[i].getPrimaryTrack(j);
}
}
}
cerr << "Could not find root spine\n" << endl;
exit(1);
}
//////////////////////////////
//
// checkOptions --
//
void checkOptions(Options& opts, int argc, char** argv) {
opts.define("d|debug=b", "Debugging information");
opts.define("author=b", "Program author");
opts.define("version=b", "Program version");
opts.define("example=b", "Program examples");
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, December 2010" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 26 December 2010" << 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");
marklevel.setSize(7);
marklevel.allowGrowth(0);
marklevel.setAll(0);
markused.setSize(7);
markused.allowGrowth(0);
markused.setAll(0);
levelcolor.setSize(7);
levelcolor.allowGrowth(0);
int i;
for (i=0; i<levelcolor.getSize(); i++) {
levelcolor[i].setSize(3);
levelcolor[i].allowGrowth(0);
levelcolor[i].setAll(0);
}
// default coloring:
marklevel[0] = 'N';
marklevel[2] = 'U';
marklevel[4] = 'Z';
// Root = red
levelcolor[0][0] = 1.0;
levelcolor[0][1] = 0.0;
levelcolor[0][2] = 0.0;
// third = green
levelcolor[2][0] = 0.0;
levelcolor[2][1] = 0.7;
levelcolor[2][2] = 0.0;
// fifth = blue
levelcolor[4][0] = 0.0;
levelcolor[4][1] = 0.7;
levelcolor[4][2] = 0.0;
// seventh = fuchsia
levelcolor[6][0] = 1.0;
levelcolor[6][1] = 0.0;
levelcolor[6][2] = 1.0;
// ninth/second = orange
levelcolor[1][0] = 1.0;
levelcolor[1][1] = 0.4;
levelcolor[1][2] = 0.0;
// eleventh/fourth = light blue
levelcolor[3][0] = 0.0;
levelcolor[3][1] = 1.0;
levelcolor[3][2] = 1.0;
// thirteenth/sixth = purple
levelcolor[5][0] = 0.5;
levelcolor[5][1] = 0.0;
levelcolor[5][2] = 0.6;
}
//////////////////////////////
//
// example -- example function calls to the program.
//
void example(void) {
}
//////////////////////////////
//
// usage -- command-line usage description and brief summary
//
void usage(const char* command) {
}
// md5sum: c8dee3aebc50cc0e6bf41b03d4397fad chordmark.cpp [20110206]