1 /* Effect: loudness filter Copyright (c) 2008 robs@users.sourceforge.net
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "dft_filter.h"
23 dft_filter_priv_t base
;
28 static int create(sox_effect_t
* effp
, int argc
, char **argv
)
30 priv_t
* p
= (priv_t
*)effp
->priv
;
31 dft_filter_priv_t
* b
= &p
->base
;
32 b
->filter_ptr
= &b
->filter
;
37 do { /* break-able block */
38 NUMERIC_PARAMETER(delta
,-50 , 15) /* FIXME expand range */
39 NUMERIC_PARAMETER(start
, 50 , 75) /* FIXME expand range */
40 NUMERIC_PARAMETER(n
,127 ,2047)
43 return argc
? lsx_usage(effp
) : SOX_SUCCESS
;
46 static double * make_filter(int n
, double start
, double delta
, double rate
)
48 static const struct {double f
, af
, lu
, tf
;} iso226_table
[] = {
49 { 20,0.532,-31.6,78.5},{ 25,0.506,-27.2,68.7},{ 31.5,0.480,-23.0,59.5},
50 { 40,0.455,-19.1,51.1},{ 50,0.432,-15.9,44.0},{ 63,0.409,-13.0,37.5},
51 { 80,0.387,-10.3,31.5},{ 100,0.367, -8.1,26.5},{ 125,0.349, -6.2,22.1},
52 { 160,0.330, -4.5,17.9},{ 200,0.315, -3.1,14.4},{ 250,0.301, -2.0,11.4},
53 { 315,0.288, -1.1, 8.6},{ 400,0.276, -0.4, 6.2},{ 500,0.267, 0.0, 4.4},
54 { 630,0.259, 0.3, 3.0},{ 800,0.253, 0.5, 2.2},{ 1000,0.250, 0.0, 2.4},
55 { 1250,0.246, -2.7, 3.5},{ 1600,0.244, -4.1, 1.7},{ 2000,0.243, -1.0,-1.3},
56 { 2500,0.243, 1.7,-4.2},{ 3150,0.243, 2.5,-6.0},{ 4000,0.242, 1.2,-5.4},
57 { 5000,0.242, -2.1,-1.5},{ 6300,0.245, -7.1, 6.0},{ 8000,0.254,-11.2,12.6},
58 {10000,0.271,-10.7,13.9},{12500,0.301, -3.1,12.3},
60 #define LEN (array_length(iso226_table) + 2)
61 #define SPL(phon, t) (10 / t.af * log10(4.47e-3 * (pow(10., .025 * (phon)) - \
62 1.15) + pow(.4 * pow(10., (t.tf + t.lu) / 10 - 9), t.af)) - t.lu + 94)
63 double fs
[LEN
], spl
[LEN
], d
[LEN
], * work
, * h
;
68 for (i
= 0; i
< (int)LEN
- 2; ++i
) {
69 spl
[i
+ 1] = SPL(start
+ delta
, iso226_table
[i
]) -
70 SPL(start
, iso226_table
[i
]);
71 fs
[i
+ 1] = log(iso226_table
[i
].f
);
73 fs
[i
+ 1] = log(100000.);
75 lsx_prepare_spline3(fs
, spl
, (int)LEN
, HUGE_VAL
, HUGE_VAL
, d
);
77 for (work_len
= 8192; work_len
< rate
/ 2; work_len
<<= 1);
78 work
= lsx_calloc(work_len
, sizeof(*work
));
79 h
= lsx_calloc(n
, sizeof(*h
));
81 for (i
= 0; i
<= work_len
/ 2; ++i
) {
82 double f
= rate
* i
/ work_len
;
83 double spl1
= f
< 1? spl
[0] : lsx_spline3(fs
, spl
, d
, (int)LEN
, log(f
));
84 work
[i
< work_len
/ 2 ? 2 * i
: 1] = dB_to_linear(spl1
);
86 lsx_safe_rdft(work_len
, -1, work
);
87 for (i
= 0; i
< n
; ++i
)
88 h
[i
] = work
[(work_len
- n
/ 2 + i
) % work_len
] * 2. / work_len
;
89 lsx_apply_kaiser(h
, n
, lsx_kaiser_beta(40 + 2./3 * fabs(delta
), .1));
97 static int start(sox_effect_t
* effp
)
99 priv_t
* p
= (priv_t
*) effp
->priv
;
100 dft_filter_t
* f
= p
->base
.filter_ptr
;
106 double * h
= make_filter(p
->n
, p
->start
, p
->delta
, effp
->in_signal
.rate
);
107 if (effp
->global_info
->plot
!= sox_plot_off
) {
109 sprintf(title
, "SoX effect: loudness %g (%g)", p
->delta
, p
->start
);
110 lsx_plot_fir(h
, p
->n
, effp
->in_signal
.rate
,
111 effp
->global_info
->plot
, title
, p
->delta
- 5, 0.);
114 lsx_set_dft_filter(f
, h
, p
->n
, p
->n
>> 1);
116 return lsx_dft_filter_effect_fn()->start(effp
);
119 sox_effect_handler_t
const * lsx_loudness_effect_fn(void)
121 static sox_effect_handler_t handler
;
122 handler
= *lsx_dft_filter_effect_fn();
123 handler
.name
= "loudness";
124 handler
.usage
= "[gain [ref]]";
125 handler
.getopts
= create
;
126 handler
.start
= start
;
127 handler
.priv_size
= sizeof(priv_t
);