Merged pcm2 branch.

This commit is contained in:
Jaroslav Kysela 2000-05-08 18:53:38 +00:00
parent 986c1500d2
commit 1cd6778173
40 changed files with 5053 additions and 3045 deletions

View file

@ -1,6 +1,6 @@
EXTRA_LTLIBRARIES = libpcmplugin.la
libpcmplugin_la_SOURCES = block.c mmap.c stream.c linear.c \
libpcmplugin_la_SOURCES = block.c mmap.c stream.c copy.c linear.c \
mulaw.c alaw.c adpcm.c rate.c route.c
all: libpcmplugin.la

View file

@ -78,7 +78,7 @@ typedef struct {
typedef void (*adpcm_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
typedef struct adpcm_private_data {
@ -90,7 +90,7 @@ typedef struct adpcm_private_data {
static void adpcm_init(snd_pcm_plugin_t *plugin)
{
int voice;
unsigned int voice;
adpcm_t *data = (adpcm_t *)plugin->extra_data;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
adpcm_voice_t *v = &data->voices[voice];
@ -212,7 +212,7 @@ static int adpcm_decoder(unsigned char code, adpcm_voice_t * state)
static void adpcm_decode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define PUT16_LABELS
@ -229,13 +229,13 @@ static void adpcm_decode(snd_pcm_plugin_t *plugin,
int src_step, srcbit_step, dst_step;
size_t samples1;
adpcm_voice_t *state;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
srcbit = src_voices[voice].first % 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
@ -270,7 +270,7 @@ static void adpcm_decode(snd_pcm_plugin_t *plugin,
static void adpcm_encode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define GET16_LABELS
@ -288,13 +288,13 @@ static void adpcm_encode(snd_pcm_plugin_t *plugin,
int src_step, dst_step, dstbit_step;
size_t samples1;
adpcm_voice_t *state;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
dstbit = dst_voices[voice].first % 8;
@ -328,22 +328,17 @@ static void adpcm_encode(snd_pcm_plugin_t *plugin,
static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
adpcm_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (plugin->src_format.format == SND_PCM_SFMT_IMA_ADPCM) {
if (src_voices[voice].first % 4 != 0 ||
src_voices[voice].step % 4 != 0 ||
@ -365,7 +360,7 @@ static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
static int adpcm_action(snd_pcm_plugin_t * plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
unsigned long udata UNUSED)
{
if (plugin == NULL)
return -EINVAL;
@ -376,15 +371,19 @@ static int adpcm_action(snd_pcm_plugin_t * plugin,
case FLUSH:
adpcm_init(plugin);
break;
default:
break;
}
return 0; /* silenty ignore other actions */
}
int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct adpcm_private_data *data;
snd_pcm_plugin_t *plugin;
snd_pcm_format_t *format;
@ -412,13 +411,14 @@ int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
if (!snd_pcm_format_linear(format->format))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"Ima-ADPCM<->linear conversion",
src_format,
dst_format,
sizeof(adpcm_t) + src_format->voices * sizeof(adpcm_voice_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"Ima-ADPCM<->linear conversion",
src_format,
dst_format,
sizeof(adpcm_t) + src_format->voices * sizeof(adpcm_voice_t),
&plugin);
if (err < 0)
return err;
data = (adpcm_t *)plugin->extra_data;
data->func = func;
data->conv = getput_index(format->format);

View file

@ -134,7 +134,7 @@ static int alaw2linear(unsigned char a_val)
typedef void (*alaw_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
typedef struct alaw_private_data {
@ -144,7 +144,7 @@ typedef struct alaw_private_data {
static void alaw_decode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define PUT16_LABELS
@ -159,13 +159,13 @@ static void alaw_decode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -186,7 +186,7 @@ static void alaw_decode(snd_pcm_plugin_t *plugin,
static void alaw_encode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define GET16_LABELS
@ -202,13 +202,13 @@ static void alaw_encode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -229,22 +229,17 @@ static void alaw_encode(snd_pcm_plugin_t *plugin,
static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
alaw_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -258,10 +253,12 @@ static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
}
int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
alaw_t *data;
snd_pcm_plugin_t *plugin;
snd_pcm_format_t *format;
@ -289,13 +286,14 @@ int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
if (!snd_pcm_format_linear(format->format))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"A-Law<->linear conversion",
src_format,
dst_format,
sizeof(alaw_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"A-Law<->linear conversion",
src_format,
dst_format,
sizeof(alaw_t),
&plugin);
if (err < 0)
return err;
data = (alaw_t*)plugin->extra_data;
data->func = func;
data->conv = getput_index(format->format);

View file

@ -19,6 +19,15 @@
*
*/
#ifdef __KERNEL__
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#define snd_pcm_write(handle,buf,count) snd_pcm_oss_write3(handle,buf,count,1)
#define snd_pcm_writev(handle,vec,count) snd_pcm_oss_writev3(handle,vec,count,1)
#define snd_pcm_read(handle,buf,count) snd_pcm_oss_read3(handle,buf,count,1)
#define snd_pcm_readv(handle,vec,count) snd_pcm_oss_readv3(handle,vec,count,1)
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -26,18 +35,19 @@
#include <errno.h>
#include <sys/uio.h>
#include "../pcm_local.h"
#endif
/*
* Basic block plugin
*/
typedef struct block_private_data {
int channel;
snd_pcm_plugin_handle_t *slave;
} block_t;
static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
block_t *data;
@ -51,40 +61,50 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
if (data == NULL)
return -EINVAL;
vec = (struct iovec *)((char *)data + sizeof(*data));
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (src_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->src_format.voices;
if (plugin->src_format.interleave) {
result = snd_pcm_write(plugin->handle, src_voices->addr, result);
result = snd_pcm_write(data->slave, src_voices->addr, result);
} else {
count = plugin->src_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = src_voices[voice].addr;
if (src_voices[voice].enabled)
vec[voice].iov_base = src_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_writev(plugin->handle, vec, count);
result = snd_pcm_writev(data->slave, vec, count);
}
if (result < 0)
return result;
return snd_pcm_plugin_src_size_to_samples(plugin, result);
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
} else if (plugin->channel == SND_PCM_CHANNEL_CAPTURE) {
if (dst_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->dst_format.voices;
if (plugin->dst_format.interleave) {
result = snd_pcm_read(plugin->handle, dst_voices->addr, result);
result = snd_pcm_read(data->slave, dst_voices->addr, result);
for (voice = 0; voice < count; voice++) {
dst_voices[voice].enabled = src_voices[voice].enabled;
}
} else {
count = plugin->dst_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = dst_voices[voice].addr;
dst_voices[voice].enabled = src_voices[voice].enabled;
if (dst_voices[voice].enabled)
vec[voice].iov_base = dst_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_readv(plugin->handle, vec, count);
result = snd_pcm_readv(data->slave, vec, count);
}
if (result < 0)
return result;
@ -94,29 +114,49 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
}
}
int snd_pcm_plugin_build_block(snd_pcm_t *pcm, int channel,
static int block_src_voices(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
err = snd_pcm_plugin_client_voices(plugin, samples, &v);
if (err < 0)
return err;
*voices = v;
for (voice = 0; voice < plugin->src_format.voices; ++voice, ++v)
v->wanted = 1;
return 0;
}
int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_plugin_handle_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
block_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
return -EINVAL;
*r_plugin = NULL;
if (pcm == NULL || channel < 0 || channel > 1 || format == NULL)
if (pcm == NULL || format == NULL)
return -EINVAL;
plugin = snd_pcm_plugin_build(pcm,
channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O block playback" :
"I/O block capture",
format, format,
sizeof(block_t) + sizeof(struct iovec) * format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(pcm, channel,
"I/O block",
format, format,
sizeof(block_t) + sizeof(struct iovec) * format->voices,
&plugin);
if (err < 0)
return err;
data = (block_t *)plugin->extra_data;
data->channel = channel;
data->slave = slave;
plugin->transfer = block_transfer;
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
plugin->client_voices = block_src_voices;
*r_plugin = plugin;
return 0;
}

156
src/pcm/plugin/copy.c Normal file
View file

@ -0,0 +1,156 @@
/*
* Linear conversion Plug-In
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef __KERNEL__
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
#include <sys/uio.h>
#include "../pcm_local.h"
#endif
typedef struct copy_private_data {
int copy;
} copy_t;
static void copy(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define COPY_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
copy_t *data = (copy_t *)plugin->extra_data;
void *copy = copy_labels[data->copy];
int voice;
int nvoices = plugin->src_format.voices;
for (voice = 0; voice < nvoices; ++voice) {
char *src;
char *dst;
int src_step, dst_step;
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *copy;
#define COPY_END after
#include "plugin_ops.h"
#undef COPY_END
after:
src += src_step;
dst += dst_step;
}
}
}
static ssize_t copy_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
copy_t *data;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
data = (copy_t *)plugin->extra_data;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
return -EINVAL;
}
copy(plugin, src_voices, dst_voices, samples);
return samples;
}
int copy_index(int format)
{
int size = snd_pcm_format_physical_width(format);
switch (size) {
case 8:
return 0;
case 16:
return 1;
case 32:
return 2;
case 64:
return 3;
default:
return -EINVAL;
}
}
int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct copy_private_data *data;
snd_pcm_plugin_t *plugin;
int copy;
if (r_plugin == NULL)
return -EFAULT;
*r_plugin = NULL;
copy = copy_index(format->format);
if (copy < 0)
return -EINVAL;
err = snd_pcm_plugin_build(handle, channel,
"copy",
format,
format,
sizeof(copy_t),
&plugin);
if (err < 0)
return err;
data = (copy_t *)plugin->extra_data;
data->copy = copy;
plugin->transfer = copy_transfer;
*r_plugin = plugin;
return 0;
}

View file

@ -41,19 +41,19 @@
*/
typedef struct linear_private_data {
int copy;
int conv;
} linear_t;
static void convert(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define COPY_LABELS
#define CONV_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
#undef CONV_LABELS
linear_t *data = (linear_t *)plugin->extra_data;
void *copy = copy_labels[data->copy];
void *conv = conv_labels[data->conv];
int voice;
int nvoices = plugin->src_format.voices;
for (voice = 0; voice < nvoices; ++voice) {
@ -61,23 +61,23 @@ static void convert(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *copy;
#define COPY_END after
goto *conv;
#define CONV_END after
#include "plugin_ops.h"
#undef COPY_END
#undef CONV_END
after:
src += src_step;
dst += dst_step;
@ -87,23 +87,18 @@ static void convert(snd_pcm_plugin_t *plugin,
static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
linear_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
data = (linear_t *)plugin->extra_data;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -115,7 +110,7 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
return samples;
}
int copy_index(int src_format, int dst_format)
int conv_index(int src_format, int dst_format)
{
int src_endian, dst_endian, sign, src_width, dst_width;
@ -143,10 +138,12 @@ int copy_index(int src_format, int dst_format)
}
int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct linear_private_data *data;
snd_pcm_plugin_t *plugin;
@ -162,15 +159,16 @@ int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
snd_pcm_format_linear(dst_format->format)))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"linear format conversion",
src_format,
dst_format,
sizeof(linear_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"linear format conversion",
src_format,
dst_format,
sizeof(linear_t),
&plugin);
if (err < 0)
return err;
data = (linear_t *)plugin->extra_data;
data->copy = copy_index(src_format->format, dst_format->format);
data->conv = conv_index(src_format->format, dst_format->format);
plugin->transfer = linear_transfer;
*r_plugin = plugin;
return 0;

View file

@ -24,6 +24,7 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include "../pcm_local.h"
@ -33,310 +34,248 @@
*/
typedef struct mmap_private_data {
int channel;
snd_pcm_t *slave;
snd_pcm_mmap_control_t *control;
char *buffer;
int frag;
int frag_size, samples_frag_size;
int start_mode, stop_mode;
int frags, frags_used;
int frags_min, frags_max;
unsigned int lastblock;
void *buffer;
unsigned int frag;
size_t samples_frag_size;
char *silence;
snd_pcm_plugin_voice_t voices[0];
} mmap_t;
static int playback_ok(snd_pcm_plugin_t *plugin)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
if (delta < data->lastblock) {
delta += (~0 - data->lastblock) + 1;
} else {
delta -= data->lastblock;
}
data->frags_used -= delta;
if (data->frags_used < 0) {
/* correction for rollover */
data->frag += -data->frags_used;
data->frag %= data->frags;
data->frags_used = 0;
}
data->lastblock += delta;
return data->frags_used <= data->frags_max &&
(data->frags - data->frags_used) >= data->frags_min;
}
static int poll_playback(snd_pcm_t *pcm)
{
int err;
struct pollfd pfd;
if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
return -EAGAIN;
pfd.fd = pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd;
pfd.events = POLLOUT;
pfd.revents = 0;
err = poll(&pfd, 1, 1000);
return err < 0 ? err : 0;
}
static int query_playback(snd_pcm_plugin_t *plugin, int not_use_poll)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int err;
switch (control->status.status) {
case SND_PCM_STATUS_PREPARED:
if (data->start_mode == SND_PCM_START_GO)
return -EAGAIN;
if ((data->start_mode == SND_PCM_START_DATA &&
playback_ok(plugin)) ||
(data->start_mode == SND_PCM_START_FULL &&
data->frags_used == data->frags)) {
err = snd_pcm_channel_go(plugin->handle, data->channel);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + 1;
err = poll_playback(plugin->handle);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_UNDERRUN:
return -EPIPE;
default:
return -EIO;
}
return 0;
}
static int capture_ok(snd_pcm_plugin_t *plugin)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
if (delta < data->lastblock) {
delta += (~0 - data->lastblock) + 1;
} else {
delta -= data->lastblock;
}
data->frags_used += delta;
if (data->frags_used > data->frags) {
/* correction for rollover */
data->frag += data->frags_used - data->frags;
data->frag %= data->frags;
data->frags_used = data->frags;
}
data->lastblock += delta;
return data->frags_used >= data->frags_min;
}
static int poll_capture(snd_pcm_t *pcm)
{
int err;
struct pollfd pfd;
if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
return -EAGAIN;
pfd.fd = pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd;
pfd.events = POLLIN;
pfd.revents = 0;
err = poll(&pfd, 1, 1000);
return err < 0 ? err : 0;
}
static int query_capture(snd_pcm_plugin_t *plugin, int not_use_poll)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int err;
switch (control->status.status) {
case SND_PCM_STATUS_PREPARED:
if (data->start_mode != SND_PCM_START_DATA)
return -EAGAIN;
err = snd_pcm_channel_go(plugin->handle, data->channel);
if (err < 0)
return err;
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + data->frags_min;
err = poll_capture(plugin->handle);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_OVERRUN:
return -EPIPE;
default:
return -EIO;
}
return 0;
}
static int mmap_src_voices(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples)
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
mmap_t *data;
int err;
int voice;
unsigned int voice;
snd_pcm_plugin_voice_t *dv, *sv;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
int frag, f;
struct pollfd pfd;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (data->channel != SND_PCM_CHANNEL_PLAYBACK)
if (samples != data->samples_frag_size)
return -EINVAL;
if (snd_pcm_plugin_dst_samples_to_size(plugin, samples) != data->frag_size)
return -EINVAL;
/* wait until the block is not free */
while (!playback_ok(plugin)) {
err = query_playback(plugin, 0);
if (err < 0)
return err;
}
sv = data->voices;
dv = plugin->voices;
ctrl = data->control;
chan = &plugin->handle->chan[plugin->channel];
setup = &chan->setup;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
ready = snd_pcm_mmap_ready(data->slave, plugin->channel);
if (ready < 0)
return ready;
if (!ready) {
if (ctrl->status != SND_PCM_STATUS_RUNNING)
return -EPIPE;
if (chan->mode & SND_PCM_NONBLOCK)
return -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
pfd.events = POLLOUT | POLLERR;
ready = poll(&pfd, 1, 10000);
if (ready < 0)
return ready;
if (ready && pfd.revents & POLLERR)
return -EPIPE;
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
}
frag = ctrl->frag_data;
f = frag % setup->frags;
dv = data->voices;
sv = plugin->src_voices;
*voices = sv;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
dv->addr = sv->addr + (sv->step * data->samples_frag_size * data->frag) / 8;
dv->first = sv->first;
dv->step = sv->step;
sv->enabled = 1;
sv->wanted = !data->silence[voice * setup->frags + f];
sv->aptr = 0;
sv->addr = dv->addr + (dv->step * data->samples_frag_size * f) / 8;
sv->first = dv->first;
sv->step = dv->step;
++sv;
++dv;
}
*voices = plugin->voices;
data->frag = frag;
return 0;
}
static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples)
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
mmap_t *data;
int voice;
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *dv, *sv;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
int frag, f;
struct pollfd pfd;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (data->channel != SND_PCM_CHANNEL_CAPTURE)
return -EINVAL;
if (snd_pcm_plugin_src_samples_to_size(plugin, samples) != data->frag_size)
if (samples != data->samples_frag_size)
return -EINVAL;
chan = &plugin->handle->chan[plugin->channel];
setup = &chan->setup;
ctrl = data->control;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
chan->setup.start_mode == SND_PCM_START_DATA) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
ready = snd_pcm_mmap_ready(data->slave, plugin->channel);
if (ready < 0)
return ready;
if (!ready) {
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
chan->setup.start_mode == SND_PCM_START_FULL) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
if (ctrl->status != SND_PCM_STATUS_RUNNING)
return -EPIPE;
if (chan->mode & SND_PCM_NONBLOCK)
return -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
pfd.events = POLLIN | POLLERR;
ready = poll(&pfd, 1, 10000);
if (ready < 0)
return ready;
if (ready && pfd.revents & POLLERR)
return -EPIPE;
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
}
frag = ctrl->frag_data;
f = frag % setup->frags;
sv = data->voices;
dv = plugin->voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
dv->addr = sv->addr + (sv->step * data->samples_frag_size * data->frag) / 8;
dv = plugin->dst_voices;
*voices = dv;
for (voice = 0; voice < plugin->dst_format.voices; ++voice) {
dv->enabled = 1;
dv->wanted = 0;
dv->aptr = 0;
dv->addr = sv->addr + (sv->step * data->samples_frag_size * f) / 8;
dv->first = sv->first;
dv->step = sv->step;
++sv;
++dv;
}
*voices = plugin->voices;
data->frag = frag;
return 0;
}
static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices UNUSED,
size_t samples)
{
mmap_t *data;
snd_pcm_mmap_control_t *control;
ssize_t size;
unsigned int voice;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
struct snd_pcm_chan *chan;
unsigned int frag, f;
int err;
if (plugin == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
control = data->control;
if (control == NULL)
if (src_voices == NULL)
return -EINVAL;
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (src_voices == NULL)
return -EINVAL;
while (!playback_ok(plugin)) {
err = query_playback(plugin, 0);
if (err < 0)
return err;
}
size = snd_pcm_plugin_src_samples_to_size(plugin, samples);
if (size != data->frag_size)
return -EINVAL;
if (plugin->prev == NULL) {
if (plugin->src_format.interleave) {
void *dst = data->voices[0].addr + data->frag * data->frag_size;
/* Paranoia: add check for src_voices */
memcpy(dst, src_voices[0].addr, size);
} else {
int voice;
size /= plugin->src_format.voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
void *dst = data->voices[voice].addr + (data->voices[voice].step * data->samples_frag_size * data->frag) / 8;
/* Paranoia: add check for src_voices */
memcpy(dst, src_voices[voice].addr, size);
}
}
}
control->fragments[data->frag].data = 1;
data->frag++;
data->frag %= data->frags;
data->frags_used++;
return samples;
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
if (dst_voices == NULL)
return -EINVAL;
while (!capture_ok(plugin)) {
err = query_capture(plugin, 0);
if (err < 0)
return err;
}
size = snd_pcm_plugin_dst_samples_to_size(plugin, samples);
if (size != data->frag_size)
return -EINVAL;
if (plugin->next == NULL) {
if (plugin->dst_format.interleave) {
void *src = data->voices[0].addr + data->frag * data->frag_size;
/* Paranoia: add check for dst_voices */
memcpy(dst_voices[0].addr, src, size);
} else {
int voice;
size /= plugin->src_format.voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
void *src = data->voices[voice].addr + (data->voices[voice].step * data->samples_frag_size * data->frag) / 8;
/* Paranoia: add check for dst_voices */
memcpy(dst_voices[voice].addr, src, size);
}
}
control->fragments[data->frag].data = 0;
} else {
int prev_frag = data->frag - 1;
if (prev_frag < 0)
prev_frag = data->frags - 1;
control->fragments[prev_frag].data = 0;
}
data->frag++;
data->frag %= data->frags;
data->frags_used--;
return samples;
} else {
if (plugin->prev == NULL)
return -EINVAL;
ctrl = data->control;
if (ctrl == NULL)
return -EINVAL;
chan = &data->slave->chan[SND_PCM_CHANNEL_PLAYBACK];
setup = &chan->setup;
frag = ctrl->frag_data;
if (frag != data->frag)
return -EIO;
f = frag % setup->frags;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].enabled)
data->silence[voice * setup->frags + f] = 0;
}
frag++;
if (frag == setup->frag_boundary) {
ctrl->frag_data = 0;
ctrl->pos_data = 0;
} else {
ctrl->frag_data = frag;
ctrl->pos_data += setup->frag_size;
}
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
(chan->setup.start_mode == SND_PCM_START_DATA ||
(chan->setup.start_mode == SND_PCM_START_FULL &&
!snd_pcm_mmap_ready(data->slave, plugin->channel)))) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
return samples;
}
static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices UNUSED,
snd_pcm_plugin_voice_t *dst_voices UNUSED,
size_t samples)
{
mmap_t *data;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
unsigned int frag;
if (plugin == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (plugin->next == NULL)
return -EINVAL;
ctrl = data->control;
if (ctrl == NULL)
return -EINVAL;
frag = ctrl->frag_data;
if (frag != data->frag)
return -EIO;
setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
/* FIXME: not here the increment */
frag++;
if (frag == setup->frag_boundary) {
ctrl->frag_data = 0;
ctrl->pos_data = 0;
} else {
ctrl->frag_data = frag;
ctrl->pos_data += setup->frag_size;
}
return samples;
}
static int mmap_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
unsigned long udata UNUSED)
{
struct mmap_private_data *data;
@ -344,48 +283,25 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (action == INIT) {
snd_pcm_channel_params_t *params;
snd_pcm_channel_setup_t setup;
snd_pcm_channel_setup_t *setup;
int result;
int voice;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
if (data->control)
snd_pcm_munmap(plugin->handle, data->channel);
result = snd_pcm_mmap(plugin->handle, data->channel, &data->control, (void **)&data->buffer);
snd_pcm_munmap(data->slave, plugin->channel);
result = snd_pcm_mmap(data->slave, plugin->channel, &data->control, (void **)&data->buffer);
if (result < 0)
return result;
params = (snd_pcm_channel_params_t *)udata;
data->start_mode = params->start_mode;
data->stop_mode = params->stop_mode;
memset(&setup, 0, sizeof(setup));
setup.channel = data->channel;
if ((result = snd_pcm_channel_setup(plugin->handle, &setup)) < 0)
return result;
data->frags = setup.buf.block.frags;
data->frag_size = setup.buf.block.frag_size;
data->samples_frag_size = data->frag_size / snd_pcm_format_size(plugin->src_format.format, plugin->src_format.voices);
data->frags_min = setup.buf.block.frags_min;
data->frags_max = setup.buf.block.frags_max;
if (data->frags_min < 0)
data->frags_min = 0;
if (data->frags_min >= setup.buf.block.frags)
data->frags_min = setup.buf.block.frags - 1;
if (data->frags_max < 0)
data->frags_max = setup.buf.block.frags + data->frags_max;
if (data->frags_max < data->frags_min)
data->frags_max = data->frags_min;
if (data->frags_max < 1)
data->frags_max = 1;
if (data->frags_max > setup.buf.block.frags)
data->frags_max = setup.buf.block.frags;
setup = &data->slave->chan[plugin->channel].setup;
data->samples_frag_size = setup->frag_size / snd_pcm_format_size(setup->format.format, setup->format.voices);
v = data->voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
for (voice = 0; voice < setup->format.voices; ++voice) {
snd_pcm_voice_setup_t vsetup;
vsetup.voice = voice;
if ((result = snd_pcm_voice_setup(plugin->handle, data->channel, &vsetup)) < 0)
if ((result = snd_pcm_voice_setup(data->slave, plugin->channel, &vsetup)) < 0)
return result;
if (vsetup.addr < 0)
return -EBADFD;
@ -394,56 +310,60 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
v->step = vsetup.step;
v++;
}
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->silence = malloc(setup->frags * setup->format.voices);
memset(data->silence, 0, setup->frags * setup->format.voices);
} else
data->silence = 0;
return 0;
} else if (action == PREPARE) {
data->frag = 0;
data->lastblock = 0;
} else if (action == DRAIN && data->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->frag = 0;
data->lastblock = 0;
} else if (action == FLUSH) {
data->frag = 0;
data->lastblock = 0;
}
return 0; /* silenty ignore other actions */
}
static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data)
static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data UNUSED)
{
struct mmap_private_data *data;
if (plugin == NULL)
return;
data = (mmap_t *)plugin->extra_data;
if (data->silence)
free(data->silence);
if (data->control)
snd_pcm_munmap(plugin->handle, data->channel);
snd_pcm_munmap(data->slave, plugin->channel);
}
int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel,
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
mmap_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
return -EINVAL;
*r_plugin = NULL;
if (!pcm || channel < 0 || channel > 1)
if (!pcm)
return -EINVAL;
plugin = snd_pcm_plugin_build(pcm,
channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O mmap playback" :
"I/O mmap capture",
format, format,
sizeof(mmap_t) + sizeof(snd_pcm_plugin_voice_t) * format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(pcm, channel,
"I/O mmap",
format, format,
sizeof(mmap_t) + sizeof(snd_pcm_plugin_voice_t) * format->voices,
&plugin);
if (err < 0)
return err;
data = (mmap_t *)plugin->extra_data;
data->channel = channel;
plugin->src_voices = mmap_src_voices;
plugin->dst_voices = mmap_dst_voices;
plugin->transfer = mmap_transfer;
data->slave = slave;
if (channel == SND_PCM_CHANNEL_PLAYBACK) {
plugin->client_voices = mmap_src_voices;
plugin->transfer = mmap_playback_transfer;
} else {
plugin->client_voices = mmap_dst_voices;
plugin->transfer = mmap_capture_transfer;
}
plugin->action = mmap_action;
plugin->private_free = mmap_free;
*r_plugin = plugin;

View file

@ -150,7 +150,7 @@ static int ulaw2linear(unsigned char u_val)
typedef void (*mulaw_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
typedef struct mulaw_private_data {
@ -160,7 +160,7 @@ typedef struct mulaw_private_data {
static void mulaw_decode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define PUT16_LABELS
@ -175,13 +175,13 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -202,7 +202,7 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
static void mulaw_encode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define GET16_LABELS
@ -218,13 +218,13 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -245,22 +245,17 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
mulaw_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -274,10 +269,12 @@ static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
}
int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
mulaw_t *data;
snd_pcm_plugin_t *plugin;
snd_pcm_format_t *format;
@ -305,13 +302,14 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
if (!snd_pcm_format_linear(format->format))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"Mu-Law<->linear conversion",
src_format,
dst_format,
sizeof(mulaw_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"Mu-Law<->linear conversion",
src_format,
dst_format,
sizeof(mulaw_t),
&plugin);
if (err < 0)
return err;
data = (mulaw_t*)plugin->extra_data;
data->func = func;
data->conv = getput_index(format->format);

View file

@ -23,241 +23,260 @@
#define as_u8(ptr) (*(u_int8_t*)(ptr))
#define as_u16(ptr) (*(u_int16_t*)(ptr))
#define as_u32(ptr) (*(u_int32_t*)(ptr))
#define as_u64(ptr) (*(u_int64_t*)(ptr))
#define as_s8(ptr) (*(int8_t*)(ptr))
#define as_s16(ptr) (*(int16_t*)(ptr))
#define as_s32(ptr) (*(int32_t*)(ptr))
#define as_s64(ptr) (*(int64_t*)(ptr))
#ifdef COPY_LABELS
/* src_wid src_endswap sign_toggle dst_wid dst_endswap */
static void *copy_labels[4 * 2 * 2 * 4 * 2] = {
&&copy_xxx1_xxx1, /* 8h -> 8h */
&&copy_xxx1_xxx1, /* 8h -> 8s */
&&copy_xxx1_xx10, /* 8h -> 16h */
&&copy_xxx1_xx01, /* 8h -> 16s */
&&copy_xxx1_x100, /* 8h -> 24h */
&&copy_xxx1_001x, /* 8h -> 24s */
&&copy_xxx1_1000, /* 8h -> 32h */
&&copy_xxx1_0001, /* 8h -> 32s */
&&copy_xxx1_xxx9, /* 8h ^> 8h */
&&copy_xxx1_xxx9, /* 8h ^> 8s */
&&copy_xxx1_xx90, /* 8h ^> 16h */
&&copy_xxx1_xx09, /* 8h ^> 16s */
&&copy_xxx1_x900, /* 8h ^> 24h */
&&copy_xxx1_009x, /* 8h ^> 24s */
&&copy_xxx1_9000, /* 8h ^> 32h */
&&copy_xxx1_0009, /* 8h ^> 32s */
&&copy_xxx1_xxx1, /* 8s -> 8h */
&&copy_xxx1_xxx1, /* 8s -> 8s */
&&copy_xxx1_xx10, /* 8s -> 16h */
&&copy_xxx1_xx01, /* 8s -> 16s */
&&copy_xxx1_x100, /* 8s -> 24h */
&&copy_xxx1_001x, /* 8s -> 24s */
&&copy_xxx1_1000, /* 8s -> 32h */
&&copy_xxx1_0001, /* 8s -> 32s */
&&copy_xxx1_xxx9, /* 8s ^> 8h */
&&copy_xxx1_xxx9, /* 8s ^> 8s */
&&copy_xxx1_xx90, /* 8s ^> 16h */
&&copy_xxx1_xx09, /* 8s ^> 16s */
&&copy_xxx1_x900, /* 8s ^> 24h */
&&copy_xxx1_009x, /* 8s ^> 24s */
&&copy_xxx1_9000, /* 8s ^> 32h */
&&copy_xxx1_0009, /* 8s ^> 32s */
&&copy_xx12_xxx1, /* 16h -> 8h */
&&copy_xx12_xxx1, /* 16h -> 8s */
&&copy_xx12_xx12, /* 16h -> 16h */
&&copy_xx12_xx21, /* 16h -> 16s */
&&copy_xx12_x120, /* 16h -> 24h */
&&copy_xx12_021x, /* 16h -> 24s */
&&copy_xx12_1200, /* 16h -> 32h */
&&copy_xx12_0021, /* 16h -> 32s */
&&copy_xx12_xxx9, /* 16h ^> 8h */
&&copy_xx12_xxx9, /* 16h ^> 8s */
&&copy_xx12_xx92, /* 16h ^> 16h */
&&copy_xx12_xx29, /* 16h ^> 16s */
&&copy_xx12_x920, /* 16h ^> 24h */
&&copy_xx12_029x, /* 16h ^> 24s */
&&copy_xx12_9200, /* 16h ^> 32h */
&&copy_xx12_0029, /* 16h ^> 32s */
&&copy_xx12_xxx2, /* 16s -> 8h */
&&copy_xx12_xxx2, /* 16s -> 8s */
&&copy_xx12_xx21, /* 16s -> 16h */
&&copy_xx12_xx12, /* 16s -> 16s */
&&copy_xx12_x210, /* 16s -> 24h */
&&copy_xx12_012x, /* 16s -> 24s */
&&copy_xx12_2100, /* 16s -> 32h */
&&copy_xx12_0012, /* 16s -> 32s */
&&copy_xx12_xxxA, /* 16s ^> 8h */
&&copy_xx12_xxxA, /* 16s ^> 8s */
&&copy_xx12_xxA1, /* 16s ^> 16h */
&&copy_xx12_xx1A, /* 16s ^> 16s */
&&copy_xx12_xA10, /* 16s ^> 24h */
&&copy_xx12_01Ax, /* 16s ^> 24s */
&&copy_xx12_A100, /* 16s ^> 32h */
&&copy_xx12_001A, /* 16s ^> 32s */
&&copy_x123_xxx1, /* 24h -> 8h */
&&copy_x123_xxx1, /* 24h -> 8s */
&&copy_x123_xx12, /* 24h -> 16h */
&&copy_x123_xx21, /* 24h -> 16s */
&&copy_x123_x123, /* 24h -> 24h */
&&copy_x123_321x, /* 24h -> 24s */
&&copy_x123_1230, /* 24h -> 32h */
&&copy_x123_0321, /* 24h -> 32s */
&&copy_x123_xxx9, /* 24h ^> 8h */
&&copy_x123_xxx9, /* 24h ^> 8s */
&&copy_x123_xx92, /* 24h ^> 16h */
&&copy_x123_xx29, /* 24h ^> 16s */
&&copy_x123_x923, /* 24h ^> 24h */
&&copy_x123_329x, /* 24h ^> 24s */
&&copy_x123_9230, /* 24h ^> 32h */
&&copy_x123_0329, /* 24h ^> 32s */
&&copy_123x_xxx3, /* 24s -> 8h */
&&copy_123x_xxx3, /* 24s -> 8s */
&&copy_123x_xx32, /* 24s -> 16h */
&&copy_123x_xx23, /* 24s -> 16s */
&&copy_123x_x321, /* 24s -> 24h */
&&copy_123x_123x, /* 24s -> 24s */
&&copy_123x_3210, /* 24s -> 32h */
&&copy_123x_0123, /* 24s -> 32s */
&&copy_123x_xxxB, /* 24s ^> 8h */
&&copy_123x_xxxB, /* 24s ^> 8s */
&&copy_123x_xxB2, /* 24s ^> 16h */
&&copy_123x_xx2B, /* 24s ^> 16s */
&&copy_123x_xB21, /* 24s ^> 24h */
&&copy_123x_12Bx, /* 24s ^> 24s */
&&copy_123x_B210, /* 24s ^> 32h */
&&copy_123x_012B, /* 24s ^> 32s */
&&copy_1234_xxx1, /* 32h -> 8h */
&&copy_1234_xxx1, /* 32h -> 8s */
&&copy_1234_xx12, /* 32h -> 16h */
&&copy_1234_xx21, /* 32h -> 16s */
&&copy_1234_x123, /* 32h -> 24h */
&&copy_1234_321x, /* 32h -> 24s */
&&copy_1234_1234, /* 32h -> 32h */
&&copy_1234_4321, /* 32h -> 32s */
&&copy_1234_xxx9, /* 32h ^> 8h */
&&copy_1234_xxx9, /* 32h ^> 8s */
&&copy_1234_xx92, /* 32h ^> 16h */
&&copy_1234_xx29, /* 32h ^> 16s */
&&copy_1234_x923, /* 32h ^> 24h */
&&copy_1234_329x, /* 32h ^> 24s */
&&copy_1234_9234, /* 32h ^> 32h */
&&copy_1234_4329, /* 32h ^> 32s */
&&copy_1234_xxx4, /* 32s -> 8h */
&&copy_1234_xxx4, /* 32s -> 8s */
&&copy_1234_xx43, /* 32s -> 16h */
&&copy_1234_xx34, /* 32s -> 16s */
&&copy_1234_x432, /* 32s -> 24h */
&&copy_1234_234x, /* 32s -> 24s */
&&copy_1234_4321, /* 32s -> 32h */
&&copy_1234_1234, /* 32s -> 32s */
&&copy_1234_xxxC, /* 32s ^> 8h */
&&copy_1234_xxxC, /* 32s ^> 8s */
&&copy_1234_xxC3, /* 32s ^> 16h */
&&copy_1234_xx3C, /* 32s ^> 16s */
&&copy_1234_xC32, /* 32s ^> 24h */
&&copy_1234_23Cx, /* 32s ^> 24s */
&&copy_1234_C321, /* 32s ^> 32h */
&&copy_1234_123C, /* 32s ^> 32s */
static void *copy_labels[4] = {
&&copy_8,
&&copy_16,
&&copy_32,
&&copy_64
};
#endif
#ifdef COPY_END
while(0) {
copy_xxx1_xxx1: as_u8(dst) = as_u8(src); goto COPY_END;
copy_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto COPY_END;
copy_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto COPY_END;
copy_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto COPY_END;
copy_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto COPY_END;
copy_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto COPY_END;
copy_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto COPY_END;
copy_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto COPY_END;
copy_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto COPY_END;
copy_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto COPY_END;
copy_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto COPY_END;
copy_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto COPY_END;
copy_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto COPY_END;
copy_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto COPY_END;
copy_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto COPY_END;
copy_xx12_xx12: as_u16(dst) = as_u16(src); goto COPY_END;
copy_xx12_xx21: as_u16(dst) = bswap_16(as_u16(src)); goto COPY_END;
copy_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto COPY_END;
copy_xx12_021x: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto COPY_END;
copy_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto COPY_END;
copy_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)); goto COPY_END;
copy_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto COPY_END;
copy_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto COPY_END;
copy_xx12_xx29: as_u16(dst) = bswap_16(as_u16(src)) ^ 0x80; goto COPY_END;
copy_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto COPY_END;
copy_xx12_029x: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80) << 8; goto COPY_END;
copy_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto COPY_END;
copy_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80); goto COPY_END;
copy_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto COPY_END;
copy_xx12_x210: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto COPY_END;
copy_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto COPY_END;
copy_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 16; goto COPY_END;
copy_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto COPY_END;
copy_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto COPY_END;
copy_xx12_xxA1: as_u16(dst) = bswap_16(as_u16(src) ^ 0x80); goto COPY_END;
copy_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto COPY_END;
copy_xx12_xA10: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 8; goto COPY_END;
copy_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto COPY_END;
copy_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 16; goto COPY_END;
copy_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto COPY_END;
copy_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto COPY_END;
copy_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto COPY_END;
copy_x123_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto COPY_END;
copy_x123_x123: as_u32(dst) = as_u32(src); goto COPY_END;
copy_x123_321x: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END;
copy_x123_1230: as_u32(dst) = as_u32(src) << 8; goto COPY_END;
copy_x123_0321: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto COPY_END;
copy_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto COPY_END;
copy_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto COPY_END;
copy_x123_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 8) ^ 0x80; goto COPY_END;
copy_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto COPY_END;
copy_x123_329x: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x8000; goto COPY_END;
copy_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto COPY_END;
copy_x123_0329: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x80; goto COPY_END;
copy_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto COPY_END;
copy_123x_xx32: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto COPY_END;
copy_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto COPY_END;
copy_123x_x321: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END;
copy_123x_123x: as_u32(dst) = as_u32(src); goto COPY_END;
copy_123x_3210: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto COPY_END;
copy_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto COPY_END;
copy_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto COPY_END;
copy_123x_xxB2: as_u16(dst) = bswap_16((as_u32(src) >> 8) ^ 0x80); goto COPY_END;
copy_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto COPY_END;
copy_123x_xB21: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x800000; goto COPY_END;
copy_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto COPY_END;
copy_123x_B210: as_u32(dst) = bswap_32(as_u32(src) ^ 0x8000) << 8; goto COPY_END;
copy_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto COPY_END;
copy_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto COPY_END;
copy_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto COPY_END;
copy_1234_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 16); goto COPY_END;
copy_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto COPY_END;
copy_1234_321x: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto COPY_END;
copy_1234_1234: as_u32(dst) = as_u32(src); goto COPY_END;
copy_1234_4321: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END;
copy_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto COPY_END;
copy_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto COPY_END;
copy_1234_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 16) ^ 0x80; goto COPY_END;
copy_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto COPY_END;
copy_1234_329x: as_u32(dst) = (bswap_32(as_u32(src)) ^ 0x80) << 8; goto COPY_END;
copy_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto COPY_END;
copy_1234_4329: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x80; goto COPY_END;
copy_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto COPY_END;
copy_1234_xx43: as_u16(dst) = bswap_16(as_u32(src)); goto COPY_END;
copy_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto COPY_END;
copy_1234_x432: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto COPY_END;
copy_1234_234x: as_u32(dst) = as_u32(src) << 8; goto COPY_END;
copy_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto COPY_END;
copy_1234_xxC3: as_u16(dst) = bswap_16(as_u32(src) ^ 0x80); goto COPY_END;
copy_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto COPY_END;
copy_1234_xC32: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x800000; goto COPY_END;
copy_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto COPY_END;
copy_1234_C321: as_u32(dst) = bswap_32(as_u32(src) ^ 0x80); goto COPY_END;
copy_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto COPY_END;
copy_8: as_s8(dst) = as_s8(src); goto COPY_END;
copy_16: as_s16(dst) = as_s16(src); goto COPY_END;
copy_32: as_s32(dst) = as_s32(src); goto COPY_END;
copy_64: as_s64(dst) = as_s64(src); goto COPY_END;
}
#endif
#ifdef CONV_LABELS
/* src_wid src_endswap sign_toggle dst_wid dst_endswap */
static void *conv_labels[4 * 2 * 2 * 4 * 2] = {
&&conv_xxx1_xxx1, /* 8h -> 8h */
&&conv_xxx1_xxx1, /* 8h -> 8s */
&&conv_xxx1_xx10, /* 8h -> 16h */
&&conv_xxx1_xx01, /* 8h -> 16s */
&&conv_xxx1_x100, /* 8h -> 24h */
&&conv_xxx1_001x, /* 8h -> 24s */
&&conv_xxx1_1000, /* 8h -> 32h */
&&conv_xxx1_0001, /* 8h -> 32s */
&&conv_xxx1_xxx9, /* 8h ^> 8h */
&&conv_xxx1_xxx9, /* 8h ^> 8s */
&&conv_xxx1_xx90, /* 8h ^> 16h */
&&conv_xxx1_xx09, /* 8h ^> 16s */
&&conv_xxx1_x900, /* 8h ^> 24h */
&&conv_xxx1_009x, /* 8h ^> 24s */
&&conv_xxx1_9000, /* 8h ^> 32h */
&&conv_xxx1_0009, /* 8h ^> 32s */
&&conv_xxx1_xxx1, /* 8s -> 8h */
&&conv_xxx1_xxx1, /* 8s -> 8s */
&&conv_xxx1_xx10, /* 8s -> 16h */
&&conv_xxx1_xx01, /* 8s -> 16s */
&&conv_xxx1_x100, /* 8s -> 24h */
&&conv_xxx1_001x, /* 8s -> 24s */
&&conv_xxx1_1000, /* 8s -> 32h */
&&conv_xxx1_0001, /* 8s -> 32s */
&&conv_xxx1_xxx9, /* 8s ^> 8h */
&&conv_xxx1_xxx9, /* 8s ^> 8s */
&&conv_xxx1_xx90, /* 8s ^> 16h */
&&conv_xxx1_xx09, /* 8s ^> 16s */
&&conv_xxx1_x900, /* 8s ^> 24h */
&&conv_xxx1_009x, /* 8s ^> 24s */
&&conv_xxx1_9000, /* 8s ^> 32h */
&&conv_xxx1_0009, /* 8s ^> 32s */
&&conv_xx12_xxx1, /* 16h -> 8h */
&&conv_xx12_xxx1, /* 16h -> 8s */
&&conv_xx12_xx12, /* 16h -> 16h */
&&conv_xx12_xx21, /* 16h -> 16s */
&&conv_xx12_x120, /* 16h -> 24h */
&&conv_xx12_021x, /* 16h -> 24s */
&&conv_xx12_1200, /* 16h -> 32h */
&&conv_xx12_0021, /* 16h -> 32s */
&&conv_xx12_xxx9, /* 16h ^> 8h */
&&conv_xx12_xxx9, /* 16h ^> 8s */
&&conv_xx12_xx92, /* 16h ^> 16h */
&&conv_xx12_xx29, /* 16h ^> 16s */
&&conv_xx12_x920, /* 16h ^> 24h */
&&conv_xx12_029x, /* 16h ^> 24s */
&&conv_xx12_9200, /* 16h ^> 32h */
&&conv_xx12_0029, /* 16h ^> 32s */
&&conv_xx12_xxx2, /* 16s -> 8h */
&&conv_xx12_xxx2, /* 16s -> 8s */
&&conv_xx12_xx21, /* 16s -> 16h */
&&conv_xx12_xx12, /* 16s -> 16s */
&&conv_xx12_x210, /* 16s -> 24h */
&&conv_xx12_012x, /* 16s -> 24s */
&&conv_xx12_2100, /* 16s -> 32h */
&&conv_xx12_0012, /* 16s -> 32s */
&&conv_xx12_xxxA, /* 16s ^> 8h */
&&conv_xx12_xxxA, /* 16s ^> 8s */
&&conv_xx12_xxA1, /* 16s ^> 16h */
&&conv_xx12_xx1A, /* 16s ^> 16s */
&&conv_xx12_xA10, /* 16s ^> 24h */
&&conv_xx12_01Ax, /* 16s ^> 24s */
&&conv_xx12_A100, /* 16s ^> 32h */
&&conv_xx12_001A, /* 16s ^> 32s */
&&conv_x123_xxx1, /* 24h -> 8h */
&&conv_x123_xxx1, /* 24h -> 8s */
&&conv_x123_xx12, /* 24h -> 16h */
&&conv_x123_xx21, /* 24h -> 16s */
&&conv_x123_x123, /* 24h -> 24h */
&&conv_x123_321x, /* 24h -> 24s */
&&conv_x123_1230, /* 24h -> 32h */
&&conv_x123_0321, /* 24h -> 32s */
&&conv_x123_xxx9, /* 24h ^> 8h */
&&conv_x123_xxx9, /* 24h ^> 8s */
&&conv_x123_xx92, /* 24h ^> 16h */
&&conv_x123_xx29, /* 24h ^> 16s */
&&conv_x123_x923, /* 24h ^> 24h */
&&conv_x123_329x, /* 24h ^> 24s */
&&conv_x123_9230, /* 24h ^> 32h */
&&conv_x123_0329, /* 24h ^> 32s */
&&conv_123x_xxx3, /* 24s -> 8h */
&&conv_123x_xxx3, /* 24s -> 8s */
&&conv_123x_xx32, /* 24s -> 16h */
&&conv_123x_xx23, /* 24s -> 16s */
&&conv_123x_x321, /* 24s -> 24h */
&&conv_123x_123x, /* 24s -> 24s */
&&conv_123x_3210, /* 24s -> 32h */
&&conv_123x_0123, /* 24s -> 32s */
&&conv_123x_xxxB, /* 24s ^> 8h */
&&conv_123x_xxxB, /* 24s ^> 8s */
&&conv_123x_xxB2, /* 24s ^> 16h */
&&conv_123x_xx2B, /* 24s ^> 16s */
&&conv_123x_xB21, /* 24s ^> 24h */
&&conv_123x_12Bx, /* 24s ^> 24s */
&&conv_123x_B210, /* 24s ^> 32h */
&&conv_123x_012B, /* 24s ^> 32s */
&&conv_1234_xxx1, /* 32h -> 8h */
&&conv_1234_xxx1, /* 32h -> 8s */
&&conv_1234_xx12, /* 32h -> 16h */
&&conv_1234_xx21, /* 32h -> 16s */
&&conv_1234_x123, /* 32h -> 24h */
&&conv_1234_321x, /* 32h -> 24s */
&&conv_1234_1234, /* 32h -> 32h */
&&conv_1234_4321, /* 32h -> 32s */
&&conv_1234_xxx9, /* 32h ^> 8h */
&&conv_1234_xxx9, /* 32h ^> 8s */
&&conv_1234_xx92, /* 32h ^> 16h */
&&conv_1234_xx29, /* 32h ^> 16s */
&&conv_1234_x923, /* 32h ^> 24h */
&&conv_1234_329x, /* 32h ^> 24s */
&&conv_1234_9234, /* 32h ^> 32h */
&&conv_1234_4329, /* 32h ^> 32s */
&&conv_1234_xxx4, /* 32s -> 8h */
&&conv_1234_xxx4, /* 32s -> 8s */
&&conv_1234_xx43, /* 32s -> 16h */
&&conv_1234_xx34, /* 32s -> 16s */
&&conv_1234_x432, /* 32s -> 24h */
&&conv_1234_234x, /* 32s -> 24s */
&&conv_1234_4321, /* 32s -> 32h */
&&conv_1234_1234, /* 32s -> 32s */
&&conv_1234_xxxC, /* 32s ^> 8h */
&&conv_1234_xxxC, /* 32s ^> 8s */
&&conv_1234_xxC3, /* 32s ^> 16h */
&&conv_1234_xx3C, /* 32s ^> 16s */
&&conv_1234_xC32, /* 32s ^> 24h */
&&conv_1234_23Cx, /* 32s ^> 24s */
&&conv_1234_C321, /* 32s ^> 32h */
&&conv_1234_123C, /* 32s ^> 32s */
};
#endif
#ifdef CONV_END
while(0) {
conv_xxx1_xxx1: as_u8(dst) = as_u8(src); goto CONV_END;
conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto CONV_END;
conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto CONV_END;
conv_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto CONV_END;
conv_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto CONV_END;
conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto CONV_END;
conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto CONV_END;
conv_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto CONV_END;
conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto CONV_END;
conv_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto CONV_END;
conv_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto CONV_END;
conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto CONV_END;
conv_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto CONV_END;
conv_xx12_xx12: as_u16(dst) = as_u16(src); goto CONV_END;
conv_xx12_xx21: as_u16(dst) = bswap_16(as_u16(src)); goto CONV_END;
conv_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
conv_xx12_021x: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto CONV_END;
conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto CONV_END;
conv_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)); goto CONV_END;
conv_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto CONV_END;
conv_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto CONV_END;
conv_xx12_xx29: as_u16(dst) = bswap_16(as_u16(src)) ^ 0x80; goto CONV_END;
conv_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto CONV_END;
conv_xx12_029x: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80) << 8; goto CONV_END;
conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto CONV_END;
conv_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80); goto CONV_END;
conv_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto CONV_END;
conv_xx12_x210: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto CONV_END;
conv_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
conv_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 16; goto CONV_END;
conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto CONV_END;
conv_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto CONV_END;
conv_xx12_xxA1: as_u16(dst) = bswap_16(as_u16(src) ^ 0x80); goto CONV_END;
conv_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto CONV_END;
conv_xx12_xA10: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 8; goto CONV_END;
conv_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto CONV_END;
conv_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 16; goto CONV_END;
conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto CONV_END;
conv_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto CONV_END;
conv_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto CONV_END;
conv_x123_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto CONV_END;
conv_x123_x123: as_u32(dst) = as_u32(src); goto CONV_END;
conv_x123_321x: as_u32(dst) = bswap_32(as_u32(src)); goto CONV_END;
conv_x123_1230: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
conv_x123_0321: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto CONV_END;
conv_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto CONV_END;
conv_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto CONV_END;
conv_x123_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 8) ^ 0x80; goto CONV_END;
conv_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto CONV_END;
conv_x123_329x: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x8000; goto CONV_END;
conv_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto CONV_END;
conv_x123_0329: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x80; goto CONV_END;
conv_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto CONV_END;
conv_123x_xx32: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto CONV_END;
conv_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto CONV_END;
conv_123x_x321: as_u32(dst) = bswap_32(as_u32(src)); goto CONV_END;
conv_123x_123x: as_u32(dst) = as_u32(src); goto CONV_END;
conv_123x_3210: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto CONV_END;
conv_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
conv_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto CONV_END;
conv_123x_xxB2: as_u16(dst) = bswap_16((as_u32(src) >> 8) ^ 0x80); goto CONV_END;
conv_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END;
conv_123x_xB21: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x800000; goto CONV_END;
conv_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto CONV_END;
conv_123x_B210: as_u32(dst) = bswap_32(as_u32(src) ^ 0x8000) << 8; goto CONV_END;
conv_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto CONV_END;
conv_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto CONV_END;
conv_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto CONV_END;
conv_1234_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 16); goto CONV_END;
conv_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
conv_1234_321x: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto CONV_END;
conv_1234_1234: as_u32(dst) = as_u32(src); goto CONV_END;
conv_1234_4321: as_u32(dst) = bswap_32(as_u32(src)); goto CONV_END;
conv_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto CONV_END;
conv_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto CONV_END;
conv_1234_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 16) ^ 0x80; goto CONV_END;
conv_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto CONV_END;
conv_1234_329x: as_u32(dst) = (bswap_32(as_u32(src)) ^ 0x80) << 8; goto CONV_END;
conv_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto CONV_END;
conv_1234_4329: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x80; goto CONV_END;
conv_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto CONV_END;
conv_1234_xx43: as_u16(dst) = bswap_16(as_u32(src)); goto CONV_END;
conv_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto CONV_END;
conv_1234_x432: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto CONV_END;
conv_1234_234x: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
conv_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto CONV_END;
conv_1234_xxC3: as_u16(dst) = bswap_16(as_u32(src) ^ 0x80); goto CONV_END;
conv_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto CONV_END;
conv_1234_xC32: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x800000; goto CONV_END;
conv_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto CONV_END;
conv_1234_C321: as_u32(dst) = bswap_32(as_u32(src) ^ 0x80); goto CONV_END;
conv_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto CONV_END;
}
#endif

View file

@ -49,7 +49,7 @@ typedef struct {
typedef void (*rate_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
int src_samples, int dst_samples);
typedef struct rate_private_data {
@ -63,7 +63,7 @@ typedef struct rate_private_data {
static void rate_init(snd_pcm_plugin_t *plugin)
{
int voice;
unsigned int voice;
rate_t *data = (rate_t *)plugin->extra_data;
data->pos = 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
@ -74,14 +74,14 @@ static void rate_init(snd_pcm_plugin_t *plugin)
static void resample_expand(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
int src_samples, int dst_samples)
{
unsigned int pos = 0;
signed int val;
signed short S1, S2;
char *src, *dst;
int voice;
unsigned int voice;
int src_step, dst_step;
int src_samples1, dst_samples1;
rate_t *data = (rate_t *)plugin->extra_data;
@ -104,13 +104,13 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
pos = data->pos;
S1 = rvoices->last_S1;
S2 = rvoices->last_S2;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], dst_samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -162,14 +162,14 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
static void resample_shrink(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
int src_samples, int dst_samples)
{
unsigned int pos = 0;
signed int val;
signed short S1, S2;
char *src, *dst;
int voice;
unsigned int voice;
int src_step, dst_step;
int src_samples1, dst_samples1;
rate_t *data = (rate_t *)plugin->extra_data;
@ -188,13 +188,13 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
pos = data->pos;
S1 = rvoices->last_S1;
S2 = rvoices->last_S2;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], dst_samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -301,23 +301,18 @@ static ssize_t rate_dst_samples(snd_pcm_plugin_t *plugin, size_t samples)
static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
size_t dst_samples;
int voice;
unsigned int voice;
rate_t *data;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -334,7 +329,7 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
static int rate_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
unsigned long udata UNUSED)
{
if (plugin == NULL)
return -EINVAL;
@ -345,15 +340,19 @@ static int rate_action(snd_pcm_plugin_t *plugin,
case FLUSH:
rate_init(plugin);
break;
default:
break;
}
return 0; /* silenty ignore other actions */
}
int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
rate_t *data;
snd_pcm_plugin_t *plugin;
@ -372,13 +371,14 @@ int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
if (src_format->rate == dst_format->rate)
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"rate conversion",
src_format,
dst_format,
sizeof(rate_t) + src_format->voices * sizeof(rate_voice_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"rate conversion",
src_format,
dst_format,
sizeof(rate_t) + src_format->voices * sizeof(rate_voice_t),
&plugin);
if (err < 0)
return err;
data = (rate_t *)plugin->extra_data;
data->get = getput_index(src_format->format);
data->put = getput_index(dst_format->format);

View file

@ -1,6 +1,6 @@
/*
* Attenuated route Plug-In
* Copyright (c) 2000 by Abramo Bagnara <abbagnara@racine.ra.it>
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
@ -23,8 +23,6 @@
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#define my_calloc(size) snd_kmalloc(size, GFP_KERNEL)
#define my_free(ptr) snd_kfree(ptr)
#else
#include <stdio.h>
#include <stdlib.h>
@ -35,8 +33,6 @@
#include <byteswap.h>
#include <math.h>
#include "../pcm_local.h"
#define my_calloc(size) calloc(1, size)
#define my_free(ptr) free(ptr)
#endif
typedef struct ttable_dst ttable_dst_t;
@ -44,7 +40,7 @@ typedef struct route_private_data route_t;
typedef void (*route_voice_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples);
typedef struct {
@ -65,7 +61,7 @@ struct ttable_dst {
struct route_private_data {
enum {INT32=0, INT64=1, FLOAT=2} sum_type;
int get, put;
int copy;
int conv;
int src_sample_size;
ttable_dst_t ttable[0];
};
@ -79,77 +75,26 @@ typedef union {
} sum_t;
void zero_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *dst_voice,
size_t samples)
{
char *dst = dst_voice->addr + dst_voice->first / 8;
int dst_step = dst_voice->step / 8;
switch (plugin->dst_width) {
case 4: {
int dstbit = dst_voice->first % 8;
int dstbit_step = dst_voice->step % 8;
while (samples-- > 0) {
if (dstbit)
*dst &= 0x0f;
else
*dst &= 0xf0;
dst += dst_step;
dstbit += dstbit_step;
if (dstbit == 8) {
dst++;
dstbit = 0;
}
}
break;
}
case 8:
while (samples-- > 0) {
*dst = 0;
dst += dst_step;
}
break;
case 16:
while (samples-- > 0) {
*(int16_t*)dst = 0;
dst += dst_step;
}
break;
case 32:
while (samples-- > 0) {
*(int32_t*)dst = 0;
dst += dst_step;
}
break;
case 64:
while (samples-- > 0) {
*(int64_t*)dst = 0;
dst += dst_step;
}
break;
}
}
static void route_to_voice_zero(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples)
const snd_pcm_plugin_voice_t *src_voices UNUSED,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable UNUSED, size_t samples)
{
// null_voice(&dst_voices[voice]);
zero_voice(plugin, dst_voice, samples);
if (dst_voice->wanted)
snd_pcm_plugin_silence_voice(plugin, dst_voice, samples);
dst_voice->enabled = 0;
}
static void route_to_voice_one(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples)
{
#define COPY_LABELS
#define CONV_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
#undef CONV_LABELS
route_t *data = (route_t *)plugin->extra_data;
void *copy;
void *conv;
const snd_pcm_plugin_voice_t *src_voice = 0;
int srcidx;
char *src, *dst;
@ -164,16 +109,17 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
return;
}
copy = copy_labels[data->copy];
dst_voice->enabled = 1;
conv = conv_labels[data->conv];
src = src_voice->addr + src_voice->first / 8;
src_step = src_voice->step / 8;
dst = dst_voice->addr + dst_voice->first / 8;
dst_step = dst_voice->step / 8;
while (samples-- > 0) {
goto *copy;
#define COPY_END after
goto *conv;
#define CONV_END after
#include "plugin_ops.h"
#undef COPY_END
#undef CONV_END
after:
src += src_step;
dst += dst_step;
@ -182,7 +128,7 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
static void route_to_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples)
{
#define GET_LABELS
@ -242,7 +188,7 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
int srcidx, srcidx1 = 0;
for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
const snd_pcm_plugin_voice_t *src_voice = &src_voices[ttable->srcs[srcidx].voice];
if (src_voice->addr == NULL)
if (!src_voice->enabled)
continue;
srcs[srcidx1] = src_voice->addr + src_voices->first / 8;
src_steps[srcidx1] = src_voice->step / 8;
@ -258,6 +204,7 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
return;
}
dst_voice->enabled = 1;
zero = zero_labels[data->sum_type];
get = get_labels[data->get];
add = add_labels[data->sum_type * 2 + ttable->att];
@ -416,6 +363,55 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
}
}
int route_src_voices_mask(snd_pcm_plugin_t *plugin,
bitset_t *dst_vmask,
bitset_t **src_vmask)
{
route_t *data = (route_t *)plugin->extra_data;
int svoices = plugin->src_format.voices;
int dvoices = plugin->dst_format.voices;
bitset_t *vmask = plugin->src_vmask;
int voice;
ttable_dst_t *dp = data->ttable;
bitset_zero(vmask, svoices);
for (voice = 0; voice < dvoices; voice++, dp++) {
int src;
ttable_src_t *sp;
if (!bitset_get(dst_vmask, voice))
continue;
sp = dp->srcs;
for (src = 0; src < dp->nsrcs; src++, sp++)
bitset_set(vmask, sp->voice);
}
*src_vmask = vmask;
return 0;
}
int route_dst_voices_mask(snd_pcm_plugin_t *plugin,
bitset_t *src_vmask,
bitset_t **dst_vmask)
{
route_t *data = (route_t *)plugin->extra_data;
int dvoices = plugin->dst_format.voices;
bitset_t *vmask = plugin->dst_vmask;
int voice;
ttable_dst_t *dp = data->ttable;
bitset_zero(vmask, dvoices);
for (voice = 0; voice < dvoices; voice++, dp++) {
int src;
ttable_src_t *sp;
sp = dp->srcs;
for (src = 0; src < dp->nsrcs; src++, sp++) {
if (bitset_get(src_vmask, sp->voice)) {
bitset_set(vmask, voice);
break;
}
}
}
*dst_vmask = vmask;
return 0;
}
#ifdef __KERNEL__
#define FULL ROUTE_PLUGIN_RESOLUTION
typedef int src_ttable_entry_t;
@ -424,13 +420,13 @@ typedef int src_ttable_entry_t;
typedef float src_ttable_entry_t;
#endif
static void route_free(snd_pcm_plugin_t *plugin, void* private_data)
static void route_free(snd_pcm_plugin_t *plugin, void* private_data UNUSED)
{
route_t *data = (route_t *)plugin->extra_data;
int dst_voice;
unsigned int dst_voice;
for (dst_voice = 0; dst_voice < plugin->dst_format.voices; ++dst_voice) {
if (data->ttable[dst_voice].srcs != NULL)
my_free(data->ttable[dst_voice].srcs);
free(data->ttable[dst_voice].srcs);
}
}
@ -438,7 +434,7 @@ static int route_load_ttable(snd_pcm_plugin_t *plugin,
const src_ttable_entry_t* src_ttable)
{
route_t *data;
int src_voice, dst_voice;
unsigned int src_voice, dst_voice;
const src_ttable_entry_t *sptr;
ttable_dst_t *dptr;
if (src_ttable == NULL)
@ -488,8 +484,11 @@ static int route_load_ttable(snd_pcm_plugin_t *plugin,
dptr->func = route_to_voice;
break;
}
dptr->srcs = my_calloc(sizeof(*srcs) * nsrcs);
memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
if (nsrcs > 0) {
dptr->srcs = calloc(nsrcs, sizeof(*srcs));
memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
} else
dptr->srcs = 0;
dptr++;
}
return 0;
@ -497,19 +496,17 @@ static int route_load_ttable(snd_pcm_plugin_t *plugin,
static ssize_t route_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
route_t *data;
int src_nvoices, dst_nvoices;
int src_voice, dst_voice;
ttable_dst_t *ttp;
const snd_pcm_plugin_voice_t *dvp;
snd_pcm_plugin_voice_t *dvp;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
data = (route_t *)plugin->extra_data;
@ -556,6 +553,7 @@ int getput_index(int format)
}
int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
src_ttable_entry_t *ttable,
@ -574,19 +572,20 @@ int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
snd_pcm_format_linear(dst_format->format)))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"attenuated route conversion",
src_format,
dst_format,
sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"attenuated route conversion",
src_format,
dst_format,
sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->voices,
&plugin);
if (err < 0)
return err;
data = (route_t *) plugin->extra_data;
data->get = getput_index(src_format->format);
data->put = getput_index(dst_format->format);
data->copy = copy_index(src_format->format, dst_format->format);
data->conv = conv_index(src_format->format, dst_format->format);
#ifdef __KERNEL__
if (snd_pcm_format_width(src_format->format) == 32)
@ -603,6 +602,8 @@ int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
return err;
}
plugin->transfer = route_transfer;
plugin->src_voices_mask = route_src_voices_mask;
plugin->dst_voices_mask = route_dst_voices_mask;
*r_plugin = plugin;
return 0;
}

View file

@ -32,12 +32,12 @@
*/
typedef struct stream_private_data {
int channel;
snd_pcm_t *slave;
} stream_t;
static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
stream_t *data;
@ -51,41 +51,49 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
if (data == NULL)
return -EINVAL;
vec = (struct iovec *)((char *)data + sizeof(*data));
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (src_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->src_format.voices;
if (plugin->src_format.interleave) {
result = snd_pcm_write(plugin->handle, src_voices->addr, result);
result = snd_pcm_write(data->slave, src_voices->addr, result);
} else {
count = plugin->src_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = src_voices[voice].addr;
if (src_voices[voice].enabled)
vec[voice].iov_base = src_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_writev(plugin->handle, vec, count);
result = snd_pcm_writev(data->slave, vec, count);
}
if (result < 0)
return result;
return snd_pcm_plugin_src_size_to_samples(plugin, result);
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
} else if (plugin->channel == SND_PCM_CHANNEL_CAPTURE) {
if (dst_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->dst_format.voices;
if (plugin->dst_format.interleave) {
result = snd_pcm_read(plugin->handle, dst_voices->addr, result);
result = snd_pcm_read(data->slave, dst_voices->addr, result);
for (voice = 0; voice < count; voice++)
dst_voices[voice].enabled = src_voices[voice].enabled;
} else {
count = plugin->dst_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = dst_voices[voice].addr;
dst_voices[voice].enabled = src_voices[voice].enabled;
if (dst_voices[voice].enabled)
vec[voice].iov_base = dst_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_readv(plugin->handle, vec, count);
result = snd_pcm_readv(data->slave, vec, count);
}
if (result < 0)
return result;
@ -95,10 +103,29 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
}
}
int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel,
static int stream_src_voices(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
err = snd_pcm_plugin_client_voices(plugin, samples, &v);
if (err < 0)
return err;
*voices = v;
for (voice = 0; voice < plugin->src_format.voices; ++voice, ++v)
v->wanted = 1;
return 0;
}
int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
stream_t *data;
snd_pcm_plugin_t *plugin;
@ -107,17 +134,18 @@ int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel,
*r_plugin = NULL;
if (!pcm || channel < 0 || channel > 1)
return -EINVAL;
plugin = snd_pcm_plugin_build(pcm,
channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O stream playback" :
"I/O stream capture",
format, format,
sizeof(stream_t) + sizeof(struct iovec) * format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(pcm, channel,
"I/O stream",
format, format,
sizeof(stream_t) + sizeof(struct iovec) * format->voices,
&plugin);
if (err < 0)
return err;
data = (stream_t *)plugin->extra_data;
data->channel = channel;
data->slave = slave;
plugin->transfer = stream_transfer;
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
plugin->client_voices = stream_src_voices;
*r_plugin = plugin;
return 0;
}