/* synth.c: The functions for synthesizing samples, at the end of decoding. copyright 1995-2008 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.org initially written by Michael Hipp, heavily dissected and rearranged by Thomas Orgis */ #include "mpg123lib_intern.h" #ifdef OPT_GENERIC_DITHER #define FORCE_ACCURATE #endif #include "sample.h" #include "debug.h" /* Part 1: All synth functions that produce signed short. That is: - synth_1to1 with cpu-specific variants (synth_1to1_i386, synth_1to1_i586 ...) - synth_1to1_mono and synth_1to1_m2s; which use fr->synths.plain[r_1to1][f_16]. Nearly every decoder variant has it's own synth_1to1, while the mono conversion is shared. */ #define SAMPLE_T short #define WRITE_SAMPLE(samples,sum,clip) WRITE_SHORT_SAMPLE(samples,sum,clip) /* Part 1a: All straight 1to1 decoding functions */ #define BLOCK 0x40 /* One decoding block is 64 samples. */ #define SYNTH_NAME synth_1to1 #include "synth.h" #undef SYNTH_NAME /* Mono-related synths; they wrap over _some_ synth_1to1. */ #define SYNTH_NAME fr->synths.plain[r_1to1][f_16] #define MONO_NAME synth_1to1_mono #define MONO2STEREO_NAME synth_1to1_m2s #include "synth_mono.h" #undef SYNTH_NAME #undef MONO_NAME #undef MONO2STEREO_NAME /* Now we have possibly some special synth_1to1 ... ... they produce signed short; the mono functions defined above work on the special synths, too. */ #ifdef OPT_GENERIC_DITHER #define SYNTH_NAME synth_1to1_dither /* We need the accurate sample writing... */ #undef WRITE_SAMPLE #define WRITE_SAMPLE(samples,sum,clip) WRITE_SHORT_SAMPLE_ACCURATE(samples,sum,clip) #define USE_DITHER #include "synth.h" #undef USE_DITHER #undef SYNTH_NAME #undef WRITE_SAMPLE #define WRITE_SAMPLE(samples,sum,clip) WRITE_SHORT_SAMPLE(samples,sum,clip) #endif #ifdef OPT_X86 /* The i386-specific C code, here as short variant, later 8bit and float. */ #define NO_AUTOINCREMENT #define SYNTH_NAME synth_1to1_i386 #include "synth.h" #undef SYNTH_NAME /* i386 uses the normal mono functions. */ #undef NO_AUTOINCREMENT #endif #undef BLOCK /* Following functions are so special that they don't need this. */ #ifdef OPT_I586 /* This is defined in assembler. */ int synth_1to1_i586_asm(real *bandPtr, int channel, unsigned char *out, unsigned char *buffs, int *bo, real *decwin); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_i586(real *bandPtr, int channel, mpg123_handle *fr, int final) { int ret; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif ret = synth_1to1_i586_asm(bandPtr, channel, fr->buffer.data+fr->buffer.fill, fr->rawbuffs, &fr->bo, fr->decwin); if(final) fr->buffer.fill += 128; return ret; } #endif #ifdef OPT_I586_DITHER /* This is defined in assembler. */ int synth_1to1_i586_asm_dither(real *bandPtr, int channel, unsigned char *out, unsigned char *buffs, int *bo, real *decwin, float *dithernoise); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_i586_dither(real *bandPtr, int channel, mpg123_handle *fr, int final) { int ret; int bo_dither[2]; /* Temporary workaround? Could expand the asm code. */ #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif /* Applying this hack, to change the asm only bit by bit (adding dithernoise pointer). */ bo_dither[0] = fr->bo; bo_dither[1] = fr->ditherindex; ret = synth_1to1_i586_asm_dither(bandPtr, channel, fr->buffer.data+fr->buffer.fill, fr->rawbuffs, bo_dither, fr->decwin, fr->dithernoise); fr->bo = bo_dither[0]; fr->ditherindex = bo_dither[1]; if(final) fr->buffer.fill += 128; return ret; } #endif #if defined(OPT_3DNOW) || defined(OPT_3DNOW_VINTAGE) /* Those are defined in assembler. */ void do_equalizer_3dnow(real *bandPtr,int channel, real equalizer[2][32]); int synth_1to1_3dnow_asm(real *bandPtr, int channel, unsigned char *out, unsigned char *buffs, int *bo, real *decwin); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_3dnow(real *bandPtr, int channel, mpg123_handle *fr, int final) { int ret; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer_3dnow(bandPtr,channel,fr->equalizer); #endif /* this is in asm, can be dither or not */ /* uh, is this return from pointer correct? */ ret = (int) synth_1to1_3dnow_asm(bandPtr, channel, fr->buffer.data+fr->buffer.fill, fr->rawbuffs, &fr->bo, fr->decwin); if(final) fr->buffer.fill += 128; return ret; } #endif #ifdef OPT_MMX /* This is defined in assembler. */ int synth_1to1_MMX(real *bandPtr, int channel, short *out, short *buffs, int *bo, float *decwins); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_mmx(real *bandPtr, int channel, mpg123_handle *fr, int final) { #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif /* in asm */ synth_1to1_MMX(bandPtr, channel, (short*) (fr->buffer.data+fr->buffer.fill), (short *) fr->rawbuffs, &fr->bo, fr->decwins); if(final) fr->buffer.fill += 128; return 0; } #endif #if defined(OPT_SSE) || defined(OPT_SSE_VINTAGE) #ifdef ACCURATE_ROUNDING /* This is defined in assembler. */ int synth_1to1_sse_accurate_asm(real *window, real *b0, short *samples, int bo1); int synth_1to1_s_sse_accurate_asm(real *window, real *b0l, real *b0r, short *samples, int bo1); void dct64_real_sse(real *out0, real *out1, real *samples); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_sse(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_real_sse(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_real_sse(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_sse_accurate_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_sse(real *bandPtr_l, real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0l, *b0r, **bufl, **bufr; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->real_buffs[0]; bufr = fr->real_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_real_sse(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_real_sse(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_real_sse(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_real_sse(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_sse_accurate_asm(fr->decwin, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #else /* This is defined in assembler. */ void synth_1to1_sse_asm(real *bandPtr, int channel, short *samples, short *buffs, int *bo, real *decwin); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_sse(real *bandPtr, int channel, mpg123_handle *fr, int final) { #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif synth_1to1_sse_asm(bandPtr, channel, (short*) (fr->buffer.data+fr->buffer.fill), (short *) fr->rawbuffs, &fr->bo, fr->decwins); if(final) fr->buffer.fill += 128; return 0; } #endif #endif #if defined(OPT_3DNOWEXT) || defined(OPT_3DNOWEXT_VINTAGE) /* This is defined in assembler. */ void synth_1to1_3dnowext_asm(real *bandPtr, int channel, short *samples, short *buffs, int *bo, real *decwin); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_3dnowext(real *bandPtr, int channel, mpg123_handle *fr, int final) { #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif synth_1to1_3dnowext_asm(bandPtr, channel, (short*) (fr->buffer.data+fr->buffer.fill), (short *) fr->rawbuffs, &fr->bo, fr->decwins); if(final) fr->buffer.fill += 128; return 0; } #endif #ifdef OPT_X86_64 #ifdef ACCURATE_ROUNDING /* Assembler routines. */ int synth_1to1_x86_64_accurate_asm(real *window, real *b0, short *samples, int bo1); int synth_1to1_s_x86_64_accurate_asm(real *window, real *b0l, real *b0r, short *samples, int bo1); void dct64_real_x86_64(real *out0, real *out1, real *samples); /* Hull for C mpg123 API */ int synth_1to1_x86_64(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_real_x86_64(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_real_x86_64(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_x86_64_accurate_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_x86_64(real *bandPtr_l, real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0l, *b0r, **bufl, **bufr; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->real_buffs[0]; bufr = fr->real_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_real_x86_64(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_real_x86_64(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_real_x86_64(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_real_x86_64(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_x86_64_accurate_asm(fr->decwin, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #else /* This is defined in assembler. */ int synth_1to1_x86_64_asm(short *window, short *b0, short *samples, int bo1); int synth_1to1_s_x86_64_asm(short *window, short *b0l, short *b0r, short *samples, int bo1); void dct64_x86_64(short *out0, short *out1, real *samples); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_x86_64(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0, **buf; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->short_buffs[0]; } else { samples++; buf = fr->short_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_x86_64(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_x86_64(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_x86_64_asm((short *)fr->decwins, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_x86_64(real *bandPtr_l,real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0l, *b0r, **bufl, **bufr; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->short_buffs[0]; bufr = fr->short_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_x86_64(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_x86_64(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_x86_64(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_x86_64(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_x86_64_asm((short *)fr->decwins, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #endif #endif #ifdef OPT_AVX #ifdef ACCURATE_ROUNDING /* Assembler routines. */ #ifndef OPT_X86_64 int synth_1to1_x86_64_accurate_asm(real *window, real *b0, short *samples, int bo1); #endif int synth_1to1_s_avx_accurate_asm(real *window, real *b0l, real *b0r, short *samples, int bo1); void dct64_real_avx(real *out0, real *out1, real *samples); /* Hull for C mpg123 API */ int synth_1to1_avx(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_real_avx(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_real_avx(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_x86_64_accurate_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_avx(real *bandPtr_l, real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0l, *b0r, **bufl, **bufr; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->real_buffs[0]; bufr = fr->real_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_real_avx(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_real_avx(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_real_avx(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_real_avx(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_avx_accurate_asm(fr->decwin, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #else /* This is defined in assembler. */ #ifndef OPT_X86_64 int synth_1to1_x86_64_asm(short *window, short *b0, short *samples, int bo1); #endif int synth_1to1_s_avx_asm(short *window, short *b0l, short *b0r, short *samples, int bo1); void dct64_avx(short *out0, short *out1, real *samples); /* This is just a hull to use the mpg123 handle. */ int synth_1to1_avx(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0, **buf; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->short_buffs[0]; } else { samples++; buf = fr->short_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_avx(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_avx(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_x86_64_asm((short *)fr->decwins, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_avx(real *bandPtr_l,real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0l, *b0r, **bufl, **bufr; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->short_buffs[0]; bufr = fr->short_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_avx(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_avx(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_avx(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_avx(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_avx_asm((short *)fr->decwins, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #endif #endif #ifdef OPT_ARM #ifdef ACCURATE_ROUNDING /* Assembler routines. */ int synth_1to1_arm_accurate_asm(real *window, real *b0, short *samples, int bo1); /* Hull for C mpg123 API */ int synth_1to1_arm(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_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); } clip = synth_1to1_arm_accurate_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } #else /* Assembler routines. */ int synth_1to1_arm_asm(real *window, real *b0, short *samples, int bo1); /* Hull for C mpg123 API */ int synth_1to1_arm(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_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); } clip = synth_1to1_arm_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } #endif #endif #ifdef OPT_NEON #ifdef ACCURATE_ROUNDING /* This is defined in assembler. */ int synth_1to1_neon_accurate_asm(real *window, real *b0, short *samples, int bo1); int synth_1to1_s_neon_accurate_asm(real *window, real *b0l, real *b0r, short *samples, int bo1); void dct64_real_neon(real *out0, real *out1, real *samples); /* Hull for C mpg123 API */ int synth_1to1_neon(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_real_neon(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_real_neon(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_neon_accurate_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_neon(real *bandPtr_l, real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0l, *b0r, **bufl, **bufr; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->real_buffs[0]; bufr = fr->real_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_real_neon(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_real_neon(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_real_neon(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_real_neon(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_neon_accurate_asm(fr->decwin, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #else /* This is defined in assembler. */ int synth_1to1_neon_asm(short *window, short *b0, short *samples, int bo1); int synth_1to1_s_neon_asm(short *window, short *b0l, short *b0r, short *samples, int bo1); void dct64_neon(short *out0, short *out1, real *samples); /* Hull for C mpg123 API */ int synth_1to1_neon(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0, **buf; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->short_buffs[0]; } else { samples++; buf = fr->short_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_neon(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_neon(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_neon_asm((short *)fr->decwins, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_neon(real *bandPtr_l,real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0l, *b0r, **bufl, **bufr; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->short_buffs[0]; bufr = fr->short_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_neon(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_neon(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_neon(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_neon(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_neon_asm((short *)fr->decwins, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #endif #endif #ifdef OPT_NEON64 #ifdef ACCURATE_ROUNDING /* This is defined in assembler. */ int synth_1to1_neon64_accurate_asm(real *window, real *b0, short *samples, int bo1); int synth_1to1_s_neon64_accurate_asm(real *window, real *b0l, real *b0r, short *samples, int bo1); void dct64_real_neon64(real *out0, real *out1, real *samples); /* Hull for C mpg123 API */ int synth_1to1_neon64(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0, **buf; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->real_buffs[0]; } else { samples++; buf = fr->real_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_real_neon64(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_real_neon64(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_neon64_accurate_asm(fr->decwin, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_neon64(real *bandPtr_l, real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); real *b0l, *b0r, **bufl, **bufr; int bo1; int clip; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->real_buffs[0]; bufr = fr->real_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_real_neon64(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_real_neon64(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_real_neon64(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_real_neon64(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_neon64_accurate_asm(fr->decwin, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #else /* This is defined in assembler. */ int synth_1to1_neon64_asm(short *window, short *b0, short *samples, int bo1); int synth_1to1_s_neon64_asm(short *window, short *b0l, short *b0r, short *samples, int bo1); void dct64_neon64(short *out0, short *out1, real *samples); /* Hull for C mpg123 API */ int synth_1to1_neon64(real *bandPtr,int channel, mpg123_handle *fr, int final) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0, **buf; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) do_equalizer(bandPtr,channel,fr->equalizer); #endif if(!channel) { fr->bo--; fr->bo &= 0xf; buf = fr->short_buffs[0]; } else { samples++; buf = fr->short_buffs[1]; } if(fr->bo & 0x1) { b0 = buf[0]; bo1 = fr->bo; dct64_neon64(buf[1]+((fr->bo+1)&0xf),buf[0]+fr->bo,bandPtr); } else { b0 = buf[1]; bo1 = fr->bo+1; dct64_neon64(buf[0]+fr->bo,buf[1]+fr->bo+1,bandPtr); } clip = synth_1to1_neon64_asm((short *)fr->decwins, b0, samples, bo1); if(final) fr->buffer.fill += 128; return clip; } int synth_1to1_stereo_neon64(real *bandPtr_l,real *bandPtr_r, mpg123_handle *fr) { short *samples = (short *) (fr->buffer.data+fr->buffer.fill); short *b0l, *b0r, **bufl, **bufr; int clip; int bo1; #ifndef NO_EQUALIZER if(fr->have_eq_settings) { do_equalizer(bandPtr_l,0,fr->equalizer); do_equalizer(bandPtr_r,1,fr->equalizer); } #endif fr->bo--; fr->bo &= 0xf; bufl = fr->short_buffs[0]; bufr = fr->short_buffs[1]; if(fr->bo & 0x1) { b0l = bufl[0]; b0r = bufr[0]; bo1 = fr->bo; dct64_neon64(bufl[1]+((fr->bo+1)&0xf),bufl[0]+fr->bo,bandPtr_l); dct64_neon64(bufr[1]+((fr->bo+1)&0xf),bufr[0]+fr->bo,bandPtr_r); } else { b0l = bufl[1]; b0r = bufr[1]; bo1 = fr->bo+1; dct64_neon64(bufl[0]+fr->bo,bufl[1]+fr->bo+1,bandPtr_l); dct64_neon64(bufr[0]+fr->bo,bufr[1]+fr->bo+1,bandPtr_r); } clip = synth_1to1_s_neon64_asm((short *)fr->decwins, b0l, b0r, samples, bo1); fr->buffer.fill += 128; return clip; } #endif #endif #ifndef NO_DOWNSAMPLE /* Part 1b: 2to1 synth. Only generic and i386 functions this time. */ #define BLOCK 0x20 /* One decoding block is 32 samples. */ #define SYNTH_NAME synth_2to1 #include "synth.h" #undef SYNTH_NAME #ifdef OPT_DITHER /* Used for generic_dither and as fallback for i586_dither. */ #define SYNTH_NAME synth_2to1_dither #define USE_DITHER #include "synth.h" #undef USE_DITHER #undef SYNTH_NAME #endif #define SYNTH_NAME fr->synths.plain[r_2to1][f_16] #define MONO_NAME synth_2to1_mono #define MONO2STEREO_NAME synth_2to1_m2s #include "synth_mono.h" #undef SYNTH_NAME #undef MONO_NAME #undef MONO2STEREO_NAME #ifdef OPT_X86 #define NO_AUTOINCREMENT #define SYNTH_NAME synth_2to1_i386 #include "synth.h" #undef SYNTH_NAME /* i386 uses the normal mono functions. */ #undef NO_AUTOINCREMENT #endif #undef BLOCK /* Part 1c: 4to1 synth. Same procedure as above... */ #define BLOCK 0x10 /* One decoding block is 16 samples. */ #define SYNTH_NAME synth_4to1 #include "synth.h" #undef SYNTH_NAME #ifdef OPT_DITHER #define SYNTH_NAME synth_4to1_dither #define USE_DITHER #include "synth.h" #undef USE_DITHER #undef SYNTH_NAME #endif #define SYNTH_NAME fr->synths.plain[r_4to1][f_16] /* This is just for the _i386 one... gotta check if it is really useful... */ #define MONO_NAME synth_4to1_mono #define MONO2STEREO_NAME synth_4to1_m2s #include "synth_mono.h" #undef SYNTH_NAME #undef MONO_NAME #undef MONO2STEREO_NAME #ifdef OPT_X86 #define NO_AUTOINCREMENT #define SYNTH_NAME synth_4to1_i386 #include "synth.h" #undef SYNTH_NAME /* i386 uses the normal mono functions. */ #undef NO_AUTOINCREMENT #endif #undef BLOCK #endif /* NO_DOWNSAMPLE */ #ifndef NO_NTOM /* Part 1d: ntom synth. Same procedure as above... Just no extra play anymore, straight synth that uses the plain dct64. */ /* These are all in one header, there's no flexibility to gain. */ #define SYNTH_NAME synth_ntom #define MONO_NAME synth_ntom_mono #define MONO2STEREO_NAME synth_ntom_m2s #include "synth_ntom.h" #undef SYNTH_NAME #undef MONO_NAME #undef MONO2STEREO_NAME #endif /* Done with short output. */ #undef SAMPLE_T #undef WRITE_SAMPLE