//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sun Sep 30 23:06:34 PDT 2007
// Last Modified: Tue Oct 2 04:57:29 PDT 2007
// Filename: ...sig/examples/all/smoother.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/smoother.cpp
// Syntax: C++; museinfo
//
// Description: Smoothes data with exponential smoothing filter.
//
#include "humdrum.h"
#include <stdlib.h>
#include <math.h>
#ifndef OLDCPP
using namespace std;
#endif
#define GEOMETRIC 1
#define ARITHMETIC 2
#define EMPTY 0
#define PEAK 1
#define VALLEY 2
///////////////////////////////////////////////////////////////////////////
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void example(void);
void usage(const char* command);
void processFile(HumdrumFile& infile);
void smoothData(Array<double>& output,
Array<double>& input, double gain);
void generateRow(Array<char>& imagerow, int row, int rows,
double gain, Array<double>& sequence);
void printImage(Array<Array<char> >& image);
// global variables
Options options; // database for command-line arguments
double sgain = 0.05; // maximum smoothing amount
int height = 100; // number of pixels high for image
// (width controlled by sequence length)
int method = GEOMETRIC; // GEOMETRIC or ARITHMETIC interpolation
// betwin lines in image.
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
HumdrumFile infile;
// process the command-line options
checkOptions(options, argc, argv);
const char* filename;
infile.clear();
// if no command-line arguments read data file from standard input
int numinputs = options.getArgCount();
if (numinputs < 1) {
infile.read(cin);
} else {
filename = options.getArg(1);
infile.read(options.getArg(1));
}
processFile(infile);
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// processFile -- only read the first row for processing for now...
//
void processFile(HumdrumFile& infile) {
Array<double> sequence;
sequence.setSize(infile.getNumLines());
sequence.setSize(0);
double value;
int i;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() == E_humrec_data) {
value = atof(infile[i][0]);
sequence.append(value);
}
}
int thesize = sequence.getSize();
Array<Array<char> > image;
image.setSize(height);
image.allowGrowth(0);
for (i=0; i<height; i++) {
image[i].setSize(thesize);
image[i].allowGrowth(0);
image[i].setAll(0);
generateRow(image[i], i, height, sgain, sequence);
}
printImage(image);
}
//////////////////////////////
//
// printImage --
//
void printImage(Array >& image) {
cout << "P3\n";
cout << image[0].getSize() << " " << image.getSize() << "\n";
cout << "255\n";
int i, j;
for (i=0; i<image.getSize(); i++) {
for (j=0; j<image[i].getSize(); j++) {
switch (image[i][j]) {
case PEAK: cout << "255 0 0"; break;
case VALLEY: cout << "0 0 255"; break;
default: cout << "255 255 255";
}
if (j<image[i].getSize()-1) {
cout << " ";
}
}
cout << "\n";
}
}
//////////////////////////////
//
// generateRow --
//
void generateRow(Array<char>& imagerow, int row, int rows, double gain,
Array<double>& sequence) {
Array<double> smoothed;
double localgain;
if (method == GEOMETRIC) {
localgain = gain * pow(1.0 / gain, (double)row/(rows-1));
} else {
localgain = (double)row/(rows-1) * (1.0 - gain);
}
smoothData(smoothed, sequence, localgain);
int i;
for (i=2; i<imagerow.getSize()-2; i++) {
if (smoothed[i] > smoothed[i-1] && smoothed[i] > smoothed[i+1] &&
smoothed[i] > smoothed[i-2] && smoothed[i] > smoothed[i+2] ) {
imagerow[i] = PEAK;
} else if (smoothed[i] < smoothed[i-1] && smoothed[i] < smoothed[i+1] &&
smoothed[i] < smoothed[i-2] && smoothed[i] < smoothed[i+2] ) {
imagerow[i] = VALLEY;
}
}
}
//////////////////////////////
//
// smoothData --
//
void smoothData(Array& output, Array& input, double gain) {
int thesize = input.getSize();
output.setSize(thesize);
double filterk = gain;
double oneminusk = 1.0 - filterk;
// reverse filtering first
output[thesize-1] = input[thesize-1];
int i;
for (i=thesize-2; i>=0; i--) {
output[i] = filterk*input[i] + oneminusk*output[i+1];
}
// then forward filtering
for (i=1; i<thesize; i++) {
output[i] = filterk*output[i] + oneminusk*output[i-1];
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("s|smooth=d:0.05"); // smoothing factor limit
opts.define("r|rows=i:100"); // number of rows in the image
opts.define("A|arithmetic=b"); // do arithmetic rather than geometric
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 2007" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 1 Oct 2007" << 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);
}
sgain = opts.getDouble("smooth");
height = opts.getInteger("rows");
if (opts.getBoolean("arithmetic")) {
method = ARITHMETIC;
}
}
//////////////////////////////
//
// example -- example usage of the program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
// md5sum: 8c27480c3a73647fa55856f922638a54 levogram.cpp [20080518]