Mercurial > hg > audiostuff
diff spandsp-0.0.6pre17/tests/echo_monitor.cpp @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.6pre17/tests/echo_monitor.cpp Fri Jun 25 15:50:58 2010 +0200 @@ -0,0 +1,459 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * echo_monitor.cpp - Display echo canceller status, using the FLTK toolkit. + * + * Written by Steve Underwood <steveu@coppice.org> + * + * Copyright (C) 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: echo_monitor.cpp,v 1.13 2008/09/08 16:10:41 steveu Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) + +#define __STDC_LIMIT_MACROS + +#include <inttypes.h> +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/select.h> +#if defined(HAVE_FFTW3_H) +#include <fftw3.h> +#else +#include <fftw.h> +#endif + +#include <FL/Fl.H> +#include <FL/Fl_Overlay_Window.H> +#include <FL/Fl_Light_Button.H> +#include <FL/Fl_Cartesian.H> +#include <FL/Fl_Audio_Meter.H> +#include <FL/fl_draw.H> + +#include "spandsp.h" +#include "echo_monitor.h" + +struct line_model_monitor_s +{ + Fl_Double_Window *w; + + Fl_Audio_Meter *audio_meter; + Fl_Group *c_spec; + Fl_Group *c_right; + Fl_Group *c_can; + Fl_Group *c_line_model; + + Ca_Canvas *canvas_spec; + Ca_X_Axis *spec_freq; + Ca_Y_Axis *spec_amp; + Ca_Line *spec_re; + double spec_re_plot[2*512]; + + Ca_Canvas *canvas_can; + Ca_X_Axis *can_x; + Ca_Y_Axis *can_y; + Ca_Line *can_re; + double can_re_plot[512]; + + Ca_Canvas *canvas_line_model; + Ca_X_Axis *line_model_x; + Ca_Y_Axis *line_model_y; + Ca_Line *line_model_re; + double line_model_re_plot[512]; + + int in_ptr; +#if defined(HAVE_FFTW3_H) + double in[1024][2]; + double out[1024][2]; +#else + fftw_complex in[1024]; + fftw_complex out[1024]; +#endif + fftw_plan p; +}; + + +static int skip = 0; +static struct line_model_monitor_s echo; +static struct line_model_monitor_s *s = &echo; + +int echo_can_monitor_can_update(const int16_t *coeffs, int len) +{ + int i; + float min; + float max; + + if (s->can_re) + delete s->can_re; + + s->canvas_can->current(s->canvas_can); + i = 0; + min = coeffs[i]; + max = coeffs[i]; + for (i = 0; i < len; i++) + { + s->can_re_plot[2*i] = i; + s->can_re_plot[2*i + 1] = coeffs[i]; + if (min > coeffs[i]) + min = coeffs[i]; + if (max < coeffs[i]) + max = coeffs[i]; + } + s->can_y->maximum((max == min) ? max + 0.2 : max); + s->can_y->minimum(min); + s->can_re = new Ca_Line(len, s->can_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); + if (++skip >= 100) + { + skip = 0; + Fl::check(); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int echo_can_monitor_line_model_update(const int32_t *coeffs, int len) +{ + int i; + float min; + float max; + + if (s->line_model_re) + delete s->line_model_re; + + s->canvas_line_model->current(s->canvas_line_model); + i = 0; + min = coeffs[i]; + max = coeffs[i]; + for (i = 0; i < len; i++) + { + s->line_model_re_plot[2*i] = i; + s->line_model_re_plot[2*i + 1] = coeffs[i]; + if (min > coeffs[i]) + min = coeffs[i]; + if (max < coeffs[i]) + max = coeffs[i]; + } + s->line_model_y->maximum((max == min) ? max + 0.2 : max); + s->line_model_y->minimum(min); + s->line_model_re = new Ca_Line(len, s->line_model_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); + if (++skip >= 100) + { + skip = 0; + Fl::check(); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int echo_can_monitor_line_spectrum_update(const int16_t amp[], int len) +{ + int i; + int x; + + for (i = 0; i < len; i++) + s->audio_meter->sample(amp[i]/32768.0); + + if (s->in_ptr + len < 512) + { + /* Just add this fragment to the buffer. */ + for (i = 0; i < len; i++) +#if defined(HAVE_FFTW3_H) + s->in[s->in_ptr + i][0] = amp[i]; +#else + s->in[s->in_ptr + i].re = amp[i]; +#endif + s->in_ptr += len; + return 0; + } + if (len >= 512) + { + /* We have enough for a whole block. Use the last 512 samples + we have. */ + x = len - 512; + for (i = 0; i < 512; i++) +#if defined(HAVE_FFTW3_H) + s->in[i][0] = amp[x + i]; +#else + s->in[i].re = amp[x + i]; +#endif + } + else + { + /* We want the last 512 samples. */ + x = 512 - len; + for (i = 0; i < x; i++) +#if defined(HAVE_FFTW3_H) + s->in[i][0] = s->in[s->in_ptr - x + i][0]; +#else + s->in[i].re = s->in[s->in_ptr - x + i].re; +#endif + for (i = x; i < 512; i++) +#if defined(HAVE_FFTW3_H) + s->in[i][0] = amp[i - x]; +#else + s->in[i].re = amp[i - x]; +#endif + } + s->in_ptr = 0; +#if defined(HAVE_FFTW3_H) + fftw_execute(s->p); +#else + fftw_one(s->p, s->in, s->out); +#endif + if (s->spec_re) + delete s->spec_re; + s->canvas_spec->current(s->canvas_spec); + for (i = 0; i < 512; i++) + { + s->spec_re_plot[2*i] = i*4000.0/512.0; +#if defined(HAVE_FFTW3_H) + s->spec_re_plot[2*i + 1] = 20.0*log10(sqrt(s->out[i][0]*s->out[i][0] + s->out[i][1]*s->out[i][1])/(256.0*32768)) + 3.14; +#else + s->spec_re_plot[2*i + 1] = 20.0*log10(sqrt(s->out[i].re*s->out[i].re + s->out[i].im*s->out[i].im)/(256.0*32768)) + 3.14; +#endif + } + s->spec_re = new Ca_Line(512, s->spec_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); + Fl::check(); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int start_echo_can_monitor(int len) +{ + char buf[132 + 1]; + float x; + float y; + int i; + + s->w = new Fl_Double_Window(850, 400, "Echo canceller monitor"); + + s->c_spec = new Fl_Group(0, 0, 380, 400); + s->c_spec->box(FL_DOWN_BOX); + s->c_spec->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); + + s->canvas_spec = new Ca_Canvas(60, 30, 300, 300, "Spectrum"); + s->canvas_spec->box(FL_PLASTIC_DOWN_BOX); + s->canvas_spec->color(7); + s->canvas_spec->align(FL_ALIGN_TOP); + s->canvas_spec->border(15); + + s->spec_freq = new Ca_X_Axis(65, 330, 290, 30, "Freq (Hz)"); + s->spec_freq->align(FL_ALIGN_BOTTOM); + s->spec_freq->minimum(0); + s->spec_freq->maximum(4000); + s->spec_freq->label_format("%g"); + s->spec_freq->minor_grid_color(fl_gray_ramp(20)); + s->spec_freq->major_grid_color(fl_gray_ramp(15)); + s->spec_freq->label_grid_color(fl_gray_ramp(10)); + s->spec_freq->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->spec_freq->minor_grid_style(FL_DOT); + s->spec_freq->major_step(5); + s->spec_freq->label_step(1); + s->spec_freq->axis_color(FL_BLACK); + s->spec_freq->axis_align(CA_BOTTOM | CA_LINE); + + s->spec_amp = new Ca_Y_Axis(20, 35, 40, 290, "Amp (dBmO)"); + s->spec_amp->align(FL_ALIGN_LEFT); + s->spec_amp->minimum(-80.0); + s->spec_amp->maximum(10.0); + s->spec_amp->minor_grid_color(fl_gray_ramp(20)); + s->spec_amp->major_grid_color(fl_gray_ramp(15)); + s->spec_amp->label_grid_color(fl_gray_ramp(10)); + //s->spec_amp->grid_visible(CA_MINOR_TICK | CA_MAJOR_TICK | CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->spec_amp->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->spec_amp->minor_grid_style(FL_DOT); + s->spec_amp->major_step(5); + s->spec_amp->label_step(1); + s->spec_amp->axis_color(FL_BLACK); + + s->spec_amp->current(); + s->spec_re = NULL; + + s->c_spec->end(); + + s->c_right = new Fl_Group(440, 0, 465, 405); + + s->c_can = new Fl_Group(380, 0, 415, 200); + s->c_can->box(FL_DOWN_BOX); + s->c_can->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); + s->c_can->current(); + + s->canvas_can = new Ca_Canvas(460, 35, 300, 100, "Canceller coefficients"); + s->canvas_can->box(FL_PLASTIC_DOWN_BOX); + s->canvas_can->color(7); + s->canvas_can->align(FL_ALIGN_TOP); + Fl_Group::current()->resizable(s->canvas_can); + s->canvas_can->border(15); + + s->can_x = new Ca_X_Axis(465, 135, 290, 30, "Tap"); + s->can_x->align(FL_ALIGN_BOTTOM); + s->can_x->minimum(0.0); + s->can_x->maximum((float) len); + s->can_x->label_format("%g"); + s->can_x->minor_grid_color(fl_gray_ramp(20)); + s->can_x->major_grid_color(fl_gray_ramp(15)); + s->can_x->label_grid_color(fl_gray_ramp(10)); + s->can_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->can_x->minor_grid_style(FL_DOT); + s->can_x->major_step(5); + s->can_x->label_step(1); + s->can_x->axis_align(CA_BOTTOM | CA_LINE); + s->can_x->axis_color(FL_BLACK); + s->can_x->current(); + + s->can_y = new Ca_Y_Axis(420, 40, 40, 90, "Amp"); + s->can_y->align(FL_ALIGN_LEFT); + s->can_y->minimum(-0.1); + s->can_y->maximum(0.1); + s->can_y->minor_grid_color(fl_gray_ramp(20)); + s->can_y->major_grid_color(fl_gray_ramp(15)); + s->can_y->label_grid_color(fl_gray_ramp(10)); + s->can_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->can_y->minor_grid_style(FL_DOT); + s->can_y->major_step(5); + s->can_y->label_step(1); + s->can_y->axis_color(FL_BLACK); + s->can_y->current(); + + s->c_can->end(); + s->can_re = NULL; + + s->c_line_model = new Fl_Group(380, 200, 415, 200); + s->c_line_model->box(FL_DOWN_BOX); + s->c_line_model->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); + s->c_line_model->current(); + + s->canvas_line_model = new Ca_Canvas(460, 235, 300, 100, "Line impulse response model"); + s->canvas_line_model->box(FL_PLASTIC_DOWN_BOX); + s->canvas_line_model->color(7); + s->canvas_line_model->align(FL_ALIGN_TOP); + Fl_Group::current()->resizable(s->canvas_line_model); + s->canvas_line_model->border(15); + + s->line_model_x = new Ca_X_Axis(465, 335, 290, 30, "Tap"); + s->line_model_x->align(FL_ALIGN_BOTTOM); + s->line_model_x->minimum(0.0); + s->line_model_x->maximum((float) len); + s->line_model_x->label_format("%g"); + s->line_model_x->minor_grid_color(fl_gray_ramp(20)); + s->line_model_x->major_grid_color(fl_gray_ramp(15)); + s->line_model_x->label_grid_color(fl_gray_ramp(10)); + s->line_model_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->line_model_x->minor_grid_style(FL_DOT); + s->line_model_x->major_step(5); + s->line_model_x->label_step(1); + s->line_model_x->axis_align(CA_BOTTOM | CA_LINE); + s->line_model_x->axis_color(FL_BLACK); + s->line_model_x->current(); + + s->line_model_y = new Ca_Y_Axis(420, 240, 40, 90, "Amp"); + s->line_model_y->align(FL_ALIGN_LEFT); + s->line_model_y->minimum(-0.1); + s->line_model_y->maximum(0.1); + s->line_model_y->minor_grid_color(fl_gray_ramp(20)); + s->line_model_y->major_grid_color(fl_gray_ramp(15)); + s->line_model_y->label_grid_color(fl_gray_ramp(10)); + s->line_model_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); + s->line_model_y->minor_grid_style(FL_DOT); + s->line_model_y->major_step(5); + s->line_model_y->label_step(1); + s->line_model_y->axis_color(FL_BLACK); + s->line_model_y->current(); + + s->c_line_model->end(); + s->line_model_re = NULL; + + s->audio_meter = new Fl_Audio_Meter(810, 40, 10, 250, ""); + s->audio_meter->box(FL_PLASTIC_UP_BOX); + s->audio_meter->type(FL_VERT_AUDIO_METER); + + s->c_right->end(); + + Fl_Group::current()->resizable(s->c_right); + s->w->end(); + s->w->show(); + +#if defined(HAVE_FFTW3_H) + s->p = fftw_plan_dft_1d(1024, s->in, s->out, FFTW_BACKWARD, FFTW_ESTIMATE); + for (i = 0; i < 1024; i++) + { + s->in[i][0] = 0.0; + s->in[i][1] = 0.0; + } +#else + s->p = fftw_create_plan(1024, FFTW_BACKWARD, FFTW_ESTIMATE); + for (i = 0; i < 1024; i++) + { + s->in[i].re = 0.0; + s->in[i].im = 0.0; + } +#endif + s->in_ptr = 0; + + Fl::check(); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +void echo_can_monitor_wait_to_end(void) +{ + fd_set rfds; + int res; + struct timeval tv; + + fprintf(stderr, "Processing complete. Press the <enter> key to end\n"); + do + { + usleep(100000); + Fl::check(); + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_usec = 100000; + tv.tv_sec = 0; + res = select(1, &rfds, NULL, NULL, &tv); + } + while (res <= 0); +} +/*- End of function --------------------------------------------------------*/ + +void echo_can_monitor_update_display(void) +{ + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); + Fl::check(); +} +/*- End of function --------------------------------------------------------*/ +#endif +/*- End of file ------------------------------------------------------------*/