File: deemphas.c

package info (click to toggle)
sox 12.16-6
  • links: PTS
  • area: main
  • in suites: potato
  • size: 1,180 kB
  • ctags: 1,466
  • sloc: ansic: 16,658; sh: 2,071; makefile: 126
file content (201 lines) | stat: -rw-r--r-- 5,716 bytes parent folder | download
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
38
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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
119
120
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
150
151
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
/*
 * July 5, 1991
 * Copyright 1991 Lance Norskog And Sundry Contributors
 * This source code is freely redistributable and may be used for
 * any purpose.  This copyright notice must be maintained.
 * Lance Norskog And Sundry Contributors are not responsible for
 * the consequences of using this software.
 *
 * Fixed deemphasis filter for processing pre-emphasized audio cd samples
 * 09/02/98 (c) Heiko Ei�feldt
 * License: GPL (Gnu Public License)
 *
 * This implements the inverse filter of the optional pre-emphasis stage as
 * defined by ISO 908 (describing the audio cd format).
 *
 * Background:
 * In the early days of audio cds, there were recording problems
 * with noise (for example in classical recordings). The high dynamics
 * of audio cds exposed these recording errors a lot.
 *
 * The commonly used solution at that time was to 'pre-emphasize' the
 * trebles to have a better signal-noise-ratio. That is trebles were
 * amplified before recording, so that they would give a stronger
 * signal compared to the underlying (tape)noise.
 *
 * For that purpose the audio signal was prefiltered with the following
 * frequency response (simple first order filter):
 *
 * V (in dB)
 * ^
 * |
 * |                         _________________
 * |                        /
 * |                       / |
 * |     20 dB / decade ->/  |
 * |                     /   |
 * |____________________/_ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ lg f
 * |0 dB                |    |
 * |                    |    |
 * |                    |    |
 *                 3.1KHz    ca. 10KHz
 *
 * So the recorded audio signal has amplified trebles compared to the
 * original.
 * HiFi cd players do correct this by applying an inverse filter
 * automatically, the cd-rom drives or cd burners used by digital
 * sampling programs (like cdda2wav) however do not.
 *
 * So, this is what this effect does.
 *
 * Here is the gnuplot file for the frequency response
   of the deemphasis. The error is below +-0.1dB

-------- Start of gnuplot file ---------------------
# first define the ideal filter. We use the tenfold sampling frequency.
T=1./441000.
OmegaU=1./15E-6
OmegaL=15./50.*OmegaU
V0=OmegaL/OmegaU
H0=V0-1.
B=V0*tan(OmegaU*T/2.)
# the coefficients follow
a1=(B - 1.)/(B + 1.)
b0=(1.0 + (1.0 - a1) * H0/2.)
b1=(a1 + (a1 - 1.0) * H0/2.)
# helper variables
D=b1/b0
o=2*pi*T
H2(f)=b0*sqrt((1+2*cos(f*o)*D+D*D)/(1+2*cos(f*o)*a1+a1*a1))
#
# now approximate the ideal curve with a fitted one for sampling
frequency
# of 44100 Hz. Fitting parameters are
# amplification at high frequencies V02
# and tau of the upper edge frequency OmegaU2 = 2 *pi * f(upper)
T2=1./44100.
V02=0.3365
OmegaU2=1./19E-6
B2=V02*tan(OmegaU2*T2/2.)
# the coefficients follow
a12=(B2 - 1.)/(B2 + 1.)
b02=(1.0 + (1.0 - a12) * (V02-1.)/2.)
b12=(a12 + (a12 - 1.0) * (V02-1.)/2.)
# helper variables
D2=b12/b02
o2=2*pi*T2
H(f)=b02*sqrt((1+2*cos(f*o2)*D2+D2*D2)/(1+2*cos(f*o2)*a12+a12*a12))
# plot best, real, ideal, level with halved attenuation,
#      level at full attentuation, 10fold magnified error
set logscale x
set grid xtics ytics mxtics mytics
plot [f=1000:20000] [-12:2] 20*log10(H(f)),20*log10(H2(f)),
20*log10(OmegaL/(2*
pi*f)), 0.5*20*log10(V0), 20*log10(V0), 200*log10(H(f)/H2(f))
pause -1 "Hit return to continue"
-------- End of gnuplot file ---------------------

 */

/*
 * adapted from Sound Tools skeleton effect file.
 */

#include <math.h>
#include "st.h"

/* Private data for deemph file */
typedef struct deemphstuff {
     LONG lastin;
     double    lastout;
} *deemph_t;

/*
 * Process options
 *
 * Don't do initialization now.
 * The 'info' fields are not yet filled in.
 */
void deemph_getopts(effp, n, argv)
eff_t effp;
int n;
char **argv;
{
     if (n)
          fail("Deemphasis filtering effect takes no options.\n");
     if (sizeof(double)*PRIVSIZE < sizeof(struct deemphstuff))
          fail("Internal error: PRIVSIZE too small.\n");
}

/*
 * Prepare processing.
 * Do all initializations.
 */
void deemph_start(effp)
eff_t effp;
{
     /* check the input format */
     if (effp->ininfo.style != SIGN2
         || effp->ininfo.rate != 44100
         || effp->ininfo.size != WORD)
          fail("The deemphasis effect works only with audio cd like samples.\nThe input format however has %d Hz sample rate and %d-byte%s signed linearly coded samples.",
            effp->ininfo.rate, effp->ininfo.size,
            effp->ininfo.style != SIGN2 ? ", but not" : "");
     {
          deemph_t deemph = (deemph_t) effp->priv;

          deemph->lastin = 0;
          deemph->lastout = 0.0;
     }
}

/*
 * Processed signed long samples from ibuf to obuf.
 * Return number of samples processed.
 */

/* filter coefficients */
#define a1      -0.62786881719628784282
#define b0      0.45995451989513153057
#define b1      -0.08782333709141937339

void deemph_flow(effp, ibuf, obuf, isamp, osamp)
eff_t effp;
LONG *ibuf, *obuf;
int *isamp, *osamp;
{
     deemph_t deemph = (deemph_t) effp->priv;
     int len, done;

     len = ((*isamp > *osamp) ? *osamp : *isamp);
     for(done = len; done; done--) {
          deemph->lastout = *ibuf * b0 +
                         deemph->lastin * b1 -
                         deemph->lastout * a1;
          deemph->lastin = *ibuf++;
          *obuf++ = deemph->lastout > 0.0 ?
                    deemph->lastout + 0.5 :
                    deemph->lastout - 0.5;
     }
}

/*
 * Drain out remaining samples if the effect generates any.
 */

void deemph_drain(effp, obuf, osamp)
LONG *obuf;
int *osamp;
{
     /* nothing to do */
}

/*
 * Do anything required when you stop reading samples.
 *   (free allocated memory, etc.)
 */
void deemph_stop(effp)
eff_t effp;
{
     /* nothing to do */
}