//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Sep 9 21:30:46 PDT 2004
// Last Modified: Thu Sep 9 21:30:48 PDT 2004
// Filename: ...sig/examples/all/barnum.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/barnum.cpp
// Syntax: C++; museinfo
//
// Description: Number, renumber or remove measure numbers from Humdrum files.
//
#include "humdrum.h"
#include <string.h>
#include <ctype.h>
#ifndef OLDCPP
#include <sstream>
#define SSTREAM stringstream
#define CSTRING str().c_str()
using namespace std;
#else
#ifdef VISUAL
#include <strstrea.h> /* for windows 95 */
#else
#include <strstream.h>
#endif
#define SSTREAM strstream
#define CSTRING str()
#endif
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
void processFile(HumdrumFile& file);
void removeBarNumbers(HumdrumFile& infile);
void printWithoutBarNumbers(HumdrumRecord& humrecord);
void printWithBarNumbers(HumdrumRecord& humrecord, int measurenum);
void printSingleBarNumber(const char* string, int measurenum);
// global variables
Options options; // database for command-line arguments
int removeQ = 0; // used with -r option
int startnum = 1; // used with -s option
int allQ = 0; // used with -a option
int debugQ = 0; // used with --debug option
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile, outfile;
// process the command-line options
checkOptions(options, argc, argv);
// if no command-line arguments read data file from standard input
int numinputs = options.getArgCount();
if (numinputs < 1) {
infile.read(cin);
} else {
infile.read(options.getArg(1));
}
if (removeQ) {
removeBarNumbers(infile);
} else{
processFile(infile);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////
//
// removeBarNumbers -- You guessed it.
//
void removeBarNumbers(HumdrumFile& infile) {
int i;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() != E_humrec_data_measure) {
cout << infile[i] << "\n";
continue;
}
printWithoutBarNumbers(infile[i]);
}
}
//////////////////////////////
//
// printWithoutBarNumbers --
//
void printWithoutBarNumbers(HumdrumRecord& humrecord) {
int i;
int j;
int length;
for (i=0; i<humrecord.getFieldCount(); i++) {
if (humrecord[i][0] != '=') {
cout << humrecord[i];
} else {
length = strlen(humrecord[i]);
for (j=0; j<length; j++) {
if (!isdigit(humrecord[i][j])) {
cout << humrecord[i][j];
}
}
}
if (i < humrecord.getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// processFile --
//
void processFile(HumdrumFile& infile) {
infile.analyzeRhythm("4");
Array<int> measureline; // line number in the file where measure occur
Array<double> measurebeats; // duration of measure
Array<double> timesigbeats; // duration according to timesignature
Array<int> control; // control = numbered measure
Array<int> measurenums; // output measure numbers
measureline.setSize(infile.getNumLines());
measureline.setSize(0);
measurebeats.setSize(infile.getNumLines());
measurebeats.setSize(0);
timesigbeats.setSize(infile.getNumLines());
timesigbeats.setSize(0);
int i;
double timesigdur = 0.0;
double timetop = 4;
double timebot = 1;
double value = 1;
double lastvalue = 1;
for (i=0; i<infile.getNumLines(); i++) {
if (debugQ) {
cout << "LINE " << i+1 << "\t" << infile[i] << endl;
}
if (infile[i].getType() == E_humrec_interpretation) {
if ((strncmp(infile[i][0], "*M", 2) == 0)
&& (strchr(infile[i][0], '/') != NULL)) {
timetop = Convert::kernTimeSignatureTop(infile[i][0]);
timebot = Convert::kernTimeSignatureBottomToDuration(infile[i][0]);
timesigdur = timetop * timebot;
// fix last timesigbeats value
if (timesigbeats.getSize() > 0) {
timesigbeats[timesigbeats.getSize()-1] = timesigdur;
measurebeats[measurebeats.getSize()-1] = lastvalue * timebot;
}
}
} else if (infile[i].getType() == E_humrec_data_measure) {
measureline.append(i);
lastvalue = infile[i].getBeat();
// shouldn't use timebot (now analyzing rhythm by "4")
// value = lastvalue * timebot;
value = lastvalue;
measurebeats.append(value);
timesigbeats.append(timesigdur);
}
}
if (measurebeats.getSize() == 0) {
// no barlines, nothing to do...
cout << infile;
return;
}
// Identify controlling/non-controlling barlines
// at each measure line determine one of three cases:
//
// (1) all ok -- the summation of durations in the measure
// matches the current time sign
// (2) a partial measure -- the measure durations do not
// add up to the time signature, but the measure is
// at the start/end of a musical section such as the
// beginning of a piece, end of a piece, or between
// repeat bar dividing a full measure.
// (3) the sum of the durations does not match the
// time signature because the durations are incorrectly
// given.
//
control.setSize(measureline.getSize());
measurenums.setSize(measureline.getSize());
control.setAll(-1);
measurenums.setAll(-1);
// if the time signature and the number of beats in a measure
// agree, then the bar is worth numbering:
for (i=0; i<control.getSize(); i++) {
if (measurebeats[i] == timesigbeats[i]) {
control[i] = 1;
}
}
// determine first bar (which is marked with a negative value)
// if there is a pickup bar
if (measurebeats[0] < 0) {
if (-measurebeats[0] == timesigbeats[0]) {
control[0] = 1;
}
}
// Check for intermediate barlines which split one measure
for (i=control.getSize()-2; i>=0; i--) {
if ((control[i] == 1) || (control[i+1] == 1)) {
continue;
}
if (timesigbeats[i] != timesigbeats[i+1]) {
continue;
}
if ((measurebeats[i]+measurebeats[i+1]) == timesigbeats[i]) {
control[i] = 1;
control[i+1] = 0;
}
}
// if two (or more) non-controlling bars occur in a row, then
// make them controlling:
for (i=0; i<control.getSize()-1; i++) {
if ((control[i] < 1) && (control[i+1] < 1)) {
while ((i < control.getSize()) && (control[i] < 1)) {
control[i++] = 1;
}
}
}
// if a measure contains no beats, then it is not a controlling barline
for (i=0; i<control.getSize(); i++) {
if (measurebeats[i] == 0) {
control[i] = 0;
}
}
// if the first bar is not a pickup measure, but there is no
// starting measure, then subtract one from the starting barline
// count;
int offset = 0;
int dataq = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isData()) {
dataq = 1;
continue;
}
if (infile[i].getType() == E_humrec_data_measure) {
if ((measurebeats[0] > 0) && dataq) {
offset = 1;
}
break;
}
}
if (allQ) {
control.setAll(1);
offset = 0;
}
// assign the measure numbers;
int mnum = startnum + offset;
for (i=0; i<measurenums.getSize(); i++) {
if (control[i] == 1) {
measurenums[i] = mnum++;
}
}
if (debugQ) {
cout << "cont\tnum\tbeats" << endl;
for (i=0; i<control.getSize(); i++) {
cout << control[i] << "\t" << measurenums[i] << "\t"
<< measurebeats[i] << "\t" << timesigbeats[i] << endl;
}
}
// ready to print the new barline numbers
int mindex = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() != E_humrec_data_measure) {
cout << infile[i] << "\n";
continue;
}
if (measurenums[mindex] < 0) {
printWithoutBarNumbers(infile[i]);
} else {
printWithBarNumbers(infile[i], measurenums[mindex]);
}
mindex++;
}
}
//////////////////////////////
//
// printWithBarNumbers --
//
void printWithBarNumbers(HumdrumRecord& humrecord, int measurenum) {
int i;
for (i=0; i<humrecord.getFieldCount(); i++) {
printSingleBarNumber(humrecord[i], measurenum);
if (i < humrecord.getFieldCount() -1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// printSingleBarNumber --
//
void printSingleBarNumber(const char* string, int measurenum) {
int length = strlen(string);
int i;
for (i=0; i<length; i++) {
if (string[i] == '=' && string[i+1] != '=') {
cout << string[i] << measurenum;
} else if (!isdigit(string[i])) {
cout << string[i];
}
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("r|remove=b", "Remove barlines from the file");
opts.define("s|start=i:1", "starting barline number");
opts.define("a|all=b", "print numbers on all barlines");
opts.define("debug=b"); // print debug info
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, Sep 2004" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 10 Sep 2004" << 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);
}
removeQ = opts.getBoolean("remove");
startnum = opts.getInteger("start");
debugQ = opts.getBoolean("debug");
allQ = opts.getBoolean("all");
}
//////////////////////////////
//
// 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: dc8a875e92aded1fc1ae7353f83977fa barnum.cpp [20050403]