1
0
mirror of https://github.com/YGGverse/xash3d-fwgs.git synced 2025-01-09 14:47:59 +00:00
xash3d-fwgs/engine/common/soundlib/libmpg/synth.c
Gleb Mazovetskiy 5e0a0765ce Trim all trailing whitespace
The `.editorconfig` file in this repo is configured to trim all trailing
whitespace regardless of whether the line is modified.

Trims all trailing whitespace in the repository to make the codebase easier
to work with in editors that respect `.editorconfig`.

`git blame` becomes less useful on these lines but it already isn't very useful.

Commands:

```
find . -type f -name '*.h' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
find . -type f -name '*.c' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
```
2021-01-04 20:55:10 +03:00

312 lines
7.8 KiB
C

/*
synth.c - compact version of famous library mpg123
Copyright (C) 2017 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "mpg123.h"
#include "sample.h"
#define BACKPEDAL 0x10 // we use autoincrement and thus need this re-adjustment for window/b0.
#define BLOCK 0x40 // one decoding block is 64 samples.
#define WRITE_SHORT_SAMPLE( samples, sum, clip ) \
if(( sum ) > 32767.0f ) { *(samples) = 0x7fff; (clip)++; } \
else if(( sum ) < -32768.0f ) { *(samples) = -0x8000; (clip)++; } \
else { *(samples) = REAL_TO_SHORT( sum ); }
// main synth function, uses the plain dct64
int synth_1to1( float *bandPtr, int channel, mpg123_handle_t *fr, int final )
{
static const int step = 2;
short *samples = (short *) (fr->buffer.data + fr->buffer.fill);
float *b0, **buf; // (*buf)[0x110];
int clip = 0;
int bo1;
if( !channel )
{
fr->bo--;
fr->bo &= 0xf;
buf = fr->float_buffs[0];
}
else
{
samples++;
buf = fr->float_buffs[1];
}
if( fr->bo & 0x1 )
{
b0 = buf[0];
bo1 = fr->bo;
dct64( buf[1] + ((fr->bo + 1) & 0xf ), buf[0] + fr->bo, bandPtr );
}
else
{
b0 = buf[1];
bo1 = fr->bo+1;
dct64( buf[0] + fr->bo, buf[1] + fr->bo + 1, bandPtr );
}
{
float *window = fr->decwin + 16 - bo1;
register int j;
for( j = (BLOCK / 4); j; j--, b0 += 0x400 / BLOCK - BACKPEDAL, window += 0x800 / BLOCK - BACKPEDAL, samples += step )
{
float sum;
sum = REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
sum += REAL_MUL_SYNTH( *window++, *b0++ );
sum -= REAL_MUL_SYNTH( *window++, *b0++ );
WRITE_SHORT_SAMPLE( samples, sum, clip );
}
{
float sum;
sum = REAL_MUL_SYNTH( window[0x0], b0[0x0] );
sum += REAL_MUL_SYNTH( window[0x2], b0[0x2] );
sum += REAL_MUL_SYNTH( window[0x4], b0[0x4] );
sum += REAL_MUL_SYNTH( window[0x6], b0[0x6] );
sum += REAL_MUL_SYNTH( window[0x8], b0[0x8] );
sum += REAL_MUL_SYNTH( window[0xA], b0[0xA] );
sum += REAL_MUL_SYNTH( window[0xC], b0[0xC] );
sum += REAL_MUL_SYNTH( window[0xE], b0[0xE] );
WRITE_SHORT_SAMPLE( samples, sum, clip );
samples += step;
b0 -= 0x400 / BLOCK;
window -= 0x800 / BLOCK;
}
window += bo1<<1;
for( j= (BLOCK / 4) - 1; j; j--, b0 -= 0x400 / BLOCK + BACKPEDAL, window -= 0x800 / BLOCK - BACKPEDAL, samples += step )
{
float sum;
sum = -REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
sum -= REAL_MUL_SYNTH( *(--window), *b0++ );
WRITE_SHORT_SAMPLE( samples, sum, clip );
}
}
if( final ) fr->buffer.fill += BLOCK * sizeof( short );
return clip;
}
// the call of left and right plain synth, wrapped.
// this may be replaced by a direct stereo optimized synth.
static int synth_stereo( float *bandPtr_l, float *bandPtr_r, mpg123_handle_t *fr )
{
int clip;
clip = (fr->synth)( bandPtr_l, 0, fr, 0 );
clip += (fr->synth)( bandPtr_r, 1, fr, 1 );
return clip;
}
// mono to stereo synth, wrapping over synth_1to1
int synth_1to1_m2s(float *bandPtr, mpg123_handle_t *fr )
{
byte *samples = fr->buffer.data;
int i, ret;
ret = synth_1to1( bandPtr, 0, fr, 1 );
samples += fr->buffer.fill - BLOCK * sizeof( short );
for( i = 0; i < (BLOCK / 2); i++ )
{
((short *)samples)[1] = ((short *)samples)[0];
samples += 2 * sizeof( short );
}
return ret;
}
// mono synth, wrapping over synth_1to1
int synth_1to1_mono( float *bandPtr, mpg123_handle_t *fr )
{
short samples_tmp[BLOCK];
short *tmp1 = samples_tmp;
byte *samples = fr->buffer.data;
int pnt = fr->buffer.fill;
int i, ret;
// save buffer stuff, trick samples_tmp into there, decode, restore
fr->buffer.data = (byte *)samples_tmp;
fr->buffer.fill = 0;
ret = synth_1to1( bandPtr, 0, fr, 0 ); // decode into samples_tmp
fr->buffer.data = samples; // restore original value
// now append samples from samples_tmp
samples += pnt; // just the next mem in frame buffer
for( i = 0; i < (BLOCK / 2); i++ )
{
*((short *)samples) = *tmp1;
samples += sizeof( short );
tmp1 += 2;
}
fr->buffer.fill = pnt + (BLOCK / 2) * sizeof( short );
return ret;
}
static const struct synth_s synth_base =
{
{
{ synth_1to1 } // plain
},
{
{ synth_stereo } // stereo, by default only wrappers over plain synth
},
{
{ synth_1to1_m2s } // mono2stereo
},
{
{ synth_1to1_mono } // mono
}
};
void init_synth( mpg123_handle_t *fr )
{
fr->synths = synth_base;
}
static int find_synth(func_synth synth, const func_synth synths[r_limit][f_limit])
{
enum synth_resample ri;
enum synth_format fi;
for( ri = 0; ri < r_limit; ++ri )
{
for( fi = 0; fi < f_limit; ++fi )
{
if( synth == synths[ri][fi] )
return TRUE;
}
}
return FALSE;
}
enum optdec
{
autodec = 0,
generic,
nodec
};
// determine what kind of decoder is actually active
// this depends on runtime choices which may cause fallback to i386 or generic code.
static int find_dectype( mpg123_handle_t *fr )
{
enum optdec type = nodec;
func_synth basic_synth = fr->synth;
if( find_synth( basic_synth, synth_base.plain ))
type = generic;
if( type != nodec )
{
return MPG123_OK;
}
else
{
fr->err = MPG123_BAD_DECODER_SETUP;
return MPG123_ERR;
}
}
// set synth functions for current frame
int set_synth_functions( mpg123_handle_t *fr )
{
enum synth_resample resample = r_none;
enum synth_format basic_format = f_none; // default is always 16bit, or whatever.
if( fr->af.dec_enc & MPG123_ENC_16 )
basic_format = f_16;
// make sure the chosen format is compiled into this lib.
if( basic_format == f_none )
return -1;
// be explicit about downsampling variant.
switch( fr->down_sample )
{
case 0: resample = r_1to1; break;
}
if( resample == r_none )
return -1;
// finally selecting the synth functions for stereo / mono.
fr->synth = fr->synths.plain[resample][basic_format];
fr->synth_stereo = fr->synths.stereo[resample][basic_format];
fr->synth_mono = fr->af.channels == 2 ? fr->synths.mono2stereo[resample][basic_format] : fr->synths.mono[resample][basic_format];
if( find_dectype( fr ) != MPG123_OK )
{
fr->err = MPG123_BAD_DECODER_SETUP;
return MPG123_ERR;
}
if( frame_buffers( fr ) != 0 )
{
fr->err = MPG123_NO_BUFFERS;
return MPG123_ERR;
}
init_layer3_stuff( fr );
fr->make_decode_tables = make_decode_tables;
// we allocated the table buffers just now, so (re)create the tables.
fr->make_decode_tables( fr );
return 0;
}