Re: [alsa-devel] ALSA 1.0.20 Speex PCM Plugin
At Mon, 8 Jun 2009 15:56:38 -0400, Robert Krakora wrote:
Takashi:
I applied your Speex echo cancellation patch. I had to modify it since the 'buf_out' buffer was not being malloc'd. Attached are the files affected by your patch. The echo cancellation seems to work pretty well. However, turning on 'denoise' seems to cause audio to drop in and out at a very periodic rate. Do you have any example of how to set up all of the parameters? A tutorial or something? Thanks again.
No idea, I just wrote it up blindly :) Can the preprocessor be dropped, possibly, like the patch below?
Takashi
--- diff --git a/doc/speexdsp.txt b/doc/speexdsp.txt index 875fc19..5b5e5a0 100644 --- a/doc/speexdsp.txt +++ b/doc/speexdsp.txt @@ -12,7 +12,7 @@ using libspeex DSP API. You can use the plugin with the plugin type
Then record like
- % arecord -fdat -c1 -Dplug:speex foo.wav + % arecord -fdat -c1 -Dplug:my_pcm foo.wav
so that you'll get 48kHz mono stream with the denoising effect.
@@ -44,6 +44,15 @@ The following parameters can be set optionally:
A boolean value to enable/disable dereverb function. Default is no.
+* echo + + A boolean value to enable/disable echo-cancellation function. + Default is no. + +* filter_length + + Number of samples of echo to cancel. As default it's 256. + For example, you can enable agc like
pcm.my_pcm { diff --git a/speex/pcm_speex.c b/speex/pcm_speex.c index 7bb9213..757a400 100644 --- a/speex/pcm_speex.c +++ b/speex/pcm_speex.c @@ -1,5 +1,5 @@ /* - * Speex preprocess plugin + * Speex DSP plugin * * Copyright (c) 2009 by Takashi Iwai tiwai@suse.de * @@ -21,12 +21,15 @@ #include <alsa/asoundlib.h> #include <alsa/pcm_external.h> #include <speex/speex_preprocess.h> +#include <speex/speex_echo.h>
-/* preprocessing parameters */ +/* DSP parameters */ struct spx_parms { int frames; int denoise; int agc; + int echo; + int filter_length; float agc_level; int dereverb; float dereverb_decay; @@ -38,7 +41,9 @@ typedef struct { struct spx_parms parms; /* instance and intermedate buffer */ SpeexPreprocessState *state; + SpeexEchoState *echo_state; short *buf; + short *outbuf; /* running states */ unsigned int filled; unsigned int processed; @@ -64,6 +69,18 @@ spx_transfer(snd_pcm_extplug_t *ext, short *src = area_addr(src_areas, src_offset); short *dst = area_addr(dst_areas, dst_offset); unsigned int count = size; + short *databuf; + + if (!spx->state && !spx->echo_state) { + /* no DSP processing */ + memcpy(dst, src, count * 2); + return size; + } + + if (spx->echo_state) + databuf = spx->outbuf; + else + databuf = spx->buf;
while (count > 0) { unsigned int chunk; @@ -72,14 +89,20 @@ spx_transfer(snd_pcm_extplug_t *ext, else chunk = count; if (spx->processed) - memcpy(dst, spx->buf + spx->filled, chunk * 2); + memcpy(dst, databuf + spx->filled, chunk * 2); else memset(dst, 0, chunk * 2); dst += chunk; memcpy(spx->buf + spx->filled, src, chunk * 2); spx->filled += chunk; if (spx->filled == spx->parms.frames) { - speex_preprocess_run(spx->state, spx->buf); + if (spx->echo_state) + speex_echo_capture(spx->echo_state, spx->buf, + spx->outbuf); + if (spx->state) + speex_preprocess_run(spx->state, databuf); + if (spx->echo_state) + speex_echo_playback(spx->echo_state, databuf); spx->processed = 1; spx->filled = 0; } @@ -94,6 +117,9 @@ static int spx_init(snd_pcm_extplug_t *ext) { snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext;
+ spx->filled = 0; + spx->processed = 0; + if (!spx->buf) { spx->buf = malloc(spx->parms.frames * 2); if (!spx->buf) @@ -101,12 +127,43 @@ static int spx_init(snd_pcm_extplug_t *ext) } memset(spx->buf, 0, spx->parms.frames * 2);
- if (spx->state) + if (!spx->outbuf) { + spx->outbuf = malloc(spx->parms.frames * 2); + if (!spx->outbuf) + return -ENOMEM; + } + memset(spx->outbuf, 0, spx->parms.frames * 2); + + if (spx->state) { speex_preprocess_state_destroy(spx->state); + spx->state = NULL; + } + if (spx->echo_state) { + speex_echo_state_destroy(spx->echo_state); + spx->echo_state = NULL; + } + + if (spx->parms.echo) { + spx->echo_state = speex_echo_state_init(spx->parms.frames, + spx->parms.filter_length); + if (!spx->echo_state) + return -EIO; + speex_echo_ctl(spx->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, + &spx->ext.rate); + } + + /* no preprocessor? */ + if (!spx->parms.denoise && !spx->parms.agc && !spx->parms.dereverb) + return 0; + spx->state = speex_preprocess_state_init(spx->parms.frames, spx->ext.rate); if (!spx->state) return -EIO; + if (spx->echo_state) + speex_preprocess_ctl(spx->state, + SPEEX_PREPROCESS_SET_ECHO_STATE, + spx->echo_state);
speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DENOISE, &spx->parms.denoise); @@ -120,18 +177,18 @@ static int spx_init(snd_pcm_extplug_t *ext) &spx->parms.dereverb_decay); speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &spx->parms.dereverb_level); - - spx->filled = 0; - spx->processed = 0; return 0; }
static int spx_close(snd_pcm_extplug_t *ext) { snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext; + free(spx->outbuf); free(spx->buf); if (spx->state) speex_preprocess_state_destroy(spx->state); + if (spx->echo_state) + speex_echo_state_destroy(spx->echo_state); return 0; }
@@ -205,6 +262,8 @@ SND_PCM_PLUGIN_DEFINE_FUNC(speex) .dereverb = 0, .dereverb_decay = 0, .dereverb_level = 0, + .echo = 0, + .filter_length = 256, };
snd_config_for_each(i, next, conf) { @@ -242,6 +301,13 @@ SND_PCM_PLUGIN_DEFINE_FUNC(speex) &parms.dereverb_level); if (err) goto ok; + err = get_bool_parm(n, id, "echo", &parms.echo); + if (err) + goto ok; + err = get_int_parm(n, id, "filter_length", + &parms.filter_length); + if (err) + goto ok; SNDERR("Unknown field %s", id); err = -EINVAL; ok: @@ -259,7 +325,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(speex) return -ENOMEM;
spx->ext.version = SND_PCM_EXTPLUG_VERSION; - spx->ext.name = "Speex Denoise Plugin"; + spx->ext.name = "Speex DSP Plugin"; spx->ext.callback = &speex_callback; spx->ext.private_data = spx; spx->parms = parms;
On Tue, Jun 9, 2009 at 4:07 AM, Takashi Iwaitiwai@suse.de wrote:
At Mon, 8 Jun 2009 15:56:38 -0400, Robert Krakora wrote:
Takashi:
I applied your Speex echo cancellation patch. I had to modify it since the 'buf_out' buffer was not being malloc'd. Attached are the files affected by your patch. The echo cancellation seems to work pretty well. However, turning on 'denoise' seems to cause audio to drop in and out at a very periodic rate. Do you have any example of how to set up all of the parameters? A tutorial or something? Thanks again.
No idea, I just wrote it up blindly :) Can the preprocessor be dropped, possibly, like the patch below?
Takashi
diff --git a/doc/speexdsp.txt b/doc/speexdsp.txt index 875fc19..5b5e5a0 100644 --- a/doc/speexdsp.txt +++ b/doc/speexdsp.txt @@ -12,7 +12,7 @@ using libspeex DSP API. You can use the plugin with the plugin type
Then record like
- % arecord -fdat -c1 -Dplug:speex foo.wav
- % arecord -fdat -c1 -Dplug:my_pcm foo.wav
so that you'll get 48kHz mono stream with the denoising effect.
@@ -44,6 +44,15 @@ The following parameters can be set optionally:
A boolean value to enable/disable dereverb function. Default is no.
+* echo
- A boolean value to enable/disable echo-cancellation function.
- Default is no.
+* filter_length
- Number of samples of echo to cancel. As default it's 256.
For example, you can enable agc like
pcm.my_pcm { diff --git a/speex/pcm_speex.c b/speex/pcm_speex.c index 7bb9213..757a400 100644 --- a/speex/pcm_speex.c +++ b/speex/pcm_speex.c @@ -1,5 +1,5 @@ /*
- Speex preprocess plugin
- Speex DSP plugin
* * Copyright (c) 2009 by Takashi Iwai tiwai@suse.de * @@ -21,12 +21,15 @@ #include <alsa/asoundlib.h> #include <alsa/pcm_external.h> #include <speex/speex_preprocess.h> +#include <speex/speex_echo.h>
-/* preprocessing parameters */ +/* DSP parameters */ struct spx_parms { int frames; int denoise; int agc;
- int echo;
- int filter_length;
float agc_level; int dereverb; float dereverb_decay; @@ -38,7 +41,9 @@ typedef struct { struct spx_parms parms; /* instance and intermedate buffer */ SpeexPreprocessState *state;
- SpeexEchoState *echo_state;
short *buf;
- short *outbuf;
/* running states */ unsigned int filled; unsigned int processed; @@ -64,6 +69,18 @@ spx_transfer(snd_pcm_extplug_t *ext, short *src = area_addr(src_areas, src_offset); short *dst = area_addr(dst_areas, dst_offset); unsigned int count = size;
- short *databuf;
- if (!spx->state && !spx->echo_state) {
- /* no DSP processing */
- memcpy(dst, src, count * 2);
- return size;
- }
- if (spx->echo_state)
- databuf = spx->outbuf;
- else
- databuf = spx->buf;
while (count > 0) { unsigned int chunk; @@ -72,14 +89,20 @@ spx_transfer(snd_pcm_extplug_t *ext, else chunk = count; if (spx->processed)
- memcpy(dst, spx->buf + spx->filled, chunk * 2);
- memcpy(dst, databuf + spx->filled, chunk * 2);
else memset(dst, 0, chunk * 2); dst += chunk; memcpy(spx->buf + spx->filled, src, chunk * 2); spx->filled += chunk; if (spx->filled == spx->parms.frames) {
- speex_preprocess_run(spx->state, spx->buf);
- if (spx->echo_state)
- speex_echo_capture(spx->echo_state, spx->buf,
- spx->outbuf);
- if (spx->state)
- speex_preprocess_run(spx->state, databuf);
- if (spx->echo_state)
- speex_echo_playback(spx->echo_state, databuf);
spx->processed = 1; spx->filled = 0; } @@ -94,6 +117,9 @@ static int spx_init(snd_pcm_extplug_t *ext) { snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext;
- spx->filled = 0;
- spx->processed = 0;
if (!spx->buf) { spx->buf = malloc(spx->parms.frames * 2); if (!spx->buf) @@ -101,12 +127,43 @@ static int spx_init(snd_pcm_extplug_t *ext) } memset(spx->buf, 0, spx->parms.frames * 2);
- if (spx->state)
- if (!spx->outbuf) {
- spx->outbuf = malloc(spx->parms.frames * 2);
- if (!spx->outbuf)
- return -ENOMEM;
- }
- memset(spx->outbuf, 0, spx->parms.frames * 2);
- if (spx->state) {
speex_preprocess_state_destroy(spx->state);
- spx->state = NULL;
- }
- if (spx->echo_state) {
- speex_echo_state_destroy(spx->echo_state);
- spx->echo_state = NULL;
- }
- if (spx->parms.echo) {
- spx->echo_state = speex_echo_state_init(spx->parms.frames,
- spx->parms.filter_length);
- if (!spx->echo_state)
- return -EIO;
- speex_echo_ctl(spx->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE,
- &spx->ext.rate);
- }
- /* no preprocessor? */
- if (!spx->parms.denoise && !spx->parms.agc && !spx->parms.dereverb)
- return 0;
spx->state = speex_preprocess_state_init(spx->parms.frames, spx->ext.rate); if (!spx->state) return -EIO;
- if (spx->echo_state)
- speex_preprocess_ctl(spx->state,
- SPEEX_PREPROCESS_SET_ECHO_STATE,
- spx->echo_state);
speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DENOISE, &spx->parms.denoise); @@ -120,18 +177,18 @@ static int spx_init(snd_pcm_extplug_t *ext) &spx->parms.dereverb_decay); speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &spx->parms.dereverb_level);
- spx->filled = 0;
- spx->processed = 0;
return 0; }
static int spx_close(snd_pcm_extplug_t *ext) { snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext;
- free(spx->outbuf);
free(spx->buf); if (spx->state) speex_preprocess_state_destroy(spx->state);
- if (spx->echo_state)
- speex_echo_state_destroy(spx->echo_state);
return 0; }
@@ -205,6 +262,8 @@ SND_PCM_PLUGIN_DEFINE_FUNC(speex) .dereverb = 0, .dereverb_decay = 0, .dereverb_level = 0,
- .echo = 0,
- .filter_length = 256,
};
snd_config_for_each(i, next, conf) { @@ -242,6 +301,13 @@ SND_PCM_PLUGIN_DEFINE_FUNC(speex) &parms.dereverb_level); if (err) goto ok;
- err = get_bool_parm(n, id, "echo", &parms.echo);
- if (err)
- goto ok;
- err = get_int_parm(n, id, "filter_length",
- &parms.filter_length);
- if (err)
- goto ok;
SNDERR("Unknown field %s", id); err = -EINVAL; ok: @@ -259,7 +325,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(speex) return -ENOMEM;
spx->ext.version = SND_PCM_EXTPLUG_VERSION;
- spx->ext.name = "Speex Denoise Plugin";
- spx->ext.name = "Speex DSP Plugin";
spx->ext.callback = &speex_callback; spx->ext.private_data = spx; spx->parms = parms;
Takashi:
Finally, I have your patch applied successfully and all seems to be working well. See the attached files.
Best Regards,
At Wed, 10 Jun 2009 17:36:20 -0400, Robert Krakora wrote:
Takashi:
Finally, I have your patch applied successfully and all seems to be working well. See the attached files.
Good to hear. I applied the patch to GIT tree now.
thanks,
Takashi
participants (2)
-
Robert Krakora
-
Takashi Iwai