Merge branch 'develop'

This commit is contained in:
Matthias Ringwald 2022-06-03 16:49:03 +02:00
commit 4a9eead824
450 changed files with 23380 additions and 21918 deletions

4
3rd-party/README.md vendored
View File

@ -6,8 +6,7 @@ Library
----------------------------------------------------------------------------------------------------------------|----------|---------------|------------------|----------
[Android SBC Codec](https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/embdrv/sbc) | e8c3d75b | Apache 2.0 | HFP WBS, A2DP | optimized audio codec
[hxcmod-player](https://github.com/jfdelnero/HxCModPlayer) | 03d495c8 | Public Domain | A2DP Source Demo | mod music player
[kiss-fft](https://github.com/mborgerding/kissfft) | 131.1.0 | BSD 2-Clause | LE Audio | FFT library
[EHIMA LC3 Codec](https://github.com/zephyrproject-rtos/liblc3codec) | 6e8ad0bd | Apache 2.0 | LE Audio | audio codec
[Google LC3 Codec](https://android.googlesource.com/platform/packages/modules/Bluetooth) | 49b925f1 | Apache 2.0 | LE Audio | audio codec
[lwIP](http://savannah.nongnu.org/projects/lwip/) | b3a93941 | BSD 3-Clause | PAN Demo | complete network stack
[md5](http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5) | 1.0 | Public Domain | PBAP | cryptographic hash function
[micro-ecc](https://github.com/kmackay/micro-ecc) | e4d264b5 | BSD 2-Clause | LE SC, Mesh | elliptic curve library
@ -15,3 +14,4 @@ Library
[segger-rtt](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/) | v6.20d | BSD 3-Clause | HCI PacketLog | high-speed logging with SEGGER J-Link debug probes (development)
[tinydir](https://github.com/cxong/tinydir) | 677733da | BSD 2-Clause | GAP Bonding | get a directory listing on POSIX + Windwows systems
[Yxml](https://dev.yorhel.nl/yxml) | 10f968b0 | MIT | PBAP | minimal stream XML parser

View File

@ -57,13 +57,13 @@ PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT *common,
if (filterBufferCount < SBC_CODEC_MIN_FILTER_BUFFERS) {
return OI_STATUS_OUT_OF_MEMORY;
}
common->filterBufferLen = filterBufferCount * SBC_MAX_BANDS;
common->filterBufferLen = (uint32_t) filterBufferCount * SBC_MAX_BANDS;
/* Allocate memory for the subband data */
common->subdata = (OI_INT32*)codecData;
codecData += subdataSize;
OI_ASSERT(codecDataBytes >= subdataSize);
codecDataBytes -= subdataSize;
codecDataBytes -= (uint32_t) subdataSize;
/* Allocate memory for the synthesis buffers */
for (i = 0; i < maxChannels; ++i) {
@ -71,7 +71,7 @@ PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT *common,
common->filterBuffer[i] = (SBC_BUFFER_T*)codecData;
OI_ASSERT(codecDataBytes >= allocSize);
codecData += allocSize;
codecDataBytes -= allocSize;
codecDataBytes -= (uint32_t) allocSize;
}
return OI_OK;

View File

@ -53,7 +53,7 @@ PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const * RESTRIC
/* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(26479, buffer[ 60]))>> 2;
/* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(23167, buffer[ 68]))>> 3;
/* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(8235, buffer[ 76]))>> 3;
/* 1 - stage 0 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[0<<strideShift] = (OI_INT16)pcm_b;
/* 1 - stage 0 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[(uint32_t)(0<<strideShift)] = (OI_INT16)pcm_b;
/* 1 - stage 1 */ pcm_a = 0;
/* 1 - stage 1 */ pcm_b = 0;
/* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(-3263, buffer[ 5]))>> 5;
@ -76,8 +76,8 @@ PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const * RESTRIC
/* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(685, buffer[ 69]))<< 1;
/* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(12419, buffer[ 75]))>> 4;
/* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(8721, buffer[ 75]))>> 7;
/* 1 - stage 1 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[1<<strideShift] = (OI_INT16)pcm_a;
/* 1 - stage 1 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[7<<strideShift] = (OI_INT16)pcm_b;
/* 1 - stage 1 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[(uint32_t)(1<<strideShift)] = (OI_INT16)pcm_a;
/* 1 - stage 1 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[(uint32_t)(7<<strideShift)] = (OI_INT16)pcm_b;
/* 1 - stage 2 */ pcm_a = 0;
/* 1 - stage 2 */ pcm_b = 0;
/* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(-10385, buffer[ 6]))>> 6;
@ -100,8 +100,8 @@ PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const * RESTRIC
/* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(7543, buffer[ 70]))>> 3;
/* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(9251, buffer[ 74]))>> 4;
/* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(8603, buffer[ 74]))>> 6;
/* 1 - stage 2 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[2<<strideShift] = (OI_INT16)pcm_a;
/* 1 - stage 2 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[6<<strideShift] = (OI_INT16)pcm_b;
/* 1 - stage 2 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[(uint32_t)(2<<strideShift)] = (OI_INT16)pcm_a;
/* 1 - stage 2 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[(uint32_t)(6<<strideShift)] = (OI_INT16)pcm_b;
/* 1 - stage 3 */ pcm_a = 0;
/* 1 - stage 3 */ pcm_b = 0;
/* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(-16457, buffer[ 7]))>> 6;
@ -124,13 +124,13 @@ PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const * RESTRIC
/* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(1499, buffer[ 71]))>> 1;
/* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(26913, buffer[ 73]))>> 6;
/* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(26189, buffer[ 73]))>> 7;
/* 1 - stage 3 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[3<<strideShift] = (OI_INT16)pcm_a;
/* 1 - stage 3 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[5<<strideShift] = (OI_INT16)pcm_b;
/* 1 - stage 3 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[(uint32_t)(3<<strideShift)] = (OI_INT16)pcm_a;
/* 1 - stage 3 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[(uint32_t)(5<<strideShift)] = (OI_INT16)pcm_b;
/* 1 - stage 4 */ pcm_a = 0;
/* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(10445, buffer[ 8]))>> 4;
/* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(-5297, buffer[ 24]))<< 1;
/* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(22299, buffer[ 40]))<< 2;
/* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(10603, buffer[ 56]));
/* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(9539, buffer[ 72]))>> 4;
/* 1 - stage 4 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[4<<strideShift] = (OI_INT16)pcm_a;
/* 1 - stage 4 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[(uint32_t)(4<<strideShift)] = (OI_INT16)pcm_a;
}

View File

@ -418,7 +418,7 @@ void SynthWindow40_int32_int32_symmetry_with_sum(OI_INT16 *pcm, SBC_BUFFER_T buf
pa += dec_window_4[20] * buffer[44];
pa = SCALE(-pa, 15);
CLIP_INT16(pa);
pcm[0 << strideShift] = (OI_INT16)pa;
pcm[(uint32_t)(0 << strideShift)] = (OI_INT16)pa;
pa = dec_window_4[ 1] * buffer[ 1]; pb = dec_window_4[ 1] * buffer[79];
@ -433,10 +433,10 @@ void SynthWindow40_int32_int32_symmetry_with_sum(OI_INT16 *pcm, SBC_BUFFER_T buf
pb += dec_window_4[19] * buffer[35]; pa += dec_window_4[19] * buffer[45];
pa = SCALE(-pa, 15);
CLIP_INT16(pa);
pcm[1 << strideShift] = (OI_INT16)(pa);
pcm[(uint32_t)(1 << strideShift)] = (OI_INT16)(pa);
pb = SCALE(-pb, 15);
CLIP_INT16(pb);
pcm[3 << strideShift] = (OI_INT16)(pb);
pcm[(uint32_t)(3 << strideShift)] = (OI_INT16)(pb);
pa = dec_window_4[2] * (/*buffer[ 2] + */ buffer[78]); /* buffer[ 2] is always zero */
@ -446,7 +446,7 @@ void SynthWindow40_int32_int32_symmetry_with_sum(OI_INT16 *pcm, SBC_BUFFER_T buf
pa += dec_window_4[18] * (/*buffer[34] + */ buffer[46]); /* buffer[34] is always zero */
pa = SCALE(-pa, 15);
CLIP_INT16(pa);
pcm[2 << strideShift] = (OI_INT16)(pa);
pcm[(uint32_t)(2 << strideShift)] = (OI_INT16)(pa);
}

View File

@ -234,7 +234,7 @@ void EncPacking(SBC_ENC_PARAMS *pstrEncParams)
Temp <<= s32PresentBit;
*pu8PacketPtr=Temp;
pstrEncParams->u16PacketLength=pu8PacketPtr-pstrEncParams->pu8NextPacket+1;
pstrEncParams->u16PacketLength= (uint16_t)(pu8PacketPtr-pstrEncParams->pu8NextPacket)+1;
/*find CRC*/
pu8PacketPtr = pstrEncParams->pu8NextPacket+1; /*Initialize the ptr*/
u8CRC = 0x0F;

View File

@ -1,49 +0,0 @@
*.o
*.swp
*.so
*.so.*
*.a
*.dylib
test/testcpp
test/bm_fftw_double
test/bm_fftw_float
test/bm_fftw_int16_t
test/bm_fftw_int32_t
test/bm_fftw_simd
test/bm_kiss_double
test/bm_kiss_float
test/bm_kiss_int16_t
test/bm_kiss_int32_t
test/bm_kiss_simd
test/st_double
test/st_float
test/st_int16_t
test/st_int32_t
test/st_simd
test/tkfc_double
test/tkfc_float
test/tkfc_int16_t
test/tkfc_int32_t
test/tkfc_simd
test/tr_double
test/tr_float
test/tr_int16_t
test/tr_int32_t
test/tr_simd
tools/fastconv_double
tools/fastconv_float
tools/fastconv_int16_t
tools/fastconv_int32_t
tools/fastconv_simd
tools/fastconvr_double
tools/fastconvr_float
tools/fastconvr_int16_t
tools/fastconvr_int32_t
tools/fastconvr_simd
tools/fft_double
tools/fft_float
tools/fft_int16_t
tools/fft_int32_t
tools/fft_simd
test/test_simd
build

View File

@ -1,27 +0,0 @@
language: python
python:
- "3.7"
dist: focal
before_install:
- sudo apt-get install -y libfftw3-dev
addons:
apt:
update: true
install: true
jobs:
include:
- name: "build (make)"
script:
- make all
- make testall
- name: "build (cmake)"
script:
- mkdir build && cd build
- cmake ..
- make

View File

@ -1,123 +0,0 @@
1.3.0 2012-07-18
removed non-standard malloc.h from kiss_fft.h
moved -lm to end of link line
checked various return values
converted python Numeric code to NumPy
fixed test of int32_t on 64 bit OS
added padding in a couple of places to allow SIMD alignment of structs
1.2.9 2010-05-27
threadsafe ( including OpenMP )
first edition of kissfft.hh the C++ template fft engine
1.2.8
Changed memory.h to string.h -- apparently more standard
Added openmp extensions. This can have fairly linear speedups for larger FFT sizes.
1.2.7
Shrank the real-fft memory footprint. Thanks to Galen Seitz.
1.2.6 (Nov 14, 2006) The "thanks to GenArts" release.
Added multi-dimensional real-optimized FFT, see tools/kiss_fftndr
Thanks go to GenArts, Inc. for sponsoring the development.
1.2.5 (June 27, 2006) The "release for no good reason" release.
Changed some harmless code to make some compilers' warnings go away.
Added some more digits to pi -- why not.
Added kiss_fft_next_fast_size() function to help people decide how much to pad.
Changed multidimensional test from 8 dimensions to only 3 to avoid testing
problems with fixed point (sorry Buckaroo Banzai).
1.2.4 (Oct 27, 2005) The "oops, inverse fixed point real fft was borked" release.
Fixed scaling bug for inverse fixed point real fft -- also fixed test code that should've been failing.
Thanks to Jean-Marc Valin for bug report.
Use sys/types.h for more portable types than short,int,long => int16_t,int32_t,int64_t
If your system does not have these, you may need to define them -- but at least it breaks in a
loud and easily fixable way -- unlike silently using the wrong size type.
Hopefully tools/psdpng.c is fixed -- thanks to Steve Kellog for pointing out the weirdness.
1.2.3 (June 25, 2005) The "you want to use WHAT as a sample" release.
Added ability to use 32 bit fixed point samples -- requires a 64 bit intermediate result, a la 'long long'
Added ability to do 4 FFTs in parallel by using SSE SIMD instructions. This is accomplished by
using the __m128 (vector of 4 floats) as kiss_fft_scalar. Define USE_SIMD to use this.
I know, I know ... this is drifting a bit from the "kiss" principle, but the speed advantages
make it worth it for some. Also recent gcc makes it SOO easy to use vectors of 4 floats like a POD type.
1.2.2 (May 6, 2005) The Matthew release
Replaced fixed point division with multiply&shift. Thanks to Jean-Marc Valin for
discussions regarding. Considerable speedup for fixed-point.
Corrected overflow protection in real fft routines when using fixed point.
Finder's Credit goes to Robert Oschler of robodance for pointing me at the bug.
This also led to the CHECK_OVERFLOW_OP macro.
1.2.1 (April 4, 2004)
compiles cleanly with just about every -W warning flag under the sun
reorganized kiss_fft_state so it could be read-only/const. This may be useful for embedded systems
that are willing to predeclare twiddle factors, factorization.
Fixed C_MUL,S_MUL on 16-bit platforms.
tmpbuf will only be allocated if input & output buffers are same
scratchbuf will only be allocated for ffts that are not multiples of 2,3,5
NOTE: The tmpbuf,scratchbuf changes may require synchronization code for multi-threaded apps.
1.2 (Feb 23, 2004)
interface change -- cfg object is forward declaration of struct instead of void*
This maintains type saftey and lets the compiler warn/error about stupid mistakes.
(prompted by suggestion from Erik de Castro Lopo)
small speed improvements
added psdpng.c -- sample utility that will create png spectrum "waterfalls" from an input file
( not terribly useful yet)
1.1.1 (Feb 1, 2004 )
minor bug fix -- only affects odd rank, in-place, multi-dimensional FFTs
1.1 : (Jan 30,2004)
split sample_code/ into test/ and tools/
Removed 2-D fft and added N-D fft (arbitrary)
modified fftutil.c to allow multi-d FFTs
Modified core fft routine to allow an input stride via kiss_fft_stride()
(eased support of multi-D ffts)
Added fast convolution filtering (FIR filtering using overlap-scrap method, with tail scrap)
Add kfc.[ch]: the KISS FFT Cache. It takes care of allocs for you ( suggested by Oscar Lesta ).
1.0.1 (Dec 15, 2003)
fixed bug that occurred when nfft==1. Thanks to Steven Johnson.
1.0 : (Dec 14, 2003)
changed kiss_fft function from using a single buffer, to two buffers.
If the same buffer pointer is supplied for both in and out, kiss will
manage the buffer copies.
added kiss_fft2d and kiss_fftr as separate source files (declarations in kiss_fft.h )
0.4 :(Nov 4,2003) optimized for radix 2,3,4,5
0.3 :(Oct 28, 2003) woops, version 2 didn't actually factor out any radices other than 2.
Thanks to Steven Johnson for finding this one.
0.2 :(Oct 27, 2003) added mixed radix, only radix 2,4 optimized versions
0.1 :(May 19 2003) initial release, radix 2 only

View File

@ -1,371 +0,0 @@
# Directory for easier includes
# Anywhere you see include(...) you can check <root>/cmake for that file
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
#
# Extract version from Makefile
#
file(READ Makefile _MAKEFILE_CONTENTS)
string(REGEX MATCH "KFVER_MAJOR = ([0-9]+)\n" KFVER_MAJOR_MATCH "${_MAKEFILE_CONTENTS}")
if(NOT KFVER_MAJOR_MATCH)
message(FATAL_ERROR "Cannot extract major (ABI) version from Makefile")
endif()
set(KFVER_MAJOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "KFVER_MINOR = ([0-9]+)\n" KFVER_MINOR_MATCH "${_MAKEFILE_CONTENTS}")
if(NOT KFVER_MINOR_MATCH)
message(FATAL_ERROR "Cannot extract minor version from Makefile")
endif()
set(KFVER_MINOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "KFVER_PATCH = ([0-9]+)\n" KFVER_PATCH_MATCH "${_MAKEFILE_CONTENTS}")
if(NOT KFVER_PATCH_MATCH)
message(FATAL_ERROR "Cannot extract patch version from Makefile")
endif()
set(KFVER_PATCH "${CMAKE_MATCH_1}")
set(MAKEFILE_EXTRACTED_VERSION "${KFVER_MAJOR}.${KFVER_MINOR}.${KFVER_PATCH}")
#
# Declare CMake project
#
cmake_minimum_required(VERSION 3.6)
project(kissfft VERSION "${MAKEFILE_EXTRACTED_VERSION}")
#
# CMake configuration options
#
# Principal datatype: double, float (default), int16_t, int32_t, simd
set(KISSFFT_DATATYPE "float" CACHE STRING "Principal datatype of kissfft: double, float (default), int16_t, int32_t, simd")
# Additional options
option(KISSFFT_OPENMP "Build kissfft with OpenMP support" OFF)
option(KISSFFT_PKGCONFIG "Build pkg-config files" ON)
option(KISSFFT_STATIC "Build kissfft as static (ON) or shared library (OFF)" OFF)
option(KISSFFT_TEST "Build kissfft tests" ON)
option(KISSFFT_TOOLS "Build kissfft command-line tools" ON)
option(KISSFFT_USE_ALLOCA "Use alloca instead of malloc" OFF)
#
# Validate datatype
#
if (NOT KISSFFT_DATATYPE MATCHES "^double$" AND
NOT KISSFFT_DATATYPE MATCHES "^float$" AND
NOT KISSFFT_DATATYPE MATCHES "^int16_t$" AND
NOT KISSFFT_DATATYPE MATCHES "^int32_t$" AND
NOT KISSFFT_DATATYPE MATCHES "^simd$")
message(FATAL_ERROR "Incorrect value of KISSFFT_DATATYPE! It can be one of: double, float, int16_t, int32_t, simd")
endif()
#
# Print principal datatype
#
message(STATUS "Building KissFFT with datatype: ${KISSFFT_DATATYPE}")
set(KISSFFT_OUTPUT_NAME "kissfft-${KISSFFT_DATATYPE}")
#
# Validate KISSFFT_STATIC
#
if (BUILD_SHARED_LIBS AND KISSFFT_STATIC)
message(FATAL_ERROR "Conflicting CMake configuration: -DBUILD_SHARED_LIBS=ON and -DKISSFFT_STATIC=ON")
endif()
#
# Enable BUILD_SHARED_LIBS for shared library build before
# kissfft library is declared
#
if (NOT KISSFFT_STATIC)
set(BUILD_SHARED_LIBS ON)
message(STATUS "Building shared library")
else()
message(STATUS "Building static library")
endif()
#
# Detect C compiler and pass appropriate flags
#
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
add_compile_options(-ffast-math -fomit-frame-pointer
-W -Wall -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings
"$<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes;-Wmissing-prototypes;-Wnested-externs;-Wbad-function-cast>")
endif()
#
# Add GNUInstallDirs for GNU infrastructure before target)include_directories
#
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
include(GNUInstallDirs)
endif()
#
# Declare PKGINCLUDEDIR for kissfft include path
#
set(PKGINCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/kissfft")
message(STATUS "PKGINCLUDEDIR is ${PKGINCLUDEDIR}")
#
# Declare kissfft library ( libkissfft.a / libkissfft-${KISSFFT_DATATYPE}.so.${MAKEFILE_EXTRACTED_VERSION} )
#
add_library(kissfft
kiss_fft.c
kfc.c
kiss_fftnd.c
kiss_fftndr.c
kiss_fftr.c)
target_include_directories(kissfft PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${PKGINCLUDEDIR}>)
#
# Set compile definitions based on datatype and additional support flags
#
set(KISSFFT_COMPILE_DEFINITIONS)
#
# double / float
#
if(KISSFFT_DATATYPE MATCHES "^float$" OR KISSFFT_DATATYPE MATCHES "^double$")
list(APPEND KISSFFT_COMPILE_DEFINITIONS kiss_fft_scalar=${KISSFFT_DATATYPE})
else()
#
# int16_t
#
if(KISSFFT_DATATYPE MATCHES "^int16_t$")
list(APPEND KISSFFT_COMPILE_DEFINITIONS FIXED_POINT=16)
else()
#
# int32_t
#
if(KISSFFT_DATATYPE MATCHES "^int32_t$")
list(APPEND KISSFFT_COMPILE_DEFINITIONS FIXED_POINT=32)
else()
#
# simd
#
if(KISSFFT_DATATYPE MATCHES "^simd$")
list(APPEND KISSFFT_COMPILE_DEFINITIONS USE_SIMD)
if (NOT MSVC)
target_compile_options(kissfft PRIVATE -msse)
else()
target_compile_options(kissfft PRIVATE "/arch:SSE")
endif()
endif()
endif()
endif()
endif()
#
# OpenMP support
#
if(KISSFFT_OPENMP)
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
if (NOT MSVC)
target_compile_options(kissfft PRIVATE -fopenmp)
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
target_link_libraries(kissfft PRIVATE "-fopenmp")
else()
target_link_options(kissfft PRIVATE -fopenmp)
endif()
else()
target_compile_options(kissfft PRIVATE "/openmp")
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
target_link_libraries(kissfft PRIVATE "/openmp")
else()
target_link_options(kissfft PRIVATE "/openmp")
endif()
endif()
set(KISSFFT_EXPORT_SUFFIX "-openmp")
set(KISSFFT_OUTPUT_NAME "kissfft-${KISSFFT_DATATYPE}-openmp")
else()
message(FATAL_ERROR "Don't know how to enable OpenMP for this compiler")
endif()
endif()
#
# Shared / static library
#
if(NOT KISSFFT_STATIC)
list(APPEND KISSFFT_COMPILE_DEFINITIONS KISS_FFT_SHARED)
set_target_properties(kissfft PROPERTIES
C_VISIBILITY_PRESET hidden)
set(KISSFFT_EXPORT_SUFFIX "${KISSFFT_EXPORT_SUFFIX}-shared")
else()
set(KISSFFT_EXPORT_SUFFIX "${KISSFFT_EXPORT_SUFFIX}-static")
endif()
#
# Alloca support
#
if(KISSFFT_USE_ALLOCA)
list(APPEND KISSFFT_COMPILE_DEFINITIONS KISS_FFT_USE_ALLOCA)
endif()
# Set library name, version, soversion and aliases
target_compile_definitions(kissfft PUBLIC ${KISSFFT_COMPILE_DEFINITIONS})
set_target_properties(kissfft PROPERTIES
OUTPUT_NAME "${KISSFFT_OUTPUT_NAME}"
DEFINE_SYMBOL KISS_FFT_BUILD
EXPORT_NAME "${KISSFFT_OUTPUT_NAME}"
VERSION ${PROJECT_VERSION}
SOVERSION ${KFVER_MAJOR})
add_library(kissfft::kissfft ALIAS kissfft)
add_library(kissfft::kissfft-${KISSFFT_DATATYPE} ALIAS kissfft)
#
# Build with libm (-lm) on Linux and kFreeBSD
#
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
target_link_libraries(kissfft PRIVATE m)
endif()
#
# Define a helper function to define executable file
#
function(add_kissfft_executable NAME)
add_executable(${NAME} ${ARGN})
target_link_libraries(${NAME} PRIVATE kissfft::kissfft)
#
# Build with libm (-lm) on Linux and kFreeBSD
#
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
target_link_libraries(${NAME} PRIVATE m)
endif()
if (NOT KISSFFT_OPENMP)
set_target_properties(${NAME} PROPERTIES
OUTPUT_NAME "${NAME}-${KISSFFT_DATATYPE}")
else()
if (NOT MSVC)
target_compile_options(${NAME} PRIVATE -fopenmp)
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
target_link_libraries(${NAME} PRIVATE "-fopenmp")
else()
target_link_options(${NAME} PRIVATE -fopenmp)
endif()
else()
target_compile_options(${NAME} PRIVATE "/openmp")
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
target_link_libraries(${NAME} PRIVATE "/openmp")
else()
target_link_options(${NAME} PRIVATE "/openmp")
endif()
endif()
set_target_properties(${NAME} PROPERTIES
OUTPUT_NAME "${NAME}-${KISSFFT_DATATYPE}-openmp")
endif()
endfunction()
#
# Perform installation of kissfft library and development files
#
install(TARGETS kissfft EXPORT kissfft
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(FILES kiss_fft.h
kissfft.hh
kiss_fftnd.h
kiss_fftndr.h
kiss_fftr.h
DESTINATION "${PKGINCLUDEDIR}")
set(KISSFFT_INSTALL_CMAKE "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
CACHE FILEPATH "Install destination of kissfft cmake modules")
mark_as_advanced(KISSFFT_INSTALL_CMAKE)
install(EXPORT kissfft DESTINATION "${KISSFFT_INSTALL_CMAKE}"
NAMESPACE "kissfft::"
FILE "${PROJECT_NAME}-${KISSFFT_DATATYPE}${KISSFFT_EXPORT_SUFFIX}-targets.cmake")
include(CMakePackageConfigHelpers)
configure_package_config_file(kissfft-config.cmake.in kissfft-config.cmake
INSTALL_DESTINATION "${KISSFFT_INSTALL_CMAKE}")
write_basic_package_version_file(kissfft-config-version.cmake COMPATIBILITY AnyNewerVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kissfft-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/kissfft-config-version.cmake"
DESTINATION "${KISSFFT_INSTALL_CMAKE}")
set(PKG_KISSFFT_DEFS)
foreach(_def ${KISSFFT_COMPILE_DEFINITIONS})
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} -D${_def}")
endforeach()
if (KISSFFT_PKGCONFIG)
include(JoinPaths)
set(PKGCONFIG_KISSFFT_PKGINCLUDEDIR "\${includedir}/kissfft")
set(PKGCONFIG_KISSFFT_PREFIX "${CMAKE_INSTALL_PREFIX}")
set(PKGCONFIG_KISSFFT_VERSION "${kissfft_VERSION}")
join_paths(PKGCONFIG_KISSFFT_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
join_paths(PKGCONFIG_KISSFFT_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
if(KISSFFT_DATATYPE MATCHES "^simd$")
list(APPEND KISSFFT_COMPILE_DEFINITIONS USE_SIMD)
if (NOT MSVC)
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} -msse")
else()
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} /ARCH:SSE")
endif()
endif()
if (NOT KISSFFT_OPENMP)
configure_file(kissfft.pc.in "kissfft-${KISSFFT_DATATYPE}.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kissfft-${KISSFFT_DATATYPE}.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
else()
if (NOT MSVC)
set(PKG_OPENMP "-fopenmp")
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} -fopenmp")
else()
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} /openmp")
set(PKG_OPENMP "/openmp")
endif()
configure_file(kissfft.pc.in "kissfft-${KISSFFT_DATATYPE}-openmp.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kissfft-${KISSFFT_DATATYPE}-openmp.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
endif()
#
# Build and install tools if requested by user
#
if(KISSFFT_TOOLS)
add_subdirectory(tools)
endif()
#
# Build and run tests if requested by user
#
if(KISSFFT_TEST)
enable_testing()
add_subdirectory(test)
endif()

View File

@ -1,11 +0,0 @@
Copyright (c) 2003-2010 Mark Borgerding . All rights reserved.
KISS FFT is provided under:
SPDX-License-Identifier: BSD-3-Clause
Being under the terms of the BSD 3-clause "New" or "Revised" License,
according with:
LICENSES/BSD-3-Clause

View File

@ -1,35 +0,0 @@
Valid-License-Identifier: BSD-3-Clause
SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html
Usage-Guide:
To use the BSD 3-clause "New" or "Revised" License put the following SPDX
tag/value pair into a comment according to the placement guidelines in
the licensing rules documentation:
SPDX-License-Identifier: BSD-3-Clause
License-Text:
Copyright (c) <year> <owner> . 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.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.

View File

@ -1,30 +0,0 @@
Valid-License-Identifier: Unlicense
SPDX-URL: https://spdx.org/licenses/Unlicense.html
Usage-Guide:
To use the Unlicense put the following SPDX tag/value pair into a
comment according to the placement guidelines in the licensing rules
documentation:
SPDX-License-Identifier: Unlicense
License-Text:
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute
this software, either in source code form or as a compiled binary, for any
purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and
to the detriment of our heirs and successors. We intend this dedication to be
an overt act of relinquishment in perpetuity of all present and future rights
to this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View File

@ -1,323 +0,0 @@
#
# Semantic versioning
#
# KFVER_MAJOR denotes the ABI version.
#
# - It must be bumped only if API public members are removed or
# changed in the incompatible
#
# KFVER_MINOR denotes the minor version within a compatible ABI.
#
# - It should be bumped if new API public members are added
# (but not removed!) so programs linked against the same library
# version continue operating properly
#
# KFVER_PATCH denotes bugfix count since the last minor update.
#
# - It should be bumped whenever a bug fix is pushed.
#
export KFVER_MAJOR = 131
export KFVER_MINOR = 1
export KFVER_PATCH = 0
#
# Data type (float / int16_t / int32_t / simd)
#
export KISSFFT_DATATYPE ?= float
#
# Default options
#
export KISSFFT_OPENMP ?= 0
export KISSFFT_STATIC ?= 0
export KISSFFT_TOOLS ?= 1
export KISSFFT_USE_ALLOCA ?= 0
#
# Installation directories
#
PREFIX ?= /usr/local
export ABS_PREFIX = $(abspath $(PREFIX))
BINDIR ?= $(ABS_PREFIX)/bin
export ABS_BINDIR = $(abspath $(BINDIR))
INCLUDEDIR ?= $(ABS_PREFIX)/include
export ABS_INCLUDEDIR = $(abspath $(INCLUDEDIR))
export ABS_PKGINCLUDEDIR = $(ABS_INCLUDEDIR)/kissfft
#
# Override LIBDIR with lib64 following CMake's
# GNUInstallDirs logic:
#
CANDIDATE_LIBDIR_NAME = lib
ifneq ($(MAKECMDGOALS),clean)
ifeq ($(shell uname -s),Linux)
_UNAME_ARCH = $(shell uname -i)
ifeq (,$(_UNAME_ARCH))
_UNAME_ARCH = $(shell uname -m)
ifeq (,$(_UNAME_ARCH))
$(warning WARNING: Can not detect system architecture!)
endif
endif
ifeq ($(_UNAME_ARCH),x86_64)
CANDIDATE_LIBDIR_NAME = lib64
endif
endif
endif
CANDIDATE_LIBDIR = $(PREFIX)/$(CANDIDATE_LIBDIR_NAME)
LIBDIR ?= $(CANDIDATE_LIBDIR)
export ABS_LIBDIR = $(abspath $(LIBDIR))
export INSTALL ?= install
#
# Library name and version
#
ifeq ($(KISSFFT_OPENMP), 1)
KISSFFTLIB_SHORTNAME = kissfft-$(KISSFFT_DATATYPE)-openmp
KISSFFT_PKGCONFIG = kissfft-$(KISSFFT_DATATYPE)-openmp.pc
KISSFFTLIB_FLAGS = -fopenmp
TYPEFLAGS = -fopenmp
PKGCONFIG_OPENMP = -fopenmp
else
KISSFFTLIB_SHORTNAME = kissfft-$(KISSFFT_DATATYPE)
KISSFFT_PKGCONFIG = kissfft-$(KISSFFT_DATATYPE).pc
TYPEFLAGS =
PKGCONFIG_OPENMP =
endif
ifeq ($(KISSFFT_STATIC), 1)
KISSFFTLIB_NAME = lib$(KISSFFTLIB_SHORTNAME).a
KISSFFTLIB_FLAGS += -static
else ifeq ($(shell uname -s),Darwin)
KISSFFTLIB_NAME = lib$(KISSFFTLIB_SHORTNAME).dylib
KISSFFTLIB_FLAGS += -shared -Wl,-install_name,$(KISSFFTLIB_NAME)
else
KISSFFTLIB_SODEVELNAME = lib$(KISSFFTLIB_SHORTNAME).so
KISSFFTLIB_SONAME = $(KISSFFTLIB_SODEVELNAME).$(KFVER_MAJOR)
KISSFFTLIB_NAME = $(KISSFFTLIB_SONAME).$(KFVER_MINOR).$(KFVER_PATCH)
KISSFFTLIB_FLAGS += -shared -Wl,-soname,$(KISSFFTLIB_SONAME)
endif
export KISSFFTLIB_SHORTNAME
#
# Compile-time definitions by datatype
#
#
# Note: -DKISS_FFT_BUILD and -DKISS_FFT_SHARED control
# C symbol visibility.
#
ifeq "$(KISSFFT_DATATYPE)" "int32_t"
TYPEFLAGS += -DFIXED_POINT=32
else ifeq "$(KISSFFT_DATATYPE)" "int16_t"
TYPEFLAGS += -DFIXED_POINT=16
else ifeq "$(KISSFFT_DATATYPE)" "simd"
TYPEFLAGS += -DUSE_SIMD=1 -msse
else ifeq "$(KISSFFT_DATATYPE)" "float"
TYPEFLAGS += -Dkiss_fft_scalar=$(KISSFFT_DATATYPE)
else ifeq "$(KISSFFT_DATATYPE)" "double"
TYPEFLAGS += -Dkiss_fft_scalar=$(KISSFFT_DATATYPE)
else
$(error ERROR: KISSFFT_DATATYPE must be one of: float double int16_t int32_t simd)
endif
ifneq ($(KISSFFT_STATIC), 1)
TYPEFLAGS += -DKISS_FFT_SHARED
endif
ifeq ($(KISSFFT_USE_ALLOCA), 1)
TYPEFLAGS += -DKISS_FFT_USE_ALLOCA=1
endif
#
# Compile-time definitions
#
#
# Save pkgconfig variables before appending
# -DKISS_FFT_BUILD to TYPEFLAGS
#
ifneq ($(shell uname -s),Darwin)
PKGCONFIG_KISSFFT_VERSION = $(KFVER_MAJOR).$(KFVER_MINOR).$(KFVER_PATCH)
PKGCONFIG_KISSFFT_OUTPUT_NAME = $(KISSFFTLIB_SHORTNAME)
PKGCONFIG_PKG_KISSFFT_DEFS = $(TYPEFLAGS)
PKGCONFIG_KISSFFT_PREFIX = $(ABS_PREFIX)
ifeq ($(ABS_INCLUDEDIR),$(ABS_PREFIX)/include)
PKGCONFIG_KISSFFT_INCLUDEDIR = $${prefix}/include
else
PKGCONFIG_KISSFFT_INCLUDEDIR = $(ABS_INCLUDEDIR)
endif
ifeq ($(ABS_LIBDIR),$(ABS_PREFIX)/$(CANDIDATE_LIBDIR_NAME))
PKGCONFIG_KISSFFT_LIBDIR = $${prefix}/$(CANDIDATE_LIBDIR_NAME)
else
PKGCONFIG_KISSFFT_LIBDIR = $(ABS_LIBDIR)
endif
PKGCONFIG_KISSFFT_PKGINCLUDEDIR = $${includedir}/kissfft
endif
export TYPEFLAGS
# Compile .c into .o
#
#
# -DKISS_FFT_BUILD is used for library artifacts, so
# consumer executable in 'test' and 'tools' do _NOT_
# need it. pkg-config output does not need it either.
#
%.c.o: %.c
$(CC) -Wall -fPIC \
-o $@ \
$(CFLAGS) $(TYPEFLAGS) -DKISS_FFT_BUILD \
-c $<
#
# Target: "make all"
#
all: kfc.c.o kiss_fft.c.o kiss_fftnd.c.o kiss_fftndr.c.o kiss_fftr.c.o
ifneq ($(KISSFFT_STATIC), 1)
$(CC) $(KISSFFTLIB_FLAGS) -o $(KISSFFTLIB_NAME) $^
ifneq ($(shell uname -s),Darwin)
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SONAME)
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SODEVELNAME)
endif
else
$(AR) crus $(KISSFFTLIB_NAME) $^
endif
ifneq ($(KISSFFT_TOOLS), 0)
make -C tools CFLAGADD="$(CFLAGADD)" all
endif
#
# Target: "make install"
#
install: all
$(INSTALL) -Dt $(ABS_PKGINCLUDEDIR) -m 644 \
kiss_fft.h \
kissfft.hh \
kiss_fftnd.h \
kiss_fftndr.h \
kiss_fftr.h
$(INSTALL) -Dt $(ABS_LIBDIR) -m 644 $(KISSFFTLIB_NAME)
ifneq ($(KISSFFT_STATIC), 1)
ifneq ($(shell uname -s),Darwin)
cd $(LIBDIR) && \
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SONAME) && \
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SODEVELNAME)
endif
endif
ifneq ($(shell uname -s),Darwin)
mkdir "$(ABS_LIBDIR)/pkgconfig"
sed \
-e 's+@PKGCONFIG_KISSFFT_VERSION@+$(PKGCONFIG_KISSFFT_VERSION)+' \
-e 's+@KISSFFT_OUTPUT_NAME@+$(PKGCONFIG_KISSFFT_OUTPUT_NAME)+' \
-e 's+@PKG_KISSFFT_DEFS@+$(PKGCONFIG_PKG_KISSFFT_DEFS)+' \
-e 's+@PKG_OPENMP@+$(PKGCONFIG_OPENMP)+' \
-e 's+@PKGCONFIG_KISSFFT_PREFIX@+$(PKGCONFIG_KISSFFT_PREFIX)+' \
-e 's+@PKGCONFIG_KISSFFT_INCLUDEDIR@+$(PKGCONFIG_KISSFFT_INCLUDEDIR)+' \
-e 's+@PKGCONFIG_KISSFFT_LIBDIR@+$(PKGCONFIG_KISSFFT_LIBDIR)+' \
-e 's+@PKGCONFIG_KISSFFT_PKGINCLUDEDIR@+$(PKGCONFIG_KISSFFT_PKGINCLUDEDIR)+' \
kissfft.pc.in 1>"$(ABS_LIBDIR)/pkgconfig/$(KISSFFT_PKGCONFIG)"
endif
ifneq ($(KISSFFT_TOOLS), 0)
make -C tools install
endif
#
# Target: "make doc"
#
doc:
$(warning Start by reading the README file. If you want to build and test lots of stuff, do a 'make testall')
$(warning but be aware that 'make testall' has dependencies that the basic kissfft software does not.)
$(warning It is generally unneeded to run these tests yourself, unless you plan on changing the inner workings)
$(warning of kissfft and would like to make use of its regression tests.)
#
# Target: "make testsingle"
#
testsingle:
make clean
make all
make -C test CFLAGADD="$(CFLAGADD)" test testcpp
#
# Target: "make testall"
#
testall:
# Shared libraries
make KISSFFT_DATATYPE=double testsingle
make KISSFFT_DATATYPE=float testsingle
make KISSFFT_DATATYPE=int16_t testsingle
# The simd and int32_t types may or may not work on your machine
make KISSFFT_DATATYPE=int32_t testsingle
make KISSFFT_DATATYPE=simd testsingle
# Static libraries
make KISSFFT_DATATYPE=double KISSFFT_STATIC=1 testsingle
make KISSFFT_DATATYPE=float KISSFFT_STATIC=1 testsingle
make KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 testsingle
# The simd and int32_t types may or may not work on your machine
make KISSFFT_DATATYPE=int32_t KISSFFT_STATIC=1 testsingle
make KISSFFT_DATATYPE=simd KISSFFT_STATIC=1 testsingle
# OpenMP libraries
make KISSFFT_DATATYPE=double KISSFFT_OPENMP=1 testsingle
make KISSFFT_DATATYPE=float KISSFFT_OPENMP=1 testsingle
make KISSFFT_DATATYPE=int16_t KISSFFT_OPENMP=1 testsingle
# The simd and int32_t types may or may not work on your machine
make KISSFFT_DATATYPE=int32_t KISSFFT_OPENMP=1 testsingle
make KISSFFT_DATATYPE=simd KISSFFT_OPENMP=1 testsingle
$(warning All tests passed!)
#
# Target: "make tarball"
#
tarball: clean
git archive --prefix=kissfft/ -o kissfft$(KFVER).tar.gz v$(KFVER)
git archive --prefix=kissfft/ -o kissfft$(KFVER).zip v$(KFVER)
#
# Target: "make clean"
#
clean:
rm -f *.o *.a *.so *.so.*
cd test && make clean
cd tools && make clean
rm -f kiss_fft*.tar.gz *~ *.pyc kiss_fft*.zip
#
# Target: "make asm"
#
asm: kiss_fft.s
# TODO: Sort out if we should add kfc / other C headers
kiss_fft.s: kiss_fft.c kiss_fft.h _kiss_fft_guts.h
[ -e kiss_fft.s ] && mv kiss_fft.s kiss_fft.s~ || true
$(CC) -S kiss_fft.c -O3 -mtune=native -ffast-math -fomit-frame-pointer -unroll-loops -dA -fverbose-asm
$(CC) -o kiss_fft_short.s -S kiss_fft.c -O3 -mtune=native -ffast-math -fomit-frame-pointer -dA -fverbose-asm -DFIXED_POINT
[ -e kiss_fft.s~ ] && diff kiss_fft.s~ kiss_fft.s || true

View File

@ -1,245 +0,0 @@
# KISS FFT [![Build Status](https://travis-ci.com/mborgerding/kissfft.svg?branch=master)](https://travis-ci.com/mborgerding/kissfft)
KISS FFT - A mixed-radix Fast Fourier Transform based up on the principle,
"Keep It Simple, Stupid."
There are many great fft libraries already around. Kiss FFT is not trying
to be better than any of them. It only attempts to be a reasonably efficient,
moderately useful FFT that can use fixed or floating data types and can be
incorporated into someone's C program in a few minutes with trivial licensing.
## USAGE:
The basic usage for 1-d complex FFT is:
```c
#include "kiss_fft.h"
kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 );
while ...
... // put kth sample in cx_in[k].r and cx_in[k].i
kiss_fft( cfg , cx_in , cx_out );
... // transformed. DC is in cx_out[0].r and cx_out[0].i
kiss_fft_free(cfg);
```
- **Note**: frequency-domain data is stored from dc up to 2pi.
so cx_out[0] is the dc bin of the FFT
and cx_out[nfft/2] is the Nyquist bin (if exists)
Declarations are in "kiss_fft.h", along with a brief description of the
functions you'll need to use.
Code definitions for 1d complex FFTs are in kiss_fft.c.
You can do other cool stuff with the extras you'll find in tools/
> - multi-dimensional FFTs
> - real-optimized FFTs (returns the positive half-spectrum:
(nfft/2+1) complex frequency bins)
> - fast convolution FIR filtering (not available for fixed point)
> - spectrum image creation
The core fft and most tools/ code can be compiled to use float, double,
Q15 short or Q31 samples. The default is float.
## BUILDING:
There are two functionally-equivalent build systems supported by kissfft:
- Make (traditional Makefiles for Unix / Linux systems)
- CMake (more modern and feature-rich build system developed by Kitware)
To build kissfft, the following build environment can be used:
- GNU build environment with GCC, Clang and GNU Make or CMake (>= 3.6)
- Microsoft Visual C++ (MSVC) with CMake (>= 3.6)
Additional libraries required to build and test kissfft include:
- libpng for psdpng tool,
- libfftw3 to validate kissfft results against it,
- python 2/3 with Numpy to validate kissfft results against it.
- OpenMP supported by GCC, Clang or MSVC for multi-core FFT transformations
Environments like Cygwin and MinGW can be highly likely used to build kissfft
targeting Windows platform, but no tests were performed to the date.
Both Make and CMake builds are easily configurable:
- `KISSFFT_DATATYPE=<datatype>` (for Make) or `-DKISSFFT_DATATYPE=<datatype>`
(for CMake) denote the principal datatype used by kissfft. It can be one
of the following:
- float (default)
- double
- int16_t
- int32_t
- SIMD (requires SSE instruction set support on target CPU)
- `KISSFFT_OPENMP=1` (for Make) or `-DKISSFFT_OPENMP=ON` (for CMake) builds kissfft
with OpenMP support. Please note that a supported compiler is required and this
option is turned off by default.
- `KISSFFT_STATIC=1` (for Make) or `-DKISSFFT_STATIC=ON` (for CMake) instructs
the builder to create static library ('.lib' for Windows / '.a' for Unix or Linux).
By default, this option is turned off and the shared library is created
('.dll' for Windows, '.so' for Linux or Unix, '.dylib' for Mac OSX)
- `-DKISSFFT_TEST=OFF` (for CMake) disables building tests for kissfft. On Make,
building tests is done separately by 'make testall' or 'make testsingle', so
no specific setting is required.
- `KISSFFT_TOOLS=0` (for Make) or `-DKISSFFT_TOOLS=OFF` (for CMake) builds kissfft
without command-line tools like 'fastconv'. By default the tools are built.
- `KISSFFT_USE_ALLOCA=1` (for Make) or `-DKISSFFT_USE_ALLOCA=ON` (for CMake)
build kissfft with 'alloca' usage instead of 'malloc' / 'free'.
- `PREFIX=/full/path/to/installation/prefix/directory` (for Make) or
`-DCMAKE_INSTALL_PREFIX=/full/path/to/installation/prefix/directory` (for CMake)
specifies the prefix directory to install kissfft into.
For example, to build kissfft as a static library with 'int16_t' datatype and
OpenMP support using Make, run the command from kissfft source tree:
```
make KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 KISSFFT_OPENMP=1 all
```
The same configuration for CMake is:
```
mkdir build && cd build
cmake -DKISSFFT_DATATYPE=int16_t -DKISSFFT_STATIC=ON -DKISSFFT_OPENMP=ON ..
make all
```
To specify '/tmp/1234' as installation prefix directory, run:
```
make PREFIX=/tmp/1234 KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 KISSFFT_OPENMP=1 install
```
or
```
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/tmp/1234 -DKISSFFT_DATATYPE=int16_t -DKISSFFT_STATIC=ON -DKISSFFT_OPENMP=ON ..
make all
make install
```
## TESTING:
To validate the build configured as an example above, run the following command from
kissfft source tree:
```
make KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 KISSFFT_OPENMP=1 testsingle
```
if using Make, or:
```
make test
```
if using CMake.
To test all possible build configurations, please run an extended testsuite from
kissfft source tree:
```
sh test/kissfft-testsuite.sh
```
Please note that the extended testsuite takes around 20-40 minutes depending on device
it runs on. This testsuite is useful for reporting bugs or testing the pull requests.
## BACKGROUND
I started coding this because I couldn't find a fixed point FFT that didn't
use assembly code. I started with floating point numbers so I could get the
theory straight before working on fixed point issues. In the end, I had a
little bit of code that could be recompiled easily to do ffts with short, float
or double (other types should be easy too).
Once I got my FFT working, I was curious about the speed compared to
a well respected and highly optimized fft library. I don't want to criticize
this great library, so let's call it FFT_BRANDX.
During this process, I learned:
> 1. FFT_BRANDX has more than 100K lines of code. The core of kiss_fft is about 500 lines (cpx 1-d).
> 2. It took me an embarrassingly long time to get FFT_BRANDX working.
> 3. A simple program using FFT_BRANDX is 522KB. A similar program using kiss_fft is 18KB (without optimizing for size).
> 4. FFT_BRANDX is roughly twice as fast as KISS FFT in default mode.
It is wonderful that free, highly optimized libraries like FFT_BRANDX exist.
But such libraries carry a huge burden of complexity necessary to extract every
last bit of performance.
**Sometimes simpler is better, even if it's not better.**
## FREQUENTLY ASKED QUESTIONS:
> Q: Can I use kissfft in a project with a ___ license?</br>
> A: Yes. See LICENSE below.
> Q: Why don't I get the output I expect?</br>
> A: The two most common causes of this are
> 1) scaling : is there a constant multiplier between what you got and what you want?
> 2) mixed build environment -- all code must be compiled with same preprocessor
> definitions for FIXED_POINT and kiss_fft_scalar
> Q: Will you write/debug my code for me?</br>
> A: Probably not unless you pay me. I am happy to answer pointed and topical questions, but
> I may refer you to a book, a forum, or some other resource.
## PERFORMANCE
(on Athlon XP 2100+, with gcc 2.96, float data type)
Kiss performed 10000 1024-pt cpx ffts in .63 s of cpu time.
For comparison, it took md5sum twice as long to process the same amount of data.
Transforming 5 minutes of CD quality audio takes less than a second (nfft=1024).
**DO NOT:**
- use Kiss if you need the Fastest Fourier Transform in the World
- ask me to add features that will bloat the code
## UNDER THE HOOD
Kiss FFT uses a time decimation, mixed-radix, out-of-place FFT. If you give it an input buffer
and output buffer that are the same, a temporary buffer will be created to hold the data.
No static data is used. The core routines of kiss_fft are thread-safe (but not all of the tools directory).[
No scaling is done for the floating point version (for speed).
Scaling is done both ways for the fixed-point version (for overflow prevention).
Optimized butterflies are used for factors 2,3,4, and 5.
The real (i.e. not complex) optimization code only works for even length ffts. It does two half-length
FFTs in parallel (packed into real&imag), and then combines them via twiddling. The result is
nfft/2+1 complex frequency bins from DC to Nyquist. If you don't know what this means, search the web.
The fast convolution filtering uses the overlap-scrap method, slightly
modified to put the scrap at the tail.
## LICENSE
Revised BSD License, see COPYING for verbiage.
Basically, "free to use&change, give credit where due, no guarantees"
Note this license is compatible with GPL at one end of the spectrum and closed, commercial software at
the other end. See http://www.fsf.org/licensing/licenses
## TODO
- Add real optimization for odd length FFTs
- Document/revisit the input/output fft scaling
- Make doc describing the overlap (tail) scrap fast convolution filtering in kiss_fastfir.c
- Test all the ./tools/ code with fixed point (kiss_fastfir.c doesn't work, maybe others)
## AUTHOR
Mark Borgerding
Mark@Borgerding.net

View File

@ -1,78 +0,0 @@
If you are reading this, it means you think you may be interested in using the SIMD extensions in kissfft
to do 4 *separate* FFTs at once.
Beware! Beyond here there be dragons!
This API is not easy to use, is not well documented, and breaks the KISS principle.
Still reading? Okay, you may get rewarded for your patience with a considerable speedup
(2-3x) on intel x86 machines with SSE if you are willing to jump through some hoops.
The basic idea is to use the packed 4 float __m128 data type as a scalar element.
This means that the format is pretty convoluted. It performs 4 FFTs per fft call on signals A,B,C,D.
For complex data, the data is interlaced as follows:
rA0,rB0,rC0,rD0, iA0,iB0,iC0,iD0, rA1,rB1,rC1,rD1, iA1,iB1,iC1,iD1 ...
where "rA0" is the real part of the zeroth sample for signal A
Real-only data is laid out:
rA0,rB0,rC0,rD0, rA1,rB1,rC1,rD1, ...
Compile with gcc flags something like
-O3 -mpreferred-stack-boundary=4 -DUSE_SIMD=1 -msse
Be aware of SIMD alignment. This is the most likely cause of segfaults.
The code within kissfft uses scratch variables on the stack.
With SIMD, these must have addresses on 16 byte boundaries.
Search on "SIMD alignment" for more info.
Robin at Divide Concept was kind enough to share his code for formatting to/from the SIMD kissfft.
I have not run it -- use it at your own risk. It appears to do 4xN and Nx4 transpositions
(out of place).
void SSETools::pack128(float* target, float* source, unsigned long size128)
{
__m128* pDest = (__m128*)target;
__m128* pDestEnd = pDest+size128;
float* source0=source;
float* source1=source0+size128;
float* source2=source1+size128;
float* source3=source2+size128;
while(pDest<pDestEnd)
{
*pDest=_mm_set_ps(*source3,*source2,*source1,*source0);
source0++;
source1++;
source2++;
source3++;
pDest++;
}
}
void SSETools::unpack128(float* target, float* source, unsigned long size128)
{
float* pSrc = source;
float* pSrcEnd = pSrc+size128*4;
float* target0=target;
float* target1=target0+size128;
float* target2=target1+size128;
float* target3=target2+size128;
while(pSrc<pSrcEnd)
{
*target0=pSrc[0];
*target1=pSrc[1];
*target2=pSrc[2];
*target3=pSrc[3];
target0++;
target1++;
target2++;
target3++;
pSrc+=4;
}
}

View File

@ -1,39 +0,0 @@
Speed:
* If you want to use multiple cores, then compile with -openmp or -fopenmp (see your compiler docs).
Realize that larger FFTs will reap more benefit than smaller FFTs. This generally uses more CPU time, but
less wall time.
* experiment with compiler flags
Special thanks to Oscar Lesta. He suggested some compiler flags
for gcc that make a big difference. They shave 10-15% off
execution time on some systems. Try some combination of:
-march=pentiumpro
-ffast-math
-fomit-frame-pointer
* If the input data has no imaginary component, use the kiss_fftr code under tools/.
Real ffts are roughly twice as fast as complex.
* If you can rearrange your code to do 4 FFTs in parallel and you are on a recent Intel or AMD machine,
then you might want to experiment with the USE_SIMD code. See README.simd
Reducing code size:
* remove some of the butterflies. There are currently butterflies optimized for radices
2,3,4,5. It is worth mentioning that you can still use FFT sizes that contain
other factors, they just won't be quite as fast. You can decide for yourself
whether to keep radix 2 or 4. If you do some work in this area, let me
know what you find.
* For platforms where ROM/code space is more plentiful than RAM,
consider creating a hardcoded kiss_fft_state. In other words, decide which
FFT size(s) you want and make a structure with the correct factors and twiddles.
* Frank van der Hulst offered numerous suggestions for smaller code size and correct operation
on embedded targets. "I'm happy to help anyone who is trying to implement KISSFFT on a micro"
Some of these were rolled into the mainline code base:
- using long casts to promote intermediate results of short*short multiplication
- delaying allocation of buffers that are sometimes unused.
In some cases, it may be desirable to limit capability in order to better suit the target:
- predefining the twiddle tables for the desired fft size.

View File

@ -1,167 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
/* kiss_fft.h
defines kiss_fft_scalar as either short or a float type
and defines
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
#ifndef _kiss_fft_guts_h
#define _kiss_fft_guts_h
#include "kiss_fft.h"
#include "kiss_fft_log.h"
#include <limits.h>
#define MAXFACTORS 32
/* e.g. an fft of length 128 has 4 factors
as far as kissfft is concerned
4*4*4*2
*/
struct kiss_fft_state{
int nfft;
int inverse;
int factors[2*MAXFACTORS];
kiss_fft_cpx twiddles[1];
};
/*
Explanation of macros dealing with complex math:
C_MUL(m,a,b) : m = a*b
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
C_SUB( res, a,b) : res = a - b
C_SUBFROM( res , a) : res -= a
C_ADDTO( res , a) : res += a
* */
#ifdef FIXED_POINT
#include <stdint.h>
#if (FIXED_POINT==32)
# define FRACBITS 31
# define SAMPPROD int64_t
#define SAMP_MAX INT32_MAX
#define SAMP_MIN INT32_MIN
#else
# define FRACBITS 15
# define SAMPPROD int32_t
#define SAMP_MAX INT16_MAX
#define SAMP_MIN INT16_MIN
#endif
#if defined(CHECK_OVERFLOW)
# define CHECK_OVERFLOW_OP(a,op,b) \
if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
KISS_FFT_WARNING("overflow (%d " #op" %d) = %ld", (a),(b),(SAMPPROD)(a) op (SAMPPROD)(b)); }
#endif
# define smul(a,b) ( (SAMPPROD)(a)*(b) )
# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )
# define S_MUL(a,b) sround( smul(a,b) )
# define C_MUL(m,a,b) \
do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
(m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
# define DIVSCALAR(x,k) \
(x) = sround( smul( x, SAMP_MAX/k ) )
# define C_FIXDIV(c,div) \
do { DIVSCALAR( (c).r , div); \
DIVSCALAR( (c).i , div); }while (0)
# define C_MULBYSCALAR( c, s ) \
do{ (c).r = sround( smul( (c).r , s ) ) ;\
(c).i = sround( smul( (c).i , s ) ) ; }while(0)
#else /* not FIXED_POINT*/
# define S_MUL(a,b) ( (a)*(b) )
#define C_MUL(m,a,b) \
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
# define C_FIXDIV(c,div) /* NOOP */
# define C_MULBYSCALAR( c, s ) \
do{ (c).r *= (s);\
(c).i *= (s); }while(0)
#endif
#ifndef CHECK_OVERFLOW_OP
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
#endif
#define C_ADD( res, a,b)\
do { \
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
}while(0)
#define C_SUB( res, a,b)\
do { \
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
}while(0)
#define C_ADDTO( res , a)\
do { \
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
(res).r += (a).r; (res).i += (a).i;\
}while(0)
#define C_SUBFROM( res , a)\
do {\
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
(res).r -= (a).r; (res).i -= (a).i; \
}while(0)
#ifdef FIXED_POINT
# define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase))
# define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase))
# define HALF_OF(x) ((x)>>1)
#elif defined(USE_SIMD)
# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
# define HALF_OF(x) ((x)*_mm_set1_ps(.5))
#else
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
# define HALF_OF(x) ((x)*((kiss_fft_scalar).5))
#endif
#define kf_cexp(x,phase) \
do{ \
(x)->r = KISS_FFT_COS(phase);\
(x)->i = KISS_FFT_SIN(phase);\
}while(0)
/* a debugging function */
#define pcpx(c)\
KISS_FFT_DEBUG("%g + %gi\n",(double)((c)->r),(double)((c)->i))
#ifdef KISS_FFT_USE_ALLOCA
// define this to allow use of alloca instead of malloc for temporary buffers
// Temporary buffers are used in two case:
// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5
// 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform.
#include <alloca.h>
#define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes)
#define KISS_FFT_TMP_FREE(ptr)
#else
#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes)
#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr)
#endif
#endif /* _kiss_fft_guts_h */

View File

@ -1,23 +0,0 @@
# This module provides function for joining paths
# known from most languages
#
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()

View File

@ -1,109 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kfc.h"
typedef struct cached_fft *kfc_cfg;
struct cached_fft
{
int nfft;
int inverse;
kiss_fft_cfg cfg;
kfc_cfg next;
};
static kfc_cfg cache_root=NULL;
static int ncached=0;
static kiss_fft_cfg find_cached_fft(int nfft,int inverse)
{
size_t len;
kfc_cfg cur=cache_root;
kfc_cfg prev=NULL;
while ( cur ) {
if ( cur->nfft == nfft && inverse == cur->inverse )
break;/*found the right node*/
prev = cur;
cur = prev->next;
}
if (cur== NULL) {
/* no cached node found, need to create a new one*/
kiss_fft_alloc(nfft,inverse,0,&len);
#ifdef USE_SIMD
int padding = (16-sizeof(struct cached_fft)) & 15;
// make sure the cfg aligns on a 16 byte boundary
len += padding;
#endif
cur = (kfc_cfg)KISS_FFT_MALLOC((sizeof(struct cached_fft) + len ));
if (cur == NULL)
return NULL;
cur->cfg = (kiss_fft_cfg)(cur+1);
#ifdef USE_SIMD
cur->cfg = (kiss_fft_cfg) ((char*)(cur+1)+padding);
#endif
kiss_fft_alloc(nfft,inverse,cur->cfg,&len);
cur->nfft=nfft;
cur->inverse=inverse;
cur->next = NULL;
if ( prev )
prev->next = cur;
else
cache_root = cur;
++ncached;
}
return cur->cfg;
}
void kfc_cleanup(void)
{
kfc_cfg cur=cache_root;
kfc_cfg next=NULL;
while (cur){
next = cur->next;
free(cur);
cur=next;
}
ncached=0;
cache_root = NULL;
}
void kfc_fft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout)
{
kiss_fft( find_cached_fft(nfft,0),fin,fout );
}
void kfc_ifft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout)
{
kiss_fft( find_cached_fft(nfft,1),fin,fout );
}
#ifdef KFC_TEST
static void check(int nc)
{
if (ncached != nc) {
fprintf(stderr,"ncached should be %d,but it is %d\n",nc,ncached);
exit(1);
}
}
int main(void)
{
kiss_fft_cpx buf1[1024],buf2[1024];
memset(buf1,0,sizeof(buf1));
check(0);
kfc_fft(512,buf1,buf2);
check(1);
kfc_fft(512,buf1,buf2);
check(1);
kfc_ifft(512,buf1,buf2);
check(2);
kfc_cleanup();
check(0);
return 0;
}
#endif

View File

@ -1,54 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KFC_H
#define KFC_H
#include "kiss_fft.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
KFC -- Kiss FFT Cache
Not needing to deal with kiss_fft_alloc and a config
object may be handy for a lot of programs.
KFC uses the underlying KISS FFT functions, but caches the config object.
The first time kfc_fft or kfc_ifft for a given FFT size, the cfg
object is created for it. All subsequent calls use the cached
configuration object.
NOTE:
You should probably not use this if your program will be using a lot
of various sizes of FFTs. There is a linear search through the
cached objects. If you are only using one or two FFT sizes, this
will be negligible. Otherwise, you may want to use another method
of managing the cfg objects.
There is no automated cleanup of the cached objects. This could lead
to large memory usage in a program that uses a lot of *DIFFERENT*
sized FFTs. If you want to force all cached cfg objects to be freed,
call kfc_cleanup.
*/
/*forward complex FFT */
void KISS_FFT_API kfc_fft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
/*reverse complex FFT */
void KISS_FFT_API kfc_ifft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
/*free all cached objects*/
void KISS_FFT_API kfc_cleanup(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,420 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "_kiss_fft_guts.h"
/* The guts header contains all the multiplication and addition macros that are defined for
fixed or floating point complex numbers. It also delares the kf_ internal functions.
*/
static void kf_bfly2(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m
)
{
kiss_fft_cpx * Fout2;
kiss_fft_cpx * tw1 = st->twiddles;
kiss_fft_cpx t;
Fout2 = Fout + m;
do{
C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);
C_MUL (t, *Fout2 , *tw1);
tw1 += fstride;
C_SUB( *Fout2 , *Fout , t );
C_ADDTO( *Fout , t );
++Fout2;
++Fout;
}while (--m);
}
static void kf_bfly4(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
const size_t m
)
{
kiss_fft_cpx *tw1,*tw2,*tw3;
kiss_fft_cpx scratch[6];
size_t k=m;
const size_t m2=2*m;
const size_t m3=3*m;
tw3 = tw2 = tw1 = st->twiddles;
do {
C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);
C_MUL(scratch[0],Fout[m] , *tw1 );
C_MUL(scratch[1],Fout[m2] , *tw2 );
C_MUL(scratch[2],Fout[m3] , *tw3 );
C_SUB( scratch[5] , *Fout, scratch[1] );
C_ADDTO(*Fout, scratch[1]);
C_ADD( scratch[3] , scratch[0] , scratch[2] );
C_SUB( scratch[4] , scratch[0] , scratch[2] );
C_SUB( Fout[m2], *Fout, scratch[3] );
tw1 += fstride;
tw2 += fstride*2;
tw3 += fstride*3;
C_ADDTO( *Fout , scratch[3] );
if(st->inverse) {
Fout[m].r = scratch[5].r - scratch[4].i;
Fout[m].i = scratch[5].i + scratch[4].r;
Fout[m3].r = scratch[5].r + scratch[4].i;
Fout[m3].i = scratch[5].i - scratch[4].r;
}else{
Fout[m].r = scratch[5].r + scratch[4].i;
Fout[m].i = scratch[5].i - scratch[4].r;
Fout[m3].r = scratch[5].r - scratch[4].i;
Fout[m3].i = scratch[5].i + scratch[4].r;
}
++Fout;
}while(--k);
}
static void kf_bfly3(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
size_t m
)
{
size_t k=m;
const size_t m2 = 2*m;
kiss_fft_cpx *tw1,*tw2;
kiss_fft_cpx scratch[5];
kiss_fft_cpx epi3;
epi3 = st->twiddles[fstride*m];
tw1=tw2=st->twiddles;
do{
C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
C_MUL(scratch[1],Fout[m] , *tw1);
C_MUL(scratch[2],Fout[m2] , *tw2);
C_ADD(scratch[3],scratch[1],scratch[2]);
C_SUB(scratch[0],scratch[1],scratch[2]);
tw1 += fstride;
tw2 += fstride*2;
Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
C_MULBYSCALAR( scratch[0] , epi3.i );
C_ADDTO(*Fout,scratch[3]);
Fout[m2].r = Fout[m].r + scratch[0].i;
Fout[m2].i = Fout[m].i - scratch[0].r;
Fout[m].r -= scratch[0].i;
Fout[m].i += scratch[0].r;
++Fout;
}while(--k);
}
static void kf_bfly5(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m
)
{
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
int u;
kiss_fft_cpx scratch[13];
kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx *tw;
kiss_fft_cpx ya,yb;
ya = twiddles[fstride*m];
yb = twiddles[fstride*2*m];
Fout0=Fout;
Fout1=Fout0+m;
Fout2=Fout0+2*m;
Fout3=Fout0+3*m;
Fout4=Fout0+4*m;
tw=st->twiddles;
for ( u=0; u<m; ++u ) {
C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
scratch[0] = *Fout0;
C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
C_ADD( scratch[7],scratch[1],scratch[4]);
C_SUB( scratch[10],scratch[1],scratch[4]);
C_ADD( scratch[8],scratch[2],scratch[3]);
C_SUB( scratch[9],scratch[2],scratch[3]);
Fout0->r += scratch[7].r + scratch[8].r;
Fout0->i += scratch[7].i + scratch[8].i;
scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
C_SUB(*Fout1,scratch[5],scratch[6]);
C_ADD(*Fout4,scratch[5],scratch[6]);
scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
C_ADD(*Fout2,scratch[11],scratch[12]);
C_SUB(*Fout3,scratch[11],scratch[12]);
++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
}
}
/* perform the butterfly for one stage of a mixed radix FFT */
static void kf_bfly_generic(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m,
int p
)
{
int u,k,q1,q;
kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx t;
int Norig = st->nfft;
kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);
if (scratch == NULL){
KISS_FFT_ERROR("Memory allocation failed.");
return;
}
for ( u=0; u<m; ++u ) {
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
scratch[q1] = Fout[ k ];
C_FIXDIV(scratch[q1],p);
k += m;
}
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
int twidx=0;
Fout[ k ] = scratch[0];
for (q=1;q<p;++q ) {
twidx += fstride * k;
if (twidx>=Norig) twidx-=Norig;
C_MUL(t,scratch[q] , twiddles[twidx] );
C_ADDTO( Fout[ k ] ,t);
}
k += m;
}
}
KISS_FFT_TMP_FREE(scratch);
}
static
void kf_work(
kiss_fft_cpx * Fout,
const kiss_fft_cpx * f,
const size_t fstride,
int in_stride,
int * factors,
const kiss_fft_cfg st
)
{
kiss_fft_cpx * Fout_beg=Fout;
const int p=*factors++; /* the radix */
const int m=*factors++; /* stage's fft length/p */
const kiss_fft_cpx * Fout_end = Fout + p*m;
#ifdef _OPENMP
// use openmp extensions at the
// top-level (not recursive)
if (fstride==1 && p<=5 && m!=1)
{
int k;
// execute the p different work units in different threads
# pragma omp parallel for
for (k=0;k<p;++k)
kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
// all threads have joined by this point
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
case 4: kf_bfly4(Fout,fstride,st,m); break;
case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
}
return;
}
#endif
if (m==1) {
do{
*Fout = *f;
f += fstride*in_stride;
}while(++Fout != Fout_end );
}else{
do{
// recursive call:
// DFT of size m*p performed by doing
// p instances of smaller DFTs of size m,
// each one takes a decimated version of the input
kf_work( Fout , f, fstride*p, in_stride, factors,st);
f += fstride*in_stride;
}while( (Fout += m) != Fout_end );
}
Fout=Fout_beg;
// recombine the p smaller DFTs
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
case 4: kf_bfly4(Fout,fstride,st,m); break;
case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
}
}
/* facbuf is populated by p1,m1,p2,m2, ...
where
p[i] * m[i] = m[i-1]
m0 = n */
static
void kf_factor(int n,int * facbuf)
{
int p=4;
double floor_sqrt;
floor_sqrt = floor( sqrt((double)n) );
/*factor out powers of 4, powers of 2, then any remaining primes */
do {
while (n % p) {
switch (p) {
case 4: p = 2; break;
case 2: p = 3; break;
default: p += 2; break;
}
if (p > floor_sqrt)
p = n; /* no more factors, skip to end */
}
n /= p;
*facbuf++ = p;
*facbuf++ = n;
} while (n > 1);
}
/*
*
* User-callable function to allocate all necessary storage space for the fft.
*
* The return value is a contiguous block of memory, allocated with malloc. As such,
* It can be freed with free(), rather than a kiss_fft-specific function.
* */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
{
KISS_FFT_ALIGN_CHECK(mem)
kiss_fft_cfg st=NULL;
size_t memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fft_state)
+ sizeof(kiss_fft_cpx)*(nfft-1)); /* twiddle factors*/
if ( lenmem==NULL ) {
st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
}else{
if (mem != NULL && *lenmem >= memneeded)
st = (kiss_fft_cfg)mem;
*lenmem = memneeded;
}
if (st) {
int i;
st->nfft=nfft;
st->inverse = inverse_fft;
for (i=0;i<nfft;++i) {
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
double phase = -2*pi*i / nfft;
if (st->inverse)
phase *= -1;
kf_cexp(st->twiddles+i, phase );
}
kf_factor(nfft,st->factors);
}
return st;
}
void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{
if (fin == fout) {
//NOTE: this is not really an in-place FFT algorithm.
//It just performs an out-of-place FFT into a temp buffer
if (fout == NULL){
KISS_FFT_ERROR("fout buffer NULL.");
return;
}
kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
if (tmpbuf == NULL){
KISS_FFT_ERROR("Memory allocation error.");
return;
}
kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
KISS_FFT_TMP_FREE(tmpbuf);
}else{
kf_work( fout, fin, 1,in_stride, st->factors,st );
}
}
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
{
kiss_fft_stride(cfg,fin,fout,1);
}
void kiss_fft_cleanup(void)
{
// nothing needed any more
}
int kiss_fft_next_fast_size(int n)
{
while(1) {
int m=n;
while ( (m%2) == 0 ) m/=2;
while ( (m%3) == 0 ) m/=3;
while ( (m%5) == 0 ) m/=5;
if (m<=1)
break; /* n is completely factorable by twos, threes, and fives */
n++;
}
return n;
}

View File

@ -1,160 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISS_FFT_H
#define KISS_FFT_H
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
// Define KISS_FFT_SHARED macro to properly export symbols
#ifdef KISS_FFT_SHARED
# ifdef _WIN32
# ifdef KISS_FFT_BUILD
# define KISS_FFT_API __declspec(dllexport)
# else
# define KISS_FFT_API __declspec(dllimport)
# endif
# else
# define KISS_FFT_API __attribute__ ((visibility ("default")))
# endif
#else
# define KISS_FFT_API
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
ATTENTION!
If you would like a :
-- a utility that will handle the caching of fft objects
-- real-only (no imaginary time component ) FFT
-- a multi-dimensional FFT
-- a command-line utility to perform ffts
-- a command-line utility to perform fast-convolution filtering
Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
in the tools/ directory.
*/
/* User may override KISS_FFT_MALLOC and/or KISS_FFT_FREE. */
#ifdef USE_SIMD
# include <xmmintrin.h>
# define kiss_fft_scalar __m128
# ifndef KISS_FFT_MALLOC
# define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
# define KISS_FFT_ALIGN_CHECK(ptr)
# define KISS_FFT_ALIGN_SIZE_UP(size) ((size + 15UL) & ~0xFUL)
# endif
# ifndef KISS_FFT_FREE
# define KISS_FFT_FREE _mm_free
# endif
#else
# define KISS_FFT_ALIGN_CHECK(ptr)
# define KISS_FFT_ALIGN_SIZE_UP(size) (size)
# ifndef KISS_FFT_MALLOC
# define KISS_FFT_MALLOC malloc
# endif
# ifndef KISS_FFT_FREE
# define KISS_FFT_FREE free
# endif
#endif
#ifdef FIXED_POINT
#include <stdint.h>
# if (FIXED_POINT == 32)
# define kiss_fft_scalar int32_t
# else
# define kiss_fft_scalar int16_t
# endif
#else
# ifndef kiss_fft_scalar
/* default is float */
# define kiss_fft_scalar float
# endif
#endif
typedef struct {
kiss_fft_scalar r;
kiss_fft_scalar i;
}kiss_fft_cpx;
typedef struct kiss_fft_state* kiss_fft_cfg;
/*
* kiss_fft_alloc
*
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
*
* typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
*
* The return value from fft_alloc is a cfg buffer used internally
* by the fft routine or NULL.
*
* If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
* The returned value should be free()d when done to avoid memory leaks.
*
* The state can be placed in a user supplied buffer 'mem':
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
* then the function places the cfg in mem and the size used in *lenmem
* and returns mem.
*
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
* then the function returns NULL and places the minimum cfg
* buffer size in *lenmem.
* */
kiss_fft_cfg KISS_FFT_API kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
/*
* kiss_fft(cfg,in_out_buf)
*
* Perform an FFT on a complex input buffer.
* for a forward FFT,
* fin should be f[0] , f[1] , ... ,f[nfft-1]
* fout will be F[0] , F[1] , ... ,F[nfft-1]
* Note that each element is complex and can be accessed like
f[k].r and f[k].i
* */
void KISS_FFT_API kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
/*
A more generic version of the above function. It reads its input from every Nth sample.
* */
void KISS_FFT_API kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
/* If kiss_fft_alloc allocated a buffer, it is one contiguous
buffer and can be simply free()d when no longer needed*/
#define kiss_fft_free KISS_FFT_FREE
/*
Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
your compiler output to call this before you exit.
*/
void KISS_FFT_API kiss_fft_cleanup(void);
/*
* Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
*/
int KISS_FFT_API kiss_fft_next_fast_size(int n);
/* for real ffts, we need an even size */
#define kiss_fftr_next_fast_size_real(n) \
(kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef kiss_fft_log_h
#define kiss_fft_log_h
#define ERROR 1
#define WARNING 2
#define INFO 3
#define DEBUG 4
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(NDEBUG)
# define KISS_FFT_LOG_MSG(severity, ...) ((void)0)
#else
# define KISS_FFT_LOG_MSG(severity, ...) \
fprintf(stderr, "[" #severity "] " __FILE__ ":" TOSTRING(__LINE__) " "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n")
#endif
#define KISS_FFT_ERROR(...) KISS_FFT_LOG_MSG(ERROR, __VA_ARGS__)
#define KISS_FFT_WARNING(...) KISS_FFT_LOG_MSG(WARNING, __VA_ARGS__)
#define KISS_FFT_INFO(...) KISS_FFT_LOG_MSG(INFO, __VA_ARGS__)
#define KISS_FFT_DEBUG(...) KISS_FFT_LOG_MSG(DEBUG, __VA_ARGS__)
#endif /* kiss_fft_log_h */

View File

@ -1,188 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kiss_fftnd.h"
#include "_kiss_fft_guts.h"
struct kiss_fftnd_state{
int dimprod; /* dimsum would be mighty tasty right now */
int ndims;
int *dims;
kiss_fft_cfg *states; /* cfg states for each dimension */
kiss_fft_cpx * tmpbuf; /*buffer capable of hold the entire input */
};
kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
{
KISS_FFT_ALIGN_CHECK(mem)
kiss_fftnd_cfg st = NULL;
int i;
int dimprod=1;
size_t memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftnd_state));
char * ptr = NULL;
for (i=0;i<ndims;++i) {
size_t sublen=0;
kiss_fft_alloc (dims[i], inverse_fft, NULL, &sublen);
memneeded += sublen; /* st->states[i] */
dimprod *= dims[i];
}
memneeded += KISS_FFT_ALIGN_SIZE_UP(sizeof(int) * ndims);/* st->dims */
memneeded += KISS_FFT_ALIGN_SIZE_UP(sizeof(void*) * ndims);/* st->states */
memneeded += KISS_FFT_ALIGN_SIZE_UP(sizeof(kiss_fft_cpx) * dimprod); /* st->tmpbuf */
if (lenmem == NULL) {/* allocate for the caller*/
ptr = (char *) malloc (memneeded);
} else { /* initialize supplied buffer if big enough */
if (*lenmem >= memneeded)
ptr = (char *) mem;
*lenmem = memneeded; /*tell caller how big struct is (or would be) */
}
if (!ptr)
return NULL; /*malloc failed or buffer too small */
st = (kiss_fftnd_cfg) ptr;
st->dimprod = dimprod;
st->ndims = ndims;
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftnd_state));
st->states = (kiss_fft_cfg *)ptr;
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(void*) * ndims);
st->dims = (int*)ptr;
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(int) * ndims);
st->tmpbuf = (kiss_fft_cpx*)ptr;
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(kiss_fft_cpx) * dimprod);
for (i=0;i<ndims;++i) {
size_t len;
st->dims[i] = dims[i];
kiss_fft_alloc (st->dims[i], inverse_fft, NULL, &len);
st->states[i] = kiss_fft_alloc (st->dims[i], inverse_fft, ptr,&len);
ptr += len;
}
/*
Hi there!
If you're looking at this particular code, it probably means you've got a brain-dead bounds checker
that thinks the above code overwrites the end of the array.
It doesn't.
-- Mark
P.S.
The below code might give you some warm fuzzies and help convince you.
*/
if ( ptr - (char*)st != (int)memneeded ) {
fprintf(stderr,
"################################################################################\n"
"Internal error! Memory allocation miscalculation\n"
"################################################################################\n"
);
}
return st;
}
/*
This works by tackling one dimension at a time.
In effect,
Each stage starts out by reshaping the matrix into a DixSi 2d matrix.
A Di-sized fft is taken of each column, transposing the matrix as it goes.
Here's a 3-d example:
Take a 2x3x4 matrix, laid out in memory as a contiguous buffer
[ [ [ a b c d ] [ e f g h ] [ i j k l ] ]
[ [ m n o p ] [ q r s t ] [ u v w x ] ] ]
Stage 0 ( D=2): treat the buffer as a 2x12 matrix
[ [a b ... k l]
[m n ... w x] ]
FFT each column with size 2.
Transpose the matrix at the same time using kiss_fft_stride.
[ [ a+m a-m ]
[ b+n b-n]
...
[ k+w k-w ]
[ l+x l-x ] ]
Note fft([x y]) == [x+y x-y]
Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix,
[ [ a+m a-m b+n b-n c+o c-o d+p d-p ]
[ e+q e-q f+r f-r g+s g-s h+t h-t ]
[ i+u i-u j+v j-v k+w k-w l+x l-x ] ]
And perform FFTs (size=3) on each of the columns as above, transposing
the matrix as it goes. The output of stage 1 is
(Legend: ap = [ a+m e+q i+u ]
am = [ a-m e-q i-u ] )
[ [ sum(ap) fft(ap)[0] fft(ap)[1] ]
[ sum(am) fft(am)[0] fft(am)[1] ]
[ sum(bp) fft(bp)[0] fft(bp)[1] ]
[ sum(bm) fft(bm)[0] fft(bm)[1] ]
[ sum(cp) fft(cp)[0] fft(cp)[1] ]
[ sum(cm) fft(cm)[0] fft(cm)[1] ]
[ sum(dp) fft(dp)[0] fft(dp)[1] ]
[ sum(dm) fft(dm)[0] fft(dm)[1] ] ]
Stage 2 ( D=4) treats this buffer as a 4*6 matrix,
[ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ]
[ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ]
[ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ]
[ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ]
Then FFTs each column, transposing as it goes.
The resulting matrix is the 3d FFT of the 2x3x4 input matrix.
Note as a sanity check that the first element of the final
stage's output (DC term) is
sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] )
, i.e. the summation of all 24 input elements.
*/
void kiss_fftnd(kiss_fftnd_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
{
int i,k;
const kiss_fft_cpx * bufin=fin;
kiss_fft_cpx * bufout;
/*arrange it so the last bufout == fout*/
if ( st->ndims & 1 ) {
bufout = fout;
if (fin==fout) {
memcpy( st->tmpbuf, fin, sizeof(kiss_fft_cpx) * st->dimprod );
bufin = st->tmpbuf;
}
}else
bufout = st->tmpbuf;
for ( k=0; k < st->ndims; ++k) {
int curdim = st->dims[k];
int stride = st->dimprod / curdim;
for ( i=0 ; i<stride ; ++i )
kiss_fft_stride( st->states[k], bufin+i , bufout+i*curdim, stride );
/*toggle back and forth between the two buffers*/
if (bufout == st->tmpbuf){
bufout = fout;
bufin = st->tmpbuf;
}else{
bufout = st->tmpbuf;
bufin = fout;
}
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISS_FFTND_H
#define KISS_FFTND_H
#include "kiss_fft.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kiss_fftnd_state * kiss_fftnd_cfg;
kiss_fftnd_cfg KISS_FFT_API kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem);
void KISS_FFT_API kiss_fftnd(kiss_fftnd_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,120 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kiss_fftndr.h"
#include "_kiss_fft_guts.h"
#define MAX(x,y) ( ( (x)<(y) )?(y):(x) )
struct kiss_fftndr_state
{
int dimReal;
int dimOther;
kiss_fftr_cfg cfg_r;
kiss_fftnd_cfg cfg_nd;
void * tmpbuf;
};
static int prod(const int *dims, int ndims)
{
int x=1;
while (ndims--)
x *= *dims++;
return x;
}
kiss_fftndr_cfg kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
{
KISS_FFT_ALIGN_CHECK(mem)
kiss_fftndr_cfg st = NULL;
size_t nr=0 , nd=0,ntmp=0;
int dimReal = dims[ndims-1];
int dimOther = prod(dims,ndims-1);
size_t memneeded;
char * ptr = NULL;
(void)kiss_fftr_alloc(dimReal,inverse_fft,NULL,&nr);
(void)kiss_fftnd_alloc(dims,ndims-1,inverse_fft,NULL,&nd);
ntmp =
MAX( 2*dimOther , dimReal+2) * sizeof(kiss_fft_scalar) // freq buffer for one pass
+ dimOther*(dimReal+2) * sizeof(kiss_fft_scalar); // large enough to hold entire input in case of in-place
memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof( struct kiss_fftndr_state )) + KISS_FFT_ALIGN_SIZE_UP(nr) + KISS_FFT_ALIGN_SIZE_UP(nd) + KISS_FFT_ALIGN_SIZE_UP(ntmp);
if (lenmem==NULL) {
ptr = (char*) malloc(memneeded);
}else{
if (*lenmem >= memneeded)
ptr = (char *)mem;
*lenmem = memneeded;
}
if (ptr==NULL)
return NULL;
st = (kiss_fftndr_cfg) ptr;
memset( st , 0 , memneeded);
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftndr_state));
st->dimReal = dimReal;
st->dimOther = dimOther;
st->cfg_r = kiss_fftr_alloc( dimReal,inverse_fft,ptr,&nr);
ptr += KISS_FFT_ALIGN_SIZE_UP(nr);
st->cfg_nd = kiss_fftnd_alloc(dims,ndims-1,inverse_fft, ptr,&nd);
ptr += KISS_FFT_ALIGN_SIZE_UP(nd);
st->tmpbuf = ptr;
return st;
}
void kiss_fftndr(kiss_fftndr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
{
int k1,k2;
int dimReal = st->dimReal;
int dimOther = st->dimOther;
int nrbins = dimReal/2+1;
kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf;
kiss_fft_cpx * tmp2 = tmp1 + MAX(nrbins,dimOther);
// timedata is N0 x N1 x ... x Nk real
// take a real chunk of data, fft it and place the output at correct intervals
for (k1=0;k1<dimOther;++k1) {
kiss_fftr( st->cfg_r, timedata + k1*dimReal , tmp1 ); // tmp1 now holds nrbins complex points
for (k2=0;k2<nrbins;++k2)
tmp2[ k2*dimOther+k1 ] = tmp1[k2];
}
for (k2=0;k2<nrbins;++k2) {
kiss_fftnd(st->cfg_nd, tmp2+k2*dimOther, tmp1); // tmp1 now holds dimOther complex points
for (k1=0;k1<dimOther;++k1)
freqdata[ k1*(nrbins) + k2] = tmp1[k1];
}
}
void kiss_fftndri(kiss_fftndr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
{
int k1,k2;
int dimReal = st->dimReal;
int dimOther = st->dimOther;
int nrbins = dimReal/2+1;
kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf;
kiss_fft_cpx * tmp2 = tmp1 + MAX(nrbins,dimOther);
for (k2=0;k2<nrbins;++k2) {
for (k1=0;k1<dimOther;++k1)
tmp1[k1] = freqdata[ k1*(nrbins) + k2 ];
kiss_fftnd(st->cfg_nd, tmp1, tmp2+k2*dimOther);
}
for (k1=0;k1<dimOther;++k1) {
for (k2=0;k2<nrbins;++k2)
tmp1[k2] = tmp2[ k2*dimOther+k1 ];
kiss_fftri( st->cfg_r,tmp1,timedata + k1*dimReal);
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISS_NDR_H
#define KISS_NDR_H
#include "kiss_fft.h"
#include "kiss_fftr.h"
#include "kiss_fftnd.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kiss_fftndr_state *kiss_fftndr_cfg;
kiss_fftndr_cfg KISS_FFT_API kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem);
/*
dims[0] must be even
If you don't care to allocate space, use mem = lenmem = NULL
*/
void KISS_FFT_API kiss_fftndr(
kiss_fftndr_cfg cfg,
const kiss_fft_scalar *timedata,
kiss_fft_cpx *freqdata);
/*
input timedata has dims[0] X dims[1] X ... X dims[ndims-1] scalar points
output freqdata has dims[0] X dims[1] X ... X dims[ndims-1]/2+1 complex points
*/
void KISS_FFT_API kiss_fftndri(
kiss_fftndr_cfg cfg,
const kiss_fft_cpx *freqdata,
kiss_fft_scalar *timedata);
/*
input and output dimensions are the exact opposite of kiss_fftndr
*/
#define kiss_fftndr_free free
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,155 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"
struct kiss_fftr_state{
kiss_fft_cfg substate;
kiss_fft_cpx * tmpbuf;
kiss_fft_cpx * super_twiddles;
#ifdef USE_SIMD
void * pad;
#endif
};
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
{
KISS_FFT_ALIGN_CHECK(mem)
int i;
kiss_fftr_cfg st = NULL;
size_t subsize = 0, memneeded;
if (nfft & 1) {
KISS_FFT_ERROR("Real FFT optimization must be even.");
return NULL;
}
nfft >>= 1;
kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
if (lenmem == NULL) {
st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
} else {
if (*lenmem >= memneeded)
st = (kiss_fftr_cfg) mem;
*lenmem = memneeded;
}
if (!st)
return NULL;
st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
st->super_twiddles = st->tmpbuf + nfft;
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
for (i = 0; i < nfft/2; ++i) {
double phase =
-3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
if (inverse_fft)
phase *= -1;
kf_cexp (st->super_twiddles+i,phase);
}
return st;
}
void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
{
/* input buffer timedata is stored row-wise */
int k,ncfft;
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
if ( st->substate->inverse) {
KISS_FFT_ERROR("kiss fft usage error: improper alloc");
return;/* The caller did not call the correct function */
}
ncfft = st->substate->nfft;
/*perform the parallel fft of two real signals packed in real,imag*/
kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
* contains the sum of the even-numbered elements of the input time sequence
* The imag part is the sum of the odd-numbered elements
*
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
* yielding DC of input time sequence
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
* yielding Nyquist bin of input time sequence
*/
tdc.r = st->tmpbuf[0].r;
tdc.i = st->tmpbuf[0].i;
C_FIXDIV(tdc,2);
CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
freqdata[0].r = tdc.r + tdc.i;
freqdata[ncfft].r = tdc.r - tdc.i;
#ifdef USE_SIMD
freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
#else
freqdata[ncfft].i = freqdata[0].i = 0;
#endif
for ( k=1;k <= ncfft/2 ; ++k ) {
fpk = st->tmpbuf[k];
fpnk.r = st->tmpbuf[ncfft-k].r;
fpnk.i = - st->tmpbuf[ncfft-k].i;
C_FIXDIV(fpk,2);
C_FIXDIV(fpnk,2);
C_ADD( f1k, fpk , fpnk );
C_SUB( f2k, fpk , fpnk );
C_MUL( tw , f2k , st->super_twiddles[k-1]);
freqdata[k].r = HALF_OF(f1k.r + tw.r);
freqdata[k].i = HALF_OF(f1k.i + tw.i);
freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
}
}
void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
{
/* input buffer timedata is stored row-wise */
int k, ncfft;
if (st->substate->inverse == 0) {
KISS_FFT_ERROR("kiss fft usage error: improper alloc");
return;/* The caller did not call the correct function */
}
ncfft = st->substate->nfft;
st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
C_FIXDIV(st->tmpbuf[0],2);
for (k = 1; k <= ncfft / 2; ++k) {
kiss_fft_cpx fk, fnkc, fek, fok, tmp;
fk = freqdata[k];
fnkc.r = freqdata[ncfft - k].r;
fnkc.i = -freqdata[ncfft - k].i;
C_FIXDIV( fk , 2 );
C_FIXDIV( fnkc , 2 );
C_ADD (fek, fk, fnkc);
C_SUB (tmp, fk, fnkc);
C_MUL (fok, tmp, st->super_twiddles[k-1]);
C_ADD (st->tmpbuf[k], fek, fok);
C_SUB (st->tmpbuf[ncfft - k], fek, fok);
#ifdef USE_SIMD
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
#else
st->tmpbuf[ncfft - k].i *= -1;
#endif
}
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISS_FTR_H
#define KISS_FTR_H
#include "kiss_fft.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
*/
typedef struct kiss_fftr_state *kiss_fftr_cfg;
kiss_fftr_cfg KISS_FFT_API kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
/*
nfft must be even
If you don't care to allocate space, use mem = lenmem = NULL
*/
void KISS_FFT_API kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
/*
input timedata has nfft scalar points
output freqdata has nfft/2+1 complex points
*/
void KISS_FFT_API kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
/*
input freqdata has nfft/2+1 complex points
output timedata has nfft scalar points
*/
#define kiss_fftr_free KISS_FFT_FREE
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,82 +0,0 @@
# kissfft-config.ccmake accept the following components:
#
# SHARED/STATIC:
# This components allows one to choose a shared/static kissfft library.
# The default is selected by BUILD_SHARED_LIBS.
# They are to be used exclusively. Using them together is an error.
#
# example:
# find_package(kissfft CONFIG REQUIRED COMPONENTS STATIC)
#
# simd/int16/int32/float/double:
# This components allows one to choose the datatype.
# When using this component, the target kissfft::kissfft becomes available.
# When not using this component, you will have to choose the correct kissfft target.
#
# example:
# find_package(kissfft CONFIG REQUIRED)
# # - kissfft::kissfft-float, kissfft::kissfft-int32_t/ ... are available (if they are installed)
# # - kissfft::kissfft is not available,
#
# find_package(kissfft CONFIG REQUIRED COMPONENTS int32_t)
# # - kissfft::kissfft-float, kissfft::kissfft-int32_t/ ... are available (if they are installed)
# # - kissfft::kissfft is available (as an alias for kissfft::kissfft-int32_t),
@PACKAGE_INIT@
cmake_minimum_required(VERSION 3.3)
# Set include glob of config files using SHARED/static component, BUILD_SHARED_LIBS by default
set(_kissfft_shared_detected OFF)
set(_kissfft_shared ${BUILD_SHARED_LIBS})
if("SHARED" IN_LIST kissfft_FIND_COMPONENTS)
set(_kissfft_shared_detected ON)
set(_kissfft_shared ON)
endif()
if("STATIC" IN_LIST kissfft_FIND_COMPONENTS)
if(_kissfft_shared_detected)
message(FATAL_ERROR "SHARED and STATIC components cannot be used together")
endif()
set(_kissfft_shared_detected ON)
set(_kissfft_shared OFF)
endif()
if(_kissfft_shared)
set(_kissfft_config_glob "kissfft-*-shared-targets.cmake")
else()
set(_kissfft_config_glob "kissfft-*-static-targets.cmake")
endif()
# Load information for all configured kissfft
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/${_kissfft_config_glob}")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
# If a datatype component is passed, create kissfft::kissfft
set(_kissfft_datatype_detected)
foreach(_kissfft_datatype simd int16 int32 float double)
if(_kissfft_datatype IN_LIST kissfft_FIND_COMPONENTS)
if(_kissfft_datatype_detected)
message(FATAL_ERROR "Cannot define datatype COMPONENT twice: ${_kissfft_datatype_detected} and ${_kissfft_datatype}")
endif()
set(_kissfft_datatype_detected ${_kissfft_datatype})
endif()
endforeach()
if(_kissfft_datatype_detected)
if(NOT TARGET kissfft::kissfft-${_kissfft_datatype_detected})
message(FATAL_ERROR "kissfft with datatype=${_kissfft_datatype_detected} is not installed")
endif()
if(TARGET kissfft::kissfft)
message(SEND_ERROR "kissfft::kissfft already exists. You cannot use 2 find_package's with datatype that are visible to eachother.")
else()
add_library(kissfft::kissfft INTERFACE IMPORTED)
set_property(TARGET kissfft::kissfft PROPERTY INTERFACE_LINK_LIBRARIES kissfft::kissfft-${_kissfft_datatype_detected})
endif()
endif()
set(kissfft_FOUND ON)
set(KISSFFT_VERSION @kissfft_VERSION@)

View File

@ -1,361 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISSFFT_CLASS_HH
#define KISSFFT_CLASS_HH
#include <complex>
#include <utility>
#include <vector>
template <typename scalar_t>
class kissfft
{
public:
typedef std::complex<scalar_t> cpx_t;
kissfft( const std::size_t nfft,
const bool inverse )
:_nfft(nfft)
,_inverse(inverse)
{
// fill twiddle factors
_twiddles.resize(_nfft);
const scalar_t phinc = (_inverse?2:-2)* std::acos( (scalar_t) -1) / _nfft;
for (std::size_t i=0;i<_nfft;++i)
_twiddles[i] = std::exp( cpx_t(0,i*phinc) );
//factorize
//start factoring out 4's, then 2's, then 3,5,7,9,...
std::size_t n= _nfft;
std::size_t p=4;
do {
while (n % p) {
switch (p) {
case 4: p = 2; break;
case 2: p = 3; break;
default: p += 2; break;
}
if (p*p>n)
p = n;// no more factors
}
n /= p;
_stageRadix.push_back(p);
_stageRemainder.push_back(n);
}while(n>1);
}
/// Changes the FFT-length and/or the transform direction.
///
/// @post The @c kissfft object will be in the same state as if it
/// had been newly constructed with the passed arguments.
/// However, the implementation may be faster than constructing a
/// new fft object.
void assign( const std::size_t nfft,
const bool inverse )
{
if ( nfft != _nfft )
{
kissfft tmp( nfft, inverse ); // O(n) time.
std::swap( tmp, *this ); // this is O(1) in C++11, O(n) otherwise.
}
else if ( inverse != _inverse )
{
// conjugate the twiddle factors.
for ( typename std::vector<cpx_t>::iterator it = _twiddles.begin();
it != _twiddles.end(); ++it )
it->imag( -it->imag() );
}
}
/// Calculates the complex Discrete Fourier Transform.
///
/// The size of the passed arrays must be passed in the constructor.
/// The sum of the squares of the absolute values in the @c dst
/// array will be @c N times the sum of the squares of the absolute
/// values in the @c src array, where @c N is the size of the array.
/// In other words, the l_2 norm of the resulting array will be
/// @c sqrt(N) times as big as the l_2 norm of the input array.
/// This is also the case when the inverse flag is set in the
/// constructor. Hence when applying the same transform twice, but with
/// the inverse flag changed the second time, then the result will
/// be equal to the original input times @c N.
void transform(const cpx_t * fft_in, cpx_t * fft_out, const std::size_t stage = 0, const std::size_t fstride = 1, const std::size_t in_stride = 1) const
{
const std::size_t p = _stageRadix[stage];
const std::size_t m = _stageRemainder[stage];
cpx_t * const Fout_beg = fft_out;
cpx_t * const Fout_end = fft_out + p*m;
if (m==1) {
do{
*fft_out = *fft_in;
fft_in += fstride*in_stride;
}while(++fft_out != Fout_end );
}else{
do{
// recursive call:
// DFT of size m*p performed by doing
// p instances of smaller DFTs of size m,
// each one takes a decimated version of the input
transform(fft_in, fft_out, stage+1, fstride*p,in_stride);
fft_in += fstride*in_stride;
}while( (fft_out += m) != Fout_end );
}
fft_out=Fout_beg;
// recombine the p smaller DFTs
switch (p) {
case 2: kf_bfly2(fft_out,fstride,m); break;
case 3: kf_bfly3(fft_out,fstride,m); break;
case 4: kf_bfly4(fft_out,fstride,m); break;
case 5: kf_bfly5(fft_out,fstride,m); break;
default: kf_bfly_generic(fft_out,fstride,m,p); break;
}
}
/// Calculates the Discrete Fourier Transform (DFT) of a real input
/// of size @c 2*N.
///
/// The 0-th and N-th value of the DFT are real numbers. These are
/// stored in @c dst[0].real() and @c dst[0].imag() respectively.
/// The remaining DFT values up to the index N-1 are stored in
/// @c dst[1] to @c dst[N-1].
/// The other half of the DFT values can be calculated from the
/// symmetry relation
/// @code
/// DFT(src)[2*N-k] == conj( DFT(src)[k] );
/// @endcode
/// The same scaling factors as in @c transform() apply.
///
/// @note For this to work, the types @c scalar_t and @c cpx_t
/// must fulfill the following requirements:
///
/// For any object @c z of type @c cpx_t,
/// @c reinterpret_cast<scalar_t(&)[2]>(z)[0] is the real part of @c z and
/// @c reinterpret_cast<scalar_t(&)[2]>(z)[1] is the imaginary part of @c z.
/// For any pointer to an element of an array of @c cpx_t named @c p
/// and any valid array index @c i, @c reinterpret_cast<T*>(p)[2*i]
/// is the real part of the complex number @c p[i], and
/// @c reinterpret_cast<T*>(p)[2*i+1] is the imaginary part of the
/// complex number @c p[i].
///
/// Since C++11, these requirements are guaranteed to be satisfied for
/// @c scalar_ts being @c float, @c double or @c long @c double
/// together with @c cpx_t being @c std::complex<scalar_t>.
void transform_real( const scalar_t * const src,
cpx_t * const dst ) const
{
const std::size_t N = _nfft;
if ( N == 0 )
return;
// perform complex FFT
transform( reinterpret_cast<const cpx_t*>(src), dst );
// post processing for k = 0 and k = N
dst[0] = cpx_t( dst[0].real() + dst[0].imag(),
dst[0].real() - dst[0].imag() );
// post processing for all the other k = 1, 2, ..., N-1
const scalar_t pi = std::acos( (scalar_t) -1);
const scalar_t half_phi_inc = ( _inverse ? pi : -pi ) / N;
const cpx_t twiddle_mul = std::exp( cpx_t(0, half_phi_inc) );
for ( std::size_t k = 1; 2*k < N; ++k )
{
const cpx_t w = (scalar_t)0.5 * cpx_t(
dst[k].real() + dst[N-k].real(),
dst[k].imag() - dst[N-k].imag() );
const cpx_t z = (scalar_t)0.5 * cpx_t(
dst[k].imag() + dst[N-k].imag(),
-dst[k].real() + dst[N-k].real() );
const cpx_t twiddle =
k % 2 == 0 ?
_twiddles[k/2] :
_twiddles[k/2] * twiddle_mul;
dst[ k] = w + twiddle * z;
dst[N-k] = std::conj( w - twiddle * z );
}
if ( N % 2 == 0 )
dst[N/2] = std::conj( dst[N/2] );
}
private:
void kf_bfly2( cpx_t * Fout, const size_t fstride, const std::size_t m) const
{
for (std::size_t k=0;k<m;++k) {
const cpx_t t = Fout[m+k] * _twiddles[k*fstride];
Fout[m+k] = Fout[k] - t;
Fout[k] += t;
}
}
void kf_bfly3( cpx_t * Fout, const std::size_t fstride, const std::size_t m) const
{
std::size_t k=m;
const std::size_t m2 = 2*m;
const cpx_t *tw1,*tw2;
cpx_t scratch[5];
const cpx_t epi3 = _twiddles[fstride*m];
tw1=tw2=&_twiddles[0];
do{
scratch[1] = Fout[m] * *tw1;
scratch[2] = Fout[m2] * *tw2;
scratch[3] = scratch[1] + scratch[2];
scratch[0] = scratch[1] - scratch[2];
tw1 += fstride;
tw2 += fstride*2;
Fout[m] = Fout[0] - scratch[3]*scalar_t(0.5);
scratch[0] *= epi3.imag();
Fout[0] += scratch[3];
Fout[m2] = cpx_t( Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );
Fout[m] += cpx_t( -scratch[0].imag(),scratch[0].real() );
++Fout;
}while(--k);
}
void kf_bfly4( cpx_t * const Fout, const std::size_t fstride, const std::size_t m) const
{
cpx_t scratch[7];
const scalar_t negative_if_inverse = _inverse ? -1 : +1;
for (std::size_t k=0;k<m;++k) {
scratch[0] = Fout[k+ m] * _twiddles[k*fstride ];
scratch[1] = Fout[k+2*m] * _twiddles[k*fstride*2];
scratch[2] = Fout[k+3*m] * _twiddles[k*fstride*3];
scratch[5] = Fout[k] - scratch[1];
Fout[k] += scratch[1];
scratch[3] = scratch[0] + scratch[2];
scratch[4] = scratch[0] - scratch[2];
scratch[4] = cpx_t( scratch[4].imag()*negative_if_inverse ,
-scratch[4].real()*negative_if_inverse );
Fout[k+2*m] = Fout[k] - scratch[3];
Fout[k ]+= scratch[3];
Fout[k+ m] = scratch[5] + scratch[4];
Fout[k+3*m] = scratch[5] - scratch[4];
}
}
void kf_bfly5( cpx_t * const Fout, const std::size_t fstride, const std::size_t m) const
{
cpx_t *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
cpx_t scratch[13];
const cpx_t ya = _twiddles[fstride*m];
const cpx_t yb = _twiddles[fstride*2*m];
Fout0=Fout;
Fout1=Fout0+m;
Fout2=Fout0+2*m;
Fout3=Fout0+3*m;
Fout4=Fout0+4*m;
for ( std::size_t u=0; u<m; ++u ) {
scratch[0] = *Fout0;
scratch[1] = *Fout1 * _twiddles[ u*fstride];
scratch[2] = *Fout2 * _twiddles[2*u*fstride];
scratch[3] = *Fout3 * _twiddles[3*u*fstride];
scratch[4] = *Fout4 * _twiddles[4*u*fstride];
scratch[7] = scratch[1] + scratch[4];
scratch[10]= scratch[1] - scratch[4];
scratch[8] = scratch[2] + scratch[3];
scratch[9] = scratch[2] - scratch[3];
*Fout0 += scratch[7];
*Fout0 += scratch[8];
scratch[5] = scratch[0] + cpx_t(
scratch[7].real()*ya.real() + scratch[8].real()*yb.real(),
scratch[7].imag()*ya.real() + scratch[8].imag()*yb.real()
);
scratch[6] = cpx_t(
scratch[10].imag()*ya.imag() + scratch[9].imag()*yb.imag(),
-scratch[10].real()*ya.imag() - scratch[9].real()*yb.imag()
);
*Fout1 = scratch[5] - scratch[6];
*Fout4 = scratch[5] + scratch[6];
scratch[11] = scratch[0] +
cpx_t(
scratch[7].real()*yb.real() + scratch[8].real()*ya.real(),
scratch[7].imag()*yb.real() + scratch[8].imag()*ya.real()
);
scratch[12] = cpx_t(
-scratch[10].imag()*yb.imag() + scratch[9].imag()*ya.imag(),
scratch[10].real()*yb.imag() - scratch[9].real()*ya.imag()
);
*Fout2 = scratch[11] + scratch[12];
*Fout3 = scratch[11] - scratch[12];
++Fout0;
++Fout1;
++Fout2;
++Fout3;
++Fout4;
}
}
/* perform the butterfly for one stage of a mixed radix FFT */
void kf_bfly_generic(
cpx_t * const Fout,
const size_t fstride,
const std::size_t m,
const std::size_t p
) const
{
const cpx_t * twiddles = &_twiddles[0];
if(p > _scratchbuf.size()) _scratchbuf.resize(p);
for ( std::size_t u=0; u<m; ++u ) {
std::size_t k = u;
for ( std::size_t q1=0 ; q1<p ; ++q1 ) {
_scratchbuf[q1] = Fout[ k ];
k += m;
}
k=u;
for ( std::size_t q1=0 ; q1<p ; ++q1 ) {
std::size_t twidx=0;
Fout[ k ] = _scratchbuf[0];
for ( std::size_t q=1;q<p;++q ) {
twidx += fstride * k;
if (twidx>=_nfft)
twidx-=_nfft;
Fout[ k ] += _scratchbuf[q] * twiddles[twidx];
}
k += m;
}
}
}
std::size_t _nfft;
bool _inverse;
std::vector<cpx_t> _twiddles;
std::vector<std::size_t> _stageRadix;
std::vector<std::size_t> _stageRemainder;
mutable std::vector<cpx_t> _scratchbuf;
};
#endif

View File

@ -1,10 +0,0 @@
prefix=@PKGCONFIG_KISSFFT_PREFIX@
libdir=@PKGCONFIG_KISSFFT_LIBDIR@
includedir=@PKGCONFIG_KISSFFT_INCLUDEDIR@
Name: kissfft
Description: A Fast Fourier Transform (FFT) library that tries to Keep it Simple, Stupid
Version: @PKGCONFIG_KISSFFT_VERSION@
Libs: @PKG_OPENMP@ -L${libdir} -l@KISSFFT_OUTPUT_NAME@
Cflags: -I@PKGCONFIG_KISSFFT_PKGINCLUDEDIR@ @PKG_KISSFFT_DEFS@

View File

@ -1,304 +0,0 @@
#ifndef KISSFFT_I32_CLASS_HH
#define KISSFFT_I32_CLASS_HH
#include <complex>
#include <utility>
#include <vector>
// TODO1: substitute complex<type> (behaviour not defined for nonfloats), should be faster
// TODO2: use std:: namespace
// TODO3: make unittests for all ffts (c, cpp, i32)
template <typename DType>
struct complex_s
{
DType real;
DType imag;
};
class kissfft_i32
{
private:
using scalar_type = int32_t;
using cpx_type = complex<int32_t>;
scalar_type _scale_factor;
std::size_t _nfft;
bool _inverse;
std::vector<cpx_type> _twiddles;
std::vector<std::size_t> _stageRadix;
std::vector<std::size_t> _stageRemainder;
public:
// scale_factor: upscale twiddle-factors otherwise they lie between 0..1 (out of range for integer) --> fixed point math
kissfft_i32(const std::size_t nfft, const bool inverse, const double scale_factor = 1024.0)
: _scale_factor(scalar_type(scale_factor)), _nfft(nfft), _inverse(inverse)
{
// fill twiddle factors
_twiddles.resize(_nfft);
const double phinc = (_inverse ? 2 : -2) * acos(-1.0) / _nfft;
for (std::size_t i = 0; i < _nfft; ++i)
{
_twiddles[i] = scale_factor * exp(complex<double>(0, i * phinc));
}
//factorize
//start factoring out 4's, then 2's, then 3,5,7,9,...
std::size_t n = _nfft;
std::size_t p = 4;
do
{
while (n % p)
{
switch (p)
{
case 4:
p = 2;
break;
case 2:
p = 3;
break;
default:
p += 2;
break;
}
if (p * p > n) p = n;// no more factors
}
n /= p;
_stageRadix.push_back(p);
_stageRemainder.push_back(n);
} while (n > 1);
}
/// Calculates the complex Discrete Fourier Transform.
///
/// The size of the passed arrays must be passed in the constructor.
/// The sum of the squares of the absolute values in the @c dst
/// array will be @c N times the sum of the squares of the absolute
/// values in the @c src array, where @c N is the size of the array.
/// In other words, the l_2 norm of the resulting array will be
/// @c sqrt(N) times as big as the l_2 norm of the input array.
/// This is also the case when the inverse flag is set in the
/// constructor. Hence when applying the same transform twice, but with
/// the inverse flag changed the second time, then the result will
/// be equal to the original input times @c N.
void transform(const cpx_type * FSrc,
cpx_type * FDst,
const std::size_t stage = 0,
const std::size_t fstride = 1,
const std::size_t in_stride = 1) const
{
const std::size_t p = _stageRadix[stage];
const std::size_t m = _stageRemainder[stage];
cpx_type *const Fout_beg = FDst;
cpx_type *const Fout_end = FDst + p * m;
if (m == 1)
{
do
{
*FDst = *FSrc;
FSrc += fstride * in_stride;
} while (++FDst != Fout_end);
}
else
{
do
{
// recursive call:
// DFT of size m*p performed by doing
// p instances of smaller DFTs of size m,
// each one takes a decimated version of the input
transform(FSrc, FDst, stage + 1, fstride * p, in_stride);
FSrc += fstride * in_stride;
} while ((FDst += m) != Fout_end);
}
FDst = Fout_beg;
// recombine the p smaller DFTs
switch (p)
{
case 2:
kf_bfly2(FDst, fstride, m);
break;
case 3:
kf_bfly3(FDst, fstride, m);
break;
case 4:
kf_bfly4(FDst, fstride, m);
break;
case 5:
kf_bfly5(FDst, fstride, m);
break;
default:
kf_bfly_generic(FDst, fstride, m, p);
break;
}
}
private:
void kf_bfly2(cpx_type *const Fout, const size_t fstride, const std::size_t m) const
{
for (std::size_t k = 0; k < m; ++k)
{
const cpx_type t = (Fout[m + k] * _twiddles[k * fstride]) / _scale_factor;
Fout[m + k] = Fout[k] - t;
Fout[k] += t;
}
}
void kf_bfly3(cpx_type *Fout, const std::size_t fstride, const std::size_t m) const
{
std::size_t k = m;
const std::size_t m2 = 2 * m;
const cpx_type *tw1, *tw2;
cpx_type scratch[5];
const cpx_type epi3 = _twiddles[fstride * m];
tw1 = tw2 = &_twiddles[0];
do
{
scratch[1] = (Fout[m] * *tw1) / _scale_factor;
scratch[2] = (Fout[m2] * *tw2) / _scale_factor;
scratch[3] = scratch[1] + scratch[2];
scratch[0] = scratch[1] - scratch[2];
tw1 += fstride;
tw2 += fstride * 2;
Fout[m] = Fout[0] - (scratch[3] / 2);
scratch[0] *= epi3.imag();
scratch[0] /= _scale_factor;
Fout[0] += scratch[3];
Fout[m2] = cpx_type(Fout[m].real() + scratch[0].imag(), Fout[m].imag() - scratch[0].real());
Fout[m] += cpx_type(-scratch[0].imag(), scratch[0].real());
++Fout;
} while (--k);
}
void kf_bfly4(cpx_type *const Fout, const std::size_t fstride, const std::size_t m) const
{
cpx_type scratch[7];
const scalar_type negative_if_inverse = _inverse ? -1 : +1;
for (std::size_t k = 0; k < m; ++k)
{
scratch[0] = (Fout[k + m] * _twiddles[k * fstride]) / _scale_factor;
scratch[1] = (Fout[k + 2 * m] * _twiddles[k * fstride * 2]) / _scale_factor;
scratch[2] = (Fout[k + 3 * m] * _twiddles[k * fstride * 3]) / _scale_factor;
scratch[5] = Fout[k] - scratch[1];
Fout[k] += scratch[1];
scratch[3] = scratch[0] + scratch[2];
scratch[4] = scratch[0] - scratch[2];
scratch[4] = cpx_type(scratch[4].imag() * negative_if_inverse,
-scratch[4].real() * negative_if_inverse);
Fout[k + 2 * m] = Fout[k] - scratch[3];
Fout[k] += scratch[3];
Fout[k + m] = scratch[5] + scratch[4];
Fout[k + 3 * m] = scratch[5] - scratch[4];
}
}
void kf_bfly5(cpx_type *const Fout, const std::size_t fstride, const std::size_t m) const
{
cpx_type *Fout0, *Fout1, *Fout2, *Fout3, *Fout4;
cpx_type scratch[13];
const cpx_type ya = _twiddles[fstride * m];
const cpx_type yb = _twiddles[fstride * 2 * m];
Fout0 = Fout;
Fout1 = Fout0 + m;
Fout2 = Fout0 + 2 * m;
Fout3 = Fout0 + 3 * m;
Fout4 = Fout0 + 4 * m;
for (std::size_t u = 0; u < m; ++u)
{
scratch[0] = *Fout0;
scratch[1] = (*Fout1 * _twiddles[u * fstride]) / _scale_factor;
scratch[2] = (*Fout2 * _twiddles[2 * u * fstride]) / _scale_factor;
scratch[3] = (*Fout3 * _twiddles[3 * u * fstride]) / _scale_factor;
scratch[4] = (*Fout4 * _twiddles[4 * u * fstride]) / _scale_factor;
scratch[7] = scratch[1] + scratch[4];
scratch[10] = scratch[1] - scratch[4];
scratch[8] = scratch[2] + scratch[3];
scratch[9] = scratch[2] - scratch[3];
*Fout0 += scratch[7];
*Fout0 += scratch[8];
scratch[5] = scratch[0] + (cpx_type(
scratch[7].real() * ya.real() + scratch[8].real() * yb.real(),
scratch[7].imag() * ya.real() + scratch[8].imag() * yb.real() ) / _scale_factor);
scratch[6] = cpx_type(
scratch[10].imag() * ya.imag() + scratch[9].imag() * yb.imag(),
-scratch[10].real() * ya.imag() - scratch[9].real() * yb.imag() ) / _scale_factor;
*Fout1 = scratch[5] - scratch[6];
*Fout4 = scratch[5] + scratch[6];
scratch[11] = scratch[0] + (cpx_type(
scratch[7].real() * yb.real() + scratch[8].real() * ya.real(),
scratch[7].imag() * yb.real() + scratch[8].imag() * ya.real() ) / _scale_factor);
scratch[12] = cpx_type(
-scratch[10].imag() * yb.imag() + scratch[9].imag() * ya.imag(),
scratch[10].real() * yb.imag() - scratch[9].real() * ya.imag() ) / _scale_factor;
*Fout2 = scratch[11] + scratch[12];
*Fout3 = scratch[11] - scratch[12];
++Fout0;
++Fout1;
++Fout2;
++Fout3;
++Fout4;
}
}
/* perform the butterfly for one stage of a mixed radix FFT */
void kf_bfly_generic(cpx_type * const Fout, const size_t fstride, const std::size_t m, const std::size_t p) const
{
const cpx_type *twiddles = &_twiddles[0];
cpx_type scratchbuf[p];
for (std::size_t u = 0; u < m; ++u)
{
std::size_t k = u;
for (std::size_t q1 = 0; q1 < p; ++q1)
{
scratchbuf[q1] = Fout[k];
k += m;
}
k = u;
for (std::size_t q1 = 0; q1 < p; ++q1)
{
std::size_t twidx = 0;
Fout[k] = scratchbuf[0];
for (std::size_t q = 1; q < p; ++q)
{
twidx += fstride * k;
if (twidx >= _nfft)
twidx -= _nfft;
Fout[k] += (scratchbuf[q] * twiddles[twidx]) / _scale_factor;
}
k += m;
}
}
}
};
#endif

View File

@ -1,63 +0,0 @@
function(add_kissfft_test_executable NAME)
add_kissfft_executable(${NAME} ${ARGN})
target_include_directories(${NAME} PRIVATE ..)
add_test(NAME ${NAME} COMMAND ${NAME})
set_tests_properties(${NAME} PROPERTIES TIMEOUT 3600)
endfunction()
set(KISSFFT_TEST_NUMFFTS 10000)
#
# Add tools-independent fastfilt_* (../tools/fft_*) executable without adding a test
#
add_kissfft_executable(fastfilt ../tools/fftutil.c)
target_include_directories(fastfilt PRIVATE ..)
#
# Add test executables and define tests
#
add_kissfft_test_executable(bm_kiss benchkiss.c pstats.c)
# add_test(NAME benchmar COMMAND ${NAME})
# set_tests_properties(${NAME} PROPERTIES TIMEOUT 3600)
include(FindPkgConfig)
if(KISSFFT_FLOAT)
set(fftw3_pkg fftw3f)
else()
set(fftw3_pkg fftw3)
endif()
pkg_check_modules(fftw3 REQUIRED IMPORTED_TARGET ${fftw3_pkg})
add_kissfft_test_executable(bm_fftw benchfftw.c pstats.c)
target_link_libraries(bm_fftw PRIVATE PkgConfig::fftw3)
add_kissfft_test_executable(st twotonetest.c)
add_kissfft_test_executable(tkfc twotonetest.c)
target_compile_definitions(tkfc PRIVATE KFC_TEST)
add_kissfft_test_executable(ffr twotonetest.c)
add_kissfft_test_executable(tr test_real.c)
add_kissfft_test_executable(testcpp testcpp.cc)
if(KISSFFT_DATATYPE MATCHES "^simd$")
add_kissfft_test_executable(tsimd test_simd.c)
target_compile_definitions(tsimd PRIVATE USE_SIMD)
if (NOT MSVC)
target_compile_options(kissfft PRIVATE -msse)
else()
target_compile_options(kissfft PRIVATE "/arch:SSE")
endif()
endif()
find_package(PythonInterp REQUIRED)
add_test(NAME testkiss.py COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/testkiss.py")
list(APPEND TESTKISS_PY_ENV "KISSFFT_DATATYPE=${KISSFFT_DATATYPE}")
list(APPEND TESTKISS_PY_ENV "KISSFFT_OPENMP=${KISSFFT_OPENMP}")
set_tests_properties(testkiss.py PROPERTIES
TIMEOUT 3600
ENVIRONMENT "${TESTKISS_PY_ENV}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

View File

@ -1,188 +0,0 @@
#
# Warnings
#
WARNINGS = -W -Wall -Wstrict-prototypes -Wmissing-prototypes \
-Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast \
-Wwrite-strings
#
# Compile-time definitions
#
CFLAGS = -O3 -I.. -I../tools $(WARNINGS)
CFLAGS += -ffast-math -fomit-frame-pointer
#CFLAGS += -funroll-loops
#CFLAGS += -march=prescott
#CFLAGS += -mtune=native
# TIP: try adding -openmp or -fopenmp to enable OPENMP directives and use of multiple cores
#CFLAGS += -fopenmp
CFLAGS += $(CFLAGADD)
CXXFLAGS = -O3 -ffast-math -fomit-frame-pointer -I.. -W -Wall -march=native -mtune=native
#
# Count of FFT runs tested
#
ifeq "$(NFFT)" ""
NFFT = 1800
endif
ifeq "$(NUMFFTS)" ""
NUMFFTS = 10000
endif
#
# Test binary executable names
#
SELFTESTSRC = twotonetest.c
ifneq ($(KISSFFT_OPENMP),1)
BENCHKISS = bm-kiss-$(KISSFFT_DATATYPE)
BENCHFFTW = bm-fftw-$(KISSFFT_DATATYPE)
SELFTEST = st-$(KISSFFT_DATATYPE)
TESTREAL = tr-$(KISSFFT_DATATYPE)
TESTKFC = tkfc-$(KISSFFT_DATATYPE)
TESTFASTFILT = fastfilt-$(KISSFFT_DATATYPE)
TESTCPP = testcpp-$(KISSFFT_DATATYPE)
TESTSIMD = testsimd
else
BENCHKISS = bm-kiss-$(KISSFFT_DATATYPE)-openmp
BENCHFFTW = bm-fftw-$(KISSFFT_DATATYPE)-openmp
SELFTEST = st-$(KISSFFT_DATATYPE)-openmp
TESTREAL = tr-$(KISSFFT_DATATYPE)-openmp
TESTKFC = tkfc-$(KISSFFT_DATATYPE)-openmp
TESTFASTFILT = fastfilt-$(KISSFFT_DATATYPE)-openmp
TESTCPP = testcpp-$(KISSFFT_DATATYPE)-openmp
TESTSIMD = testsimd-openmp
CFLAGS += -fopenmp
CXXFLAGS += -fopenmp
endif
ifeq "$(KISSFFT_DATATYPE)" "float"
# fftw needs to be built with --enable-float to build this lib
FFTWLIB = -lfftw3f
else
FFTWLIB = -lfftw3
endif
FFTWLIBDIR ?= $(ABS_LIBDIR)
ABS_FFTWLIBDIR = $(abspath $(FFTWLIBDIR))
#
# Check missing external libraries
#
ifneq ($(MAKECMDGOALS),clean)
LIBFFTW_MISSING = $(shell echo "int main(){return 0;}" > _test_library_dummy.c; \
$(CC) -o _test_library_dummy _test_library_dummy.c $(FFTWLIB) -L$(ABS_FFTWLIBDIR); \
echo $$?; \
rm -f _test_library_dummy.c _test_library_dummy)
endif
#
# Find Python interpreter
#
ifneq ($(MAKECMDGOALS),clean)
PYTHON_INTERPRETER = $(shell python --version)
ifeq ($(PYTHON_INTERPRETER), )
PYTHON_INTERPRETER = $(shell python2 --version)
ifeq ($(PYTHON_INTERPRETER), )
PYTHON_INTERPRETER = $(shell python3 --version)
ifeq ($(PYTHON_INTERPRETER), )
$(error ERROR: Can not find Python interpreter!)
else
PYTHON_INTERPRETER = "python3"
endif
else
PYTHON_INTERPRETER = "python2"
endif
else
PYTHON_INTERPRETER = "python"
endif
endif
#
# Target: "make all"
#
all: $(BENCHKISS) $(SELFTEST) $(BENCHFFTW) $(TESTREAL) $(TESTKFC) $(TESTFASTFILT)
#
# Individual test make rules
#
$(SELFTEST): $(SELFTESTSRC)
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(TESTKFC): ../kfc.c
$(CC) -o $@ $(CFLAGS) -DKFC_TEST $(TYPEFLAGS) $^ -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(TESTREAL): test_real.c
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(BENCHKISS): benchkiss.c pstats.c
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $^ -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(TESTFASTFILT): ../tools/fftutil.c
$(CC) -o $@ $(CFLAGS) -DKFC_TEST $(TYPEFLAGS) $^ -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(BENCHFFTW): benchfftw.c pstats.c
$(warning ======attempting to build FFTW benchmark)
ifeq ($(LIBFFTW_MISSING), 0)
$(CC) -o $@ $(CFLAGS) -DDATATYPE$(KISSFFT_DATATYPE) $^ $(FFTWLIB) -L$(ABS_FFTWLIBDIR) -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
else
$(warning WARNING: No FFTW development files found! FFTW not available for comparison!0
endif
#
# Test SSE
#
$(TESTSIMD): test_simd.c
ifeq "$(KISSFFT_DATATYPE)" "simd"
$(CC) -o $@ -g $(CFLAGS) -DUSE_SIMD=1 -msse $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
else
$(error ERROR: This test makes sense only with KISSFFT_DATATYPE=simd)
endif
testsse: $(TESTSIMD)
LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTSIMD)
#
# Test C++
#
$(TESTCPP): testcpp.cc ../kissfft.hh
$(CXX) -o $@ $(CXXFLAGS) testcpp.cc -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
testcpp: $(TESTCPP)
LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTCPP)
#
# Target: "make test"
#
test: all
ifeq "$(KISSFFT_DATATYPE)" "simd"
make testsse
endif
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTKFC)
$(warning ======1d & 2-d complex fft self test (type= $(KISSFFT_DATATYPE) ))
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(SELFTEST)
$(warning ======real FFT (type= $(KISSFFT_DATATYPE) ))
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTREAL)
$(warning ======timing test (type=$(KISSFFT_DATATYPE)))
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(BENCHKISS) -x $(NUMFFTS) -n $(NFFT)
@[ -x ./$(BENCHFFTW) ] && LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(BENCHFFTW) -x $(NUMFFTS) -n $(NFFT) || true
$(warning ======higher dimensions (type=$(KISSFFT_DATATYPE)))
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." $(PYTHON_INTERPRETER) ./testkiss.py
#
# Target: "make clean"
#
clean:
rm -f *~ bm-* st-* tr-* kf-* tkfc-* ff-* fastfilt-* *.pyc *.pyo *.dat testcpp-* testsimd testsimd-* _test_library_dummy _test_library_dummy.c

View File

@ -1,101 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fftw3.h>
#include <unistd.h>
#include "pstats.h"
#ifdef DATATYPEdouble
#define CPXTYPE fftw_complex
#define PLAN fftw_plan
#define FFTMALLOC fftw_malloc
#define MAKEPLAN fftw_plan_dft_1d
#define DOFFT fftw_execute
#define DESTROYPLAN fftw_destroy_plan
#define FFTFREE fftw_free
#elif defined(DATATYPEfloat)
#define CPXTYPE fftwf_complex
#define PLAN fftwf_plan
#define FFTMALLOC fftwf_malloc
#define MAKEPLAN fftwf_plan_dft_1d
#define DOFFT fftwf_execute
#define DESTROYPLAN fftwf_destroy_plan
#define FFTFREE fftwf_free
#endif
#ifndef CPXTYPE
int main(void)
{
fprintf(stderr,"Datatype not available in FFTW\n" );
return 0;
}
#else
int main(int argc,char ** argv)
{
int nfft=1024;
int isinverse=0;
int numffts=1000,i;
CPXTYPE * in=NULL;
CPXTYPE * out=NULL;
PLAN p;
pstats_init();
while (1) {
int c = getopt (argc, argv, "n:ix:h");
if (c == -1)
break;
switch (c) {
case 'n':
nfft = atoi (optarg);
break;
case 'x':
numffts = atoi (optarg);
break;
case 'i':
isinverse = 1;
break;
case 'h':
case '?':
default:
fprintf(stderr,"options:\n-n N: complex fft length\n-i: inverse\n-x N: number of ffts to compute\n"
"");
}
}
in=FFTMALLOC(sizeof(CPXTYPE) * nfft);
out=FFTMALLOC(sizeof(CPXTYPE) * nfft);
for (i=0;i<nfft;++i ) {
in[i][0] = rand() - RAND_MAX/2;
in[i][1] = rand() - RAND_MAX/2;
}
if ( isinverse )
p = MAKEPLAN(nfft, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
else
p = MAKEPLAN(nfft, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
for (i=0;i<numffts;++i)
DOFFT(p);
DESTROYPLAN(p);
FFTFREE(in); FFTFREE(out);
fprintf(stderr,"fftw\tnfft=%d\tnumffts=%d\n", nfft,numffts);
pstats_report();
return 0;
}
#endif

View File

@ -1,129 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/times.h>
#include <unistd.h>
#include "kiss_fft.h"
#include "kiss_fftr.h"
#include "kiss_fftnd.h"
#include "kiss_fftndr.h"
#include "pstats.h"
static
int getdims(int * dims, char * arg)
{
char *s;
int ndims=0;
while ( (s=strtok( arg , ",") ) ) {
dims[ndims++] = atoi(s);
//printf("%s=%d\n",s,dims[ndims-1]);
arg=NULL;
}
return ndims;
}
int main(int argc,char ** argv)
{
int k;
int nfft[32];
int ndims = 1;
int isinverse=0;
int numffts=1000,i;
kiss_fft_cpx * buf;
kiss_fft_cpx * bufout;
int real = 0;
nfft[0] = 1024;// default
while (1) {
int c = getopt (argc, argv, "n:ix:r");
if (c == -1)
break;
switch (c) {
case 'r':
real = 1;
break;
case 'n':
ndims = getdims(nfft, optarg );
if (nfft[0] != kiss_fft_next_fast_size(nfft[0]) ) {
int ng = kiss_fft_next_fast_size(nfft[0]);
fprintf(stderr,"warning: %d might be a better choice for speed than %d\n",ng,nfft[0]);
}
break;
case 'x':
numffts = atoi (optarg);
break;
case 'i':
isinverse = 1;
break;
}
}
int nbytes = sizeof(kiss_fft_cpx);
for (k=0;k<ndims;++k)
nbytes *= nfft[k];
#ifdef USE_SIMD
numffts /= 4;
fprintf(stderr,"since SIMD implementation does 4 ffts at a time, numffts is being reduced to %d\n",numffts);
#endif
buf=(kiss_fft_cpx*)KISS_FFT_MALLOC(nbytes);
bufout=(kiss_fft_cpx*)KISS_FFT_MALLOC(nbytes);
memset(buf,0,nbytes);
pstats_init();
if (ndims==1) {
if (real) {
kiss_fftr_cfg st = kiss_fftr_alloc( nfft[0] ,isinverse ,0,0);
if (isinverse)
for (i=0;i<numffts;++i)
kiss_fftri( st ,(kiss_fft_cpx*)buf,(kiss_fft_scalar*)bufout );
else
for (i=0;i<numffts;++i)
kiss_fftr( st ,(kiss_fft_scalar*)buf,(kiss_fft_cpx*)bufout );
free(st);
}else{
kiss_fft_cfg st = kiss_fft_alloc( nfft[0] ,isinverse ,0,0);
for (i=0;i<numffts;++i)
kiss_fft( st ,buf,bufout );
free(st);
}
}else{
if (real) {
kiss_fftndr_cfg st = kiss_fftndr_alloc( nfft,ndims ,isinverse ,0,0);
if (isinverse)
for (i=0;i<numffts;++i)
kiss_fftndri( st ,(kiss_fft_cpx*)buf,(kiss_fft_scalar*)bufout );
else
for (i=0;i<numffts;++i)
kiss_fftndr( st ,(kiss_fft_scalar*)buf,(kiss_fft_cpx*)bufout );
free(st);
}else{
kiss_fftnd_cfg st= kiss_fftnd_alloc(nfft,ndims,isinverse ,0,0);
for (i=0;i<numffts;++i)
kiss_fftnd( st ,buf,bufout );
free(st);
}
}
free(buf); free(bufout);
fprintf(stderr,"KISS\tnfft=");
for (k=0;k<ndims;++k)
fprintf(stderr, "%d,",nfft[k]);
fprintf(stderr,"\tnumffts=%d\n" ,numffts);
pstats_report();
kiss_fft_cleanup();
return 0;
}

View File

@ -1,134 +0,0 @@
/*
* This program is in the public domain
* A program that helps the authors of the fine fftw library benchmark kiss
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: Unlicense
* See LICENSES/Unlicense for more information.
*/
#include "bench-user.h"
#include <math.h>
#include "kiss_fft.h"
#include "kiss_fftnd.h"
#include "kiss_fftr.h"
BEGIN_BENCH_DOC
BENCH_DOC("name", "kissfft")
BENCH_DOC("version", "1.0.1")
BENCH_DOC("year", "2004")
BENCH_DOC("author", "Mark Borgerding")
BENCH_DOC("language", "C")
BENCH_DOC("url", "http://sourceforge.net/projects/kissfft/")
BENCH_DOC("copyright",
"Copyright (c) 2003,4 Mark Borgerding\n"
"\n"
"All rights reserved.\n"
"\n"
"Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n"
"\n"
" * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n"
" * 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.\n"
" * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.\n")
END_BENCH_DOC
int can_do(struct problem *p)
{
if (p->rank == 1) {
if (p->kind == PROBLEM_REAL) {
return (p->n[0] & 1) == 0; /* only even real is okay */
} else {
return 1;
}
} else {
return p->kind == PROBLEM_COMPLEX;
}
}
static kiss_fft_cfg cfg=NULL;
static kiss_fftr_cfg cfgr=NULL;
static kiss_fftnd_cfg cfgnd=NULL;
#define FAILIF( c ) \
if ( c ) do {\
fprintf(stderr,\
"kissfft: " #c " (file=%s:%d errno=%d %s)\n",\
__FILE__,__LINE__ , errno,strerror( errno ) ) ;\
exit(1);\
}while(0)
void setup(struct problem *p)
{
size_t i;
/*
fprintf(stderr,"%s %s %d-d ",
(p->sign == 1)?"Inverse":"Forward",
p->kind == PROBLEM_COMPLEX?"Complex":"Real",
p->rank);
*/
if (p->rank == 1) {
if (p->kind == PROBLEM_COMPLEX) {
cfg = kiss_fft_alloc (p->n[0], (p->sign == 1), 0, 0);
FAILIF(cfg==NULL);
}else{
cfgr = kiss_fftr_alloc (p->n[0], (p->sign == 1), 0, 0);
FAILIF(cfgr==NULL);
}
}else{
int dims[5];
for (i=0;i<p->rank;++i){
dims[i] = p->n[i];
}
/* multi-dimensional */
if (p->kind == PROBLEM_COMPLEX) {
cfgnd = kiss_fftnd_alloc( dims , p->rank, (p->sign == 1), 0, 0 );
FAILIF(cfgnd==NULL);
}
}
}
void doit(int iter, struct problem *p)
{
int i;
void *in = p->in;
void *out = p->out;
if (p->in_place)
out = p->in;
if (p->rank == 1) {
if (p->kind == PROBLEM_COMPLEX){
for (i = 0; i < iter; ++i)
kiss_fft (cfg, in, out);
} else {
/* PROBLEM_REAL */
if (p->sign == -1) /* FORWARD */
for (i = 0; i < iter; ++i)
kiss_fftr (cfgr, in, out);
else
for (i = 0; i < iter; ++i)
kiss_fftri (cfgr, in, out);
}
}else{
/* multi-dimensional */
for (i = 0; i < iter; ++i)
kiss_fftnd(cfgnd,in,out);
}
}
void done(struct problem *p)
{
free(cfg);
cfg=NULL;
free(cfgr);
cfgr=NULL;
free(cfgnd);
cfgnd=NULL;
UNUSED(p);
}

View File

@ -1,275 +0,0 @@
#!/bin/sh
#
# Test suite for kissfft
#
# Copyright (c) 2021, Vasyl Gello.
# This file is part of KISS FFT - https://github.com/mborgerding/kissfft
#
# SPDX-License-Identifier: BSD-3-Clause
# See COPYING file for more information.
#
if [ ! -f CHANGELOG ] && [ ! -f kiss_fft.h ]; then
echo "ERROR: Please run this testsuite from top level of kissfft source tree!" >&2
return 1
fi
TESTSUITEOUTDIR="$2"
if [ -z "$TESTSUITEOUTDIR" ]; then
TESTSUITEOUTDIR="/tmp/kissfft-testsuite"
fi
if ! mkdir -p "$TESTSUITEOUTDIR"; then
echo "ERROR: Can not create directory '$TESTSUITEOUTDIR'!" >&2
return 1
fi
#
# Test runner function
#
# Parameters:
#
# $1 - Action: "test" or "install"
# $2 - Build type: "make" or "cmake"
# $3 - Data type: "float" "double" "int16_t" "int32_t" "simd"
# $4 - library type: "shared" or "static"
# $5 - Include tools: "yes" or "no"
# $6 - Install root dir: "existing writable directory"
#
test_runner() {
_ACTION="$1"
_BUILD_TYPE="$2"
_DATA_TYPE="$3"
_LIB_TYPE="$4"
_OPENMP="$5"
_INCLUDE_TOOLS="$6"
_INSTALL_ROOT_DIR="$7"
_CMAKE_OPTS=""
_MAKE_OPTS=""
# Prepare install directory name without "$_OPENMP" and "$_INCLUDE_TOOLS"
_INSTALL_DIR="$_INSTALL_ROOT_DIR/$_BUILD_TYPE/$_DATA_TYPE/$_LIB_TYPE"
# Prepare log file without "$_OPENMP" and "$_INCLUDE_TOOLS"
_LOG_FILE="$_INSTALL_ROOT_DIR/$_ACTION-$_BUILD_TYPE-$_DATA_TYPE-$_LIB_TYPE"
# Validate parameters
# Create install root directory
if [ -z "$_INSTALL_ROOT_DIR" ]; then
echo "" >&2
echo "ERROR: Empty path to writeable directory" >&2
echo "" >&2
return 1
fi
if [ ! -d "$_INSTALL_ROOT_DIR" ]; then
if ! mkdir -p "$_INSTALL_ROOT_DIR"; then
echo "" >&2
echo "ERROR: Can not create directory '$_INSTALL_ROOT_DIR'" >&2
echo "" >&2
return 1
fi
fi
if [ "$_BUILD_TYPE" != "make" ] && [ "$_BUILD_TYPE" != "cmake" ]; then
echo "ERROR: Build type must be one of: cmake make" >&2
echo "" >&2
return 1
fi
if [ "$_DATA_TYPE" != "double" ] &&
[ "$_DATA_TYPE" != "float" ] &&
[ "$_DATA_TYPE" != "int16_t" ] &&
[ "$_DATA_TYPE" != "int32_t" ] &&
[ "$_DATA_TYPE" != "simd" ];
then
echo "ERROR: Data type must be one of: double float int16_t int32_t simd" >&2
echo "" >&2
return 1
else
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_DATATYPE=$_DATA_TYPE"
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_DATATYPE=$_DATA_TYPE"
fi
if [ "$_LIB_TYPE" != "shared" ] && [ "$_LIB_TYPE" != "static" ]; then
echo "ERROR: Library type must be one of: shared static" >&2
echo "" >&2
return 1
fi
case "$_LIB_TYPE" in
"shared")
;;
"static")
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_STATIC=1"
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_STATIC=ON"
;;
"*")
echo "ERROR: OpenMP inclusion must be one of: no yes" >&2
echo "" >&2
return 1
;;
esac
case "$_OPENMP" in
"yes")
_INSTALL_DIR="$_INSTALL_DIR/openmp"
_LOG_FILE="$_LOG_FILE-openmp"
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_OPENMP=1"
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_OPENMP=ON"
;;
"no")
_INSTALL_DIR="$_INSTALL_DIR/noopenmp"
_LOG_FILE="$_LOG_FILE-noopenmp"
;;
"*")
echo "ERROR: OpenMP inclusion must be one of: no yes" >&2
echo "" >&2
return 1
;;
esac
case "$_INCLUDE_TOOLS" in
"yes")
_INSTALL_DIR="$_INSTALL_DIR/tools"
_LOG_FILE="$_LOG_FILE-tools"
;;
"no")
_INSTALL_DIR="$_INSTALL_DIR/notools"
_LOG_FILE="$_LOG_FILE-notools"
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_TOOLS=0"
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_TOOLS=OFF"
;;
"*")
echo "ERROR: Tools inclusion must be one of: no yes" >&2
echo "" >&2
return 1
;;
esac
# Clean kissfft
rm -rf build 1>/dev/null 2>/dev/null
make clean 1>/dev/null 2>&1
# Prepare status line
_STATUS_LINE="Running: $(printf "% 10s" "$_ACTION") |"
_STATUS_LINE="$_STATUS_LINE Build Type: $(printf "% 7s" "$_BUILD_TYPE") |"
_STATUS_LINE="$_STATUS_LINE Data Type: $(printf "% 7s" "$_DATA_TYPE") |"
_STATUS_LINE="$_STATUS_LINE Lib Type: $(printf "% 7s" "$_LIB_TYPE") |"
_STATUS_LINE="$_STATUS_LINE OpenMP: $(printf "% 3s" "$_OPENMP") |"
_STATUS_LINE="$_STATUS_LINE Tools: $(printf "% 3s" "$_INCLUDE_TOOLS") |"
# Skip tests with tools not installed as they are same as with tools
if [ "$_ACTION" = "test" ] && [ "$_INCLUDE_TOOLS" = "no" ]; then
return 2
fi
# Run selected action
echo "$_STATUS_LINE"
case "$_ACTION" in
"test")
_MAKE_OPTS="$_MAKE_OPTS PREFIX=$_INSTALL_DIR"
_CMAKE_OPTS="$_CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=$_INSTALL_DIR"
case "$_BUILD_TYPE" in
"make")
make $_MAKE_OPTS all 1>>"$_LOG_FILE" 2>&1 &&
make $_MAKE_OPTS testsingle 1>>"$_LOG_FILE" 2>&1 &&
_RET=$?
;;
"cmake")
mkdir build 1>/dev/null 2>&1 &&
cd build &&
cmake $_CMAKE_OPTS .. 1>"$_LOG_FILE" 2>&1 &&
make all 1>>"$_LOG_FILE" 2>&1 &&
make test 1>>"$_LOG_FILE" 2>&1
_RET=$?
cd ..
;;
esac
;;
"install")
_MAKE_OPTS="$_MAKE_OPTS PREFIX=$_INSTALL_DIR"
_CMAKE_OPTS="$_CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=$_INSTALL_DIR"
case "$_BUILD_TYPE" in
"make")
make $_MAKE_OPTS install 1>>"$_LOG_FILE" 2>&1
_RET=$?
;;
"cmake")
mkdir build 1>/dev/null 2>&1 &&
cd build &&
cmake $_CMAKE_OPTS .. 1>"$_LOG_FILE" 2>&1 &&
make all 1>>"$_LOG_FILE" 2>&1 &&
make install 1>>"$_LOG_FILE" 2>&1
_RET=$?
cd ..
;;
esac
;;
*)
echo "ERROR: Action must be one of: test install" >&2
echo "" >&2
return 1
;;
esac
# Clean kissfft
rm -rf build 1>/dev/null 2>/dev/null
make clean 1>/dev/null 2>&1
# Return result
[ $_RET -eq 0 ] && return 0 || return 1
}
# Main script
for ACTION in test install; do
for BUILD_TYPE in make cmake; do
for DATA_TYPE in float double int16_t int32_t simd; do
for LIB_TYPE in shared static; do
for OPENMP in no yes; do
for INCLUDE_TOOLS in no yes; do
test_runner \
"$ACTION" \
"$BUILD_TYPE" \
"$DATA_TYPE" \
"$LIB_TYPE" \
"$OPENMP" \
"$INCLUDE_TOOLS" \
"$TESTSUITEOUTDIR"
case $? in
0)
echo "Result: OK"
;;
1)
echo "Result: FAIL"
;;
2)
# Ignore it
echo "Result: IGNORE" 1>/dev/null
;;
esac
done
done
done
done
done
done 2>&1 | tee "$TESTSUITEOUTDIR/all-tests.log"

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/times.h>
#include <sys/types.h>
#include <unistd.h>
#include "pstats.h"
static struct tms tms_beg;
static struct tms tms_end;
static int has_times = 0;
void pstats_init(void)
{
has_times = times(&tms_beg) != -1;
}
static void tms_report(void)
{
double cputime;
if (! has_times )
return;
times(&tms_end);
cputime = ( ((float)tms_end.tms_utime + tms_end.tms_stime + tms_end.tms_cutime + tms_end.tms_cstime ) -
((float)tms_beg.tms_utime + tms_beg.tms_stime + tms_beg.tms_cutime + tms_beg.tms_cstime ) )
/ sysconf(_SC_CLK_TCK);
fprintf(stderr,"\tcputime=%.3f\n" , cputime);
}
static void ps_report(void)
{
char buf[1024];
#ifdef __APPLE__ /* MAC OS X */
sprintf(buf,"ps -o command,majflt,minflt,rss,pagein,vsz -p %d 1>&2",getpid() );
#else /* GNU/Linux */
sprintf(buf,"ps -o comm,majflt,minflt,rss,drs,pagein,sz,trs,vsz %d 1>&2",getpid() );
#endif
if (system( buf )==-1) {
perror("system call to ps failed");
}
}
void pstats_report()
{
ps_report();
tms_report();
}

View File

@ -1,14 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef PSTATS_H
#define PSTATS_H
void pstats_init(void);
void pstats_report(void);
#endif

View File

@ -1,179 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"
#include <sys/times.h>
#include <time.h>
#include <unistd.h>
static double cputime(void)
{
struct tms t;
times(&t);
return (double)(t.tms_utime + t.tms_stime)/ sysconf(_SC_CLK_TCK) ;
}
static
kiss_fft_scalar rand_scalar(void)
{
#ifdef USE_SIMD
return _mm_set1_ps(rand()-RAND_MAX/2);
#else
kiss_fft_scalar s = (kiss_fft_scalar)(rand() -RAND_MAX/2);
return s/2;
#endif
}
static
double snr_compare( kiss_fft_cpx * vec1,kiss_fft_cpx * vec2, int n)
{
int k;
double sigpow=1e-10,noisepow=1e-10,err,snr,scale=0;
#ifdef USE_SIMD
float *fv1 = (float*)vec1;
float *fv2 = (float*)vec2;
for (k=0;k<8*n;++k) {
sigpow += *fv1 * *fv1;
err = *fv1 - *fv2;
noisepow += err*err;
++fv1;
++fv2;
}
#else
for (k=0;k<n;++k) {
sigpow += (double)vec1[k].r * (double)vec1[k].r +
(double)vec1[k].i * (double)vec1[k].i;
err = (double)vec1[k].r - (double)vec2[k].r;
noisepow += err * err;
err = (double)vec1[k].i - (double)vec2[k].i;
noisepow += err * err;
if (vec1[k].r)
scale +=(double) vec2[k].r / (double)vec1[k].r;
}
#endif
snr = 10*log10( sigpow / noisepow );
scale /= n;
if (snr<10) {
printf( "\npoor snr, try a scaling factor %f\n" , scale );
exit(1);
}
return snr;
}
#ifndef NUMFFTS
#define NUMFFTS 10000
#endif
int main(int argc,char ** argv)
{
int nfft = 8*3*5;
double ts,tfft,trfft;
int i;
if (argc>1)
nfft = atoi(argv[1]);
kiss_fft_cpx cin[nfft];
kiss_fft_cpx cout[nfft];
kiss_fft_cpx sout[nfft];
kiss_fft_cfg kiss_fft_state;
kiss_fftr_cfg kiss_fftr_state;
kiss_fft_scalar rin[nfft+2];
kiss_fft_scalar rout[nfft+2];
kiss_fft_scalar zero;
memset(&zero,0,sizeof(zero) ); // ugly way of setting short,int,float,double, or __m128 to zero
srand(time(0));
for (i=0;i<nfft;++i) {
rin[i] = rand_scalar();
cin[i].r = rin[i];
cin[i].i = zero;
}
kiss_fft_state = kiss_fft_alloc(nfft,0,0,0);
kiss_fftr_state = kiss_fftr_alloc(nfft,0,0,0);
kiss_fft(kiss_fft_state,cin,cout);
kiss_fftr(kiss_fftr_state,rin,sout);
/*
printf(" results from kiss_fft : (%f,%f), (%f,%f), (%f,%f) ...\n "
, (float)cout[0].r , (float)cout[0].i
, (float)cout[1].r , (float)cout[1].i
, (float)cout[2].r , (float)cout[2].i);
printf(" results from kiss_fftr: (%f,%f), (%f,%f), (%f,%f) ...\n "
, (float)sout[0].r , (float)sout[0].i
, (float)sout[1].r , (float)sout[1].i
, (float)sout[2].r , (float)sout[2].i);
*/
printf( "nfft=%d, inverse=%d, snr=%g\n",
nfft,0, snr_compare(cout,sout,(nfft/2)+1) );
ts = cputime();
for (i=0;i<NUMFFTS;++i) {
kiss_fft(kiss_fft_state,cin,cout);
}
tfft = cputime() - ts;
ts = cputime();
for (i=0;i<NUMFFTS;++i) {
kiss_fftr( kiss_fftr_state, rin, cout );
/* kiss_fftri(kiss_fftr_state,cout,rin); */
}
trfft = cputime() - ts;
printf("%d complex ffts took %gs, real took %gs\n",NUMFFTS,tfft,trfft);
free(kiss_fft_state);
free(kiss_fftr_state);
kiss_fft_state = kiss_fft_alloc(nfft,1,0,0);
kiss_fftr_state = kiss_fftr_alloc(nfft,1,0,0);
memset(cin,0,sizeof(cin));
#if 1
for (i=1;i< nfft/2;++i) {
//cin[i].r = (kiss_fft_scalar)(rand()-RAND_MAX/2);
cin[i].r = rand_scalar();
cin[i].i = rand_scalar();
}
#else
cin[0].r = 12000;
cin[3].r = 12000;
cin[nfft/2].r = 12000;
#endif
// conjugate symmetry of real signal
for (i=1;i< nfft/2;++i) {
cin[nfft-i].r = cin[i].r;
cin[nfft-i].i = - cin[i].i;
}
kiss_fft(kiss_fft_state,cin,cout);
kiss_fftri(kiss_fftr_state,cin,rout);
/*
printf(" results from inverse kiss_fft : (%f,%f), (%f,%f), (%f,%f), (%f,%f), (%f,%f) ...\n "
, (float)cout[0].r , (float)cout[0].i , (float)cout[1].r , (float)cout[1].i , (float)cout[2].r , (float)cout[2].i , (float)cout[3].r , (float)cout[3].i , (float)cout[4].r , (float)cout[4].i
);
printf(" results from inverse kiss_fftr: %f,%f,%f,%f,%f ... \n"
,(float)rout[0] ,(float)rout[1] ,(float)rout[2] ,(float)rout[3] ,(float)rout[4]);
*/
for (i=0;i<nfft;++i) {
sout[i].r = rout[i];
sout[i].i = zero;
}
printf( "nfft=%d, inverse=%d, snr=%g\n",
nfft,1, snr_compare(cout,sout,nfft/2) );
free(kiss_fft_state);
free(kiss_fftr_state);
return 0;
}

View File

@ -1,25 +0,0 @@
#include <kiss_fftnd.h>
static void test1(void)
{
int is_inverse = 1;
int n[2] = {256,256};
size_t nbytes = sizeof(kiss_fft_cpx)*n[0]*n[1];
kiss_fft_cpx * inbuf = _mm_malloc(nbytes,16);
kiss_fft_cpx * outbuf = _mm_malloc(nbytes,16);
memset(inbuf,0,nbytes);
memset(outbuf,0,nbytes);
kiss_fftnd_cfg cfg = kiss_fftnd_alloc(n,2,is_inverse,0,0);
kiss_fftnd(cfg,inbuf,outbuf);
kiss_fft_free(cfg);
_mm_free(inbuf);
_mm_free(outbuf);
}
int main(void)
{
test1();
return 0;
}

View File

@ -1,80 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kissfft.hh"
#include <iostream>
#include <cstdlib>
#include <typeinfo>
#include <sys/time.h>
static inline
double curtime(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec*.000001;
}
using namespace std;
template <class T>
void dotest(int nfft)
{
typedef kissfft<T> FFT;
typedef std::complex<T> cpx_type;
cout << "type:" << typeid(T).name() << " nfft:" << nfft;
FFT fft(nfft,false);
vector<cpx_type> inbuf(nfft);
vector<cpx_type> outbuf(nfft);
for (int k=0;k<nfft;++k)
inbuf[k]= cpx_type(
(T)(rand()/(double)RAND_MAX - .5),
(T)(rand()/(double)RAND_MAX - .5) );
fft.transform( &inbuf[0] , &outbuf[0] );
long double totalpower=0;
long double difpower=0;
for (int k0=0;k0<nfft;++k0) {
complex<long double> acc = 0;
long double phinc = 2*k0* M_PIl / nfft;
for (int k1=0;k1<nfft;++k1) {
complex<long double> x(inbuf[k1].real(),inbuf[k1].imag());
acc += x * exp( complex<long double>(0,-k1*phinc) );
}
totalpower += norm(acc);
complex<long double> x(outbuf[k0].real(),outbuf[k0].imag());
complex<long double> dif = acc - x;
difpower += norm(dif);
}
cout << " RMSE:" << sqrt(difpower/totalpower) << "\t";
double t0 = curtime();
int nits=20e6/nfft;
for (int k=0;k<nits;++k) {
fft.transform( &inbuf[0] , &outbuf[0] );
}
double t1 = curtime();
cout << " MSPS:" << ( (nits*nfft)*1e-6/ (t1-t0) ) << endl;
}
int main(int argc,char ** argv)
{
if (argc>1) {
for (int k=1;k<argc;++k) {
int nfft = atoi(argv[k]);
dotest<float>(nfft); dotest<double>(nfft); dotest<long double>(nfft);
}
}else{
dotest<float>(32); dotest<double>(32); dotest<long double>(32);
dotest<float>(1024); dotest<double>(1024); dotest<long double>(1024);
dotest<float>(840); dotest<double>(840); dotest<long double>(840);
}
return 0;
}

View File

@ -1,143 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2003-2019, Mark Borgerding. All rights reserved.
# This file is part of KISS FFT - https://github.com/mborgerding/kissfft
#
# SPDX-License-Identifier: BSD-3-Clause
# See COPYING file for more information.
from __future__ import absolute_import, division, print_function
import math
import sys
import os
import random
import struct
import getopt
import numpy as np
po = math.pi
e = math.e
do_real = False
datatype = os.environ.get('KISSFFT_DATATYPE', 'float')
openmp = os.environ.get('KISSFFT_OPENMP', 'float')
util = './fastfilt-' + datatype
if openmp == '1' or openmp == 'ON':
util = util + '-openmp'
minsnr = 90
if datatype == 'double':
dtype = np.float64
elif datatype == 'float':
dtype = np.float32
elif datatype == 'int16_t':
dtype = np.int16
minsnr = 10
elif datatype == 'int32_t':
dtype = np.int32
elif datatype == 'simd':
sys.stderr.write('testkiss.py does not yet test simd')
sys.exit(0)
else:
sys.stderr.write('unrecognized datatype {0}\n'.format(datatype))
sys.exit(1)
def dopack(x):
if np.iscomplexobj(x):
x = x.astype(np.complex128).view(np.float64)
else:
x = x.astype(np.float64)
return x.astype(dtype).tobytes()
def dounpack(x, cpx):
x = np.frombuffer(x, dtype).astype(np.float64)
if cpx:
x = x[::2] + 1j * x[1::2]
return x
def make_random(shape):
'create random uniform (-1,1) data of the given shape'
if do_real:
return np.random.uniform(-1, 1, shape)
else:
return (np.random.uniform(-1, 1, shape) + 1j * np.random.uniform(-1, 1, shape))
def randmat(ndim):
'create a random multidimensional array in range (-1,1)'
dims = np.random.randint(2, 5, ndim)
if do_real:
dims[-1] = (dims[-1] // 2) * 2 # force even last dimension if real
return make_random(dims)
def test_fft(ndim):
x = randmat(ndim)
if do_real:
xver = np.fft.rfftn(x)
else:
xver = np.fft.fftn(x)
x2 = dofft(x, do_real)
err = xver - x2
errf = err.ravel()
xverf = xver.ravel()
errpow = np.vdot(errf, errf) + 1e-10
sigpow = np.vdot(xverf, xverf) + 1e-10
snr = 10 * math.log10(abs(sigpow / errpow))
print('SNR (compared to NumPy) : {0:.1f}dB'.format(float(snr)))
if snr < minsnr:
print('xver=', xver)
print('x2=', x2)
print('err', err)
sys.exit(1)
def dofft(x, isreal):
dims = list(np.shape(x))
x = x.ravel()
scale = 1
if datatype == 'int16_t':
x = 32767 * x
scale = len(x) / 32767.0
elif datatype == 'int32_t':
x = 2147483647.0 * x
scale = len(x) / 2147483647.0
cmd = util + ' -n '
cmd += ','.join([str(d) for d in dims])
if do_real:
cmd += ' -R '
print(cmd)
from subprocess import Popen, PIPE
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
p.stdin.write(dopack(x))
p.stdin.close()
res = dounpack(p.stdout.read(), 1)
if do_real:
dims[-1] = (dims[-1] // 2) + 1
res = scale * res
p.wait()
return np.reshape(res, dims)
def main():
opts, args = getopt.getopt(sys.argv[1:], 'r')
opts = dict(opts)
global do_real
do_real = '-r' in opts
if do_real:
print('Testing multi-dimensional real FFTs')
else:
print('Testing multi-dimensional FFTs')
for dim in range(1, 4):
test_fft(dim)
if __name__ == "__main__":
main()

View File

@ -1,101 +0,0 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "kiss_fft.h"
#include "kiss_fftr.h"
#include <limits.h>
static
double two_tone_test( int nfft, int bin1,int bin2)
{
kiss_fftr_cfg cfg = NULL;
kiss_fft_cpx *kout = NULL;
kiss_fft_scalar *tbuf = NULL;
int i;
double f1 = bin1*2*M_PI/nfft;
double f2 = bin2*2*M_PI/nfft;
double sigpow=0;
double noisepow=0;
#if FIXED_POINT==32
long maxrange = LONG_MAX;
#else
long maxrange = SHRT_MAX;/* works fine for float too*/
#endif
cfg = kiss_fftr_alloc(nfft , 0, NULL, NULL);
tbuf = KISS_FFT_MALLOC(nfft * sizeof(kiss_fft_scalar));
kout = KISS_FFT_MALLOC(nfft * sizeof(kiss_fft_cpx));
/* generate a signal with two tones*/
for (i = 0; i < nfft; i++) {
#ifdef USE_SIMD
tbuf[i] = _mm_set1_ps( (maxrange>>1)*cos(f1*i)
+ (maxrange>>1)*cos(f2*i) );
#else
tbuf[i] = (maxrange>>1)*cos(f1*i)
+ (maxrange>>1)*cos(f2*i);
#endif
}
kiss_fftr(cfg, tbuf, kout);
for (i=0;i < (nfft/2+1);++i) {
#ifdef USE_SIMD
double tmpr = (double)*(float*)&kout[i].r / (double)maxrange;
double tmpi = (double)*(float*)&kout[i].i / (double)maxrange;
#else
double tmpr = (double)kout[i].r / (double)maxrange;
double tmpi = (double)kout[i].i / (double)maxrange;
#endif
double mag2 = tmpr*tmpr + tmpi*tmpi;
if (i!=0 && i!= nfft/2)
mag2 *= 2; /* all bins except DC and Nyquist have symmetric counterparts implied*/
/* if there is power in one of the expected bins, it is signal, otherwise noise*/
if ( i!=bin1 && i != bin2 )
noisepow += mag2;
else
sigpow += mag2;
}
kiss_fft_cleanup();
/*printf("TEST %d,%d,%d noise @ %fdB\n",nfft,bin1,bin2,10*log10(noisepow/sigpow +1e-30) );*/
return 10*log10(sigpow/(noisepow+1e-50) );
}
int main(int argc,char ** argv)
{
int nfft = 4*2*2*3*5;
if (argc>1) nfft = atoi(argv[1]);
int i,j;
double minsnr = 500;
double maxsnr = -500;
double snr;
for (i=0;i<nfft/2;i+= (nfft>>4)+1) {
for (j=i;j<nfft/2;j+=(nfft>>4)+7) {
snr = two_tone_test(nfft,i,j);
if (snr<minsnr) {
minsnr=snr;
}
if (snr>maxsnr) {
maxsnr=snr;
}
}
}
snr = two_tone_test(nfft,nfft/2,nfft/2);
if (snr<minsnr) minsnr=snr;
if (snr>maxsnr) maxsnr=snr;
printf("TwoToneTest: snr ranges from %ddB to %ddB\n",(int)minsnr,(int)maxsnr);
printf("sizeof(kiss_fft_scalar) = %d\n",(int)sizeof(kiss_fft_scalar) );
return 0;
}

View File

@ -1,29 +0,0 @@
add_kissfft_executable(fastconvr kiss_fastfir.c)
target_compile_definitions(fastconvr PRIVATE REAL_FASTFIR FAST_FILT_UTIL)
add_kissfft_executable(fastconv kiss_fastfir.c)
target_compile_definitions(fastconv PRIVATE FAST_FILT_UTIL)
add_kissfft_executable(fft fftutil.c)
install(TARGETS fastconv fastconvr fft
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PUBLIC_HEADER DESTINATION ${PKGINCLUDEDIR})
# psdpng does not build with "simd" datatype
if(NOT KISSFFT_DATATYPE MATCHES "simd")
include(FindPkgConfig)
pkg_check_modules(libpng REQUIRED IMPORTED_TARGET libpng)
add_kissfft_executable(psdpng psdpng.c)
target_link_libraries(psdpng PRIVATE PkgConfig::libpng)
install(TARGETS psdpng
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PUBLIC_HEADER DESTINATION ${PKGINCLUDEDIR})
endif()
#FIXME: dumphdr.c is not available
#add_kissfft_executable(dumphdr dumphdr.c)

View File

@ -1,101 +0,0 @@
#
# Warnings
#
WARNINGS = -W -Wall -Wstrict-prototypes -Wmissing-prototypes \
-Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast \
-Wwrite-strings
#
# Compile-time definitions
#
CFLAGS = -Wall -O3 $(WARNINGS)
#CFLAGS = -Wall -O3 -pedantic -march=pentiumpro -ffast-math -fomit-frame-pointer $(WARNINGS)
# If the above flags do not work, try the following
# tip: try -openmp or -fopenmp to use multiple cores
CFLAGS += $(CFLAGADD)
#
# Check missing external libraries
#
ifneq ($(MAKECMDGOALS),clean)
LIBPNG_MISSING = $(shell echo "int main(){return 0;}" > _test_library_dummy.c; \
$(CC) -o _test_library_dummy _test_library_dummy.c -lpng; \
echo $$?; \
rm -f _test_library_dummy.c _test_library_dummy)
endif
#
# Tool names
#
ifneq ($(KISSFFT_OPENMP),1)
FFTUTIL = fft-$(KISSFFT_DATATYPE)
FASTFILT = fastconv-$(KISSFFT_DATATYPE)
FASTFILTREAL = fastconvr-$(KISSFFT_DATATYPE)
PSDPNG = psdpng-$(KISSFFT_DATATYPE)
DUMPHDR = dumphdr-$(KISSFFT_DATATYPE)
else
FFTUTIL = fft-$(KISSFFT_DATATYPE)-openmp
FASTFILT = fastconv-$(KISSFFT_DATATYPE)-openmp
FASTFILTREAL = fastconvr-$(KISSFFT_DATATYPE)-openmp
PSDPNG = psdpng-$(KISSFFT_DATATYPE)-openmp
DUMPHDR = dumphdr-$(KISSFFT_DATATYPE)-openmp
endif
#
# Target: "make all"
#
all: $(FFTUTIL) $(FASTFILT) $(FASTFILTREAL) $(PSDPNG)
# $(DUMPHDR)
#
# Individual tool make rules
#
$(FASTFILTREAL): kiss_fastfir.c
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) -DREAL_FASTFIR $< -DFAST_FILT_UTIL -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(FASTFILT): kiss_fastfir.c
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -DFAST_FILT_UTIL -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(FFTUTIL): fftutil.c
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
$(PSDPNG): psdpng.c
ifeq "$(KISSFFT_DATATYPE)" "simd"
$(warning WARNING: psdpng can not utilize SIMD!)
else ifeq ($(LIBPNG_MISSING), 0)
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lpng -lm
else
$(error ERROR: no libpng development files found!)
endif
$(DUMPHDR): dumphdr.c
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
#
# Target: "make install"
#
install: all
$(INSTALL) -Dt $(ABS_BINDIR) -m 755 \
$(FFTUTIL) \
$(FASTFILT) \
$(FASTFILTREAL)
ifneq "$(KISSFFT_DATATYPE)" "simd"
$(INSTALL) -Dt $(ABS_BINDIR) -m 755 \
$(PSDPNG)
endif
#
# Target: "make clean"
#
clean:
rm -f *~ fft fft-* fastconv fastconv-* fastconvr fastconvr-* psdpng psdpng-* _test_library_dummy _test_library_dummy.c

View File

@ -1,202 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "kiss_fft.h"
#include "kiss_fftndr.h"
static
void fft_file(FILE * fin,FILE * fout,int nfft,int isinverse)
{
kiss_fft_cfg st;
kiss_fft_cpx * buf;
kiss_fft_cpx * bufout;
buf = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * nfft );
bufout = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * nfft );
st = kiss_fft_alloc( nfft ,isinverse ,0,0);
while ( fread( buf , sizeof(kiss_fft_cpx) * nfft ,1, fin ) > 0 ) {
kiss_fft( st , buf ,bufout);
fwrite( bufout , sizeof(kiss_fft_cpx) , nfft , fout );
}
free(st);
free(buf);
free(bufout);
}
static
void fft_filend(FILE * fin,FILE * fout,int *dims,int ndims,int isinverse)
{
kiss_fftnd_cfg st;
kiss_fft_cpx *buf;
int dimprod=1,i;
for (i=0;i<ndims;++i)
dimprod *= dims[i];
buf = (kiss_fft_cpx *) malloc (sizeof (kiss_fft_cpx) * dimprod);
st = kiss_fftnd_alloc (dims, ndims, isinverse, 0, 0);
while (fread (buf, sizeof (kiss_fft_cpx) * dimprod, 1, fin) > 0) {
kiss_fftnd (st, buf, buf);
fwrite (buf, sizeof (kiss_fft_cpx), dimprod, fout);
}
free (st);
free (buf);
}
static
void fft_filend_real(FILE * fin,FILE * fout,int *dims,int ndims,int isinverse)
{
int dimprod=1,i;
kiss_fftndr_cfg st;
void *ibuf;
void *obuf;
int insize,outsize; // size in bytes
for (i=0;i<ndims;++i)
dimprod *= dims[i];
insize = outsize = dimprod;
int rdim = dims[ndims-1];
if (isinverse)
insize = insize*2*(rdim/2+1)/rdim;
else
outsize = outsize*2*(rdim/2+1)/rdim;
ibuf = malloc(insize*sizeof(kiss_fft_scalar));
obuf = malloc(outsize*sizeof(kiss_fft_scalar));
st = kiss_fftndr_alloc(dims, ndims, isinverse, 0, 0);
while ( fread (ibuf, sizeof(kiss_fft_scalar), insize, fin) > 0) {
if (isinverse) {
kiss_fftndri(st,
(kiss_fft_cpx*)ibuf,
(kiss_fft_scalar*)obuf);
}else{
kiss_fftndr(st,
(kiss_fft_scalar*)ibuf,
(kiss_fft_cpx*)obuf);
}
fwrite (obuf, sizeof(kiss_fft_scalar), outsize,fout);
}
free(st);
free(ibuf);
free(obuf);
}
static
void fft_file_real(FILE * fin,FILE * fout,int nfft,int isinverse)
{
kiss_fftr_cfg st;
kiss_fft_scalar * rbuf;
kiss_fft_cpx * cbuf;
rbuf = (kiss_fft_scalar*)malloc(sizeof(kiss_fft_scalar) * nfft );
cbuf = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * (nfft/2+1) );
st = kiss_fftr_alloc( nfft ,isinverse ,0,0);
if (isinverse==0) {
while ( fread( rbuf , sizeof(kiss_fft_scalar) * nfft ,1, fin ) > 0 ) {
kiss_fftr( st , rbuf ,cbuf);
fwrite( cbuf , sizeof(kiss_fft_cpx) , (nfft/2 + 1) , fout );
}
}else{
while ( fread( cbuf , sizeof(kiss_fft_cpx) * (nfft/2+1) ,1, fin ) > 0 ) {
kiss_fftri( st , cbuf ,rbuf);
fwrite( rbuf , sizeof(kiss_fft_scalar) , nfft , fout );
}
}
free(st);
free(rbuf);
free(cbuf);
}
static
int get_dims(char * arg,int * dims)
{
char *p0;
int ndims=0;
do{
p0 = strchr(arg,',');
if (p0)
*p0++ = '\0';
dims[ndims++] = atoi(arg);
// fprintf(stderr,"dims[%d] = %d\n",ndims-1,dims[ndims-1]);
arg = p0;
}while (p0);
return ndims;
}
int main(int argc,char ** argv)
{
int isinverse=0;
int isreal=0;
FILE *fin=stdin;
FILE *fout=stdout;
int ndims=1;
int dims[32];
dims[0] = 1024; /*default fft size*/
while (1) {
int c=getopt(argc,argv,"n:iR");
if (c==-1) break;
switch (c) {
case 'n':
ndims = get_dims(optarg,dims);
break;
case 'i':isinverse=1;break;
case 'R':isreal=1;break;
case '?':
fprintf(stderr,"usage options:\n"
"\t-n d1[,d2,d3...]: fft dimension(s)\n"
"\t-i : inverse\n"
"\t-R : real input samples, not complex\n");
exit (1);
default:fprintf(stderr,"bad %c\n",c);break;
}
}
if ( optind < argc ) {
if (strcmp("-",argv[optind]) !=0)
fin = fopen(argv[optind],"rb");
++optind;
}
if ( optind < argc ) {
if ( strcmp("-",argv[optind]) !=0 )
fout = fopen(argv[optind],"wb");
++optind;
}
if (ndims==1) {
if (isreal)
fft_file_real(fin,fout,dims[0],isinverse);
else
fft_file(fin,fout,dims[0],isinverse);
}else{
if (isreal)
fft_filend_real(fin,fout,dims,ndims,isinverse);
else
fft_filend(fin,fout,dims,ndims,isinverse);
}
if (fout!=stdout) fclose(fout);
if (fin!=stdin) fclose(fin);
return 0;
}

View File

@ -1,464 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "_kiss_fft_guts.h"
/*
Some definitions that allow real or complex filtering
*/
#ifdef REAL_FASTFIR
#define MIN_FFT_LEN 2048
#include "kiss_fftr.h"
typedef kiss_fft_scalar kffsamp_t;
typedef kiss_fftr_cfg kfcfg_t;
#define FFT_ALLOC kiss_fftr_alloc
#define FFTFWD kiss_fftr
#define FFTINV kiss_fftri
#else
#define MIN_FFT_LEN 1024
typedef kiss_fft_cpx kffsamp_t;
typedef kiss_fft_cfg kfcfg_t;
#define FFT_ALLOC kiss_fft_alloc
#define FFTFWD kiss_fft
#define FFTINV kiss_fft
#endif
typedef struct kiss_fastfir_state *kiss_fastfir_cfg;
kiss_fastfir_cfg kiss_fastfir_alloc(const kffsamp_t * imp_resp,size_t n_imp_resp,
size_t * nfft,void * mem,size_t*lenmem);
/* see do_file_filter for usage */
size_t kiss_fastfir( kiss_fastfir_cfg cfg, kffsamp_t * inbuf, kffsamp_t * outbuf, size_t n, size_t *offset);
static int verbose=0;
struct kiss_fastfir_state{
size_t nfft;
size_t ngood;
kfcfg_t fftcfg;
kfcfg_t ifftcfg;
kiss_fft_cpx * fir_freq_resp;
kiss_fft_cpx * freqbuf;
size_t n_freq_bins;
kffsamp_t * tmpbuf;
};
kiss_fastfir_cfg kiss_fastfir_alloc(
const kffsamp_t * imp_resp,size_t n_imp_resp,
size_t *pnfft, /* if <= 0, an appropriate size will be chosen */
void * mem,size_t*lenmem)
{
kiss_fastfir_cfg st = NULL;
size_t len_fftcfg,len_ifftcfg;
size_t memneeded = sizeof(struct kiss_fastfir_state);
char * ptr;
size_t i;
size_t nfft=0;
float scale;
int n_freq_bins;
if (pnfft)
nfft=*pnfft;
if (nfft<=0) {
/* determine fft size as next power of two at least 2x
the impulse response length*/
i=n_imp_resp-1;
nfft=2;
do{
nfft<<=1;
}while (i>>=1);
#ifdef MIN_FFT_LEN
if ( nfft < MIN_FFT_LEN )
nfft=MIN_FFT_LEN;
#endif
}
if (pnfft)
*pnfft = nfft;
#ifdef REAL_FASTFIR
n_freq_bins = nfft/2 + 1;
#else
n_freq_bins = nfft;
#endif
/*fftcfg*/
FFT_ALLOC (nfft, 0, NULL, &len_fftcfg);
memneeded += len_fftcfg;
/*ifftcfg*/
FFT_ALLOC (nfft, 1, NULL, &len_ifftcfg);
memneeded += len_ifftcfg;
/* tmpbuf */
memneeded += sizeof(kffsamp_t) * nfft;
/* fir_freq_resp */
memneeded += sizeof(kiss_fft_cpx) * n_freq_bins;
/* freqbuf */
memneeded += sizeof(kiss_fft_cpx) * n_freq_bins;
if (lenmem == NULL) {
st = (kiss_fastfir_cfg) malloc (memneeded);
} else {
if (*lenmem >= memneeded)
st = (kiss_fastfir_cfg) mem;
*lenmem = memneeded;
}
if (!st)
return NULL;
st->nfft = nfft;
st->ngood = nfft - n_imp_resp + 1;
st->n_freq_bins = n_freq_bins;
ptr=(char*)(st+1);
st->fftcfg = (kfcfg_t)ptr;
ptr += len_fftcfg;
st->ifftcfg = (kfcfg_t)ptr;
ptr += len_ifftcfg;
st->tmpbuf = (kffsamp_t*)ptr;
ptr += sizeof(kffsamp_t) * nfft;
st->freqbuf = (kiss_fft_cpx*)ptr;
ptr += sizeof(kiss_fft_cpx) * n_freq_bins;
st->fir_freq_resp = (kiss_fft_cpx*)ptr;
ptr += sizeof(kiss_fft_cpx) * n_freq_bins;
FFT_ALLOC (nfft,0,st->fftcfg , &len_fftcfg);
FFT_ALLOC (nfft,1,st->ifftcfg , &len_ifftcfg);
memset(st->tmpbuf,0,sizeof(kffsamp_t)*nfft);
/*zero pad in the middle to left-rotate the impulse response
This puts the scrap samples at the end of the inverse fft'd buffer */
st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ];
for (i=0;i<n_imp_resp - 1; ++i) {
st->tmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ];
}
FFTFWD(st->fftcfg,st->tmpbuf,st->fir_freq_resp);
/* TODO: this won't work for fixed point */
scale = 1.0 / st->nfft;
for ( i=0; i < st->n_freq_bins; ++i ) {
#ifdef USE_SIMD
st->fir_freq_resp[i].r *= _mm_set1_ps(scale);
st->fir_freq_resp[i].i *= _mm_set1_ps(scale);
#else
st->fir_freq_resp[i].r *= scale;
st->fir_freq_resp[i].i *= scale;
#endif
}
return st;
}
static void fastconv1buf(const kiss_fastfir_cfg st,const kffsamp_t * in,kffsamp_t * out)
{
size_t i;
/* multiply the frequency response of the input signal by
that of the fir filter*/
FFTFWD( st->fftcfg, in , st->freqbuf );
for ( i=0; i<st->n_freq_bins; ++i ) {
kiss_fft_cpx tmpsamp;
C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]);
st->freqbuf[i] = tmpsamp;
}
/* perform the inverse fft*/
FFTINV(st->ifftcfg,st->freqbuf,out);
}
/* n : the size of inbuf and outbuf in samples
return value: the number of samples completely processed
n-retval samples should be copied to the front of the next input buffer */
static size_t kff_nocopy(
kiss_fastfir_cfg st,
const kffsamp_t * inbuf,
kffsamp_t * outbuf,
size_t n)
{
size_t norig=n;
while (n >= st->nfft ) {
fastconv1buf(st,inbuf,outbuf);
inbuf += st->ngood;
outbuf += st->ngood;
n -= st->ngood;
}
return norig - n;
}
static
size_t kff_flush(kiss_fastfir_cfg st,const kffsamp_t * inbuf,kffsamp_t * outbuf,size_t n)
{
size_t zpad=0,ntmp;
ntmp = kff_nocopy(st,inbuf,outbuf,n);
n -= ntmp;
inbuf += ntmp;
outbuf += ntmp;
zpad = st->nfft - n;
memset(st->tmpbuf,0,sizeof(kffsamp_t)*st->nfft );
memcpy(st->tmpbuf,inbuf,sizeof(kffsamp_t)*n );
fastconv1buf(st,st->tmpbuf,st->tmpbuf);
memcpy(outbuf,st->tmpbuf,sizeof(kffsamp_t)*( st->ngood - zpad ));
return ntmp + st->ngood - zpad;
}
size_t kiss_fastfir(
kiss_fastfir_cfg vst,
kffsamp_t * inbuf,
kffsamp_t * outbuf,
size_t n_new,
size_t *offset)
{
size_t ntot = n_new + *offset;
if (n_new==0) {
return kff_flush(vst,inbuf,outbuf,ntot);
}else{
size_t nwritten = kff_nocopy(vst,inbuf,outbuf,ntot);
*offset = ntot - nwritten;
/*save the unused or underused samples at the front of the input buffer */
memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kffsamp_t) );
return nwritten;
}
}
#ifdef FAST_FILT_UTIL
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <assert.h>
static
void direct_file_filter(
FILE * fin,
FILE * fout,
const kffsamp_t * imp_resp,
size_t n_imp_resp)
{
size_t nlag = n_imp_resp - 1;
const kffsamp_t *tmph;
kffsamp_t *buf, *circbuf;
kffsamp_t outval;
size_t nread;
size_t nbuf;
size_t oldestlag = 0;
size_t k, tap;
#ifndef REAL_FASTFIR
kffsamp_t tmp;
#endif
nbuf = 4096;
buf = (kffsamp_t *) malloc ( sizeof (kffsamp_t) * nbuf);
circbuf = (kffsamp_t *) malloc (sizeof (kffsamp_t) * nlag);
if (!circbuf || !buf) {
perror("circbuf allocation");
exit(1);
}
if ( fread (circbuf, sizeof (kffsamp_t), nlag, fin) != nlag ) {
perror ("insufficient data to overcome transient");
exit (1);
}
do {
nread = fread (buf, sizeof (kffsamp_t), nbuf, fin);
if (nread <= 0)
break;
for (k = 0; k < nread; ++k) {
tmph = imp_resp+nlag;
#ifdef REAL_FASTFIR
# ifdef USE_SIMD
outval = _mm_set1_ps(0);
#else
outval = 0;
#endif
for (tap = oldestlag; tap < nlag; ++tap)
outval += circbuf[tap] * *tmph--;
for (tap = 0; tap < oldestlag; ++tap)
outval += circbuf[tap] * *tmph--;
outval += buf[k] * *tmph;
#else
# ifdef USE_SIMD
outval.r = outval.i = _mm_set1_ps(0);
#else
outval.r = outval.i = 0;
#endif
for (tap = oldestlag; tap < nlag; ++tap){
C_MUL(tmp,circbuf[tap],*tmph);
--tmph;
C_ADDTO(outval,tmp);
}
for (tap = 0; tap < oldestlag; ++tap) {
C_MUL(tmp,circbuf[tap],*tmph);
--tmph;
C_ADDTO(outval,tmp);
}
C_MUL(tmp,buf[k],*tmph);
C_ADDTO(outval,tmp);
#endif
circbuf[oldestlag++] = buf[k];
buf[k] = outval;
if (oldestlag == nlag)
oldestlag = 0;
}
if (fwrite (buf, sizeof (buf[0]), nread, fout) != nread) {
perror ("short write");
exit (1);
}
} while (nread);
free (buf);
free (circbuf);
}
static
void do_file_filter(
FILE * fin,
FILE * fout,
const kffsamp_t * imp_resp,
size_t n_imp_resp,
size_t nfft )
{
int fdout;
size_t n_samps_buf;
kiss_fastfir_cfg cfg;
kffsamp_t *inbuf,*outbuf;
int nread,nwrite;
size_t idx_inbuf;
fdout = fileno(fout);
cfg=kiss_fastfir_alloc(imp_resp,n_imp_resp,&nfft,0,0);
/* use length to minimize buffer shift*/
n_samps_buf = 8*4096/sizeof(kffsamp_t);
n_samps_buf = nfft + 4*(nfft-n_imp_resp+1);
if (verbose) fprintf(stderr,"bufsize=%d\n",(int)(sizeof(kffsamp_t)*n_samps_buf) );
/*allocate space and initialize pointers */
inbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf);
outbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf);
idx_inbuf=0;
do{
/* start reading at inbuf[idx_inbuf] */
nread = fread( inbuf + idx_inbuf, sizeof(kffsamp_t), n_samps_buf - idx_inbuf,fin );
/* If nread==0, then this is a flush.
The total number of samples in input is idx_inbuf + nread . */
nwrite = kiss_fastfir(cfg, inbuf, outbuf,nread,&idx_inbuf) * sizeof(kffsamp_t);
/* kiss_fastfir moved any unused samples to the front of inbuf and updated idx_inbuf */
if ( write(fdout, outbuf, nwrite) != nwrite ) {
perror("short write");
exit(1);
}
}while ( nread );
free(cfg);
free(inbuf);
free(outbuf);
}
int main(int argc,char**argv)
{
kffsamp_t * h;
int use_direct=0;
size_t nh,nfft=0;
FILE *fin=stdin;
FILE *fout=stdout;
FILE *filtfile=NULL;
while (1) {
int c=getopt(argc,argv,"n:h:i:o:vd");
if (c==-1) break;
switch (c) {
case 'v':
verbose=1;
break;
case 'n':
nfft=atoi(optarg);
break;
case 'i':
fin = fopen(optarg,"rb");
if (fin==NULL) {
perror(optarg);
exit(1);
}
break;
case 'o':
fout = fopen(optarg,"w+b");
if (fout==NULL) {
perror(optarg);
exit(1);
}
break;
case 'h':
filtfile = fopen(optarg,"rb");
if (filtfile==NULL) {
perror(optarg);
exit(1);
}
break;
case 'd':
use_direct=1;
break;
case '?':
fprintf(stderr,"usage options:\n"
"\t-n nfft: fft size to use\n"
"\t-d : use direct FIR filtering, not fast convolution\n"
"\t-i filename: input file\n"
"\t-o filename: output(filtered) file\n"
"\t-n nfft: fft size to use\n"
"\t-h filename: impulse response\n");
exit (1);
default:fprintf(stderr,"bad %c\n",c);break;
}
}
if (filtfile==NULL) {
fprintf(stderr,"You must supply the FIR coeffs via -h\n");
exit(1);
}
fseek(filtfile,0,SEEK_END);
nh = ftell(filtfile) / sizeof(kffsamp_t);
if (verbose) fprintf(stderr,"%d samples in FIR filter\n",(int)nh);
h = (kffsamp_t*)malloc(sizeof(kffsamp_t)*nh);
fseek(filtfile,0,SEEK_SET);
if (fread(h,sizeof(kffsamp_t),nh,filtfile) != nh)
fprintf(stderr,"short read on filter file\n");
fclose(filtfile);
if (use_direct)
direct_file_filter( fin, fout, h,nh);
else
do_file_filter( fin, fout, h,nh,nfft);
if (fout!=stdout) fclose(fout);
if (fin!=stdin) fclose(fin);
return 0;
}
#endif

View File

@ -1,232 +0,0 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <png.h>
#include "kiss_fft.h"
#include "kiss_fftr.h"
int nfft=1024;
FILE * fin=NULL;
FILE * fout=NULL;
int navg=20;
int remove_dc=0;
int nrows=0;
float * vals=NULL;
int stereo=0;
static
void config(int argc,char** argv)
{
while (1) {
int c = getopt (argc, argv, "n:r:as");
if (c == -1)
break;
switch (c) {
case 'n': nfft=(int)atoi(optarg);break;
case 'r': navg=(int)atoi(optarg);break;
case 'a': remove_dc=1;break;
case 's': stereo=1;break;
case '?':
fprintf (stderr, "usage options:\n"
"\t-n d: fft dimension(s) [1024]\n"
"\t-r d: number of rows to average [20]\n"
"\t-a : remove average from each fft buffer\n"
"\t-s : input is stereo, channels will be combined before fft\n"
"16 bit machine format real input is assumed\n"
);
break;
default:
fprintf (stderr, "bad %c\n", c);
exit (1);
break;
}
}
if ( optind < argc ) {
if (strcmp("-",argv[optind]) !=0)
fin = fopen(argv[optind],"rb");
++optind;
}
if ( optind < argc ) {
if ( strcmp("-",argv[optind]) !=0 )
fout = fopen(argv[optind],"wb");
++optind;
}
if (fin==NULL)
fin=stdin;
if (fout==NULL)
fout=stdout;
}
#define CHECKNULL(p) if ( (p)==NULL ) do { fprintf(stderr,"CHECKNULL failed @ %s(%d): %s\n",__FILE__,__LINE__,#p );exit(1);} while(0)
typedef struct
{
png_byte r;
png_byte g;
png_byte b;
} rgb_t;
static
void val2rgb(float x,rgb_t *p)
{
const double pi = 3.14159265358979;
p->g = (int)(255*sin(x*pi));
p->r = (int)(255*abs(sin(x*pi*3/2)));
p->b = (int)(255*abs(sin(x*pi*5/2)));
//fprintf(stderr,"%.2f : %d,%d,%d\n",x,(int)p->r,(int)p->g,(int)p->b);
}
static
void cpx2pixels(rgb_t * res,const float * fbuf,size_t n)
{
size_t i;
float minval,maxval,valrange;
minval=maxval=fbuf[0];
for (i = 0; i < n; ++i) {
if (fbuf[i] > maxval) maxval = fbuf[i];
if (fbuf[i] < minval) minval = fbuf[i];
}
fprintf(stderr,"min ==%f,max=%f\n",minval,maxval);
valrange = maxval-minval;
if (valrange == 0) {
fprintf(stderr,"min == max == %f\n",minval);
exit (1);
}
for (i = 0; i < n; ++i)
val2rgb( (fbuf[i] - minval)/valrange , res+i );
}
static
void transform_signal(void)
{
short *inbuf;
kiss_fftr_cfg cfg=NULL;
kiss_fft_scalar *tbuf;
kiss_fft_cpx *fbuf;
float *mag2buf;
int i;
int n;
int avgctr=0;
int nfreqs=nfft/2+1;
CHECKNULL( cfg=kiss_fftr_alloc(nfft,0,0,0) );
CHECKNULL( inbuf=(short*)malloc(sizeof(short)*2*nfft ) );
CHECKNULL( tbuf=(kiss_fft_scalar*)malloc(sizeof(kiss_fft_scalar)*nfft ) );
CHECKNULL( fbuf=(kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx)*nfreqs ) );
CHECKNULL( mag2buf=(float*)calloc(nfreqs,sizeof(float) ) );
while (1) {
if (stereo) {
n = fread(inbuf,sizeof(short)*2,nfft,fin);
if (n != nfft )
break;
for (i=0;i<nfft;++i)
tbuf[i] = inbuf[2*i] + inbuf[2*i+1];
}else{
n = fread(inbuf,sizeof(short),nfft,fin);
if (n != nfft )
break;
for (i=0;i<nfft;++i)
tbuf[i] = inbuf[i];
}
if (remove_dc) {
float avg = 0;
for (i=0;i<nfft;++i) avg += tbuf[i];
avg /= nfft;
for (i=0;i<nfft;++i) tbuf[i] -= (kiss_fft_scalar)avg;
}
/* do FFT */
kiss_fftr(cfg,tbuf,fbuf);
for (i=0;i<nfreqs;++i)
mag2buf[i] += fbuf[i].r * fbuf[i].r + fbuf[i].i * fbuf[i].i;
if (++avgctr == navg) {
avgctr=0;
++nrows;
CHECKNULL( vals = (float*)realloc(vals,sizeof(float)*nrows*nfreqs) );
float eps = 1;
for (i=0;i<nfreqs;++i)
vals[(nrows - 1) * nfreqs + i] = 10 * log10 ( mag2buf[i] / navg + eps );
memset(mag2buf,0,sizeof(mag2buf[0])*nfreqs);
}
}
free(cfg);
free(inbuf);
free(tbuf);
free(fbuf);
free(mag2buf);
}
static
void make_png(void)
{
png_bytepp row_pointers=NULL;
rgb_t * row_data=NULL;
int i;
int nfreqs = nfft/2+1;
png_structp png_ptr=NULL;
png_infop info_ptr=NULL;
CHECKNULL( png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0) );
CHECKNULL( info_ptr = png_create_info_struct(png_ptr) );
png_init_io(png_ptr, fout );
png_set_IHDR(png_ptr, info_ptr ,nfreqs,nrows,8,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT );
CHECKNULL( row_data = (rgb_t*)malloc(sizeof(rgb_t) * nrows * nfreqs) );
cpx2pixels(row_data, vals, nfreqs*nrows );
CHECKNULL( row_pointers = malloc(nrows*sizeof(png_bytep)) );
for (i=0;i<nrows;++i) {
row_pointers[i] = (png_bytep)(row_data + i*nfreqs);
}
png_set_rows(png_ptr, info_ptr, row_pointers);
fprintf(stderr,"creating %dx%d png\n",nfreqs,nrows);
fprintf(stderr,"bitdepth %d \n",png_get_bit_depth(png_ptr,info_ptr ) );
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY , NULL);
free(row_pointers);
free(row_data);
png_destroy_write_struct(&png_ptr, &info_ptr);
}
int main(int argc,char ** argv)
{
config(argc,argv);
transform_signal();
make_png();
if (fout!=stdout) fclose(fout);
if (fin!=stdin) fclose(fin);
free(vals);
return 0;
}

61
3rd-party/lc3-google/Android.bp vendored Normal file
View File

@ -0,0 +1,61 @@
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "system_bt_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["system_bt_license"],
}
cc_library_static {
name: "liblc3",
host_supported: true,
apex_available: [
"//apex_available:platform",
"com.android.bluetooth"
],
defaults: ["fluoride_defaults"],
srcs: [
"src/*.c",
],
cflags: [
"-O3",
"-ffast-math",
"-Werror",
"-Wmissing-braces",
"-Wno-unused-parameter",
"-Wno-#warnings",
"-Wuninitialized",
"-Wno-self-assign",
"-Wno-implicit-fallthrough",
],
target: {
android: {
sanitize: {
misc_undefined:[
"unsigned-integer-overflow",
"signed-integer-overflow",
"bounds",
],
cfi: true,
},
},
},
export_include_dirs: [
"include",
],
}
cc_fuzz {
name: "liblc3_fuzzer",
srcs: [
"fuzzer/liblc3_fuzzer.cpp",
],
static_libs: [
"liblc3",
],
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fuzzer/FuzzedDataProvider.h>
#include "include/lc3.h"
void TestEncoder(FuzzedDataProvider& fdp) {
enum lc3_pcm_format pcm_format =
fdp.PickValueInArray({LC3_PCM_FORMAT_S16, LC3_PCM_FORMAT_S24});
int dt_us = fdp.PickValueInArray({10000, 7500});
int sr_hz =
fdp.PickValueInArray({8000, 16000, 24000, 32000, /*44100,*/ 48000});
unsigned enc_size = lc3_encoder_size(dt_us, sr_hz);
uint16_t output_byte_count = fdp.ConsumeIntegralInRange(20, 400);
uint16_t num_frames = lc3_frame_samples(dt_us, sr_hz);
uint8_t bytes_per_frame = (pcm_format == LC3_PCM_FORMAT_S16 ? 2 : 4);
if (fdp.remaining_bytes() < num_frames * bytes_per_frame) {
return;
}
std::vector<uint32_t> input_frames(
num_frames / (pcm_format == LC3_PCM_FORMAT_S16 ? 2 : 1));
fdp.ConsumeData(input_frames.data(), num_frames * bytes_per_frame);
void* lc3_encoder_mem = nullptr;
lc3_encoder_mem = malloc(enc_size);
lc3_encoder_t lc3_encoder =
lc3_setup_encoder(dt_us, sr_hz, 0, lc3_encoder_mem);
std::vector<uint8_t> output(output_byte_count);
lc3_encode(lc3_encoder, pcm_format, (const int16_t*)input_frames.data(), 1,
output.size(), output.data());
free(lc3_encoder_mem);
lc3_encoder_mem = nullptr;
return;
}
void TestDecoder(FuzzedDataProvider& fdp) {
enum lc3_pcm_format pcm_format =
fdp.PickValueInArray({LC3_PCM_FORMAT_S16, LC3_PCM_FORMAT_S24});
int dt_us = fdp.PickValueInArray({10000, 7500});
int sr_hz =
fdp.PickValueInArray({8000, 16000, 24000, 32000, /*44100,*/ 48000});
unsigned dec_size = lc3_decoder_size(dt_us, sr_hz);
uint16_t input_byte_count = fdp.ConsumeIntegralInRange(20, 400);
uint16_t num_frames = lc3_frame_samples(dt_us, sr_hz);
if (fdp.remaining_bytes() < input_byte_count) {
return;
}
std::vector<uint8_t> input(input_byte_count);
fdp.ConsumeData(input.data(), input.size());
void* lc3_decoder_mem = nullptr;
lc3_decoder_mem = malloc(dec_size);
lc3_decoder_t lc3_decoder =
lc3_setup_decoder(dt_us, sr_hz, 0, lc3_decoder_mem);
std::vector<uint32_t> output(num_frames /
(pcm_format == LC3_PCM_FORMAT_S16 ? 2 : 1));
lc3_decode(lc3_decoder, input.data(), input.size(), pcm_format,
(int16_t*)output.data(), 1);
/* Empty input performs PLC (packet loss concealment) */
lc3_decode(lc3_decoder, nullptr, 0, pcm_format, (int16_t*)output.data(), 1);
free(lc3_decoder_mem);
lc3_decoder_mem = nullptr;
return;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
TestEncoder(fdp);
TestDecoder(fdp);
return 0;
}

300
3rd-party/lc3-google/include/lc3.h vendored Normal file
View File

@ -0,0 +1,300 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* Low Complexity Communication Codec (LC3)
*
* This implementation conforms to :
* Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*
*
* The LC3 is an efficient low latency audio codec.
*
* - Unlike most other codecs, the LC3 codec is focused on audio streaming
* in constrained (on packet sizes and interval) tranport layer.
* In this way, the LC3 does not handle :
* VBR (Variable Bitrate), based on input signal complexity
* ABR (Adaptative Bitrate). It does not rely on any bit reservoir,
* a frame will be strictly encoded in the bytes budget given by
* the user (or transport layer).
*
* However, the bitrate (bytes budget for encoding a frame) can be
* freely changed at any time. But will not rely on signal complexity,
* it can follow a temporary bandwidth increase or reduction.
*
* - Unlike classic codecs, the LC3 codecs does not run on fixed amount
* of samples as input. It operate only on fixed frame duration, for
* any supported samplerates (8 to 48 KHz). Two frame duration are
* available 7.5ms and 10ms.
*
*
* --- About 44.1 KHz samplerate ---
*
* The Bluetooth specification oddly add the 44.1 KHz samplerate. Although
* there is NO SUPPORT in the core algorithm of the codec of 44.1 KHz.
* We can summarize the 44.1 KHz support by "you can put any samplerate
* around the base defined samplerates". But be concerned by :
*
* 1. The frame size will not be 7.5 ms or 10 ms, but is scaled
* by 'supported samplerate' / 'input samplerate'
*
* 2. The bandwidth will be hard limited (to 20 KHz) if you select 48 KHz.
* The encoded bandwidth will also be affected by the above inverse
* factor of 20 KHz.
*
* Applied to 44.1 KHz, we get :
*
* 1. About 8.16 ms frame duration, instead of 7.5 ms
* About 10.88 ms frame duration, instead of 10 ms
*
* 2. The bandwidth becomes limited to 18.375 KHz
*
*
* --- How to encode / decode ---
*
* An encoder / decoder context need to be setup. This context keep states
* on the current stream to proceed, and samples that overlapped across
* frames.
*
* You have two ways to setup the encoder / decoder :
*
* - Using static memory allocation (this module does not rely on
* any dynamic memory allocation). The types `lc3_xxcoder_mem_16k_t`,
* and `lc3_xxcoder_mem_48k_t` have size of the memory needed for
* encoding up to 16 KHz or 48 KHz.
*
* - Using dynamic memory allocation. The `lc3_xxcoder_size()` procedure
* returns the needed memory size, for a given configuration. The memory
* space must be aligned to a pointer size. As an example, you can setup
* encoder like this :
*
* | enc = lc3_setup_encoder(frame_us, samplerate,
* | malloc(lc3_encoder_size(frame_us, samplerate)));
* | ...
* | free(enc);
*
* Note :
* - A NULL memory adress as input, will return a NULL encoder context.
* - The returned encoder handle is set at the address of the allocated
* memory space, you can directly free the handle.
*
* Next, call the `lc3_encode()` encoding procedure, for each frames.
* To handle multichannel streams (Stereo or more), you can proceed with
* inerleaved channels PCM stream like this :
*
* | for(int ich = 0; ich < nch: ich++)
* | lc3_encode(encoder[ich], pcm + ich, nch, ...);
*
* with `nch` as the number of channels in the PCM stream
*/
#ifndef __LC3_H
#define __LC3_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "lc3_private.h"
/**
* Limitations
* - On the bitrate, in bps, of a stream
* - On the size of the frames in bytes
*/
#define LC3_MIN_BITRATE 16000
#define LC3_MAX_BITRATE 320000
#define LC3_MIN_FRAME_BYTES 20
#define LC3_MAX_FRAME_BYTES 400
/**
* Parameters check
* LC3_CHECK_DT_US(us) True when frame duration in us is suitable
* LC3_CHECK_SR_HZ(sr) True when samplerate in Hz is suitable
*/
#define LC3_CHECK_DT_US(us) \
( ((us) == 7500) || ((us) == 10000) )
#define LC3_CHECK_SR_HZ(sr) \
( ((sr) == 8000) || ((sr) == 16000) || ((sr) == 24000) || \
((sr) == 32000) || ((sr) == 48000) )
/**
* PCM Sample Format
* S16 Signed 16 bits, in 16 bits words (int16_t)
* S24 Signed 24 bits, using low three bytes of 32 bits words (int32_t).
* The high byte sign extends the sample value (bits 31..24 set to b23).
*/
enum lc3_pcm_format {
LC3_PCM_FORMAT_S16,
LC3_PCM_FORMAT_S24,
};
/**
* Handle
*/
typedef struct lc3_encoder *lc3_encoder_t;
typedef struct lc3_decoder *lc3_decoder_t;
/**
* Static memory of encoder context
*
* Propose types suitable for static memory allocation, supporting
* any frame duration, and maximum samplerates 16k and 48k respectively
* You can customize your type using the `LC3_ENCODER_MEM_T` or
* `LC3_DECODER_MEM_T` macro.
*/
typedef LC3_ENCODER_MEM_T(10000, 16000) lc3_encoder_mem_16k_t;
typedef LC3_ENCODER_MEM_T(10000, 48000) lc3_encoder_mem_48k_t;
typedef LC3_DECODER_MEM_T(10000, 16000) lc3_decoder_mem_16k_t;
typedef LC3_DECODER_MEM_T(10000, 48000) lc3_decoder_mem_48k_t;
/**
* Return the number of PCM samples in a frame
* dt_us Frame duration in us, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Number of PCM samples, -1 on bad parameters
*/
int lc3_frame_samples(int dt_us, int sr_hz);
/**
* Return the size of frames, from bitrate
* dt_us Frame duration in us, 7500 or 10000
* bitrate Target bitrate in bit per seconds
* return The floor size in bytes of the frames, -1 on bad parameters
*/
int lc3_frame_bytes(int dt_us, int bitrate);
/**
* Resolve the bitrate, from the size of frames
* dt_us Frame duration in us, 7500 or 10000
* nbytes Size in bytes of the frames
* return The according bitrate in bps, -1 on bad parameters
*/
int lc3_resolve_bitrate(int dt_us, int nbytes);
/**
* Return algorithmic delay, as a number of samples
* dt_us Frame duration in us, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Number of algorithmic delay samples, -1 on bad parameters
*/
int lc3_delay_samples(int dt_us, int sr_hz);
/**
* Return size needed for an encoder
* dt_us Frame duration in us, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Size of then encoder in bytes, 0 on bad parameters
*
* The `sr_hz` parameter is the samplerate of the PCM input stream,
* and will match `sr_pcm_hz` of `lc3_setup_encoder()`.
*/
unsigned lc3_encoder_size(int dt_us, int sr_hz);
/**
* Setup encoder
* dt_us Frame duration in us, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* sr_pcm_hz Input samplerate, downsampling option of input, or 0
* mem Encoder memory space, aligned to pointer type
* return Encoder as an handle, NULL on bad parameters
*
* The `sr_pcm_hz` parameter is a downsampling option of PCM input,
* the value `0` fallback to the samplerate of the encoded stream `sr_hz`.
* When used, `sr_pcm_hz` is intended to be higher or equal to the encoder
* samplerate `sr_hz`. The size of the context needed, given by
* `lc3_encoder_size()` will be set accordingly to `sr_pcm_hz`.
*/
lc3_encoder_t lc3_setup_encoder(
int dt_us, int sr_hz, int sr_pcm_hz, void *mem);
/**
* Encode a frame
* encoder Handle of the encoder
* fmt PCM input format
* pcm, stride Input PCM samples, and count between two consecutives
* nbytes Target size, in bytes, of the frame (20 to 400)
* out Output buffer of `nbytes` size
* return 0: On success -1: Wrong parameters
*/
int lc3_encode(lc3_encoder_t encoder, enum lc3_pcm_format fmt,
const void *pcm, int stride, int nbytes, void *out);
/**
* Return size needed for an decoder
* dt_us Frame duration in us, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Size of then decoder in bytes, 0 on bad parameters
*
* The `sr_hz` parameter is the samplerate of the PCM output stream,
* and will match `sr_pcm_hz` of `lc3_setup_decoder()`.
*/
unsigned lc3_decoder_size(int dt_us, int sr_hz);
/**
* Setup decoder
* dt_us Frame duration in us, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* sr_pcm_hz Output samplerate, upsampling option of output (or 0)
* mem Decoder memory space, aligned to pointer type
* return Decoder as an handle, NULL on bad parameters
*
* The `sr_pcm_hz` parameter is an upsampling option of PCM output,
* the value `0` fallback to the samplerate of the decoded stream `sr_hz`.
* When used, `sr_pcm_hz` is intended to be higher or equal to the decoder
* samplerate `sr_hz`. The size of the context needed, given by
* `lc3_decoder_size()` will be set accordingly to `sr_pcm_hz`.
*/
lc3_decoder_t lc3_setup_decoder(
int dt_us, int sr_hz, int sr_pcm_hz, void *mem);
/**
* Decode a frame
* decoder Handle of the decoder
* in, nbytes Input bitstream, and size in bytes, NULL performs PLC
* fmt PCM output format
* pcm, stride Output PCM samples, and count between two consecutives
* return 0: On success 1: PLC operated -1: Wrong parameters
*/
int lc3_decode(lc3_decoder_t decoder, const void *in, int nbytes,
enum lc3_pcm_format fmt, void *pcm, int stride);
#ifdef __cplusplus
}
#endif
#endif /* __LC3_H */

View File

@ -0,0 +1,158 @@
/******************************************************************************
*
* Copyright 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef __LC3_PRIVATE_H
#define __LC3_PRIVATE_H
#include <stdint.h>
#include <stdbool.h>
/**
* Return number of samples, delayed samples and
* encoded spectrum coefficients within a frame
* For decoding, add number of samples of 18 ms history
*/
#define __LC3_NS(dt_us, sr_hz) \
((dt_us * sr_hz) / 1000 / 1000)
#define __LC3_ND(dt_us, sr_hz) \
( (dt_us) == 7500 ? 23 * __LC3_NS(dt_us, sr_hz) / 30 \
: 5 * __LC3_NS(dt_us, sr_hz) / 8 )
#define __LC3_NH(sr_hz) \
( (18 * sr_hz) / 1000 )
/**
* Frame duration 7.5ms or 10ms
*/
enum lc3_dt {
LC3_DT_7M5,
LC3_DT_10M,
LC3_NUM_DT
};
/**
* Sampling frequency
*/
enum lc3_srate {
LC3_SRATE_8K,
LC3_SRATE_16K,
LC3_SRATE_24K,
LC3_SRATE_32K,
LC3_SRATE_48K,
LC3_NUM_SRATE,
};
/**
* Encoder state and memory
*/
typedef struct lc3_attdet_analysis {
float en1, an1;
int p_att;
} lc3_attdet_analysis_t;
struct lc3_ltpf_hp50_state {
float s1, s2;
};
typedef struct lc3_ltpf_analysis {
bool active;
int pitch;
float nc[2];
struct lc3_ltpf_hp50_state hp50;
float x_12k8[384];
float x_6k4[178];
int tc;
} lc3_ltpf_analysis_t;
typedef struct lc3_spec_analysis {
float nbits_off;
int nbits_spare;
} lc3_spec_analysis_t;
struct lc3_encoder {
enum lc3_dt dt;
enum lc3_srate sr, sr_pcm;
lc3_attdet_analysis_t attdet;
lc3_ltpf_analysis_t ltpf;
lc3_spec_analysis_t spec;
// BK: s[0] -> s[1] to avoid compiler warning for zero sized warning
float *xs, *xf, s[1];
};
#define LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz) \
( 2*__LC3_NS(dt_us, sr_hz) + __LC3_ND(dt_us, sr_hz) )
#define LC3_ENCODER_MEM_T(dt_us, sr_hz) \
struct { \
struct lc3_encoder __e; \
float __s[LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz)]; \
}
/**
* Decoder state and memory
*/
typedef struct lc3_ltpf_synthesis {
bool active;
int pitch;
float c[12][2], x[12];
} lc3_ltpf_synthesis_t;
typedef struct lc3_plc_state {
uint16_t seed;
int count;
float alpha;
} lc3_plc_state_t;
struct lc3_decoder {
enum lc3_dt dt;
enum lc3_srate sr, sr_pcm;
lc3_ltpf_synthesis_t ltpf;
lc3_plc_state_t plc;
// BK: s[0] -> s[1] to avoid compiler warning for zero sized warning
float *xs, *xd, *xg, s[1];
};
#define LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz) \
( __LC3_NH(sr_hz) + __LC3_NS(dt_us, sr_hz) + \
__LC3_ND(dt_us, sr_hz) + __LC3_NS(dt_us, sr_hz) )
#define LC3_DECODER_MEM_T(dt_us, sr_hz) \
struct { \
struct lc3_decoder __d; \
float __s[LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz)]; \
}
#endif /* __LC3_PRIVATE_H */

92
3rd-party/lc3-google/src/attdet.c vendored Normal file
View File

@ -0,0 +1,92 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "attdet.h"
/**
* Time domain attack detector
*/
bool lc3_attdet_run(enum lc3_dt dt, enum lc3_srate sr,
int nbytes, struct lc3_attdet_analysis *attdet, const float *x)
{
/* --- Check enabling --- */
const int nbytes_ranges[LC3_NUM_DT][LC3_NUM_SRATE - LC3_SRATE_32K][2] = {
[LC3_DT_7M5] = { { 61, 149 }, { 75, 149 } },
[LC3_DT_10M] = { { 81, INT_MAX }, { 100, INT_MAX } },
};
if (sr < LC3_SRATE_32K ||
nbytes < nbytes_ranges[dt][sr - LC3_SRATE_32K][0] ||
nbytes > nbytes_ranges[dt][sr - LC3_SRATE_32K][1] )
return 0;
/* --- Filtering & Energy calculation --- */
int nblk = 4 - (dt == LC3_DT_7M5);
float e[4];
for (int i = 0; i < nblk; i++) {
e[i] = 0;
if (sr == LC3_SRATE_32K) {
float xn2 = x[-4] + x[-3];
float xn1 = x[-2] + x[-1];
float xn, xf;
for (int j = 0; j < 40; j++, x += 2, xn2 = xn1, xn1 = xn) {
xn = x[0] + x[1];
xf = 0.375 * xn - 0.5 * xn1 + 0.125 * xn2;
e[i] += xf * xf;
}
}
else {
float xn2 = x[-6] + x[-5] + x[-4];
float xn1 = x[-3] + x[-2] + x[-1];
float xn, xf;
for (int j = 0; j < 40; j++, x += 3, xn2 = xn1, xn1 = xn) {
xn = x[0] + x[1] + x[2];
xf = 0.375 * xn - 0.5 * xn1 + 0.125 * xn2;
e[i] += xf * xf;
}
}
}
/* --- Attack detection ---
* The attack block `p_att` is defined as the normative value + 1,
* in such way, it will be initialized to 0 */
int p_att = 0;
float a[4];
for (int i = 0; i < nblk; i++) {
a[i] = fmaxf(0.25 * attdet->an1, attdet->en1);
attdet->en1 = e[i], attdet->an1 = a[i];
if (e[i] > 8.5 * a[i])
p_att = i + 1;
}
int att = attdet->p_att >= 1 + (nblk >> 1) || p_att > 0;
attdet->p_att = p_att;
return att;
}

44
3rd-party/lc3-google/src/attdet.h vendored Normal file
View File

@ -0,0 +1,44 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Time domain attack detector
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_ATTDET_H
#define __LC3_ATTDET_H
#include "common.h"
/**
* Time domain attack detector
* dt, sr Duration and samplerate of the frame
* nbytes Size in bytes of the frame
* attdet Context of the Attack Detector
* x [-6..-1] Previous, [0..ns-1] Current samples
* return 1: Attack detected 0: Otherwise
*/
bool lc3_attdet_run(enum lc3_dt dt, enum lc3_srate sr,
int nbytes, lc3_attdet_analysis_t *attdet, const float *x);
#endif /* __LC3_ATTDET_H */

375
3rd-party/lc3-google/src/bits.c vendored Normal file
View File

@ -0,0 +1,375 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "bits.h"
#include "common.h"
/* ----------------------------------------------------------------------------
* Common
* -------------------------------------------------------------------------- */
static inline int ac_get(struct lc3_bits_buffer *);
static inline void accu_load(struct lc3_bits_accu *, struct lc3_bits_buffer *);
/**
* Arithmetic coder return range bits
* ac Arithmetic coder
* return 1 + log2(ac->range)
*/
static int ac_get_range_bits(const struct lc3_bits_ac *ac)
{
int nbits = 0;
for (unsigned r = ac->range; r; r >>= 1, nbits++);
return nbits;
}
/**
* Arithmetic coder return pending bits
* ac Arithmetic coder
* return Pending bits
*/
static int ac_get_pending_bits(const struct lc3_bits_ac *ac)
{
return 26 - ac_get_range_bits(ac) +
((ac->cache >= 0) + ac->carry_count) * 8;
}
/**
* Return number of bits left in the bitstream
* bits Bitstream context
* return >= 0: Number of bits left < 0: Overflow
*/
static int get_bits_left(const struct lc3_bits *bits)
{
const struct lc3_bits_buffer *buffer = &bits->buffer;
const struct lc3_bits_accu *accu = &bits->accu;
const struct lc3_bits_ac *ac = &bits->ac;
uintptr_t end = (uintptr_t)buffer->p_bw +
(bits->mode == LC3_BITS_MODE_READ ? LC3_ACCU_BITS/8 : 0);
uintptr_t start = (uintptr_t)buffer->p_fw -
(bits->mode == LC3_BITS_MODE_READ ? LC3_AC_BITS/8 : 0);
int n = end > start ? (int)(end - start) : -(int)(start - end);
return 8 * n - (accu->n + accu->nover + ac_get_pending_bits(ac));
}
/**
* Setup bitstream writing
*/
void lc3_setup_bits(struct lc3_bits *bits,
enum lc3_bits_mode mode, void *buffer, int len)
{
*bits = (struct lc3_bits){
.mode = mode,
.accu = {
.n = mode == LC3_BITS_MODE_READ ? LC3_ACCU_BITS : 0,
},
.ac = {
.range = 0xffffff,
.cache = -1
},
.buffer = {
.start = (uint8_t *)buffer, .end = (uint8_t *)buffer + len,
.p_fw = (uint8_t *)buffer, .p_bw = (uint8_t *)buffer + len,
}
};
if (mode == LC3_BITS_MODE_READ) {
struct lc3_bits_ac *ac = &bits->ac;
struct lc3_bits_accu *accu = &bits->accu;
struct lc3_bits_buffer *buffer = &bits->buffer;
ac->low = ac_get(buffer) << 16;
ac->low |= ac_get(buffer) << 8;
ac->low |= ac_get(buffer);
accu_load(accu, buffer);
}
}
/**
* Return number of bits left in the bitstream
*/
int lc3_get_bits_left(const struct lc3_bits *bits)
{
return LC3_MAX(get_bits_left(bits), 0);
}
/**
* Return number of bits left in the bitstream
*/
int lc3_check_bits(const struct lc3_bits *bits)
{
const struct lc3_bits_ac *ac = &bits->ac;
return -(get_bits_left(bits) < 0 || ac->error);
}
/* ----------------------------------------------------------------------------
* Writing
* -------------------------------------------------------------------------- */
/**
* Flush the bits accumulator
* accu Bitstream accumulator
* buffer Bitstream buffer
*/
static inline void accu_flush(
struct lc3_bits_accu *accu, struct lc3_bits_buffer *buffer)
{
int nbytes = LC3_MIN(accu->n >> 3,
LC3_MAX(buffer->p_bw - buffer->p_fw, 0));
accu->n -= 8 * nbytes;
for ( ; nbytes; accu->v >>= 8, nbytes--)
*(--buffer->p_bw) = accu->v & 0xff;
if (accu->n >= 8)
accu->n = 0;
}
/**
* Arithmetic coder put byte
* buffer Bitstream buffer
* byte Byte to output
*/
static inline void ac_put(struct lc3_bits_buffer *buffer, int byte)
{
if (buffer->p_fw < buffer->end)
*(buffer->p_fw++) = byte;
}
/**
* Arithmetic coder range shift
* ac Arithmetic coder
* buffer Bitstream buffer
*/
static inline void ac_shift(
struct lc3_bits_ac *ac, struct lc3_bits_buffer *buffer)
{
if (ac->low < 0xff0000 || ac->carry)
{
if (ac->cache >= 0)
ac_put(buffer, ac->cache + ac->carry);
for ( ; ac->carry_count > 0; ac->carry_count--)
ac_put(buffer, ac->carry ? 0x00 : 0xff);
ac->cache = ac->low >> 16;
ac->carry = 0;
}
else
ac->carry_count++;
ac->low = (ac->low << 8) & 0xffffff;
}
/**
* Arithmetic coder termination
* ac Arithmetic coder
* buffer Bitstream buffer
* end_val/nbits End value and count of bits to terminate (1 to 8)
*/
static void ac_terminate(struct lc3_bits_ac *ac,
struct lc3_bits_buffer *buffer)
{
int nbits = 25 - ac_get_range_bits(ac);
unsigned mask = 0xffffff >> nbits;
unsigned val = ac->low + mask;
unsigned high = ac->low + ac->range;
bool over_val = val >> 24;
bool over_high = high >> 24;
val = (val & 0xffffff) & ~mask;
high = (high & 0xffffff);
if (over_val == over_high) {
if (val + mask >= high) {
nbits++;
mask >>= 1;
val = ((ac->low + mask) & 0xffffff) & ~mask;
}
ac->carry |= val < ac->low;
}
ac->low = val;
for (; nbits > 8; nbits -= 8)
ac_shift(ac, buffer);
ac_shift(ac, buffer);
int end_val = ac->cache >> (8 - nbits);
if (ac->carry_count) {
ac_put(buffer, ac->cache);
for ( ; ac->carry_count > 1; ac->carry_count--)
ac_put(buffer, 0xff);
end_val = nbits < 8 ? 0 : 0xff;
}
if (buffer->p_fw < buffer->end) {
*buffer->p_fw &= 0xff >> nbits;
*buffer->p_fw |= end_val << (8 - nbits);
}
}
/**
* Flush and terminate bitstream
*/
void lc3_flush_bits(struct lc3_bits *bits)
{
struct lc3_bits_ac *ac = &bits->ac;
struct lc3_bits_accu *accu = &bits->accu;
struct lc3_bits_buffer *buffer = &bits->buffer;
int nleft = buffer->p_bw - buffer->p_fw;
for (int n = 8 * nleft - accu->n; n > 0; n -= 32)
lc3_put_bits(bits, 0, LC3_MIN(n, 32));
accu_flush(accu, buffer);
ac_terminate(ac, buffer);
}
/**
* Write from 1 to 32 bits,
* exceeding the capacity of the accumulator
*/
void lc3_put_bits_generic(struct lc3_bits *bits, unsigned v, int n)
{
struct lc3_bits_accu *accu = &bits->accu;
/* --- Fulfill accumulator and flush -- */
int n1 = LC3_MIN(LC3_ACCU_BITS - accu->n, n);
if (n1) {
accu->v |= v << accu->n;
accu->n = LC3_ACCU_BITS;
}
accu_flush(accu, &bits->buffer);
/* --- Accumulate remaining bits -- */
accu->v = v >> n1;
accu->n = n - n1;
}
/**
* Arithmetic coder renormalization
*/
void lc3_ac_write_renorm(struct lc3_bits *bits)
{
struct lc3_bits_ac *ac = &bits->ac;
for ( ; ac->range < 0x10000; ac->range <<= 8)
ac_shift(ac, &bits->buffer);
}
/* ----------------------------------------------------------------------------
* Reading
* -------------------------------------------------------------------------- */
/**
* Arithmetic coder get byte
* buffer Bitstream buffer
* return Byte read, 0 on overflow
*/
static inline int ac_get(struct lc3_bits_buffer *buffer)
{
return buffer->p_fw < buffer->end ? *(buffer->p_fw++) : 0;
}
/**
* Load the accumulator
* accu Bitstream accumulator
* buffer Bitstream buffer
*/
static inline void accu_load(struct lc3_bits_accu *accu,
struct lc3_bits_buffer *buffer)
{
int nbytes = LC3_MIN(accu->n >> 3, buffer->p_bw - buffer->start);
accu->n -= 8 * nbytes;
for ( ; nbytes; nbytes--) {
accu->v >>= 8;
accu->v |= *(--buffer->p_bw) << (LC3_ACCU_BITS - 8);
}
if (accu->n >= 8) {
accu->nover = LC3_MIN(accu->nover + accu->n, LC3_ACCU_BITS);
accu->v >>= accu->n;
accu->n = 0;
}
}
/**
* Read from 1 to 32 bits,
* exceeding the capacity of the accumulator
*/
unsigned lc3_get_bits_generic(struct lc3_bits *bits, int n)
{
struct lc3_bits_accu *accu = &bits->accu;
struct lc3_bits_buffer *buffer = &bits->buffer;
/* --- Fulfill accumulator and read -- */
accu_load(accu, buffer);
int n1 = LC3_MIN(LC3_ACCU_BITS - accu->n, n);
unsigned v = (accu->v >> accu->n) & ((1u << n1) - 1);
accu->n += n1;
/* --- Second round --- */
int n2 = n - n1;
if (n2) {
accu_load(accu, buffer);
v |= ((accu->v >> accu->n) & ((1u << n2) - 1)) << n1;
accu->n += n2;
}
return v;
}
/**
* Arithmetic coder renormalization
*/
void lc3_ac_read_renorm(struct lc3_bits *bits)
{
struct lc3_bits_ac *ac = &bits->ac;
for ( ; ac->range < 0x10000; ac->range <<= 8)
ac->low = ((ac->low << 8) | ac_get(&bits->buffer)) & 0xffffff;
}

314
3rd-party/lc3-google/src/bits.h vendored Normal file
View File

@ -0,0 +1,314 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Bitstream management
*
* The bitstream is written by the 2 ends of the buffer :
*
* - Arthmetic coder put bits while increasing memory addresses
* in the buffer (forward)
*
* - Plain bits are puts starting the end of the buffer, with memeory
* addresses decreasing (backward)
*
* .---------------------------------------------------.
* | > > > > > > > > > > : : < < < < < < < < < |
* '---------------------------------------------------'
* |---------------------> - - - - - - - - - - - - - ->|
* |< - - - <-------------------|
* Arithmetic coding Plain bits
* `lc3_put_symbol()` `lc3_put_bits()`
*
* - The forward writing is protected against buffer overflow, it cannot
* write after the buffer, but can overwrite plain bits previously
* written in the buffer.
*
* - The backward writing is protected against overwrite of the arithmetic
* coder bitstream. In such way, the backward bitstream is always limited
* by the aritmetic coder bitstream, and can be overwritten by him.
*
* .---------------------------------------------------.
* | > > > > > > > > > > : : < < < < < < < < < |
* '---------------------------------------------------'
* |---------------------> - - - - - - - - - - - - - ->|
* |< - - - - - - - - - - - - - - <-------------------|
* Arithmetic coding Plain bits
* `lc3_get_symbol()` `lc3_get_bits()`
*
* - Reading is limited to read of the complementary end of the buffer.
*
* - The procedure `lc3_check_bits()` returns indication that read has been
* made crossing the other bit plane.
*
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*
*/
#ifndef __LC3_BITS_H
#define __LC3_BITS_H
#include "common.h"
/**
* Bitstream mode
*/
enum lc3_bits_mode {
LC3_BITS_MODE_READ,
LC3_BITS_MODE_WRITE,
};
/**
* Arithmetic coder symbol interval
* The model split the interval in 17 symbols
*/
struct lc3_ac_symbol {
uint16_t low : 16;
uint16_t range : 16;
};
struct lc3_ac_model {
struct lc3_ac_symbol s[17];
};
/**
* Bitstream context
*/
#define LC3_ACCU_BITS (int)(8 * sizeof(unsigned))
struct lc3_bits_accu {
unsigned v;
int n, nover;
};
#define LC3_AC_BITS (int)(24)
struct lc3_bits_ac {
unsigned low, range;
int cache, carry, carry_count;
bool error;
};
struct lc3_bits_buffer {
const uint8_t *start, *end;
uint8_t *p_fw, *p_bw;
};
typedef struct lc3_bits {
enum lc3_bits_mode mode;
struct lc3_bits_ac ac;
struct lc3_bits_accu accu;
struct lc3_bits_buffer buffer;
} lc3_bits_t;
/**
* Setup bitstream reading/writing
* bits Bitstream context
* mode Either READ or WRITE mode
* buffer, len Output buffer and length (in bytes)
*/
void lc3_setup_bits(lc3_bits_t *bits,
enum lc3_bits_mode mode, void *buffer, int len);
/**
* Return number of bits left in the bitstream
* bits Bitstream context
* return Number of bits left
*/
int lc3_get_bits_left(const lc3_bits_t *bits);
/**
* Check if error occured on bitstream reading/writing
* bits Bitstream context
* return 0: Ok -1: Bitstream overflow or AC reading error
*/
int lc3_check_bits(const lc3_bits_t *bits);
/**
* Put a bit
* bits Bitstream context
* v Bit value, 0 or 1
*/
static inline void lc3_put_bit(lc3_bits_t *bits, int v);
/**
* Put from 1 to 32 bits
* bits Bitstream context
* v, n Value, in range 0 to 2^n - 1, and bits count (1 to 32)
*/
static inline void lc3_put_bits(lc3_bits_t *bits, unsigned v, int n);
/**
* Put arithmetic coder symbol
* bits Bitstream context
* model, s Model distribution and symbol value
*/
static inline void lc3_put_symbol(lc3_bits_t *bits,
const struct lc3_ac_model *model, unsigned s);
/**
* Flush and terminate bitstream writing
* bits Bitstream context
*/
void lc3_flush_bits(lc3_bits_t *bits);
/**
* Get a bit
* bits Bitstream context
*/
static inline int lc3_get_bit(lc3_bits_t *bits);
/**
* Get from 1 to 32 bits
* bits Bitstream context
* n Number of bits to read (1 to 32)
* return The value read
*/
static inline unsigned lc3_get_bits(lc3_bits_t *bits, int n);
/**
* Get arithmetic coder symbol
* bits Bitstream context
* model Model distribution
* return The value read
*/
static inline unsigned lc3_get_symbol(lc3_bits_t *bits,
const struct lc3_ac_model *model);
/* ----------------------------------------------------------------------------
* Inline implementations
* -------------------------------------------------------------------------- */
void lc3_put_bits_generic(lc3_bits_t *bits, unsigned v, int n);
unsigned lc3_get_bits_generic(struct lc3_bits *bits, int n);
void lc3_ac_read_renorm(lc3_bits_t *bits);
void lc3_ac_write_renorm(lc3_bits_t *bits);
/**
* Put a bit
*/
static inline void lc3_put_bit(lc3_bits_t *bits, int v)
{
lc3_put_bits(bits, v, 1);
}
/**
* Put from 1 to 32 bits
*/
static inline void lc3_put_bits(struct lc3_bits *bits, unsigned v, int n)
{
struct lc3_bits_accu *accu = &bits->accu;
if (accu->n + n <= LC3_ACCU_BITS) {
accu->v |= v << accu->n;
accu->n += n;
} else {
lc3_put_bits_generic(bits, v, n);
}
}
/**
* Get a bit
*/
static inline int lc3_get_bit(lc3_bits_t *bits)
{
return lc3_get_bits(bits, 1);
}
/**
* Get from 1 to 32 bits
*/
static inline unsigned lc3_get_bits(struct lc3_bits *bits, int n)
{
struct lc3_bits_accu *accu = &bits->accu;
if (accu->n + n <= LC3_ACCU_BITS) {
int v = (accu->v >> accu->n) & ((1u << n) - 1);
return (accu->n += n), v;
}
else {
return lc3_get_bits_generic(bits, n);
}
}
/**
* Put arithmetic coder symbol
*/
static inline void lc3_put_symbol(
struct lc3_bits *bits, const struct lc3_ac_model *model, unsigned s)
{
const struct lc3_ac_symbol *symbols = model->s;
struct lc3_bits_ac *ac = &bits->ac;
unsigned range = ac->range >> 10;
ac->low += range * symbols[s].low;
ac->range = range * symbols[s].range;
ac->carry |= ac->low >> 24;
ac->low &= 0xffffff;
if (ac->range < 0x10000)
lc3_ac_write_renorm(bits);
}
/**
* Get arithmetic coder symbol
*/
static inline unsigned lc3_get_symbol(
lc3_bits_t *bits, const struct lc3_ac_model *model)
{
const struct lc3_ac_symbol *symbols = model->s;
struct lc3_bits_ac *ac = &bits->ac;
unsigned range = (ac->range >> 10) & 0xffff;
ac->error |= (ac->low >= (range << 10));
if (ac->error)
ac->low = 0;
int s = 16;
if (ac->low < range * symbols[s].low) {
s >>= 1;
s -= ac->low < range * symbols[s].low ? 4 : -4;
s -= ac->low < range * symbols[s].low ? 2 : -2;
s -= ac->low < range * symbols[s].low ? 1 : -1;
s -= ac->low < range * symbols[s].low;
}
ac->low -= range * symbols[s].low;
ac->range = range * symbols[s].range;
if (ac->range < 0x10000)
lc3_ac_read_renorm(bits);
return s;
}
#endif /* __LC3_BITS_H */

129
3rd-party/lc3-google/src/bwdet.c vendored Normal file
View File

@ -0,0 +1,129 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "bwdet.h"
/**
* Bandwidth detector
*/
enum lc3_bandwidth lc3_bwdet_run(
enum lc3_dt dt, enum lc3_srate sr, const float *e)
{
/* Bandwidth regions (Table 3.6) */
struct region { int is : 8; int ie : 8; };
static const struct region bws_table[LC3_NUM_DT]
[LC3_NUM_BANDWIDTH-1][LC3_NUM_BANDWIDTH-1] = {
[LC3_DT_7M5] = {
{ { 51, 63+1 } },
{ { 45, 55+1 }, { 58, 63+1 } },
{ { 42, 51+1 }, { 53, 58+1 }, { 60, 63+1 } },
{ { 40, 48+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } },
},
[LC3_DT_10M] = {
{ { 53, 63+1 } },
{ { 47, 56+1 }, { 59, 63+1 } },
{ { 44, 52+1 }, { 54, 59+1 }, { 60, 63+1 } },
{ { 41, 49+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } },
},
};
static const int l_table[LC3_NUM_DT][LC3_NUM_BANDWIDTH-1] = {
[LC3_DT_7M5] = { 4, 4, 3, 2 },
[LC3_DT_10M] = { 4, 4, 3, 1 },
};
/* --- Stage 1 ---
* Determine bw0 candidate */
enum lc3_bandwidth bw0 = LC3_BANDWIDTH_NB;
enum lc3_bandwidth bwn = (enum lc3_bandwidth)sr;
if (bwn <= bw0)
return bwn;
const struct region *bwr = bws_table[dt][bwn-1];
for (enum lc3_bandwidth bw = bw0; bw < bwn; bw++) {
int i = bwr[bw].is, ie = bwr[bw].ie;
int n = ie - i;
float se = e[i];
for (i++; i < ie; i++)
se += e[i];
if (se >= (10 << (bw == LC3_BANDWIDTH_NB)) * n)
bw0 = bw + 1;
}
/* --- Stage 2 ---
* Detect drop above cut-off frequency.
* The Tc condition (13) is precalculated, as
* Tc[] = 10 ^ (n / 10) , n = { 15, 23, 20, 20 } */
int hold = bw0 >= bwn;
if (!hold) {
int i0 = bwr[bw0].is, l = l_table[dt][bw0];
float tc = (const float []){
31.62277660, 199.52623150, 100, 100 }[bw0];
for (int i = i0 - l + 1; !hold && i <= i0 + 1; i++) {
hold = e[i-l] > tc * e[i];
}
}
return hold ? bw0 : bwn;
}
/**
* Return number of bits coding the bandwidth value
*/
int lc3_bwdet_get_nbits(enum lc3_srate sr)
{
return (sr > 0) + (sr > 1) + (sr > 3);
}
/**
* Put bandwidth indication
*/
void lc3_bwdet_put_bw(lc3_bits_t *bits,
enum lc3_srate sr, enum lc3_bandwidth bw)
{
int nbits_bw = lc3_bwdet_get_nbits(sr);
if (nbits_bw > 0)
lc3_put_bits(bits, bw, nbits_bw);
}
/**
* Get bandwidth indication
*/
int lc3_bwdet_get_bw(lc3_bits_t *bits,
enum lc3_srate sr, enum lc3_bandwidth *bw)
{
enum lc3_bandwidth max_bw = (enum lc3_bandwidth)sr;
int nbits_bw = lc3_bwdet_get_nbits(sr);
*bw = nbits_bw > 0 ? lc3_get_bits(bits, nbits_bw) : LC3_BANDWIDTH_NB;
return *bw > max_bw ? (*bw = max_bw), -1 : 0;
}

69
3rd-party/lc3-google/src/bwdet.h vendored Normal file
View File

@ -0,0 +1,69 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Bandwidth detector
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_BWDET_H
#define __LC3_BWDET_H
#include "common.h"
#include "bits.h"
/**
* Bandwidth detector (cf. 3.3.5)
* dt, sr Duration and samplerate of the frame
* e Energy estimation per bands
* return Return detected bandwitdth
*/
enum lc3_bandwidth lc3_bwdet_run(
enum lc3_dt dt, enum lc3_srate sr, const float *e);
/**
* Return number of bits coding the bandwidth value
* sr Samplerate of the frame
* return Number of bits coding the bandwidth value
*/
int lc3_bwdet_get_nbits(enum lc3_srate sr);
/**
* Put bandwidth indication
* bits Bitstream context
* sr Samplerate of the frame
* bw Bandwidth detected
*/
void lc3_bwdet_put_bw(lc3_bits_t *bits,
enum lc3_srate sr, enum lc3_bandwidth bw);
/**
* Get bandwidth indication
* bits Bitstream context
* sr Samplerate of the frame
* bw Return bandwidth indication
* return 0: Ok -1: Invalid bandwidth indication
*/
int lc3_bwdet_get_bw(lc3_bits_t *bits,
enum lc3_srate sr, enum lc3_bandwidth *bw);
#endif /* __LC3_BWDET_H */

105
3rd-party/lc3-google/src/common.h vendored Normal file
View File

@ -0,0 +1,105 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Common constants and types
*/
#ifndef __LC3_COMMON_H
#define __LC3_COMMON_H
#include <lc3.h>
#include <limits.h>
#include <string.h>
#include <math.h>
/**
* Macros
* MIN/MAX Minimum and maximum between 2 values
* CLIP Clip a value between low and high limits
* ABS Return the absolute value
*/
#define LC3_MIN(a, b) ( (a) < (b) ? (a) : (b) )
#define LC3_MAX(a, b) ( (a) > (b) ? (a) : (b) )
#define LC3_CLIP(v, min, max) LC3_MIN(LC3_MAX(v, min), max)
#define LC3_ABS(n) ( (n) < 0 ? -(n) : (n) )
/**
* Convert `dt` in us and `sr` in KHz
*/
#define LC3_DT_US(dt) \
( (3 + (dt)) * 2500 )
#define LC3_SRATE_KHZ(sr) \
( (1 + (sr) + ((sr) == LC3_SRATE_48K)) * 8 )
/**
* Return number of samples, delayed samples and
* encoded spectrum coefficients within a frame
* For decoding, add number of samples of 18 ms history
*/
#define LC3_NS(dt, sr) \
( 20 * (3 + (dt)) * (1 + (sr) + ((sr) == LC3_SRATE_48K)) )
#define LC3_ND(dt, sr) \
( (dt) == LC3_DT_7M5 ? 23 * LC3_NS(dt, sr) / 30 \
: 5 * LC3_NS(dt, sr) / 8 )
#define LC3_NE(dt, sr) \
( 20 * (3 + (dt)) * (1 + (sr)) )
#define LC3_MAX_NE \
LC3_NE(LC3_DT_10M, LC3_SRATE_48K)
#define LC3_NH(sr) \
(18 * LC3_SRATE_KHZ(sr))
/**
* Bandwidth, mapped to Nyquist frequency of samplerates
*/
enum lc3_bandwidth {
LC3_BANDWIDTH_NB = LC3_SRATE_8K,
LC3_BANDWIDTH_WB = LC3_SRATE_16K,
LC3_BANDWIDTH_SSWB = LC3_SRATE_24K,
LC3_BANDWIDTH_SWB = LC3_SRATE_32K,
LC3_BANDWIDTH_FB = LC3_SRATE_48K,
LC3_NUM_BANDWIDTH,
};
/**
* Complex floating point number
*/
struct lc3_complex
{
float re, im;
};
#endif /* __LC3_COMMON_H */

70
3rd-party/lc3-google/src/energy.c vendored Normal file
View File

@ -0,0 +1,70 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "energy.h"
#include "tables.h"
/**
* Energy estimation per band
*/
bool lc3_energy_compute(
enum lc3_dt dt, enum lc3_srate sr, const float *x, float *e)
{
static const int n1_table[LC3_NUM_DT][LC3_NUM_SRATE] = {
[LC3_DT_7M5] = { 56, 34, 27, 24, 22 },
[LC3_DT_10M] = { 49, 28, 23, 20, 18 },
};
/* First bands are 1 coefficient width */
int n1 = n1_table[dt][sr];
float e_sum[2] = { 0, 0 };
int iband;
for (iband = 0; iband < n1; iband++) {
*e = x[iband] * x[iband];
e_sum[0] += *(e++);
}
/* Mean the square of coefficients within each band,
* note that 7.5ms 8KHz frame has more bands than samples */
int nb = LC3_MIN(LC3_NUM_BANDS, LC3_NS(dt, sr));
int iband_h = nb - 2*(2 - dt);
const int *lim = lc3_band_lim[dt][sr];
for (int i = lim[iband]; iband < nb; iband++) {
int ie = lim[iband+1];
int n = ie - i;
float sx2 = x[i] * x[i];
for (i++; i < ie; i++)
sx2 += x[i] * x[i];
*e = sx2 / n;
e_sum[iband >= iband_h] += *(e++);
}
for (; iband < LC3_NUM_BANDS; iband++)
*(e++) = 0;
/* Return the near nyquist flag */
return e_sum[1] > 30 * e_sum[0];
}

43
3rd-party/lc3-google/src/energy.h vendored Normal file
View File

@ -0,0 +1,43 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Energy estimation per band
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_ENERGY_H
#define __LC3_ENERGY_H
#include "common.h"
/**
* Energy estimation per band
* dt, sr Duration and samplerate of the frame
* x Input MDCT coefficient
* e Energy estimation per bands
* return True when high energy detected near Nyquist frequency
*/
bool lc3_energy_compute(
enum lc3_dt dt, enum lc3_srate sr, const float *x, float *e);
#endif /* __LC3_ENERGY_H */

570
3rd-party/lc3-google/src/lc3.c vendored Normal file
View File

@ -0,0 +1,570 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <lc3.h>
#include "common.h"
#include "bits.h"
#include "attdet.h"
#include "bwdet.h"
#include "ltpf.h"
#include "mdct.h"
#include "energy.h"
#include "sns.h"
#include "tns.h"
#include "spec.h"
#include "plc.h"
/**
* Frame side data
*/
struct side_data {
enum lc3_bandwidth bw;
bool pitch_present;
lc3_ltpf_data_t ltpf;
lc3_sns_data_t sns;
lc3_tns_data_t tns;
lc3_spec_side_t spec;
};
/* ----------------------------------------------------------------------------
* General
* -------------------------------------------------------------------------- */
/**
* Resolve frame duration in us
* us Frame duration in us
* return Frame duration identifier, or LC3_NUM_DT
*/
static enum lc3_dt resolve_dt(int us)
{
return us == 7500 ? LC3_DT_7M5 :
us == 10000 ? LC3_DT_10M : LC3_NUM_DT;
}
/**
* Resolve samplerate in Hz
* hz Samplerate in Hz
* return Sample rate identifier, or LC3_NUM_SRATE
*/
static enum lc3_srate resolve_sr(int hz)
{
return hz == 8000 ? LC3_SRATE_8K : hz == 16000 ? LC3_SRATE_16K :
hz == 24000 ? LC3_SRATE_24K : hz == 32000 ? LC3_SRATE_32K :
hz == 48000 ? LC3_SRATE_48K : LC3_NUM_SRATE;
}
/**
* Return the number of PCM samples in a frame
*/
int lc3_frame_samples(int dt_us, int sr_hz)
{
enum lc3_dt dt = resolve_dt(dt_us);
enum lc3_srate sr = resolve_sr(sr_hz);
if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE)
return -1;
return LC3_NS(dt, sr);
}
/**
* Return the size of frames, from bitrate
*/
int lc3_frame_bytes(int dt_us, int bitrate)
{
if (resolve_dt(dt_us) >= LC3_NUM_DT)
return -1;
if (bitrate < LC3_MIN_BITRATE)
return LC3_MIN_FRAME_BYTES;
if (bitrate > LC3_MAX_BITRATE)
return LC3_MAX_FRAME_BYTES;
int nbytes = ((unsigned)bitrate * dt_us) / (1000*1000*8);
return LC3_CLIP(nbytes, LC3_MIN_FRAME_BYTES, LC3_MAX_FRAME_BYTES);
}
/**
* Resolve the bitrate, from the size of frames
*/
int lc3_resolve_bitrate(int dt_us, int nbytes)
{
if (resolve_dt(dt_us) >= LC3_NUM_DT)
return -1;
if (nbytes < LC3_MIN_FRAME_BYTES)
return LC3_MIN_BITRATE;
if (nbytes > LC3_MAX_FRAME_BYTES)
return LC3_MAX_BITRATE;
int bitrate = ((unsigned)nbytes * (1000*1000*8) + dt_us/2) / dt_us;
return LC3_CLIP(bitrate, LC3_MIN_BITRATE, LC3_MAX_BITRATE);
}
/**
* Return algorithmic delay, as a number of samples
*/
int lc3_delay_samples(int dt_us, int sr_hz)
{
enum lc3_dt dt = resolve_dt(dt_us);
enum lc3_srate sr = resolve_sr(sr_hz);
if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE)
return -1;
return (dt == LC3_DT_7M5 ? 8 : 5) * (LC3_SRATE_KHZ(sr) / 2);
}
/* ----------------------------------------------------------------------------
* Encoder
* -------------------------------------------------------------------------- */
/**
* Input PCM Samples from signed 16 bits
* encoder Encoder state
* pcm, stride Input PCM samples, and count between two consecutives
*/
static void load_s16(
struct lc3_encoder *encoder, const void *_pcm, int stride)
{
const int16_t *pcm = _pcm;
enum lc3_dt dt = encoder->dt;
enum lc3_srate sr = encoder->sr_pcm;
float *xs = encoder->xs;
int ns = LC3_NS(dt, sr);
for (int i = 0; i < ns; i++)
xs[i] = pcm[i*stride];
}
/**
* Input PCM Samples from signed 24 bits
* encoder Encoder state
* pcm, stride Input PCM samples, and count between two consecutives
*/
static void load_s24(
struct lc3_encoder *encoder, const void *_pcm, int stride)
{
const int32_t *pcm = _pcm;
enum lc3_dt dt = encoder->dt;
enum lc3_srate sr = encoder->sr_pcm;
float *xs = encoder->xs;
int ns = LC3_NS(dt, sr);
for (int i = 0; i < ns; i++)
xs[i] = ldexpf(pcm[i*stride], -8);
}
/**
* Frame Analysis
* encoder Encoder state
* nbytes Size in bytes of the frame
* side, xq Return frame data
*/
static void analyze(struct lc3_encoder *encoder,
int nbytes, struct side_data *side, int16_t *xq)
{
enum lc3_dt dt = encoder->dt;
enum lc3_srate sr = encoder->sr;
enum lc3_srate sr_pcm = encoder->sr_pcm;
int ns = LC3_NS(dt, sr_pcm);
int nd = LC3_ND(dt, sr_pcm);
float *xs = encoder->xs;
float *xf = encoder->xf;
/* --- Temporal --- */
bool att = lc3_attdet_run(dt, sr_pcm, nbytes, &encoder->attdet, xs);
side->pitch_present =
lc3_ltpf_analyse(dt, sr_pcm, &encoder->ltpf, xs, &side->ltpf);
/* --- Spectral --- */
float e[LC3_NUM_BANDS];
lc3_mdct_forward(dt, sr_pcm, sr, xs, xf);
memmove(xs - nd, xs + ns-nd, nd * sizeof(float));
bool nn_flag = lc3_energy_compute(dt, sr, xf, e);
if (nn_flag)
lc3_ltpf_disable(&side->ltpf);
side->bw = lc3_bwdet_run(dt, sr, e);
lc3_sns_analyze(dt, sr, e, att, &side->sns, xf, xf);
lc3_tns_analyze(dt, side->bw, nn_flag, nbytes, &side->tns, xf);
lc3_spec_analyze(dt, sr,
nbytes, side->pitch_present, &side->tns,
&encoder->spec, xf, xq, &side->spec);
}
/**
* Encode bitstream
* encoder Encoder state
* side, xq The frame data
* nbytes Target size of the frame (20 to 400)
* buffer Output bitstream buffer of `nbytes` size
*/
static void encode(struct lc3_encoder *encoder,
const struct side_data *side, int16_t *xq, int nbytes, void *buffer)
{
enum lc3_dt dt = encoder->dt;
enum lc3_srate sr = encoder->sr;
enum lc3_bandwidth bw = side->bw;
float *xf = encoder->xf;
lc3_bits_t bits;
lc3_setup_bits(&bits, LC3_BITS_MODE_WRITE, buffer, nbytes);
lc3_bwdet_put_bw(&bits, sr, bw);
lc3_spec_put_side(&bits, dt, sr, &side->spec);
lc3_tns_put_data(&bits, &side->tns);
lc3_put_bit(&bits, side->pitch_present);
lc3_sns_put_data(&bits, &side->sns);
if (side->pitch_present)
lc3_ltpf_put_data(&bits, &side->ltpf);
lc3_spec_encode(&bits,
dt, sr, bw, nbytes, xq, &side->spec, xf);
lc3_flush_bits(&bits);
}
/**
* Return size needed for an encoder
*/
unsigned lc3_encoder_size(int dt_us, int sr_hz)
{
if (resolve_dt(dt_us) >= LC3_NUM_DT ||
resolve_sr(sr_hz) >= LC3_NUM_SRATE)
return 0;
return sizeof(struct lc3_encoder) +
LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz) * sizeof(float);
}
/**
* Setup encoder
*/
struct lc3_encoder *lc3_setup_encoder(
int dt_us, int sr_hz, int sr_pcm_hz, void *mem)
{
if (sr_pcm_hz <= 0)
sr_pcm_hz = sr_hz;
enum lc3_dt dt = resolve_dt(dt_us);
enum lc3_srate sr = resolve_sr(sr_hz);
enum lc3_srate sr_pcm = resolve_sr(sr_pcm_hz);
if (dt >= LC3_NUM_DT || sr_pcm >= LC3_NUM_SRATE || sr > sr_pcm || !mem)
return NULL;
struct lc3_encoder *encoder = mem;
int ns = LC3_NS(dt, sr_pcm);
int nd = LC3_ND(dt, sr_pcm);
*encoder = (struct lc3_encoder){
.dt = dt, .sr = sr,
.sr_pcm = sr_pcm,
.xs = encoder->s + nd,
.xf = encoder->s + nd+ns,
};
memset(encoder->s, 0,
LC3_ENCODER_BUFFER_COUNT(dt_us, sr_pcm_hz) * sizeof(float));
return encoder;
}
/**
* Encode a frame
*/
int lc3_encode(struct lc3_encoder *encoder, enum lc3_pcm_format fmt,
const void *pcm, int stride, int nbytes, void *out)
{
static void (* const load[])(struct lc3_encoder *, const void *, int) = {
[LC3_PCM_FORMAT_S16] = load_s16,
[LC3_PCM_FORMAT_S24] = load_s24,
};
/* --- Check parameters --- */
if (!encoder || nbytes < LC3_MIN_FRAME_BYTES
|| nbytes > LC3_MAX_FRAME_BYTES)
return -1;
/* --- Processing --- */
struct side_data side;
int16_t xq[LC3_NE(encoder->dt, encoder->sr)];
load[fmt](encoder, pcm, stride);
analyze(encoder, nbytes, &side, xq);
encode(encoder, &side, xq, nbytes, out);
return 0;
}
/* ----------------------------------------------------------------------------
* Decoder
* -------------------------------------------------------------------------- */
/**
* Output PCM Samples to signed 16 bits
* decoder Decoder state
* pcm, stride Output PCM samples, and count between two consecutives
*/
static void store_s16(
struct lc3_decoder *decoder, void *_pcm, int stride)
{
int16_t *pcm = _pcm;
enum lc3_dt dt = decoder->dt;
enum lc3_srate sr = decoder->sr_pcm;
float *xs = decoder->xs;
int ns = LC3_NS(dt, sr);
for ( ; ns > 0; ns--, xs++, pcm += stride) {
int s = *xs >= 0 ? (int)(*xs + 0.5f) : (int)(*xs - 0.5f);
*pcm = LC3_CLIP(s, INT16_MIN, INT16_MAX);
}
}
/**
* Output PCM Samples to signed 24 bits
* decoder Decoder state
* pcm, stride Output PCM samples, and count between two consecutives
*/
static void store_s24(
struct lc3_decoder *decoder, void *_pcm, int stride)
{
int32_t *pcm = _pcm;
const int32_t int24_max = (1 << 23) - 1;
const int32_t int24_min = -(1 << 23);
enum lc3_dt dt = decoder->dt;
enum lc3_srate sr = decoder->sr_pcm;
float *xs = decoder->xs;
int ns = LC3_NS(dt, sr);
for ( ; ns > 0; ns--, xs++, pcm += stride) {
int32_t s = *xs >= 0 ? (int32_t)(ldexpf(*xs, 8) + 0.5f)
: (int32_t)(ldexpf(*xs, 8) - 0.5f);
*pcm = LC3_CLIP(s, int24_min, int24_max);
}
}
/**
* Decode bitstream
* decoder Decoder state
* data, nbytes Input bitstream buffer
* side Return the side data
* return 0: Ok < 0: Bitsream error detected
*/
static int decode(struct lc3_decoder *decoder,
const void *data, int nbytes, struct side_data *side)
{
enum lc3_dt dt = decoder->dt;
enum lc3_srate sr = decoder->sr;
float *xf = decoder->xs;
int ns = LC3_NS(dt, sr);
int ne = LC3_NE(dt, sr);
lc3_bits_t bits;
int ret = 0;
lc3_setup_bits(&bits, LC3_BITS_MODE_READ, (void *)data, nbytes);
if ((ret = lc3_bwdet_get_bw(&bits, sr, &side->bw)) < 0)
return ret;
if ((ret = lc3_spec_get_side(&bits, dt, sr, &side->spec)) < 0)
return ret;
lc3_tns_get_data(&bits, dt, side->bw, nbytes, &side->tns);
side->pitch_present = lc3_get_bit(&bits);
if ((ret = lc3_sns_get_data(&bits, &side->sns)) < 0)
return ret;
if (side->pitch_present)
lc3_ltpf_get_data(&bits, &side->ltpf);
if ((ret = lc3_spec_decode(&bits, dt, sr,
side->bw, nbytes, &side->spec, xf)) < 0)
return ret;
memset(xf + ne, 0, (ns - ne) * sizeof(float));
return lc3_check_bits(&bits);
}
/**
* Frame synthesis
* decoder Decoder state
* side Frame data, NULL performs PLC
* nbytes Size in bytes of the frame
*/
static void synthesize(struct lc3_decoder *decoder,
const struct side_data *side, int nbytes)
{
enum lc3_dt dt = decoder->dt;
enum lc3_srate sr = decoder->sr;
enum lc3_srate sr_pcm = decoder->sr_pcm;
int ns = LC3_NS(dt, sr_pcm);
int ne = LC3_NE(dt, sr);
int nh = LC3_NH(sr_pcm);
float *xf = decoder->xs;
float *xg = decoder->xg;
float *xd = decoder->xd;
float *xs = xf;
if (side) {
enum lc3_bandwidth bw = side->bw;
lc3_plc_suspend(&decoder->plc);
lc3_tns_synthesize(dt, bw, &side->tns, xf);
lc3_sns_synthesize(dt, sr, &side->sns, xf, xg);
lc3_mdct_inverse(dt, sr_pcm, sr, xg, xd, xs);
} else {
lc3_plc_synthesize(dt, sr, &decoder->plc, xg, xf);
memset(xf + ne, 0, (ns - ne) * sizeof(float));
lc3_mdct_inverse(dt, sr_pcm, sr, xf, xd, xs);
}
lc3_ltpf_synthesize(dt, sr_pcm, nbytes, &decoder->ltpf,
side && side->pitch_present ? &side->ltpf : NULL, xs);
memmove(xs - nh, xs - nh+ns, nh * sizeof(*xs));
}
/**
* Return size needed for a decoder
*/
unsigned lc3_decoder_size(int dt_us, int sr_hz)
{
if (resolve_dt(dt_us) >= LC3_NUM_DT ||
resolve_sr(sr_hz) >= LC3_NUM_SRATE)
return 0;
return sizeof(struct lc3_decoder) +
LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz) * sizeof(float);
}
/**
* Setup decoder
*/
struct lc3_decoder *lc3_setup_decoder(
int dt_us, int sr_hz, int sr_pcm_hz, void *mem)
{
if (sr_pcm_hz <= 0)
sr_pcm_hz = sr_hz;
enum lc3_dt dt = resolve_dt(dt_us);
enum lc3_srate sr = resolve_sr(sr_hz);
enum lc3_srate sr_pcm = resolve_sr(sr_pcm_hz);
if (dt >= LC3_NUM_DT || sr_pcm >= LC3_NUM_SRATE || sr > sr_pcm || !mem)
return NULL;
struct lc3_decoder *decoder = mem;
int nh = LC3_NH(sr_pcm);
int ns = LC3_NS(dt, sr_pcm);
int nd = LC3_ND(dt, sr_pcm);
*decoder = (struct lc3_decoder){
.dt = dt, .sr = sr,
.sr_pcm = sr_pcm,
.xs = decoder->s + nh,
.xd = decoder->s + nh+ns,
.xg = decoder->s + nh+ns+nd,
};
lc3_plc_reset(&decoder->plc);
memset(decoder->s, 0,
LC3_DECODER_BUFFER_COUNT(dt_us, sr_pcm_hz) * sizeof(float));
return decoder;
}
/**
* Decode a frame
*/
int lc3_decode(struct lc3_decoder *decoder, const void *in, int nbytes,
enum lc3_pcm_format fmt, void *pcm, int stride)
{
static void (* const store[])(struct lc3_decoder *, void *, int) = {
[LC3_PCM_FORMAT_S16] = store_s16,
[LC3_PCM_FORMAT_S24] = store_s24,
};
/* --- Check parameters --- */
if (!decoder)
return -1;
if (in && (nbytes < LC3_MIN_FRAME_BYTES ||
nbytes > LC3_MAX_FRAME_BYTES ))
return -1;
/* --- Processing --- */
struct side_data side;
int ret = !in || (decode(decoder, in, nbytes, &side) < 0);
synthesize(decoder, ret ? NULL : &side, nbytes);
store[fmt](decoder, pcm, stride);
return ret;
}

621
3rd-party/lc3-google/src/ltpf.c vendored Normal file
View File

@ -0,0 +1,621 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "ltpf.h"
#include "tables.h"
/* ----------------------------------------------------------------------------
* Resampling
* -------------------------------------------------------------------------- */
/**
* Resample to 12.8 KHz (cf. 3.3.9.3-4) Template
* sr Samplerate source of the frame
* hp50 State of the High-Pass 50 Hz filter
* x [-d..-1] Previous, [0..ns-1] Current samples
* y, n [0..n-1] Output `n` processed samples
*
* The number of previous samples `d` accessed on `x` is :
* d: { 10, 20, 30, 40, 60 } - 1 for samplerates from 8KHz to 48KHz
*/
static inline void resample_12k8_template(const enum lc3_srate sr,
struct lc3_ltpf_hp50_state *hp50, const float *x, float *y, int n)
{
/* --- Parameters ---
* p: Resampling factor, from 4 to 24
* w: Half width of polyphase filter
*
* bn, an: High-Pass Biquad coefficients,
* with `bn` support of rescaling resampling factor.
* Note that it's an High-Pass filter, so we have `b0 = b2`,
* in the following steps we use `b0` as `b2`. */
const int p = 192 / LC3_SRATE_KHZ(sr);
const int w = 5 * LC3_SRATE_KHZ(sr) / 8;
const int b_scale = p >> (sr == LC3_SRATE_8K);
const float a1 = -1.965293373, b1 = -1.965589417 * b_scale;
const float a2 = 0.965885461, b2 = 0.982794708 * b_scale;
/* --- Resampling ---
* The value `15*8 * n` is divisible by all resampling factors `p`,
* integer and fractionnal position can be determined at compilation
* time while unrolling the loops by 8 samples.
* The biquad filter implementation chosen in the `Direct Form 2`. */
const float *h = lc3_ltpf_h12k8 + 119;
x -= w;
for (int i = 0; i < n; i += 8, x += 120/p)
for (int j = 0; j < 15*8; j += 15) {
float un, yn;
int e, f, k;
e = j / p, f = j % p;
for (un = 0, k = 1-w; k <= w; k++)
un += x[e+k] * h[k*p - f];
yn = b2 * un + hp50->s1;
hp50->s1 = b1 * un - a1 * yn + hp50->s2;
hp50->s2 = b2 * un - a2 * yn;
*(y++) = yn;
}
}
/**
* LTPF Resample to 12.8 KHz implementations for each samplerates
*/
static void resample_8k_12k8(
struct lc3_ltpf_hp50_state *hp50, const float *x, float *y, int n)
{
resample_12k8_template(LC3_SRATE_8K, hp50, x, y, n);
}
static void resample_16k_12k8(
struct lc3_ltpf_hp50_state *hp50, const float *x, float *y, int n)
{
resample_12k8_template(LC3_SRATE_16K, hp50, x, y, n);
}
static void resample_24k_12k8(
struct lc3_ltpf_hp50_state *hp50, const float *x, float *y, int n)
{
resample_12k8_template(LC3_SRATE_24K, hp50, x, y, n);
}
static void resample_32k_12k8(
struct lc3_ltpf_hp50_state *hp50, const float *x, float *y, int n)
{
resample_12k8_template(LC3_SRATE_32K, hp50, x, y, n);
}
static void resample_48k_12k8(
struct lc3_ltpf_hp50_state *hp50, const float *x, float *y, int n)
{
resample_12k8_template(LC3_SRATE_48K, hp50, x, y, n);
}
static void (* const resample_12k8[])
(struct lc3_ltpf_hp50_state *, const float *, float *, int ) =
{
[LC3_SRATE_8K ] = resample_8k_12k8,
[LC3_SRATE_16K] = resample_16k_12k8,
[LC3_SRATE_24K] = resample_24k_12k8,
[LC3_SRATE_32K] = resample_32k_12k8,
[LC3_SRATE_48K] = resample_48k_12k8,
};
/**
* Resample to 6.4 KHz (cf. 3.3.9.3-4)
* x [-3..-1] Previous, [0..n-1] Current samples
* y, n [0..n-1] Output `n` processed samples
*/
static void resample_6k4(const float *x, float *y, int n)
{
static const float h[] = { 0.2819382921, 0.2353512128, 0.1236796411 };
float xn2 = x[-3], xn1 = x[-2], x0 = x[-1], x1, x2;
for (const float *ye = y + n; y < ye; xn2 = x0, xn1 = x1, x0 = x2) {
x1 = *(x++); x2 = *(x++);
*(y++) = x0 * h[0] + (xn1 + x1) * h[1] + (xn2 + x2) * h[2];
}
}
/* ----------------------------------------------------------------------------
* Analysis
* -------------------------------------------------------------------------- */
/**
* Return dot product of 2 vectors
* a, b, n The 2 vectors of size `n`
* return sum( a[i] * b[i] ), i = [0..n-1]
*/
static inline float dot(const float *a, const float *b, int n)
{
float v = 0;
while (n--)
v += *(a++) * *(b++);
return v;
}
/**
* Return vector of correlations
* a, b, n The 2 vector of size `n` to correlate
* y, nc Output the correlation vector of size `nc`
*
* The size `n` of input vectors must be multiple of 16
*/
static void correlate(
const float *a, const float *b, int n, float *y, int nc)
{
for (const float *ye = y + nc; y < ye; )
*(y++) = dot(a, b--, n);
}
/**
* Search the maximum value and returns its argument
* x, n The input vector of size `n`
* x_max Return the maximum value
* return Return the argument of the maximum
*/
static int argmax(const float *x, int n, float *x_max)
{
int arg = 0;
*x_max = x[arg = 0];
for (int i = 1; i < n; i++)
if (*x_max < x[i])
*x_max = x[arg = i];
return arg;
}
/**
* Search the maximum weithed value and returns its argument
* x, n The input vector of size `n`
* w_incr Increment of the weight
* x_max, xw_max Return the maximum not weighted value
* return Return the argument of the weigthed maximum
*/
static int argmax_weighted(
const float *x, int n, float w_incr, float *x_max)
{
int arg;
float xw_max = (*x_max = x[arg = 0]);
float w = 1 + w_incr;
for (int i = 1; i < n; i++, w += w_incr)
if (xw_max < x[i] * w)
xw_max = (*x_max = x[arg = i]) * w;
return arg;
}
/**
* Interpolate from pitch detected value (3.3.9.8)
* x, n [-2..-1] Previous, [0..n] Current input
* d The phase of interpolation (0 to 3)
* return The interpolated vector
*
* The size `n` of vectors must be multiple of 4
*/
static void interpolate(const float *x, int n, int d, float *y)
{
static const float h4[][8] = {
{ 2.09880463e-01, 5.83527575e-01, 2.09880463e-01 },
{ 1.06999186e-01, 5.50075002e-01, 3.35690625e-01, 6.69885837e-03 },
{ 3.96711478e-02, 4.59220930e-01, 4.59220930e-01, 3.96711478e-02 },
{ 6.69885837e-03, 3.35690625e-01, 5.50075002e-01, 1.06999186e-01 },
};
const float *h = h4[d];
float x3 = x[-2], x2 = x[-1], x1, x0;
x1 = (*x++);
for (const float *ye = y + n; y < ye; ) {
*(y++) = (x0 = *(x++)) * h[0] + x1 * h[1] + x2 * h[2] + x3 * h[3];
*(y++) = (x3 = *(x++)) * h[0] + x0 * h[1] + x1 * h[2] + x2 * h[3];
*(y++) = (x2 = *(x++)) * h[0] + x3 * h[1] + x0 * h[2] + x1 * h[3];
*(y++) = (x1 = *(x++)) * h[0] + x2 * h[1] + x3 * h[2] + x0 * h[3];
}
}
/**
* Interpolate autocorrelation (3.3.9.7)
* x [-4..-1] Previous, [0..4] Current input
* d The phase of interpolation (-3 to 3)
* return The interpolated value
*/
static float interpolate_4(const float *x, int d)
{
static const float h4[][8] = {
{ 1.53572770e-02, -4.72963246e-02, 8.35788573e-02, 8.98638285e-01,
8.35788573e-02, -4.72963246e-02, 1.53572770e-02, },
{ 2.74547165e-03, 4.59833449e-03, -7.54404636e-02, 8.17488686e-01,
3.30182571e-01, -1.05835916e-01, 2.86823405e-02, -2.87456116e-03 },
{ -3.00125103e-03, 2.95038503e-02, -1.30305021e-01, 6.03297008e-01,
6.03297008e-01, -1.30305021e-01, 2.95038503e-02, -3.00125103e-03 },
{ -2.87456116e-03, 2.86823405e-02, -1.05835916e-01, 3.30182571e-01,
8.17488686e-01, -7.54404636e-02, 4.59833449e-03, 2.74547165e-03 },
};
const float *h = h4[(4+d) % 4];
float y = d < 0 ? x[-4] * *(h++) :
d > 0 ? x[ 4] * *(h+7) : 0;
y += x[-3] * h[0] + x[-2] * h[1] + x[-1] * h[2] + x[0] * h[3] +
x[ 1] * h[4] + x[ 2] * h[5] + x[ 3] * h[6];
return y;
}
/**
* Pitch detection algorithm (3.3.9.5-6)
* ltpf Context of analysis
* x, n [-114..-17] Previous, [0..n-1] Current 6.4KHz samples
* tc Return the pitch-lag estimation
* return True when pitch present
*/
static bool detect_pitch(
struct lc3_ltpf_analysis *ltpf, const float *x, int n, int *tc)
{
float rm1, rm2;
float r[98];
const int r0 = 17, nr = 98;
int k0 = LC3_MAX( 0, ltpf->tc-4);
int nk = LC3_MIN(nr-1, ltpf->tc+4) - k0 + 1;
correlate(x, x - r0, n, r, nr);
int t1 = argmax_weighted(r, nr, -.5/(nr-1), &rm1);
int t2 = k0 + argmax(r + k0, nk, &rm2);
const float *x1 = x - (r0 + t1);
const float *x2 = x - (r0 + t2);
float nc1 = rm1 <= 0 ? 0 :
rm1 / sqrtf(dot(x, x, n) * dot(x1, x1, n));
float nc2 = rm2 <= 0 ? 0 :
rm2 / sqrtf(dot(x, x, n) * dot(x2, x2, n));
int t1sel = nc2 <= 0.85 * nc1;
ltpf->tc = (t1sel ? t1 : t2);
*tc = r0 + ltpf->tc;
return (t1sel ? nc1 : nc2) > 0.6;
}
/**
* Pitch-lag parameter (3.3.9.7)
* x, n [-232..-28] Previous, [0..n-1] Current 12.8KHz samples
* tc Pitch-lag estimation
* pitch The pitch value, in fixed .4
* return The bitstream pitch index value
*/
static int refine_pitch(const float *x, int n, int tc, int *pitch)
{
float r[17], rm;
int e, f;
int r0 = LC3_MAX( 32, 2*tc - 4);
int nr = LC3_MIN(228, 2*tc + 4) - r0 + 1;
correlate(x, x - (r0 - 4), n, r, nr + 8);
e = r0 + argmax(r + 4, nr, &rm);
const float *re = r + (e - (r0 - 4));
float dm = interpolate_4(re, f = 0);
for (int i = 1; i <= 3; i++) {
float d;
if (e >= 127 && ((i & 1) | (e >= 157)))
continue;
if ((d = interpolate_4(re, i)) > dm)
dm = d, f = i;
if (e > 32 && (d = interpolate_4(re, -i)) > dm)
dm = d, f = -i;
}
e -= (f < 0);
f += 4*(f < 0);
*pitch = 4*e + f;
return e < 127 ? 4*e + f - 128 :
e < 157 ? 2*e + (f >> 1) + 126 : e + 283;
}
/**
* LTPF Analysis
*/
bool lc3_ltpf_analyse(enum lc3_dt dt, enum lc3_srate sr,
struct lc3_ltpf_analysis *ltpf, const float *x, struct lc3_ltpf_data *data)
{
/* --- Resampling to 12.8 KHz --- */
int z_12k8 = sizeof(ltpf->x_12k8) / sizeof(float);
int n_12k8 = dt == LC3_DT_7M5 ? 96 : 128;
memmove(ltpf->x_12k8, ltpf->x_12k8 + n_12k8,
(z_12k8 - n_12k8) * sizeof(float));
float *x_12k8 = ltpf->x_12k8 + (z_12k8 - n_12k8);
resample_12k8[sr](&ltpf->hp50, x, x_12k8, n_12k8);
x_12k8 -= (dt == LC3_DT_7M5 ? 44 : 24);
/* --- Resampling to 6.4 KHz --- */
int z_6k4 = sizeof(ltpf->x_6k4) / sizeof(float);
int n_6k4 = n_12k8 >> 1;
memmove(ltpf->x_6k4, ltpf->x_6k4 + n_6k4,
(z_6k4 - n_6k4) * sizeof(float));
float *x_6k4 = ltpf->x_6k4 + (z_6k4 - n_6k4);
resample_6k4(x_12k8, x_6k4, n_6k4);
/* --- Pitch detection --- */
int tc, pitch = 0;
float nc = 0;
bool pitch_present = detect_pitch(ltpf, x_6k4, n_6k4, &tc);
if (pitch_present) {
float u[n_12k8], v[n_12k8];
data->pitch_index = refine_pitch(x_12k8, n_12k8, tc, &pitch);
interpolate(x_12k8, n_12k8, 0, u);
interpolate(x_12k8 - (pitch >> 2), n_12k8, pitch & 3, v);
nc = dot(u, v, n_12k8) / sqrtf(dot(u, u, n_12k8) * dot(v, v, n_12k8));
}
/* --- Activation --- */
if (ltpf->active) {
int pitch_diff =
LC3_MAX(pitch, ltpf->pitch) - LC3_MIN(pitch, ltpf->pitch);
float nc_diff = nc - ltpf->nc[0];
data->active = pitch_present &&
((nc > 0.9) || (nc > 0.84 && pitch_diff < 8 && nc_diff > -0.1));
} else {
data->active = pitch_present &&
( (dt == LC3_DT_10M || ltpf->nc[1] > 0.94) &&
(ltpf->nc[0] > 0.94 && nc > 0.94) );
}
ltpf->active = data->active;
ltpf->pitch = pitch;
ltpf->nc[1] = ltpf->nc[0];
ltpf->nc[0] = nc;
return pitch_present;
}
/* ----------------------------------------------------------------------------
* Synthesis
* -------------------------------------------------------------------------- */
/**
* Synthesis filter template
* ym [-w/2..0] Previous, [0..w-1] Current pitch samples
* xm w-1 previous input samples
* x, n Current samples as input, filtered as output
* c, w Coefficients by pair (num, den), and count of pairs
* fade Fading mode of filter -1: Out 1: In 0: None
*/
static inline void synthesize_template(const float *ym, const float *xm,
float *x, int n, const float (*c)[2], const int w, int fade)
{
float g = (float)(fade <= 0);
float g_incr = (float)((fade > 0) - (fade < 0)) / n;
float u[w];
int i;
ym -= (w >> 1);
/* --- Load previous samples --- */
for (i = 1-w; i < 0; i++) {
float xi = *(xm++), yi = *(ym++);
u[i + w-1] = 0;
for (int k = w-1; k+i >= 0; k--)
u[i+k] += xi * c[k][0] - yi * c[k][1];
}
u[w-1] = 0;
/* --- Process --- */
for (; i < n; i += w) {
for (int j = 0; j < w; j++, g += g_incr) {
float xi = *x, yi = *(ym++);
for (int k = w-1; k >= 0; k--)
u[(j+k)%w] += xi * c[k][0] - yi * c[k][1];
*(x++) = xi - g * u[j];
u[j] = 0;
}
}
}
/**
* Synthesis filter for each samplerates (width of filter)
*/
static void synthesize_4(const float *ym, const float *xm,
float *x, int n, const float (*c)[2], int fade)
{
synthesize_template(ym, xm, x, n, c, 4, fade);
}
static void synthesize_6(const float *ym, const float *xm,
float *x, int n, const float (*c)[2], int fade)
{
synthesize_template(ym, xm, x, n, c, 6, fade);
}
static void synthesize_8(const float *ym, const float *xm,
float *x, int n, const float (*c)[2], int fade)
{
synthesize_template(ym, xm, x, n, c, 8, fade);
}
static void synthesize_12(const float *ym, const float *xm,
float *x, int n, const float (*c)[2], int fade)
{
synthesize_template(ym, xm, x, n, c, 12, fade);
}
static void (* const synthesize[])(
const float *, const float *, float *, int, const float (*)[2], int) =
{
[LC3_SRATE_8K ] = synthesize_4,
[LC3_SRATE_16K] = synthesize_4,
[LC3_SRATE_24K] = synthesize_6,
[LC3_SRATE_32K] = synthesize_8,
[LC3_SRATE_48K] = synthesize_12,
};
/**
* LTPF Synthesis
*/
void lc3_ltpf_synthesize(enum lc3_dt dt, enum lc3_srate sr,
int nbytes, struct lc3_ltpf_synthesis *ltpf,
const struct lc3_ltpf_data *data, float *x)
{
int dt_us = LC3_DT_US(dt);
/* --- Filter parameters --- */
int p_idx = data ? data->pitch_index : 0;
int pitch =
p_idx >= 440 ? (((p_idx ) - 283) << 2) :
p_idx >= 380 ? (((p_idx >> 1) - 63) << 2) + (((p_idx & 1)) << 1) :
(((p_idx >> 2) + 32) << 2) + (((p_idx & 3)) << 0) ;
pitch = (pitch * LC3_SRATE_KHZ(sr) * 10 + 64) / 128;
int nbits = (nbytes*8 * 10000 + (dt_us/2)) / dt_us;
int g_idx = LC3_MAX(nbits / 80, 3 + (int)sr) - (3 + sr);
bool active = data && data->active && g_idx < 4;
int w = LC3_MAX(4, LC3_SRATE_KHZ(sr) / 4);
float c[w][2];
for (int i = 0; i < w; i++) {
float g = active ? 0.4f - 0.05f * g_idx : 0;
c[i][0] = active ? 0.85f * g * lc3_ltpf_cnum[sr][g_idx][i] : 0;
c[i][1] = active ? g * lc3_ltpf_cden[sr][pitch & 3][i] : 0;
}
/* --- Transition handling --- */
int ns = LC3_NS(dt, sr);
int nt = ns / (4 - (dt == LC3_DT_7M5));
float xm[12];
if (active)
memcpy(xm, x + nt-(w-1), (w-1) * sizeof(float));
if (!ltpf->active && active)
synthesize[sr](x - pitch/4, ltpf->x, x, nt, c, 1);
else if (ltpf->active && !active)
synthesize[sr](x - ltpf->pitch/4, ltpf->x, x, nt, ltpf->c, -1);
else if (ltpf->active && active && ltpf->pitch == pitch)
synthesize[sr](x - pitch/4, ltpf->x, x, nt, c, 0);
else if (ltpf->active && active) {
synthesize[sr](x - ltpf->pitch/4, ltpf->x, x, nt, ltpf->c, -1);
synthesize[sr](x - pitch/4, x - (w-1), x, nt, c, 1);
}
/* --- Remainder --- */
memcpy(ltpf->x, x + ns-(w-1), (w-1) * sizeof(float));
if (active)
synthesize[sr](x - pitch/4 + nt, xm, x + nt, ns-nt, c, 0);
/* --- Update state --- */
ltpf->active = active;
ltpf->pitch = pitch;
memcpy(ltpf->c, c, w * sizeof(ltpf->c[0]));
}
/* ----------------------------------------------------------------------------
* Bitstream data
* -------------------------------------------------------------------------- */
/**
* LTPF disable
*/
void lc3_ltpf_disable(struct lc3_ltpf_data *data)
{
data->active = false;
}
/**
* Return number of bits coding the bitstream data
*/
int lc3_ltpf_get_nbits(bool pitch)
{
return 1 + 10 * pitch;
}
/**
* Put bitstream data
*/
void lc3_ltpf_put_data(lc3_bits_t *bits,
const struct lc3_ltpf_data *data)
{
lc3_put_bit(bits, data->active);
lc3_put_bits(bits, data->pitch_index, 9);
}
/**
* Get bitstream data
*/
void lc3_ltpf_get_data(lc3_bits_t *bits, struct lc3_ltpf_data *data)
{
data->active = lc3_get_bit(bits);
data->pitch_index = lc3_get_bits(bits, 9);
}

107
3rd-party/lc3-google/src/ltpf.h vendored Normal file
View File

@ -0,0 +1,107 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Long Term Postfilter
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_LTPF_H
#define __LC3_LTPF_H
#include "common.h"
#include "bits.h"
/**
* LTPF data
*/
typedef struct lc3_ltpf_data {
bool active;
int pitch_index;
} lc3_ltpf_data_t;
/* ----------------------------------------------------------------------------
* Encoding
* -------------------------------------------------------------------------- */
/**
* LTPF analysis
* dt, sr Duration and samplerate of the frame
* ltpf Context of analysis
* allowed True when activation of LTPF is allowed
* x [-d..-1] Previous, [0..ns-1] Current samples
* data Return bitstream data
* return True when pitch present, False otherwise
*
* The number of previous samples `d` accessed on `x` is :
* d: { 10, 20, 30, 40, 60 } - 1 for samplerates from 8KHz to 48KHz
*/
bool lc3_ltpf_analyse(enum lc3_dt dt, enum lc3_srate sr,
lc3_ltpf_analysis_t *ltpf, const float *x, lc3_ltpf_data_t *data);
/**
* LTPF disable
* data LTPF data, disabled activation on return
*/
void lc3_ltpf_disable(lc3_ltpf_data_t *data);
/**
* Return number of bits coding the bitstream data
* pitch True when pitch present, False otherwise
* return Bit consumption, including the pitch present flag
*/
int lc3_ltpf_get_nbits(bool pitch);
/**
* Put bitstream data
* bits Bitstream context
* data LTPF data
*/
void lc3_ltpf_put_data(lc3_bits_t *bits, const lc3_ltpf_data_t *data);
/* ----------------------------------------------------------------------------
* Decoding
* -------------------------------------------------------------------------- */
/**
* Get bitstream data
* bits Bitstream context
* data Return bitstream data
*/
void lc3_ltpf_get_data(lc3_bits_t *bits, lc3_ltpf_data_t *data);
/**
* LTPF synthesis
* dt, sr Duration and samplerate of the frame
* nbytes Size in bytes of the frame
* ltpf Context of synthesis
* data Bitstream data, NULL when pitch not present
* x [-d..-1] Previous, [0..ns-1] Current, filtered as output
*
* The number of previous samples `d` accessed on `x` is about 18 ms
*/
void lc3_ltpf_synthesize(enum lc3_dt dt, enum lc3_srate sr, int nbytes,
lc3_ltpf_synthesis_t *ltpf, const lc3_ltpf_data_t *data, float *x);
#endif /* __LC3_LTPF_H */

502
3rd-party/lc3-google/src/mdct.c vendored Normal file
View File

@ -0,0 +1,502 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "tables.h"
/* ----------------------------------------------------------------------------
* FFT processing
* -------------------------------------------------------------------------- */
/**
* FFT 5 Points template
* s -1: Forward 1: Inverse
* x, y Input and output coefficients, of size 5xn
* n Number of interleaved transform to perform
*/
static inline void xfft_5(const float s,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
static const float cos1 = 0.3090169944; /* cos(-2Pi 1/5) */
static const float cos2 = -0.8090169944; /* cos(-2Pi 2/5) */
static const float sin1 = -0.9510565163; /* sin(-2Pi 1/5) */
static const float sin2 = -0.5877852523; /* sin(-2Pi 2/5) */
for (int i = 0; i < n; i++, x++, y+= 5) {
struct lc3_complex s14 =
{ x[1*n].re + x[4*n].re, x[1*n].im + x[4*n].im };
struct lc3_complex d14 =
{ x[1*n].re - x[4*n].re, x[1*n].im - x[4*n].im };
struct lc3_complex s23 =
{ x[2*n].re + x[3*n].re, x[2*n].im + x[3*n].im };
struct lc3_complex d23 =
{ x[2*n].re - x[3*n].re, x[2*n].im - x[3*n].im };
y[0].re = x[0].re + s14.re + s23.re;
y[0].im = x[0].im + s14.im + s23.im;
y[1].re = x[0].re + s14.re * cos1 + s * d14.im * sin1
+ s23.re * cos2 + s * d23.im * sin2;
y[1].im = x[0].im + s14.im * cos1 - s * d14.re * sin1
+ s23.im * cos2 - s * d23.re * sin2;
y[2].re = x[0].re + s14.re * cos2 + s * d14.im * sin2
+ s23.re * cos1 - s * d23.im * sin1;
y[2].im = x[0].im + s14.im * cos2 - s * d14.re * sin2
+ s23.im * cos1 + s * d23.re * sin1;
y[3].re = x[0].re + s14.re * cos2 - s * d14.im * sin2
+ s23.re * cos1 + s * d23.im * sin1;
y[3].im = x[0].im + s14.im * cos2 + s * d14.re * sin2
+ s23.im * cos1 - s * d23.re * sin1;
y[4].re = x[0].re + s14.re * cos1 - s * d14.im * sin1
+ s23.re * cos2 - s * d23.im * sin2;
y[4].im = x[0].im + s14.im * cos1 + s * d14.re * sin1
+ s23.im * cos2 + s * d23.re * sin2;
}
}
/**
* FFT Butterfly 3 Points template
* s -1: Forward 1: Inverse
* x, y Input and output coefficients
* twiddles Twiddles factors, determine size of transform
* n Number of interleaved transforms
*/
static inline void xfft_bf3(
const float s, const struct lc3_fft_bf3_twiddles *twiddles,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
int n3 = twiddles->n3;
const struct lc3_complex (*w0)[2] = twiddles->t;
const struct lc3_complex (*w1)[2] = w0 + n3, (*w2)[2] = w1 + n3;
const struct lc3_complex *x0 = x, *x1 = x0 + n*n3, *x2 = x1 + n*n3;
struct lc3_complex *y0 = y, *y1 = y0 + n3, *y2 = y1 + n3;
for (int i = 0; i < n; i++, y0 += 3*n3, y1 += 3*n3, y2 += 3*n3) {
for (int j = 0; j < n3; j++, x0++, x1++, x2++) {
y0[j].re = x0->re + x1->re * w0[j][0].re + s * x1->im * w0[j][0].im
+ x2->re * w0[j][1].re + s * x2->im * w0[j][1].im;
y0[j].im = x0->im + x1->im * w0[j][0].re - s * x1->re * w0[j][0].im
+ x2->im * w0[j][1].re - s * x2->re * w0[j][1].im;
y1[j].re = x0->re + x1->re * w1[j][0].re + s * x1->im * w1[j][0].im
+ x2->re * w1[j][1].re + s * x2->im * w1[j][1].im;
y1[j].im = x0->im + x1->im * w1[j][0].re - s * x1->re * w1[j][0].im
+ x2->im * w1[j][1].re - s * x2->re * w1[j][1].im;
y2[j].re = x0->re + x1->re * w2[j][0].re + s * x1->im * w2[j][0].im
+ x2->re * w2[j][1].re + s * x2->im * w2[j][1].im;
y2[j].im = x0->im + x1->im * w2[j][0].re - s * x1->re * w2[j][0].im
+ x2->im * w2[j][1].re - s * x2->re * w2[j][1].im;
}
}
}
/**
* FFT Butterfly 2 Points template
* s -1: Forward 1: Inverse
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static inline void xfft_bf2(
const float s, const struct lc3_fft_bf2_twiddles *twiddles,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
int n2 = twiddles->n2;
const struct lc3_complex *w = twiddles->t;
const struct lc3_complex *x0 = x, *x1 = x0 + n*n2;
struct lc3_complex *y0 = y, *y1 = y0 + n2;
for (int i = 0; i < n; i++, y0 += 2*n2, y1 += 2*n2) {
for (int j = 0; j < n2; j++, x0++, x1++) {
y0[j].re = x0->re + x1->re * w[j].re + s * x1->im * w[j].im;
y0[j].im = x0->im + x1->im * w[j].re - s * x1->re * w[j].im;
y1[j].re = x0->re - x1->re * w[j].re - s * x1->im * w[j].im;
y1[j].im = x0->im - x1->im * w[j].re + s * x1->re * w[j].im;
}
}
}
/**
* Forward FFT 5 Points
* x, y Input and output coefficients, of size 5xn
* n Number of interleaved transform to perform
*/
static void ffft_5(const struct lc3_complex *x, struct lc3_complex *y, int n)
{
xfft_5(-1, x, y, n);
}
/**
* Inverse FFT 5 Points
* x, y Input and output coefficients, of size 5xn
* n Number of interleaved transform to perform
*/
static void ifft_5(const struct lc3_complex *x, struct lc3_complex *y, int n)
{
xfft_5(1, x, y, n);
}
/**
* Forward FFT Butterfly 3 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ffft_bf3(const struct lc3_fft_bf3_twiddles *twiddles,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
xfft_bf3(-1, twiddles, x, y, n);
}
/**
* Inverse FFT Butterfly 3 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ifft_bf3(const struct lc3_fft_bf3_twiddles *twiddles,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
xfft_bf3(1, twiddles, x, y, n);
}
/**
* Forward FFT Butterfly 2 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ffft_bf2(const struct lc3_fft_bf2_twiddles *twiddles,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
xfft_bf2(-1, twiddles, x, y, n);
}
/**
* InverseIFFT Butterfly 2 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ifft_bf2(const struct lc3_fft_bf2_twiddles *twiddles,
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
xfft_bf2(1, twiddles, x, y, n);
}
/**
* Perform FFT
* inverse True on inverse transform else forward
* x, y0, y1 Input, and 2 scratch buffers of size `n`
* n Number of points 30, 40, 60, 80, 90, 120, 160, 180, 240
* return The buffer `y0` or `y1` that hold the result
*
* Input `x` can be the same as the `y0` second scratch buffer
*/
static struct lc3_complex *fft(
bool inverse, const struct lc3_complex *x, int n,
struct lc3_complex *y0, struct lc3_complex *y1)
{
struct lc3_complex *y[2] = { y1, y0 };
int i2, i3, is = 0;
/* The number of points `n` can be decomposed as :
*
* n = 5^1 * 3^n3 * 2^n2
*
* for n = 40, 80, 160 n3 = 0, n2 = [3..5]
* n = 30, 60, 120, 240 n3 = 1, n2 = [1..4]
* n = 90, 180 n3 = 2, n2 = [1..2]
*
* Note that the expression `n & (n-1) == 0` is equivalent
* to the check that `n` is a power of 2. */
(inverse ? ifft_5 : ffft_5)(x, y[is], n /= 5);
for (i3 = 0; n & (n-1); i3++, is ^= 1)
(inverse ? ifft_bf3 : ffft_bf3)
(lc3_fft_twiddles_bf3[i3], y[is], y[is ^ 1], n /= 3);
for (i2 = 0; n > 1; i2++, is ^= 1)
(inverse ? ifft_bf2 : ffft_bf2)
(lc3_fft_twiddles_bf2[i2][i3], y[is], y[is ^ 1], n >>= 1);
return y[is];
}
/* ----------------------------------------------------------------------------
* MDCT processing
* -------------------------------------------------------------------------- */
/**
* Windowing of samples before MDCT
* dt, sr Duration and samplerate (size of the transform)
* x [-nd..-1] Previous, [0..ns-1] Current samples
* y Output `ns` windowed samples
*
* The number of previous samples `nd` accessed on `x` is :
* nd: `ns` * 23/30 for 7.5ms frame duration
* nd: `ns` * 5/ 8 for 10ms frame duration
*/
static void mdct_window(
enum lc3_dt dt, enum lc3_srate sr, const float *x, float *y)
{
int ns = LC3_NS(dt, sr), nd = LC3_ND(dt, sr);
const float *w0 = lc3_mdct_win[dt][sr], *w1 = w0 + ns;
const float *w2 = w1, *w3 = w2 + nd;
const float *x0 = x - nd, *x1 = x0 + ns;
const float *x2 = x1, *x3 = x2 + nd;
float *y0 = y + ns/2, *y1 = y0;
while (x0 < x1)
*(--y0) = *(x0++) * *(w0++) - *(--x1) * *(--w1);
for (const float *xe = x2 + ns-nd; x2 < xe; )
*(y1++) = *(x2++) * *(w2++);
while (x2 < x3)
*(y1++) = *(x2++) * *(w2++) + *(--x3) * *(--w3);
}
/**
* Pre-rotate MDCT coefficients of N/2 points, before FFT N/4 points FFT
* def Size and twiddles factors
* x, y Input and output coefficients
*
* `x` and y` can be the same buffer
*/
static void mdct_pre_fft(const struct lc3_mdct_rot_def *def,
const float *x, struct lc3_complex *y)
{
int n4 = def->n4;
const float *x0 = x, *x1 = x0 + 2*n4;
const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
struct lc3_complex *y0 = y, *y1 = y0 + n4;
while (x0 < x1) {
struct lc3_complex u, uw = *(w0++);
u.re = - *(--x1) * uw.re + *x0 * uw.im;
u.im = *(x0++) * uw.re + *x1 * uw.im;
struct lc3_complex v, vw = *(--w1);
v.re = - *(--x1) * vw.im + *x0 * vw.re;
v.im = - *(x0++) * vw.im - *x1 * vw.re;
*(y0++) = u;
*(--y1) = v;
}
}
/**
* Post-rotate FFT N/4 points coefficients, resulting MDCT N points
* def Size and twiddles factors
* x, y Input and output coefficients
* scale Scale on output coefficients
*
* `x` and y` can be the same buffer
*/
static void mdct_post_fft(const struct lc3_mdct_rot_def *def,
const struct lc3_complex *x, float *y, float scale)
{
int n4 = def->n4, n8 = n4 >> 1;
const struct lc3_complex *w0 = def->w + n8, *w1 = w0 - 1;
const struct lc3_complex *x0 = x + n8, *x1 = x0 - 1;
float *y0 = y + n4, *y1 = y0;
for ( ; y1 > y; x0++, x1--, w0++, w1--) {
float u0 = (x0->im * w0->im + x0->re * w0->re) * scale;
float u1 = (x1->re * w1->im - x1->im * w1->re) * scale;
float v0 = (x0->re * w0->im - x0->im * w0->re) * scale;
float v1 = (x1->im * w1->im + x1->re * w1->re) * scale;
*(y0++) = u0; *(y0++) = u1;
*(--y1) = v0; *(--y1) = v1;
}
}
/**
* Pre-rotate IMDCT coefficients of N points, before FFT N/4 points FFT
* def Size and twiddles factors
* x, y Input and output coefficients
*
* `x` and y` can be the same buffer
*/
static void imdct_pre_fft(const struct lc3_mdct_rot_def *def,
const float *x, struct lc3_complex *y)
{
int n4 = def->n4;
const float *x0 = x, *x1 = x0 + 2*n4;
const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
struct lc3_complex *y0 = y, *y1 = y0 + n4;
while (x0 < x1) {
float u0 = *(x0++), u1 = *(--x1);
float v0 = *(x0++), v1 = *(--x1);
struct lc3_complex uw = *(w0++), vw = *(--w1);
(y0 )->re = - u1 * uw.re + u0 * uw.im;
(y0++)->im = - u0 * uw.re - u1 * uw.im;
(--y1)->re = - v0 * vw.re + v1 * vw.im;
( y1)->im = - v1 * vw.re - v0 * vw.im;
}
}
/**
* Post-rotate FFT N/4 points coefficients, resulting IMDCT N points
* def Size and twiddles factors
* x, y Input and output coefficients
* scale Scale on output coefficients
*
* `x` and y` can be the same buffer
*/
static void imdct_post_fft(const struct lc3_mdct_rot_def *def,
const struct lc3_complex *x, float *y, float scale)
{
int n4 = def->n4;
const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
const struct lc3_complex *x0 = x, *x1 = x0 + n4;
float *y0 = y, *y1 = y0 + 2*n4;
while (x0 < x1) {
struct lc3_complex uz = *(x0++), vz = *(--x1);
struct lc3_complex uw = *(w0++), vw = *(--w1);
*(y0++) = (uz.im * uw.im - uz.re * uw.re) * scale;
*(--y1) = (uz.im * uw.re + uz.re * uw.im) * scale;
*(--y1) = (vz.im * vw.im - vz.re * vw.re) * scale;
*(y0++) = (vz.im * vw.re + vz.re * vw.im) * scale;
}
}
/**
* Apply windowing of samples
* dt, sr Duration and samplerate
* x, d Middle half of IMDCT coefficients and delayed samples
* y, d Output samples and delayed ones
*/
static void imdct_window(enum lc3_dt dt, enum lc3_srate sr,
const float *x, float *d, float *y)
{
/* The full MDCT coefficients is given by symmetry :
* T[ 0 .. n/4-1] = -half[n/4-1 .. 0 ]
* T[ n/4 .. n/2-1] = half[0 .. n/4-1]
* T[ n/2 .. 3n/4-1] = half[n/4 .. n/2-1]
* T[3n/4 .. n-1] = half[n/2-1 .. n/4 ] */
int n4 = LC3_NS(dt, sr) >> 1, nd = LC3_ND(dt, sr);
const float *w2 = lc3_mdct_win[dt][sr], *w0 = w2 + 3*n4, *w1 = w0;
const float *x0 = d + nd-n4, *x1 = x0;
float *y0 = y + nd-n4, *y1 = y0, *y2 = d + nd, *y3 = d;
while (y0 > y) {
*(--y0) = *(--x0) - *(x ) * *(w1++);
*(y1++) = *(x1++) + *(x++) * *(--w0);
}
while (y1 < y + nd) {
*(y1++) = *(x1++) + *(x++) * *(--w0);
}
while (y1 < y + 2*n4) {
*(y1++) = *(x ) * *(--w0);
*(--y2) = *(x++) * *(w2++);
}
while (y2 > y3) {
*(y3++) = *(x ) * *(--w0);
*(--y2) = *(x++) * *(w2++);
}
}
/**
* Forward MDCT transformation
*/
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_dst, const float *x, float *y)
{
const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
int nf = LC3_NS(dt, sr_dst);
int ns = LC3_NS(dt, sr);
union { float *f; struct lc3_complex *z; } u = { .f = y };
struct lc3_complex z[ns/2];
mdct_window(dt, sr, x, u.f);
mdct_pre_fft(rot, u.f, u.z);
u.z = fft(false, u.z, ns/2, u.z, z);
mdct_post_fft(rot, u.z, y, sqrtf( (2.f*nf) / (ns*ns) ));
}
/**
* Inverse MDCT transformation
*/
void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_src, const float *x, float *d, float *y)
{
const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
int nf = LC3_NS(dt, sr_src);
int ns = LC3_NS(dt, sr);
struct lc3_complex buffer[ns/2];
struct lc3_complex *z = (struct lc3_complex *)y;
union { float *f; struct lc3_complex *z; } u = { .z = buffer };
imdct_pre_fft(rot, x, z);
z = fft(true, z, ns/2, z, u.z);
imdct_post_fft(rot, z, u.f, sqrtf(2.f / nf));
imdct_window(dt, sr, u.f, d, y);
}

59
3rd-party/lc3-google/src/mdct.h vendored Normal file
View File

@ -0,0 +1,59 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Compute LD-MDCT (Low Delay Modified Discret Cosinus Transform)
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_MDCT_H
#define __LC3_MDCT_H
#include "common.h"
/**
* Forward MDCT transformation
* dt, sr Duration and samplerate (size of the transform)
* sr_dst Samplerate destination, scale transforam accordingly
* x [-nd..-1] Previous, [0..ns-1] Current samples
* y Output `ns` frequency coefficients
*
* The number of previous samples `nd` accessed on `x` is :
* nd: `ns` * 23/30 for 7.5ms frame duration
* nd: `ns` * 5/ 8 for 10ms frame duration
*/
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_dst, const float *x, float *y);
/**
* Inverse MDCT transformation
* dt, sr Duration and samplerate (size of the transform)
* sr_src Samplerate source, scale transforam accordingly
* x, d Frequency coefficients and delayed buffer
* y, d Output `ns` samples and `nd` delayed ones
*
* `x` and `y` can be the same buffer
*/
void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_src, const float *x, float *d, float *y);
#endif /* __LC3_MDCT_H */

61
3rd-party/lc3-google/src/plc.c vendored Normal file
View File

@ -0,0 +1,61 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "plc.h"
/**
* Reset Packet Loss Concealment state
*/
void lc3_plc_reset(struct lc3_plc_state *plc)
{
plc->seed = 24607;
lc3_plc_suspend(plc);
}
/**
* Suspend PLC execution (Good frame received)
*/
void lc3_plc_suspend(struct lc3_plc_state *plc)
{
plc->count = 1;
plc->alpha = 1.0f;
}
/**
* Synthesis of a PLC frame
*/
void lc3_plc_synthesize(enum lc3_dt dt, enum lc3_srate sr,
struct lc3_plc_state *plc, const float *x, float *y)
{
uint16_t seed = plc->seed;
float alpha = plc->alpha;
int ne = LC3_NE(dt, sr);
alpha *= (plc->count < 4 ? 1.0f :
plc->count < 8 ? 0.9f : 0.85f);
for (int i = 0; i < ne; i++) {
seed = (16831 + seed * 12821) & 0xffff;
y[i] = alpha * (seed & 0x8000 ? -x[i] : x[i]);
}
plc->seed = seed;
plc->alpha = alpha;
plc->count++;
}

57
3rd-party/lc3-google/src/plc.h vendored Normal file
View File

@ -0,0 +1,57 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Packet Loss Concealment
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_PLC_H
#define __LC3_PLC_H
#include "common.h"
/**
* Reset PLC state
* plc PLC State to reset
*/
void lc3_plc_reset(lc3_plc_state_t *plc);
/**
* Suspend PLC synthesis (Error-free frame decoded)
* plc PLC State
*/
void lc3_plc_suspend(lc3_plc_state_t *plc);
/**
* Synthesis of a PLC frame
* dt, sr Duration and samplerate of the frame
* plc PLC State
* x Last good spectral coefficients
* y Return emulated ones
*
* `x` and `y` can be the same buffer
*/
void lc3_plc_synthesize(enum lc3_dt dt, enum lc3_srate sr,
lc3_plc_state_t *plc, const float *x, float *y);
#endif /* __LC3_PLC_H */

878
3rd-party/lc3-google/src/sns.c vendored Normal file
View File

@ -0,0 +1,878 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "sns.h"
#include "tables.h"
/* ----------------------------------------------------------------------------
* DCT-16
* -------------------------------------------------------------------------- */
/**
* Matrix of DCT-16 coefficients
*
* M[n][k] = 2f cos( Pi k (2n + 1) / 2N )
*
* k = [0..N-1], n = [0..N-1], N = 16
* f = sqrt(1/4N) for k=0, sqrt(1/2N) otherwise
*/
static const float dct16_m[16][16] = {
{ 2.50000000e-01, 3.51850934e-01, 3.46759961e-01, 3.38329500e-01,
3.26640741e-01, 3.11806253e-01, 2.93968901e-01, 2.73300467e-01,
2.50000000e-01, 2.24291897e-01, 1.96423740e-01, 1.66663915e-01,
1.35299025e-01, 1.02631132e-01, 6.89748448e-02, 3.46542923e-02 },
{ 2.50000000e-01, 3.38329500e-01, 2.93968901e-01, 2.24291897e-01,
1.35299025e-01, 3.46542923e-02, -6.89748448e-02, -1.66663915e-01,
-2.50000000e-01, -3.11806253e-01, -3.46759961e-01, -3.51850934e-01,
-3.26640741e-01, -2.73300467e-01, -1.96423740e-01, -1.02631132e-01 },
{ 2.50000000e-01, 3.11806253e-01, 1.96423740e-01, 3.46542923e-02,
-1.35299025e-01, -2.73300467e-01, -3.46759961e-01, -3.38329500e-01,
-2.50000000e-01, -1.02631132e-01, 6.89748448e-02, 2.24291897e-01,
3.26640741e-01, 3.51850934e-01, 2.93968901e-01, 1.66663915e-01 },
{ 2.50000000e-01, 2.73300467e-01, 6.89748448e-02, -1.66663915e-01,
-3.26640741e-01, -3.38329500e-01, -1.96423740e-01, 3.46542923e-02,
2.50000000e-01, 3.51850934e-01, 2.93968901e-01, 1.02631132e-01,
-1.35299025e-01, -3.11806253e-01, -3.46759961e-01, -2.24291897e-01 },
{ 2.50000000e-01, 2.24291897e-01, -6.89748448e-02, -3.11806253e-01,
-3.26640741e-01, -1.02631132e-01, 1.96423740e-01, 3.51850934e-01,
2.50000000e-01, -3.46542923e-02, -2.93968901e-01, -3.38329500e-01,
-1.35299025e-01, 1.66663915e-01, 3.46759961e-01, 2.73300467e-01 },
{ 2.50000000e-01, 1.66663915e-01, -1.96423740e-01, -3.51850934e-01,
-1.35299025e-01, 2.24291897e-01, 3.46759961e-01, 1.02631132e-01,
-2.50000000e-01, -3.38329500e-01, -6.89748448e-02, 2.73300467e-01,
3.26640741e-01, 3.46542923e-02, -2.93968901e-01, -3.11806253e-01 },
{ 2.50000000e-01, 1.02631132e-01, -2.93968901e-01, -2.73300467e-01,
1.35299025e-01, 3.51850934e-01, 6.89748448e-02, -3.11806253e-01,
-2.50000000e-01, 1.66663915e-01, 3.46759961e-01, 3.46542923e-02,
-3.26640741e-01, -2.24291897e-01, 1.96423740e-01, 3.38329500e-01 },
{ 2.50000000e-01, 3.46542923e-02, -3.46759961e-01, -1.02631132e-01,
3.26640741e-01, 1.66663915e-01, -2.93968901e-01, -2.24291897e-01,
2.50000000e-01, 2.73300467e-01, -1.96423740e-01, -3.11806253e-01,
1.35299025e-01, 3.38329500e-01, -6.89748448e-02, -3.51850934e-01 },
{ 2.50000000e-01, -3.46542923e-02, -3.46759961e-01, 1.02631132e-01,
3.26640741e-01, -1.66663915e-01, -2.93968901e-01, 2.24291897e-01,
2.50000000e-01, -2.73300467e-01, -1.96423740e-01, 3.11806253e-01,
1.35299025e-01, -3.38329500e-01, -6.89748448e-02, 3.51850934e-01 },
{ 2.50000000e-01, -1.02631132e-01, -2.93968901e-01, 2.73300467e-01,
1.35299025e-01, -3.51850934e-01, 6.89748448e-02, 3.11806253e-01,
-2.50000000e-01, -1.66663915e-01, 3.46759961e-01, -3.46542923e-02,
-3.26640741e-01, 2.24291897e-01, 1.96423740e-01, -3.38329500e-01 },
{ 2.50000000e-01, -1.66663915e-01, -1.96423740e-01, 3.51850934e-01,
-1.35299025e-01, -2.24291897e-01, 3.46759961e-01, -1.02631132e-01,
-2.50000000e-01, 3.38329500e-01, -6.89748448e-02, -2.73300467e-01,
3.26640741e-01, -3.46542923e-02, -2.93968901e-01, 3.11806253e-01 },
{ 2.50000000e-01, -2.24291897e-01, -6.89748448e-02, 3.11806253e-01,
-3.26640741e-01, 1.02631132e-01, 1.96423740e-01, -3.51850934e-01,
2.50000000e-01, 3.46542923e-02, -2.93968901e-01, 3.38329500e-01,
-1.35299025e-01, -1.66663915e-01, 3.46759961e-01, -2.73300467e-01 },
{ 2.50000000e-01, -2.73300467e-01, 6.89748448e-02, 1.66663915e-01,
-3.26640741e-01, 3.38329500e-01, -1.96423740e-01, -3.46542923e-02,
2.50000000e-01, -3.51850934e-01, 2.93968901e-01, -1.02631132e-01,
-1.35299025e-01, 3.11806253e-01, -3.46759961e-01, 2.24291897e-01 },
{ 2.50000000e-01, -3.11806253e-01, 1.96423740e-01, -3.46542923e-02,
-1.35299025e-01, 2.73300467e-01, -3.46759961e-01, 3.38329500e-01,
-2.50000000e-01, 1.02631132e-01, 6.89748448e-02, -2.24291897e-01,
3.26640741e-01, -3.51850934e-01, 2.93968901e-01, -1.66663915e-01 },
{ 2.50000000e-01, -3.38329500e-01, 2.93968901e-01, -2.24291897e-01,
1.35299025e-01, -3.46542923e-02, -6.89748448e-02, 1.66663915e-01,
-2.50000000e-01, 3.11806253e-01, -3.46759961e-01, 3.51850934e-01,
-3.26640741e-01, 2.73300467e-01, -1.96423740e-01, 1.02631132e-01 },
{ 2.50000000e-01, -3.51850934e-01, 3.46759961e-01, -3.38329500e-01,
3.26640741e-01, -3.11806253e-01, 2.93968901e-01, -2.73300467e-01,
2.50000000e-01, -2.24291897e-01, 1.96423740e-01, -1.66663915e-01,
1.35299025e-01, -1.02631132e-01, 6.89748448e-02, -3.46542923e-02 },
};
/**
* Forward DCT-16 transformation
* x, y Input and output 16 values
*/
static void dct16_forward(const float *x, float *y)
{
for (int i = 0, j; i < 16; i++)
for (y[i] = 0, j = 0; j < 16; j++)
y[i] += x[j] * dct16_m[j][i];
}
/**
* Inverse DCT-16 transformation
* x, y Input and output 16 values
*/
static void dct16_inverse(const float *x, float *y)
{
for (int i = 0, j; i < 16; i++)
for (y[i] = 0, j = 0; j < 16; j++)
y[i] += x[j] * dct16_m[i][j];
}
/* ----------------------------------------------------------------------------
* Scale factors
* -------------------------------------------------------------------------- */
/**
* Scale factors
* dt, sr Duration and samplerate of the frame
* eb Energy estimation per bands
* att 1: Attack detected 0: Otherwise
* scf Output 16 scale factors
*/
static void compute_scale_factors(enum lc3_dt dt, enum lc3_srate sr,
const float *eb, bool att, float *scf)
{
/* Pre-emphasis gain table :
* Ge[b] = 10 ^ (b * g_tilt) / 630 , b = [0..63] */
static const float ge_table[LC3_NUM_SRATE][LC3_NUM_BANDS] = {
[LC3_SRATE_8K] = { /* g_tilt = 14 */
1.00000000e+00, 1.05250029e+00, 1.10775685e+00, 1.16591440e+00,
1.22712524e+00, 1.29154967e+00, 1.35935639e+00, 1.43072299e+00,
1.50583635e+00, 1.58489319e+00, 1.66810054e+00, 1.75567629e+00,
1.84784980e+00, 1.94486244e+00, 2.04696827e+00, 2.15443469e+00,
2.26754313e+00, 2.38658979e+00, 2.51188643e+00, 2.64376119e+00,
2.78255940e+00, 2.92864456e+00, 3.08239924e+00, 3.24422608e+00,
3.41454887e+00, 3.59381366e+00, 3.78248991e+00, 3.98107171e+00,
4.19007911e+00, 4.41005945e+00, 4.64158883e+00, 4.88527357e+00,
5.14175183e+00, 5.41169527e+00, 5.69581081e+00, 5.99484250e+00,
6.30957344e+00, 6.64082785e+00, 6.98947321e+00, 7.35642254e+00,
7.74263683e+00, 8.14912747e+00, 8.57695899e+00, 9.02725178e+00,
9.50118507e+00, 1.00000000e+01, 1.05250029e+01, 1.10775685e+01,
1.16591440e+01, 1.22712524e+01, 1.29154967e+01, 1.35935639e+01,
1.43072299e+01, 1.50583635e+01, 1.58489319e+01, 1.66810054e+01,
1.75567629e+01, 1.84784980e+01, 1.94486244e+01, 2.04696827e+01,
2.15443469e+01, 2.26754313e+01, 2.38658979e+01, 2.51188643e+01 },
[LC3_SRATE_16K] = { /* g_tilt = 18 */
1.00000000e+00, 1.06800043e+00, 1.14062492e+00, 1.21818791e+00,
1.30102522e+00, 1.38949549e+00, 1.48398179e+00, 1.58489319e+00,
1.69266662e+00, 1.80776868e+00, 1.93069773e+00, 2.06198601e+00,
2.20220195e+00, 2.35195264e+00, 2.51188643e+00, 2.68269580e+00,
2.86512027e+00, 3.05994969e+00, 3.26802759e+00, 3.49025488e+00,
3.72759372e+00, 3.98107171e+00, 4.25178630e+00, 4.54090961e+00,
4.84969343e+00, 5.17947468e+00, 5.53168120e+00, 5.90783791e+00,
6.30957344e+00, 6.73862717e+00, 7.19685673e+00, 7.68624610e+00,
8.20891416e+00, 8.76712387e+00, 9.36329209e+00, 1.00000000e+01,
1.06800043e+01, 1.14062492e+01, 1.21818791e+01, 1.30102522e+01,
1.38949549e+01, 1.48398179e+01, 1.58489319e+01, 1.69266662e+01,
1.80776868e+01, 1.93069773e+01, 2.06198601e+01, 2.20220195e+01,
2.35195264e+01, 2.51188643e+01, 2.68269580e+01, 2.86512027e+01,
3.05994969e+01, 3.26802759e+01, 3.49025488e+01, 3.72759372e+01,
3.98107171e+01, 4.25178630e+01, 4.54090961e+01, 4.84969343e+01,
5.17947468e+01, 5.53168120e+01, 5.90783791e+01, 6.30957344e+01 },
[LC3_SRATE_24K] = { /* g_tilt = 22 */
1.00000000e+00, 1.08372885e+00, 1.17446822e+00, 1.27280509e+00,
1.37937560e+00, 1.49486913e+00, 1.62003281e+00, 1.75567629e+00,
1.90267705e+00, 2.06198601e+00, 2.23463373e+00, 2.42173704e+00,
2.62450630e+00, 2.84425319e+00, 3.08239924e+00, 3.34048498e+00,
3.62017995e+00, 3.92329345e+00, 4.25178630e+00, 4.60778348e+00,
4.99358789e+00, 5.41169527e+00, 5.86481029e+00, 6.35586411e+00,
6.88803330e+00, 7.46476041e+00, 8.08977621e+00, 8.76712387e+00,
9.50118507e+00, 1.02967084e+01, 1.11588399e+01, 1.20931568e+01,
1.31057029e+01, 1.42030283e+01, 1.53922315e+01, 1.66810054e+01,
1.80776868e+01, 1.95913107e+01, 2.12316686e+01, 2.30093718e+01,
2.49359200e+01, 2.70237760e+01, 2.92864456e+01, 3.17385661e+01,
3.43959997e+01, 3.72759372e+01, 4.03970086e+01, 4.37794036e+01,
4.74450028e+01, 5.14175183e+01, 5.57226480e+01, 6.03882412e+01,
6.54444792e+01, 7.09240702e+01, 7.68624610e+01, 8.32980665e+01,
9.02725178e+01, 9.78309319e+01, 1.06022203e+02, 1.14899320e+02,
1.24519708e+02, 1.34945600e+02, 1.46244440e+02, 1.58489319e+02 },
[LC3_SRATE_32K] = { /* g_tilt = 26 */
1.00000000e+00, 1.09968890e+00, 1.20931568e+00, 1.32987103e+00,
1.46244440e+00, 1.60823388e+00, 1.76855694e+00, 1.94486244e+00,
2.13874364e+00, 2.35195264e+00, 2.58641621e+00, 2.84425319e+00,
3.12779366e+00, 3.43959997e+00, 3.78248991e+00, 4.15956216e+00,
4.57422434e+00, 5.03022373e+00, 5.53168120e+00, 6.08312841e+00,
6.68954879e+00, 7.35642254e+00, 8.08977621e+00, 8.89623710e+00,
9.78309319e+00, 1.07583590e+01, 1.18308480e+01, 1.30102522e+01,
1.43072299e+01, 1.57335019e+01, 1.73019574e+01, 1.90267705e+01,
2.09235283e+01, 2.30093718e+01, 2.53031508e+01, 2.78255940e+01,
3.05994969e+01, 3.36499270e+01, 3.70044512e+01, 4.06933843e+01,
4.47500630e+01, 4.92111475e+01, 5.41169527e+01, 5.95118121e+01,
6.54444792e+01, 7.19685673e+01, 7.91430346e+01, 8.70327166e+01,
9.57089124e+01, 1.05250029e+02, 1.15742288e+02, 1.27280509e+02,
1.39968963e+02, 1.53922315e+02, 1.69266662e+02, 1.86140669e+02,
2.04696827e+02, 2.25102829e+02, 2.47543082e+02, 2.72220379e+02,
2.99357729e+02, 3.29200372e+02, 3.62017995e+02, 3.98107171e+02 },
[LC3_SRATE_48K] = { /* g_tilt = 30 */
1.00000000e+00, 1.11588399e+00, 1.24519708e+00, 1.38949549e+00,
1.55051578e+00, 1.73019574e+00, 1.93069773e+00, 2.15443469e+00,
2.40409918e+00, 2.68269580e+00, 2.99357729e+00, 3.34048498e+00,
3.72759372e+00, 4.15956216e+00, 4.64158883e+00, 5.17947468e+00,
5.77969288e+00, 6.44946677e+00, 7.19685673e+00, 8.03085722e+00,
8.96150502e+00, 1.00000000e+01, 1.11588399e+01, 1.24519708e+01,
1.38949549e+01, 1.55051578e+01, 1.73019574e+01, 1.93069773e+01,
2.15443469e+01, 2.40409918e+01, 2.68269580e+01, 2.99357729e+01,
3.34048498e+01, 3.72759372e+01, 4.15956216e+01, 4.64158883e+01,
5.17947468e+01, 5.77969288e+01, 6.44946677e+01, 7.19685673e+01,
8.03085722e+01, 8.96150502e+01, 1.00000000e+02, 1.11588399e+02,
1.24519708e+02, 1.38949549e+02, 1.55051578e+02, 1.73019574e+02,
1.93069773e+02, 2.15443469e+02, 2.40409918e+02, 2.68269580e+02,
2.99357729e+02, 3.34048498e+02, 3.72759372e+02, 4.15956216e+02,
4.64158883e+02, 5.17947468e+02, 5.77969288e+02, 6.44946677e+02,
7.19685673e+02, 8.03085722e+02, 8.96150502e+02, 1.00000000e+03 },
};
float e[LC3_NUM_BANDS];
/* --- Copy and padding --- */
int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
int n2 = LC3_NUM_BANDS - nb;
for (int i2 = 0; i2 < n2; i2++)
e[2*i2 + 0] = e[2*i2 + 1] = eb[i2];
memcpy(e + 2*n2, eb + n2, (nb - n2) * sizeof(float));
/* --- Smoothing, pre-emphasis and logarithm --- */
const float *ge = ge_table[sr];
float e0 = e[0], e1 = e[0], e2;
float e_sum = 0;
for (int i = 0; i < LC3_NUM_BANDS-1; ) {
e[i] = (e0 * 0.25 + e1 * 0.5 + (e2 = e[i+1]) * 0.25) * ge[i];
e_sum += e[i++];
e[i] = (e1 * 0.25 + e2 * 0.5 + (e0 = e[i+1]) * 0.25) * ge[i];
e_sum += e[i++];
e[i] = (e2 * 0.25 + e0 * 0.5 + (e1 = e[i+1]) * 0.25) * ge[i];
e_sum += e[i++];
}
e[LC3_NUM_BANDS-1] = (e0 * 0.25 + e1 * 0.75) * ge[LC3_NUM_BANDS-1];
e_sum += e[LC3_NUM_BANDS-1];
float noise_floor = fmaxf(e_sum * (1e-4 / 64), 0x1p-32);
for (int i = 0; i < LC3_NUM_BANDS; i++)
e[i] = log2f(fmaxf(e[i], noise_floor)) * 0.5;
/* --- Grouping & scaling --- */
float scf_sum;
scf[0] = (e[0] + e[4]) * 1./12 +
(e[0] + e[3]) * 2./12 +
(e[1] + e[2]) * 3./12 ;
scf_sum = scf[0];
for (int i = 1; i < 15; i++) {
scf[i] = (e[4*i-1] + e[4*i+4]) * 1./12 +
(e[4*i ] + e[4*i+3]) * 2./12 +
(e[4*i+1] + e[4*i+2]) * 3./12 ;
scf_sum += scf[i];
}
scf[15] = (e[59] + e[63]) * 1./12 +
(e[60] + e[63]) * 2./12 +
(e[61] + e[62]) * 3./12 ;
scf_sum += scf[15];
for (int i = 0; i < 16; i++)
scf[i] = 0.85 * (scf[i] - scf_sum * 1./16);
/* --- Attack handling --- */
if (!att)
return;
float s0, s1 = scf[0], s2 = scf[1], s3 = scf[2], s4 = scf[3];
float sn = s1 + s2;
scf[0] = (sn += s3) * 1./3;
scf[1] = (sn += s4) * 1./4;
scf_sum = scf[0] + scf[1];
for (int i = 2; i < 14; i++, sn -= s0) {
s0 = s1, s1 = s2, s2 = s3, s3 = s4, s4 = scf[i+2];
scf[i] = (sn += s4) * 1./5;
scf_sum += scf[i];
}
scf[14] = (sn ) * 1./4;
scf[15] = (sn -= s1) * 1./3;
scf_sum += scf[14] + scf[15];
for (int i = 0; i < 16; i++)
scf[i] = (dt == LC3_DT_7M5 ? 0.3 : 0.5) *
(scf[i] - scf_sum * 1./16);
}
/**
* Codebooks
* scf Input 16 scale factors
* lf/hfcb_idx Output the low and high frequency codebooks index
*/
static void resolve_codebooks(const float *scf, int *lfcb_idx, int *hfcb_idx)
{
float dlfcb_max = 0, dhfcb_max = 0;
*lfcb_idx = *hfcb_idx = 0;
for (int icb = 0; icb < 32; icb++) {
const float *lfcb = lc3_sns_lfcb[icb];
const float *hfcb = lc3_sns_hfcb[icb];
float dlfcb = 0, dhfcb = 0;
for (int i = 0; i < 8; i++) {
dlfcb += (scf[ i] - lfcb[i]) * (scf[ i] - lfcb[i]);
dhfcb += (scf[8+i] - hfcb[i]) * (scf[8+i] - hfcb[i]);
}
if (icb == 0 || dlfcb < dlfcb_max)
*lfcb_idx = icb, dlfcb_max = dlfcb;
if (icb == 0 || dhfcb < dhfcb_max)
*hfcb_idx = icb, dhfcb_max = dhfcb;
}
}
/**
* Unit energy normalize pulse configuration
* c Pulse configuration
* cn Normalized pulse configuration
*/
static void normalize(const int *c, float *cn)
{
int c2_sum = 0;
for (int i = 0; i < 16; i++)
c2_sum += c[i] * c[i];
float c_norm = 1.f / sqrtf(c2_sum);
for (int i = 0; i < 16; i++)
cn[i] = c[i] * c_norm;
}
/**
* Sub-procedure of `quantize()`, add unit pulse
* x, y, n Transformed residual, and vector of pulses with length
* start, end Current number of pulses, limit to reach
* corr, energy Correlation (x,y) and y energy, updated at output
*/
static void add_pulse(const float *x, int *y, int n,
int start, int end, float *corr, float *energy)
{
for (int k = start; k < end; k++) {
float best_c2 = (*corr + x[0]) * (*corr + x[0]);
float best_e = *energy + 2*y[0] + 1;
int nbest = 0;
for (int i = 1; i < n; i++) {
float c2 = (*corr + x[i]) * (*corr + x[i]);
float e = *energy + 2*y[i] + 1;
if (c2 * best_e > e * best_c2)
best_c2 = c2, best_e = e, nbest = i;
}
*corr += x[nbest];
*energy += 2*y[nbest] + 1;
y[nbest]++;
}
}
/**
* Quantization of codebooks residual
* scf Input 16 scale factors, output quantized version
* lf/hfcb_idx Codebooks index
* c, cn Output 4 pulse configurations candidates, normalized
* shape/gain_idx Output selected shape/gain indexes
*/
static void quantize(const float *scf, int lfcb_idx, int hfcb_idx,
int (*c)[16], float (*cn)[16], int *shape_idx, int *gain_idx)
{
/* --- Residual --- */
const float *lfcb = lc3_sns_lfcb[lfcb_idx];
const float *hfcb = lc3_sns_hfcb[hfcb_idx];
float r[16], x[16];
for (int i = 0; i < 8; i++) {
r[ i] = scf[ i] - lfcb[i];
r[8+i] = scf[8+i] - hfcb[i];
}
dct16_forward(r, x);
/* --- Shape 3 candidate ---
* Project to or below pyramid N = 16, K = 6,
* then add unit pulses until you reach K = 6, over N = 16 */
float xm[16];
float xm_sum = 0;
for (int i = 0; i < 16; i++) {
xm[i] = fabsf(x[i]);
xm_sum += xm[i];
}
float proj_factor = (6 - 1) / fmaxf(xm_sum, 1e-31);
float corr = 0, energy = 0;
int npulses = 0;
for (int i = 0; i < 16; i++) {
c[3][i] = floorf(xm[i] * proj_factor);
npulses += c[3][i];
corr += c[3][i] * xm[i];
energy += c[3][i] * c[3][i];
}
add_pulse(xm, c[3], 16, npulses, 6, &corr, &energy);
npulses = 6;
/* --- Shape 2 candidate ---
* Add unit pulses until you reach K = 8 on shape 3 */
memcpy(c[2], c[3], sizeof(c[2]));
add_pulse(xm, c[2], 16, npulses, 8, &corr, &energy);
npulses = 8;
/* --- Shape 1 candidate ---
* Remove any unit pulses from shape 2 that are not part of 0 to 9
* Update energy and correlation terms accordingly
* Add unit pulses until you reach K = 10, over N = 10 */
memcpy(c[1], c[2], sizeof(c[1]));
for (int i = 10; i < 16; i++) {
c[1][i] = 0;
npulses -= c[2][i];
corr -= c[2][i] * xm[i];
energy -= c[2][i] * c[2][i];
}
add_pulse(xm, c[1], 10, npulses, 10, &corr, &energy);
npulses = 10;
/* --- Shape 0 candidate ---
* Add unit pulses until you reach K = 1, on shape 1 */
memcpy(c[0], c[1], sizeof(c[0]));
add_pulse(xm + 10, c[0] + 10, 6, 0, 1, &corr, &energy);
/* --- Add sign and unit energy normalize --- */
for (int j = 0; j < 16; j++)
for (int i = 0; i < 4; i++)
c[i][j] = x[j] < 0 ? -c[i][j] : c[i][j];
for (int i = 0; i < 4; i++)
normalize(c[i], cn[i]);
/* --- Determe shape & gain index ---
* Search the Mean Square Error, within (shape, gain) combinations */
float mse_min = INFINITY;
*shape_idx = *gain_idx = 0;
for (int ic = 0; ic < 4; ic++) {
const struct lc3_sns_vq_gains *cgains = lc3_sns_vq_gains + ic;
float cmse_min = INFINITY;
int cgain_idx = 0;
for (int ig = 0; ig < cgains->count; ig++) {
float g = cgains->v[ig];
float mse = 0;
for (int i = 0; i < 16; i++)
mse += (x[i] - g * cn[ic][i]) * (x[i] - g * cn[ic][i]);
if (mse < cmse_min) {
cgain_idx = ig,
cmse_min = mse;
}
}
if (cmse_min < mse_min) {
*shape_idx = ic, *gain_idx = cgain_idx;
mse_min = cmse_min;
}
}
}
/**
* Unquantization of codebooks residual
* lf/hfcb_idx Low and high frequency codebooks index
* c Table of normalized pulse configuration
* shape/gain Selected shape/gain indexes
* scf Return unquantized scale factors
*/
static void unquantize(int lfcb_idx, int hfcb_idx,
const float *c, int shape, int gain, float *scf)
{
const float *lfcb = lc3_sns_lfcb[lfcb_idx];
const float *hfcb = lc3_sns_hfcb[hfcb_idx];
float g = lc3_sns_vq_gains[shape].v[gain];
dct16_inverse(c, scf);
for (int i = 0; i < 8; i++)
scf[i] = lfcb[i] + g * scf[i];
for (int i = 8; i < 16; i++)
scf[i] = hfcb[i-8] + g * scf[i];
}
/**
* Sub-procedure of `sns_enumerate()`, enumeration of a vector
* c, n Table of pulse configuration, and length
* idx, ls Return enumeration set
*/
static void enum_mvpq(const int *c, int n, int *idx, bool *ls)
{
int ci, i, j;
/* --- Scan for 1st significant coeff --- */
for (i = 0, c += n; (ci = *(--c)) == 0 ; i++);
*idx = 0;
*ls = ci < 0;
/* --- Scan remaining coefficients --- */
for (i++, j = LC3_ABS(ci); i < n; i++, j += LC3_ABS(ci)) {
if ((ci = *(--c)) != 0) {
*idx = (*idx << 1) | *ls;
*ls = ci < 0;
}
*idx += lc3_sns_mpvq_offsets[i][j];
}
}
/**
* Sub-procedure of `sns_deenumerate()`, deenumeration of a vector
* idx, ls Enumeration set
* npulses Number of pulses in the set
* c, n Table of pulses configuration, and length
*/
static void deenum_mvpq(int idx, bool ls, int npulses, int *c, int n)
{
int i;
/* --- Scan for coefficients --- */
for (i = n-1; i >= 0 && idx; i--) {
int ci = 0;
for (ci = 0; idx < lc3_sns_mpvq_offsets[i][npulses - ci]; ci++);
idx -= lc3_sns_mpvq_offsets[i][npulses - ci];
*(c++) = ls ? -ci : ci;
npulses -= ci;
if (ci > 0) {
ls = idx & 1;
idx >>= 1;
}
}
/* --- Set last significant --- */
int ci = npulses;
if (i-- >= 0)
*(c++) = ls ? -ci : ci;
while (i-- >= 0)
*(c++) = 0;
}
/**
* SNS Enumeration of PVQ configuration
* shape Selected shape index
* c Selected pulse configuration
* idx_a, ls_a Return enumeration set A
* idx_b, ls_b Return enumeration set B (shape = 0)
*/
static void enumerate(int shape, const int *c,
int *idx_a, bool *ls_a, int *idx_b, bool *ls_b)
{
enum_mvpq(c, shape < 2 ? 10 : 16, idx_a, ls_a);
if (shape == 0)
enum_mvpq(c + 10, 6, idx_b, ls_b);
}
/**
* SNS Deenumeration of PVQ configuration
* shape Selected shape index
* idx_a, ls_a enumeration set A
* idx_b, ls_b enumeration set B (shape = 0)
* c Return pulse configuration
*/
static void deenumerate(int shape,
int idx_a, bool ls_a, int idx_b, bool ls_b, int *c)
{
int npulses_a = (const int []){ 10, 10, 8, 6 }[shape];
deenum_mvpq(idx_a, ls_a, npulses_a, c, shape < 2 ? 10 : 16);
if (shape == 0)
deenum_mvpq(idx_b, ls_b, 1, c + 10, 6);
else if (shape == 1)
memset(c + 10, 0, 6 * sizeof(*c));
}
/* ----------------------------------------------------------------------------
* Filtering
* -------------------------------------------------------------------------- */
/**
* Spectral shaping
* dt, sr Duration and samplerate of the frame
* scf_q Quantized scale factors
* inv True on inverse shaping, False otherwise
* x Spectral coefficients
* y Return shapped coefficients
*
* `x` and `y` can be the same buffer
*/
static void spectral_shaping(enum lc3_dt dt, enum lc3_srate sr,
const float *scf_q, bool inv, const float *x, float *y)
{
/* --- Interpolate scale factors --- */
float scf[LC3_NUM_BANDS];
float s0, s1 = inv ? -scf_q[0] : scf_q[0];
scf[0] = scf[1] = s1;
for (int i = 0; i < 15; i++) {
s0 = s1, s1 = inv ? -scf_q[i+1] : scf_q[i+1];
scf[4*i+2] = s0 + 0.125 * (s1 - s0);
scf[4*i+3] = s0 + 0.375 * (s1 - s0);
scf[4*i+4] = s0 + 0.625 * (s1 - s0);
scf[4*i+5] = s0 + 0.875 * (s1 - s0);
}
scf[62] = s1 + 0.125 * (s1 - s0);
scf[63] = s1 + 0.375 * (s1 - s0);
int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
int n2 = LC3_NUM_BANDS - nb;
for (int i2 = 0; i2 < n2; i2++)
scf[i2] = 0.5 * (scf[2*i2] + scf[2*i2+1]);
if (n2 > 0)
memmove(scf + n2, scf + 2*n2, (nb - n2) * sizeof(float));
/* --- Spectral shaping --- */
const int *lim = lc3_band_lim[dt][sr];
for (int i = 0, ib = 0; ib < nb; ib++) {
float g_sns = powf(2, -scf[ib]);
for ( ; i < lim[ib+1]; i++)
y[i] = x[i] * g_sns;
}
}
/* ----------------------------------------------------------------------------
* Interface
* -------------------------------------------------------------------------- */
/**
* SNS analysis
*/
void lc3_sns_analyze(enum lc3_dt dt, enum lc3_srate sr,
const float *eb, bool att, struct lc3_sns_data *data,
const float *x, float *y)
{
/* Processing steps :
* - Determine 16 scale factors from bands energy estimation
* - Get codebooks indexes that match thoses scale factors
* - Quantize the residual with the selected codebook
* - The pulse configuration `c[]` is enumerated
* - Finally shape the spectrum coefficients accordingly */
float scf[16], cn[4][16];
int c[4][16];
compute_scale_factors(dt, sr, eb, att, scf);
resolve_codebooks(scf, &data->lfcb, &data->hfcb);
quantize(scf, data->lfcb, data->hfcb,
c, cn, &data->shape, &data->gain);
unquantize(data->lfcb, data->hfcb,
cn[data->shape], data->shape, data->gain, scf);
enumerate(data->shape, c[data->shape],
&data->idx_a, &data->ls_a, &data->idx_b, &data->ls_b);
spectral_shaping(dt, sr, scf, false, x, y);
}
/**
* SNS synthesis
*/
void lc3_sns_synthesize(enum lc3_dt dt, enum lc3_srate sr,
const lc3_sns_data_t *data, const float *x, float *y)
{
float scf[16], cn[16];
int c[16];
deenumerate(data->shape,
data->idx_a, data->ls_a, data->idx_b, data->ls_b, c);
normalize(c, cn);
unquantize(data->lfcb, data->hfcb, cn, data->shape, data->gain, scf);
spectral_shaping(dt, sr, scf, true, x, y);
}
/**
* Return number of bits coding the bitstream data
*/
int lc3_sns_get_nbits(void)
{
return 38;
}
/**
* Put bitstream data
*/
void lc3_sns_put_data(lc3_bits_t *bits, const struct lc3_sns_data *data)
{
/* --- Codebooks --- */
lc3_put_bits(bits, data->lfcb, 5);
lc3_put_bits(bits, data->hfcb, 5);
/* --- Shape, gain and vectors --- *
* Write MSB bit of shape index, next LSB bits of shape and gain,
* and MVPQ vectors indexes are muxed */
int shape_msb = data->shape >> 1;
lc3_put_bit(bits, shape_msb);
if (shape_msb == 0) {
const int size_a = 2390004;
int submode = data->shape & 1;
int mux_high = submode == 0 ?
2 * (data->idx_b + 1) + data->ls_b : data->gain & 1;
int mux_code = mux_high * size_a + data->idx_a;
lc3_put_bits(bits, data->gain >> submode, 1);
lc3_put_bits(bits, data->ls_a, 1);
lc3_put_bits(bits, mux_code, 25);
} else {
const int size_a = 15158272;
int submode = data->shape & 1;
int mux_code = submode == 0 ?
data->idx_a : size_a + 2 * data->idx_a + (data->gain & 1);
lc3_put_bits(bits, data->gain >> submode, 2);
lc3_put_bits(bits, data->ls_a, 1);
lc3_put_bits(bits, mux_code, 24);
}
}
/**
* Get bitstream data
*/
int lc3_sns_get_data(lc3_bits_t *bits, struct lc3_sns_data *data)
{
/* --- Codebooks --- */
*data = (struct lc3_sns_data){
.lfcb = lc3_get_bits(bits, 5),
.hfcb = lc3_get_bits(bits, 5)
};
/* --- Shape, gain and vectors --- */
int shape_msb = lc3_get_bit(bits);
data->gain = lc3_get_bits(bits, 1 + shape_msb);
data->ls_a = lc3_get_bit(bits);
int mux_code = lc3_get_bits(bits, 25 - shape_msb);
if (shape_msb == 0) {
const int size_a = 2390004;
if (mux_code >= size_a * 14)
return -1;
data->idx_a = mux_code % size_a;
mux_code = mux_code / size_a;
data->shape = (mux_code < 2);
if (data->shape == 0) {
data->idx_b = (mux_code - 2) / 2;
data->ls_b = (mux_code - 2) % 2;
} else {
data->gain = (data->gain << 1) + (mux_code % 2);
}
} else {
const int size_a = 15158272;
if (mux_code >= size_a + 1549824)
return -1;
data->shape = 2 + (mux_code >= size_a);
if (data->shape == 2) {
data->idx_a = mux_code;
} else {
mux_code -= size_a;
data->idx_a = mux_code / 2;
data->gain = (data->gain << 1) + (mux_code % 2);
}
}
return 0;
}

103
3rd-party/lc3-google/src/sns.h vendored Normal file
View File

@ -0,0 +1,103 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Spectral Noise Shaping
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_SNS_H
#define __LC3_SNS_H
#include "common.h"
#include "bits.h"
/**
* Bitstream data
*/
typedef struct lc3_sns_data {
int lfcb, hfcb;
int shape, gain;
int idx_a, idx_b;
bool ls_a, ls_b;
} lc3_sns_data_t;
/* ----------------------------------------------------------------------------
* Encoding
* -------------------------------------------------------------------------- */
/**
* SNS analysis
* dt, sr Duration and samplerate of the frame
* eb Energy estimation per bands, and count of bands
* att 1: Attack detected 0: Otherwise
* data Return bitstream data
* x Spectral coefficients
* y Return shapped coefficients
*
* `x` and `y` can be the same buffer
*/
void lc3_sns_analyze(enum lc3_dt dt, enum lc3_srate sr,
const float *eb, bool att, lc3_sns_data_t *data,
const float *x, float *y);
/**
* Return number of bits coding the bitstream data
* return Bit consumption
*/
int lc3_sns_get_nbits(void);
/**
* Put bitstream data
* bits Bitstream context
* data Bitstream data
*/
void lc3_sns_put_data(lc3_bits_t *bits, const lc3_sns_data_t *data);
/* ----------------------------------------------------------------------------
* Decoding
* -------------------------------------------------------------------------- */
/**
* Get bitstream data
* bits Bitstream context
* data Return SNS data
* return 0: Ok -1: Invalid SNS data
*/
int lc3_sns_get_data(lc3_bits_t *bits, lc3_sns_data_t *data);
/**
* SNS synthesis
* dt, sr Duration and samplerate of the frame
* data Bitstream data
* x Spectral coefficients
* y Return shapped coefficients
*
* `x` and `y` can be the same buffer
*/
void lc3_sns_synthesize(enum lc3_dt dt, enum lc3_srate sr,
const lc3_sns_data_t *data, const float *x, float *y);
#endif /* __LC3_SNS_H */

877
3rd-party/lc3-google/src/spec.c vendored Normal file
View File

@ -0,0 +1,877 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "spec.h"
#include "bits.h"
#include "tables.h"
/* ----------------------------------------------------------------------------
* Global Gain / Quantization
* -------------------------------------------------------------------------- */
/**
* Resolve quantized gain index offset
* sr, nbytes Samplerate and size of the frame
* return Gain index offset
*/
static int resolve_gain_offset(enum lc3_srate sr, int nbytes)
{
int g_off = (nbytes * 8) / (10 * (1 + sr));
return 105 + 5*(1 + sr) + LC3_MIN(g_off, 115);
}
/**
* Global Gain Estimation
* dt, sr Duration and samplerate of the frame
* x Spectral coefficients
* nbits_budget Number of bits available coding the spectrum
* nbits_off Offset on the available bits, temporarily smoothed
* g_off Gain index offset
* reset_off Return True when the nbits_off must be reset
* return The quantized gain value
*/
static int estimate_gain(
enum lc3_dt dt, enum lc3_srate sr, const float *x,
int nbits_budget, float nbits_off, int g_off, bool *reset_off)
{
int ne = LC3_NE(dt, sr) >> 2;
float e[ne];
/* --- Energy (dB) by 4 NDCT blocks ---
* For the next steps, add energy offset 28/20 dB,
* and compute the maximum magnitude */
float x_max = 0;
for (int i = 0; i < ne; i++, x += 4) {
float x0 = fabsf(x[0]), x1 = fabsf(x[1]);
float x2 = fabsf(x[2]), x3 = fabsf(x[3]);
x_max = fmaxf(x_max, x0);
x_max = fmaxf(x_max, x1);
x_max = fmaxf(x_max, x2);
x_max = fmaxf(x_max, x3);
float s2 = x0*x0 + x1*x1 + x2*x2 + x3*x3;
e[i] = 28.f/20 * 10 * (s2 > 0 ? log10f(s2) : -10);
}
/* --- Determine gain index --- */
int nbits = nbits_budget + nbits_off + 0.5f;
int g_int = 255 - g_off;
for (int i = 128; i > 0; i >>= 1) {
const float *e_ptr = e + ne-1;
float v = 0;
g_int -= i;
for ( ; e_ptr >= e && *e_ptr < g_int; e_ptr--);
while (e_ptr >= e) {
float e_diff = *(e_ptr--) - g_int;
if (e_diff < 0) {
v += 2.7f * 28.f/20;
} else {
v += e_diff + 7 * 28.f/20;
if (e_diff > 43 * 28.f/20)
v += e_diff - 43 * 28.f/20;
}
}
if (v > nbits * 1.4 * 28./20)
g_int += i;
}
/* --- Limit gain index --- */
int g_min = x_max == 0 ? -g_off :
ceilf(28 * log10f(x_max / (32768 - 0.375f)));
*reset_off = g_int < g_min || x_max == 0;
if (*reset_off)
g_int = g_min;
return g_int;
}
/**
* Global Gain Adjustment
* sr Samplerate of the frame
* g_idx The estimated quantized gain index
* nbits Computed number of bits coding the spectrum
* nbits_budget Number of bits available for coding the spectrum
* return Gain adjust value (-1 to 2)
*/
static int adjust_gain(enum lc3_srate sr,
int g_idx, int nbits, int nbits_budget)
{
/* --- Compute delta threshold --- */
const int *t = (const int [LC3_NUM_SRATE][3]){
{ 80, 500, 850 }, { 230, 1025, 1700 }, { 380, 1550, 2550 },
{ 530, 2075, 3400 }, { 680, 2600, 4250 }
}[sr];
int delta, den = 48;
if (nbits < t[0]) {
delta = 3*(nbits + 48);
} else if (nbits < t[1]) {
int n0 = 3*(t[0] + 48), range = t[1] - t[0];
delta = n0 * range + (nbits - t[0]) * (t[1] - n0);
den *= range;
} else {
delta = LC3_MIN(nbits, t[2]);
}
delta = (delta + den/2) / den;
/* --- Adjust gain --- */
if (nbits < nbits_budget - (delta + 2))
return -(g_idx > 0);
if (nbits > nbits_budget)
return (g_idx < 255) + (g_idx < 254 && nbits >= nbits_budget + delta);
return 0;
}
/**
* Unquantize gain
* g_int Quantization gain value
* return Unquantized gain value
*/
static float unquantize_gain(int g_int)
{
/* Unquantization gain table :
* G[i] = 10 ^ (i / 28) , i = [0..64] */
static const float iq_table[] = {
1.00000000e+00, 1.08571112e+00, 1.17876863e+00, 1.27980221e+00,
1.38949549e+00, 1.50859071e+00, 1.63789371e+00, 1.77827941e+00,
1.93069773e+00, 2.09617999e+00, 2.27584593e+00, 2.47091123e+00,
2.68269580e+00, 2.91263265e+00, 3.16227766e+00, 3.43332002e+00,
3.72759372e+00, 4.04708995e+00, 4.39397056e+00, 4.77058270e+00,
5.17947468e+00, 5.62341325e+00, 6.10540230e+00, 6.62870316e+00,
7.19685673e+00, 7.81370738e+00, 8.48342898e+00, 9.21055318e+00,
1.00000000e+01, 1.08571112e+01, 1.17876863e+01, 1.27980221e+01,
1.38949549e+01, 1.50859071e+01, 1.63789371e+01, 1.77827941e+01,
1.93069773e+01, 2.09617999e+01, 2.27584593e+01, 2.47091123e+01,
2.68269580e+01, 2.91263265e+01, 3.16227766e+01, 3.43332002e+01,
3.72759372e+01, 4.04708995e+01, 4.39397056e+01, 4.77058270e+01,
5.17947468e+01, 5.62341325e+01, 6.10540230e+01, 6.62870316e+01,
7.19685673e+01, 7.81370738e+01, 8.48342898e+01, 9.21055318e+01,
1.00000000e+02, 1.08571112e+02, 1.17876863e+02, 1.27980221e+02,
1.38949549e+02, 1.50859071e+02, 1.63789371e+02, 1.77827941e+02,
1.93069773e+02
};
float g = iq_table[LC3_ABS(g_int) & 0x3f];
for(int n64 = LC3_ABS(g_int) >> 6; n64--; )
g *= iq_table[64];
return g_int >= 0 ? g : 1 / g;
}
/**
* Spectrum quantization
* dt, sr Duration and samplerate of the frame
* g_int Quantization gain value
* x Spectral coefficients, scaled as output
* xq, nq Output spectral quantized coefficients, and count
*/
static void quantize(enum lc3_dt dt, enum lc3_srate sr,
int g_int, float *x, int16_t *xq, int *nq)
{
float g_inv = 1 / unquantize_gain(g_int);
int ne = LC3_NE(dt, sr);
*nq = ne;
for (int i = 0; i < ne; i += 2) {
int16_t x0, x1;
x[i+0] *= g_inv;
x0 = fminf(floorf(fabsf(x[i+0]) + 6.f/16), INT16_MAX);
xq[i+0] = x[i+0] < 0 ? -x0 : x0;
x[i+1] *= g_inv;
x1 = fminf(floorf(fabsf(x[i+1]) + 6.f/16), INT16_MAX);
xq[i+1] = x[i+1] < 0 ? -x1 : x1;
*nq = x0 || x1 ? ne : *nq - 2;
}
}
/**
* Spectrum quantization inverse
* dt, sr Duration and samplerate of the frame
* g_int Quantization gain value
* x, nq Spectral quantized, and count of significants
* return Unquantized gain value
*/
static float unquantize(enum lc3_dt dt, enum lc3_srate sr,
int g_int, float *x, int nq)
{
float g = unquantize_gain(g_int);
int i, ne = LC3_NE(dt, sr);
for (i = 0; i < nq; i++)
x[i] = x[i] * g;
for ( ; i < ne; i++)
x[i] = 0;
return g;
}
/* ----------------------------------------------------------------------------
* Spectrum coding
* -------------------------------------------------------------------------- */
/**
* Resolve High-bitrate mode according size of the frame
* sr, nbytes Samplerate and size of the frame
* return True when High-Rate mode enabled
*/
static int resolve_high_rate(enum lc3_srate sr, int nbytes)
{
return nbytes > 20 * (1 + (int)sr);
}
/**
* Bit consumption
* dt, sr, nbytes Duration, samplerate and size of the frame
* x Spectral quantized coefficients
* n Count of significant coefficients, updated on truncation
* nbits_budget Truncate to stay in budget, when not zero
* p_lsb_mode Return True when LSB's are not AC coded, or NULL
* return The number of bits coding the spectrum
*/
static int compute_nbits(
enum lc3_dt dt, enum lc3_srate sr, int nbytes,
const int16_t *x, int *n, int nbits_budget, bool *p_lsb_mode)
{
int ne = LC3_NE(dt, sr);
/* --- Mode and rate --- */
bool lsb_mode = nbytes >= 20 * (3 + (int)sr);
bool high_rate = resolve_high_rate(sr, nbytes);
/* --- Loop on quantized coefficients --- */
int nbits = 0, nbits_lsb = 0;
uint8_t state = 0;
int nbits_end = 0;
int n_end = 0;
nbits_budget = nbits_budget ? nbits_budget * 2048 : INT_MAX;
for (int i = 0, h = 0; h < 2; h++) {
const uint8_t (*lut_coeff)[4] = lc3_spectrum_lookup[high_rate][h];
for ( ; i < LC3_MIN(*n, (ne + 2) >> (1 - h))
&& nbits <= nbits_budget; i += 2) {
const uint8_t *lut = lut_coeff[state];
int a = LC3_ABS(x[i]), b = LC3_ABS(x[i+1]);
/* --- Sign values --- */
int s = (a != 0) + (b != 0);
nbits += s * 2048;
/* --- LSB values Reduce to 2*2 bits MSB values ---
* Reduce to 2x2 bits MSB values. The LSB's pair are arithmetic
* coded with an escape code followed by 1 bit for each values.
* The LSB mode does not arthmetic code the first LSB,
* add the sign of the LSB when one of pair was at value 1 */
int k = 0;
int m = (a | b) >> 2;
if (m) {
if (lsb_mode) {
nbits += lc3_spectrum_bits[lut[k++]][16] - 2*2048;
nbits_lsb += 2 + (a == 1) + (b == 1);
}
for (m >>= lsb_mode; m; m >>= 1, k++)
nbits += lc3_spectrum_bits[lut[LC3_MIN(k, 3)]][16];
nbits += k * 2*2048;
a >>= k;
b >>= k;
k = LC3_MIN(k, 3);
}
/* --- MSB values --- */
nbits += lc3_spectrum_bits[lut[k]][a + 4*b];
/* --- Update state --- */
if (s && nbits <= nbits_budget) {
n_end = i + 2;
nbits_end = nbits;
}
state = (state << 4) + (k > 1 ? 12 + k : 1 + (a + b) * (k + 1));
}
}
/* --- Return --- */
*n = n_end;
if (p_lsb_mode)
*p_lsb_mode = lsb_mode &&
nbits_end + nbits_lsb * 2048 > nbits_budget;
if (nbits_budget >= INT_MAX)
nbits_end += nbits_lsb * 2048;
return (nbits_end + 2047) / 2048;
}
/**
* Put quantized spectrum
* bits Bitstream context
* dt, sr, nbytes Duration, samplerate and size of the frame
* x Spectral quantized
* nq, lsb_mode Count of significants, and LSB discard indication
*/
static void put_quantized(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, int nbytes,
const int16_t *x, int nq, bool lsb_mode)
{
int ne = LC3_NE(dt, sr);
bool high_rate = resolve_high_rate(sr, nbytes);
/* --- Loop on quantized coefficients --- */
uint8_t state = 0;
for (int i = 0, h = 0; h < 2; h++) {
const uint8_t (*lut_coeff)[4] = lc3_spectrum_lookup[high_rate][h];
for ( ; i < LC3_MIN(nq, (ne + 2) >> (1 - h)); i += 2) {
const uint8_t *lut = lut_coeff[state];
bool a_neg = x[i] < 0, b_neg = x[i+1] < 0;
int a = LC3_ABS(x[i]), b = LC3_ABS(x[i+1]);
/* --- LSB values Reduce to 2*2 bits MSB values ---
* Reduce to 2x2 bits MSB values. The LSB's pair are arithmetic
* coded with an escape code and 1 bits for each values.
* The LSB mode discard the first LSB (at this step) */
int m = (a | b) >> 2;
int k = 0, shr = 0;
if (m) {
if (lsb_mode)
lc3_put_symbol(bits,
lc3_spectrum_models + lut[k++], 16);
for (m >>= lsb_mode; m; m >>= 1, k++) {
lc3_put_bit(bits, (a >> k) & 1);
lc3_put_bit(bits, (b >> k) & 1);
lc3_put_symbol(bits,
lc3_spectrum_models + lut[LC3_MIN(k, 3)], 16);
}
a >>= lsb_mode;
b >>= lsb_mode;
shr = k - lsb_mode;
k = LC3_MIN(k, 3);
}
/* --- Sign values --- */
if (a) lc3_put_bit(bits, a_neg);
if (b) lc3_put_bit(bits, b_neg);
/* --- MSB values --- */
a >>= shr;
b >>= shr;
lc3_put_symbol(bits, lc3_spectrum_models + lut[k], a + 4*b);
/* --- Update state --- */
state = (state << 4) + (k > 1 ? 12 + k : 1 + (a + b) * (k + 1));
}
}
}
/**
* Get quantized spectrum
* bits Bitstream context
* dt, sr, nbytes Duration, samplerate and size of the frame
* nq, lsb_mode Count of significants, and LSB discard indication
* xq Return `nq` spectral quantized coefficients
* nf_seed Return the noise factor seed associated
* return 0: Ok -1: Invalid bitstream data
*/
static int get_quantized(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, int nbytes,
int nq, bool lsb_mode, float *xq, uint16_t *nf_seed)
{
int ne = LC3_NE(dt, sr);
bool high_rate = resolve_high_rate(sr, nbytes);
*nf_seed = 0;
/* --- Loop on quantized coefficients --- */
uint8_t state = 0;
for (int i = 0, h = 0; h < 2; h++) {
const uint8_t (*lut_coeff)[4] = lc3_spectrum_lookup[high_rate][h];
for ( ; i < LC3_MIN(nq, (ne + 2) >> (1 - h)); i += 2) {
const uint8_t *lut = lut_coeff[state];
/* --- LSB values ---
* Until the symbol read indicates the escape value 16,
* read an LSB bit for each values.
* The LSB mode discard the first LSB (at this step) */
int u = 0, v = 0;
int k = 0, shl = 0;
unsigned s = lc3_get_symbol(bits, lc3_spectrum_models + lut[k]);
if (lsb_mode && s >= 16) {
s = lc3_get_symbol(bits, lc3_spectrum_models + lut[++k]);
shl++;
}
for ( ; s >= 16 && shl < 14; shl++) {
u |= lc3_get_bit(bits) << shl;
v |= lc3_get_bit(bits) << shl;
k += (k < 3);
s = lc3_get_symbol(bits, lc3_spectrum_models + lut[k]);
}
if (s >= 16)
return -1;
/* --- MSB & sign values --- */
int a = s % 4;
int b = s / 4;
u |= a << shl;
v |= b << shl;
xq[i ] = u && lc3_get_bit(bits) ? -u : u;
xq[i+1] = v && lc3_get_bit(bits) ? -v : v;
*nf_seed = (*nf_seed + u * i + v * (i+1)) & 0xffff;
/* --- Update state --- */
state = (state << 4) + (k > 1 ? 12 + k : 1 + (a + b) * (k + 1));
}
}
return 0;
}
/**
* Put residual bits of quantization
* bits Bitstream context
* nbits Maximum number of bits to output
* xq, n Spectral quantized, and count of significants
* xf Scaled spectral coefficients
*/
static void put_residual(lc3_bits_t *bits, int nbits,
const int16_t *xq, int n, const float *xf)
{
for (int i = 0; i < n && nbits > 0; i++) {
if (xq[i] == 0)
continue;
lc3_put_bit(bits, xf[i] >= xq[i]);
nbits--;
}
}
/**
* Get residual bits of quantization
* bits Bitstream context
* nbits Maximum number of bits to output
* x, nq Spectral quantized, and count of significants
*/
static void get_residual(lc3_bits_t *bits, int nbits, float *x, int nq)
{
for (int i = 0; i < nq && nbits > 0; i++) {
if (x[i] == 0)
continue;
if (lc3_get_bit(bits) == 0)
x[i] -= x[i] < 0 ? 5.f/16 : 3.f/16;
else
x[i] += x[i] > 0 ? 5.f/16 : 3.f/16;
nbits--;
}
}
/**
* Put LSB values of quantized spectrum values
* bits Bitstream context
* nbits Maximum number of bits to output
* x, n Spectral quantized, and count of significants
*/
static void put_lsb(lc3_bits_t *bits, int nbits, const int16_t *x, int n)
{
for (int i = 0; i < n && nbits > 0; i += 2) {
bool a_neg = x[i] < 0, b_neg = x[i+1] < 0;
int a = LC3_ABS(x[i]), b = LC3_ABS(x[i+1]);
if ((a | b) >> 2 == 0)
continue;
if (nbits-- > 0)
lc3_put_bit(bits, a & 1);
if (a == 1 && nbits-- > 0)
lc3_put_bit(bits, a_neg);
if (nbits-- > 0)
lc3_put_bit(bits, b & 1);
if (b == 1 && nbits-- > 0)
lc3_put_bit(bits, b_neg);
}
}
/**
* Get LSB values of quantized spectrum values
* bits Bitstream context
* nbits Maximum number of bits to output
* x, nq Spectral quantized, and count of significants
* nf_seed Update the noise factor seed according
*/
static void get_lsb(lc3_bits_t *bits,
int nbits, float *x, int nq, uint16_t *nf_seed)
{
for (int i = 0; i < nq && nbits > 0; i += 2) {
float a = fabsf(x[i]), b = fabsf(x[i+1]);
if (fmaxf(a, b) < 4)
continue;
if (nbits-- > 0 && lc3_get_bit(bits)) {
if (a) {
x[i] += x[i] < 0 ? -1 : 1;
*nf_seed = (*nf_seed + i) & 0xffff;
} else if (nbits-- > 0) {
x[i] = lc3_get_bit(bits) ? -1 : 1;
*nf_seed = (*nf_seed + i) & 0xffff;
}
}
if (nbits-- > 0 && lc3_get_bit(bits)) {
if (b) {
x[i+1] += x[i+1] < 0 ? -1 : 1;
*nf_seed = (*nf_seed + i+1) & 0xffff;
} else if (nbits-- > 0) {
x[i+1] = lc3_get_bit(bits) ? -1 : 1;
*nf_seed = (*nf_seed + i+1) & 0xffff;
}
}
}
}
/* ----------------------------------------------------------------------------
* Noise coding
* -------------------------------------------------------------------------- */
/**
* Estimate noise level
* dt, bw Duration and bandwidth of the frame
* xq, nq Quantized spectral coefficients
* x Quantization scaled spectrum coefficients
* return Noise factor (0 to 7)
*/
static int estimate_noise(enum lc3_dt dt, enum lc3_bandwidth bw,
const int16_t *xq, int nq, const float *x)
{
int bw_stop = (dt == LC3_DT_7M5 ? 60 : 80) * (1 + bw);
int w = 2 + dt;
float sum = 0;
int i, n = 0, z = 0;
for (i = 6*(3 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) {
z = xq[i] ? 0 : z + 1;
if (z > 2*w)
sum += fabs(x[i - w]), n++;
}
for ( ; i < bw_stop + w; i++)
if (++z > 2*w)
sum += fabs(x[i - w]), n++;
int nf = n ? 8 - (int)((16 * sum) / n + 0.5f) : 0;
return LC3_CLIP(nf, 0, 7);
}
/**
* Noise filling
* dt, bw Duration and bandwidth of the frame
* nf, nf_seed The noise factor and pseudo-random seed
* g Quantization gain
* x, nq Spectral quantized, and count of significants
*/
static void fill_noise(enum lc3_dt dt, enum lc3_bandwidth bw,
int nf, uint16_t nf_seed, float g, float *x, int nq)
{
int bw_stop = (dt == LC3_DT_7M5 ? 60 : 80) * (1 + bw);
int w = 2 + dt;
float s = g * (float)(8 - nf) / 16;
int i, z = 0;
for (i = 6*(3 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) {
z = x[i] ? 0 : z + 1;
if (z > 2*w) {
nf_seed = (13849 + nf_seed*31821) & 0xffff;
x[i - w] = nf_seed & 0x8000 ? -s : s;
}
}
for ( ; i < bw_stop + w; i++)
if (++z > 2*w) {
nf_seed = (13849 + nf_seed*31821) & 0xffff;
x[i - w] = nf_seed & 0x8000 ? -s : s;
}
}
/**
* Put noise factor
* bits Bitstream context
* nf Noise factor (0 to 7)
*/
static void put_noise_factor(lc3_bits_t *bits, int nf)
{
lc3_put_bits(bits, nf, 3);
}
/**
* Get noise factor
* bits Bitstream context
* return Noise factor (0 to 7)
*/
static int get_noise_factor(lc3_bits_t *bits)
{
return lc3_get_bits(bits, 3);
}
/* ----------------------------------------------------------------------------
* Encoding
* -------------------------------------------------------------------------- */
/**
* Bit consumption of the number of coded coefficients
* dt, sr Duration, samplerate of the frame
* return Bit consumpution of the number of coded coefficients
*/
static int get_nbits_nq(enum lc3_dt dt, enum lc3_srate sr)
{
int ne = LC3_NE(dt, sr);
return 4 + (ne > 32) + (ne > 64) + (ne > 128) + (ne > 256);
}
/**
* Bit consumption of the arithmetic coder
* dt, sr, nbytes Duration, samplerate and size of the frame
* return Bit consumption of bitstream data
*/
static int get_nbits_ac(enum lc3_dt dt, enum lc3_srate sr, int nbytes)
{
return get_nbits_nq(dt, sr) + 3 + LC3_MIN((nbytes-1) / 160, 2);
}
/**
* Spectrum analysis
*/
void lc3_spec_analyze(enum lc3_dt dt, enum lc3_srate sr,
int nbytes, bool pitch, const lc3_tns_data_t *tns,
struct lc3_spec_analysis *spec, float *x,
int16_t *xq, struct lc3_spec_side *side)
{
bool reset_off;
/* --- Bit budget --- */
const int nbits_gain = 8;
const int nbits_nf = 3;
int nbits_budget = 8*nbytes - get_nbits_ac(dt, sr, nbytes) -
lc3_bwdet_get_nbits(sr) - lc3_ltpf_get_nbits(pitch) -
lc3_sns_get_nbits() - lc3_tns_get_nbits(tns) - nbits_gain - nbits_nf;
/* --- Global gain --- */
float nbits_off = spec->nbits_off + spec->nbits_spare;
nbits_off = fminf(fmaxf(nbits_off, -40), 40);
nbits_off = 0.8 * spec->nbits_off + 0.2 * nbits_off;
int g_off = resolve_gain_offset(sr, nbytes);
int g_int = estimate_gain(dt, sr,
x, nbits_budget, nbits_off, g_off, &reset_off);
/* --- Quantization --- */
quantize(dt, sr, g_int, x, xq, &side->nq);
int nbits = compute_nbits(dt, sr, nbytes, xq, &side->nq, 0, NULL);
spec->nbits_off = reset_off ? 0 : nbits_off;
spec->nbits_spare = reset_off ? 0 : nbits_budget - nbits;
/* --- Adjust gain and requantize --- */
int g_adj = adjust_gain(sr, g_int + g_off, nbits, nbits_budget);
if (g_adj)
quantize(dt, sr, g_adj, x, xq, &side->nq);
side->g_idx = g_int + g_adj + g_off;
nbits = compute_nbits(dt, sr, nbytes,
xq, &side->nq, nbits_budget, &side->lsb_mode);
}
/**
* Put spectral quantization side data
*/
void lc3_spec_put_side(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, const struct lc3_spec_side *side)
{
int nbits_nq = get_nbits_nq(dt, sr);
lc3_put_bits(bits, LC3_MAX(side->nq >> 1, 1) - 1, nbits_nq);
lc3_put_bits(bits, side->lsb_mode, 1);
lc3_put_bits(bits, side->g_idx, 8);
}
/**
* Encode spectral coefficients
*/
void lc3_spec_encode(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, enum lc3_bandwidth bw, int nbytes,
const int16_t *xq, const lc3_spec_side_t *side, const float *x)
{
bool lsb_mode = side->lsb_mode;
int nq = side->nq;
put_noise_factor(bits, estimate_noise(dt, bw, xq, nq, x));
put_quantized(bits, dt, sr, nbytes, xq, nq, lsb_mode);
int nbits_left = lc3_get_bits_left(bits);
if (lsb_mode)
put_lsb(bits, nbits_left, xq, nq);
else
put_residual(bits, nbits_left, xq, nq, x);
}
/* ----------------------------------------------------------------------------
* Decoding
* -------------------------------------------------------------------------- */
/**
* Get spectral quantization side data
*/
int lc3_spec_get_side(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, struct lc3_spec_side *side)
{
int nbits_nq = get_nbits_nq(dt, sr);
int ne = LC3_NE(dt, sr);
side->nq = (lc3_get_bits(bits, nbits_nq) + 1) << 1;
side->lsb_mode = lc3_get_bit(bits);
side->g_idx = lc3_get_bits(bits, 8);
return side->nq > ne ? (side->nq = ne), -1 : 0;
}
/**
* Decode spectral coefficients
*/
int lc3_spec_decode(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, enum lc3_bandwidth bw,
int nbytes, const lc3_spec_side_t *side, float *x)
{
bool lsb_mode = side->lsb_mode;
int nq = side->nq;
int ret = 0;
int nf = get_noise_factor(bits);
uint16_t nf_seed;
if ((ret = get_quantized(bits, dt, sr, nbytes,
nq, lsb_mode, x, &nf_seed)) < 0)
return ret;
int nbits_left = lc3_get_bits_left(bits);
if (lsb_mode)
get_lsb(bits, nbits_left, x, nq, &nf_seed);
else
get_residual(bits, nbits_left, x, nq);
int g_int = side->g_idx - resolve_gain_offset(sr, nbytes);
float g = unquantize(dt, sr, g_int, x, nq);
if (nq > 2 || x[0] || x[1] || side->g_idx > 0 || nf < 7)
fill_noise(dt, bw, nf, nf_seed, g, x, nq);
return 0;
}

111
3rd-party/lc3-google/src/spec.h vendored Normal file
View File

@ -0,0 +1,111 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Spectral coefficients encoding/decoding
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_SPEC_H
#define __LC3_SPEC_H
#include "common.h"
#include "tables.h"
#include "bwdet.h"
#include "ltpf.h"
#include "tns.h"
#include "sns.h"
/**
* Spectral quantization side data
*/
typedef struct lc3_spec_side {
int g_idx, nq;
bool lsb_mode;
} lc3_spec_side_t;
/* ----------------------------------------------------------------------------
* Encoding
* -------------------------------------------------------------------------- */
/**
* Spectrum analysis
* dt, sr, nbytes Duration, samplerate and size of the frame
* pitch, tns Pitch present indication and TNS bistream data
* spec Context of analysis
* x Spectral coefficients, scaled as output
* xq, side Return quantization data
*/
void lc3_spec_analyze(enum lc3_dt dt, enum lc3_srate sr,
int nbytes, bool pitch, const lc3_tns_data_t *tns,
lc3_spec_analysis_t *spec, float *x, int16_t *xq, lc3_spec_side_t *side);
/**
* Put spectral quantization side data
* bits Bitstream context
* dt, sr Duration and samplerate of the frame
* side Spectral quantization side data
*/
void lc3_spec_put_side(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, const lc3_spec_side_t *side);
/**
* Encode spectral coefficients
* bits Bitstream context
* dt, sr, bw Duration, samplerate, bandwidth
* nbytes and size of the frame
* xq, side Quantization data
* x Scaled spectral coefficients
*/
void lc3_spec_encode(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, enum lc3_bandwidth bw, int nbytes,
const int16_t *xq, const lc3_spec_side_t *side, const float *x);
/* ----------------------------------------------------------------------------
* Decoding
* -------------------------------------------------------------------------- */
/**
* Get spectral quantization side data
* bits Bitstream context
* dt, sr Duration and samplerate of the frame
* side Return quantization side data
* return 0: Ok -1: Invalid bandwidth indication
*/
int lc3_spec_get_side(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_srate sr, lc3_spec_side_t *side);
/**
* Decode spectral coefficients
* bits Bitstream context
* dt, sr, bw Duration, samplerate, bandwidth
* nbytes and size of the frame
* side Quantization side data
* x Spectral coefficients
* return 0: Ok -1: Invalid bitstream data
*/
int lc3_spec_decode(lc3_bits_t *bits, enum lc3_dt dt, enum lc3_srate sr,
enum lc3_bandwidth bw, int nbytes, const lc3_spec_side_t *side, float *x);
#endif /* __LC3_SPEC_H */

3526
3rd-party/lc3-google/src/tables.c vendored Normal file

File diff suppressed because it is too large Load Diff

96
3rd-party/lc3-google/src/tables.h vendored Normal file
View File

@ -0,0 +1,96 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef __LC3_TABLES_H
#define __LC3_TABLES_H
#include "common.h"
#include "bits.h"
/**
* MDCT Twiddles and window coefficients
*/
struct lc3_fft_bf3_twiddles { int n3; const struct lc3_complex (*t)[2]; };
struct lc3_fft_bf2_twiddles { int n2; const struct lc3_complex *t; };
struct lc3_mdct_rot_def { int n4; const struct lc3_complex *w; };
extern const struct lc3_fft_bf3_twiddles *lc3_fft_twiddles_bf3[];
extern const struct lc3_fft_bf2_twiddles *lc3_fft_twiddles_bf2[][3];
extern const struct lc3_mdct_rot_def *lc3_mdct_rot[LC3_NUM_DT][LC3_NUM_SRATE];
extern const float *lc3_mdct_win[LC3_NUM_DT][LC3_NUM_SRATE];
/**
* Limits of bands
*/
#define LC3_NUM_BANDS 64
extern const int lc3_band_lim[LC3_NUM_DT][LC3_NUM_SRATE][LC3_NUM_BANDS+1];
/**
* SNS Quantization
*/
extern const float lc3_sns_lfcb[32][8];
extern const float lc3_sns_hfcb[32][8];
struct lc3_sns_vq_gains {
int count; const float *v;
};
extern const struct lc3_sns_vq_gains lc3_sns_vq_gains[4];
extern const int32_t lc3_sns_mpvq_offsets[][11];
/**
* TNS Arithmetic Coding
*/
extern const struct lc3_ac_model lc3_tns_order_models[];
extern const uint16_t lc3_tns_order_bits[][8];
extern const struct lc3_ac_model lc3_tns_coeffs_models[];
extern const uint16_t lc3_tns_coeffs_bits[][17];
/**
* Long Term Postfilter
*/
extern const float lc3_ltpf_h12k8[240];
extern const float *lc3_ltpf_cnum[LC3_NUM_SRATE][4];
extern const float *lc3_ltpf_cden[LC3_NUM_SRATE][4];
/**
* Spectral Data Arithmetic Coding
*/
extern const uint8_t lc3_spectrum_lookup[2][2][256][4];
extern const struct lc3_ac_model lc3_spectrum_models[];
extern const uint16_t lc3_spectrum_bits[][17];
#endif /* __LC3_TABLES_H */

454
3rd-party/lc3-google/src/tns.c vendored Normal file
View File

@ -0,0 +1,454 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "tns.h"
#include "tables.h"
/* ----------------------------------------------------------------------------
* Filter Coefficients
* -------------------------------------------------------------------------- */
/**
* Resolve LPC Weighting indication according bitrate
* dt, nbytes Duration and size of the frame
* return True when LPC Weighting enabled
*/
static bool resolve_lpc_weighting(enum lc3_dt dt, int nbytes)
{
return nbytes < (dt == LC3_DT_7M5 ? 360/8 : 480/8);
}
/**
* Return dot product of 2 vectors
* a, b, n The 2 vectors of size `n`
* return sum( a[i] * b[i] ), i = [0..n-1]
*/
static inline float dot(const float *a, const float *b, int n)
{
float v = 0;
while (n--)
v += *(a++) * *(b++);
return v;
}
/**
* LPC Coefficients
* dt, bw Duration and bandwidth of the frame
* x Spectral coefficients
* gain, a Output the prediction gains and LPC coefficients
*/
static void compute_lpc_coeffs(enum lc3_dt dt, enum lc3_bandwidth bw,
const float *x, float *gain, float (*a)[9])
{
static const int sub_7m5_nb[] = { 9, 26, 43, 60 };
static const int sub_7m5_wb[] = { 9, 46, 83, 120 };
static const int sub_7m5_sswb[] = { 9, 66, 123, 180 };
static const int sub_7m5_swb[] = { 9, 46, 82, 120, 159, 200, 240 };
static const int sub_7m5_fb[] = { 9, 56, 103, 150, 200, 250, 300 };
static const int sub_10m_nb[] = { 12, 34, 57, 80 };
static const int sub_10m_wb[] = { 12, 61, 110, 160 };
static const int sub_10m_sswb[] = { 12, 88, 164, 240 };
static const int sub_10m_swb[] = { 12, 61, 110, 160, 213, 266, 320 };
static const int sub_10m_fb[] = { 12, 74, 137, 200, 266, 333, 400 };
/* --- Normalized autocorrelation --- */
static const float lag_window[] = {
1.00000000e+00, 9.98028026e-01, 9.92135406e-01, 9.82391584e-01,
9.68910791e-01, 9.51849807e-01, 9.31404933e-01, 9.07808230e-01,
8.81323137e-01
};
const int *sub = (const int * const [LC3_NUM_DT][LC3_NUM_SRATE]){
{ sub_7m5_nb, sub_7m5_wb, sub_7m5_sswb, sub_7m5_swb, sub_7m5_fb },
{ sub_10m_nb, sub_10m_wb, sub_10m_sswb, sub_10m_swb, sub_10m_fb },
}[dt][bw];
int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
const float *xs, *xe = x + *sub;
float r[2][9];
for (int f = 0; f < nfilters; f++) {
float c[9][3];
for (int s = 0; s < 3; s++) {
xs = xe, xe = x + *(++sub);
for (int k = 0; k < 9; k++)
c[k][s] = dot(xs, xs + k, (xe - xs) - k);
}
float e0 = c[0][0], e1 = c[0][1], e2 = c[0][2];
r[f][0] = 3;
for (int k = 1; k < 9; k++)
r[f][k] = e0 == 0 || e1 == 0 || e2 == 0 ? 0 :
(c[k][0]/e0 + c[k][1]/e1 + c[k][2]/e2) * lag_window[k];
}
/* --- Levinson-Durbin recursion --- */
for (int f = 0; f < nfilters; f++) {
float *a0 = a[f], a1[9];
float err = r[f][0], rc;
gain[f] = err;
a0[0] = 1;
for (int k = 1; k < 9; ) {
rc = -r[f][k];
for (int i = 1; i < k; i++)
rc -= a0[i] * r[f][k-i];
rc /= err;
err *= 1 - rc * rc;
for (int i = 1; i < k; i++)
a1[i] = a0[i] + rc * a0[k-i];
a1[k++] = rc;
rc = -r[f][k];
for (int i = 1; i < k; i++)
rc -= a1[i] * r[f][k-i];
rc /= err;
err *= 1 - rc * rc;
for (int i = 1; i < k; i++)
a0[i] = a1[i] + rc * a1[k-i];
a0[k++] = rc;
}
gain[f] /= err;
}
}
/**
* LPC Weighting
* gain, a Prediction gain and LPC coefficients, weighted as output
*/
static void lpc_weighting(float pred_gain, float *a)
{
float gamma = 1. - (1. - 0.85) * (2. - pred_gain) / (2. - 1.5), g = 1;
for (int i = 1; i < 9; i++)
a[i] *= (g *= gamma);
}
/**
* LPC reflection
* a LPC coefficients
* rc Output refelection coefficients
*/
static void lpc_reflection(const float *a, float *rc)
{
float e, b[2][7], *b0, *b1;
rc[7] = a[1+7];
e = 1 - rc[7] * rc[7];
b1 = b[1];
for (int i = 0; i < 7; i++)
b1[i] = (a[1+i] - rc[7] * a[7-i]) / e;
for (int k = 6; k > 0; k--) {
b0 = b1, b1 = b[k & 1];
rc[k] = b0[k];
e = 1 - rc[k] * rc[k];
for (int i = 0; i < k; i++)
b1[i] = (b0[i] - rc[k] * b0[k-1-i]) / e;
}
rc[0] = b1[0];
}
/**
* Quantization of RC coefficients
* rc Refelection coefficients
* rc_order Return order of coefficients
* rc_i Return quantized coefficients
*/
static void quantize_rc(const float *rc, int *rc_order, int *rc_q)
{
/* Quantization table, sin(delta * (i + 0.5)), delta = Pi / 17 */
static float q_thr[] = {
9.22683595e-02, 2.73662990e-01, 4.45738356e-01, 6.02634636e-01,
7.39008917e-01, 8.50217136e-01, 9.32472229e-01, 9.82973100e-01
};
*rc_order = 8;
for (int i = 0; i < 8; i++) {
float rc_m = fabsf(rc[i]);
rc_q[i] = 4 * (rc_m >= q_thr[4]);
for (int j = 0; j < 4 && rc_m >= q_thr[rc_q[i]]; j++, rc_q[i]++);
if (rc[i] < 0)
rc_q[i] = -rc_q[i];
*rc_order = rc_q[i] != 0 ? 8 : *rc_order - 1;
}
}
/**
* Unquantization of RC coefficients
* rc_q Quantized coefficients
* rc_order Order of coefficients
* rc Return refelection coefficients
*/
static void unquantize_rc(const int *rc_q, int rc_order, float rc[8])
{
/* Quantization table, sin(delta * i), delta = Pi / 17 */
static float q_inv[] = {
0.00000000e+00, 1.83749517e-01, 3.61241664e-01, 5.26432173e-01,
6.73695641e-01, 7.98017215e-01, 8.95163302e-01, 9.61825645e-01,
9.95734176e-01
};
int i;
for (i = 0; i < rc_order; i++) {
float rc_m = q_inv[LC3_ABS(rc_q[i])];
rc[i] = rc_q[i] < 0 ? -rc_m : rc_m;
}
}
/* ----------------------------------------------------------------------------
* Filtering
* -------------------------------------------------------------------------- */
/**
* Forward filtering
* dt, bw Duration and bandwidth of the frame
* rc_order, rc Order of coefficients, and coefficients
* x Spectral coefficients, filtered as output
*/
static void forward_filtering(
enum lc3_dt dt, enum lc3_bandwidth bw,
const int rc_order[2], const float rc[2][8], float *x)
{
int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
int nf = LC3_NE(dt, bw) >> (nfilters - 1);
int i0, ie = 3*(3 + dt);
float s[8] = { 0 };
for (int f = 0; f < nfilters; f++) {
i0 = ie;
ie = nf * (1 + f);
if (!rc_order[f])
continue;
for (int i = i0; i < ie; i++) {
float xi = x[i];
float s0, s1 = xi;
for (int k = 0; k < rc_order[f]; k++) {
s0 = s[k];
s[k] = s1;
s1 = rc[f][k] * xi + s0;
xi += rc[f][k] * s0;
}
x[i] = xi;
}
}
}
/**
* Inverse filtering
* dt, bw Duration and bandwidth of the frame
* rc_order, rc Order of coefficients, and unquantized coefficients
* x Spectral coefficients, filtered as output
*/
static void inverse_filtering(
enum lc3_dt dt, enum lc3_bandwidth bw,
const int rc_order[2], const float rc[2][8], float *x)
{
int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
int nf = LC3_NE(dt, bw) >> (nfilters - 1);
int i0, ie = 3*(3 + dt);
float s[8] = { 0 };
for (int f = 0; f < nfilters; f++) {
i0 = ie;
ie = nf * (1 + f);
if (!rc_order[f])
continue;
for (int i = i0; i < ie; i++) {
float xi = x[i];
xi -= s[7] * rc[f][7];
for (int k = 6; k >= 0; k--) {
xi -= s[k] * rc[f][k];
s[k+1] = s[k] + rc[f][k] * xi;
}
s[0] = xi;
x[i] = xi;
}
for (int k = 7; k >= rc_order[f]; k--)
s[k] = 0;
}
}
/* ----------------------------------------------------------------------------
* Interface
* -------------------------------------------------------------------------- */
/**
* TNS analysis
*/
void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw,
bool nn_flag, int nbytes, struct lc3_tns_data *data, float *x)
{
/* Processing steps :
* - Determine the LPC (Linear Predictive Coding) Coefficients
* - Check is the filtering is disabled
* - The coefficients are weighted on low bitrates and predicition gain
* - Convert to reflection coefficients and quantize
* - Finally filter the spectral coefficients */
float pred_gain[2], a[2][9];
float rc[2][8];
data->nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
data->lpc_weighting = resolve_lpc_weighting(dt, nbytes);
compute_lpc_coeffs(dt, bw, x, pred_gain, a);
for (int f = 0; f < data->nfilters; f++) {
data->rc_order[f] = 0;
if (nn_flag || pred_gain[f] <= 1.5)
continue;
if (data->lpc_weighting && pred_gain[f] < 2)
lpc_weighting(pred_gain[f], a[f]);
lpc_reflection(a[f], rc[f]);
quantize_rc(rc[f], &data->rc_order[f], data->rc[f]);
unquantize_rc(data->rc[f], data->rc_order[f], rc[f]);
}
forward_filtering(dt, bw, data->rc_order, rc, x);
}
/**
* TNS synthesis
*/
void lc3_tns_synthesize(enum lc3_dt dt, enum lc3_bandwidth bw,
const struct lc3_tns_data *data, float *x)
{
float rc[2][8] = { };
for (int f = 0; f < data->nfilters; f++)
if (data->rc_order[f])
unquantize_rc(data->rc[f], data->rc_order[f], rc[f]);
inverse_filtering(dt, bw, data->rc_order, rc, x);
}
/**
* Bit consumption of bitstream data
*/
int lc3_tns_get_nbits(const struct lc3_tns_data *data)
{
int nbits = 0;
for (int f = 0; f < data->nfilters; f++) {
int nbits_2048 = 2048;
int rc_order = data->rc_order[f];
nbits_2048 += rc_order > 0 ? lc3_tns_order_bits
[data->lpc_weighting][rc_order-1] : 0;
for (int i = 0; i < rc_order; i++)
nbits_2048 += lc3_tns_coeffs_bits[i][8 + data->rc[f][i]];
nbits += (nbits_2048 + (1 << 11) - 1) >> 11;
}
return nbits;
}
/**
* Put bitstream data
*/
void lc3_tns_put_data(lc3_bits_t *bits, const struct lc3_tns_data *data)
{
for (int f = 0; f < data->nfilters; f++) {
int rc_order = data->rc_order[f];
lc3_put_bits(bits, rc_order > 0, 1);
if (rc_order <= 0)
continue;
lc3_put_symbol(bits,
lc3_tns_order_models + data->lpc_weighting, rc_order-1);
for (int i = 0; i < rc_order; i++)
lc3_put_symbol(bits,
lc3_tns_coeffs_models + i, 8 + data->rc[f][i]);
}
}
/**
* Get bitstream data
*/
void lc3_tns_get_data(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data)
{
data->nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
data->lpc_weighting = resolve_lpc_weighting(dt, nbytes);
for (int f = 0; f < data->nfilters; f++) {
data->rc_order[f] = lc3_get_bit(bits);
if (!data->rc_order[f])
continue;
data->rc_order[f] += lc3_get_symbol(bits,
lc3_tns_order_models + data->lpc_weighting);
for (int i = 0; i < data->rc_order[f]; i++)
data->rc[f][i] = (int)lc3_get_symbol(bits,
lc3_tns_coeffs_models + i) - 8;
}
}

99
3rd-party/lc3-google/src/tns.h vendored Normal file
View File

@ -0,0 +1,99 @@
/******************************************************************************
*
* Copyright 2021 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Temporal Noise Shaping
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_TNS_H
#define __LC3_TNS_H
#include "common.h"
#include "bits.h"
/**
* Bitstream data
*/
typedef struct lc3_tns_data {
int nfilters;
bool lpc_weighting;
int rc_order[2];
int rc[2][8];
} lc3_tns_data_t;
/* ----------------------------------------------------------------------------
* Encoding
* -------------------------------------------------------------------------- */
/**
* TNS analysis
* dt, bw Duration and bandwidth of the frame
* nn_flag True when high energy detected near Nyquist frequency
* nbytes Size in bytes of the frame
* data Return bitstream data
* x Spectral coefficients, filtered as output
*/
void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw,
bool nn_flag, int nbytes, lc3_tns_data_t *data, float *x);
/**
* Return number of bits coding the data
* data Bitstream data
* return Bit consumption
*/
int lc3_tns_get_nbits(const lc3_tns_data_t *data);
/**
* Put bitstream data
* bits Bitstream context
* data Bitstream data
*/
void lc3_tns_put_data(lc3_bits_t *bits, const lc3_tns_data_t *data);
/* ----------------------------------------------------------------------------
* Decoding
* -------------------------------------------------------------------------- */
/**
* Get bitstream data
* bits Bitstream context
* dt, bw Duration and bandwidth of the frame
* nbytes Size in bytes of the frame
* data Bitstream data
*/
void lc3_tns_get_data(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data);
/**
* TNS synthesis
* dt, bw Duration and bandwidth of the frame
* data Bitstream data
* x Spectral coefficients, filtered as output
*/
void lc3_tns_synthesize(enum lc3_dt dt, enum lc3_bandwidth bw,
const lc3_tns_data_t *data, float *x);
#endif /* __LC3_TNS_H */

View File

@ -1,195 +0,0 @@
/*
* Lc3Config.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __LC3_CONFIG_HPP_
#define __LC3_CONFIG_HPP_
#include <cstdint>
/*
* The LC3 encoder and decoder have a common set of essential session
* configuration parameters - see LC3 specification Sections 2.2 "Encoder interfaces"
* and Section 2.4 "Decoder interfaces" (dr09r07).
* The set of common session configuration parameters is represented
* by an instance of class Lc3Config.
*
* Lc3Config is designed such that all parameters need to be
* providing when constructing an instance. Afterwards, success of creation,
* the actual parameter values, and derived parameter values are provided
* by corresponding const getter methods or public const fields.
*
* When parameters need to be changes, a new instance of Lc3Config has to be
* created.
*
* Instances of Lc3Config are provided to instances of Lc3Encoder and Lc3Decoder
* when constructing them.
*
* The main purpose of Lc3Config is to verify and handle common LC3 session
* configuration parameters in a consistent way.
*
*/
class Lc3Config
{
public:
/*
* Enumeration of supported frame durations N_ms = 7.5ms and N_ms = 10ms.
*
* Note: although the LC3 specification describes frame duration N_ms as
* a parameter with floating point values 7.5 and 10.0, we decided
* to make this parameter a discrete enumeration of supported
* frame durations. There are too many codec parts that need
* specifically listed constants dependent on the configured
* frame duration, so that it never will be possible to chose from a
* larger set of floating point values for N_ms.
* Making the data type of N_ms an enumeration supports
* straight forwards verification that meaningful parameters are given.
*/
enum class FrameDuration
{
d10ms,
d7p5ms
};
// configuration error (see "getErrorStatus")
static const uint8_t ERROR_FREE = 0x00;
static const uint8_t INVALID_SAMPLING_RATE = 0x01;
static const uint8_t INVALID_FRAME_DURATION = 0x02;
static const uint8_t INVALID_NUMBER_OF_CHANNELS = 0x04;
/*
* Constructor of an instance of Lc3Config
* Parameters:
* (see also see LC3 specification Sections 2.2 "Encoder interfaces"
* and Section 2.4 "Decoder interfaces" (dr09r07) )
*
* Fs_ : Sampling frequency in Hz -> defines public constant Fs
* Supported values are
* 8000 Hz
* 16000 Hz
* 24000 Hz
* 32000 Hz
* 44100 Hz
* 48000 Hz
*
* N_ms_ : Frame duration given by value from enumeration FrameDuration (see above)
* -> defines public constant N_ms
* Supported values see enumeration FrameDuration.
*
* Nc_ : Number of channels -> defines public constant Nc
* Supported values are Nc > 0 and Nc < 256 such that device resources are not exhausted.
* Notes:
* - Exhausting device resources can mean that there is not enough memory
* to instantiate the corresponding number of encoders and/or decoders, but
* also that computing the encoders and/or decoders in real-time is not possible.
* - The parameter N_c_max described in the LC3 specifciation is not given here,
* since there is too little knowledge on the target devices where this code
* may be used.
*
*/
Lc3Config(uint16_t Fs_, FrameDuration N_ms_, uint8_t Nc_);
// no default constructor supported
Lc3Config() = delete;
// Destructor
virtual ~Lc3Config();
/*
* Getter "isValid" provides a convenience function that returns true when an instance of Lc3Config
* could be created without error.
*/
bool isValid() const;
/*
* Getter "getErrorStatus" provides details on the success of instantiating Lc3Config.
* The possible return values are listed as constants in this class (see configuration error constants above)
*/
uint8_t getErrorStatus() const;
/*
* Getter "getByteCountFromBitrate" provides the number of bytes available in one encoded frame
* of one channel (see "nbytes" as described in Section 3.2.5 "Bit budget and bitrate" (dr09r07) )
*
* The number of bytes "nbytes" to use for encoding a single channel is a required external input to
* each single channel LC3 encoder. The same number of bytes (now to be used for decoding) is also
* a required external input to each single channel LC3 decoder. The corresponding number of bits
* available in one frame is thus "nbits 8*nbytes".
* The codec works on a byte boundary, i.e. the variable "nbytes" shall be an integer number.
* A certain "bitrate" can be converted to a number of bytes "nbytes" where the number of bytes is
* rounded towards the nearest lower integer.
*
* The algorithm is verified from the bitrate corresponding to
* nbytes = 20 up to the bitrate corresponding to
* nbytes = 400 per channel for all sampling rates.
* The LC3 specification does not specify or recommend what bitrate to use for encoding a frame of
* audio samples. This is specified by the profiles making use of the LC3.
*/
uint16_t getByteCountFromBitrate(uint32_t bitrate) const; // meant for a single channel
/*
* Getter "getBitrateFromByteCount" provides the bitrate of the codec in bits per second
* of one channel (see Section 3.2.5 "Bit budget and bitrate" (dr1.0r03) )
*
* This is a convenience utility and not directly used by the LC3 implementation.
*
* The bitrate of the codec in bits per second is
* "bitrate = ceil(nbits / frame_duration) = ceil(nbits*Fs/NF) = ceil(8*nbytes*Fs/NF)".
*
* The LC3 specification does not specify or recommend what bitrate to use for encoding a frame of
* audio samples. This is specified by the profiles making use of the LC3.
*/
uint32_t getBitrateFromByteCount(uint16_t nbytes) const;
/*
* Getter "getFscal" provides a utility used within the LC3 implementation
* for easier parameter mapping when Fs == 44100
* (see Section 3.2.2 "Sampling rates" (dr1.0r03) )
*/
double getFscal() const;
/*
* Getter "getNmsValue" provides a utility used within the LC3 implementation
* that converts FrameDuration N_ms enumeration values to duration values in milliseconds.
*/
double getNmsValue() const;
private:
// internal utilities used for verifying the given input parameters and computing derived parameters
uint8_t getFs_ind(uint16_t Fs);
uint16_t getNF(uint16_t Fs, FrameDuration N_ms);
uint16_t getNE(uint16_t NF, FrameDuration N_ms);
// errors status set during construction and returned by getErrorStatus()
uint8_t errorStatus;
public:
// configuration details -> see also Section 3.1.2 "Mathematical symbols" (dr09r07)
const uint16_t Fs; // Sampling rate (in Hz)
const uint8_t Fs_ind; // Sampling rate index (see also Section 3.2.2 "Sampling rates" (dr09r07)
const FrameDuration N_ms; // Frame duration -> see Lc3Config constructor documentation
// Note: that the actual frame duration is longer by a factor of 480/441
// if the sampling rate is 44100 Hz
const uint16_t NF; // Number of samples processed in one frame of one channel (also known as frame size)
const uint16_t NE; // Number of encoded spectral lines (per frame and channel)
const uint16_t Z; // Number of leading zeros in MDCT window
const uint8_t Nc; // Number of channels
const uint8_t N_b; // Number of bands
};
#endif // __LC3_CONFIG_HPP_

View File

@ -1,329 +0,0 @@
/*
* Lc3Decoder.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef API_LC3DECODER_HPP_
#define API_LC3DECODER_HPP_
#include <cstdint>
#include <vector>
#include "Lc3Config.hpp"
/*
* Forward declaration of the "internal" class DecoderTop, so
* that the private vector of single channel decoders can be declared in Lc3Decoder.
*/
namespace Lc3Dec
{
class DecoderTop;
}
/*
* The LC3 decoder interface is specified in
* LC3 specification Sections 2.4 "Decoder interfaces" (dr09r07).
*
* Lc3Decoder is designed such that all specified features are provided.
*
* In contrast to the Lc3Encoder, even 24bit and 32bit decoded audio
* data can be provided - however in one fix byte arrangement which will
* not meet all meaningful options. Providing 24bit and 32bit decoded audio
* data makes the API more complex but does not increase the needed
* resources when basic 16bit/sample audio data is desired only.
*
* Instantiating Lc3Decoder implies providing a Lc3Config instance. A copy of
* this instance is available as public const member so that all essential session
* parameters can be obtained throughout the lifetime of the Lc3Decoder instance.
*
* There is no possibility of changing Lc3Config within Lc3Decoder. When session
* parameters have to be changed, the calling application has to create a new
* instance of Lc3Decoder.
*
* Lc3 supports operation with variable encoded bitrate. It is possible to change
* the bitrate from frame to frame, where for preciseness the parameter is not
* given as bitrate directly but in terms of the byte_count per frame. This
* parameter has to be in the range of 20 to 400
* (see LC3 specification Section 3.2.5 "Bit budget and bitrate").
* LC3 specification Sections 2.4 "Decoder interfaces" specifies "byte_count_max"
* of the decoder to allow pre-allocation of resources. This parameter is provided
* here for completeness and used for verifying the byte_count value of individual
* frames only. The needed memory has to be provided by the calling application anyway,
* so that it is up to the application whether a pre-allocation of memory is useful.
*
*/
class Lc3Decoder
{
public:
/*
* Convenience constructor of Lc3Decoder with two simple parameter only.
* Note that this constructor instantiated Lc3Config implicitly with
* Lc3Decoder(Lc3Config(Fs,frameDuration, 1)) that means that this
* constructor provides processing of one channel (mono) and 16bit/sample
* PCM output only.
*
* Parameters:
* Fs : Sampling frequency in Hz -> see Lc3Config.hpp for supported values
*
* frameDuration : frame duration of 10ms (default) or 7.5ms
* -> see Lc3Config.hpp for more details
*/
Lc3Decoder(uint16_t Fs, Lc3Config::FrameDuration frameDuration = Lc3Config::FrameDuration::d10ms);
/*
* General constructor of Lc3Decoder.
*
* Parameters:
* lc3Config_ : instance of Lc3Config. See documentation of Lc3Config for more details.
* Note: providing an invalid instance of Lc3Config will result
* in skipping any processing later.
* The provided instance of Lc3Config will be copied to the
* public field "lc3Config" (see below).
*
* bits_per_audio_sample_dec_ : Bits per audio sample for the output PCM signal.
* See LC3 specification Section 2.4 "Decoder interfaces"
* and Section 3.2.3 "Bits per sample" for the general LC3
* requirement to support 16, 24 and 32 bit.
* Note: This parameter may differ from the encoder input PCM
* setting "bits_per_audio_sample_enc".
*
* byte_count_max_dec_ : Maximum allowed payload byte_count for a single channel.
* When using and allowing external rate control, the maximum byte
* count for the session may be used to configure the session buffers
* without a need to dynamically reallocate memory during the session.
*
* datapoints : pointer to an instance of a class allowing to collect internal data.
* Note: this feature is used and prepared for testing of the codec
* implementation only. See general "Readme.txt"
*/
Lc3Decoder(Lc3Config lc3Config_, uint8_t bits_per_audio_sample_dec_ = 16, uint16_t byte_count_max_dec_ = 400, void* datapoints=nullptr);
// no default constructor supported
Lc3Decoder() = delete;
// Destructor
virtual ~Lc3Decoder();
/*
* Configuration provided during instantiation accessible as public const fields.
* Note: Lc3Config provides a getter to check whether the configuration is valid.
*/
const Lc3Config lc3Config;
const uint8_t bits_per_audio_sample_dec;
const uint16_t byte_count_max_dec;
// encoding error (see return values of "run" methods)
static const uint8_t ERROR_FREE = 0x00;
static const uint8_t INVALID_CONFIGURATION = 0x01;
static const uint8_t INVALID_BYTE_COUNT = 0x02;
static const uint8_t INVALID_X_OUT_SIZE = 0x03;
static const uint8_t INVALID_BITS_PER_AUDIO_SAMPLE = 0x04;
static const uint8_t DECODER_ALLOCATION_ERROR = 0x05;
/*
* Decoding one 16 bit/sample output frame for one channel
*
* Note that this methods returns the error INVALID_BITS_PER_AUDIO_SAMPLE
* when the session has been configured for any bits_per_audio_sample_dec != 16.
*
* Further, note that this method can be used for multi-channel configurations as well,
* particularly when the provided multi-channel "run" (see below) is not supporting
* the kind of byte stream concatenation existing in the calling application.
*
* Parameters:
* bytes : pointer to byte array holding the input LC3 encoded byte stream
* of the given channel.
* The size of this memory is given by the byte_count parameter.
*
* byte_count : number of encoded bytes; byte count to be used for decoding
* the received frame payload.
* Supported values are 20 bytes to byte_count_max_dec bytes.
*
* BFI : Bad Frame Indication flags
* "0" signifies that no bit errors where detected in given "bytes"
* "1" signifies a corrupt payload packet was detected in given "bytes"
*
* x_out : pointer to output PCM data (16 bit/sample), where the memory
* has to be provided by the calling application.
*
* x_out_size : number of 16 bit values supported by x_out
* Note: this parameter has been introduced for clarity and
* verification purpose only. The method will return
* the error INVALID_X_OUT_SIZE when x_out_size != lc3Config.NF.
*
* BEC_detect : flag indication bit errors detected during decoding of input bytes
* Note: a basic packet loss concealment (PLC) will be applied when
* BEC_detect!=0, so that the returned audio data stays
* somewhat acceptable.
*
* channelNr : index of channel to be processed (default=0), where channelNr < lc3Config.Nc
*
*
* Return value: error code as listed above.
*/
uint8_t run(const uint8_t* bytes, uint16_t byte_count, uint8_t BFI,
int16_t* x_out, uint16_t x_out_size, uint8_t& BEC_detect, uint8_t channelNr=0);
/*
* Decoding one 16, 24, or 32 bit/sample output frame for one channel
*
* Note that every output PCM sample will need one 32 bit memory place in the
* output stream independently from the configured bits_per_audio_sample_dec.
*
* Further, note that this method can be used for multi-channel configurations as well,
* particularly when the provided multi-channel "run" (see below) is not supporting
* the kind of byte stream concatenation existing in the calling application.
*
* Parameters:
* bytes : pointer to byte array holding the input LC3 encoded byte stream
* of the given channel.
* The size of this memory is given by the byte_count parameter.
*
* byte_count : number of encoded bytes; byte count to be used for decoding
* the received frame payload.
* Supported values are 20 bytes to byte_count_max_dec bytes.
*
* BFI : Bad Frame Indication flags
* "0" signifies that no bit errors where detected in given "bytes"
* "1" signifies a corrupt payload packet was detected in given "bytes"
*
* x_out : pointer to output PCM data (memory 32 bit/sample, precision 16 bit/sample,
* 24 bit/sample or 32 bit/sample), where the memory
* has to be provided by the calling application.
*
* x_out_size : number of 32 bit values supported by x_out
* Note: this parameter has been introduced for clarity and
* verification purpose only. The method will return
* the error INVALID_X_OUT_SIZE when x_out_size != lc3Config.NF.
*
* BEC_detect : flag indication bit errors detected during decoding of input bytes
* Note: a basic packet loss concealment (PLC) will be applied when
* BEC_detect!=0, so that the returned audio data stays
* somewhat acceptable.
*
* channelNr : index of channel to be processed (default=0), where channelNr < lc3Config.Nc
*
*
* Return value: error code as listed above.
*/
uint8_t run(const uint8_t* bytes, uint16_t byte_count, uint8_t BFI,
int32_t* x_out, uint16_t x_out_size, uint8_t& BEC_detect, uint8_t channelNr=0);
/*
* Decoding one 16 bit/sample output frame for multiple channels.
*
* Note that this methods returns the error INVALID_BITS_PER_AUDIO_SAMPLE
* when the session has been configured for any bits_per_audio_sample_dec != 16.
*
* Parameters:
* bytes : pointer to byte array holding the input LC3 encoded byte stream
* of all given channels.
* The size of this memory is given by the sum of all byte_count_per_channel
* values (see parameter byte_count_per_channel).
* Note that the encoded values of all channels are expected to be
* concatenated without any stuffing bytes of meta data in between.
*
* byte_count_per_channel : number of encoded bytes; byte count to be used for decoding
* the received frame payload per channel.
* Thus, byte_count_per_channel is an array of byte_count values
* with length lc3Conig.Nc
* Supported values are 20 bytes to byte_count_max_dec bytes per
* channel.
*
* BFI_per_channel : lc3Conig.Nc length array of Bad Frame Indication flags
* "0" signifies that no bit errors where detected in given "bytes"
* "1" signifies a corrupt payload packet was detected in given "bytes"
*
* x_out : pointer to output 16 bit/sample PCM data, where the memory
* has to be provided by the calling application.
*
* x_out_size : number of 16 bit values supported by x_out
* Note: this parameter has been introduced for clarity and
* verification purpose only. The method will return
* the error INVALID_X_OUT_SIZE when x_out_size != lc3Config.NF * lc3Conig.Nc.
*
* BEC_detect_per_channel : lc3Conig.Nc length array of flags indicating bit errors
* detected during decoding of input bytes of a certain channel.
* Note: a basic packet loss concealment (PLC) will be applied when
* BEC_detect!=0, so that the returned audio data stays
* somewhat acceptable.
*
*
* Return value: error code via "or" concatenation of the error codes of processing
* the individual channels. Note: this "or" concatenation make specific
* error diagnosis impossible. Thus only checking != ERROR_FREE is meaningful.
* When more specific information is needed, the single channel call (see above)
* need to be called.
*/
uint8_t run(const uint8_t* bytes, const uint16_t* byte_count_per_channel, const uint8_t* BFI_per_channel,
int16_t* x_out, uint32_t x_out_size, uint8_t* BEC_detect_per_channel);
/*
* Decoding one 16, 24, or 32 bit/sample output frame for multiple channels
*
* Note that every output PCM sample will need one 32 bit memory place in the
* output stream independently from the configured bits_per_audio_sample_dec.
*
* Parameters:
* bytes : pointer to byte array holding the input LC3 encoded byte stream
* of all given channels.
* The size of this memory is given by the sum of all byte_count_per_channel
* values (see parameter byte_count_per_channel).
* Note that the encoded values of all channels are expected to be
* concatenated without any stuffing bytes of meta data in between.
*
* byte_count_per_channel : number of encoded bytes; byte count to be used for decoding
* the received frame payload per channel.
* Thus, byte_count_per_channel is an array of byte_count values
* with length lc3Conig.Nc
* Supported values are 20 bytes to byte_count_max_dec bytes per
* channel.
*
* BFI_per_channel : lc3Conig.Nc length array of Bad Frame Indication flags
* "0" signifies that no bit errors where detected in given "bytes"
* "1" signifies a corrupt payload packet was detected in given "bytes"
*
* x_out : pointer to output 16, 24, or 32 bit/sample PCM data, where the memory
* has to be provided by the calling application.
*
* x_out_size : number of 32 bit values supported by x_out
* Note: this parameter has been introduced for clarity and
* verification purpose only. The method will return
* the error INVALID_X_OUT_SIZE when x_out_size != lc3Config.NF * lc3Conig.Nc.
*
* BEC_detect_per_channel : lc3Conig.Nc length array of flags indicating bit errors
* detected during decoding of input bytes of a certain channel.
* Note: a basic packet loss concealment (PLC) will be applied when
* BEC_detect!=0, so that the returned audio data stays
* somewhat acceptable.
*
*
* Return value: error code via "or" concatenation of the error codes of processing
* the individual channels. Note: this "or" concatenation make specific
* error diagnosis impossible. Thus only checking != ERROR_FREE is meaningful.
* When more specific information is needed, the single channel call (see above)
* need to be called.
*/
uint8_t run(const uint8_t* bytes, const uint16_t* byte_count_per_channel, const uint8_t* BFI_per_channel,
int32_t* x_out, uint32_t x_out_size, uint8_t* BEC_detect_per_channel);
private:
std::vector<Lc3Dec::DecoderTop*> decoderList;
};
#endif /* API_LC3DECODER_HPP_ */

View File

@ -1,192 +0,0 @@
/*
* Lc3Encoder.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef API_LC3ENCODER_HPP_
#define API_LC3ENCODER_HPP_
#include <cstdint>
#include <vector>
#include "Lc3Config.hpp"
/*
* Forward declaration of the "internal" class EncoderTop, so
* that the private vector of single channel encoders can be declared in Lc3Encoder.
*/
namespace Lc3Enc
{
class EncoderTop;
}
/*
* The LC3 encoder interface is specified in
* LC3 specification Sections 2.2 "Encoder interfaces" (dr09r07).
*
* Lc3Encoder is designed such that all specified features are provided
* with the (current) exception of not providing other input bit depth
* than 16 bit/sample. At the time of writing, the main purpose of the
* implementation was to handle 16bit audio data provided within android
* smartphones. Providing the specified 24bit and 32 bit audio data input,
* would make the API more complex. However, the main argument to not support
* these sample rates right now, is that internal operations and memory
* consumption would have to be increased measurable otherwise.
*
* Instantiating Lc3Encoder implies providing a Lc3Config instance. A copy of
* this instance is available as public const member so that all essential session
* parameters can be obtained throughout the lifetime of the Lc3Encoder instance.
*
* There is no possibility of changing Lc3Config within Lc3Encoder. When session
* parameters have to be changed, the calling application has to create a new
* instance of Lc3Encoder.
*
* Lc3 supports operation with variable encoded bitrate. It is possible to change
* the bitrate from frame to frame, where for preciseness the parameter is not
* given as bit rate directly but in terms of the byte_count per frame. This
* parameter has to be in the range of 20 to 400
* (see LC3 specification Section 3.2.5 "Bit budget and bitrate")
*
*/
class Lc3Encoder
{
public:
/*
* Convenience constructor of Lc3Encoder with one simple parameter only.
* Note that this constructor instantiated Lc3Config implicitly with
* Lc3Config(Fs, Lc3Config::FrameDuration::d10ms, 1) that means that this
* constructor provides processing of one channel (mono) with 10ms frame duration.
*
* Parameters:
* Fs : Sampling frequency in Hz -> see Lc3Config.hpp for supported values
*/
Lc3Encoder(uint16_t Fs);
/*
* General constructor of Lc3Encoder.
*
* Parameters:
* lc3Config_ : instance of Lc3Config. See documentation of Lc3Config for more details.
* Note: providing an invalid instance of Lc3Config will result
* in skipping any processing later.
* The provided instance of Lc3Config will be copied to the
* public field "lc3Config" (see below).
*
* bits_per_audio_sample_enc_ : The bits per audio sample for the input PCM signal.
* See LC3 specification Section 2.2 "Encoder interfaces"
* and Section 3.2.3 "Bits per sample" for the general LC3
* requirement to support 16, 24 and 32 bit.
* Note: This parameter may differ from the decoder output PCM
* setting "bits_per_audio_sample_dec".
*
* However, the current implementation allows 16 bit only
* and will return an error INVALID_BITS_PER_AUDIO_SAMPLE
* for run() when configured with any other value.
* (see reasoning for this constraint in the general class
* descripton above)
*
* datapoints : pointer to an instance of a class allowing to collect internal data.
* Note: this feature is used and prepared for testing of the codec
* implementation only. See general "Readme.txt"
*/
Lc3Encoder(Lc3Config lc3Config_, uint8_t bits_per_audio_sample_enc_ = 16, void* datapoints=nullptr);
// no default constructor supported
Lc3Encoder() = delete;
// Destructor
virtual ~Lc3Encoder();
/*
* Configuration provided during instantiation accessible as public const fields.
* Note: Lc3Config provides a getter to check whether the configuration is valid.
*/
const Lc3Config lc3Config;
const uint8_t bits_per_audio_sample_enc;
// encoding errors (see return values of "run" methods)
static const uint8_t ERROR_FREE = 0x00;
static const uint8_t INVALID_CONFIGURATION = 0x01;
static const uint8_t INVALID_BYTE_COUNT = 0x02;
static const uint8_t INVALID_BITS_PER_AUDIO_SAMPLE = 0x03;
static const uint8_t ENCODER_ALLOCATION_ERROR = 0x04;
/*
* Encoding of one input frame for one channel.
*
* Note that this method can be used for multi-channel configurations as well,
* particularly when the provided multi-channel "run" (see below) is not providing
* the kind of byte stream concatenation desired by a specific application.
*
* Parameters:
* x : pointer to input signal array with 16bit/sample.
* The length of the signal to be provided depends on the given
* session configuration and can be obtained via
* lc3Config.NF
*
* byte_count : determines the compression strength (-> bitrate) to be used
* for this specific frame. Supported values are 20 bytes to 400 bytes,
* where values well below 40 bytes typically give rather poor audio quality.
* Note: in case of having an application targeting a given bitrate, the
* helper method "lc3Config.getByteCountFromBitrate(.)" can be used
* to compute the proper setting for this byte_count parameter.
*
* bytes : pointer to byte array (memory) provided by the application, where the
* encoded byte stream will be placed. The size of this memory is given by
* the byte_count parameter.
*
* channelNr : index of channel to be processed (default=0), where channelNr < lc3Config.Nc
*
* Return value: error code as listed above.
*/
uint8_t run(const int16_t* x, uint16_t byte_count, uint8_t* bytes, uint8_t channelNr=0);
/*
* Encoding of one multi-channel frame.
*
* Note that this call always processes all channels configured in the given session.
*
* Parameters:
* x : pointer to input signal array with 16bit/sample.
* The length of the signal to be provided depends on the given
* session configuration and can be obtained via
* lc3Config.NF * lc3Config.Nc
*
* byte_count_per_channel : determines the compression strength (-> bitrate) to be used
* for each channel individually of this specific frame.
* Thus, byte_count_per_channel is an array of byte_count values
* with length lc3Conig.Nc
* Supported values per channel are 20 bytes to 400 bytes.
* See also the documentation for the single channel "run" above.
*
* bytes : pointer to byte array (memory) provided by the application, where the
* encoded byte stream will be placed. The size of this memory is given by
* the byte_count_per_channel parameter, specifically by the sum of all
* channel-wise byte_count values
* (byte_count_per_channel[0] + ... + byte_count_per_channel[lc3Config.Nc])
* This implies that the encoded bytes from the individual channels are
* concatenated directly (without any stuffing bytes or meta information).
*
* Return value: error code as listed above.
*/
uint8_t run(const int16_t* x, const uint16_t* byte_count_per_channel, uint8_t* bytes);
private:
std::vector<Lc3Enc::EncoderTop*> encoderList;
};
#endif /* API_LC3ENCODER_HPP_ */

View File

@ -1,261 +0,0 @@
/*
* DctIV.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "DctIV.hpp"
#include <cmath>
/*
* Notes on the choice of the applied FFT library:
* - Different fast transform implementations for the DCT-IV can be selected via
* USE_FFTW
* USE_FFTW_FOR_FFT // assume NF being 4 times an integer
* USE_KISSFFT // assume NF being 4 times an integer
* where only one of them is meaningful to be defined
*
* - Defining none of the fast transforms will lead to a direct implementation
* which is good for testing but usually to slow for practial applications
*
* - USE_FFTW: The free "fftw" library should be fastest, but may be more complicated to be build
* for embedded target devices. It provides dedicated optimization for the DCT-IV
* and thus is preferred from a technical perspective. In terms of licences "fftw"
* is free in the sense of GPL, which is not liked in some products. There might be the option
* to ask the authors for other licences (which they propose). Nevertheless, the "license" issue
* has driven us to not bundle "fftw" directly with the LC3 implementation, although the API
* for using it is provided and tested.
*
* - USE_FFTW_FOR_FFT: this is a not fully optimized alternative approach using the complex fft
* provided by "fftw" instead of the dedicated optimized DCT-IV implementation. This option
* is mainly provided to demonstrate the transition from USE_FFTW to USE_KISSFFT
*
* - USE_KISSFFT: the free "kissfft" library is sligthly slower than "fftw", but gives a majority
* of the possible performance gain over a "stupid" direct DCT-IV implementation.
* "kissfft" does not provide a dedicated optimization for DCT-IV so that some additional code
* for implementing a DCT-IV by a complex fft has to be added. This also implies additional
* memory needed.
* The big advantage of the "kissfft" is that it is less restrictive
* in terms of its license. Further, the template based C++ implementation reduces its impact
* on the build system to a minimum (we just need to include the right header without needing
* to compile and link a separate file).
*
* - USE_KISSFFT is defined below to be the default choice. The other alternatives may be selecting
* by providing its define via the compiler switch -D<define>
*
* - The impact of the defines is restricted to this *.cpp file for clarity reasons.
* Ok, to make this work, we needed a few "ugly" pointer casts, but we really wanted to make
* sure, that no other code or build impact is generated by the options in this file.
*/
#define USE_KISSFFT
#if defined USE_FFTW || defined USE_FFTW_FOR_FFT
#include <fftw3.h>
#elif defined USE_KISSFFT
#include "kissfft.hh"
class KissfftConfig
{
public:
KissfftConfig(uint16_t N)
: inbuf(nullptr), outbuf(nullptr), fft(nullptr)
{
inbuf = new std::complex<double>[N];
outbuf = new std::complex<double>[N];
twiddle = new std::complex<double>[N];
fft = new kissfft<double>(N, false);
const double pi = std::acos(-1);
for (uint16_t n=0; n < N; n++)
{
twiddle[n] = std::complex<double>( std::cos(-pi*(8*n+1)/(8.0*N*2)), std::sin(-pi*(8*n+1)/(8.0*N*2)) );
}
}
~KissfftConfig()
{
if (nullptr != fft)
{
delete fft;
}
if (nullptr != inbuf)
{
delete[] inbuf;
}
if (nullptr != outbuf)
{
delete[] outbuf;
}
if (nullptr != twiddle)
{
delete[] twiddle;
}
}
void transform()
{
if (nullptr != fft)
{
fft->transform( inbuf, outbuf );
}
}
std::complex<double>* inbuf;
std::complex<double>* outbuf;
std::complex<double>* twiddle;
kissfft<double>* fft;
};
#endif
DctIVDbl::DctIVDbl(uint16_t NF_) :
NF(NF_),
in(nullptr),
out(nullptr),
dctIVconfig(nullptr)
{
in = new double[NF];
out = new double[NF];
#if defined USE_FFTW
dctIVconfig = fftw_plan_r2r_1d(NF, in, out, FFTW_REDFT11, FFTW_ESTIMATE);
#elif defined USE_FFTW_FOR_FFT
dctIVconfig = fftw_plan_dft_1d( NF/2,
reinterpret_cast<fftw_complex*>(in),
reinterpret_cast<fftw_complex*>(out),
FFTW_FORWARD, FFTW_ESTIMATE);
#elif defined USE_KISSFFT
dctIVconfig = new KissfftConfig(NF/2);
#endif
for (uint16_t n=0; n < NF; n++)
{
in[n]=0;
out[n]=0;
}
}
DctIVDbl::~DctIVDbl()
{
#if defined USE_FFTW || defined USE_FFTW_FOR_FFT
if (nullptr != dctIVconfig)
{
fftw_destroy_plan(reinterpret_cast<fftw_plan>(dctIVconfig));
}
#elif defined USE_KISSFFT
if (nullptr != dctIVconfig)
{
KissfftConfig* kissfftConfig = reinterpret_cast<KissfftConfig*>(dctIVconfig);
delete kissfftConfig;
}
#endif
if (nullptr != in)
{
delete[] in;
}
if (nullptr != out)
{
delete[] out;
}
}
void DctIVDirectDbl(uint16_t N, const double* const tw, double* const X)
{
const double pi = std::acos(-1);
for (uint16_t k=0; k < N; k++)
{
X[k] = 0;
for (uint16_t n=0; n < N; n++)
{
X[k] += tw[n] * std::cos( pi / N * (n+0.5)*(k+0.5) );
}
X[k] *= 2;
}
}
void DctIVDbl::run()
{
#ifdef USE_FFTW
fftw_execute(reinterpret_cast<fftw_plan>(dctIVconfig));
#elif defined USE_FFTW_FOR_FFT
const double pi = std::acos(-1);
// assume NF being 4 times an integer
for (uint16_t n=1; n < NF/2; n+=2)
{
double buffer;
buffer = in[n];
in[n] = in[NF-n];
in[NF-n] = buffer;
}
for (uint16_t n=0; n < NF; n+=2)
{
double real = in[n+0];
double imag = in[n+1];
in[n+0] = real * std::cos( -pi*(4*n+1)/(8.0*NF) )
- imag * std::sin( -pi*(4*n+1)/(8.0*NF) );
in[n+1] = real * std::sin( -pi*(4*n+1)/(8.0*NF) )
+ imag * std::cos( -pi*(4*n+1)/(8.0*NF) );
}
fftw_execute(reinterpret_cast<fftw_plan>(dctIVconfig));
for (uint16_t n=0; n < NF; n+=2)
{
double real = out[n+0];
double imag = out[n+1];
out[n+0] = 2*(real * std::cos( -pi*(4*n+1)/(8.0*NF) )
- imag * std::sin( -pi*(4*n+1)/(8.0*NF) ) );
out[n+1] = 2*(real * std::sin( -pi*(4*n+1)/(8.0*NF) )
+ imag * std::cos( -pi*(4*n+1)/(8.0*NF) ) );
}
for (uint16_t n=1; n < NF/2; n+=2)
{
double buffer;
buffer = out[n];
out[n] = -out[NF-n];
out[NF-n] = -buffer;
}
#elif defined USE_KISSFFT
// assume NF being 4 times an integer
KissfftConfig* kissfftConfig = reinterpret_cast<KissfftConfig*>(dctIVconfig);
for (uint16_t n=0; n < NF/2; n++)
{
kissfftConfig->inbuf[n] = kissfftConfig->twiddle[n] * std::complex<double>( in[2*n], in[NF-2*n-1] );
}
kissfftConfig->transform();
for (uint16_t n=0; n < NF/2; n++)
{
std::complex<double> complexOut = kissfftConfig->twiddle[n] * kissfftConfig->outbuf[n];
out[2*n] = complexOut.real()*2;
out[NF-2*n-1] = -complexOut.imag()*2;
}
#else
DctIVDirectDbl(NF, in, out);
#endif
}

View File

@ -1,38 +0,0 @@
/*
* DctIV.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DCT_IV_H_
#define DCT_IV_H_
#include <cstdint>
class DctIVDbl
{
public:
DctIVDbl(uint16_t NF_);
virtual ~DctIVDbl();
void run();
const uint16_t NF;
double* in;
double* out;
void* dctIVconfig;
};
#endif // DCT_IV_H_

View File

@ -1,157 +0,0 @@
/*
* Lc3Config.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Lc3Config.hpp"
#include <cmath>
Lc3Config::Lc3Config(uint16_t Fs_, FrameDuration N_ms_, uint8_t Nc_)
:
errorStatus(ERROR_FREE),
Fs(Fs_),
Fs_ind(getFs_ind(Fs)),
N_ms(N_ms_),
NF(getNF(Fs, N_ms_)),
NE(getNE(NF, N_ms_)),
Z( (N_ms==FrameDuration::d10ms) ? 3*NF/8 : 7*NF/30 ),
Nc(Nc_),
N_b( ((N_ms == Lc3Config::FrameDuration::d7p5ms) && (Fs==8000)) ? 60 : 64 )
{
if (0==Nc) // we do not restrict the maximum yet (naturally limited to 255 because of the chosen datatype)
{
errorStatus |= INVALID_NUMBER_OF_CHANNELS;
}
}
Lc3Config::~Lc3Config()
{
}
bool Lc3Config::isValid() const
{
return ERROR_FREE == errorStatus;
}
uint8_t Lc3Config::getErrorStatus() const
{
return errorStatus;
}
uint8_t Lc3Config::getFs_ind(uint16_t Fs)
{
uint8_t fs_ind=0;
switch(Fs)
{
case 8000: fs_ind=0; break;
case 16000: fs_ind=1; break;
case 24000: fs_ind=2; break;
case 32000: fs_ind=3; break;
case 44100:;
case 48000: fs_ind=4; break;
default:
errorStatus |= INVALID_SAMPLING_RATE;
}
return fs_ind;
}
uint16_t Lc3Config::getNF(uint16_t Fs, FrameDuration N_ms)
{
uint16_t NF = 80;
if (FrameDuration::d10ms == N_ms)
{
switch(Fs)
{
case 8000: NF=80; break;
case 16000: NF=160; break;
case 24000: NF=240; break;
case 32000: NF=320; break;
case 44100:;
case 48000: NF=480; break;
default :
errorStatus |= INVALID_SAMPLING_RATE;
}
}
else if (FrameDuration::d7p5ms == N_ms)
{
switch(Fs)
{
case 8000: NF=60; break;
case 16000: NF=120; break;
case 24000: NF=180; break;
case 32000: NF=240; break;
case 44100:;
case 48000: NF=360; break;
default :
errorStatus |= INVALID_SAMPLING_RATE;
}
}
else
{
// We never should reach this line unless
// strange things happen. However, we want
// to be on the safe side and thus handle
// this case explicitly.
errorStatus |= INVALID_FRAME_DURATION;
}
return NF;
}
uint16_t Lc3Config::getNE(uint16_t NF, FrameDuration N_ms)
{
//3.3.4.3 Time-Frequency Transformation (d09r04_*implementorComments*)
if (FrameDuration::d10ms == N_ms)
{
return (480==NF) ? 400:NF;
}
else
{
return (360==NF) ? 300:NF;
}
}
uint16_t Lc3Config::getByteCountFromBitrate(uint32_t bitrate) const
{
// Section 3.2.5 Bit budget and bitrate (LC3_Specification_d09r06)
double f_scal = getFscal();
double N_ms_value = getNmsValue();
return floor( (bitrate * N_ms_value * f_scal)/8000.0 );
}
uint32_t Lc3Config::getBitrateFromByteCount(uint16_t nbytes) const
{
// Section 3.2.5 Bit budget and bitrate (LC3_Specification_d1.0r03)
// Notes:
// - this implementation includes Errata 15051
// - this utility function is not used within the LC3 code so far, but
// provided here for completeness
double f_scal = getFscal();
double N_ms_value = getNmsValue();
return ceil( (8000.0 * nbytes) / (N_ms_value * f_scal) );
}
double Lc3Config::getFscal() const
{
// Section 3.2.2 Sampling rates (LC3_Specification_d1.0r03)
return (44100==Fs)? 48000.0/44100.0 : 1.0;
}
double Lc3Config::getNmsValue() const
{
return (FrameDuration::d10ms == N_ms) ? 10.0 : 7.5;
}

View File

@ -1,41 +0,0 @@
/*
* BandIndexTables.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.1 Band Tables Index I_fs
#include "BandIndexTables.hpp"
// LC3 Specification d09r01.pdf; Page 86 of 177
// LC3 Specification Section 3.7.2 (d09r04_*implementorComments*)
// Page 115 of 256
// Band tables index I_fs for 10 ms frame duration
int I_8000[65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,80};
int I_16000[65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,32,34,36,38,40,42,44,46,48,50,52,55,58,61,64,67,70,73,76,80,84,88,92,96,101,106,111,116,121,127,133,139,146,153,160};
int I_24000[65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,25,27,29,31,33,35,37,39,41,43,46,49,52,55,58,61,64,68,72,76,80,85,90,95,100,106,112,118,125,132,139,147,155,164,173,183,193,204,215,227,240};
int I_32000[65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,24,26,28,30,32,34,36,38,41,44,47,50,53,56,60,64,68,72,76,81,86,91,97,103,109,116,123,131,139,148,157,166,176,187,199,211,224,238,252,268,284,302,320};
int I_48000[65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36,39,42,45,48,51,55,59,63,67,71,76,81,86,92,98,105,112,119,127,135,144,154,164,175,186,198,211,225,240,256,273,291,310,330,352,375,400};
// LC3 Specification Section 3.7.2 (d09r04_*implementorComments*)
// Page 115/116 of 256
// Band tables index I_fs for 7.5 ms frame duration
int I_8000_7p5ms[61] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60};
int I_16000_7p5ms [65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,65,68,71,74,77,80,83,86,90,94,98,102,106,110,115,120};
int I_24000_7p5ms [65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,31,33,35,37,39,41,43,45,47,49,52,55,58,61,64,67,70,74,78,82,86,90,95,100,105,110,115,121,127,134,141,148,155,163,171,180};
int I_32000_7p5ms [65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,26,28,30,32,34,36,38,40,42,45,48,51,54,57,60,63,67,71,75,79,84,89,94,99,105,111,117,124,131,138,146,154,163,172,182,192,203,215,227,240};
int I_48000_7p5ms [65] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,26,28,30,32,34,36,38,40,43,46,49,52,55,59,63,67,71,75,80,85,90,96,102,108,115,122,129,137,146,155,165,175,186,197,209,222,236,251,266,283,300};

View File

@ -1,43 +0,0 @@
/*
* BandIndexTables.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BAND_INDEX_TABLES_H_
#define BAND_INDEX_TABLES_H_
// LC3 Specification d09r01.pdf
// Section 5.7.1 Band Tables Index I_fs
// LC3 Specification d09r04_*implementorComments*
// Section 3.7.1 Band tables index I_fs for 10 ms frame duration
extern int I_8000[65];
extern int I_16000[65];
extern int I_24000[65];
extern int I_32000[65];
extern int I_48000[65];
// LC3 Specification d09r04_*implementorComments*
// Section 3.7.2 Band tables index I_fs for 7.5 ms frame duration
extern int I_8000_7p5ms[61];
extern int I_16000_7p5ms [65];
extern int I_24000_7p5ms [65];
extern int I_32000_7p5ms [65];
extern int I_48000_7p5ms [65];
#endif // BAND_INDEX_TABLES_H_

View File

@ -1,176 +0,0 @@
/*
* LongTermPostfilterCoefficients.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.5 Long Term Postfiltering
#include "LongTermPostfilterCoefficients.hpp"
// LC3 Specification d09r01.pdf; Page 110 of 177
double tab_resamp_filter[239] = {
-2.043055832879108e-05, -4.463458936757081e-05, -7.163663994481459e-05,
-1.001011132655914e-04, -1.283728480660395e-04, -1.545438297704662e-04,
-1.765445671257668e-04, -1.922569599584802e-04, -1.996438192500382e-04,
-1.968886856400547e-04, -1.825383318834690e-04, -1.556394266046803e-04,
-1.158603651792638e-04, -6.358930335348977e-05, +2.810064795067786e-19,
+7.292180213001337e-05, +1.523970757644272e-04, +2.349207769898906e-04,
+3.163786496265269e-04, +3.922117380894736e-04, +4.576238491064392e-04,
+5.078242936704864e-04, +5.382955231045915e-04, +5.450729176175875e-04,
+5.250221548270982e-04, +4.760984242947349e-04, +3.975713799264791e-04,
+2.902002172907180e-04, +1.563446669975615e-04, -5.818801416923580e-19,
-1.732527127898052e-04, -3.563859653300760e-04, -5.411552308801147e-04,
-7.184140229675020e-04, -8.785052315963854e-04, -1.011714513697282e-03,
-1.108767055632304e-03, -1.161345220483996e-03, -1.162601694464620e-03,
-1.107640974148221e-03, -9.939415631563015e-04, -8.216921898513225e-04,
// LC3 Specification d09r01.pdf; Page 111 of 177
-5.940177657925908e-04, -3.170746535382728e-04, +9.746950818779534e-19,
+3.452937604228947e-04, +7.044808705458705e-04, +1.061334465662964e-03,
+1.398374734488549e-03, +1.697630799350524e-03, +1.941486748731660e-03,
+2.113575906669355e-03, +2.199682452179964e-03, +2.188606246517629e-03,
+2.072945458973295e-03, +1.849752491313908e-03, +1.521021876908738e-03,
+1.093974255016849e-03, +5.811080624426164e-04, -1.422482656398999e-18,
-6.271537303228204e-04, -1.274251404913447e-03, -1.912238389850182e-03,
-2.510269249380764e-03, -3.037038298629825e-03, -3.462226871101535e-03,
-3.758006719596473e-03, -3.900532466948409e-03, -3.871352309895838e-03,
-3.658665583679722e-03, -3.258358512646846e-03, -2.674755551508349e-03,
-1.921033054368456e-03, -1.019254326838640e-03, +1.869623690895593e-18,
+1.098415446732263e-03, +2.231131973532823e-03, +3.348309272768835e-03,
+4.397022774386510e-03, +5.323426722644900e-03, +6.075105310368700e-03,
+6.603520247552113e-03, +6.866453987193027e-03, +6.830342695906946e-03,
+6.472392343549424e-03, +5.782375213956374e-03, +4.764012726389739e-03,
+3.435863514113467e-03, +1.831652835406657e-03, -2.251898372838663e-18,
-1.996476188279370e-03, -4.082668858919100e-03, -6.173080374929424e-03,
-8.174448945974208e-03, -9.988823864332691e-03, -1.151698705819990e-02,
-1.266210056063963e-02, -1.333344579518481e-02, -1.345011199343934e-02,
-1.294448809639154e-02, -1.176541543002924e-02, -9.880867320401294e-03,
-7.280036402392082e-03, -3.974730209151807e-03, +2.509617777250391e-18,
+4.586044219717467e-03, +9.703248998383679e-03, +1.525124770818010e-02,
+2.111205854013017e-02, +2.715337236094137e-02, +3.323242450843114e-02,
+3.920032029020130e-02, +4.490666443426786e-02, +5.020433088017846e-02,
+5.495420172681558e-02, +5.902970324375908e-02, +6.232097270672976e-02,
+6.473850225260731e-02, +6.621612450840858e-02, +6.671322871619612e-02,
+6.621612450840858e-02, +6.473850225260731e-02, +6.232097270672976e-02,
+5.902970324375908e-02, +5.495420172681558e-02, +5.020433088017846e-02,
+4.490666443426786e-02, +3.920032029020130e-02, +3.323242450843114e-02,
+2.715337236094137e-02, +2.111205854013017e-02, +1.525124770818010e-02,
+9.703248998383679e-03, +4.586044219717467e-03, +2.509617777250391e-18,
-3.974730209151807e-03, -7.280036402392082e-03, -9.880867320401294e-03,
-1.176541543002924e-02, -1.294448809639154e-02, -1.345011199343934e-02,
-1.333344579518481e-02, -1.266210056063963e-02, -1.151698705819990e-02,
-9.988823864332691e-03, -8.174448945974208e-03, -6.173080374929424e-03,
-4.082668858919100e-03, -1.996476188279370e-03, -2.251898372838663e-18,
+1.831652835406657e-03, +3.435863514113467e-03, +4.764012726389739e-03,
+5.782375213956374e-03, +6.472392343549424e-03, +6.830342695906946e-03,
+6.866453987193027e-03, +6.603520247552113e-03, +6.075105310368700e-03,
+5.323426722644900e-03, +4.397022774386510e-03, +3.348309272768835e-03,
+2.231131973532823e-03, +1.098415446732263e-03, +1.869623690895593e-18,
-1.019254326838640e-03, -1.921033054368456e-03, -2.674755551508349e-03,
-3.258358512646846e-03, -3.658665583679722e-03, -3.871352309895838e-03,
-3.900532466948409e-03, -3.758006719596473e-03, -3.462226871101535e-03,
-3.037038298629825e-03, -2.510269249380764e-03, -1.912238389850182e-03,
-1.274251404913447e-03, -6.271537303228204e-04, -1.422482656398999e-18,
+5.811080624426164e-04, +1.093974255016849e-03, +1.521021876908738e-03,
+1.849752491313908e-03, +2.072945458973295e-03, +2.188606246517629e-03,
+2.199682452179964e-03, +2.113575906669355e-03, +1.941486748731660e-03,
+1.697630799350524e-03, +1.398374734488549e-03, +1.061334465662964e-03,
+7.044808705458705e-04, +3.452937604228947e-04, +9.746950818779534e-19,
-3.170746535382728e-04, -5.940177657925908e-04, -8.216921898513225e-04,
-9.939415631563015e-04, -1.107640974148221e-03, -1.162601694464620e-03,
-1.161345220483996e-03, -1.108767055632304e-03, -1.011714513697282e-03,
-8.785052315963854e-04, -7.184140229675020e-04, -5.411552308801147e-04,
-3.563859653300760e-04, -1.732527127898052e-04, -5.818801416923580e-19,
// LC3 Specification d09r01.pdf; Page 112 of 177
+1.563446669975615e-04, +2.902002172907180e-04, +3.975713799264791e-04,
+4.760984242947349e-04, +5.250221548270982e-04, +5.450729176175875e-04,
+5.382955231045915e-04, +5.078242936704864e-04, +4.576238491064392e-04,
+3.922117380894736e-04, +3.163786496265269e-04, +2.349207769898906e-04,
+1.523970757644272e-04, +7.292180213001337e-05, +2.810064795067786e-19,
-6.358930335348977e-05, -1.158603651792638e-04, -1.556394266046803e-04,
-1.825383318834690e-04, -1.968886856400547e-04, -1.996438192500382e-04,
-1.922569599584802e-04, -1.765445671257668e-04, -1.545438297704662e-04,
-1.283728480660395e-04, -1.001011132655914e-04, -7.163663994481459e-05,
-4.463458936757081e-05, -2.043055832879108e-05};
double tab_ltpf_interp_R[31] = {
-2.874561161519444e-03, -3.001251025861499e-03, +2.745471654059321e-03,
+1.535727698935322e-02, +2.868234046665657e-02, +2.950385026557377e-02,
+4.598334491135473e-03, -4.729632459043440e-02, -1.058359163062837e-01,
-1.303050213607112e-01, -7.544046357555201e-02, +8.357885725250529e-02,
+3.301825710764459e-01, +6.032970076366158e-01, +8.174886856243178e-01,
+8.986382851273982e-01, +8.174886856243178e-01, +6.032970076366158e-01,
+3.301825710764459e-01, +8.357885725250529e-02, -7.544046357555201e-02,
-1.303050213607112e-01, -1.058359163062837e-01, -4.729632459043440e-02,
+4.598334491135473e-03, +2.950385026557377e-02, +2.868234046665657e-02,
+1.535727698935322e-02, +2.745471654059321e-03, -3.001251025861499e-03,
-2.874561161519444e-03};
double tab_ltpf_interp_x12k8[15] = {
+6.698858366939680e-03, +3.967114782344967e-02, +1.069991860896389e-01,
+2.098804630681809e-01, +3.356906254147840e-01, +4.592209296082350e-01,
+5.500750019177116e-01, +5.835275754221211e-01, +5.500750019177116e-01,
+4.592209296082350e-01, +3.356906254147840e-01, +2.098804630681809e-01,
+1.069991860896389e-01, +3.967114782344967e-02, +6.698858366939680e-03};
double tab_ltpf_num_8000[4][3] = {
{6.023618207009578e-01,4.197609261363617e-01,-1.883424527883687e-02},
{5.994768582584314e-01,4.197609261363620e-01,-1.594928283631041e-02},
{5.967764663733787e-01,4.197609261363617e-01,-1.324889095125780e-02},
{5.942410120098895e-01,4.197609261363618e-01,-1.071343658776831e-02}};
double tab_ltpf_num_16000[4][3] = {
{6.023618207009578e-01,4.197609261363617e-01,-1.883424527883687e-02},
{5.994768582584314e-01,4.197609261363620e-01,-1.594928283631041e-02},
{5.967764663733787e-01,4.197609261363617e-01,-1.324889095125780e-02},
{5.942410120098895e-01,4.197609261363618e-01,-1.071343658776831e-02}};
double tab_ltpf_num_24000[4][5] = {
{3.989695588963494e-01,5.142508607708275e-01,1.004382966157454e-01,-1.278893956818042e-02,-1.572280075461383e-03},
{3.948634911286333e-01,5.123819208048688e-01,1.043194926386267e-01,-1.091999960222166e-02,-1.347408330627317e-03},
{3.909844475885914e-01,5.106053522688359e-01,1.079832524685944e-01,-9.143431066188848e-03,-1.132124620551895e-03},
{3.873093888199928e-01,5.089122083363975e-01,1.114517380217371e-01,-7.450287133750717e-03,-9.255514050963111e-04}};
double tab_ltpf_num_32000[4][7] = {
// LC3 Specification d09r01.pdf; Page 113 of 177
{2.982379446702096e-01,4.652809203721290e-01,2.105997428614279e-01,3.766780380806063e-02,-1.015696155796564e-02,-2.535880996101096e-03,-3.182946168719958e-04},
{2.943834154510240e-01,4.619294002718798e-01,2.129465770091844e-01,4.066175002688857e-02,-8.693272297010050e-03,-2.178307114679820e-03,-2.742888063983188e-04},
{2.907439213122688e-01,4.587461910960279e-01,2.151456974108970e-01,4.350104772529774e-02,-7.295495347716925e-03,-1.834395637237086e-03,-2.316920186482416e-04},
{2.872975852589158e-01,4.557148886861379e-01,2.172126950911401e-01,4.620088878229615e-02,-5.957463802125952e-03,-1.502934284345198e-03,-1.903851911308866e-04}};
double tab_ltpf_num_48000[4][11] = {
{1.981363739883217e-01,3.524494903964904e-01,2.513695269649414e-01,1.424146237314458e-01,5.704731023952599e-02,9.293366241586384e-03,-7.226025368953745e-03,-3.172679890356356e-03,-1.121835963567014e-03,-2.902957238400140e-04,-4.270815593769240e-05},
{1.950709426598375e-01,3.484660408341632e-01,2.509988459466574e-01,1.441167412482088e-01,5.928947317677285e-02,1.108923827452231e-02,-6.192908108653504e-03,-2.726705509251737e-03,-9.667125826217151e-04,-2.508100923165204e-04,-3.699938766131869e-05},
{1.921810055196015e-01,3.446945561091513e-01,2.506220094626024e-01,1.457102447664837e-01,6.141132133664525e-02,1.279941396562798e-02,-5.203721087886321e-03,-2.297324511109085e-03,-8.165608133217555e-04,-2.123855748277408e-04,-3.141271330981649e-05},
{1.894485314175868e-01,3.411139251108252e-01,2.502406876894361e-01,1.472065631098081e-01,6.342477229539051e-02,1.443203434150312e-02,-4.254449144657098e-03,-1.883081472613493e-03,-6.709619060722140e-04,-1.749363341966872e-04,-2.593864735284285e-05}};
double tab_ltpf_den_8000[4][5] = {
{0.000000000000000e+00, 2.098804630681809e-01, 5.835275754221211e-01, 2.098804630681809e-01, 0.000000000000000e+00},
{0.000000000000000e+00, 1.069991860896389e-01, 5.500750019177116e-01, 3.356906254147840e-01, 6.698858366939680e-03},
{0.000000000000000e+00, 3.967114782344967e-02, 4.592209296082350e-01, 4.592209296082350e-01, 3.967114782344967e-02},
{0.000000000000000e+00, 6.698858366939680e-03, 3.356906254147840e-01, 5.500750019177116e-01, 1.069991860896389e-01}};
double tab_ltpf_den_16000[4][5] = {
{0.000000000000000e+00, 2.098804630681809e-01, 5.835275754221211e-01, 2.098804630681809e-01, 0.000000000000000e+00},
{0.000000000000000e+00, 1.069991860896389e-01, 5.500750019177116e-01, 3.356906254147840e-01, 6.698858366939680e-03},
{0.000000000000000e+00, 3.967114782344967e-02, 4.592209296082350e-01, 4.592209296082350e-01, 3.967114782344967e-02},
{0.000000000000000e+00, 6.698858366939680e-03, 3.356906254147840e-01, 5.500750019177116e-01, 1.069991860896389e-01}};
double tab_ltpf_den_24000[4][7] = {
{0.000000000000000e+00, 6.322231627323796e-02, 2.507309606013235e-01, 3.713909428901578e-01, 2.507309606013235e-01, 6.322231627323796e-02, 0.000000000000000e+00},
// LC3 Specification d09r01.pdf; Page 114 of 177
{0.000000000000000e+00, 3.459272174099855e-02, 1.986515602645028e-01, 3.626411726581452e-01, 2.986750548992179e-01, 1.013092873505928e-01, 4.263543712369752e-03},
{0.000000000000000e+00, 1.535746784963907e-02, 1.474344878058222e-01, 3.374259553990717e-01, 3.374259553990717e-01, 1.474344878058222e-01, 1.535746784963907e-02},
{0.000000000000000e+00, 4.263543712369752e-03, 1.013092873505928e-01, 2.986750548992179e-01, 3.626411726581452e-01, 1.986515602645028e-01, 3.459272174099855e-02}};
double tab_ltpf_den_32000[4][9] = {
{0.000000000000000e+00, 2.900401878228730e-02, 1.129857420560927e-01, 2.212024028097570e-01, 2.723909472446145e-01, 2.212024028097570e-01, 1.129857420560927e-01, 2.900401878228730e-02, 0.000000000000000e+00},
{0.000000000000000e+00, 1.703153418385261e-02, 8.722503785537784e-02, 1.961407762232199e-01, 2.689237982237257e-01, 2.424999102756389e-01, 1.405773364650031e-01, 4.474877169485788e-02, 3.127030243100724e-03},
{0.000000000000000e+00, 8.563673748488349e-03, 6.426222944493845e-02, 1.687676705918012e-01, 2.587445937795505e-01, 2.587445937795505e-01, 1.687676705918012e-01, 6.426222944493845e-02, 8.563673748488349e-03},
{0.000000000000000e+00, 3.127030243100724e-03, 4.474877169485788e-02, 1.405773364650031e-01, 2.424999102756389e-01, 2.689237982237257e-01, 1.961407762232199e-01, 8.722503785537784e-02, 1.703153418385261e-02}};
double tab_ltpf_den_48000[4][13] = {
{0.000000000000000e+00, 1.082359386659387e-02, 3.608969221303979e-02, 7.676401468099964e-02, 1.241530577501703e-01, 1.627596438300696e-01, 1.776771417779109e-01, 1.627596438300696e-01, 1.241530577501703e-01, 7.676401468099964e-02, 3.608969221303979e-02, 1.082359386659387e-02, 0.000000000000000e+00},
{0.000000000000000e+00, 7.041404930459358e-03, 2.819702319820420e-02, 6.547044935127551e-02, 1.124647986743299e-01, 1.548418956489015e-01, 1.767122381341857e-01, 1.691507213057663e-01, 1.352901577989766e-01, 8.851425011427483e-02, 4.499353848562444e-02, 1.557613714732002e-02, 2.039721956502016e-03},
{0.000000000000000e+00, 4.146998467444788e-03, 2.135757310741917e-02, 5.482735584552816e-02, 1.004971444643720e-01, 1.456060342830002e-01, 1.738439838565869e-01, 1.738439838565869e-01, 1.456060342830002e-01, 1.004971444643720e-01, 5.482735584552816e-02, 2.135757310741917e-02, 4.146998467444788e-03},
{0.000000000000000e+00, 2.039721956502016e-03, 1.557613714732002e-02, 4.499353848562444e-02, 8.851425011427483e-02, 1.352901577989766e-01, 1.691507213057663e-01, 1.767122381341857e-01, 1.548418956489015e-01, 1.124647986743299e-01, 6.547044935127551e-02, 2.819702319820420e-02, 7.041404930459358e-03}};

View File

@ -1,39 +0,0 @@
/*
* LongTermPostfilterCoefficients.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.5 Long Term Postfiltering
#ifndef LONG_TERM_POSTFILTER_COEFFICIENTS_H_
#define LONG_TERM_POSTFILTER_COEFFICIENTS_H_
extern double tab_resamp_filter[239];
extern double tab_ltpf_interp_R[31];
extern double tab_ltpf_interp_x12k8[15];
extern double tab_ltpf_num_8000[4][3];
extern double tab_ltpf_num_16000[4][3];
extern double tab_ltpf_num_24000[4][5];
extern double tab_ltpf_num_32000[4][7];
extern double tab_ltpf_num_48000[4][11];
extern double tab_ltpf_den_8000[4][5];
extern double tab_ltpf_den_16000[4][5];
extern double tab_ltpf_den_24000[4][7];
extern double tab_ltpf_den_32000[4][9];
extern double tab_ltpf_den_48000[4][13];
#endif // LONG_TERM_POSTFILTER_COEFFICIENTS_H_

File diff suppressed because one or more lines are too long

View File

@ -1,45 +0,0 @@
/*
* MdctWindows.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MDCT_WINDOWS_H_
#define MDCT_WINDOWS_H_
// LC3 Specification d09r01.pdf
// Section 5.7.2
// LC3 Specification d09r04_*implementorComments*
// Section 3.7.3 Low delay MDCT windows
// Section 3.7.3.1 10 ms Frame Duration
extern double w_N80[160];
extern double w_N160[320];
extern double w_N240[480];
extern double w_N320[640];
extern double w_N480[960];
// Section 3.7.3.2 7.5 ms Frame Duration
extern double w_N60_7p5ms[120];
extern double w_N120_7p5ms[240];
extern double w_N180_7p5ms[360];
extern double w_N240_7p5ms[480];
extern double w_N360_7p5ms[720];
#endif // MDCT_WINDOWS_H_

View File

@ -1,355 +0,0 @@
/*
* SnsQuantizationTables.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.3 SNS Quantization
// LC3 Specification d09r04_*implementorComments*
// Section 3.7.4 SNS Quantization
#include "SnsQuantizationTables.hpp"
// LC3 Specification d09r01.pdf; Page 102 of 177
double LFCB[32][8] = {{ +2.262833655926780e+00, +8.133112690613385e-01, -5.301934948714359e-01,
-1.356648359034418e+00, -1.599521765631959e+00, -1.440987684300950e+00,
-1.143816483058210e+00, -7.552037679090641e-01}, //0
{+2.945164791913764e+00, +2.411433179566788e+00, +9.604551064007274e-01,
-4.432264880769172e-01, -1.229136124255896e+00, -1.555900391181699e+00,
-1.496886559523759e+00, -1.116899865014692e+00}, //1
{-2.186107070099790e+00, -1.971521356752276e+00, -1.787186196810059e+00,
-1.918658956855768e+00, -1.793991218365963e+00, -1.357384042572884e+00,
-7.054442793538694e-01, -4.781729447777114e-02}, //2
{+6.936882365289195e-01, +9.556098571582197e-01, +5.752307870387333e-01,
-1.146034194628886e-01, -6.460506374360290e-01, -9.523513704496247e-01,
-1.074052472261504e+00, -7.580877070949045e-01}, //3
{-1.297521323152956e+00, -7.403690571778526e-01, -3.453724836421064e-01,
-3.132856962479401e-01, -4.029772428244766e-01, -3.720208534652272e-01,
-7.834141773237381e-02, +9.704413039922949e-02}, //4
{+9.146520378306716e-01, +1.742930434352573e+00, +1.909066268599861e+00,
+1.544084838426651e+00, +1.093449607614550e+00, +6.474795495182776e-01,
+3.617907524496421e-02, -2.970928071788889e-01}, //5
{-2.514288125789621e+00, -2.891752713843728e+00, -2.004506667594338e+00,
-7.509122739031269e-01, +4.412021049046914e-01, +1.201909876010087e+00,
+1.327428572572904e+00, +1.220490811409839e+00}, //6
{-9.221884048123851e-01, +6.324951414405520e-01, +1.087364312546411e+00,
+6.086286245358197e-01, +1.311745675473482e-01, -2.961491577437521e-01,
-2.070135165256287e-01, +1.349249166420795e-01}, //7
{+7.903222883692664e-01, +6.284012618761988e-01, +3.931179235404499e-01,
+4.800077108669007e-01, +4.478151380501427e-01, +2.097342145522343e-01,
+6.566919964280205e-03, -8.612423420618573e-02}, //8
// LC3 Specification d09r01.pdf; Page 103 of 177
{+1.447755801787238e+00, +2.723999516749523e+00, +2.310832687375278e+00,
+9.350512695665294e-01, -2.747439113836877e-01, -9.020776968286019e-01,
-9.406815119454044e-01, -6.336970389743102e-01}, //9
{+7.933545264174744e-01, +1.439311855234535e-02, -5.678348447296789e-01,
-6.547604679167449e-01, -4.794589984757430e-01, -1.738946619028885e-01,
+6.801627055154381e-02, +2.951259483697938e-01}, //10
{+2.724253473850336e+00, +2.959475724048243e+00, +1.849535592684608e+00,
+5.632849223223643e-01, +1.399170881250724e-01, +3.596410933662221e-01,
+6.894613547745887e-01, +6.397901768331046e-01}, //11
{-5.308301983754000e-01, -2.126906828121638e-01, +5.766136283770966e-03,
+4.248714843837454e-01, +4.731289521586675e-01, +8.588941993212806e-01,
+1.191111608544352e+00, +9.961896696383581e-01}, //12
{+1.687284108450062e+00, +2.436145092376558e+00, +2.330194290782250e+00,
+1.779837778350905e+00, +1.444112953900818e+00, +1.519951770097301e+00,
+1.471993937504249e+00, +9.776824738917613e-01}, //13
{-2.951832728018580e+00, -1.593934967733454e+00, -1.099187728780224e-01,
+3.886090729192574e-01, +5.129326495175837e-01, +6.281125970634966e-01,
+8.226217964306339e-01, +8.758914246550805e-01}, //14
{+1.018783427856281e-01, +5.898573242289165e-01, +6.190476467934656e-01,
+1.267313138517963e+00, +2.419610477698038e+00, +2.251742525721865e+00,
+5.265370309912005e-01, -3.965915132279989e-01}, //15
{+2.682545754984259e+00, +1.327380108994199e+00, +1.301852738040482e-01,
-3.385330885113471e-01, -3.682192358996665e-01, -1.916899467159607e-01,
-1.547823771539079e-01, -2.342071777743923e-01}, //16
{+4.826979236804030e+00, +3.119478044924880e+00, +1.395136713851784e+00,
+2.502953159187215e-01, -3.936138393797931e-01, -6.434581730547007e-01,
-6.425707368569433e-01, -7.231932234440720e-01}, //17
{+8.784199364703349e-02, -5.695868402385010e-01, -1.145060156688110e+00,
-1.669684881725975e+00, -1.845344176036817e+00, -1.564680273288019e+00,
-1.117467590764198e+00, -5.339816633667862e-01}, //18
{+1.391023082043259e+00, +1.981464791994655e+00, +1.112657963887701e+00,
-2.201075094207434e-01, -7.749656115523655e-01, -5.940638741491173e-01,
+1.369376806289231e-01, +8.182428912643381e-01}, //19
{+3.845858938891820e-01, -1.605887855365100e-01, -5.393668095577095e-01,
-5.293090787898571e-01, +1.904335474379324e-01, +2.560629181065215e+00,
+2.818963982452484e+00, +6.566708756961611e-01}, //20
{+1.932273994417191e+00, +3.010301804120569e+00, +3.065438938262036e+00,
+2.501101608700079e+00, +1.930895929789344e+00, +5.721538109618367e-01,
-8.117417940810907e-01, -1.176418108619025e+00}, //21
{+1.750804628998837e-01, -7.505228322489846e-01, -1.039438933422309e+00,
-1.135775089376484e+00, -1.041979038374938e+00, -1.520600989933816e-02,
+2.070483917167066e+00, +3.429489180816891e+00}, //22
// LC3 Specification d09r01.pdf; Page 104 of 177
{-1.188170202505555e+00, +3.667928736626364e-01, +1.309578304090959e+00,
+1.683306872804914e+00, +1.251009242251268e+00, +9.423757516286146e-01,
+8.262504833741330e-01, +4.399527411209563e-01}, //23
{+2.533222033270612e+00, +2.112746426959081e+00, +1.262884115020644e+00,
+7.615135124304274e-01, +5.221179379761699e-01, +1.186800697571213e-01,
-4.523468275073703e-01, -7.003524261611032e-01}, //24
{+3.998898374856063e+00, +4.079017514519560e+00, +2.822856611024964e+00,
+1.726072128495800e+00, +6.471443773486192e-01, -3.311485212172380e-01,
-8.840425708487493e-01, -1.126973406454781e+00}, //25
{+5.079025931863813e-01, +1.588384497895265e+00, +1.728990238692094e+00,
+1.006922302417256e+00, +3.771212318163816e-01, +4.763707668994976e-01,
+1.087547403721699e+00, +1.087562660992209e+00}, //26
{+3.168568251075689e+00, +3.258534581594065e+00, +2.422305913285988e+00,
+1.794460776432612e+00, +1.521779106530886e+00, +1.171967065376021e+00,
+4.893945969806952e-01, -6.227957157187685e-02}, //27
{+1.894147667317636e+00, +1.251086946092320e+00, +5.904512107206275e-01,
+6.083585832937136e-01, +8.781710100110816e-01, +1.119125109509496e+00,
+1.018576615503421e+00, +6.204538910117241e-01}, //28
{+9.488806045171881e-01, +2.132394392499823e+00, +2.723453503442780e+00,
+2.769860768665877e+00, +2.542869732549456e+00, +2.020462638250194e+00,
+8.300458594009102e-01, -2.755691738882634e-02}, //29
{-1.880267570456275e+00, -1.264310727587049e+00, +3.114249769686986e-01,
+1.836702103064300e+00, +2.256341918398738e+00, +2.048189984634735e+00,
+2.195268374585677e+00, +2.026596138366193e+00}, //30
{+2.463757462771289e-01, +9.556217733930993e-01, +1.520467767417663e+00,
+1.976474004194571e+00, +1.940438671774617e+00, +2.233758472826862e+00,
+1.988359777584072e+00, +1.272326725547010e+00 }}; //31
double HFCB[32][8] = {
{+2.320284191244650e-01, -1.008902706044547e+00, -2.142235027894714e+00,
-2.375338135706641e+00, -2.230419330496551e+00, -2.175958812236960e+00,
-2.290659135409999e+00, -2.532863979798455e+00}, //0
{-1.295039366736175e+00, -1.799299653843385e+00, -1.887031475315188e+00,
-1.809916596873323e+00, -1.763400384792061e+00, -1.834184284679500e+00,
-1.804809806874051e+00, -1.736795453174010e+00}, //1
{+1.392857160458027e-01, -2.581851261717519e-01, -6.508045726701103e-01,
-1.068157317819692e+00, -1.619287415243023e+00, -2.187625664417564e+00,
-2.637575869390537e+00, -2.978977495750963e+00}, //2
{-3.165131021857248e-01, -4.777476572098050e-01, -5.511620758797545e-01,
-4.847882833811970e-01, -2.383883944558142e-01, -1.430245072855038e-01,
+6.831866736490735e-02, +8.830617172880660e-02}, //3
{+8.795184052264962e-01, +2.983400960071886e-01, -9.153863964057101e-01,
// LC3 Specification d09r01.pdf; Page 105 of 177
-2.206459747397620e+00, -2.741421809599509e+00, -2.861390742768913e+00,
-2.888415971052714e+00, -2.951826082625207e+00}, //4
{-2.967019224553751e-01, -9.750049191745525e-01, -1.358575002469926e+00,
-9.837211058374442e-01, -6.529569391008090e-01, -9.899869929218105e-01,
-1.614672245988999e+00, -2.407123023851163e+00}, //5
{+3.409811004696971e-01, +2.688997889460545e-01, +5.633356848280326e-02,
+4.991140468266853e-02, -9.541307274143691e-02, -7.601661460838854e-01,
-2.327581201770068e+00, -3.771554853856562e+00}, //6
{-1.412297590775968e+00, -1.485221193498518e+00, -1.186035798347001e+00,
-6.250016344413516e-01, +1.539024974683036e-01, +5.763864978107553e-01,
+7.950926037988714e-01, +5.965646321449126e-01}, //7
{-2.288395118273794e-01, -3.337190697846616e-01, -8.093213593246560e-01,
-1.635878769237973e+00, -1.884863973309819e+00, -1.644966913163562e+00,
-1.405157780466116e+00, -1.466664713261457e+00}, //8
{-1.071486285444486e+00, -1.417670154562606e+00, -1.548917622654407e+00,
-1.452960624755303e+00, -1.031829700622701e+00, -6.906426402725842e-01,
-4.288438045321706e-01, -4.949602154088736e-01}, //9
{-5.909885111880511e-01, -7.117377585376282e-02, +3.457195229473127e-01,
+3.005494609962507e-01, -1.118652182958568e+00, -2.440891511480490e+00,
-2.228547324507349e+00, -1.895092282108533e+00}, //10
{-8.484340988361639e-01, -5.832268107088888e-01, +9.004236881428734e-02,
+8.450250075568864e-01, +1.065723845017161e+00, +7.375829993777555e-01,
+2.565904524599121e-01, -4.919633597623784e-01}, //11
{+1.140691455623824e+00, +9.640168923982929e-01, +3.814612059847975e-01,
-4.828493406089983e-01, -1.816327212605887e+00, -2.802795127285548e+00,
-3.233857248338638e+00, -3.459087144914729e+00}, //12
{-3.762832379674643e-01, +4.256754620961052e-02, +5.165476965923055e-01,
+2.517168818646298e-01, -2.161799675243032e-01, -5.340740911245042e-01,
-6.407860962621957e-01, -8.697450323741350e-01}, //13
{+6.650041205984020e-01, +1.097907646907945e+00, +1.383426671120792e+00,
+1.343273586282854e+00, +8.229788368559223e-01, +2.158767985156789e-01,
-4.049257530802925e-01, -1.070256058705229e+00}, //14
{-8.262659539826793e-01, -6.711812327666034e-01, -2.284955927794715e-01,
+5.189808525519373e-01, +1.367218963402784e+00, +2.180230382530922e+00,
+2.535960927501071e+00, +2.201210988600361e+00}, //15
{+1.410083268321729e+00, +7.544419078354684e-01, -1.305505849586310e+00,
-1.871337113509707e+00, -1.240086851563054e+00, -1.267129248662737e+00,
-2.036708130039070e+00, -2.896851622423807e+00}, //16
{+3.613868175743476e-01, -2.199917054278258e-02, -5.793688336338242e-01,
-8.794279609410701e-01, -8.506850234081188e-01, -7.793970501558157e-01,
-7.321829272918255e-01, -8.883485148212548e-01}, //17
{+4.374692393303287e-01, +3.054404196059607e-01, -7.387865664783739e-03,
// LC3 Specification d09r01.pdf; Page 106 of 177
-4.956498547102520e-01, -8.066512711183929e-01, -1.224318919844005e+00,
-1.701577700431810e+00, -2.244919137556108e+00}, //18
{+6.481003189965029e-01, +6.822991336406795e-01, +2.532474643329756e-01,
+7.358421437884688e-02, +3.142167093890103e-01, +2.347298809236790e-01,
+1.446001344798368e-01, -6.821201788801744e-02}, //19
{+1.119198330913041e+00, +1.234655325360046e+00, +5.891702380853181e-01,
-1.371924596531664e+00, -2.370957072415767e+00, -2.007797826823599e+00,
-1.666885402243946e+00, -1.926318462584058e+00}, //20
{+1.418474970871759e-01, -1.106600706331509e-01, -2.828245925436287e-01,
-6.598134746141936e-03, +2.859292796272158e-01, +4.604455299529710e-02,
-6.025964155778858e-01, -2.265687286325748e+00}, //21
{+5.040469553902519e-01, +8.269821629590972e-01, +1.119812362918282e+00,
+1.179140443327336e+00, +1.079874291972597e+00, +6.975362390675000e-01,
-9.125488173710808e-01, -3.576847470627726e+00}, //22
{-5.010760504793567e-01, -3.256780060814170e-01, +2.807981949470768e-02,
+2.620545547631326e-01, +3.605908060857668e-01, +6.356237220536995e-01,
+9.590124671781544e-01, +1.307451566886533e+00}, //23
{+3.749709827096420e+00, +1.523426118470452e+00, -4.577156618978547e-01,
-7.987110082431923e-01, -3.868193293091003e-01, -3.759010622312032e-01,
-6.578368999305377e-01, -1.281639642436027e+00}, //24
{-1.152589909805491e+00, -1.108008859062412e+00, -5.626151165124718e-01,
-2.205621237656746e-01, -3.498428803366437e-01, -7.534327702504950e-01,
-9.885965933963837e-01, -1.287904717914711e+00}, //25
{+1.028272464221398e+00, +1.097705193898282e+00, +7.686455457647760e-01,
+2.060819777407656e-01, -3.428057350919982e-01, -7.549394046253397e-01,
-1.041961776319998e+00, -1.503356529555287e+00}, //26
{+1.288319717078174e-01, +6.894393952648783e-01, +1.123469050095749e+00,
+1.309345231065936e+00, +1.355119647139345e+00, +1.423113814707990e+00,
+1.157064491909045e+00, +4.063194375168383e-01}, //27
{+1.340330303347565e+00, +1.389968250677893e+00, +1.044679217088833e+00,
+6.358227462443666e-01, -2.747337555184823e-01, -1.549233724306950e+00,
-2.442397102780069e+00, -3.024576069445502e+00}, //28
{+2.138431054193125e+00, +4.247112673031041e+00, +2.897341098304393e+00,
+9.327306580268148e-01, -2.928222497298096e-01, -8.104042968531823e-01,
-7.888680987564828e-01, -9.353531487613377e-01}, //29
{+5.648304873553961e-01, +1.591849779587432e+00, +2.397716990151462e+00,
+3.036973436007040e+00, +2.664243503371508e+00, +1.393044850326060e+00,
+4.038340235957454e-01, -6.562709713281135e-01}, //30
{-4.224605475860865e-01, +3.261496250498011e-01, +1.391713133422612e+00,
+2.231466146364735e+00, +2.611794421696881e+00, +2.665403401965702e+00,
+2.401035541057067e+00, +1.759203796708810e+00} //31
};
// LC3 Specification d09r01.pdf; Page 107 of 177
double sns_vq_reg_adj_gains[2] = {8915.0/4096.0, 12054.0/4096.0};
double sns_vq_reg_lf_adj_gains[4] = {6245.0/4096.0, 15043.0/4096.0, 17861.0/4096.0, 21014.0/4096.0};
double sns_vq_near_adj_gains[4] = {7099.0/4096.0, 9132.0/4096.0, 11253.0/4096.0, 14808.0/4096.0};
double sns_vq_far_adj_gains[8] = {4336.0/4096.0, 5067.0/4096.0, 5895.0/4096.0, 8149.0/4096.0,
10235.0/4096.0, 12825.0/4096.0, 16868.0/4096.0, 19882.0/4096.0};
int sns_gainMSBbits[4]={1,1,2,2};
int sns_gainLSBbits[4]={0,1,0,1};
unsigned int MPVQ_offsets[16][1+10]= { /* k=0, k=1, k=2,... , k=10 */
{0,1,1,1,1,1,1,1,1,1,1}, /* n=0*/
{0,1,3,5,7,9,11,13,15,17,19}, /* n=1*/
{0,1,5,13,25,41,61,85,113,145,181},
{0,1,7,25,63,129,231,377,575,833,1159},
{0,1,9,41,129,321,681,1289,2241,3649,5641},
{0,1,11,61,231,681,1683,3653,7183,13073,22363},
{0,1,13,85,377,1289,3653,8989,19825,40081,75517},
{0,1,15,113,575,2241,7183,19825,48639,108545,224143},
{0,1,17,145,833,3649,13073,40081,108545,265729,598417},
{0,1,19,181,1159,5641,22363,75517,224143,598417,1462563},
{0,1,21,221,1561,8361,36365,134245,433905,1256465,3317445},
{0,1,23,265,2047,11969,56695,227305,795455,2485825,7059735},
{0,1,25,313,2625,16641,85305,369305,1392065,4673345,14218905},
{0,1,27,365,3303,22569,124515,579125,2340495,8405905,27298155},
{0,1,29,421,4089,29961,177045,880685,3800305,14546705,50250765}, /* n=14*/
{0,1,31,481,4991,39041,246047,1303777,5984767,24331777,89129247}, /* n=15*/
};
double D[16][16] = {
/* D consists of the base vectors of the DCT (orthogonalized DCT-II)*/
/* (the DCT base vector are stored in column-wise in this table)*/
/* first row results in the first coeff in fwd synthesis (dec+(enc))*/
/* first column results in the first coeff in the analysis(encoder) */
{+2.500000000000000e-01, +3.518509343815957e-01, +3.467599613305369e-01,
+3.383295002935882e-01, +3.266407412190941e-01, +3.118062532466678e-01,
+2.939689006048397e-01, +2.733004667504394e-01, +2.500000000000001e-01,
+2.242918965856591e-01, +1.964237395967756e-01, +1.666639146194367e-01,
+1.352990250365493e-01, +1.026311318805893e-01, +6.897484482073578e-02,
+3.465429229977293e-02}, // 0 Note: needed a ',' as correction compared to d09r01 (already fixed in d09r02_F2F)
{+2.500000000000000e-01, +3.383295002935882e-01, +2.939689006048397e-01,
+2.242918965856591e-01, +1.352990250365493e-01, +3.465429229977286e-02,
-6.897484482073579e-02, -1.666639146194366e-01, -2.500000000000001e-01,
-3.118062532466678e-01, -3.467599613305369e-01, -3.518509343815956e-01,
-3.266407412190941e-01, -2.733004667504394e-01, -1.964237395967756e-01,
-1.026311318805893e-01}, // 1
// LC3 Specification d09r01.pdf; Page 108 of 177
{+2.500000000000000e-01, +3.118062532466678e-01, +1.964237395967756e-01,
+3.465429229977286e-02, -1.352990250365493e-01, -2.733004667504394e-01,
-3.467599613305369e-01, -3.383295002935882e-01, -2.500000000000001e-01,
-1.026311318805894e-01, +6.897484482073574e-02, +2.242918965856590e-01,
+3.266407412190941e-01, +3.518509343815957e-01, +2.939689006048397e-01,
+1.666639146194367e-01}, // 2
{+2.500000000000000e-01, +2.733004667504394e-01, +6.897484482073575e-02,
-1.666639146194366e-01, -3.266407412190941e-01, -3.383295002935882e-01,
-1.964237395967755e-01, +3.465429229977288e-02, +2.500000000000001e-01,
+3.518509343815957e-01, +2.939689006048397e-01, +1.026311318805893e-01,
-1.352990250365493e-01, -3.118062532466679e-01, -3.467599613305369e-01,
-2.242918965856590e-01}, // 3
{+2.500000000000000e-01, +2.242918965856591e-01, -6.897484482073575e-02,
-3.118062532466678e-01, -3.266407412190941e-01, -1.026311318805894e-01,
+1.964237395967755e-01, +3.518509343815957e-01, +2.500000000000001e-01,
-3.465429229977282e-02, -2.939689006048397e-01, -3.383295002935882e-01,
-1.352990250365493e-01, +1.666639146194367e-01, +3.467599613305369e-01,
+2.733004667504394e-01}, // 4
{+2.500000000000000e-01, +1.666639146194366e-01, -1.964237395967756e-01,
-3.518509343815956e-01, -1.352990250365493e-01, +2.242918965856591e-01,
+3.467599613305369e-01, +1.026311318805894e-01, -2.500000000000001e-01,
-3.383295002935882e-01, -6.897484482073574e-02, +2.733004667504394e-01,
+3.266407412190941e-01, +3.465429229977289e-02, -2.939689006048397e-01,
-3.118062532466677e-01}, // 5
{+2.500000000000000e-01, +1.026311318805894e-01, -2.939689006048397e-01,
-2.733004667504393e-01, +1.352990250365493e-01, +3.518509343815957e-01,
+6.897484482073579e-02, -3.118062532466678e-01, -2.500000000000001e-01,
+1.666639146194366e-01, +3.467599613305369e-01, +3.465429229977293e-02,
-3.266407412190941e-01, -2.242918965856591e-01, +1.964237395967756e-01,
+3.383295002935882e-01}, // 6
{+2.500000000000000e-01, +3.465429229977287e-02, -3.467599613305369e-01,
-1.026311318805893e-01, +3.266407412190941e-01, +1.666639146194366e-01,
-2.939689006048397e-01, -2.242918965856591e-01, +2.500000000000001e-01,
+2.733004667504393e-01, -1.964237395967756e-01, -3.118062532466678e-01,
+1.352990250365493e-01, +3.383295002935882e-01, -6.897484482073578e-02,
-3.518509343815956e-01}, // 7
{+2.500000000000000e-01, -3.465429229977287e-02, -3.467599613305369e-01,
+1.026311318805893e-01, +3.266407412190941e-01, -1.666639146194366e-01,
-2.939689006048397e-01, +2.242918965856591e-01, +2.500000000000001e-01,
-2.733004667504393e-01, -1.964237395967756e-01, +3.118062532466678e-01,
+1.352990250365493e-01, -3.383295002935882e-01, -6.897484482073578e-02,
+3.518509343815956e-01}, // 8
{+2.500000000000000e-01, -1.026311318805894e-01, -2.939689006048397e-01,
+2.733004667504393e-01, +1.352990250365493e-01, -3.518509343815957e-01,
+6.897484482073579e-02, +3.118062532466678e-01, -2.500000000000001e-01,
-1.666639146194366e-01, +3.467599613305369e-01, -3.465429229977293e-02,
-3.266407412190941e-01, +2.242918965856591e-01, +1.964237395967756e-01,
-3.383295002935882e-01}, // 9
// LC3 Specification d09r01.pdf; Page 109 of 177
{+2.500000000000000e-01, -1.666639146194366e-01, -1.964237395967756e-01,
+3.518509343815956e-01, -1.352990250365493e-01, -2.242918965856591e-01,
+3.467599613305369e-01, -1.026311318805894e-01, -2.500000000000001e-01,
+3.383295002935882e-01, -6.897484482073574e-02, -2.733004667504394e-01,
+3.266407412190941e-01, -3.465429229977289e-02, -2.939689006048397e-01,
+3.118062532466677e-01}, // 10
{+2.500000000000000e-01, -2.242918965856591e-01, -6.897484482073575e-02,
+3.118062532466678e-01, -3.266407412190941e-01, +1.026311318805894e-01,
+1.964237395967755e-01, -3.518509343815957e-01, +2.500000000000001e-01,
+3.465429229977282e-02, -2.939689006048397e-01, +3.383295002935882e-01,
-1.352990250365493e-01, -1.666639146194367e-01, +3.467599613305369e-01,
-2.733004667504394e-01}, // 11
{+2.500000000000000e-01, -2.733004667504394e-01, +6.897484482073575e-02,
+1.666639146194366e-01, -3.266407412190941e-01, +3.383295002935882e-01,
-1.964237395967755e-01, -3.465429229977288e-02, +2.500000000000001e-01,
-3.518509343815957e-01, +2.939689006048397e-01, -1.026311318805893e-01,
-1.352990250365493e-01, +3.118062532466679e-01, -3.467599613305369e-01,
+2.242918965856590e-01}, // 12
{+2.500000000000000e-01, -3.118062532466678e-01, +1.964237395967756e-01,
-3.465429229977286e-02, -1.352990250365493e-01, +2.733004667504394e-01,
-3.467599613305369e-01, +3.383295002935882e-01, -2.500000000000001e-01,
+1.026311318805894e-01, +6.897484482073574e-02, -2.242918965856590e-01,
+3.266407412190941e-01, -3.518509343815957e-01, +2.939689006048397e-01,
-1.666639146194367e-01}, // 13
{+2.500000000000000e-01, -3.383295002935882e-01, +2.939689006048397e-01,
-2.242918965856591e-01, +1.352990250365493e-01, -3.465429229977286e-02,
-6.897484482073579e-02, +1.666639146194366e-01, -2.500000000000001e-01,
+3.118062532466678e-01, -3.467599613305369e-01, +3.518509343815956e-01,
-3.266407412190941e-01, +2.733004667504394e-01, -1.964237395967756e-01,
+1.026311318805893e-01}, // 14
{+2.500000000000000e-01, -3.518509343815957e-01, +3.467599613305369e-01,
-3.383295002935882e-01, +3.266407412190941e-01, -3.118062532466678e-01,
+2.939689006048397e-01, -2.733004667504394e-01, +2.500000000000001e-01,
-2.242918965856591e-01, +1.964237395967756e-01, -1.666639146194367e-01,
+1.352990250365493e-01, -1.026311318805893e-01, +6.897484482073578e-02,
-3.465429229977293e-02} };//15

View File

@ -1,40 +0,0 @@
/*
* SnsQuantizationTables.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SNS_QUANTIZATION_TABLES_H_
#define SNS_QUANTIZATION_TABLES_H_
// LC3 Specification d09r01.pdf
// Section 5.7.3 SNS Quantization
// LC3 Specification d09r04_*implementorComments*
// Section 3.7.4 SNS Quantization
extern double LFCB[32][8];
extern double HFCB[32][8];
extern double sns_vq_reg_adj_gains[2];
extern double sns_vq_reg_lf_adj_gains[4];
extern double sns_vq_near_adj_gains[4];
extern double sns_vq_far_adj_gains[8];
extern int sns_gainMSBbits[4];
extern int sns_gainLSBbits[4];
extern unsigned int MPVQ_offsets[16][1+10];
extern double D[16][16];
#endif // SNS_QUANTIZATION_TABLES_H_

View File

@ -1,752 +0,0 @@
/*
* SpectralDataTables.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.6 Spectral data
#include "SpectralDataTables.hpp"
// LC3 Specification d09r01.pdf; Page 114 of 177
unsigned char ac_spec_lookup[4096] = {
0x01,0x27,0x07,0x19,0x16,0x16,0x1C,0x16,
0x16,0x16,0x16,0x1C,0x1C,0x1C,0x22,0x1F,
0x1F,0x28,0x2B,0x2E,0x31,0x34,0x0E,0x11,
0x24,0x24,0x24,0x26,0x00,0x39,0x26,0x16,
0x00,0x08,0x09,0x0B,0x2F,0x0E,0x0E,0x11,
// LC3 Specification d09r01.pdf; Page 115 of 177
0x24,0x24,0x24,0x26,0x3B,0x3B,0x26,0x16,
0x16,0x1A,0x2E,0x1D,0x1E,0x20,0x21,0x23,
0x24,0x24,0x24,0x26,0x00,0x3B,0x17,0x16,
0x2E,0x2E,0x2D,0x2F,0x30,0x32,0x32,0x12,
0x36,0x36,0x36,0x26,0x3B,0x3B,0x3B,0x16,
0x00,0x3E,0x3F,0x03,0x21,0x02,0x02,0x3D,
0x14,0x14,0x14,0x15,0x3B,0x3B,0x27,0x1C,
0x1C,0x3F,0x3F,0x03,0x21,0x02,0x02,0x3D,
0x26,0x26,0x26,0x15,0x3B,0x3B,0x27,0x1C,
0x1C,0x06,0x06,0x06,0x02,0x12,0x3D,0x14,
0x15,0x15,0x15,0x3B,0x27,0x27,0x07,0x22,
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
0x22,0x33,0x33,0x33,0x35,0x36,0x14,0x26,
0x26,0x39,0x27,0x27,0x27,0x07,0x18,0x22,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x38,0x26,0x39,
0x39,0x3B,0x07,0x07,0x07,0x2A,0x2A,0x22,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x05,0x04,0x04,0x05,0x15,0x15,0x3B,
0x07,0x07,0x07,0x07,0x19,0x19,0x19,0x22,
0x04,0x04,0x04,0x04,0x05,0x17,0x17,0x27,
0x07,0x07,0x07,0x2A,0x19,0x19,0x16,0x1F,
0x1F,0x27,0x27,0x27,0x27,0x07,0x07,0x2A,
0x00,0x19,0x16,0x16,0x16,0x1C,0x22,0x1F,
0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,
0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,
0x37,0x37,0x28,0x08,0x09,0x31,0x31,0x34,
0x11,0x11,0x11,0x04,0x00,0x14,0x11,0x3C,
0x28,0x28,0x08,0x2B,0x1B,0x31,0x31,0x0E,
0x11,0x11,0x11,0x24,0x2A,0x2A,0x11,0x39,
0x39,0x28,0x08,0x1A,0x1B,0x31,0x0C,0x0E,
0x11,0x11,0x11,0x24,0x00,0x26,0x24,0x01,
0x08,0x08,0x2B,0x09,0x0B,0x31,0x0C,0x0E,
0x0E,0x21,0x32,0x32,0x32,0x3D,0x24,0x27,
0x08,0x08,0x2B,0x2E,0x31,0x34,0x1E,0x0E,
0x0E,0x21,0x32,0x32,0x32,0x32,0x12,0x19,
0x08,0x08,0x2B,0x2E,0x31,0x34,0x1E,0x0E,
0x0E,0x12,0x05,0x05,0x05,0x3D,0x12,0x17,
0x2B,0x2B,0x2B,0x09,0x31,0x34,0x03,0x0E,
0x0E,0x32,0x32,0x32,0x32,0x3D,0x11,0x18,
0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,
0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,
0x2B,0x2B,0x2B,0x09,0x0B,0x34,0x34,0x0E,
0x0E,0x11,0x3D,0x3D,0x3D,0x36,0x11,0x27,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2C,0x1B,0x1D,0x34,0x30,0x34,
0x34,0x11,0x11,0x11,0x11,0x02,0x11,0x07,
0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,
0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,
0x1B,0x1B,0x09,0x1B,0x1B,0x0C,0x34,0x0E,
0x0E,0x3A,0x29,0x29,0x29,0x06,0x11,0x25,
0x09,0x09,0x09,0x1B,0x0B,0x31,0x0C,0x34,
// LC3 Specification d09r01.pdf; Page 116 of 177
0x0E,0x0E,0x0E,0x32,0x00,0x35,0x11,0x1C,
0x34,0x34,0x31,0x34,0x0C,0x34,0x1E,0x0E,
0x0E,0x11,0x02,0x02,0x02,0x26,0x26,0x22,
0x1F,0x22,0x22,0x1F,0x1F,0x1F,0x1F,0x13,
0x13,0x13,0x13,0x13,0x13,0x13,0x1F,0x13,
0x2C,0x2C,0x3E,0x1E,0x20,0x3A,0x23,0x24,
0x24,0x26,0x00,0x3B,0x07,0x07,0x27,0x22,
0x22,0x2D,0x2F,0x30,0x21,0x23,0x23,0x24,
0x26,0x26,0x26,0x3B,0x07,0x07,0x27,0x22,
0x22,0x3E,0x1E,0x0F,0x32,0x35,0x35,0x36,
0x15,0x15,0x15,0x3B,0x07,0x07,0x07,0x22,
0x1E,0x1E,0x30,0x21,0x3A,0x12,0x12,0x38,
0x17,0x17,0x17,0x3B,0x07,0x07,0x18,0x22,
0x22,0x06,0x06,0x3A,0x35,0x36,0x36,0x15,
0x3B,0x3B,0x3B,0x27,0x07,0x07,0x2A,0x22,
0x06,0x06,0x21,0x3A,0x35,0x36,0x3D,0x15,
0x3B,0x3B,0x3B,0x27,0x07,0x07,0x2A,0x22,
0x22,0x33,0x33,0x35,0x36,0x38,0x38,0x39,
0x27,0x27,0x27,0x07,0x2A,0x2A,0x19,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x04,0x04,0x04,0x05,0x17,0x17,0x27,
0x07,0x07,0x07,0x2A,0x19,0x19,0x16,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x05,0x05,0x05,0x05,0x39,0x39,0x27,
0x18,0x18,0x18,0x2A,0x16,0x16,0x1C,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x29,0x29,0x29,0x29,0x27,0x27,0x07,
0x2A,0x2A,0x2A,0x19,0x1C,0x1C,0x1C,0x1F,
0x1F,0x29,0x29,0x29,0x29,0x27,0x27,0x18,
0x19,0x19,0x19,0x16,0x1C,0x1C,0x22,0x1F,
0x1F,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x1C,
0x22,0x22,0x22,0x22,0x22,0x22,0x1F,0x13,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x09,0x0B,0x2F,0x20,0x32,0x12,
0x12,0x14,0x15,0x15,0x15,0x27,0x3B,0x22,
0x1A,0x1A,0x1B,0x1D,0x1E,0x21,0x32,0x12,
0x12,0x14,0x39,0x39,0x39,0x3B,0x3B,0x22,
0x1B,0x1B,0x0B,0x0C,0x30,0x32,0x3A,0x3D,
0x3D,0x38,0x39,0x39,0x39,0x3B,0x27,0x22,
0x2D,0x2D,0x0C,0x1E,0x20,0x02,0x02,0x3D,
0x26,0x26,0x26,0x39,0x00,0x3B,0x27,0x22,
0x3F,0x3F,0x03,0x20,0x3A,0x12,0x12,0x14,
0x15,0x15,0x15,0x3B,0x27,0x27,0x07,0x1F,
0x1F,0x03,0x03,0x21,0x3A,0x12,0x12,0x14,
0x15,0x15,0x15,0x3B,0x07,0x07,0x07,0x1F,
0x06,0x06,0x33,0x33,0x35,0x36,0x36,0x26,
0x39,0x39,0x39,0x27,0x07,0x07,0x2A,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x33,0x35,0x35,0x36,0x38,0x38,0x39,
0x3B,0x3B,0x3B,0x07,0x18,0x18,0x19,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
// LC3 Specification d09r01.pdf; Page 117 of 177
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x04,0x04,0x04,0x36,0x15,0x15,0x39,
0x27,0x27,0x27,0x07,0x2A,0x2A,0x16,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0x1F,0x05,0x05,0x05,0x05,0x17,0x17,0x3B,
0x07,0x07,0x07,0x2A,0x16,0x16,0x1C,0x1F,
0x1F,0x04,0x04,0x04,0x05,0x17,0x17,0x27,
0x18,0x18,0x18,0x19,0x1C,0x1C,0x22,0x1F,
0x1F,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x1C,
0x22,0x22,0x22,0x1F,0x1F,0x1F,0x1F,0x13,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x10,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0D,0x0D,0x0D,0x00,0x0D,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 118 of 177
0x00,0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x00,0x0D,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,
0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x25,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x3C,0x10,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x3C,0x10,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x10,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x10,0x10,0x10,0x10,0x10,0x25,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 119 of 177
0x00,0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0D,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x3C,0x3C,0x3C,0x10,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x25,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 120 of 177
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x00,0x0D,0x0D,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x00,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3C,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x00,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x00,0x13,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x13,0x0D,0x0D,0x0D,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3C,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 121 of 177
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x3C,0x3C,0x3C,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,
0x0D,0x0D,0x0D,0x0D,0x0D,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 122 of 177
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x00,0x00,0x00,
0x00,0x00,0x0D,0x0D,0x0D,0x0D,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0D,0x0D,0x0D,0x0D,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0D,0x0D,0x0D,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x3C,
0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 123 of 177
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// LC3 Specification d09r01.pdf; Page 124 of 177
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
short ac_spec_cumfreq[64][17] = {
{ 0, 1, 2, 177, 225, 226, 227, 336, 372, 543, 652, 699, 719, 768, 804, 824, 834 },
{ 0, 18, 44, 61, 71, 98, 135, 159, 175, 197, 229, 251, 265, 282, 308, 328, 341 },
{ 0, 71, 163, 212, 237, 318, 420, 481, 514, 556, 613, 652, 675, 697, 727, 749, 764 },
{ 0, 160, 290, 336, 354, 475, 598, 653, 677, 722, 777, 808, 823, 842, 866, 881, 890 },
{ 0, 71, 144, 177, 195, 266, 342, 385, 411, 445, 489, 519, 539, 559, 586, 607, 622 },
{ 0, 48, 108, 140, 159, 217, 285, 327, 354, 385, 427, 457, 478, 497, 524, 545, 561 },
{ 0, 138, 247, 290, 308, 419, 531, 584, 609, 655, 710, 742, 759, 780, 807, 825, 836 },
{ 0, 16, 40, 62, 79, 103, 139, 170, 195, 215, 245, 270, 290, 305, 327, 346, 362 },
{ 0, 579, 729, 741, 743, 897, 970, 980, 982, 996, 1007, 1010, 1011, 1014, 1017, 1018, 1019 },
{ 0, 398, 582, 607, 612, 788, 902, 925, 931, 956, 979, 987, 990, 996, 1002, 1005, 1007 },
{ 0, 13, 34, 52, 63, 83, 112, 134, 149, 163, 183, 199, 211, 221, 235, 247, 257 },
{ 0, 281, 464, 501, 510, 681, 820, 857, 867, 902, 938, 953, 959, 968, 978, 984, 987 },
{ 0, 198, 362, 408, 421, 575, 722, 773, 789, 832, 881, 905, 915, 928, 944, 954, 959 },
{ 0, 1, 2, 95, 139, 140, 141, 213, 251, 337, 407, 450, 475, 515, 551, 576, 592 },
{ 0, 133, 274, 338, 366, 483, 605, 664, 691, 730, 778, 807, 822, 837, 857, 870, 878 },
{ 0, 128, 253, 302, 320, 443, 577, 636, 659, 708, 767, 799, 814, 833, 857, 872, 881 },
{ 0, 1, 2, 25, 42, 43, 44, 67, 85, 105, 126, 144, 159, 174, 191, 205, 217 },
{ 0, 70, 166, 229, 267, 356, 468, 533, 569, 606, 653, 685, 705, 722, 745, 762, 774 },
{ 0, 55, 130, 175, 200, 268, 358, 416, 449, 488, 542, 581, 606, 628, 659, 683, 699 },
{ 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 },
{ 0, 34, 85, 123, 147, 196, 265, 317, 352, 386, 433, 470, 497, 518, 549, 574, 593 },
{ 0, 30, 73, 105, 127, 170, 229, 274, 305, 335, 377, 411, 436, 455, 483, 506, 524 },
{ 0, 9, 24, 38, 51, 65, 87, 108, 126, 139, 159, 177, 193, 204, 221, 236, 250 },
{ 0, 30, 74, 105, 125, 166, 224, 266, 294, 322, 361, 391, 413, 431, 457, 478, 494 },
{ 0, 15, 38, 58, 73, 95, 128, 156, 178, 196, 222, 245, 263, 276, 296, 314, 329 },
// LC3 Specification d09r01.pdf; Page 125 of 177
{ 0, 11, 28, 44, 57, 74, 100, 123, 142, 157, 179, 199, 216, 228, 246, 262, 276 },
{ 0, 448, 619, 639, 643, 821, 926, 944, 948, 971, 991, 998, 1000, 1005, 1010, 1012, 1013 },
{ 0, 332, 520, 549, 555, 741, 874, 903, 910, 940, 970, 981, 985, 991, 998, 1002, 1004 },
{ 0, 8, 21, 34, 45, 58, 78, 96, 112, 124, 141, 157, 170, 180, 194, 207, 219 },
{ 0, 239, 415, 457, 468, 631, 776, 820, 833, 872, 914, 933, 940, 951, 964, 971, 975 },
{ 0, 165, 310, 359, 375, 513, 652, 707, 727, 774, 828, 856, 868, 884, 904, 916, 923 },
{ 0, 3, 8, 13, 18, 23, 30, 37, 44, 48, 55, 62, 68, 72, 78, 84, 90 },
{ 0, 115, 237, 289, 311, 422, 547, 608, 635, 680, 737, 771, 788, 807, 832, 849, 859 },
{ 0, 107, 221, 272, 293, 399, 521, 582, 610, 656, 714, 749, 767, 787, 813, 831, 842 },
{ 0, 6, 16, 26, 35, 45, 60, 75, 89, 98, 112, 125, 137, 145, 157, 168, 178 },
{ 0, 72, 160, 210, 236, 320, 422, 482, 514, 555, 608, 644, 665, 685, 712, 732, 745 },
{ 0, 45, 108, 153, 183, 244, 327, 385, 421, 455, 502, 536, 559, 578, 605, 626, 641 },
{ 0, 1, 2, 9, 16, 17, 18, 26, 34, 40, 48, 55, 62, 68, 75, 82, 88 },
{ 0, 29, 73, 108, 132, 174, 236, 284, 318, 348, 391, 426, 452, 471, 500, 524, 543 },
{ 0, 20, 51, 76, 93, 123, 166, 200, 225, 247, 279, 305, 326, 342, 365, 385, 401 },
{ 0, 742, 845, 850, 851, 959, 997, 1001, 1002, 1009, 1014, 1016, 1017, 1019, 1020, 1021, 1022 },
{ 0, 42, 94, 121, 137, 186, 244, 280, 303, 330, 366, 392, 410, 427, 451, 470, 484 },
{ 0, 13, 33, 51, 66, 85, 114, 140, 161, 178, 203, 225, 243, 256, 275, 292, 307 },
{ 0, 501, 670, 689, 693, 848, 936, 952, 956, 975, 991, 997, 999, 1004, 1008, 1010, 1011 },
{ 0, 445, 581, 603, 609, 767, 865, 888, 895, 926, 954, 964, 968, 977, 986, 991, 993 },
{ 0, 285, 442, 479, 489, 650, 779, 818, 830, 870, 912, 930, 937, 949, 963, 971, 975 },
{ 0, 349, 528, 561, 569, 731, 852, 883, 892, 923, 953, 965, 970, 978, 987, 992, 994 },
{ 0, 199, 355, 402, 417, 563, 700, 750, 767, 811, 860, 884, 894, 909, 926, 936, 942 },
{ 0, 141, 275, 325, 343, 471, 606, 664, 686, 734, 791, 822, 836, 854, 877, 891, 899 },
{ 0, 243, 437, 493, 510, 649, 775, 820, 836, 869, 905, 923, 931, 941, 953, 960, 964 },
{ 0, 91, 197, 248, 271, 370, 487, 550, 580, 625, 684, 721, 741, 761, 788, 807, 819 },
{ 0, 107, 201, 242, 262, 354, 451, 503, 531, 573, 626, 660, 680, 701, 730, 751, 765 },
{ 0, 168, 339, 407, 432, 553, 676, 731, 755, 789, 830, 854, 866, 879, 895, 906, 912 },
// LC3 Specification d09r01.pdf; Page 126 of 177
{ 0, 67, 147, 191, 214, 290, 384, 441, 472, 513, 567, 604, 627, 648, 678, 700, 715 },
{ 0, 46, 109, 148, 171, 229, 307, 359, 391, 427, 476, 513, 537, 558, 588, 612, 629 },
{ 0, 848, 918, 920, 921, 996, 1012, 1013, 1014, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023 },
{ 0, 36, 88, 123, 145, 193, 260, 308, 340, 372, 417, 452, 476, 496, 525, 548, 565 },
{ 0, 24, 61, 90, 110, 145, 196, 237, 266, 292, 330, 361, 385, 403, 430, 453, 471 },
{ 0, 85, 182, 230, 253, 344, 454, 515, 545, 590, 648, 685, 706, 727, 756, 776, 789 },
{ 0, 22, 55, 82, 102, 135, 183, 222, 252, 278, 315, 345, 368, 385, 410, 431, 448 },
{ 0, 1, 2, 56, 89, 90, 91, 140, 172, 221, 268, 303, 328, 358, 388, 412, 430 },
{ 0, 45, 109, 152, 177, 239, 320, 376, 411, 448, 499, 537, 563, 585, 616, 640, 658 },
{ 0, 247, 395, 433, 445, 599, 729, 771, 785, 829, 875, 896, 905, 920, 937, 946, 951 },
{ 0, 231, 367, 408, 423, 557, 676, 723, 742, 786, 835, 860, 872, 889, 909, 921, 928 }
};
short ac_spec_freq[64][17] = {
{ 1, 1, 175, 48, 1, 1, 109, 36, 171, 109, 47, 20, 49, 36, 20, 10, 190 },
{ 18, 26, 17, 10, 27, 37, 24, 16, 22, 32, 22, 14, 17, 26, 20, 13, 683 },
{ 71, 92, 49, 25, 81, 102, 61, 33, 42, 57, 39, 23, 22, 30, 22, 15, 260 },
{ 160, 130, 46, 18, 121, 123, 55, 24, 45, 55, 31, 15, 19, 24, 15, 9, 134 },
{ 71, 73, 33, 18, 71, 76, 43, 26, 34, 44, 30, 20, 20, 27, 21, 15, 402 },
{ 48, 60, 32, 19, 58, 68, 42, 27, 31, 42, 30, 21, 19, 27, 21, 16, 463 },
{ 138, 109, 43, 18, 111, 112, 53, 25, 46, 55, 32, 17, 21, 27, 18, 11, 188 },
{ 16, 24, 22, 17, 24, 36, 31, 25, 20, 30, 25, 20, 15, 22, 19, 16, 662 },
{ 579, 150, 12, 2, 154, 73, 10, 2, 14, 11, 3, 1, 3, 3, 1, 1, 5 },
{ 398, 184, 25, 5, 176, 114, 23, 6, 25, 23, 8, 3, 6, 6, 3, 2, 17 },
{ 13, 21, 18, 11, 20, 29, 22, 15, 14, 20, 16, 12, 10, 14, 12, 10, 767 },
{ 281, 183, 37, 9, 171, 139, 37, 10, 35, 36, 15, 6, 9, 10, 6, 3, 37 },
{ 198, 164, 46, 13, 154, 147, 51, 16, 43, 49, 24, 10, 13, 16, 10, 5, 65 },
{ 1, 1, 93, 44, 1, 1, 72, 38, 86, 70, 43, 25, 40, 36, 25, 16, 432 },
{ 133, 141, 64, 28, 117, 122, 59, 27, 39, 48, 29, 15, 15, 20, 13, 8, 146 },
// LC3 Specification d09r01.pdf; Page 127 of 177
{ 128, 125, 49, 18, 123, 134, 59, 23, 49, 59, 32, 15, 19, 24, 15, 9, 143 },
{ 1, 1, 23, 17, 1, 1, 23, 18, 20, 21, 18, 15, 15, 17, 14, 12, 807 },
{ 70, 96, 63, 38, 89, 112, 65, 36, 37, 47, 32, 20, 17, 23, 17, 12, 250 },
{ 55, 75, 45, 25, 68, 90, 58, 33, 39, 54, 39, 25, 22, 31, 24, 16, 325 },
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 993 },
{ 34, 51, 38, 24, 49, 69, 52, 35, 34, 47, 37, 27, 21, 31, 25, 19, 431 },
{ 30, 43, 32, 22, 43, 59, 45, 31, 30, 42, 34, 25, 19, 28, 23, 18, 500 },
{ 9, 15, 14, 13, 14, 22, 21, 18, 13, 20, 18, 16, 11, 17, 15, 14, 774 },
{ 30, 44, 31, 20, 41, 58, 42, 28, 28, 39, 30, 22, 18, 26, 21, 16, 530 },
{ 15, 23, 20, 15, 22, 33, 28, 22, 18, 26, 23, 18, 13, 20, 18, 15, 695 },
{ 11, 17, 16, 13, 17, 26, 23, 19, 15, 22, 20, 17, 12, 18, 16, 14, 748 },
{ 448, 171, 20, 4, 178, 105, 18, 4, 23, 20, 7, 2, 5, 5, 2, 1, 11 },
{ 332, 188, 29, 6, 186, 133, 29, 7, 30, 30, 11, 4, 6, 7, 4, 2, 20 },
{ 8, 13, 13, 11, 13, 20, 18, 16, 12, 17, 16, 13, 10, 14, 13, 12, 805 },
{ 239, 176, 42, 11, 163, 145, 44, 13, 39, 42, 19, 7, 11, 13, 7, 4, 49 },
{ 165, 145, 49, 16, 138, 139, 55, 20, 47, 54, 28, 12, 16, 20, 12, 7, 101 },
{ 3, 5, 5, 5, 5, 7, 7, 7, 4, 7, 7, 6, 4, 6, 6, 6, 934 },
{ 115, 122, 52, 22, 111, 125, 61, 27, 45, 57, 34, 17, 19, 25, 17, 10, 165 },
{ 107, 114, 51, 21, 106, 122, 61, 28, 46, 58, 35, 18, 20, 26, 18, 11, 182 },
{ 6, 10, 10, 9, 10, 15, 15, 14, 9, 14, 13, 12, 8, 12, 11, 10, 846 },
{ 72, 88, 50, 26, 84, 102, 60, 32, 41, 53, 36, 21, 20, 27, 20, 13, 279 },
{ 45, 63, 45, 30, 61, 83, 58, 36, 34, 47, 34, 23, 19, 27, 21, 15, 383 },
{ 1, 1, 7, 7, 1, 1, 8, 8, 6, 8, 7, 7, 6, 7, 7, 6, 936 },
{ 29, 44, 35, 24, 42, 62, 48, 34, 30, 43, 35, 26, 19, 29, 24, 19, 481 },
{ 20, 31, 25, 17, 30, 43, 34, 25, 22, 32, 26, 21, 16, 23, 20, 16, 623 },
{ 742, 103, 5, 1, 108, 38, 4, 1, 7, 5, 2, 1, 2, 1, 1, 1, 2 },
{ 42, 52, 27, 16, 49, 58, 36, 23, 27, 36, 26, 18, 17, 24, 19, 14, 540 },
{ 13, 20, 18, 15, 19, 29, 26, 21, 17, 25, 22, 18, 13, 19, 17, 15, 717 },
// LC3 Specification d09r01.pdf; Page 128 of 177
{ 501, 169, 19, 4, 155, 88, 16, 4, 19, 16, 6, 2, 5, 4, 2, 1, 13 },
{ 445, 136, 22, 6, 158, 98, 23, 7, 31, 28, 10, 4, 9, 9, 5, 2, 31 },
{ 285, 157, 37, 10, 161, 129, 39, 12, 40, 42, 18, 7, 12, 14, 8, 4, 49 },
{ 349, 179, 33, 8, 162, 121, 31, 9, 31, 30, 12, 5, 8, 9, 5, 2, 30 },
{ 199, 156, 47, 15, 146, 137, 50, 17, 44, 49, 24, 10, 15, 17, 10, 6, 82 },
{ 141, 134, 50, 18, 128, 135, 58, 22, 48, 57, 31, 14, 18, 23, 14, 8, 125 },
{ 243, 194, 56, 17, 139, 126, 45, 16, 33, 36, 18, 8, 10, 12, 7, 4, 60 },
{ 91, 106, 51, 23, 99, 117, 63, 30, 45, 59, 37, 20, 20, 27, 19, 12, 205 },
{ 107, 94, 41, 20, 92, 97, 52, 28, 42, 53, 34, 20, 21, 29, 21, 14, 259 },
{ 168, 171, 68, 25, 121, 123, 55, 24, 34, 41, 24, 12, 13, 16, 11, 6, 112 },
{ 67, 80, 44, 23, 76, 94, 57, 31, 41, 54, 37, 23, 21, 30, 22, 15, 309 },
{ 46, 63, 39, 23, 58, 78, 52, 32, 36, 49, 37, 24, 21, 30, 24, 17, 395 },
{ 848, 70, 2, 1, 75, 16, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 36, 52, 35, 22, 48, 67, 48, 32, 32, 45, 35, 24, 20, 29, 23, 17, 459 },
{ 24, 37, 29, 20, 35, 51, 41, 29, 26, 38, 31, 24, 18, 27, 23, 18, 553 },
{ 85, 97, 48, 23, 91, 110, 61, 30, 45, 58, 37, 21, 21, 29, 20, 13, 235 },
{ 22, 33, 27, 20, 33, 48, 39, 30, 26, 37, 30, 23, 17, 25, 21, 17, 576 },
{ 1, 1, 54, 33, 1, 1, 49, 32, 49, 47, 35, 25, 30, 30, 24, 18, 594 },
{ 45, 64, 43, 25, 62, 81, 56, 35, 37, 51, 38, 26, 22, 31, 24, 18, 366 },
{ 247, 148, 38, 12, 154, 130, 42, 14, 44, 46, 21, 9, 15, 17, 9, 5, 73 },
{ 231, 136, 41, 15, 134, 119, 47, 19, 44, 49, 25, 12, 17, 20, 12, 7, 96 }
};
short ac_spec_bits[64][17] = {
{ 20480,20480, 5220, 9042,20480,20480, 6619, 9892, 5289, 6619, 9105,11629, 8982, 9892,11629,13677, 4977 },
{ 11940,10854,12109,13677,10742, 9812,11090,12288,11348,10240,11348,12683,12109,10854,11629,12902, 1197 },
{ 7886, 7120, 8982,10970, 7496, 6815, 8334,10150, 9437, 8535, 9656,11216,11348,10431,11348,12479, 4051 },
{ 5485, 6099, 9168,11940, 6311, 6262, 8640,11090, 9233, 8640,10334,12479,11781,11090,12479,13988, 6009 },
{ 7886, 7804,10150,11940, 7886, 7685, 9368,10854,10061, 9300,10431,11629,11629,10742,11485,12479, 2763 },
// LC3 Specification d09r01.pdf; Page 129 of 177
{ 9042, 8383,10240,11781, 8483, 8013, 9437,10742,10334, 9437,10431,11485,11781,10742,11485,12288, 2346 },
{ 5922, 6619, 9368,11940, 6566, 6539, 8750,10970, 9168, 8640,10240,12109,11485,10742,11940,13396, 5009 },
{ 12288,11090,11348,12109,11090, 9892,10334,10970,11629,10431,10970,11629,12479,11348,11781,12288, 1289 },
{ 1685, 5676,13138,18432, 5598, 7804,13677,18432,12683,13396,17234,20480,17234,17234,20480,20480,15725 },
{ 2793, 5072,10970,15725, 5204, 6487,11216,15186,10970,11216,14336,17234,15186,15186,17234,18432,12109 },
{ 12902,11485,11940,13396,11629,10531,11348,12479,12683,11629,12288,13138,13677,12683,13138,13677, 854 },
{ 3821, 5088, 9812,13988, 5289, 5901, 9812,13677, 9976, 9892,12479,15186,13988,13677,15186,17234, 9812 },
{ 4856, 5412, 9168,12902, 5598, 5736, 8863,12288, 9368, 8982,11090,13677,12902,12288,13677,15725, 8147 },
{ 20480,20480, 7088, 9300,20480,20480, 7844, 9733, 7320, 7928, 9368,10970, 9581, 9892,10970,12288, 2550 },
{ 6031, 5859, 8192,10635, 6410, 6286, 8433,10742, 9656, 9042,10531,12479,12479,11629,12902,14336, 5756 },
{ 6144, 6215, 8982,11940, 6262, 6009, 8433,11216, 8982, 8433,10240,12479,11781,11090,12479,13988, 5817 },
{ 20480,20480,11216,12109,20480,20480,11216,11940,11629,11485,11940,12479,12479,12109,12683,13138, 704 },
{ 7928, 6994, 8239, 9733, 7218, 6539, 8147, 9892, 9812, 9105,10240,11629,12109,11216,12109,13138, 4167 },
{ 8640, 7724, 9233,10970, 8013, 7185, 8483,10150, 9656, 8694, 9656,10970,11348,10334,11090,12288, 3391 },
{ 20480,18432,18432,18432,18432,18432,18432,18432,18432,18432,18432,18432,18432,18432,18432,18432, 91 },
{ 10061, 8863, 9733,11090, 8982, 7970, 8806, 9976,10061, 9105, 9812,10742,11485,10334,10970,11781, 2557 },
{ 10431, 9368,10240,11348, 9368, 8433, 9233,10334,10431, 9437,10061,10970,11781,10635,11216,11940, 2119 },
{ 13988,12479,12683,12902,12683,11348,11485,11940,12902,11629,11940,12288,13396,12109,12479,12683, 828 },
{ 10431, 9300,10334,11629, 9508, 8483, 9437,10635,10635, 9656,10431,11348,11940,10854,11485,12288, 1946 },
{ 12479,11216,11629,12479,11348,10150,10635,11348,11940,10854,11216,11940,12902,11629,11940,12479, 1146 },
{ 13396,12109,12288,12902,12109,10854,11216,11781,12479,11348,11629,12109,13138,11940,12288,12683, 928 },
{ 2443, 5289,11629,16384, 5170, 6730,11940,16384,11216,11629,14731,18432,15725,15725,18432,20480,13396 },
{ 3328, 5009,10531,15186, 5040, 6031,10531,14731,10431,10431,13396,16384,15186,14731,16384,18432,11629 },
{ 14336,12902,12902,13396,12902,11629,11940,12288,13138,12109,12288,12902,13677,12683,12902,13138, 711 },
// LC3 Specification d09r01.pdf; Page 130 of 177
{ 4300, 5204, 9437,13396, 5430, 5776, 9300,12902, 9656, 9437,11781,14731,13396,12902,14731,16384, 8982 },
{ 5394, 5776, 8982,12288, 5922, 5901, 8640,11629, 9105, 8694,10635,13138,12288,11629,13138,14731, 6844 },
{ 17234,15725,15725,15725,15725,14731,14731,14731,16384,14731,14731,15186,16384,15186,15186,15186, 272 },
{ 6461, 6286, 8806,11348, 6566, 6215, 8334,10742, 9233, 8535,10061,12109,11781,10970,12109,13677, 5394 },
{ 6674, 6487, 8863,11485, 6702, 6286, 8334,10635, 9168, 8483, 9976,11940,11629,10854,11940,13396, 5105 },
{ 15186,13677,13677,13988,13677,12479,12479,12683,13988,12683,12902,13138,14336,13138,13396,13677, 565 },
{ 7844, 7252, 8922,10854, 7389, 6815, 8383,10240, 9508, 8750, 9892,11485,11629,10742,11629,12902, 3842 },
{ 9233, 8239, 9233,10431, 8334, 7424, 8483, 9892,10061, 9105,10061,11216,11781,10742,11485,12479, 2906 },
{ 20480,20480,14731,14731,20480,20480,14336,14336,15186,14336,14731,14731,15186,14731,14731,15186, 266 },
{ 10531, 9300, 9976,11090, 9437, 8286, 9042,10061,10431, 9368, 9976,10854,11781,10531,11090,11781, 2233 },
{ 11629,10334,10970,12109,10431, 9368,10061,10970,11348,10240,10854,11485,12288,11216,11629,12288, 1469 },
{ 952, 6787,15725,20480, 6646, 9733,16384,20480,14731,15725,18432,20480,18432,20480,20480,20480,18432 },
{ 9437, 8806,10742,12288, 8982, 8483, 9892,11216,10742, 9892,10854,11940,12109,11090,11781,12683, 1891 },
{ 12902,11629,11940,12479,11781,10531,10854,11485,12109,10970,11348,11940,12902,11781,12109,12479, 1054 },
{ 2113, 5323,11781,16384, 5579, 7252,12288,16384,11781,12288,15186,18432,15725,16384,18432,20480,12902 },
{ 2463, 5965,11348,15186, 5522, 6934,11216,14731,10334,10635,13677,16384,13988,13988,15725,18432,10334 },
{ 3779, 5541, 9812,13677, 5467, 6122, 9656,13138, 9581, 9437,11940,14731,13138,12683,14336,16384, 8982 },
{ 3181, 5154,10150,14336, 5448, 6311,10334,13988,10334,10431,13138,15725,14336,13988,15725,18432,10431 },
{ 4841, 5560, 9105,12479, 5756, 5944, 8922,12109, 9300, 8982,11090,13677,12479,12109,13677,15186, 7460 },
{ 5859, 6009, 8922,11940, 6144, 5987, 8483,11348, 9042, 8535,10334,12683,11940,11216,12683,14336, 6215 },
{ 4250, 4916, 8587,12109, 5901, 6191, 9233,12288,10150, 9892,11940,14336,13677,13138,14731,16384, 8383 },
{ 7153, 6702, 8863,11216, 6904, 6410, 8239,10431, 9233, 8433, 9812,11629,11629,10742,11781,13138, 4753 },
{ 6674, 7057, 9508,11629, 7120, 6964, 8806,10635, 9437, 8750,10061,11629,11485,10531,11485,12683, 4062 },
{ 5341, 5289, 8013,10970, 6311, 6262, 8640,11090,10061, 9508,11090,13138,12902,12288,13396,15186, 6539 },
{ 8057, 7533, 9300,11216, 7685, 7057, 8535,10334, 9508, 8694, 9812,11216,11485,10431,11348,12479, 3541 },
{ 9168, 8239, 9656,11216, 8483, 7608, 8806,10240, 9892, 8982, 9812,11090,11485,10431,11090,12109, 2815 },
// LC3 Specification d09r01.pdf; Page 131 of 177
{ 558, 7928,18432,20480, 7724,12288,20480,20480,18432,20480,20480,20480,20480,20480,20480,20480,20480 },
{ 9892, 8806, 9976,11348, 9042, 8057, 9042,10240,10240, 9233, 9976,11090,11629,10531,11216,12109, 2371 },
{ 11090, 9812,10531,11629, 9976, 8863, 9508,10531,10854, 9733,10334,11090,11940,10742,11216,11940, 1821 },
{ 7354, 6964, 9042,11216, 7153, 6592, 8334,10431, 9233, 8483, 9812,11485,11485,10531,11629,12902, 4349 },
{ 11348,10150,10742,11629,10150, 9042, 9656,10431,10854, 9812,10431,11216,12109,10970,11485,12109, 1700 },
{ 20480,20480, 8694,10150,20480,20480, 8982,10240, 8982, 9105, 9976,10970,10431,10431,11090,11940, 1610 },
{ 9233, 8192, 9368,10970, 8286, 7496, 8587, 9976, 9812, 8863, 9733,10854,11348,10334,11090,11940, 3040 },
{ 4202, 5716, 9733,13138, 5598, 6099, 9437,12683, 9300, 9168,11485,13988,12479,12109,13988,15725, 7804 },
{ 4400, 5965, 9508,12479, 6009, 6360, 9105,11781, 9300, 8982,10970,13138,12109,11629,13138,14731, 6994 }
};

View File

@ -1,30 +0,0 @@
/*
* SpectralDataTables.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.6 Spectral data
#ifndef SPECTRAL_DATA_TABLES_H_
#define SPECTRAL_DATA_TABLES_H_
extern unsigned char ac_spec_lookup[4096];
extern short ac_spec_cumfreq[64][17];
extern short ac_spec_freq[64][17];
extern short ac_spec_bits[64][17];
#endif // SPECTRAL_DATA_TABLES_H_

View File

@ -1,51 +0,0 @@
/*
* TemporalNoiseShapingTables.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.4 Temporal Noise Shaping
#include "TemporalNoiseShapingTables.hpp"
// LC3 Specification d09r01.pdf; Page 109 of 177
short ac_tns_order_bits[2][8] = {{17234,13988,11216,8694,6566,4977,3961,3040}, {12683,9437,6874,5541,5121,5170,5359,5056}};
short ac_tns_order_freq[2][8] = {{3,9,23,54,111,190,268,366}, {14,42,100,157,181,178,167,185}};
short ac_tns_order_cumfreq[2][8] = {{0,3,12,35,89,200,390,658}, {0,14,56,156,313,494,672,839}};
// LC3 Specification d09r01.pdf; Page 110 of 177
short ac_tns_coef_bits[8][17] = {{20480,15725,12479,10334,8694,7320,6964,6335,5504,5637,6566,6758,8433,11348,15186,20480,20480},
{20480,20480,20480,20480,12902,9368,7057,5901,5254,5485,5598,6076,7608,10742,15186,20480,20480},
{20480,20480,20480,20480,13988,9368,6702,4841,4585,4682,5859,7764,12109,20480,20480,20480,20480},
{20480,20480,20480,20480,18432,13396,8982,4767,3779,3658,6335,9656,13988,20480,20480,20480,20480},
{20480,20480,20480,20480,20480,14731,9437,4275,3249,3493,8483,13988,17234,20480,20480,20480,20480},
{20480,20480,20480,20480,20480,20480,12902,4753,3040,2953,9105,15725,20480,20480,20480,20480,20480},
{20480,20480,20480,20480,20480,20480,12902,3821,3346,3000,12109,20480,20480,20480,20480,20480,20480},
{20480,20480,20480,20480,20480,20480,15725,3658,20480,1201,10854,18432,20480,20480,20480,20480,20480}};
short ac_tns_coef_freq[8][17] = {{1,5,15,31,54,86,97,120,159,152,111,104,59,22,6,1,1},
{1,1,1,1,13,43,94,139,173,160,154,131,78,27,6,1,1},
{1,1,1,1,9,43,106,199,217,210,141,74,17,1,1,1,1},
{1,1,1,1,2,11,49,204,285,297,120,39,9,1,1,1,1},
{1,1,1,1,1,7,42,241,341,314,58,9,3,1,1,1,1},
{1,1,1,1,1,1,13,205,366,377,47,5,1,1,1,1,1},
{1,1,1,1,1,1,13,281,330,371,17,1,1,1,1,1,1},
{1,1,1,1,1,1,5,297,1,682,26,2,1,1,1,1,1}};
short ac_tns_coef_cumfreq[8][17] = {{0,1,6,21,52,106,192,289,409,568,720,831,935,994,1016,1022,1023},
{0,1,2,3,4,17,60,154,293,466,626,780,911,989,1016,1022,1023},
{0,1,2,3,4,13,56,162,361,578,788,929,1003,1020,1021,1022,1023},
{0,1,2,3,4,6,17,66,270,555,852,972,1011,1020,1021,1022,1023},
{0,1,2,3,4,5,12,54,295,636,950,1008,1017,1020,1021,1022,1023},
{0,1,2,3,4,5,6,19,224,590,967,1014,1019,1020,1021,1022,1023},
{0,1,2,3,4,5,6,19,300,630,1001,1018,1019,1020,1021,1022,1023},
{0,1,2,3,4,5,6,11,308,309,991,1017,1019,1020,1021,1022,1023}};

View File

@ -1,34 +0,0 @@
/*
* TemporalNoiseShapingTables.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// LC3 Specification d09r01.pdf
// Section 5.7.4 Temporal Noise Shaping
#ifndef TEMPORAL_NOISE_SHAPING_TABLES_H_
#define TEMPORAL_NOISE_SHAPING_TABLES_H_
// LC3 Specification d09r01.pdf; Page 109 of 177
extern short ac_tns_order_bits[2][8];
extern short ac_tns_order_freq[2][8];
extern short ac_tns_order_cumfreq[2][8];
extern short ac_tns_coef_bits[8][17];
extern short ac_tns_coef_freq[8][17];
extern short ac_tns_coef_cumfreq[8][17];
#endif // TEMPORAL_NOISE_SHAPING_TABLES_H_

View File

@ -1,300 +0,0 @@
/*
* ArithmeticDec.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ArithmeticDec.hpp"
#include "TemporalNoiseShapingTables.hpp"
#include "SpectralDataTables.hpp"
#include "BitReader.hpp"
#include <cstring>
#include <cmath>
#include <algorithm> // std::min
namespace Lc3Dec
{
ArithmeticDec::ArithmeticDec(uint16_t NF_, uint16_t NE_, uint16_t rateFlag_, uint8_t tns_lpc_weighting_)
:
NF(NF_),
NE(NE_),
rateFlag(rateFlag_),
tns_lpc_weighting(tns_lpc_weighting_),
X_hat_q_ari(nullptr),
save_lev(nullptr),
nf_seed(0),
nbits_residual(0)
{
X_hat_q_ari = new int16_t[NE];
save_lev = new uint8_t[NE];
}
ArithmeticDec::~ArithmeticDec()
{
delete[] X_hat_q_ari;
delete[] save_lev;
}
void ac_dec_init(const uint8_t bytes[], uint16_t* bp, struct ac_dec_state* st)
{
st->low = 0;
st->range = 0x00ffffff;
for (uint8_t i = 0; i < 3; i++)
{
st->low <<= 8;
st->low += bytes[(*bp)++];
}
}
uint8_t ac_decode(
const uint8_t bytes[],
uint16_t* bp,
struct ac_dec_state* st,
int16_t cum_freq[],
int16_t sym_freq[],
uint8_t numsym,
uint8_t& BEC_detect
)
{
uint32_t tmp = st->range >> 10;
if (st->low >= (tmp<<10))
{
BEC_detect = 1;
return 0;
}
uint8_t val = numsym-1;
while (st->low < tmp * cum_freq[val])
{
val--;
}
st->low -= tmp * cum_freq[val];
st->range = tmp * sym_freq[val];
while (st->range < 0x10000)
{
st->low <<= 8;
st->low &= 0x00ffffff;
st->low += bytes[(*bp)++];
st->range <<= 8;
}
return val;
}
double ArithmeticDec::rc_q(uint8_t k, uint8_t f)
{
// with Δ =π/17
const double pi = std::acos(-1);
double quantizer_stepsize = pi / 17.0;
return sin( quantizer_stepsize * ( rc_i[k + 8*f] -8 ) );
}
void ArithmeticDec::run(
const uint8_t* bytes,
uint16_t& bp,
uint16_t& bp_side,
uint8_t& mask_side,
int16_t& num_tns_filters,
int16_t rc_order[],
const uint8_t& lsbMode,
const int16_t& lastnz,
uint16_t nbits,
uint8_t& BEC_detect
)
{
int16_t c = 0;
// make local copy of rc_order (is this really what we want)
rc_order_ari[0] = rc_order[0];
rc_order_ari[1] = rc_order[1];
/* Arithmetic Decoder Initialization */
ac_dec_init(bytes, &bp, &st);
/* TNS data */
// Note: some initialization code like that below can be found in d09r02,
// but there has been none in d09r01. However, the complete initialization
// has been added here, in order to get a proper match to the reference output data
for (uint8_t f = 0; f < 2; f++)
{
for (uint8_t k = 0; k < 8; k++)
{
rc_i[k + 8*f] = 8;
}
}
for (uint8_t f = 0; f < num_tns_filters; f++)
{
//if (𝑟𝑐𝑜𝑟𝑑𝑒𝑟(𝑓) > 0)
if (rc_order[f] > 0)
{
//𝑟𝑐𝑜𝑟𝑑𝑒𝑟(𝑓) = ac_decode(bytes, &bp, &st,
rc_order_ari[f] = ac_decode(bytes, &bp, &st,
ac_tns_order_cumfreq[tns_lpc_weighting],
ac_tns_order_freq[tns_lpc_weighting], 8,
BEC_detect);
if (BEC_detect)
{
// early exit to avoid unpredictable side-effects
return;
}
rc_order_ari[f] = rc_order_ari[f] + 1;
// specification (d09r02_F2F) proposes initialization
// of rc_i at this place; here implemented above in order
// to be performed independet from num_tns_filters
for (uint8_t k = 0; k < rc_order_ari[f]; k++)
{
//𝑟𝑐𝑖(𝑘,𝑓) = ac_decode(bytes, &bp, &st, ac_tns_coef_cumfreq[k],
//rc_i[k][f] = ac_decode(bytes, &bp, &st, ac_tns_coef_cumfreq[k],
rc_i[k + 8*f] = ac_decode(bytes, &bp, &st, ac_tns_coef_cumfreq[k],
ac_tns_coef_freq[k], 17,
BEC_detect);
if (BEC_detect)
{
// early exit to avoid unpredictable side-effects
return;
}
}
}
}
/* Spectral data */
for (uint16_t k = 0; k < lastnz; k += 2)
{
uint16_t t = c + rateFlag;
//if (k > 𝑁𝐸/2)
if (k > NE/2)
{
t += 256;
}
//𝑋𝑞̂[k] = 𝑋𝑞̂[k+1] = 0;
X_hat_q_ari[k] = X_hat_q_ari[k+1] = 0;
uint8_t lev;
uint8_t sym;
for (lev = 0; lev < 14; lev++)
{
uint8_t pki = ac_spec_lookup[t+std::min(lev,static_cast<uint8_t>(3U))*1024];
sym = ac_decode(bytes, &bp, &st, ac_spec_cumfreq[pki],
ac_spec_freq[pki], 17,
BEC_detect);
if (BEC_detect)
{
// early exit to avoid unpredictable side-effects
return;
}
if (sym < 16)
{
break;
}
if (lsbMode == 0 || lev > 0)
{
uint8_t bit = read_bit(bytes, &bp_side, &mask_side);
//𝑋𝑞̂[k] += bit << lev;
X_hat_q_ari[k] += bit << lev;
bit = read_bit(bytes, &bp_side, &mask_side);
//𝑋𝑞̂[k+1] += bit << lev;
X_hat_q_ari[k+1] += bit << lev;
}
}
if (lev == 14)
{
BEC_detect = 1;
return;
}
if (lsbMode == 1)
{
save_lev[k] = lev;
}
uint8_t a = sym & 0x3;
uint8_t b = sym >> 2;
//𝑋𝑞̂[k] += a << lev;
//𝑋𝑞̂[k+1] += b << lev;
//if (𝑋𝑞̂[k] > 0)
X_hat_q_ari[k] += a << lev;
X_hat_q_ari[k+1] += b << lev;
if (X_hat_q_ari[k] > 0)
{
uint8_t bit = read_bit(bytes, &bp_side, &mask_side);
if (bit == 1)
{
//𝑋𝑞̂[k] = -𝑋𝑞̂[k];
X_hat_q_ari[k] = -X_hat_q_ari[k];
}
}
//if (𝑋𝑞̂[k+1] > 0)
if (X_hat_q_ari[k+1] > 0)
{
uint8_t bit = read_bit(bytes, &bp_side, &mask_side);
if (bit == 1)
{
//𝑋𝑞̂[k+1] = -𝑋𝑞̂[k+1];
X_hat_q_ari[k+1] = -X_hat_q_ari[k+1];
}
}
lev = std::min(lev,static_cast<uint8_t>(3));
if (lev <= 1)
{
t = 1 + (a+b)*(lev+1);
}
else
{
t = 12 + lev;
}
c = (c&15)*16 + t;
// Note: specification of the following line hase been changed from d09r01 to d09r02_F2F
if (bp - bp_side > 3)
{
BEC_detect = 1;
return;
}
}
// reset remaining fields in array X_hat_q_ari to simplify testing
for (int16_t k = lastnz; k < NE; k++)
{
X_hat_q_ari [k] = 0;
}
// 3.4.2.6 Residual data and finalization (d09r02_F2F)
/* Number of residual bits */
int16_t nbits_side = nbits - (8 * bp_side + 8 - log2(mask_side));
int16_t nbits_ari = (bp - 3) * 8;
nbits_ari += 25 - floor(log2(st.range));
int16_t nbits_residual_tmp = nbits - (nbits_side + nbits_ari);
if (nbits_residual_tmp < 0)
{
BEC_detect = 1;
return;
}
nbits_residual = nbits_residual_tmp;
}
void ArithmeticDec::registerDatapoints(DatapointContainer* datapoints)
{
if (nullptr != datapoints)
{
datapoints->addDatapoint( "rateFlag", &rateFlag, sizeof(rateFlag) );
datapoints->addDatapoint( "tns_lpc_weighting", &tns_lpc_weighting, sizeof(tns_lpc_weighting) );
datapoints->addDatapoint( "rc_order_ari", &rc_order_ari[0], sizeof(rc_order_ari) );
datapoints->addDatapoint( "rc_i", &rc_i[0], sizeof(rc_i) );
datapoints->addDatapoint( "X_hat_q_ari", &X_hat_q_ari[0], sizeof(int16_t)*NE );
datapoints->addDatapoint( "nbits_residual", &nbits_residual, sizeof(nbits_residual) );
}
}
}//namespace Lc3Dec

View File

@ -1,75 +0,0 @@
/*
* ArithmeticDec.hpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __ARITHMETIC_DEC_HPP_
#define __ARITHMETIC_DEC_HPP_
#include <cstdint>
#include "Datapoints.hpp"
namespace Lc3Dec
{
struct ac_dec_state {
uint32_t low;
uint32_t range;
};
class ArithmeticDec
{
public:
ArithmeticDec(uint16_t NF_, uint16_t NE_, uint16_t rateFlag_, uint8_t tns_lpc_weighting_);
virtual ~ArithmeticDec();
void registerDatapoints(DatapointContainer* datapoints);
double rc_q(uint8_t k, uint8_t f);
void run(
const uint8_t* bytes,
uint16_t& bp,
uint16_t& bp_side,
uint8_t& mask_side,
int16_t& num_tns_filters,
int16_t rc_order[],
const uint8_t& lsbMode,
const int16_t& lastnz,
uint16_t nbits,
uint8_t& BEC_detect
);
const uint16_t NF;
const uint16_t NE;
const uint16_t rateFlag;
const uint8_t tns_lpc_weighting;
// states & outputs
int16_t* X_hat_q_ari;
uint8_t* save_lev;
int16_t nf_seed;
int16_t rc_order_ari[2];
int16_t rc_i[2*8]; // [max(rc_order[f])=8][max(num_tns_filters)=2]
uint16_t nbits_residual;
private:
struct ac_dec_state st;
};
}//namespace Lc3Dec
#endif // __ARITHMETIC_DEC_HPP_

View File

@ -1,58 +0,0 @@
/*
* BitReader.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "BitReader.hpp"
namespace Lc3Dec
{
uint8_t read_bit(const uint8_t bytes[], uint16_t* bp, uint8_t* mask)
{
uint8_t bit;
if (bytes[*bp] & *mask)
{
bit = 1;
}
else
{
bit = 0;
}
if (*mask == 0x80)
{
*mask = 1;
*bp -= 1;
}
else
{
*mask <<= 1;
}
return bit;
}
uint16_t read_uint(const uint8_t bytes[], uint16_t* bp, uint8_t* mask, uint8_t numbits)
{
uint16_t value = read_bit(bytes, bp, mask);
for (uint8_t i = 1; i < numbits; i++)
{
uint16_t bit = read_bit(bytes, bp, mask);
value += bit << i;
}
return value;
}
}//namespace Lc3Dec

Some files were not shown because too many files have changed in this diff Show More