da8623eca0
Approved by: ariff
1143 lines
33 KiB
C
1143 lines
33 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$");
|
|
|
|
MALLOC_DEFINE(M_FMTFEEDER, "fmtfeed", "pcm format feeder");
|
|
|
|
#define FEEDBUFSZ 8192
|
|
#define FEEDBUF24SZ 8190
|
|
|
|
#define FMT_TRACE(x...) /* printf(x) */
|
|
#define FMT_TEST(x, y...) /* if (x) FMT_TRACE(y) */
|
|
#define FMT_ALIGNBYTE(x) /* x */
|
|
|
|
/*
|
|
* Sign inverted ulaw/alaw -> 8 table
|
|
*/
|
|
static uint8_t ulaw_to_s8_tbl[] = {
|
|
131, 135, 139, 143, 147, 151, 155, 159,
|
|
163, 167, 171, 175, 179, 183, 187, 191,
|
|
194, 196, 198, 200, 202, 204, 206, 208,
|
|
210, 212, 214, 216, 218, 220, 222, 224,
|
|
226, 227, 228, 229, 230, 231, 232, 233,
|
|
234, 235, 236, 237, 238, 239, 240, 241,
|
|
241, 242, 242, 243, 243, 244, 244, 245,
|
|
245, 246, 246, 247, 247, 248, 248, 249,
|
|
249, 249, 250, 250, 250, 250, 251, 251,
|
|
251, 251, 252, 252, 252, 252, 253, 253,
|
|
253, 253, 253, 253, 254, 254, 254, 254,
|
|
254, 254, 254, 254, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
125, 121, 117, 113, 109, 105, 101, 97,
|
|
93, 89, 85, 81, 77, 73, 69, 65,
|
|
62, 60, 58, 56, 54, 52, 50, 48,
|
|
46, 44, 42, 40, 38, 36, 34, 32,
|
|
30, 29, 28, 27, 26, 25, 24, 23,
|
|
22, 21, 20, 19, 18, 17, 16, 15,
|
|
15, 14, 14, 13, 13, 12, 12, 11,
|
|
11, 10, 10, 9, 9, 8, 8, 7,
|
|
7, 7, 6, 6, 6, 6, 5, 5,
|
|
5, 5, 4, 4, 4, 4, 3, 3,
|
|
3, 3, 3, 3, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
};
|
|
|
|
static uint8_t alaw_to_s8_tbl[] = {
|
|
236, 237, 234, 235, 240, 241, 238, 239,
|
|
228, 229, 226, 227, 232, 233, 230, 231,
|
|
246, 246, 245, 245, 248, 248, 247, 247,
|
|
242, 242, 241, 241, 244, 244, 243, 243,
|
|
171, 175, 163, 167, 187, 191, 179, 183,
|
|
139, 143, 131, 135, 155, 159, 147, 151,
|
|
214, 216, 210, 212, 222, 224, 218, 220,
|
|
198, 200, 194, 196, 206, 208, 202, 204,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
251, 251, 251, 251, 252, 252, 252, 252,
|
|
249, 249, 249, 249, 250, 250, 250, 250,
|
|
254, 254, 254, 254, 254, 254, 254, 254,
|
|
253, 253, 253, 253, 253, 253, 253, 253,
|
|
20, 19, 22, 21, 16, 15, 18, 17,
|
|
28, 27, 30, 29, 24, 23, 26, 25,
|
|
10, 10, 11, 11, 8, 8, 9, 9,
|
|
14, 14, 15, 15, 12, 12, 13, 13,
|
|
85, 81, 93, 89, 69, 65, 77, 73,
|
|
117, 113, 125, 121, 101, 97, 109, 105,
|
|
42, 40, 46, 44, 34, 32, 38, 36,
|
|
58, 56, 62, 60, 50, 48, 54, 52,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
5, 5, 5, 5, 4, 4, 4, 4,
|
|
7, 7, 7, 7, 6, 6, 6, 6,
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
};
|
|
|
|
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_u8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int j, k = FEEDER_FEED(f->source, c, b, count, source);
|
|
uint8_t *tbl = (uint8_t *)f->data;
|
|
|
|
j = k;
|
|
while (j > 0) {
|
|
j--;
|
|
b[j] = tbl[b[j]] ^ 0x80;
|
|
}
|
|
return k;
|
|
}
|
|
|
|
static int
|
|
feed_table_s16le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
uint8_t *tbl = (uint8_t *)f->data;
|
|
|
|
i = k;
|
|
k <<= 1;
|
|
j = k;
|
|
while (i > 0) {
|
|
b[--j] = tbl[b[--i]];
|
|
b[--j] = 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, k = FEEDER_FEED(f->source, c, b, count, source);
|
|
uint8_t *tbl = (uint8_t *)f->data;
|
|
|
|
j = k;
|
|
while (j > 0) {
|
|
j--;
|
|
b[j] = tbl[b[j]];
|
|
}
|
|
return k;
|
|
}
|
|
|
|
static struct pcm_feederdesc feeder_ulawtou8_desc[] = {
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_ulawtou8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_u8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_ulawtou8, 0, ulaw_to_s8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_alawtou8_desc[] = {
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_U8, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_alawtou8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_u8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_alawtou8, 0, alaw_to_s8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_ulawtos16le_desc[] = {
|
|
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_ulawtos16le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_s16le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_ulawtos16le, 0, ulaw_to_s8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_alawtos16le_desc[] = {
|
|
{FEEDER_FMT, AFMT_A_LAW, AFMT_S16_LE, 0},
|
|
{FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_alawtos16le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_s16le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_alawtos16le, 0, alaw_to_s8_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_u8toulaw_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0},
|
|
{FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_MU_LAW|AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_u8toulaw_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_xlaw),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_u8toulaw, 0, u8_to_ulaw_tbl);
|
|
|
|
static struct pcm_feederdesc feeder_u8toalaw_desc[] = {
|
|
{FEEDER_FMT, AFMT_U8, AFMT_A_LAW, 0},
|
|
{FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_A_LAW|AFMT_STEREO, 0},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_u8toalaw_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_table_xlaw),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_u8toalaw, 0, u8_to_alaw_tbl);
|
|
|
|
/*
|
|
* Conversion rules:-
|
|
* 1. BE -> LE
|
|
* 2. if fmt == u8 , u8 -> s8 (economical)
|
|
* 3. Xle -> 16le
|
|
* 4. if fmt != u8 && fmt == u16le , u16le -> s16le
|
|
* 4. s16le mono -> s16le stereo
|
|
*
|
|
* All conversion done in byte level to preserve endianess.
|
|
*/
|
|
|
|
static int
|
|
feed_common_init(struct pcm_feeder *f)
|
|
{
|
|
f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_NOWAIT|M_ZERO);
|
|
if (f->data == NULL)
|
|
return ENOMEM;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
feed_common_free(struct pcm_feeder *f)
|
|
{
|
|
if (f->data)
|
|
free(f->data, M_FMTFEEDER);
|
|
f->data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Bit conversion
|
|
*/
|
|
static int
|
|
feed_8to16le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
|
|
i = k;
|
|
k <<= 1;
|
|
j = k;
|
|
while (i > 0) {
|
|
b[--j] = b[--i];
|
|
b[--j] = 0;
|
|
}
|
|
return k;
|
|
}
|
|
static struct pcm_feederdesc feeder_8to16le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_8to16le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_8to16le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_8to16le, 0, NULL);
|
|
|
|
static int
|
|
feed_16leto8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = count << 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUFSZ), source);
|
|
if (k < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~1);
|
|
i = k;
|
|
j = k >> 1;
|
|
while (i > 0) {
|
|
b[--j] = src[--i];
|
|
i--;
|
|
}
|
|
return k >> 1;
|
|
}
|
|
static struct pcm_feederdesc feeder_16leto8_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_16leto8_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_16leto8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_16leto8, 0, NULL);
|
|
|
|
static int
|
|
feed_16leto24le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
|
|
k = (count / 3) << 1;
|
|
k = FEEDER_FEED(f->source, c, b, k, source);
|
|
if (k < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~1);
|
|
i = k;
|
|
j = (k >> 1) * 3;
|
|
k = j;
|
|
while (i > 0) {
|
|
b[--j] = b[--i];
|
|
b[--j] = b[--i];
|
|
b[--j] = 0;
|
|
}
|
|
return k;
|
|
}
|
|
static struct pcm_feederdesc feeder_16leto24le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_16leto24le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_16leto24le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_16leto24le, 0, NULL);
|
|
|
|
static int
|
|
feed_24leto16le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = (count * 3) >> 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUF24SZ), source);
|
|
if (k < 3) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k -= k % 3);
|
|
i = (k / 3) << 1;
|
|
j = i;
|
|
while (i > 0) {
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
k--;
|
|
}
|
|
return j;
|
|
}
|
|
static struct pcm_feederdesc feeder_24leto16le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_24leto16le_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_24leto16le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_24leto16le, 1, NULL);
|
|
|
|
static int
|
|
feed_16leto32le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
if (k < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~1);
|
|
i = k;
|
|
j = k << 1;
|
|
k = j;
|
|
while (i > 0) {
|
|
b[--j] = b[--i];
|
|
b[--j] = b[--i];
|
|
b[--j] = 0;
|
|
b[--j] = 0;
|
|
}
|
|
return k;
|
|
}
|
|
static struct pcm_feederdesc feeder_16leto32le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_16leto32le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_16leto32le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_16leto32le, 0, NULL);
|
|
|
|
static int
|
|
feed_32leto16le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = count << 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUFSZ), source);
|
|
if (k < 4) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~3);
|
|
i = k;
|
|
k >>= 1;
|
|
j = k;
|
|
while (i > 0) {
|
|
b[--j] = src[--i];
|
|
b[--j] = src[--i];
|
|
i -= 2;
|
|
}
|
|
return k;
|
|
}
|
|
static struct pcm_feederdesc feeder_32leto16le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_32leto16le_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_32leto16le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_32leto16le, 1, NULL);
|
|
/*
|
|
* Bit conversion end
|
|
*/
|
|
|
|
/*
|
|
* Channel conversion (mono -> stereo)
|
|
*/
|
|
static int
|
|
feed_monotostereo8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
|
|
i = k;
|
|
j = k << 1;
|
|
while (i > 0) {
|
|
b[--j] = b[--i];
|
|
b[--j] = b[i];
|
|
}
|
|
return k << 1;
|
|
}
|
|
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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_monotostereo8_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_monotostereo8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo8, 0, NULL);
|
|
|
|
static int
|
|
feed_monotostereo16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
uint8_t l, m;
|
|
|
|
if (k < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~1);
|
|
i = k;
|
|
j = k << 1;
|
|
while (i > 0) {
|
|
l = b[--i];
|
|
m = b[--i];
|
|
b[--j] = l;
|
|
b[--j] = m;
|
|
b[--j] = l;
|
|
b[--j] = m;
|
|
}
|
|
return k << 1;
|
|
}
|
|
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_monotostereo16),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo16, 0, NULL);
|
|
|
|
static int
|
|
feed_monotostereo24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
uint8_t l, m, n;
|
|
|
|
if (k < 3) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k -= k % 3);
|
|
i = k;
|
|
j = k << 1;
|
|
while (i > 0) {
|
|
l = b[--i];
|
|
m = b[--i];
|
|
n = b[--i];
|
|
b[--j] = l;
|
|
b[--j] = m;
|
|
b[--j] = n;
|
|
b[--j] = l;
|
|
b[--j] = m;
|
|
b[--j] = n;
|
|
}
|
|
return k << 1;
|
|
}
|
|
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_monotostereo24),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo24, 0, NULL);
|
|
|
|
static int
|
|
feed_monotostereo32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k = FEEDER_FEED(f->source, c, b, count >> 1, source);
|
|
uint8_t l, m, n, o;
|
|
|
|
if (k < 4) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~3);
|
|
i = k;
|
|
j = k << 1;
|
|
while (i > 0) {
|
|
l = b[--i];
|
|
m = b[--i];
|
|
n = b[--i];
|
|
o = b[--i];
|
|
b[--j] = l;
|
|
b[--j] = m;
|
|
b[--j] = n;
|
|
b[--j] = o;
|
|
b[--j] = l;
|
|
b[--j] = m;
|
|
b[--j] = n;
|
|
b[--j] = o;
|
|
}
|
|
return k << 1;
|
|
}
|
|
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_monotostereo32),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_monotostereo32, 0, NULL);
|
|
/*
|
|
* Channel conversion (mono -> stereo) end
|
|
*/
|
|
|
|
/*
|
|
* Channel conversion (stereo -> mono)
|
|
*/
|
|
static int
|
|
feed_stereotomono8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = count << 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUFSZ), source);
|
|
if (k < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 1, "%s: Bytes not 8bit (stereo) aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~1);
|
|
i = k >> 1;
|
|
j = i;
|
|
while (i > 0) {
|
|
k--;
|
|
b[--i] = src[--k];
|
|
}
|
|
return j;
|
|
}
|
|
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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_stereotomono8_methods[] = {
|
|
KOBJMETHOD(feeder_init, feed_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono8, 0, NULL);
|
|
|
|
static int
|
|
feed_stereotomono16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = count << 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUFSZ), source);
|
|
if (k < 4) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 3, "%s: Bytes not 16bit (stereo) aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~3);
|
|
i = k >> 1;
|
|
j = i;
|
|
while (i > 0) {
|
|
k -= 2;
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
}
|
|
return j;
|
|
}
|
|
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_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono16),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono16, 0, NULL);
|
|
|
|
static int
|
|
feed_stereotomono24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = count << 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUF24SZ), source);
|
|
if (k < 6) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k % 6, "%s: Bytes not 24bit (stereo) aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k -= k % 6);
|
|
i = k >> 1;
|
|
j = i;
|
|
while (i > 0) {
|
|
k -= 3;
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
}
|
|
return j;
|
|
}
|
|
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_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono24),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono24, 0, NULL);
|
|
|
|
static int
|
|
feed_stereotomono32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j, k;
|
|
uint8_t *src = (uint8_t *)f->data;
|
|
|
|
k = count << 1;
|
|
k = FEEDER_FEED(f->source, c, src, min(k, FEEDBUFSZ), source);
|
|
if (k < 8) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, k);
|
|
return 0;
|
|
}
|
|
FMT_TEST(k & 7, "%s: Bytes not 32bit (stereo) aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(k &= ~7);
|
|
i = k >> 1;
|
|
j = i;
|
|
while (i > 0) {
|
|
k -= 4;
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
b[--i] = src[--k];
|
|
}
|
|
return j;
|
|
}
|
|
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_common_init),
|
|
KOBJMETHOD(feeder_free, feed_common_free),
|
|
KOBJMETHOD(feeder_feed, feed_stereotomono32),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_stereotomono32, 0, NULL);
|
|
/*
|
|
* Channel conversion (stereo -> mono) end
|
|
*/
|
|
|
|
/*
|
|
* Sign conversion
|
|
*/
|
|
static int
|
|
feed_sign8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
|
|
i = j;
|
|
while (i > 0)
|
|
b[--i] ^= 0x80;
|
|
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_sign8),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign8, 0, NULL);
|
|
|
|
static int
|
|
feed_sign16le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
|
|
if (j < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, j);
|
|
return 0;
|
|
}
|
|
FMT_TEST(j & 1, "%s: Bytes not 16bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(j &= ~1);
|
|
i = j;
|
|
while (i > 0) {
|
|
b[--i] ^= 0x80;
|
|
i--;
|
|
}
|
|
return j;
|
|
}
|
|
static struct pcm_feederdesc feeder_sign16le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign16le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign16le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign16le, 0, NULL);
|
|
|
|
static int
|
|
feed_sign24le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
|
|
if (j < 3) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, j);
|
|
return 0;
|
|
}
|
|
FMT_TEST(j % 3, "%s: Bytes not 24bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(j -= j % 3);
|
|
i = j;
|
|
while (i > 0) {
|
|
b[--i] ^= 0x80;
|
|
i -= 2;
|
|
}
|
|
return j;
|
|
}
|
|
static struct pcm_feederdesc feeder_sign24le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign24le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign24le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign24le, 0, NULL);
|
|
|
|
static int
|
|
feed_sign32le(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
|
|
if (j < 4) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, j);
|
|
return 0;
|
|
}
|
|
FMT_TEST(j & 3, "%s: Bytes not 32bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(j &= ~3);
|
|
i = j;
|
|
while (i > 0) {
|
|
b[--i] ^= 0x80;
|
|
i -= 3;
|
|
}
|
|
return j;
|
|
}
|
|
static struct pcm_feederdesc feeder_sign32le_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},
|
|
{0, 0, 0, 0},
|
|
};
|
|
static kobj_method_t feeder_sign32le_methods[] = {
|
|
KOBJMETHOD(feeder_feed, feed_sign32le),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_sign32le, 0, NULL);
|
|
/*
|
|
* Sign conversion end.
|
|
*/
|
|
|
|
/*
|
|
* Endian conversion.
|
|
*/
|
|
static int
|
|
feed_endian16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
uint8_t v;
|
|
|
|
if (j < 2) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, j);
|
|
return 0;
|
|
}
|
|
FMT_TEST(j & 1, "%s: Bytes not 16bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(j &= ~1);
|
|
i = j;
|
|
while (i > 0) {
|
|
v = b[--i];
|
|
b[i] = b[i - 1];
|
|
b[--i] = v;
|
|
}
|
|
return j;
|
|
}
|
|
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_endian16),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_endian16, 0, NULL);
|
|
|
|
static int
|
|
feed_endian24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
uint8_t v;
|
|
|
|
if (j < 3) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, j);
|
|
return 0;
|
|
}
|
|
FMT_TEST(j % 3, "%s: Bytes not 24bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(j -= j % 3);
|
|
i = j;
|
|
while (i > 0) {
|
|
v = b[--i];
|
|
b[i] = b[i - 2];
|
|
b[i -= 2] = v;
|
|
}
|
|
return j;
|
|
}
|
|
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_endian24),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_endian24, 0, NULL);
|
|
|
|
static int
|
|
feed_endian32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
|
|
uint32_t count, void *source)
|
|
{
|
|
int i, j = FEEDER_FEED(f->source, c, b, count, source);
|
|
uint8_t l, m;
|
|
|
|
if (j < 4) {
|
|
FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
|
|
__func__, j);
|
|
return 0;
|
|
}
|
|
FMT_TEST(j & 3, "%s: Bytes not 32bit aligned.\n", __func__);
|
|
FMT_ALIGNBYTE(j &= ~3);
|
|
i = j;
|
|
while (i > 0) {
|
|
l = b[--i];
|
|
m = b[--i];
|
|
b[i] = b[i - 1];
|
|
b[i + 1] = b[i - 2];
|
|
b[--i] = m;
|
|
b[--i] = l;
|
|
}
|
|
return j;
|
|
}
|
|
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_endian32),
|
|
{0, 0}
|
|
};
|
|
FEEDER_DECLARE(feeder_endian32, 0, NULL);
|
|
/*
|
|
* Endian conversion end
|
|
*/
|