Goto: [ Program Documentation ]
//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Fri Apr 24 01:54:14 PDT 1998
// Last Modified: Fri Apr 24 01:54:20 PDT 1998
// Filename: ...sig/doc/examples/sig/sigfile/sinebark/sinebark.cpp
// Syntax: C++; sig
//
// Description: makes a soundfile with the specified number
// of sinewaves per critical band.
//
#include "sigAudio.h"
#include <stdlib.h>
#include <time.h>
#include <math.h>
#ifndef OLDCPP
#include <iostream>
using namespace std;
#else
#include <iostream.h>
#endif
void checkOptions(Options& opts);
void example(void);
void usage(const char* command);
double* createFrequencyArray(const char* method, int count);
double freq2bark(double freqValue);
double bark2freq(double barkValue);
double Bark[26] = {
0, 100, 200, 300, 400, 500, 630, 770, 920, 1080, 1270, 1480,
1720, 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700,
9500, 12000, 15500, 20000};
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
Options options(argc, argv);
checkOptions(options);
// determine how many samples in the output based on the duration
int numSamples;
if (options.getInt("samples") > 0) {
numSamples = options.getInt("samples");
} else {
numSamples = (int)(options.getDouble("duration") * 44100 + 0.5);
}
// determine if the random number generator needs to be seeded:
if (options.getInt("seed") != 0) {
srand(options.getInt("seed"));
} else {
srand(time(NULL));
}
// prepare for a monophonic output file
SoundHeader header;
header.setHighMono();
// determine how many sines per critical band
int count = options.getInt("number");
double *frequencies;
frequencies = createFrequencyArray(options.getString("method"), count);
// Elements:
Osc *oscillators = new Osc[count*25];
Add add;
Scale scale(options.getDouble("amplitude")/(count*25.0));
SoundFileOut outsound(options.getArg(1), header);
int print = options.getBoolean("print");
// Connections:
for (int i=0; i<count*25; i++) {
oscillators[i].setPhase((double)rand()/RAND_MAX);
oscillators[i].connect(frequencies[i], 0);
add.connect(oscillators[i]);
if (print) {
cout << frequencies[i] << '\n';
}
}
scale.connect(add);
outsound.connect(scale);
Action action;
action.tick(outsound, numSamples);
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// checkOptions -- handle command-line options.
//
void checkOptions(Options& opts) {
opts.define("a|amp|amplitude=d:1");
opts.define("d|dur|duration=d:1.0 second");
opts.define("s|samples=i");
opts.define("e|seed=i");
opts.define("m|method=s:equal");
opts.define("n|number=i:1");
opts.define("p|print=b");
opts.define("author=b");
opts.define("version=b");
opts.define("example=b");
opts.define("help=b");
opts.process();
if (opts.getBoolean("author")) {
cout << "Written by Craig Stuart Sapp, "
<< "craig@ccrma.stanford.edu, April 1998" << endl;
exit(0);
}
if (opts.getBoolean("version")) {
cout << "compiled: " << __DATE__ << endl;
cout << SIG_VERSION << endl;
exit(0);
}
if (opts.getBoolean("help")) {
usage(opts.getCommand());
exit(0);
}
if (opts.getBoolean("example")) {
example();
exit(0);
}
// can only have one output filename
if (opts.getArgCount() == 0) {
cout << "Error: need one output file name." << endl;
usage(opts.getCommand());
exit(1);
} else if (opts.getArgCount() > 1) {
cout << "Error: too many arguments. Given "
<< opts.getArgCount() << " but need only 1." << endl;
usage(opts.getCommand());
exit(1);
}
}
//////////////////////////////
//
// example -- gives example calls to the sinebark program.
//
void example(void) {
cout <<
"# sinebark examples: \n"
"# 10 randomly distributed sines in each critical band region for 3 sec:\n"
" sinebark -m random -n -d 3 band10.snd \n"
<< endl;
}
//////////////////////////////
//
// usage -- how to run the osc program on the command line.
//
void usage(const char* command) {
cout <<
" \n"
"Creates sinewaves spaced equally on the basilar membrane or uniform \n"
"randomly distributed in each of 25 adjacent critical band regions. \n"
" \n"
"Usage: " << command << " [-d duration| -s samples][-a amp][-m method] \n"
" [-n numuber][-p] outsound \n"
" \n"
"Options: \n"
" -d = duration of the oscillator in seconds (default 1.0). \n"
" -s = duration in samples. Overrides the -d option (default null) \n"
" -a = amplitude of output (default 0.5). \n"
" -n = number of sines to generate in each adjacent critical band \n"
" (default 1) \n"
" -m = method for distributing sines in critical band: \n"
" equal = equally spaced, random = ramdomly spaced \n"
" (default equal) \n"
" -p = print the frequencies of the sinewaves being created. \n"
" --options = list of all options, aliases and default values. \n"
" \n"
" \n"
<< endl;
}
//////////////////////////////
//
// createFrequencyArray -- creates a list of the frequencies
// from bark values based on spacing method and number
// of sinewaves per critical band.
//
double* createFrequencyArray(const char* method, int count) {
double* output;
output = new double[count*25];
double step;
int i, j;
if (strcmp(method, "random") == 0) {
for (i=0; i<25; i++) {
for (j=0; j<count; j++) {
output[i*count+j] = bark2freq(i + (double)rand()/RAND_MAX);
}
}
} else if (strcmp(method, "equal") == 0) {
step = 1.0/count;
for (i=0; i<25*count; i++) {
output[i] = bark2freq((i+0.5)*step);
}
} else if (strcmp(method, "harmonic") == 0) {
step = 22050/(25*count);
for (i=0; i<25*count; i++) {
output[i] = (i+1)*step;
}
} else {
cout << "Error: unknown distribution method: " << method << endl;
exit(1);
}
return output;
}
//////////////////////////////
//
// freq2bark -- converts frequency in Hertz to the Bark scale.
//
double freq2bark(double freqValue) {
if (freqValue <= 500.0) { // linear bark region
return freqValue/100.0;
} else if (freqValue >= 20000.0) { // out of audible range
return 25.0;
} else { // logarithmic bark region
int index = 6;
while (freqValue >= Bark[index]) {
index++;
}
// index now points to bark value just higher than freqValue.
// Use linear interpolation on the logarighmic scale to
// find intermediate bark value.
return index - fabs((log(Bark[index])-log(freqValue)) /
(log(Bark[index])-log(Bark[index-1])));
}
}
//////////////////////////////
//
// bark2freq -- converts Bark scale values to frequency in Hertz.
//
double bark2freq(double barkValue) {
if (barkValue <= 5.0) { // linear bark region
return barkValue * 100.0;
} else if (barkValue >= 25.0) { // out of audible range
return 20000.0;
} else { // logarithmic bark region
int index = (int)barkValue;
double fraction = barkValue - index;
return exp((log(Bark[index+1])-log(Bark[index]))*fraction +
log(Bark[index]));
}
}
// md5sum: 397ac79f0710c39d7ad32ae5cdbcefa4 sinebark.cpp [20050403]