fd1475d34d
channel.c/channel_if.m: - Macros cleanups, prefer inlined min() over MIN(). - Rework chn_read()/chn_write() for better dead interrupt detection policy. Reduce scheduling overhead by doing pure 5 seconds sleep before giving up, instead of several cycle of brute micro sleeping. - Avoid calling wakeup_one() for non-sleeping channel (for example, vchan parent channel). - EWOULDBLOCK -> EAGAIN. - Fix possible divide-by-zero panic on chn_sync(). - Re-enforce ^2 blocksize policy, since there are too many broken userland apps that blindly assume it without even trying to do serious calculations. - New channel method - CHANNEL_SETFRAGMENTS(), a refined version of CHANNEL_SETBLOCKSIZE(). It accept _both_ blocksize and blockcount arguments, so the driver internals will have better hints for buffering and timing calculations. - Hook FEEDER_SWAPLR into feederchain building process. feeder_fmt.c: - Unified version of various filters, avoiding duplications. - malloc()less feeder_fmt. Informations can be retrieved dynamically by doing table lookup on static data. For cases such as converting from stereo to mono or reducing bit depth where input data is larger than output, cycle remaining available free space until it has been exhausted and start kicking 8 bytes reservoir space from there to complete the remaining requested count. - Introduce FEEDER_SWAPLR. Few super broken hardwares (found on several extremely cheap uaudio stick, possibly others) mistakenly wired left and right channels wrongly, screwing output or input.
1434 lines
47 KiB
C
1434 lines
47 KiB
C
/*-
|
|
* Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
|
|
* Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* *New* and rewritten soft format converter, supporting 24/32bit pcm data,
|
|
* simplified and optimized.
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* *
|
|
* This new implementation is fully dedicated in memory of Cameron Grant, *
|
|
* the creator of the magnificent, highly addictive feeder infrastructure. *
|
|
* *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
*/
|
|
|
|
#include <dev/sound/pcm/sound.h>
|
|
#include "feeder_if.h"
|
|
|
|
SND_DECLARE_FILE("$FreeBSD$");
|
|
|
|
static int feeder_fmt_stereodownmix = 0;
|
|
TUNABLE_INT("hw.snd.feeder_fmt_stereodownmix", &feeder_fmt_stereodownmix);
|
|
#ifdef SND_DEBUG
|
|
SYSCTL_INT(_hw_snd, OID_AUTO, feeder_fmt_stereodownmix, CTLFLAG_RW,
|
|
&feeder_fmt_stereodownmix, 1, "averaging stereo downmix");
|
|
#endif
|
|
|
|
#define FEEDFMT_RESERVOIR 8 /* 32bit stereo */
|
|
|
|
static uint8_t ulaw_to_u8_tbl[] = {
|
|
3, 7, 11, 15, 19, 23, 27, 31,
|
|
35, 39, 43, 47, 51, 55, 59, 63,
|
|
66, 68, 70, 72, 74, 76, 78, 80,
|
|
82, 84, 86, 88, 90, 92, 94, 96,
|
|
98, 99, 100, 101, 102, 103, 104, 105,
|
|
106, 107, 108, 109, 110, 111, 112, 113,
|
|
113, 114, 114, 115, 115, 116, 116, 117,
|
|
117, 118, 118, 119, 119, 120, 120, 121,
|
|
121, 121, 122, 122, 122, 122, 123, 123,
|
|
123, 123, 124, 124, 124, 124, 125, 125,
|
|
125, 125, 125, 125, 126, 126, 126, 126,
|
|
126, 126, 126, 126, 127, 127, 127, 127,
|
|
127, 127, 127, 127, 127, 127, 127, 127,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
253, 249, 245, 241, 237, 233, 229, 225,
|
|
221, 217, 213, 209, 205, 201, 197, 193,
|
|
190, 188, 186, 184, 182, 180, 178, 176,
|
|
174, 172, 170, 168, 166, 164, 162, 160,
|
|
158, 157, 156, 155, 154, 153, 152, 151,
|
|
150, 149, 148, 147, 146, 145, 144, 143,
|
|
143, 142, 142, 141, 141, 140, 140, 139,
|
|
139, 138, 138, 137, 137, 136, 136, 135,
|
|
135, 135, 134, 134, 134, 134, 133, 133,
|
|
133, 133, 132, 132, 132, 132, 131, 131,
|
|
131, 131, 131, 131, 130, 130, 130, 130,
|
|
130, 130, 130, 130, 129, 129, 129, 129,
|
|
129, 129, 129, 129, 129, 129, 129, 129,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
};
|
|
|
|
static uint8_t alaw_to_u8_tbl[] = {
|
|
108, 109, 106, 107, 112, 113, 110, 111,
|
|
100, 101, 98, 99, 104, 105, 102, 103,
|
|
118, 118, 117, 117, 120, 120, 119, 119,
|
|
114, 114, 113, 113, 116, 116, 115, 115,
|
|
43, 47, 35, 39, 59, 63, 51, 55,
|
|
11, 15, 3, 7, 27, 31, 19, 23,
|
|
86, 88, 82, 84, 94, 96, 90, 92,
|
|
70, 72, 66, 68, 78, 80, 74, 76,
|
|
127, 127, 127, 127, 127, 127, 127, 127,
|
|
127, 127, 127, 127, 127, 127, 127, 127,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
123, 123, 123, 123, 124, 124, 124, 124,
|
|
121, 121, 121, 121, 122, 122, 122, 122,
|
|
126, 126, 126, 126, 126, 126, 126, 126,
|
|
125, 125, 125, 125, 125, 125, 125, 125,
|
|
148, 147, 150, 149, 144, 143, 146, 145,
|
|
156, 155, 158, 157, 152, 151, 154, 153,
|
|
138, 138, 139, 139, 136, 136, 137, 137,
|
|
142, 142, 143, 143, 140, 140, 141, 141,
|
|
213, 209, 221, 217, 197, 193, 205, 201,
|
|
245, 241, 253, 249, 229, 225, 237, 233,
|
|
170, 168, 174, 172, 162, 160, 166, 164,
|
|
186, 184, 190, 188, 178, 176, 182, 180,
|
|
129, 129, 129, 129, 129, 129, 129, 129,
|
|
129, 129, 129, 129, 129, 129, 129, 129,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
128, 128, 128, 128, 128, 128, 128, 128,
|
|
133, 133, 133, 133, 132, 132, 132, 132,
|
|
135, 135, 135, 135, 134, 134, 134, 134,
|
|
130, 130, 130, 130, 130, 130, 130, 130,
|
|
131, 131, 131, 131, 131, 131, 131, 131,
|
|
};
|
|
|
|
static uint8_t u8_to_ulaw_tbl[] = {
|
|
0, 0, 0, 0, 0, 1, 1, 1,
|
|
1, 2, 2, 2, 2, 3, 3, 3,
|
|
3, 4, 4, 4, 4, 5, 5, 5,
|
|
5, 6, 6, 6, 6, 7, 7, 7,
|
|
7, 8, 8, 8, 8, 9, 9, 9,
|
|
9, 10, 10, 10, 10, 11, 11, 11,
|
|
11, 12, 12, 12, 12, 13, 13, 13,
|
|
13, 14, 14, 14, 14, 15, 15, 15,
|
|
15, 16, 16, 17, 17, 18, 18, 19,
|
|
19, 20, 20, 21, 21, 22, 22, 23,
|
|
23, 24, 24, 25, 25, 26, 26, 27,
|
|
27, 28, 28, 29, 29, 30, 30, 31,
|
|
31, 32, 33, 34, 35, 36, 37, 38,
|
|
39, 40, 41, 42, 43, 44, 45, 46,
|
|
47, 49, 51, 53, 55, 57, 59, 61,
|
|
63, 66, 70, 74, 78, 84, 92, 104,
|
|
254, 231, 219, 211, 205, 201, 197, 193,
|
|
190, 188, 186, 184, 182, 180, 178, 176,
|
|
175, 174, 173, 172, 171, 170, 169, 168,
|
|
167, 166, 165, 164, 163, 162, 161, 160,
|
|
159, 159, 158, 158, 157, 157, 156, 156,
|
|
155, 155, 154, 154, 153, 153, 152, 152,
|
|
151, 151, 150, 150, 149, 149, 148, 148,
|
|
147, 147, 146, 146, 145, 145, 144, 144,
|
|
143, 143, 143, 143, 142, 142, 142, 142,
|
|
141, 141, 141, 141, 140, 140, 140, 140,
|
|
139, 139, 139, 139, 138, 138, 138, 138,
|
|
137, 137, 137, 137, 136, 136, 136, 136,
|
|
135, 135, 135, 135, 134, 134, 134, 134,
|
|
133, 133, 133, 133, 132, 132, 132, 132,
|
|
131, 131, 131, 131, 130, 130, 130, 130,
|
|
129, 129, 129, 129, 128, 128, 128, 128,
|
|
};
|
|
|
|
static uint8_t u8_to_alaw_tbl[] = {
|
|
42, 42, 42, 42, 42, 43, 43, 43,
|
|
43, 40, 40, 40, 40, 41, 41, 41,
|
|
41, 46, 46, 46, 46, 47, 47, 47,
|
|
47, 44, 44, 44, 44, 45, 45, 45,
|
|
45, 34, 34, 34, 34, 35, 35, 35,
|
|
35, 32, 32, 32, 32, 33, 33, 33,
|
|
33, 38, 38, 38, 38, 39, 39, 39,
|
|
39, 36, 36, 36, 36, 37, 37, 37,
|
|
37, 58, 58, 59, 59, 56, 56, 57,
|
|
57, 62, 62, 63, 63, 60, 60, 61,
|
|
61, 50, 50, 51, 51, 48, 48, 49,
|
|
49, 54, 54, 55, 55, 52, 52, 53,
|
|
53, 10, 11, 8, 9, 14, 15, 12,
|
|
13, 2, 3, 0, 1, 6, 7, 4,
|
|
5, 24, 30, 28, 18, 16, 22, 20,
|
|
106, 110, 98, 102, 122, 114, 75, 90,
|
|
213, 197, 245, 253, 229, 225, 237, 233,
|
|
149, 151, 145, 147, 157, 159, 153, 155,
|
|
133, 132, 135, 134, 129, 128, 131, 130,
|
|
141, 140, 143, 142, 137, 136, 139, 138,
|
|
181, 181, 180, 180, 183, 183, 182, 182,
|
|
177, 177, 176, 176, 179, 179, 178, 178,
|
|
189, 189, 188, 188, 191, 191, 190, 190,
|
|
185, 185, 184, 184, 187, 187, 186, 186,
|
|
165, 165, 165, 165, 164, 164, 164, 164,
|
|
167, 167, 167, 167, 166, 166, 166, 166,
|
|
161, 161, 161, 161, 160, 160, 160, 160,
|
|
163, 163, 163, 163, 162, 162, 162, 162,
|
|
173, 173, 173, 173, 172, 172, 172, 172,
|
|
175, 175, 175, 175, 174, 174, 174, 174,
|
|
169, 169, 169, 169, 168, 168, 168, 168,
|
|
171, 171, 171, 171, 170, 170, 170, 170,
|
|
};
|
|
|
|
static int
|
|
feed_table_8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int j, sign, k;
|
|
uint8_t *tbl = (uint8_t *)f->data;
|
|
|
|
if (count < PCM_8_BPS)
|
|
return (0);
|
|
|
|
k = FEEDER_FEED(f->source, c, b, count, source);
|
|
if (k < PCM_8_BPS)
|
|
return (0);
|
|
|
|
j = k;
|
|
sign = (f->desc->out & AFMT_SIGNED) ? 0x80 : 0x00;
|
|
|
|
do {
|
|
j--;
|
|
b[j] = tbl[b[j]] ^ sign;
|
|
} while (j != 0);
|
|
|
|
return (k);
|
|
}
|
|
|
|
static int
|
|
feed_table_16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, sign, k;
|
|
uint8_t *tbl = (uint8_t *)f->data;
|
|
|
|
if (count < PCM_16_BPS)
|
|
return (0);
|
|
|
|
k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
if (k < PCM_8_BPS)
|
|
return (0);
|
|
|
|
i = k;
|
|
k <<= 1;
|
|
j = k;
|
|
sign = (f->desc->out & AFMT_SIGNED) ? 0x80 : 0x00;
|
|
|
|
if (f->desc->out & AFMT_BIGENDIAN) {
|
|
do {
|
|
b[--j] = 0;
|
|
b[--j] = tbl[b[--i]] ^ sign;
|
|
} while (i != 0);
|
|
} else {
|
|
do {
|
|
b[--j] = tbl[b[--i]] ^ sign;
|
|
b[--j] = 0;
|
|
} while (i != 0);
|
|
}
|
|
|
|
return (k);
|
|
}
|
|
|
|
static int
|
|
feed_table_xlaw(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int j, sign, k;
|
|
uint8_t *tbl = (uint8_t *)f->data;
|
|
|
|
if (count < PCM_8_BPS)
|
|
return (0);
|
|
|
|
k = FEEDER_FEED(f->source, c, b, count, source);
|
|
if (k < PCM_8_BPS)
|
|
return (0);
|
|
|
|
j = k ;
|
|
sign = (f->desc->in & AFMT_SIGNED) ? 0x80 : 0x00;
|
|
|
|
do {
|
|
j--;
|
|
b[j] = tbl[b[j] ^ sign];
|
|
} while (j != 0);
|
|
|
|
return (k);
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_ulawto8_desc[] = {
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_ulawto8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_ulawto8, 0, ulaw_to_u8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_alawto8_desc[] = {
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_alawto8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_alawto8, 0, alaw_to_u8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_ulawto16_desc[] = {
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_ulawto16_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_16),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_ulawto16, 0, ulaw_to_u8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_alawto16_desc[] = {
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_alawto16_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_16),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_alawto16, 0, alaw_to_u8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_8toulaw_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_MU_LAW, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_8toulaw_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_xlaw),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_8toulaw, 0, u8_to_ulaw_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_8toalaw_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_A_LAW, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_A_LAW, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_8toalaw_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_xlaw),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_8toalaw, 0, u8_to_alaw_tbl);
|
|
|
|
/*
|
|
* All conversion done in byte level to preserve endianess.
|
|
*/
|
|
|
|
#define FEEDFMT_SWAP_SIGN(f) (((((f)->desc->in & AFMT_SIGNED) == 0) != \
|
|
(((f)->desc->out & AFMT_SIGNED) == 0)) \
|
|
? 0x80 : 0x00)
|
|
|
|
/*
|
|
* Bit conversion
|
|
*/
|
|
|
|
#define FBIT_DATA(i, o, c) ((intptr_t)((((c) & 0xf) << 6) | \
|
|
(((i) & 0x7) << 3) | ((o) & 0x7)))
|
|
#define FBIT_OUTBPS(m) ((m) & 0x7)
|
|
#define FBIT_INBPS(m) FBIT_OUTBPS((m) >> 3)
|
|
#define FBIT_CHANNELS(m) (((m) >> 6) & 0xf)
|
|
|
|
static int
|
|
feed_updownbit_init(struct pcm_feeder *f)
|
|
{
|
|
int ibps, obps, channels;
|
|
|
|
if (f->desc->in == f->desc->out || (f->desc->in & AFMT_STEREO) !=
|
|
(f->desc->out & AFMT_STEREO))
|
|
return (-1);
|
|
|
|
channels = (f->desc->in & AFMT_STEREO) ? 2 : 1;
|
|
|
|
if (f->desc->in & AFMT_32BIT)
|
|
ibps = PCM_32_BPS;
|
|
else if (f->desc->in & AFMT_24BIT)
|
|
ibps = PCM_24_BPS;
|
|
else if (f->desc->in & AFMT_16BIT)
|
|
ibps = PCM_16_BPS;
|
|
else
|
|
ibps = PCM_8_BPS;
|
|
|
|
if (f->desc->out & AFMT_32BIT)
|
|
obps = PCM_32_BPS;
|
|
else if (f->desc->out & AFMT_24BIT)
|
|
obps = PCM_24_BPS;
|
|
else if (f->desc->out & AFMT_16BIT)
|
|
obps = PCM_16_BPS;
|
|
else
|
|
obps = PCM_8_BPS;
|
|
|
|
f->data = (void *)FBIT_DATA(ibps, obps, channels);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
feed_upbit(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k, sign, ibps, ialign, obps, oalign, pad;
|
|
uint8_t *src, *dst;
|
|
|
|
ibps = FBIT_INBPS((intptr_t)f->data);
|
|
obps = FBIT_OUTBPS((intptr_t)f->data);
|
|
|
|
ialign = ibps * FBIT_CHANNELS((intptr_t)f->data);
|
|
oalign = obps * FBIT_CHANNELS((intptr_t)f->data);
|
|
|
|
if (count < oalign)
|
|
return (0);
|
|
|
|
k = FEEDER_FEED(f->source, c, b, (count / oalign) * ialign, source);
|
|
if (k < ialign)
|
|
return (0);
|
|
|
|
k -= k % ialign;
|
|
j = (k / ibps) * obps;
|
|
pad = obps - ibps;
|
|
src = b + k;
|
|
dst = b + j;
|
|
sign = FEEDFMT_SWAP_SIGN(f);
|
|
|
|
if (f->desc->out & AFMT_BIGENDIAN) {
|
|
do {
|
|
i = pad;
|
|
do {
|
|
*--dst = 0;
|
|
} while (--i != 0);
|
|
i = ibps;
|
|
while (--i != 0)
|
|
*--dst = *--src;
|
|
*--dst = *--src ^ sign;
|
|
} while (dst != b);
|
|
} else {
|
|
do {
|
|
*--dst = *--src ^ sign;
|
|
i = ibps;
|
|
while (--i != 0)
|
|
*--dst = *--src;
|
|
i = pad;
|
|
do {
|
|
*--dst = 0;
|
|
} while (--i != 0);
|
|
} while (dst != b);
|
|
}
|
|
|
|
return (j);
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_8to16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_8to16_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_upbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_8to16, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_8to24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_8to24_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_upbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_8to24, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_8to32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_8to32_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_upbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_8to32, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_16to24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_16to24_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_upbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_16to24, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_16to32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_16to32_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_upbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_16to32, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_24to32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_24to32_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_upbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_24to32, 0, NULL);
|
|
|
|
static int
|
|
feed_downbit(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k, sign, be, ibps, ialign, obps, oalign,dump;
|
|
uint8_t *src, *dst, *end;
|
|
uint8_t reservoir[FEEDFMT_RESERVOIR];
|
|
|
|
ibps = FBIT_INBPS((intptr_t)f->data);
|
|
obps = FBIT_OUTBPS((intptr_t)f->data);
|
|
|
|
ialign = ibps * FBIT_CHANNELS((intptr_t)f->data);
|
|
oalign = obps * FBIT_CHANNELS((intptr_t)f->data);
|
|
|
|
if (count < oalign)
|
|
return (0);
|
|
|
|
dst = b;
|
|
dump = ibps - obps;
|
|
sign = FEEDFMT_SWAP_SIGN(f);
|
|
be = (f->desc->in & AFMT_BIGENDIAN) ? 1 : 0;
|
|
k = count - (count % oalign);
|
|
|
|
do {
|
|
if (k < oalign)
|
|
break;
|
|
|
|
if (k < ialign) {
|
|
src = reservoir;
|
|
j = ialign;
|
|
} else {
|
|
src = dst;
|
|
j = k;
|
|
}
|
|
|
|
j = FEEDER_FEED(f->source, c, src, j - (j % ialign), source);
|
|
if (j < ialign)
|
|
break;
|
|
|
|
j -= j % ialign;
|
|
j *= obps;
|
|
j /= ibps;
|
|
end = dst + j;
|
|
|
|
if (be != 0) {
|
|
do {
|
|
*dst++ = *src++ ^ sign;
|
|
i = obps;
|
|
while (--i != 0)
|
|
*dst++ = *src++;
|
|
src += dump;
|
|
} while (dst != end);
|
|
} else {
|
|
do {
|
|
src += dump;
|
|
i = obps;
|
|
while (--i != 0)
|
|
*dst++ = *src++;
|
|
*dst++ = *src++ ^ sign;
|
|
} while (dst != end);
|
|
}
|
|
|
|
k -= j;
|
|
} while (k != 0);
|
|
|
|
return (dst - b);
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_16to8_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_16to8_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_downbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_16to8, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_24to8_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_24to8_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_downbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_24to8, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_24to16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_24to16_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_downbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_24to16, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_32to8_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_32to8_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_downbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_32to8, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_32to16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_32to16_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_downbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_32to16, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_32to24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_32to24_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_updownbit_init),
|
|
KOBJMETHOD(feeder_feed, feed_downbit),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_32to24, 0, NULL);
|
|
/*
|
|
* Bit conversion end
|
|
*/
|
|
|
|
/*
|
|
* Channel conversion (mono -> stereo)
|
|
*/
|
|
static int
|
|
feed_monotostereo(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int bps, i, j, k, l;
|
|
uint8_t v;
|
|
|
|
bps = (int)((intptr_t)f->data);
|
|
if (count < (bps << 1))
|
|
return (0);
|
|
|
|
j = FEEDER_FEED(f->source, c, b, (count - (count % bps)) >> 1, source);
|
|
if (j < bps)
|
|
return (0);
|
|
|
|
j -= j % bps;
|
|
i = j << 1;
|
|
l = i;
|
|
|
|
do {
|
|
k = bps;
|
|
do {
|
|
v = b[--j];
|
|
b[--i] = v;
|
|
b[i - bps] = v;
|
|
} while (--k != 0);
|
|
i -= bps;
|
|
} while (i != 0);
|
|
|
|
return (l);
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_monotostereo8_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_MU_LAW | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_A_LAW | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_monotostereo8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_monotostereo),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo8, 0, (void *)PCM_8_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_monotostereo16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_monotostereo16_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_monotostereo),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo16, 0, (void *)PCM_16_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_monotostereo24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_monotostereo24_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_monotostereo),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo24, 0, (void *)PCM_24_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_monotostereo32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_monotostereo32_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_monotostereo),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo32, 0, (void *)PCM_32_BPS);
|
|
/*
|
|
* Channel conversion (mono -> stereo) end
|
|
*/
|
|
|
|
/*
|
|
* Channel conversion (stereo -> mono)
|
|
*/
|
|
#define FEEDER_FMT_STEREODOWNMIX(FMTBIT, FMT_INTCAST, SIGN, \
|
|
SIGNS, ENDIAN, ENDIANS) \
|
|
static void \
|
|
SIGNS##FMTBIT##ENDIANS##_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy) \
|
|
{ \
|
|
int32_t v; \
|
|
\
|
|
v = ((FMT_INTCAST)PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sx) + \
|
|
PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sy)) >> 1; \
|
|
PCM_WRITE_##SIGN##FMTBIT##_##ENDIAN(dst, v); \
|
|
}
|
|
|
|
FEEDER_FMT_STEREODOWNMIX(8, int32_t, S, s, NE, ne);
|
|
FEEDER_FMT_STEREODOWNMIX(16, int32_t, S, s, LE, le);
|
|
FEEDER_FMT_STEREODOWNMIX(24, int32_t, S, s, LE, le);
|
|
FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, S, s, LE, le);
|
|
FEEDER_FMT_STEREODOWNMIX(16, int32_t, S, s, BE, be);
|
|
FEEDER_FMT_STEREODOWNMIX(24, int32_t, S, s, BE, be);
|
|
FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, S, s, BE, be);
|
|
FEEDER_FMT_STEREODOWNMIX(8, int32_t, U, u, NE, ne);
|
|
FEEDER_FMT_STEREODOWNMIX(16, int32_t, U, u, LE, le);
|
|
FEEDER_FMT_STEREODOWNMIX(24, int32_t, U, u, LE, le);
|
|
FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, U, u, LE, le);
|
|
FEEDER_FMT_STEREODOWNMIX(16, int32_t, U, u, BE, be);
|
|
FEEDER_FMT_STEREODOWNMIX(24, int32_t, U, u, BE, be);
|
|
FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, U, u, BE, be);
|
|
|
|
static void
|
|
ulaw_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy)
|
|
{
|
|
uint8_t v;
|
|
|
|
v = ((uint32_t)ulaw_to_u8_tbl[*sx] + ulaw_to_u8_tbl[*sy]) >> 1;
|
|
*dst = u8_to_ulaw_tbl[v];
|
|
}
|
|
|
|
static void
|
|
alaw_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy)
|
|
{
|
|
uint8_t v;
|
|
|
|
v = ((uint32_t)alaw_to_u8_tbl[*sx] + alaw_to_u8_tbl[*sy]) >> 1;
|
|
*dst = u8_to_alaw_tbl[v];
|
|
}
|
|
|
|
typedef void (*feed_fmt_stereodownmix_filter)(uint8_t *,
|
|
uint8_t *, uint8_t *);
|
|
|
|
struct feed_fmt_stereodownmix_info {
|
|
uint32_t format;
|
|
int bps;
|
|
feed_fmt_stereodownmix_filter func[2];
|
|
};
|
|
|
|
static struct feed_fmt_stereodownmix_info feed_fmt_stereodownmix_tbl[] = {
|
|
{ AFMT_S8, PCM_8_BPS, { NULL, s8ne_stereodownmix }},
|
|
{ AFMT_S16_LE, PCM_16_BPS, { NULL, s16le_stereodownmix }},
|
|
{ AFMT_S16_BE, PCM_16_BPS, { NULL, s16be_stereodownmix }},
|
|
{ AFMT_S24_LE, PCM_24_BPS, { NULL, s24le_stereodownmix }},
|
|
{ AFMT_S24_BE, PCM_24_BPS, { NULL, s24be_stereodownmix }},
|
|
{ AFMT_S32_LE, PCM_32_BPS, { NULL, s32le_stereodownmix }},
|
|
{ AFMT_S32_BE, PCM_32_BPS, { NULL, s32be_stereodownmix }},
|
|
{ AFMT_U8, PCM_8_BPS, { NULL, u8ne_stereodownmix }},
|
|
{ AFMT_A_LAW, PCM_8_BPS, { NULL, alaw_stereodownmix }},
|
|
{ AFMT_MU_LAW, PCM_8_BPS, { NULL, ulaw_stereodownmix }},
|
|
{ AFMT_U16_LE, PCM_16_BPS, { NULL, u16le_stereodownmix }},
|
|
{ AFMT_U16_BE, PCM_16_BPS, { NULL, u16be_stereodownmix }},
|
|
{ AFMT_U24_LE, PCM_24_BPS, { NULL, u24le_stereodownmix }},
|
|
{ AFMT_U24_BE, PCM_24_BPS, { NULL, u24be_stereodownmix }},
|
|
{ AFMT_U32_LE, PCM_32_BPS, { NULL, u32le_stereodownmix }},
|
|
{ AFMT_U32_BE, PCM_32_BPS, { NULL, u32be_stereodownmix }},
|
|
};
|
|
|
|
#define FSM_DATA(i, j) ((intptr_t)((((i) & 0x1f) << 1) | ((j) & 0x1)))
|
|
#define FSM_INFOIDX(m) (((m) >> 1) & 0x1f)
|
|
#define FSM_FUNCIDX(m) ((m) & 0x1)
|
|
|
|
static int
|
|
feed_stereotomono_init(struct pcm_feeder *f)
|
|
{
|
|
int i, funcidx;
|
|
|
|
if (!(f->desc->in & AFMT_STEREO) || (f->desc->out & AFMT_STEREO))
|
|
return (-1);
|
|
|
|
funcidx = (feeder_fmt_stereodownmix != 0) ? 1 : 0;
|
|
|
|
for (i = 0; i < sizeof(feed_fmt_stereodownmix_tbl) /
|
|
sizeof(feed_fmt_stereodownmix_tbl[0]); i++) {
|
|
if (f->desc->out == feed_fmt_stereodownmix_tbl[i].format) {
|
|
f->data = (void *)FSM_DATA(i, funcidx);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
static int
|
|
feed_stereotomono(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
struct feed_fmt_stereodownmix_info *info;
|
|
feed_fmt_stereodownmix_filter stereodownmix;
|
|
int i, j, k, ibps, obps;
|
|
uint8_t *src, *dst, *end;
|
|
uint8_t reservoir[FEEDFMT_RESERVOIR];
|
|
|
|
info = &feed_fmt_stereodownmix_tbl[FSM_INFOIDX((intptr_t)f->data)];
|
|
obps = info->bps;
|
|
|
|
if (count < obps)
|
|
return (0);
|
|
|
|
stereodownmix = info->func[FSM_FUNCIDX((intptr_t)f->data)];
|
|
ibps = obps << 1;
|
|
dst = b;
|
|
k = count - (count % obps);
|
|
|
|
do {
|
|
if (k < obps)
|
|
break;
|
|
|
|
if (k < ibps) {
|
|
src = reservoir;
|
|
j = ibps;
|
|
} else {
|
|
src = dst;
|
|
j = k;
|
|
}
|
|
|
|
j = FEEDER_FEED(f->source, c, src, j - (j % ibps), source);
|
|
if (j < ibps)
|
|
break;
|
|
|
|
j -= j % ibps;
|
|
j >>= 1;
|
|
end = dst + j;
|
|
|
|
if (stereodownmix != NULL) {
|
|
do {
|
|
stereodownmix(dst, src, src + obps);
|
|
dst += obps;
|
|
src += ibps;
|
|
} while (dst != end);
|
|
} else {
|
|
do {
|
|
i = obps;
|
|
do {
|
|
*dst++ = *src++;
|
|
} while (--i != 0);
|
|
src += obps;
|
|
} while (dst != end);
|
|
}
|
|
|
|
k -= j;
|
|
} while (k != 0);
|
|
|
|
return (dst - b);
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_stereotomono8_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_MU_LAW, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_A_LAW, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_stereotomono8_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_stereotomono_init),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono8, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_stereotomono16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_stereotomono16_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_stereotomono_init),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono16, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_stereotomono24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_stereotomono24_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_stereotomono_init),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono24, 0, NULL);
|
|
|
|
static struct pcm_feederdesc feeder_stereotomono32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_stereotomono32_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_stereotomono_init),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono32, 0, NULL);
|
|
/*
|
|
* Channel conversion (stereo -> mono) end
|
|
*/
|
|
|
|
/*
|
|
* Sign conversion
|
|
*/
|
|
static int
|
|
feed_sign(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, bps, ofs;
|
|
|
|
bps = (int)((intptr_t)f->data);
|
|
if (count < bps)
|
|
return (0);
|
|
|
|
i = FEEDER_FEED(f->source, c, b, count - (count % bps), source);
|
|
if (i < bps)
|
|
return (0);
|
|
|
|
i -= i % bps;
|
|
j = i;
|
|
ofs = (f->desc->in & AFMT_BIGENDIAN) ? bps : 1;
|
|
|
|
do {
|
|
b[i - ofs] ^= 0x80;
|
|
i -= bps;
|
|
} while (i != 0);
|
|
|
|
return (j);
|
|
}
|
|
static struct pcm_feederdesc feeder_sign8_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_S8, 0},
|
|
{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S8, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign8, 0, (void *)PCM_8_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_sign16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign16_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign16, 0, (void *)PCM_16_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_sign24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign24_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign24, 0, (void *)PCM_24_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_sign32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign32_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign32, 0, (void *)PCM_32_BPS);
|
|
|
|
/*
|
|
* Endian conversion
|
|
*/
|
|
static int
|
|
feed_endian(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k, bps;
|
|
uint8_t *buf, v;
|
|
|
|
bps = (int)((intptr_t)f->data);
|
|
if (count < bps)
|
|
return (0);
|
|
|
|
k = FEEDER_FEED(f->source, c, b, count - (count % bps), source);
|
|
if (k < bps)
|
|
return (0);
|
|
|
|
k -= k % bps;
|
|
j = bps >> 1;
|
|
buf = b + k;
|
|
|
|
do {
|
|
buf -= bps;
|
|
i = j;
|
|
do {
|
|
v = buf[--i];
|
|
buf[i] = buf[bps - i - 1];
|
|
buf[bps - i - 1] = v;
|
|
} while (i != 0);
|
|
} while (buf != b);
|
|
|
|
return (k);
|
|
}
|
|
static struct pcm_feederdesc feeder_endian16_desc[] = {
|
|
{FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0},
|
|
{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0},
|
|
{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0},
|
|
{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_endian16_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_endian),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_endian16, 0, (void *)PCM_16_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_endian24_desc[] = {
|
|
{FEEDER_FMT, AFMT_U24_LE, AFMT_U24_BE, 0},
|
|
{FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE, AFMT_S24_BE, 0},
|
|
{FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE, AFMT_U24_LE, 0},
|
|
{FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE, AFMT_S24_LE, 0},
|
|
{FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_endian24_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_endian),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_endian24, 0, (void *)PCM_24_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_endian32_desc[] = {
|
|
{FEEDER_FMT, AFMT_U32_LE, AFMT_U32_BE, 0},
|
|
{FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE, AFMT_S32_BE, 0},
|
|
{FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE, AFMT_U32_LE, 0},
|
|
{FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE, AFMT_S32_LE, 0},
|
|
{FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_endian32_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_endian),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_endian32, 0, (void *)PCM_32_BPS);
|
|
/*
|
|
* Endian conversion end
|
|
*/
|
|
|
|
/*
|
|
* L/R swap conversion
|
|
*/
|
|
static int
|
|
feed_swaplr(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, bps, smpsz;
|
|
uint8_t *buf, v;
|
|
|
|
bps = (int)((intptr_t)f->data);
|
|
smpsz = bps << 1;
|
|
if (count < smpsz)
|
|
return (0);
|
|
|
|
j = FEEDER_FEED(f->source, c, b, count - (count % smpsz), source);
|
|
if (j < smpsz)
|
|
return (0);
|
|
|
|
j -= j % smpsz;
|
|
buf = b + j;
|
|
|
|
do {
|
|
buf -= smpsz;
|
|
i = bps;
|
|
do {
|
|
v = buf[--i];
|
|
buf[i] = buf[bps + i];
|
|
buf[bps + i] = v;
|
|
} while (i != 0);
|
|
} while (buf != b);
|
|
|
|
return (j);
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_swaplr8_desc[] = {
|
|
{FEEDER_SWAPLR, AFMT_S8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_A_LAW | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_MU_LAW | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_swaplr8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_swaplr),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_swaplr8, -1, (void *)PCM_8_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_swaplr16_desc[] = {
|
|
{FEEDER_SWAPLR, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_swaplr16_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_swaplr),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_swaplr16, -1, (void *)PCM_16_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_swaplr24_desc[] = {
|
|
{FEEDER_SWAPLR, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_swaplr24_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_swaplr),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_swaplr24, -1, (void *)PCM_24_BPS);
|
|
|
|
static struct pcm_feederdesc feeder_swaplr32_desc[] = {
|
|
{FEEDER_SWAPLR, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
|
|
{FEEDER_SWAPLR, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_swaplr32_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_swaplr),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_swaplr32, -1, (void *)PCM_32_BPS);
|
|
/*
|
|
* L/R swap conversion end
|
|
*/
|