Goto: [ Program Documentation ]
//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat May 23 21:08:48 PDT 1998
// Last Modified: Fri Jul 3 14:18:04 PDT 1998
// Last Modified: Sat Oct 14 20:26:15 PDT 2000 (revised for museinfo 1.0)
// Filename: ...sig/examples/all/sonority.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/sonority.cpp
// Syntax: C++; museinfo
//
// Description: Analyzes **kern data for timeslice chord qualities
//
#include "humdrum.h"
#include <stdlib.h>
#include <string.h>
#ifndef OLDCPP
#include <iostream>
using namespace std;
#else
#include <iostream.h>
#endif
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void determineChordQuality(ChordQuality& cq,
const HumdrumRecord& aRecord);
void example(void);
void processRecords(HumdrumFile& infile,
HumdrumFile& outfile);
void usage(const char* command);
// global variables
Options options; // database for command-line arguments
char unknown[256] = {0}; // space for unknown chord simplification
int chordinit; // for initializing chord detection function
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile, outfile;
// 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++) {
chordinit = 1;
infile.clear();
outfile.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
processRecords(infile, outfile);
// check to see if only the analysis spine is required
if (!options.getBoolean("assemble")) {
outfile = outfile.extract(-1);
}
outfile.write(cout);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("t|type=b"); // show only chord type
opts.define("i|inversion=b"); // show only chord inversion
opts.define("r|root=b"); // show only chord root
opts.define("a|assemble=b"); // assemble analysis with input
opts.define("f|format=s:t:i:r"); // control display style
opts.define("u|unknown=s:X"); // control display of unknowns
opts.define("d|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, May 1998" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 3 July 1998" << 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("root")) {
ChordQuality::setDisplay("r");
} else if (opts.getBoolean("type")) {
ChordQuality::setDisplay("t");
} else if (opts.getBoolean("inversion")) {
ChordQuality::setDisplay("i");
} else {
ChordQuality::setDisplay(opts.getString("format"));
}
Convert::chordType.setNullName(opts.getString("unknown"));
Convert::chordInversion.setNullName(opts.getString("unknown"));
Convert::kernPitchClass.setNullName(opts.getString("unknown"));
strncpy(unknown, opts.getString("unknown"), 64);
strcat(unknown, ":");
strncat(unknown, opts.getString("unknown"), 64);
strcat(unknown, ":");
strncat(unknown, opts.getString("unknown"), 64);
}
//////////////////////////////
//
// determineChordQuality -- extracts notes from humdrum data record
// and sends them to a chord identifier. Notes from previous
// records are remembered, and replace any null records in the
// data. Rests are represented by some negative value
// and will be ignored by the chord identifier.
//
void determineChordQuality(ChordQuality& cq,
const HumdrumRecord& aRecord) {
static SigCollection<int> lastnotes; // for keeping track of null record notes
int i;
if (chordinit) {
chordinit = 0;
lastnotes.setSize(aRecord.getFieldCount());
for (i=0; i<aRecord.getFieldCount(); i++) {
lastnotes[i] = E_root_rest;
}
// remove non-kern spines from note list
for (i=0; i<aRecord.getFieldCount(); i++) {
if (aRecord.getExInterpNum(i) != E_KERN_EXINT) {
lastnotes.setSize(lastnotes.getSize() - 1);
}
}
}
// determine chord notes and send to chord identifier
SigCollection<int> currentNotes(lastnotes.getSize());
int count = 0;
for (i=0; i<aRecord.getFieldCount(); i++) {
if (aRecord.getExInterpNum(i) == E_KERN_EXINT) {
if (strcmp(aRecord[i], ".") == 0) {
currentNotes[count] = lastnotes[count];
} else {
currentNotes[count] = Convert::kernToBase40(aRecord[i]);
lastnotes[count] = currentNotes[count];
}
count++;
}
}
Convert::noteSetToChordQuality(cq, currentNotes);
}
//////////////////////////////
//
// example -- example usage of the sonority program
//
void example(void) {
cout <<
" \n"
"# example usage of the sonority program. \n"
"# analyze a Bach chorale for chord qualities: \n"
" sonority chor217.krn \n"
" \n"
"# display the chord analysis with original data: \n"
" sonority -a chor217.krn \n"
" \n"
"# display only the roots of chords: \n"
" sonority -r chor217.krn \n"
" \n"
<< endl;
}
//////////////////////////////
//
// processRecords -- looks at humdrum records and determines chord
// sonority quality;
//
void processRecords(HumdrumFile& infile, HumdrumFile& outfile) {
ChordQuality quality;
int foundstart = 0;
char aString[256] = {0};
HumdrumRecord currRecord;
for (int i=0; i<infile.getNumLines(); i++) {
if (options.getBoolean("debug")) {
cout << "processing line " << (i+1) << " of input ..." << endl;
}
currRecord = infile[i];
switch (currRecord.getType()) {
case E_humrec_none:
case E_humrec_empty:
case E_humrec_bibliography:
case E_humrec_global_comment:
outfile.appendLine(currRecord);
break;
case E_humrec_data_comment:
if (currRecord.equalFieldsQ("**kern")) {
currRecord.appendField(currRecord[0]);
} else {
currRecord.appendField("!");
}
outfile.appendLine(currRecord);
break;
case E_humrec_data_interpretation:
if (!foundstart && currRecord.hasExclusiveQ()) {
foundstart = 1;
currRecord.appendField("**qual");
} else {
if (currRecord.equalFieldsQ("**kern")) {
currRecord.appendField(currRecord[0]);
} else {
currRecord.appendField("*");
}
}
outfile.appendLine(currRecord);
break;
case E_humrec_data_kern_measure:
if (currRecord.equalFieldsQ("**kern")) {
currRecord.appendField(currRecord[0]);
} else {
currRecord.appendField("=");
}
outfile.appendLine(currRecord);
break;
case E_humrec_data:
// handle null fields
if (currRecord.equalFieldsQ("**kern", ".")) {
currRecord.appendField(".");
outfile.appendLine(currRecord);
break;
}
determineChordQuality(quality, infile[i]);
quality.makeString(aString);
if (strcmp(aString, unknown) == 0 || (
quality.getType()==E_chord_note && options.getBoolean("root"))
) {
strcpy(aString, options.getString("unknown"));
}
currRecord.appendField(aString);
outfile.appendLine(currRecord);
break;
default:
cerr << "Error on line " << (i+1) << " of input" << endl;
cerr << "record type = " << currRecord.getType() << endl;
exit(1);
}
}
}
//////////////////////////////
//
// usage -- gives the usage statement for the sonority program
//
void usage(const char* command) {
cout <<
" \n"
"Analyzes **kern data and generates a **qual spine which gives the chord \n"
"quality of the **kern spines. Currently, input spines cannot split or \n"
"join. \n"
" \n"
"Usage: " << command << " [-a][-i|-r|-t] [input1 [input2 ...]] \n"
" \n"
"Options: \n"
" -a = assemble the **qual analysis spine with input data \n"
" -i = displays the **qual chord inversion only \n"
" -r = displays the **qual chord root only \n"
" -t = displays the **qual chord type only \n"
" --options = list of all options, aliases and default values \n"
" \n"
<< endl;
}
// md5sum: 41b8dfccab65e3f404834dfabc088b25 sonority1.cpp [20090626]