]> git.sesse.net Git - mlt/commitdiff
Add ladspa producer
authorBrian Matherly <pez4brian@yahoo.com>
Fri, 15 Feb 2013 20:53:00 +0000 (14:53 -0600)
committerBrian Matherly <pez4brian@yahoo.com>
Fri, 15 Feb 2013 20:53:00 +0000 (14:53 -0600)
src/modules/jackrack/Makefile
src/modules/jackrack/factory.c
src/modules/jackrack/plugin_desc.c
src/modules/jackrack/plugin_desc.h
src/modules/jackrack/plugin_mgr.c
src/modules/jackrack/process.c
src/modules/jackrack/producer_ladspa.c [new file with mode: 0644]
src/modules/jackrack/producer_ladspa.yml [new file with mode: 0644]

index aedb7b5e34052344b7c6b7b25ea21abb624be62a..dba6b7b7320d1236db03dab8db5b9125f753bc70 100644 (file)
@@ -14,6 +14,7 @@ GPL_OBJS = jack_rack.o \
        plugin_mgr.o \
        plugin_settings.o \
        process.o \
+       producer_ladspa.o \
        filter_jackrack.o \
        filter_ladspa.o
 
index 7ba3bf8585723efbae3557902e7eb3e7f4ccf539..6f09c9550fcc9009a610b1d0abe7352f9e9ffcf2 100644 (file)
@@ -35,6 +35,7 @@ extern mlt_consumer consumer_jack_init( mlt_profile profile, mlt_service_type ty
 
 extern mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
 extern mlt_filter filter_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_producer producer_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
 
 plugin_mgr_t *g_jackrack_plugin_mgr = NULL;
 #endif
@@ -42,8 +43,16 @@ plugin_mgr_t *g_jackrack_plugin_mgr = NULL;
 static mlt_properties metadata( mlt_service_type type, const char *id, char *data )
 {
        char file[ PATH_MAX ];
-       snprintf( file, PATH_MAX, "%s/jackrack/%s",
+       if( type == filter_type )
+       {
+               snprintf( file, PATH_MAX, "%s/jackrack/%s",
                          mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "filter_ladspa.yml" );
+       }
+       else
+       {
+               snprintf( file, PATH_MAX, "%s/jackrack/%s",
+                         mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "producer_ladspa.yml" );
+       }
        mlt_properties result = mlt_properties_parse_yaml( file );
 
 #ifdef GPL
@@ -114,15 +123,19 @@ static mlt_properties metadata( mlt_service_type type, const char *id, char *dat
                                if ( LADSPA_IS_HINT_LOGARITHMIC( hint_descriptor ) )
                                        mlt_properties_set( p, "scale", "log" );
                        }
-                       p = mlt_properties_new();
-                       snprintf( key, sizeof(key), "%d", i );
-                       mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );
-                       mlt_properties_set( p, "identifier", "wetness" );
-                       mlt_properties_set( p, "title", "Wet/Dry" );
-                       mlt_properties_set( p, "type", "float" );
-                       mlt_properties_set_double( p, "default", 1 );
-                       mlt_properties_set_double( p, "minimum", 0 );
-                       mlt_properties_set_double( p, "maximum", 1 );
+
+                       if( type == filter_type )
+                       {
+                               p = mlt_properties_new();
+                               snprintf( key, sizeof(key), "%d", i );
+                               mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );
+                               mlt_properties_set( p, "identifier", "wetness" );
+                               mlt_properties_set( p, "title", "Wet/Dry" );
+                               mlt_properties_set( p, "type", "float" );
+                               mlt_properties_set_double( p, "default", 1 );
+                               mlt_properties_set_double( p, "minimum", 0 );
+                               mlt_properties_set_double( p, "maximum", 1 );
+                       }
                }
        }
 #endif
@@ -142,8 +155,18 @@ MLT_REPOSITORY
                char *s = malloc( strlen( "ladpsa." ) + 21 );
 
                sprintf( s, "ladspa.%lu", desc->id );
-               MLT_REGISTER( filter_type, s, filter_ladspa_init );
-               MLT_REGISTER_METADATA( filter_type, s, metadata, NULL );
+
+               if( desc->has_input )
+               {
+                       MLT_REGISTER( filter_type, s, filter_ladspa_init );
+                       MLT_REGISTER_METADATA( filter_type, s, metadata, NULL );
+               }
+               else
+               {
+                       MLT_REGISTER( producer_type, s, producer_ladspa_init );
+                       MLT_REGISTER_METADATA( producer_type, s, metadata, NULL );
+               }
+
                free( s );
        }
        mlt_factory_register_for_clean_up( g_jackrack_plugin_mgr, (mlt_destructor) plugin_mgr_destroy );
index 0baa5835e247dfa75a1069450ec73740541e893a..88512ccaec6b874b8c57a37140358407e8760492 100644 (file)
@@ -69,6 +69,7 @@ plugin_desc_init (plugin_desc_t * pd)
   pd->control_port_indicies = NULL;
   pd->aux_channels = 0;
   pd->aux_are_input = TRUE;
+  pd->has_input = TRUE;
 }
 
 static void
@@ -220,6 +221,11 @@ plugin_desc_set_port_counts (plugin_desc_t * pd)
   
   if (icount == ocount)
     pd->channels = icount;
+  else if( icount == 0 )
+    {
+      pd->channels = ocount;
+      pd->has_input = FALSE;
+    }
   else
     { /* deal with auxilliary ports */
       unsigned long ** port_indicies;
index 31b7fe52313b6667c024634815898d2167af766f..ff511f0a8f3c4aa53b5798a8a8712f956bbb7f87 100644 (file)
@@ -58,6 +58,8 @@ struct _plugin_desc
 
   unsigned long            control_port_count;
   unsigned long *          control_port_indicies;
+
+  gboolean                 has_input;
 };
 
 plugin_desc_t * plugin_desc_new ();
index a5842105c565dd6ab490e09e765703c5a79df8ea..92ea74a9eac82e3d0e2bbf28c1d509ac2404ae1a 100644 (file)
@@ -60,7 +60,7 @@ plugin_is_valid (const LADSPA_Descriptor * descriptor)
         ocount++;
     }
   
-  if (icount == 0 || ocount == 0)
+  if (ocount == 0)
     return FALSE;
   
   return TRUE;
index 88c00e8f55915a64150118848f0e5b117e4c0c88..6d29571a1c7d2ef166e2f2f3d9382b92b0a848d5 100644 (file)
@@ -206,7 +206,8 @@ connect_chain (process_info_t * procinfo, jack_nframes_t frames)
     }
 
   /* input buffers for first plugin */
-  plugin_connect_input_ports (first_enabled, procinfo->jack_input_buffers);
+  if( plugin->desc->has_input )
+    plugin_connect_input_ports (first_enabled, procinfo->jack_input_buffers);
 }
 
 void
@@ -313,13 +314,15 @@ int process_ladspa (process_info_t * procinfo, jack_nframes_t frames,
   
   for (channel = 0; channel < procinfo->channels; channel++)
     {
-      procinfo->jack_input_buffers[channel] = inputs[channel];
-      if (!procinfo->jack_input_buffers[channel])
+      if(get_first_enabled_plugin (procinfo)->desc->has_input)
         {
-          mlt_log_verbose( NULL, "%s: no jack buffer for input port %ld\n", __FUNCTION__, channel);
-          return 1;
+          procinfo->jack_input_buffers[channel] = inputs[channel];
+          if (!procinfo->jack_input_buffers[channel])
+            {
+              mlt_log_verbose( NULL, "%s: no jack buffer for input port %ld\n", __FUNCTION__, channel);
+              return 1;
+            }
         }
-
       procinfo->jack_output_buffers[channel] = outputs[channel];
       if (!procinfo->jack_output_buffers[channel])
         {
diff --git a/src/modules/jackrack/producer_ladspa.c b/src/modules/jackrack/producer_ladspa.c
new file mode 100644 (file)
index 0000000..29fc794
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * producer_ladspa.c -- LADSPA plugin producer
+ * Copyright (C) 2013 Ushodaya Enterprises Limited
+ * Author: Brian Matherly <pez4brian@yahoo.com>
+ *
+ * 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 <framework/mlt_producer.h>
+#include <framework/mlt_frame.h>
+#include <framework/mlt_log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include "jack_rack.h"
+
+#define BUFFER_LEN 10000
+
+/** One-time initialization of jack rack.
+*/
+
+static jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels )
+{
+       jack_rack_t *jackrack = NULL;
+       unsigned long plugin_id = mlt_properties_get_int64( properties, "_pluginid" );
+
+       // Start JackRack
+       if ( plugin_id )
+       {
+               // Create JackRack without Jack client name so that it only uses LADSPA
+               jackrack = jack_rack_new( NULL, channels );
+               mlt_properties_set_data( properties, "_jackrack", jackrack, 0,
+                       (mlt_destructor) jack_rack_destroy, NULL );
+
+               // Load one LADSPA plugin by its UniqueID
+               plugin_desc_t *desc = plugin_mgr_get_any_desc( jackrack->plugin_mgr, plugin_id );
+               plugin_t *plugin;
+
+               if ( desc && ( plugin = jack_rack_instantiate_plugin( jackrack, desc ) ) )
+               {
+                       LADSPA_Data value;
+                       int index, c;
+
+                       plugin->enabled = TRUE;
+                       plugin->wet_dry_enabled = FALSE;
+                       for ( index = 0; index < desc->control_port_count; index++ )
+                       {
+                               // Apply the control port values
+                               char key[20];
+                               value = plugin_desc_get_default_control_value( desc, index, sample_rate );
+                               snprintf( key, sizeof(key), "%d", index );
+                               if ( mlt_properties_get( properties, key ) )
+                                       value = mlt_properties_get_double( properties, key );
+                               for ( c = 0; c < plugin->copies; c++ )
+                                       plugin->holders[c].control_memory[index] = value;
+                       }
+                       process_add_plugin( jackrack->procinfo, plugin );
+               }
+               else
+               {
+                       mlt_log_error( properties, "failed to load plugin %lu\n", plugin_id );
+               }
+       }
+
+       return jackrack;
+}
+
+static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       // Get the producer service
+       mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_ladspa", NULL );
+       mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
+       int size = 0;
+       LADSPA_Data** output_buffers = NULL;
+       int i = 0;
+
+       // Initialize LADSPA if needed
+       jack_rack_t *jackrack = mlt_properties_get_data( producer_properties, "_jackrack", NULL );
+       if ( !jackrack )
+       {
+               sample_rate = *frequency; // global inside jack_rack
+               jackrack = initialise_jack_rack( producer_properties, *channels );
+       }
+
+       if( jackrack )
+       {
+               // Correct the returns if necessary
+               *samples = *samples <= 0 ? 1920 : *samples;
+               *channels = *channels <= 0 ? 2 : *channels;
+               *frequency = *frequency <= 0 ? 48000 : *frequency;
+               *format = mlt_audio_float;
+
+               // Calculate the size of the buffer
+               size = *samples * *channels * sizeof( float );
+
+               // Allocate the buffer
+               *buffer = mlt_pool_alloc( size );
+
+               // Initialize the LADSPA output buffer.
+               output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels );
+               for ( i = 0; i < *channels; i++ )
+               {
+                       output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples;
+               }
+
+               // Do LADSPA processing
+               process_ladspa( jackrack->procinfo, *samples, NULL, output_buffers );
+               mlt_pool_release( output_buffers );
+
+               // Set the buffer for destruction
+               mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release );
+       }
+
+       return 0;
+}
+
+static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
+{
+       // Generate a frame
+       *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
+
+       // Check that we created a frame and initialize it
+       if ( *frame != NULL )
+       {
+               // Obtain properties of frame
+               mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame );
+
+               // Update timecode on the frame we're creating
+               mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
+
+               // Save the producer to be used in get_audio
+               mlt_properties_set_data( frame_properties, "_producer_ladspa", producer, 0, NULL, NULL );
+
+               // Push the get_audio method
+               mlt_frame_push_audio( *frame, producer_get_audio );
+       }
+
+       // Calculate the next time code
+       mlt_producer_prepare_next( producer );
+
+       return 0;
+}
+
+/** Destructor for the producer.
+*/
+
+static void producer_close( mlt_producer producer )
+{
+       producer->close = NULL;
+       mlt_producer_close( producer );
+       free( producer );
+}
+
+/** Constructor for the producer.
+*/
+
+mlt_producer producer_ladspa_init( mlt_profile profile, mlt_service_type type, const char* id, char* arg )
+{
+       // Create a new producer object
+       mlt_producer producer = mlt_producer_new( profile );
+
+       if ( producer != NULL )
+       {
+               mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
+
+               producer->get_frame = producer_get_frame;
+               producer->close = ( mlt_destructor )producer_close;
+
+               // Save the plugin ID.
+               if ( !strncmp( id, "ladspa.", 7 ) )
+               {
+                       mlt_properties_set( properties, "_pluginid", id + 7 );
+               }
+
+               // Make sure the plugin ID is valid.
+               unsigned long plugin_id = mlt_properties_get_int64( properties, "_pluginid" );
+               if( plugin_id < 1000 || plugin_id > 0x00FFFFFF )
+               {
+                       producer_close( producer );
+                       producer = NULL;
+               }
+       }
+       return producer;
+}
diff --git a/src/modules/jackrack/producer_ladspa.yml b/src/modules/jackrack/producer_ladspa.yml
new file mode 100644 (file)
index 0000000..7033dc9
--- /dev/null
@@ -0,0 +1,15 @@
+schema_version: 0.1
+type: producer
+identifier: ladspa
+title: LADSPA
+version: 1
+copyright: Copyright (C) 2013 Ushodaya Enterprises Limited
+license: GPLv2
+language: en
+creator: Brian Matherly
+tags:
+  - Audio
+description: Generate audio using LADSPA plugins.
+notes: >
+  Automatically adapts to the number of channels and sampling rate of the consumer.
+