diff options
Diffstat (limited to 'usr.sbin/virtual_oss/virtual_oss/format.c')
-rw-r--r-- | usr.sbin/virtual_oss/virtual_oss/format.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/usr.sbin/virtual_oss/virtual_oss/format.c b/usr.sbin/virtual_oss/virtual_oss/format.c new file mode 100644 index 000000000000..d32d0c726510 --- /dev/null +++ b/usr.sbin/virtual_oss/virtual_oss/format.c @@ -0,0 +1,429 @@ +/*- + * Copyright (c) 2012-2020 Hans Petter Selasky + * + * 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. + */ + +#include <sys/queue.h> +#include <sys/soundcard.h> + +#include <stdint.h> +#include <string.h> + +#include "int.h" + +void +format_import(uint32_t fmt, const uint8_t *src, uint32_t len, + int64_t *dst) +{ + const uint8_t *end = src + len; + int64_t val; + + if (fmt & AFMT_16BIT) { + while (src != end) { + if (fmt & (AFMT_S16_LE | AFMT_U16_LE)) + val = src[0] | (src[1] << 8); + else + val = src[1] | (src[0] << 8); + + src += 2; + + if (fmt & (AFMT_U16_LE | AFMT_U16_BE)) + val = val ^ 0x8000; + + val <<= (64 - 16); + val >>= (64 - 16); + + *dst++ = val; + } + + } else if (fmt & AFMT_24BIT) { + while (src < end) { + if (fmt & (AFMT_S24_LE | AFMT_U24_LE)) + val = src[0] | (src[1] << 8) | (src[2] << 16); + else + val = src[2] | (src[1] << 8) | (src[0] << 16); + + src += 3; + + if (fmt & (AFMT_U24_LE | AFMT_U24_BE)) + val = val ^ 0x800000; + + val <<= (64 - 24); + val >>= (64 - 24); + + *dst++ = val; + } + } else if (fmt & AFMT_32BIT) { + while (src < end) { + int64_t e, m, s; + + if (fmt & (AFMT_S32_LE | AFMT_U32_LE | AFMT_F32_LE)) + val = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + else + val = src[3] | (src[2] << 8) | (src[1] << 16) | (src[0] << 24); + + src += 4; + + if (fmt & (AFMT_U32_LE | AFMT_U32_BE)) + val = val ^ 0x80000000LL; + + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) { + e = (val >> 23) & 0xff; + /* NaN, +/- Inf or too small */ + if (e == 0xff || e < 96) { + val = 0; + goto skip; + } + s = val & 0x80000000U; + if (e > 126) { + val = s == 0 ? format_max(fmt) : + -0x80000000LL; + goto skip; + } + m = 0x800000 | (val & 0x7fffff); + e += 8 - 127; + if (e < 0) + m >>= -e; + else + m <<= e; + val = s == 0 ? m : -m; + } +skip: + val <<= (64 - 32); + val >>= (64 - 32); + + *dst++ = val; + } + + } else if (fmt & AFMT_8BIT) { + while (src < end) { + val = src[0]; + + src += 1; + + if (fmt & AFMT_U8) + val = val ^ 0x80; + + val <<= (64 - 8); + val >>= (64 - 8); + + *dst++ = val; + } + } +} + +void +format_export(uint32_t fmt, const int64_t *src, uint8_t *dst, uint32_t len) +{ + const uint8_t *end = dst + len; + int64_t val; + + if (fmt & AFMT_16BIT) { + while (dst != end) { + + val = *src++; + + if (val > 0x7FFF) + val = 0x7FFF; + else if (val < -0x7FFF) + val = -0x7FFF; + + if (fmt & (AFMT_U16_LE | AFMT_U16_BE)) + val = val ^ 0x8000; + + if (fmt & (AFMT_S16_LE | AFMT_U16_LE)) { + dst[0] = val; + dst[1] = val >> 8; + } else { + dst[1] = val; + dst[0] = val >> 8; + } + + dst += 2; + } + + } else if (fmt & AFMT_24BIT) { + while (dst != end) { + + val = *src++; + + if (val > 0x7FFFFF) + val = 0x7FFFFF; + else if (val < -0x7FFFFF) + val = -0x7FFFFF; + + if (fmt & (AFMT_U24_LE | AFMT_U24_BE)) + val = val ^ 0x800000; + + if (fmt & (AFMT_S24_LE | AFMT_U24_LE)) { + dst[0] = val; + dst[1] = val >> 8; + dst[2] = val >> 16; + } else { + dst[2] = val; + dst[1] = val >> 8; + dst[0] = val >> 16; + } + + dst += 3; + } + } else if (fmt & AFMT_32BIT) { + while (dst != end) { + int64_t r, e; + + val = *src++; + + if (val > 0x7FFFFFFFLL) + val = 0x7FFFFFFFLL; + else if (val < -0x7FFFFFFFLL) + val = -0x7FFFFFFFLL; + + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) { + if (val == 0) + r = 0; + else if (val == format_max(fmt)) + r = 0x3f800000; + else if (val == -0x80000000LL) + r = 0x80000000U | 0x3f800000; + else { + r = 0; + if (val < 0) { + r |= 0x80000000U; + val = -val; + } + e = 127 - 8; + while ((val & 0x7f000000) != 0) { + val >>= 1; + e++; + } + while ((val & 0x7f800000) == 0) { + val <<= 1; + e--; + } + r |= (e & 0xff) << 23; + r |= val & 0x7fffff; + } + val = r; + } + + if (fmt & (AFMT_U32_LE | AFMT_U32_BE)) + val = val ^ 0x80000000LL; + + if (fmt & (AFMT_S32_LE | AFMT_U32_LE | AFMT_F32_LE)) { + dst[0] = val; + dst[1] = val >> 8; + dst[2] = val >> 16; + dst[3] = val >> 24; + } else { + dst[3] = val; + dst[2] = val >> 8; + dst[1] = val >> 16; + dst[0] = val >> 24; + } + + dst += 4; + } + + } else if (fmt & AFMT_8BIT) { + while (dst != end) { + + val = *src++; + + if (val > 0x7F) + val = 0x7F; + else if (val < -0x7F) + val = -0x7F; + + if (fmt & (AFMT_U8)) + val = val ^ 0x80; + + dst[0] = val; + + dst += 1; + } + } +} + +int64_t +format_max(uint32_t fmt) +{ + if (fmt & AFMT_16BIT) + return (0x7FFF); + else if (fmt & AFMT_24BIT) + return (0x7FFFFF); + else if (fmt & AFMT_32BIT) + return (0x7FFFFFFF); + else if (fmt & AFMT_8BIT) + return (0x7F); + return (0); +} + +void +format_maximum(const int64_t *src, int64_t *dst, uint32_t ch, + uint32_t samples, int8_t shift) +{ + const int64_t *end = src + (samples * ch); + int64_t max[ch]; + int64_t temp; + uint32_t x; + + memset(max, 0, sizeof(max)); + + while (src != end) { + for (x = 0; x != ch; x++) { + temp = *src++; + if (temp < 0) + temp = -temp; + if (temp > max[x]) + max[x] = temp; + } + } + + for (x = 0; x != ch; x++) { + if (shift < 0) + max[x] >>= -shift; + else + max[x] <<= shift; + if (dst[x] < max[x]) + dst[x] = max[x]; + } +} + +void +format_remix(int64_t *buffer_data, uint32_t in_chans, + uint32_t out_chans, uint32_t samples) +{ + uint32_t x; + + if (out_chans > in_chans) { + uint32_t dst = out_chans * (samples - 1); + uint32_t src = in_chans * (samples - 1); + uint32_t fill = out_chans - in_chans; + + for (x = 0; x != samples; x++) { + memset(buffer_data + dst + in_chans, 0, 8 * fill); + if (src != dst) { + memcpy(buffer_data + dst, + buffer_data + src, + in_chans * 8); + } + dst -= out_chans; + src -= in_chans; + } + } else if (out_chans < in_chans) { + uint32_t dst = 0; + uint32_t src = 0; + + for (x = 0; x != samples; x++) { + if (src != dst) { + memcpy(buffer_data + dst, + buffer_data + src, + out_chans * 8); + } + dst += out_chans; + src += in_chans; + } + } +} + +void +format_silence(uint32_t fmt, uint8_t *dst, uint32_t len) +{ + const uint8_t *end = dst + len; + + if (fmt & AFMT_16BIT) { + uint16_t val; + + if (fmt & (AFMT_U16_LE | AFMT_U16_BE)) + val = 1U << 15; + else + val = 0; + + while (dst != end) { + if (fmt & (AFMT_S16_LE | AFMT_U16_LE)) { + dst[0] = val; + dst[1] = val >> 8; + } else { + dst[1] = val; + dst[0] = val >> 8; + } + dst += 2; + } + + } else if (fmt & AFMT_24BIT) { + uint32_t val; + + if (fmt & (AFMT_U24_LE | AFMT_U24_BE)) + val = 1U << 23; + else + val = 0; + + while (dst != end) { + if (fmt & (AFMT_S24_LE | AFMT_U24_LE)) { + dst[0] = val; + dst[1] = val >> 8; + dst[2] = val >> 16; + } else { + dst[2] = val; + dst[1] = val >> 8; + dst[0] = val >> 16; + } + dst += 3; + } + } else if (fmt & AFMT_32BIT) { + uint32_t val; + + if (fmt & (AFMT_U32_LE | AFMT_U32_BE)) + val = 1U << 31; + else + val = 0; + + while (dst != end) { + if (fmt & (AFMT_S32_LE | AFMT_U32_LE | AFMT_F32_LE)) { + dst[0] = val; + dst[1] = val >> 8; + dst[2] = val >> 16; + dst[3] = val >> 24; + } else { + dst[3] = val; + dst[2] = val >> 8; + dst[1] = val >> 16; + dst[0] = val >> 24; + } + dst += 4; + } + + } else if (fmt & AFMT_8BIT) { + uint8_t val; + + if (fmt & AFMT_U8) + val = 1U << 7; + else + val = 0; + + while (dst != end) { + dst[0] = val; + dst += 1; + } + } +} |