freebsd-dev/sys/dev/sound/pcm/pcm.h
Pedro F. Giffuni 718cf2ccb9 sys/dev: further adoption of SPDX licensing ID tags.
Mainly focus on files that use BSD 2-Clause license, however the tool I
was using misidentified many licenses so this was mostly a manual - error
prone - task.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.
2017-11-27 14:52:40 +00:00

441 lines
15 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2006-2009 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.
*
* $FreeBSD$
*/
#ifndef _SND_PCM_H_
#define _SND_PCM_H_
#include <sys/param.h>
/*
* Macros for reading/writing PCM sample / int values from bytes array.
* Since every process is done using signed integer (and to make our life
* less miserable), unsigned sample will be converted to its signed
* counterpart and restored during writing back. To avoid overflow,
* we truncate 32bit (and only 32bit) samples down to 24bit (see below
* for the reason), unless SND_PCM_64 is defined.
*/
/*
* Automatically turn on 64bit arithmetic on suitable archs
* (amd64 64bit, etc..) for wider 32bit samples / integer processing.
*/
#if LONG_BIT >= 64
#undef SND_PCM_64
#define SND_PCM_64 1
#endif
typedef int32_t intpcm_t;
typedef int32_t intpcm8_t;
typedef int32_t intpcm16_t;
typedef int32_t intpcm24_t;
typedef uint32_t uintpcm_t;
typedef uint32_t uintpcm8_t;
typedef uint32_t uintpcm16_t;
typedef uint32_t uintpcm24_t;
#ifdef SND_PCM_64
typedef int64_t intpcm32_t;
typedef uint64_t uintpcm32_t;
#else
typedef int32_t intpcm32_t;
typedef uint32_t uintpcm32_t;
#endif
typedef int64_t intpcm64_t;
typedef uint64_t uintpcm64_t;
/* 32bit fixed point shift */
#define PCM_FXSHIFT 8
#define PCM_S8_MAX 0x7f
#define PCM_S8_MIN -0x80
#define PCM_S16_MAX 0x7fff
#define PCM_S16_MIN -0x8000
#define PCM_S24_MAX 0x7fffff
#define PCM_S24_MIN -0x800000
#ifdef SND_PCM_64
#if LONG_BIT >= 64
#define PCM_S32_MAX 0x7fffffffL
#define PCM_S32_MIN -0x80000000L
#else
#define PCM_S32_MAX 0x7fffffffLL
#define PCM_S32_MIN -0x80000000LL
#endif
#else
#define PCM_S32_MAX 0x7fffffff
#define PCM_S32_MIN (-0x7fffffff - 1)
#endif
/* Bytes-per-sample definition */
#define PCM_8_BPS 1
#define PCM_16_BPS 2
#define PCM_24_BPS 3
#define PCM_32_BPS 4
#define INTPCM_T(v) ((intpcm_t)(v))
#define INTPCM8_T(v) ((intpcm8_t)(v))
#define INTPCM16_T(v) ((intpcm16_t)(v))
#define INTPCM24_T(v) ((intpcm24_t)(v))
#define INTPCM32_T(v) ((intpcm32_t)(v))
#if BYTE_ORDER == LITTLE_ENDIAN
#define _PCM_READ_S16_LE(b8) INTPCM_T(*((int16_t *)(b8)))
#define _PCM_READ_S32_LE(b8) INTPCM_T(*((int32_t *)(b8)))
#define _PCM_READ_S16_BE(b8) \
INTPCM_T((b8)[1] | (((int8_t)((b8)[0])) << 8))
#define _PCM_READ_S32_BE(b8) \
INTPCM_T((b8)[3] | ((b8)[2] << 8) | ((b8)[1] << 16) | \
(((int8_t)((b8)[0])) << 24))
#define _PCM_WRITE_S16_LE(b8, val) do { \
*((int16_t *)(b8)) = (val); \
} while (0)
#define _PCM_WRITE_S32_LE(b8, val) do { \
*((int32_t *)(b8)) = (val); \
} while (0)
#define _PCM_WRITE_S16_BE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[1] = val; \
b8[0] = val >> 8; \
} while (0)
#define _PCM_WRITE_S32_BE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[3] = val; \
b8[2] = val >> 8; \
b8[1] = val >> 16; \
b8[0] = val >> 24; \
} while (0)
#define _PCM_READ_U16_LE(b8) \
INTPCM_T((int16_t)(*((uint16_t *)(b8)) ^ 0x8000))
#define _PCM_READ_U32_LE(b8) \
INTPCM_T((int32_t)(*((uint32_t *)(b8)) ^ 0x80000000))
#define _PCM_READ_U16_BE(b8) \
INTPCM_T((b8)[1] | (((int8_t)((b8)[0] ^ 0x80)) << 8))
#define _PCM_READ_U32_BE(b8) \
INTPCM_T((b8)[3] | ((b8)[2] << 8) | ((b8)[1] << 16) | \
(((int8_t)((b8)[0] ^ 0x80)) << 24))
#define _PCM_WRITE_U16_LE(b8, val) do { \
*((uint16_t *)(b8)) = (val) ^ 0x8000; \
} while (0)
#define _PCM_WRITE_U32_LE(b8, val) do { \
*((uint32_t *)(b8)) = (val) ^ 0x80000000; \
} while (0)
#define _PCM_WRITE_U16_BE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[1] = val; \
b8[0] = (val >> 8) ^ 0x80; \
} while (0)
#define _PCM_WRITE_U32_BE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[3] = val; \
b8[2] = val >> 8; \
b8[1] = val >> 16; \
b8[0] = (val >> 24) ^ 0x80; \
} while (0)
#define _PCM_READ_S16_NE(b8) _PCM_READ_S16_LE(b8)
#define _PCM_READ_U16_NE(b8) _PCM_READ_U16_LE(b8)
#define _PCM_READ_S32_NE(b8) _PCM_READ_S32_LE(b8)
#define _PCM_READ_U32_NE(b8) _PCM_READ_U32_LE(b8)
#define _PCM_WRITE_S16_NE(b6) _PCM_WRITE_S16_LE(b8)
#define _PCM_WRITE_U16_NE(b6) _PCM_WRITE_U16_LE(b8)
#define _PCM_WRITE_S32_NE(b6) _PCM_WRITE_S32_LE(b8)
#define _PCM_WRITE_U32_NE(b6) _PCM_WRITE_U32_LE(b8)
#else /* !LITTLE_ENDIAN */
#define _PCM_READ_S16_LE(b8) \
INTPCM_T((b8)[0] | (((int8_t)((b8)[1])) << 8))
#define _PCM_READ_S32_LE(b8) \
INTPCM_T((b8)[0] | ((b8)[1] << 8) | ((b8)[2] << 16) | \
(((int8_t)((b8)[3])) << 24))
#define _PCM_READ_S16_BE(b8) INTPCM_T(*((int16_t *)(b8)))
#define _PCM_READ_S32_BE(b8) INTPCM_T(*((int32_t *)(b8)))
#define _PCM_WRITE_S16_LE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[0] = val; \
b8[1] = val >> 8; \
} while (0)
#define _PCM_WRITE_S32_LE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[0] = val; \
b8[1] = val >> 8; \
b8[2] = val >> 16; \
b8[3] = val >> 24; \
} while (0)
#define _PCM_WRITE_S16_BE(b8, val) do { \
*((int16_t *)(b8)) = (val); \
} while (0)
#define _PCM_WRITE_S32_BE(b8, val) do { \
*((int32_t *)(b8)) = (val); \
} while (0)
#define _PCM_READ_U16_LE(b8) \
INTPCM_T((b8)[0] | (((int8_t)((b8)[1] ^ 0x80)) << 8))
#define _PCM_READ_U32_LE(b8) \
INTPCM_T((b8)[0] | ((b8)[1] << 8) | ((b8)[2] << 16) | \
(((int8_t)((b8)[3] ^ 0x80)) << 24))
#define _PCM_READ_U16_BE(b8) \
INTPCM_T((int16_t)(*((uint16_t *)(b8)) ^ 0x8000))
#define _PCM_READ_U32_BE(b8) \
INTPCM_T((int32_t)(*((uint32_t *)(b8)) ^ 0x80000000))
#define _PCM_WRITE_U16_LE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[0] = val; \
b8[1] = (val >> 8) ^ 0x80; \
} while (0)
#define _PCM_WRITE_U32_LE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[0] = val; \
b8[1] = val >> 8; \
b8[2] = val >> 16; \
b8[3] = (val >> 24) ^ 0x80; \
} while (0)
#define _PCM_WRITE_U16_BE(b8, val) do { \
*((uint16_t *)(b8)) = (val) ^ 0x8000; \
} while (0)
#define _PCM_WRITE_U32_BE(b8, val) do { \
*((uint32_t *)(b8)) = (val) ^ 0x80000000; \
} while (0)
#define _PCM_READ_S16_NE(b8) _PCM_READ_S16_BE(b8)
#define _PCM_READ_U16_NE(b8) _PCM_READ_U16_BE(b8)
#define _PCM_READ_S32_NE(b8) _PCM_READ_S32_BE(b8)
#define _PCM_READ_U32_NE(b8) _PCM_READ_U32_BE(b8)
#define _PCM_WRITE_S16_NE(b6) _PCM_WRITE_S16_BE(b8)
#define _PCM_WRITE_U16_NE(b6) _PCM_WRITE_U16_BE(b8)
#define _PCM_WRITE_S32_NE(b6) _PCM_WRITE_S32_BE(b8)
#define _PCM_WRITE_U32_NE(b6) _PCM_WRITE_U32_BE(b8)
#endif /* LITTLE_ENDIAN */
#define _PCM_READ_S24_LE(b8) \
INTPCM_T((b8)[0] | ((b8)[1] << 8) | (((int8_t)((b8)[2])) << 16))
#define _PCM_READ_S24_BE(b8) \
INTPCM_T((b8)[2] | ((b8)[1] << 8) | (((int8_t)((b8)[0])) << 16))
#define _PCM_WRITE_S24_LE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[0] = val; \
b8[1] = val >> 8; \
b8[2] = val >> 16; \
} while (0)
#define _PCM_WRITE_S24_BE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[2] = val; \
b8[1] = val >> 8; \
b8[0] = val >> 16; \
} while (0)
#define _PCM_READ_U24_LE(b8) \
INTPCM_T((b8)[0] | ((b8)[1] << 8) | \
(((int8_t)((b8)[2] ^ 0x80)) << 16))
#define _PCM_READ_U24_BE(b8) \
INTPCM_T((b8)[2] | ((b8)[1] << 8) | \
(((int8_t)((b8)[0] ^ 0x80)) << 16))
#define _PCM_WRITE_U24_LE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[0] = val; \
b8[1] = val >> 8; \
b8[2] = (val >> 16) ^ 0x80; \
} while (0)
#define _PCM_WRITE_U24_BE(bb8, vval) do { \
intpcm_t val = (vval); \
uint8_t *b8 = (bb8); \
b8[2] = val; \
b8[1] = val >> 8; \
b8[0] = (val >> 16) ^ 0x80; \
} while (0)
#if BYTE_ORDER == LITTLE_ENDIAN
#define _PCM_READ_S24_NE(b8) _PCM_READ_S24_LE(b8)
#define _PCM_READ_U24_NE(b8) _PCM_READ_U24_LE(b8)
#define _PCM_WRITE_S24_NE(b6) _PCM_WRITE_S24_LE(b8)
#define _PCM_WRITE_U24_NE(b6) _PCM_WRITE_U24_LE(b8)
#else /* !LITTLE_ENDIAN */
#define _PCM_READ_S24_NE(b8) _PCM_READ_S24_BE(b8)
#define _PCM_READ_U24_NE(b8) _PCM_READ_U24_BE(b8)
#define _PCM_WRITE_S24_NE(b6) _PCM_WRITE_S24_BE(b8)
#define _PCM_WRITE_U24_NE(b6) _PCM_WRITE_U24_BE(b8)
#endif /* LITTLE_ENDIAN */
/*
* 8bit sample is pretty much useless since it doesn't provide
* sufficient dynamic range throughout our filtering process.
* For the sake of completeness, declare it anyway.
*/
#define _PCM_READ_S8_NE(b8) INTPCM_T(*((int8_t *)(b8)))
#define _PCM_READ_U8_NE(b8) \
INTPCM_T((int8_t)(*((uint8_t *)(b8)) ^ 0x80))
#define _PCM_WRITE_S8_NE(b8, val) do { \
*((int8_t *)(b8)) = (val); \
} while (0)
#define _PCM_WRITE_U8_NE(b8, val) do { \
*((uint8_t *)(b8)) = (val) ^ 0x80; \
} while (0)
/*
* Common macross. Use this instead of "_", unless we want
* the real sample value.
*/
/* 8bit */
#define PCM_READ_S8_NE(b8) _PCM_READ_S8_NE(b8)
#define PCM_READ_U8_NE(b8) _PCM_READ_U8_NE(b8)
#define PCM_WRITE_S8_NE(b8, val) _PCM_WRITE_S8_NE(b8, val)
#define PCM_WRITE_U8_NE(b8, val) _PCM_WRITE_U8_NE(b8, val)
/* 16bit */
#define PCM_READ_S16_LE(b8) _PCM_READ_S16_LE(b8)
#define PCM_READ_S16_BE(b8) _PCM_READ_S16_BE(b8)
#define PCM_READ_U16_LE(b8) _PCM_READ_U16_LE(b8)
#define PCM_READ_U16_BE(b8) _PCM_READ_U16_BE(b8)
#define PCM_WRITE_S16_LE(b8, val) _PCM_WRITE_S16_LE(b8, val)
#define PCM_WRITE_S16_BE(b8, val) _PCM_WRITE_S16_BE(b8, val)
#define PCM_WRITE_U16_LE(b8, val) _PCM_WRITE_U16_LE(b8, val)
#define PCM_WRITE_U16_BE(b8, val) _PCM_WRITE_U16_BE(b8, val)
#define PCM_READ_S16_NE(b8) _PCM_READ_S16_NE(b8)
#define PCM_READ_U16_NE(b8) _PCM_READ_U16_NE(b8)
#define PCM_WRITE_S16_NE(b8) _PCM_WRITE_S16_NE(b8)
#define PCM_WRITE_U16_NE(b8) _PCM_WRITE_U16_NE(b8)
/* 24bit */
#define PCM_READ_S24_LE(b8) _PCM_READ_S24_LE(b8)
#define PCM_READ_S24_BE(b8) _PCM_READ_S24_BE(b8)
#define PCM_READ_U24_LE(b8) _PCM_READ_U24_LE(b8)
#define PCM_READ_U24_BE(b8) _PCM_READ_U24_BE(b8)
#define PCM_WRITE_S24_LE(b8, val) _PCM_WRITE_S24_LE(b8, val)
#define PCM_WRITE_S24_BE(b8, val) _PCM_WRITE_S24_BE(b8, val)
#define PCM_WRITE_U24_LE(b8, val) _PCM_WRITE_U24_LE(b8, val)
#define PCM_WRITE_U24_BE(b8, val) _PCM_WRITE_U24_BE(b8, val)
#define PCM_READ_S24_NE(b8) _PCM_READ_S24_NE(b8)
#define PCM_READ_U24_NE(b8) _PCM_READ_U24_NE(b8)
#define PCM_WRITE_S24_NE(b8) _PCM_WRITE_S24_NE(b8)
#define PCM_WRITE_U24_NE(b8) _PCM_WRITE_U24_NE(b8)
/* 32bit */
#ifdef SND_PCM_64
#define PCM_READ_S32_LE(b8) _PCM_READ_S32_LE(b8)
#define PCM_READ_S32_BE(b8) _PCM_READ_S32_BE(b8)
#define PCM_READ_U32_LE(b8) _PCM_READ_U32_LE(b8)
#define PCM_READ_U32_BE(b8) _PCM_READ_U32_BE(b8)
#define PCM_WRITE_S32_LE(b8, val) _PCM_WRITE_S32_LE(b8, val)
#define PCM_WRITE_S32_BE(b8, val) _PCM_WRITE_S32_BE(b8, val)
#define PCM_WRITE_U32_LE(b8, val) _PCM_WRITE_U32_LE(b8, val)
#define PCM_WRITE_U32_BE(b8, val) _PCM_WRITE_U32_BE(b8, val)
#define PCM_READ_S32_NE(b8) _PCM_READ_S32_NE(b8)
#define PCM_READ_U32_NE(b8) _PCM_READ_U32_NE(b8)
#define PCM_WRITE_S32_NE(b8) _PCM_WRITE_S32_NE(b8)
#define PCM_WRITE_U32_NE(b8) _PCM_WRITE_U32_NE(b8)
#else /* !SND_PCM_64 */
/*
* 24bit integer ?!? This is quite unfortunate, eh? Get the fact straight:
* Dynamic range for:
* 1) Human =~ 140db
* 2) 16bit = 96db (close enough)
* 3) 24bit = 144db (perfect)
* 4) 32bit = 196db (way too much)
* 5) Bugs Bunny = Gazillion!@%$Erbzzztt-EINVAL db
* Since we're not Bugs Bunny ..uh..err.. avoiding 64bit arithmetic, 24bit
* is pretty much sufficient for our signed integer processing.
*/
#define PCM_READ_S32_LE(b8) (_PCM_READ_S32_LE(b8) >> PCM_FXSHIFT)
#define PCM_READ_S32_BE(b8) (_PCM_READ_S32_BE(b8) >> PCM_FXSHIFT)
#define PCM_READ_U32_LE(b8) (_PCM_READ_U32_LE(b8) >> PCM_FXSHIFT)
#define PCM_READ_U32_BE(b8) (_PCM_READ_U32_BE(b8) >> PCM_FXSHIFT)
#define PCM_READ_S32_NE(b8) (_PCM_READ_S32_NE(b8) >> PCM_FXSHIFT)
#define PCM_READ_U32_NE(b8) (_PCM_READ_U32_NE(b8) >> PCM_FXSHIFT)
#define PCM_WRITE_S32_LE(b8, val) \
_PCM_WRITE_S32_LE(b8, (val) << PCM_FXSHIFT)
#define PCM_WRITE_S32_BE(b8, val) \
_PCM_WRITE_S32_BE(b8, (val) << PCM_FXSHIFT)
#define PCM_WRITE_U32_LE(b8, val) \
_PCM_WRITE_U32_LE(b8, (val) << PCM_FXSHIFT)
#define PCM_WRITE_U32_BE(b8, val) \
_PCM_WRITE_U32_BE(b8, (val) << PCM_FXSHIFT)
#define PCM_WRITE_S32_NE(b8, val) \
_PCM_WRITE_S32_NE(b8, (val) << PCM_FXSHIFT)
#define PCM_WRITE_U32_NE(b8, val) \
_PCM_WRITE_U32_NE(b8, (val) << PCM_FXSHIFT)
#endif /* SND_PCM_64 */
#define PCM_CLAMP_S8(val) \
(((val) > PCM_S8_MAX) ? PCM_S8_MAX : \
(((val) < PCM_S8_MIN) ? PCM_S8_MIN : (val)))
#define PCM_CLAMP_S16(val) \
(((val) > PCM_S16_MAX) ? PCM_S16_MAX : \
(((val) < PCM_S16_MIN) ? PCM_S16_MIN : (val)))
#define PCM_CLAMP_S24(val) \
(((val) > PCM_S24_MAX) ? PCM_S24_MAX : \
(((val) < PCM_S24_MIN) ? PCM_S24_MIN : (val)))
#ifdef SND_PCM_64
#define PCM_CLAMP_S32(val) \
(((val) > PCM_S32_MAX) ? PCM_S32_MAX : \
(((val) < PCM_S32_MIN) ? PCM_S32_MIN : (val)))
#else /* !SND_PCM_64 */
#define PCM_CLAMP_S32(val) \
(((val) > PCM_S24_MAX) ? PCM_S32_MAX : \
(((val) < PCM_S24_MIN) ? PCM_S32_MIN : \
((val) << PCM_FXSHIFT)))
#endif /* SND_PCM_64 */
#define PCM_CLAMP_U8(val) PCM_CLAMP_S8(val)
#define PCM_CLAMP_U16(val) PCM_CLAMP_S16(val)
#define PCM_CLAMP_U24(val) PCM_CLAMP_S24(val)
#define PCM_CLAMP_U32(val) PCM_CLAMP_S32(val)
#endif /* !_SND_PCM_H_ */