Skip to content

Latest commit

 

History

History
203 lines (165 loc) · 5.53 KB

filter.c

File metadata and controls

203 lines (165 loc) · 5.53 KB
 
Oct 21, 1999
Oct 21, 1999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
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 GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "config.h"
#include "common.h"
May 14, 2006
May 14, 2006
38
#include "ctrlmode.h"
Oct 21, 1999
Oct 21, 1999
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#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;
Feb 1, 2000
Feb 1, 2000
66
xind = (float)((2*n - 1) * (2*n - 1));
Oct 21, 1999
Oct 21, 1999
67
68
for (i =0; i<n ; i++)
{
Feb 1, 2000
Feb 1, 2000
69
xi = (float)(i + 0.5);
Oct 21, 1999
Oct 21, 1999
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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++)
{
Feb 1, 2000
Feb 1, 2000
86
87
88
xi = (float) (i + 0.5);
omega = (float)(PI * xi);
g[i] = (float)(sin( (double) omega * fc) / omega);
Oct 21, 1999
Oct 21, 1999
89
90
91
}
att = 40.; /* attenuation in db */
Feb 1, 2000
Feb 1, 2000
92
93
beta = (float) (exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886
* (att - 20.96));
Oct 21, 1999
Oct 21, 1999
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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++)
Feb 1, 2000
Feb 1, 2000
119
120
sum += (float)(coef[i] *
((sample_window<0)? 0.0 : data[sample_window++])) ;
Oct 21, 1999
Oct 21, 1999
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* 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++)
Feb 1, 2000
Feb 1, 2000
150
151
sum += (float)(coef[i] *
((sample_window>=length)? 0.0 : data[sample_window++])) ;
Oct 21, 1999
Oct 21, 1999
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/* 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);
}