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;
+}