//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Mon Jan 8 23:45:43 PST 2007
// Last Modified: Mon Jan 8 23:45:36 PST 2007
// Filename: ...sig/examples/all/seqalign.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/seqalign.cpp
// Syntax: C++; museinfo
//
// Description: Align score beats to audio onset times.
//
#include "humdrum.h"
#include <math.h>
#include <string.h>
#ifndef OLDCPP
using namespace std;
#else
#endif
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
void extractSequence(Array<double>& hdata, HumdrumFile& hfile);
void fillSequence(Array<int>& array, Array<int>& index,
Array<double>& data, int totalsize);
int findNearest(int index, Array<int>& beatarray,
Array<int>& beatindex, Array<int>& onsetarray,
Array<int>& onsetindex);
// global variables
Options options; // database for command-line arguments
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile beats, onsets;
// process the command-line options
checkOptions(options, argc, argv);
// figure out the number of input files to process
int numinputs = options.getArgCount();
if (numinputs != 2) {
usage(options.getCommand());
exit(1);
}
beats.read(options.getArg(1));
onsets.read(options.getArg(2));
Array<double> beatdata;
Array<double> onsetdata;
extractSequence(beatdata, beats);
extractSequence(onsetdata, onsets);
// cout << "BEAT DATA contains " << beatdata.getSize() << " numbers" << endl;
// cout << "ONSET DATA contains " << onsetdata.getSize() << " numbers" << endl;
Array<int> beatarray;
Array<int> onsetarray;
int sequencesize = 100000;
Array<int> beatindex;
Array<int> onsetindex;
fillSequence(beatarray, beatindex, beatdata, sequencesize);
fillSequence(onsetarray, onsetindex, onsetdata, sequencesize);
int i;
int newi;
Array<int> mapping;
mapping.setSize(2*beatindex.getSize());
mapping.setSize(0);
for (i=0; i<beatindex.getSize(); i++) {
newi = findNearest(i, beatarray, beatindex, onsetarray, onsetindex);
mapping.append(newi);
}
double difference;
for (i=0; i<beatindex.getSize(); i++) {
difference = beatdata[i] - onsetdata[mapping[i]];
cout << i << " to " << mapping[i] << "\t"
<< beatdata[i] << " - " << onsetdata[mapping[i]] << " = "
<< difference << endl;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// findNearest --
//
int findNearest(int index, Array<int>& beatarray, Array<int>& beatindex,
Array<int>& onsetarray, Array<int>& onsetindex) {
int correction = onsetarray[beatindex[index]];
if (correction > 0) {
correction = 0;
} else if (correction > -1000) {
correction = correction;
} else {
correction = -correction / 1000;
}
return onsetarray[correction + beatindex[index]];
}
//////////////////////////////
//
// fillSequence -- make a literal representation of the sequence
//
#define OFFSET 100000
void fillSequence(Array<int>& array, Array<int>& index,
Array<double>& data, int totalsize) {
double minval = data[0];
double maxval = data[data.getSize()-1];
int indexmap;
array.setSize(totalsize);
array.allowGrowth(0);
int i;
for (i=0; i<array.getSize(); i++) {
array[i] = -1;
}
index.setSize(data.getSize());
for (i=0; i<data.getSize(); i++) {
indexmap = (int)((data[i]-minval)/(maxval-minval)*totalsize + 0.5);
if (indexmap > array.getSize()-1) { indexmap = array.getSize()-1; }
if (indexmap < 0) { indexmap = 0; }
index[i] = indexmap;
array[indexmap] = i;
}
// mark the closest event in the long array
int counter = 0;
int j;
int found = 0;
for (i=0; i<array.getSize(); i++) {
if (array[i] > 0) {
if (found == 0) {
counter = 0;
for (j=i-1; j>=0; j--) {
counter++;
array[j] = -counter * 1000;
}
}
found = 1;
counter = 0;
continue;
}
if (array[i] < 0 && !found) {
continue;
}
counter++;
array[i] = -counter;
}
int rfound = 0;
counter = 0;
int distance;
for (i=array.getSize()-1; i>=0; i--) {
if (array[i] > 0) {
rfound = 1;
counter = 0;
continue;
}
if (array[i] < 0 && !rfound) {
continue;
}
counter++;
distance = -array[i];
if (distance > counter) {
array[i] = -counter * 1000;
}
}
}
//////////////////////////////
//
// extractSequence --
//
void extractSequence(Array& hdata, HumdrumFile& hfile) {
int i;
hdata.setSize(hfile.getNumLines());
hdata.setSize(0);
double value;
int count;
for (i=0; i<hfile.getNumLines(); i++) {
if (hfile[i].getType() != E_humrec_data) {
continue;
}
if (strcmp(hfile[i][0], ".") == 0) {
continue;
}
count = sscanf(hfile[i][0], "%lf", &value);
if (count == 1) {
hdata.append(value);
}
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
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, Oct 2000" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 28 May 2002" << 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);
}
}
//////////////////////////////
//
// 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: a0ebffb4f13c943a8f40f62cbac85e77 seqalign.cpp [20070512]