[alsa-devel] ALSA 1.0.20 Speex PCM Plugin
Takashi Iwai
tiwai at suse.de
Thu Jun 4 15:46:19 CEST 2009
At Tue, 2 Jun 2009 16:39:46 -0400,
Robert Krakora wrote:
>
> Hello,
>
> Has anyone successfully employed the ALSA 1.0.20 Speex PCM Plugin? I
> followed the "speexdsp.txt" document under the 'doc' directory but the
> result was the following error:
>
> [root at vizioroom105 ~]# arecord -Dplug:mic poopy.wav
> Recording WAVE 'poopy.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
> ALSA lib pcm_params.c:2135:(snd1_pcm_hw_refine_slave) Slave PCM not usable
> arecord: set_params:957: Broken configuration for this PCM: no
> configurations available
It's because the slave plugin of pcm.mic is "hw" and that doesn't
support mono streams but only stereo. speex plugin requires a mono
stream explicitly.
Wrap speex plugin over the default or add plug layer inside it, too.
BTW, I found that I didn't put any echo-cancelling code in the speex
plugin. It was just written for denoising.
The below is a quick hack to add the echo-cancelling part. Give it a try
(although it's totally untested :)
Takashi
---
diff --git a/doc/speexdsp.txt b/doc/speexdsp.txt
index 875fc19..1937de6 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,16 @@ 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..38b3582 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 at 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,12 @@ 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->parms.echo)
+ databuf = spx->outbuf;
+ else
+ databuf = spx->buf;
while (count > 0) {
unsigned int chunk;
@@ -72,14 +83,19 @@ 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->parms.echo)
+ speex_echo_capture(spx->echo_state, spx->buf,
+ spx->outbuf);
+ speex_preprocess_run(spx->state, databuf);
+ if (spx->parms.echo)
+ speex_echo_playback(spx->echo_state, databuf);
spx->processed = 1;
spx->filled = 0;
}
@@ -101,13 +117,34 @@ static int spx_init(snd_pcm_extplug_t *ext)
}
memset(spx->buf, 0, spx->parms.frames * 2);
- if (spx->state)
+ 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);
+ }
+
spx->state = speex_preprocess_state_init(spx->parms.frames,
spx->ext.rate);
if (!spx->state)
return -EIO;
+ if (spx->parms.echo)
+ 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);
speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_AGC,
@@ -132,6 +169,8 @@ static int spx_close(snd_pcm_extplug_t *ext)
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 +244,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 +283,12 @@ 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 +306,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;
More information about the Alsa-devel
mailing list