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 ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.