mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-10 13:30:01 -05:00
Merged pcm2 branch.
This commit is contained in:
parent
986c1500d2
commit
1cd6778173
40 changed files with 5053 additions and 3045 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
156
src/pcm/plugin/copy.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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] = {
|
||||
&©_xxx1_xxx1, /* 8h -> 8h */
|
||||
&©_xxx1_xxx1, /* 8h -> 8s */
|
||||
&©_xxx1_xx10, /* 8h -> 16h */
|
||||
&©_xxx1_xx01, /* 8h -> 16s */
|
||||
&©_xxx1_x100, /* 8h -> 24h */
|
||||
&©_xxx1_001x, /* 8h -> 24s */
|
||||
&©_xxx1_1000, /* 8h -> 32h */
|
||||
&©_xxx1_0001, /* 8h -> 32s */
|
||||
&©_xxx1_xxx9, /* 8h ^> 8h */
|
||||
&©_xxx1_xxx9, /* 8h ^> 8s */
|
||||
&©_xxx1_xx90, /* 8h ^> 16h */
|
||||
&©_xxx1_xx09, /* 8h ^> 16s */
|
||||
&©_xxx1_x900, /* 8h ^> 24h */
|
||||
&©_xxx1_009x, /* 8h ^> 24s */
|
||||
&©_xxx1_9000, /* 8h ^> 32h */
|
||||
&©_xxx1_0009, /* 8h ^> 32s */
|
||||
&©_xxx1_xxx1, /* 8s -> 8h */
|
||||
&©_xxx1_xxx1, /* 8s -> 8s */
|
||||
&©_xxx1_xx10, /* 8s -> 16h */
|
||||
&©_xxx1_xx01, /* 8s -> 16s */
|
||||
&©_xxx1_x100, /* 8s -> 24h */
|
||||
&©_xxx1_001x, /* 8s -> 24s */
|
||||
&©_xxx1_1000, /* 8s -> 32h */
|
||||
&©_xxx1_0001, /* 8s -> 32s */
|
||||
&©_xxx1_xxx9, /* 8s ^> 8h */
|
||||
&©_xxx1_xxx9, /* 8s ^> 8s */
|
||||
&©_xxx1_xx90, /* 8s ^> 16h */
|
||||
&©_xxx1_xx09, /* 8s ^> 16s */
|
||||
&©_xxx1_x900, /* 8s ^> 24h */
|
||||
&©_xxx1_009x, /* 8s ^> 24s */
|
||||
&©_xxx1_9000, /* 8s ^> 32h */
|
||||
&©_xxx1_0009, /* 8s ^> 32s */
|
||||
&©_xx12_xxx1, /* 16h -> 8h */
|
||||
&©_xx12_xxx1, /* 16h -> 8s */
|
||||
&©_xx12_xx12, /* 16h -> 16h */
|
||||
&©_xx12_xx21, /* 16h -> 16s */
|
||||
&©_xx12_x120, /* 16h -> 24h */
|
||||
&©_xx12_021x, /* 16h -> 24s */
|
||||
&©_xx12_1200, /* 16h -> 32h */
|
||||
&©_xx12_0021, /* 16h -> 32s */
|
||||
&©_xx12_xxx9, /* 16h ^> 8h */
|
||||
&©_xx12_xxx9, /* 16h ^> 8s */
|
||||
&©_xx12_xx92, /* 16h ^> 16h */
|
||||
&©_xx12_xx29, /* 16h ^> 16s */
|
||||
&©_xx12_x920, /* 16h ^> 24h */
|
||||
&©_xx12_029x, /* 16h ^> 24s */
|
||||
&©_xx12_9200, /* 16h ^> 32h */
|
||||
&©_xx12_0029, /* 16h ^> 32s */
|
||||
&©_xx12_xxx2, /* 16s -> 8h */
|
||||
&©_xx12_xxx2, /* 16s -> 8s */
|
||||
&©_xx12_xx21, /* 16s -> 16h */
|
||||
&©_xx12_xx12, /* 16s -> 16s */
|
||||
&©_xx12_x210, /* 16s -> 24h */
|
||||
&©_xx12_012x, /* 16s -> 24s */
|
||||
&©_xx12_2100, /* 16s -> 32h */
|
||||
&©_xx12_0012, /* 16s -> 32s */
|
||||
&©_xx12_xxxA, /* 16s ^> 8h */
|
||||
&©_xx12_xxxA, /* 16s ^> 8s */
|
||||
&©_xx12_xxA1, /* 16s ^> 16h */
|
||||
&©_xx12_xx1A, /* 16s ^> 16s */
|
||||
&©_xx12_xA10, /* 16s ^> 24h */
|
||||
&©_xx12_01Ax, /* 16s ^> 24s */
|
||||
&©_xx12_A100, /* 16s ^> 32h */
|
||||
&©_xx12_001A, /* 16s ^> 32s */
|
||||
&©_x123_xxx1, /* 24h -> 8h */
|
||||
&©_x123_xxx1, /* 24h -> 8s */
|
||||
&©_x123_xx12, /* 24h -> 16h */
|
||||
&©_x123_xx21, /* 24h -> 16s */
|
||||
&©_x123_x123, /* 24h -> 24h */
|
||||
&©_x123_321x, /* 24h -> 24s */
|
||||
&©_x123_1230, /* 24h -> 32h */
|
||||
&©_x123_0321, /* 24h -> 32s */
|
||||
&©_x123_xxx9, /* 24h ^> 8h */
|
||||
&©_x123_xxx9, /* 24h ^> 8s */
|
||||
&©_x123_xx92, /* 24h ^> 16h */
|
||||
&©_x123_xx29, /* 24h ^> 16s */
|
||||
&©_x123_x923, /* 24h ^> 24h */
|
||||
&©_x123_329x, /* 24h ^> 24s */
|
||||
&©_x123_9230, /* 24h ^> 32h */
|
||||
&©_x123_0329, /* 24h ^> 32s */
|
||||
&©_123x_xxx3, /* 24s -> 8h */
|
||||
&©_123x_xxx3, /* 24s -> 8s */
|
||||
&©_123x_xx32, /* 24s -> 16h */
|
||||
&©_123x_xx23, /* 24s -> 16s */
|
||||
&©_123x_x321, /* 24s -> 24h */
|
||||
&©_123x_123x, /* 24s -> 24s */
|
||||
&©_123x_3210, /* 24s -> 32h */
|
||||
&©_123x_0123, /* 24s -> 32s */
|
||||
&©_123x_xxxB, /* 24s ^> 8h */
|
||||
&©_123x_xxxB, /* 24s ^> 8s */
|
||||
&©_123x_xxB2, /* 24s ^> 16h */
|
||||
&©_123x_xx2B, /* 24s ^> 16s */
|
||||
&©_123x_xB21, /* 24s ^> 24h */
|
||||
&©_123x_12Bx, /* 24s ^> 24s */
|
||||
&©_123x_B210, /* 24s ^> 32h */
|
||||
&©_123x_012B, /* 24s ^> 32s */
|
||||
&©_1234_xxx1, /* 32h -> 8h */
|
||||
&©_1234_xxx1, /* 32h -> 8s */
|
||||
&©_1234_xx12, /* 32h -> 16h */
|
||||
&©_1234_xx21, /* 32h -> 16s */
|
||||
&©_1234_x123, /* 32h -> 24h */
|
||||
&©_1234_321x, /* 32h -> 24s */
|
||||
&©_1234_1234, /* 32h -> 32h */
|
||||
&©_1234_4321, /* 32h -> 32s */
|
||||
&©_1234_xxx9, /* 32h ^> 8h */
|
||||
&©_1234_xxx9, /* 32h ^> 8s */
|
||||
&©_1234_xx92, /* 32h ^> 16h */
|
||||
&©_1234_xx29, /* 32h ^> 16s */
|
||||
&©_1234_x923, /* 32h ^> 24h */
|
||||
&©_1234_329x, /* 32h ^> 24s */
|
||||
&©_1234_9234, /* 32h ^> 32h */
|
||||
&©_1234_4329, /* 32h ^> 32s */
|
||||
&©_1234_xxx4, /* 32s -> 8h */
|
||||
&©_1234_xxx4, /* 32s -> 8s */
|
||||
&©_1234_xx43, /* 32s -> 16h */
|
||||
&©_1234_xx34, /* 32s -> 16s */
|
||||
&©_1234_x432, /* 32s -> 24h */
|
||||
&©_1234_234x, /* 32s -> 24s */
|
||||
&©_1234_4321, /* 32s -> 32h */
|
||||
&©_1234_1234, /* 32s -> 32s */
|
||||
&©_1234_xxxC, /* 32s ^> 8h */
|
||||
&©_1234_xxxC, /* 32s ^> 8s */
|
||||
&©_1234_xxC3, /* 32s ^> 16h */
|
||||
&©_1234_xx3C, /* 32s ^> 16s */
|
||||
&©_1234_xC32, /* 32s ^> 24h */
|
||||
&©_1234_23Cx, /* 32s ^> 24s */
|
||||
&©_1234_C321, /* 32s ^> 32h */
|
||||
&©_1234_123C, /* 32s ^> 32s */
|
||||
static void *copy_labels[4] = {
|
||||
&©_8,
|
||||
&©_16,
|
||||
&©_32,
|
||||
&©_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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue