/* 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; }