kopia lustrzana https://github.com/ag1le/morse-wip
758 wiersze
18 KiB
C++
758 wiersze
18 KiB
C++
// ----------------------------------------------------------------------------
|
|
// bmorse.c -- bayesian morse code decoder
|
|
//
|
|
// Copyright (C) 2012-2014 Mauri Niininen, AG1LE
|
|
//
|
|
// This file is part of Bayesian Morse code decoder
|
|
// Parts of this is adapted from FLDIGI cw.cxx
|
|
// Copyright (C) 2006-2010 Dave Freese, W1HKJ
|
|
// Parts of this is adapted from sndfile-spectrogram
|
|
// Copyright (C) 2007-2009 Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
//
|
|
// bmorse is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// bmorse is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with bmorse. If not, see <http://www.gnu.org/licenses/>.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
#include <sndfile.h>
|
|
#include <fftw3.h>
|
|
#include "complex.h"
|
|
#include "window.h"
|
|
#include "bmorse.h"
|
|
#include "fftfilt.h"
|
|
|
|
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof (x [0])))
|
|
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
|
#define MIN_WIDTH 640
|
|
#define MIN_HEIGHT 480
|
|
#define MAX_WIDTH 65536
|
|
#define MAX_HEIGHT 4096
|
|
#define TWOPI 2.0*M_PI
|
|
#define DEC_RATIO 20
|
|
|
|
/*
|
|
{ int print_variables ; // FALSE
|
|
int print_symbols; // FALSE
|
|
int process_textfile; // FALSE
|
|
int print_text; // FALSE
|
|
int print_xplot; // FALSE
|
|
int width; // 8192
|
|
int speclen ; // 32
|
|
int bfv; // 0
|
|
double frequency; // 600
|
|
double sample_duration; // 5
|
|
double sample_rate; // 0
|
|
double delta; // 10.0
|
|
double amplify; // 0.0
|
|
int fft; // 0
|
|
int agc; // 0
|
|
int speed; // 20
|
|
int dec_ratio; // 20 (4000 Hz/ 20 => 200 Hz ) decimation ratio samplerate / bayes decoder rate
|
|
*/
|
|
PARAMS params = {
|
|
FALSE, FALSE, FALSE, FALSE, FALSE, 8192, 32, 0, 600, 5, 4000, 10.0, 0.0, 0, 0,20,20};
|
|
|
|
fftfilt *FFT_filter;
|
|
|
|
|
|
double filter(double a, int len)
|
|
{
|
|
static double in[2000];
|
|
static double out;
|
|
static int i, pint;
|
|
static int empty = 1;
|
|
|
|
if ((len == 0) || (len ==1)) {
|
|
return a;
|
|
}
|
|
if (empty) {
|
|
empty = 0;
|
|
for (i = 0; i < len; i++) {
|
|
in[i] = a;
|
|
}
|
|
out = a * len;
|
|
pint = 0;
|
|
return a;
|
|
}
|
|
out = out - in[pint] + a;
|
|
in[pint] = a;
|
|
if (++pint >= len) pint = 0;
|
|
return out / len;
|
|
}
|
|
|
|
double decayavg(double average, double input, double weight)
|
|
{
|
|
if (weight <= 1.0) return input;
|
|
return input * (1.0 / weight) + average * (1.0 - (1.0 / weight));
|
|
}
|
|
|
|
sf_count_t sfx_mix_mono_read_double (SNDFILE * file, double * data, sf_count_t datalen)
|
|
{
|
|
SF_INFO info ;
|
|
|
|
#if HAVE_SF_GET_INFO
|
|
/*
|
|
** The function sf_get_info was in a number of 1.0.18 pre-releases but was removed
|
|
** before 1.0.18 final and replaced with the SFC_GET_CURRENT_SF_INFO command.
|
|
*/
|
|
sf_get_info (file, &info) ;
|
|
#else
|
|
sf_command (file, SFC_GET_CURRENT_SF_INFO, &info, sizeof (info)) ;
|
|
#endif
|
|
|
|
if (info.channels == 1)
|
|
return sf_read_double (file, data, datalen) ;
|
|
|
|
static double multi_data [2048] ;
|
|
int k, ch, frames_read ;
|
|
sf_count_t dataout = 0 ;
|
|
|
|
while (dataout < datalen)
|
|
{ int this_read ;
|
|
|
|
this_read = MIN (ARRAY_LEN (multi_data) / info.channels, datalen) ;
|
|
|
|
frames_read = sf_readf_double (file, multi_data, this_read) ;
|
|
if (frames_read == 0)
|
|
break ;
|
|
|
|
for (k = 0 ; k < frames_read ; k++)
|
|
{ double mix = 0.0 ;
|
|
|
|
for (ch = 0 ; ch < info.channels ; ch++)
|
|
mix += multi_data [k * info.channels + ch] ;
|
|
data [dataout + k] = mix / info.channels ;
|
|
} ;
|
|
|
|
dataout += this_read ;
|
|
} ;
|
|
|
|
return dataout ;
|
|
} /* sfx_mix_mono_read_double */
|
|
|
|
|
|
static void read_mono_audio (SNDFILE * file, sf_count_t filelen, double * data, int datalen, int indx, int total)
|
|
{
|
|
sf_count_t start;
|
|
|
|
memset (data, 0, datalen * sizeof (data [0])) ;
|
|
|
|
|
|
start = (indx * filelen) / total - datalen / 2 ;
|
|
|
|
if (start >= 0)
|
|
sf_seek (file, start, SEEK_SET) ;
|
|
else
|
|
{ start = -start ;
|
|
sf_seek (file, 0, SEEK_SET) ;
|
|
data += start ;
|
|
datalen -= start ;
|
|
} ;
|
|
|
|
sfx_mix_mono_read_double (file, data, datalen) ;
|
|
|
|
return ;
|
|
} /* read_mono_audio */
|
|
|
|
static double calc_magnitude (const double * freq, int freqlen, double * magnitude)
|
|
{
|
|
int k ;
|
|
double max = 0.0 ;
|
|
|
|
for (k = 1 ; k < freqlen / 2 ; k++)
|
|
{ magnitude [k] = sqrt (freq [k] * freq [k] + freq [freqlen - k - 1] * freq [freqlen - k - 1]) ;
|
|
max = MAX (max, magnitude [k]) ;
|
|
} ;
|
|
magnitude [0] = 0.0 ;
|
|
|
|
return max ;
|
|
} /* calc_magnitude */
|
|
|
|
|
|
#define PEAKS_SIZE 2000
|
|
|
|
struct PEAKS {
|
|
double mx[PEAKS_SIZE];
|
|
double mn[PEAKS_SIZE];
|
|
int mxpos[PEAKS_SIZE];
|
|
int mnpos[PEAKS_SIZE];
|
|
int mxcount;
|
|
int mncount;
|
|
double delta;
|
|
};
|
|
|
|
|
|
// peak_detect() detects peaks in a vector *******************************************************************************
|
|
// Finds the local maxima and minima ("peaks") in the vector V.
|
|
// A point is considered a maximum peak if it has the maximal
|
|
// value, and was preceded (to the left) by a value lower by DELTA.
|
|
|
|
void peak_detect(double *v, int length, struct PEAKS *p)
|
|
{
|
|
|
|
int i, lookformax;
|
|
double value, mn,mx;
|
|
int mnpos,mxpos;
|
|
|
|
p->mxcount = 0;
|
|
p->mncount = 0;
|
|
|
|
|
|
if (p->delta <= 0) {
|
|
printf ("%s : line %d :Input argument DELTA must be positive.\n", __FILE__, __LINE__) ;
|
|
exit (1) ;
|
|
}
|
|
|
|
mn = 1.0/0.0;
|
|
mx = -1.0/0.0;
|
|
mnpos = -10000; mxpos = 10000;
|
|
lookformax = 1;
|
|
|
|
for (i=0; i< length; i++) {
|
|
value = v[i];
|
|
if (value > mx) {mx = value; mxpos = i;}
|
|
if (value < mn) {mn = value; mnpos = i;}
|
|
|
|
if (lookformax){
|
|
if (value < mx-p->delta) {
|
|
p->mx[p->mxcount] = mx;
|
|
p->mxpos[p->mxcount] = mxpos;
|
|
p->mxcount += 1;
|
|
mn = value; mnpos = i;
|
|
lookformax = 0;
|
|
};
|
|
} else {
|
|
if (value > mn+p->delta) {
|
|
p->mn[p->mncount] = mn;
|
|
p->mnpos[p->mncount] = mnpos;
|
|
p->mncount += 1;
|
|
mx = value; mxpos = i;
|
|
lookformax = 1;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
static void apply_window (double * data, int datalen)
|
|
{
|
|
static double window [10 * MAX_HEIGHT] ;
|
|
static int window_len = 0 ;
|
|
int k ;
|
|
|
|
if (window_len != datalen)
|
|
{
|
|
window_len = datalen ;
|
|
if (datalen > ARRAY_LEN (window))
|
|
{
|
|
printf ("%s : datalen > MAX_HEIGHT\n", __func__) ;
|
|
exit (1) ;
|
|
} ;
|
|
|
|
calc_kaiser_window (window, datalen, 20.0) ;
|
|
// calc_nuttall_window (window, datalen);
|
|
} ;
|
|
|
|
for (k = 0 ; k < datalen ; k++)
|
|
data [k] *= window [k] ;
|
|
|
|
return ;
|
|
} /* apply_window */
|
|
|
|
static void interp_spec (float * mag, int maglen, const double *spec, int speclen)
|
|
{
|
|
int k, lastspec = 0 ;
|
|
|
|
mag [0] = spec [0] ;
|
|
|
|
for (k = 1 ; k < maglen ; k++) {
|
|
double sum = 0.0 ;
|
|
int count = 0 ;
|
|
|
|
do {
|
|
sum += spec [lastspec] ;
|
|
lastspec ++ ;
|
|
count ++ ;
|
|
}
|
|
while (lastspec <= ceil ((k * speclen) / maglen)) ;
|
|
|
|
mag [k] = sum / count ;
|
|
|
|
} ;
|
|
|
|
return ;
|
|
} /* interp_spec */
|
|
|
|
void process_data(double x)
|
|
{
|
|
static integer sample_counter = 0;
|
|
static real rn = .1f;
|
|
static integer retstat, n1, n2, imax, xhat, elmhat;
|
|
static real pmax, zout, spdhat, px;
|
|
static int init = 1;
|
|
static double agc_peak = 0.1;
|
|
|
|
if (params.amplify != 0.0)
|
|
x = params.amplify * x;
|
|
|
|
if (params.agc) {
|
|
|
|
if (x > agc_peak)
|
|
agc_peak = decayavg(agc_peak, x, 20);
|
|
else
|
|
agc_peak = decayavg(agc_peak, x, 800);
|
|
|
|
if (agc_peak != 0.0)
|
|
x /= agc_peak;
|
|
else
|
|
x = 0.0;
|
|
}
|
|
|
|
|
|
if (params.print_xplot)
|
|
printf("\n%f",x);
|
|
|
|
if (params.print_variables && init) { //print variable labels first (only once) iu
|
|
printf("\nretstat\timax\telmhat\txhat\tx\tpx\tpmax\tspdhat\trn\tzout\tp1\tp2\tp3\tp4\tp5\tp6\n");
|
|
init = 0;
|
|
}
|
|
|
|
noise_(x, &rn, &zout);
|
|
|
|
// if (zout > 1.0) zout = 1.0;
|
|
// if (zout < 0.0) zout = 0.0;
|
|
|
|
retstat = proces_(&zout, &rn, &xhat, &px, &elmhat, &spdhat, &imax, &pmax, params.speed);
|
|
if (params.print_variables)
|
|
printf("\n%d\t%d\t%d\t%d\t%f\t%f\t%f\t%f\t%f\t%f",(int)retstat,(int)imax,(int)elmhat,(int)xhat,x,px,pmax,spdhat,rn,zout);
|
|
|
|
|
|
}
|
|
|
|
int rx_FFTprocess(const double *buf, int len)
|
|
{
|
|
complex z, *zp;
|
|
int n,i;
|
|
static int smpl_ctr = 0;
|
|
static double FFTvalue,FFTphase =0.0;
|
|
|
|
while (len-- > 0) {
|
|
// convert CW signal to baseband
|
|
z = complex ( *buf * cos(FFTphase), *buf * sin(FFTphase) );
|
|
FFTphase += TWOPI * params.frequency / params.sample_rate;
|
|
if (FFTphase > M_PI)
|
|
FFTphase -= TWOPI;
|
|
else if (FFTphase < M_PI)
|
|
FFTphase += TWOPI;
|
|
|
|
buf++;
|
|
|
|
// run low pass filter
|
|
n = FFT_filter->run(z, &zp); // n = 0 or filterlen/2
|
|
|
|
if (!n) continue;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
|
|
|
|
// update the basic sample counter used for morse timing
|
|
++smpl_ctr;
|
|
if (smpl_ctr % params.dec_ratio) continue; // decimate by DEC_RATIO
|
|
|
|
// demodulate
|
|
FFTvalue = zp[i].mag();
|
|
// run envelope filter
|
|
FFTvalue = filter(FFTvalue,params.bfv);
|
|
|
|
process_data(FFTvalue);
|
|
|
|
} // for (i =0; i < n ...
|
|
|
|
} //while (len-- > 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
decode_sndfile (SNDFILE *infile, SF_INFO info)
|
|
{
|
|
|
|
|
|
static double time_domain [10 * MAX_HEIGHT] ;
|
|
static double freq_domain [10 * MAX_HEIGHT] ;
|
|
static double single_mag_spec [5 * MAX_HEIGHT] ;
|
|
static float mag_spec [MAX_WIDTH][MAX_HEIGHT] ;
|
|
static struct PEAKS p;
|
|
|
|
static int once=1;
|
|
|
|
fftw_plan plan ;
|
|
double x, max_mag = 0.0 ;
|
|
int width = 8192, height= 32, w, speclen ;
|
|
|
|
int f,sr,sc =0,c,num_items,num,i,j;
|
|
double *buf;
|
|
int bfv; // bit filter value
|
|
|
|
// speclen should be multiple of 2^n but also keep time resolution < 5 ms
|
|
// for 48Khz sampling rate speclen 64 represents 2.6667 ms sample time??
|
|
//
|
|
|
|
|
|
/* Print some of the info, and figure out how much data to read. */
|
|
f = info.frames;
|
|
sr = info.samplerate;
|
|
params.sample_rate = info.samplerate;
|
|
params.dec_ratio = info.samplerate / BAYES_RATE;
|
|
c = info.channels;
|
|
num_items = f*c;
|
|
|
|
|
|
|
|
// bit filter based on 10 msec rise time of CW waveform or manually set
|
|
if (params.bfv !=0)
|
|
bfv = params.bfv;
|
|
else
|
|
bfv = sr/100; // Samplerate / 100 => bfv value required for 10 msec rise time
|
|
|
|
speclen = params.speclen;
|
|
p.delta = params.delta;
|
|
//params.sample_duration= (2.0*speclen*1000.0)/((double)16*sr);
|
|
|
|
printf("frames=%d\n",f);
|
|
printf("channels=%d\n",c);
|
|
printf("samplerate=%d\n",sr);
|
|
printf("dec_ratio=%d\n",params.dec_ratio);
|
|
printf("bit filter=%d\n",bfv);
|
|
printf("num_items=%d\n",num_items);
|
|
printf("sample_duration=%f\n",params.sample_duration);
|
|
printf("bitfilter=%d\n",params.bfv);
|
|
printf("speed(WPM):%d\n",params.speed);
|
|
printf("FFT filter %f\n",(params.speed/(1.2 * params.sample_rate)));
|
|
|
|
|
|
|
|
if (params.fft) {
|
|
// speclen = 16; // 16 ok for 4000 Hz test60db.wav @16384 width
|
|
// 64 for 48000 Hz capture.wav @4096 w or 2048
|
|
width = params.width;
|
|
|
|
if (2 * speclen > ARRAY_LEN (time_domain))
|
|
{ printf ("%s : 2 * speclen > ARRAY_LEN (time_domain)\n", __func__) ;
|
|
exit (1) ;
|
|
} ;
|
|
// fprintf(stderr,"\nsamplerate:%d\nwidth:%d\nspeclen:%d\nsample duration:%f\n", samplerate,width, speclen,params.sample_duration);
|
|
|
|
plan = fftw_plan_r2r_1d (2 * speclen, time_domain, freq_domain, FFTW_R2HC, FFTW_MEASURE | FFTW_PRESERVE_INPUT) ;
|
|
if (plan == NULL)
|
|
{ printf ("%s : line %d : create plan failed.\n", __FILE__, __LINE__) ;
|
|
exit (1) ;
|
|
} ;
|
|
|
|
|
|
|
|
for (w = 0 ; w < width ; w++)
|
|
{ double single_max ;
|
|
|
|
read_mono_audio (infile, info.frames, time_domain, 2 * speclen, w, width) ;
|
|
apply_window (time_domain, 2 * speclen) ;
|
|
fftw_execute (plan) ;
|
|
|
|
single_max = calc_magnitude (freq_domain, 2 * speclen, single_mag_spec) ;
|
|
|
|
// print one FFT row - just to check
|
|
/*
|
|
if (once) {
|
|
for (int i=0; i< speclen; i++)
|
|
printf("\n%f",single_mag_spec[i]);
|
|
once=0;
|
|
}
|
|
*/
|
|
|
|
// detect peaks in the FFT spectrum
|
|
peak_detect(single_mag_spec, speclen, &p);
|
|
|
|
// print found freq peaks - only once
|
|
if (once ) {
|
|
for (i=0; i <p.mxcount; i++) {
|
|
int Hz = (p.mxpos[i]*(sr/2))/(speclen);
|
|
printf("peak[%d]:%f\tHz:%d\tmaxcount:%d\n",p.mxpos[i],p.mx[i],Hz,p.mxcount);
|
|
}
|
|
once=0;
|
|
}
|
|
|
|
|
|
|
|
max_mag = MAX (max_mag, single_max) ;
|
|
single_max = filter(single_max,bfv);
|
|
process_data(single_max/max_mag); // decode Morse code here
|
|
|
|
// interp_spec (mag_spec [w], height, single_mag_spec, speclen) ;
|
|
} ;
|
|
|
|
fftw_destroy_plan (plan) ;
|
|
|
|
} else { // use FLDIGI CW.CXX FFT filtering
|
|
|
|
//overlap and add filter length should be a factor of 2
|
|
// low pass implementation
|
|
int FilterFFTLen = 4096;
|
|
FFT_filter = new fftfilt((params.speed*20)/(1.2 * params.sample_rate), FilterFFTLen);
|
|
|
|
/* Allocate space for the data to be read, then read it. */
|
|
buf = (double *) malloc(num_items*sizeof(double));
|
|
if (buf == 0) {
|
|
printf ("%s : line %d :out of memory.\n", __FILE__, __LINE__) ;
|
|
exit (1) ;
|
|
}
|
|
|
|
num = sf_read_double(infile,buf,num_items);
|
|
printf("Read %d items\n",num);
|
|
|
|
for (i = 0; i < num; i += 512){
|
|
|
|
rx_FFTprocess(buf, 512);
|
|
buf += 512;
|
|
|
|
/*
|
|
if (x < 0) x = -x;
|
|
x = filter(x,bfv);
|
|
sc++;
|
|
if ((sc % dec_ratio)==0) { // 48 kHz to 200 Hz - decimate samples by 240
|
|
|
|
|
|
|
|
process_data(x);
|
|
*/
|
|
|
|
}
|
|
//free(buf);
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
static void
|
|
process_sndfile (char * filename)
|
|
{
|
|
SNDFILE *infile ;
|
|
SF_INFO info ;
|
|
|
|
memset (&info, 0, sizeof (info)) ;
|
|
|
|
infile = sf_open (filename, SFM_READ, &info) ;
|
|
if (infile == NULL)
|
|
{ printf ("Error : failed to open sound file '%s' : \n%s\n", filename, sf_strerror (NULL)) ;
|
|
return ;
|
|
} ;
|
|
|
|
decode_sndfile ( infile, info) ;
|
|
|
|
sf_close (infile);
|
|
|
|
return ;
|
|
} /* render_sndfile */
|
|
|
|
|
|
|
|
|
|
|
|
static void process_textfile(char *filename)
|
|
{
|
|
FILE *fp;
|
|
float x;
|
|
int res;
|
|
static int samplecounter =0;
|
|
|
|
fp = fopen(filename, "r");
|
|
if (fp == NULL) {
|
|
printf("\nError : failed to open text file '%s' : \n", filename);
|
|
return;
|
|
}
|
|
while (1) {
|
|
res = fscanf(fp,"%f",&x);
|
|
if ( res != 1) {
|
|
fclose(fp);
|
|
printf("\n");
|
|
exit(0);
|
|
}
|
|
samplecounter++;
|
|
if ((samplecounter % 20) == 0) { // assuming that text envelope files have 4000 Hz sampling rate, decimate by 20 to get to 200 Hz (5ms sample time)
|
|
process_data((double)x);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void usage_exit (const char * argv0)
|
|
{
|
|
const char * progname ;
|
|
|
|
progname = strrchr (argv0, '/') ;
|
|
progname = (progname == NULL) ? argv0 : progname + 1 ;
|
|
|
|
puts ("\nBayesian Morse Decoder program reads sound file and decodes CW to text.") ;
|
|
|
|
printf ("\nUsage :\n\n %s [options] <sound file> \n\n", progname) ;
|
|
|
|
puts (
|
|
" Options include:\n\n"
|
|
" -var Print variables for post-analysis (default off).\n"
|
|
" -sym Print symbols before translation (default off). \n"
|
|
" -txt Print decoded and translated text (default off).\n"
|
|
" -txf Process text file instead of soundfile.\n"
|
|
" -agc Use Automatic Gain Control (default off).\n"
|
|
" -bfv <value> Bit filter value (default 10 msec).\n"
|
|
" -frq <value> CW signal frequency (default 600 Hz).\n"
|
|
" -fft <value> Enable FFT filtering (default 0 - off) \n"
|
|
" -plt Plot envelope using xplot: ./morse -plt <sndfile> | xplot \n"
|
|
" -spd <value> Set default speed in WPM for decoder (default 20 ) \n"
|
|
" -len <length> Window length for FFT [8,16,32,64,128...].\n"
|
|
" -wid <width> Width of buffer to read & process [8192, 16384].\n"
|
|
" -dur <duration> Sample duration in msec [5.0] used in path.c.\n"
|
|
" -del <delta> Peak detection delta [10.0].\n"
|
|
|
|
|
|
) ;
|
|
|
|
puts (
|
|
" -txf: The text file contains real valued input (1 datapoint per line) to be decoded.\n"
|
|
" Default: The sound file type is determined by the file name extension which should be one\n"
|
|
" of 'wav', 'aifc', 'aif', 'aiff', 'au', 'caf' and 'w64'.\n"
|
|
) ;
|
|
|
|
exit (0) ;
|
|
} /* usage_exit */
|
|
|
|
|
|
|
|
|
|
// MAIN PROGRAM = BAYESIAN MORSE DECODER
|
|
// (c) Mauri Niininen AG1LE
|
|
//
|
|
|
|
int main(int argc, const char* argv[])
|
|
{
|
|
/* Initialized data */
|
|
|
|
|
|
int k;
|
|
|
|
int s_stop(char *, ftnlen);
|
|
|
|
/* Local variables */
|
|
|
|
int res;
|
|
FILE *fp;
|
|
|
|
/* PARSE PARAMETERS FROM COMMAND LINE */
|
|
|
|
if (argc < 2)
|
|
usage_exit (argv [0]) ;
|
|
|
|
for (k = 1 ; k < argc; k++) {
|
|
if (strcmp (argv [k], "-bfv") == 0){
|
|
k++ ;
|
|
params.bfv = atoi (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-wid") == 0){
|
|
k++ ;
|
|
params.width = atoi (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-len") == 0) {
|
|
k++ ;
|
|
params.speclen = atoi (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-fft") == 0){
|
|
k++ ;
|
|
params.fft = atoi (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-dur") == 0){
|
|
k++ ;
|
|
params.sample_duration = atof (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-del") == 0){
|
|
k++ ;
|
|
params.delta = atof (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-spd") == 0){
|
|
k++ ;
|
|
params.speed = atoi (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-frq") == 0){
|
|
k++ ;
|
|
params.frequency = atof (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-amp") == 0){
|
|
k++ ;
|
|
params.amplify = atof (argv [k]) ;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-var") == 0){
|
|
params.print_variables = TRUE;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-sym") == 0){
|
|
params.print_symbols = TRUE;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-agc") == 0){
|
|
params.agc = TRUE;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-txt") == 0){
|
|
params.print_text = TRUE;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-txf") == 0){
|
|
params.process_textfile = TRUE;
|
|
continue ;
|
|
}
|
|
if (strcmp (argv [k], "-plt") == 0){
|
|
params.print_xplot = TRUE;
|
|
continue ;
|
|
}
|
|
} ;
|
|
|
|
/* INITIALIZE DATA STRUCTURES */
|
|
initl_();
|
|
|
|
if(params.process_textfile)
|
|
process_textfile((char *)argv[k-1]);
|
|
else
|
|
process_sndfile((char *)argv[k-1]);
|
|
|
|
|
|
} /* MAIN__ */
|
|
|
|
|
|
|
|
|
|
|