Mixer: Fix issues with port auto-connection

Closes #188
This commit is contained in:
Jonathan Moore Liles 2016-03-02 21:13:17 -08:00
parent 1ef382fbbe
commit 3946d39221
10 changed files with 191 additions and 62 deletions

@ -1 +1 @@
Subproject commit 9884cca97d2dc7a34e730b942465b0bb808c6ccb
Subproject commit 5719b0044d9f267de5391fab006370cc7f4e70bd

View File

@ -383,7 +383,7 @@ Chain::configure_ports ( void )
for ( unsigned int i = 0; i < req_buffers; ++i )
{
Module::Port p( NULL, Module::Port::OUTPUT, Module::Port::AUDIO );
p.connect_to( buffer_alloc( client()->nframes() ) );
p.set_buffer( buffer_alloc( client()->nframes() ) );
buffer_fill_with_silence( (sample_t*)p.buffer(), client()->nframes() );
scratch_port.push_back( p );
}
@ -749,11 +749,11 @@ Chain::build_process_queue ( void )
for ( unsigned int j = 0; j < m->audio_input.size(); ++j )
{
m->audio_input[j].connect_to( &scratch_port[j] );
m->audio_input[j].set_buffer( scratch_port[j].buffer() );
}
for ( unsigned int j = 0; j < m->audio_output.size(); ++j )
{
m->audio_output[j].connect_to( &scratch_port[j] );
m->audio_output[j].set_buffer( scratch_port[j].buffer() );
}
m->handle_port_connection_change();

View File

@ -51,6 +51,8 @@ extern char *instance_name;
static JACK_Module *receptive_to_drop = NULL;
const int MAX_PORTS = 16;
JACK_Module::JACK_Module ( bool log )
: Module ( 25, 25, name() )
{
@ -70,8 +72,8 @@ JACK_Module::JACK_Module ( bool log )
{
Port p( this, Port::INPUT, Port::CONTROL, "Inputs" );
p.hints.type = Port::Hints::INTEGER;
p.hints.minimum = 0;
p.hints.maximum = 16;
p.hints.minimum = 1;
p.hints.maximum = MAX_PORTS;
p.hints.ranged = true;
p.hints.visible = false;
@ -84,8 +86,8 @@ JACK_Module::JACK_Module ( bool log )
{
Port p( this, Port::INPUT, Port::CONTROL, "Outputs" );
p.hints.type = Port::Hints::INTEGER;
p.hints.minimum = 0;
p.hints.maximum = 16;
p.hints.minimum = 1;
p.hints.maximum = MAX_PORTS;
p.hints.ranged = true;
p.hints.visible = false;
@ -226,8 +228,7 @@ get_connections_for_ports ( std::vector<Module::Port> ports )
free( strip_name );
strip_name = s;
}
else
if ( 2 == sscanf( *c, "Non-Mixer.%a[^:(] (%a[^:)]):", &client_id, &strip_name ) )
else if ( 2 == sscanf( *c, "Non-Mixer.%a[^:(] (%a[^:)]):", &client_id, &strip_name ) )
{
free( client_id );
char *s = NULL;
@ -235,8 +236,7 @@ get_connections_for_ports ( std::vector<Module::Port> ports )
free( strip_name );
strip_name = s;
}
else
if ( 2 == sscanf( *c, "Non-Timeline.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
else if ( 2 == sscanf( *c, "Non-Timeline.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
{
free( client_id );
char *s = NULL;
@ -244,8 +244,7 @@ get_connections_for_ports ( std::vector<Module::Port> ports )
free( strip_name );
strip_name = s;
}
else
if ( 2 == sscanf( *c, "Non-DAW.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
else if ( 2 == sscanf( *c, "Non-DAW.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
{
free( client_id );
char *s = NULL;
@ -379,12 +378,12 @@ JACK_Module::configure_inputs ( int n )
{
if ( n > 0 )
{
if ( is_default() )
control_input[0].hints.minimum = 1;
output_connection_handle->show();
}
if ( n < 1 || n > MAX_PORTS )
return false;
int on = audio_input.size();
if ( n > on )
@ -396,6 +395,8 @@ JACK_Module::configure_inputs ( int n )
add_port( Port( this, Port::INPUT, Port::AUDIO ) );
}
}
mixer->maybe_auto_connect_output(&aux_audio_output.back());
}
else
{
@ -403,9 +404,11 @@ JACK_Module::configure_inputs ( int n )
{
audio_input.back().disconnect();
audio_input.pop_back();
aux_audio_output.back().disconnect();
aux_audio_output.back().jack_port()->shutdown();
delete aux_audio_output.back().jack_port();
aux_audio_output.pop_back();
}
}
@ -423,6 +426,9 @@ JACK_Module::configure_outputs ( int n )
{
int on = audio_output.size();
if ( n > MAX_PORTS )
return false;
if ( n > 0 )
{
input_connection_handle->show();
@ -437,6 +443,8 @@ JACK_Module::configure_outputs ( int n )
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
}
}
mixer->auto_connect();
}
else
{
@ -444,6 +452,7 @@ JACK_Module::configure_outputs ( int n )
{
audio_output.back().disconnect();
audio_output.pop_back();
aux_audio_input.back().disconnect();
aux_audio_input.back().jack_port()->shutdown();
delete aux_audio_input.back().jack_port();
aux_audio_input.pop_back();
@ -458,9 +467,11 @@ JACK_Module::configure_outputs ( int n )
dec_button->show();
inc_button->show();
}
return true;
}
bool
JACK_Module::initialize ( void )
{
@ -703,7 +714,7 @@ JACK_Module::process ( nframes_t nframes )
buffer_copy( (sample_t*)aux_audio_output[i].jack_port()->buffer(nframes),
(sample_t*)audio_input[i].buffer(),
nframes );
}
}
}

View File

@ -1148,6 +1148,12 @@ Mixer::get_auto_connect_targets ( void )
void
Mixer::auto_connect ( void )
{
if ( Project::is_opening() )
/* it's more efficient to do this once at the end rather than as we go. */
return;
DMESSAGE("Full auto-connect cycle" );
/* give strips with group affinity the first shot */
for ( int i = 0; i < mixer_strips->children(); i++ )
{
@ -1170,6 +1176,12 @@ Mixer::auto_connect ( void )
void
Mixer::maybe_auto_connect_output ( Module::Port *p )
{
if ( Project::is_opening() )
/* it's more efficient to do this once at the end rather than as we go. */
return;
// DMESSAGE( "Single output auto connect cycle" );
/* give strips with group affinity the first shot */
for ( int i = 0; i < mixer_strips->children(); i++ )
{

View File

@ -996,7 +996,6 @@ Mixer_Strip::has_group_affinity ( void ) const
return _auto_input && strncmp( _auto_input, "*/", 2 );
}
bool
Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
{
@ -1009,25 +1008,16 @@ Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
if ( ! _auto_input )
{
if ( p->connected_port() && p->connected_port()->module()->chain()->strip() == this )
{
/* first break previous auto connection */
p->connected_port()->jack_port()->disconnect( p->jack_port()->jack_name() );
p->disconnect();
}
/* break any previous connection between this port and this module */
p->disconnect_from_strip(this);
}
if ( _auto_input && matches_pattern( _auto_input, p ) )
{
DMESSAGE( "Auto connecting port" );
if ( p->connected_port() )
{
/* first break previous auto connection */
p->connected_port()->jack_port()->disconnect( p->jack_port()->jack_name() );
p->disconnect();
}
/* break any prior auto-connection */
p->disconnect();
// FIXME: Find a better way to get the port index.
const char* jack_name = p->jack_port()->jack_name();
/* get port number */
@ -1037,13 +1027,20 @@ Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
/* FIXME: safe assumption? */
JACK_Module *m = (JACK_Module*)chain()->module(0);
if ( n < m->aux_audio_input.size() )
if ( !m )
{
m->aux_audio_input[n].jack_port()->connect( jack_name );
/* make a note of the connection so we know to disconnected later */
m->aux_audio_input[n].connect_to( p );
/* no jack module in the chian... may be in the process of adding the JACK module to the chain... i.e in log replay when loading a project. */
return false;
}
if ( n >= m->aux_audio_input.size() )
{
// DMESSAGE( "No port to connect to at this index");
return false;
}
m->aux_audio_input[n].connect_to( p );
if ( p->module()->is_default() )
{
/* only do this for mains */

View File

@ -86,6 +86,18 @@ Module::~Module ( )
audio_input[i].disconnect();
for ( unsigned int i = 0; i < audio_output.size(); ++i )
audio_output[i].disconnect();
for ( unsigned int i = 0; i < aux_audio_input.size(); ++i )
{
aux_audio_input[i].disconnect();
aux_audio_input[i].jack_port()->shutdown();
delete aux_audio_input[i].jack_port();
}
for ( unsigned int i = 0; i < aux_audio_output.size(); ++i )
{
aux_audio_output[i].disconnect();
aux_audio_output[i].jack_port()->shutdown();
delete aux_audio_output[i].jack_port();
}
for ( unsigned int i = 0; i < control_input.size(); ++i )
{
/* destroy connected Controller_Module */
@ -129,6 +141,15 @@ Module::~Module ( )
void
Module::init ( void )
{
/* we use pointers to these vector elements for port auto connection stuff and need to prevent reallocation from invalidating them. */
audio_input.reserve(16);
audio_output.reserve(16);
control_input.reserve(16);
control_output.reserve(16);
aux_audio_input.reserve(16);
aux_audio_output.reserve(16);
// _latency = 0;
_is_default = false;
_editor = 0;
@ -245,6 +266,23 @@ Module::paste_before ( void )
void
Module::Port::disconnect_from_strip ( Mixer_Strip *o )
{
for ( std::list<Port*>::iterator i = _connected.begin(); i != _connected.end(); i++ )
{
Port *p = *i;
if ( p->module()->chain()->strip() == o )
{
/* iterator about to be invalidated... */
i = _connected.erase(i);
disconnect(p);
}
}
}
const char *
Module::Port::osc_number_path ( void )
{

View File

@ -31,12 +31,15 @@
#include "Loggable.H"
#include "JACK/Port.H"
#include "OSC/Endpoint.H"
#include <list>
#include <algorithm>
class Chain;
class Module_Parameter_Editor;
class Fl_Menu_;
class Fl_Menu_Button;
class Fl_Button;
class Mixer_Strip;
class Module : public Fl_Group, public Loggable {
@ -86,6 +89,11 @@ public:
class Port
{
/* support multiple connection for audio ports (many to one, one to many, many to many).
control ports only support one to one and one to many. */
/* char *type_names[] = { "Audio", "Control" }; */
/* char *direction_names[] = { "Input", "Output" }; */
@ -139,7 +147,6 @@ public:
_type = type;
_buf = 0;
_nframes = 0;
_connected = 0;
_module = module;
_scaled_signal = 0;
_unscaled_signal = 0;
@ -155,7 +162,6 @@ public:
_type = p._type;
_buf = p._buf;
_nframes = p._nframes;
_connected = p._connected;
_module = p._module;
hints = p.hints;
_scaled_signal = p._scaled_signal;
@ -170,9 +176,6 @@ public:
if ( _by_number_path )
free( _by_number_path );
_by_number_path = NULL;
// change_osc_path( NULL );
// disconnect();
}
const char *name ( void ) const { return _name; }
@ -242,44 +245,94 @@ public:
return 0.0f;
}
bool connected ( void ) const { return _connected; }
bool connected ( void ) const {
if ( _type == Port::AUDIO )
/* internal audio ports are considered connected by the buffer setting */
return _buf != 0;
else
/* control and external audio ports belong to a graph */
return _connected.size() > 0;
}
bool connected_osc ( void ) const;
Port *connected_port ( void ) const
{
return _connected;
ASSERT( _type == Port::CONTROL, "Operation only available for control ports" );
return _connected.size() == 0 ? NULL : _connected.front();
}
void connect_to ( Port *to )
{
_buf = to->_buf;
to->_connected = this;
_connected = to;
if ( _type != Port::AUX_AUDIO )
{
_buf = to->_buf;
}
if ( jack_port() && to->jack_port() )
jack_port()->connect( to->jack_port()->jack_name() );
if ( std::find(_connected.begin(),_connected.end(),to) == _connected.end() )
{
_connected.push_back(to);
to->_connected.push_back(this);
}
}
/* disconnect this port from any ports of modules belonging to strip /o/ */
void disconnect_from_strip ( Mixer_Strip *o );
void connect_to ( void *buf )
{
ASSERT( _type == Port::CONTROL, "Operation only available for control ports" );
_buf = buf;
update_connected_port_buffer();
}
void set_buffer ( void *buf )
{
ASSERT( _type != Port::CONTROL, "Operation only available for audio ports" );
_buf = buf;
}
void send_feedback ( void );
bool connected_to ( Port *p )
{
return std::find( _connected.begin(), _connected.end(), p ) != _connected.end();
}
/* disconnect from specified port */
void disconnect ( Port *p )
{
if ( ! connected_to(p) )
return;
if ( _type == Port::CONTROL && p->_module )
p->_module->handle_control_disconnect( this );
if ( jack_port() && p->jack_port() )
jack_port()->disconnect( p->jack_port()->jack_name() );
_connected.remove(p);
p->_connected.remove(this);
}
/* disconnect from *all* connected ports */
void disconnect ( void )
{
if ( _connected && _connected != (void*)0x01 )
if ( _connected.size() )
{
_connected->_connected = NULL;
for ( std::list<Port*>::iterator i = _connected.begin(); i != _connected.end(); i++ )
{
Port *p = *i;
if ( _connected->_module )
_connected->_module->handle_control_disconnect( this );
/* iterator about to be invalidated... */
i = _connected.erase(i);
_connected = NULL;
disconnect(p);
}
}
else
_connected = NULL;
/* FIXME: do something! */
}
void jack_port ( JACK::Port *v ) { _jack_port = v; }
@ -290,7 +343,7 @@ public:
char *generate_osc_path ( void );
void change_osc_path ( char *path );
Port *_connected;
std::list <Port*> _connected;
Type _type;
Direction _direction;
const char *_name;

View File

@ -58,6 +58,7 @@ char Project::_name[256];
char Project::_created_on[40];
char Project::_path[512];
bool Project::_is_open = false;
bool Project::_is_opening = false;
int Project::_lockfd = 0;
@ -261,6 +262,8 @@ Project::open ( const char *name )
if ( version != PROJECT_VERSION )
return E_VERSION;
_is_opening = true;
if ( ! Loggable::replay( "snapshot" ) )
return E_INVALID;
@ -279,6 +282,7 @@ Project::open ( const char *name )
_is_open = true;
_is_opening = false;
// tle->load_timeline_settings();
// timeline->zoom_fit();

View File

@ -27,6 +27,7 @@ class Project
static int _lockfd;
static bool _is_open;
static bool _is_opening;
static char _name[256];
static char _path[512];
static char _created_on[40];
@ -61,4 +62,5 @@ public:
static const char *path ( void ) { return _path; }
static const char *created_on ( void ) { return _created_on; }
static const bool is_opening ( void ) { return _is_opening; }
};

View File

@ -380,12 +380,20 @@ namespace JACK
{
const char *name = jack_port_name( _port );
/* jack complains when you attempt to connect an already connected port... */
if ( connected_to( to ) )
return 0;
if ( _direction == Output )
{
DMESSAGE("Connecting jack port %s to %s", name, to );
return jack_connect( _client->jack_client(), name, to );
}
else
{
DMESSAGE("Connecting jack port %s to %s", to, name );
return jack_connect( _client->jack_client(), to, name );
}
}
@ -398,10 +406,14 @@ namespace JACK
if ( _direction == Output )
{
DMESSAGE("Disconnecting jack port %s from %s", name, from );
return jack_disconnect( _client->jack_client(), name, from );
}
else
{
DMESSAGE("Disconnecting jack port %s from %s", from, name );
return jack_disconnect( _client->jack_client(), from, name );
}
}