--- /dev/null
+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
--- /dev/null
+#!/bin/sh
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../filters.dat
+jackrack libmltjackrack.so
+EOF
+
+fi
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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__ */