From: Brian Matherly Date: Fri, 15 Feb 2013 20:53:00 +0000 (-0600) Subject: Add ladspa producer X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=e99b978de79541ed3d6644f0a828a3efbd54595f;p=mlt Add ladspa producer --- diff --git a/src/modules/jackrack/Makefile b/src/modules/jackrack/Makefile index aedb7b5e..dba6b7b7 100644 --- a/src/modules/jackrack/Makefile +++ b/src/modules/jackrack/Makefile @@ -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 diff --git a/src/modules/jackrack/factory.c b/src/modules/jackrack/factory.c index 7ba3bf85..6f09c955 100644 --- a/src/modules/jackrack/factory.c +++ b/src/modules/jackrack/factory.c @@ -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 ); diff --git a/src/modules/jackrack/plugin_desc.c b/src/modules/jackrack/plugin_desc.c index 0baa5835..88512cca 100644 --- a/src/modules/jackrack/plugin_desc.c +++ b/src/modules/jackrack/plugin_desc.c @@ -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; diff --git a/src/modules/jackrack/plugin_desc.h b/src/modules/jackrack/plugin_desc.h index 31b7fe52..ff511f0a 100644 --- a/src/modules/jackrack/plugin_desc.h +++ b/src/modules/jackrack/plugin_desc.h @@ -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 (); diff --git a/src/modules/jackrack/plugin_mgr.c b/src/modules/jackrack/plugin_mgr.c index a5842105..92ea74a9 100644 --- a/src/modules/jackrack/plugin_mgr.c +++ b/src/modules/jackrack/plugin_mgr.c @@ -60,7 +60,7 @@ plugin_is_valid (const LADSPA_Descriptor * descriptor) ocount++; } - if (icount == 0 || ocount == 0) + if (ocount == 0) return FALSE; return TRUE; diff --git a/src/modules/jackrack/process.c b/src/modules/jackrack/process.c index 88c00e8f..6d29571a 100644 --- a/src/modules/jackrack/process.c +++ b/src/modules/jackrack/process.c @@ -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 index 00000000..29fc7948 --- /dev/null +++ b/src/modules/jackrack/producer_ladspa.c @@ -0,0 +1,201 @@ +/* + * producer_ladspa.c -- LADSPA plugin producer + * Copyright (C) 2013 Ushodaya Enterprises Limited + * Author: Brian Matherly + * + * 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 +#include +#include + +#include +#include +#include +#include + +#include + +#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 index 00000000..7033dc92 --- /dev/null +++ b/src/modules/jackrack/producer_ladspa.yml @@ -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. +