summaryrefslogtreecommitdiffstats
path: root/apps/plugins/sdl/SDL_mixer/timidity/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/SDL_mixer/timidity/filter.c')
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/filter.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/filter.c b/apps/plugins/sdl/SDL_mixer/timidity/filter.c
new file mode 100644
index 0000000000..e93cc6b23c
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/filter.c
@@ -0,0 +1,187 @@
+/*
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the Perl Artistic License, available in COPYING.
+
+ filter.c: written by Vincent Pagel ( pagel@loria.fr )
+
+ implements fir antialiasing filter : should help when setting sample
+ rates as low as 8Khz.
+
+ April 95
+ - first draft
+
+ 22/5/95
+ - modify "filter" so that it simulate leading and trailing 0 in the buffer
+ */
+
+#include "config.h"
+#include "common.h"
+#include "ctrlmode.h"
+#include "instrum.h"
+#include "filter.h"
+
+/* bessel function */
+static float ino(float x)
+{
+ float y, de, e, sde;
+ int i;
+
+ y = x / 2;
+ e = 1.0;
+ de = 1.0;
+ i = 1;
+ do {
+ de = de * y / (float) i;
+ sde = de * de;
+ e += sde;
+ } while (!( (e * 1.0e-08 - sde > 0) || (i++ > 25) ));
+ return(e);
+}
+
+/* Kaiser Window (symetric) */
+static void kaiser(float *w,int n,float beta)
+{
+ float xind, xi;
+ int i;
+
+ xind = (float)((2*n - 1) * (2*n - 1));
+ for (i =0; i<n ; i++)
+ {
+ xi = (float)(i + 0.5);
+ w[i] = ino((float)(beta * sqrt((double)(1. - 4 * xi * xi / xind))))
+ / ino((float)beta);
+ }
+}
+
+/*
+ * fir coef in g, cuttoff frequency in fc
+ */
+static void designfir(float *g , float fc)
+{
+ int i;
+ float xi, omega, att, beta ;
+ float w[ORDER2];
+
+ for (i =0; i < ORDER2 ;i++)
+ {
+ xi = (float) (i + 0.5);
+ omega = (float)(PI * xi);
+ g[i] = (float)(sin( (double) omega * fc) / omega);
+ }
+
+ att = 40.; /* attenuation in db */
+ beta = (float) (exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886
+ * (att - 20.96));
+ kaiser( w, ORDER2, beta);
+
+ /* Matrix product */
+ for (i =0; i < ORDER2 ; i++)
+ g[i] = g[i] * w[i];
+}
+
+/*
+ * FIR filtering -> apply the filter given by coef[] to the data buffer
+ * Note that we simulate leading and trailing 0 at the border of the
+ * data buffer
+ */
+static void filter(sample_t *result,sample_t *data, int32 length,float coef[])
+{
+ int32 sample,i,sample_window;
+ int16 peak = 0;
+ float sum;
+
+ /* Simulate leading 0 at the begining of the buffer */
+ for (sample = 0; sample < ORDER2 ; sample++ )
+ {
+ sum = 0.0;
+ sample_window= sample - ORDER2;
+
+ for (i = 0; i < ORDER ;i++)
+ sum += (float)(coef[i] *
+ ((sample_window<0)? 0.0 : data[sample_window++])) ;
+
+ /* Saturation ??? */
+ if (sum> 32767.) { sum=32767.; peak++; }
+ if (sum< -32768.) { sum=-32768; peak++; }
+ result[sample] = (sample_t) sum;
+ }
+
+ /* The core of the buffer */
+ for (sample = ORDER2; sample < length - ORDER + ORDER2 ; sample++ )
+ {
+ sum = 0.0;
+ sample_window= sample - ORDER2;
+
+ for (i = 0; i < ORDER ;i++)
+ sum += data[sample_window++] * coef[i];
+
+ /* Saturation ??? */
+ if (sum> 32767.) { sum=32767.; peak++; }
+ if (sum< -32768.) { sum=-32768; peak++; }
+ result[sample] = (sample_t) sum;
+ }
+
+ /* Simulate 0 at the end of the buffer */
+ for (sample = length - ORDER + ORDER2; sample < length ; sample++ )
+ {
+ sum = 0.0;
+ sample_window= sample - ORDER2;
+
+ for (i = 0; i < ORDER ;i++)
+ sum += (float)(coef[i] *
+ ((sample_window>=length)? 0.0 : data[sample_window++])) ;
+
+ /* Saturation ??? */
+ if (sum> 32767.) { sum=32767.; peak++; }
+ if (sum< -32768.) { sum=-32768; peak++; }
+ result[sample] = (sample_t) sum;
+ }
+
+ if (peak)
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Saturation %2.3f %%.", 100.0*peak/ (float) length);
+}
+
+/***********************************************************************/
+/* Prevent aliasing by filtering any freq above the output_rate */
+/* */
+/* I don't worry about looping point -> they will remain soft if they */
+/* were already */
+/***********************************************************************/
+void antialiasing(Sample *sp, int32 output_rate )
+{
+ sample_t *temp;
+ int i;
+ float fir_symetric[ORDER];
+ float fir_coef[ORDER2];
+ float freq_cut; /* cutoff frequency [0..1.0] FREQ_CUT/SAMP_FREQ*/
+
+
+ ctl->cmsg(CMSG_INFO, VERB_NOISY, "Antialiasing: Fsample=%iKHz",
+ sp->sample_rate);
+
+ /* No oversampling */
+ if (output_rate>=sp->sample_rate)
+ return;
+
+ freq_cut= (float) output_rate / (float) sp->sample_rate;
+ ctl->cmsg(CMSG_INFO, VERB_NOISY, "Antialiasing: cutoff=%f%%",
+ freq_cut*100.);
+
+ designfir(fir_coef,freq_cut);
+
+ /* Make the filter symetric */
+ for (i = 0 ; i<ORDER2 ;i++)
+ fir_symetric[ORDER-1 - i] = fir_symetric[i] = fir_coef[ORDER2-1 - i];
+
+ /* We apply the filter we have designed on a copy of the patch */
+ temp = safe_malloc(sp->data_length);
+ memcpy(temp,sp->data,sp->data_length);
+
+ filter(sp->data,temp,sp->data_length/sizeof(sample_t),fir_symetric);
+
+ free(temp);
+}