full compilation and linking (coding not finished, will not run)

This commit is contained in:
Paul Davis 2013-08-01 14:43:12 -04:00
parent 18c68bfd12
commit 682ebad62b
21 changed files with 538 additions and 214 deletions

View file

@ -296,18 +296,17 @@ class AudioBackend {
* It is extremely likely that any implementation will use a DLL, since * It is extremely likely that any implementation will use a DLL, since
* this function can be called from any thread, at any time, and must be * this function can be called from any thread, at any time, and must be
* able to accurately determine the correct sample time. * able to accurately determine the correct sample time.
*
* Can be called from any thread.
*/ */
virtual pframes_t sample_time () = 0; virtual pframes_t sample_time () = 0;
/** return the time according to the sample clock in use when the current /** Return the time according to the sample clock in use when the most
* buffer process cycle began. * recent buffer process cycle began. Can be called from any thread.
*
* Can ONLY be called from within a process() callback tree (which
* implies that it can only be called by a process thread)
*/ */
virtual pframes_t sample_time_at_cycle_start () = 0; virtual pframes_t sample_time_at_cycle_start () = 0;
/** return the time since the current buffer process cycle started, /** Return the time since the current buffer process cycle started,
* in samples, according to the sample clock in use. * in samples, according to the sample clock in use.
* *
* Can ONLY be called from within a process() callback tree (which * Can ONLY be called from within a process() callback tree (which
@ -315,7 +314,7 @@ class AudioBackend {
*/ */
virtual pframes_t samples_since_cycle_start () = 0; virtual pframes_t samples_since_cycle_start () = 0;
/** return true if it possible to determine the offset in samples of the /** Return true if it possible to determine the offset in samples of the
* first video frame that starts within the current buffer process cycle, * first video frame that starts within the current buffer process cycle,
* measured from the first sample of the cycle. If returning true, * measured from the first sample of the cycle. If returning true,
* set @param offset to that offset. * set @param offset to that offset.
@ -340,6 +339,8 @@ class AudioBackend {
*/ */
virtual int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize) = 0; virtual int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize) = 0;
virtual void update_latencies () = 0;
protected: protected:
AudioEngine& engine; AudioEngine& engine;
}; };

View file

@ -108,6 +108,16 @@ public:
bool is_realtime() const; bool is_realtime() const;
bool connected() const; bool connected() const;
int set_device_name (const std::string&);
int set_sample_rate (float);
int set_buffer_size (uint32_t);
int set_sample_format (SampleFormat);
int set_interleaved (bool yn);
int set_input_channels (uint32_t);
int set_output_channels (uint32_t);
int set_systemic_input_latency (uint32_t);
int set_systemic_output_latency (uint32_t);
/* END BACKEND PROXY API */ /* END BACKEND PROXY API */
bool freewheeling() const { return _freewheeling; } bool freewheeling() const { return _freewheeling; }
@ -115,7 +125,9 @@ public:
Glib::Threads::Mutex& process_lock() { return _process_lock; } Glib::Threads::Mutex& process_lock() { return _process_lock; }
int request_buffer_size (pframes_t); int request_buffer_size (pframes_t samples) {
return set_buffer_size (samples);
}
framecnt_t processed_frames() const { return _processed_frames; } framecnt_t processed_frames() const { return _processed_frames; }
@ -165,10 +177,6 @@ public:
PBD::Signal0<void> Running; PBD::Signal0<void> Running;
PBD::Signal0<void> Stopped; PBD::Signal0<void> Stopped;
std::string make_port_name_relative (std::string) const;
std::string make_port_name_non_relative (std::string) const;
bool port_is_mine (const std::string&) const;
static AudioEngine* instance() { return _instance; } static AudioEngine* instance() { return _instance; }
static void destroy(); static void destroy();
void died (); void died ();

View file

@ -99,6 +99,8 @@ class JACKAudioBackend : public AudioBackend {
int set_time_master (bool /*yn*/); int set_time_master (bool /*yn*/);
bool get_sync_offset (pframes_t& /*offset*/) const; bool get_sync_offset (pframes_t& /*offset*/) const;
void update_latencies ();
private: private:
boost::shared_ptr<JackConnection> _jack_connection; //< shared with JACKPortEngine boost::shared_ptr<JackConnection> _jack_connection; //< shared with JACKPortEngine
bool _running; bool _running;

View file

@ -38,8 +38,8 @@ class JACKPortEngine : public PortEngine
{ {
public: public:
JACKPortEngine (PortManager&, boost::shared_ptr<JackConnection>); JACKPortEngine (PortManager&, boost::shared_ptr<JackConnection>);
~JACKPortEngine();
bool connected() const;
void* private_handle() const; void* private_handle() const;
const std::string& my_name() const; const std::string& my_name() const;
@ -48,10 +48,6 @@ class JACKPortEngine : public PortEngine
std::string get_port_name (PortHandle) const; std::string get_port_name (PortHandle) const;
PortHandle* get_port_by_name (const std::string&) const; PortHandle* get_port_by_name (const std::string&) const;
std::string make_port_name_relative (const std::string& name) const;
std::string make_port_name_non_relative (const std::string& name) const;
bool port_is_mine (const std::string& fullname) const;
int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&) const; int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&) const;
DataType port_data_type (PortHandle) const; DataType port_data_type (PortHandle) const;
@ -62,19 +58,16 @@ class JACKPortEngine : public PortEngine
bool connected (PortHandle); bool connected (PortHandle);
bool connected_to (PortHandle, const std::string&); bool connected_to (PortHandle, const std::string&);
bool physically_connected (PortHandle); bool physically_connected (PortHandle);
int get_connections (PortHandle, std::vector<std::string>&); int get_connections (PortHandle, std::vector<std::string>&);
int connect (PortHandle, const std::string&); int connect (PortHandle, const std::string&);
int disconnect (PortHandle, const std::string&); int disconnect (PortHandle, const std::string&);
int disconnect_all (PortHandle); int disconnect_all (PortHandle);
int connect (const std::string& src, const std::string& dst); int connect (const std::string& src, const std::string& dst);
int disconnect (const std::string& src, const std::string& dst); int disconnect (const std::string& src, const std::string& dst);
/* MIDI */ /* MIDI */
void midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index); int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index);
int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size); int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
uint32_t get_midi_event_count (void* port_buffer); uint32_t get_midi_event_count (void* port_buffer);
void midi_clear (void* port_buffer); void midi_clear (void* port_buffer);
@ -91,7 +84,8 @@ class JACKPortEngine : public PortEngine
void set_latency_range (PortHandle, bool for_playback, LatencyRange); void set_latency_range (PortHandle, bool for_playback, LatencyRange);
LatencyRange get_latency_range (PortHandle, bool for_playback); LatencyRange get_latency_range (PortHandle, bool for_playback);
LatencyRange get_connected_latency_range (PortHandle, int dir);
/* Physical ports */
bool port_is_physical (PortHandle) const; bool port_is_physical (PortHandle) const;
void get_physical_outputs (DataType type, std::vector<std::string>&); void get_physical_outputs (DataType type, std::vector<std::string>&);
@ -99,9 +93,13 @@ class JACKPortEngine : public PortEngine
ChanCount n_physical_outputs () const; ChanCount n_physical_outputs () const;
ChanCount n_physical_inputs () const; ChanCount n_physical_inputs () const;
/* Getting access to the data buffer for a port */
void* get_buffer (PortHandle, pframes_t); void* get_buffer (PortHandle, pframes_t);
framecnt_t last_frame_time () const; /* Miscellany */
pframes_t sample_time_at_cycle_start ();
private: private:
boost::shared_ptr<JackConnection> _jack_connection; boost::shared_ptr<JackConnection> _jack_connection;
@ -110,10 +108,11 @@ class JACKPortEngine : public PortEngine
static void _registration_callback (jack_port_id_t, int, void *); static void _registration_callback (jack_port_id_t, int, void *);
static void _connect_callback (jack_port_id_t, jack_port_id_t, int, void *); static void _connect_callback (jack_port_id_t, jack_port_id_t, int, void *);
int graph_order_callback ();
void connect_callback (jack_port_id_t, jack_port_id_t, int); void connect_callback (jack_port_id_t, jack_port_id_t, int);
ChanCount n_physical (unsigned long flags) const;
void get_physical (DataType type, unsigned long flags, std::vector<std::string>& phy) const;
}; };
} // namespace } // namespace

View file

@ -77,7 +77,7 @@ class PortManager;
class PortEngine { class PortEngine {
public: public:
PortEngine (PortManager& pm) : manager (pm) {} PortEngine (PortManager& pm) : manager (pm) {}
virtual ~PortEngine(); virtual ~PortEngine() {}
/* We use void* here so that the API can be defined for any implementation. /* We use void* here so that the API can be defined for any implementation.
* *
@ -89,7 +89,6 @@ class PortEngine {
typedef void* PortHandle; typedef void* PortHandle;
virtual bool connected() const = 0;
virtual void* private_handle() const = 0; virtual void* private_handle() const = 0;
virtual const std::string& my_name() const = 0; virtual const std::string& my_name() const = 0;
@ -125,10 +124,10 @@ class PortEngine {
/* MIDI */ /* MIDI */
virtual void midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0; virtual int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0;
virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) = 0; virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) = 0;
virtual uint32_t get_midi_event_count (void* port_buffer); virtual uint32_t get_midi_event_count (void* port_buffer) = 0;
virtual void midi_clear (void* port_buffer); virtual void midi_clear (void* port_buffer) = 0;
/* Monitoring */ /* Monitoring */
@ -142,7 +141,6 @@ class PortEngine {
virtual void set_latency_range (PortHandle, bool for_playback, LatencyRange) = 0; virtual void set_latency_range (PortHandle, bool for_playback, LatencyRange) = 0;
virtual LatencyRange get_latency_range (PortHandle, bool for_playback) = 0; virtual LatencyRange get_latency_range (PortHandle, bool for_playback) = 0;
virtual LatencyRange get_connected_latency_range (PortHandle, int dir) = 0;
/* Discovering physical ports */ /* Discovering physical ports */
@ -158,7 +156,16 @@ class PortEngine {
virtual void* get_buffer (PortHandle, pframes_t) = 0; virtual void* get_buffer (PortHandle, pframes_t) = 0;
virtual framecnt_t last_frame_time() const = 0; /* MIDI ports (the ones in libmidi++) need this to be able to correctly
* schedule MIDI events within their buffers. It is a bit odd that we
* expose this here, because it is also exposed by AudioBackend, but they
* only have access to a PortEngine object, not an AudioBackend.
*
* Return the time according to the sample clock in use when the current
* buffer process cycle began.
*
*/
virtual pframes_t sample_time_at_cycle_start () = 0;
protected: protected:
PortManager& manager; PortManager& manager;

View file

@ -59,7 +59,6 @@ class PortManager
int connect (const std::string& source, const std::string& destination); int connect (const std::string& source, const std::string& destination);
int disconnect (const std::string& source, const std::string& destination); int disconnect (const std::string& source, const std::string& destination);
int disconnect (boost::shared_ptr<Port>); int disconnect (boost::shared_ptr<Port>);
bool has_connections (const std::string&);
int reestablish_ports (); int reestablish_ports ();
int reconnect_ports (); int reconnect_ports ();

View file

@ -48,6 +48,7 @@ namespace ARDOUR {
class TempoMap; class TempoMap;
class Session; class Session;
class AudioEngine;
/** /**
* @class Slave * @class Slave
@ -492,7 +493,7 @@ class MIDIClock_Slave : public Slave {
class JACK_Slave : public Slave class JACK_Slave : public Slave
{ {
public: public:
JACK_Slave (jack_client_t*); JACK_Slave (AudioEngine&);
~JACK_Slave (); ~JACK_Slave ();
bool speed_and_position (double& speed, framepos_t& pos); bool speed_and_position (double& speed, framepos_t& pos);
@ -502,11 +503,10 @@ class JACK_Slave : public Slave
bool ok() const; bool ok() const;
framecnt_t resolution () const { return 1; } framecnt_t resolution () const { return 1; }
bool requires_seekahead () const { return false; } bool requires_seekahead () const { return false; }
void reset_client (jack_client_t* jack);
bool is_always_synced() const { return true; } bool is_always_synced() const { return true; }
private: private:
jack_client_t* jack; AudioEngine& engine;
double speed; double speed;
bool _starting; bool _starting;
}; };

View file

@ -103,39 +103,6 @@ AudioEngine::create (const std::string& bcn, const std::string& bsu)
return new AudioEngine (bcn, bsu); return new AudioEngine (bcn, bsu);
} }
void
AudioEngine::drop_backend ()
{
if (_backend) {
_backend->stop ();
_backend.reset ();
}
}
int
AudioEngine::set_backend (const std::string& name)
{
BackendMap::iterator b = _backends.find (name);
if (b == _backends.end()) {
return -1;
}
drop_backend ();
try {
_backend = b->second->backend_factory (*this);
_impl = b->second->portengine_factory (*this);
} catch (...) {
error << string_compose (_("Could not create backend for %1"), name) << endmsg;
return -1;
}
return 0;
}
void void
_thread_init_callback (void * /*arg*/) _thread_init_callback (void * /*arg*/)
{ {
@ -570,6 +537,60 @@ AudioEngine::backend_discover (const string& path)
return info; return info;
} }
vector<string>
AudioEngine::available_backends() const
{
vector<string> r;
for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
r.push_back (i->first);
}
return r;
}
string
AudioEngine::current_backend_name() const
{
if (_backend) {
return _backend->name();
}
return string();
}
void
AudioEngine::drop_backend ()
{
if (_backend) {
_backend->stop ();
_backend.reset ();
}
}
int
AudioEngine::set_backend (const std::string& name)
{
BackendMap::iterator b = _backends.find (name);
if (b == _backends.end()) {
return -1;
}
drop_backend ();
try {
_backend = b->second->backend_factory (*this);
_impl = b->second->portengine_factory (*this);
} catch (...) {
error << string_compose (_("Could not create backend for %1"), name) << endmsg;
return -1;
}
return 0;
}
/* BACKEND PROXY WRAPPERS */ /* BACKEND PROXY WRAPPERS */
int int
@ -812,6 +833,89 @@ AudioEngine::create_process_thread (boost::function<void()> func, pthread_t* thr
} }
int
AudioEngine::set_device_name (const std::string& name)
{
if (!_backend) {
return -1;
}
return _backend->set_device_name (name);
}
int
AudioEngine::set_sample_rate (float sr)
{
if (!_backend) {
return -1;
}
return _backend->set_sample_rate (sr);
}
int
AudioEngine::set_buffer_size (uint32_t bufsiz)
{
if (!_backend) {
return -1;
}
return _backend->set_buffer_size (bufsiz);
}
int
AudioEngine::set_sample_format (SampleFormat sf)
{
if (!_backend) {
return -1;
}
return _backend->set_sample_format (sf);
}
int
AudioEngine::set_interleaved (bool yn)
{
if (!_backend) {
return -1;
}
return _backend->set_interleaved (yn);
}
int
AudioEngine::set_input_channels (uint32_t ic)
{
if (!_backend) {
return -1;
}
return _backend->set_input_channels (ic);
}
int
AudioEngine::set_output_channels (uint32_t oc)
{
if (!_backend) {
return -1;
}
return _backend->set_output_channels (oc);
}
int
AudioEngine::set_systemic_input_latency (uint32_t il)
{
if (!_backend) {
return -1;
}
return _backend->set_systemic_input_latency (il);
}
int
AudioEngine::set_systemic_output_latency (uint32_t ol)
{
if (!_backend) {
return -1;
}
return _backend->set_systemic_output_latency (ol);
}
/* END OF BACKEND PROXY API */
void void
AudioEngine::thread_init_callback (void* arg) AudioEngine::thread_init_callback (void* arg)
{ {
@ -873,6 +977,14 @@ AudioEngine::latency_callback (bool for_playback)
} }
} }
void
AudioEngine::update_latencies ()
{
if (_backend) {
_backend->update_latencies ();
}
}
void void
AudioEngine::halted_callback (const char* why) AudioEngine::halted_callback (const char* why)
{ {

View file

@ -450,6 +450,8 @@ Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine)
bool bool
Bundle::connected_to_anything (AudioEngine& engine) Bundle::connected_to_anything (AudioEngine& engine)
{ {
PortManager& pm (engine);
for (uint32_t i = 0; i < nchannels().n_total(); ++i) { for (uint32_t i = 0; i < nchannels().n_total(); ++i) {
Bundle::PortList const & ports = channel_ports (i); Bundle::PortList const & ports = channel_ports (i);
@ -459,7 +461,7 @@ Bundle::connected_to_anything (AudioEngine& engine)
rather than doing it with Port. rather than doing it with Port.
*/ */
if (engine.has_connections (ports[j])) { if (pm.connected (ports[j])) {
return true; return true;
} }
} }

View file

@ -818,3 +818,10 @@ JACKAudioBackend::cpu_load() const
GET_PRIVATE_JACK_POINTER_RET(_priv_jack,0); GET_PRIVATE_JACK_POINTER_RET(_priv_jack,0);
return jack_cpu_load (_priv_jack); return jack_cpu_load (_priv_jack);
} }
void
JACKAudioBackend::update_latencies ()
{
GET_PRIVATE_JACK_POINTER (_priv_jack);
jack_recompute_total_latencies (_priv_jack);
}

View file

@ -1,3 +1,35 @@
/*
Copyright (C) 2013 Paul Davis
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdint.h>
#include "pbd/failed_constructor.h"
#include "ardour/jack_portengine.h"
#include "ardour/jack_connection.h"
#include "ardour/port_manager.h"
using namespace ARDOUR;
using std::string;
using std::vector;
#define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; } #define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
#define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
@ -6,13 +38,13 @@ ardour_port_flags_to_jack_flags (PortFlags flags)
{ {
uint32_t jack_flags = 0; uint32_t jack_flags = 0;
if (flags & PortIsInput) { if (flags & IsInput) {
jack_flags |= JackPortIsInput; jack_flags |= JackPortIsInput;
} }
if (flags & IsInput) { if (flags & IsOutput) {
jack_flags |= JackPortIsOutput; jack_flags |= JackPortIsOutput;
} }
if (flags & IsOutput) { if (flags & IsTerminal) {
jack_flags |= JackPortIsTerminal; jack_flags |= JackPortIsTerminal;
} }
if (flags & IsPhysical) { if (flags & IsPhysical) {
@ -53,17 +85,63 @@ JACKPortEngine::JACKPortEngine (PortManager& pm, boost::shared_ptr<JackConnectio
: PortEngine (pm) : PortEngine (pm)
, _jack_connection (jc) , _jack_connection (jc)
{ {
jack_client_t* client = _jack_connection-> jack_client_t* client = _jack_connection->jack();
jack_set_port_registration_callback (_priv_jack, _registration_callback, this); if (!client) {
jack_set_port_connect_callback (_priv_jack, _connect_callback, this); throw failed_constructor ();
jack_set_graph_order_callback (_priv_jack, _graph_order_callback, this); }
/* register callbacks for stuff that is our responsibility */
jack_set_port_registration_callback (client, _registration_callback, this);
jack_set_port_connect_callback (client, _connect_callback, this);
jack_set_graph_order_callback (client, _graph_order_callback, this);
}
JACKPortEngine::~JACKPortEngine ()
{
/* a default destructor would do this, and so would this one,
but we'll make it explicit in case we ever need to debug
the lifetime of the JACKConnection
*/
_jack_connection.reset ();
}
void*
JACKPortEngine::private_handle() const
{
return _jack_connection->jack();
}
int
JACKPortEngine::set_port_name (PortHandle port, const std::string& name)
{
return jack_port_set_name ((jack_port_t*) port, name.c_str());
}
string
JACKPortEngine::get_port_name (PortHandle port) const
{
return jack_port_name ((jack_port_t*) port);
}
PortEngine::PortHandle*
JACKPortEngine:: get_port_by_name (const std::string& name) const
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0);
return (PortHandle*) jack_port_by_name (_priv_jack, name.c_str());
} }
void void
JACKPortEngine::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* arg) JACKPortEngine::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* arg)
{ {
static_cast<JACKPortEngine*> (arg)->_manager->registration_callback (); static_cast<JACKPortEngine*> (arg)->manager.registration_callback ();
}
int
JACKPortEngine::_graph_order_callback (void *arg)
{
return static_cast<JACKPortEngine*> (arg)->manager.graph_order_callback ();
} }
void void
@ -75,7 +153,7 @@ JACKPortEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int
void void
JACKPortEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn) JACKPortEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn)
{ {
if (_manager->port_remove_in_progress()) { if (manager.port_remove_in_progress()) {
return; return;
} }
@ -84,79 +162,90 @@ JACKPortEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int
jack_port_t* a = jack_port_by_id (_priv_jack, id_a); jack_port_t* a = jack_port_by_id (_priv_jack, id_a);
jack_port_t* b = jack_port_by_id (_priv_jack, id_b); jack_port_t* b = jack_port_by_id (_priv_jack, id_b);
_manager->connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true); manager.connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true);
} }
int bool
JACKPortEngine::_graph_order_callback (void *arg) JACKPortEngine::connected (PortHandle port)
{ {
return static_cast<JACKPortEngine*> (arg)->graph_order_callback (); bool ret = false;
}
int const char** ports = jack_port_get_connections ((jack_port_t*) port);
JACKPortEngine::graph_order_callback ()
{ if (ports) {
if (_jack_connection->connected()) { ret = true;
_manager->graph_order_callback ();
} }
return 0; jack_free (ports);
return ret;
} }
bool
JACKPortEngine::connected_to (PortHandle port, const std::string& other)
{
bool ret = false;
const char** ports = jack_port_get_connections ((jack_port_t*) port);
if (ports) {
for (int i = 0; ports[i]; ++i) {
if (other == ports[i]) {
ret = true;
}
}
jack_free (ports);
}
return ret;
}
bool
JACKPortEngine::physically_connected (PortHandle p) JACKPortEngine::physically_connected (PortHandle p)
{ {
jack_port_t* _jack_port = (jack_port_t*) p; GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
jack_port_t* port = (jack_port_t*) p;
const char** jc = jack_port_get_connections (_jack_port); const char** ports = jack_port_get_connections (port);
if (jc) { if (ports) {
for (int i = 0; jc[i]; ++i) { for (int i = 0; ports[i]; ++i) {
jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]); jack_port_t* other = jack_port_by_name (_priv_jack, ports[i]);
if (port && (jack_port_flags (port) & JackPortIsPhysical)) { if (other && (jack_port_flags (other) & JackPortIsPhysical)) {
if (jack_free) {
jack_free (jc);
} else {
free (jc);
}
return true; return true;
} }
} }
if (jack_free) { jack_free (ports);
jack_free (jc);
} else {
free (jc);
}
} }
return false; return false;
} }
DataType DataType
JACKPortEngine::port_data_type (PortHandle p) JACKPortEngine::port_data_type (PortHandle p) const
{ {
return jack_port_type_to_ardour_data_type (jack_port_type (p)); return jack_port_type_to_ardour_data_type (jack_port_type ((jack_port_t*) p));
} }
const string& const string&
JACKPortEngine::my_name() const JACKPortEngine::my_name() const
{ {
return _client_name; return _jack_connection->client_name();
} }
bool bool
JACKPortEngine::port_is_physical (PortHandle* ph) const JACKPortEngine::port_is_physical (PortHandle ph) const
{ {
if (!ph) { if (!ph) {
return false; return false;
} }
return jack_port_flags (ph) & JackPortIsPhysical; return jack_port_flags ((jack_port_t*) ph) & JackPortIsPhysical;
} }
int int
JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s) JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s) const
{ {
GET_PRIVATE_JACK_POINTER_RET (_priv_jack,0); GET_PRIVATE_JACK_POINTER_RET (_priv_jack,0);
@ -166,12 +255,11 @@ JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortF
ardour_port_flags_to_jack_flags (flags)); ardour_port_flags_to_jack_flags (flags));
if (ports == 0) { if (ports == 0) {
return s; return 0;
} }
for (uint32_t i = 0; ports[i]; ++i) { for (uint32_t i = 0; ports[i]; ++i) {
s.push_back (ports[i]); s.push_back (ports[i]);
jack_free (ports[i]);
} }
jack_free (ports); jack_free (ports);
@ -184,16 +272,15 @@ JACKPortEngine::n_physical (unsigned long flags) const
{ {
ChanCount c; ChanCount c;
GET_PRIVATE_JACK_POINTER_RET (_jack, c); GET_PRIVATE_JACK_POINTER_RET (_priv_jack, c);
const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags); const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
if (ports) { if (ports) {
for (uint32_t i = 0; ports[i]; ++i) { for (uint32_t i = 0; ports[i]; ++i) {
if (!strstr (ports[i], "Midi-Through")) { if (!strstr (ports[i], "Midi-Through")) {
DataType t (jack_port_type (jack_port_by_name (_jack, ports[i]))); DataType t (jack_port_type (jack_port_by_name (_priv_jack, ports[i])));
c.set (t, c.get (t) + 1); c.set (t, c.get (t) + 1);
jack_free (ports[i]);
} }
} }
@ -216,12 +303,12 @@ JACKPortEngine::n_physical_outputs () const
} }
void void
JACKPortEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy) JACKPortEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy) const
{ {
GET_PRIVATE_JACK_POINTER (_priv_jack); GET_PRIVATE_JACK_POINTER (_priv_jack);
const char ** ports; const char ** ports;
if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) { if ((ports = jack_get_ports (_priv_jack, NULL, ardour_data_type_to_jack_port_type (type), JackPortIsPhysical | flags)) == 0) {
return; return;
} }
@ -231,7 +318,6 @@ JACKPortEngine::get_physical (DataType type, unsigned long flags, vector<string>
continue; continue;
} }
phy.push_back (ports[i]); phy.push_back (ports[i]);
jack_free (ports[i]);
} }
jack_free (ports); jack_free (ports);
} }
@ -257,7 +343,7 @@ JACKPortEngine::get_physical_outputs (DataType type, vector<string>& outs)
bool bool
JACKPortEngine::can_request_hardware_monitoring () JACKPortEngine::can_monitor_input () const
{ {
GET_PRIVATE_JACK_POINTER_RET (_priv_jack,false); GET_PRIVATE_JACK_POINTER_RET (_priv_jack,false);
const char ** ports; const char ** ports;
@ -266,18 +352,131 @@ JACKPortEngine::can_request_hardware_monitoring ()
return false; return false;
} }
for (uint32_t i = 0; ports[i]; ++i) {
jack_free (ports[i]);
}
jack_free (ports); jack_free (ports);
return true; return true;
} }
framecnt_t pframes_t
JACKPortEngine::last_frame_time () const JACKPortEngine::sample_time_at_cycle_start ()
{ {
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0); GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0);
return jack_last_frame_time (_priv_jack); return jack_last_frame_time (_priv_jack);
} }
PortEngine::PortHandle
JACKPortEngine::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0);
return jack_port_register (_priv_jack, shortname.c_str(),
ardour_data_type_to_jack_port_type (type),
ardour_port_flags_to_jack_flags (flags),
0);
}
void
JACKPortEngine::unregister_port (PortHandle port)
{
GET_PRIVATE_JACK_POINTER (_priv_jack);
(void) jack_port_unregister (_priv_jack, (jack_port_t*) port);
}
int
JACKPortEngine::connect (PortHandle port, const std::string& other)
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
return jack_connect (_priv_jack, jack_port_name ((jack_port_t*) port), other.c_str());
}
int
JACKPortEngine::connect (const std::string& src, const std::string& dst)
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
return jack_connect (_priv_jack, src.c_str(), dst.c_str());
}
int
JACKPortEngine::disconnect (PortHandle port, const std::string& other)
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
return jack_disconnect (_priv_jack, jack_port_name ((jack_port_t*) port), other.c_str());
}
int
JACKPortEngine::disconnect (const std::string& src, const std::string& dst)
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
return jack_disconnect (_priv_jack, src.c_str(), dst.c_str());
}
int
JACKPortEngine::disconnect_all (PortHandle port)
{
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
return jack_port_disconnect (_priv_jack, (jack_port_t*) port);
}
int
JACKPortEngine::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index)
{
jack_midi_event_t ev;
int ret;
if ((ret = jack_midi_event_get (&ev, port_buffer, event_index)) == 0) {
timestamp = ev.time;
size = ev.size;
*buf = ev.buffer;
}
return ret;
}
int
JACKPortEngine::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)
{
return jack_midi_event_write (port_buffer, timestamp, buffer, size);
}
uint32_t
JACKPortEngine::get_midi_event_count (void* port_buffer)
{
return jack_midi_get_event_count (port_buffer);
}
void
JACKPortEngine::midi_clear (void* port_buffer)
{
jack_midi_clear_buffer (port_buffer);
}
void
JACKPortEngine::set_latency_range (PortHandle port, bool for_playback, LatencyRange r)
{
jack_latency_range_t range;
range.min = r.min;
range.max = r.max;
jack_port_set_latency_range ((jack_port_t*) port, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range);
}
LatencyRange
JACKPortEngine::get_latency_range (PortHandle port, bool for_playback)
{
jack_latency_range_t range;
LatencyRange ret;
jack_port_get_latency_range ((jack_port_t*) port, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range);
ret.min = range.min;
ret.max = range.max;
return ret;
}
void*
JACKPortEngine::get_buffer (PortHandle port, pframes_t nframes)
{
return jack_port_get_buffer ((jack_port_t*) port, nframes);
}

View file

@ -20,16 +20,14 @@
#include <iostream> #include <iostream>
#include <cerrno> #include <cerrno>
#include <jack/jack.h> #include "ardour/audioengine.h"
#include <jack/transport.h>
#include "ardour/slave.h" #include "ardour/slave.h"
using namespace std; using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
JACK_Slave::JACK_Slave (jack_client_t* j) JACK_Slave::JACK_Slave (AudioEngine& e)
: jack (j) : engine (e)
{ {
double x; double x;
framepos_t p; framepos_t p;
@ -41,12 +39,6 @@ JACK_Slave::~JACK_Slave ()
{ {
} }
void
JACK_Slave::reset_client (jack_client_t* j)
{
jack = j;
}
bool bool
JACK_Slave::locked() const JACK_Slave::locked() const
{ {
@ -62,33 +54,26 @@ JACK_Slave::ok() const
bool bool
JACK_Slave::speed_and_position (double& sp, framepos_t& position) JACK_Slave::speed_and_position (double& sp, framepos_t& position)
{ {
jack_position_t pos; switch (engine.transport_state()) {
jack_transport_state_t state; case TransportStopped:
state = jack_transport_query (jack, &pos);
switch (state) {
case JackTransportStopped:
speed = 0; speed = 0;
_starting = false; _starting = false;
break; break;
case JackTransportRolling: case TransportRolling:
speed = 1.0; speed = 1.0;
_starting = false; _starting = false;
break; break;
case JackTransportLooping: case TransportLooping:
speed = 1.0; speed = 1.0;
_starting = false; _starting = false;
break; break;
case JackTransportStarting: case TransportStarting:
_starting = true; _starting = true;
// don't adjust speed here, just leave it as it was // don't adjust speed here, just leave it as it was
break; break;
default:
cerr << "WARNING: Unknown JACK transport state: " << state << endl;
} }
sp = speed; sp = speed;
position = pos.frame; position = engine.transport_frame();
return true; return true;
} }

View file

@ -70,10 +70,6 @@ Port::Port (std::string const & n, DataType t, PortFlags f)
assert (_name.find_first_of (':') == std::string::npos); assert (_name.find_first_of (':') == std::string::npos);
if (!port_engine.connected()) {
throw failed_constructor ();
}
if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) { if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n"; cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
throw failed_constructor (); throw failed_constructor ();
@ -124,14 +120,6 @@ Port::disconnect_all ()
bool bool
Port::connected_to (std::string const & o) const Port::connected_to (std::string const & o) const
{ {
if (!port_engine.connected()) {
/* in some senses, this answer isn't the right one all the time,
because we know about our connections and will re-establish
them when we reconnect to the port engine.
*/
return false;
}
return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o)); return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
} }

View file

@ -127,6 +127,30 @@ PortManager::port_is_physical (const std::string& portname) const
return _impl->port_is_physical (ph); return _impl->port_is_physical (ph);
} }
void
PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
{
_impl->get_physical_outputs (type, s);
}
void
PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
{
_impl->get_physical_inputs (type, s);
}
ChanCount
PortManager::n_physical_outputs () const
{
return _impl->n_physical_outputs ();
}
ChanCount
PortManager::n_physical_inputs () const
{
return _impl->n_physical_inputs ();
}
/** @param name Full or short name of port /** @param name Full or short name of port
* @return Corresponding Port or 0. * @return Corresponding Port or 0.
*/ */
@ -134,11 +158,6 @@ PortManager::port_is_physical (const std::string& portname) const
boost::shared_ptr<Port> boost::shared_ptr<Port>
PortManager::get_port_by_name (const string& portname) PortManager::get_port_by_name (const string& portname)
{ {
if (!_impl->connected()) {
fatal << _("get_port_by_name() called before engine was started") << endmsg;
/*NOTREACHED*/
}
if (!port_is_mine (portname)) { if (!port_is_mine (portname)) {
/* not an ardour port */ /* not an ardour port */
return boost::shared_ptr<Port> (); return boost::shared_ptr<Port> ();
@ -254,13 +273,6 @@ PortManager::unregister_port (boost::shared_ptr<Port> port)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
if (!_impl->connected()) {
/* probably happening when the engine has been halted by JACK,
in which case, there is nothing we can do here.
*/
return 0;
}
{ {
RCUWriter<Ports> writer (ports); RCUWriter<Ports> writer (ports);
boost::shared_ptr<Ports> ps = writer.get_copy (); boost::shared_ptr<Ports> ps = writer.get_copy ();
@ -295,10 +307,6 @@ PortManager::connect (const string& source, const string& destination)
{ {
int ret; int ret;
if (!_impl->connected()) {
return -1;
}
string s = make_port_name_non_relative (source); string s = make_port_name_non_relative (source);
string d = make_port_name_non_relative (destination); string d = make_port_name_non_relative (destination);
@ -330,10 +338,6 @@ PortManager::disconnect (const string& source, const string& destination)
{ {
int ret; int ret;
if (!_impl->connected()) {
return -1;
}
string s = make_port_name_non_relative (source); string s = make_port_name_non_relative (source);
string d = make_port_name_non_relative (destination); string d = make_port_name_non_relative (destination);
@ -429,3 +433,30 @@ PortManager::registration_callback ()
PortRegisteredOrUnregistered (); /* EMIT SIGNAL */ PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
} }
} }
bool
PortManager::can_request_input_monitoring () const
{
return _impl->can_monitor_input ();
}
void
PortManager::request_input_monitoring (const string& name, bool yn) const
{
PortEngine::PortHandle ph = _impl->get_port_by_name (name);
if (ph) {
_impl->request_input_monitoring (ph, yn);
}
}
void
PortManager::ensure_input_monitoring (const string& name, bool yn) const
{
PortEngine::PortHandle ph = _impl->get_port_by_name (name);
if (ph) {
_impl->ensure_input_monitoring (ph, yn);
}
}

View file

@ -967,7 +967,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
DEBUG_TRACE (DEBUG::Processors, string_compose ( DEBUG_TRACE (DEBUG::Processors, string_compose (
"%1 adding processor %2\n", name(), processor->name())); "%1 adding processor %2\n", name(), processor->name()));
if (!AudioEngine::instance()->port_engine().connected() || !processor) { if (!AudioEngine::instance()->connected() || !processor) {
return 1; return 1;
} }
@ -1132,7 +1132,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
loc = _processors.end (); loc = _processors.end ();
} }
if (!_session.engine().port_engine().connected()) { if (!_session.engine().connected()) {
return 1; return 1;
} }
@ -1329,7 +1329,7 @@ Route::ab_plugins (bool forward)
void void
Route::clear_processors (Placement p) Route::clear_processors (Placement p)
{ {
if (!_session.engine().port_engine().connected()) { if (!_session.engine().connected()) {
return; return;
} }
@ -1416,7 +1416,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
return 0; return 0;
} }
if (!_session.engine().port_engine().connected()) { if (!_session.engine().connected()) {
return 1; return 1;
} }
@ -1508,7 +1508,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
{ {
ProcessorList deleted; ProcessorList deleted;
if (!_session.engine().port_engine().connected()) { if (!_session.engine().connected()) {
return 1; return 1;
} }

View file

@ -170,7 +170,7 @@ Session::Session (AudioEngine &eng,
interpolation.add_channel_to (0, 0); interpolation.add_channel_to (0, 0);
if (!eng.port_engine().connected()) { if (!eng.connected()) {
throw failed_constructor(); throw failed_constructor();
} }
@ -4677,7 +4677,7 @@ Session::set_worst_playback_latency ()
_worst_output_latency = 0; _worst_output_latency = 0;
if (!_engine.port_engine().connected()) { if (!_engine.connected()) {
return; return;
} }
@ -4699,7 +4699,7 @@ Session::set_worst_capture_latency ()
_worst_input_latency = 0; _worst_input_latency = 0;
if (!_engine.port_engine().connected()) { if (!_engine.connected()) {
return; return;
} }

View file

@ -147,7 +147,7 @@ Session::start_audio_export (framepos_t position)
/* we are ready to go ... */ /* we are ready to go ... */
if (!_engine.port_engine().connected()) { if (!_engine.connected()) {
return -1; return -1;
} }

View file

@ -765,7 +765,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
return 1; return 1;
} }
if (!_engine.port_engine().connected ()) { if (!_engine.connected ()) {
error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
PROGRAM_NAME) PROGRAM_NAME)
<< endmsg; << endmsg;

View file

@ -44,7 +44,6 @@
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/slave.h" #include "ardour/slave.h"
#include "ardour/operations.h" #include "ardour/operations.h"
#include "ardour/jack_portengine.h"
#include "i18n.h" #include "i18n.h"
@ -1417,13 +1416,6 @@ Session::switch_to_sync_source (SyncSource src)
break; break;
case JACK: case JACK:
/* if we are not using JACK as the port engine, we can't do
* this
*/
if (dynamic_cast<JACKPortEngine*>(&AudioEngine::instance()->port_engine())) {
return;
}
if (_slave && dynamic_cast<JACK_Slave*>(_slave)) { if (_slave && dynamic_cast<JACK_Slave*>(_slave)) {
return; return;
} }
@ -1432,7 +1424,7 @@ Session::switch_to_sync_source (SyncSource src)
return; return;
} }
new_slave = new JACK_Slave ((jack_client_t*) AudioEngine::instance()->port_engine().private_handle()); new_slave = new JACK_Slave (*AudioEngine::instance());
break; break;
default: default:
@ -1622,16 +1614,6 @@ Session::allow_auto_play (bool yn)
auto_play_legal = yn; auto_play_legal = yn;
} }
void
Session::reset_jack_connection (jack_client_t* jack)
{
JACK_Slave* js;
if (_slave && ((js = dynamic_cast<JACK_Slave*> (_slave)) != 0)) {
js->reset_client (jack);
}
}
bool bool
Session::maybe_stop (framepos_t limit) Session::maybe_stop (framepos_t limit)
{ {

View file

@ -43,6 +43,7 @@ libardour_sources = [
'automation_control.cc', 'automation_control.cc',
'automation_list.cc', 'automation_list.cc',
'automation_watch.cc', 'automation_watch.cc',
'backend_search_path.cc',
'beats_frames_converter.cc', 'beats_frames_converter.cc',
'broadcast_info.cc', 'broadcast_info.cc',
'buffer.cc', 'buffer.cc',
@ -439,7 +440,8 @@ def build(bld):
source = [ source = [
'jack_api.cc', 'jack_api.cc',
'jack_connection.cc', 'jack_connection.cc',
'jack_audiobackend.cc' 'jack_audiobackend.cc',
'jack_portengine.cc'
]) ])
obj.cxxflags = [ '-fPIC' ] obj.cxxflags = [ '-fPIC' ]
obj.name = 'jack_audiobackend' obj.name = 'jack_audiobackend'

View file

@ -155,7 +155,7 @@ JackMIDIPort::cycle_start (pframes_t nframes)
pframes_t time; pframes_t time;
size_t size; size_t size;
uint8_t* buf; uint8_t* buf;
timestamp_t cycle_start_frame = _port_engine.last_frame_time (); timestamp_t cycle_start_frame = _port_engine.sample_time_at_cycle_start ();
for (pframes_t i = 0; i < event_count; ++i) { for (pframes_t i = 0; i < event_count; ++i) {
_port_engine.midi_event_get (time, size, &buf, buffer, i); _port_engine.midi_event_get (time, size, &buf, buffer, i);