summaryrefslogtreecommitdiff
path: root/fxotune.c
diff options
context:
space:
mode:
authorDoug Bailey <dbailey@digium.com>2008-12-16 17:02:47 +0000
committerDoug Bailey <dbailey@digium.com>2008-12-16 17:02:47 +0000
commitd85ad78b34ca529974b16b721e9ebe84ac0f10b6 (patch)
tree1cbd2bfd5f1b03938fbd211123b5148fbf4a3609 /fxotune.c
parent0eaf4b48481fc79514bb205c98738b7e7c6e7ad5 (diff)
Add ability to use sine tables for systems that don't have efficient floating point
Add the ability to print out the best results found during tuning Some format cleanup git-svn-id: http://svn.asterisk.org/svn/dahdi/tools/trunk@5555 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'fxotune.c')
-rw-r--r--fxotune.c192
1 files changed, 171 insertions, 21 deletions
diff --git a/fxotune.c b/fxotune.c
index 77b01ea..c2efd40 100644
--- a/fxotune.c
+++ b/fxotune.c
@@ -4,7 +4,7 @@
*
* by Matthew Fredrickson <creslin@digium.com>
*
- * (C) 2004-2005 Digium, Inc.
+ * (C) 2004-2008 Digium, Inc.
*/
/*
@@ -41,6 +41,9 @@
#define TEST_DURATION 2000
#define BUFFER_LENGTH (2 * TEST_DURATION)
#define SKIP_SAMPLES 800
+#define SINE_SAMPLES 8000
+
+static float sintable[SINE_SAMPLES];
static const float amplitude = 16384.0;
@@ -49,6 +52,21 @@ static char *configfile = "/etc/fxotune.conf";
static int audio_dump_fd = -1;
+static int printbest = 0;
+
+#define MAX_RESULTS (5)
+struct result_catalog {
+ int idx;
+ float echo;
+ float freqres;
+ struct wctdm_echo_coefs settings;
+};
+
+struct {
+ struct result_catalog results[MAX_RESULTS];
+ int numactive;
+} topresults;
+
static char *usage =
"Usage: fxotune [-v[vv] (-s | -i <options> | -d <options>)\n"
"\n"
@@ -61,6 +79,8 @@ static char *usage =
" options : [-b <device>][-w <waveform>]\n"
" [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
" -v : more output (-vv, -vvv also)\n"
+" -p : print the 5 best candidates for acim and coefficients settings\n"
+" -x : Perform sin/cos functions using table lookup\n"
" -o <path> : Write the received raw 16-bit signed linear audio that is\n"
" used in processing to the file specified by <path>\n"
" -c <config_file>\n"
@@ -103,6 +123,8 @@ static int debug = 0;
static FILE *debugoutfile = NULL;
+static int use_table = 0;
+
static int fxotune_read(int fd, void *buffer, int len)
{
int res;
@@ -195,15 +217,15 @@ static int ensure_silence(struct silence_info *info)
* Generates a tone of specified frequency.
*
* @param hz the frequency of the tone to be generated
- * @param index the current sample
+ * @param idx the current sample
* to begenerated. For a normal waveform you need to increment
* this every time you execute the function.
*
* @return 16bit slinear sample for the specified index
*/
-static short inline gentone(int hz, int index)
+static short inline gentone(int hz, int idx)
{
- return amplitude * sin((index * 2.0 * M_PI * hz)/8000);
+ return amplitude * sin((idx * 2.0 * M_PI * hz)/8000);
}
/* Using DTMF tones for now since they provide good mid band testing
@@ -214,18 +236,18 @@ static int freqcount = 6;
/**
* Generates a waveform of several frequencies.
*
- * @param index the current sample
+ * @param idx the current sample
* to begenerated. For a normal waveform you need to increment
* this every time you execute the function.
*
* @return 16bit slinear sample for the specified index
*/
-static short inline genwaveform(int index)
+static short inline genwaveform(int idx)
{
int i = 0;
float response = (float)0;
for (i = 0; i < freqcount; i++){
- response += sin((index * 2.0 * M_PI * freqs[i])/8000);
+ response += sin((idx * 2.0 * M_PI * freqs[i])/8000);
}
@@ -278,7 +300,7 @@ static float power_of(void *prebuf, int bufsize, int short_format)
finalanswer = sum_of_squares/(float)bufsize; /* need to divide by the number of elements in the sample for RMS calc */
if (finalanswer < 0) {
- printf("Error: Final answer negative number %f\n", finalanswer);
+ fprintf(stderr, "Error: Final answer negative number %f\n", finalanswer);
return -3;
}
@@ -304,6 +326,40 @@ static float power_of(void *prebuf, int bufsize, int short_format)
* This essentially filters out any other noise which maybe present on the line which is outside
* the frequencies used in our test multi-tone.
*/
+
+void init_sinetable(void)
+{
+ int i;
+ if (debug) {
+ fprintf(stdout, "Using sine tables with %d samples\n", SINE_SAMPLES);
+ }
+ for (i = 0; i < SINE_SAMPLES; i++) {
+ sintable[i] = sin(((float)i * 2.0 * M_PI )/(float)(SINE_SAMPLES));
+ }
+}
+
+/* Sine and cosine table lookup to use periodicity of the calculations being done */
+float sin_tbl(int arg, int num_per_period)
+{
+ arg = arg % num_per_period;
+
+ arg = (arg * SINE_SAMPLES)/num_per_period;
+
+ return sintable[arg];
+}
+
+float cos_tbl(int arg, int num_per_period)
+{
+ arg = arg % num_per_period;
+
+ arg = (arg * SINE_SAMPLES)/num_per_period;
+
+ arg = (arg + SINE_SAMPLES/4) % SINE_SAMPLES; /* Pi/2 adjustment */
+
+ return sintable[arg];
+}
+
+
static float db_loss(float measured, float reference)
{
return 20 * (logf(measured/reference)/logf(10));
@@ -315,8 +371,13 @@ static void one_point_dft(const short *inbuf, int len, int frequency, float *rea
int i;
for (i = 0; i < len; i++) {
- myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000);
- myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000);
+ if (use_table) {
+ myreal += (float) inbuf[i] * cos_tbl(i*frequency, 8000);
+ myimag += (float) inbuf[i] * sin_tbl(i*frequency, 8000);
+ } else {
+ myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000);
+ myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000);
+ }
}
myimag *= -1;
@@ -325,6 +386,7 @@ static void one_point_dft(const short *inbuf, int len, int frequency, float *rea
*imaginary = myimag / (float) len;
}
+
static float calc_magnitude(short *inbuf, int insamps)
{
float real, imaginary, magnitude;
@@ -340,6 +402,7 @@ static float calc_magnitude(short *inbuf, int insamps)
return totalmagnitude;
}
+
/**
* dumps input and output buffer contents for the echo test - used to see exactly what's going on
*/
@@ -422,15 +485,15 @@ retry:
/* read return response */
res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH);
if (res != BUFFER_LENGTH) {
- int x;
+ int dummy;
- ioctl(whichdahdi, DAHDI_GETEVENT, &x);
+ ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
goto retry;
}
/* write content of output buffer to debug file */
- power_result = power_of(inbuf, TEST_DURATION, 1);
- power_waveform = power_of(outbuf, TEST_DURATION, 1);
+ power_result = power_of(inbuf, TEST_DURATION, 1);
+ power_waveform = power_of(outbuf, TEST_DURATION, 1);
echo = power_result/power_waveform;
fprintf(outfile, "Buffers, freq=%d, outpower=%0.0f, echo=%0.4f\n", freq, power_result, echo);
@@ -451,6 +514,73 @@ retry:
}
+/**
+ * Initialize the data store for storing off best calculated results
+ */
+static void init_topresults(void)
+{
+ topresults.numactive = 0;
+}
+
+
+/**
+ * If this is a best result candidate, store in the top results data store
+ * This is dependent on being the lowest echo value
+ *
+ * @param tbleoffset - The offset into the echo_trys table used
+ * @param setting - Pointer to the settings used to achieve the fgiven value
+ * @param echo - The calculated echo return value (in dB)
+ * @param echo - The calculated magnitude of the response
+ */
+static void set_topresults(int tbloffset, struct wctdm_echo_coefs *setting, float echo, float freqres)
+{
+ int place;
+ int idx;
+
+ for ( place = 0; place < MAX_RESULTS && place < topresults.numactive; place++) {
+ if (echo < topresults.results[place].echo) {
+ break;
+ }
+ }
+
+ if (place < MAX_RESULTS) {
+ /* move results to the bottom */
+ for (idx = topresults.numactive-2; idx >= place; idx--) {
+ topresults.results[idx+1] = topresults.results[idx];
+ }
+ topresults.results[place].idx = tbloffset;
+ topresults.results[place].settings = *setting;
+ topresults.results[place].echo = echo;
+ topresults.results[place].freqres = freqres;
+ if (MAX_RESULTS > topresults.numactive) {
+ topresults.numactive++;
+ }
+ }
+}
+
+
+/**
+ * Prints the top results stored to stdout
+ *
+ * @param header - Text that goes in the header of the response
+ */
+static void print_topresults(char * header)
+{
+ int item;
+
+ fprintf(stdout, "Top %d results for %s\n", topresults.numactive, header);
+ for (item = 0; item < topresults.numactive; item++) {
+ fprintf(stdout, "Res #%d: index=%d, %3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
+ item+1, topresults.results[item].idx, topresults.results[item].settings.acim,
+ topresults.results[item].settings.coef1, topresults.results[item].settings.coef2,
+ topresults.results[item].settings.coef3, topresults.results[item].settings.coef4,
+ topresults.results[item].settings.coef5, topresults.results[item].settings.coef6,
+ topresults.results[item].settings.coef7, topresults.results[item].settings.coef8,
+ topresults.results[item].freqres, topresults.results[item].echo);
+
+ }
+}
+
/**
* Perform calibration type 2 on the specified device
@@ -492,6 +622,8 @@ static int acim_tune2(int whichdahdi, int freq, char *dialstr, int delayuntilsil
float freq_result;
float echo;
+ init_topresults();
+
if (debug && !debugoutfile) {
if (!(debugoutfile = fopen("fxotune.vals", "w"))) {
fprintf(stdout, "Cannot create fxotune.vals\n");
@@ -578,9 +710,9 @@ retry:
/* read return response */
res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH * 2);
if (res != BUFFER_LENGTH * 2) {
- int x;
+ int dummy;
- ioctl(whichdahdi, DAHDI_GETEVENT, &x);
+ ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
goto retry;
}
@@ -618,18 +750,25 @@ retry:
);
fprintf(debugoutfile, "%s\n", result);
- fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
+ fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
freq_result, echo);
}
+
+ if (printbest) {
+ set_topresults(trys, &echo_trys[trys], echo, freq_result);
+ }
}
if (debug > 0)
fprintf(stdout, "Config with lowest response = %d, magnitude = %0.0f, echo = %0.4f dB\n", lowesttry, lowesttryresult, lowestecho);
memcpy(coefs_out, &echo_trys[lowesttry], sizeof(struct wctdm_echo_coefs));
+ if (printbest) {
+ print_topresults("Acim2_tune Test");
+ }
return 0;
}
@@ -731,9 +870,9 @@ retry:
/* read return response */
res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH);
if (res != BUFFER_LENGTH) {
- int x;
+ int dummy;
- ioctl(whichdahdi, DAHDI_GETEVENT, &x);
+ ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
goto retry;
}
@@ -909,7 +1048,7 @@ static int do_dump(int startdev, char* dialstr, int delayuntilsilence, int silen
* (this is basically the amount of time it takes before the 'if you'd like to make a call...' message
* kicks in after you dial dialstr
*
- * @return 0 if successful, !0 otherwise
+ * @return 0 if successful, -1 for serious error such as device not available , > 0 indicates the number of channels
*/
static int do_calibrate(int startdev, int enddev, int calibtype, char* configfilename, char* dialstr, int delayuntilsilence, int silencegoodfor)
{
@@ -1055,6 +1194,12 @@ int main(int argc , char **argv)
case 'n':
dialstr = moreargs ? argv[++i] : dialstr;
break;
+ case 'p':
+ printbest++;
+ break;
+ case 'x':
+ use_table = 1;
+ break;
case 'v':
debug = strlen(argv[i])-1;
break;
@@ -1084,7 +1229,8 @@ int main(int argc , char **argv)
fprintf(stdout, "\tdoset=%d\n", doset);
fprintf(stdout, "\tdocalibrate=%d\n", docalibrate);
fprintf(stdout, "\tdodump=%d\n", dodump);
- fprintf(stdout, "\tstartdev=%d\n", startdev);
+ fprintf(stdout, "\tprint best settings=%d\n", printbest);
+ fprintf(stdout, "\tstartdev=%d\n", startdev);
fprintf(stdout, "\tstopdev=%d\n", stopdev);
fprintf(stdout, "\tcalibtype=%d\n", calibtype);
fprintf(stdout, "\twaveformtype=%d\n", waveformtype);
@@ -1094,6 +1240,10 @@ int main(int argc , char **argv)
fprintf(stdout, "\tdebug=%d\n", debug);
}
+ if(use_table) {
+ init_sinetable();
+ }
+
if (docalibrate){
res = do_calibrate(startdev, stopdev, calibtype, configfile, dialstr, delaytosilence, silencegoodfor);
if (!res)