ALSA fixes, MIDI fixes and some new features, misc fixes and a
authorterminatorX <>
Fri, 18 Jul 2003 17:17:21 +0000 (17:17 +0000)
committerterminatorX <>
Fri, 18 Jul 2003 17:17:21 +0000 (17:17 +0000)
preliminary JACK backend - Alex

17 files changed:
configure.in
src/main.cc
src/tX_audiodevice.cc
src/tX_audiodevice.h
src/tX_dialog.cc
src/tX_engine.cc
src/tX_glade_interface.cc
src/tX_global.c
src/tX_global.h
src/tX_midiin.cc
src/tX_midiin.h
src/tX_seqpar.cc
src/tX_seqpar.h
src/tX_vtt.cc
src/tX_vtt.h
src/tX_vttfx.cc
terminatorX.glade

index c06885cf34a8c87cdae89d61cbfa71ec79df42e3..95650cb26510736389113da1cfbcb9576ff6c71d 100644 (file)
@@ -13,6 +13,7 @@ dnl AC_ARG_ENABLE(benchmark,[  --enable-benchmark      creates a non-functional
 AC_ARG_ENABLE(wav,          [  --enable-wav            enables the builtin wav-loader (default=yes) ])
 AC_ARG_ENABLE(xsetpointer,  [  --enable-xsetpointer    enables executing of xsetpointer (default=auto) ])
 AC_ARG_ENABLE(alsa,         [  --enable-alsa           use ALSA for sound output (default=auto) ])
+AC_ARG_ENABLE(jack,         [  --enable-jack           use JACK for sound output (default=auto) ])
 AC_ARG_ENABLE(oss,          [  --enable-oss            use OSS for sound output (default=auto) ])
 dnl AC_ARG_ENABLE(dga2,     [  --enable-dga2           use DGA2 instead of DGA1. (experimental) (default=no) ])
 AC_ARG_ENABLE(libxml2,     [  --disable-libxml2       use libxml even if verion 2 detected (default=auto) ])
@@ -33,6 +34,9 @@ AC_PROG_INSTALL
 AC_PROG_LN_S
 AC_PROG_RANLIB
 
+OPTION_OSS="no"
+OPTION_ALSA="no"
+OPTION_JACK="no"
 OPTION_SOX="no"
 OPTION_MPG123="no"
 OPTION_MAD="no"
@@ -275,6 +279,7 @@ fi
 
 using_alsa=no
 using_oss=no
+using_jack=no
 
 if test "$enable_alsa" != "no"; then
     AC_CHECK_LIB(asound, snd_pcm_writei,alsalib=yes,alsalib=no)
@@ -282,9 +287,10 @@ if test "$enable_alsa" != "no"; then
 
     if test "$alsalib" = "yes"; then
            if test "$alsaheader" = "yes"; then
-                   AC_DEFINE_UNQUOTED([USE_ALSA], 1, [ Define to use ALSA audio backend instead of OSS.])
+                   AC_DEFINE_UNQUOTED([USE_ALSA], 1, [ Define to enable ALSA audio backend. ])
                    LIBS="$LIBS -lasound"
-                   using_alsa=yes;
+                   using_alsa=yes
+                   OPTION_ALSA=yes
            else 
                    if test "$enable_alsa" = "yes"; then
                            AC_MSG_ERROR([** Coulnd't find ALSA header file sys/asoundlib.h **])
@@ -297,11 +303,35 @@ if test "$enable_alsa" != "no"; then
     fi
 fi
 
+if test "$enable_jack" != "no"; then
+    AC_CHECK_LIB(jack,jack_activate,jacklib=yes,jacklib=no)
+    AC_CHECK_HEADERS(jack/jack.h,jackheader=yes,jackheader=no)
+
+    if test "$jacklib" = "yes"; then
+           if test "$jackheader" = "yes"; then
+                   AC_DEFINE_UNQUOTED([USE_JACK], 1, [ Define to enable JACK audio backend.])
+                   LIBS="$LIBS -ljack"
+                   using_jack=yes
+                   OPTION_JACK=yes
+           else 
+                   if test "$enable_jack" = "yes"; then
+                           AC_MSG_ERROR([** Coulnd't find JACK header file jack/jack.h **])
+                   fi
+           fi
+    else
+           if test "$enable_jack" = "yes"; then
+                   AC_MSG_ERROR([** Coulnd'f find JACK library libjack. **])
+           fi
+    fi
+fi
+
+
 if test "$enable_oss" != "no"; then
        AC_CHECK_HEADERS(sys/ioctl.h sys/soundcard.h,oss=yes,oss=no)
        
        if test "$oss" = "yes"; then
                AC_DEFINE_UNQUOTED([USE_OSS], 1, [Use OSS])
+               OPTION_OSS=yes
                using_oss=yes;
        else
                if test "$enable_oss" = "yes"; then
@@ -336,18 +366,11 @@ if test "$enable_alsamidi" != "no"; then
        fi
 fi
 
-if test "$using_alsa" = "yes"; then
-       AC_MSG_RESULT([termnatorX audiodevice: using ALSA.])
-       AC_DEFINE_UNQUOTED([USE_ALSA], 1, [Define for ALSA pcm output])
-else 
-       if test "$using_oss" = "yes"; then
-               AC_MSG_RESULT([termnatorX audiodevice: using OSS.])
-       fi
-fi
-
 if test "$using_alsa" != "yes"; then
        if test "$using_oss" != "yes"; then
-               AC_MSG_ERROR([** Found neither OSS nor ALSA! **])
+               if test "$using_jack" != "yes"; then
+                       AC_MSG_ERROR([** Found neither OSS, ALSA nor JACK - no output device! **])
+               fi
        fi
 fi     
        
@@ -564,6 +587,16 @@ echo "     -       http://www.mpg123.de/"
 echo " - and reconfigure terminatorX"
 fi
 
+
+option=oss; option_val=$OPTION_OSS; option_url=http://www.kernel.org
+option_info;
+
+option=alsa; option_val=$OPTION_ALSA; option_url=http://www.alsa-project.org
+option_info;
+
+option=jack; option_val=$OPTION_JACK; option_url=http://jackit.sourceforge.net
+option_info;
+
 option=mad; option_val=$OPTION_MAD; option_url=http://www.mars.org/home/rob/proj/mpeg/
 option_info;
 
@@ -587,9 +620,10 @@ if test "$OPTION_SUIDROOT" = "yes"; then
        option_info;
 fi
 
-echo "legacy files supprt: $OPTION_LEGACY"
+echo "legacy files support: $OPTION_LEGACY"
 echo "builtin-wav support: $OPTION_WAV"
 echo "enhanced scheduling support: $OPTION_SCHEDULER"
+echo "suid-root support: $OPTION_SUIDROOT"
 echo "GNOME support: $OPTION_GNOME"
 echo
 echo You can now run \'make\' to compile terminatorX
index 4da4f7c366085ffde65892bbfd33ea37ce68ff86..b2fae4ff2feebd7ab44b9e61a9ba0a8a5cef9c81 100644 (file)
@@ -53,6 +53,7 @@
 #include "tX_endian.h"
 #include "tX_types.h"
 #include "tX_global.h"
+#include "tX_audiodevice.h"
 #include "version.h"
 #include "tX_dialog.h"
 #include <gtk/gtk.h>
 
 GTimer *my_time;
 gint idle_tag;
+#ifdef USE_JACK        
+void jack_check()
+{
+       if (!tX_jack_client::get_instance()) {
+               tx_note("Couldn't connect to JACK server - JACK output not available.\n\nIf you want to use JACK, ensure the JACK daemon is running before you start terminatorX.", true);
+       }
+}
+#endif                 
 
 int idle()
 {
@@ -81,6 +90,9 @@ int idle()
                g_timer_destroy(my_time);
                destroy_about();                
                display_mastergui();            
+#ifdef USE_JACK        
+               jack_check();
+#endif                 
        }
        
        return TRUE;
@@ -225,10 +237,18 @@ int main(int argc, char **argv)
        
        LADSPA_Class :: init();
        LADSPA_Plugin :: init();
+#ifdef USE_JACK        
+       tX_jack_client :: init();
+#endif 
        
        create_mastergui(globals.width, globals.height);
                
-       if (!globals.show_nag)  display_mastergui();
+       if (!globals.show_nag) {
+               display_mastergui();
+#ifdef USE_JACK        
+               jack_check();
+#endif                 
+       }
                
        if (globals.startup_set)
        {
@@ -245,6 +265,11 @@ int main(int argc, char **argv)
        store_globals();
 
        delete engine;
+#ifdef USE_JACK        
+       if (tX_jack_client::get_instance()) {
+               delete tX_jack_client::get_instance();
+       }
+#endif 
        
        fprintf(stderr, "Have a nice life.\n");
 #else
index cd96657afd39e21fea7684a0304af85170b14c62..60958f5b2275a13a4ef2da41b17c15e0f95c1b0e 100644 (file)
@@ -176,11 +176,6 @@ int tX_audiodevice_oss :: close()
 tX_audiodevice_oss :: tX_audiodevice_oss() : tX_audiodevice(),
 fd(0), blocksize(0) {}
 
-double tX_audiodevice_oss :: get_latency()
-{
-       return 0;
-}
-
 void tX_audiodevice_oss :: play(int16_t *buffer)
 {
 #ifdef BIG_ENDIAN_MACHINE
@@ -204,7 +199,15 @@ int tX_audiodevice_alsa :: open()
        char pcm_name[64];
        char foo[PATH_MAX];
        
-       strcpy(pcm_name, globals.alsa_device_id);
+       /* Removing the device ID comment... */
+       for (int i=0; i<strlen(globals.alsa_device_id); i++) {
+               if (globals.alsa_device_id[i]!='#') {
+                       pcm_name[i]=globals.alsa_device_id[i];
+               } else {
+                       pcm_name[i]=0;
+                       break;
+               }
+       }
        
        if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
                tX_error("ALSA: Failed to access PCM device \"%s\"", pcm_name);
@@ -315,11 +318,6 @@ int tX_audiodevice_alsa :: close()
        return 0;
 }
 
-double tX_audiodevice_alsa :: get_latency()
-{
-       return 0;
-}
-
 tX_audiodevice_alsa :: tX_audiodevice_alsa() : tX_audiodevice(),
 pcm_handle(NULL) {}
 
@@ -353,3 +351,191 @@ void tX_audiodevice_alsa :: play(int16_t *buffer)
 }
 
 #endif //USE_ALSA
+
+#ifdef USE_JACK
+
+tX_jack_client* tX_jack_client::instance=NULL;
+
+void tX_jack_client::init()
+{
+               tX_jack_client *test=new tX_jack_client();
+               
+               if (!instance) {
+                       delete test;
+               }       
+}
+
+tX_jack_client::tX_jack_client():device(NULL)
+{
+       jack_set_error_function(tX_jack_client::error);
+       
+       if ((client=jack_client_new("terminatorX"))==0) {
+               tX_error("tX_jack_client() -> failed to connect to jackd.");
+               instance=NULL;
+       } else {
+               instance=this;
+               const char **ports;
+               
+               /* Setting up jack callbacks... */              
+               jack_set_process_callback(client, tX_jack_client::process, NULL);
+               jack_set_sample_rate_callback(client, tX_jack_client::srate, NULL);             
+               jack_on_shutdown (client, tX_jack_client::shutdown, NULL);
+               
+               /* Creating the port... */
+               left_port = jack_port_register (client, "output_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+               right_port = jack_port_register (client, "output_2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+       
+               /* Action... */
+               jack_activate(client);
+               
+               /* Connect some ports... */
+               if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
+                       tX_error("tX_jack_client() no ports to connect to found. Connect manually.");
+               } else if (ports[0] && ports[1]) {
+                       if (jack_connect (client, jack_port_name(left_port), ports[0])) {
+                               tX_error("tX_jack_client() failed to connect left port.");
+                       }
+                       if (jack_connect (client, jack_port_name(right_port), ports[1])) {
+                               tX_error("tX_jack_client() failed to connect right port.");
+                       }
+                       free (ports);
+               }
+       }
+}
+
+tX_jack_client::~tX_jack_client()
+{
+       instance=NULL;
+       if (client) jack_client_close(client);
+}
+
+void tX_jack_client::error(const char *desc)
+{
+       tX_error("tX_jack_client::error() jack error: %s.", desc);
+}
+
+int tX_jack_client::srate(jack_nframes_t nframes, void *arg)
+{
+       tX_error("tX_jack_client::srate() jack changed samplerate -> this is bad, stopping audio.");
+       return 0;
+}
+
+void tX_jack_client::shutdown(void *arg)
+{
+       /***AARGH how to handle this?***/
+}
+
+int tX_jack_client::process(jack_nframes_t nframes, void *arg)
+{
+       if (instance) {
+               return instance->play(nframes);
+       }
+       
+       /* Hmm, what to do in such a case? */
+       return 0;
+}
+
+int tX_jack_client::play(jack_nframes_t nframes)
+{
+       jack_default_audio_sample_t *left = (jack_default_audio_sample_t *) jack_port_get_buffer (left_port, nframes);
+       jack_default_audio_sample_t *right = (jack_default_audio_sample_t *) jack_port_get_buffer (right_port, nframes);
+
+       if (device) {
+               device->fill_frames(left, right, nframes);
+       } else {
+               memset(left, 0, sizeof (jack_default_audio_sample_t) * nframes);
+               memset(right, 0, sizeof (jack_default_audio_sample_t) * nframes);
+       }
+       
+       return 0;
+}
+
+int tX_jack_client::get_sample_rate() 
+{
+       return jack_get_sample_rate(client);
+}
+
+/* tX_audiodevice_jack */
+
+tX_audiodevice_jack::tX_audiodevice_jack():tX_audiodevice()
+{
+       client=NULL;
+}
+
+int tX_audiodevice_jack::open()
+{
+       tX_jack_client *jack_client=tX_jack_client::get_instance();
+       sample_rate=jack_client->get_sample_rate();
+       
+       if (jack_client) {
+               client=jack_client;
+               is_open=true;
+               
+               return 0;
+       }
+       
+       return 1;
+}
+
+int tX_audiodevice_jack::close()
+{
+       if (client) {
+               client->set_device(NULL);
+       }
+       
+       is_open=false;  
+       
+       return 0;
+}
+
+void tX_audiodevice_jack::play(int16_t *buffer)
+{
+       tX_error("tX_audiodevice_jack::play()");
+}
+
+void tX_audiodevice_jack::start()
+{
+       tX_debug("activating jack playback");
+       overrun_buffer=new f_prec[vtt_class::samples_in_mix_buffer];
+       
+       client->set_device(this);
+       while (!engine->is_stopped()) {
+               usleep(100);
+       }       
+       tX_debug("stopping jack playback");     
+       client->set_device(NULL);
+       
+       delete [] overrun_buffer;
+}
+
+void tX_audiodevice_jack::fill_frames(jack_default_audio_sample_t *left, jack_default_audio_sample_t *right, jack_nframes_t nframes)
+{
+       int outbuffer_pos=0;
+       int sample;
+       
+       if (samples_in_overrun_buffer) {
+               for (sample=0; ((sample<samples_in_overrun_buffer) && (outbuffer_pos<nframes));) {
+                       left[outbuffer_pos]=overrun_buffer[sample++]/32767.0;
+                       right[outbuffer_pos++]=overrun_buffer[sample++]/32767.0;
+               }
+       }
+       
+       while (outbuffer_pos<nframes) {
+               engine->render_cycle();
+               
+               for (sample=0; ((sample<vtt_class::samples_in_mix_buffer) && (outbuffer_pos<nframes));) {
+                       left[outbuffer_pos]=vtt_class::mix_buffer[sample++]/32767.0;
+                       right[outbuffer_pos++]=vtt_class::mix_buffer[sample++]/32767.0;
+               }
+               
+               if (sample<vtt_class::samples_in_mix_buffer) {
+                       samples_in_overrun_buffer=vtt_class::samples_in_mix_buffer-sample;
+                       /* There's more data in the mixbuffer... */
+                       memcpy(overrun_buffer, &vtt_class::mix_buffer[sample], sizeof(f_prec) * samples_in_overrun_buffer);
+               } else {
+                       samples_in_overrun_buffer=0;
+               }
+       }
+}
+
+#endif // USE_JACK
index 04abd6df9764df6fe56da2d09201aa260f08e65c..82f2e9850e30b1277de0d77e43b4ebeb3a041dc1 100644 (file)
 #include <alsa/asoundlib.h>
 #endif
 
+#ifdef USE_JACK
+#include <jack/jack.h>
+#endif
+
 class tX_engine;
 
 class tX_audiodevice
@@ -54,7 +58,6 @@ class tX_audiodevice
        tX_audiodevice();
        
        public:
-       virtual double get_latency()=0; /* call only valid *after* open() */
        int get_buffersize() { return samples_per_buffer; } /* call only valid *after* open() */
        int get_sample_rate() { return sample_rate; }
        
@@ -79,10 +82,7 @@ class tX_audiodevice_oss : public tX_audiodevice
        public:
        virtual int open();
        virtual int close();
-       
-       virtual double get_latency(); /* call only valid *after* open() */
-       
-       virtual void play(int16_t*); /* play blocked */
+       virtual void play(int16_t*);
        
        tX_audiodevice_oss();
 };
@@ -100,14 +100,60 @@ class tX_audiodevice_alsa : public tX_audiodevice
        public:
        virtual int open();
        virtual int close();
-               
-       virtual double get_latency(); /* call only valid *after* open() */
-
-       virtual void play(int16_t*); /* play blocked */
+       virtual void play(int16_t*);
        
        tX_audiodevice_alsa();
 };
 
 #endif
 
+#ifdef USE_JACK
+
+class tX_jack_client;
+
+class tX_audiodevice_jack : public tX_audiodevice
+{
+       private:
+       tX_jack_client *client;
+       jack_default_audio_sample_t *overrun_buffer;
+       int samples_in_overrun_buffer;
+       
+       public:
+       virtual int open();
+       virtual int close();
+       virtual void play(int16_t*);
+       virtual void start();
+       void fill_frames(jack_default_audio_sample_t *left, jack_default_audio_sample_t *right, jack_nframes_t nframes);
+       
+       tX_audiodevice_jack();  
+};
+
+class tX_jack_client
+{
+       public:
+       static void init();
+       static tX_jack_client *get_instance() { return instance; };
+       ~tX_jack_client();
+       
+       private:
+       tX_jack_client();
+       static tX_jack_client *instance;
+       static void error(const char *desc);
+       static int srate(jack_nframes_t nframes, void *arg);
+       static void shutdown(void *arg);
+       static int process(jack_nframes_t nframes, void *arg);
+       
+       jack_client_t *client;
+       tX_audiodevice_jack *device;
+       jack_port_t *left_port;
+       jack_port_t *right_port;
+       int play(jack_nframes_t nframes);
+       
+       public:
+       int get_sample_rate();
+       void set_device(tX_audiodevice_jack *dev) { device=dev; }
+};
+
+#endif
+
 #endif
index f2cc72a4fd6d2125f14024218e0067764bc08ff3..b3f891fe362b594eb785574da2608bcb13cb7786 100644 (file)
@@ -16,7 +16,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  
-    File: tX_dialog.c
+    File: tX_dialog.cc
  
     Description: Contains the implementation of the Options and About
                 Dialogs. (And some really ugly "WE WANT TO 
@@ -55,27 +55,6 @@ int opt_hidden=0;
 static GtkWidget *last_alsa_device_widget=NULL;
 static GtkWidget *alsa_device_entry=NULL;
 
-static void alsa_device_changed(GtkList *list, GtkWidget *widget, gpointer user_data) {
-       if (widget) {
-               if (widget != last_alsa_device_widget) {
-                       last_alsa_device_widget = widget;
-                       GtkWidget *label=gtk_bin_get_child(GTK_BIN(widget));
-                       
-                       if (label) {
-                               char foo[PATH_MAX];
-                               char tmp[PATH_MAX];
-                               int card;
-                               int device;
-                               sscanf(gtk_label_get_text(GTK_LABEL(label)), "%i-%i: %s", &card, &device, foo);
-                               sprintf(tmp, "hw:%i,%i", card, device);
-                               
-                               gtk_entry_set_text(GTK_ENTRY(alsa_device_entry), tmp);
-                       }
-               }
-       }
-}
-
 void apply_options(GtkWidget *dialog) {
        /* Audio */
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "alsa_driver")))) {
@@ -135,6 +114,7 @@ void apply_options(GtkWidget *dialog) {
        strcpy(globals.lrdf_path, gtk_entry_get_text(GTK_ENTRY(lookup_widget(dialog, "ladspa_rdf_path"))));
        globals.compress_set_files=(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "compress_set_files")))==TRUE);        
        globals.prelis=(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "prelisten_enabled")))==TRUE);
+       globals.restore_midi_connections=(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "reconnect_enabled")))==TRUE);
 }
 
 
@@ -194,7 +174,16 @@ GList *get_alsa_device_list() {
                        buffer[PATH_MAX]=0;
                        if (strlen(buffer)) buffer[strlen(buffer)-1]=0;
                        if(strstr(buffer, "playback")) {
-                               alsa_devices=g_list_append (alsa_devices, strdup(buffer));
+                               char foo[PATH_MAX];
+                               char tmp[PATH_MAX];
+                               memset(foo, 0, PATH_MAX);
+                               int card;
+                               int device;
+                               sscanf(buffer, "%i-%i: %1024c", &card, &device, foo);
+                               sprintf(tmp, "hw:%i,%i# %s", card, device, foo);
+                               
+                               alsa_devices=g_list_append (alsa_devices, strdup(tmp));
                        }
                }
                fclose(file);
@@ -336,8 +325,6 @@ void init_tx_options(GtkWidget *dialog) {
        }
        gtk_entry_set_text(GTK_ENTRY(combo->entry), globals.alsa_device_id);
 
-       g_signal_connect(G_OBJECT(combo->list), "select_child", G_CALLBACK(alsa_device_changed), NULL);
-       
        gtk_range_set_value(GTK_RANGE(lookup_widget(dialog, "alsa_buffer_time")), globals.alsa_buffer_time/1000);
        gtk_tooltips_set_tip(tooltips, lookup_widget(dialog, "alsa_buffer_time"), "Sets the size of the ALSA ring buffer. On slower systems you might have to increase this value (if you hear \"clicks\" or drop-outs). Lower values mean lower latency though.", NULL);       
        gtk_range_set_value(GTK_RANGE(lookup_widget(dialog, "alsa_period_time")), globals.alsa_period_time/1000);
@@ -400,12 +387,13 @@ void init_tx_options(GtkWidget *dialog) {
        gtk_entry_set_text(GTK_ENTRY(lookup_widget(dialog, "ladspa_rdf_path")), globals.lrdf_path);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "compress_set_files")), globals.compress_set_files);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "prelisten_enabled")), globals.prelis);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "reconnect_enabled")), globals.restore_midi_connections);
 }
 
 void create_options()
 {
        opt_dialog=create_tx_options();
-       gtk_widget_hide(lookup_widget(opt_dialog, "jack_driver"));      
+       //gtk_widget_hide(lookup_widget(opt_dialog, "jack_driver"));    
        init_tx_options(opt_dialog);
        gtk_widget_show(opt_dialog);
 }
@@ -423,22 +411,18 @@ GtkWidget *about=NULL;
 
 void raise_about()
 {
-       if (about)
-       gdk_window_raise(about->window);
+       if (about) gdk_window_raise(about->window);
 }
 
 
 void destroy_about()
 {
-       if (about)
-       {       
+       if (about) {    
                gtk_widget_destroy(about);
                about=NULL;
        }
 }
 
-
-
 #define add_about_wid(wid); gtk_box_pack_start(GTK_BOX(box), wid, WID_DYN); \
        gtk_widget_show(wid);
 
@@ -461,32 +445,25 @@ void show_about(int nag)
        GtkWidget *scroll;
        GdkPixmap *pmap=NULL;
        
-       if (about) 
-       {
+       /* Only raise the window if it's already open... */
+       if (about)  {
                gdk_window_raise(about->window);
                return;
        }
        
+       /* Create the window... */
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);   
        gtk_window_set_wmclass(GTK_WINDOW(window), "terminatorX", "tX_about");
-
        gtk_container_set_border_width(GTK_CONTAINER(window), 5);
-
-//     GTK_WINDOW(window)->use_uposition=TRUE;
-
        g_object_set (G_OBJECT (window), "type", GTK_WINDOW_TOPLEVEL, NULL);
-       if (nag) { gtk_window_set_decorated(GTK_WINDOW(window), FALSE); }
+       gtk_window_set_decorated(GTK_WINDOW(window), nag ? TRUE : FALSE);
        gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
-       //gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+       gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
        gtk_window_set_title(GTK_WINDOW(window), "terminatorX - About");
-       //gtk_widget_set_size_request(window, 640, 210);
        
-       gtk_widget_realize(window);
+       GdkPixbuf *image=gdk_pixbuf_new_from_xpm_data((const char **)logo_xpm);
+       gdk_pixbuf_render_pixmap_and_mask(image, &pmap, &mask, 0);
        
-       style = gtk_widget_get_style( window );
-
-       pmap=gdk_pixmap_create_from_xpm_d(window->window, &mask, &style->bg[GTK_STATE_NORMAL], (gchar **)logo_xpm);
-
        pwid = gtk_pixmap_new( pmap, mask );
        
        if (nag) {
@@ -510,13 +487,10 @@ void show_about(int nag)
                
                gtk_widget_show(box2);
                gtk_widget_show(box);
-               gtk_widget_show(window);
                gtk_widget_show(pwid);
                
-               while (gtk_events_pending()) gtk_main_iteration();      
-       }
-       else
-       {
+               gtk_widget_show(window);
+       } else {
                box=gtk_vbox_new(FALSE, 5);
                add_about_wid_fix(pwid);
                
@@ -588,7 +562,7 @@ void show_about(int nag)
                gtk_text_buffer_get_iter_at_offset (tbuffer, &iter, 0);
                
                scroll=gtk_scrolled_window_new (NULL, NULL);
-               gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
                gtk_container_add (GTK_CONTAINER (scroll), text);
                gtk_text_buffer_create_tag (tbuffer, "courier", "family", "courier", NULL);
                
@@ -629,15 +603,10 @@ GtkWidget *tX_icon_widget=NULL;
 
 void tX_set_icon(GtkWidget *widget, char *name)
 {
-       GtkStyle *style;
-
-       style = gtk_widget_get_style( widget );
+       GtkStyle *style = gtk_widget_get_style(widget);
 
-       if (!tX_icon_pmap)
-       {
+       if (!tX_icon_pmap) {
                tX_icon_pmap=gdk_pixmap_create_from_xpm_d(widget->window, &tX_icon_mask, &style->bg[GTK_STATE_NORMAL], (gchar **) tX_icon_xpm );
-               //tX_icon_widget = gtk_pixmap_new( tX_icon_pmap, tX_icon_mask );                
-               //gtk_widget_realize(tX_icon_widget);           
        }
 
        gdk_window_set_icon(widget->window, NULL, tX_icon_pmap, tX_icon_mask);
index 165646da42e4f477d6d318437ab5d32d9bd0cf5c..c439c18d03bac9e9dd0d94b1e33d8561e982555d 100644 (file)
@@ -126,7 +126,6 @@ void tX_engine :: loop() {
        }
 }
 
-
 void *engine_thread_entry(void *engine_void) {
        tX_engine *engine=(tX_engine*) engine_void;
        int result;
@@ -150,6 +149,11 @@ void *engine_thread_entry(void *engine_void) {
                }
        }
        
+#ifdef USE_JACK
+       /* Create the client now, so the user has something to connect to. */
+       tX_jack_client *jack_client=tX_jack_client::get_instance();
+#endif 
+       
        engine->loop();
        
        tX_debug("engine_thread_entry() - Engine thread terminating.");
@@ -185,7 +189,7 @@ tX_engine :: tX_engine() {
                
                result=pthread_create(&thread, &pattr, engine_thread_entry, (void *) this);
        } else {
-               tX_debug("tX_engine() - Lacking root privileges - no realtime scheduling!");
+               tX_debug("tX_engine() - Lacking root privileges - no realtime scheduling.");
 #endif         
                result=pthread_create(&thread, NULL, engine_thread_entry, (void *) this);
 #ifdef USE_SCHEDULER           
@@ -245,6 +249,12 @@ tX_engine_error tX_engine :: run() {
                        device=new tX_audiodevice_alsa(); 
                break;
 #endif
+
+#ifdef USE_JACK
+               case JACK:
+                       device=new tX_audiodevice_jack();
+               break;
+#endif
                
                default:
                        device=NULL; return ERROR_AUDIO;
index 8d49e40d6931f8af77c78bb721015c52a924a5c1..9e232f2c0f837b1f37be62c226e0e081f1d1e3e4 100644 (file)
@@ -222,6 +222,8 @@ create_tx_options (void)
   GtkWidget *ladspa_rdf_path;
   GtkWidget *label33;
   GtkWidget *compress_set_files;
+  GtkWidget *label40;
+  GtkWidget *reconnect_enabled;
   GtkWidget *label3;
   GtkWidget *dialog_action_area3;
   GtkWidget *pref_reset;
@@ -690,7 +692,7 @@ create_tx_options (void)
   gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 4), label2);
   gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
 
-  table3 = gtk_table_new (4, 2, FALSE);
+  table3 = gtk_table_new (5, 2, FALSE);
   gtk_widget_show (table3);
   gtk_container_add (GTK_CONTAINER (notebook1), table3);
   gtk_container_set_border_width (GTK_CONTAINER (table3), 4);
@@ -755,6 +757,21 @@ create_tx_options (void)
                     (GtkAttachOptions) (GTK_FILL),
                     (GtkAttachOptions) (0), 0, 0);
 
+  label40 = gtk_label_new ("Restore MIDI connections:");
+  gtk_widget_show (label40);
+  gtk_table_attach (GTK_TABLE (table3), label40, 0, 1, 4, 5,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_label_set_justify (GTK_LABEL (label40), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (label40), 0, 0.5);
+
+  reconnect_enabled = gtk_check_button_new_with_mnemonic ("Enabled");
+  gtk_widget_show (reconnect_enabled);
+  gtk_table_attach (GTK_TABLE (table3), reconnect_enabled, 1, 2, 4, 5,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_tooltips_set_tip (tooltips, reconnect_enabled, "When enabled soundfiles will be playedback when selected in a file dialog (before loading them).", NULL);
+
   label3 = gtk_label_new ("Misc");
   gtk_widget_show (label3);
   gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 5), label3);
@@ -881,6 +898,8 @@ create_tx_options (void)
   GLADE_HOOKUP_OBJECT (tx_options, ladspa_rdf_path, "ladspa_rdf_path");
   GLADE_HOOKUP_OBJECT (tx_options, label33, "label33");
   GLADE_HOOKUP_OBJECT (tx_options, compress_set_files, "compress_set_files");
+  GLADE_HOOKUP_OBJECT (tx_options, label40, "label40");
+  GLADE_HOOKUP_OBJECT (tx_options, reconnect_enabled, "reconnect_enabled");
   GLADE_HOOKUP_OBJECT (tx_options, label3, "label3");
   GLADE_HOOKUP_OBJECT_NO_REF (tx_options, dialog_action_area3, "dialog_action_area3");
   GLADE_HOOKUP_OBJECT (tx_options, pref_reset, "pref_reset");
index 6281e59016a516397532ebe89f982b4b97a47b5d..8890b4ef9230b8c9f78fc9395f1105edfcde0ea8 100644 (file)
 tx_global globals;
 int _store_compress_xml=0;
 
+#ifdef USE_ALSA_MIDI_IN
+extern void tX_midiin_store_connections(FILE *rc, char *indent);
+extern void tX_midiin_restore_connections(xmlNodePtr node);
+#endif
+
 void get_rc_name(char *buffer)
 {
        strcpy(buffer,"");
@@ -138,6 +143,7 @@ void set_global_defaults() {
        
        globals.alsa_free_hwstats=1;
        globals.filename_length=20;
+       globals.restore_midi_connections=1;
 }
 
 int load_globals_xml() {
@@ -219,6 +225,16 @@ int load_globals_xml() {
                        restore_int("fullscreen_enabled", globals.fullscreen_enabled);
                        restore_int("confirm_events", globals.confirm_events);
                        restore_float("vtt_inertia", globals.vtt_inertia);
+                       restore_int("restore_midi_connections", globals.restore_midi_connections);
+
+#ifdef USE_ALSA_MIDI_IN
+                       if (!elementFound && (xmlStrcmp(cur->name, (xmlChar *) "midi_connections")==0)) {
+                               if (globals.restore_midi_connections) {
+                                       tX_midiin_restore_connections(cur);
+                               }
+                               elementFound=1;
+                       }
+#endif                 
 
                        if (!elementFound) {
                                fprintf(stderr, "tX: Unhandled XML element: \"%s\"\n", cur->name);
@@ -238,7 +254,7 @@ int load_globals_xml() {
 void store_globals() {
        char rc_name[PATH_MAX+256]="";
        char device_type[16];
-       char indent[]="\t";
+       char indent[32]="\t";
        FILE *rc=NULL;
        gzFile rz=NULL;
        char tmp_xml_buffer[4096];
@@ -310,6 +326,11 @@ void store_globals() {
                store_float("vtt_inertia", globals.vtt_inertia);
 
                store_string("last_path", globals.current_path);
+               store_int("restore_midi_connections", globals.restore_midi_connections);
+
+#ifdef USE_ALSA_MIDI_IN
+               tX_midiin_store_connections(rc, indent);
+#endif         
 
                fprintf(rc,"</terminatorXrc>\n");
        }
index 816507f4b91af179dc8da9755cd9b63fa6d2bb43..a0b90f75fe229b8a43a9f0ea18fd7313f11d4379 100644 (file)
@@ -145,6 +145,7 @@ typedef struct {
        int alsa_free_hwstats;
        int filename_length;
        
+       int restore_midi_connections;
 } tx_global;
 
 extern tx_global globals;
index df977e5ef143d1cfc6d44200aba7c3337fc8e4e8..3cd565dd11c5ffcacf34468b31d23f44d6c25bb5 100644 (file)
@@ -37,6 +37,7 @@
 #ifdef USE_ALSA_MIDI_IN
 #include "tX_global.h"
 #include <iostream>
+#include "tX_engine.h"
 
 using namespace std;
 
@@ -49,8 +50,6 @@ static gboolean midi_callback(GIOChannel *source, GIOCondition condition, gpoint
 
 tX_midiin::tX_midiin()
 {
-       
-       int portid;
        is_open=false;
        sp_to_learn=NULL;
        learn_dialog=NULL;
@@ -110,9 +109,10 @@ int tX_midiin::check_event()
                tX_midievent event;
                event.is_noteon = false;
                bool event_usable = true;
-               
+               printf("type: %i\n", ev->type);
                switch (ev->type) {
                        case SND_SEQ_EVENT_CONTROLLER: 
+                               printf("ctrl: p: %i, v: %i, c: %i\n", ev->data.control.param, ev->data.control.value, ev->data.control.channel);
                                event.type = tX_midievent::CC;
                                event.number = ev->data.control.param;
                                event.value = ev->data.control.value / 127.0;
@@ -131,12 +131,14 @@ int tX_midiin::check_event()
                                event.channel = ev->data.control.channel;
                                break;
                        case SND_SEQ_EVENT_REGPARAM:
+                               printf("rpn: p: %i, v: %i, c: %i\n", ev->data.control.param, ev->data.control.value, ev->data.control.channel);
                                event.type = tX_midievent::RPN;
                                event.number = ev->data.control.param;
                                event.value = ev->data.control.value / 16383.0;
                                event.channel = ev->data.control.channel;
                                break;
                        case SND_SEQ_EVENT_NONREGPARAM:
+                               printf("nrpn: p: %i, v: %i, c: %i\n", ev->data.control.param, ev->data.control.value, ev->data.control.channel);
                                event.type = tX_midievent::NRPN;
                                event.number = ev->data.control.param;
                                event.value = ev->data.control.value / 16383.0;
@@ -436,5 +438,100 @@ gboolean tX_midiin::midi_learn_destroy(GtkWidget *widget, tX_midiin *midi)
        midi->cancel_midi_learn();
 }
 
+void tX_midiin::store_connections(FILE *rc, char *indent) 
+{
+       gzFile *rz;
+       
+       tX_store("%s<midi_connections>\n", indent);
+       strcat(indent, "\t");
+
+       snd_seq_addr_t my_addr;
+       my_addr.client=snd_seq_client_id(ALSASeqHandle);
+       my_addr.port=portid;
+
+       snd_seq_query_subscribe_t *subs;
+       snd_seq_query_subscribe_alloca(&subs);
+       snd_seq_query_subscribe_set_root(subs, &my_addr);
+       snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_WRITE);
+       snd_seq_query_subscribe_set_index(subs, 0);
+       
+       while (snd_seq_query_port_subscribers(ALSASeqHandle, subs) >= 0) {
+               const snd_seq_addr_t *addr;
+               addr = snd_seq_query_subscribe_get_addr(subs);
+               
+               tX_store("%s<link client=\"%i\" port=\"%i\"/>\n", indent, addr->client, addr->port);
+               snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
+       }       
+               
+       indent[strlen(indent)-1]=0;
+       tX_store("%s</midi_connections>\n", indent);    
+}
+
+void tX_midiin::restore_connections(xmlNodePtr node)
+{
+       snd_seq_addr_t my_addr;
+       my_addr.client=snd_seq_client_id(ALSASeqHandle);
+       my_addr.port=portid;
+       
+       if (xmlStrcmp(node->name, (xmlChar *) "midi_connections")==0) {
+               for (xmlNodePtr cur=node->xmlChildrenNode; cur != NULL; cur = cur->next) {
+                       if (cur->type == XML_ELEMENT_NODE) {
+                               if (xmlStrcmp(cur->name, (xmlChar *) "link")==0) {
+                                       char *buffer;
+                                       int client=-1;
+                                       int port=-1;
+                                       
+                                       buffer=(char *) xmlGetProp(cur, (xmlChar *) "client");
+                                       if (buffer) {
+                                               sscanf(buffer, "%i", &client);
+                                       }
+                                       
+                                       buffer=(char *) xmlGetProp(cur, (xmlChar *) "port");
+                                       if (buffer) {
+                                               sscanf(buffer, "%i", &port);
+                                       }
+                                       
+                                       if ((port>=0) && (client>=0)) {
+                                               snd_seq_addr_t sender_addr;
+                                               sender_addr.client=client;
+                                               sender_addr.port=port;
+                                               
+                                               snd_seq_port_subscribe_t *subs;
+                                               snd_seq_port_subscribe_alloca(&subs);
+                                               snd_seq_port_subscribe_set_sender(subs, &sender_addr);
+                                               snd_seq_port_subscribe_set_dest(subs, &my_addr);
+
+                                               if (snd_seq_subscribe_port(ALSASeqHandle, subs) < 0) {
+                                                       tX_error("tX_midiin::restore_connections() -> failed to connect to: %d:%d.", port, client);
+                                               }
+                                       } else {
+                                               tX_error("tX_midiin::restore_connections() -> invalid port: %d:%d.", port, client);
+                                       }
+                                       
+                               } else {
+                                       tX_error("tX_midiin::restore_connections() -> invalid element: %s.", cur->name);
+                               }
+                       }
+               }
+       } else {
+               tX_error("tX_midiin::restore_connections() -> invalid XML element.");
+       }
+}
+
+
+extern "C" {
+       void tX_midiin_store_connections(FILE *rc, char *indent);
+       void tX_midiin_restore_connections(xmlNodePtr node);
+};
+
+void tX_midiin_store_connections(FILE *rc, char *indent) 
+{
+       tX_engine::get_instance()->get_midi()->store_connections(rc, indent);
+}
+
+void tX_midiin_restore_connections(xmlNodePtr node) 
+{
+       tX_engine::get_instance()->get_midi()->restore_connections(node);
+}
 
 #endif // USE_ALSA_MIDI_IN
index 60770c55a49d1815dd6d41708f8224849d9a2da3..71013be90b087323a2c84bf991425920bcac8ff7 100644 (file)
@@ -29,6 +29,9 @@
 #define _tx_midiin_h 1
 
 #include <stdio.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/encoding.h>
 
 class vtt_class;
 class tX_seqpar;
@@ -79,6 +82,7 @@ class tX_midiin
        bool is_open;
        tX_seqpar *sp_to_learn;
        GtkWidget *learn_dialog;
+       int portid;
        
   public:
        tX_midiin();
@@ -99,6 +103,8 @@ class tX_midiin
 
        void set_midi_learn_sp(tX_seqpar *);
        void cancel_midi_learn();
+       void store_connections(FILE *rc, char *indent);
+       void restore_connections(xmlNodePtr node);
        
        static gboolean midi_learn_cancel(GtkWidget *, tX_midiin *);
        static gboolean midi_learn_destroy(GtkWidget *, tX_midiin *);   
index ebc3b3f75b83ad1a58118f3eacd4216d9fc0243d..242c32a4ca5e244159a4b087d14c79e2b1b76696 100644 (file)
@@ -51,6 +51,9 @@ tX_seqpar :: tX_seqpar () : bound_midi_event()
        is_mappable=1;
        all.push_back(this);
        last_event_recorded=NULL;
+       
+       midi_lower_bound_set=false;
+       midi_upper_bound_set=false;
 }
 
 void tX_seqpar :: set_mapping_parameters(float max, float min, float scale, int mappable)
@@ -77,19 +80,26 @@ void tX_seqpar :: handle_mouse_input(float adjustment)
 #ifdef USE_ALSA_MIDI_IN
 void tX_seqpar :: handle_midi_input( const tX_midievent& event )
 {
-       float tmpvalue = -1000;
-
-       //event.print( (string(__FUNCTION__) + " - " + get_name()).c_str() );
+       double tmpvalue = -1000;
+       double max=max_value;
+       double min=min_value;
        
-       if( !is_boolean )
-       {
+       if (midi_upper_bound_set) {
+               max=midi_upper_bound;
+       }
+       
+       if (midi_lower_bound_set) {
+               min=midi_lower_bound;
+       }
+       
+       if( !is_boolean ) {
                switch (event.type) {
                        case tX_midievent::CC:
                        case tX_midievent::CC14:
                        case tX_midievent::PITCHBEND:
                        case tX_midievent::RPN:
                        case tX_midievent::NRPN:
-                                       tmpvalue = event.value * (max_value-min_value) + min_value;                             
+                                       tmpvalue = event.value * (max-min) + min;
                                break;
                        case tX_midievent::NOTE:
                                        tmpvalue = event.is_noteon;
@@ -98,11 +108,9 @@ void tX_seqpar :: handle_midi_input( const tX_midievent& event )
                                return;
                }
 
-               if (tmpvalue>max_value) tmpvalue=max_value;
-               else if (tmpvalue<min_value) tmpvalue=min_value;
-       }
-       else
-       {
+               if (tmpvalue>max) tmpvalue=max;
+               else if (tmpvalue<min) tmpvalue=min;
+       } else {
                tmpvalue=event.value;
        }
        
@@ -231,11 +239,24 @@ char * tX_seqpar :: get_vtt_name()
 
 void tX_seqpar :: restore_meta(xmlNodePtr node) {
        char *buffer;
+       double temp;
        
        buffer=(char *) xmlGetProp(node, (xmlChar *) "id");
        if (buffer) { sscanf(buffer, "%i", &persistence_id); }
        else { tX_error("no ID for seqpar %s", this->get_name()); }
        
+       buffer=(char *) xmlGetProp(node, (xmlChar *) "midiUpperBound");
+       if (buffer) {
+               sscanf(buffer, "%lf", &temp);
+               set_upper_midi_bound(temp);
+       }
+
+       buffer=(char *) xmlGetProp(node, (xmlChar *) "midiLowerBound");
+       if (buffer) {
+               sscanf(buffer, "%lf", &temp);
+               set_lower_midi_bound(temp);
+       }
+       
        buffer=(char *) xmlGetProp(node, (xmlChar *) "midiType");
        if (buffer) {
                if (strcmp("cc", buffer)==0) {
@@ -266,7 +287,8 @@ void tX_seqpar :: restore_meta(xmlNodePtr node) {
 }
 
 void tX_seqpar :: store_meta(FILE *rc, gzFile rz) {
-       char buffer[256];
+       char buffer[512];
+       char buffer2[256];
        
        if (bound_midi_event.type!=tX_midievent::NONE) {
                char *type;
@@ -284,6 +306,17 @@ void tX_seqpar :: store_meta(FILE *rc, gzFile rz) {
        } else {
                sprintf(buffer, "id=\"%i\"", persistence_id);
        }
+       
+       if (midi_upper_bound_set) {
+               sprintf(buffer2, " midiUpperBound=\"%lf\"", midi_upper_bound);
+               strcat(buffer, buffer2);
+       }
+
+       if (midi_lower_bound_set) {
+               sprintf(buffer2, " midiLowerBound=\"%lf\"", midi_lower_bound);
+               strcat(buffer, buffer2);
+       }
+       
        tX_store(buffer);
 }
 
@@ -1036,6 +1069,41 @@ gboolean tX_seqpar::tX_seqpar_press(GtkWidget *widget, GdkEventButton *event, gp
                        gtk_widget_set_sensitive(item, FALSE);
                }
                g_signal_connect(item, "activate", (GCallback) tX_seqpar::remove_midi_binding, sp);             
+
+               if (!sp->is_boolean) {
+                       item = gtk_menu_item_new();
+                       gtk_menu_append(menu, item);
+                       gtk_widget_set_sensitive(item, FALSE);
+                       gtk_widget_show(item);
+                       
+                       item = gtk_menu_item_new_with_label("Set Upper MIDI Bound");
+                       gtk_menu_append(menu, item);
+                       gtk_widget_show(item);
+                       g_signal_connect(item, "activate", (GCallback) tX_seqpar::set_midi_upper_bound, sp);            
+                       
+                       item = gtk_menu_item_new_with_label("Reset Upper MIDI Bound");
+                       gtk_menu_append(menu, item);
+                       gtk_widget_show(item);                  
+                       g_signal_connect(item, "activate", (GCallback) tX_seqpar::reset_midi_upper_bound, sp);          
+                       
+                       if (!sp->midi_upper_bound_set) {
+                               gtk_widget_set_sensitive(item, FALSE);                          
+                       }
+                       
+                       item = gtk_menu_item_new_with_label("Set Lower MIDI Bound");
+                       gtk_menu_append(menu, item);
+                       gtk_widget_show(item);
+                       g_signal_connect(item, "activate", (GCallback) tX_seqpar::set_midi_lower_bound, sp);                                    
+                       
+                       item = gtk_menu_item_new_with_label("Reset Lower MIDI Bound");
+                       gtk_menu_append(menu, item);
+                       gtk_widget_show(item);          
+                       g_signal_connect(item, "activate", (GCallback) tX_seqpar::reset_midi_lower_bound, sp);          
+
+                       if (!sp->midi_lower_bound_set) {
+                               gtk_widget_set_sensitive(item, FALSE);                          
+                       }                       
+               }
                
                item = gtk_menu_item_new();
                gtk_menu_append(menu, item);
@@ -1050,7 +1118,7 @@ gboolean tX_seqpar::tX_seqpar_press(GtkWidget *widget, GdkEventButton *event, gp
                gtk_widget_show(menu);
                
                gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
-               gtk_grab_remove(gtk_grab_get_current());
+               //gtk_grab_remove(gtk_grab_get_current());
 
                return TRUE;
        } 
@@ -1075,3 +1143,31 @@ gboolean tX_seqpar::learn_midi_binding(GtkWidget *widget, gpointer data) {
        
        return TRUE;
 }
+
+gboolean tX_seqpar::set_midi_upper_bound(GtkWidget *widget, gpointer data) {
+       tX_seqpar *sp=(tX_seqpar *) data;
+       sp->set_upper_midi_bound(sp->get_value());
+       
+       return TRUE;
+}
+
+gboolean tX_seqpar::reset_midi_upper_bound(GtkWidget *widget, gpointer data) {
+       tX_seqpar *sp=(tX_seqpar *) data;
+       sp->reset_upper_midi_bound();
+       
+       return TRUE;
+}
+
+gboolean tX_seqpar::set_midi_lower_bound(GtkWidget *widget, gpointer data) {
+       tX_seqpar *sp=(tX_seqpar *) data;
+       sp->set_lower_midi_bound(sp->get_value());
+       
+       return TRUE;
+}
+
+gboolean tX_seqpar::reset_midi_lower_bound(GtkWidget *widget, gpointer data) {
+       tX_seqpar *sp=(tX_seqpar *) data;
+       sp->reset_lower_midi_bound();
+       
+       return TRUE;
+}
index 1b7ef14fd380fd9ce9f5fa0ca7e8bb548f2fa5ee..2e8d02e10123d847893ea6d4eba69501e9e3a02d 100644 (file)
@@ -127,6 +127,12 @@ class tX_seqpar
        float min_value;
        float scale_value;
 
+       bool midi_upper_bound_set;
+       double midi_upper_bound;
+       
+       bool midi_lower_bound_set;
+       double midi_lower_bound;
+       
        bool is_boolean;
        
        public:
@@ -134,9 +140,29 @@ class tX_seqpar
        void restore_meta(xmlNodePtr node);
        void store_meta(FILE *rc, gzFile rz);
        
+       void set_upper_midi_bound(double val) {
+               midi_upper_bound=val;
+               midi_upper_bound_set=true;              
+       }
+       
+       void reset_upper_midi_bound() { midi_upper_bound_set=false; }
+
+       void set_lower_midi_bound(double val) {
+               midi_lower_bound=val;
+               midi_lower_bound_set=true;              
+       }
+       
+       void reset_lower_midi_bound() { midi_lower_bound_set=false; }
+       
        static gboolean tX_seqpar_press(GtkWidget *widget, GdkEventButton *event, gpointer data);
        static gboolean remove_midi_binding(GtkWidget *widget, gpointer data);
-       static gboolean learn_midi_binding(GtkWidget *widget, gpointer data);
+       static gboolean learn_midi_binding(GtkWidget *widget, gpointer data);   
+       
+       static gboolean set_midi_upper_bound(GtkWidget *widget, gpointer data);
+       static gboolean reset_midi_upper_bound(GtkWidget *widget, gpointer data);
+       
+       static gboolean set_midi_lower_bound(GtkWidget *widget, gpointer data);
+       static gboolean reset_midi_lower_bound(GtkWidget *widget, gpointer data);       
 };
 
 class tX_seqpar_update : public tX_seqpar
index c5000aef7917621cb84d420fd1a66dc98995cc3c..ca40c47471fd32188006f28613249736730b8fdb 100644 (file)
@@ -813,8 +813,7 @@ int vtt_class :: set_mix_buffer_size(int no_samples)
 
 //     printf("mix_out_buffer: %12x\n", mix_out_buffer);
        
-       for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++)
-       {
+       for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++) {
                res|=(*vtt)->set_output_buffer_size(no_samples);
        }
        
@@ -836,22 +835,17 @@ int16_t * vtt_class :: render_all_turntables()
        
        pthread_mutex_lock(&render_lock);
        
-       if (render_list.size()==0)
-       {
-               for (sample=0; sample<samples_in_mix_buffer; sample++)
-               {
+       if (render_list.size()==0) {
+               for (sample=0; sample<samples_in_mix_buffer; sample++) {
                        mix_out_buffer[sample]=0;
                }
-       }
-       else
-       {
+       } else {
                        vtt=render_list.begin();
                        (*vtt)->render();                       
                        max=(*vtt)->max_value;
                        min=max;
 
-                       for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
-                       {                               
+                       for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {                                
                                temp=(*vtt)->output_buffer[sample];
                                mix_buffer[mix_sample]=temp*(*vtt)->res_volume_left;
                                mix_sample++;
@@ -865,10 +859,8 @@ int16_t * vtt_class :: render_all_turntables()
                        min*=-1.0;
                        if (min>max) (*vtt)->max_value=min; else (*vtt)->max_value=max;
 
-                       if ((*vtt)->ec_enable)
-                       {
-                               for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
-                               {                               
+                       if ((*vtt)->ec_enable) {
+                               for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {                                
                                        temp=(*vtt)->ec_output_buffer[sample];
                                        
                                        mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_left;
@@ -878,19 +870,13 @@ int16_t * vtt_class :: render_all_turntables()
                                }
                        }
                        
-                       if (master_triggered)
-                       {
+                       if (master_triggered) {
                                pthread_mutex_unlock(&render_lock);
-                               for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++)
-                               {
-                                       if ((*vtt)->is_sync_client)
-                                       {
-                                               if ((*vtt)->sync_countdown)
-                                               {
+                               for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++) {
+                                       if ((*vtt)->is_sync_client)     {
+                                               if ((*vtt)->sync_countdown)     {
                                                        (*vtt)->sync_countdown--;
-                                               }
-                                               else
-                                               {
+                                               } else {
                                                        (*vtt)->sync_countdown=(*vtt)->sync_cycles;
                                                        (*vtt)->trigger();
                                                }
@@ -900,14 +886,12 @@ int16_t * vtt_class :: render_all_turntables()
                        }
                        
                        vtt=render_list.begin();
-                       for (vtt++; vtt!=render_list.end(); vtt++)
-                       {
+                       for (vtt++; vtt!=render_list.end(); vtt++) {
                                (*vtt)->render();                                       
                                max=(*vtt)->max_value;
                                min=max;
 
-                               for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
-                               {                               
+                               for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
                                        temp=(*vtt)->output_buffer[sample];
                                        mix_buffer[mix_sample]+=temp*(*vtt)->res_volume_left;
                                        mix_sample++;                                   
@@ -921,10 +905,8 @@ int16_t * vtt_class :: render_all_turntables()
                                min*=-1.0;
                                if (min>max) (*vtt)->max_value=min; else (*vtt)->max_value=max;
                                
-                               if ((*vtt)->ec_enable)
-                               {
-                                       for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++)
-                                       {                               
+                               if ((*vtt)->ec_enable) {
+                                       for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
                                                temp=(*vtt)->ec_output_buffer[sample];
                                                
                                                mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_left;
@@ -940,8 +922,7 @@ int16_t * vtt_class :: render_all_turntables()
                        max=mix_max_l;
                        min=max;
 
-                       for (sample=0; sample<samples_in_mix_buffer; sample+=2)
-                       {                               
+                       for (sample=0; sample<samples_in_mix_buffer; sample+=2) {                               
                                temp=mix_buffer[sample];
 
 #ifndef TX_DO_CLIP
@@ -965,8 +946,7 @@ int16_t * vtt_class :: render_all_turntables()
                        max=mix_max_r;
                        min=max;
 
-                       for (sample=1; sample<samples_in_mix_buffer; sample+=2)
-                       {                               
+                       for (sample=1; sample<samples_in_mix_buffer; sample+=2) {                               
                                temp=mix_buffer[sample];
 
 #ifndef TX_DO_CLIP
@@ -987,8 +967,7 @@ int16_t * vtt_class :: render_all_turntables()
        master_triggered=0;
                
        vtt=render_list.begin();
-       while (vtt!=render_list.end())
-       {
+       while (vtt!=render_list.end()) {
                next=vtt;
                next++;
                
@@ -1563,6 +1542,10 @@ void vtt_class :: delete_all()
        sp_master_volume.do_exec(1.0);
        sp_master_volume.do_update_graphics();
        
+       /* Remove master MIDI mappings... */
+       sp_master_pitch.bound_midi_event.type=tX_midievent::NONE;
+       sp_master_volume.bound_midi_event.type=tX_midievent::NONE;
+       
        seq_update();
 }
 
@@ -1651,6 +1634,9 @@ int vtt_class :: load_all(xmlDocPtr doc, char *fname) {
                }
        }
        
+       sp_master_volume.do_update_graphics();
+       sp_master_pitch.do_update_graphics();
+       
        ld_destroy();
        
        return(res);
index a8d87e2ef41d18acd913db1230d94145e4b3d154..b820d430037b8bf19564028e654c5b7d1677a30c 100644 (file)
@@ -317,10 +317,11 @@ class vtt_class
        void set_mix_solo(int newstate);
        static int get_last_sample_rate() { return last_sample_rate; }
        
-       void calc_mute()
-       {
+       void calc_mute() {
                res_mute=((mute) || (mix_mute && (!mix_solo)) || ((solo_ctr>0)&&(!mix_solo)));
        }
+       
+       static f_prec *get_mix_buffer() { return mix_buffer; }
 };
 
 #endif
index 34ab35ee3d7e2796dc4056eedeff4278408687d7..70f948114755c08260186c419e741ff4df6a287f 100644 (file)
@@ -279,7 +279,7 @@ void vtt_fx_ladspa :: save (FILE *rc, gzFile rz, char *indent) {
        store_int("ladspa_id", ID);
        
        for (sp=controls.begin(); sp!=controls.end(); sp++) {
-               store_float_id("param", (*sp)->get_value(), (*sp)->get_persistence_id());
+               store_float_sp("param", (*sp)->get_value(), (*(*sp)));
        }
        
        store_bool("panel_hidden", panel->is_hidden());
@@ -293,7 +293,6 @@ void vtt_fx_ladspa :: load(xmlDocPtr doc, xmlNodePtr node) {
        bool hidden=false;
        list <tX_seqpar_vttfx *> :: iterator sp=controls.begin();
        int elementFound;
-       guint32 pid=0;
        double val;
        
        for (xmlNodePtr cur=node->xmlChildrenNode; cur!=NULL; cur=cur->next) {
@@ -302,21 +301,16 @@ void vtt_fx_ladspa :: load(xmlDocPtr doc, xmlNodePtr node) {
                        
                        restore_int("ladspa_id", dummy);
                        restore_bool("panel_hidden", hidden);
+                       
                        if ((!elementFound) && (xmlStrcmp(cur->name, (xmlChar *) "param")==0)) {
                                val=0;
-                               elementFound=1;
+                               elementFound=0;
+                               double dvalue;
                        
                                if (sp==controls.end()) {
                                        tX_warning("found unexpected parameters for ladspa plugin [%i].", dummy);
-                               } else {                        
-                                       char *buff=(char *) xmlGetProp(cur, (xmlChar *) "id");
-                                       sscanf(buff, "%i", &pid);
-                       
-                                       if  (xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)) {
-                                               sscanf((char *) xmlNodeListGetString(doc, cur->xmlChildrenNode, 1), "%lf", &val); 
-                                       }
-                                       (*sp)->set_persistence_id(pid);
-                                       (*sp)->do_exec(val);
+                               } else {
+                                       restore_float_id("param", val, (*(*sp)), (*sp)->do_exec(val));                                  
                                        (*sp)->do_update_graphics();
                                        sp++;
                                }
index 73b4792ba3e39a786bb5692a64e533f4b5ab186c..b5412e9f54aa588648ed497a7f14b236f9a444b1 100644 (file)
            <widget class="GtkTable" id="table3">
              <property name="border_width">4</property>
              <property name="visible">True</property>
-             <property name="n_rows">4</property>
+             <property name="n_rows">5</property>
              <property name="n_columns">2</property>
              <property name="homogeneous">False</property>
              <property name="row_spacing">2</property>
                  <property name="y_options"></property>
                </packing>
              </child>
+
+             <child>
+               <widget class="GtkLabel" id="label40">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Restore MIDI connections:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">0</property>
+                 <property name="right_attach">1</property>
+                 <property name="top_attach">4</property>
+                 <property name="bottom_attach">5</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options"></property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkCheckButton" id="reconnect_enabled">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">When enabled soundfiles will be playedback when selected in a file dialog (before loading them).</property>
+                 <property name="can_focus">True</property>
+                 <property name="label" translatable="yes">Enabled</property>
+                 <property name="use_underline">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <property name="active">False</property>
+                 <property name="inconsistent">False</property>
+                 <property name="draw_indicator">True</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">1</property>
+                 <property name="right_attach">2</property>
+                 <property name="top_attach">4</property>
+                 <property name="bottom_attach">5</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options"></property>
+               </packing>
+             </child>
            </widget>
            <packing>
              <property name="tab_expand">False</property>