Mercurial > audlegacy-plugins
diff src/sndstretch/sndstretch.c @ 881:6bb0e52df3d6 trunk
[svn] - Made port of XMMS plugin SndStretch
author | mf0102 |
---|---|
date | Tue, 20 Mar 2007 12:22:25 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sndstretch/sndstretch.c Tue Mar 20 12:22:25 2007 -0700 @@ -0,0 +1,1298 @@ +// sndstretch.c +// +// sndstretch - algorithm for adjusting pitch and speed of s16le data +// Copyright (C) 2000 Florian Berger +// Email: florian.berger@jk.uni-linz.ac.at +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License Version 2 as +// published by the Free Software Foundation; +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +//#define DEBUG + +#include<stdio.h> +#include<stdlib.h> +#include<math.h> +#include"sndstretch.h" + + +static double _1_div_e = 0.367879441; // 1/e +static double _1_m_1_div_e = 0.632120558; // 1-1/e + +#define RESMAX 65536 +#define RESMAXVC 32768 +#define LOG2RESMAX 16 +#define LOG2RESMAXVC 15 +static int _1_div_e_i = 24109; // 1/e * 2^LOG2RESMAX +static int _1_m_1_div_e_i = 41427; // 1-1/e * 2^LOG2RESMAX +static int _1_div_e_i_vc = 12055; // 1/e * 2^LOG2RESMAXVC +static int _1_m_1_div_e_i_vc = 28333; // sqrt(1-1/e^2) * 2^LOG2RESMAXVC +//static int _1_div_e_i = 12055; // 1/e * 2^LOG2RESMAX +//static int _1_m_1_div_e_i = 20713; // 1-1/e * 2^LOG2RESMAX + + +void InitScaleJob( ScaleJob * job ) +{ + /* nothing to do */ +} + + +void InitStretchJob( StretchJob * job ) +{ + job->is_initialized=0; + job->snr_rest=0.0; +} + + +void InitPitchSpeedJob( PitchSpeedJob * job ) +{ + job->ring_buff = (s16*)0; // init me = (s16*)0 + job->ring_buff_old = (s16*)0; // init me = (s16*)0 + job->buff_help = (s16*)0; // init me = (s16*)0 + job->ring_size = 1; // init me = 1 + job->ring_size_old = 0; // init me = 0 + job->ring_pos_w = 0; // init me = 0 + job->ring_pos_r = 0; // init me = 0 + job->is_init = 0; // init me = 0 + job->speed_act = 0; // init me = 0 + job->pitch_act = 0; // init me = 0 + job->fade_shift_act = 0; + InitStretchJob(&(job->stretch_job)); + InitScaleJob(&(job->scale_job)); +} + + + +void CleanupPitchSpeedJob( PitchSpeedJob * job ) +{ + free(job->ring_buff); + free(job->ring_buff_old); + free(job->buff_help); +} + + + +inline int ringpos( int pos, int size ) +{ + while ( pos >= size ) pos-=size; + while ( pos < 0 ) pos+=size; + return( pos ); +} + + +void ringload( s16 * ringbuff, int ring_size, int pos, s16 *buffer, int size ) +/* put <size> samples to ring with size <ring_size> on position <pos> */ +{ + int i,j; + + j=0; + if( pos+size > ring_size ){ + for( i=pos; i<ring_size; i++,j++ ) ringbuff[i]=buffer[j]; + for( i=0; i<size-ring_size+pos; i++,j++ ) ringbuff[i]=buffer[j]; + }else{ + for( i=pos; i<size+pos; i++,j++ ) ringbuff[i]=buffer[j]; + } +} + + +void ringcopy( s16 * src_ring, int src_size, int src_from, int src_to, + s16 * dest_ring, int dest_size, int dest_pos ) +{ + int is,id; + + is=src_from; id=dest_pos; + while( is!=src_to ){ + dest_ring[id]=src_ring[is]; + is=ringpos(is+1,src_size); + id=ringpos(id+1,dest_size); + } +} + + +void ringload_IIR_1_div_e_echo_d( s16 * ringbuff, int ring_size, int pos, s16 *buffer, int size , int delay) +/* put <size> samples to ring with size <ring_size> on position <pos> */ +{ + int i,p1,p2; + + p1=pos, p2=ringpos(p1-delay, ring_size); + for( i=0; i<size; i++ ){ + ringbuff[p1] =(s16)( (double)buffer[i]*_1_m_1_div_e + (double)ringbuff[p2]*_1_div_e ); + p1++; if(p1>=ring_size) p1-=ring_size; + p2++; if(p2>=ring_size) p2-=ring_size; + } +} + + +void ringload_IIR_1_div_e_echo_i( s16 * ringbuff, int ring_size, int pos, s16 *buffer, int size , int delay) +/* put <size> samples to ring with size <ring_size> on position <pos> */ +{ + int i,p1,p2; + + p1=pos, p2=ringpos(p1-delay, ring_size); + for( i=0; i<size; i++ ){ + ringbuff[p1] =(s16)( ( + _1_m_1_div_e_i * buffer[i] + + _1_div_e_i * ringbuff[p2] + ) >> LOG2RESMAX ); + p1++; if(p1>=ring_size) p1-=ring_size; + p2++; if(p2>=ring_size) p2-=ring_size; + } +} + + +void ringload_IIR_1_div_e_echo_i_vc( s16 * ringbuff, int ring_size, int pos, s16 *buffer, int size , int delay) +/* put <size> samples to ring with size <ring_size> on position <pos> */ +{ + int i,p1,p2; + int actval; + + p1=pos, p2=ringpos(p1-delay, ring_size); + for( i=0; i<size; i++ ){ +/* ringbuff[p1] =(s16)( ( + _1_m_1_div_e_i_vc * buffer[i] + + _1_div_e_i_vc * ringbuff[p2] + ) >> LOG2RESMAXVC );*/ + actval = _1_m_1_div_e_i_vc * buffer[i] + + _1_div_e_i_vc * ringbuff[p2]; + /* prevent overflow */ + if( actval > (int)0x3FFFFFFF ) actval=(int)0x3FFFFFFF; + if( actval < (int)0xC0000000 ) actval=(int)0xC0000000; + ringbuff[p1] = actval >> LOG2RESMAXVC; + p1++; if(p1>=ring_size) p1-=ring_size; + p2++; if(p2>=ring_size) p2-=ring_size; + } +} + + +/*void ringget ( s16 * ringbuff, int ring_size, int pos, s16 *buffer, int size ) +{ + int i; + + if( pos+size > ring_size ){ + for( i=pos; i<ring_size; i++ ) buffer[i]=ringbuff[i]; + for( i=0; i<size-ring_size+pos; i++ ) buffer[i]=ringbuff[i]; + }else{ + for( i=pos; i<size+pos; i++ ) buffer[i]=ringbuff[i]; + } +} +*/ + +//int sndstretch( // not optimized +int sndstretch_not_optimized( +/* stretches the sound (not changing pitch !!!) */ +/* returns number of output samples produced */ +/* chnr simply gives multiples of chnr as snr_prod */ + s16 * buffer, int buff_size, /* ring buffer */ + int pos_init, /* only initial pos in ringbuffer */ + int snr_i, int snr_o, /* enlarge - spec */ + int chnr, /* # of channels */ + s16 * outbuff, /* output */ + int * out_prod, /* # of output-samples produced */ + int snr_proc, /* # of in-samples to process */ + int initialize /* bool */ + ) +{ + static int is_initialized=0; + static int snr_o_prod; + static int snr_i_act; + static int snr_o_act; +/* static int snr_offs; */ + static int pos_act; + static int dsnr; +/* static int p1,p2; */ + static double snr_rest=0.0; + + int snr; + double snr_d; + + int i,p1,p2; + double fade_in, fade_out; + double outd; + +/* s16 * outbuff; */ + + /* reset */ + if( !is_initialized || initialize || + snr_i!=snr_i_act || snr_o!=snr_o_act ){ + + snr_rest = 0.0; + snr_o_prod = 0; + snr_i_act = snr_i; + snr_o_act = snr_o; + dsnr = snr_o_act-snr_i_act; + pos_act = pos_init; + + is_initialized = 1; + + } + +/* fprintf(stderr,"pos_act=%d\n",pos_act); +*/ + snr_d = (double)snr_proc*(double)snr_o_act/(double)snr_i_act + + snr_rest; + snr = (int) (snr_d) / 2 * 2; + snr_rest = snr_d - (double)snr; + +/* fprintf(stderr,"snr=%d\n",snr); +*/ +/* outbuff=malloc(snr*sizeof(s16)); +*/ + /* produce snr samples */ + i=0; + do { + if( snr_o_prod == snr_o_act ) { + snr_o_prod=0; +/* fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!! dsnr = %d\n",dsnr);*/ + pos_act = ringpos( pos_act-dsnr, buff_size ); + } + for ( ; snr_o_prod < snr_o_act && i<snr ; snr_o_prod++,i++ ){ + p1=pos_act; + p2=ringpos( p1-dsnr, buff_size ); +// p3=ringpos( p2-dsnr, buff_size ); +// p4=ringpos( p3-dsnr, buff_size ); +// p2=ringpos( p1-abs(dsnr), buff_size ); +// p3=ringpos( p2-abs(dsnr), buff_size ); +// p4=ringpos( p3-abs(dsnr), buff_size ); + fade_in = (double)snr_o_prod/(double)snr_o_act; + fade_out = 1.0-fade_in; +// fade1 = (dsnr>0)?fade_out:fade_in; +// fade2 = (dsnr>0)?fade_in:fade_out; + outd = ( + (double)buffer[p1] * fade_out /* fade out */ + + (double)buffer[p2] * fade_in /* fade in */ +// +( 0.67 * (double)buffer[p1] /* fade out for lengthen */ +// + 0.24 * (double)buffer[p2] /* fade out */ +// + 0.09 * (double)buffer[p3]) * fade_out /* fade out */ +// +( 0.67 * (double)buffer[p2] /* fade in */ +// + 0.24 * (double)buffer[p3] /* fade in */ +// + 0.09 * (double)buffer[p4]) * fade_in /* fade in */ + ); + outbuff[i] = outd+0.5; + pos_act=ringpos( pos_act+1, buff_size ); + } + } while( i<snr ); + +/* fwrite( outbuff, sizeof(s16), snr, stdout ); +*/ +/* free(outbuff); +*/ + *out_prod = snr; + +/* fprintf(stderr,"snr = %d\n",snr); +*/ + return( *out_prod ); +} + + +int sndstretch( // optimized +//int sndstretch_optimized( // optimized +/* stretches the sound (not changing pitch !!!) */ +/* returns number of output samples produced */ +/* chnr simply gives multiples of chnr as snr_prod */ + s16 * buffer, int buff_size, /* ring buffer */ + int pos_init, /* only initial pos in ringbuffer */ + int snr_i, int snr_o, /* enlarge - spec */ + int chnr, /* # of channels */ + s16 * outbuff, /* output */ + int * out_prod, /* # of output-samples produced */ + int snr_proc, /* # of in-samples to process */ + int initialize /* bool */ + ) +{ + static int is_initialized=0; + static int snr_o_prod; + static int snr_i_act; + static int snr_o_act; + static int pos_act; + static int dsnr; + static double snr_rest=0.0; + + static int _RESMAX_div_max, _RESMAX_mod_max; + static int fade_in_i, fade_out_i, fade_rest_i; + + /* not necessarily static */ + static int snr; + static double snr_d; + static int i,p2; + + /* reset */ + if( !is_initialized || initialize || + snr_i!=snr_i_act || snr_o!=snr_o_act ){ + + snr_rest = 0.0; + snr_o_prod = 0; + snr_i_act = snr_i; + snr_o_act = snr_o; + dsnr = snr_o_act-snr_i_act; + pos_act = pos_init; + + is_initialized = 1; + + } + + snr_d = (double)snr_proc*(double)snr_o_act/(double)snr_i_act + + snr_rest; + snr = (int) (snr_d) / 2 * 2; + snr_rest = snr_d - (double)snr; + + /* produce snr samples */ + i=0; + do { + if( snr_o_prod == snr_o_act ) { + snr_o_prod=0; + pos_act = ringpos( pos_act-dsnr, buff_size ); + } + fade_in_i = RESMAX*((double)snr_o_prod/(double)snr_o_act); + fade_out_i = RESMAX-fade_in_i; + fade_rest_i= (RESMAX*snr_o_prod)%snr_o_act; + _RESMAX_div_max=RESMAX/snr_o_act; + _RESMAX_mod_max=RESMAX%snr_o_act; + p2=ringpos( pos_act-dsnr, buff_size ); + for ( ; snr_o_prod < snr_o_act && i<snr ; snr_o_prod++,i++ ){ + fade_in_i +=_RESMAX_div_max; + fade_out_i -=_RESMAX_div_max; + fade_rest_i+=_RESMAX_mod_max; + if(fade_rest_i>snr_o_act){ + fade_rest_i-=snr_o_act; + fade_in_i++; + fade_out_i--; + } + outbuff[i] = (s16)( ( + + (int)buffer[pos_act] * fade_out_i + + (int)buffer[p2] * fade_in_i + ) >> LOG2RESMAX ); + pos_act++; if(pos_act>=buff_size) pos_act-=buff_size; + p2++; if(p2 >=buff_size) p2 -=buff_size; + } + } while( i<snr ); + + *out_prod = snr; + + return( *out_prod ); +} + + +int sndstretch_job( // optimized +//int sndstretch_optimized( // optimized +/* stretches the sound (not changing pitch !!!) */ +/* returns number of output samples produced */ +/* chnr simply gives multiples of chnr as snr_prod */ + s16 * buffer, int buff_size, /* ring buffer */ + int pos_init, /* only initial pos in ringbuffer */ + int snr_i, int snr_o, /* enlarge - spec */ + int chnr, /* # of channels */ + s16 * outbuff, /* output */ + int * out_prod, /* # of output-samples produced */ + int snr_proc, /* # of in-samples to process */ + int initialize, /* bool */ + StretchJob * job + ) +{ +/* static int is_initialized=0; + static int snr_o_prod; + static int snr_i_act; + static int snr_o_act; + static int pos_act; + static int dsnr; + static double snr_rest=0.0; + + static int _RESMAX_div_max, _RESMAX_mod_max; + static int fade_in_i, fade_out_i, fade_rest_i;*/ + + /* not necessarily static */ + static int snr; + static double snr_d; + static int i,p2; + +#define is_initialized (job->is_initialized ) +#define snr_o_prod (job->snr_o_prod ) +#define snr_i_act (job->snr_i_act ) +#define snr_o_act (job->snr_o_act ) +#define pos_act (job->pos_act ) +#define dsnr (job->dsnr ) +#define snr_rest (job->snr_rest ) +#define _RESMAX_div_max (job->_RESMAX_div_max) +#define _RESMAX_mod_max (job->_RESMAX_mod_max) +#define fade_in_i (job->fade_in_i ) +#define fade_out_i (job->fade_out_i ) +#define fade_rest_i (job->fade_rest_i ) + + /* reset */ + if( !is_initialized || initialize || + snr_i!=snr_i_act || snr_o!=snr_o_act ){ + + snr_rest = 0.0; + snr_o_prod = 0; + snr_i_act = snr_i; + snr_o_act = snr_o; + dsnr = snr_o_act-snr_i_act; + pos_act = pos_init; + + is_initialized = 1; + + } + + snr_d = (double)snr_proc*(double)snr_o_act/(double)snr_i_act + + snr_rest; + snr = (int) (snr_d) / 2 * 2; + snr_rest = snr_d - (double)snr; + + /* produce snr samples */ + i=0; + do { + if( snr_o_prod == snr_o_act ) { + snr_o_prod=0; + pos_act = ringpos( pos_act-dsnr, buff_size ); + } + fade_in_i = RESMAX*((double)snr_o_prod/(double)snr_o_act); + fade_out_i = RESMAX-fade_in_i; + fade_rest_i= (RESMAX*snr_o_prod)%snr_o_act; + _RESMAX_div_max=RESMAX/snr_o_act; + _RESMAX_mod_max=RESMAX%snr_o_act; + p2=ringpos( pos_act-dsnr, buff_size ); + for ( ; snr_o_prod < snr_o_act && i<snr ; snr_o_prod++,i++ ){ + fade_in_i +=_RESMAX_div_max; + fade_out_i -=_RESMAX_div_max; + fade_rest_i+=_RESMAX_mod_max; + if(fade_rest_i>snr_o_act){ + fade_rest_i-=snr_o_act; + fade_in_i++; + fade_out_i--; + } + outbuff[i] = (s16)( ( + + (int)buffer[pos_act] * fade_out_i + + (int)buffer[p2] * fade_in_i + ) >> LOG2RESMAX ); + pos_act++; if(pos_act>=buff_size) pos_act-=buff_size; + p2++; if(p2 >=buff_size) p2 -=buff_size; + } + } while( i<snr ); + + *out_prod = snr; + + return( *out_prod ); + +#undef is_initialized +#undef snr_o_prod +#undef snr_i_act +#undef snr_o_act +#undef pos_act +#undef dsnr +#undef snr_rest +#undef _RESMAX_div_max +#undef _RESMAX_mod_max +#undef fade_in_i +#undef fade_out_i +#undef fade_rest_i +} + + +//int sndscale( +int sndscale_not_optimized( +/* rescales the sound (including pitch) */ +/* returns number of output samples produced */ + s16 * buffer, /* ring buffer */ + int snr_i, int snr_o, /* enlarge - spec */ + int chnr, /* # of channels */ + s16 * outbuff, /* output */ + int * out_prod, /* # of output-samples produced */ + int snr_proc, /* # of in-samples to process */ + /* must be manifold of channels */ + int initialize /* bool */ + ) +{ + static s16 last_samp[10]; /* 10 channels maximum ;) */ + static double pos_d = 0.0; + + int snr; + int pos1, pos2; + s16 samp1, samp2; + int index1, index2; + int ch; + double ds; + double ratio1, ratio2, outd; + + + if ( initialize ){ + for( ch=0; ch<chnr; ch++ ){ + last_samp[ch] = 0; + } + pos_d = 0.0; + } + + ds = 1.0*(double)snr_i/(double)snr_o; + +/* fprintf(stderr,"ds=%f\n",ds); */ +/* fprintf(stderr,"pos_d =%f\n",pos_d);*/ + + /* produce proper amount of samples */ + for( snr=0 ; pos_d < snr_proc/chnr-1 ; pos_d+=ds ){ + + pos1 = (int)floor(pos_d); + pos2 = pos1+1; + ratio1 = 1-pos_d+floor(pos_d); + ratio2 = pos_d-floor(pos_d); + + for( ch=0; ch<chnr; ch++ ){ + + index1 = pos1*chnr+ch; + index2 = pos2*chnr+ch; + + samp1 = (pos_d<0) ? last_samp[ch] : buffer[index1] ; + samp2 = buffer[index2]; + + outd = (double)samp1 * ratio1 + + (double)samp2 * ratio2 ; + + outbuff[snr+ch] = outd+0.5; + + } + + snr+=chnr; + + } + + pos_d -= (double)(snr_proc/chnr); + + for( ch=0; ch<chnr; ch++ ){ + last_samp[ch] = buffer[snr_proc-chnr+ch]; + } + + *out_prod = snr; + +/* fprintf(stderr,"snr = %d\n",snr);*/ + +/* last_samp = buffer[snr_proc-1]; */ + + return( snr ); +} + + + +int sndscale( //optimized +//int sndscale2p_optimized( +/* rescales the sound (including pitch) */ +/* returns number of output samples produced */ + s16 * buffer, /* ring buffer */ + int snr_i, int snr_o, /* enlarge - spec snr_o must not exceed RESMAX */ + int chnr, /* # of channels */ + s16 * outbuff, /* output */ + int * out_prod, /* # of output-samples produced */ + int snr_proc, /* # of in-samples to process */ + /* must be manifold of channels */ + int initialize /* bool */ + ) +{ + static s16 last_samp[10]; /* 10 channels maximum ;) */ + static int pos_rest; + + static int snr; + static int pos1, pos2; + static int ch; + static int ratio1_i; + static int ds_li, ds_li_c, ds_rest; + static int snr_proc_m_chnr; + + + if ( initialize ){ + for( ch=0; ch<chnr; ch++ ){ + last_samp[ch] = 0; + } + pos1 = 0; + } + + ds_li = snr_i/snr_o; + ds_li_c = ds_li*chnr; + ds_rest = snr_i%snr_o; + + snr_proc_m_chnr = snr_proc-chnr; + for( snr=0 ; pos1 < snr_proc_m_chnr ; pos1+=ds_li_c ){ + + pos2 = pos1+chnr; + ratio1_i = snr_o-pos_rest; + + if (pos1<0){ + for( ch=0; ch<chnr; ch++ ){ + outbuff[snr+ch] = (s16) + ( ( (int)last_samp[ch] * ratio1_i + + (int)buffer[pos2+ch] * pos_rest ) / snr_o ) ; + } + } else { + for( ch=0; ch<chnr; ch++ ){ + outbuff[snr+ch] = (s16) + ( ( (int)buffer[pos1+ch] * ratio1_i + + (int)buffer[pos2+ch] * pos_rest ) / snr_o ) ; + } + } + + snr+=chnr; + + pos_rest+=ds_rest; + if( pos_rest>=snr_o ){ pos_rest-=snr_o; pos1+=chnr; } + } + + pos1 -= snr_proc; + + for( ch=0; ch<chnr; ch++ ){ + last_samp[ch] = buffer[snr_proc-chnr+ch]; + } + + *out_prod = snr; + + return( snr ); +} + + + +int sndscale_job( //optimized +//int sndscale2p_optimized( +/* rescales the sound (including pitch) */ +/* returns number of output samples produced */ + s16 * buffer, /* ring buffer */ + int snr_i, int snr_o, /* enlarge - spec snr_o must not exceed RESMAX */ + int chnr, /* # of channels */ + s16 * outbuff, /* output */ + int * out_prod, /* # of output-samples produced */ + int snr_proc, /* # of in-samples to process */ + /* must be manifold of channels */ + int initialize, /* bool */ + ScaleJob * job + ) +{ +/* static s16 * last_samp; + static int pos_rest; + + static int snr; + static int pos1, pos2; + static int ch; + static int ratio1_i; + static int ds_li, ds_li_c, ds_rest; + static int snr_proc_m_chnr;*/ + +#define last_samp job->last_samp +#define pos_rest job->pos_rest +#define snr job->snr +#define pos1 job->pos1 +#define pos2 job->pos2 +#define ch job->ch +#define ratio1_i job->ratio1_i +#define ds_li job->ds_li +#define ds_li_c job->ds_li_c +#define ds_rest job->ds_rest +#define snr_proc_m_chnr job->snr_proc_m_chnr + + if ( initialize ){ + for( ch=0; ch<chnr; ch++ ){ + last_samp[ch] = 0; + } + pos1 = 0; + } + + ds_li = snr_i/snr_o; + ds_li_c = ds_li*chnr; + ds_rest = snr_i%snr_o; + + snr_proc_m_chnr = snr_proc-chnr; + for( snr=0 ; pos1 < snr_proc_m_chnr ; pos1+=ds_li_c ){ + + pos2 = pos1+chnr; + ratio1_i = snr_o-pos_rest; + + if (pos1<0){ + for( ch=0; ch<chnr; ch++ ){ + outbuff[snr+ch] = (s16) + ( ( (int)last_samp[ch] * ratio1_i + + (int)buffer[pos2+ch] * pos_rest ) / snr_o ) ; + } + } else { + for( ch=0; ch<chnr; ch++ ){ + outbuff[snr+ch] = (s16) + ( ( (int)buffer[pos1+ch] * ratio1_i + + (int)buffer[pos2+ch] * pos_rest ) / snr_o ) ; + } + } + + snr+=chnr; + + pos_rest+=ds_rest; + if( pos_rest>=snr_o ){ pos_rest-=snr_o; pos1+=chnr; } + } + + pos1 -= snr_proc; + + for( ch=0; ch<chnr; ch++ ){ + last_samp[ch] = buffer[snr_proc-chnr+ch]; + } + + *out_prod = snr; + + return( snr ); + +#undef last_samp +#undef pos_rest +#undef snr +#undef pos1 +#undef pos2 +#undef ch +#undef ratio1_i +#undef ds_li +#undef ds_li_c +#undef ds_rest +#undef snr_proc_m_chnr +} + + + +int snd_pitch_speed( + /* input */ + s16 *buff_i, int channels, int snr_proc, + /* algorihm parameters */ + int initialize, double pitch, double speed, int fade_shift, + /* output */ + s16 * buff_o, int * snr_produced + ) +{ + static s16 * ring_buff = (s16*)0; + static s16 * ring_buff_old = (s16*)0; + static s16 * buff_help = (s16*)0; + static int ring_size = 1; + static int ring_size_old = 0; + static int ring_pos_w = 0; + static int ring_pos_r = 0; + static int snr_scale_i; + static int snr_scale_o; + static int snr_stretch_i; + static int snr_stretch_o; + static int snr_proc_scale; + static int snr_proc_stretch; + static int is_init = 0; + static int dsnr; + static double speed_act = 0; + static double pitch_act = 0; + static double fade_shift_act = 0; + + int snr_prod; + double speed_eff; + double pitch_eff; + int scaling_first; + int snr_stretching_i_max; + int snr_stretching_o_max; + +// int channels = 2; + int init_me = 0; + + speed_eff = speed/pitch; + pitch_eff = pitch; + + scaling_first=0; +// if( pitch > 1.0 ) scaling_first=0; else scaling_first=1; + + if ( !is_init || initialize || speed!=speed_act || pitch!=pitch_act || + fade_shift!=fade_shift_act ){ + + if( !is_init || initialize ) init_me=1; else init_me=0; + +#ifdef DEBUG + fprintf(stderr,"snd_stretch_scale - init - pitch:%f, speed:%f\n",pitch,speed); +#endif + + speed_act = speed; + pitch_act = pitch; + fade_shift_act = fade_shift; + +// if (ring_buff!=0) free(ring_buff); +// if (buff_help!=0) free(buff_help); + + if (initialize != -1){ + + dsnr = fade_shift; +// dsnr = 1764; // 25Hz +// dsnr = 1536; // 30Hz +// dsnr = 1102; // 40Hz +// dsnr = 882; // 50Hz + + if( scaling_first ){ + snr_stretching_i_max = ceil((double)snr_proc/pitch_act); + snr_stretching_i_max += channels-1; + snr_stretching_i_max /= channels; + snr_stretching_i_max *= channels; + } else { + snr_stretching_i_max = (snr_proc+channels-1)/channels*channels; + } + + snr_stretching_o_max = + ceil((double)snr_stretching_i_max / speed_eff); + snr_stretching_o_max = + (snr_stretching_o_max+channels-1)/channels*channels; + + ring_size = snr_stretching_o_max /* for reading */ + + dsnr*channels /* for grabbing back */ + + dsnr*channels /* for readpos catching */ + /* up with writepos */ + + 2*dsnr*channels ; /* for 2 pre - echos */ +// ring_size = snr_stretching_o_max+3*dsnr*channels; + + if( ring_size <= ring_size_old ){ + ring_size = ring_size_old; +#ifdef DEBUG + fprintf(stderr," ring_size = %d \n",ring_size); +#endif + } else { +/* if (ring_buff!=0) free(ring_buff); + if (buff_help!=0) free(buff_help); + ring_buff = calloc( ring_size, sizeof(s16) ); + buff_help = calloc( 65536, sizeof(s16) ); + ring_pos_r = 0;*/ + if (buff_help!=0) free(buff_help); + ring_buff_old = ring_buff; + ring_buff = calloc( ring_size, sizeof(s16) ); + buff_help = calloc( 65536, sizeof(s16) ); + if (ring_buff_old!=0) ringcopy( ring_buff, ring_size, ring_pos_r, ring_pos_w, ring_buff_old, ring_size_old, ring_pos_r ); + if (ring_buff_old!=0) free(ring_buff_old); +// ring_pos_w=ringpos(ring_pos_w+ring_size_old,ring_size); +#ifdef DEBUG + fprintf(stderr," %d s16-samples reserved\n",ring_size); +#endif + } + + ring_pos_w = + ringpos( ring_pos_r + /* base */ + dsnr*channels /* for grabing back */ +// dsnr*2 /* for grabing back */ // why *2 + , ring_size ); +#ifdef DEBUG + fprintf(stderr," ring_pos_w = %d\n",ring_pos_w); +#endif + ring_pos_w = (ring_pos_w+(channels-1))/channels*channels; + + ring_size_old = ring_size; + + is_init = 1; + + } else { /* initialize == -1 */ + if (ring_buff!=0) free(ring_buff); + if (buff_help!=0) free(buff_help); + /* buffers are released -> leave the function */ + return 0; /* !!! sloppy */ + } + + } + + if ( fabs(speed_eff-1.0)>0.001 ){ /* + 0.001 ?! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + this should be examined to the limits + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + snr_stretch_i = (double)dsnr/(1.0/speed_eff-1.0); + snr_stretch_o = fabs(snr_stretch_i + dsnr); + snr_stretch_i = abs(snr_stretch_i); +// fprintf(stderr,"snd_stretch_scale - snr_str_i=%d\n",snr_stretch_i); +// fprintf(stderr,"snd_stretch_scale - snr_str_o=%d\n",snr_stretch_o); + } else { + snr_stretch_i = 10; + snr_stretch_o = 10; + } + + if ( pitch_eff!=1.0 ){ + snr_scale_i = (double)dsnr/(1.0/pitch_eff-1.0); + snr_scale_o = fabs(snr_scale_i + dsnr); + snr_scale_i = abs(snr_scale_i); + if( 1 /* optimized version doesnt support all scaling */ ){ + if( snr_scale_o > 65536 ){ + snr_scale_i = (int)((double)snr_scale_i*((double)65536/(double)snr_scale_o)+0.5); + snr_scale_o = 65536; + // make sure that snr_o for sndscale wont exceed 2^16 + } + } +// fprintf(stderr,"snd_stretch_scale - snr_sc_i=%d\n",snr_stretch_i); +// fprintf(stderr,"snd_stretch_scale - snr_sc_o=%d\n",snr_stretch_o); + } else { +// fprintf(stderr,"snd_stretch_scale - snr_scale_i=snr_scale_o=10\n"); + snr_scale_i = 65536; + snr_scale_o = 65536; + } + + if( 0/*scaling_first*/ ){ + + snr_proc_scale = snr_proc; + sndscale ( buff_i, + snr_scale_i, snr_scale_o, channels, + buff_help, &snr_prod, snr_proc_scale, init_me ); +/* buff_o, &snr_prod, snr_proc_scale, 0 ); */ + + if( speed_eff!=1.0 ){ /* add echo only when really stretching */ + ringload_IIR_1_div_e_echo_i( ring_buff, ring_size, ring_pos_w, buff_help, snr_prod, dsnr*channels ); + } else { + ringload( ring_buff, ring_size, ring_pos_w, buff_help, snr_prod ); + } + ring_pos_w = ringpos( ring_pos_w+snr_prod, ring_size ); + + snr_proc_stretch = snr_prod; + sndstretch ( ring_buff, ring_size, ring_pos_r, + snr_stretch_i*channels, snr_stretch_o*channels, channels, + buff_o, &snr_prod, snr_proc_stretch, init_me ); + + ring_pos_r = ringpos( ring_pos_r+snr_prod, ring_size ); + + } else { + +// fprintf(stderr,"sndstretch: ring_pos_r = %d\n",ring_pos_r); +// fprintf(stderr,"sndstretch: ring_pos_w = %d\n\n",ring_pos_w); + snr_prod = snr_proc; + if( speed_eff!=1.0 ){ /* add echo only when really stretching */ + ringload_IIR_1_div_e_echo_i( ring_buff, ring_size, ring_pos_w, buff_i, snr_proc, dsnr*channels ); + } else { + ringload( ring_buff, ring_size, ring_pos_w, buff_i, snr_proc ); + } + ring_pos_w = ringpos( ring_pos_w+snr_proc, ring_size ); + + snr_proc_stretch = snr_proc; + sndstretch ( ring_buff, ring_size, ring_pos_r, + snr_stretch_i*channels, snr_stretch_o*channels, channels, + buff_help, &snr_prod, snr_proc_stretch, init_me ); + + ring_pos_r = ringpos( ring_pos_r+snr_prod, ring_size ); + + snr_proc_scale = snr_prod; +// fprintf(stderr,"snr_scale_i, snr_scale_o = %d,%d\n",snr_scale_i, snr_scale_o); + sndscale ( buff_help, + snr_scale_i, snr_scale_o, channels, + buff_o, &snr_prod, snr_proc_scale, init_me ); + + } + + *snr_produced = snr_prod; + + return snr_prod; +} + + +int snd_pitch_speed_job( + /* input */ + s16 *buff_i, int channels, int snr_proc, + /* algorihm parameters */ + int initialize, double pitch, double speed, int fade_shift, + /* output */ + s16 * buff_o, int * snr_produced, PitchSpeedJob * job, + int vol_corr + ) +{ +/* static s16 * ring_buff = (s16*)0; + static s16 * ring_buff_old = (s16*)0; + static s16 * buff_help = (s16*)0; + static int ring_size = 1; + static int ring_size_old = 0; + static int ring_pos_w = 0; + static int ring_pos_r = 0; + static int snr_scale_i; + static int snr_scale_o; + static int snr_stretch_i; + static int snr_stretch_o; + static int snr_proc_scale; + static int snr_proc_stretch; + static int is_init = 0; + static int dsnr; + static double speed_act = 0; + static double pitch_act = 0;*/ + + int snr_prod; + double speed_eff; + double pitch_eff; + int scaling_first; + int snr_stretching_i_max; + int snr_stretching_o_max; + +// int channels = 2; + int init_me = 0; + +#define ring_buff job->ring_buff +#define ring_buff_old job->ring_buff_old +#define buff_help job->buff_help +#define ring_size job->ring_size +#define ring_size_old job->ring_size_old +#define ring_pos_w job->ring_pos_w +#define ring_pos_r job->ring_pos_r +#define snr_scale_i job->snr_scale_i +#define snr_scale_o job->snr_scale_o +#define snr_stretch_i job->snr_stretch_i +#define snr_stretch_o job->snr_stretch_o +#define snr_proc_scale job->snr_proc_scale +#define snr_proc_stretch job->snr_proc_stretch +#define is_init job->is_init +#define dsnr job->dsnr +#define speed_act job->speed_act +#define pitch_act job->pitch_act +#define fade_shift_act job->fade_shift_act + + speed_eff = speed/pitch; + pitch_eff = pitch; + + scaling_first=0; +// if( pitch > 1.0 ) scaling_first=0; else scaling_first=1; + + if ( !is_init || initialize || speed!=speed_act || pitch!=pitch_act || + fade_shift != fade_shift_act ){ + + if( !is_init || initialize ) init_me=1; else init_me=0; + +#ifdef DEBUG + fprintf(stderr,"snd_stretch_scale - init - pitch:%f, speed:%f\n",pitch,speed); +#endif + + speed_act = speed; + pitch_act = pitch; + if ( fade_shift != fade_shift_act ){ + fprintf(stderr,"changed fade_shift_act\n"); + } + fade_shift_act = fade_shift; + +// if (ring_buff!=0) free(ring_buff); +// if (buff_help!=0) free(buff_help); + + if (initialize != -1){ + + dsnr = fade_shift; +// dsnr = 1764; // 25Hz +// dsnr = 1536; // 30Hz +// dsnr = 1102; // 40Hz +// dsnr = 882; // 50Hz + + if( scaling_first ){ + snr_stretching_i_max = ceil((double)snr_proc/pitch_act); + snr_stretching_i_max += channels-1; + snr_stretching_i_max /= channels; + snr_stretching_i_max *= channels; + } else { + snr_stretching_i_max = (snr_proc+channels-1)/channels*channels; + } + + snr_stretching_o_max = + ceil((double)snr_stretching_i_max / speed_eff); + snr_stretching_o_max = + (snr_stretching_o_max+channels-1)/channels*channels; + + ring_size = snr_stretching_o_max /* for reading */ + + dsnr*channels /* for grabbing back */ + + dsnr*channels /* for readpos catching */ + /* up with writepos */ + + 2*dsnr*channels ; /* for 2 pre - echos */ +// ring_size = snr_stretching_o_max+3*dsnr*channels; + + if( ring_size <= ring_size_old ){ + ring_size = ring_size_old; +#ifdef DEBUG + fprintf(stderr," ring_size = %d \n",ring_size); +#endif + } else { +/* if (ring_buff!=0) free(ring_buff); + if (buff_help!=0) free(buff_help); + ring_buff = calloc( ring_size, sizeof(s16) ); + buff_help = calloc( 65536, sizeof(s16) ); + ring_pos_r = 0;*/ + if (buff_help!=0) free(buff_help); + ring_buff_old = ring_buff; + ring_buff = calloc( ring_size, sizeof(s16) ); + buff_help = calloc( 65536, sizeof(s16) ); + if (ring_buff_old!=0) ringcopy( ring_buff, ring_size, ring_pos_r, ring_pos_w, ring_buff_old, ring_size_old, ring_pos_r ); + if (ring_buff_old!=0) free(ring_buff_old); +// ring_pos_w=ringpos(ring_pos_w+ring_size_old,ring_size); +#ifdef DEBUG + fprintf(stderr," %d s16-samples reserved\n",ring_size); +#endif + } + + ring_pos_w = + ringpos( ring_pos_r + /* base */ + dsnr*channels /* for grabing back */ +// dsnr*2 /* for grabing back */ // why *2 + , ring_size ); +#ifdef DEBUG + fprintf(stderr," ring_pos_w = %d\n",ring_pos_w); +#endif + ring_pos_w = (ring_pos_w+(channels-1))/channels*channels; + + ring_size_old = ring_size; + + is_init = 1; + + } else { /* initialize == -1 */ + if (ring_buff!=0) free(ring_buff); + if (buff_help!=0) free(buff_help); + /* buffers are released -> leave the function */ + return 0; /* !!! sloppy */ + } + + } + + if ( fabs(speed_eff-1.0)>0.001 ){ /* + 0.001 ?! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + this should be examined to the limits + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + snr_stretch_i = (double)dsnr/(1.0/speed_eff-1.0); + snr_stretch_o = fabs(snr_stretch_i + dsnr); + snr_stretch_i = abs(snr_stretch_i); +// fprintf(stderr,"snd_stretch_scale - snr_str_i=%d\n",snr_stretch_i); +// fprintf(stderr,"snd_stretch_scale - snr_str_o=%d\n",snr_stretch_o); + } else { + snr_stretch_i = 10; + snr_stretch_o = 10; + } + + if ( pitch_eff!=1.0 ){ + snr_scale_i = (double)dsnr/(1.0/pitch_eff-1.0); + snr_scale_o = fabs(snr_scale_i + dsnr); + snr_scale_i = abs(snr_scale_i); + if( 1 /* optimized version doesnt support all scaling */ ){ + if( snr_scale_o > 65536 ){ + snr_scale_i = (int)((double)snr_scale_i*((double)65536/(double)snr_scale_o)+0.5); + snr_scale_o = 65536; + // make sure that snr_o for sndscale wont exceed 2^16 + } + } +// fprintf(stderr,"snd_stretch_scale - snr_sc_i=%d\n",snr_stretch_i); +// fprintf(stderr,"snd_stretch_scale - snr_sc_o=%d\n",snr_stretch_o); + } else { +// fprintf(stderr,"snd_stretch_scale - snr_scale_i=snr_scale_o=10\n"); + snr_scale_i = 65536; + snr_scale_o = 65536; + } + + if( 0/*scaling_first*/ ){ + + snr_proc_scale = snr_proc; + sndscale_job ( buff_i, + snr_scale_i, snr_scale_o, channels, + buff_help, &snr_prod, snr_proc_scale, init_me, + &(job->scale_job) ); +/* buff_o, &snr_prod, snr_proc_scale, 0 ); */ + + if( speed_eff!=1.0 ){ /* add echo only when really stretching */ + if( !vol_corr ){ + ringload_IIR_1_div_e_echo_i( ring_buff, ring_size, ring_pos_w, buff_help, snr_prod, dsnr*channels ); + } else { + ringload_IIR_1_div_e_echo_i_vc( ring_buff, ring_size, ring_pos_w, buff_help, snr_prod, dsnr*channels ); + } + } else { + ringload( ring_buff, ring_size, ring_pos_w, buff_help, snr_prod ); + } + ring_pos_w = ringpos( ring_pos_w+snr_prod, ring_size ); + + snr_proc_stretch = snr_prod; + sndstretch_job ( ring_buff, ring_size, ring_pos_r, + snr_stretch_i*channels, snr_stretch_o*channels, channels, + buff_o, &snr_prod, snr_proc_stretch, init_me, + &(job->stretch_job) + ); + + ring_pos_r = ringpos( ring_pos_r+snr_prod, ring_size ); + + } else { + +// fprintf(stderr,"sndstretch: ring_pos_r = %d\n",ring_pos_r); +// fprintf(stderr,"sndstretch: ring_pos_w = %d\n\n",ring_pos_w); + snr_prod = snr_proc; + if( speed_eff!=1.0 ){ /* add echo only when really stretching */ + if( !vol_corr ){ + ringload_IIR_1_div_e_echo_i( ring_buff, ring_size, ring_pos_w, buff_i, snr_proc, dsnr*channels ); + }else{ + ringload_IIR_1_div_e_echo_i_vc( ring_buff, ring_size, ring_pos_w, buff_i, snr_proc, dsnr*channels ); + } + } else { + ringload( ring_buff, ring_size, ring_pos_w, buff_i, snr_proc ); + } + ring_pos_w = ringpos( ring_pos_w+snr_proc, ring_size ); + + snr_proc_stretch = snr_proc; + sndstretch_job ( ring_buff, ring_size, ring_pos_r, + snr_stretch_i*channels, snr_stretch_o*channels, channels, + buff_help, &snr_prod, snr_proc_stretch, init_me, + &(job->stretch_job) + ); + + ring_pos_r = ringpos( ring_pos_r+snr_prod, ring_size ); + + snr_proc_scale = snr_prod; +// fprintf(stderr,"snr_scale_i, snr_scale_o = %d,%d\n",snr_scale_i, snr_scale_o); + sndscale_job ( buff_help, + snr_scale_i, snr_scale_o, channels, + buff_o, &snr_prod, snr_proc_scale, init_me, + &(job->scale_job) + ); + + } + + *snr_produced = snr_prod; + + return snr_prod; +#undef ring_buff +#undef ring_buff_old +#undef buff_help +#undef ring_size +#undef ring_size_old +#undef ring_pos_w +#undef ring_pos_r +#undef snr_scale_i +#undef snr_scale_o +#undef snr_stretch_i +#undef snr_stretch_o +#undef snr_proc_scale +#undef snr_proc_stretch +#undef is_init +#undef dsnr +#undef speed_act +#undef pitch_act +#undef fade_shift_act +} + + +int snd_stretch_scale(s16 *buff_i, s16 * buff_o, + double pitch, double speed, int channels, + int snr_proc, int * snr_produced, int initialize + ) +{ + return snd_pitch_speed( + /* input */ + buff_i, channels, snr_proc, + /* algorihm parameters */ + initialize, pitch, speed, 1764, + /* output */ + buff_o, snr_produced + ); +} + + +int snd_stretch_scale_job(s16 *buff_i, s16 * buff_o, + double pitch, double speed, int channels, + int snr_proc, int * snr_produced, int initialize, + PitchSpeedJob * job, int init_job) +/* init_job should be set to one the first time the routine is called with + the actual job (e.g. for creating a new job) */ +{ + if(init_job){ + InitPitchSpeedJob(job); + } + return snd_pitch_speed_job( + /* input */ + buff_i, channels, snr_proc, + /* algorihm parameters */ + initialize, pitch, speed, 1764 , + /* output */ + buff_o, snr_produced, + /* job data */ + job, 0 + ); +}