start work on JACK specific audiobackend and port engine

This commit is contained in:
Paul Davis 2013-07-25 22:40:21 -04:00
parent 20b1a7d9d8
commit c7b000f401
2 changed files with 328 additions and 29 deletions

View file

@ -17,8 +17,13 @@
*/ */
#include <math.h>
#include <jack/jack.h> #include <jack/jack.h>
#include <boost/scoped_ptr.hpp>
#include "pbd/epa.h"
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/types.h" #include "ardour/types.h"
#include "ardour/jack_audiobackend.h" #include "ardour/jack_audiobackend.h"
@ -29,6 +34,20 @@ using std::string;
#define GET_PRIVATE_JACK_POINTER(j) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return; } #define GET_PRIVATE_JACK_POINTER(j) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return; }
#define GET_PRIVATE_JACK_POINTER_RET(j,r) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return r; } #define GET_PRIVATE_JACK_POINTER_RET(j,r) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return r; }
extern "C" {
/* functions looked up using dlopen-and-cousins, and so naming scope
* must be non-mangled.
*/
AudioBackend* backend_factory (AudioEngine& ae)
{
JACKAudioBackend* ab = new JACKAudioBackend (ae);
return ab;
}
}
JACKAudioBackend::JACKAudioBackend (AudioEngine& e) JACKAudioBackend::JACKAudioBackend (AudioEngine& e)
: AudioBackend (e) : AudioBackend (e)
, _jack (0) , _jack (0)
@ -43,13 +62,274 @@ JACKAudioBackend::JACKAudioBackend (AudioEngine& e)
{ {
} }
string
JACKAudioBackend::name() const
{
return X_("JACK");
}
void*
JACKAudioBackend::private_handle()
{
return _jack;
}
bool
JACKAudioBackend::connected() const
{
return (_jack != 0);
}
bool
JACKAudioBackend::is_realtime ()
{
GET_PRIVATE_JACK_POINTER_RET (_jack,false);
return jack_is_realtime (_priv_jack);
}
vector<string>
JACKAudioBackend::enumerate_devices () const
{
vector<string> devices;
return devices;
}
vector<float>
JACKAudioBackend::available_sample_rates (const string& /*device*/) const
{
vector<float> f;
if (_jack) {
f.push_back (get_sample_rate());
return f;
}
/* if JACK is not already running, just list a bunch of reasonable
values and let the future sort it all out.
*/
f.push_back (8000.0);
f.push_back (16000.0);
f.push_back (24000.0);
f.push_back (32000.0);
f.push_back (44100.0);
f.push_back (48000.0);
f.push_back (88200.0);
f.push_back (96000.0);
f.push_back (192000.0);
f.push_back (384000.0);
return f;
}
vector<uint32_t>
JACKAudioBackend::available_buffer_sizes (const string& /*device*/) const
{
vector<uint32_t> s;
if (_jack) {
s.push_back (get_buffer_size());
return s;
}
s.push_back (8);
s.push_back (16);
s.push_back (32);
s.push_back (64);
s.push_back (128);
s.push_back (256);
s.push_back (512);
s.push_back (1024);
s.push_back (2048);
s.push_back (4096);
s.push_back (8192);
return s;
}
uint32_t
JACKAudioBackend::available_input_channel_count (const string& /*device*/)
{
return 128;
}
uint32_t
JACKAudioBackend::available_output_channel_count (const string& /*device*/)
{
return 128;
}
/* -- parameter setting -- */
int int
JACKAudioBackend::set_device_name (const string& dev) JACKAudioBackend::set_device_name (const string& dev)
{ {
if (_jack) {
/* need to stop and restart JACK for this to work, at present */
return -1;
}
_target_device = dev; _target_device = dev;
return 0; return 0;
} }
int
JACKAudioBackend::set_sample_rate (float sr)
{
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
if (sr == jack_get_sample_rate (_priv_jack)) {
return 0;
}
return jack_set_sample_rate (_priv_jack, lrintf (sr));
}
int
JACKAudioBackend::set_buffer_size (uint32_t nframes)
{
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
if (nframes == jack_get_buffer_size (_priv_jack)) {
return 0;
}
return jack_set_buffer_size (_priv_jack, nframes);
}
int
JACKAudioBackend::set_sample_format (SampleFormat sf)
{
/* as far as JACK clients are concerned, the hardware is always
* floating point format.
*/
if (sf == FloatingPoint) {
return 0;
}
return -1;
}
int
JACKAudioBackend::set_interleaved (bool yn)
{
/* as far as JACK clients are concerned, the hardware is always
* non-interleaved
*/
if (!yn) {
return 0;
}
return -1;
}
int
JACKAudioBackend::set_input_channels (uint32_t cnt)
{
if (_jack) {
return -1;
}
_target_input_channels = cnt;
}
int
JACKAudioBackend::set_output_channels (uint32_t cnt)
{
if (_jack) {
return -1;
}
_target_output_channels = cnt;
}
int
JACKAudioBackend::set_systemic_input_latency (uint32_t l)
{
if (_jack) {
return -1;
}
_target_systemic_input_latency = l;
}
int
JACKAudioBackend::set_systemic_output_latency (uint32_t l)
{
if (_jack) {
return -1;
}
_target_systemic_output_latency = l;
}
/* --- Parameter retrieval --- */
std::string
JACKAudioBackend::get_device_name () const
{
}
float
JACKAudioBackend::get_sample_rate () const
{
if (_jack) {
return _current_sample_rate;
}
return _target_sample_rate;
}
uint32_t
JACKAudioBackend::get_buffer_size () const
{
if (_jack) {
return _current_buffer_size;
}
return _target_buffer_size;
}
SampleFormat
JACKAudioBackend::get_sample_format () const
{
return FloatingPoint;
}
bool
JACKAudioBackend::get_interleaved () const
{
return false;
}
uint32_t
JACKAudioBackend::get_input_channels () const
{
if (_jack) {
return n_physical (JackPortIsInput);
}
return _target_input_channels;
}
uint32_t
JACKAudioBackend::get_output_channels () const
{
if (_jack) {
return n_physical (JackPortIsOutput);
}
return _target_output_channels;
}
uint32_t
JACKAudioBackend::get_systemic_input_latency () const
{
return _current_systemic_output_latency;
}
uint32_t
JACKAudioBackend::get_systemic_output_latency () const
{
return _current_systemic_output_latency;
}
/* ---- BASIC STATE CONTROL API: start/stop/pause/freewheel --- */
int int
JACKAudioBackend::start () JACKAudioBackend::start ()
{ {
@ -223,6 +503,7 @@ JACKAudioBackend::connect_to_jack (string client_name, string session_uuid)
int int
JACKAudioBackend::disconnect_from_jack () JACKAudioBackend::disconnect_from_jack ()
{ {
}
int int
JACKAudioBackend::reconnect_to_jack () JACKAudioBackend::reconnect_to_jack ()
@ -290,18 +571,6 @@ JACKAudioBackend::reconnect_to_jack ()
return 0; return 0;
} }
int
JACKAudioBackend::request_buffer_size (pframes_t nframes)
{
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
if (nframes == jack_get_buffer_size (_priv_jack)) {
return 0;
}
return jack_set_buffer_size (_priv_jack, nframes);
}
/* --- TRANSPORT STATE MANAGEMENT --- */ /* --- TRANSPORT STATE MANAGEMENT --- */
void void
@ -353,12 +622,22 @@ JACKAudioBackend::set_time_master (bool yn)
/* process-time */ /* process-time */
framecnt_t frame_rate () const; framecnt_t
pframes_t frames_per_cycle () const; JACKAudioBackend::sample_rate () const
{
size_t raw_buffer_size(DataType t); }
pframes_t
JACKAudioBackend::samples_per_cycle () const
{
}
int usecs_per_cycle () const { return _usecs_per_cycle; } size_t
JACKAudioBackend::raw_buffer_size(DataType t)
{
std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
return (s != _raw_buffer_sizes.end()) ? s->second : 0;
}
bool bool
JACKAudioBackend::get_sync_offset (pframes_t& offset) const JACKAudioBackend::get_sync_offset (pframes_t& offset) const
@ -586,7 +865,6 @@ JACKAudioBackend::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, in
Ports::iterator x; Ports::iterator x;
boost::shared_ptr<Ports> pr = ports.reader (); boost::shared_ptr<Ports> pr = ports.reader ();
x = pr->find (make_port_name_relative (jack_port_name (jack_port_a))); x = pr->find (make_port_name_relative (jack_port_name (jack_port_a)));
if (x != pr->end()) { if (x != pr->end()) {
port_a = x->second; port_a = x->second;
@ -706,14 +984,14 @@ JACKAudioBackend::jack_bufsize_callback (pframes_t nframes)
{ {
/* if the size has not changed, this should be a no-op */ /* if the size has not changed, this should be a no-op */
if (nframes == _buffer_size) { if (nframes == _current_buffer_size) {
return 0; return 0;
} }
GET_PRIVATE_JACK_POINTER_RET (_jack, 1); GET_PRIVATE_JACK_POINTER_RET (_jack, 1);
_buffer_size = nframes; _current_buffer_size = nframes;
_usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0); _current_usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
last_monitor_check = 0; last_monitor_check = 0;
if (jack_port_type_get_buffer_size) { if (jack_port_type_get_buffer_size) {
@ -736,15 +1014,7 @@ JACKAudioBackend::jack_bufsize_callback (pframes_t nframes)
_raw_buffer_sizes[DataType::MIDI] = nframes * 4 - (nframes/2); _raw_buffer_sizes[DataType::MIDI] = nframes * 4 - (nframes/2);
} }
{ BufferSizeChange (nframes);
Glib::Threads::Mutex::Lock lm (_process_lock);
boost::shared_ptr<Ports> p = ports.reader();
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
i->second->reset();
}
}
if (_session) { if (_session) {
_session->set_block_size (_buffer_size); _session->set_block_size (_buffer_size);

View file

@ -0,0 +1,29 @@
JACKPortEngine::physically_connected (PortHandle p)
{
jack_port_t* _jack_port = (jack_port_t*) p;
const char** jc = jack_port_get_connections (_jack_port);
if (jc) {
for (int i = 0; jc[i]; ++i) {
jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]);
if (port && (jack_port_flags (port) & JackPortIsPhysical)) {
if (jack_free) {
jack_free (jc);
} else {
free (jc);
}
return true;
}
}
if (jack_free) {
jack_free (jc);
} else {
free (jc);
}
}
return false;
}