Mercurial > audlegacy-plugins
changeset 881:6bb0e52df3d6 trunk
[svn] - Made port of XMMS plugin SndStretch
author | mf0102 |
---|---|
date | Tue, 20 Mar 2007 12:22:25 -0700 |
parents | eb5fe37b785d |
children | d58c48b014ed |
files | ChangeLog src/sndstretch/FB_logo.xpm src/sndstretch/Makefile src/sndstretch/sndstretch.c src/sndstretch/sndstretch.h src/sndstretch/sndstretch_xmms-logo.xpm src/sndstretch/sndstretch_xmms.c |
diffstat | 7 files changed, 2108 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Mon Mar 19 16:49:57 2007 -0700 +++ b/ChangeLog Tue Mar 20 12:22:25 2007 -0700 @@ -1,3 +1,11 @@ +2007-03-19 23:49:57 +0000 Yoshiki Yazawa <yaz@cc.rim.or.jp> + revision [1860] + - suppress a warning. + + trunk/src/scrobbler/plugin.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + + 2007-03-19 20:18:28 +0000 Giacomo Lozito <james@develia.org> revision [1858] alsa output plugin: use snd_pcm_wait in place of raw polls to handle device readyness; this allows to use alsa plugins such as jackplug; requires testing
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sndstretch/FB_logo.xpm Tue Mar 20 12:22:25 2007 -0700 @@ -0,0 +1,130 @@ +/* XPM */ +static char * FB_logo_xpm[] = { +"66 62 65 1", +" c None", +". c #2C2617", +"+ c #866202", +"@ c #BA941E", +"# c #AB9650", +"$ c #FDEA8F", +"% c #A0966E", +"& c #CAB776", +"* c #C6BA92", +"= c #F3DD8F", +"- c #7B7566", +"; c #5F5530", +"> c #FBEDBC", +", c #916804", +"' c #CDB255", +") c #D9B83B", +"! c #E5D08F", +"~ c #907826", +"{ c #502F02", +"] c #ECE8DE", +"^ c #EEDDA6", +"/ c #DCBF51", +"( c #FCF3D5", +"_ c #CFAC30", +": c #524A2D", +"< c #D6CDB6", +"[ c #AE860E", +"} c #B4B2AA", +"| c #D9C277", +"1 c #605947", +"2 c #D6D6D5", +"3 c #DEDDDA", +"4 c #474334", +"5 c #F1F0ED", +"6 c #C8A62D", +"7 c #9D8949", +"8 c #F4D95F", +"9 c #9E9B90", +"0 c #FCFBF8", +"a c #73683F", +"b c #C8C0A5", +"c c #6B5B23", +"d c #E7CF77", +"e c #CBCCCD", +"f c #6E4B03", +"g c #5D3C02", +"h c #8A7B41", +"i c #B9B8B5", +"j c #C39F24", +"k c #8F886F", +"l c #D2D2D3", +"m c #AEAB9E", +"n c #EFE0C1", +"o c #3B362D", +"p c #A78934", +"q c #817646", +"r c #A37908", +"s c #C6C5C4", +"t c #BCA553", +"u c #E9CB54", +"v c #442B08", +"w c #F4DC74", +"x c #B8A675", +"y c #7D5702", +"z c #B68E14", +" ", +" eellllllleee ", +" ee222e}9-----%9ie22lleee ", +" el2e}-::ch@'//|u|t#hqa-kmbellee eee ", +" ell}a4+p_66'&'tjzzzj_u8$$8##qh9mellee ee2s9e ", +" e2m4c[j&3]55]322333<<t[[[juw$$8)thkk}ellleeeeeel222}ao73 ", +" e2s;:@t2503essseseessee23<|z[[6uww888uthqa%mbseei9-:4q@t05s", +" elm.@@e05ssss see2b6z[@u$888ww$$|#qhach7b(8rx0]se", +" e2k;z#50lss eeebj@[@/$8888w=$$$>$>($rfx03ss ", +" elk1zx05ss eel2232l&jzrzw=88dw==!^>$6ggx03ss ", +" l9;[903se el2eik-:;g7e*_jrr@!$wd88=$'gv{#03s ", +" lio670]ss e2sk1;q[z&3003ei_jzr,@d>$$_yv{g#03s ", +" e24'r]5ss e2i;:x!z,x]03eesees'j@r,,j)y{{{gp0]ss ", +" l9a[s0se el214b0r{fb03ese ss'6@[,,+vggg,55ss ", +" e24'#03s elmo90=yvfs02ss es*6@zr+{gg+30es ", +" eia[30ss el9o<0^gvf*02s ee*_@@rggf#0ls ", +" lk@p02s l}on0(g{fp03s el2222lllls'j@rf,n5s ", +" l1j*0s lb.n00,vg,30ss ellm14;cqaq%ss&j@,,0ls ", +" l1j3]s ee4b(0dvgyr02s el9o-<(((>$$u#xsb_@r0se ", +" lcj02s e%a>50rvg,x0s el1a=u_@j6)8=8u//<e'z0s ", +" la60se el4n]n(ggf,<0s ll4k6,,rrr[r[)wu__/2eb0e ", +" ea60b e}1>n(!vgf,2nsel17z@s]5]3&j@zz8)6@|2sls ", +" 2q60s la*>n5/vgy[n3sl9;@l0]2ss e<'6z[6rr@^le ", +" lkj0s e2o(nn5_{g,r<]e2vt50ess es'_j@r+[j5s ", +" e}p5<s e}a>nn5)gf,['5em:55ss em'/_)y~[nls ", +" ee7<]s 2;b>n]5)yf,r@5sk<0ss ee78u8,yrb]s ", +" emj5es eeo>]nn5|,+,[@!3ee2s lk/w$@frt0s ", +" ee%d3e 2-%(]]>]w[r,rzj]ss 29x$>6g,@0s ", +" eex^ee lbo5(0((>=j@r,[@_]see eee l9%=>6{+@0s ", +" esx^eeee leob0|j[@6))6@[rzj)<bel222e7se 2-xn0rg+t0s ", +" eeb|x}ele4x_[,,,r[j_)j@rr@_//%h-a14~3e e2:^]0gg,b0s ", +" ee2x29.rz[[[z[rr[j'/6@[rj)uw=^^)@0(s lm;((dvf+53s ", +" eenee55]2'jj@rr[j_/j@[@_/w$w[y20se2i.n50,{rj(bee ", +" essss le_j@[r[j_)j@j_u86ff#02l29ol00>,r6)u)&se ", +" sss&_j[r@j))__/@fvg,<0iaoa|d_j@66j_u))|<e ", +" e}t_jz[6_)jrf{ggyr53s}<|j[[[rr@__)__6|le ", +" l})/_@_)u@ygggg+p0eee<22|6j@rrju)j@zzd2s ", +" es7u/__)ujfgggf,*0b sees_j@rr_ur,,[@nes ", +" l9u8u/u8_ggggf,35s eei')jz[)z+yr[']s ", +" e}#w8uu$6{gggf[0ls ee%/)_j_)yf+r[5es ", +" eeh$w8w$@vggf+x0s es#u)__urgf,r|]s ", +" 2a$^==>[{ggg,]5s eku8uu8jgf+rj0s ", +" 21$^^^>fgggfp0ls emtw8u8/{gf,r0s ", +" 21$^=nwvggg,20s ei7$^w=8g{y,r0s ", +" 2;>^^>jvggfp02s esq$^^^wggf,r0s ", +" e24>nn(f{gg,30s esa>!^ndvgfyr0s ", +" e}qnn('{ggf*0<s em->nn>'{gg+[0s ", +" l-x>](f{gfp03s 2-#nnn(rvgfyt0s ", +" el4^]0jv{g~50ss e2o]]>5(f{gf+25s ", +" lm1((/{{g,30ss 2kq(]]0jvggfr03s ", +" e24<0^{{g,]0ee li.5(]0>g{g{y*0se ", +" l9a0$gvg~30labee e2io<(5((y{gggr03s ", +" ls.0=fvyp]0eem/<eee el29.<0]0>+{ggg+30ss ", +" lso<df{+x50eseem/'}sl222s%41>(00|gvgggys0es ", +" le4i)ffrl03ss esi))#h-a;;-n000^~{{g{fyb02s ", +" e2sox[y,*502ss eei__u=$>(0>='y{{gfffp302s ", +" ell%o'rrx503se eesj[[z[r+fffy+y,[}50es ", +" eel2l94f@#b]03ess eels&@[rrrrrr[#<503se ", +" eei71{c#<]553ess eel232!<<l]]552sss ", +" saq%b5005less e el<eelesss ", +" ee3]3lbsss ssse ", +" eess "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sndstretch/Makefile Tue Mar 20 12:22:25 2007 -0700 @@ -0,0 +1,15 @@ +include ../../mk/rules.mk +include ../../mk/init.mk + +OBJECTIVE_LIBS = libsndstretch$(SHARED_SUFFIX) + +LIBDIR = $(plugindir)/$(EFFECT_PLUGIN_DIR) + +SOURCES = sndstretch_xmms.c sndstretch.c + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(GLIB_CFLAGS) $(PANGO_CFLAGS) \ + -I../../intl -I../.. + +include ../../mk/objective.mk
--- /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 + ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sndstretch/sndstretch.h Tue Mar 20 12:22:25 2007 -0700 @@ -0,0 +1,152 @@ +// sndstretch.h +// +// 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. +// +// + +#ifndef SNDSTRETCH_H +#define SNDSTRETCH_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef short int s16; + + +typedef struct{ + int is_initialized; // init me = 0 + int snr_o_prod; + int snr_i_act; + int snr_o_act; + int pos_act; + int dsnr; + double snr_rest; // init me = 0.0 + + int _RESMAX_div_max, _RESMAX_mod_max; + int fade_in_i, fade_out_i, fade_rest_i; +} StretchJob; + +typedef struct{ + s16 last_samp[10]; /* 10 channels maximum ;) */ + int pos_rest; + + int snr; + int pos1, pos2; + int ch; + int ratio1_i; + int ds_li, ds_li_c, ds_rest; + int snr_proc_m_chnr; +} ScaleJob; + +typedef struct{ + s16 * ring_buff; // init me = (s16*)0 + s16 * ring_buff_old; // init me = (s16*)0 + s16 * buff_help; // init me = (s16*)0 + int ring_size; // init me = 1 + int ring_size_old; // init me = 0 + int ring_pos_w; // init me = 0 + int ring_pos_r; // init me = 0 + int snr_scale_i; + int snr_scale_o; + int snr_stretch_i; + int snr_stretch_o; + int snr_proc_scale; + int snr_proc_stretch; + int is_init; // init me = 0 + int dsnr; + double speed_act; // init me = 0 + double pitch_act; // init me = 0 + int fade_shift_act; + StretchJob stretch_job; + ScaleJob scale_job; +} PitchSpeedJob; + + + +int sndstretch( +// stretches the sound (not changing pitch !!!) +// returns number of output samples produced + 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 + ); + + +int sndscale( +// rescales the sound (including pitch) +// returns number of output samples produced + s16 * buffer, // ring buffer + int snr_i, int snr_o, // enlarge - specification + // (snr_o may not exceed 2^16 for + // integer optimized version) + 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 + ); + + +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 + ); + + +int snd_stretch_scale(s16 *buff_i, s16 * buff_o, + double pitch, double speed, int channels, + int snr_proc, int * snr_produced, int initialize ); + + +void InitPitchSpeedJob( PitchSpeedJob * job ); + +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 + ); + +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); + +void CleanupPitchSpeedJob( PitchSpeedJob * job ); +/* cleaning up the allocated mess would be a good idea */ + +#ifdef __cplusplus +} +#endif + +#endif // SNDSTRETCH_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sndstretch/sndstretch_xmms-logo.xpm Tue Mar 20 12:22:25 2007 -0700 @@ -0,0 +1,46 @@ +/* XPM */ +static char * sndstretch_xmms_logo_xpm[] = { +"200 26 17 1", +" c None", +". c #C7BEAD", +"+ c #BCB2A2", +"@ c #9A835B", +"# c #83653E", +"$ c #B2A895", +"% c #FDDA72", +"& c #C59246", +"* c #4E3C20", +"= c #7D4B1E", +"- c #655133", +"; c #F7C75A", +"> c #412810", +", c #DB9B3C", +"' c #251D0F", +") c #ECA536", +"! c #BB661C", +" ", +" ", +" .+.+ ", +" .@@#@@@@@#@+ ", +" $#@.%%%%%%+@#$ +++. +@@#@.@#@#$@#@#@##@+@##$ @@#@@##@$@@#@+ @###@@$ ", +" @#+%%&**=+%%%@#$ .@#-@#@-##$ +@@$+@#@$.@@@$.@@.+##&.&#@@@.$#$.@#@$.#@#@.;.$@# ", +" $@@+ +#$%%@>-#->@%%;-@ $-@+;%%%%+##@ $##%%&#.%%@#;%;#%%%#$%%%-#&%%@,%%;-.%%+#@%;>=%@- ", +" $#--@#@ ##%%%--$.$#-%%&*@ $-@%%#''-;%%@- @-&%)$,=!>#;%!.&%%#;&%%*##%%#.;%)$,;%&-@%;--!*- ", +" $#--@$%;*- ##%%%@-@ ##%;'-$ -@%%#>##**%%@-. .--%%+'-*-#%%&-&%;$'$%,*-$%;&>;%,@>%%=-#%%+--*# ", +" @#*-#&.%%;>*# #-%%%;#--.--='*-#@@+ +@@@$@@@@@@@+ *$%%#-@.--)%>-#@@@@@@@@@@@@@@$ @@@@@@@@@@@@@@@@@@@ @####$ $@@@ .@@@$ -*;%=-#@-@%%#*;%)>-%%=*-.%;>#%%&>@%%'-*,%%&--+ ", +" $@#--*#@.%%%%)'># #*)%%%;@----*------*@*---*--*----*@ *&%%)-*$#-,*>---*-*--*--*--*-*#-*--*-*--*--*-*-*--*-*--@#-*#@*--*- *--**+++#*$%)--@-$%;'-%%=>@%%>--%%!>$%;'*.%)'--*)%%-* ", +" +$@@-*-*--@&.%%%%;%;>*- @**;%%%%,#**-.@-.%,*-*+%@*#%%%%%.-*# *=%%%+-*-*>*%%%%%%%%,-%%%%%%;@**&%%%%%%%@@%%%%%%%%-*@.%%%;@*--;%=*$*$%&*#***@&%%*--*;;=*@%;'-&%,>-#%;'-)%!>-;%=-##**;%=* ", +" +$@-***>**-##$,;;%%%%;;%;%='- ->>;;%%%%@-*@-*;%;***;;**#%;,,;%%** *>,%;%;@****,,,%;),)**%;,,,)%;**&%),),),>=),)%;,))'#%%%,)%%-**%;>*#*)%=>--.)&')%,##-%%'*)%!>-;%&@>&%,'-%%>*#%;##@&*>,%>* ", +" +@#**-#@@$;.;;%%%%;%;;;%;;;;'*+ *>'!;;;;%)-***%;%=**;;>*&%='''&%!>@ $>',;%;%.-*>'''%)''''@%!'''')%**;%''''''>>''!%*'''*;;!'''!%,*-%)'-**;;>**>%!'*=;%&'@%)'-;;**>;;)'*;;=>#;;'*=%;!'&;@@;='* ", +" $@&&,);;;;;;%%;%;;;;;;;;;;;)'* #**@ ->'>);;;;)*>#%)%&>*%)'>,%>>>>*;)'-$$@>'>);;%;#**>#%&'*->&%='>>*;%>>;;'>>>>**#**,%>>*>#%)''*>'='>#%!'*>*%;'**>>'>>'>''>>'''>>''>>'>''>>''*>'''*'>''>>'>>''>$ ", +" +#-'''''''>>==!!);;%;%;;%;%!'# ->--> $*>'!;%;%#*!%!);>#%&'*;;'*.**%;'*>>#@*>'!;;%;**>!%!'@#*);###&.%)'-%;+,+,+#>$->;;>*#*,%='- #*>>*&%;;.;;;,'#$>>>@.*>>>=*>*-***>$->>>#->**-*>**@*>>*->*>>>*+ ", +" +@@-*****>>''>'''>=!);;%;%&># ->@;*> #*');;%!>,%>!%#!%=>*%;'*.>=%)'-+*> #>'=;;%!**,%*>+**;%%%%%;,'>#%;%%%%%=>@*-%)'--*;;>>. #****)%))));%!'@ ", +" +$@#=**>>'''=!;;;>* $>#%;>> @*=;%;>*;;>*%))%*>#%,'-#*&%!>;;'* *>;%;>>*;;>*.>-%)'>,;='>*&;=''''''*$>#%,'##>;;>* #>-***;;''''&%*>$ ", +" +@#*>>>'=)** #*;%%**# $*=%%='-%;'>)%;;>*!%!>**-;%>@%;>*@ ->)%!'**%;'*+>@%!>>>;;***)%>>>>>**@$*&%=>@@>)%=***-%;*#%)'***;;>* ", +" #=>>''- @>);%)->****>*,%!'*=%,'*!%%)'*,%=--#;%!'!%%&**>*>*#%!'**#%,'#@*&%=>=>&%!**;;>=----*#-*)%** @*!%;--#;%!'!%!>#*=%;'* ", +" +###$ @**;%%;@##-#@;%='**,%!>**;%,>-;%;%%%%,'*>,;%;@##@.;!'*#*&%!>$#*;%**@**%;*#%%%%%%%%*--*;;>* *';%%%%%&'*,%=*#*#%)'- ", +" ->>,)%%%%%%;!''*#*!)>*->!)**=,,,,,!>'>-*'*!,;;))!''*$$*!)>*+-*,,>* ->!,==),,,,,,!'-#=,,'- #>'!)),>'**&)>*@*!)=>@ ", +" -*''>>*>*'''**$$*>'>-@*>''*>''''''>*@ @**>''''''>*$ +*''>* #>''>- $*>'>>''''''''*@#>''># #*''''>*-*''>-+*>''*+ ", +" @#****>***=& $#@# $@#@$@@#@##@$ &#=####@+ $@@# @#@@ $#@#@######@@@ @@@@ $####@ @@@@ +@#@$ ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sndstretch/sndstretch_xmms.c Tue Mar 20 12:22:25 2007 -0700 @@ -0,0 +1,459 @@ +// sndstretch_xmms.c +// +// sndstretch_xmms - xmms-output plugin for adjusting +// pitch and speed of s16le data +// Copyright (C) 2001 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. +// +// + +#include "sndstretch.h" +#include "sndstretch_xmms-logo.xpm" +#include "FB_logo.xpm" + +#include "audacious/configdb.h" +#include "audacious/plugin.h" +#include <gtk/gtk.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define SNDSTRETCH_VERSION_STRING "0.7" + +#define SS sndstretch_var + +void sndstretch_init (void); +void sndstretch_about (void); +void sndstretch_config (void); +int sndstretch_mod_samples (gpointer *ptr, gint length, AFormat fmt, gint srate, gint nch); + +EffectPlugin sndstretch_ep = { + NULL, + NULL, + "SndStretch", + sndstretch_init, + NULL, + sndstretch_about, + sndstretch_config, + sndstretch_mod_samples, + NULL +}; + + +EffectPlugin *get_eplugin_info(void) +{ + return &sndstretch_ep; +} + +static struct { + int handle; // file handle + int fragsize; + int chnr; + int paused; + int time_offs; + int fmtsize; + int fmt; + int sampfreq; + int written; + int bpsec; + int vol_l,vol_r; + int going; + double pitch; + double speed; + double scale; + int short_overlap; + int volume_corr; + GtkObject * pitch_adj; + GtkObject * speed_adj; + GtkObject * scale_adj; +} sndstretch_var; + + +static const char sndstretch_title_text[] = "SndStretch xmms - " SNDSTRETCH_VERSION_STRING; + +static const gchar sndstretch_about_text[] = + "Copyright (C) 2001 Florian Berger\n<harpin_floh@yahoo.de>\n" + "Ported to Audacious by Michael Färber\n" + "http://www.geocities.com/harpin_floh/home.html"; + +static const gchar sndstretch_GPL_text[] = + "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 2 of the License, or " + "(at your option) any later version.\n\n" + "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.\n\n" + "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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, " + "USA."; + +GtkWidget * sndstretch_about_dialog = NULL; +GtkWidget * sndstretch_config_dialog = NULL; + + +static gint sndstretch_about_destroy_cb(GtkWidget * w, GdkEventAny * e, gpointer data) +{ + gtk_widget_destroy(sndstretch_about_dialog); + sndstretch_about_dialog = NULL; + return TRUE; +} + +static void sndstretch_about_ok_cb(GtkButton * button, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(sndstretch_about_dialog)); + sndstretch_about_dialog = NULL; +} + +void sndstretch_about(void) +{ + GtkWidget * vbox, * scrolltext, * button; + GtkWidget * titlelabel, * copylabel; + GtkWidget * text; + GtkTextBuffer * textbuffer; + GtkTextIter iter; + + GdkPixmap * logopix; + GdkBitmap * logomask; + GtkWidget * logo; + + GdkPixmap * FBlogopix; + GdkBitmap * FBlogomask; + GtkWidget * FBlogo; + GtkWidget * copyhbox, * copy_rbox, * copy_lbox; + + + if (sndstretch_about_dialog != NULL) + return; + + sndstretch_about_dialog = gtk_dialog_new(); + gtk_widget_show(sndstretch_about_dialog); + + /* title logo */ + logopix = gdk_pixmap_create_from_xpm_d(sndstretch_about_dialog->window, &logomask, + NULL, + (gchar **) sndstretch_xmms_logo_xpm); + logo = gtk_pixmap_new(logopix,logomask); + + /* FB-logo */ + FBlogopix = gdk_pixmap_create_from_xpm_d(sndstretch_about_dialog->window, &FBlogomask, + NULL, + (gchar **) FB_logo_xpm); + FBlogo = gtk_pixmap_new(FBlogopix,FBlogomask); + + + gtk_signal_connect(GTK_OBJECT(sndstretch_about_dialog), "destroy", + GTK_SIGNAL_FUNC(sndstretch_about_destroy_cb), NULL); + gtk_window_set_title(GTK_WINDOW(sndstretch_about_dialog), "About SndStretch"); + + + /* labels */ + titlelabel = gtk_label_new(sndstretch_title_text); + copylabel = gtk_label_new(sndstretch_about_text); + gtk_label_set_justify(GTK_LABEL(copylabel), GTK_JUSTIFY_LEFT); + + copy_lbox = gtk_hbox_new(FALSE,0); + copy_rbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_end (GTK_BOX(copy_lbox), FBlogo, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(copy_rbox), copylabel, FALSE, TRUE, 0); + copyhbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start(GTK_BOX(copyhbox), copy_lbox, TRUE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(copyhbox), copy_rbox, TRUE, TRUE, 5); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sndstretch_about_dialog)->vbox), vbox, + TRUE, TRUE, 5); + + scrolltext = gtk_scrolled_window_new(NULL,NULL); + text = gtk_text_view_new(); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); + textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); + gtk_text_buffer_get_iter_at_offset(textbuffer, &iter, 0); + gtk_text_buffer_insert(textbuffer, &iter, + sndstretch_GPL_text, strlen(sndstretch_GPL_text)); + + + scrolltext = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolltext), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(scrolltext), text); + + gtk_box_pack_start(GTK_BOX(vbox), logo, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(vbox), titlelabel, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(vbox), copyhbox, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(vbox), scrolltext, TRUE, TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_widget_set_usize(scrolltext, -1, 110); + + button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sndstretch_about_dialog)->action_area), + button, FALSE, FALSE, 0); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(sndstretch_about_ok_cb), NULL); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show(button); + gtk_widget_show_all(sndstretch_about_dialog); +} + + + +static void speed_change_cb(GtkAdjustment * adj, gpointer data) +{ + SS.speed = pow(2.0, GTK_ADJUSTMENT(adj)->value / (GTK_ADJUSTMENT(adj)->upper-10)); +} + +static void pitch_change_cb(GtkAdjustment * adj, gpointer data) +{ + SS.pitch = pow(2.0, GTK_ADJUSTMENT(adj)->value / (GTK_ADJUSTMENT(adj)->upper-10)); + gtk_adjustment_set_value(GTK_ADJUSTMENT(SS.scale_adj), + (GTK_ADJUSTMENT(SS.scale_adj)->upper-10.0)*log(SS.pitch)/log(2.0)); +} + +static void scale_change_cb(GtkAdjustment * adj, gpointer data) +{ + double speed_eff; + + SS.scale = pow(2.0, GTK_ADJUSTMENT(adj)->value / (GTK_ADJUSTMENT(adj)->upper-10)); + speed_eff= SS.speed/SS.pitch; + SS.pitch = SS.scale; + SS.speed = speed_eff*SS.scale; + if (SS.speed>2.0) SS.speed=2.0; + if (SS.speed<0.5) SS.speed=0.5; + gtk_adjustment_set_value(GTK_ADJUSTMENT(SS.speed_adj), + (GTK_ADJUSTMENT(SS.speed_adj)->upper-10.0)*log(SS.speed)/log(2.0)); + gtk_adjustment_set_value(GTK_ADJUSTMENT(SS.pitch_adj), + (GTK_ADJUSTMENT(SS.pitch_adj)->upper-10.0)*log(SS.pitch)/log(2.0)); +} + +static void overlap_toggle_cb(GtkToggleButton *butt, gpointer user_data) +{ + SS.short_overlap = gtk_toggle_button_get_active(butt); +} + +static void volume_toggle_cb(GtkToggleButton *butt, gpointer user_data) +{ + SS.volume_corr = gtk_toggle_button_get_active(butt); +} + +static void sndstretch_config_logobutton_cb(GtkButton * button, gpointer data) +{ + sndstretch_about(); +} + +static gint sndstretch_config_destroy_cb(GtkWidget * w, GdkEventAny * e, gpointer data) +{ + ConfigDb *db = bmp_cfg_db_open(); + + bmp_cfg_db_set_double(db, "sndstretch", "pitch", SS.pitch); + bmp_cfg_db_set_double(db, "sndstretch", "speed", SS.speed); + + bmp_cfg_db_set_bool(db, "sndstretch", "short_overlap", SS.short_overlap); + bmp_cfg_db_set_bool(db, "sndstretch", "volume_corr", SS.volume_corr); + + bmp_cfg_db_close(db); + + gtk_widget_destroy(sndstretch_config_dialog); + sndstretch_config_dialog = NULL; + return TRUE; +} + +void sndstretch_config(void) +{ + GtkWidget * vbox; + GtkWidget * speed_scale, * pitch_scale, * scale_scale; + GtkWidget * speed_spin, * pitch_spin, * scale_spin; + GtkWidget * speed_hbox, * pitch_hbox, * scale_hbox, * opt_hbox; + GtkWidget * speed_frame, * pitch_frame, * scale_frame, * opt_frame; + GdkPixmap * logopix; + GdkBitmap * logomask; + GtkWidget * logo; + GtkWidget * logohbox; + GtkWidget * logobutton; + GtkWidget * volume_toggle; + GtkWidget * overlap_toggle; + + if (sndstretch_config_dialog != NULL) + return; + + sndstretch_config_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_show(sndstretch_config_dialog); + + logopix = gdk_pixmap_create_from_xpm_d(sndstretch_config_dialog->window, &logomask, + NULL, (gchar **)sndstretch_xmms_logo_xpm); + + logo = gtk_pixmap_new(logopix,logomask); + + logobutton = gtk_button_new(); + gtk_button_set_relief(GTK_BUTTON(logobutton), GTK_RELIEF_NONE); + gtk_container_add(GTK_CONTAINER(logobutton), logo); + gtk_signal_connect(GTK_OBJECT(logobutton), "clicked", + GTK_SIGNAL_FUNC(sndstretch_config_logobutton_cb), NULL); + GTK_WIDGET_SET_FLAGS(logobutton, GTK_CAN_DEFAULT); + gtk_widget_grab_default(logobutton); + + logohbox = gtk_hbox_new(FALSE,0); // to make it rightbound + gtk_box_pack_end(GTK_BOX(logohbox), logobutton, FALSE, TRUE, 4); + + SS.speed_adj = gtk_adjustment_new( 100.0*log(SS.speed)/log(2.0), + -100, 100+10, 2, 10, 10); + SS.pitch_adj = gtk_adjustment_new( 120.0*log(SS.pitch)/log(2.0), + -120, 120+10, 2, 10, 10); + SS.scale_adj = gtk_adjustment_new( 100.0*log(SS.scale)/log(2.0), + -100, 100+10, 2, 10, 10); + + volume_toggle = gtk_check_button_new_with_label("Volume corr."); + overlap_toggle = gtk_check_button_new_with_label("Short Overlap"); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(volume_toggle), SS.volume_corr ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(overlap_toggle), SS.short_overlap ); + + + gtk_signal_connect(GTK_OBJECT(SS.speed_adj), "value-changed", + GTK_SIGNAL_FUNC(speed_change_cb), NULL); + + gtk_signal_connect(GTK_OBJECT(SS.pitch_adj), "value-changed", + GTK_SIGNAL_FUNC(pitch_change_cb), NULL); + + gtk_signal_connect(GTK_OBJECT(SS.scale_adj), "value-changed", + GTK_SIGNAL_FUNC(scale_change_cb), NULL); + + gtk_signal_connect(GTK_OBJECT(volume_toggle), "toggled", + GTK_SIGNAL_FUNC(volume_toggle_cb), NULL); + + gtk_signal_connect(GTK_OBJECT(overlap_toggle), "toggled", + GTK_SIGNAL_FUNC(overlap_toggle_cb), NULL); + + speed_scale = gtk_hscale_new(GTK_ADJUSTMENT(SS.speed_adj)); + pitch_scale = gtk_hscale_new(GTK_ADJUSTMENT(SS.pitch_adj)); + scale_scale = gtk_hscale_new(GTK_ADJUSTMENT(SS.scale_adj)); + gtk_scale_set_draw_value (GTK_SCALE(speed_scale),FALSE); + gtk_scale_set_draw_value (GTK_SCALE(pitch_scale),FALSE); + gtk_scale_set_draw_value (GTK_SCALE(scale_scale),FALSE); + + speed_spin = gtk_spin_button_new(GTK_ADJUSTMENT(SS.speed_adj),1.0,2); + pitch_spin = gtk_spin_button_new(GTK_ADJUSTMENT(SS.pitch_adj),1.0,2); + scale_spin = gtk_spin_button_new(GTK_ADJUSTMENT(SS.scale_adj),1.0,2); + gtk_widget_set_usize (speed_spin,70,20); + gtk_widget_set_usize (pitch_spin,70,20); + gtk_widget_set_usize (scale_spin,70,20); + gtk_entry_set_max_length (GTK_ENTRY(pitch_spin),7); + gtk_entry_set_max_length (GTK_ENTRY(speed_spin),7); + gtk_entry_set_max_length (GTK_ENTRY(scale_spin),7); + + speed_hbox = gtk_hbox_new(FALSE,5); + pitch_hbox = gtk_hbox_new(FALSE,5); + scale_hbox = gtk_hbox_new(FALSE,5); + opt_hbox = gtk_hbox_new(FALSE,5); + gtk_container_set_border_width(GTK_CONTAINER(speed_hbox), 3); + gtk_container_set_border_width(GTK_CONTAINER(pitch_hbox), 3); + gtk_container_set_border_width(GTK_CONTAINER(scale_hbox), 3); + gtk_container_set_border_width(GTK_CONTAINER(opt_hbox), 3); + gtk_box_pack_start(GTK_BOX(speed_hbox), speed_spin, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(speed_hbox), speed_scale, TRUE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(pitch_hbox), pitch_spin, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(pitch_hbox), pitch_scale, TRUE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(scale_hbox), scale_spin, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(scale_hbox), scale_scale, TRUE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(opt_hbox), volume_toggle, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(opt_hbox), overlap_toggle,TRUE, TRUE, 5); + + speed_frame = gtk_frame_new("Speed"); + pitch_frame = gtk_frame_new("Pitch"); + scale_frame = gtk_frame_new("Scale"); + opt_frame = gtk_frame_new("Options"); + gtk_container_add(GTK_CONTAINER(speed_frame), speed_hbox); + gtk_container_add(GTK_CONTAINER(pitch_frame), pitch_hbox); + gtk_container_add(GTK_CONTAINER(scale_frame), scale_hbox); + gtk_container_add(GTK_CONTAINER(opt_frame), opt_hbox); + gtk_container_set_border_width(GTK_CONTAINER(speed_frame), 5); + gtk_container_set_border_width(GTK_CONTAINER(pitch_frame), 5); + gtk_container_set_border_width(GTK_CONTAINER(scale_frame), 5); + gtk_container_set_border_width(GTK_CONTAINER(opt_frame), 5); + + vbox=gtk_vbox_new(FALSE,0); + gtk_box_pack_start(GTK_BOX(vbox), pitch_frame, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), speed_frame, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), scale_frame, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), opt_frame, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), logohbox, FALSE, TRUE, 0); + + gtk_signal_connect(GTK_OBJECT(sndstretch_config_dialog), "destroy", + GTK_SIGNAL_FUNC(sndstretch_config_destroy_cb), NULL); + gtk_window_set_title(GTK_WINDOW(sndstretch_config_dialog), "SndStretch - Configuration"); + gtk_container_add(GTK_CONTAINER(sndstretch_config_dialog), vbox); + + gtk_widget_set_usize(sndstretch_config_dialog, 275, -1); + gtk_widget_show_all(sndstretch_config_dialog); +} + + +void sndstretch_init(void) +{ + ConfigDb *db; + + db = bmp_cfg_db_open(); + + SS.fragsize=0; + SS.chnr=2; + SS.paused=0; + SS.time_offs=0; + SS.fmtsize=2; + SS.fmt=FMT_S16_NE; + SS.sampfreq=44100; + SS.written=0; + SS.bpsec=176400; + SS.vol_r=50; + SS.vol_l=50; + SS.pitch=1.0; + SS.speed=1.0; + SS.scale=1.0; + + gboolean b; + bmp_cfg_db_get_double(db, "sndstretch", "pitch", &SS.pitch); + bmp_cfg_db_get_double(db, "sndstretch", "speed", &SS.speed); + if (bmp_cfg_db_get_bool(db, "sndstretch", "short_overlap", &b)) + SS.short_overlap = b; + if (bmp_cfg_db_get_bool(db, "sndstretch", "volume_corr", &b)) + SS.volume_corr = b; + bmp_cfg_db_close(db); +} + +int sndstretch_mod_samples (gpointer *ptr, gint length, AFormat fmt, gint srate, gint nch) +{ + static short int * buff_o; + static int prod_size; + static PitchSpeedJob job; + static int init_job=1; + + buff_o = realloc(buff_o, 65536); + + if (init_job) { + InitPitchSpeedJob(&job); + init_job = 0; + } + snd_pitch_speed_job(*ptr, nch, length/2, 0, SS.pitch, SS.speed, + (SS.short_overlap) ? 882 : 1764, + buff_o, &prod_size, &job, SS.volume_corr); + + *ptr = (gpointer) buff_o; + + return prod_size*2; +}