]> git.sesse.net Git - mlt/commitdiff
added jackrack filter
authorddennedy <ddennedy@d19143bc-622f-0410-bfdd-b5b2a6649095>
Mon, 27 Dec 2004 21:34:10 +0000 (21:34 +0000)
committerddennedy <ddennedy@d19143bc-622f-0410-bfdd-b5b2a6649095>
Mon, 27 Dec 2004 21:34:10 +0000 (21:34 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@581 d19143bc-622f-0410-bfdd-b5b2a6649095

23 files changed:
src/modules/jackrack/Makefile [new file with mode: 0644]
src/modules/jackrack/configure [new file with mode: 0755]
src/modules/jackrack/control_message.h [new file with mode: 0644]
src/modules/jackrack/factory.c [new file with mode: 0644]
src/modules/jackrack/filter_jackrack.c [new file with mode: 0644]
src/modules/jackrack/filter_jackrack.h [new file with mode: 0644]
src/modules/jackrack/gpl [new file with mode: 0644]
src/modules/jackrack/jack_rack.c [new file with mode: 0644]
src/modules/jackrack/jack_rack.h [new file with mode: 0644]
src/modules/jackrack/lock_free_fifo.c [new file with mode: 0644]
src/modules/jackrack/lock_free_fifo.h [new file with mode: 0644]
src/modules/jackrack/plugin.c [new file with mode: 0644]
src/modules/jackrack/plugin.h [new file with mode: 0644]
src/modules/jackrack/plugin_desc.c [new file with mode: 0644]
src/modules/jackrack/plugin_desc.h [new file with mode: 0644]
src/modules/jackrack/plugin_mgr.c [new file with mode: 0644]
src/modules/jackrack/plugin_mgr.h [new file with mode: 0644]
src/modules/jackrack/plugin_settings.c [new file with mode: 0644]
src/modules/jackrack/plugin_settings.h [new file with mode: 0644]
src/modules/jackrack/process.c [new file with mode: 0644]
src/modules/jackrack/process.h [new file with mode: 0644]
src/modules/jackrack/ui.c [new file with mode: 0644]
src/modules/jackrack/ui.h [new file with mode: 0644]

diff --git a/src/modules/jackrack/Makefile b/src/modules/jackrack/Makefile
new file mode 100644 (file)
index 0000000..e2ab8d4
--- /dev/null
@@ -0,0 +1,47 @@
+include ../../../config.mak
+
+TARGET = ../libmltjackrack.so
+
+OBJS = factory.o \
+          jack_rack.o \
+          lock_free_fifo.o \
+          plugin.o \
+          plugin_desc.o \
+          plugin_mgr.o \
+          plugin_settings.o \
+          process.o \
+          ui.o \
+          filter_jackrack.o 
+
+CFLAGS += -I../.. `pkg-config --cflags jack`
+CFLAGS += `xml2-config --cflags`
+CFLAGS += `pkg-config glib-2.0 --cflags` 
+
+LDFLAGS += `pkg-config --libs jack`
+LDFLAGS += `xml2-config --libs`
+LDFLAGS += `pkg-config glib-2.0 --libs`
+
+LDFLAGS+=-L../../framework -lmlt
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+install: all
+       install -m 755 $(TARGET) "$(prefix)/share/mlt/modules"
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/modules/jackrack/configure b/src/modules/jackrack/configure
new file mode 100755 (executable)
index 0000000..6f647bc
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../filters.dat
+jackrack               libmltjackrack.so
+EOF
+
+fi
diff --git a/src/modules/jackrack/control_message.h b/src/modules/jackrack/control_message.h
new file mode 100644 (file)
index 0000000..80071f6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_CONTROL_MESSAGE_H__
+#define __JR_CONTROL_MESSAGE_H__
+
+#include <glib.h>
+#include <ladspa.h>
+
+/** These are for messages between the gui and the process() callback */
+typedef enum _ctrlmsg_type
+{
+  CTRLMSG_ADD,
+  CTRLMSG_REMOVE,
+  CTRLMSG_QUIT,
+
+} ctrlmsg_type_t;
+
+typedef struct _ctrlmsg ctrlmsg_t;
+
+struct _plugin;
+struct _plugin_desc;
+
+struct _ctrlmsg
+{
+  ctrlmsg_type_t type;
+  union
+  {
+    struct
+    {
+      struct _plugin      * plugin;
+    } add;
+    
+    struct
+    {
+      struct _plugin      * plugin;
+    } remove;
+    
+  } data;
+};
+
+#endif /* __JR_CONTROL_MESSAGE_H__ */
diff --git a/src/modules/jackrack/factory.c b/src/modules/jackrack/factory.c
new file mode 100644 (file)
index 0000000..c5c9a96
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "filter_jackrack.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       if ( !strcmp( id, "jackrack" ) )
+               return filter_jackrack_init( arg );
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       return NULL;
+}
diff --git a/src/modules/jackrack/filter_jackrack.c b/src/modules/jackrack/filter_jackrack.c
new file mode 100644 (file)
index 0000000..954917d
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * filter_jackrack.c -- filter audio through Jack and/or LADSPA plugins
+ * Copyright (C) 2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "filter_jackrack.h"
+
+#include <framework/mlt_frame.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <samplerate.h>
+#define __USE_ISOC99 1
+#include <math.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "ui.h"
+
+#define BUFFER_LEN 2048 * 20
+
+static void *jackrack_thread( void *arg )
+{
+       mlt_properties properties = arg;
+       ui_t *jackrack = mlt_properties_get_data( properties, "jackrack", NULL );
+               
+       while ( mlt_properties_get_int( properties, "_done" ) == 0 )
+               if ( ui_loop_iterate( jackrack ) )
+                       break;
+               
+       ui_quit( jackrack );
+       ui_destroy( jackrack );
+       
+       return NULL;
+}
+
+static void initialise_jack_ports( mlt_properties properties, int channels, int samples )
+{
+       int i;
+       char mlt_name[20], rack_name[30];
+       jack_port_t **port = NULL;
+       jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
+       jack_nframes_t jack_buffer_size = jack_get_buffer_size( jack_client );
+       
+       // Propogate these for the Jack processing callback
+       mlt_properties_set_int( properties, "_channels", channels );
+       mlt_properties_set_int( properties, "_samples", samples );
+
+       // Start JackRack
+       if ( mlt_properties_get( properties, "src" ) )
+       {
+               pthread_t *jackrack_pthread = calloc( 1, sizeof( pthread_t ) );
+
+               snprintf( rack_name, sizeof( rack_name ), "jackrack%d", getpid() );
+               ui_t *jackrack = ui_new( rack_name, mlt_properties_get_int( properties, "_channels" ), 0, 0 );
+               jack_rack_open_file( jackrack, mlt_properties_get( properties, "src" ) );               
+               
+               mlt_properties_set_data( properties, "jackrack", jackrack, 0, NULL, NULL );
+               mlt_properties_set( properties, "_rack_client_name", rack_name );
+               mlt_properties_set_int( properties, "_done", 0 );
+               mlt_properties_set_data( properties, "jackrack_pthread", jackrack_pthread, 0, NULL, NULL );
+               
+               pthread_create( jackrack_pthread, NULL, jackrack_thread, properties );
+       }
+               
+       // Allocate buffers and ports
+       jack_ringbuffer_t **output_buffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels );
+       jack_ringbuffer_t **input_buffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels );
+       jack_port_t **jack_output_ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels );
+       jack_port_t **jack_input_ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels );
+       float **jack_output_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size );
+       float **jack_input_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size );
+
+       // Set properties for self-destruction  
+       mlt_properties_set_data( properties, "output_buffers", output_buffers, sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL );
+       mlt_properties_set_data( properties, "input_buffers", input_buffers, sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL );
+       mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, sizeof( jack_port_t *) * channels, mlt_pool_release, NULL );
+       mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, sizeof( jack_port_t *) * channels, mlt_pool_release, NULL );
+       mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, sizeof( float *) * channels, mlt_pool_release, NULL );
+       mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, sizeof( float *) * channels, mlt_pool_release, NULL );
+
+       // Start Jack processing - required before registering ports
+       jack_activate( jack_client );
+       
+       // Register Jack ports
+       for ( i = 0; i < channels; i++ )
+       {
+               int in;
+               
+               output_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) );
+               input_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) );
+               snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i );
+               mlt_properties_set_data( properties, mlt_name, output_buffers[i], BUFFER_LEN * sizeof(float), ( mlt_destructor )jack_ringbuffer_free, NULL );
+               snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i );
+               mlt_properties_set_data( properties, mlt_name, input_buffers[i], BUFFER_LEN * sizeof(float), ( mlt_destructor )jack_ringbuffer_free, NULL );
+               
+               for ( in = 0; in < 2; in++ )
+               {
+                       snprintf( mlt_name, sizeof( mlt_name ), "%s_%d", in ? "in" : "out", i + 1);
+                       port = ( in ? &jack_input_ports[i] : &jack_output_ports[i] );
+                       
+                       *port =  jack_port_register( jack_client, mlt_name, JACK_DEFAULT_AUDIO_TYPE,
+                               ( in ? JackPortIsInput : JackPortIsOutput ) | JackPortIsTerminal, 0 );
+               }
+       }
+       
+       // Establish connections
+       for ( i = 0; i < channels; i++ )
+       {
+               int in;
+               for ( in = 0; in < 2; in++ )
+               {
+                       port = ( in ? &jack_input_ports[i] : &jack_output_ports[i] );
+                       snprintf( mlt_name, sizeof( mlt_name ), "%s", jack_port_name( *port ) );
+
+                       snprintf( rack_name, sizeof( rack_name ), "%s_%d", in ? "in" : "out", i + 1 );
+                       if ( mlt_properties_get( properties, "_rack_client_name" ) )
+                               snprintf( rack_name, sizeof( rack_name ), "%s:%s_%d", mlt_properties_get( properties, "_rack_client_name" ), in ? "out" : "in", i + 1);
+                       else if ( mlt_properties_get( properties, rack_name ) )
+                               snprintf( rack_name, sizeof( rack_name ), "%s", mlt_properties_get( properties, rack_name ) );
+                       else
+                               snprintf( rack_name, sizeof( rack_name ), "%s:%s_%d", mlt_properties_get( properties, "_client_name" ), in ? "out" : "in", i + 1);
+                       
+                       if ( in )
+                       {
+                               fprintf( stderr, "jack connect %s to %s\n", rack_name, mlt_name );
+                               jack_connect( jack_client, rack_name, mlt_name );
+                       }
+                       else
+                       {
+                               fprintf( stderr, "jack connect %s to %s\n", mlt_name, rack_name );
+                               jack_connect( jack_client, mlt_name, rack_name );
+                       }
+               }
+       }
+}
+
+static int jack_process (jack_nframes_t frames, void * data)
+{
+       mlt_filter filter = (mlt_filter) data;
+       mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+       int channels = mlt_properties_get_int( properties, "_channels" );
+       int err = 0;
+       int i;
+       static size_t total_size = 0;
+       size_t first_ring_size = mlt_properties_get_int( properties, "_samples" ) * sizeof(float);
+  
+       jack_ringbuffer_t **output_buffers = mlt_properties_get_data( properties, "output_buffers", NULL );
+       if ( output_buffers == NULL )
+               return 0;
+       jack_ringbuffer_t **input_buffers = mlt_properties_get_data( properties, "input_buffers", NULL );
+       jack_port_t **jack_output_ports = mlt_properties_get_data( properties, "jack_output_ports", NULL );
+       jack_port_t **jack_input_ports = mlt_properties_get_data( properties, "jack_input_ports", NULL );
+       float **jack_output_buffers = mlt_properties_get_data( properties, "jack_output_buffers", NULL );
+       float **jack_input_buffers = mlt_properties_get_data( properties, "jack_input_buffers", NULL );
+       pthread_mutex_t *output_lock = mlt_properties_get_data( properties, "output_lock", NULL );
+       pthread_cond_t *output_ready = mlt_properties_get_data( properties, "output_ready", NULL );
+       
+       for ( i = 0; i < channels; i++ )
+       {
+               size_t jack_size = ( frames * sizeof(float) );
+               size_t ring_size;
+               
+               // Send audio through out port
+               jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames );
+               if ( ! jack_output_buffers[i] )
+               {
+                       fprintf( stderr, "%s: no jack buffer for output port %d\n", __FUNCTION__, i );
+                       err = 1;
+                       break;
+               }
+               ring_size = jack_ringbuffer_read_space( output_buffers[i] );
+               jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size );
+               
+               // Do not start returning audio until we have sent first mlt frame
+               if ( first_ring_size != -sizeof(float) && i == 0 )
+                       total_size += ring_size;
+               if ( first_ring_size == -sizeof(float) || total_size >= first_ring_size )
+               {
+                       // Set flag to skip this henceforth
+                       mlt_properties_set_int( properties, "_samples", -1 );
+                       
+                       // Return audio through in port
+                       jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames );
+                       if ( ! jack_input_buffers[i] )
+                       {
+                               fprintf( stderr, "%s: no jack buffer for input port %d\n", __FUNCTION__, i );
+                               err = 1;
+                               break;
+                       }
+                       
+                       ring_size = jack_ringbuffer_write_space( input_buffers[i] );
+                       jack_ringbuffer_write( input_buffers[i], ( char * )jack_input_buffers[i], ring_size < jack_size ? ring_size : jack_size );
+                       
+                       // Tell mlt that audio is available
+                       if ( i == ( channels - 1 ) && pthread_mutex_trylock( output_lock) == 0 )
+                       {
+                               pthread_cond_signal( output_ready );
+                               pthread_mutex_unlock( output_lock );
+                       }
+               }
+       }
+
+       return err;
+}
+
+
+/** Get the audio.
+*/
+
+static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       // Get the filter service
+       mlt_filter filter = mlt_frame_pop_audio( frame );
+
+       // Get the filter properties
+       mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
+
+       // Restore the original get_audio
+       frame->get_audio = mlt_frame_pop_audio( frame );
+
+       // Get the producer's audio
+       mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
+       //fprintf( stderr, "%s: %d frames %d channels\n", __FUNCTION__, *samples, *channels );
+
+       // Initialise Jack ports and connections if needed
+       if ( ! mlt_properties_get_data( filter_properties, "jack_output_ports", NULL ) )
+               initialise_jack_ports( filter_properties, *channels, *samples );
+       
+       // Get the filter-specific properties
+       jack_ringbuffer_t **output_buffers = mlt_properties_get_data( filter_properties, "output_buffers", NULL );
+       jack_ringbuffer_t **input_buffers = mlt_properties_get_data( filter_properties, "input_buffers", NULL );
+       pthread_mutex_t *output_lock = mlt_properties_get_data( filter_properties, "output_lock", NULL );
+       pthread_cond_t *output_ready = mlt_properties_get_data( filter_properties, "output_ready", NULL );
+       
+       // Process the audio
+       int16_t *q = *buffer;
+       float sample;
+       int i, j;
+
+       // Convert to floats and write into output ringbuffer
+       if ( jack_ringbuffer_write_space( output_buffers[0] ) >= ( *samples * sizeof(float) ) )
+       {
+               //fprintf( stderr, "%s: buffer overrun!\n", __FUNCTION__ );
+               //pthread_cond_wait( &output_ready, &output_lock );
+               for ( i = 0; i < *samples; i++ )
+                       for ( j = 0; j < *channels; j++ )
+                       {
+                               sample = ( float )( *q ++ ) / 32768.0;
+                               jack_ringbuffer_write( output_buffers[j], ( char * )&sample, sizeof(float) );
+                       }
+       }
+       //else
+       //      fprintf( stderr, "%s: out buffer size %d\n", __FUNCTION__, jack_ringbuffer_write_space( output_buffers[0] ) );
+       
+       // Read from input ringbuffer and convert from floats
+       while ( jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < ( *samples * sizeof(float) ) )
+               pthread_cond_wait( output_ready, output_lock );
+       {
+               q = *buffer;
+               
+               // Initialise to silence, but repeat last frame if available in case of 
+               // buffer underrun
+               sample = 0;
+               
+               for ( i = 0; i < *samples; i++ )
+                       for ( j = 0; j < *channels; j++ )
+                       {
+                               jack_ringbuffer_read( input_buffers[j], ( char * )&sample, sizeof(float) );
+
+                               if ( sample > 1.0 )
+                                       sample = 1.0;
+                               else if ( sample < -1.0 )
+                                       sample = -1.0;
+                       
+                               if ( sample > 0 )
+                                       *q ++ = 32767 * sample;
+                               else
+                                       *q ++ = 32768 * sample;
+                       }
+       }
+       //else
+       //      fprintf( stderr, "%s: in buffer size %d\n", __FUNCTION__, jack_ringbuffer_read_space( output_buffers[0] ) );
+
+       return 0;
+}
+
+
+/** Filter processing.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+       if ( frame->get_audio != NULL )
+       {
+               mlt_frame_push_audio( frame, frame->get_audio );
+               mlt_frame_push_audio( frame, this );
+               frame->get_audio = jackrack_get_audio;
+       }
+
+       return frame;
+}
+
+
+void filter_close( mlt_filter this )
+{
+       mlt_properties properties = MLT_FILTER_PROPERTIES( this );
+       jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
+       
+       jack_deactivate( jack_client );
+       jack_client_close( jack_client );
+       pthread_t *jackrack_pthread = mlt_properties_get_data( properties, "jackrack_thread", NULL );
+       if ( jackrack_pthread != NULL )
+       {
+               mlt_properties_set_int( properties, "_done", 1 );
+               pthread_join( *jackrack_pthread, NULL );
+               free( jackrack_pthread );
+       }
+}
+
+/** Constructor for the filter.
+*/
+
+mlt_filter filter_jackrack_init( char *arg )
+{
+       mlt_filter this = mlt_filter_new( );
+       if ( this != NULL )
+       {
+               char name[14];
+               
+               snprintf( name, sizeof( name ), "mlt%d", getpid() );
+               jack_client_t *jack_client = jack_client_new( name );
+               if ( jack_client )
+               {
+                       mlt_properties properties = MLT_FILTER_PROPERTIES( this );
+                       pthread_mutex_t *output_lock = calloc( 1, sizeof( pthread_mutex_t ) );
+                       pthread_cond_t  *output_ready = calloc( 1, sizeof( pthread_cond_t ) );
+                       
+                       jack_set_process_callback( jack_client, jack_process, this );
+                       //TODO: jack_on_shutdown( jack_client, jack_shutdown_cb, this );
+                       this->process = filter_process;
+                       pthread_mutex_init( output_lock, NULL );
+                       pthread_cond_init( output_ready, NULL );
+                       
+                       mlt_properties_set( properties, "src", arg );
+                       mlt_properties_set( properties, "_client_name", name );
+                       mlt_properties_set_data( properties, "jack_client", jack_client, 0, ( mlt_destructor )filter_close, NULL );
+                       mlt_properties_set_int( properties, "_sample_rate", jack_get_sample_rate( jack_client ) );
+                       mlt_properties_set_data( properties, "output_lock", output_lock, 0, free, NULL );
+                       mlt_properties_set_data( properties, "output_ready", output_ready, 0, free, NULL );
+               }
+       }
+       return this;
+}
diff --git a/src/modules/jackrack/filter_jackrack.h b/src/modules/jackrack/filter_jackrack.h
new file mode 100644 (file)
index 0000000..2215f05
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * filter_jackrack.h -- filter audio through Jack and/or LADSPA plugins
+ * Copyright (C) 2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FILTER_JACKRACK_H_
+#define _FILTER_JACKRACK_H_
+
+#include <framework/mlt_filter.h>
+
+extern mlt_filter filter_jackrack_init( char *arg );
+
+#endif
diff --git a/src/modules/jackrack/gpl b/src/modules/jackrack/gpl
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/modules/jackrack/jack_rack.c b/src/modules/jackrack/jack_rack.c
new file mode 100644 (file)
index 0000000..577694c
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ladspa.h>
+#include <libxml/tree.h>
+
+#include "jack_rack.h"
+#include "lock_free_fifo.h"
+#include "control_message.h"
+#include "ui.h"
+#include "plugin_settings.h"
+
+#ifndef _
+#define _(x) x
+#endif
+
+jack_rack_t *
+jack_rack_new (ui_t * ui, unsigned long channels)
+{
+  jack_rack_t *rack;
+
+  rack = g_malloc (sizeof (jack_rack_t));
+  rack->saved_plugins  = NULL;
+  rack->ui             = ui;
+  rack->channels       = channels;
+
+  return rack;
+}
+
+
+void
+jack_rack_destroy (jack_rack_t * jack_rack)
+{
+  g_free (jack_rack);
+}
+
+plugin_t *
+jack_rack_instantiate_plugin (jack_rack_t * jack_rack, plugin_desc_t * desc)
+{
+  plugin_t * plugin;
+  
+  /* check whether or not the plugin is RT capable and confirm with the user if it isn't */
+  if (!LADSPA_IS_HARD_RT_CAPABLE(desc->properties)) {
+    fprintf (stderr, "Plugin not RT capable. The plugin '%s' does not describe itself as being capable of real-time operation. You may experience drop outs or jack may even kick us out if you use it.\n",
+               desc->name);
+  }
+
+  /* create the plugin */
+  plugin = plugin_new (desc, jack_rack);
+
+  if (!plugin) {
+   fprintf (stderr, "Error loading file plugin '%s' from file '%s'\n",
+               desc->name, desc->object_file);
+  }
+  
+  return plugin;
+}
+
+void
+jack_rack_send_add_plugin (jack_rack_t * jack_rack, plugin_desc_t * desc)
+{
+  plugin_t * plugin;
+  ctrlmsg_t ctrlmsg;
+  
+  plugin = jack_rack_instantiate_plugin (jack_rack, desc);
+  
+  if (!plugin)
+    return;
+  
+  /* send the chain link off to the process() callback */
+  ctrlmsg.type = CTRLMSG_ADD;
+  ctrlmsg.data.add.plugin = plugin;
+  lff_write (jack_rack->ui->ui_to_process, &ctrlmsg);
+}
+
+void
+jack_rack_add_saved_plugin (jack_rack_t * jack_rack, saved_plugin_t * saved_plugin)
+{
+  jack_rack->saved_plugins = g_slist_append (jack_rack->saved_plugins, saved_plugin);
+  
+  jack_rack_send_add_plugin (jack_rack, saved_plugin->settings->desc);
+}
+
+
+void
+jack_rack_add_plugin (jack_rack_t * jack_rack, plugin_t * plugin)
+{
+  saved_plugin_t * saved_plugin = NULL;
+  GSList * list;
+  unsigned long control, channel;
+  LADSPA_Data value;
+  guint copy;
+  
+  /* see if there's any saved settings that match the plugin id */
+  for (list = jack_rack->saved_plugins; list; list = g_slist_next (list))
+    {
+      saved_plugin = list->data;
+      
+      if (saved_plugin->settings->desc->id == plugin->desc->id)
+        {
+          /* process the settings! */
+          jack_rack->saved_plugins = g_slist_remove (jack_rack->saved_plugins, saved_plugin);
+          break;
+        }
+      saved_plugin = NULL;
+    }
+       
+  /* initialize plugin parameters */
+  plugin->enabled = settings_get_enabled (saved_plugin->settings);
+  plugin->wet_dry_enabled = settings_get_wet_dry_enabled (saved_plugin->settings);
+       
+  for (control = 0; control < saved_plugin->settings->desc->control_port_count; control++)
+    for (copy = 0; copy < plugin->copies; copy++)
+      {
+        value = settings_get_control_value (saved_plugin->settings, copy, control);
+        plugin->holders[copy].control_memory[control] = value;
+//printf("setting control value %s (%d) = %f\n", saved_plugin->settings->desc->port_names[control], copy, value);
+//        lff_write (plugin->holders[copy].ui_control_fifos + control, &value);
+      }
+  if (plugin->wet_dry_enabled)
+    for (channel = 0; channel < jack_rack->channels; channel++)
+      {
+        value = settings_get_wet_dry_value (saved_plugin->settings, channel);
+        plugin->wet_dry_values[channel] = value;
+//printf("setting wet/dry value %d = %f\n", channel, value);
+//        lff_write (plugin->wet_dry_fifos + channel, &value);
+      }
+}
+
+
+static void
+saved_rack_parse_plugin (saved_rack_t * saved_rack, saved_plugin_t * saved_plugin,
+                         ui_t * ui, const char * filename, xmlNodePtr plugin)
+{
+  plugin_desc_t * desc;
+  settings_t * settings = NULL;
+  xmlNodePtr node;
+  xmlNodePtr sub_node;
+  xmlChar *content;
+  unsigned long num;
+  unsigned long control = 0;
+
+  for (node = plugin->children; node; node = node->next)
+    {
+      if (strcmp (node->name, "id") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          num = strtoul (content, NULL, 10);
+          xmlFree (content);
+
+          desc = plugin_mgr_get_any_desc (ui->plugin_mgr, num);
+          if (!desc)
+            {
+              fprintf (stderr, _("The file '%s' contains an unknown plugin with ID '%ld'; skipping\n"), filename, num);
+              return;
+            }
+          
+          settings = settings_new (desc, saved_rack->channels, saved_rack->sample_rate);
+        }
+      else if (strcmp (node->name, "enabled") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          settings_set_enabled (settings, strcmp (content, "true") == 0 ? TRUE : FALSE);
+          xmlFree (content);
+        }
+      else if (strcmp (node->name, "wet_dry_enabled") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          settings_set_wet_dry_enabled (settings, strcmp (content, "true") == 0 ? TRUE : FALSE);
+          xmlFree (content);
+        }
+      else if (strcmp (node->name, "wet_dry_locked") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          settings_set_wet_dry_locked (settings, strcmp (content, "true") == 0 ? TRUE : FALSE);
+          xmlFree (content);
+        }
+      else if (strcmp (node->name, "wet_dry_values") == 0)
+        {
+          unsigned long channel = 0;
+          
+          for (sub_node = node->children; sub_node; sub_node = sub_node->next)
+            {
+              if (strcmp (sub_node->name, "value") == 0)
+                {
+                  content = xmlNodeGetContent (sub_node);
+                  settings_set_wet_dry_value (settings, channel, strtod (content, NULL));
+                  xmlFree (content);
+                  
+                  channel++;
+                }
+            }
+        }
+      else if (strcmp (node->name, "lockall") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          settings_set_lock_all (settings, strcmp (content, "true") == 0 ? TRUE : FALSE);
+          xmlFree (content);
+        }
+      else if (strcmp (node->name, "controlrow") == 0)
+        {
+          gint copy = 0;
+
+          for (sub_node = node->children; sub_node; sub_node = sub_node->next)
+            {
+              if (strcmp (sub_node->name, "lock") == 0)
+                {
+                  content = xmlNodeGetContent (sub_node);
+                  settings_set_lock (settings, control, strcmp (content, "true") == 0 ? TRUE : FALSE);
+                  xmlFree (content);
+                }
+              else if (strcmp (sub_node->name, "value") == 0)
+                {
+                  content = xmlNodeGetContent (sub_node);
+                  settings_set_control_value (settings, copy, control, strtod (content, NULL));
+                  xmlFree (content);
+                  copy++;
+                }
+            }
+          
+          control++;
+        }
+    }
+  
+  if (settings)
+    saved_plugin->settings = settings;
+}
+
+static void
+saved_rack_parse_jackrack (saved_rack_t * saved_rack, ui_t * ui, const char * filename, xmlNodePtr jackrack)
+{
+  xmlNodePtr node;
+  xmlChar *content;
+  saved_plugin_t * saved_plugin;
+
+  for (node = jackrack->children; node; node = node->next)
+    {
+      if (strcmp (node->name, "channels") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          saved_rack->channels = strtoul (content, NULL, 10);
+          xmlFree (content);
+        }
+      else if (strcmp (node->name, "samplerate") == 0)
+        {
+          content = xmlNodeGetContent (node);
+          saved_rack->sample_rate = strtoul (content, NULL, 10);
+          xmlFree (content);
+        }
+      else if (strcmp (node->name, "plugin") == 0)
+        {
+          saved_plugin = g_malloc0 (sizeof (saved_plugin_t));
+          saved_rack->plugins = g_slist_append (saved_rack->plugins, saved_plugin);
+          saved_rack_parse_plugin (saved_rack, saved_plugin, ui, filename, node);
+        }
+    }
+}
+
+static saved_rack_t *
+saved_rack_new (ui_t * ui, const char * filename, xmlDocPtr doc)
+{
+  xmlNodePtr node;
+  saved_rack_t *saved_rack;
+  
+  /* create the saved rack */
+  saved_rack = g_malloc (sizeof (saved_rack_t));
+  saved_rack->plugins = NULL;
+  saved_rack->sample_rate = 48000;
+  saved_rack->channels = 2;
+  
+  for (node = doc->children; node; node = node->next)
+    {
+      if (strcmp (node->name, "jackrack") == 0)
+        saved_rack_parse_jackrack (saved_rack, ui, filename, node);
+    }
+  
+  return saved_rack;
+}
+
+static void
+saved_rack_destroy (saved_rack_t * saved_rack)
+{
+/*  GSList * list;*/
+  
+/*  for (list = saved_rack->settings; list; list = g_slist_next (list))
+    settings_destroy ((settings_t *) list->data); */
+/*  g_slist_free (saved_rack->settings); */
+  
+  g_free (saved_rack);
+}
+
+
+int
+jack_rack_open_file (ui_t * ui, const char * filename)
+{
+  xmlDocPtr doc;
+  saved_rack_t * saved_rack;
+  GSList * list;
+  saved_plugin_t * saved_plugin;
+
+  doc = xmlParseFile (filename);
+  if (!doc)
+    {
+      fprintf (stderr, _("Could not parse file '%s'\n"), filename);
+      return 1;
+    }
+  
+  if (strcmp ( ((xmlDtdPtr)doc->children)->name, "jackrack") != 0)
+    {
+      fprintf (stderr, _("The file '%s' is not a JACK Rack settings file\n"), filename);
+      return 1;
+    }
+  
+  saved_rack = saved_rack_new (ui, filename, doc);
+  xmlFreeDoc (doc);
+  
+  if (!saved_rack)
+    return 1;
+
+  for (list = saved_rack->plugins; list; list = g_slist_next (list))
+    {
+      saved_plugin = list->data;
+      
+      settings_set_sample_rate (saved_plugin->settings, sample_rate);
+      
+      jack_rack_add_saved_plugin (ui->jack_rack, saved_plugin);
+    }
+  
+  g_slist_free (saved_rack->plugins);  
+  g_free (saved_rack);
+  
+  return 0;
+}
+
+
+/* EOF */
diff --git a/src/modules/jackrack/jack_rack.h b/src/modules/jackrack/jack_rack.h
new file mode 100644 (file)
index 0000000..e500e0e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_JACK_RACK_H__
+#define __JR_JACK_RACK_H__
+
+#include <glib.h>
+#include <ladspa.h>
+
+#include "plugin.h"
+#include "plugin_mgr.h"
+#include "plugin_settings.h"
+#include "ui.h"
+
+typedef struct _saved_plugin saved_plugin_t;
+
+struct _saved_plugin
+{
+  settings_t     *settings;
+};
+
+typedef struct _saved_rack   saved_rack_t;
+
+struct _saved_rack
+{
+  unsigned long  channels;
+  jack_nframes_t sample_rate;
+  GSList *       plugins;
+};
+
+typedef struct _jack_rack jack_rack_t;
+
+struct _jack_rack
+{
+  struct _ui *      ui;
+  
+  unsigned long     channels;
+  
+  GSList *          saved_plugins;
+};
+
+jack_rack_t * jack_rack_new     (struct _ui * ui, unsigned long channels);
+void          jack_rack_destroy (jack_rack_t * jack_rack);
+
+int jack_rack_open_file (struct _ui * ui, const char * filename);
+void jack_rack_send_add_plugin (jack_rack_t * jack_rack, plugin_desc_t * plugin);
+void jack_rack_add_plugin (jack_rack_t * jack_rack, plugin_t * plugin);
+void jack_rack_add_saved_plugin (jack_rack_t * jack_rack, struct _saved_plugin * saved_plugin);
+
+plugin_t * jack_rack_instantiate_plugin (jack_rack_t * jack_rack, plugin_desc_t * desc);
+
+#endif /* __JR_JACK_RACK_H__ */
diff --git a/src/modules/jackrack/lock_free_fifo.c b/src/modules/jackrack/lock_free_fifo.c
new file mode 100644 (file)
index 0000000..296d6b1
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "lock_free_fifo.h"
+
+/** initialise a lock free fifo */
+
+void
+lff_init (lff_t * lff, unsigned int size, size_t object_size)
+{
+  lff->size = size;
+  lff->object_size = object_size;
+  lff->read_index = 0;
+  lff->write_index = 0;
+  lff->data = g_malloc (object_size * size);
+}
+
+lff_t *
+lff_new (unsigned int size, size_t object_size)
+{
+  lff_t * lff;
+  
+  lff = g_malloc (sizeof (lff_t));
+  
+  lff_init (lff, size, object_size);
+  
+  return lff;
+}
+
+void
+lff_free (lff_t * lff)
+{
+  g_free (lff->data);
+}
+
+void
+lff_destroy (lff_t * lff)
+{
+  lff_free (lff);
+  g_free (lff);
+}
+
+/** read an element from the fifo into data.
+returns 0 on success, non-zero if there were no elements to read */
+int lff_read (lff_t * lff, void * data) {
+  if (lff->read_index == lff->write_index) {
+    return -1;
+  } else {
+    memcpy (data, ((char *)lff->data) + (lff->read_index * lff->object_size),
+            lff->object_size);
+    lff->read_index++;
+    if (lff->read_index >= lff->size) {
+      lff->read_index = 0;
+    }
+    return 0;
+  }
+}
+
+/** write an element from data to the fifo.
+returns 0 on success, non-zero if there was no space */
+int lff_write (lff_t * lff, void * data) {
+  static unsigned int ri;
+  
+  /* got to read read_index only once for safety */
+  ri = lff->read_index;
+
+  /* lots of logic for when we're allowed to write to the fifo which basically
+     boils down to "don't write if we're one element behind the read index" */  
+  if ((ri > lff->write_index && ri - lff->write_index > 1) ||
+      (lff->write_index >= ri && lff->write_index != lff->size - 1) ||
+      (lff->write_index >= ri && lff->write_index == lff->size - 1 && ri != 0)) { 
+
+/*  if ((ri > lff->write_index && ri - lff->write_index > 1) ||
+      (lff->write_index >= ri && (lff->write_index != lff->size - 1 || ri != 0))) { */
+
+    memcpy (((char *)lff->data) + (lff->write_index * lff->object_size),
+            data, lff->object_size);
+
+    /* FIXME: is this safe? */
+    lff->write_index++;
+    if (lff->write_index >= lff->size) {
+      lff->write_index = 0;
+    }
+
+    return 0;
+  } else {
+    return -1;
+  }
+}
diff --git a/src/modules/jackrack/lock_free_fifo.h b/src/modules/jackrack/lock_free_fifo.h
new file mode 100644 (file)
index 0000000..af8c19d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JLH_LOCK_FREE_FIFO_H__
+#define __JLH_LOCK_FREE_FIFO_H__
+
+/** lock free fifo ring buffer structure */
+typedef struct lock_free_fifo {
+  /** Size of the ringbuffer (in elements) */
+  unsigned int size;
+  /** the memory containing the ringbuffer */
+  void * data;
+  /** the size of an element */
+  size_t object_size;
+  /** the current position of the reader */
+  unsigned int read_index;
+  /** the current position of the writer */
+  unsigned int write_index;
+} lff_t;
+
+void lff_init (lff_t * lff, unsigned int size, size_t object_size);
+void lff_free (lff_t * lff);
+
+lff_t * lff_new     (unsigned int size, size_t object_size);
+void    lff_destroy (lff_t * lock_free_fifo);
+               
+int lff_read (lff_t * lock_free_fifo, void * data);
+int lff_write (lff_t * lock_free_fifo, void * data);
+
+
+#endif /* __JLH_LOCK_FREE_FIFO_H__ */
diff --git a/src/modules/jackrack/plugin.c b/src/modules/jackrack/plugin.c
new file mode 100644 (file)
index 0000000..753910b
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ *   jack-ladspa-host
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ladspa.h>
+#include <dlfcn.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "plugin.h"
+#include "jack_rack.h"
+#include "process.h"
+#include "ui.h"
+
+#define CONTROL_FIFO_SIZE   128
+
+
+
+/* swap over the jack ports in two plugins */
+static void
+plugin_swap_aux_ports (plugin_t * plugin, plugin_t * other)
+{
+  guint copy;
+  jack_port_t ** aux_ports_tmp;
+  
+  for (copy = 0; copy < plugin->copies; copy++)
+    {
+      aux_ports_tmp = other->holders[copy].aux_ports;
+      other->holders[copy].aux_ports = plugin->holders[copy].aux_ports;
+      plugin->holders[copy].aux_ports = aux_ports_tmp;
+    }
+}
+
+/** connect up the ladspa instance's input buffers to the previous
+    plugin's audio memory.  make sure to check that plugin->prev
+    exists. */
+void
+plugin_connect_input_ports (plugin_t * plugin, LADSPA_Data ** inputs)
+{
+  gint copy;
+  unsigned long channel;
+  unsigned long rack_channel;
+
+  if (!plugin || !inputs)
+    return;
+
+  rack_channel = 0;
+  for (copy = 0; copy < plugin->copies; copy++)
+    {
+      for (channel = 0; channel < plugin->desc->channels; channel++)
+        {
+          plugin->descriptor->
+            connect_port (plugin->holders[copy].instance,
+                          plugin->desc->audio_input_port_indicies[channel],
+                          inputs[rack_channel]);
+          rack_channel++;
+        }
+    }
+  
+  plugin->audio_input_memory = inputs;
+}
+
+/** connect up a plugin's output ports to its own audio_output_memory output memory */
+void
+plugin_connect_output_ports (plugin_t * plugin)
+{
+  gint copy;
+  unsigned long channel;
+  unsigned long rack_channel = 0;
+
+  if (!plugin)
+    return;
+
+
+  for (copy = 0; copy < plugin->copies; copy++)
+    {
+      for (channel = 0; channel < plugin->desc->channels; channel++)
+        {
+          plugin->descriptor->
+            connect_port (plugin->holders[copy].instance,
+                          plugin->desc->audio_output_port_indicies[channel],
+                          plugin->audio_output_memory[rack_channel]);
+          rack_channel++;
+        }
+    }
+}
+
+void
+process_add_plugin (process_info_t * procinfo, plugin_t * plugin)
+{
+
+  /* sort out list pointers */
+  plugin->next = NULL;
+  plugin->prev = procinfo->chain_end;
+
+  if (procinfo->chain_end)
+    procinfo->chain_end->next = plugin;
+  else
+    procinfo->chain = plugin;
+
+  procinfo->chain_end = plugin;
+
+}
+
+
+/** remove a plugin from the chain */
+plugin_t *
+process_remove_plugin (process_info_t * procinfo, plugin_t *plugin)
+{
+  /* sort out chain pointers */
+  if (plugin->prev)
+    plugin->prev->next = plugin->next;
+  else
+    procinfo->chain = plugin->next;
+
+  if (plugin->next)
+    plugin->next->prev = plugin->prev;
+  else
+    procinfo->chain_end = plugin->prev;
+    
+  /* sort out the aux ports */
+  if (plugin->desc->aux_channels > 0)
+    {
+      plugin_t * other;
+      
+      for (other = plugin->next; other; other = other->next)
+        if (other->desc->id == plugin->desc->id)
+          plugin_swap_aux_ports (plugin, other);
+    }
+
+  return plugin;
+}
+
+/** enable/disable a plugin */
+void
+process_ablise_plugin (process_info_t * procinfo, plugin_t *plugin, gboolean enable)
+{
+  plugin->enabled = enable;
+}
+
+/** enable/disable a plugin */
+void
+process_ablise_plugin_wet_dry (process_info_t * procinfo, plugin_t *plugin, gboolean enable)
+{
+  plugin->wet_dry_enabled = enable;
+}
+
+/** move a plugin up or down one place in the chain */
+void
+process_move_plugin (process_info_t * procinfo, plugin_t *plugin, gint up)
+{
+  /* other plugins in the chain */
+  plugin_t *pp = NULL, *p, *n, *nn = NULL;
+
+  /* note that we should never recieve an illogical move request
+     ie, there will always be at least 1 plugin before for an up
+     request or 1 plugin after for a down request */
+
+  /* these are pointers to the plugins surrounding the specified one:
+     { pp, p, plugin, n, nn } which makes things much clearer than
+     tptr, tptr2 etc */
+  p = plugin->prev;
+  if (p) pp = p->prev;
+  n = plugin->next;
+  if (n) nn = n->next;
+
+  if (up)
+    {
+      if (!p)
+       return;
+
+      if (pp)
+        pp->next = plugin;
+      else
+        procinfo->chain = plugin;
+
+      p->next = n;
+      p->prev = plugin;
+
+      plugin->prev = pp;
+      plugin->next = p;
+
+      if (n)
+       n->prev = p;
+      else
+       procinfo->chain_end = p;
+
+    }
+  else
+    {
+      if (!n)
+       return;
+
+      if (p)
+       p->next = n;
+      else
+       procinfo->chain = n;
+
+      n->prev = p;
+      n->next = plugin;
+
+      plugin->prev = n;
+      plugin->next = nn;
+
+      if (nn)
+       nn->prev = plugin;
+      else
+       procinfo->chain_end = plugin;
+    }
+  
+  if (plugin->desc->aux_channels > 0)
+    {
+      plugin_t * other;
+      other = up ? plugin->next : plugin->prev;
+      
+      /* swap around the jack ports */
+      if (other->desc->id == plugin->desc->id)
+        plugin_swap_aux_ports (plugin, other);
+    }
+}
+
+/** exchange an existing plugin for a newly created one */
+plugin_t *
+process_change_plugin (process_info_t * procinfo,
+                      plugin_t *plugin, plugin_t * new_plugin)
+{
+  new_plugin->next = plugin->next;
+  new_plugin->prev = plugin->prev;
+
+  if (plugin->prev)
+    plugin->prev->next = new_plugin;
+  else
+    procinfo->chain = new_plugin;
+
+  if (plugin->next)
+    plugin->next->prev = new_plugin;
+  else
+    procinfo->chain_end = new_plugin;
+
+  /* sort out the aux ports */
+  if (plugin->desc->aux_channels > 0)
+    {
+      plugin_t * other;
+      
+      for (other = plugin->next; other; other = other->next)
+        if (other->desc->id == plugin->desc->id)
+          plugin_swap_aux_ports (plugin, other);
+    }
+
+  return plugin;
+}
+
+
+/******************************************
+ ************* non RT stuff ***************
+ ******************************************/
+
+
+static int
+plugin_open_plugin (plugin_desc_t * desc,
+                    void ** dl_handle_ptr,
+                    const LADSPA_Descriptor ** descriptor_ptr)
+{
+  void * dl_handle;
+  const char * dlerr;
+  LADSPA_Descriptor_Function get_descriptor;
+    
+  /* open the object file */
+  dl_handle = dlopen (desc->object_file, RTLD_NOW|RTLD_GLOBAL);
+  if (!dl_handle)
+    {
+      fprintf (stderr, "%s: error opening shared object file '%s': %s\n",
+               __FUNCTION__, desc->object_file, dlerror());
+      return 1;
+    }
+  
+  
+  /* get the get_descriptor function */
+  dlerror (); /* clear the error report */
+  
+  get_descriptor = (LADSPA_Descriptor_Function)
+    dlsym (dl_handle, "ladspa_descriptor");
+  
+  dlerr = dlerror();
+  if (dlerr)
+    {
+      fprintf (stderr, "%s: error finding descriptor symbol in object file '%s': %s\n",
+               __FUNCTION__, desc->object_file, dlerr);
+      dlclose (dl_handle);
+      return 1;
+    }
+  
+  *descriptor_ptr = get_descriptor (desc->index);
+  *dl_handle_ptr = dl_handle;
+  
+  return 0;
+}
+
+static int
+plugin_instantiate (const LADSPA_Descriptor * descriptor,
+                    unsigned long plugin_index,
+                    gint copies,
+                    LADSPA_Handle * instances)
+{
+  gint i;
+  
+  for (i = 0; i < copies; i++)
+    {
+      instances[i] = descriptor->instantiate (descriptor, sample_rate);
+      
+      if (!instances[i])
+        {
+          unsigned long d;
+          for (d = 0; d < i; d++)
+            descriptor->cleanup (instances[d]);
+          
+          return 1;
+        }
+    }
+  
+  return 0;
+}
+
+static void
+plugin_create_aux_ports (plugin_t * plugin, guint copy, jack_rack_t * jack_rack)
+{
+  plugin_desc_t * desc;
+//  plugin_slot_t * slot;
+  unsigned long aux_channel = 1;
+  unsigned long plugin_index = 1;
+  unsigned long i;
+  char port_name[64];
+  char * plugin_name;
+  char * ptr;
+//  GList * list;
+  ladspa_holder_t * holder;
+  
+  desc = plugin->desc;
+  holder = plugin->holders + copy;
+  
+  holder->aux_ports = g_malloc (sizeof (jack_port_t *) * desc->aux_channels);
+  
+  /* make the plugin name jack worthy */
+  ptr = plugin_name = g_strndup (plugin->desc->name, 7);
+  while (*ptr != '\0')
+    {
+      if (*ptr == ' ')
+        *ptr = '_';
+      else
+        *ptr = tolower (*ptr);
+      
+      ptr++;
+    }
+
+/*     
+  for (list = jack_rack->slots; list; list = g_list_next (list))
+    {
+      slot = (plugin_slot_t *) list->data;
+      
+      if (slot->plugin->desc->id == plugin->desc->id)
+        plugin_index++;
+    }
+*/
+      
+  for (i = 0; i < desc->aux_channels; i++, aux_channel++)
+    {
+      sprintf (port_name, "%s_%ld-%d_%c%ld",
+               plugin_name,
+               plugin_index,
+               copy + 1,
+               desc->aux_are_input ? 'i' : 'o',
+               aux_channel);
+      
+      holder->aux_ports[i] =
+        jack_port_register (jack_rack->ui->procinfo->jack_client,
+                            port_name,
+                            JACK_DEFAULT_AUDIO_TYPE,
+                            desc->aux_are_input ? JackPortIsInput : JackPortIsOutput,
+                            0);
+      
+      if (!holder->aux_ports[i])
+        {
+          fprintf (stderr, "Could not register jack port '%s'; aborting\n", port_name);
+          abort ();
+        }
+    }
+  
+  g_free (plugin_name);
+}
+
+static LADSPA_Data unused_control_port_output;
+
+static void
+plugin_init_holder (plugin_t * plugin,
+                    guint copy,
+                    LADSPA_Handle instance,
+                    jack_rack_t * jack_rack)
+{
+  unsigned long i;
+  plugin_desc_t * desc;
+  ladspa_holder_t * holder;
+  
+  desc = plugin->desc;
+  holder = plugin->holders + copy;
+  
+  holder->instance = instance;
+  
+  if (desc->control_port_count > 0)
+    {
+      holder->ui_control_fifos    = g_malloc (sizeof (lff_t) * desc->control_port_count);
+      holder->control_memory = g_malloc (sizeof (LADSPA_Data) * desc->control_port_count);
+    }
+  else
+    {
+      holder->ui_control_fifos  = NULL;
+      holder->control_memory = NULL;
+    }
+  
+  for (i = 0; i < desc->control_port_count; i++)
+    {
+      lff_init (holder->ui_control_fifos + i, CONTROL_FIFO_SIZE, sizeof (LADSPA_Data));
+      holder->control_memory[i] =
+        plugin_desc_get_default_control_value (desc, desc->control_port_indicies[i], sample_rate);        
+      
+      plugin->descriptor->
+        connect_port (instance, desc->control_port_indicies[i], holder->control_memory + i);
+    }
+  
+  for (i = 0; i < desc->port_count; i++)
+    {
+      if (!LADSPA_IS_PORT_CONTROL (desc->port_descriptors[i]))
+        continue;
+      
+      if (LADSPA_IS_PORT_OUTPUT (desc->port_descriptors[i]))
+        plugin->descriptor-> connect_port (instance, i, &unused_control_port_output);
+    }
+  
+  if (plugin->desc->aux_channels > 0)
+    plugin_create_aux_ports (plugin, copy, jack_rack);
+  
+  if (plugin->descriptor->activate)
+    plugin->descriptor->activate (instance);
+}
+
+
+plugin_t *
+plugin_new (plugin_desc_t * desc, jack_rack_t * jack_rack)
+{
+  void * dl_handle;
+  const LADSPA_Descriptor * descriptor;
+  LADSPA_Handle * instances;
+  gint copies;
+  unsigned long i;
+  int err;
+  plugin_t * plugin;
+  
+  /* open the plugin */
+  err = plugin_open_plugin (desc, &dl_handle, &descriptor);
+  if (err)
+    return NULL;
+
+  /* create the instances */
+  copies = plugin_desc_get_copies (desc, jack_rack->channels);
+  instances = g_malloc (sizeof (LADSPA_Handle) * copies);
+
+  err = plugin_instantiate (descriptor, desc->index, copies, instances);
+  if (err)
+    {
+      g_free (instances);
+      dlclose (dl_handle);
+      return NULL;
+    }
+  
+
+  plugin = g_malloc (sizeof (plugin_t));
+  
+  plugin->descriptor = descriptor;
+  plugin->dl_handle = dl_handle;
+  plugin->desc = desc;
+  plugin->copies = copies;
+  plugin->enabled = FALSE;
+  plugin->next = NULL;
+  plugin->prev = NULL;
+  plugin->wet_dry_enabled = FALSE;
+  
+  /* create audio memory and wet/dry stuff */
+  plugin->audio_output_memory   = g_malloc (sizeof (LADSPA_Data *) * jack_rack->channels);
+  plugin->wet_dry_fifos  = g_malloc (sizeof (lff_t) * jack_rack->channels);
+  plugin->wet_dry_values = g_malloc (sizeof (LADSPA_Data) * jack_rack->channels);
+  
+  for (i = 0; i < jack_rack->channels; i++)
+    {
+      plugin->audio_output_memory[i] = g_malloc (sizeof (LADSPA_Data) * buffer_size);
+      lff_init (plugin->wet_dry_fifos + i, CONTROL_FIFO_SIZE, sizeof (LADSPA_Data));
+      plugin->wet_dry_values[i] = 1.0;
+    }
+  
+  /* create holders and fill them out */
+  plugin->holders = g_malloc (sizeof (ladspa_holder_t) * copies);
+  for (i = 0; i < copies; i++)
+    plugin_init_holder (plugin, i, instances[i], jack_rack);
+  
+  return plugin;
+}
+
+
+void
+plugin_destroy (plugin_t * plugin, ui_t *ui)
+{
+  unsigned long i, j;
+  int err;
+
+  /* destroy holders */
+  for (i = 0; i < plugin->copies; i++)
+    {
+      if (plugin->descriptor->deactivate)
+        plugin->descriptor->deactivate (plugin->holders[i].instance);
+      
+/*      if (plugin->descriptor->cleanup)
+        plugin->descriptor->cleanup (plugin->holders[i].instance); */
+      
+      if (plugin->desc->control_port_count > 0)
+        {
+          for (j = 0; j < plugin->desc->control_port_count; j++)
+            {
+              lff_free (plugin->holders[i].ui_control_fifos + j);
+            }
+          g_free (plugin->holders[i].ui_control_fifos);
+          g_free (plugin->holders[i].control_memory);
+        }
+      
+      /* aux ports */
+      if (plugin->desc->aux_channels > 0)
+        {
+          for (j = 0; j < plugin->desc->aux_channels; j++)
+            {
+              err = jack_port_unregister (ui->procinfo->jack_client,
+                                          plugin->holders[i].aux_ports[j]);
+          
+              if (err)
+                fprintf (stderr, "%s: could not unregister jack port\n", __FUNCTION__);
+            }
+       
+          g_free (plugin->holders[i].aux_ports);
+        }
+    }
+    
+  g_free (plugin->holders);
+  
+  for (i = 0; i < ui->jack_rack->channels; i++)
+    {
+      g_free (plugin->audio_output_memory[i]);
+      lff_free (plugin->wet_dry_fifos + i);
+    }
+    
+  g_free (plugin->audio_output_memory);
+  g_free (plugin->wet_dry_fifos);
+  g_free (plugin->wet_dry_values);
+  
+  err = dlclose (plugin->dl_handle);
+  if (err)
+    {
+      fprintf (stderr, "%s: error closing shared object '%s': %s\n",
+               __FUNCTION__, plugin->desc->object_file, dlerror ());
+    }
+   
+  g_free (plugin);
+}
+
+
+/* EOF */
diff --git a/src/modules/jackrack/plugin.h b/src/modules/jackrack/plugin.h
new file mode 100644 (file)
index 0000000..ddead6e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_PLUGIN_H__
+#define __JR_PLUGIN_H__
+
+#include <glib.h>
+#include <ladspa.h>
+#include <jack/jack.h>
+
+#include "process.h"
+#include "plugin_desc.h"
+
+typedef struct _ladspa_holder ladspa_holder_t;
+typedef struct _plugin plugin_t;
+
+struct _ladspa_holder
+{
+  LADSPA_Handle instance;
+  lff_t * ui_control_fifos;
+  LADSPA_Data * control_memory;
+
+  jack_port_t **             aux_ports;
+};
+
+struct _plugin
+{
+  plugin_desc_t *            desc;
+  gint                       enabled;
+
+  gint                       copies;
+  ladspa_holder_t *          holders;
+  LADSPA_Data **             audio_input_memory;
+  LADSPA_Data **             audio_output_memory;
+  
+  gboolean                   wet_dry_enabled;
+  /* 1.0 = all wet, 0.0 = all dry, 0.5 = 50% wet/50% dry */
+  LADSPA_Data *              wet_dry_values;
+  lff_t *                    wet_dry_fifos;
+  
+  plugin_t *                 next;
+  plugin_t *                 prev;
+
+  const LADSPA_Descriptor *  descriptor;
+  void *                     dl_handle;
+  
+};
+
+void       process_add_plugin            (process_info_t *, plugin_t *plugin);
+plugin_t * process_remove_plugin         (process_info_t *, plugin_t *plugin);
+void       process_ablise_plugin         (process_info_t *, plugin_t *plugin, gboolean able);
+void       process_ablise_plugin_wet_dry (process_info_t *, plugin_t *plugin, gboolean enable);
+void       process_move_plugin           (process_info_t *, plugin_t *plugin, gint up);
+plugin_t * process_change_plugin         (process_info_t *, plugin_t *plugin, plugin_t * new_plugin);
+
+struct _jack_rack;
+struct _ui;
+
+plugin_t * plugin_new (plugin_desc_t * plugin_desc, struct _jack_rack * jack_rack);
+void       plugin_destroy (plugin_t * plugin, struct _ui *ui);
+
+void plugin_connect_input_ports (plugin_t * plugin, LADSPA_Data ** inputs);
+void plugin_connect_output_ports (plugin_t * plugin);
+
+#endif /* __JR_PLUGIN_H__ */
diff --git a/src/modules/jackrack/plugin_desc.c b/src/modules/jackrack/plugin_desc.c
new file mode 100644 (file)
index 0000000..1dfea31
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+
+#include "plugin_desc.h"
+#include "plugin.h"
+
+#define set_string_property(property, value) \
+  \
+  if (property) \
+    g_free (property); \
+  \
+  if (value) \
+    (property) = g_strdup (value); \
+  else \
+    (property) = NULL;
+
+
+void
+plugin_desc_set_ports (plugin_desc_t * pd,
+                       unsigned long port_count,
+                      const LADSPA_PortDescriptor * port_descriptors,
+                       const LADSPA_PortRangeHint * port_range_hints,
+                       const char * const * port_names);
+
+
+
+static void
+plugin_desc_init (plugin_desc_t * pd)
+{
+  pd->object_file      = NULL;
+  pd->id               = 0;
+  pd->name             = NULL;
+  pd->properties       = 0;
+  pd->channels         = 0;
+  pd->port_count       = 0;
+  pd->port_descriptors = NULL;
+  pd->port_range_hints = NULL;
+  pd->audio_input_port_indicies = NULL;
+  pd->audio_output_port_indicies = NULL;
+  pd->audio_aux_port_indicies = NULL;
+  pd->control_port_count = 0;
+  pd->control_port_indicies = NULL;
+  pd->aux_channels = 0;
+  pd->aux_are_input = TRUE;
+}
+
+static void
+plugin_desc_free_ports (plugin_desc_t * pd)
+{
+  if (pd->port_count)
+    {
+      g_free (pd->port_descriptors);
+      g_free (pd->port_range_hints);
+      pd->port_descriptors = NULL;
+      pd->port_range_hints = NULL;
+      pd->port_count = 0;
+    }
+}
+
+static void
+plugin_desc_free (plugin_desc_t * pd)
+{
+  plugin_desc_set_object_file (pd, NULL);
+  plugin_desc_set_name        (pd, NULL);
+  plugin_desc_free_ports      (pd);
+}
+
+plugin_desc_t *
+plugin_desc_new ()
+{
+  plugin_desc_t * pd;
+  pd = g_malloc (sizeof (plugin_desc_t));
+  plugin_desc_init (pd);
+  return pd;
+}
+
+plugin_desc_t *
+plugin_desc_new_with_descriptor (const char * object_file,
+                                 unsigned long index,
+                                 const LADSPA_Descriptor * descriptor)
+{
+  plugin_desc_t * pd;
+  pd = plugin_desc_new ();
+  
+  plugin_desc_set_object_file (pd, object_file);
+  plugin_desc_set_index       (pd, index);
+  plugin_desc_set_id          (pd, descriptor->UniqueID);
+  plugin_desc_set_name        (pd, descriptor->Name);
+  plugin_desc_set_properties  (pd, descriptor->Properties);
+  plugin_desc_set_ports       (pd,
+                               descriptor->PortCount,
+                               descriptor->PortDescriptors,
+                               descriptor->PortRangeHints,
+                               descriptor->PortNames);
+  
+  pd->rt = LADSPA_IS_HARD_RT_CAPABLE(pd->properties) ? TRUE : FALSE;
+
+  return pd;
+}
+
+void
+plugin_desc_destroy (plugin_desc_t * pd)
+{
+  plugin_desc_free (pd);
+  g_free (pd);
+}
+
+void
+plugin_desc_set_object_file (plugin_desc_t * pd, const char * object_file)
+{
+  set_string_property (pd->object_file, object_file);
+}
+
+void
+plugin_desc_set_index          (plugin_desc_t * pd, unsigned long index)
+{
+  pd->index = index;
+}
+
+
+void
+plugin_desc_set_id          (plugin_desc_t * pd, unsigned long id)
+{
+  pd->id = id;
+}
+
+void
+plugin_desc_set_name        (plugin_desc_t * pd, const char * name)
+{
+  set_string_property (pd->name, name);
+}
+
+void
+plugin_desc_set_properties  (plugin_desc_t * pd, LADSPA_Properties properties)
+{
+  pd->properties = properties;
+}
+
+static void
+plugin_desc_add_audio_port_index (unsigned long ** indicies,
+                                  unsigned long * current_port_count,
+                                  unsigned long index)
+{
+  (*current_port_count)++;
+  
+  if (*current_port_count == 1)
+    *indicies = g_malloc (sizeof (unsigned long) * *current_port_count);
+  else
+    *indicies = g_realloc (*indicies, sizeof (unsigned long) * *current_port_count);
+  
+  (*indicies)[*current_port_count - 1] = index;
+}
+
+static void
+plugin_desc_set_port_counts (plugin_desc_t * pd)
+{
+  unsigned long i;
+  unsigned long icount = 0;
+  unsigned long ocount = 0;
+  
+  for (i = 0; i < pd->port_count; i++)
+    {
+      if (LADSPA_IS_PORT_AUDIO (pd->port_descriptors[i]))
+        {
+          if (LADSPA_IS_PORT_INPUT (pd->port_descriptors[i]))
+            plugin_desc_add_audio_port_index (&pd->audio_input_port_indicies, &icount, i);
+          else
+            plugin_desc_add_audio_port_index (&pd->audio_output_port_indicies, &ocount, i);
+        }
+      else
+        {
+          if (LADSPA_IS_PORT_OUTPUT (pd->port_descriptors[i]))
+            continue;
+            
+          pd->control_port_count++;
+          if (pd->control_port_count == 1)
+            pd->control_port_indicies = g_malloc (sizeof (unsigned long) * pd->control_port_count);
+          else
+            pd->control_port_indicies = g_realloc (pd->control_port_indicies,
+                                                   sizeof (unsigned long) * pd->control_port_count);
+          
+          pd->control_port_indicies[pd->control_port_count - 1] = i;
+        }
+    }
+  
+  if (icount == ocount)
+    pd->channels = icount;
+  else
+    { /* deal with auxilliary ports */
+      unsigned long ** port_indicies;
+      unsigned long port_count;
+      unsigned long i, j;
+      
+      if (icount > ocount)
+        {
+          pd->channels = ocount;
+          pd->aux_channels = icount - ocount;
+          pd->aux_are_input = TRUE;
+          port_indicies = &pd->audio_input_port_indicies;
+          port_count = icount;
+        }
+      else
+        {
+          pd->channels = icount;
+          pd->aux_channels = ocount - icount;
+          pd->aux_are_input = FALSE;
+          port_indicies = &pd->audio_output_port_indicies;
+          port_count = ocount;
+        }
+      
+      /* allocate indicies */
+      pd->audio_aux_port_indicies = g_malloc (sizeof (unsigned long) * pd->aux_channels);
+      
+      /* copy indicies */
+      for (i = pd->channels, j = 0; i < port_count; i++, j++)
+        pd->audio_aux_port_indicies[j] = (*port_indicies)[i];
+      
+      /* shrink the main indicies to only have channels indicies */
+      *port_indicies = g_realloc (*port_indicies, sizeof (unsigned long) * pd->channels);
+    }
+}
+
+void
+plugin_desc_set_ports (plugin_desc_t * pd,
+                       unsigned long port_count,
+                       const LADSPA_PortDescriptor * port_descriptors,
+                       const LADSPA_PortRangeHint * port_range_hints,
+                       const char * const * port_names)
+{
+  unsigned long i;
+
+  plugin_desc_free_ports (pd);
+  
+  if (!port_count)
+    return;
+  
+  pd->port_count = port_count;
+  pd->port_descriptors = g_malloc (sizeof (LADSPA_PortDescriptor) * port_count);
+  pd->port_range_hints = g_malloc (sizeof (LADSPA_PortRangeHint) * port_count);
+  pd->port_names       = g_malloc (sizeof (char *) * port_count);
+  
+  memcpy (pd->port_descriptors, port_descriptors, sizeof (LADSPA_PortDescriptor) * port_count);
+  memcpy (pd->port_range_hints, port_range_hints, sizeof (LADSPA_PortRangeHint) * port_count);
+  
+  for (i = 0; i < port_count; i++)
+    pd->port_names[i] = g_strdup (port_names[i]);
+  
+  plugin_desc_set_port_counts (pd);
+}
+
+
+LADSPA_Data
+plugin_desc_get_default_control_value (plugin_desc_t * pd, unsigned long port_index, guint32 sample_rate)
+{
+  LADSPA_Data upper, lower;
+  LADSPA_PortRangeHintDescriptor hint_descriptor;
+  
+  hint_descriptor = pd->port_range_hints[port_index].HintDescriptor;
+  
+  /* set upper and lower, possibly adjusted to the sample rate */
+  if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) {
+    upper = pd->port_range_hints[port_index].UpperBound * (LADSPA_Data) sample_rate;
+    lower = pd->port_range_hints[port_index].LowerBound * (LADSPA_Data) sample_rate;
+  } else {
+    upper = pd->port_range_hints[port_index].UpperBound;
+    lower = pd->port_range_hints[port_index].LowerBound;
+  }
+  
+  if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor))
+    {
+      if (lower < FLT_EPSILON)
+        lower = FLT_EPSILON;
+    }
+    
+
+  if (LADSPA_IS_HINT_HAS_DEFAULT(hint_descriptor)) {
+      
+           if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) {
+    
+      return lower;
+       
+    } else if (LADSPA_IS_HINT_DEFAULT_LOW(hint_descriptor)) {
+        
+      if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) {
+        return exp(log(lower) * 0.75 + log(upper) * 0.25);
+      } else {
+        return lower * 0.75 + upper * 0.25;
+      }
+
+    } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) {
+        
+      if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) {
+        return exp(log(lower) * 0.5 + log(upper) * 0.5);
+      } else {
+        return lower * 0.5 + upper * 0.5;
+      }
+
+    } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint_descriptor)) {
+      
+      if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) {
+        return exp(log(lower) * 0.25 + log(upper) * 0.75);
+      } else {
+        return lower * 0.25 + upper * 0.75;
+      }
+      
+    } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) {
+      
+      return upper;
+    
+    } else if (LADSPA_IS_HINT_DEFAULT_0(hint_descriptor)) {
+      
+      return 0.0;
+      
+    } else if (LADSPA_IS_HINT_DEFAULT_1(hint_descriptor)) {
+      
+      if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) {
+        return (LADSPA_Data) sample_rate;
+      } else {
+        return 1.0;
+      }
+      
+    } else if (LADSPA_IS_HINT_DEFAULT_100(hint_descriptor)) {
+      
+      if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) {
+        return 100.0 * (LADSPA_Data) sample_rate;
+      } else {
+        return 100.0;
+      }
+      
+    } else if (LADSPA_IS_HINT_DEFAULT_440(hint_descriptor)) {
+      
+      if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) {
+        return 440.0 * (LADSPA_Data) sample_rate;
+      } else {
+        return 440.0;
+      }
+      
+    }  
+      
+  } else { /* try and find a reasonable default */
+        
+           if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) {
+      return lower;
+    } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) {
+      return upper;
+    }
+  }
+
+  return 0.0;
+}
+
+LADSPA_Data
+plugin_desc_change_control_value (plugin_desc_t * pd,
+                                  unsigned long control_index,
+                                  LADSPA_Data value,
+                                  guint32 old_sample_rate,
+                                  guint32 new_sample_rate)
+{
+  
+  if (LADSPA_IS_HINT_SAMPLE_RATE (pd->port_range_hints[control_index].HintDescriptor))
+    {
+      LADSPA_Data old_sr, new_sr;
+  
+      old_sr = (LADSPA_Data) old_sample_rate;
+      new_sr = (LADSPA_Data) new_sample_rate;
+  
+      value /= old_sr;
+      value *= new_sr;
+    }
+  
+  return value;
+}
+
+gint
+plugin_desc_get_copies (plugin_desc_t * pd, unsigned long rack_channels)
+{
+  gint copies = 1;
+  
+  if (pd->channels > rack_channels)
+    return 0;
+  
+  while (pd->channels * copies < rack_channels)
+    copies++;
+  
+  if (pd->channels * copies > rack_channels)
+    return 0;
+  
+  return copies;
+}
+
+/* EOF */
diff --git a/src/modules/jackrack/plugin_desc.h b/src/modules/jackrack/plugin_desc.h
new file mode 100644 (file)
index 0000000..c9198d0
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_PLUGIN_DESC_H__
+#define __JR_PLUGIN_DESC_H__
+
+#include <ladspa.h>
+#include <glib.h>
+
+typedef struct _plugin_desc plugin_desc_t;
+
+struct _plugin_desc
+{
+  char *                   object_file;
+  unsigned long            index;
+  unsigned long            id;
+  char *                   name;
+  LADSPA_Properties        properties;
+  gboolean                 rt;
+  
+  unsigned long            channels;
+  
+  gboolean                 aux_are_input;
+  unsigned long            aux_channels;
+
+  unsigned long            port_count;
+  LADSPA_PortDescriptor *  port_descriptors;
+  LADSPA_PortRangeHint *   port_range_hints;
+  char **                  port_names;
+  
+  unsigned long *          audio_input_port_indicies;
+  unsigned long *          audio_output_port_indicies;
+  
+  unsigned long *          audio_aux_port_indicies;
+
+  unsigned long            control_port_count;
+  unsigned long *          control_port_indicies;
+};
+
+plugin_desc_t * plugin_desc_new ();
+plugin_desc_t * plugin_desc_new_with_descriptor (const char * object_file,
+                                                 unsigned long index,
+                                                 const LADSPA_Descriptor * descriptor);
+void            plugin_desc_destroy ();
+
+void plugin_desc_set_object_file (plugin_desc_t * pd, const char * object_file);
+void plugin_desc_set_index       (plugin_desc_t * pd, unsigned long index);
+void plugin_desc_set_id          (plugin_desc_t * pd, unsigned long id);
+void plugin_desc_set_name        (plugin_desc_t * pd, const char * name);
+void plugin_desc_set_properties  (plugin_desc_t * pd, LADSPA_Properties properties);
+
+struct _plugin * plugin_desc_instantiate (plugin_desc_t * pd);
+
+LADSPA_Data plugin_desc_get_default_control_value (plugin_desc_t * pd, unsigned long port_index, guint32 sample_rate);
+LADSPA_Data plugin_desc_change_control_value (plugin_desc_t *, unsigned long, LADSPA_Data, guint32, guint32);
+
+gint plugin_desc_get_copies (plugin_desc_t * pd, unsigned long rack_channels);
+
+#endif /* __JR_PLUGIN_DESC_H__ */
diff --git a/src/modules/jackrack/plugin_mgr.c b/src/modules/jackrack/plugin_mgr.c
new file mode 100644 (file)
index 0000000..b666e35
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *   jack-ladspa-host
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <math.h>
+#include <strings.h>
+#include <ctype.h>
+#include <ladspa.h>
+
+#include "plugin_mgr.h"
+#include "plugin_desc.h"
+#include "ui.h"
+
+
+static gboolean
+plugin_is_valid (const LADSPA_Descriptor * descriptor)
+{
+  unsigned long i;
+  unsigned long icount = 0;
+  unsigned long ocount = 0;
+  
+  for (i = 0; i < descriptor->PortCount; i++)
+    {
+      if (!LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[i]))
+        continue;
+      
+      if (LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[i]))
+        icount++;
+      else
+        ocount++;
+    }
+  
+  if (icount == 0 || ocount == 0)
+    return FALSE;
+  
+  return TRUE;
+}
+
+static void
+plugin_mgr_get_object_file_plugins (ui_t * ui, plugin_mgr_t * plugin_mgr, const char * filename)
+{
+  const char * dlerr;
+  void * dl_handle;
+  LADSPA_Descriptor_Function get_descriptor;
+  const LADSPA_Descriptor * descriptor;
+  unsigned long plugin_index;
+  plugin_desc_t * desc, * other_desc = NULL;
+  GSList * list;
+  gboolean exists;
+  int err;
+  
+  /* open the object file */
+  dl_handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
+  if (!dl_handle)
+    {
+      fprintf (stderr, "%s: error opening shared object file '%s': %s\n",
+               __FUNCTION__, filename, dlerror());
+      return;
+    }
+  
+  
+  /* get the get_descriptor function */
+  dlerror (); /* clear the error report */
+  
+  get_descriptor = (LADSPA_Descriptor_Function)
+    dlsym (dl_handle, "ladspa_descriptor");
+  
+  dlerr = dlerror();
+  if (dlerr) {
+    fprintf (stderr, "%s: error finding ladspa_descriptor symbol in object file '%s': %s\n",
+             __FUNCTION__, filename, dlerr);
+    dlclose (dl_handle);
+    return;
+  }
+  
+  plugin_index = 0;
+  while ( (descriptor = get_descriptor (plugin_index)) )
+    {
+      if (!plugin_is_valid (descriptor))
+        {
+          plugin_index++;
+          continue;
+        }
+
+      
+      /* check it doesn't already exist */
+      exists = FALSE;
+      for (list = plugin_mgr->all_plugins; list; list = g_slist_next (list))
+        {
+          other_desc = (plugin_desc_t *) list->data;
+          
+          if (other_desc->id == descriptor->UniqueID)
+            {
+              exists = TRUE;
+              break;
+            }
+        }
+      
+      if (exists)
+        {
+          printf ("Plugin %ld exists in both '%s' and '%s'; using version in '%s'\n",
+                  descriptor->UniqueID, other_desc->object_file, filename, other_desc->object_file);
+          plugin_index++;
+          continue;
+        }
+
+      
+      desc = plugin_desc_new_with_descriptor (filename, plugin_index, descriptor);
+      plugin_mgr->all_plugins = g_slist_append (plugin_mgr->all_plugins, desc);
+      plugin_index++;
+      plugin_mgr->plugin_count++;
+      
+      /* print in the splash screen */
+      /* printf ("Loaded plugin '%s'\n", desc->name); */
+    }
+  
+  err = dlclose (dl_handle);
+  if (err)
+    {
+      fprintf (stderr, "%s: error closing object file '%s': %s\n",
+               __FUNCTION__, filename, dlerror ());
+    }
+}
+
+static void
+plugin_mgr_get_dir_plugins (ui_t * ui, plugin_mgr_t * plugin_mgr, const char * dir)
+{
+  DIR * dir_stream;
+  struct dirent * dir_entry;
+  char * file_name;
+  int err;
+  size_t dirlen;
+  
+  dir_stream = opendir (dir);
+  if (!dir_stream)
+    {
+/*      fprintf (stderr, "%s: error opening directory '%s': %s\n",
+               __FUNCTION__, dir, strerror (errno)); */
+      return;
+    }
+  
+  dirlen = strlen (dir);
+  
+  while ( (dir_entry = readdir (dir_stream)) )
+    {
+      if (strcmp (dir_entry->d_name, ".") == 0 ||
+          strcmp (dir_entry->d_name, "..") == 0)
+        continue;
+  
+      file_name = g_malloc (dirlen + 1 + strlen (dir_entry->d_name) + 1);
+    
+      strcpy (file_name, dir);
+      if (file_name[dirlen - 1] == '/')
+        strcpy (file_name + dirlen, dir_entry->d_name);
+      else
+        {
+          file_name[dirlen] = '/';
+          strcpy (file_name + dirlen + 1, dir_entry->d_name);
+        }
+    
+      plugin_mgr_get_object_file_plugins (ui, plugin_mgr, file_name);
+      
+      g_free (file_name);
+    }
+
+  err = closedir (dir_stream);
+  if (err)
+    fprintf (stderr, "%s: error closing directory '%s': %s\n",
+             __FUNCTION__, dir, strerror (errno));
+}
+
+static void
+plugin_mgr_get_path_plugins (ui_t * ui, plugin_mgr_t * plugin_mgr)
+{
+  char * ladspa_path, * dir;
+  
+  ladspa_path = g_strdup (getenv ("LADSPA_PATH"));
+  if (!ladspa_path)
+    ladspa_path = g_strdup ("/usr/local/lib/ladspa:/usr/lib/ladspa");
+  
+  dir = strtok (ladspa_path, ":");
+  do
+    plugin_mgr_get_dir_plugins (ui, plugin_mgr, dir);
+  while ((dir = strtok (NULL, ":")));
+
+  g_free (ladspa_path);
+}
+
+static gint
+plugin_mgr_sort (gconstpointer a, gconstpointer b)
+{
+  const plugin_desc_t * da;
+  const plugin_desc_t * db;
+  da = (const plugin_desc_t *) a;
+  db = (const plugin_desc_t *) b;
+  
+  return strcasecmp (da->name, db->name);
+}
+
+plugin_mgr_t *
+plugin_mgr_new (ui_t * ui)
+{
+  plugin_mgr_t * pm;
+  
+  pm = g_malloc (sizeof (plugin_mgr_t));
+  pm->all_plugins = NULL;  
+  pm->plugins = NULL;
+  pm->plugin_count = 0;
+  
+  plugin_mgr_get_path_plugins (ui, pm);
+  
+  if (!pm->all_plugins)
+    {
+      fprintf (stderr, "No LADSPA plugins were found!\n\nCheck your LADSPA_PATH environment variable.\n");
+      abort ();
+    }
+  
+  pm->all_plugins = g_slist_sort (pm->all_plugins, plugin_mgr_sort);
+  
+  return pm;
+}
+
+void
+plugin_mgr_destroy (plugin_mgr_t * plugin_mgr)
+{
+  GSList * list;
+  
+  for (list = plugin_mgr->all_plugins; list; list = g_slist_next (list))
+    plugin_desc_destroy ((plugin_desc_t *) list->data);
+  
+  g_slist_free (plugin_mgr->plugins);
+  g_slist_free (plugin_mgr->all_plugins);
+  free (plugin_mgr);
+}
+
+
+void
+plugin_mgr_set_plugins (plugin_mgr_t * plugin_mgr, unsigned long rack_channels)
+{
+  GSList * list;
+  plugin_desc_t * desc;
+
+  /* clear the current plugins */
+  g_slist_free (plugin_mgr->plugins);
+  plugin_mgr->plugins = NULL;
+  
+  for (list = plugin_mgr->all_plugins; list; list = g_slist_next (list))
+    {
+      desc = (plugin_desc_t *) list->data;
+      
+      if (plugin_desc_get_copies (desc, rack_channels) != 0)
+        plugin_mgr->plugins = g_slist_append (plugin_mgr->plugins, desc);
+    }
+}
+
+static plugin_desc_t *
+plugin_mgr_find_desc (plugin_mgr_t * plugin_mgr, GSList * plugins, unsigned long id)
+{
+  GSList * list;
+  plugin_desc_t * desc;
+  
+  for (list = plugins; list; list = g_slist_next (list))
+    {
+      desc = (plugin_desc_t *) list->data;
+      
+      if (desc->id == id)
+        return desc;
+    }
+  
+  return NULL;
+}
+
+plugin_desc_t *
+plugin_mgr_get_desc (plugin_mgr_t * plugin_mgr, unsigned long id)
+{
+  return plugin_mgr_find_desc (plugin_mgr, plugin_mgr->plugins, id);
+}
+
+plugin_desc_t *
+plugin_mgr_get_any_desc (plugin_mgr_t * plugin_mgr, unsigned long id)
+{
+  return plugin_mgr_find_desc (plugin_mgr, plugin_mgr->all_plugins, id);
+}
+
+
+/* EOF */
diff --git a/src/modules/jackrack/plugin_mgr.h b/src/modules/jackrack/plugin_mgr.h
new file mode 100644 (file)
index 0000000..9a3f8dc
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_PLUGIN_MANAGER_H__
+#define __JR_PLUGIN_MANAGER_H__
+
+#include <glib.h>
+
+#include "plugin_desc.h"
+
+typedef struct _plugin_mgr plugin_mgr_t;
+
+struct _plugin_mgr
+{
+  GSList * all_plugins;
+
+  GSList * plugins;
+  unsigned long plugin_count;
+};
+
+struct _ui;
+
+plugin_mgr_t * plugin_mgr_new (struct _ui * ui);
+void           plugin_mgr_destroy (plugin_mgr_t * plugin_mgr);
+
+void plugin_mgr_set_plugins (plugin_mgr_t * plugin_mgr, unsigned long rack_channels);
+
+plugin_desc_t * plugin_mgr_get_desc (plugin_mgr_t * plugin_mgr, unsigned long id);
+plugin_desc_t * plugin_mgr_get_any_desc (plugin_mgr_t * plugin_mgr, unsigned long id);
+
+#endif /* __JR_PLUGIN_MANAGER_H__ */
diff --git a/src/modules/jackrack/plugin_settings.c b/src/modules/jackrack/plugin_settings.c
new file mode 100644 (file)
index 0000000..68c277c
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+
+#include <math.h>
+
+#include "plugin_settings.h"
+
+
+static void
+settings_set_to_default (settings_t * settings, guint32 sample_rate)
+{
+  unsigned long control;
+  guint copy;
+  LADSPA_Data value;
+  
+  for (control = 0; control < settings->desc->control_port_count; control++)
+    {
+      value = plugin_desc_get_default_control_value (settings->desc, control, sample_rate);
+
+      for (copy = 0; copy < settings->copies; copy++)
+        {
+          settings->control_values[copy][control] = value;
+        }
+          
+      settings->locks[control] = TRUE;
+    }
+}
+
+settings_t *
+settings_new     (plugin_desc_t * desc, unsigned long channels, guint32 sample_rate)
+{
+  settings_t * settings;
+  unsigned long channel;
+  guint copies;
+  
+  settings = g_malloc (sizeof (settings_t));
+  copies = plugin_desc_get_copies (desc, channels);
+  
+  settings->sample_rate = sample_rate;
+  settings->desc = desc;
+  settings->copies = copies;
+  settings->channels = channels;
+  settings->lock_all = TRUE;
+  settings->enabled = FALSE;
+  settings->locks = NULL;
+  settings->control_values = NULL;
+  settings->wet_dry_enabled = FALSE;
+  settings->wet_dry_locked = TRUE;
+  
+  /* control settings */  
+  if (desc->control_port_count > 0)
+    {
+      guint copy;
+      
+      settings->locks = g_malloc (sizeof (gboolean) * desc->control_port_count);
+
+      settings->control_values = g_malloc (sizeof (LADSPA_Data *) * copies);
+      for (copy = 0; copy < copies; copy++)
+        {
+          settings->control_values[copy] = g_malloc (sizeof (LADSPA_Data) * desc->control_port_count);
+        }
+      
+      settings_set_to_default (settings, sample_rate);
+    }
+  
+  /* wet/dry settings */
+  settings->wet_dry_values = g_malloc (sizeof (LADSPA_Data) * channels);
+  for (channel = 0; channel < channels; channel++)
+    settings->wet_dry_values[channel] = 1.0;
+  
+  return settings;
+}
+
+settings_t *
+settings_dup     (settings_t * other)
+{
+  settings_t * settings;
+  plugin_desc_t * desc;
+  unsigned long channel;
+  
+  settings = g_malloc (sizeof (settings_t));
+  
+  settings->sample_rate     = other->sample_rate;
+  settings->desc            = other->desc;
+  settings->copies          = settings_get_copies (other);
+  settings->channels        = settings_get_channels (other);
+  settings->wet_dry_enabled = settings_get_wet_dry_enabled (other);
+  settings->wet_dry_locked  = settings_get_wet_dry_locked (other);
+  settings->lock_all        = settings_get_lock_all (other);
+  settings->enabled         = settings_get_enabled (other);
+  settings->locks           = NULL;
+  settings->control_values  = NULL;
+  
+  desc = other->desc;
+  
+  if (desc->control_port_count > 0)
+    {
+      guint copy;
+      unsigned long control;
+      
+      settings->locks = g_malloc (sizeof (gboolean) * desc->control_port_count);
+      for (control = 0; control < desc->control_port_count; control++)
+        settings_set_lock (settings, control, settings_get_lock (other, control));
+
+      settings->control_values = g_malloc (sizeof (LADSPA_Data *) * settings->copies);
+      for (copy = 0; copy < settings->copies; copy++)
+        {
+          settings->control_values[copy] = g_malloc (sizeof (LADSPA_Data) * desc->control_port_count);
+
+          for (control = 0; control < desc->control_port_count; control++)
+            {
+              settings->control_values[copy][control] = settings_get_control_value (other, copy, control);
+            }
+        }
+    }
+  
+  settings->wet_dry_values = g_malloc (sizeof (LADSPA_Data) * settings->channels);
+  for (channel = 0; channel < settings->channels; channel++)
+    settings->wet_dry_values[channel] = settings_get_wet_dry_value (other, channel);
+  
+  return settings;
+}
+
+void
+settings_destroy (settings_t * settings)
+{
+  if (settings->desc->control_port_count > 0)
+    {
+      guint i;
+      for (i = 0; i < settings->copies; i++)
+        g_free (settings->control_values[i]);
+
+      g_free (settings->control_values);
+      g_free (settings->locks);
+    }
+    
+  g_free (settings->wet_dry_values);
+  
+  g_free (settings);
+}
+
+static void
+settings_set_copies (settings_t * settings, guint copies)
+{
+  guint copy;
+  guint last_copy;
+  unsigned long control;
+  
+  if (copies <= settings->copies)
+    return;
+  
+  last_copy = settings->copies - 1;
+  
+  settings->control_values = g_realloc (settings->control_values,
+                                        sizeof (LADSPA_Data *) * copies);
+  
+  /* copy over the last settings to the new copies */
+  for (copy = settings->copies; copy < copies; copy++)
+    {
+      for (control = 0; control < settings->desc->control_port_count; control++)
+        {
+          settings->control_values[copy][control] = 
+            settings->control_values[last_copy][control];
+        }
+    }
+  
+  settings->copies = copies;
+}
+
+static void
+settings_set_channels (settings_t * settings, unsigned long channels)
+{
+  unsigned long channel;
+  LADSPA_Data last_value;
+      
+  if (channels <= settings->channels)
+    return;
+  
+  settings->wet_dry_values = g_realloc (settings->wet_dry_values, sizeof (LADSPA_Data) * channels);
+  
+  last_value = settings->wet_dry_values[settings->channels - 1];
+  
+  for (channel = settings->channels; channel < channels; channel++)
+    settings->wet_dry_values[channel] = last_value;
+  
+  settings->channels = channels;
+}
+
+void
+settings_set_sample_rate (settings_t * settings, guint32 sample_rate)
+{
+  LADSPA_Data old_sample_rate;
+  LADSPA_Data new_sample_rate;
+
+  g_return_if_fail (settings != NULL);
+  
+  if (settings->sample_rate == sample_rate)
+    return;
+  
+  if (settings->desc->control_port_count > 0)
+    {
+      unsigned long control;
+      guint copy;
+      
+      new_sample_rate = (LADSPA_Data) sample_rate;
+      old_sample_rate = (LADSPA_Data) settings->sample_rate;
+
+      for (control = 0; control < settings->desc->control_port_count; control++)
+        {
+          for (copy = 0; copy < settings->copies; copy++)
+            {
+              if (LADSPA_IS_HINT_SAMPLE_RATE (settings->desc->port_range_hints[control].HintDescriptor))
+                {
+                  settings->control_values[copy][control] =
+                    (settings->control_values[copy][control] / old_sample_rate) * new_sample_rate;
+                }
+            }
+        }
+    }
+  
+  settings->sample_rate = sample_rate;
+}
+
+void
+settings_set_control_value (settings_t * settings, guint copy, unsigned long control_index, LADSPA_Data value)
+{
+  g_return_if_fail (settings != NULL);
+  g_return_if_fail (control_index < settings->desc->control_port_count);
+  
+  if (copy >= settings->copies)
+    settings_set_copies (settings, copy + 1);
+  
+  settings->control_values[copy][control_index] = value;
+}
+
+void
+settings_set_lock          (settings_t * settings, unsigned long control_index, gboolean locked)
+{
+  g_return_if_fail (settings != NULL);
+  g_return_if_fail (control_index < settings->desc->control_port_count);
+  
+  settings->locks[control_index] = locked;
+}
+
+void
+settings_set_lock_all (settings_t * settings, gboolean lock_all)
+{
+  g_return_if_fail (settings != NULL);
+
+  settings->lock_all = lock_all;
+}
+
+void
+settings_set_enabled (settings_t * settings, gboolean enabled)
+{
+  g_return_if_fail (settings != NULL);
+
+  settings->enabled = enabled;
+}
+
+void
+settings_set_wet_dry_enabled (settings_t * settings, gboolean enabled)
+{
+  g_return_if_fail (settings != NULL);
+  
+  settings->wet_dry_enabled = enabled;
+}
+
+void
+settings_set_wet_dry_locked  (settings_t * settings, gboolean locked)
+{
+  g_return_if_fail (settings != NULL);
+  
+  settings->wet_dry_locked = locked;
+}
+
+void
+settings_set_wet_dry_value   (settings_t * settings, unsigned long channel, LADSPA_Data value)
+{
+  g_return_if_fail (settings != NULL);
+
+  if (channel >= settings->channels)
+    settings_set_channels (settings, channel + 1);
+  
+  settings->wet_dry_values[channel] = value;
+}
+
+
+LADSPA_Data
+settings_get_control_value (settings_t * settings, guint copy, unsigned long control_index)
+{
+  g_return_val_if_fail (settings != NULL, NAN);
+  g_return_val_if_fail (control_index < settings->desc->control_port_count, NAN);
+
+  if (copy >= settings->copies)
+    settings_set_copies (settings, copy - 1);
+
+  return settings->control_values[copy][control_index];
+}
+
+gboolean
+settings_get_lock          (const settings_t * settings, unsigned long control_index)
+{
+  g_return_if_fail (settings != NULL);
+  
+  return settings->locks[control_index]; 
+}
+
+gboolean
+settings_get_lock_all      (const settings_t * settings)
+{
+  g_return_if_fail (settings != NULL);
+
+  return settings->lock_all;
+}
+
+gboolean
+settings_get_enabled      (const settings_t * settings)
+{
+  g_return_if_fail (settings != NULL);
+  
+  return settings->enabled;
+}
+
+guint
+settings_get_copies        (const settings_t * settings)
+{
+  g_return_if_fail (settings != NULL);
+  
+  return settings->copies;
+}
+
+
+unsigned long
+settings_get_channels        (const settings_t * settings)
+{
+  g_return_if_fail (settings != NULL);
+  
+  return settings->channels;
+}
+
+gboolean
+settings_get_wet_dry_enabled (const settings_t * settings)
+{
+  g_return_if_fail (settings != NULL);
+
+  return settings->wet_dry_enabled;
+}
+
+gboolean
+settings_get_wet_dry_locked  (const settings_t * settings)
+{
+  g_return_if_fail (settings != NULL);
+  
+  return settings->wet_dry_locked;
+}
+
+LADSPA_Data
+settings_get_wet_dry_value   (settings_t * settings, unsigned long channel)
+{
+  g_return_if_fail (settings != NULL);
+
+  if (channel >= settings->channels)
+    settings_set_channels (settings, channel + 1);
+  
+  return settings->wet_dry_values[channel];
+}
+
+
+
+/* EOF */
diff --git a/src/modules/jackrack/plugin_settings.h b/src/modules/jackrack/plugin_settings.h
new file mode 100644 (file)
index 0000000..49d6953
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_PLUGIN_SETTINGS_H__
+#define __JR_PLUGIN_SETTINGS_H__
+
+#include <glib.h>
+#include <ladspa.h>
+
+#include "plugin_mgr.h"
+#include "plugin_desc.h"
+
+typedef struct _settings settings_t;
+
+struct _settings
+{
+  guint32   sample_rate;
+  plugin_desc_t *  desc;
+  guint            copies;
+  LADSPA_Data **   control_values;
+  gboolean *       locks;
+  gboolean         lock_all;
+  gboolean         enabled;
+  unsigned long    channels;
+  gboolean         wet_dry_enabled;
+  gboolean         wet_dry_locked;
+  LADSPA_Data *    wet_dry_values;
+};
+
+settings_t * settings_new     (plugin_desc_t * desc, unsigned long channels, guint32 sample_rate);
+settings_t * settings_dup     (settings_t * settings);
+void         settings_destroy (settings_t * settings);
+
+void settings_set_control_value   (settings_t * settings, guint copy, unsigned long control_index, LADSPA_Data value);
+void settings_set_lock            (settings_t * settings, unsigned long control_index, gboolean locked);
+void settings_set_lock_all        (settings_t * settings, gboolean lock_all);
+void settings_set_enabled         (settings_t * settings, gboolean enabled);
+void settings_set_wet_dry_enabled (settings_t * settings, gboolean enabled);
+void settings_set_wet_dry_locked  (settings_t * settings, gboolean locked);
+void settings_set_wet_dry_value   (settings_t * settings, unsigned long channel, LADSPA_Data value);
+
+LADSPA_Data   settings_get_control_value   (settings_t * settings, guint copy, unsigned long control_index);
+gboolean      settings_get_lock            (const settings_t * settings, unsigned long control_index);
+gboolean      settings_get_lock_all        (const settings_t * settings);
+gboolean      settings_get_enabled         (const settings_t * settings);
+guint         settings_get_copies          (const settings_t * settings);
+unsigned long settings_get_channels        (const settings_t * settings);
+gboolean      settings_get_wet_dry_enabled (const settings_t * settings);
+gboolean      settings_get_wet_dry_locked  (const settings_t * settings);
+LADSPA_Data   settings_get_wet_dry_value   (settings_t * settings, unsigned long channel);
+
+void settings_set_sample_rate (settings_t * settings, guint32 sample_rate);
+
+#endif /* __JR_PLUGIN_SETTINGS_H__ */
diff --git a/src/modules/jackrack/process.c b/src/modules/jackrack/process.c
new file mode 100644 (file)
index 0000000..e200642
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ *   jack-ladspa-host
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <jack/jack.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "process.h"
+#include "control_message.h"
+#include "lock_free_fifo.h"
+#include "plugin.h"
+#include "jack_rack.h"
+#include "ui.h"
+
+#ifndef _
+#define _(x) x
+#endif
+
+#define USEC_PER_SEC         1000000
+#define MSEC_PER_SEC         1000
+#define TIME_RUN_SKIP_COUNT  5
+
+jack_nframes_t sample_rate;
+jack_nframes_t buffer_size;
+
+static char * jack_client_name;
+
+int process_control_messages (process_info_t * procinfo) {
+  static int quitting = 0;
+  ctrlmsg_t ctrlmsg;
+  int err = 0;
+  
+  if (quitting) return quitting;
+  
+  while (lff_read (procinfo->ui_to_process, &ctrlmsg) == 0)
+    {
+    switch (ctrlmsg.type)
+      {
+    
+      /* add a link to the end of the plugin chain */
+      case CTRLMSG_ADD:
+        process_add_plugin (procinfo, ctrlmsg.data.add.plugin);
+        err = lff_write (procinfo->process_to_ui, &ctrlmsg);
+        break;
+        
+      /* remove a link (plugin will be sent back) */
+      case CTRLMSG_REMOVE:
+        ctrlmsg.data.remove.plugin =
+          process_remove_plugin (procinfo, ctrlmsg.data.remove.plugin);
+        err = lff_write (procinfo->process_to_ui, &ctrlmsg);
+        break;
+        
+      case CTRLMSG_QUIT:
+        quitting = 1;
+        err = lff_write (procinfo->process_to_ui, &ctrlmsg);
+        return 1;
+      }
+    
+    if (err)
+      {
+        fprintf (stderr, "%s: gui fifo is out of space\n", __FUNCTION__);
+        return err;
+      }
+      
+    }
+    
+  return 0;
+}
+
+/** process messages for plugins' control ports */
+void process_control_port_messages (process_info_t * procinfo) {
+  plugin_t * plugin;
+  unsigned long control;
+  unsigned long channel;
+  gint copy;
+  
+  if (!procinfo->chain) return;
+  
+  for (plugin = procinfo->chain; plugin; plugin = plugin->next)
+    {
+      if (plugin->desc->control_port_count > 0)
+        for (control = 0; control < plugin->desc->control_port_count; control++)
+          for (copy = 0; copy < plugin->copies; copy++)
+            {
+              while (lff_read (plugin->holders[copy].ui_control_fifos + control,
+                               plugin->holders[copy].control_memory + control) == 0);
+            }
+      
+      if (plugin->wet_dry_enabled)
+        for (channel = 0; channel < procinfo->channels; channel++)
+          {
+            while (lff_read (plugin->wet_dry_fifos + channel,
+                             plugin->wet_dry_values + channel) == 0);
+          }
+    }
+}
+
+int get_jack_buffers (process_info_t * procinfo, jack_nframes_t frames) {
+  unsigned long channel;
+  
+  for (channel = 0; channel < procinfo->channels; channel++)
+    {
+      procinfo->jack_input_buffers[channel] = jack_port_get_buffer (procinfo->jack_input_ports[channel], frames);
+      if (!procinfo->jack_input_buffers[channel])
+        {
+          fprintf (stderr, "%s: no jack buffer for input port %ld\n", __FUNCTION__, channel);
+          return 1;
+        }
+
+      procinfo->jack_output_buffers[channel] = jack_port_get_buffer (procinfo->jack_output_ports[channel], frames);
+      if (!procinfo->jack_output_buffers[channel])
+        {
+          fprintf (stderr, "%s: no jack buffer for output port %ld\n", __FUNCTION__, channel);
+          return 1;
+        }
+    }
+
+  return 0;
+}
+
+plugin_t *
+get_first_enabled_plugin (process_info_t * procinfo)
+{
+  plugin_t * first_enabled;
+  
+  if (!procinfo->chain) return NULL;
+
+  for (first_enabled = procinfo->chain;
+       first_enabled;
+       first_enabled = first_enabled->next)
+    {
+      if (first_enabled->enabled) return first_enabled;
+    }
+  return NULL;
+}
+
+plugin_t *
+get_last_enabled_plugin (process_info_t * procinfo)
+{
+  plugin_t * last_enabled;
+  
+  if (!procinfo->chain) return NULL;
+
+  for (last_enabled = procinfo->chain_end;
+       last_enabled;
+       last_enabled = last_enabled->prev)
+    {
+      if (last_enabled->enabled) return last_enabled;
+    }
+  
+  return NULL;
+}
+
+void
+connect_chain (process_info_t * procinfo, jack_nframes_t frames)
+{
+  plugin_t * first_enabled, * last_enabled, * plugin;
+  gint copy;
+  unsigned long channel;
+  if (!procinfo->chain) return;
+  
+  first_enabled = get_first_enabled_plugin (procinfo);
+  if (!first_enabled) return;
+  
+  last_enabled = get_last_enabled_plugin (procinfo);
+  
+  /* sort out the aux ports */
+  plugin = first_enabled;
+  do
+    {
+      if (plugin->desc->aux_channels > 0)
+        {
+          if (plugin->enabled)
+            for (copy = 0; copy < plugin->copies; copy++)
+              for (channel = 0; channel < plugin->desc->aux_channels; channel++)
+                plugin->descriptor->
+                  connect_port (plugin->holders[copy].instance,
+                                plugin->desc->audio_aux_port_indicies[channel],
+                                jack_port_get_buffer (plugin->holders[copy].aux_ports[channel], frames));
+        }
+      
+    }
+  while ( (plugin != last_enabled) && (plugin = plugin->next) );
+
+  /* ensure that all the of the enabled plugins are connected to their memory */
+  plugin_connect_output_ports (first_enabled);
+  if (first_enabled != last_enabled)
+    {
+      plugin_connect_input_ports (last_enabled, last_enabled->prev->audio_output_memory);
+      
+      for (plugin = first_enabled->next;
+           plugin;
+           plugin = plugin->next)
+        {
+          if (plugin->enabled)
+            {
+              plugin_connect_input_ports (plugin, plugin->prev->audio_output_memory);
+              plugin_connect_output_ports (plugin);
+            }
+        }
+    }
+
+  /* input buffers for first plugin */
+  plugin_connect_input_ports (first_enabled, procinfo->jack_input_buffers);
+}
+
+void
+process_chain (process_info_t * procinfo, jack_nframes_t frames)
+{
+  LADSPA_Data zero_signal[frames];
+  plugin_t * first_enabled;
+  plugin_t * last_enabled = NULL;
+  plugin_t * plugin;
+  unsigned long channel;
+  unsigned long i;
+  guint copy;
+
+  /* set the zero signal to zero */
+  for (channel = 0; channel < frames; channel++)
+    zero_signal[channel] = 0.0;
+    
+  /* possibly set aux output channels to zero if they're not enabled */
+  for (plugin = procinfo->chain; plugin; plugin = plugin->next)
+    if (!plugin->enabled &&
+        plugin->desc->aux_channels > 0 &&
+        !plugin->desc->aux_are_input)
+      for (copy = 0; copy < plugin->copies; copy++)
+        for (channel = 0; channel < plugin->desc->aux_channels; channel++)
+          memcpy (jack_port_get_buffer (plugin->holders[copy].aux_ports[channel], frames),
+                  zero_signal, sizeof (LADSPA_Data) * frames);
+
+  first_enabled = get_first_enabled_plugin (procinfo);
+  
+  /* no chain; just copy input to output */
+  if (!procinfo->chain || !first_enabled)
+    {
+      unsigned long channel;
+      for (channel = 0; channel < procinfo->channels; channel++)
+        {
+          memcpy (procinfo->jack_output_buffers[channel],
+                  procinfo->jack_input_buffers[channel],
+                  sizeof(LADSPA_Data) * frames);
+        }
+      return;
+    }
+  
+  /* all past here is guaranteed to have at least 1 enabled plugin */
+
+  last_enabled = get_last_enabled_plugin (procinfo);
+  
+  for (plugin = first_enabled;
+       plugin;
+       plugin = plugin->next)
+    {
+      if (plugin->enabled)
+        {
+          for (i = 0; i < plugin->copies; i++)
+            plugin->descriptor->run (plugin->holders[i].instance, frames);
+          
+          if (plugin->wet_dry_enabled)
+            for (channel = 0; channel < procinfo->channels; channel++)
+              for (i = 0; i < frames; i++)
+                {
+                  plugin->audio_output_memory[channel][i] *= plugin->wet_dry_values[channel];
+                  plugin->audio_output_memory[channel][i] += plugin->audio_input_memory[channel][i] * (1.0 - plugin->wet_dry_values[channel]);
+                }
+          
+          if (plugin == last_enabled)
+            break;
+        }
+      else
+        {
+    
+          /* copy the data through */
+          for (i = 0; i < procinfo->channels; i++)
+            memcpy (plugin->audio_output_memory[i],
+                    plugin->prev->audio_output_memory[i],
+                    sizeof(LADSPA_Data) * frames);
+        }
+    }
+  
+  /* copy the last enabled data to the jack ports */
+  for (i = 0; i < procinfo->channels; i++)
+    memcpy (procinfo->jack_output_buffers[i],
+            last_enabled->audio_output_memory[i],
+            sizeof(LADSPA_Data) * frames);
+  
+}
+
+int process (jack_nframes_t frames, void * data) {
+  int err, quitting;
+  process_info_t * procinfo;
+  
+  procinfo = (process_info_t *) data;
+  
+  if (!procinfo)
+    {
+      fprintf (stderr, "%s: no process_info from jack!\n", __FUNCTION__);
+      return 1;
+    }
+  
+  if (procinfo->port_count == 0)
+    return 0;
+  
+  quitting = process_control_messages (procinfo);
+  
+  if (quitting)
+    return 1;
+  
+  process_control_port_messages (procinfo);
+  
+  err = get_jack_buffers (procinfo, frames);
+  if (err)
+    {
+      fprintf(stderr, "%s: failed to get jack ports, not processing\n", __FUNCTION__);
+      return 0;
+    }
+  
+  connect_chain (procinfo, frames);
+  
+  process_chain (procinfo, frames);
+  
+  return 0;
+}
+
+
+
+/*******************************************
+ ************** non RT stuff ***************
+ *******************************************/
+static int
+process_info_connect_jack (process_info_t * procinfo, ui_t * ui)
+{
+  printf (_("Connecting to JACK server with client name '%s'\n"), jack_client_name);
+
+  procinfo->jack_client = jack_client_new (jack_client_name);
+
+  if (!procinfo->jack_client)
+    {
+      fprintf (stderr, "%s: could not create jack client; is the jackd server running?\n", __FUNCTION__);
+      return 1;
+    }
+
+  printf (_("Connected to JACK server\n"));
+
+  jack_set_process_callback (procinfo->jack_client, process, procinfo);
+  jack_on_shutdown (procinfo->jack_client, jack_shutdown_cb, ui);
+                                            
+  return 0;
+}
+
+static void
+process_info_connect_port (process_info_t * procinfo,
+                           ui_t * ui,
+                           gshort in,
+                           unsigned long port_index,
+                           const char * port_name)
+{
+  const char ** jack_ports;
+  unsigned long jack_port_index;
+  int err;
+  char * full_port_name;
+  
+  jack_ports = jack_get_ports (procinfo->jack_client, NULL, NULL,
+                               JackPortIsPhysical | (in ? JackPortIsOutput : JackPortIsInput));
+  
+  if (!jack_ports)
+    return;
+  
+  for (jack_port_index = 0;
+       jack_ports[jack_port_index] && jack_port_index <= port_index;
+       jack_port_index++)
+    {
+      if (jack_port_index != port_index)
+        continue;
+        
+      full_port_name = g_strdup_printf ("%s:%s", jack_client_name, port_name);
+
+      printf (_("Connecting ports '%s' and '%s'\n"), full_port_name, jack_ports[jack_port_index]);
+
+      err = jack_connect (procinfo->jack_client,
+                          in ? jack_ports[jack_port_index] : full_port_name,
+                          in ? full_port_name : jack_ports[jack_port_index]);
+
+      if (err)
+        fprintf (stderr, "%s: error connecting ports '%s' and '%s'\n",
+                 __FUNCTION__, full_port_name, jack_ports[jack_port_index]);
+      else
+        printf (_("Connected ports '%s' and '%s'\n"), full_port_name, jack_ports[jack_port_index]);
+      
+      free (full_port_name);
+    }
+  
+  free (jack_ports);
+}
+
+int
+process_info_set_port_count (process_info_t * procinfo, ui_t * ui, 
+       unsigned long port_count, gboolean connect_inputs, gboolean connect_outputs)
+{
+  unsigned long i;
+  char * port_name;
+  jack_port_t ** port_ptr;
+  gshort in;
+  
+  if (procinfo->port_count >= port_count)
+      return;
+  
+  if (procinfo->port_count == 0)
+    {
+      procinfo->jack_input_ports = g_malloc (sizeof (jack_port_t *) * port_count);
+      procinfo->jack_output_ports = g_malloc (sizeof (jack_port_t *) * port_count);
+      
+      procinfo->jack_input_buffers = g_malloc (sizeof (LADSPA_Data *) * port_count);
+      procinfo->jack_output_buffers = g_malloc (sizeof (LADSPA_Data *) * port_count);
+    }
+  else
+    {
+      procinfo->jack_input_ports = g_realloc (procinfo->jack_input_ports, sizeof (jack_port_t *) * port_count);
+      procinfo->jack_output_ports = g_realloc (procinfo->jack_output_ports, sizeof (jack_port_t *) * port_count);
+
+      procinfo->jack_input_buffers = g_realloc (procinfo->jack_input_buffers, sizeof (LADSPA_Data *) * port_count);
+      procinfo->jack_output_buffers = g_realloc (procinfo->jack_output_buffers, sizeof (LADSPA_Data *) * port_count);
+    }
+  
+  for (i = procinfo->port_count; i < port_count; i++)
+    {
+    for (in = 0; in < 2; in++)
+      {
+        port_name = g_strdup_printf ("%s_%ld", in ? "in" : "out", i + 1);
+       
+        //printf (_("Creating %s port %s\n"), in ? "input" : "output", port_name);
+        
+        port_ptr = (in ? &procinfo->jack_input_ports[i]
+                       : &procinfo->jack_output_ports[i]);
+        
+        *port_ptr =  jack_port_register (procinfo->jack_client,
+                                         port_name,
+                                         JACK_DEFAULT_AUDIO_TYPE,
+                                         in ? JackPortIsInput : JackPortIsOutput,
+                                         0);
+        
+        if (!*port_ptr)
+          {
+            fprintf (stderr, "%s: could not register port '%s'; aborting\n",
+                     __FUNCTION__, port_name);
+            return 1;
+          }
+
+        //printf (_("Created %s port %s\n"), in ? "input" : "output", port_name);
+        
+        if ((in && connect_inputs) || (!in && connect_outputs))
+          process_info_connect_port (procinfo, ui, in, i, port_name);
+        
+        g_free (port_name);
+      }
+    }
+  
+  procinfo->port_count = port_count;
+
+  return 0;
+}
+
+void
+process_info_set_channels (process_info_t * procinfo, ui_t * ui, 
+       unsigned long channels, gboolean connect_inputs, gboolean connect_outputs)
+{
+  process_info_set_port_count (procinfo, ui, channels, connect_inputs, connect_outputs);
+  procinfo->channels = channels; 
+}
+
+process_info_t *
+process_info_new (ui_t * ui, const char * client_name, unsigned long rack_channels, 
+       gboolean connect_inputs, gboolean connect_outputs)
+{
+  process_info_t * procinfo;
+  int err;
+
+  procinfo = g_malloc (sizeof (process_info_t));
+  
+  procinfo->chain = NULL;
+  procinfo->chain_end = NULL;
+  procinfo->jack_client = NULL;
+  procinfo->port_count = 0;
+  procinfo->jack_input_ports = NULL;
+  procinfo->jack_output_ports = NULL;
+  procinfo->channels = rack_channels;
+       
+  /* sort out the client name */
+  jack_client_name = strdup (client_name);
+  for (err = 0; jack_client_name[err] != '\0'; err++)
+    {
+      if (jack_client_name[err] == ' ')
+        jack_client_name[err] = '_';
+      else if (!isalnum (jack_client_name[err]))
+        { /* shift all the chars up one (to remove the non-alphanumeric char) */
+          int i;
+          for (i = err; jack_client_name[i] != '\0'; i++)
+            jack_client_name[i] = jack_client_name[i + 1];
+        }
+      else if (isupper (jack_client_name[err]))
+        jack_client_name[err] = tolower (jack_client_name[err]);
+    }
+  
+  err = process_info_connect_jack (procinfo, ui);
+  if (err)
+    {
+/*      g_free (procinfo); */
+      return NULL;
+/*      abort (); */
+    }
+  
+  sample_rate = jack_get_sample_rate (procinfo->jack_client);
+  buffer_size = jack_get_sample_rate (procinfo->jack_client);
+  
+  jack_set_process_callback (procinfo->jack_client, process, procinfo);
+  jack_on_shutdown (procinfo->jack_client, jack_shutdown_cb, ui);
+  
+  procinfo->ui_to_process = ui->ui_to_process; 
+  procinfo->process_to_ui = ui->process_to_ui; 
+  
+  jack_activate (procinfo->jack_client);
+
+  err = process_info_set_port_count (procinfo, ui, rack_channels, connect_inputs, connect_outputs);
+  if (err)
+    return NULL;
+
+  return procinfo;
+}
+
+void
+process_info_destroy (process_info_t * procinfo) {
+  jack_deactivate (procinfo->jack_client);
+  jack_client_close (procinfo->jack_client);
+  g_free (procinfo);
+}
diff --git a/src/modules/jackrack/process.h b/src/modules/jackrack/process.h
new file mode 100644 (file)
index 0000000..1d218f3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JLH_PROCESS_H__
+#define __JLH_PROCESS_H__
+
+#include <glib.h>
+#include <jack/jack.h>
+#include <ladspa.h>
+
+#include "lock_free_fifo.h"
+
+typedef struct _process_info process_info_t;
+
+/** this is what gets passed to the process() callback and contains all
+    the data the process callback will need */
+struct _process_info {
+
+  /** the plugin instance chain */
+  struct _plugin * chain;
+  struct _plugin * chain_end;
+  
+  jack_client_t * jack_client;
+  unsigned long port_count;
+  jack_port_t ** jack_input_ports;
+  jack_port_t ** jack_output_ports;
+
+  unsigned long channels;
+  LADSPA_Data ** jack_input_buffers;
+  LADSPA_Data ** jack_output_buffers;
+  
+  lff_t * ui_to_process;
+  lff_t * process_to_ui;
+};
+
+extern jack_nframes_t sample_rate;
+extern jack_nframes_t buffer_size;
+
+struct _ui;
+
+process_info_t * process_info_new (struct _ui * ui, const char * client_name, 
+       unsigned long rack_channels, gboolean connect_inputs, gboolean connect_outputs);
+void process_info_destroy (process_info_t * procinfo);
+
+void process_info_set_channels (process_info_t * procinfo, struct _ui * ui, 
+       unsigned long channels, gboolean connect_inputs, gboolean connect_outputs);
+
+
+int process (jack_nframes_t frames, void * data);
+
+
+#endif /* __JLH_PROCESS_H__ */
diff --git a/src/modules/jackrack/ui.c b/src/modules/jackrack/ui.c
new file mode 100644 (file)
index 0000000..d839f08
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <ladspa.h>
+
+#include "ui.h"
+#include "control_message.h"
+
+
+#define PROCESS_FIFO_SIZE 64
+#define MIDI_FIFO_SIZE 256
+
+ui_t *
+ui_new (const char * client_name, unsigned long channels, 
+       gboolean connect_inputs, gboolean connect_outputs)
+{
+  ui_t * ui;
+
+  ui = g_malloc (sizeof (ui_t));
+  ui->filename = NULL;
+  ui->shutdown = FALSE;
+  ui->state = STATE_NORMAL;
+
+  ui->ui_to_process = lff_new (PROCESS_FIFO_SIZE, sizeof (ctrlmsg_t));
+  ui->process_to_ui = lff_new (PROCESS_FIFO_SIZE, sizeof (ctrlmsg_t));
+
+  ui->procinfo = process_info_new (ui, client_name, channels, connect_inputs, connect_outputs);
+  if (!ui->procinfo)
+    return NULL;
+
+  ui->plugin_mgr = plugin_mgr_new (ui);
+  plugin_mgr_set_plugins (ui->plugin_mgr, channels);
+  ui->jack_rack = jack_rack_new (ui, channels);
+  
+  return ui;
+}
+
+
+void
+ui_quit (ui_t * ui)
+{
+  ctrlmsg_t ctrlmsg;
+
+  ui_set_state (ui, STATE_QUITTING);
+  ctrlmsg.type = CTRLMSG_QUIT;
+  lff_write (ui->ui_to_process, &ctrlmsg);
+}
+
+void
+ui_destroy (ui_t * ui)
+{
+  if (!ui->shutdown)
+    ui_quit (ui);
+  jack_rack_destroy (ui->jack_rack);  
+  
+  g_free (ui);
+}
+
+void
+ui_set_state    (ui_t * ui, ui_state_t state)
+{
+  ui->state = state;
+}
+
+ui_state_t
+ui_get_state (ui_t * ui)
+{
+  return ui->state;
+}
+
+void
+jack_shutdown_cb (void * data)
+{
+  ui_t * ui = data;
+  
+  ui->shutdown = TRUE;
+}
+
+/* do the process->gui message processing */
+gboolean
+ui_loop_iterate (ui_t * ui)
+{
+  ctrlmsg_t ctrlmsg;
+  jack_rack_t * jack_rack = ui->jack_rack;
+
+  while (lff_read (ui->process_to_ui, &ctrlmsg) == 0)
+    {
+    switch (ctrlmsg.type)
+      {
+      case CTRLMSG_ADD:
+        jack_rack_add_plugin (jack_rack, ctrlmsg.data.add.plugin);
+        break;
+
+      case CTRLMSG_REMOVE:
+        plugin_destroy (ctrlmsg.data.remove.plugin, ui);
+        break;
+
+      case CTRLMSG_QUIT:
+        return TRUE;
+        break;
+        
+      }
+    }
+  usleep (100000);
+  
+  return FALSE;
+}
+
+/* EOF */
diff --git a/src/modules/jackrack/ui.h b/src/modules/jackrack/ui.h
new file mode 100644 (file)
index 0000000..db616fd
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *   JACK Rack
+ *    
+ *   Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JR_UI_H__
+#define __JR_UI_H__
+
+#include <glib.h>
+
+#include "jack_rack.h"
+#include "plugin_mgr.h"
+#include "process.h"
+#include "lock_free_fifo.h"
+
+typedef struct _ui ui_t;
+
+enum _ui_state
+{
+  /* nothing's happening */
+  STATE_NORMAL,
+  
+  /* the gui is waiting for the process callback to do something */
+  STATE_RACK_CHANGE,
+  
+  /* we're closing down */
+  STATE_QUITTING
+};
+typedef enum _ui_state ui_state_t;
+
+
+struct _jack_rack;
+       
+struct _ui
+{
+  plugin_mgr_t *    plugin_mgr;
+  process_info_t *  procinfo;
+  struct _jack_rack *     jack_rack;
+
+  lff_t *           ui_to_process;
+  lff_t *           process_to_ui;
+  
+  lff_t             *ui_to_midi;
+  lff_t             *midi_to_ui;
+
+  char *            filename;
+  
+  gboolean          shutdown;
+  ui_state_t        state;
+
+};
+
+ui_t * ui_new     (const char * client_name, unsigned long channels, 
+       gboolean connect_inputs, gboolean connect_outputs);
+void   ui_quit    (ui_t * ui);
+void   ui_destroy (ui_t * ui);
+
+void ui_set_state    (ui_t * ui, ui_state_t state);
+ui_state_t ui_get_state (ui_t * ui);
+
+void jack_shutdown_cb (void * data);
+gboolean ui_loop_iterate (ui_t * ui);
+
+#endif /* __JR_UI_H__ */