1 /* libSoX effect: SpeexDsp effect to apply processing from libspeexdsp.
3 * Copyright 1999-2009 Chris Bagwell And SoX Contributors
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or (at
8 * your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <speex/speex_types.h>
25 #include <speex/speex_preprocess.h>
27 /* Private data for effect */
28 typedef struct speexdsp_priv_t
{
29 size_t buffer_end
; /* Index of the end of the buffer. */
30 size_t buffer_ipos
; /* Index for the next input sample. */
31 size_t buffer_opos
; /* Index of the next sample that has not been drained. */
32 int16_t* buffer
; /* Work buffer. */
33 SpeexPreprocessState
* sps
;/* DSP state. */
34 size_t agc
; /* Param: Automatic Gain Control target volume level: 0 to disable, or 1-100 (target volume). */
35 size_t denoise
; /* Param: Denoise: 0 to disable, or maximum noise attenuation in dB. */
36 size_t dereverb
; /* Param: Dereverb: 0 to disable, 1 to enable. */
37 size_t frames_per_second
; /* Param: Used to compute buffer size from sample rate. */
38 size_t samples_per_frame
; /* Param: Used to compute buffer size directly. Default is to use frames_per_second instead. */
49 *pParam
= default_val
;
50 if (*pArgc
> 1 && (*pArgv
)[1][0] != '-')
53 *pParam
= strtoul((*pArgv
)[1], &arg_end
, 0);
54 if (!arg_end
|| arg_end
[0] || *pParam
< min_valid
|| max_valid
<= *pParam
)
65 * Process command-line options but don't do other
66 * initialization now: effp->in_signal & effp->out_signal are not
69 static int getopts(sox_effect_t
* effp
, int argc
, char** argv
)
71 priv_t
* p
= (priv_t
*)effp
->priv
;
72 const size_t agcDefault
= 100;
73 const size_t denoiseDefault
= 15;
74 const size_t fpsDefault
= 50;
76 for (argc
--, argv
++; argc
; argc
--, argv
++)
78 if (!strcasecmp("-agc", argv
[0]))
80 /* AGC level argument is optional. If not specified, it defaults to agcDefault.
81 If specified, it must be from 0 to 100. */
82 if (!get_param(&argc
, &argv
, &p
->agc
, agcDefault
, 0, 100))
84 lsx_fail("Invalid argument \"%s\" to -agc parameter - expected number from 0 to 100.", argv
[1]);
85 return lsx_usage(effp
);
88 else if (!strcasecmp("-denoise", argv
[0]))
90 /* Denoise level argument is optional. If not specified, it defaults to denoiseDefault.
91 If specified, it must be from 0 to 100. */
92 if (!get_param(&argc
, &argv
, &p
->denoise
, denoiseDefault
, 0, 100))
94 lsx_fail("Invalid argument \"%s\" to -denoise parameter - expected number from 0 to 100.", argv
[1]);
95 return lsx_usage(effp
);
98 else if (!strcasecmp("-dereverb", argv
[0]))
102 else if (!strcasecmp("-spf", argv
[0]))
104 /* If samples_per_frame option is given, argument is required and must be
106 if (!get_param(&argc
, &argv
, &p
->samples_per_frame
, 0, 1, 1000000000) || !p
->samples_per_frame
)
108 lsx_fail("Invalid argument \"%s\" to -spf parameter - expected positive number.", argv
[1]);
109 return lsx_usage(effp
);
112 else if (!strcasecmp("-fps", argv
[0]))
114 /* If frames_per_second option is given, argument is required and must be
115 from 1 to 100. This will be used later to compute samples_per_frame once
116 we know the sample rate). */
117 if (!get_param(&argc
, &argv
, &p
->frames_per_second
, 0, 1, 100) || !p
->frames_per_second
)
119 lsx_fail("Invalid argument \"%s\" to -fps parameter - expected number from 1 to 100.", argv
[1]);
120 return lsx_usage(effp
);
125 lsx_fail("Invalid parameter \"%s\".", argv
[0]);
126 return lsx_usage(effp
);
130 if (!p
->frames_per_second
)
131 p
->frames_per_second
= fpsDefault
;
133 if (!p
->agc
&& !p
->denoise
&& !p
->dereverb
)
135 lsx_report("No features specified. Enabling default settings \"-agc %u -denoise %u\".", agcDefault
, denoiseDefault
);
137 p
->denoise
= denoiseDefault
;
144 * Do anything required when you stop reading samples.
146 static int stop(sox_effect_t
* effp
)
148 priv_t
* p
= (priv_t
*)effp
->priv
;
152 speex_preprocess_state_destroy(p
->sps
);
166 * Prepare processing.
167 * Do all initializations.
169 static int start(sox_effect_t
* effp
)
171 priv_t
* p
= (priv_t
*)effp
->priv
;
172 int result
= SOX_SUCCESS
;
176 if (p
->samples_per_frame
)
178 p
->buffer_end
= p
->samples_per_frame
;
182 p
->buffer_end
= effp
->in_signal
.rate
/ p
->frames_per_second
;
185 lsx_fail("frames_per_second too large for the current sample rate.");
190 p
->buffer_opos
= p
->buffer_end
;
191 effp
->out_signal
.precision
= 16;
193 p
->buffer
= lsx_malloc(p
->buffer_end
* sizeof(p
->buffer
[0]));
200 p
->sps
= speex_preprocess_state_init((int)p
->buffer_end
, (int)(effp
->in_signal
.rate
+ .5));
203 lsx_fail("Failed to initialize preprocessor DSP.");
208 int_val
= p
->agc
? 1 : 2;
209 speex_preprocess_ctl(p
->sps
, SPEEX_PREPROCESS_SET_AGC
, &int_val
);
212 float_val
= p
->agc
* 327.68f
;
213 speex_preprocess_ctl(p
->sps
, SPEEX_PREPROCESS_SET_AGC_LEVEL
, &float_val
);
216 int_val
= p
->denoise
? 1 : 2;
217 speex_preprocess_ctl(p
->sps
, SPEEX_PREPROCESS_SET_DENOISE
, &int_val
);
220 int_val
= -(spx_int32_t
)p
->denoise
;
221 speex_preprocess_ctl(p
->sps
, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS
, &int_val
);
224 int_val
= p
->dereverb
? 1 : 2;
225 speex_preprocess_ctl(p
->sps
, SPEEX_PREPROCESS_SET_DEREVERB
, &int_val
);
228 if (result
!= SOX_SUCCESS
)
235 * Process up to *isamp samples from ibuf and produce up to *osamp samples
236 * in obuf. Write back the actual numbers of samples to *isamp and *osamp.
237 * Return SOX_SUCCESS or, if error occurs, SOX_EOF.
241 const sox_sample_t
* ibuf
,
246 priv_t
* p
= (priv_t
*)effp
->priv
;
248 size_t ibuf_end
= *isamp
;
250 size_t obuf_end
= *osamp
;
256 /* Write any processed data in working buffer to the output buffer. */
257 end_pos
= obuf_pos
+ min(p
->buffer_end
- p
->buffer_opos
, obuf_end
- obuf_pos
);
258 for (; obuf_pos
< end_pos
; obuf_pos
++, p
->buffer_opos
++)
259 obuf
[obuf_pos
] = SOX_SIGNED_16BIT_TO_SAMPLE(p
->buffer
[p
->buffer_opos
], dummy
);
260 if (p
->buffer_opos
!= p
->buffer_end
)
261 break; /* Output buffer is full and we still have more processed data. */
263 /* Fill working buffer from input buffer. */
264 end_pos
= ibuf_pos
+ min(p
->buffer_end
- p
->buffer_ipos
, ibuf_end
- ibuf_pos
);
265 for (; ibuf_pos
< end_pos
; ibuf_pos
++, p
->buffer_ipos
++)
266 p
->buffer
[p
->buffer_ipos
] = SOX_SAMPLE_TO_SIGNED_16BIT(ibuf
[ibuf_pos
], effp
->clips
);
267 if (p
->buffer_ipos
!= p
->buffer_end
)
268 break; /* Working buffer is not full and there is no more input data. */
270 speex_preprocess_run(p
->sps
, p
->buffer
);
281 * Drain out remaining samples if the effect generates any.
283 static int drain(sox_effect_t
* effp
, sox_sample_t
* obuf
, size_t* osamp
)
285 priv_t
* p
= (priv_t
*)effp
->priv
;
287 size_t obuf_end
= *osamp
;
291 /* Input that hasn't been processed yet? */
292 if (p
->buffer_ipos
!= 0)
294 /* DSP only works on full frames, so fill the remaining space with 0s. */
295 for (i
= p
->buffer_ipos
; i
< p
->buffer_end
; i
++)
297 speex_preprocess_run(p
->sps
, p
->buffer
);
298 p
->buffer_end
= p
->buffer_ipos
;
303 end_pos
= obuf_pos
+ min(p
->buffer_end
- p
->buffer_opos
, obuf_end
- obuf_pos
);
304 for (; obuf_pos
< end_pos
; obuf_pos
++, p
->buffer_opos
++)
305 obuf
[obuf_pos
] = SOX_SIGNED_16BIT_TO_SAMPLE(p
->buffer
[p
->buffer_opos
], dummy
);
309 p
->buffer_opos
!= p
->buffer_end
315 * Function returning effect descriptor. This should be the only
316 * externally visible object.
318 const sox_effect_handler_t
* lsx_speexdsp_effect_fn(void)
322 * If no specific processing is needed for any of
323 * the 6 functions, then the function above can be deleted
324 * and NULL used in place of the its name below.
326 static sox_effect_handler_t descriptor
= {
327 "speexdsp", 0, SOX_EFF_PREC
| SOX_EFF_GAIN
| SOX_EFF_ALPHA
,
328 getopts
, start
, flow
, drain
, stop
, NULL
, sizeof(priv_t
)
330 static char const * lines
[] = {
331 "Uses the Speex DSP library to improve perceived sound quality.",
332 "If no options are specified, the -agc and -denoise features are enabled.",
334 "-agc [target_level] Enable automatic gain control, and optionally specify a",
335 " target volume level from 1-100 (default is 100).",
336 "-denoise [max_dB] Enable noise reduction, and optionally specify the max",
337 " attenuation (default is 15).",
338 "-dereverb Enable reverb reduction.",
339 "-fps frames_per_second Specify the number of frames per second from 1-100",
341 "-spf samples_per_frame Specify the number of samples per frame. Default is to",
342 " use the -fps setting.",
345 descriptor
.usage
= lsx_usage_lines(&usage
, lines
, array_length(lines
));
349 #endif /* HAVE_SPEEXDSP */