furnace/extern/libsndfile-modified/src/ALAC/ag_dec.c
tildearrow 061991fe60 desubmodulize libsndfile - PLEASE READ
it appears a one-character typo in the cmake_minimum_required line prevents it from compiling under CMake 4.0.
in order to fix that, I had to take this thing out of submodules...

it is recommended to do this after you pull;

git submodule deinit extern/libsndfile
2025-04-02 15:09:53 -05:00

359 lines
7.8 KiB
C

/*
* Copyright (c) 2011 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* 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.
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
/*
File: ag_dec.c
Contains: Adaptive Golomb decode routines.
Copyright: (c) 2001-2011 Apple, Inc.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aglib.h"
#include "ALACBitUtilities.h"
#include "ALACAudioTypes.h"
#define CODE_TO_LONG_MAXBITS 32
#define N_MAX_MEAN_CLAMP 0xffff
#define N_MEAN_CLAMP_VAL 0xffff
#define REPORT_VAL 40
#if __GNUC__
#define ALWAYS_INLINE __attribute__ ((always_inline))
#elif defined _MSC_VER
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE
#endif
/* And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
to help the compiler out. In many cases this required manual inlining or a macro. Sorry
if it is ugly but the performance gains are well worth it.
- WSK 5/19/04
*/
void set_standard_ag_params (AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth)
{
/* Use
fullwidth = sectorwidth = numOfSamples, for analog 1-dimensional type-short data,
but use
fullwidth = full image width, sectorwidth = sector (patch) width
for such as image (2-dim.) data.
*/
set_ag_params (params, MB0, PB0, KB0, fullwidth, sectorwidth, MAX_RUN_DEFAULT) ;
}
void set_ag_params (AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun)
{
params->mb = params->mb0 = m ;
params->pb = p ;
params->kb = k ;
params->wb = (1u << params->kb) - 1 ;
params->qb = QB-params->pb ;
params->fw = f ;
params->sw = s ;
params->maxrun = maxrun ;
}
#if PRAGMA_MARK
#pragma mark -
#endif
// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
static inline int32_t lead (int32_t m)
{
long j ;
unsigned long c = (1ul << 31) ;
for (j = 0 ; j < 32 ; j++)
{
if ((c & m) != 0)
break ;
c >>= 1 ;
}
return j ;
}
#define arithmin(a, b) ((a) < (b) ? (a) : (b))
static inline int32_t ALWAYS_INLINE lg3a (int32_t x)
{
int32_t result ;
x += 3 ;
result = lead (x) ;
return 31 - result ;
}
static inline uint32_t ALWAYS_INLINE read32bit (uint8_t * buffer)
{
// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
uint32_t value ;
value = ((uint32_t) buffer [0] << 24) | ((uint32_t) buffer [1] << 16) |
((uint32_t) buffer [2] << 8) | (uint32_t) buffer [3] ;
return value ;
}
#if PRAGMA_MARK
#pragma mark -
#endif
#define get_next_fromlong(inlong, suff) ((inlong) >> (32 - (suff)))
static inline uint32_t ALWAYS_INLINE
getstreambits (uint8_t *in, int32_t bitoffset, int32_t numbits)
{
uint32_t load1, load2 ;
uint32_t byteoffset = bitoffset / 8 ;
uint32_t result ;
//Assert (numbits <= 32) ;
load1 = read32bit (in + byteoffset) ;
if ((numbits + (bitoffset & 0x7)) > 32)
{
int32_t load2shift ;
result = load1 << (bitoffset & 0x7) ;
load2 = (uint32_t) in [byteoffset + 4] ;
load2shift = (8 - (numbits + (bitoffset & 0x7) - 32)) ;
load2 >>= load2shift ;
result >>= (32 - numbits) ;
result |= load2 ;
}
else
{
result = load1 >> (32 - numbits - (bitoffset & 7)) ;
}
// a shift of >= "the number of bits in the type of the value being shifted" results in undefined
// behavior so don't try to shift by 32
if (numbits != (sizeof (result) * 8))
result &= ~ (0xfffffffful << numbits) ;
return result ;
}
static inline int32_t dyn_get (unsigned char *in, uint32_t *bitPos, uint32_t m, uint32_t k)
{
uint32_t tempbits = *bitPos ;
uint32_t result ;
uint32_t pre = 0, v ;
uint32_t streamlong ;
streamlong = read32bit (in + (tempbits >> 3)) ;
streamlong <<= (tempbits & 7) ;
/* find the number of bits in the prefix */
{
uint32_t notI = ~streamlong ;
pre = lead (notI) ;
}
if (pre >= MAX_PREFIX_16)
{
pre = MAX_PREFIX_16 ;
tempbits += pre ;
streamlong <<= pre ;
result = get_next_fromlong (streamlong, MAX_DATATYPE_BITS_16) ;
tempbits += MAX_DATATYPE_BITS_16 ;
}
else
{
// all of the bits must fit within the long we have loaded
//Assert (pre+1+k <= 32) ;
tempbits += pre ;
tempbits += 1 ;
streamlong <<= pre + 1 ;
v = get_next_fromlong (streamlong, k) ;
tempbits += k ;
result = pre*m + v-1 ;
if (v < 2)
{
result -= (v-1) ;
tempbits -= 1 ;
}
}
*bitPos = tempbits ;
return result ;
}
static inline int32_t dyn_get_32bit (uint8_t * in, uint32_t * bitPos, int32_t m, int32_t k, int32_t maxbits)
{
uint32_t tempbits = *bitPos ;
uint32_t v ;
uint32_t streamlong ;
uint32_t result ;
streamlong = read32bit (in + (tempbits >> 3)) ;
streamlong <<= (tempbits & 7) ;
/* find the number of bits in the prefix */
{
uint32_t notI = ~streamlong ;
result = lead (notI) ;
}
if (result >= MAX_PREFIX_32)
{
result = getstreambits (in, tempbits+MAX_PREFIX_32, maxbits) ;
tempbits += MAX_PREFIX_32 + maxbits ;
}
else
{
/* all of the bits must fit within the long we have loaded*/
//Assert (k<=14) ;
//Assert (result<MAX_PREFIX_32) ;
//Assert (result+1+k <= 32) ;
tempbits += result ;
tempbits += 1 ;
if (k != 1)
{
streamlong <<= result + 1 ;
v = get_next_fromlong (streamlong, k) ;
tempbits += k ;
tempbits -= 1 ;
result = result*m ;
if (v >= 2)
{
result += (v-1) ;
tempbits += 1 ;
}
}
}
*bitPos = tempbits ;
return result ;
}
int32_t dyn_decomp (AGParamRecPtr params, BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits)
{
uint8_t *in ;
int32_t *outPtr = pc ;
uint32_t bitPos, startPos, maxPos ;
uint32_t j, m, k, n, c, mz ;
int32_t del, zmode ;
uint32_t mb ;
uint32_t pb_local = params->pb ;
uint32_t kb_local = params->kb ;
uint32_t wb_local = params->wb ;
int32_t status ;
RequireAction ((bitstream != NULL) && (pc != NULL) && (outNumBits != NULL), return kALAC_ParamError ;) ;
*outNumBits = 0 ;
in = bitstream->cur ;
startPos = bitstream->bitIndex ;
maxPos = bitstream->byteSize * 8 ;
bitPos = startPos ;
mb = params->mb0 ;
zmode = 0 ;
c = 0 ;
status = ALAC_noErr ;
while (c < (uint32_t) numSamples)
{
// bail if we've run off the end of the buffer
RequireAction (bitPos < maxPos, status = kALAC_ParamError ; goto Exit ;) ;
m = (mb) >> QBSHIFT ;
k = lg3a (m) ;
k = arithmin (k, kb_local) ;
m = (1 << k) - 1 ;
n = dyn_get_32bit (in, &bitPos, m, k, maxSize) ;
// least significant bit is sign bit
{
uint32_t ndecode = n + zmode ;
int32_t multiplier = - (int) (ndecode & 1) ;
multiplier |= 1 ;
del = ((ndecode+1) >> 1) * (multiplier) ;
}
*outPtr++ = del ;
c++ ;
mb = pb_local * (n + zmode) + mb - ((pb_local * mb) >> QBSHIFT) ;
// update mean tracking
if (n > N_MAX_MEAN_CLAMP)
mb = N_MEAN_CLAMP_VAL ;
zmode = 0 ;
if (((mb << MMULSHIFT) < QB) && (c < (uint32_t) numSamples))
{
zmode = 1 ;
k = lead (mb) - BITOFF + ((mb + MOFF) >> MDENSHIFT) ;
mz = ((1 << k) - 1) & wb_local ;
n = dyn_get (in, &bitPos, mz, k) ;
RequireAction (c+n <= (uint32_t) numSamples, status = kALAC_ParamError ; goto Exit ;) ;
for (j = 0 ; j < n ; j++)
{
*outPtr++ = 0 ;
++c ;
}
if (n >= 65535)
zmode = 0 ;
mb = 0 ;
}
}
Exit:
*outNumBits = (bitPos - startPos) ;
BitBufferAdvance (bitstream, *outNumBits) ;
RequireAction (bitstream->cur <= bitstream->end, status = kALAC_ParamError ;) ;
return status ;
}