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 jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels ) { jack_rack_t *jackrack = NULL; char *resource = mlt_properties_get( properties, "resource" ); if ( !resource && mlt_properties_get( properties, "src" ) ) resource = mlt_properties_get( properties, "src" ); // Start JackRack if ( resource || mlt_properties_get_int64( properties, "_pluginid" ) ) { // 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 ); if ( resource ) // Load JACK Rack XML file jack_rack_open_file( jackrack, resource ); else if ( mlt_properties_get_int64( properties, "_pluginid" ) ) { // Load one LADSPA plugin by its UniqueID unsigned long id = mlt_properties_get_int64( properties, "_pluginid" ); plugin_desc_t *desc = plugin_mgr_get_any_desc( jackrack->plugin_mgr, id ); plugin_t *plugin; if ( desc && ( plugin = jack_rack_instantiate_plugin( jackrack, desc ) ) ) { plugin->enabled = TRUE; process_add_plugin( jackrack->procinfo, plugin ); mlt_properties_set_int( properties, "instances", plugin->copies ); } else { mlt_log_error( properties, "failed to load plugin %lu\n", id ); return jackrack; } if ( plugin && plugin->desc && plugin->copies == 0 ) { mlt_log_warning( properties, "Not compatible with %d channels. Requesting %d channels instead.\n", channels, plugin->desc->channels ); jackrack = initialise_jack_rack( properties, plugin->desc->channels ); } } } return jackrack; }
static int ladspa_get_audio( mlt_frame frame, void **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 ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( filter_properties, *channels ); } // Get the filter-specific properties LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); int i; for ( i = 0; i < *channels; i++ ) { input_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } // Do LADSPA processing int error = jackrack && process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers ); mlt_pool_release( input_buffers ); mlt_pool_release( output_buffers ); return error; }
static jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels ) { jack_rack_t *jackrack = NULL; char *resource = mlt_properties_get( properties, "resource" ); if ( !resource && mlt_properties_get( properties, "src" ) ) resource = mlt_properties_get( properties, "src" ); // Start JackRack if ( resource || mlt_properties_get_int64( properties, "_pluginid" ) ) { // 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 ); if ( resource ) // Load JACK Rack XML file jack_rack_open_file( jackrack, resource ); else if ( mlt_properties_get_int64( properties, "_pluginid" ) ) { // Load one LADSPA plugin by its UniqueID unsigned long id = mlt_properties_get_int64( properties, "_pluginid" ); plugin_desc_t *desc = plugin_mgr_get_any_desc( jackrack->plugin_mgr, id ); plugin_t *plugin; if ( desc && ( plugin = jack_rack_instantiate_plugin( jackrack, desc ) ) ) { plugin->enabled = TRUE; process_add_plugin( jackrack->procinfo, plugin ); mlt_properties_set_int( properties, "instances", plugin->copies ); } else { mlt_log_error( properties, "failed to load plugin %lu\n", id ); return jackrack; } if ( plugin && plugin->desc && plugin->copies == 0 ) { // Calculate the number of channels that will work with this plugin int request_channels = plugin->desc->channels; while ( request_channels < channels ) request_channels += plugin->desc->channels; if ( request_channels != channels ) { // Try to load again with a compatible number of channels. mlt_log_warning( properties, "Not compatible with %d channels. Requesting %d channels instead.\n", channels, request_channels ); jack_rack_destroy( jackrack ); jackrack = initialise_jack_rack( properties, request_channels ); } else { mlt_log_error( properties, "Invalid plugin configuration: %lu\n", id ); return jackrack; } } if ( plugin && plugin->desc && plugin->copies ) mlt_log_debug( properties, "Plugin Initialized. Channels: %lu\tCopies: %d\tTotal: %lu\n", plugin->desc->channels, plugin->copies, jackrack->channels ); } } return jackrack; }
static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int error = 0; // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Check if the channel configuration has changed int prev_channels = mlt_properties_get_int( filter_properties, "_prev_channels" ); if ( prev_channels != *channels ) { if( prev_channels ) { mlt_log_info( MLT_FILTER_SERVICE(filter), "Channel configuration changed. Old: %d New: %d.\n", prev_channels, *channels ); mlt_properties_set_data( filter_properties, "jackrack", NULL, 0, (mlt_destructor) NULL, NULL ); } mlt_properties_set_int( filter_properties, "_prev_channels", *channels ); } // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( filter_properties, *channels ); } if ( jackrack && jackrack->procinfo && jackrack->procinfo->chain && mlt_properties_get_int64( filter_properties, "_pluginid" ) ) { plugin_t *plugin = jackrack->procinfo->chain; LADSPA_Data value; int i, c; mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Resize the buffer if necessary. if ( *channels < jackrack->channels ) { // Add extra channels to satisfy the plugin. // Extra channels in the buffer will be ignored by downstream services. int old_size = mlt_audio_format_size( *format, *samples, *channels ); int new_size = mlt_audio_format_size( *format, *samples, jackrack->channels ); uint8_t* new_buffer = mlt_pool_alloc( new_size ); memcpy( new_buffer, *buffer, old_size ); // Put silence in extra channels. memset( new_buffer + old_size, 0, new_size - old_size ); mlt_frame_set_audio( frame, new_buffer, *format, new_size, mlt_pool_release ); *buffer = new_buffer; } for ( i = 0; i < plugin->desc->control_port_count; i++ ) { // Apply the control port values char key[20]; value = plugin_desc_get_default_control_value( plugin->desc, i, sample_rate ); snprintf( key, sizeof(key), "%d", i ); if ( mlt_properties_get( filter_properties, key ) ) value = mlt_properties_anim_get_double( filter_properties, key, position, length ); for ( c = 0; c < plugin->copies; c++ ) plugin->holders[c].control_memory[i] = value; } plugin->wet_dry_enabled = mlt_properties_get( filter_properties, "wetness" ) != NULL; if ( plugin->wet_dry_enabled ) { value = mlt_properties_anim_get_double( filter_properties, "wetness", position, length ); for ( c = 0; c < jackrack->channels; c++ ) plugin->wet_dry_values[c] = value; } // Configure the buffers LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * jackrack->channels ); LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * jackrack->channels ); // Some plugins crash with too many frames (samples). // So, feed the plugin with N samples per loop iteration. int samples_offset = 0; int sample_count = MIN(*samples, MAX_SAMPLE_COUNT); for (i = 0; samples_offset < *samples; i++) { int j = 0; for (; j < jackrack->channels; j++) output_buffers[j] = input_buffers[j] = (LADSPA_Data*) *buffer + j * (*samples) + samples_offset; sample_count = MIN(*samples - samples_offset, MAX_SAMPLE_COUNT); // Do LADSPA processing error = process_ladspa( jackrack->procinfo, sample_count, input_buffers, output_buffers ); samples_offset += MAX_SAMPLE_COUNT; } mlt_pool_release( input_buffers ); mlt_pool_release( output_buffers ); // read the status port values for ( i = 0; i < plugin->desc->status_port_count; i++ ) { char key[20]; int p = plugin->desc->status_port_indicies[i]; for ( c = 0; c < plugin->copies; c++ ) { snprintf( key, sizeof(key), "%d[%d]", p, c ); value = plugin->holders[c].status_memory[i]; mlt_properties_set_double( filter_properties, key, value ); } } } else { // Nothing to do. error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } return error; }
static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int error = 0; // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( filter_properties, *channels ); } if ( jackrack && jackrack->procinfo && jackrack->procinfo->chain && mlt_properties_get_int64( filter_properties, "_pluginid" ) ) { plugin_t *plugin = jackrack->procinfo->chain; LADSPA_Data value; int i, c; mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); // Get the producer's audio *channels = jackrack->channels; *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); for ( i = 0; i < plugin->desc->control_port_count; i++ ) { // Apply the control port values char key[20]; value = plugin_desc_get_default_control_value( plugin->desc, i, sample_rate ); snprintf( key, sizeof(key), "%d", i ); if ( mlt_properties_get( filter_properties, key ) ) value = mlt_properties_anim_get_double( filter_properties, key, position, length ); for ( c = 0; c < plugin->copies; c++ ) plugin->holders[c].control_memory[i] = value; } plugin->wet_dry_enabled = mlt_properties_get( filter_properties, "wetness" ) != NULL; if ( plugin->wet_dry_enabled ) { value = mlt_properties_anim_get_double( filter_properties, "wetness", position, length ); for ( c = 0; c < *channels; c++ ) plugin->wet_dry_values[c] = value; } // Configure the buffers LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); for ( i = 0; i < *channels; i++ ) { input_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } // Do LADSPA processing error = process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers ); mlt_pool_release( input_buffers ); mlt_pool_release( output_buffers ); // read the status port values for ( i = 0; i < plugin->desc->status_port_count; i++ ) { char key[20]; int p = plugin->desc->status_port_indicies[i]; for ( c = 0; c < plugin->copies; c++ ) { snprintf( key, sizeof(key), "%d[%d]", p, c ); value = plugin->holders[c].status_memory[i]; mlt_properties_set_double( filter_properties, key, value ); } } } else { // Nothing to do. error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } return error; }