//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat Nov 18 13:11:13 PST 2000
// Last Modified: Sat Nov 18 13:11:17 PST 2000
// Filename: ...sig/examples/all/atttacks.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/attacks.cpp
// Syntax: C++; museinfo
//
// Description: Counts attack notes for every position in the input score.
// Examines **kern spines and ignores all other spines.
//
#include "humdrum.h"
#include <string.h>
#include <ctype.h>
#include <math.h>
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
int countAttacks(HumdrumRecord& record);
int doublecompare(const void* a, const void* b);
void example(void);
void generateAnalysis(HumdrumFile& infile, Array<int>& attacks);
void generateSummary(HumdrumFile& infile, Array<int>& attacks);
void generateSubSummary(HumdrumFile& infile, Array<int>& attacks,
const char* metricmarker, int start, int stop);
void printAnalysis(HumdrumFile& infile, Array<int>&metric);
void usage(const char* command);
// global variables
Options options; // database for command-line arguments
int debugQ = 0; // used with the --debug option
int appendQ = 0; // used with the -a option
int summaryQ = 0; // used with the -c option
int densityQ = 0; // used with the -d option
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile;
Array<int> attacks;
// 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));
}
generateAnalysis(infile, attacks);
if (summaryQ) {
generateSummary(infile, attacks);
} else {
printAnalysis(infile, attacks);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("a|append=b", "append analysis to data in output");
opts.define("s|sum|summary=b", "average value for each metrical position");
opts.define("d|density|delta=b", "display the change in attack density");
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, Nov 2000" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: Nov 2000" << 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");
if (opts.getBoolean("summary")) {
summaryQ = 1;
appendQ = 0;
} else {
summaryQ = 0;
}
if (opts.getBoolean("density")) {
densityQ = 1;
} else {
densityQ = 0;
}
}
//////////////////////////////
//
// example -- example usage of the quality program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// generateAnalysis --
//
void generateAnalysis(HumdrumFile& infile, Array& attacks) {
attacks.setSize(infile.getNumLines());
for (int i=0; i<infile.getNumLines(); i++) {
if (options.getBoolean("debug")) {
cout << "processing line " << (i+1) << " of input ..." << endl;
}
if (infile[i].getType() != E_humrec_data) {
attacks[i] = -1;
continue;
}
attacks[i] = countAttacks(infile[i]);
}
}
//////////////////////////////
//
// generateSummary -- generate the average measurement value for
// each metrical position in the meter.
//
void generateSummary(HumdrumFile& infile, Array& attacks) {
int start = 0;
int stop = 0;
int i=0;
int m=0;
int datatrigger = 0;
int metertrigger = 0;
int summarytrigger = 0;
int length;
const char* metricmarker = "";
cout << "**takt\t**attack\t**avg\t**fract\n";
while (i<infile.getNumLines()) {
if (infile[i].getType() == E_humrec_data) {
datatrigger = 1;
if (start == 0) {
start = i;
}
}
if (infile[i].getType() == E_humrec_interpretation) {
for (m=0; m<infile[i].getFieldCount(); m++) {
if ((infile[i].getExInterpNum(m) == E_KERN_EXINT) &&
(strncmp(infile[i][m], "*M", 2) == 0)) {
length = strlen(infile[i][m]);
if ((length > 2) && isdigit(infile[i][m][2]) &&
(strchr(infile[i][m], '/') != NULL)) {
metertrigger = 1;
metricmarker = infile[i][m];
if (datatrigger) {
summarytrigger = 1;
stop = i-1;
} else {
start = i;
}
break;
} else if (strncmp(infile[i][m], "*MM", 3) == 0) {
cout << infile[i][m] << "\t";
cout << infile[i][m] << "\t";
cout << infile[i][m] << "\n";
break;
}
}
}
}
if (strcmp(infile[i][0], "*-") == 0) {
summarytrigger = 1;
stop = i;
}
if (datatrigger == 1 && metertrigger == 0) {
generateSubSummary(infile, attacks, "*MX", 0, infile.getNumLines());
break;
}
if (summarytrigger) {
generateSubSummary(infile, attacks, metricmarker, start, stop);
summarytrigger = 0;
datatrigger = 0;
metricmarker = "";
start = stop + 1;
}
i++;
}
cout << "*-\t*-\t*-\t*-\n";
}
//////////////////////////////
//
// generateSubSummary --
//
void generateSubSummary(HumdrumFile& infile, Array<int>& attacks,
const char* metricmarker, int start, int stop) {
infile.analyzeRhythm();
Array<double> metposition;
metposition.setSize(0);
metposition.allowGrowth();
Array<int> count;
count.setSize(0);
count.allowGrowth();
Array<int> data;
data.setSize(0);
data.allowGrowth();
double current;
int one = 1;
const char* metermarker = "*";
int sumcount = 0;
int attackcount = 0;
int i;
int j;
int k;
int sindex;
for (i=start; i<stop; i++) {
if (infile[i].getType() == E_humrec_interpretation) {
for (j=0; j<infile[i].getFieldCount(); j++) {
if (strncmp(infile[i][j], "*M", 2) == 0) {
if (isdigit(infile[i][j][2]) &&
(strchr(infile[i][j], '/') != NULL)) {
metermarker = infile[i][j];
}
}
}
}
if (infile[i].getType() != E_humrec_data) {
continue;
}
sindex = -1;
if (metposition.getSize() == 0) {
current = infile[i].getBeat();
metposition.append(current);
count.append(one);
data.append(attacks[i]);
sumcount++;
attackcount +=attacks[i];
} else {
k = 0;
while (k < metposition.getSize()) {
if (fabs(metposition[k] - infile[i].getBeat()) < 0.001) {
sindex = k;
break;
}
k++;
}
if (sindex >= 0) {
count[sindex]++;
data[sindex] += attacks[i];
sumcount++;
attackcount += attacks[i];
} else {
current = infile[i].getBeat();
metposition.append(current);
count.append(one);
data.append(attacks[i]);
sumcount++;
attackcount +=attacks[i];
}
}
}
Array<double> sortmet = metposition;
qsort(sortmet.getBase(), metposition.getSize(), sizeof(double),
doublecompare);
Array<double> average;
Array<double> fraction;
average.setSize(metposition.getSize());
fraction.setSize(metposition.getSize());
for (i=0; i<average.getSize(); i++) {
average[i] = (double)data[i]/count[i];
fraction[i] = (double)data[i]/attackcount;
}
cout << metermarker << "\t*lines=" << start+1 << ":" << stop+1
<< "\t*cnt=" << attackcount << "\t*\n";
for (i=0; i<metposition.getSize(); i++) {
k = 0;
while (k < metposition.getSize()) {
if (metposition[k] == sortmet[i]) {
break;
}
k++;
}
if (k > metposition.getSize()) {
continue;
}
cout << sortmet[i] << "\t"
<< data[k] << "\t"
<< average[k] << "\t"
<< fraction[k] << "\n";
}
}
//////////////////////////////
//
// countAttacks -- count the number of notes that are struck
// at each moment in the score.
//
int countAttacks(HumdrumRecord& record) {
int i, j;
int count = 0;
int tcount;
char buffer[128] = {0};
for (i=0; i<record.getFieldCount(); i++) {
if (record.getExInterpNum(i) != E_KERN_EXINT) {
continue;
}
if (strcmp(record[i], ".") == 0) {
continue;
}
tcount = record.getTokenCount(i);
for (j=0; j<tcount; j++) {
record.getToken(buffer, i, j);
if (strcmp(buffer, ".") == 0) {
continue;
}
if (strchr(buffer, '_') != NULL) {
continue;
}
if (strchr(buffer, ']') != NULL) {
continue;
}
count++;
}
}
return count;
}
//////////////////////////////
//
// printAnalysis --
//
void printAnalysis(HumdrumFile& infile, Array& attacks) {
int lastAttack = -1;
int i;
if (appendQ) {
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:
cout << infile[i].getLine() << "\t";
if (densityQ) {
if (lastAttack == -1) {
cout << "[" << attacks[i] << "]" << "\n";
} else {
cout << attacks[i] - lastAttack << "\n";
}
lastAttack = attacks[i];
} else {
cout << attacks[i] << "\n";
}
break;
case E_humrec_data_comment:
if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i].getLine() << "\t"
<< infile[i][0] << "\n";
} else {
cout << infile[i].getLine() << "\t!\n";
}
break;
case E_humrec_data_measure:
if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i].getLine() << "\t"
<< infile[i][0] << "\n";
} else {
cout << infile[i].getLine() << "\t=\n";
}
break;
case E_humrec_data_interpretation:
if (strncmp(infile[i][0], "**", 2) == 0) {
cout << infile[i].getLine() << "\t";
if (densityQ) {
cout << "**ddelta" << "\n";
} else {
cout << "**attack" << "\n";
}
} else if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i].getLine() << "\t"
<< infile[i][0] << "\n";
} else {
cout << infile[i].getLine() << "\t*\n";
}
break;
}
}
} else {
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 (densityQ) {
if (lastAttack == -1) {
cout << "[" << attacks[i] << "]" << "\n";
} else {
cout << attacks[i] - lastAttack << "\n";
}
lastAttack = attacks[i];
} else {
cout << attacks[i] << "\n";
}
break;
case E_humrec_data_comment:
if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i][0] << "\n";
} else {
// do nothing
}
break;
case E_humrec_data_measure:
if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i][0] << "\n";
} else {
cout << "\t=\n";
}
break;
case E_humrec_data_interpretation:
if (strncmp(infile[i][0], "**", 2) == 0) {
if (densityQ) {
cout << "**ddelta" << "\n";
} else {
cout << "**attack" << "\n";
}
} else if (infile[i].equalFieldsQ("**kern")) {
cout << infile[i][0] << "\n";
} else {
// do nothing
}
break;
}
}
}
}
//////////////////////////////
//
// usage -- gives the usage statement for the quality program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// doublecompare -- compare two doubles for ordering
//
int doublecompare(const void* a, const void* b) {
if (*((double*)a) < *((double*)b)) {
return -1;
} else if (*((double*)a) > *((double*)b)) {
return 1;
} else {
return 0;
}
}
// md5sum: 692c1c4950ec2ab6deb5a27223909892 attacks.cpp [20050403]