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]