From e1a41ba9c92445d0150c0cdcae16c13969292ab7 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Sat, 16 Jan 2010 18:38:27 -0600 Subject: [PATCH] Add hack to support 'renaming' of JACK::Client. We wouldn't need this if JACK had jack_client_set_name(). --- Mixer/Chain.C | 11 +++ Mixer/Controller_Module.C | 6 +- Mixer/JACK_Module.C | 8 +- Mixer/const.h | 2 + Timeline/Control_Sequence.C | 4 +- Timeline/Engine/Track.C | 4 +- Timeline/Transport.C | 2 +- nonlib/JACK/Client.C | 65 ++++++++++++++++ nonlib/JACK/Client.H | 15 +++- nonlib/JACK/Port.C | 150 ++++++++++++++++++++++++++++++++---- nonlib/JACK/Port.H | 57 +++++++++++--- 11 files changed, 286 insertions(+), 38 deletions(-) diff --git a/Mixer/Chain.C b/Mixer/Chain.C index db5af82..12f7787 100644 --- a/Mixer/Chain.C +++ b/Mixer/Chain.C @@ -77,6 +77,8 @@ #include +#include "const.h" + std::list Chain::chain; @@ -437,8 +439,17 @@ Chain::can_support_input_channels ( int n ) void Chain::name ( const char *name ) { + + char ename[512]; + snprintf( ename, sizeof(ename), "%s/%s", APP_NAME, name ); + + _name = engine()->name( ename ); + + /* FIXME: discarding the name jack picked is technically wrong! */ + _name = name; + for ( int i = 0; i < modules(); ++i ) module( i )->handle_chain_name_changed(); } diff --git a/Mixer/Controller_Module.C b/Mixer/Controller_Module.C index e3f9fb5..1b9ef64 100644 --- a/Mixer/Controller_Module.C +++ b/Mixer/Controller_Module.C @@ -166,10 +166,10 @@ Controller_Module::connect_to ( Port *p ) { chain()->engine()->lock(); - char name[256]; - snprintf( name, sizeof( name ), "%s-CV", p->name() ); +// char name[256]; +// snprintf( name, sizeof( name ), "%s-CV", p->name() ); - JACK::Port po( chain()->engine()->client(), JACK::Port::Input, chain()->name(), 0, name ); + JACK::Port po( chain()->engine(), JACK::Port::Input, p->name(), 0, "CV" ); if ( po.valid() ) { diff --git a/Mixer/JACK_Module.C b/Mixer/JACK_Module.C index 048d728..22faf13 100644 --- a/Mixer/JACK_Module.C +++ b/Mixer/JACK_Module.C @@ -86,7 +86,7 @@ JACK_Module::configure_inputs ( int n ) { for ( int i = on; i < n; ++i ) { - JACK::Port po( chain()->engine()->client(), JACK::Port::Output, chain()->name(), i ); + JACK::Port po( chain()->engine(), JACK::Port::Output, i ); if ( po.valid() ) { @@ -120,7 +120,7 @@ JACK_Module::configure_outputs ( int n ) { for ( int i = on; i < n; ++i ) { - JACK::Port po( chain()->engine()->client(), JACK::Port::Input, chain()->name(), i ); + JACK::Port po( chain()->engine(), JACK::Port::Input, i ); if ( po.valid() ) { @@ -188,10 +188,10 @@ void JACK_Module::handle_chain_name_changed ( void ) { for ( unsigned int i = 0; i < jack_output.size(); ++i ) - jack_output[ i ].name( chain()->name(), i ); + jack_output[ i ].name( NULL, i ); for ( unsigned int i = 0; i < jack_input.size(); ++i ) - jack_input[ i ].name( chain()->name(), i ); + jack_input[ i ].name( NULL, i ); } diff --git a/Mixer/const.h b/Mixer/const.h index 10d1e48..1cccaee 100644 --- a/Mixer/const.h +++ b/Mixer/const.h @@ -17,6 +17,8 @@ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ +#pragma once + #define APP_NAME "Non-Mixer" #define APP_TITLE "The Non-Mixer" #define __MODULE__ "non-mixer" diff --git a/Timeline/Control_Sequence.C b/Timeline/Control_Sequence.C index f4eb735..5feb38f 100644 --- a/Timeline/Control_Sequence.C +++ b/Timeline/Control_Sequence.C @@ -41,7 +41,7 @@ Control_Sequence::Control_Sequence ( Track *track ) : Sequence( 0 ) _track = track; - _output = new JACK::Port( engine->client(), JACK::Port::Output, track->name(), track->ncontrols(), "cv" ); + _output = new JACK::Port( engine, JACK::Port::Output, track->name(), track->ncontrols(), "cv" ); if ( track ) track->add( this ); @@ -110,7 +110,7 @@ Control_Sequence::set ( Log_Entry &e ) assert( t ); - _output = new JACK::Port( engine->client(), JACK::Port::Output, t->name(), t->ncontrols(), "cv" ); + _output = new JACK::Port( engine, JACK::Port::Output, t->name(), t->ncontrols(), "cv" ); t->add( this ); } diff --git a/Timeline/Engine/Track.C b/Timeline/Engine/Track.C index 2e0ed6f..2f54cf4 100644 --- a/Timeline/Engine/Track.C +++ b/Timeline/Engine/Track.C @@ -77,7 +77,7 @@ Track::configure_outputs ( int n ) { for ( int i = on; i < n; ++i ) { - JACK::Port p( engine->client(), JACK::Port::Output, name(), i ); + JACK::Port p( engine, JACK::Port::Output, name(), i ); if ( p.valid() ) output.push_back( p ); @@ -124,7 +124,7 @@ Track::configure_inputs ( int n ) { for ( int i = on; i < n; ++i ) { - JACK::Port p( engine->client(), JACK::Port::Input, name(), i ); + JACK::Port p( engine, JACK::Port::Input, name(), i ); if ( p.valid() ) input.push_back( p ); diff --git a/Timeline/Transport.C b/Timeline/Transport.C index f89bc23..e1d72f3 100644 --- a/Timeline/Transport.C +++ b/Timeline/Transport.C @@ -25,7 +25,7 @@ // Transport transport; -#define client engine->client() +#define client engine->jack_client() diff --git a/nonlib/JACK/Client.C b/nonlib/JACK/Client.C index 08df27f..a45d26d 100644 --- a/nonlib/JACK/Client.C +++ b/nonlib/JACK/Client.C @@ -18,6 +18,9 @@ /*******************************************************************************/ #include "Client.H" +#include "Port.H" + +#include @@ -146,4 +149,66 @@ namespace JACK // WARNING( "Unkown error while setting freewheeling mode" ); } + + void + Client::port_added ( Port *p ) + { + std::list < JACK::Port * >::iterator i = std::find( _active_ports.begin(), _active_ports.end(), p ); + + if ( i != _active_ports.end() ) + return; + + _active_ports.push_back( p ); + } + + void + Client::port_removed ( Port *p ) + { + _active_ports.remove( p ); + } + + + void + Client::freeze_ports ( void ) + { + for ( std::list < JACK::Port * >::iterator i = _active_ports.begin(); + i != _active_ports.end(); + ++i ) + { + (*i)->freeze(); + } + } + + void + Client::thaw_ports ( void ) + { + for ( std::list < JACK::Port * >::iterator i = _active_ports.begin(); + i != _active_ports.end(); + ++i ) + { + (*i)->thaw(); + } + } + + const char * + Client::name ( const char *s ) + { + /* Because the JACK API does not provide a mechanism for renaming + * clients, we have to save connections, destroy our client, + * create a client with the new name, and restore our + * connections. Lovely. */ + + freeze_ports(); + + jack_deactivate( _client ); + jack_client_close( _client ); + + _client = NULL; + + s = init( s ); + + thaw_ports(); + + return s; + } } diff --git a/nonlib/JACK/Client.H b/nonlib/JACK/Client.H index e3b0c60..5369bff 100644 --- a/nonlib/JACK/Client.H +++ b/nonlib/JACK/Client.H @@ -24,10 +24,16 @@ typedef jack_nframes_t nframes_t; typedef float sample_t; +#include + namespace JACK { + class Port; class Client { + + std::list _active_ports; + jack_client_t *_client; nframes_t _sample_rate; @@ -55,6 +61,9 @@ namespace JACK Client ( const Client &rhs ); Client & operator = ( const Client &rhs ); + void freeze_ports ( void ); + void thaw_ports ( void ); + protected: void deactivate ( void ); @@ -66,12 +75,16 @@ namespace JACK public: - jack_client_t * client ( void ) { return _client; } + jack_client_t * jack_client ( void ) { return _client; } + + void port_added ( JACK::Port * p ); + void port_removed ( JACK::Port *p ); Client ( ); virtual ~Client ( ); const char * init ( const char *client_name ); + const char * name ( const char * ); nframes_t nframes ( void ) const { return jack_get_buffer_size( _client ); } float frame_rate ( void ) const { return jack_get_sample_rate( _client ); } diff --git a/nonlib/JACK/Port.C b/nonlib/JACK/Port.C index 9fe4243..a6ef7a3 100644 --- a/nonlib/JACK/Port.C +++ b/nonlib/JACK/Port.C @@ -23,6 +23,7 @@ #include #include // sprintf +#include namespace JACK { @@ -35,22 +36,36 @@ namespace JACK return jack_port_name_size() - jack_client_name_size() - 6; } -/* nframes is the number of frames to buffer */ - Port::Port ( jack_client_t *client, jack_port_t *port ) + + Port::Port ( const Port &rhs ) { - _client = client; - _port = port; - _name = jack_port_name( _port ); + _freezer = rhs._freezer; + _client = rhs._client; + _port = rhs._port; + _name = strdup( rhs._name ); + + _client->port_added( this ); } - Port::Port ( jack_client_t *client, const char *name, type_e dir ) +/* nframes is the number of frames to buffer */ + Port::Port ( JACK::Client *client, jack_port_t *port ) { + _freezer = NULL; + _client = client; + _port = port; + _name = strdup( jack_port_name( _port ) ); + } + + Port::Port ( JACK::Client *client, const char *name, type_e dir ) + { + _freezer = NULL; _client = client; activate( name, dir ); } - Port::Port ( jack_client_t *client, type_e dir, const char *base, int n, const char *type ) + Port::Port ( JACK::Client *client, type_e dir, const char *base, int n, const char *type ) { + _freezer = NULL; _client = client; const char *name = name_for_port( dir, base, n, type ); @@ -58,8 +73,28 @@ namespace JACK activate( name, dir ); } + Port::Port ( JACK::Client *client, type_e dir, int n, const char *type ) + { + _freezer = NULL; + _client = client; + + const char *name = name_for_port( dir, NULL, n, type ); + + activate( name, dir ); + } + Port::~Port ( ) { + if ( _name ) + free( _name ); + + _client->port_removed( this ); +/* if ( _freezer ) */ +/* { */ +/* delete _freezer; */ +/* _freezer = NULL; */ +/* } */ + /* if ( _port ) */ /* jack_port_unregister( _client, _port ); */ @@ -74,15 +109,22 @@ namespace JACK const char *dir_s = dir == Port::Output ? "out" : "in"; - strncpy( pname, base, Port::max_name() ); + pname[0] = '\0'; + + if ( base ) + { + strncpy( pname, base, Port::max_name() ); + strcat( pname, "/" ); + } + pname[ Port::max_name() - 1 ] = '\0'; int l = strlen( pname ); if ( type ) - snprintf( pname + l, sizeof( pname ) - l, "/%s-%s-%d", type, dir_s, n + 1 ); + snprintf( pname + l, sizeof( pname ) - l, "%s-%s-%d", type, dir_s, n + 1 ); else - snprintf( pname + l, sizeof( pname ) - l, "/%s-%d", dir_s, n + 1 ); + snprintf( pname + l, sizeof( pname ) - l, "%s-%d", dir_s, n + 1 ); return pname; } @@ -90,11 +132,13 @@ namespace JACK void Port::activate ( const char *name, type_e dir ) { - _name = name; - _port = jack_port_register( _client, _name, + _name = strdup( name ); + _port = jack_port_register( _client->jack_client(), _name, JACK_DEFAULT_AUDIO_TYPE, dir == Output ? JackPortIsOutput : JackPortIsInput, 0 ); + + _client->port_added( this ); } /** returns the sum of latency of all ports between this one and a @@ -107,7 +151,7 @@ namespace JACK nframes_t Port::total_latency ( void ) const { - return jack_port_get_total_latency( _client, _port ); + return jack_port_get_total_latency( _client->jack_client() , _port ); } /** returns the number of frames of latency assigned to this port */ @@ -128,14 +172,16 @@ namespace JACK Port::shutdown ( void ) { if ( _port ) - jack_port_unregister( _client, _port ); + jack_port_unregister( _client->jack_client(), _port ); + + _client->port_removed( this ); } /** rename port */ bool Port::name ( const char *name ) { - _name = name; + _name = strdup( name ); return 0 == jack_port_set_name( _port, name ); } @@ -170,4 +216,78 @@ namespace JACK memset( buffer( nframes ), 0, nframes * sizeof( sample_t ) ); } + /** Return a malloc()'d null terminated array of strings + * representing all ports to which this port is connected. */ + const char ** + Port::connections ( void ) + { + return jack_port_get_connections( _port ); + } + + /** Restore the connections returned by connections() */ + bool + Port::connections ( const char **port_names ) + { + if ( ! port_names ) + return true; + + for ( const char **port_name = port_names; *port_name; ++port_name ) + { + const char *src; + const char *dst; + const char *name = jack_port_name( _port ); + + if ( type() == Output ) + { + src = name; + dst = *port_name; + } + else + { + src = *port_name; + dst = name; + } + + if ( int err = jack_connect( _client->jack_client(), src, dst ) ) + { + if ( EEXIST == err ) + { + /* connection already exists, not a problem */ + } + else + { + return false; + } + } + } + + return true; + } + + + void + Port::freeze ( void ) + { + if ( _freezer ) + delete _freezer; + + freeze_state *f = new freeze_state(); + + f->connections = connections(); + f->direction = type(); + f->name = strdup( name() ); + + _freezer = f; + } + + void + Port::thaw ( void ) + { + activate( name(), _freezer->direction ); + + connections( _freezer->connections ); + + delete _freezer; + _freezer = NULL; + } } diff --git a/nonlib/JACK/Port.H b/nonlib/JACK/Port.H index 39ec483..273a2f0 100644 --- a/nonlib/JACK/Port.H +++ b/nonlib/JACK/Port.H @@ -21,14 +21,15 @@ // #include #include "Client.H" +#include namespace JACK { class Port { jack_port_t *_port; - const char *_name; - jack_client_t *_client; + char *_name; + JACK::Client *_client; /* FIXME: reference count? */ @@ -42,18 +43,15 @@ namespace JACK static int max_name ( void ); - Port ( jack_client_t *client, jack_port_t *port ); - Port ( jack_client_t *client, const char *name, type_e dir ); - Port ( jack_client_t *client, type_e dir, const char *base, int n, const char *type=0 ); + Port ( JACK::Client *client, jack_port_t *port ); + Port ( JACK::Client *client, const char *name, type_e dir ); + Port ( JACK::Client *client, type_e dir, const char *base, int n, const char *type=0 ); + Port ( JACK::Client *client, type_e dir, int n, const char *type=0 ); // Port ( ); ~Port ( ); -/* Port ( const Port & rhs ) */ -/* { */ -/* _port = rhs.port; */ -/* _name = rhs.name; */ -/* } */ + Port ( const Port & rhs ); bool valid ( void ) const { return _port; } @@ -76,6 +74,45 @@ namespace JACK void read ( sample_t *buf, nframes_t nframes ); void *buffer ( nframes_t nframes ); void silence ( nframes_t nframes ); + + /* */ + const char ** connections ( void ); + bool connections ( const char **port_names ); + void freeze ( void ); + void thaw ( void ); + + private: + + /* holds all we need to know about a jack port to recreate it on a + new client */ + struct freeze_state + { + const char **connections; + type_e direction; + char *name; + + freeze_state ( ) + { + connections = NULL; + name = NULL; + } + + ~freeze_state ( ) + { + if ( connections ) + { + free( connections ); + connections = NULL; + } + if ( name ) + { + free( name ); + } + } + }; + + freeze_state *_freezer; + }; }