Mercurial > hg > audiostuff
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
|---|---|
| 1 /* | |
| 2 * SpanDSP - a series of DSP components for telephony | |
| 3 * | |
| 4 * echo_monitor.cpp - Display echo canceller status, using the FLTK toolkit. | |
| 5 * | |
| 6 * Written by Steve Underwood <steveu@coppice.org> | |
| 7 * | |
| 8 * Copyright (C) 2004 Steve Underwood | |
| 9 * | |
| 10 * All rights reserved. | |
| 11 * | |
| 12 * This program is free software; you can redistribute it and/or modify | |
| 13 * it under the terms of the GNU General Public License version 2, as | |
| 14 * published by the Free Software Foundation. | |
| 15 * | |
| 16 * This program is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 * GNU General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU General Public License | |
| 22 * along with this program; if not, write to the Free Software | |
| 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 24 * | |
| 25 * $Id: echo_monitor.cpp,v 1.13 2008/09/08 16:10:41 steveu Exp $ | |
| 26 */ | |
| 27 | |
| 28 #ifdef HAVE_CONFIG_H | |
| 29 #include "config.h" | |
| 30 #endif | |
| 31 | |
| 32 #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) | |
| 33 | |
| 34 #define __STDC_LIMIT_MACROS | |
| 35 | |
| 36 #include <inttypes.h> | |
| 37 #include <stdio.h> | |
| 38 #include <math.h> | |
| 39 #include <stdlib.h> | |
| 40 #include <string.h> | |
| 41 #include <unistd.h> | |
| 42 #include <sys/select.h> | |
| 43 #if defined(HAVE_FFTW3_H) | |
| 44 #include <fftw3.h> | |
| 45 #else | |
| 46 #include <fftw.h> | |
| 47 #endif | |
| 48 | |
| 49 #include <FL/Fl.H> | |
| 50 #include <FL/Fl_Overlay_Window.H> | |
| 51 #include <FL/Fl_Light_Button.H> | |
| 52 #include <FL/Fl_Cartesian.H> | |
| 53 #include <FL/Fl_Audio_Meter.H> | |
| 54 #include <FL/fl_draw.H> | |
| 55 | |
| 56 #include "spandsp.h" | |
| 57 #include "echo_monitor.h" | |
| 58 | |
| 59 struct line_model_monitor_s | |
| 60 { | |
| 61 Fl_Double_Window *w; | |
| 62 | |
| 63 Fl_Audio_Meter *audio_meter; | |
| 64 Fl_Group *c_spec; | |
| 65 Fl_Group *c_right; | |
| 66 Fl_Group *c_can; | |
| 67 Fl_Group *c_line_model; | |
| 68 | |
| 69 Ca_Canvas *canvas_spec; | |
| 70 Ca_X_Axis *spec_freq; | |
| 71 Ca_Y_Axis *spec_amp; | |
| 72 Ca_Line *spec_re; | |
| 73 double spec_re_plot[2*512]; | |
| 74 | |
| 75 Ca_Canvas *canvas_can; | |
| 76 Ca_X_Axis *can_x; | |
| 77 Ca_Y_Axis *can_y; | |
| 78 Ca_Line *can_re; | |
| 79 double can_re_plot[512]; | |
| 80 | |
| 81 Ca_Canvas *canvas_line_model; | |
| 82 Ca_X_Axis *line_model_x; | |
| 83 Ca_Y_Axis *line_model_y; | |
| 84 Ca_Line *line_model_re; | |
| 85 double line_model_re_plot[512]; | |
| 86 | |
| 87 int in_ptr; | |
| 88 #if defined(HAVE_FFTW3_H) | |
| 89 double in[1024][2]; | |
| 90 double out[1024][2]; | |
| 91 #else | |
| 92 fftw_complex in[1024]; | |
| 93 fftw_complex out[1024]; | |
| 94 #endif | |
| 95 fftw_plan p; | |
| 96 }; | |
| 97 | |
| 98 | |
| 99 static int skip = 0; | |
| 100 static struct line_model_monitor_s echo; | |
| 101 static struct line_model_monitor_s *s = &echo; | |
| 102 | |
| 103 int echo_can_monitor_can_update(const int16_t *coeffs, int len) | |
| 104 { | |
| 105 int i; | |
| 106 float min; | |
| 107 float max; | |
| 108 | |
| 109 if (s->can_re) | |
| 110 delete s->can_re; | |
| 111 | |
| 112 s->canvas_can->current(s->canvas_can); | |
| 113 i = 0; | |
| 114 min = coeffs[i]; | |
| 115 max = coeffs[i]; | |
| 116 for (i = 0; i < len; i++) | |
| 117 { | |
| 118 s->can_re_plot[2*i] = i; | |
| 119 s->can_re_plot[2*i + 1] = coeffs[i]; | |
| 120 if (min > coeffs[i]) | |
| 121 min = coeffs[i]; | |
| 122 if (max < coeffs[i]) | |
| 123 max = coeffs[i]; | |
| 124 } | |
| 125 s->can_y->maximum((max == min) ? max + 0.2 : max); | |
| 126 s->can_y->minimum(min); | |
| 127 s->can_re = new Ca_Line(len, s->can_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); | |
| 128 if (++skip >= 100) | |
| 129 { | |
| 130 skip = 0; | |
| 131 Fl::check(); | |
| 132 } | |
| 133 return 0; | |
| 134 } | |
| 135 /*- End of function --------------------------------------------------------*/ | |
| 136 | |
| 137 int echo_can_monitor_line_model_update(const int32_t *coeffs, int len) | |
| 138 { | |
| 139 int i; | |
| 140 float min; | |
| 141 float max; | |
| 142 | |
| 143 if (s->line_model_re) | |
| 144 delete s->line_model_re; | |
| 145 | |
| 146 s->canvas_line_model->current(s->canvas_line_model); | |
| 147 i = 0; | |
| 148 min = coeffs[i]; | |
| 149 max = coeffs[i]; | |
| 150 for (i = 0; i < len; i++) | |
| 151 { | |
| 152 s->line_model_re_plot[2*i] = i; | |
| 153 s->line_model_re_plot[2*i + 1] = coeffs[i]; | |
| 154 if (min > coeffs[i]) | |
| 155 min = coeffs[i]; | |
| 156 if (max < coeffs[i]) | |
| 157 max = coeffs[i]; | |
| 158 } | |
| 159 s->line_model_y->maximum((max == min) ? max + 0.2 : max); | |
| 160 s->line_model_y->minimum(min); | |
| 161 s->line_model_re = new Ca_Line(len, s->line_model_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); | |
| 162 if (++skip >= 100) | |
| 163 { | |
| 164 skip = 0; | |
| 165 Fl::check(); | |
| 166 } | |
| 167 return 0; | |
| 168 } | |
| 169 /*- End of function --------------------------------------------------------*/ | |
| 170 | |
| 171 int echo_can_monitor_line_spectrum_update(const int16_t amp[], int len) | |
| 172 { | |
| 173 int i; | |
| 174 int x; | |
| 175 | |
| 176 for (i = 0; i < len; i++) | |
| 177 s->audio_meter->sample(amp[i]/32768.0); | |
| 178 | |
| 179 if (s->in_ptr + len < 512) | |
| 180 { | |
| 181 /* Just add this fragment to the buffer. */ | |
| 182 for (i = 0; i < len; i++) | |
| 183 #if defined(HAVE_FFTW3_H) | |
| 184 s->in[s->in_ptr + i][0] = amp[i]; | |
| 185 #else | |
| 186 s->in[s->in_ptr + i].re = amp[i]; | |
| 187 #endif | |
| 188 s->in_ptr += len; | |
| 189 return 0; | |
| 190 } | |
| 191 if (len >= 512) | |
| 192 { | |
| 193 /* We have enough for a whole block. Use the last 512 samples | |
| 194 we have. */ | |
| 195 x = len - 512; | |
| 196 for (i = 0; i < 512; i++) | |
| 197 #if defined(HAVE_FFTW3_H) | |
| 198 s->in[i][0] = amp[x + i]; | |
| 199 #else | |
| 200 s->in[i].re = amp[x + i]; | |
| 201 #endif | |
| 202 } | |
| 203 else | |
| 204 { | |
| 205 /* We want the last 512 samples. */ | |
| 206 x = 512 - len; | |
| 207 for (i = 0; i < x; i++) | |
| 208 #if defined(HAVE_FFTW3_H) | |
| 209 s->in[i][0] = s->in[s->in_ptr - x + i][0]; | |
| 210 #else | |
| 211 s->in[i].re = s->in[s->in_ptr - x + i].re; | |
| 212 #endif | |
| 213 for (i = x; i < 512; i++) | |
| 214 #if defined(HAVE_FFTW3_H) | |
| 215 s->in[i][0] = amp[i - x]; | |
| 216 #else | |
| 217 s->in[i].re = amp[i - x]; | |
| 218 #endif | |
| 219 } | |
| 220 s->in_ptr = 0; | |
| 221 #if defined(HAVE_FFTW3_H) | |
| 222 fftw_execute(s->p); | |
| 223 #else | |
| 224 fftw_one(s->p, s->in, s->out); | |
| 225 #endif | |
| 226 if (s->spec_re) | |
| 227 delete s->spec_re; | |
| 228 s->canvas_spec->current(s->canvas_spec); | |
| 229 for (i = 0; i < 512; i++) | |
| 230 { | |
| 231 s->spec_re_plot[2*i] = i*4000.0/512.0; | |
| 232 #if defined(HAVE_FFTW3_H) | |
| 233 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; | |
| 234 #else | |
| 235 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; | |
| 236 #endif | |
| 237 } | |
| 238 s->spec_re = new Ca_Line(512, s->spec_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); | |
| 239 Fl::check(); | |
| 240 return 0; | |
| 241 } | |
| 242 /*- End of function --------------------------------------------------------*/ | |
| 243 | |
| 244 int start_echo_can_monitor(int len) | |
| 245 { | |
| 246 char buf[132 + 1]; | |
| 247 float x; | |
| 248 float y; | |
| 249 int i; | |
| 250 | |
| 251 s->w = new Fl_Double_Window(850, 400, "Echo canceller monitor"); | |
| 252 | |
| 253 s->c_spec = new Fl_Group(0, 0, 380, 400); | |
| 254 s->c_spec->box(FL_DOWN_BOX); | |
| 255 s->c_spec->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); | |
| 256 | |
| 257 s->canvas_spec = new Ca_Canvas(60, 30, 300, 300, "Spectrum"); | |
| 258 s->canvas_spec->box(FL_PLASTIC_DOWN_BOX); | |
| 259 s->canvas_spec->color(7); | |
| 260 s->canvas_spec->align(FL_ALIGN_TOP); | |
| 261 s->canvas_spec->border(15); | |
| 262 | |
| 263 s->spec_freq = new Ca_X_Axis(65, 330, 290, 30, "Freq (Hz)"); | |
| 264 s->spec_freq->align(FL_ALIGN_BOTTOM); | |
| 265 s->spec_freq->minimum(0); | |
| 266 s->spec_freq->maximum(4000); | |
| 267 s->spec_freq->label_format("%g"); | |
| 268 s->spec_freq->minor_grid_color(fl_gray_ramp(20)); | |
| 269 s->spec_freq->major_grid_color(fl_gray_ramp(15)); | |
| 270 s->spec_freq->label_grid_color(fl_gray_ramp(10)); | |
| 271 s->spec_freq->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 272 s->spec_freq->minor_grid_style(FL_DOT); | |
| 273 s->spec_freq->major_step(5); | |
| 274 s->spec_freq->label_step(1); | |
| 275 s->spec_freq->axis_color(FL_BLACK); | |
| 276 s->spec_freq->axis_align(CA_BOTTOM | CA_LINE); | |
| 277 | |
| 278 s->spec_amp = new Ca_Y_Axis(20, 35, 40, 290, "Amp (dBmO)"); | |
| 279 s->spec_amp->align(FL_ALIGN_LEFT); | |
| 280 s->spec_amp->minimum(-80.0); | |
| 281 s->spec_amp->maximum(10.0); | |
| 282 s->spec_amp->minor_grid_color(fl_gray_ramp(20)); | |
| 283 s->spec_amp->major_grid_color(fl_gray_ramp(15)); | |
| 284 s->spec_amp->label_grid_color(fl_gray_ramp(10)); | |
| 285 //s->spec_amp->grid_visible(CA_MINOR_TICK | CA_MAJOR_TICK | CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 286 s->spec_amp->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 287 s->spec_amp->minor_grid_style(FL_DOT); | |
| 288 s->spec_amp->major_step(5); | |
| 289 s->spec_amp->label_step(1); | |
| 290 s->spec_amp->axis_color(FL_BLACK); | |
| 291 | |
| 292 s->spec_amp->current(); | |
| 293 s->spec_re = NULL; | |
| 294 | |
| 295 s->c_spec->end(); | |
| 296 | |
| 297 s->c_right = new Fl_Group(440, 0, 465, 405); | |
| 298 | |
| 299 s->c_can = new Fl_Group(380, 0, 415, 200); | |
| 300 s->c_can->box(FL_DOWN_BOX); | |
| 301 s->c_can->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); | |
| 302 s->c_can->current(); | |
| 303 | |
| 304 s->canvas_can = new Ca_Canvas(460, 35, 300, 100, "Canceller coefficients"); | |
| 305 s->canvas_can->box(FL_PLASTIC_DOWN_BOX); | |
| 306 s->canvas_can->color(7); | |
| 307 s->canvas_can->align(FL_ALIGN_TOP); | |
| 308 Fl_Group::current()->resizable(s->canvas_can); | |
| 309 s->canvas_can->border(15); | |
| 310 | |
| 311 s->can_x = new Ca_X_Axis(465, 135, 290, 30, "Tap"); | |
| 312 s->can_x->align(FL_ALIGN_BOTTOM); | |
| 313 s->can_x->minimum(0.0); | |
| 314 s->can_x->maximum((float) len); | |
| 315 s->can_x->label_format("%g"); | |
| 316 s->can_x->minor_grid_color(fl_gray_ramp(20)); | |
| 317 s->can_x->major_grid_color(fl_gray_ramp(15)); | |
| 318 s->can_x->label_grid_color(fl_gray_ramp(10)); | |
| 319 s->can_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 320 s->can_x->minor_grid_style(FL_DOT); | |
| 321 s->can_x->major_step(5); | |
| 322 s->can_x->label_step(1); | |
| 323 s->can_x->axis_align(CA_BOTTOM | CA_LINE); | |
| 324 s->can_x->axis_color(FL_BLACK); | |
| 325 s->can_x->current(); | |
| 326 | |
| 327 s->can_y = new Ca_Y_Axis(420, 40, 40, 90, "Amp"); | |
| 328 s->can_y->align(FL_ALIGN_LEFT); | |
| 329 s->can_y->minimum(-0.1); | |
| 330 s->can_y->maximum(0.1); | |
| 331 s->can_y->minor_grid_color(fl_gray_ramp(20)); | |
| 332 s->can_y->major_grid_color(fl_gray_ramp(15)); | |
| 333 s->can_y->label_grid_color(fl_gray_ramp(10)); | |
| 334 s->can_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 335 s->can_y->minor_grid_style(FL_DOT); | |
| 336 s->can_y->major_step(5); | |
| 337 s->can_y->label_step(1); | |
| 338 s->can_y->axis_color(FL_BLACK); | |
| 339 s->can_y->current(); | |
| 340 | |
| 341 s->c_can->end(); | |
| 342 s->can_re = NULL; | |
| 343 | |
| 344 s->c_line_model = new Fl_Group(380, 200, 415, 200); | |
| 345 s->c_line_model->box(FL_DOWN_BOX); | |
| 346 s->c_line_model->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); | |
| 347 s->c_line_model->current(); | |
| 348 | |
| 349 s->canvas_line_model = new Ca_Canvas(460, 235, 300, 100, "Line impulse response model"); | |
| 350 s->canvas_line_model->box(FL_PLASTIC_DOWN_BOX); | |
| 351 s->canvas_line_model->color(7); | |
| 352 s->canvas_line_model->align(FL_ALIGN_TOP); | |
| 353 Fl_Group::current()->resizable(s->canvas_line_model); | |
| 354 s->canvas_line_model->border(15); | |
| 355 | |
| 356 s->line_model_x = new Ca_X_Axis(465, 335, 290, 30, "Tap"); | |
| 357 s->line_model_x->align(FL_ALIGN_BOTTOM); | |
| 358 s->line_model_x->minimum(0.0); | |
| 359 s->line_model_x->maximum((float) len); | |
| 360 s->line_model_x->label_format("%g"); | |
| 361 s->line_model_x->minor_grid_color(fl_gray_ramp(20)); | |
| 362 s->line_model_x->major_grid_color(fl_gray_ramp(15)); | |
| 363 s->line_model_x->label_grid_color(fl_gray_ramp(10)); | |
| 364 s->line_model_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 365 s->line_model_x->minor_grid_style(FL_DOT); | |
| 366 s->line_model_x->major_step(5); | |
| 367 s->line_model_x->label_step(1); | |
| 368 s->line_model_x->axis_align(CA_BOTTOM | CA_LINE); | |
| 369 s->line_model_x->axis_color(FL_BLACK); | |
| 370 s->line_model_x->current(); | |
| 371 | |
| 372 s->line_model_y = new Ca_Y_Axis(420, 240, 40, 90, "Amp"); | |
| 373 s->line_model_y->align(FL_ALIGN_LEFT); | |
| 374 s->line_model_y->minimum(-0.1); | |
| 375 s->line_model_y->maximum(0.1); | |
| 376 s->line_model_y->minor_grid_color(fl_gray_ramp(20)); | |
| 377 s->line_model_y->major_grid_color(fl_gray_ramp(15)); | |
| 378 s->line_model_y->label_grid_color(fl_gray_ramp(10)); | |
| 379 s->line_model_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); | |
| 380 s->line_model_y->minor_grid_style(FL_DOT); | |
| 381 s->line_model_y->major_step(5); | |
| 382 s->line_model_y->label_step(1); | |
| 383 s->line_model_y->axis_color(FL_BLACK); | |
| 384 s->line_model_y->current(); | |
| 385 | |
| 386 s->c_line_model->end(); | |
| 387 s->line_model_re = NULL; | |
| 388 | |
| 389 s->audio_meter = new Fl_Audio_Meter(810, 40, 10, 250, ""); | |
| 390 s->audio_meter->box(FL_PLASTIC_UP_BOX); | |
| 391 s->audio_meter->type(FL_VERT_AUDIO_METER); | |
| 392 | |
| 393 s->c_right->end(); | |
| 394 | |
| 395 Fl_Group::current()->resizable(s->c_right); | |
| 396 s->w->end(); | |
| 397 s->w->show(); | |
| 398 | |
| 399 #if defined(HAVE_FFTW3_H) | |
| 400 s->p = fftw_plan_dft_1d(1024, s->in, s->out, FFTW_BACKWARD, FFTW_ESTIMATE); | |
| 401 for (i = 0; i < 1024; i++) | |
| 402 { | |
| 403 s->in[i][0] = 0.0; | |
| 404 s->in[i][1] = 0.0; | |
| 405 } | |
| 406 #else | |
| 407 s->p = fftw_create_plan(1024, FFTW_BACKWARD, FFTW_ESTIMATE); | |
| 408 for (i = 0; i < 1024; i++) | |
| 409 { | |
| 410 s->in[i].re = 0.0; | |
| 411 s->in[i].im = 0.0; | |
| 412 } | |
| 413 #endif | |
| 414 s->in_ptr = 0; | |
| 415 | |
| 416 Fl::check(); | |
| 417 return 0; | |
| 418 } | |
| 419 /*- End of function --------------------------------------------------------*/ | |
| 420 | |
| 421 void echo_can_monitor_wait_to_end(void) | |
| 422 { | |
| 423 fd_set rfds; | |
| 424 int res; | |
| 425 struct timeval tv; | |
| 426 | |
| 427 fprintf(stderr, "Processing complete. Press the <enter> key to end\n"); | |
| 428 do | |
| 429 { | |
| 430 usleep(100000); | |
| 431 Fl::check(); | |
| 432 FD_ZERO(&rfds); | |
| 433 FD_SET(0, &rfds); | |
| 434 tv.tv_usec = 100000; | |
| 435 tv.tv_sec = 0; | |
| 436 res = select(1, &rfds, NULL, NULL, &tv); | |
| 437 } | |
| 438 while (res <= 0); | |
| 439 } | |
| 440 /*- End of function --------------------------------------------------------*/ | |
| 441 | |
| 442 void echo_can_monitor_update_display(void) | |
| 443 { | |
| 444 Fl::check(); | |
| 445 Fl::check(); | |
| 446 Fl::check(); | |
| 447 Fl::check(); | |
| 448 Fl::check(); | |
| 449 Fl::check(); | |
| 450 Fl::check(); | |
| 451 Fl::check(); | |
| 452 Fl::check(); | |
| 453 Fl::check(); | |
| 454 Fl::check(); | |
| 455 Fl::check(); | |
| 456 } | |
| 457 /*- End of function --------------------------------------------------------*/ | |
| 458 #endif | |
| 459 /*- End of file ------------------------------------------------------------*/ |
