1 /* Conditional Median Filter
2
3 * Copyright (C) 1998 J.A. Bezemer
4 *
5 * Licensed under the terms of the GNU General Public License.
6 * ABSOLUTELY NO WARRANTY.
7 * See the file `COPYING' in this directory.
8 */
9
10 /* Remove the `dont' to get b[t].left on left channel and g[t].left on
11 right channel - useful for verifying properties.
12
13 Note that
14 b[t] is z[t] if RMSlength=RMFlength=1
15 and
16 b[t] is w[t] if RMFlength=1
17 (See also Signproc.txt)
18 */
19 #define dontVIEW_INTERNALS
20
21
22 #include "signpr_cmf.h"
23 #include "signpr_general.h"
24 #include "errorwindow.h"
25 #ifndef SWIG
26 #include "stringinput.h"
27 #include "buttons.h"
28 #include "clrscr.h"
29 #include "boxes.h"
30 #include "helpline.h"
31 #include "yesnowindow.h"
32 #endif
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37 #ifndef SWIG
38 #ifndef OLD_CURSES
39 #include <ncurses.h>
40 #else
41 #include <curses.h>
42 #endif
43 #endif
44
45
46 /* Macros I used first:
47
48 COND_MEDIAN_MF_POSTLENGTH == parampointer->postlength1
49 COND_MEDIAN_MF_PRELENGTH == parampointer->prelength1
50
51 COND_MEDIAN_RMS_POSTLENGTH == parampointer->postlength2
52 COND_MEDIAN_RMS_PRELENGTH == parampointer->prelength2
53
54 COND_MEDIAN_RMF_POSTLENGTH == parampointer->postlength3
55 COND_MEDIAN_RMF_PRELENGTH == parampointer->prelength3
56
57 COND_MEDIAN_RMF_DECIMATE == parampointer->int1
58
59 COND_MEDIAN_THRESHOLD == parampointer->long1
60 */
61
62
63 void
cond_median_param_defaults(parampointer_t parampointer)64 cond_median_param_defaults (parampointer_t parampointer)
65 {
66 /* Best tick-reduction: 21 - 9 - 11 - 5 - 2500 */
67
68 parampointer->postlength1 = 10;
69 parampointer->prelength1 = 10;
70 parampointer->postlength2 = 4;
71 parampointer->prelength2 = 4;
72 parampointer->postlength3 = 5;
73 parampointer->prelength3 = 5;
74 parampointer->int1 = 5; /* actually, this should really be 12 */
75 parampointer->long1 = 2500;
76
77 /* If you experience badly affected sound, try 15 - 11 - 9 - 4 - 2500 */
78 }
79
80 #ifndef SWIG
81 void
cond_median_param_screen(parampointer_t parampointer)82 cond_median_param_screen (parampointer_t parampointer)
83 {
84 stringinput_t medlengthstr, rmslengthstr, rmflengthstr, decimatestr,
85 thresholdstr;
86 button_t ok_button, cancel_button, defaults_button;
87 int dont_stop = TRUE;
88 int focus = 0;
89 int in_ch;
90 int i;
91 long helplong;
92
93 char *helplines[8] =
94 {
95 " ^: no neat interpolation. v: broad ticks not filtered out. ",
96 " ^: less ticks detected. v: not all of tick interpolated. ",
97 " ^: bad following of dynamics. v: fewer ticks detected. ",
98 " ^: bad following of dynamics. v: fewer ticks detected. ",
99 " ^: only strong ticks detected. v: music-ticks also filtered out. ",
100 " Discard changes. ",
101 " Reset default values. ",
102 " Accept changes. "};
103
104 medlengthstr.maxlen = 500;
105 medlengthstr.string = (char *) malloc (medlengthstr.maxlen *
106 sizeof (char));
107 sprintf (medlengthstr.string, "%ld", parampointer->prelength1 +
108 parampointer->postlength1 + 1);
109 medlengthstr.y = 6;
110 medlengthstr.x = 57;
111 medlengthstr.w = 19;
112 medlengthstr.cursorpos = strlen (medlengthstr.string);
113 medlengthstr.firstcharonscreen = 0;
114
115 rmslengthstr.maxlen = 500;
116 rmslengthstr.string = (char *) malloc (rmslengthstr.maxlen *
117 sizeof (char));
118 sprintf (rmslengthstr.string, "%ld", parampointer->prelength2 +
119 parampointer->postlength2 + 1);
120 rmslengthstr.y = 8;
121 rmslengthstr.x = 57;
122 rmslengthstr.w = 19;
123 rmslengthstr.cursorpos = strlen (rmslengthstr.string);
124 rmslengthstr.firstcharonscreen = 0;
125
126 rmflengthstr.maxlen = 500;
127 rmflengthstr.string = (char *) malloc (rmflengthstr.maxlen *
128 sizeof (char));
129 sprintf (rmflengthstr.string, "%ld", parampointer->prelength3 +
130 parampointer->postlength3 + 1);
131 rmflengthstr.y = 10;
132 rmflengthstr.x = 57;
133 rmflengthstr.w = 19;
134 rmflengthstr.cursorpos = strlen (rmflengthstr.string);
135 rmflengthstr.firstcharonscreen = 0;
136
137 decimatestr.maxlen = 500;
138 decimatestr.string = (char *) malloc (decimatestr.maxlen *
139 sizeof (char));
140 sprintf (decimatestr.string, "%d", parampointer->int1);
141 decimatestr.y = 12;
142 decimatestr.x = 57;
143 decimatestr.w = 19;
144 decimatestr.cursorpos = strlen (decimatestr.string);
145 decimatestr.firstcharonscreen = 0;
146
147 thresholdstr.maxlen = 500;
148 thresholdstr.string = (char *) malloc (thresholdstr.maxlen *
149 sizeof (char));
150 sprintf (thresholdstr.string, "%ld", parampointer->long1);
151 thresholdstr.y = 14;
152 thresholdstr.x = 57;
153 thresholdstr.w = 19;
154 thresholdstr.cursorpos = strlen (thresholdstr.string);
155 thresholdstr.firstcharonscreen = 0;
156
157 ok_button.text = " OK ";
158 ok_button.y = 20;
159 ok_button.x = 71;
160 ok_button.selected = FALSE;
161
162 cancel_button.text = " Cancel ";
163 cancel_button.y = 20;
164 cancel_button.x = 5;
165 cancel_button.selected = FALSE;
166
167 defaults_button.text = " Defaults ";
168 defaults_button.y = 20;
169 defaults_button.x = 36;
170 defaults_button.selected = FALSE;
171
172 clearscreen (SIGNPR_CMF_PARAMSCR_HEADERTEXT);
173
174 do
175 {
176 header (SIGNPR_CMF_PARAMSCR_HEADERTEXT);
177
178 if (focus == 5)
179 cancel_button.selected = TRUE;
180 else
181 cancel_button.selected = FALSE;
182
183 if (focus == 6)
184 defaults_button.selected = TRUE;
185 else
186 defaults_button.selected = FALSE;
187
188 if (focus == 7)
189 ok_button.selected = TRUE;
190 else
191 ok_button.selected = FALSE;
192
193 mvprintw (3, 2,
194 "See the Signproc.txt file for the meaning of the parameters.");
195
196 stringinput_display (&medlengthstr);
197 mvprintw (medlengthstr.y, 2,
198 "Number of samples for median to interpolate ticks:");
199
200 stringinput_display (&rmslengthstr);
201 mvprintw (rmslengthstr.y, 2,
202 "Length of the RMS operation (samples):");
203
204 stringinput_display (&rmflengthstr);
205 mvprintw (rmflengthstr.y, 2,
206 "Length of the recursive median operation (samples):");
207
208 stringinput_display (&decimatestr);
209 mvprintw (decimatestr.y, 2,
210 "Decimation factor for the recursive median:");
211
212 stringinput_display (&thresholdstr);
213 mvprintw (thresholdstr.y, 2,
214 "Threshold for tick detection (thousandths):");
215
216 button_display (&cancel_button);
217 mybox (cancel_button.y - 1, cancel_button.x - 1,
218 3, strlen (cancel_button.text) + 2);
219 button_display (&defaults_button);
220 mybox (defaults_button.y - 1, defaults_button.x - 1,
221 3, strlen (defaults_button.text) + 2);
222 button_display (&ok_button);
223 mybox (ok_button.y - 1, ok_button.x - 1,
224 3, strlen (ok_button.text) + 2);
225
226 helpline (helplines[focus]);
227
228 switch (focus)
229 {
230 case 0:
231 stringinput_display (&medlengthstr);
232 break;
233 case 1:
234 stringinput_display (&rmslengthstr);
235 break;
236 case 2:
237 stringinput_display (&rmflengthstr);
238 break;
239 case 3:
240 stringinput_display (&decimatestr);
241 break;
242 case 4:
243 stringinput_display (&thresholdstr);
244 break;
245 default:
246 move (0, 79);
247 }
248
249 refresh ();
250
251 in_ch = getch ();
252
253 switch (focus)
254 {
255 case 0: /* medlengthstr */
256 stringinput_stdkeys (in_ch, &medlengthstr);
257 switch (in_ch)
258 {
259 case KEY_ENTER:
260 case 13:
261 i = sscanf (medlengthstr.string, "%li", &helplong);
262 if (i < 1 || helplong < 1 || helplong % 2 == 0)
263 error_window ("A whole, odd number, greater than 0, must \
264 be specified.");
265 else
266 focus++;
267 break;
268
269 case KEY_UP:
270 focus--;
271 break;
272 case KEY_DOWN:
273 focus++;
274 break;
275 }
276 break;
277
278 case 1: /* rmslengthstr */
279 stringinput_stdkeys (in_ch, &rmslengthstr);
280 switch (in_ch)
281 {
282 case KEY_ENTER:
283 case 13:
284 i = sscanf (rmslengthstr.string, "%li", &helplong);
285 if (i < 1 || helplong < 1 || helplong % 2 == 0)
286 error_window ("A whole, odd number, greater than 0, must \
287 be specified.");
288 else
289 focus++;
290 break;
291
292 case KEY_UP:
293 focus--;
294 break;
295 case KEY_DOWN:
296 focus++;
297 break;
298 }
299 break;
300
301 case 2: /* rmflengthstr */
302 stringinput_stdkeys (in_ch, &rmflengthstr);
303 switch (in_ch)
304 {
305 case KEY_ENTER:
306 case 13:
307 i = sscanf (rmflengthstr.string, "%li", &helplong);
308 if (i < 1 || helplong < 1 || helplong % 2 == 0)
309 error_window ("A whole, odd number, greater than 0, must \
310 be specified.");
311 else
312 focus++;
313 break;
314
315 case KEY_UP:
316 focus--;
317 break;
318 case KEY_DOWN:
319 focus++;
320 break;
321 }
322 break;
323
324 case 3: /* decimatestr */
325 stringinput_stdkeys (in_ch, &decimatestr);
326 switch (in_ch)
327 {
328 case KEY_ENTER:
329 case 13:
330 i = sscanf (decimatestr.string, "%li", &helplong);
331 if (i < 1 || helplong < 1)
332 error_window ("A whole number, greater than 0, must \
333 be specified.");
334 else
335 focus++;
336 break;
337
338 case KEY_UP:
339 focus--;
340 break;
341 case KEY_DOWN:
342 focus++;
343 break;
344 }
345 break;
346
347 case 4: /* thresholdstr */
348 stringinput_stdkeys (in_ch, &thresholdstr);
349 switch (in_ch)
350 {
351 case KEY_ENTER:
352 case 13:
353 i = sscanf (thresholdstr.string, "%li", &helplong);
354 if (i < 1 || helplong < 1000)
355 error_window ("A whole number, greater than 1000, must \
356 be specified.");
357 else
358 focus = 7;
359 break;
360
361 case KEY_UP:
362 focus--;
363 break;
364 case KEY_DOWN:
365 focus++;
366 break;
367 }
368 break;
369
370 case 5: /* Cancel */
371 switch (in_ch)
372 {
373 case KEY_ENTER:
374 case 13:
375 dont_stop = FALSE;
376 break;
377
378 case KEY_LEFT:
379 case KEY_UP:
380 focus--;
381 break;
382 case KEY_RIGHT:
383 case KEY_DOWN:
384 focus++;
385 break;
386 }
387 break;
388
389 case 6: /* Defaults */
390 switch (in_ch)
391 {
392 case KEY_ENTER:
393 case 13:
394 if (yesno_window ("Restore default parameters?", " Yes ",
395 " No ", 0))
396 {
397 cond_median_param_defaults (parampointer);
398 dont_stop = FALSE;
399 }
400 break;
401
402 case KEY_LEFT:
403 case KEY_UP:
404 focus--;
405 break;
406 case KEY_RIGHT:
407 case KEY_DOWN:
408 focus++;
409 break;
410 }
411 break;
412
413 case 7: /* OK */
414 switch (in_ch)
415 {
416 case KEY_ENTER:
417 case 13:
418
419 i = sscanf (medlengthstr.string, "%li", &helplong);
420 if (i < 1 || helplong < 1 || helplong % 2 == 0)
421 {
422 error_window ("A whole, odd number, greater than 0, must \
423 be specified as median length.");
424 medlengthstr.cursorpos =
425 strlen (medlengthstr.string);
426 focus = 0;
427 break;
428 }
429
430 parampointer->prelength1 = (helplong - 1) / 2;
431 parampointer->postlength1 = (helplong - 1) / 2;
432
433 i = sscanf (rmslengthstr.string, "%li", &helplong);
434 if (i < 1 || helplong < 1 || helplong % 2 == 0)
435 {
436 error_window ("A whole, odd number, greater than 0, must \
437 be specified as RMS length.");
438 rmslengthstr.cursorpos =
439 strlen (rmslengthstr.string);
440 focus = 1;
441 break;
442 }
443
444 parampointer->prelength2 = (helplong - 1) / 2;
445 parampointer->postlength2 = (helplong - 1) / 2;
446
447 i = sscanf (rmflengthstr.string, "%li", &helplong);
448 if (i < 1 || helplong < 1 || helplong % 2 == 0)
449 {
450 error_window ("A whole, odd number, greater than 0, must \
451 be specified as length of the recursive median.");
452 rmflengthstr.cursorpos =
453 strlen (rmflengthstr.string);
454 focus = 2;
455 break;
456 }
457
458 parampointer->prelength3 = (helplong - 1) / 2;
459 parampointer->postlength3 = (helplong - 1) / 2;
460
461 i = sscanf (decimatestr.string, "%li", &helplong);
462 if (i < 1 || helplong < 1)
463 {
464 error_window ("A whole number, greater than 0, must \
465 be specified as decimation factor.");
466 decimatestr.cursorpos =
467 strlen (decimatestr.string);
468 focus = 3;
469 break;
470 }
471
472 parampointer->int1 = helplong;
473
474 i = sscanf (thresholdstr.string, "%li", &helplong);
475 if (i < 1 || helplong < 1000)
476 {
477 error_window ("A whole number, greater than 1000, must \
478 be specified as threshold.");
479 thresholdstr.cursorpos =
480 strlen (thresholdstr.string);
481 focus = 4;
482 break;
483 }
484
485 parampointer->long1 = helplong;
486
487 dont_stop = FALSE;
488 break;
489
490 case KEY_LEFT:
491 case KEY_UP:
492 focus--;
493 break;
494 case KEY_RIGHT:
495 case KEY_DOWN:
496 focus++;
497 break;
498 }
499 break;
500 }
501
502 if (in_ch == 9) /* TAB */
503 focus++;
504
505 if (in_ch == 27)
506 dont_stop = FALSE;
507
508 if (focus > 7)
509 focus = 0;
510 if (focus < 0)
511 focus = 7;
512 }
513 while (dont_stop);
514
515 free (medlengthstr.string);
516 free (rmslengthstr.string);
517 free (rmflengthstr.string);
518 free (decimatestr.string);
519 free (thresholdstr.string);
520 }
521 #endif /* SWIG */
522
523 void
init_cond_median_filter(int filterno,parampointer_t parampointer)524 init_cond_median_filter (int filterno, parampointer_t parampointer)
525 {
526 long total_post;
527 long total_pre;
528
529 total_post = parampointer->postlength1;
530 if (parampointer->postlength2 > total_post)
531 total_post = parampointer->postlength2;
532
533 total_pre = parampointer->prelength1;
534 if (parampointer->prelength2 +
535 parampointer->prelength3 * parampointer->int1 + 1 > total_pre)
536 total_pre = parampointer->prelength2 +
537 parampointer->prelength3 * parampointer->int1 + 1;
538
539 parampointer->buffer = init_buffer (total_post, total_pre);
540 parampointer->buffer2 = init_buffer (parampointer->postlength2,
541 parampointer->prelength2);
542 parampointer->buffer3 = init_buffer (parampointer->postlength3,
543 parampointer->prelength3 * parampointer->int1);
544
545 parampointer->filterno = filterno;
546 }
547
548
549 void
delete_cond_median_filter(parampointer_t parampointer)550 delete_cond_median_filter (parampointer_t parampointer)
551 {
552 delete_buffer (¶mpointer->buffer);
553 delete_buffer (¶mpointer->buffer2);
554 delete_buffer (¶mpointer->buffer3);
555 }
556
557
558 sample_t
cond_median_highpass(long offset,long offset_zero,parampointer_t parampointer)559 cond_median_highpass (long offset, long offset_zero,
560 parampointer_t parampointer)
561 {
562 sample_t sample;
563 longsample_t sum;
564
565 offset += offset_zero; /* middle for highpass filter in
566 'big buffer' */
567 sum.left = 0;
568 sum.right = 0;
569
570 #define notTEST_DAVE_PLATT
571 #ifndef TEST_DAVE_PLATT
572 sample = get_from_buffer (¶mpointer->buffer, offset - 1);
573 sum.left += sample.left;
574 sum.right += sample.right;
575 sample = get_from_buffer (¶mpointer->buffer, offset);
576 sum.left -= 2 * (long) sample.left;
577 sum.right -= 2 * (long) sample.right;
578 sample = get_from_buffer (¶mpointer->buffer, offset + 1);
579 sum.left += sample.left;
580 sum.right += sample.right;
581
582 sum.left /= 4;
583 sum.right /= 4;
584 #else
585 /* Testing, suggested by Dave Platt. Invert phase of one channel, then
586 do tick detection using the sum signal. This is because most ticks
587 are out-of-phase signals. I've not really tested this - it might
588 require other settings for thresholds etc. */
589 sample = get_from_buffer (¶mpointer->buffer, offset - 1);
590 sum.left += sample.left;
591 sum.left -= sample.right;
592 sample = get_from_buffer (¶mpointer->buffer, offset);
593 sum.left -= 2 * (long) sample.left;
594 sum.left += 2 * (long) sample.right;
595 sample = get_from_buffer (¶mpointer->buffer, offset + 1);
596 sum.left += sample.left;
597 sum.left -= sample.right;
598
599 /* just in case L/R: 32000/-32000 -32000/32000 32000/-32000 : */
600 sum.left /= 8;
601 sum.right = sum.left;
602 #endif /* TEST_DAVE_PLATT */
603
604 sample.left = sum.left;
605 sample.right = sum.right;
606
607 return sample;
608 }
609
610 fillfuncpointer_t cond_median_highpass_pointer = cond_median_highpass;
611
612 sample_t
cond_median_rms(long offset,long offset_zero,parampointer_t parampointer)613 cond_median_rms (long offset, long offset_zero,
614 parampointer_t parampointer)
615 {
616 sample_t sample;
617 doublesample_t doublesample;
618 doublesample_t sum;
619 long i;
620
621 advance_current_pos_custom (¶mpointer->buffer2,
622 cond_median_highpass_pointer,
623 offset + offset_zero,
624 parampointer);
625
626 sum.left = 0;
627 sum.right = 0;
628
629 for (i = -parampointer->postlength2; i <= parampointer->prelength2;
630 i++)
631 {
632 sample = get_from_buffer (¶mpointer->buffer2, i);
633 doublesample.left = sample.left;
634 doublesample.right = sample.right;
635 sum.left += doublesample.left * doublesample.left;
636 sum.right += doublesample.right * doublesample.right;
637 }
638
639 sum.left /= (parampointer->postlength2 +
640 parampointer->prelength2 + 1);
641 sum.right /= (parampointer->postlength2 +
642 parampointer->prelength2 + 1);
643
644 sample.left = sqrt (sum.left + 1);
645 sample.right = sqrt (sum.right + 1);
646
647 return sample;
648 }
649
650 fillfuncpointer_t cond_median_rms_pointer = cond_median_rms;
651
652 sample_t
653 #ifndef SWIG
cond_median_filter(parampointer_t parampointer)654 cond_median_filter (parampointer_t parampointer)
655 #else
656 cond_median_filter (parampointer_t parampointer, int *filter_type)
657 #endif
658 {
659 sample_t sample;
660 sample_t w_t;
661 sample_t b_t;
662 sample_t returnval;
663 signed short list1[parampointer->postlength3 +
664 parampointer->prelength3 * parampointer->int1 + 1];
665 signed short list2[parampointer->postlength3 +
666 parampointer->prelength3 * parampointer->int1 + 1];
667 signed short list3[parampointer->postlength1 + parampointer->prelength1 + 1];
668 long i, j;
669
670 #ifndef SWIG
671 advance_current_pos (¶mpointer->buffer, parampointer->filterno);
672 #else
673 advance_current_pos (¶mpointer->buffer, parampointer->filterno, filter_type);
674 #endif
675
676 advance_current_pos_custom (¶mpointer->buffer3,
677 cond_median_rms_pointer,
678 0,
679 parampointer);
680
681 w_t = get_from_buffer (¶mpointer->buffer3, 0);
682
683 /* The RMF Filter */
684
685 for (i = 0; i < parampointer->postlength3; i++)
686 {
687 sample = get_from_buffer (¶mpointer->buffer3,
688 i - parampointer->postlength3);
689 list1[i] = sample.left;
690 list2[i] = sample.right;
691 }
692
693 j = i;
694
695 for (; i <= parampointer->postlength3 +
696 parampointer->prelength3 * parampointer->int1;
697 i += parampointer->int1)
698 {
699 sample = get_from_buffer (¶mpointer->buffer3,
700 i - parampointer->postlength3);
701 list1[j] = sample.left;
702 list2[j] = sample.right;
703 j++;
704 }
705
706 b_t.left = median (list1, j);
707 b_t.right = median (list2, j);
708
709 put_in_buffer (¶mpointer->buffer3, 0, b_t);
710
711 #ifdef VIEW_INTERNALS
712
713 returnval.left = b_t.left * 10;
714
715 if (
716 (labs (w_t.left - b_t.left) * 1000)
717 /
718 b_t.left > parampointer->long1)
719 returnval.right = 2000;
720 else
721 returnval.right = 0;
722
723 #else /* not VIEW_INTERNALS */
724
725 returnval = get_from_buffer (¶mpointer->buffer, 0);
726
727 /* Median Filters - if necessary */
728
729 if (
730 (labs (w_t.left - b_t.left) * 1000)
731 /
732 b_t.left > parampointer->long1)
733 {
734 for (i = 0; i <= parampointer->postlength1 +
735 parampointer->prelength1; i++)
736 list3[i] = get_from_buffer (¶mpointer->buffer,
737 i - parampointer->postlength1).left;
738
739 returnval.left = median (list3, parampointer->postlength1 +
740 parampointer->prelength1 + 1);
741 }
742
743 if (
744 (labs (w_t.right - b_t.right) * 1000)
745 /
746 b_t.right > parampointer->long1)
747 {
748 for (i = 0; i <= parampointer->postlength1 +
749 parampointer->prelength1; i++)
750 list3[i] = get_from_buffer (¶mpointer->buffer,
751 i - parampointer->postlength1).right;
752
753 returnval.right = median (list3, parampointer->postlength1 +
754 parampointer->prelength1 + 1);
755 }
756
757 #endif /* VIEW_INTERNALS */
758
759 return returnval;
760 }
761