//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Tue Aug 30 10:51:26 PDT 2011
// Last Modified: Fri Sep 2 18:25:34 PDT 2011
// Last Modified: Tue Sep 13 13:33:52 PDT 2011 added -k option
// Last Modified: Thu Sep 15 01:36:49 PDT 2011 added -D option
// Last Modified: Thu Oct 20 22:23:27 PDT 2011 fixed init bug
// Filename: ...sig/examples/all/notearray.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/notearray.cpp
// Syntax: C++; museinfo
//
// Description: Generate a two-dimensional numeric array containing
// notes in the score in base-40, base-12, or base-7
// representation. Each data line represents a sonority
// with attacked notes in that sonority being positive
// numbers, and sustained notes from previous sonorities
// being negative.
//
#include "humdrum.h"
#ifndef OLDCPP
#include <iostream>
using namespace std;
#else
#include <iostream.h>
#endif
#define STYLE_BASE40 40
#define STYLE_BASE12 12
#define STYLE_BASE7 7
#define TYPE_MIN 999
#define TYPE_NOTES 1000
#define TYPE_KERN 1000
#define TYPE_LINE (2000-1) /* +1 will be added later to make 2000 */
#define TYPE_MEASURE 3000
#define TYPE_BEAT 4000
#define TYPE_ABSOLUTE 5000
#define TYPE_LINEDUR 6000
#define TYPE_ATTACK 7100
#define TYPE_LAST 7200
#define TYPE_NEXT 7300
// function declarations
void getNoteArray(Array<Array<int> >& notes, Array<int>& measpos,
Array<int>& linenum, HumdrumFile& infile,
int base, int flags);
void printNoteArray(Array<Array<int> >& notes, Array<int>& measpos,
Array<int>& linenum, HumdrumFile& infile);
void printComments(HumdrumFile& infile, int startline, int stopline,
int style);
void printExclusiveInterpretations(int basecount);
void printLine(Array<Array<int> >& notes,
Array<Array<int> >& attacks,
Array<Array<int> >& lasts,
Array<Array<int> >& nexts, Array<int>& measpos,
Array<int>& linenum, HumdrumFile& infile,
int index, int style);
void usage(const char* command);
void example(void);
void checkOptions(Options& opts, int argc, char* argv[]);
void getNoteAttackIndexes(Array<Array<int> >& attacks,
Array<Array<int> >& notes, int offst);
void getLastAttackIndexes(Array<Array<int> >& lasts,
Array<Array<int> >& notes, int offset);
void getNextAttackIndexes(Array<Array<int> >& lasts,
Array<Array<int> >& notes, int offset);
int noteStartMarker(Array<Array<int> >& notes, int line, int column);
int noteEndMarker(Array<Array<int> >& notes, int line, int column);
int noteContinueMarker(Array<Array<int> >& notes, int line, int column);
int singleNote(Array<Array<int> >& notes, int line, int column);
// global variables
Options options; // database for command-line arguments
int humdrumQ = 0; // used with -H option
int base7Q = 0; // used with -d option
int base12Q = 0; // used with -m option
int base40Q = 1; // default output type
int base = STYLE_BASE40;
int measureQ = 1; // used with -M option
int beatQ = 1; // used with -B option
int commentQ = 1; // used with -C option
int rationalQ = 0; // used with -r option
int fractionQ = 0; // used with -f option
int absoluteQ = 0; // used with -a option
int linedurQ = 0; // used with -D option
int doubleQ = 0; // used with --double option
int lineQ = 0; // used with -l option
int mathQ = 0; // used with --mathematica option
int susxQ = 1; // used with -S option
int bibQ = 0; // used with -b option
int infoQ = 1; // used with -I option
int octadj = 0; // used with -o option
int endQ = 0; // used with -e option
int typeQ = 0; // used with -c option
int oneQ = 0; // used with -1 option
int sepQ = 0; // used with --sep option
int Offset = 0; // used with -1/--offset option
int OffsetSum = 0; // used for multiple input files
int attackQ = 0; // used with --attack option
int nextQ = 0; // used with --last option
int lastQ = 0; // used with --next option
int indexQ = 0; // used with -i option
int saQ = 0; // used with --sa option
int quoteQ = 0; // used with --quote option
int Count = 0; // count of how many input files
int Current = 0; // used with --math option
int moQ = 0; // used with --mo option
int Measure = 0; // additive value for measure number
int Mincrement= 0; // used to increment between pieces/movements
int kernQ = 0; // used with -k option
int kerntieQ = 1; // used with --no-tie option
int doubletieQ= 0; // used with -T option
RationalNumber Absoffset; // used with --sa option
const char* commentStart = "#";
const char* commentStop = "";
const char* mathvar = "data"; // used with --mathematica option
const char* beatbase = ""; // used with -t option
///////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
Array<Array<int> > notelist;
Array<double> metpos;
Array<int> measpos;
Array<int> linenum;
HumdrumFile infile;
// process the command-line options
checkOptions(options, argc, argv);
// figure out the number of input files to process
int numinputs = options.getArgCount();
Count = numinputs;
Absoffset = 0;
for (int i=0; i<numinputs || i==0; i++) {
Current = i;
if (moQ) {
Measure = (i+1) * Mincrement;
}
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));
}
// analyze the input file according to command-line options
infile.analyzeRhythm(beatbase);
getNoteArray(notelist, measpos, linenum, infile, base, doubleQ);
printNoteArray(notelist, measpos, linenum, infile);
OffsetSum += notelist.getSize();
if (!saQ) {
Absoffset += infile.getTotalDurationR();
}
if (sepQ && (Count > 1) && (Current < Count - 1)) {
// add a separate between input file analyses:
if (mathQ) {
cout << "(* ********** *)\n";
} else if (humdrumQ) {
cout << "!!!!!!!!!!\n";
} else {
cout << "##########\n";
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// getNoteArray --
// style:
// STYLE_BASE40 40: print as base-40 pitches
// STYLE_BASE12 12: print as base-12 pitches
// STYLE_BASE7 7: print as base-7 pitches
//
// flags:
// 0: all off:
// 1: turn on double-barline rest markers.
//
void getNoteArray(Array<Array<int> >& notes, Array<int>& measpos,
Array<int>& linenum, HumdrumFile& infile, int style, int flags) {
notes.setSize(infile.getNumLines());
notes.setSize(0);
measpos.setSize(infile.getNumLines());
measpos.setSize(0);
linenum.setSize(infile.getNumLines());
linenum.setSize(0);
int measnum = 0;
int rest = 0;
int i, j, ii, jj;
int negQ = 0;
// prestorage for note lists so that --no-sustain option can be applied
Array<int> templist;
templist.setSize(1000);
templist.setSize(0);
Array<int> templistI;
templistI.setSize(1000);
templistI.setSize(0);
int value;
int firstQ = 1;
if (typeQ) {
// store even if lineQ is zero!
value = TYPE_LINE;
linenum.append(value);
}
if (typeQ) {
value = TYPE_MEASURE;
measpos.append(value);
}
// increment measure number in case of pickups
measnum = Measure;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isMeasure()) {
if (doubleQ && (templist.getSize() == 0)) {
if (strstr(infile[i][0], "||") != NULL) {
// insert a rest sonority to break music
// from previous measure
notes.setSize(notes.getSize() + 1);
notes.last().setSize(infile[i].getFieldCount());
notes.last().setSize(0);
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
continue;
}
notes.last().append(rest);
linenum.append(i);
}
measpos.append(measnum);
}
}
// store new measure number (avoiding double code above)
sscanf(infile[i][0], "=%d", &measnum);
measnum += Measure;
}
if (!infile[i].isData()) {
continue;
}
templist.setSize(0);
for (j=0; j<infile[i].getFieldCount(); j++) {
if (!infile[i].isExInterp(j, "**kern")) {
continue;
}
if (strchr(infile[i].getSpineInfo(j), 'b') != NULL) {
// ignore notes non-primary tracks
continue;
}
int attack = 1;
if (strcmp(infile[i][j],".")==0) {
attack = -1;
ii = infile[i].getDotLine(j);
jj = infile[i].getDotSpine(j);
} else {
ii = i;
jj = j;
}
int baseval = Convert::kernToBase40(infile[ii][jj]);
baseval += 40 * octadj;
if (strchr(infile[ii][jj], 'r') != NULL) {
baseval = 0;
} else {
// now storing base-40, and converting to base-12/base-7 later
// switch (style) {
// case STYLE_BASE12:
// baseval = Convert::base40ToMidiNoteNumber(baseval);
// break;
// case STYLE_BASE7:
// baseval = Convert::base40ToDiatonic(baseval);
// break;
// }
}
baseval = attack * baseval;
templist.append(baseval);
}
negQ = 1;
if (susxQ) {
// if all notes are negative, then do not store the line
for (int m=0; m<templist.getSize(); m++) {
if (templist[m] >= 0) {
negQ = 0;
break;
}
}
if (negQ) {
continue;
}
}
if (firstQ && typeQ) {
firstQ = 0;
templistI.setSize(templist.getSize());
int value = TYPE_NOTES;
switch (style) {
case STYLE_BASE40: value += 40; break;
case STYLE_BASE12: value += 12; break;
case STYLE_BASE7: value += 7; break;
}
templistI.setAll(value);
notes.increase();
notes.last() = templistI;
}
notes.increase();
notes.last() = templist;
measpos.append(measnum);
linenum.append(i);
}
if (endQ) {
notes.increase();
notes.last().setSize(notes.last(-1).getSize());
notes.last().zero();
// sustains instead of rests (have to copy .last(-1):
// for (i=0; i<notes.last().getSize(); i++) {
// if (notes.last()[i] > 0) {
// notes.last()[i] *= -1;
// }
// }
measpos.append(measpos.last());
linenum.append(linenum.last());
// store the data termination line as the line number of the sonority
for (i=infile.getNumLines()-1; i>=0; i--) {
if (infile[i].isInterpretation()) {
linenum.last() = i;
break;
}
}
// increment the measure number if the beat of the end
// is at 1. This will work unless the last sonority is a
// grace note.
if (infile[linenum.last()].getBeat() == 1.0) {
measpos.last()++;
}
}
}
//////////////////////////////
//
// printNoteArray --
//
void printNoteArray(Array<Array<int> >& notes, Array<int>& measpos,
Array<int>& linenum, HumdrumFile& infile) {
linenum.allowGrowth(0);
measpos.allowGrowth(0);
notes.allowGrowth(0);
Array<Array<int> > attacks;
Array<Array<int> > lasts;
Array<Array<int> > nexts;
if (attackQ) {
getNoteAttackIndexes(attacks, notes, Offset + OffsetSum);
}
if (lastQ) {
getLastAttackIndexes(lasts, notes, Offset + OffsetSum);
}
if (nextQ) {
getNextAttackIndexes(nexts, notes, Offset + OffsetSum);
}
int i, j;
for (i=0; i<notes.getSize(); i++) {
if (i == 0) {
if (commentQ && !typeQ) {
printComments(infile, 0, linenum[0], humdrumQ);
} else if (commentQ && typeQ) {
printComments(infile, 0, linenum[1], humdrumQ);
}
if (infoQ) {
printExclusiveInterpretations(notes[0].getSize());
} else if (humdrumQ) {
// always print exclusive interpretations if Humdrum output
printExclusiveInterpretations(notes[0].getSize());
}
if (mathQ) {
if (Count <= 1) {
cout << mathvar << " = {\n";
} else if (Current == 0) {
cout << mathvar << " = {{\n";
} else {
cout << "}, {\n";
}
}
} else if (commentQ) {
printComments(infile, linenum[i-1]+1, linenum[i], humdrumQ);
}
if (typeQ && i == 0) {
printLine(notes, attacks, lasts, nexts, measpos, linenum, infile,i,1);
} else {
printLine(notes, attacks, lasts, nexts, measpos, linenum, infile,i,0);
}
}
if (humdrumQ) {
int width = 1;
if (attackQ) { width++; }
if (lastQ) { width++; }
if (nextQ) { width++; }
if (kernQ) { width++; }
int counter = notes[0].getSize();
counter *= width;
counter += indexQ + lineQ + measureQ + beatQ + absoluteQ + linedurQ;
// if (attackQ) { counter += notes[0].getSize(); }
// if (lastQ) { counter += notes[0].getSize(); }
// if (nextQ) { counter += notes[0].getSize(); }
for (j=0; j<counter; j++) {
cout << "*-";
if (j < counter-1) {
cout << "\t";
}
}
cout << endl;
}
if (mathQ) {
if (Count <= 1) {
cout << "};\n";
} else if (Current <= Count - 2) {
// cout << "}},\n";
} else if (Current == Count - 1) {
cout << "}};\n";
}
}
if (commentQ) {
printComments(infile, linenum.last(), infile.getNumLines()-1, humdrumQ);
}
}
//////////////////////////////
//
// getLastAttackIndexes -- return an index of the attack portion
// of notes (or the first rest in a series of rests) in each voice.
//
void getLastAttackIndexes(Array<Array<int> >& lasts,
Array<Array<int> >& notes, int offset) {
int start = 0;
lasts.setSize(notes.getSize());
if (typeQ) {
lasts[0].setAll(TYPE_LAST);
start = 1;
}
int i, j;
lasts[start].setAll(-1);
if (notes.getSize() == start+1) {
return;
}
Array<int> states;
states.setSize(notes[0].getSize());
if (typeQ) {
states.setAll(offset+1);
} else {
states.setAll(offset);
}
for (i=0; i<notes.getSize(); i++) {
lasts[i].setSize(notes[i].getSize());
if (i <= start) {
lasts[i].setAll(-1);
if (typeQ && (i==0)) {
lasts[i].setAll(TYPE_LAST);
}
continue;
}
for (j=0; j<notes[i].getSize(); j++) {
if (notes[i][j] > 0) {
// a new note attack, store the note attack index in
// the states array after recording the index of the previous note
lasts[i][j] = states[j];
states[j] = i + offset;
} else if (notes[i][j] < 0) {
// note is sustaining, so copy the index of the last attack
// from the previous line
if (i > start) {
lasts[i][j] = lasts[i-1][j];
} else {
lasts[i][j] = -1;
}
} else {
// rest: if last line was a rest then this is a rest sustain:
if (i > start) {
if (notes[i-1][j] == 0) {
// rest sustain
lasts[i][j] = lasts[i-1][j];
} else {
// rest attack
lasts[i][j] = states[j];
states[j] = i + offset;
}
} else {
lasts[i][j] = -1;
}
}
}
}
}
//////////////////////////////
//
// getNextAttackIndexes -- return an index of the attack portion
// of notes (or the first rest in a series of rests) in each voice.
//
void getNextAttackIndexes(Array<Array<int> >& nexts,
Array<Array<int> >& notes, int offset) {
int start = 0;
nexts.setSize(notes.getSize());
if (typeQ) {
nexts[0].setSize(notes[0].getSize());
nexts[0].setAll(TYPE_NEXT);
start = 1;
}
int i, j;
nexts.last().setSize(notes.last().getSize());
nexts.last().setAll(-1);
if (notes.getSize() == start+1) {
return;
}
for (i=notes.getSize()-2; i>=start; i--) {
nexts[i].setSize(notes[i].getSize());
for (j=0; j<notes[i].getSize(); j++) {
if ((notes[i][j] != 0) && (notes[i+1][j] == 0)) {
// next note is a "rest attack"
nexts[i][j] = i + 1 + offset;
} else if (notes[i+1][j] > 0) {
// a new note attack, store the note attack index in
// the states array after recording the index of the previous note
nexts[i][j] = i + 1 + offset;
} else {
nexts[i][j] = nexts[i+1][j];
}
}
}
}
//////////////////////////////
//
// getNoteAttackIndexes -- return an index of the attack portion
// of notes (or the first rest in a series of rests) in each voice.
//
void getNoteAttackIndexes(Array<Array<int> >& attacks,
Array<Array<int> >& notes, int offset) {
attacks.setSize(notes.getSize());
int i, j;
attacks[0].setSize(notes[0].getSize());
attacks[0].setAll(offset);
for (i=1; i<attacks.getSize(); i++) {
attacks[i].setSize(notes[i].getSize());
attacks[i].allowGrowth(0);
for (j=0; j<attacks[i].getSize(); j++) {
if (notes[i][j] < 0) {
// a sustained note, so store index of attack note
attacks[i][j] = attacks[i-1][j];
} else if (notes[i][j] > 0) {
// note being attacked, so store its index
attacks[i][j] = i + offset;
} else {
// a rest: check to see if last position was a rest.
// if so, then this is a "tied rest"; otherwise it is
// a "attacked rest".
if (notes[i-1][j] == 0) {
attacks[i][j] = attacks[i-1][j];
} else {
attacks[i][j] = i + offset;
}
}
}
}
if (typeQ) {
attacks[0].setAll(TYPE_ATTACK);
}
}
//////////////////////////////
//
// printLine -- print a line of the note array.
// style == 0: regular line
// style == 1: index line (don't extract beat or absbeat from infile)
//
void printLine(Array<Array<int> >& notes, Array<Array<int> >& attacks,
Array<Array<int> >& lasts, Array<Array<int> >& nexts,
Array<int>& measpos, Array<int>& linenum, HumdrumFile& infile,
int index, int style) {
int& i = index;
int j;
if (mathQ) {
cout << "{";
}
if (indexQ) {
cout << i + Offset + OffsetSum;
}
if (lineQ) {
if (indexQ) {
if (mathQ) {
cout << ",";
}
cout << "\t";
}
cout << linenum[i]+1;
}
if (measureQ) {
if (indexQ || lineQ) {
if (mathQ) {
cout << ",";
}
cout << "\t";
}
cout << measpos[i];
}
if (beatQ) {
if (indexQ || lineQ || measureQ) {
if (mathQ) {
cout << ",";
}
cout << "\t";
}
if (style == 1) {
cout << TYPE_BEAT;
} else if (rationalQ) {
if (fractionQ) {
cout << infile[linenum[i]].getBeatR();
} else {
infile[linenum[i]].getBeatR().printTwoPart(cout);
}
} else {
// print beat position as a floating-point number:
cout << infile[linenum[i]].getBeat();
}
}
if (absoluteQ) {
if (indexQ || lineQ || measureQ || beatQ) {
if (mathQ) {
cout << ",";
}
cout << "\t";
}
if (style == 1) {
cout << TYPE_ABSOLUTE;
} else if (rationalQ) {
if (fractionQ) {
cout << (Absoffset + infile[linenum[i]].getAbsBeatR());
} else {
RationalNumber sum = Absoffset + infile[linenum[i]].getAbsBeatR();
sum.printTwoPart(cout);
}
} else {
// print beat position as a floating-point number:
cout << infile[linenum[i]].getAbsBeat() + Absoffset.getFloat();
}
}
if (linedurQ) {
if (indexQ || lineQ || measureQ || beatQ || absoluteQ) {
if (mathQ) {
cout << ",";
}
cout << "\t";
}
if (style == 1) {
cout << TYPE_LINEDUR;
} else if (rationalQ) {
if (fractionQ) {
cout << (Absoffset + infile[linenum[i]].getDurationR());
} else {
RationalNumber num = infile[linenum[i]].getDurationR();
num.printTwoPart(cout);
}
} else {
// print beat position as a floating-point number:
cout << infile[linenum[i]].getDuration();
}
}
if (indexQ || lineQ || measureQ || beatQ || absoluteQ || linedurQ) {
if (mathQ) {
cout << ",";
}
}
Array<int> values;
values.setSize(notes.getSize() * 10);
values.setSize(0);
int vv;
int sign;
for (j=0; j<notes[i].getSize(); j++) {
vv = notes[i][j];
//if (kernQ && (style == 1) && typeQ) {
// int ww = TYPE_KERN;
// values.append(ww);
//}
if (vv < TYPE_NOTES) {
if (vv < 0) {
sign = -1;
vv = -vv;
} else {
sign = +1;
}
if (vv != 0) {
switch (style) {
case STYLE_BASE12:
vv = Convert::base40ToMidiNoteNumber(vv);
break;
case STYLE_BASE7:
vv = Convert::base40ToDiatonic(vv);
break;
}
}
vv *= sign;
values.append(vv);
} else {
values.append(vv);
}
if (attackQ) {
values.append(attacks[i][j]);
}
if (lastQ) {
values.append(lasts[i][j]);
}
if (nextQ) {
values.append(nexts[i][j]);
}
}
int width = 1; // notes
if (attackQ) { width++; }
if (lastQ) { width++; }
if (nextQ) { width++; }
char buffer[1024] = {0};
for (j=0; j<values.getSize(); j++) {
if (kernQ && ((j % width) == 0)) {
//if (mathQ) {
// cout << ",";
//}
cout << "\t";
if ((style == 1) && (i == 0)) {
cout << TYPE_KERN;
} else {
if (mathQ || quoteQ) {
cout << "\"";
}
if (kerntieQ && noteStartMarker(notes, i, j / width)) {
cout << "[";
}
if (doubletieQ && singleNote(notes, i, j / width)) {
cout << "[";
}
if (values[j] == 0) {
cout << "r";
} else {
cout << Convert::base40ToKern(buffer, abs(values[j]));
}
if (kerntieQ && noteContinueMarker(notes, i, j / width)) {
cout << "_";
} else if (kerntieQ && noteEndMarker(notes, i, j / width)) {
cout << "]";
}
if (doubletieQ && singleNote(notes, i, j / width)) {
cout << "]";
}
if (mathQ || quoteQ) {
cout << "\"";
}
}
if (mathQ) {
cout << ",";
}
}
cout << "\t" << values[j];
if (j < values.getSize()-1) {
if (mathQ) {
cout << ",";
}
//cout << "\t";
}
}
if (mathQ) {
cout << "}";
if (i < linenum.getSize() - 1) {
cout << ",";
}
}
cout << endl;
}
//////////////////////////////
//
// singleNote -- true if the note in the column/line is uniq
//
int singleNote(Array >& notes, int line, int column) {
int start = 0;
if (typeQ) {
start = 1;
}
if (line < start) {
return 0;
}
int pitch = notes[line][column];
int nextpitch = -1;
int lastpitch = -1;
if ((line > start) && (notes.getSize() > 1+start)) {
lastpitch = notes[line-1][column];
}
if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) {
nextpitch = notes[line+1][column];
}
if (pitch > TYPE_MIN) {
return 0;
}
if (pitch < 0) {
// note is a sustain, so not considered
return 0;
} else if (pitch == 0) {
// if the rest is surrounded by non-rests, then mark
if ((pitch != lastpitch) && (pitch != nextpitch)) {
return 1;
} else {
return 0;
}
} else {
if (pitch != -nextpitch) {
// next sonority does not contain a sustain of the note
return 1;
} else {
return 0;
}
}
}
//////////////////////////////
//
// noteStartMarker --
//
int noteStartMarker(Array >& notes, int line, int column) {
int start = 0;
if (typeQ) {
start = 1;
}
if (line < start) {
return 0;
}
int pitch = notes[line][column];
int nextpitch = -1;
int lastpitch = -1;
if ((line > start) && (notes.getSize() > 1+start)) {
lastpitch = notes[line-1][column];
}
if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) {
nextpitch = notes[line+1][column];
}
if (pitch == 0) {
// if the first rest in a row then true
if ((lastpitch != 0) && (nextpitch == 0)) {
// don't include rests which start and stop on the same line
return 1;
} else {
return 0;
}
} else if (pitch < 0) {
return 0;
} else {
if ((nextpitch < 0) && (nextpitch != -1)) {
return 1;
} else {
return 0;
}
}
}
//////////////////////////////
//
// noteContinueMarker --
//
int noteContinueMarker(Array >& notes, int line, int column) {
int start = 0;
if (typeQ) {
start = 1;
}
if (line < start) {
return 0;
}
int pitch = notes[line][column];
int nextpitch = -1;
int lastpitch = -1;
if ((line > start) && (notes.getSize() > 1+start)) {
lastpitch = notes[line-1][column];
}
if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) {
nextpitch = notes[line+1][column];
}
if (pitch == 0) {
// if not the first or the last zero than a continue
if ((lastpitch == 0) && (nextpitch == 0)) {
return 1;
} else {
return 0;
}
} else if (pitch > 0) {
return 0;
} else {
if (pitch == nextpitch ) {
return 1;
} else {
return 0;
}
}
}
//////////////////////////////
//
// noteEndMarker --
//
int noteEndMarker(Array >& notes, int line, int column) {
int start = 0;
if (typeQ) {
start = 1;
}
if (line < start) {
return 0;
}
int pitch = notes[line][column];
int nextpitch = -1;
int lastpitch = -1;
if ((line > start) && (notes.getSize() > 1+start)) {
lastpitch = notes[line-1][column];
}
if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) {
nextpitch = notes[line+1][column];
}
if (pitch == 0) {
// if not the first or the last zero than a continue
if (nextpitch != 0) {
return 1;
} else {
return 0;
}
} else if (pitch > 0) {
return 0;
} else {
if (pitch != nextpitch ) {
return 1;
} else {
return 0;
}
}
}
//////////////////////////////
//
// printExclusiveInterpretations -- print ** markers at the start of
// each column of data.
//
// Order of optional prefix columns:
// lineQ
// measureQ
// beatQ
// absoluteQ
// linedurQ
//
void printExclusiveInterpretations(int basecount) {
char basename[1024] = {0};
const char* prefix = "##";
if (humdrumQ || mathQ) {
prefix = "**";
}
if (kernQ) {
strcat(basename, "kern");
strcat(basename, "\t");
}
if (base7Q) {
// strcat(basename, prefix);
strcat(basename, "b7");
} else if (base12Q) {
// strcat(basename, prefix);
strcat(basename, "b12");
} else {
// strcat(basename, prefix);
strcat(basename, "b40");
}
if (attackQ) {
strcat(basename, "\t");
strcat(basename, prefix);
strcat(basename, "attk");
}
if (lastQ) {
strcat(basename, "\t");
strcat(basename, prefix);
strcat(basename, "last");
}
if (nextQ) {
strcat(basename, "\t");
strcat(basename, prefix);
strcat(basename, "next");
}
int startmark = 0;
if (indexQ) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << "idx\t";
}
if (lineQ) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << "line\t";
}
if (measureQ) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << "bar\t";
}
if (beatQ) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << "beat\t";
}
if (absoluteQ) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << "abs\t";
}
if (linedurQ) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << "ldur\t";
}
int i;
for (i=0; i<basecount; i++) {
if ((startmark == 0) && mathQ) {
cout << "(*";
startmark++;
} else {
cout << prefix;
}
cout << basename;
if (i < basecount - 1) {
cout << "\t";
}
}
if (mathQ) {
cout << " *)";
}
cout << "\n";
}
//////////////////////////////
//
//
// printComments -- print any comments
//
void printComments(HumdrumFile& infile, int startline, int stopline,
int style) {
int i;
for (i=startline; i<=stopline; i++) {
if (!infile[i].isComment()) {
continue;
}
if (bibQ && infile[i].isGlobalComment()) {
continue;
}
if (infile[i].isLocalComment()) {
// don't know how to store local comments, ignore for now.
continue;
}
if (style) {
// print in Humdrum format:
cout << infile[i] << "\n";
} else {
// print in Matlab format:
cout << commentStart << infile[i] << commentStop << "\n";
}
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("a|absolute=b", "print absolute beat numbers");
opts.define("b|bib|bibliographic|reference=b", "display only bib record");
opts.define("c|type=b", "add a numeric index at start of data array");
opts.define("d|diatonic=b", "print output in absolute diatonic");
opts.define("f|fraction=b", "display rational number as fraction");
opts.define("e|end|end-rest=b","store ending rest");
opts.define("i|index=b", "print a column with the index value");
opts.define("j|josquin=b", "default settings for josquin project");
opts.define("k|kern=b", "display kern spine");
opts.define("no-tie|no-ties=b", "don't display kern tie information");
opts.define("l|line=b", "print original line of sonority in data");
opts.define("m|midi=b", "print output as MIDI key numbers");
opts.define("o|octave=i:0", "octave adjustment value");
opts.define("r|rational=b", "display metric position as rational number");
opts.define("t|beat=s:", "metric base for constant beat analysis");
opts.define("1|one=b", "offset index values by one");
opts.define("M|no-measures=b", "don't print measure number column");
opts.define("B|no-beats=b", "don't print beat value column");
opts.define("C|no-comments=b", "don't print comments in file");
opts.define("D|linedur=b", "display duration of line");
opts.define("A|all=b", "display all options prefix columns");
opts.define("H|humdrum=b", "print output in Humdrum format");
opts.define("I|no-info=b", "do not display information header");
opts.define("S|no-sustain=b", "suppress sonorities that are only sustains");
opts.define("T|all-tie|all-ties=b", "start/stop tie marks on all notes");
opts.define("N|no-cols=b", "turn off all information columns");
opts.define("attack=b", "display note-attack index values");
opts.define("double=b", "add rests at double barlines");
opts.define("last=b", "display previous note-attack index values");
opts.define("math|mathematica=s:data", "print output data as Matlab array");
opts.define("mel|melodic=b", "display melodic note index columns");
opts.define("mo|measure-offset=i:0", "bar num increase per file");
opts.define("next=b", "display following note-attack index values");
opts.define("offset=i:0", "starting index for first row");
opts.define("sa|separate-absolute=b", "single absolute beat positions");
opts.define("sep|separator=b", "print a separator between input analyses");
opts.define("quote=b", "print quotes around kern names");
opts.define("debug=b"); // determine bad input line num
opts.define("author=b"); // author of program
opts.define("version=b"); // compilation info
opts.define("example=b"); // example usages
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, Aug 2011" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 30 August 2011" << 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("josquin")) {
beatbase = "1"; // beat is the whole note.
doubleQ = 1;
} else {
beatbase = opts.getString("beat");
doubleQ = opts.getBoolean("double");
}
humdrumQ = opts.getBoolean("humdrum");
base7Q = opts.getBoolean("diatonic");
base12Q = opts.getBoolean("midi");
if (base7Q) {
base7Q = 1;
base12Q = 0;
base40Q = 0;
} else if (base12Q) {
base7Q = 0;
base12Q = 1;
base40Q = 0;
} else {
base7Q = 0;
base12Q = 0;
base40Q = 1;
}
if (base7Q) {
base = STYLE_BASE7;
} else if (base12Q) {
base = STYLE_BASE12;
} else {
base = STYLE_BASE40;
}
mathQ = opts.getBoolean("mathematica");
mathvar = opts.getString("mathematica");
commentStart = "(* ";
commentStop = " *)";
if (!mathQ) {
commentStart = "# ";
commentStop = "";
}
lineQ = opts.getBoolean("line");
measureQ = !opts.getBoolean("no-measures");
beatQ = !opts.getBoolean("no-beats");
absoluteQ = opts.getBoolean("absolute");
linedurQ = opts.getBoolean("linedur");
commentQ = !opts.getBoolean("no-comments");
rationalQ = opts.getBoolean("rational");
fractionQ = opts.getBoolean("fraction");
susxQ = opts.getBoolean("no-sustain");
kernQ = opts.getBoolean("kern");
kerntieQ = !opts.getBoolean("no-tie");
bibQ = opts.getBoolean("bibliographic");
infoQ = !opts.getBoolean("no-info");
endQ = opts.getBoolean("end-rest");
octadj = opts.getInteger("octave");
typeQ = opts.getBoolean("type");
attackQ = opts.getBoolean("attack");
nextQ = opts.getBoolean("last");
lastQ = opts.getBoolean("next");
indexQ = opts.getBoolean("index");
sepQ = opts.getBoolean("sep");
saQ = opts.getBoolean("separate-absolute");
Mincrement= opts.getInteger("measure-offset");
moQ = opts.getBoolean("measure-offset");
Offset = opts.getInteger("offset");
quoteQ = opts.getBoolean("quote");
doubletieQ= opts.getBoolean("all-tie");
if (doubletieQ) {
kerntieQ = 1;
}
if (Offset < 0) {
Offset = 0;
}
if (opts.getBoolean("mel")) {
attackQ = 1;
nextQ = 1;
lastQ = 1;
}
if (opts.getBoolean("1")) {
Offset = 1;
}
if (fractionQ) {
rationalQ = 1;
}
if (opts.getBoolean("no-cols")) {
measureQ = 0;
beatQ = 0;
}
if (opts.getBoolean("all")) {
lineQ = measureQ = beatQ = absoluteQ = linedurQ = 1;
}
}
//////////////////////////////
//
// example -- example usage of the quality program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the meter program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
// md5sum: cae22ba3e86ede60cf34a672bb901dbd notearray.cpp [20111105]