472 lines
12 KiB
Diff
472 lines
12 KiB
Diff
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/oss/pcm_oss.c b/oss/pcm_oss.c
|
|
index 8a2a672..d43b44c 100644
|
|
--- a/oss/pcm_oss.c
|
|
+++ b/oss/pcm_oss.c
|
|
@@ -181,6 +181,7 @@ static int oss_hw_params(snd_pcm_ioplug_t *io,
|
|
fprintf(stderr, "*** OSS: invalid period size %d\n", (int)io->period_size);
|
|
return -EINVAL;
|
|
}
|
|
+ oss->periods = io->buffer_size / io->period_size;
|
|
|
|
_retry:
|
|
tmp = oss->period_shift | (oss->periods << 16);
|
|
diff --git a/pph/rate_speexrate.c b/pph/rate_speexrate.c
|
|
index 38244b6..0a1325c 100644
|
|
--- a/pph/rate_speexrate.c
|
|
+++ b/pph/rate_speexrate.c
|
|
@@ -116,6 +116,26 @@ static void pcm_src_close(void *obj)
|
|
free(obj);
|
|
}
|
|
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+static int get_supported_rates(void *obj, unsigned int *rate_min,
|
|
+ unsigned int *rate_max)
|
|
+{
|
|
+ *rate_min = *rate_max = 0; /* both unlimited */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void dump(void *obj, snd_output_t *out)
|
|
+{
|
|
+ snd_output_printf(out, "Converter: libspeex "
|
|
+#ifdef USE_LIBSPEEX
|
|
+ "(external)"
|
|
+#else
|
|
+ "(builtin)"
|
|
+#endif
|
|
+ "\n");
|
|
+}
|
|
+#endif
|
|
+
|
|
static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
.close = pcm_src_close,
|
|
.init = pcm_src_init,
|
|
@@ -125,6 +145,11 @@ static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
.convert_s16 = pcm_src_convert_s16,
|
|
.input_frames = input_frames,
|
|
.output_frames = output_frames,
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+ .version = SND_PCM_RATE_PLUGIN_VERSION,
|
|
+ .get_supported_rates = get_supported_rates,
|
|
+ .dump = dump,
|
|
+#endif
|
|
};
|
|
|
|
static int pcm_src_open(unsigned int version, void **objp,
|
|
@@ -132,18 +157,24 @@ static int pcm_src_open(unsigned int version, void **objp,
|
|
{
|
|
struct rate_src *rate;
|
|
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION < 0x010002
|
|
if (version != SND_PCM_RATE_PLUGIN_VERSION) {
|
|
fprintf(stderr, "Invalid rate plugin version %x\n", version);
|
|
return -EINVAL;
|
|
}
|
|
-
|
|
+#endif
|
|
rate = calloc(1, sizeof(*rate));
|
|
if (! rate)
|
|
return -ENOMEM;
|
|
rate->quality = quality;
|
|
|
|
*objp = rate;
|
|
- *ops = pcm_src_ops;
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+ if (version == 0x010001)
|
|
+ memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t));
|
|
+ else
|
|
+#endif
|
|
+ *ops = pcm_src_ops;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/pulse/pcm_pulse.c b/pulse/pcm_pulse.c
|
|
index db8d1e1..c276839 100644
|
|
--- a/pulse/pcm_pulse.c
|
|
+++ b/pulse/pcm_pulse.c
|
|
@@ -739,6 +739,30 @@ static int pulse_close(snd_pcm_ioplug_t * io)
|
|
return 0;
|
|
}
|
|
|
|
+static int pulse_pause(snd_pcm_ioplug_t * io, int enable)
|
|
+{
|
|
+ snd_pcm_pulse_t *pcm = io->private_data;
|
|
+ int err = 0;
|
|
+
|
|
+ assert (pcm);
|
|
+ assert (pcm->p);
|
|
+
|
|
+ pa_threaded_mainloop_lock(pcm->p->mainloop);
|
|
+
|
|
+ if (pcm->stream) {
|
|
+ pa_operation *o;
|
|
+ o = pa_stream_cork(pcm->stream, enable, NULL, NULL);
|
|
+ if (o)
|
|
+ pa_operation_unref(o);
|
|
+ else
|
|
+ err = -EIO;
|
|
+ }
|
|
+
|
|
+ pa_threaded_mainloop_unlock(pcm->p->mainloop);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
static const snd_pcm_ioplug_callback_t pulse_playback_callback = {
|
|
.start = pulse_start,
|
|
.stop = pulse_stop,
|
|
@@ -750,6 +774,7 @@ static const snd_pcm_ioplug_callback_t pulse_playback_callback = {
|
|
.prepare = pulse_prepare,
|
|
.hw_params = pulse_hw_params,
|
|
.close = pulse_close,
|
|
+ .pause = pulse_pause
|
|
};
|
|
|
|
|
|
diff --git a/rate-lavc/rate_lavcrate.c b/rate-lavc/rate_lavcrate.c
|
|
index ea2e2f5..14a2198 100644
|
|
--- a/rate-lavc/rate_lavcrate.c
|
|
+++ b/rate-lavc/rate_lavcrate.c
|
|
@@ -202,6 +202,20 @@ static void pcm_src_close(void *obj)
|
|
pcm_src_free(obj);
|
|
}
|
|
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+static int get_supported_rates(void *obj, unsigned int *rate_min,
|
|
+ unsigned int *rate_max)
|
|
+{
|
|
+ *rate_min = *rate_max = 0; /* both unlimited */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void dump(void *obj, snd_output_t *out)
|
|
+{
|
|
+ snd_output_printf(out, "Converter: liblavc\n");
|
|
+}
|
|
+#endif
|
|
+
|
|
static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
.close = pcm_src_close,
|
|
.init = pcm_src_init,
|
|
@@ -211,6 +225,11 @@ static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
.convert_s16 = pcm_src_convert_s16,
|
|
.input_frames = input_frames,
|
|
.output_frames = output_frames,
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+ .version = SND_PCM_RATE_PLUGIN_VERSION,
|
|
+ .get_supported_rates = get_supported_rates,
|
|
+ .dump = dump,
|
|
+#endif
|
|
};
|
|
|
|
int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops)
|
|
@@ -218,18 +237,24 @@ int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops)
|
|
{
|
|
struct rate_src *rate;
|
|
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION < 0x010002
|
|
if (version != SND_PCM_RATE_PLUGIN_VERSION) {
|
|
fprintf(stderr, "Invalid rate plugin version %x\n", version);
|
|
return -EINVAL;
|
|
}
|
|
-
|
|
+#endif
|
|
rate = calloc(1, sizeof(*rate));
|
|
if (!rate)
|
|
return -ENOMEM;
|
|
|
|
*objp = rate;
|
|
rate->context = NULL;
|
|
- *ops = pcm_src_ops;
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+ if (version == 0x010001)
|
|
+ memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t));
|
|
+ else
|
|
+#endif
|
|
+ *ops = pcm_src_ops;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/rate/rate_samplerate.c b/rate/rate_samplerate.c
|
|
index e366db0..53a0627 100644
|
|
--- a/rate/rate_samplerate.c
|
|
+++ b/rate/rate_samplerate.c
|
|
@@ -137,6 +137,20 @@ static void pcm_src_close(void *obj)
|
|
free(obj);
|
|
}
|
|
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+static int get_supported_rates(void *obj, unsigned int *rate_min,
|
|
+ unsigned int *rate_max)
|
|
+{
|
|
+ *rate_min = *rate_max = 0; /* both unlimited */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void dump(void *obj, snd_output_t *out)
|
|
+{
|
|
+ snd_output_printf(out, "Converter: libsamplerate\n");
|
|
+}
|
|
+#endif
|
|
+
|
|
static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
.close = pcm_src_close,
|
|
.init = pcm_src_init,
|
|
@@ -146,6 +160,11 @@ static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
.convert_s16 = pcm_src_convert_s16,
|
|
.input_frames = input_frames,
|
|
.output_frames = output_frames,
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+ .version = SND_PCM_RATE_PLUGIN_VERSION,
|
|
+ .get_supported_rates = get_supported_rates,
|
|
+ .dump = dump,
|
|
+#endif
|
|
};
|
|
|
|
static int pcm_src_open(unsigned int version, void **objp,
|
|
@@ -153,18 +172,24 @@ static int pcm_src_open(unsigned int version, void **objp,
|
|
{
|
|
struct rate_src *rate;
|
|
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION < 0x010002
|
|
if (version != SND_PCM_RATE_PLUGIN_VERSION) {
|
|
fprintf(stderr, "Invalid rate plugin version %x\n", version);
|
|
return -EINVAL;
|
|
}
|
|
-
|
|
+#endif
|
|
rate = calloc(1, sizeof(*rate));
|
|
if (! rate)
|
|
return -ENOMEM;
|
|
rate->converter = type;
|
|
|
|
*objp = rate;
|
|
- *ops = pcm_src_ops;
|
|
+#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
+ if (version == 0x010001)
|
|
+ memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t));
|
|
+ else
|
|
+#endif
|
|
+ *ops = pcm_src_ops;
|
|
return 0;
|
|
}
|
|
|
|
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;
|