You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
7.9 KiB
311 lines
7.9 KiB
/* |
|
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 |
|
static 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 |
|
static 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 |
|
static 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; |
|
}
|
|
|