File 50-cmf3.dpatch of Package gramofile

# Patch by James Tappin <james@xena.uklinux.net>
# Rediffed to unified format. [dk]
# Case changes to name of doc file to comply with rest of docs. [dk]

Index: Makefile
===================================================================
--- Makefile.orig	2012-04-20 15:55:58.431748806 +0200
+++ Makefile	2012-04-20 16:00:54.762614281 +0200
@@ -13,7 +13,8 @@ SRCS = boxes.c buttons.c checkfile.c dir
         signpr_general.c signpr_median.c signpr_filtmenu.c signpr_wav.c	\
 	secshms.c playwav.c signpr_cmf.c signpr_mean.c signpr_doubmed.c	\
 	splashscr.c tracksplit.c tracksplit_filenm.c			\
-        tracksplit_parammenu.c signpr_cmf2.c signpr_rms.c signpr_copy.c	\
+        tracksplit_parammenu.c signpr_cmf2.c  signpr_cmf3.c             \
+	signpr_rms.c signpr_copy.c					\
         signpr_exper.c endian.c signpr_mono.c signpr_l1fit.c
 
 DOCS = README COPYING ChangeLog TODO Signproc.txt Tracksplit.txt \
@@ -30,19 +31,19 @@ LDFLAGS =
 # For Linux (and maybe others), use these:
 CFLAGS = $(RPM_OPT_FLAGS) -funroll-loops -W -Wall -DTURBO_MEDIAN -DTURBO_BUFFER
 DEPS = $(OBJS) makebplay
-LIBS = -lncurses -lm
+LIBS = -lncurses -lrfftw -lfftw -lm
 COPY_A = -a
 
 # For FreeBSD (and maybe others), use these:
 #CFLAGS = -Wall -O2 -DTURBO_MEDIAN -DTURBO_BUFFER
 #DEPS = $(OBJS) makebplay
-#LIBS = -lncurses -lm
+#LIBS = -lncurses -lrfftw -lfftw -lm
 #COPY_A = -p
 
 # For IRIX (and maybe others), use these:
 #CFLAGS = -Wall -O2 -DTURBO_MEDIAN -DTURBO_BUFFER -DSWAP_ENDIAN -DOLD_CURSES
 #DEPS = $(OBJS)
-#LIBS = -lcurses -lm
+#LIBS = -lcurses -lrfftw -lfftw -lm
 #COPY_A = -a
 
 ##########
Index: Signpr_cmf3.txt
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ Signpr_cmf3.txt	2012-04-20 15:55:58.437748662 +0200
@@ -0,0 +1,42 @@
+SIGNPR_CMF3
+===========
+
+James Tappin: April 2001
+
+Signpr_cmf3 is a modification of signpr_cmf2, which uses a
+frequency-domain method to fill in the ticks.
+
+Why?: Because although cmf2 does an excellent job of detecting ticks,
+it makes a horrid mess of interpolating those that are close the peak
+of a sound wave (a situation which occurs very often on some 78's --
+indeed on some of my record the majority of the clicks are on peaks)
+and the resulting sound can then be worse than the original.
+
+What to do?: Since cmf2 does a very good job of picking out ticks that
+bit is unchanged, my goal here was to find a way that would smooth over
+the tick without cutting off more-or-less a half-cycle of the sound
+wave. Since the tick is located at the peak, and zeroth (the original
+cmf2) or first (FANCY_FILL) order interpolation will cut off the peak
+and thus cause an acoustically unpleasant breakup of the
+sound. Therefore I have here attempted to take a FFT of a region around
+the tick then exclude frequencies corresponding to features of the
+length of the tick or smaller. In the present version this is done by
+setting the components above this frequency to zero.
+
+Problems: It's slow -- If I could see a way to do 1 fft per tick rather
+than 1 fft per interpolated point it could go much quicker, but I don't
+see that this can be done within the gramofile buffers framework.
+
+What does it need: The fft's are done using the "fastest fourier
+transform in the west" http://www.fftw.org/ which attempts to find an
+optimum  way of doing the fft for the architecture and the size of the
+transform. In order to hold the fft plans and the length of the fft, 3
+new fields are added to the parampointer variable.
+
+Settings: The tick identification algorithm is identical with that used
+in cmf2 and the settings are therefore the same. The choice of fft
+length is determined as: Too large a value will slow the computation
+(remember fft is an n log(n) process), while too small a value results
+in a poor smoothing as the side lobes of the tick are have a larger
+effect on the values. The default is 2^9 (512).
+
Index: signpr_cmf3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ signpr_cmf3.c	2012-04-20 16:00:45.682833139 +0200
@@ -0,0 +1,1085 @@
+/* Conditional Median Filter - Better Version
+ *                             Using fft and eliminating high frequencies
+ *                             to fill over the ticks.
+ *
+ * Copyright (C) 1998 J.A. Bezemer
+ *               2001 S.J. Tappin
+ *
+ * Licensed under the terms of the GNU General Public License.
+ * ABSOLUTELY NO WARRANTY.
+ * See the file `COPYING' in this directory.
+ */
+
+/* Remove the `dont' to get the gate instead of the normal output - useful
+   for verifying properties. */
+#define dontVIEW_INTERNALS
+
+/* Choose the highpass filter: */
+#define noSECOND_ORDER
+#define FOURTH_ORDER
+#define noSIXTH_ORDER
+
+#define noDEBUGFILE
+
+#include "signpr_cmf3.h"
+#include "signpr_general.h"
+#include "signpr_l1fit.h"
+#include "errorwindow.h"
+#include "stringinput.h"
+#include "buttons.h"
+#include "clrscr.h"
+#include "boxes.h"
+#include "helpline.h"
+#include "yesnowindow.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#ifndef OLD_CURSES
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#ifdef DEBUGFILE
+static FILE *debugf=NULL;
+#endif
+
+#ifndef M_PIl
+# define M_PIl          3.1415926535897932384626433832795029L  /* pi */
+#endif
+
+void
+cond_median3_param_defaults (parampointer_t parampointer)
+{
+  parampointer->postlength2 = 4;
+  parampointer->prelength2 = 4;
+  parampointer->postlength3 = 5;
+  parampointer->prelength3 = 5;
+  parampointer->postlength4 = 256;
+  parampointer->prelength4 = 255;
+
+  parampointer->int1 = 12;
+  parampointer->int2 = 9;      /* This could be derived from
+				  postlength4 and prelength4,
+				  but it's messy */
+#if defined (SECOND_ORDER)
+  parampointer->long1 = 1000;	/* Threshold to detect precise tick length. */
+  parampointer->long2 = 2500;	/* Must be above this to be a tick. */
+#elif defined (FOURTH_ORDER)
+  parampointer->long1 = 2000;
+  parampointer->long2 = 8500;
+#elif defined (SIXTH_ORDER)
+  parampointer->long1 = 1500;
+  parampointer->long2 = 7500;
+#else
+#error A Highpass version must be defined (signpr_cmf3.c)
+#endif
+
+}
+
+
+#ifdef FOURTH_ORDER
+#undef SIGNPR_CMF3_PARAMSCR_HEADERTEXT
+#define SIGNPR_CMF3_PARAMSCR_HEADERTEXT "CMF IIF [FOURTH ORDER] - Parameters"
+#endif
+
+#ifdef SIXTH_ORDER
+#undef SIGNPR_CMF3_PARAMSCR_HEADERTEXT
+#define SIGNPR_CMF3_PARAMSCR_HEADERTEXT "CMF IIF [SIXTH ORDER] - Parameters"
+#endif
+
+void
+cond_median3_param_screen (parampointer_t parampointer)
+{
+  stringinput_t rmslengthstr, rmflengthstr, decimatestr, threshold1str;
+  stringinput_t threshold2str, fftstr;
+  button_t ok_button, cancel_button, defaults_button;
+  int dont_stop = TRUE;
+  int focus = 0;
+  int in_ch;
+  int i;
+  long helplong;
+
+  char *helplines[9] =
+  {
+    " ^: less ticks detected.                v: not all of tick interpolated.       ",
+    " ^: bad following of dynamics.          v: less ticks detected.                ",
+    " ^: bad following of dynamics.          v: less ticks detected.                ",
+    " ^: detected tick length too short      v: detected tick length longer.        ",
+    " ^: only strong ticks detected.         v: music-ticks also filtered out.      ",
+    " ^: Slower interpolation                v: possible problems with long ticks   ",
+    " Discard changes.                                                              ",
+    " Reset default values.                                                         ",
+    " Accept changes.                                                               "};
+
+  rmslengthstr.maxlen = 500;
+  rmslengthstr.string = (char *) malloc (rmslengthstr.maxlen *
+					 sizeof (char));
+  sprintf (rmslengthstr.string, "%ld", parampointer->prelength2 +
+	   parampointer->postlength2 + 1);
+  rmslengthstr.y = 6;
+  rmslengthstr.x = 59;
+  rmslengthstr.w = 19;
+  rmslengthstr.cursorpos = strlen (rmslengthstr.string);
+  rmslengthstr.firstcharonscreen = 0;
+
+  rmflengthstr.maxlen = 500;
+  rmflengthstr.string = (char *) malloc (rmflengthstr.maxlen *
+					 sizeof (char));
+  sprintf (rmflengthstr.string, "%ld", parampointer->prelength3 +
+	   parampointer->postlength3 + 1);
+  rmflengthstr.y = 8;
+  rmflengthstr.x = 59;
+  rmflengthstr.w = 19;
+  rmflengthstr.cursorpos = strlen (rmflengthstr.string);
+  rmflengthstr.firstcharonscreen = 0;
+
+  decimatestr.maxlen = 500;
+  decimatestr.string = (char *) malloc (decimatestr.maxlen *
+					sizeof (char));
+  sprintf (decimatestr.string, "%d", parampointer->int1);
+  decimatestr.y = 10;
+  decimatestr.x = 59;
+  decimatestr.w = 19;
+  decimatestr.cursorpos = strlen (decimatestr.string);
+  decimatestr.firstcharonscreen = 0;
+
+  threshold1str.maxlen = 500;
+  threshold1str.string = (char *) malloc (threshold1str.maxlen *
+					  sizeof (char));
+  sprintf (threshold1str.string, "%ld", parampointer->long1);
+  threshold1str.y = 12;
+  threshold1str.x = 59;
+  threshold1str.w = 19;
+  threshold1str.cursorpos = strlen (threshold1str.string);
+  threshold1str.firstcharonscreen = 0;
+
+  threshold2str.maxlen = 500;
+  threshold2str.string = (char *) malloc (threshold2str.maxlen *
+					  sizeof (char));
+  sprintf (threshold2str.string, "%ld", parampointer->long2);
+  threshold2str.y = 14;
+  threshold2str.x = 59;
+  threshold2str.w = 19;
+  threshold2str.cursorpos = strlen (threshold2str.string);
+  threshold2str.firstcharonscreen = 0;
+
+  fftstr.maxlen = 500;
+  fftstr.string = (char *) malloc (fftstr.maxlen *
+					  sizeof (char));
+  sprintf (fftstr.string, "%d", parampointer->int2);
+  fftstr.y = 16;
+  fftstr.x = 59;
+  fftstr.w = 19;
+  fftstr.cursorpos = strlen (fftstr.string);
+  fftstr.firstcharonscreen = 0;
+
+
+  ok_button.text = " OK ";
+  ok_button.y = 20;
+  ok_button.x = 71;
+  ok_button.selected = FALSE;
+
+  cancel_button.text = " Cancel ";
+  cancel_button.y = 20;
+  cancel_button.x = 5;
+  cancel_button.selected = FALSE;
+
+  defaults_button.text = " Defaults ";
+  defaults_button.y = 20;
+  defaults_button.x = 36;
+  defaults_button.selected = FALSE;
+
+  clearscreen (SIGNPR_CMF3_PARAMSCR_HEADERTEXT);
+
+  do
+    {
+      header (SIGNPR_CMF3_PARAMSCR_HEADERTEXT);
+
+      if (focus == 6)
+	cancel_button.selected = TRUE;
+      else
+	cancel_button.selected = FALSE;
+
+      if (focus == 7)
+	defaults_button.selected = TRUE;
+      else
+	defaults_button.selected = FALSE;
+
+      if (focus == 8)
+	ok_button.selected = TRUE;
+      else
+	ok_button.selected = FALSE;
+
+      mvprintw (3, 2,
+       "See also the Signproc.txt file for the meaning of the parameters.");
+
+      stringinput_display (&rmslengthstr);
+      mvprintw (rmslengthstr.y, 2,
+		"Length of the RMS operation (samples):");
+
+      stringinput_display (&rmflengthstr);
+      mvprintw (rmflengthstr.y, 2,
+		"Length of the recursive median operation (samples):");
+
+      stringinput_display (&decimatestr);
+      mvprintw (decimatestr.y, 2,
+		"Decimation factor for the recursive median:");
+
+      stringinput_display (&threshold1str);
+      mvprintw (threshold1str.y, 2,
+		"Fine threshold for tick start/end (thousandths):");
+
+      stringinput_display (&threshold2str);
+      mvprintw (threshold2str.y, 2,
+		"Threshold for detection of tick presence (thousandths):");
+
+      stringinput_display (&fftstr);
+      mvprintw (fftstr.y, 2,
+		"Length for fft to interpolate (2^n):");
+
+      button_display (&cancel_button);
+      mybox (cancel_button.y - 1, cancel_button.x - 1,
+	     3, strlen (cancel_button.text) + 2);
+      button_display (&defaults_button);
+      mybox (defaults_button.y - 1, defaults_button.x - 1,
+	     3, strlen (defaults_button.text) + 2);
+      button_display (&ok_button);
+      mybox (ok_button.y - 1, ok_button.x - 1,
+	     3, strlen (ok_button.text) + 2);
+
+      helpline (helplines[focus]);
+
+      switch (focus)
+	{
+	case 0:
+	  stringinput_display (&rmslengthstr);
+	  break;
+	case 1:
+	  stringinput_display (&rmflengthstr);
+	  break;
+	case 2:
+	  stringinput_display (&decimatestr);
+	  break;
+	case 3:
+	  stringinput_display (&threshold1str);
+	  break;
+	case 4:
+	  stringinput_display (&threshold2str);
+	  break;
+	case 5:
+	  stringinput_display (&fftstr);
+	  break;
+	default:
+	  move (0, 79);
+	}
+
+      refresh ();
+
+      in_ch = getch ();
+
+      switch (focus)
+	{
+	case 0:		/* rmslengthstr */
+	  stringinput_stdkeys (in_ch, &rmslengthstr);
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      i = sscanf (rmslengthstr.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1 || helplong % 2 == 0)
+		error_window ("A whole, odd number, greater than 0, must \
+be specified.");
+	      else
+		focus++;
+	      break;
+
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 1:		/* rmflengthstr */
+	  stringinput_stdkeys (in_ch, &rmflengthstr);
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      i = sscanf (rmflengthstr.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1 || helplong % 2 == 0)
+		error_window ("A whole, odd number, greater than 0, must \
+be specified.");
+	      else
+		focus++;
+	      break;
+
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 2:		/* decimatestr */
+	  stringinput_stdkeys (in_ch, &decimatestr);
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      i = sscanf (decimatestr.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1)
+		error_window ("A whole number, greater than 0, must \
+be specified.");
+	      else
+		focus++;
+	      break;
+
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 3:		/* threshold1str */
+	  stringinput_stdkeys (in_ch, &threshold1str);
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      i = sscanf (threshold1str.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1)
+		error_window ("A whole, positive number must be specified.");
+	      else
+		focus++;
+	      break;
+
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 4:		/* threshold2str */
+	  stringinput_stdkeys (in_ch, &threshold2str);
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      i = sscanf (threshold2str.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1)
+		error_window ("A whole, positive number must be specified.");
+	      else
+		focus++;
+	      break;
+
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 5:		/* fft length */
+	  stringinput_stdkeys (in_ch, &fftstr);
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      i = sscanf (fftstr.string, "%li", &helplong);
+	      if (i < 1 || helplong > 12 || helplong < 6)
+		error_window ("A number between 6 and 12 must be specified.");
+	      else
+		focus = 8;
+	      break;
+
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 6:		/* Cancel */
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      dont_stop = FALSE;
+	      break;
+
+	    case KEY_LEFT:
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_RIGHT:
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 7:		/* Defaults */
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+	      if (yesno_window ("Restore default parameters?", " Yes ",
+				" No ", 0))
+		{
+		  cond_median3_param_defaults (parampointer);
+		  dont_stop = FALSE;
+		}
+	      break;
+
+	    case KEY_LEFT:
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_RIGHT:
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+
+	case 8:		/* OK */
+	  switch (in_ch)
+	    {
+	    case KEY_ENTER:
+	    case 13:
+
+	      i = sscanf (rmslengthstr.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1 || helplong % 2 == 0)
+		{
+		  error_window ("A whole, odd number, greater than 0, must \
+be specified as RMS length.");
+		  rmslengthstr.cursorpos =
+		    strlen (rmslengthstr.string);
+		  focus = 0;
+		  break;
+		}
+
+	      parampointer->prelength2 = (helplong - 1) / 2;
+	      parampointer->postlength2 = (helplong - 1) / 2;
+
+	      i = sscanf (rmflengthstr.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1 || helplong % 2 == 0)
+		{
+		  error_window ("A whole, odd number, greater than 0, must \
+be specified as length of the recursive median.");
+		  rmflengthstr.cursorpos =
+		    strlen (rmflengthstr.string);
+		  focus = 1;
+		  break;
+		}
+
+	      parampointer->prelength3 = (helplong - 1) / 2;
+	      parampointer->postlength3 = (helplong - 1) / 2;
+
+	      i = sscanf (decimatestr.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1)
+		{
+		  error_window ("A whole number, greater than 0, must \
+be specified as decimation factor.");
+		  decimatestr.cursorpos =
+		    strlen (decimatestr.string);
+		  focus = 2;
+		  break;
+		}
+
+	      parampointer->int1 = helplong;
+
+	      i = sscanf (threshold1str.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1)
+		{
+		  error_window ("A whole, positive number must be \
+specified as threshold.");
+		  threshold1str.cursorpos =
+		    strlen (threshold1str.string);
+		  focus = 3;
+		  break;
+		}
+
+	      parampointer->long1 = helplong;
+
+	      i = sscanf (threshold2str.string, "%li", &helplong);
+	      if (i < 1 || helplong < 1000)
+		{
+		  error_window ("A whole, positive number must be \
+specified as threshold.");
+		  threshold2str.cursorpos =
+		    strlen (threshold2str.string);
+		  focus = 4;
+		  break;
+		}
+
+	      parampointer->long2 = helplong;
+
+	      i = sscanf (fftstr.string, "%li", &helplong);
+	      if (i < 1 || helplong > 12 || helplong < 6) {
+		error_window ("A number between 6 and 12 must be specified \
+as fft length");
+		fftstr.cursorpos = strlen(fftstr.string);
+		focus = 5;
+		break;
+	      }
+
+	      parampointer->int2 = helplong;
+	      parampointer->prelength4 = 1;
+	      for (i=1; i < parampointer->int2; i++) parampointer->prelength4 *= 2;
+	      parampointer->postlength4 = parampointer->prelength4-1;
+
+	      dont_stop = FALSE;
+	      break;
+
+	    case KEY_LEFT:
+	    case KEY_UP:
+	      focus--;
+	      break;
+	    case KEY_RIGHT:
+	    case KEY_DOWN:
+	      focus++;
+	      break;
+	    }
+	  break;
+	}
+
+      if (in_ch == 9)		/* TAB */
+	focus++;
+
+      if (in_ch == 27)
+	dont_stop = FALSE;
+
+      if (focus > 8)
+	focus = 0;
+      if (focus < 0)
+	focus = 8;
+    }
+  while (dont_stop);
+
+  free (rmslengthstr.string);
+  free (rmflengthstr.string);
+  free (decimatestr.string);
+  free (threshold1str.string);
+  free (threshold2str.string);
+}
+
+void
+init_cond_median3_filter (int filterno, parampointer_t parampointer)
+{
+  long total_post;
+  long total_pre;
+  long l;
+
+  total_post = parampointer->postlength4 + parampointer->prelength4 + 1 + 4;
+  /* +1+4=+5 : for highpass, max. 11th order */
+
+  total_pre = parampointer->postlength4 + parampointer->prelength4 + 1;
+  l = parampointer->prelength4 + parampointer->prelength3 *
+    parampointer->int1 + parampointer->prelength2 + 5;
+  /* + 5 : for highpass, max. 11th order */
+  if (l > total_pre)
+    total_pre = l;
+
+  parampointer->buffer = init_buffer (total_post, total_pre);
+  parampointer->buffer2 = init_buffer (parampointer->postlength2,
+				       parampointer->prelength2);
+  parampointer->buffer3 = init_buffer (parampointer->postlength3,
+			     parampointer->prelength3 * parampointer->int1);
+  parampointer->buffer4 = init_buffer (parampointer->postlength4,
+				       parampointer->prelength4);
+
+  parampointer->filterno = filterno;
+
+  /* Set up the FFT plans here. Since we expect to do lots of FFTs,
+     we take the time to MEASURE the best way to do them [SJT] */
+
+  parampointer->planf = rfftw_create_plan(parampointer->postlength4 +
+					  parampointer->prelength4 + 1,
+					  FFTW_REAL_TO_COMPLEX,
+					  FFTW_MEASURE);
+  parampointer->planr = rfftw_create_plan(parampointer->postlength4 +
+					  parampointer->prelength4 + 1,
+					  FFTW_COMPLEX_TO_REAL,
+					  FFTW_MEASURE);
+
+#ifdef DEBUGFILE
+  debugf = fopen("./gram.txt","w");
+#endif
+
+
+}
+
+
+void
+delete_cond_median3_filter (parampointer_t parampointer)
+{
+  delete_buffer (&parampointer->buffer);
+  delete_buffer (&parampointer->buffer2);
+  delete_buffer (&parampointer->buffer3);
+  delete_buffer (&parampointer->buffer4);
+
+  rfftw_destroy_plan(parampointer->planf);
+  rfftw_destroy_plan(parampointer->planr);
+
+#ifdef DEBUGFILE
+  fclose(debugf);
+#endif
+}
+
+
+sample_t
+cond_median3_highpass (long offset, long offset_zero,
+		       parampointer_t parampointer)
+{
+  sample_t sample;
+  longsample_t sum;
+
+  offset += offset_zero;	/* middle for highpass filter in
+				   'big buffer' */
+  sum.left = 0;
+  sum.right = 0;
+
+#if defined (SECOND_ORDER)
+#define notTEST_DAVE_PLATT
+#ifndef TEST_DAVE_PLATT
+  /* Original: */
+  sample = get_from_buffer (&parampointer->buffer, offset - 1);
+  sum.left += sample.left;
+  sum.right += sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset);
+  sum.left -= 2 * (long) sample.left;
+  sum.right -= 2 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 1);
+  sum.left += sample.left;
+  sum.right += sample.right;
+
+  sum.left /= 4;
+  sum.right /= 4;
+#else /* TEST_DAVE_PLATT */
+  /* Testing, suggested by Dave Platt. Invert phase of one channel, then
+     do tick detection using the sum signal. This is because most ticks
+     are out-of-phase signals. I've not really tested this - it might
+     require other settings for thresholds etc.
+     Note: implemented for second_order only! */
+  sample = get_from_buffer (&parampointer->buffer, offset - 1);
+  sum.left += sample.left;
+  sum.left -= sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset);
+  sum.left -= 2 * (long) sample.left;
+  sum.left += 2 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 1);
+  sum.left += sample.left;
+  sum.left -= sample.right;
+
+  /* just in case L/R: 32000/-32000 -32000/32000 32000/-32000 : */
+  sum.left /= 8;
+  sum.right = sum.left;
+#endif /* TEST_DAVE_PLATT */
+
+#elif defined (FOURTH_ORDER)
+  sample = get_from_buffer (&parampointer->buffer, offset - 2);
+  sum.left += sample.left;
+  sum.right += sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset - 1);
+  sum.left -= 4 * (long) sample.left;
+  sum.right -= 4 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset);
+  sum.left += 6 * (long) sample.left;
+  sum.right += 6 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 1);
+  sum.left -= 4 * (long) sample.left;
+  sum.right -= 4 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 2);
+  sum.left += sample.left;
+  sum.right += sample.right;
+
+  sum.left /= 4;
+  sum.right /= 4;
+
+#elif defined (SIXTH_ORDER)
+  sample = get_from_buffer (&parampointer->buffer, offset - 3);
+  sum.left -= sample.left;
+  sum.right -= sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset - 2);
+  sum.left += 6 * (long) sample.left;
+  sum.right += 6 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset - 1);
+  sum.left -= 15 * (long) sample.left;
+  sum.right -= 15 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset);
+  sum.left += 20 * (long) sample.left;
+  sum.right += 20 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 1);
+  sum.left -= 15 * (long) sample.left;
+  sum.right -= 15 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 2);
+  sum.left += 6 * (long) sample.left;
+  sum.right += 6 * (long) sample.right;
+  sample = get_from_buffer (&parampointer->buffer, offset + 3);
+  sum.left -= sample.left;
+  sum.right -= sample.right;
+
+  /* Should be /64, but the signal is extremely soft, so divide by less to
+     get more quantization levels (more accurate) */
+  sum.left /= 4;
+  sum.right /= 4;
+#endif
+
+  if (sum.left > 32767)
+    sample.left = 32767;
+  else if (sum.left < -32768)
+    sample.left = -32768;
+  else
+    sample.left = sum.left;
+
+
+  if (sum.right > 32767)
+    sample.right = 32767;
+  else if (sum.right < -32768)
+    sample.right = -32768;
+  else
+    sample.right = sum.right;
+
+
+  return sample;
+}
+
+fillfuncpointer_t cond_median3_highpass_pointer = cond_median3_highpass;
+
+sample_t
+cond_median3_rms (long offset, long offset_zero,
+		  parampointer_t parampointer)
+{
+  sample_t sample;
+  doublesample_t doublesample;
+  doublesample_t sum;
+  long i;
+
+  advance_current_pos_custom (&parampointer->buffer2,
+			      cond_median3_highpass_pointer,
+			      offset + offset_zero,
+			      parampointer);
+
+  sum.left = 0;
+  sum.right = 0;
+
+  for (i = -parampointer->postlength2; i <= parampointer->prelength2;
+       i++)
+    {
+      sample = get_from_buffer (&parampointer->buffer2, i);
+      doublesample.left = sample.left;
+      doublesample.right = sample.right;
+      sum.left += doublesample.left * doublesample.left;
+      sum.right += doublesample.right * doublesample.right;
+    }
+
+  sum.left /= (parampointer->postlength2 +
+	       parampointer->prelength2 + 1);
+  sum.right /= (parampointer->postlength2 +
+		parampointer->prelength2 + 1);
+
+  sample.left = sqrt (sum.left + 1);
+  sample.right = sqrt (sum.right + 1);
+
+  return sample;
+}
+
+fillfuncpointer_t cond_median3_rms_pointer = cond_median3_rms;
+
+sample_t
+cond_median3_gate (long offset, long offset_zero,
+		   parampointer_t parampointer)
+/* Well, not a `gate' any more - just (w[t]-b[t])/b[t], comparision to
+   make the real gate is done later. */
+{
+  sample_t sample;
+  sample_t w_t;
+  sample_t b_t;
+  sample_t returnval;
+  signed short list1[parampointer->postlength3 +
+		     parampointer->prelength3 * parampointer->int1 + 1];
+  signed short list2[parampointer->postlength3 +
+		     parampointer->prelength3 * parampointer->int1 + 1];
+  long i, j;
+
+  advance_current_pos_custom (&parampointer->buffer3,
+			      cond_median3_rms_pointer,
+			      offset + offset_zero,
+			      parampointer);
+
+  w_t = get_from_buffer (&parampointer->buffer3, 0);
+
+  /* The RMF Filter */
+
+  for (i = 0; i < parampointer->postlength3; i++)
+    {
+      sample = get_from_buffer (&parampointer->buffer3,
+				i - parampointer->postlength3);
+      list1[i] = sample.left;
+      list2[i] = sample.right;
+    }
+
+  j = i;
+
+  for (; i <= parampointer->postlength3 +
+       parampointer->prelength3 * parampointer->int1;
+       i += parampointer->int1)
+    {
+      sample = get_from_buffer (&parampointer->buffer3,
+				i - parampointer->postlength3);
+      list1[j] = sample.left;
+      list2[j] = sample.right;
+      j++;
+    }
+
+  b_t.left = median (list1, j);
+  b_t.right = median (list2, j);
+
+  put_in_buffer (&parampointer->buffer3, 0, b_t);
+
+
+  i = (labs (w_t.left - b_t.left) * 1000)
+    /
+    b_t.left;
+  if (i > 32767)
+    i = 32767;
+  else if (i < -32768)
+    i = -32768;
+
+  returnval.left = i;
+
+  i = (labs (w_t.right - b_t.right) * 1000)
+    /
+    b_t.right;
+  if (i > 32767)
+    i = 32767;
+  else if (i < -32768)
+    i = -32768;
+  returnval.right = i;
+
+  return returnval;
+}
+
+fillfuncpointer_t cond_median3_gate_pointer = cond_median3_gate;
+
+sample_t
+cond_median3_filter (parampointer_t parampointer)
+{
+  sample_t sample, gate, returnval;
+  /* Length of the fft we'll do to get the smoothed interpolate */
+
+  fftw_real list3[parampointer->postlength4 +
+		 parampointer->prelength4 + 1];
+  fftw_real list4[parampointer->postlength4 +
+		 parampointer->prelength4 + 1];
+
+  long fft_l = parampointer->postlength4 + parampointer->prelength4 + 1;
+  long i;
+  int toleft, toright, nfreq;
+  signed short maxval;
+
+  advance_current_pos (&parampointer->buffer, parampointer->filterno);
+
+  advance_current_pos_custom (&parampointer->buffer4,
+			      cond_median3_gate_pointer,
+			      0,
+			      parampointer);
+
+  gate = get_from_buffer (&parampointer->buffer4, 0);
+
+#ifdef VIEW_INTERNALS
+  returnval.left = 0;
+  returnval.right = 0;
+#else
+  /* 'Default' value - unchanged if there is no tick */
+  returnval = get_from_buffer (&parampointer->buffer, 0);
+#endif
+
+  if (gate.left > parampointer->long1)
+    {
+      maxval = gate.left;
+
+      toleft = -1;
+      sample.left = 0;
+      do
+	{
+	  toleft++;
+	  if (toleft < parampointer->postlength4)
+	    {
+	      sample = get_from_buffer (&parampointer->buffer4, -toleft - 1);
+	      if (sample.left > maxval)
+		/* if so, the `while' will continue anyway, so maxval may
+		   be adjusted here already (if necessary) */
+		maxval = sample.left;
+	    }
+	}
+      while (toleft < parampointer->postlength4 &&
+	     sample.left > parampointer->long1);
+
+      toright = -1;
+      sample.left = 0;
+      do
+	{
+	  toright++;
+	  if (toright < parampointer->prelength4)
+	    {
+	      sample = get_from_buffer (&parampointer->buffer4, toright + 1);
+	      if (sample.left > maxval)
+		/* if so, the `while' will continue anyway, so maxval may
+		   be adjusted here already (if necessary) */
+		maxval = sample.left;
+	    }
+	}
+      while (toright < parampointer->prelength4 &&
+	     sample.left > parampointer->long1);
+
+      /* only interpolate if there really is a tick */
+      if (maxval > parampointer->long2)
+	{
+
+#ifdef VIEW_INTERNALS
+	  returnval.left = (toright + toleft + 1) * 500;
+#else
+
+	  /* Use a HANNING window here for the time being; note that
+	     the FFT is centred at the middle of the tick not at the
+	     point we are interpolating.  */
+	  for (i = 0; i < fft_l; i++)
+	    {
+	      list3[i] = get_from_buffer(&parampointer->buffer,
+					 i - parampointer->prelength4 +
+					 (toright - toleft + 1)/2).left *
+		(2.-cos(2.*M_PIl*(double) i/ ((double) fft_l - 1.)))/2.;
+	    }
+	  rfftw_one(parampointer->planf, list3, list4);
+	  nfreq=floor((double) fft_l/(double) (2*(toleft+toright+1)));
+	  for (i = 2*nfreq; i <= fft_l - 2*nfreq; i++) list4[i] = 0.;
+	  for (i = nfreq; i<2*nfreq && i< fft_l/2; i++) {
+	    list4[i] *= (1. - (double) (i-nfreq)/ (double) nfreq);
+	    list4[fft_l-i] *= (1. - (double) (i-nfreq)/ (double) nfreq);
+	  }
+	  rfftw_one(parampointer->planr, list4, list3);
+	  returnval.left = (signed short) (list3[parampointer->prelength4 -
+						(toright - toleft + 1)/2]/
+					   (double) fft_l);
+
+	  /* DON'T ASK !!! -- I have NO idea why I have to MULTIPLY by
+	     the hanning window here. Everything sensible says DIVIDE, but
+	     multiply works, divide doesn't */
+
+	  returnval.left *= (2.-cos(2.*M_PIl*(double) ((toright - toleft + 1)/2) /
+				    ((double) fft_l - 1.)))/2.;
+#ifdef DEBUGFILE
+	  fprintf(debugf, "L: %ld %d %ld %ld\n",
+		  fft_l, (toleft+toright+1), nfreq,
+		  fft_l-nfreq);
+#endif
+
+#endif
+	}
+    }
+
+  if (gate.right > parampointer->long1)
+    {
+      maxval = gate.right;
+
+      toleft = -1;
+      sample.right = 0;
+      do
+	{
+	  toleft++;
+	  if (toleft < parampointer->postlength4)
+	    {
+	      sample = get_from_buffer (&parampointer->buffer4, -toleft - 1);
+	      if (sample.right > maxval)
+		/* if so, the `while' will continue anyway, so maxval may
+		   be adjusted here already (if necessary) */
+		maxval = sample.right;
+	    }
+	}
+      while (toleft < parampointer->postlength4 &&
+	     sample.right > parampointer->long1);
+
+      toright = -1;
+      sample.right = 0;
+      do
+	{
+	  toright++;
+	  if (toright < parampointer->prelength4)
+	    {
+	      sample = get_from_buffer (&parampointer->buffer4, toright + 1);
+	      if (sample.right > maxval)
+		/* if so, the `while' will continue anyway, so maxval may
+		   be adjusted here already (if necessary) */
+		maxval = sample.right;
+	    }
+	}
+      while (toright < parampointer->prelength4 &&
+	     sample.right > parampointer->long1);
+
+      /* only interpolate if there really is a tick */
+      if (maxval > parampointer->long2)
+	{
+
+#ifdef VIEW_INTERNALS
+	  returnval.right = (toright + toleft + 1) * 500;
+#else
+	  /* Use a HANNING window here for the time being; note that
+	     the FFT is centred at the middle of the tick not at the
+	     point we are interpolating.  */
+	  for (i = 0; i < fft_l; i++)
+	    {
+	      list3[i] = get_from_buffer(&parampointer->buffer,
+					 i - parampointer->prelength4 +
+					 (toright - toleft + 1)/2).right *
+		(2.-cos(2.*M_PIl*(double) i/ ((double) fft_l - 1.)))/2.;
+	    }
+	  rfftw_one(parampointer->planf, list3, list4);
+
+	  nfreq=floor((double) fft_l/(double) (2*(toleft+toright+1)));
+	  for (i = 2*nfreq; i <= fft_l - 2*nfreq; i++) list4[i] = 0.;
+	  for (i = nfreq; i<2*nfreq && i<fft_l/2; i++) {
+	    list4[i] *= (1. - (double) (i-nfreq)/ (double) nfreq);
+	    list4[fft_l-i] *= (1. - (double) (i-nfreq)/ (double) nfreq);
+	  }
+
+	  rfftw_one(parampointer->planr, list4, list3);
+	  returnval.right = (signed short) (list3[parampointer->prelength4 -
+						 (toright - toleft + 1)/2]/
+					    (double) fft_l) ;
+
+	  /* DON'T ASK !!! -- I have NO idea why I have to MULTIPLY by
+	     the hanning window here. Everything sensible says DIVIDE, but
+	     multiply works, divide doesn't */
+
+	  returnval.right *= (2.-cos(2.*M_PIl*(double) ((toright - toleft + 1)/2) /
+				     ((double) fft_l - 1.)))/2.;
+#ifdef DEBUGFILE
+	  fprintf(debugf, "R: %ld %d %ld %ld\n",
+		  fft_l, (toleft+toright+1), nfreq,
+		  fft_l - nfreq);
+#endif
+
+#endif
+	}
+    }
+
+  return returnval;
+}
Index: signpr_cmf3.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ signpr_cmf3.h	2012-04-20 15:55:58.438748638 +0200
@@ -0,0 +1,29 @@
+/* Simple Median Filter - Better Version - Header
+
+ * Copyright (C) 1998 J.A. Bezemer
+ *
+ * Licensed under the terms of the GNU General Public License.
+ * ABSOLUTELY NO WARRANTY.
+ * See the file `COPYING' in this directory.
+ */
+
+#ifndef HAVE_SIGNPR_CMF3_H
+#define HAVE_SIGNPR_CMF3_H
+
+
+#include "signpr_general.h"
+
+#define SIGNPR_CMF3_PARAMSCR_HEADERTEXT "Conditional Median Filter IIF - Parameters"
+
+void cond_median3_param_defaults (parampointer_t parampointer);
+
+void cond_median3_param_screen (parampointer_t parampointer);
+
+void init_cond_median3_filter (int filterno, parampointer_t parampointer);
+
+void delete_cond_median3_filter (parampointer_t parampointer);
+
+sample_t cond_median3_filter (parampointer_t parampointer);
+
+
+#endif /* HAVE_SIGNPR_CMF3_H */
Index: signpr_general.c
===================================================================
--- signpr_general.c.orig	2000-03-28 23:07:26.000000000 +0200
+++ signpr_general.c	2012-04-20 15:55:58.438748638 +0200
@@ -14,6 +14,7 @@
 #include "signpr_wav.h"
 #include "signpr_cmf.h"
 #include "signpr_cmf2.h"
+#include "signpr_cmf3.h"
 #include "signpr_mean.h"
 #include "signpr_doubmed.h"
 #include "signpr_rms.h"
@@ -511,6 +512,13 @@ make_filterlist (scrollmenu_t * filtlist
   add_to_filterlist (filtlist,
 		     filtnumbers,
 		     helptexts,
+		     COND_MEDIAN3_FILTER,
+		     COND_MEDIAN3_NAME,
+		     COND_MEDIAN3_HELPTEXT);
+
+  add_to_filterlist (filtlist,
+		     filtnumbers,
+		     helptexts,
 		     EXPERIMENT_FILTER,
 		     EXPERIMENT_NAME,
 		     EXPERIMENT_HELPTEXT);
@@ -559,6 +567,10 @@ get_sample_from_filter (int filterno)
 	return monoize_filter (parampointerarray[filterno]);
 	break;
 
+      case COND_MEDIAN3_FILTER:
+	return cond_median3_filter (parampointerarray[filterno]);
+	break;
+
       case EXPERIMENT_FILTER:
 	return experiment_filter (parampointerarray[filterno]);
 	break;
@@ -615,6 +627,10 @@ init_filters ()
 	init_monoize_filter (i, parampointerarray[i]);
 	break;
 
+      case COND_MEDIAN3_FILTER:
+	init_cond_median3_filter (i, parampointerarray[i]);
+	break;
+
       case EXPERIMENT_FILTER:
 	init_experiment_filter (i, parampointerarray[i]);
 	break;
@@ -671,6 +687,10 @@ delete_filters ()
 	delete_monoize_filter (parampointerarray[i]);
 	break;
 
+      case COND_MEDIAN3_FILTER:
+	delete_cond_median3_filter (parampointerarray[i]);
+	break;
+
       case EXPERIMENT_FILTER:
 	delete_experiment_filter (parampointerarray[i]);
 	break;
@@ -724,6 +744,10 @@ param_defaults (parampointer_t parampoin
       monoize_param_defaults (parampointer);
       break;
 
+    case COND_MEDIAN3_FILTER:
+      cond_median3_param_defaults (parampointer);
+      break;
+
     case EXPERIMENT_FILTER:
       experiment_param_defaults (parampointer);
       break;
@@ -777,6 +801,10 @@ param_screen (parampointer_t parampointe
       monoize_param_screen (parampointer);
       break;
 
+    case COND_MEDIAN3_FILTER:
+      cond_median3_param_screen (parampointer);
+      break;
+
     case EXPERIMENT_FILTER:
       experiment_param_screen (parampointer);
       break;
Index: signpr_general.h
===================================================================
--- signpr_general.h.orig	2000-03-28 23:07:26.000000000 +0200
+++ signpr_general.h	2012-04-20 15:55:58.438748638 +0200
@@ -13,6 +13,9 @@
 
 #include "scrollmenu.h"
 
+/* This has to be here, otherwise the FFT interpolating filter
+   can't keep its plans [SJT] */
+#include <rfftw.h>
 
 /* SAMPLES */
 
@@ -70,9 +73,12 @@ typedef struct
     signed short *sslist1;
     signed short *sslist2;
 
-    int int1;
+    int int1, int2;
     long long1;
     long long2;
+
+    rfftw_plan planf, planr;
+
   }
 param_t;
 
@@ -221,7 +227,12 @@ void param_screen (parampointer_t paramp
 #define MONOIZE_HELPTEXT        \
 "Average left & right signals."
 
-#define EXPERIMENT_FILTER	9
+#define COND_MEDIAN3_FILTER	9
+#define COND_MEDIAN3_NAME	"Conditional Median Filter IIF"
+#define COND_MEDIAN3_HELPTEXT	\
+"Remove ticks while not changing rest of signal - Using freq domain interp."
+
+#define EXPERIMENT_FILTER	10
 #define EXPERIMENT_NAME		"Experimenting Filter"
 #define EXPERIMENT_HELPTEXT	\
 "The filter YOU are experimenting with (in signpr_exper.c)"