//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Fri Mar 4 07:02:41 PST 2011
// Last Modified: Fri Mar 4 07:02:43 PST 2011
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/hexa.cpp
// Syntax: C++; museinfo
//
// Description: Describe the hexachord position of notes.
//
#include <math.h>
#include <time.h> /* for current time/date */
#ifndef OLDCPP
#include <iostream>
#include <fstream>
#include <sstream>
#define SSTREAM stringstream
#define CSTRING str().c_str()
using namespace std;
#else
#include <iostream.h>
#include <fstream.h>
#ifdef VISUAL
#include <strstrea.h>
#else
#include <strstream.h>
#endif
#define SSTREAM strstream
#define CSTRING str()
#endif
#include "string.h"
#include "humdrum.h"
#include "PerlRegularExpression.h"
#include "MuseData.h"
#include "MuseDataSet.h"
#include "CheckSum.h"
#include "SigString.h"
//////////////////////////////////////////////////////////////////////////
// function declarations:
void checkOptions(Options& opts, int argc, char** argv);
void example(void);
void usage(const char* command);
void extractPitches(Array<Array<Array<int> > >& pitches,
HumdrumFile& infile);
void printData(Array<Array<Array<int> > >& pitches,
HumdrumFile& infile);
void printLine(HumdrumFile& infile, int line,
Array<Array<Array<int> > >& pitches,
int offset);
void printDataToken(Array<Array<Array<int> > >& pitches,
int line, int col, char prefix, int interval);
void printKernTokenAndData(HumdrumFile& infile, int line, int col,
Array<Array<Array<int> > >& pitches,
int offset);
char hexPos(int interval);
void printSingleColumnLine(HumdrumRecord& arecord, int offset);
// User interface variables:
Options options;
int debugQ = 0; // used with --debug option
//////////////////////////////////////////////////////////////////////////
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));
}
infile.analyzeRhythm("4");
Array<Array<Array<int> > > pitches;
extractPitches(pitches, infile);
printData(pitches, infile);
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printData --
//
void printData(Array > >& pitches, HumdrumFile& infile) {
int i;
int offset = 75;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isData() || infile[i].isLocalComment() ||
infile[i].isInterpretation() || infile[i].isMeasure()) {
printLine(infile, i, pitches, offset);
} else {
printSingleColumnLine(infile[i], offset);
}
}
}
//////////////////////////////
//
// printSingleColumnLine -- add extract space between staves to allow
// for printing of analysis data.
//
void printSingleColumnLine(HumdrumRecord& arecord, int offset) {
PerlRegularExpression pre;
pre.search(arecord[0], "(.*muse2ps.*)(v[0-9,]+)(.*)", "");
if (strlen(pre.getSubmatch(2)) == 0) {
cout << arecord[0] << "\n";
return;
}
Array<char> pos;
pos.setSize(strlen(pre.getSubmatch(2))+1);
strcpy(pos.getBase(), pre.getSubmatch());
Array<Array<char> > tokens;
PerlRegularExpression pre2;
pre2.getTokens(tokens, "[v,\\s]+", pre.getSubmatch());
int value;
cout << pre.getSubmatch(1);
cout << "v";
int i;
for (i=0; i<tokens.getSize(); i++) {
value = atoi(tokens[i].getBase());
value += offset;
cout << value;
if (i<tokens.getSize()) {
cout << ",";
}
}
cout << pre.getSubmatch(3);
cout << "\n";
}
//////////////////////////////
//
// printLine --
//
void printLine(HumdrumFile& infile, int line,
Array<Array<Array<int> > >& pitches, int offset) {
int& i = line;
int j;
int started = 0;
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
if (started) {
cout << "\t";
}
started = 1;
cout << infile[i][j];
continue;
} else {
if (started) {
cout << "\t";
}
started = 1;
printKernTokenAndData(infile, i, j, pitches, offset);
}
}
cout << "\n";
}
//////////////////////////////
//
// printKernTokenAndData --
//
void printKernTokenAndData(HumdrumFile& infile, int line, int col,
Array<Array<Array<int> > >& pitches, int offset) {
int& i = line;
int& j = col;
int m;
PerlRegularExpression pre;
Array<char> strang;
strang.setSize(strlen(infile[i][j])+1);
strcpy(strang.getBase(), infile[i][j]);
if (pre.search(strang, "^(!LO:TX.*Y=)(\\d+)(.*)")) {
// text printed below the staff, but need to drop it so that
// it does not collide with the text (which cannot be adjsted
// in muse2ps).
cout << pre.getSubmatch(1);
int value = atoi(pre.getSubmatch(2));
// value = -50;
cout << value;
cout << ":hide"; // just hide text so that it is not displayed
cout << pre.getSubmatch(3);
} else {
cout << strang;
}
if (infile[i].isLocalComment()) {
for (m=0; m<3; m++) {
cout << "\t!";
}
return;
}
if (infile[i].isMeasure()) {
for (m=0; m<3; m++) {
cout << "\t" << infile[i][j];
}
return;
}
if (infile[i].isInterpretation()) {
if (strncmp(infile[i][j], "**", 2) == 0) {
for (m=0; m<3; m++) {
cout << "\t**hexa";
}
return;
}
if (strcmp(infile[i][j], "*-") == 0) {
for (m=0; m<3; m++) {
cout << "\t*-";
}
return;
}
for (m=0; m<3; m++) {
cout << "\t*";
}
return;
}
char prefix[3] = {'f', 'c', 'g'};
int interval[3] = {17, 0, 23};
for (m=0; m<3; m++) {
cout << "\t";
printDataToken(pitches, line, col, prefix[m], interval[m]);
}
}
//////////////////////////////
//
// printDataToken --
//
void printDataToken(Array<Array<Array<int> > >& pitches, int line, int col,
char prefix, int interval) {
int& i = line;
int& j = col;
int k;
char pos;
if (pitches[i][j].getSize() == 0) {
cout << ".";
return;
}
for (k=0; k<pitches[i][j].getSize(); k++) {
if (k > 0) {
cout << " ";
}
pos = hexPos((pitches[line][col][k] - (2 + interval)) % 40);
cout << prefix << pos;
}
}
//////////////////////////////
//
// hexPos --
//
char hexPos(int interval) {
switch (interval) {
case 0: return '1';
case 6: return '2';
case 12: return '3';
case 17: return '4';
case 23: return '5';
case 29: return '6';
}
return 'X';
}
//////////////////////////////
//
// extractPitches --
//
void extractPitches(Array > >& pitches, HumdrumFile& infile) {
pitches.setSize(infile.getNumLines());
PerlRegularExpression pre;
int i, j, k;
int value;
int tokencount;
char buffer[1024] = {0};
for (i=0; i<infile.getNumLines(); i++) {
pitches[i].setSize(infile[i].getFieldCount());
for (j=0; j<pitches[i].getSize(); j++) {
pitches[i][j].setSize(0);
}
if (!infile[i].isData()) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
continue;
}
if (strcmp(infile[i][j], ".") == 0) {
// ignore null tokens
continue;
}
if (strchr(infile[i][j], 'r') != NULL) {
// ignore rests
continue;
}
if (strchr(infile[i][j], ']') != NULL) {
// ignore endings of ties
continue;
}
if (strchr(infile[i][j], '_') != NULL) {
// ignore middle notes of ties
continue;
}
tokencount = infile[i].getTokenCount(j);
for (k=0; k<tokencount; k++) {
infile[i].getToken(buffer, j, k);
if (!pre.search(buffer, "[a-g]", "i")) {
// ignore subtoken: missing a pitch name.
continue;
}
value = Convert::kernToBase40(buffer);
pitches[i][j].append(value);
}
}
}
}
//////////////////////////////
//
// 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, March 2011" << "\n";
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 4 March 2011" << "\n";
cout << "compiled: " << __DATE__ << "\n";
cout << MUSEINFO_VERSION << "\n";
exit(0);
} else if (opts.getBoolean("help")) {
usage(opts.getCommand());
exit(0);
} else if (opts.getBoolean("example")) {
example();
exit(0);
}
debugQ = opts.getBoolean("debug");
}
//////////////////////////////
//
// example -- example function calls to the program.
//
void example(void) {
}
//////////////////////////////
//
// usage -- command-line usage description and brief summary
//
void usage(const char* command) {
}
// md5sum: 8ac674bbee352e5eee29d3d12df21e8a hexa.cpp [20110308]