//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Fri Mar 18 22:08:55 PST 2005
// Last Modified: Sat Jun 3 18:46:57 PDT 2006 (changed tempo interp direction)
// Last Modified: Sat Jun 3 18:46:57 PDT 2006 (added fill option)
// Filename: ...sig/examples/all/time2tempo.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/time2tempo.cpp
// Syntax: C++; museinfo
//
// Description:
//
#include "humdrum.h"
#include <string.h>
#include <stdio.h>
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void printAnalysis(HumdrumFile& infile, Array<double>& timings,
Array<double>& tempo);
void getTimings(HumdrumFile& infile, Array<double>& timings,
Array<double>& tempo);
void usage(const char* command);
// global variables
Options options; // database for command-line arguments
int appendQ = 0; // used with -a option
int prependQ = 0; // used with -p option
int fillQ = 0; // used with -f option
int roundQ = 0; // used with -r option
int debugQ = 0; // used with --debug option
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile;
Array<double> timings;
Array<double> tempo;
// 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));
}
getTimings(infile, timings, tempo);
printAnalysis(infile, timings, tempo);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// getTimings -- Get an array of the times for each line in the
// input file from a **time spine. Currently only look for
// the first **time spine in the file.
//
void getTimings(HumdrumFile& infile, Array<double>& timings,
Array<double>& tempo) {
infile.analyzeRhythm("4");
int i;
int j;
timings.setSize(infile.getNumLines());
tempo.setSize(infile.getNumLines());
timings.setAll(-1.0);
tempo.setAll(-1.0);
double atime;
int secondsQ = 0;
// get the timing values from the **time spine.
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() == E_humrec_interpretation) {
for (j=0; j<infile[i].getFieldCount(); j++) {
if (strcmp(infile[i].getExInterp(j), "**time") == 0) {
if (strcmp(infile[i][j], "*u=sec") == 0) {
// measuring time in seconds.
secondsQ = 1;
} else if (strcmp(infile[i][j], "*u=msec") == 0) {
secondsQ = 0;
}
break;
}
}
}
if (infile[i].getType() != E_humrec_data) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
// just looking for the first **time spine for now...
if (strcmp(infile[i].getExInterp(j), "**time") != 0) {
continue;
}
if (strcmp(infile[i][j], ".") == 0) {
timings[i] = -1.0;
} else {
if (sscanf(infile[i][j], "%lf", &atime) == 1) {
timings[i] = atime;
if (secondsQ) {
// convert seconds measurements into milliseconds
timings[i] *= 1000.0;
}
} else {
timings[i] = -1.0;
}
}
break;
}
}
// the times have been extracted from the Humdrum data, so now
// convert them into tempo markings.
int lastindex = 0;
double beatdur;
double timedur;
double atempo;
for (i=0; i<infile.getNumLines(); i++) {
if (timings[i] < 0.0) {
continue;
}
beatdur = infile[i].getAbsBeat() - infile[lastindex].getAbsBeat();
timedur = (timings[i] - timings[lastindex])/1000.0;
atempo = 60.0 * beatdur / timedur;
tempo[lastindex] = atempo;
if (roundQ) {
tempo[lastindex] = (int)(tempo[lastindex] + 0.5);
}
lastindex = i;
}
// set all zero tempos to be the same as the previous
// tempo marking.
if (fillQ) {
for (i=1; i<infile.getNumLines(); i++) {
if (tempo[i] <= 0.0) {
tempo[i] = tempo[i-1];
}
}
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("a|append=b", "append analysis to input data");
opts.define("p|prepend=b", "prepend analysis to input data");
opts.define("r|round=b", "round output tempos to nearest integer");
opts.define("f|fill=b", "fill tempo spine removing null tokens");
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, March 2004" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 4 June 2006" << 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");
appendQ = opts.getBoolean("append");
roundQ = opts.getBoolean("round");
fillQ = opts.getBoolean("fill");
prependQ = opts.getBoolean("prepend");
if (appendQ) { // exclusive options
prependQ = 0;
}
}
//////////////////////////////
//
// example -- example usage of the addtime program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// printAnalysis --
//
void printAnalysis(HumdrumFile& infile, Array<double>& timings,
Array<double>& tempo) {
int tempomark = 1; // disabled for now
double lasttempo = -1.0;
int i;
int m;
for (i=0; i<infile.getNumLines(); i++) {
switch (infile[i].getType()) {
case E_humrec_global_comment:
case E_humrec_bibliography:
case E_humrec_none:
case E_humrec_empty:
cout << infile[i].getLine() << "\n";
break;
case E_humrec_data:
if (appendQ) {
cout << infile[i].getLine() << "\t";
}
if (tempomark == 0) {
tempomark = 1;
cout << "*MM" << tempo[i] << "\t";
for (m=0; m<infile[i].getFieldCount(); m++) {
cout << "*";
if (m < infile[i].getFieldCount() - 1) {
cout << "\t";
}
}
cout << "\n";
}
if (!fillQ && tempo[i] <= 0.0) {
cout << ".";
} else if (!fillQ && tempo[i] == lasttempo) {
cout << ".";
} else {
cout << tempo[i];
lasttempo = tempo[i];
}
if (prependQ) {
cout << "\t" << infile[i].getLine();
}
cout << "\n";
break;
case E_humrec_data_comment:
if (appendQ) {
cout << infile[i].getLine() << "\t";
}
if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i][0];
} else {
cout << "!";
}
if (prependQ) {
cout << "\t" << infile[i].getLine();
}
cout << "\n";
break;
case E_humrec_data_measure:
if (appendQ) {
cout << infile[i].getLine() << "\t";
}
if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i][0];
} else {
cout << "=";
}
if (prependQ) {
cout << "\t" << infile[i].getLine();
}
cout << "\n";
break;
case E_humrec_data_interpretation:
if (appendQ) {
cout << infile[i].getLine() << "\t";
}
if (strncmp(infile[i][0], "**", 2) == 0) {
cout << "**tempo";
} else if (strcmp(infile[i][0], "*-") == 0) {
cout << "*-";
} else if (strncmp(infile[i][0], "*MM", 3) == 0) {
tempomark = 1;
cout << infile[i][0];
} else {
cout << "*";
}
if (prependQ) {
cout << "\t" << infile[i].getLine();
}
cout << "\n";
break;
}
}
}
//////////////////////////////
//
// usage -- gives the usage statement for the quality program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
// md5sum: 3bc6af6a088a036d00da4efc0f00977f time2tempo.cpp [20060701]