Consistent samplerate handling for playback and recording - Alex
[terminatorX.git] / src / tX_vtt.cc
index 5d93cf1e605d8079685f12bab9dcc524ff589204..40f3152f7118e4e4426602f3f68e7e52ebe141e2 100644 (file)
@@ -1,6 +1,6 @@
 /*
     terminatorX - realtime audio scratching software
-    Copyright (C) 1999, 2000  Alexander König
+    Copyright (C) 1999-2003  Alexander König
  
     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
@@ -25,7 +25,7 @@
                 
     08 Dec 1999 - Switched to the new audiofile class           
 */    
-   
+
 #include "tX_vtt.h"
 #include "tX_global.h"
 #include <stdio.h>
@@ -33,6 +33,8 @@
 #include <math.h>
 #include "tX_mastergui.h"
 #include "tX_sequencer.h"
+#include <glib.h>
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -41,7 +43,6 @@
 #include "3dnow.h"
 #endif
 
-
 #ifdef DEBUG
 #define tX_freemem(ptr, varname, comment); fprintf(stderr, "** free() [%s] at %08x. %s.\n", varname, ptr, comment); free(ptr);
 #define tX_malloc(ptr, varname, comment, size, type); fprintf(stderr, "**[1/2] malloc() [%s]. Size: %i. %s.\n", varname, size, comment); ptr=type malloc(size); fprintf(stderr, "**[2/2] malloc() [%s]. ptr: %08x.\n", varname, ptr);
@@ -70,7 +71,9 @@ extern void gui_update_display(vtt_class *vtt);
 extern void gui_clear_master_button(vtt_class *vtt);
 extern void cleanup_vtt(vtt_class *vtt);
 extern int vg_get_current_page(vtt_class *vtt);
-extern void vg_set_current_page(vtt_class *vtt, int page);
+extern f_prec gui_get_audio_x_zoom(vtt_class *vtt);
+extern void gui_set_audio_x_zoom(vtt_class *vtt, f_prec);
+
 
 int vtt_class::vtt_amount=0;
 list <vtt_class *> vtt_class::main_list;
@@ -78,13 +81,12 @@ list <vtt_class *> vtt_class::render_list;
 int16_t* vtt_class::mix_out_buffer=NULL;
 f_prec * vtt_class::mix_buffer=NULL;
 f_prec * vtt_class::mix_buffer_end=NULL;
+int vtt_class::solo_ctr=0;
 
 int vtt_class::samples_in_mix_buffer=0;
 pthread_mutex_t vtt_class::render_lock=PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t vtt_class::main_lock=PTHREAD_MUTEX_INITIALIZER;
 f_prec vtt_class::master_volume=1.0;
 f_prec vtt_class::res_master_volume=1.0;
-//f_prec vtt_class::saturate_fac=((f_prec) SAMPLE_MAX-SAMPLE_BORDER)*1.0/FLT_MAX;
 f_prec vtt_class::saturate_fac=0.1;
 int vtt_class::do_saturate=0;
 vtt_class * vtt_class::sync_master=NULL;
@@ -117,9 +119,6 @@ vtt_class :: vtt_class (int do_create_gui)
        sync_cycles=0,
        sync_countdown=0;
        
-       x_control=CONTROL_SCRATCH;
-       y_control=CONTROL_CUTOFF;
-       
        lp_enable=0;
        lp_reso=0.8;
        lp_freq=0.3;
@@ -135,10 +134,7 @@ vtt_class :: vtt_class (int do_create_gui)
        ec_set_pan(0);
        ec_set_volume(1);
        
-//     pthread_mutex_lock(&main_lock);
        main_list.push_back(this);
-//     pthread_mutex_unlock(&main_lock);
-
 
        /* "connecting" the seq-parameters */
        
@@ -185,16 +181,23 @@ vtt_class :: vtt_class (int do_create_gui)
        set_master_volume(globals.volume);
        set_output_buffer_size(samples_in_mix_buffer/2);
        
-       audiofile = NULL;       
+       audiofile = NULL;
+       audiofile_pitch_correction=0;
+       mix_solo=0;
+       mix_mute=0;
+       res_mute=mute;
+       res_mute_old=0;
+       
+       audio_hidden=false;
+       control_hidden=false;\r
 }
 
 vtt_class :: ~vtt_class()
 {
        vtt_fx *effect;
        stop();
-//     pthread_mutex_lock(&main_lock);
+
        main_list.remove(this);
-//     pthread_mutex_unlock(&main_lock);
        if (audiofile) delete audiofile;
        //if (buffer) free(buffer);
        if (output_buffer) tX_freemem(output_buffer, "output_buffer", "vtt Destructor");
@@ -216,9 +219,9 @@ void vtt_class :: set_name(char *newname)
        gui_set_name(this, name);       
 }
 
-int vtt_class :: load_file(char *fname)
+tX_audio_error vtt_class :: load_file(char *fname)
 {
-       int res;
+       tX_audio_error res;
        int was_playing=is_playing;
        
        if (is_playing) stop();
@@ -233,9 +236,11 @@ int vtt_class :: load_file(char *fname)
        audiofile=new tx_audiofile();
        res=audiofile->load(fname);     
        
-       if (res==TX_AUDIO_SUCCESS)
-       {
+       if (res==TX_AUDIO_SUCCESS) {
                buffer=audiofile->get_buffer();
+               double file_rate=audiofile->get_sample_rate();
+               audiofile_pitch_correction=file_rate/44100.0;
+               recalc_pitch();
                samples_in_buffer=audiofile->get_no_samples();
                maxpos=audiofile->get_no_samples();
                strcpy(filename, fname);
@@ -260,8 +265,8 @@ int vtt_class :: set_output_buffer_size(int newsize)
        tX_malloc(ec_output_buffer, "ec_output_buffer", "vtt set_output_buffer_size()", sizeof(float)*newsize, (float *));
 
        if (output_buffer) tX_freemem(output_buffer, "output_buffer", "vtt set_output_buffer_size()");
-       //output_buffer = (float *) malloc (sizeof(float)*newsize);
        tX_malloc(output_buffer, "output_buffer", "vtt set_output_buffer_size()", sizeof(float)*newsize, (float *));
+
        end_of_outputbuffer = output_buffer + newsize; //size_t(sizeof(float)*(newsize));
        
        samples_in_outputbuffer=newsize;
@@ -302,7 +307,6 @@ void vtt_class :: recalc_volume()
                res_volume_left=res_volume_right=res_volume;
        }
        
-       
        if (ec_pan>0.0)
        {
                ec_volume_left=(1.0-ec_pan)*ec_res_volume;
@@ -333,7 +337,6 @@ void vtt_class :: set_pan(f_prec newpan)
 void vtt_class :: set_pitch(f_prec newpitch)
 {
        rel_pitch=newpitch;
-//     res_pitch=fabs(globals.pitch)*rel_pitch;
        res_pitch=globals.pitch*rel_pitch;
        speed=res_pitch;
        ec_set_length(ec_length);
@@ -341,8 +344,8 @@ void vtt_class :: set_pitch(f_prec newpitch)
 
 void vtt_class :: recalc_pitch()
 {
-//     res_pitch=fabs(globals.pitch)*rel_pitch;
        res_pitch=globals.pitch*rel_pitch;
+       res_pitch*=audiofile_pitch_correction;
        speed=res_pitch;
        ec_set_length(ec_length);
 }
@@ -357,15 +360,41 @@ void vtt_class :: set_loop(int newstate)
        loop=newstate;
 }
 
-void vtt_class :: set_controls (int x, int y)
+void vtt_class :: set_mute(int newstate)
 {
-       x_control=x;
-       y_control=y;
+       mute=newstate;
+       calc_mute();
 }
 
-void vtt_class :: set_mute(int newstate)
+void vtt_class :: set_mix_mute(int newstate)
 {
-       mute=newstate;
+       mix_mute=newstate;
+       calc_mute();
+}
+
+void vtt_class :: set_mix_solo(int newstate)
+{
+       if (mix_solo && !newstate)
+       {
+               /* turning it off */
+               mix_solo=0;
+               solo_ctr--;
+       }
+       else if (!mix_solo && newstate)
+       {
+               /* turning it on */
+               mix_solo=1;
+               solo_ctr++;
+       }
+       calc_mute();
+
+       /* locking ? */
+       list <vtt_class *> :: iterator vtt;
+       
+       for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++)
+       {
+               (*vtt)->calc_mute();
+       }
 }
 
 void vtt_class :: lp_set_enable (int newstate)
@@ -400,8 +429,6 @@ void vtt_class :: lp_set_freq(f_prec freq)
        
        lp_a=0.9999-freq;
        lp_b=lp_reso*(1.0+(1.0/lp_a));
-       
-       //printf("a %f, b%f\n", lp_a, lp_b);
 }
 
 void vtt_class :: lp_setup(f_prec gain, f_prec reso, f_prec freq)
@@ -435,8 +462,7 @@ void vtt_class :: ec_set_pan(f_prec pan)
 void vtt_class :: ec_set_length(f_prec length)
 {
        int delay;
-       int i=0;
-       
+
        ec_length=length;
        if (res_pitch==0) 
        {
@@ -520,7 +546,9 @@ vtt_fx_ladspa * vtt_class :: add_effect (LADSPA_Plugin *plugin)
 
 void vtt_class :: calc_speed()
 {
-       do_mute=fade_out=fade_in=0;
+       do_mute=0;
+       fade_out=0;
+       fade_in=0;
 
        if (speed != speed_target)
        {
@@ -556,9 +584,9 @@ void vtt_class :: calc_speed()
 
        speed_last = speed_real;
 
-       if (mute != mute_old)
+       if (res_mute != res_mute_old)
        {
-               if (mute)
+               if (res_mute)
                {
                        fade_out=1; fade_in=0;
                        fade=NEED_FADE_IN;
@@ -568,11 +596,11 @@ void vtt_class :: calc_speed()
                        fade_in=1; fade_out=0;
                        fade=NEED_FADE_OUT;
                }
-               mute_old=mute;
+               res_mute_old=res_mute;
        }
        else
        {
-               if (mute) do_mute=1;
+               if (res_mute) do_mute=1;
        }       
 }
 
@@ -823,16 +851,16 @@ int vtt_class :: set_mix_buffer_size(int no_samples)
        
        if (mix_buffer) tX_freemem(mix_buffer, "mix_buffer", "vtt set_mix_buffer_size()");
        samples_in_mix_buffer=no_samples*2;
-       //mix_buffer=(float *) malloc (sizeof(float)*samples_in_mix_buffer);
+
        tX_malloc(mix_buffer, "mix_buffer", "vtt set_mix_buffer_size()", sizeof(float)*samples_in_mix_buffer, (float *));
        mix_buffer_end=mix_buffer+samples_in_mix_buffer;
+
 //     printf("mix_buffer: %12x\n", mix_buffer);
-       
 //     printf("mix_samples: %i, out_samples: %i", samples_in_mix_buffer, no_samples);
        
        if (mix_out_buffer) tX_freemem(mix_out_buffer, "mix_out_buffer", "vtt set_mix_buffer_size()");
-       //mix_out_buffer=(int16_t *) malloc (sizeof(int16_t)*samples_in_mix_buffer + 4); /* extra 4 for 3DNow! */
        tX_malloc(mix_out_buffer, "mix_out_buffer", "vtt set_mix_buffer_size()", sizeof(int16_t)*samples_in_mix_buffer + 4, (int16_t *));
+
 //     printf("mix_out_buffer: %12x\n", mix_out_buffer);
        
        for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++)
@@ -860,9 +888,47 @@ int16_t * vtt_class :: render_all_turntables()
 #ifdef USE_FLASH
        f_prec max;
        f_prec min;
-#ifdef USE_3DNOW       
+#ifdef USE_3DNOW
        mmx_t mm_max;
        mmx_t mm_min;
+       mmx_t mm_volume;
+       mmx_t mm_src1;
+       mmx_t mm_src2;
+
+#ifndef OVERRIDE_MOVQ_AUTODETECT
+#ifndef GCC_VERSION
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif /* GCC_VERSION */
+
+#if (GCC_VERSION < 2096)
+#warning "*************************"
+#warning "* gcc < 2.96            *"
+#warning "* assuming working movq *"
+#warning "*************************"
+#undef GCC_MOVQ_BUG_WORKAROUND
+#else
+#warning "*************************"
+#warning "* gcc >= 2.96           *"
+#warning "* using movq-workaround *"
+#warning "*************************"
+#define GCC_MOVQ_BUG_WORKAROUND 1
+#endif /* GCC < 2.96 */
+#endif /* OVERRIDE MOVQ AUTODETECVT */
+       
+#ifdef GCC_MOVQ_BUG_WORKAROUND
+       /* REQUIRED DUE TO GCC BUG (2.96-3.0.2) */
+       mmx_t *mm_src1_ptr=&mm_src1;
+       mmx_t *mm_src2_ptr=&mm_src2;
+       mmx_t *mm_volume_ptr=&mm_volume;
+       mmx_t *mm_max_ptr=&mm_max;
+       mmx_t *mm_min_ptr=&mm_min;
+       
+#define MM_VAR_ACC(var) (* var ## _ptr)
+#define MM_VAR_MOVQ(var) * var ## _ptr
+#else
+#define MM_VAR_ACC(var) var
+#define MM_VAR_MOVQ(var) var
+#endif 
        int32_t *temp_int=&mm_max.d[1];
 #endif 
 #endif 
@@ -883,6 +949,7 @@ int16_t * vtt_class :: render_all_turntables()
                        max=(*vtt)->max_value;
                        min=max;
 
+#ifndef USE_3DNOW
                        for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
                        {                               
                                temp=(*vtt)->output_buffer[sample];
@@ -893,13 +960,66 @@ int16_t * vtt_class :: render_all_turntables()
                                
                                if (temp>max) max=temp;
                                else if (temp<min) min=temp;
-                       }               
+                       }
+#else
+                       MM_VAR_ACC(mm_volume).s[0]=(*vtt)->res_volume_left;
+                       MM_VAR_ACC(mm_volume).s[1]=(*vtt)->res_volume_right;
+
+                       MM_VAR_ACC(mm_max).s[1]=MM_VAR_ACC(mm_max).s[0]=max;
+                       MM_VAR_ACC(mm_min).s[1]=MM_VAR_ACC(mm_min).s[0]=min;
+                       
+                       movq_m2r(MM_VAR_MOVQ(mm_max), mm1);
+                       movq_m2r(MM_VAR_MOVQ(mm_min), mm2);
+                                                       
+                       movq_m2r(MM_VAR_MOVQ(mm_volume), mm0);
+                       
+                       mix=(mmx_t*)mix_buffer;
+                       
+                       for (f_prec* src=(*vtt)->output_buffer; mix < (mmx_t*) mix_buffer_end;)
+                       {
+                               /* first sample */
+                               MM_VAR_ACC(mm_src1).s[0]=*src;
+                               MM_VAR_ACC(mm_src1).s[1]=*src;
+                                       
+                               /* sample * l/r volume */
+                               movq_m2r(MM_VAR_MOVQ(mm_src1), mm3);
+                               pfmul_r2r(mm0, mm3);
+                               movq_r2m(mm3, *mix);
+                                       
+                               /* next sample */
+                               src++, mix++;
+                               MM_VAR_ACC(mm_src2).s[0]=*src;
+                               MM_VAR_ACC(mm_src2).s[1]=*src;
+                                       
+                               /* sample * l/r volume */
+                               movq_m2r(MM_VAR_MOVQ(mm_src2), mm3);
+                               pfmul_r2r(mm0, mm3);
+                               movq_r2m(mm3, *mix);
+                                       
+                               /* calculating min/max */
+                               MM_VAR_ACC(mm_src1).s[1]=MM_VAR_ACC(mm_src2).s[0];
+                               movq_m2r(mm_src1, mm3);
+                               pfmax_r2r(mm3, mm1);
+                               pfmin_r2r(mm3, mm2);
+                               
+                               src++, mix++;
+                       }
+
+                       movq_r2m(mm1, MM_VAR_MOVQ(mm_max));
+                       movq_r2m(mm2, MM_VAR_MOVQ(mm_min));
+                       
+                       femms();
+                       
+                       if (MM_VAR_ACC(mm_max).s[0]>MM_VAR_ACC(mm_max).s[1]) max=MM_VAR_ACC(mm_max).s[0]; else max=MM_VAR_ACC(mm_max).s[1];
+                       if (MM_VAR_ACC(mm_min).s[0]<MM_VAR_ACC(mm_min).s[0]) min=MM_VAR_ACC(mm_min).s[0]; else min=MM_VAR_ACC(mm_min).s[1];
+#endif                 
                        
                        min*=-1.0;
                        if (min>max) (*vtt)->max_value=min; else (*vtt)->max_value=max;
 
                        if ((*vtt)->ec_enable)
                        {
+#ifndef USE_3DNOW                      
                                for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
                                {                               
                                        temp=(*vtt)->ec_output_buffer[sample];
@@ -908,13 +1028,36 @@ int16_t * vtt_class :: render_all_turntables()
                                        mix_sample++;
                                        mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_right;
                                        mix_sample++;
-                               }               
+                               }
+#else
+                               MM_VAR_ACC(mm_volume).s[0]=(*vtt)->ec_volume_left;
+                               MM_VAR_ACC(mm_volume).s[1]=(*vtt)->ec_volume_right;
+                                               
+                               movq_m2r(MM_VAR_MOVQ(mm_volume), mm0);
+                               mix =(mmx_t*)mix_buffer;
+
+                               for (f_prec* src=(*vtt)->ec_output_buffer; mix < (mmx_t*) mix_buffer_end; src++, mix++)
+                               {
+                                       /* first sample */
+                                       MM_VAR_ACC(mm_src1).s[0]=*src;
+                                       MM_VAR_ACC(mm_src1).s[1]=*src;
+                               
+                                       /* sample * l/r volume */
+                                       movq_m2r(MM_VAR_MOVQ(mm_src1), mm3);
+                                       pfmul_r2r(mm0, mm3);
+                               
+                                       /* accumulating complete mix */
+                                       movq_m2r(*mix, mm4);
+                                       pfadd_r2r(mm4, mm3);
+                                       movq_r2m(mm3, *mix);
+                               }
+                               femms();
+#endif                         
                        }
                        
                        if (master_triggered)
                        {
                                pthread_mutex_unlock(&render_lock);
-//                             pthread_mutex_lock(&main_lock);
                                for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++)
                                {
                                        if ((*vtt)->is_sync_client)
@@ -930,7 +1073,6 @@ int16_t * vtt_class :: render_all_turntables()
                                                }
                                        }
                                }
-//                             pthread_mutex_unlock(&main_lock);
                                pthread_mutex_lock(&render_lock);
                        }
                        
@@ -941,6 +1083,7 @@ int16_t * vtt_class :: render_all_turntables()
                                max=(*vtt)->max_value;
                                min=max;
 
+#ifndef USE_3DNOW
                                for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
                                {                               
                                        temp=(*vtt)->output_buffer[sample];
@@ -952,12 +1095,72 @@ int16_t * vtt_class :: render_all_turntables()
                                        if (temp>max) max=temp;
                                        else if (temp<min) min=temp;
                                }
+#else
+                               MM_VAR_ACC(mm_volume).s[0]=(*vtt)->res_volume_left;
+                               MM_VAR_ACC(mm_volume).s[1]=(*vtt)->res_volume_right;
+
+                               MM_VAR_ACC(mm_max).s[1]=MM_VAR_ACC(mm_max).s[0]=max;
+                               MM_VAR_ACC(mm_min).s[1]=MM_VAR_ACC(mm_min).s[0]=min;
+                       
+                               movq_m2r(MM_VAR_MOVQ(mm_max), mm1);
+                               movq_m2r(MM_VAR_MOVQ(mm_min), mm2);
+                                                       
+                               movq_m2r(MM_VAR_MOVQ(mm_volume), mm0);
+                               mix=(mmx_t*)mix_buffer;
+
+                               for (f_prec* src=(*vtt)->output_buffer; mix < (mmx_t*) mix_buffer_end;)
+                               {
+                                       /* first sample */
+                                       MM_VAR_ACC(mm_src1).s[0]=*src;
+                                       MM_VAR_ACC(mm_src1).s[1]=*src;
+                                       
+                                       /* sample * l/r volume */
+                                       movq_m2r(MM_VAR_MOVQ(mm_src1), mm3);
+                                       pfmul_r2r(mm0, mm3);
+                                       
+                                       /* accumulating complete mix */
+                                       movq_m2r(*mix, mm4);
+                                       pfadd_r2r(mm4, mm3);
+                                       movq_r2m(mm3, *mix);
+                                       
+                                       /* next sample */
+                                       src++, mix++;
+                                       MM_VAR_ACC(mm_src2).s[0]=*src;
+                                       MM_VAR_ACC(mm_src2).s[1]=*src;
+                                       
+                                       /* sample * l/r volume */
+                                       movq_m2r(MM_VAR_MOVQ(mm_src2), mm3);
+                                       pfmul_r2r(mm0, mm3);
+
+                                       /* accumulating complete mix */
+                                       movq_m2r(*mix, mm4);
+                                       pfadd_r2r(mm4, mm3);
+                                       movq_r2m(mm3, *mix);
+                                       
+                                       /* calculating min/max */
+                                       MM_VAR_ACC(mm_src1).s[1]=MM_VAR_ACC(mm_src2).s[0];
+                                       movq_m2r(MM_VAR_MOVQ(mm_src1), mm3);
+                                       pfmax_r2r(mm3, mm1);
+                                       pfmin_r2r(mm3, mm2);
+                                       
+                                       src++, mix++;
+                               }
+
+                               movq_r2m(mm1, MM_VAR_MOVQ(mm_max));
+                               movq_r2m(mm2, MM_VAR_MOVQ(mm_min));
+                               
+                               femms();
+       
+                               if (MM_VAR_ACC(mm_max).s[0]>MM_VAR_ACC(mm_max).s[1]) max=MM_VAR_ACC(mm_max).s[0]; else max=MM_VAR_ACC(mm_max).s[1];
+                               if (MM_VAR_ACC(mm_min).s[0]<MM_VAR_ACC(mm_min).s[0]) min=MM_VAR_ACC(mm_min).s[0]; else min=MM_VAR_ACC(mm_min).s[1];
+#endif
                                
                                min*=-1.0;
                                if (min>max) (*vtt)->max_value=min; else (*vtt)->max_value=max;
                                
                                if ((*vtt)->ec_enable)
                                {
+#ifndef USE_3DNOW
                                        for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
                                        {                               
                                                temp=(*vtt)->ec_output_buffer[sample];
@@ -966,7 +1169,32 @@ int16_t * vtt_class :: render_all_turntables()
                                                mix_sample++;
                                                mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_right;
                                                mix_sample++;
-                                       }               
+                                       }
+#else
+                                       MM_VAR_ACC(mm_volume).s[0]=(*vtt)->ec_volume_left;
+                                       MM_VAR_ACC(mm_volume).s[1]=(*vtt)->ec_volume_right;
+                                               
+                                       movq_m2r(MM_VAR_MOVQ(mm_volume), mm0);
+                                       mix =(mmx_t*)mix_buffer;
+
+                                       for (f_prec* src=(*vtt)->ec_output_buffer; mix < (mmx_t*) mix_buffer_end; src++, mix++)
+                                       {
+                                               /* first sample */
+                                               MM_VAR_ACC(mm_src1).s[0]=*src;
+                                               MM_VAR_ACC(mm_src1).s[1]=*src;
+                               
+                                               /* sample * l/r volume */
+                                               movq_m2r(MM_VAR_MOVQ(mm_src1), mm3);
+                                               pfmul_r2r(mm0, mm3);
+                               
+                                               /* accumulating complete mix */
+                                               movq_m2r(*mix, mm4);
+                                               pfadd_r2r(mm4, mm3);
+                                               movq_r2m(mm3, *mix);
+                                       }
+
+                                       femms();
+#endif                                 
                                }
                        }
                        
@@ -978,6 +1206,14 @@ int16_t * vtt_class :: render_all_turntables()
                        for (sample=0; sample<samples_in_mix_buffer; sample+=2)
                        {                               
                                temp=mix_buffer[sample];
+
+#ifndef TX_DO_CLIP
+#define FL_SHRT_MAX 32767.0
+#define FL_SHRT_MIN -32768.0
+                               if(temp < FL_SHRT_MIN) temp = FL_SHRT_MIN;
+                               else if (temp > FL_SHRT_MAX) temp = FL_SHRT_MAX;
+#endif                                 
+
                                mix_out_buffer[sample]=(int16_t) temp;
                        
                                if (temp>max) max=temp;
@@ -995,6 +1231,12 @@ int16_t * vtt_class :: render_all_turntables()
                        for (sample=1; sample<samples_in_mix_buffer; sample+=2)
                        {                               
                                temp=mix_buffer[sample];
+
+#ifndef TX_DO_CLIP
+                               if(temp < FL_SHRT_MIN) temp = FL_SHRT_MIN;
+                               else if (temp > FL_SHRT_MAX) temp = FL_SHRT_MAX;
+#endif
+                               
                                mix_out_buffer[sample]=(int16_t) temp;
                        
                                if (temp>max) max=temp;
@@ -1083,8 +1325,6 @@ int vtt_class :: trigger()
        speed=res_pitch;
        speed_real=res_pitch;
        speed_target=res_pitch;
-/*     mute=0;
-       mute_old=0;*/
        want_stop=0;
 
        /* activating plugins */
@@ -1201,10 +1441,8 @@ void vtt_class :: set_master_volume(f_prec new_volume)
        
        if (main_list.size()>0)
        {
-//             res_master_volume=master_volume/((f_prec) main_list.size());
                vol_channel_adjust=sqrt((f_prec) main_list.size());
-               res_master_volume=master_volume/vol_channel_adjust;
-               
+               res_master_volume=master_volume/vol_channel_adjust;             
        }
                
        for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++)
@@ -1256,18 +1494,28 @@ void vtt_class :: focus_next()
                return;
        }
        
-       for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++)
-       {
-               if ((*vtt)==focused_vtt)
-               {
+       for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++) {
+               if ((*vtt)==focused_vtt) {
+                       /* Ok, we found ourselves.. */
+                       
                        vtt++;
-                       if (vtt==main_list.end())
-                       {                       
-                               focused_vtt=(*main_list.begin());
-                               return;
+                       while ((vtt!=main_list.end()) && ((*vtt)->audio_hidden) ) {
+                               vtt++;
                        }
-                       else
-                       {
+                       
+                       if (vtt==main_list.end()) {
+                               /* No other "focusable" after this vtt so we're looking for the next */
+                               
+                               for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++) {
+                                       if (! (*vtt)->audio_hidden) {
+                                               focused_vtt=(*vtt);
+                                               return;
+                                       }
+                               }
+                               /* When we get here there's no "focusable" vtt at all... damn */
+                               focused_vtt=NULL;
+                               return;
+                       } else {
                                focused_vtt=(*vtt);
                                return;
                        }
@@ -1292,852 +1540,349 @@ void vtt_class :: set_scratch(int newstate)
        }
 }
 
-#define MAGIC 0.05
-
-void vtt_class :: handle_input(int control, f_prec value)
-{
-       f_prec temp;
-       
-       switch (control)
-       {
-               case CONTROL_SCRATCH:
-               if (do_scratch) sp_speed.receive_input_value(value*globals.mouse_speed);
-               sense_cycles=globals.sense_cycles;
-               break;
-               
-               case CONTROL_VOLUME:
-               temp=rel_volume+MAGIC*value*globals.mouse_speed;
-               if (temp>2.0) temp=2.0;
-               else if (temp<0) temp=0;
-               sp_volume.receive_input_value(temp);
-               break;
-               
-               case CONTROL_CUTOFF:
-               temp=lp_freq+MAGIC*value*globals.mouse_speed;
-               if (temp>0.99) temp=0.99;
-               else if (temp<0) temp=0;
-               sp_lp_freq.receive_input_value(temp);
-               break;
-               
-               case CONTROL_FEEDBACK:
-               temp=ec_feedback+MAGIC*value*globals.mouse_speed;
-               if (temp>1.0) temp=1.0;
-               else if (temp<0) temp=0;
-               sp_ec_feedback.receive_input_value(temp);
-               break;
-       }
-}
 
 void vtt_class :: unfocus()
 {
        focused_vtt=NULL;
 }
 
-extern void vg_display_ycontrol(vtt_class *vtt);
-extern void vg_display_xcontrol(vtt_class *vtt);
-
 void vtt_class :: set_x_input_parameter(tX_seqpar *sp)
 {
        x_par = sp;
-       vg_display_xcontrol(this);
 }
 
 void vtt_class :: set_y_input_parameter(tX_seqpar *sp)
 {
        y_par = sp;
-       vg_display_ycontrol(this);
 }
 
 void vtt_class :: xy_input(f_prec x_value, f_prec y_value)
 {
        if (x_par) x_par->handle_mouse_input(x_value*globals.mouse_speed);
        if (y_par) y_par->handle_mouse_input(y_value*globals.mouse_speed);
-       
-/*     handle_input(x_control, x_value);
-       handle_input(y_control, y_value);*/
 }
 
-
 #define store(data); if (fwrite((void *) &data, sizeof(data), 1, output)!=1) res+=1;
 
-int  vtt_class :: save(FILE * output)
-{
+int  vtt_class :: save(FILE *rc, char *indent) {
        list <vtt_fx *> :: iterator effect;
-
+       char tmp_xml_buffer[4096];
+       
        int res=0;
-       u_int32_t pid;
-       int32_t counter;
-       u_int8_t hidden;
-       
-       store(name);
-       store(filename);
-       store(is_sync_master);
-       store(is_sync_client);
-       store(sync_cycles);
-       store(rel_volume);
-       store(rel_pitch);
-       
-       store(autotrigger);
-       store(loop);
-       
-       store(mute);
-       store(pan);
-       
-       store(lp_enable);
-       store(lp_gain);
-       store(lp_reso);
-       store(lp_freq);
-       
-       store(ec_enable);
-       store(ec_length);
-       store(ec_feedback);
-       store(ec_pan);
-       store(ec_volume);
-
-       pid=sp_speed.get_persistence_id();
-       store(pid);
-       pid=sp_volume.get_persistence_id();
-       store(pid);
-       pid=sp_pitch.get_persistence_id();
-       store(pid);
-       pid=sp_trigger.get_persistence_id();
-       store(pid);
-       pid=sp_loop.get_persistence_id();
-       store(pid);
-       pid=sp_sync_client.get_persistence_id();
-       store(pid);
-       pid=sp_sync_cycles.get_persistence_id();
-       store(pid);
-       pid=sp_lp_enable.get_persistence_id();
-       store(pid);
-       pid=sp_lp_gain.get_persistence_id();
-       store(pid);
-       pid=sp_lp_reso.get_persistence_id();
-       store(pid);
-       pid=sp_lp_freq.get_persistence_id();
-       store(pid);
-       pid=sp_ec_enable.get_persistence_id();
-       store(pid);
-       pid=sp_ec_length.get_persistence_id();
-       store(pid);
-       pid=sp_ec_feedback.get_persistence_id();
-       store(pid);
-       pid=sp_ec_volume.get_persistence_id();
-       store(pid);
-       pid=sp_ec_pan.get_persistence_id();
-       store(pid);
-       pid=sp_mute.get_persistence_id();
-       store(pid);
-       pid=sp_spin.get_persistence_id();
-       store(pid);
-       pid=sp_pan.get_persistence_id();
-       store(pid);
-               
-       counter=fx_list.size();
-       store(counter);
 
-       for (effect=fx_list.begin(); effect!=fx_list.end(); effect++)
-       {
-               (*effect)->save(output);
-       }
+       fprintf(rc, "%s<turntable>\n", indent);
+       strcat(indent, "\t");
        
-       if (x_par)
-       {
-               pid=1;
-               store(pid);
-               pid=x_par->get_persistence_id();
-               store(pid);
+       store_string("name", name);
+       if (buffer) {
+               store_string("audiofile", filename);
+       } else {
+               store_string("audiofile", "");
        }
-       else
-       {
-               pid=0;
-               store(pid);
-       }
-
-       if (y_par)
-       {
-               pid=1;
-               store(pid);
-               pid=y_par->get_persistence_id();
-               store(pid);
-       }
-       else
-       {
-               pid=0;
-               store(pid);
-       }
-               
-       hidden=gui.main_panel->is_hidden();
-       store(hidden);
-
-       hidden=gui.trigger_panel->is_hidden();
-       store(hidden);
+       store_bool("sync_master", is_sync_master);
+       store_bool("autotrigger", autotrigger);
+       store_bool_sp("loop", loop, sp_loop);
 
-       hidden=gui.lp_panel->is_hidden();
-       store(hidden);
+       store_bool_sp("sync_client", is_sync_client, sp_sync_client);
+       store_int_sp("sync_cycles", sync_cycles, sp_sync_cycles);
 
-       hidden=gui.ec_panel->is_hidden();
-       store(hidden);
+       store_float_sp("volume", rel_volume, sp_volume);
+       store_float_sp("pitch", rel_pitch, sp_pitch);   
+       store_bool_sp("mute", mute, sp_mute);
+       store_float_sp("pan", pan, sp_pan);
        
-       return(res);
-}
-
-#define atload(data); if (fread((void *) &data, sizeof(data), 1, input)!=1) res+=1;
+       store_bool_sp("lowpass_enable", lp_enable, sp_lp_enable);
+       store_float_sp("lowpass_gain", lp_gain, sp_lp_gain);
+       store_float_sp("lowpass_reso", lp_reso, sp_lp_reso);
+       store_float_sp("lowpass_freq", lp_freq, sp_lp_freq);
 
-int vtt_class :: load_10(FILE * input)
-{
-       int res=0;
+       store_bool_sp("echo_enable", ec_enable, sp_ec_enable);
+       store_float_sp("echo_length", ec_length, sp_ec_length);
+       store_float_sp("echo_feedback", ec_feedback, sp_ec_feedback);
+       store_float_sp("echo_pan", ec_pan, sp_ec_pan);
+       store_float_sp("echo_volume", ec_volume, sp_ec_volume);
        
-       atload(name);
-       atload(filename);
-       atload(is_sync_master);
-       atload(is_sync_client);
-       atload(sync_cycles);
-       atload(rel_volume);
-       recalc_volume();
-       atload(rel_pitch);
-       recalc_pitch();
-       
-       atload(autotrigger);
-       atload(loop);
-       
-       atload(mute);
-       atload(x_control);
-       atload(y_control);      
-       
-       atload(lp_enable);
-       atload(lp_gain);
-       atload(lp_reso);
-       atload(lp_freq);
-       lp_setup(lp_gain, lp_reso, lp_freq);
+       store_id("speed", sp_speed.get_persistence_id());
+       store_id("trigger", sp_trigger.get_persistence_id());
+       store_id("spin", sp_spin.get_persistence_id());
+
        
-       atload(ec_enable);
-       atload(ec_length);
-       ec_set_length(ec_length);
-       atload(ec_feedback);
-       ec_set_feedback(ec_feedback);
+       if (x_par) {
+               store_int("x_axis_mapping", x_par->get_persistence_id());
+       }
        
-       return(res);
-}
+       if (y_par) {
+               store_int("y_axis_mapping", y_par->get_persistence_id());
+       }
 
+       store_bool("audio_panel_hidden", audio_hidden);
+       store_bool("control_panel_hidden", control_hidden);
+       store_bool("main_panel_hidden", gui.main_panel->is_hidden());
+       store_bool("trigger_panel_hidden", gui.trigger_panel->is_hidden());
+       store_bool("lowpass_panel_hidden", gui.lp_panel->is_hidden());
+       store_bool("echo_panel_hidden", gui.ec_panel->is_hidden());
 
-int vtt_class :: load_11(FILE * input)
-{
-       int res=0;
-       u_int32_t pid;
-       int32_t gui_page;
-       
-       atload(name);
-       atload(filename);
-       atload(is_sync_master);
-       atload(is_sync_client);
-       atload(sync_cycles);
-       atload(rel_volume);
-       recalc_volume();
-       atload(rel_pitch);
-       recalc_pitch();
+       store_float("audio_x_zoom", gui_get_audio_x_zoom(this));
        
-       atload(autotrigger);
-       atload(loop);
+       fprintf(rc, "%s<fx>\n", indent);
+       strcat(indent, "\t");
        
-       atload(mute);
-       atload(x_control);
-       atload(y_control);      
-       
-       atload(lp_enable);
-       atload(lp_gain);
-       atload(lp_reso);
-       atload(lp_freq);
-       lp_setup(lp_gain, lp_reso, lp_freq);
+       for (effect=fx_list.begin(); effect!=fx_list.end(); effect++) {
+               (*effect)->save(rc, indent);
+       }
+       indent[strlen(indent)-1]=0;
+       fprintf(rc, "%s</fx>\n", indent);
        
-       atload(ec_enable);
-       atload(ec_length);
-       ec_set_length(ec_length);
-       atload(ec_feedback);
-       ec_set_feedback(ec_feedback);
-
-       atload(pid);
-       sp_speed.set_persistence_id(pid);
-       atload(pid);
-       sp_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_pitch.set_persistence_id(pid);
-       atload(pid);
-       sp_trigger.set_persistence_id(pid);
-       atload(pid);
-       sp_loop.set_persistence_id(pid);
-       atload(pid);
-       sp_sync_client.set_persistence_id(pid);
-       atload(pid);
-       sp_sync_cycles.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_enable.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_gain.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_reso.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_freq.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_enable.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_length.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_feedback.set_persistence_id(pid);
-       atload(pid);
-       sp_mute.set_persistence_id(pid);
-       atload(pid);
-       sp_spin.set_persistence_id(pid);
-       
-       atload(gui_page);
-       vg_set_current_page(this, gui_page);
+       indent[strlen(indent)-1]=0;
+       fprintf(rc, "%s</turntable>\n", indent);
        
        return(res);
 }
 
-int vtt_class :: load_12(FILE * input)
-{
+#define TX_XML_SETFILE_VERSION "1.0"
+
+int  vtt_class :: save_all(FILE* rc) {
        int res=0;
-       u_int32_t pid;
-       int32_t counter;
-       int32_t type;
-       long id;
-       int i,t;
-       LADSPA_Plugin *plugin;
-       char buffer[256];
-       vtt_fx_ladspa *ladspa_effect;
-       u_int8_t hidden;
-       
-       atload(buffer);
-       this->set_name(buffer);
-       atload(filename);
-       atload(is_sync_master);
-       atload(is_sync_client);
-       atload(sync_cycles);
-       atload(rel_volume);
-       recalc_volume();
-       atload(rel_pitch);
-       recalc_pitch();
-       
-       atload(autotrigger);
-       atload(loop);
-       
-       atload(mute);
-       
-       atload(lp_enable);
-       atload(lp_gain);
-       atload(lp_reso);
-       atload(lp_freq);
-       lp_setup(lp_gain, lp_reso, lp_freq);
-       
-       atload(ec_enable);
-       atload(ec_length);
-       ec_set_length(ec_length);
-       atload(ec_feedback);
-       ec_set_feedback(ec_feedback);
-
-       atload(pid);
-       sp_speed.set_persistence_id(pid);
-       atload(pid);
-       sp_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_pitch.set_persistence_id(pid);
-       atload(pid);
-       sp_trigger.set_persistence_id(pid);
-       atload(pid);
-       sp_loop.set_persistence_id(pid);
-       atload(pid);
-       sp_sync_client.set_persistence_id(pid);
-       atload(pid);
-       sp_sync_cycles.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_enable.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_gain.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_reso.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_freq.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_enable.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_length.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_feedback.set_persistence_id(pid);
-       atload(pid);
-       sp_mute.set_persistence_id(pid);
-       atload(pid);
-       sp_spin.set_persistence_id(pid);
-               
-       atload(counter);
+       list <vtt_class *> :: iterator vtt;
+       char indent[256];
        
-       for (i=0; i<counter; i++)
-       {
-               atload(type);
-               switch(type)
-               {
-                       case TX_FX_BUILTINCUTOFF:
-                               for (t=0; t<fx_list.size(); t++) effect_down(lp_fx);
-                       break;
-                       
-                       case TX_FX_BUILTINECHO:
-                               for (t=0; t<fx_list.size(); t++) effect_down(ec_fx);
-                       break;
-                       
-                       case TX_FX_LADSPA:
-                               atload(id);
-                               plugin=LADSPA_Plugin::getPluginByUniqueID(id);
-                               if (plugin)
-                               {
-                                       ladspa_effect=add_effect(plugin);
-                                       ladspa_effect->load(input);
-                               }
-                               else
-                               {
-                                       sprintf(buffer,"Fatal Error: Couldn't find required plugin with ID [%i].", id);
-                                       tx_note(buffer);
-                                       res++;
-                               }
-                       break;
-                       
-                       default:
-                               tx_note("Fatal Error loading set: unknown effect type!");
-                               res++;
-               }               
-       }
+       tX_seqpar :: create_persistence_ids();
 
-       atload(pid);
+       fprintf(rc, "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n\n");
+       fprintf(rc, "<terminatorXset version=\"%s\">\n", TX_XML_SETFILE_VERSION);
        
-       if (pid)
-       {
-               atload(pid);
-               set_x_input_parameter(tX_seqpar :: get_sp_by_persistence_id(pid));
-       }
-       else set_x_input_parameter(NULL);
-       
-       atload(pid);
-       
-       if (pid)
-       {
-               atload(pid);
-               set_y_input_parameter(tX_seqpar :: get_sp_by_persistence_id(pid));
-       }
-       else set_y_input_parameter(NULL);
-
-       atload(hidden);
-       gui.main_panel->hide(hidden);
+       strcpy(indent, "\t");
 
-       atload(hidden);
-       gui.trigger_panel->hide(hidden);
+       //store_int(vtt_amount); obsolete
 
-       atload(hidden);
-       gui.lp_panel->hide(hidden);
+       store_float_sp("master_volume", master_volume, sp_master_volume);
+       store_float_sp("master_pitch", globals.pitch, sp_master_pitch);
 
-       atload(hidden);
-       gui.ec_panel->hide(hidden);
+       for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++) {
+               res+=(*vtt)->save(rc, indent);
+       }
+       
+       sequencer.save(rc, indent);
+       
+       fprintf(rc, "</terminatorXset>\n");
        
        return(res);
 }
 
-int vtt_class :: load_13(FILE * input)
-{
-       int res=0;
-       u_int32_t pid;
-       int32_t counter;
-       int32_t type;
-       long id;
-       int i,t;
-       LADSPA_Plugin *plugin;
-       char buffer[256];
-       vtt_fx_ladspa *ladspa_effect;
-       u_int8_t hidden;
-       
-       atload(buffer);
-       this->set_name(buffer);
-       atload(filename);
-       atload(is_sync_master);
-       atload(is_sync_client);
-       atload(sync_cycles);
-       atload(rel_volume);
-       atload(rel_pitch);
-       recalc_pitch();
-       
-       atload(autotrigger);
-       atload(loop);
-       
-       atload(mute);
-       atload(pan);
-       
-       atload(lp_enable);
-       atload(lp_gain);
-       atload(lp_reso);
-       atload(lp_freq);
-       lp_setup(lp_gain, lp_reso, lp_freq);
-       
-       atload(ec_enable);
-       atload(ec_length);
-       ec_set_length(ec_length);
-       atload(ec_feedback);
-       ec_set_feedback(ec_feedback);
-       atload(ec_pan);
-       ec_set_pan(ec_pan);
-       atload(ec_volume);
-       ec_set_volume(ec_volume);
-
-       recalc_volume();
-
-       atload(pid);
-       sp_speed.set_persistence_id(pid);
-       atload(pid);
-       sp_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_pitch.set_persistence_id(pid);
-       atload(pid);
-       sp_trigger.set_persistence_id(pid);
-       atload(pid);
-       sp_loop.set_persistence_id(pid);
-       atload(pid);
-       sp_sync_client.set_persistence_id(pid);
-       atload(pid);
-       sp_sync_cycles.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_enable.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_gain.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_reso.set_persistence_id(pid);
-       atload(pid);
-       sp_lp_freq.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_enable.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_length.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_feedback.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_ec_pan.set_persistence_id(pid);
-       atload(pid);
-       sp_mute.set_persistence_id(pid);
-       atload(pid);
-       sp_spin.set_persistence_id(pid);
-       atload(pid);
-       sp_pan.set_persistence_id(pid);
-               
-       atload(counter);
-       
-       for (i=0; i<counter; i++)
-       {
-               atload(type);
-               switch(type)
-               {
-                       case TX_FX_BUILTINCUTOFF:
-                               for (t=0; t<fx_list.size(); t++) effect_down(lp_fx);
-                       break;
+int vtt_class :: load(xmlDocPtr doc, xmlNodePtr node) {
+       char buffer[1024];
+       bool hidden;
+       int xpar_id=-1;
+       int ypar_id=-1;
+       int elementFound;
+       char *pid_attr;
+       int pid;
+       double dvalue;
+       double tmp;
+       
+       for (xmlNodePtr cur=node->xmlChildrenNode; cur != NULL; cur = cur->next) {
+               if (cur->type == XML_ELEMENT_NODE) {
+                       elementFound=0;
                        
-                       case TX_FX_BUILTINECHO:
-                               for (t=0; t<fx_list.size(); t++) effect_down(ec_fx);
-                       break;
+                       restore_string_ac("name", buffer, set_name(buffer));
+                       restore_string("audiofile", filename);
+                       restore_bool("sync_master", is_sync_master);
+                       restore_bool("autotrigger", autotrigger);
+                       restore_bool_id("loop", loop, sp_loop, nop);
+                       restore_bool_id("sync_client", is_sync_client, sp_sync_client, set_sync_client(is_sync_client, sync_cycles));
+                       restore_int_id("sync_cycles", sync_cycles, sp_sync_cycles, set_sync_client(is_sync_client, sync_cycles));
+                       restore_float_id("volume", rel_volume, sp_volume, recalc_volume());
+                       restore_float_id("pitch", rel_pitch, sp_pitch, recalc_pitch());
+                       restore_bool_id("mute", mute, sp_mute, set_mute(mute));
+                       restore_float_id("pan", pan, sp_pan, set_pan(pan));
+       
+                       restore_bool_id("lowpass_enable", lp_enable, sp_lp_enable, lp_set_enable(lp_enable));
+                       restore_float_id("lowpass_gain", lp_gain, sp_lp_gain, lp_set_gain(lp_gain)); 
+                       restore_float_id("lowpass_reso", lp_reso, sp_lp_reso, lp_set_reso(lp_reso));
+                       restore_float_id("lowpass_freq", lp_freq, sp_lp_freq, lp_set_freq(lp_freq));
+       
+                       restore_bool_id("echo_enable", ec_enable, sp_ec_enable, ec_set_enable(ec_enable));      
+                       restore_float_id("echo_length", ec_length, sp_ec_length, ec_set_length(ec_length));
+                       restore_float_id("echo_feedback", ec_feedback, sp_ec_feedback, ec_set_feedback(ec_feedback));
+                       restore_float_id("echo_pan", ec_pan, sp_ec_pan, ec_set_pan(ec_pan));
+                       restore_float_id("echo_volume", ec_volume, sp_ec_volume, ec_set_volume(ec_volume));             
+               
+                       restore_id("speed", sp_speed);  
+                       restore_id("trigger", sp_trigger);
+                       restore_id("spin", sp_spin);
+       
+                       restore_int("x_axis_mapping", xpar_id);
+                       restore_int("y_axis_mapping", ypar_id);
+       
+                       restore_bool("audio_panel_hidden", audio_hidden);
+                       restore_bool("control_panel_hidden", control_hidden);
+                       restore_bool_ac("main_panel_hidden", hidden, gui.main_panel->hide(hidden));
+                       restore_bool_ac("trigger_panel_hidden", hidden, gui.trigger_panel->hide(hidden));
+                       restore_bool_ac("lowpass_panel_hidden", hidden, gui.lp_panel->hide(hidden));                    
+                       restore_bool_ac("echo_panel_hidden", hidden, gui.ec_panel->hide(hidden));
+                       restore_float_ac("audio_x_zoom", tmp, gui_set_audio_x_zoom(this,tmp));
+                       vg_adjust_zoom(gui.zoom, this);
                        
-                       case TX_FX_LADSPA:
-                               atload(id);
-                               plugin=LADSPA_Plugin::getPluginByUniqueID(id);
-                               if (plugin)
-                               {
-                                       ladspa_effect=add_effect(plugin);
-                                       ladspa_effect->load(input);
-                               }
-                               else
-                               {
-                                       sprintf(buffer,"Fatal Error: Couldn't find required plugin with ID [%i].", id);
-                                       tx_note(buffer);
-                                       res++;
+                       if (xmlStrcmp(cur->name, (xmlChar *) "fx")==0) {
+                               xmlNodePtr fx=cur;
+                               elementFound=1;
+                               
+                               for (xmlNodePtr cur=fx->xmlChildrenNode; cur != NULL; cur = cur->next) {
+                                       if (cur->type == XML_ELEMENT_NODE) {
+                                               int elementFound=0;
+                                               
+                                               if (xmlStrcmp(cur->name, (xmlChar *) "cutoff")==0) {
+                                                       for (unsigned int t=0; t<fx_list.size(); t++) effect_down(lp_fx);
+                                                       elementFound=1;
+                                               } else if (xmlStrcmp(cur->name, (xmlChar *) "lowpass")==0) {
+                                                       for (unsigned int t=0; t<fx_list.size(); t++) effect_down(ec_fx);
+                                                       elementFound=1;                                                         
+                                               } else if (xmlStrcmp(cur->name, (xmlChar *) "ladspa_plugin")==0) {
+                                                       xmlNodePtr pluginNode=cur;
+                                                       int ladspa_id=-1;
+                                                       elementFound=1;
+                                                       
+                                                       for (xmlNodePtr cur=pluginNode->xmlChildrenNode; cur!=NULL; cur = cur->next) {
+                                                               int elementFound;
+                                                               if (cur->type == XML_ELEMENT_NODE) {
+                                                                       elementFound=0;
+
+                                                                       restore_int("ladspa_id", ladspa_id);
+                                                                       if (elementFound) break;
+                                                               }
+                                                       }
+                                                       
+                                                       if (ladspa_id!=-1) {
+                                                               LADSPA_Plugin *plugin=LADSPA_Plugin::getPluginByUniqueID(ladspa_id);
+                                                               if (plugin) {
+                                                                       vtt_fx_ladspa *ladspa_effect=add_effect(plugin);
+                                                                       ladspa_effect->load(doc, pluginNode);
+                                                               } else {
+                                                                       sprintf(buffer,"The terminatorX set file you are loading makes use of a LADSPA plugin that is not installed on this machine. The plugin's ID is [%i].", ladspa_id);
+                                                                       tx_note(buffer, true);                                                  
+                                                               }
+                                                       } else {
+                                                               tX_warning("ladspa_plugin section without a ladspa_id element.");
+                                                       }
+                                                       
+                                               } else {
+                                                       tX_warning("unhandled element %s in fx section.", cur->name);
+                                               }
+                                       }
                                }
-                       break;
+                       }
                        
-                       default:
-                               tx_note("Fatal Error loading set: unknown effect type!");
-                               res++;
-               }               
+                       if(!elementFound) {
+                               tX_warning("unhandled element %s in turntable secion.", cur->name);
+                       }
+               }
        }
 
-       atload(pid);
-       
-       if (pid)
-       {
-               atload(pid);
-               set_x_input_parameter(tX_seqpar :: get_sp_by_persistence_id(pid));
+       recalc_volume();
+
+       if (xpar_id>=0) {
+               set_x_input_parameter(tX_seqpar :: get_sp_by_persistence_id(xpar_id));
        }
        else set_x_input_parameter(NULL);
        
-       atload(pid);
-       
-       if (pid)
-       {
-               atload(pid);
-               set_y_input_parameter(tX_seqpar :: get_sp_by_persistence_id(pid));
+       if (ypar_id) {
+               set_y_input_parameter(tX_seqpar :: get_sp_by_persistence_id(ypar_id));
        }
        else set_y_input_parameter(NULL);
-
-       atload(hidden);
-       gui.main_panel->hide(hidden);
-
-       atload(hidden);
-       gui.trigger_panel->hide(hidden);
-
-       atload(hidden);
-       gui.lp_panel->hide(hidden);
-
-       atload(hidden);
-       gui.ec_panel->hide(hidden);
-       
-       return(res);
+               
+       return 0;
 }
 
 
-int  vtt_class :: save_all(FILE* output)
-{
+int vtt_class :: load_all(xmlDocPtr doc, char *fname) {
+       xmlNodePtr root=xmlDocGetRootElement(doc);
+       int elementFound=0;
+       char fn_buff[4096];
+       double dvalue;
        int res=0;
-       list <vtt_class *> :: iterator vtt;
-       u_int32_t pid;
-       
-       tX_seqpar :: create_persistence_ids();
-       
-       store(vtt_amount);
-       store(master_volume);
-       store(globals.pitch);
-       pid=sp_master_volume.get_persistence_id();
-       store(pid);
-       pid=sp_master_pitch.get_persistence_id();
-       store(pid);
+       int restmp=0;
+       char *pid_attr;
+       int pid;
 
-       for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++)
-       {
-               res+=(*vtt)->save(output);
-       }
        
-       sequencer.save(output);
-       
-       return(res);
-}
-
-int  vtt_class :: load_all_10(FILE* input, char *fname)
-{
-       int res=0, restmp=0;
-       list <vtt_class *> :: iterator vtt;
-       unsigned int i, max, size;
-       int16_t *newbuffer;
-       vtt_class *newvtt;
-       char ftmp[PATH_MAX];
-       
-       while (main_list.size())
-       {
-               delete((*main_list.begin()));
+       if (!root) {
+               tX_error("no root element? What kind of XML document is this?");
+               return 1;
        }
-               
-       atload(max);
-       atload(master_volume);
-       set_master_volume(master_volume);
-       globals.volume=master_volume;
-       atload(globals.pitch);  
-       set_master_pitch(globals.pitch);
-
-       ld_create_loaddlg(TX_LOADDLG_MODE_MULTI, max);
-       ld_set_setname(fname);
-
-       for (i=0; i<max; i++)
-       {
-               newvtt=new vtt_class(1);
-               res+=newvtt->load_10(input);
-               
-               if (strlen(newvtt->filename))
-               {
-                       /* ftmp IS NECESSARY !!! */
-                       strcpy(ftmp, newvtt->filename);
-                       ld_set_filename(ftmp);
-                       
-                       //restmp=load_wav(newvtt->filename, &newbuffer, &size);
-                       restmp=newvtt->load_file(ftmp);
-                       res+=restmp;
-               }
-               gtk_box_pack_start(GTK_BOX(control_parent), newvtt->gui.control_box, TRUE, TRUE, 0);
-               gtk_box_pack_start(GTK_BOX(audio_parent), newvtt->gui.audio_box, TRUE, TRUE, 0);
        
+       if (xmlStrcmp(root->name, (const xmlChar *) "terminatorXset")) {
+               tX_error("this is not a terminatorXset file.")
+               return 2;
        }
        
-       sequencer.clear();
-       
-       ld_destroy();
+       if (xmlGetProp(root,(xmlChar *) "version")==NULL) {
+               tX_error("the set file lacks a version attribute.");
+               return 3;
+       }
        
-       return(res);
-}
-
-
-int  vtt_class :: load_all_11(FILE* input, char *fname)
-{
-       int res=0, restmp=0;
-       list <vtt_class *> :: iterator vtt;
-       unsigned int i, max, size;
-       int16_t *newbuffer;
-       vtt_class *newvtt;
-       char ftmp[PATH_MAX];
-       u_int32_t pid;
+       if (xmlStrcmp(xmlGetProp(root, (xmlChar *) "version"), (xmlChar *) TX_XML_SETFILE_VERSION)) {
+               tX_warning("this set file is version %s - while this releases uses version %s - trying to load anyway.", xmlGetProp(root, (xmlChar *) "version"), TX_XML_SETFILE_VERSION);
+       }
        
-       while (main_list.size())
-       {
+       /* delete current tables... */
+       while (main_list.size()) {
                delete((*main_list.begin()));
        }
-               
-       atload(max);
-       atload(master_volume);
-       set_master_volume(master_volume);
-       globals.volume=master_volume;
-       atload(globals.pitch);  
-       set_master_pitch(globals.pitch);
-       atload(pid);
-       sp_master_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_master_pitch.set_persistence_id(pid);
-
-       ld_create_loaddlg(TX_LOADDLG_MODE_MULTI, max);
-       ld_set_setname(fname);
 
-       for (i=0; i<max; i++)
-       {
-               newvtt=new vtt_class(1);
-               res+=newvtt->load_11(input);
-               
-               if (strlen(newvtt->filename))
-               {
-                       /* ftmp IS NECESSARY !!! */
-                       strcpy(ftmp, newvtt->filename);
-                       ld_set_filename(ftmp);
-                       
-                       //restmp=load_wav(newvtt->filename, &newbuffer, &size);
-                       restmp=newvtt->load_file(ftmp);
-                       res+=restmp;
+       int table_ctr=0;
+       
+       /* counting turntables.. */
+       for (xmlNodePtr cur=root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+               if (cur->type == XML_ELEMENT_NODE) {    
+                       if (xmlStrcmp(cur->name, (xmlChar *) "turntable")==0) {
+                               table_ctr++;
+                       }
                }
-               gtk_box_pack_start(GTK_BOX(control_parent), newvtt->gui.control_box, TRUE, TRUE, 0);
-               gtk_box_pack_start(GTK_BOX(audio_parent), newvtt->gui.audio_box, TRUE, TRUE, 0);
-               
        }
-       
-       sequencer.load(input);
-       
-       ld_destroy();
-       
-       return(res);
-}
 
+       tX_debug("Found %i turntables in set.",  table_ctr);
 
-int  vtt_class :: load_all_12(FILE* input, char *fname)
-{
-       int res=0, restmp=0;
-       list <vtt_class *> :: iterator vtt;
-       unsigned int i, max, size;
-       int16_t *newbuffer;
-       vtt_class *newvtt;
-       char ftmp[PATH_MAX];
-       u_int32_t pid;
-       
-       while (main_list.size())
-       {
-               delete((*main_list.begin()));
-       }
-               
-       atload(max);
-       atload(master_volume);
-       set_master_volume(master_volume);
-       globals.volume=master_volume;
-       atload(globals.pitch);  
-       set_master_pitch(globals.pitch);
-       atload(pid);
-       sp_master_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_master_pitch.set_persistence_id(pid);
-
-       ld_create_loaddlg(TX_LOADDLG_MODE_MULTI, max);
+       ld_create_loaddlg(TX_LOADDLG_MODE_MULTI, table_ctr);
        ld_set_setname(fname);
 
-       for (i=0; i<max; i++)
-       {
-               newvtt=new vtt_class(1);
-               res+=newvtt->load_12(input);
+       /* parsing all */
+       for (xmlNodePtr cur=root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+               if (cur->type == XML_ELEMENT_NODE) {                    
+                       elementFound=0;
                
-               if (strlen(newvtt->filename))
-               {
-                       /* ftmp IS NECESSARY !!! */
-                       strcpy(ftmp, newvtt->filename);
-                       ld_set_filename(ftmp);
+                       restore_float_id("master_volume", master_volume, sp_master_volume, set_master_volume(master_volume));
+                       restore_float_id("master_pitch", globals.pitch, sp_master_pitch, set_master_pitch(globals.pitch));
                        
-                       //restmp=load_wav(newvtt->filename, &newbuffer, &size);
-                       restmp=newvtt->load_file(ftmp);
-                       res+=restmp;
-               }
-               gtk_box_pack_start(GTK_BOX(control_parent), newvtt->gui.control_box, TRUE, TRUE, 0);
-               gtk_box_pack_start(GTK_BOX(audio_parent), newvtt->gui.audio_box, TRUE, TRUE, 0);
-               
-       }
-       
-       sequencer.load(input);
-       
-       ld_destroy();
-       
-       return(res);
-}
+                       if ((!elementFound) && (xmlStrcmp(cur->name, (xmlChar *) "turntable")==0)) {
+                               elementFound=1;
+                               vtt_class *vtt=new vtt_class(1);
+                               vtt->load(doc, cur);
+                               
+                               tX_debug("loading a turntable..");
 
-int  vtt_class :: load_all_13(FILE* input, char *fname)
-{
-       int res=0, restmp=0;
-       list <vtt_class *> :: iterator vtt;
-       unsigned int i, max, size;
-       int16_t *newbuffer;
-       vtt_class *newvtt;
-       char ftmp[PATH_MAX];
-       u_int32_t pid;
+                               if (strlen(vtt->filename)) {
+                                       strcpy(fn_buff, vtt->filename);
+                                       ld_set_filename(fn_buff);
+                               
+                                       restmp=(int) vtt->load_file(fn_buff);
+                                       res+=restmp;
+                               }
        
-       while (main_list.size())
-       {
-               delete((*main_list.begin()));
-       }
-               
-       atload(max);
-       atload(master_volume);
-       set_master_volume(master_volume);
-       globals.volume=master_volume;
-       atload(globals.pitch);  
-       set_master_pitch(globals.pitch);
-       atload(pid);
-       sp_master_volume.set_persistence_id(pid);
-       atload(pid);
-       sp_master_pitch.set_persistence_id(pid);
-
-       ld_create_loaddlg(TX_LOADDLG_MODE_MULTI, max);
-       ld_set_setname(fname);
-
-       for (i=0; i<max; i++)
-       {
-               newvtt=new vtt_class(1);
-               res+=newvtt->load_13(input);
-               
-               if (strlen(newvtt->filename))
-               {
-                       /* ftmp IS NECESSARY !!! */
-                       strcpy(ftmp, newvtt->filename);
-                       ld_set_filename(ftmp);
-                       
-                       //restmp=load_wav(newvtt->filename, &newbuffer, &size);
-                       restmp=newvtt->load_file(ftmp);
-                       res+=restmp;
+                               gtk_box_pack_start(GTK_BOX(control_parent), vtt->gui.control_box, TRUE, TRUE, 0);
+                               gtk_box_pack_start(GTK_BOX(audio_parent), vtt->gui.audio_box, TRUE, TRUE, 0);
+                               if (vtt->audio_hidden) vtt->hide_audio(vtt->audio_hidden);
+                               if (vtt->control_hidden) vtt->hide_control(vtt->control_hidden);\r
+                       }
+                       if ((!elementFound) && (xmlStrcmp(cur->name, (xmlChar *) "sequencer")==0)) {
+                               elementFound=1;
+                               sequencer.load(doc, cur);
+                       }
+                       if (!elementFound) {
+                               tX_warning("unhandled element %s in setfile %s", cur->name, fname);
+                       }
                }
-               gtk_box_pack_start(GTK_BOX(control_parent), newvtt->gui.control_box, TRUE, TRUE, 0);
-               gtk_box_pack_start(GTK_BOX(audio_parent), newvtt->gui.audio_box, TRUE, TRUE, 0);
-               
        }
        
-       sequencer.load(input);
-       
        ld_destroy();
        
        return(res);
@@ -2233,5 +1978,30 @@ void vtt_class ::  effect_remove(vtt_fx_ladspa *effect)
        delete effect;
 }
 
+extern void gui_hide_control_panel(vtt_class *vtt, bool hide);
+extern void gui_hide_audio_panel(vtt_class *vtt, bool hide);
 
+void vtt_class :: hide_audio(bool hide) {
+       audio_hidden=hide;
+       gui_hide_audio_panel(this, hide);
+}
+
+void vtt_class :: hide_control(bool hide) {
+       control_hidden=hide;
+       gui_hide_control_panel(this, hide);     
+}
 
+void vtt_class :: set_sample_rate(int samplerate) {
+       list <vtt_class *> :: iterator vtt;
+       double sr=(double) samplerate;
+       
+       for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++) {
+               if ((*vtt)->audiofile) {
+                       double file_rate=(*vtt)->audiofile->get_sample_rate();
+                       (*vtt)->audiofile_pitch_correction=file_rate/sr;
+               } else {
+                       (*vtt)->audiofile_pitch_correction=1.0;
+               }
+               (*vtt)->recalc_pitch();
+       }
+}