split up session code that uses parts of the JACK API (timebase + session event handling) and connect it directly to the jack audiobackend

i've made the audiobackend call the session directly so that only one object (ARDOUR::Session) has a need for the JACK types
and only one .cc file (session_jack.cc) needs jack.h. having ARDOUR::AudioEngine act as an intermediary would be cleaner
conceptually but would end up causing two different ARDOUR objects to have jack types in their own API.
This commit is contained in:
Paul Davis 2013-08-09 12:15:37 -04:00
parent da74519911
commit a34d707175
9 changed files with 213 additions and 203 deletions

View File

@ -161,10 +161,6 @@ ARDOUR_UI::set_session (Session *s)
_session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
_session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
#ifdef HAVE_JACK_SESSION
engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
#endif
/* Clocks are on by default after we are connected to a session, so show that here.
*/

View File

@ -129,7 +129,8 @@ public:
void set_session (Session *);
void remove_session (); // not a replacement for SessionHandle::session_going_away()
Session* session() const { return _session; }
class NoBackendAvailable : public std::exception {
public:
virtual const char *what() const throw() { return "could not connect to engine backend"; }
@ -148,12 +149,7 @@ public:
PBD::Signal1<int, pframes_t> Freewheel;
PBD::Signal0<void> Xrun;
#ifdef HAVE_JACK_SESSION
PBD::Signal1<void,jack_session_event_t *> JackSessionEvent;
#endif
/* this signal is emitted if the sample rate changes */
PBD::Signal1<void, framecnt_t> SampleRateChanged;

View File

@ -381,9 +381,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
framecnt_t worst_track_latency () const { return _worst_track_latency; }
framecnt_t worst_playback_latency () const { return _worst_output_latency + _worst_track_latency; }
#ifdef HAVE_JACK_SESSION
void jack_session_event (jack_session_event_t* event);
#endif
int save_state (std::string snapshot_name, bool pending = false, bool switch_to_snapshot = false);
int restore_state (std::string snapshot_name);
int save_template (std::string template_name);
@ -863,6 +860,15 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
boost::shared_ptr<IO> ltc_input_io() { return _ltc_input; }
boost::shared_ptr<IO> ltc_output_io() { return _ltc_output; }
/* Callbacks specifically related to JACK, and called directly
* from the JACK audio backend.
*/
#ifdef HAVE_JACK_SESSION
void jack_session_event (jack_session_event_t* event);
#endif
void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
protected:
friend class AudioEngine;
void set_block_size (pframes_t nframes);
@ -1436,9 +1442,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
*/
std::list<GQuark> _current_trans_quarks;
// void timebase_callback (TransportState, pframes_t, jack_position_t*, int);
int jack_sync_callback (TransportState, framepos_t);
void reset_jack_connection (jack_client_t* jack);
int backend_sync_callback (TransportState, framepos_t);
void process_rtop (SessionEvent*);
void update_latency (bool playback);

View File

@ -891,21 +891,11 @@ AudioEngine::thread_init_callback (void* arg)
}
}
/* XXXX
void
AudioEngine::timebase_callback (TransportState state, pframes_t nframes, jack_position_t pos, int new_position)
{
if (_session && _session->synced_to_jack()) {
// _session->timebase_callback (state, nframes, pos, new_position);
}
}
*/
int
AudioEngine::sync_callback (TransportState state, framepos_t position)
{
if (_session) {
return _session->jack_sync_callback (state, position);
return _session->backend_sync_callback (state, position);
}
return 0;
}

View File

@ -28,7 +28,9 @@
#include "jack/thread.h"
#include "ardour/audioengine.h"
#include "ardour/session.h"
#include "ardour/types.h"
#include "ardour/jack_audiobackend.h"
#include "ardour/jack_connection.h"
#include "ardour/jack_portengine.h"
@ -680,32 +682,14 @@ JACKAudioBackend::_jack_timebase_callback (jack_transport_state_t state, pframes
}
void
JACKAudioBackend::jack_timebase_callback (jack_transport_state_t state, pframes_t /*nframes*/,
jack_position_t* pos, int /*new_position*/)
JACKAudioBackend::jack_timebase_callback (jack_transport_state_t state, pframes_t nframes,
jack_position_t* pos, int new_position)
{
TransportState tstate;
framepos_t position;
ARDOUR::Session* session = engine.session();
switch (state) {
case JackTransportStopped:
tstate = TransportStopped;
break;
case JackTransportRolling:
tstate = TransportRolling;
break;
case JackTransportLooping:
tstate = TransportLooping;
break;
case JackTransportStarting:
tstate = TransportStarting;
break;
if (session) {
session->jack_timebase_callback (state, nframes, pos, new_position);
}
if (pos) {
position = pos->frame;
}
// engine.timebase_callback (tstate, nframes, position, new_position);
}
int
@ -754,8 +738,10 @@ void
JACKAudioBackend::_session_callback (jack_session_event_t *event, void *arg)
{
JACKAudioBackend* ae = static_cast<JACKAudioBackend*> (arg);
if (ae->connected()) {
ae->engine.JackSessionEvent (event); /* EMIT SIGNAL */
ARDOUR::Session* session = ae->engine.session();
if (session) {
session->jack_session_event (event);
}
}
#endif

185
libs/ardour/session_jack.cc Normal file
View File

@ -0,0 +1,185 @@
/*
Copyright (C) 1999-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.
*/
#ifdef WAF_BUILD
#include "libardour-config.h"
#endif
#include <time.h>
#include <glibmm/miscutils.h>
#include "jack/jack.h"
#include "jack/session.h"
#include "ardour/audioengine.h"
#include "ardour/filename_extensions.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
#include "ardour/tempo.h"
using namespace ARDOUR;
using std::string;
#ifdef HAVE_JACK_SESSION
void
Session::jack_session_event (jack_session_event_t* event)
{
char timebuf[128], *tmp;
time_t n;
struct tm local_time;
time (&n);
localtime_r (&n, &local_time);
strftime (timebuf, sizeof(timebuf), "JS_%FT%T", &local_time);
while ((tmp = strchr(timebuf, ':'))) { *tmp = '.'; }
if (event->type == JackSessionSaveTemplate)
{
if (save_template( timebuf )) {
event->flags = JackSessionSaveError;
} else {
string cmd ("ardour3 -P -U ");
cmd += event->client_uuid;
cmd += " -T ";
cmd += timebuf;
event->command_line = strdup (cmd.c_str());
}
}
else
{
if (save_state (timebuf)) {
event->flags = JackSessionSaveError;
} else {
std::string xml_path (_session_dir->root_path());
std::string legalized_filename = legalize_for_path (timebuf) + statefile_suffix;
xml_path = Glib::build_filename (xml_path, legalized_filename);
string cmd ("ardour3 -P -U ");
cmd += event->client_uuid;
cmd += " \"";
cmd += xml_path;
cmd += '\"';
event->command_line = strdup (cmd.c_str());
}
}
/* this won't be called if the port engine in use is not JACK, so we do
not have to worry about the type of PortEngine::private_handle()
*/
jack_client_t* jack_client = (jack_client_t*) AudioEngine::instance()->port_engine().private_handle();
if (jack_client) {
jack_session_reply (jack_client, event);
}
if (event->type == JackSessionSaveAndQuit) {
Quit (); /* EMIT SIGNAL */
}
jack_session_event_free( event );
}
#endif
void
Session::jack_timebase_callback (jack_transport_state_t /*state*/,
pframes_t /*nframes*/,
jack_position_t* pos,
int /*new_position*/)
{
Timecode::BBT_Time bbt;
/* BBT info */
if (_tempo_map) {
TempoMetric metric (_tempo_map->metric_at (_transport_frame));
try {
_tempo_map->bbt_time_rt (_transport_frame, bbt);
pos->bar = bbt.bars;
pos->beat = bbt.beats;
pos->tick = bbt.ticks;
// XXX still need to set bar_start_tick
pos->beats_per_bar = metric.meter().divisions_per_bar();
pos->beat_type = metric.meter().note_divisor();
pos->ticks_per_beat = Timecode::BBT_Time::ticks_per_beat;
pos->beats_per_minute = metric.tempo().beats_per_minute();
pos->valid = jack_position_bits_t (pos->valid | JackPositionBBT);
} catch (...) {
/* no message */
}
}
#ifdef HAVE_JACK_VIDEO_SUPPORT
//poke audio video ratio so Ardour can track Video Sync
pos->audio_frames_per_video_frame = frame_rate() / timecode_frames_per_second();
pos->valid = jack_position_bits_t (pos->valid | JackAudioVideoRatio);
#endif
#if 0
/* Timecode info */
pos->timecode_offset = config.get_timecode_offset();
t.timecode_frame_rate = timecode_frames_per_second();
pos->valid = jack_position_bits_t (pos->valid | JackPositionTimecode;
if (_transport_speed) {
if (play_loop) {
Location* location = _locations.auto_loop_location();
if (location) {
t.transport_state = JackTransportLooping;
t.loop_start = location->start();
t.loop_end = location->end();
t.valid = jack_transport_bits_t (t.valid | JackTransportLoop);
} else {
t.loop_start = 0;
t.loop_end = 0;
t.transport_state = JackTransportRolling;
}
} else {
t.loop_start = 0;
t.loop_end = 0;
t.transport_state = JackTransportRolling;
}
}
#endif
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 1999-2002 Paul Davis
Copyright (C) 1999-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
@ -689,70 +689,6 @@ Session::remove_state (string snapshot_name)
}
}
#ifdef HAVE_JACK_SESSION
void
Session::jack_session_event (jack_session_event_t * event)
{
char timebuf[128], *tmp;
time_t n;
struct tm local_time;
time (&n);
localtime_r (&n, &local_time);
strftime (timebuf, sizeof(timebuf), "JS_%FT%T", &local_time);
while ((tmp = strchr(timebuf, ':'))) { *tmp = '.'; }
if (event->type == JackSessionSaveTemplate)
{
if (save_template( timebuf )) {
event->flags = JackSessionSaveError;
} else {
string cmd ("ardour3 -P -U ");
cmd += event->client_uuid;
cmd += " -T ";
cmd += timebuf;
event->command_line = strdup (cmd.c_str());
}
}
else
{
if (save_state (timebuf)) {
event->flags = JackSessionSaveError;
} else {
std::string xml_path (_session_dir->root_path());
std::string legalized_filename = legalize_for_path (timebuf) + statefile_suffix;
xml_path = Glib::build_filename (xml_path, legalized_filename);
string cmd ("ardour3 -P -U ");
cmd += event->client_uuid;
cmd += " \"";
cmd += xml_path;
cmd += '\"';
event->command_line = strdup (cmd.c_str());
}
}
/* this won't be called if the port engine in use is not JACK, so we do
not have to worry about the type of PortEngine::private_handle()
*/
jack_client_t* jack_client = (jack_client_t*) AudioEngine::instance()->port_engine().private_handle();
if (jack_client) {
jack_session_reply (jack_client, event);
}
if (event->type == JackSessionSaveAndQuit) {
Quit (); /* EMIT SIGNAL */
}
jack_session_event_free( event );
}
#endif
/** @param snapshot_name Name to save under, without .ardour / .pending prefix */
int
Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)

View File

@ -180,7 +180,7 @@ Session::timecode_time (Timecode::Time &t)
}
int
Session::jack_sync_callback (TransportState state, framepos_t pos)
Session::backend_sync_callback (TransportState state, framepos_t pos)
{
bool slave = synced_to_jack();
@ -218,91 +218,6 @@ Session::jack_sync_callback (TransportState state, framepos_t pos)
return true;
}
/* XXX REQUIRES SOMEWAY TO EFFICIENTLY ACCESS jack_position_t WITHOUT BRIDGING
* THE ENTIRE DATA STRUCTURE
*/
#if 0
void
Session::jack_timebase_callback (TransportState /*state*/,
pframes_t /*nframes*/,
framepos_t pos,
int /*new_position*/)
{
Timecode::BBT_Time bbt;
/* BBT info */
if (_tempo_map) {
TempoMetric metric (_tempo_map->metric_at (_transport_frame));
try {
_tempo_map->bbt_time_rt (_transport_frame, bbt);
pos->bar = bbt.bars;
pos->beat = bbt.beats;
pos->tick = bbt.ticks;
// XXX still need to set bar_start_tick
pos->beats_per_bar = metric.meter().divisions_per_bar();
pos->beat_type = metric.meter().note_divisor();
pos->ticks_per_beat = Timecode::BBT_Time::ticks_per_beat;
pos->beats_per_minute = metric.tempo().beats_per_minute();
pos->valid = jack_position_bits_t (pos->valid | JackPositionBBT);
} catch (...) {
/* no message */
}
}
#ifdef HAVE_JACK_VIDEO_SUPPORT
//poke audio video ratio so Ardour can track Video Sync
pos->audio_frames_per_video_frame = frame_rate() / timecode_frames_per_second();
pos->valid = jack_position_bits_t (pos->valid | JackAudioVideoRatio);
#endif
#if 0
/* Timecode info */
pos->timecode_offset = config.get_timecode_offset();
t.timecode_frame_rate = timecode_frames_per_second();
pos->valid = jack_position_bits_t (pos->valid | JackPositionTimecode;
if (_transport_speed) {
if (play_loop) {
Location* location = _locations.auto_loop_location();
if (location) {
t.transport_state = JackTransportLooping;
t.loop_start = location->start();
t.loop_end = location->end();
t.valid = jack_transport_bits_t (t.valid | JackTransportLoop);
} else {
t.loop_start = 0;
t.loop_end = 0;
t.transport_state = JackTransportRolling;
}
} else {
t.loop_start = 0;
t.loop_end = 0;
t.transport_state = JackTransportRolling;
}
}
#endif
}
#endif /* jack data structure issues */
ARDOUR::framecnt_t
Session::convert_to_frames (AnyTime const & position)

View File

@ -180,6 +180,7 @@ libardour_sources = [
'session_events.cc',
'session_export.cc',
'session_handle.cc',
'session_jack.cc',
'session_ltc.cc',
'session_metadata.cc',
'session_midi.cc',