/*- * Copyright (c) 1999 Cameron Grant * Copyright (c) 2005 Ariff Abdullah * 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 #include "feeder_if.h" SND_DECLARE_FILE("$FreeBSD$"); MALLOC_DEFINE(M_FMTFEEDER, "fmtfeed", "pcm format feeder"); #define FMT_TRACE(x...) /* printf(x) */ #define FMT_TEST(x, y...) /* if (x) FMT_TRACE(y) */ struct feed_fmt_info { int bps, bufsz; uint8_t *buffer; }; /* * 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_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 < 1) return 0; k = FEEDER_FEED(f->source, c, b, count, source); j = k; sign = (f->desc->out & AFMT_SIGNED) ? 0x00 : 0x80; while (j > 0) { j--; b[j] = tbl[b[j]] ^ sign; } 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 < 2) return 0; k = FEEDER_FEED(f->source, c, b, count >> 1, source); i = k; k <<= 1; j = k; sign = (f->desc->out & AFMT_SIGNED) ? 0x00 : 0x80; if (f->desc->out & AFMT_BIGENDIAN) { while (i > 0) { b[--j] = 0; b[--j] = tbl[b[--i]] ^ sign; } } else { while (i > 0) { b[--j] = tbl[b[--i]] ^ sign; 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, sign, k; uint8_t *tbl = (uint8_t *)f->data; if (count < 1) return 0; k = FEEDER_FEED(f->source, c, b, count, source); j = k; sign = (f->desc->in & AFMT_SIGNED) ? 0x80 : 0x00; while (j > 0) { j--; b[j] = tbl[b[j] ^ sign]; } 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_s8_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_s8_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_s8_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_s8_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. */ static int feed_fmt_init(struct pcm_feeder *f) { struct feed_fmt_info *info; info = malloc(sizeof(*info), M_FMTFEEDER, M_NOWAIT | M_ZERO); if (info == NULL) return ENOMEM; info->bps = 1; info->bps <<= (f->desc->in & AFMT_STEREO) ? 1 : 0; if (f->desc->in & AFMT_16BIT) info->bps <<= 1; else if (f->desc->in & AFMT_24BIT) info->bps *= 3; else if (f->desc->in & AFMT_32BIT) info->bps <<= 2; info->bufsz = feeder_buffersize - (feeder_buffersize % info->bps); info->buffer = malloc(info->bufsz, M_FMTFEEDER, M_NOWAIT | M_ZERO); if (info->buffer == NULL) { free(info, M_FMTFEEDER); return ENOMEM; } f->data = info; return 0; } static int feed_fmt_free(struct pcm_feeder *f) { struct feed_fmt_info *info = f->data; if (info) { if (info->buffer) free(info->buffer, M_FMTFEEDER); free(info, M_FMTFEEDER); } f->data = NULL; return 0; } #define swap_sign(fdr) \ (((((fdr)->desc->in & AFMT_SIGNED) && \ !((fdr)->desc->out & AFMT_SIGNED)) || \ (!((fdr)->desc->in & AFMT_SIGNED) && \ ((fdr)->desc->out & AFMT_SIGNED))) ? 0x80 : 0x00) /* * Bit conversion */ static int feed_8to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j, k; int sign; if (count < 2) return 0; k = FEEDER_FEED(f->source, c, b, count >> 1, source); i = k; k <<= 1; j = k; sign = swap_sign(f); if (f->desc->out & AFMT_BIGENDIAN) { while (i > 0) { b[--j] = 0; b[--j] = b[--i] ^ sign; } } else { while (i > 0) { b[--j] = b[--i] ^ sign; b[--j] = 0; } } return k; } 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_feed, feed_8to16), {0, 0} }; FEEDER_DECLARE(feeder_8to16, 0, NULL); static int feed_16to8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct feed_fmt_info *info = f->data; int i, j, k, sign; uint8_t *src = info->buffer; if (count < 1) return 0; k = count << 1; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k &= ~1; i = k; j = k >> 1; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 1) { i--; b[--j] = src[--i] ^ sign; } } else { while (i > 1) { b[--j] = src[--i] ^ sign; i--; } } return k >> 1; } 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_free), KOBJMETHOD(feeder_feed, feed_16to8), {0, 0} }; FEEDER_DECLARE(feeder_16to8, 0, NULL); static int feed_16to24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j, k, sign; if (count < 3) return 0; 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__); k &= ~1; i = k; j = (k >> 1) * 3; k = j; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 1) { b[--j] = 0; b[--j] = b[--i]; b[--j] = b[--i] ^ sign; } } else { while (i > 1) { b[--j] = b[--i] ^ sign; b[--j] = b[--i]; b[--j] = 0; } } return k; } 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_feed, feed_16to24), {0, 0} }; FEEDER_DECLARE(feeder_16to24, 0, NULL); static int feed_24to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct feed_fmt_info *info = f->data; int i, j, k, sign; uint8_t *src = info->buffer; if (count < 2) return 0; k = (count >> 1) * 3; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k -= k % 3; i = (k / 3) << 1; j = i; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 1) { k--; b[--i] = src[--k]; b[--i] = src[--k] ^ sign; } } else { while (i > 1) { b[--i] = src[--k] ^ sign; b[--i] = src[--k]; k--; } } return j; } 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_free), KOBJMETHOD(feeder_feed, feed_24to16), {0, 0} }; FEEDER_DECLARE(feeder_24to16, 1, NULL); static int feed_16to32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j, sign, k; if (count < 4) return 0; k = FEEDER_FEED(f->source, c, b, (count & ~3) >> 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__); k &= ~1; i = k; j = k << 1; k = j; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 1) { b[--j] = 0; b[--j] = 0; b[--j] = b[--i]; b[--j] = b[--i] ^ sign; } } else { while (i > 1) { b[--j] = b[--i] ^ sign; b[--j] = b[--i]; b[--j] = 0; b[--j] = 0; } } return k; } 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_feed, feed_16to32), {0, 0} }; FEEDER_DECLARE(feeder_16to32, 0, NULL); static int feed_32to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct feed_fmt_info *info = f->data; int i, j, k, sign; uint8_t *src = info->buffer; if (count < 2) return 0; k = (count & ~1) << 1; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k &= ~3; i = k; k >>= 1; j = k; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 3) { i -= 2; b[--j] = src[--i]; b[--j] = src[--i] ^ sign; } } else { while (i > 3) { b[--j] = src[--i] ^ sign; b[--j] = src[--i]; i -= 2; } } return k; } 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_free), KOBJMETHOD(feeder_feed, feed_32to16), {0, 0} }; FEEDER_DECLARE(feeder_32to16, 1, NULL); static int feed_24to32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j, k, sign; if (count < 4) return 0; k = FEEDER_FEED(f->source, c, b, (count >> 2) * 3, 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__); k -= k % 3; i = k; k = (k / 3) << 2; j = k; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 2) { b[--j] = 0; b[--j] = b[--i]; b[--j] = b[--i]; b[--j] = b[--i] ^ sign; } } else { while (i > 2) { b[--j] = b[--i] ^ sign; b[--j] = b[--i]; b[--j] = b[--i]; b[--j] = 0; } } return k; } 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_feed, feed_24to32), {0, 0} }; FEEDER_DECLARE(feeder_24to32, 1, NULL); static int feed_32to24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct feed_fmt_info *info = f->data; int i, j, k, sign; uint8_t *src = info->buffer; if (count < 3) return 0; k = (count / 3) << 2; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k &= ~3; i = k; k = (k >> 2) * 3; j = k; sign = swap_sign(f); if (f->desc->in & AFMT_BIGENDIAN) { while (i > 3) { --i; b[--j] = src[--i]; b[--j] = src[--i]; b[--j] = src[--i] ^ sign; } } else { while (i > 3) { b[--j] = src[--i] ^ sign; b[--j] = src[--i]; b[--j] = src[--i]; --i; } } return k; } 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_free), KOBJMETHOD(feeder_feed, feed_32to24), {0, 0} }; FEEDER_DECLARE(feeder_32to24, 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; if (count < 2) return 0; 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}, {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_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; uint8_t l, m; if (count < 4) return 0; k = FEEDER_FEED(f->source, c, b, (count & ~3) >> 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__); k &= ~1; i = k; j = k << 1; while (i > 1) { 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; uint8_t l, m, n; if (count < 6) return 0; k = FEEDER_FEED(f->source, c, b, ((count / 6) * 6) >> 1, 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__); k -= k % 3; i = k; j = k << 1; while (i > 2) { 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; uint8_t l, m, n, o; if (count < 8) return 0; k = FEEDER_FEED(f->source, c, b, (count & ~7) >> 1, 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__); k &= ~3; i = k; j = k << 1; while (i > 3) { 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) { struct feed_fmt_info *info = f->data; int i, j, k; uint8_t *src = info->buffer; if (count < 1) return 0; k = count << 1; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); 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}, {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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_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) { struct feed_fmt_info *info = f->data; int i, j, k; uint8_t *src = info->buffer; if (count < 2) return 0; k = (count & ~1) << 1; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k &= ~3; i = k >> 1; j = i; while (i > 1) { 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_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) { struct feed_fmt_info *info = f->data; int i, j, k; uint8_t *src = info->buffer; if (count < 3) return 0; k = ((count / 3) * 3) << 1; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k -= k % 6; i = k >> 1; j = i; while (i > 2) { 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_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) { struct feed_fmt_info *info = f->data; int i, j, k; uint8_t *src = info->buffer; if (count < 4) return 0; k = (count & ~3) << 1; k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), 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__); k &= ~7; i = k >> 1; j = i; while (i > 3) { 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_fmt_init), KOBJMETHOD(feeder_free, feed_fmt_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; if (count < 1) return 0; 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_sign16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j; if (count < 2) return 0; j = FEEDER_FEED(f->source, c, b, count & ~1, 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__); j &= ~1; i = j; if (f->desc->in & AFMT_BIGENDIAN) { while (i > 1) { i--; b[--i] ^= 0x80; } } else { while (i > 1) { b[--i] ^= 0x80; i--; } } return j; } 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_sign16), {0, 0} }; FEEDER_DECLARE(feeder_sign16, 0, NULL); static int feed_sign24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j; if (count < 3) return 0; j = FEEDER_FEED(f->source, c, b, (count / 3) * 3, 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__); j -= j % 3; i = j; if (f->desc->in & AFMT_BIGENDIAN) { while (i > 2) { i -= 2; b[--i] ^= 0x80; } } else { while (i > 2) { b[--i] ^= 0x80; i -= 2; } } return j; } 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_sign24), {0, 0} }; FEEDER_DECLARE(feeder_sign24, 0, NULL); static int feed_sign32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { int i, j; if (count < 4) return 0; j = FEEDER_FEED(f->source, c, b, count & ~3, 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__); j &= ~3; i = j; if (f->desc->in & AFMT_BIGENDIAN) { while (i > 3) { i -= 3; b[--i] ^= 0x80; } } else { while (i > 3) { b[--i] ^= 0x80; i -= 3; } } return j; } 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_sign32), {0, 0} }; FEEDER_DECLARE(feeder_sign32, 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; uint8_t v; if (count < 2) return 0; j = FEEDER_FEED(f->source, c, b, count & ~1, 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__); j &= ~1; i = j; while (i > 1) { 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; uint8_t v; if (count < 3) return 0; j = FEEDER_FEED(f->source, c, b, (count / 3) * 3, 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__); j -= j % 3; i = j; while (i > 2) { 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; uint8_t l, m; if (count < 4) return 0; j = FEEDER_FEED(f->source, c, b, count & ~3, 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__); j &= ~3; i = j; while (i > 3) { 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 */