mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 23:35:03 +01:00
incomplete merge of master into windows (requires upcoming changes to master to be complete)
This commit is contained in:
commit
bb826f4bee
153 changed files with 9655 additions and 5514 deletions
|
|
@ -58,8 +58,8 @@ vector<RefPtr<Gtk::Action> > ActionManager::playlist_selection_sensitive_actions
|
|||
vector<RefPtr<Gtk::Action> > ActionManager::mouse_edit_point_requires_canvas_actions;
|
||||
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::range_sensitive_actions;
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::jack_sensitive_actions;
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::jack_opposite_sensitive_actions;
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::engine_sensitive_actions;
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::engine_opposite_sensitive_actions;
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::transport_sensitive_actions;
|
||||
vector<RefPtr<Gtk::Action> > ActionManager::edit_point_in_region_sensitive_actions;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ namespace ActionManager {
|
|||
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > range_sensitive_actions;
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > transport_sensitive_actions;
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > jack_sensitive_actions;
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > jack_opposite_sensitive_actions;
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > engine_sensitive_actions;
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > engine_opposite_sensitive_actions;
|
||||
extern std::vector<Glib::RefPtr<Gtk::Action> > edit_point_in_region_sensitive_actions;
|
||||
|
||||
extern void map_some_state (const char* group, const char* action, bool (ARDOUR::RCConfiguration::*get)() const);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export ARDOUR_DATA_PATH=$TOP:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour:
|
|||
export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.
|
||||
export ARDOUR_MCP_PATH=$TOP/mcp:.
|
||||
export ARDOUR_EXPORT_FORMATS_PATH=$TOP/export:.
|
||||
export ARDOUR_BACKEND_PATH=$libs/backends/jack
|
||||
|
||||
#
|
||||
# even though we set the above variables, ardour requires that these
|
||||
|
|
|
|||
|
|
@ -495,27 +495,27 @@
|
|||
<menuitem action='show-marker-lines'/>
|
||||
</menu>
|
||||
<menu name='JACK' action='JACK'>
|
||||
<menuitem action='JACKDisconnect'/>
|
||||
<menuitem action='JACKReconnect'/>
|
||||
<menuitem action='EngineDisconnect'/>
|
||||
<menuitem action='EngineReconnect'/>
|
||||
<menu name='Latency' action='Latency'>
|
||||
<menuitem action='JACKLatency32'/>
|
||||
<menuitem action='JACKLatency64'/>
|
||||
<menuitem action='JACKLatency128'/>
|
||||
<menuitem action='JACKLatency256'/>
|
||||
<menuitem action='JACKLatency512'/>
|
||||
<menuitem action='JACKLatency1024'/>
|
||||
<menuitem action='JACKLatency2048'/>
|
||||
<menuitem action='JACKLatency4096'/>
|
||||
<menuitem action='JACKLatency8192'/>
|
||||
<menuitem action='EngineLatency32'/>
|
||||
<menuitem action='EngineLatency64'/>
|
||||
<menuitem action='EngineLatency128'/>
|
||||
<menuitem action='EngineLatency256'/>
|
||||
<menuitem action='EngineLatency512'/>
|
||||
<menuitem action='EngineLatency1024'/>
|
||||
<menuitem action='EngineLatency2048'/>
|
||||
<menuitem action='EngineLatency4096'/>
|
||||
<menuitem action='EngineLatency8192'/>
|
||||
</menu>
|
||||
</menu>
|
||||
<menu action = 'WindowMenu'>
|
||||
<menuitem action='toggle-audio-midi-setup'/>
|
||||
<separator/>
|
||||
<menuitem action='toggle-mixer'/>
|
||||
<menuitem action='toggle-meterbridge'/>
|
||||
<menuitem action='toggle-editor-mixer'/>
|
||||
|
||||
<separator/>
|
||||
|
||||
<menuitem action='toggle-inspector'/>
|
||||
<menuitem action='toggle-locations'/>
|
||||
<menuitem action='toggle-key-editor'/>
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ style "large_bold_text"
|
|||
font_name = "bold @FONT_LARGE@"
|
||||
}
|
||||
|
||||
style "big_text"
|
||||
{
|
||||
font_name = "@FONT_BIG@"
|
||||
}
|
||||
|
||||
style "bigger_mono_text"
|
||||
{
|
||||
font_name = "@MONOSPACE@ @FONT_BIGGER@"
|
||||
|
|
|
|||
|
|
@ -1011,3 +1011,8 @@ style "meter_strip_sep" = "default"
|
|||
{
|
||||
bg[NORMAL] = { 0.0, 0.0, 0.0 }
|
||||
}
|
||||
|
||||
style "settings_notebook" = "big_text"
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,9 +62,8 @@
|
|||
#include "gtkmm2ext/popup.h"
|
||||
#include "gtkmm2ext/window_title.h"
|
||||
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
#include "ardour/audio_backend.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/audiofilesource.h"
|
||||
#include "ardour/automation_watch.h"
|
||||
|
|
@ -162,10 +161,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
/* start of private members */
|
||||
|
||||
, _startup (0)
|
||||
, engine (0)
|
||||
, nsm (0)
|
||||
, _was_dirty (false)
|
||||
, _mixer_on_top (false)
|
||||
, first_time_engine_run (true)
|
||||
|
||||
/* transport */
|
||||
|
||||
|
|
@ -207,7 +206,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
|
||||
, _status_bar_visibility (X_("status-bar"))
|
||||
, _feedback_exists (false)
|
||||
|
||||
, _audio_midi_setup (0)
|
||||
{
|
||||
Gtkmm2ext::init(localedir);
|
||||
|
||||
|
|
@ -218,12 +217,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
}
|
||||
|
||||
ui_config = new UIConfiguration();
|
||||
_audio_midi_setup = new EngineControl;
|
||||
|
||||
editor = 0;
|
||||
mixer = 0;
|
||||
meterbridge = 0;
|
||||
editor = 0;
|
||||
engine = 0;
|
||||
_session_is_new = false;
|
||||
session_selector_window = 0;
|
||||
last_key_press_time = 0;
|
||||
|
|
@ -271,6 +270,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
|
||||
ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
|
||||
|
||||
/* handle Audio/MIDI setup when session requires it */
|
||||
|
||||
ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
|
||||
|
||||
/* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
|
||||
|
||||
ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
|
||||
|
|
@ -369,6 +372,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
_process_thread->init ();
|
||||
|
||||
DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
|
||||
|
||||
attach_to_engine ();
|
||||
}
|
||||
|
||||
GlobalPortMatrixWindow*
|
||||
|
|
@ -380,42 +385,146 @@ ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
|
|||
return new GlobalPortMatrixWindow (_session, type);
|
||||
}
|
||||
|
||||
int
|
||||
ARDOUR_UI::create_engine ()
|
||||
void
|
||||
ARDOUR_UI::attach_to_engine ()
|
||||
{
|
||||
// this gets called every time by new_session()
|
||||
AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
|
||||
AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
|
||||
AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
|
||||
|
||||
if (engine) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
loading_message (_("Starting audio engine"));
|
||||
|
||||
try {
|
||||
engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
|
||||
|
||||
} catch (...) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
|
||||
engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
|
||||
engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
|
||||
|
||||
engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
|
||||
AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
|
||||
|
||||
ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
|
||||
|
||||
post_engine ();
|
||||
/* if there is only one audio/midi backend, and it does not require setup, get our use of it underway
|
||||
* right here (we need to know the client name and potential session ID
|
||||
* to do this, which is why this is here, rather than in, say,
|
||||
* ARDOUR::init().
|
||||
*/
|
||||
|
||||
return 0;
|
||||
if (!AudioEngine::instance()->setup_required()) {
|
||||
const AudioBackendInfo* backend = AudioEngine::instance()->available_backends().front();
|
||||
AudioEngine::instance()->set_backend (backend->name, ARDOUR_COMMAND_LINE::backend_client_name, ARDOUR_COMMAND_LINE::backend_session_uuid);
|
||||
AudioEngine::instance()->start ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::engine_stopped ()
|
||||
{
|
||||
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
|
||||
ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
|
||||
ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::engine_running ()
|
||||
{
|
||||
if (first_time_engine_run) {
|
||||
post_engine();
|
||||
first_time_engine_run = false;
|
||||
}
|
||||
|
||||
ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
|
||||
ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
|
||||
|
||||
Glib::RefPtr<Action> action;
|
||||
const char* action_name = 0;
|
||||
|
||||
switch (AudioEngine::instance()->samples_per_cycle()) {
|
||||
case 32:
|
||||
action_name = X_("JACKLatency32");
|
||||
break;
|
||||
case 64:
|
||||
action_name = X_("JACKLatency64");
|
||||
break;
|
||||
case 128:
|
||||
action_name = X_("JACKLatency128");
|
||||
break;
|
||||
case 512:
|
||||
action_name = X_("JACKLatency512");
|
||||
break;
|
||||
case 1024:
|
||||
action_name = X_("JACKLatency1024");
|
||||
break;
|
||||
case 2048:
|
||||
action_name = X_("JACKLatency2048");
|
||||
break;
|
||||
case 4096:
|
||||
action_name = X_("JACKLatency4096");
|
||||
break;
|
||||
case 8192:
|
||||
action_name = X_("JACKLatency8192");
|
||||
break;
|
||||
default:
|
||||
/* XXX can we do anything useful ? */
|
||||
break;
|
||||
}
|
||||
|
||||
if (action_name) {
|
||||
|
||||
action = ActionManager::get_action (X_("JACK"), action_name);
|
||||
|
||||
if (action) {
|
||||
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
|
||||
ract->set_active ();
|
||||
}
|
||||
|
||||
update_disk_space ();
|
||||
update_cpu_load ();
|
||||
update_sample_rate (AudioEngine::instance()->sample_rate());
|
||||
update_timecode_format ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
|
||||
{
|
||||
if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
|
||||
/* we can't rely on the original string continuing to exist when we are called
|
||||
again in the GUI thread, so make a copy and note that we need to
|
||||
free it later.
|
||||
*/
|
||||
char *copy = strdup (reason);
|
||||
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
|
||||
return;
|
||||
}
|
||||
|
||||
ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
|
||||
ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
|
||||
|
||||
update_sample_rate (0);
|
||||
|
||||
string msgstr;
|
||||
|
||||
/* if the reason is a non-empty string, it means that the backend was shutdown
|
||||
rather than just Ardour.
|
||||
*/
|
||||
|
||||
if (strlen (reason)) {
|
||||
msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
|
||||
} else {
|
||||
msgstr = string_compose (_("\
|
||||
JACK has either been shutdown or it\n\
|
||||
disconnected %1 because %1\n\
|
||||
was not fast enough. Try to restart\n\
|
||||
JACK, reconnect and save the session."), PROGRAM_NAME);
|
||||
}
|
||||
|
||||
MessageDialog msg (*editor, msgstr);
|
||||
pop_back_splash (msg);
|
||||
msg.set_keep_above (true);
|
||||
msg.run ();
|
||||
|
||||
if (free_reason) {
|
||||
free (const_cast<char*> (reason));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::post_engine ()
|
||||
{
|
||||
/* Things to be done once we create the AudioEngine
|
||||
/* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
|
||||
*/
|
||||
|
||||
ARDOUR::init_post_engine ();
|
||||
|
|
@ -481,25 +590,9 @@ ARDOUR_UI::post_engine ()
|
|||
Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
|
||||
#endif
|
||||
|
||||
update_disk_space ();
|
||||
update_cpu_load ();
|
||||
update_sample_rate (engine->frame_rate());
|
||||
update_timecode_format ();
|
||||
|
||||
Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
|
||||
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
|
||||
Config->map_parameters (pc);
|
||||
|
||||
/* now start and maybe save state */
|
||||
|
||||
if (do_engine_start () == 0) {
|
||||
if (_session && _session_is_new) {
|
||||
/* we need to retain initial visual
|
||||
settings for a new session
|
||||
*/
|
||||
_session->save_state ("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ARDOUR_UI::~ARDOUR_UI ()
|
||||
|
|
@ -685,6 +778,7 @@ ARDOUR_UI::startup ()
|
|||
{
|
||||
Application* app = Application::instance ();
|
||||
char *nsm_url;
|
||||
|
||||
app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
|
||||
app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
|
||||
|
||||
|
|
@ -779,7 +873,7 @@ ARDOUR_UI::check_memory_locking ()
|
|||
|
||||
XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
|
||||
|
||||
if (engine->is_realtime() && memory_warning_node == 0) {
|
||||
if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
|
||||
|
||||
struct rlimit limits;
|
||||
int64_t ram;
|
||||
|
|
@ -919,7 +1013,8 @@ If you still wish to quit, please use the\n\n\
|
|||
_session = 0;
|
||||
}
|
||||
|
||||
engine->stop (true);
|
||||
halt_connection.disconnect ();
|
||||
AudioEngine::instance()->stop ();
|
||||
quit ();
|
||||
}
|
||||
|
||||
|
|
@ -1048,22 +1143,28 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
|
|||
|
||||
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
|
||||
|
||||
if (!engine->connected()) {
|
||||
if (!AudioEngine::instance()->connected()) {
|
||||
|
||||
snprintf (buf, sizeof (buf), "%s", _("disconnected"));
|
||||
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
|
||||
|
||||
} else {
|
||||
|
||||
framecnt_t rate = engine->frame_rate();
|
||||
framecnt_t rate = AudioEngine::instance()->sample_rate();
|
||||
|
||||
if (fmod (rate, 1000.0) != 0.0) {
|
||||
snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
|
||||
(float) rate/1000.0f,
|
||||
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
|
||||
if (rate == 0) {
|
||||
/* no sample rate available */
|
||||
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
|
||||
} else {
|
||||
snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
|
||||
rate/1000,
|
||||
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
|
||||
|
||||
if (fmod (rate, 1000.0) != 0.0) {
|
||||
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
|
||||
(float) rate / 1000.0f,
|
||||
(AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
|
||||
} else {
|
||||
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
|
||||
rate/1000,
|
||||
(AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1133,7 +1234,7 @@ ARDOUR_UI::update_cpu_load ()
|
|||
should also be changed.
|
||||
*/
|
||||
|
||||
float const c = engine->get_cpu_load ();
|
||||
float const c = AudioEngine::instance()->get_cpu_load ();
|
||||
snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
|
||||
cpu_load_label.set_markup (buf);
|
||||
}
|
||||
|
|
@ -1187,6 +1288,11 @@ ARDOUR_UI::update_disk_space()
|
|||
char buf[64];
|
||||
framecnt_t fr = _session->frame_rate();
|
||||
|
||||
if (fr == 0) {
|
||||
/* skip update - no SR available */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!opt_frames) {
|
||||
/* Available space is unknown */
|
||||
snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
|
||||
|
|
@ -1449,20 +1555,16 @@ ARDOUR_UI::open_recent_session ()
|
|||
bool
|
||||
ARDOUR_UI::check_audioengine ()
|
||||
{
|
||||
if (engine) {
|
||||
if (!engine->connected()) {
|
||||
MessageDialog msg (string_compose (
|
||||
_("%1 is not connected to JACK\n"
|
||||
"You cannot open or close sessions in this condition"),
|
||||
PROGRAM_NAME));
|
||||
pop_back_splash (msg);
|
||||
msg.run ();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (!AudioEngine::instance()->connected()) {
|
||||
MessageDialog msg (string_compose (
|
||||
_("%1 is not connected to any audio backend.\n"
|
||||
"You cannot open or close sessions in this condition"),
|
||||
PROGRAM_NAME));
|
||||
pop_back_splash (msg);
|
||||
msg.run ();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1669,9 +1771,16 @@ ARDOUR_UI::transport_goto_wallclock ()
|
|||
time (&now);
|
||||
localtime_r (&now, &tmnow);
|
||||
|
||||
frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
|
||||
frames += tmnow.tm_min * (60 * _session->frame_rate());
|
||||
frames += tmnow.tm_sec * _session->frame_rate();
|
||||
int frame_rate = _session->frame_rate();
|
||||
|
||||
if (frame_rate == 0) {
|
||||
/* no frame rate available */
|
||||
return;
|
||||
}
|
||||
|
||||
frames = tmnow.tm_hour * (60 * 60 * frame_rate);
|
||||
frames += tmnow.tm_min * (60 * frame_rate);
|
||||
frames += tmnow.tm_sec * frame_rate;
|
||||
|
||||
_session->request_locate (frames, _session->transport_rolling ());
|
||||
|
||||
|
|
@ -2031,127 +2140,6 @@ ARDOUR_UI::map_transport_state ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::engine_stopped ()
|
||||
{
|
||||
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
|
||||
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
|
||||
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::engine_running ()
|
||||
{
|
||||
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
|
||||
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
|
||||
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
|
||||
|
||||
Glib::RefPtr<Action> action;
|
||||
const char* action_name = 0;
|
||||
|
||||
switch (engine->frames_per_cycle()) {
|
||||
case 32:
|
||||
action_name = X_("JACKLatency32");
|
||||
break;
|
||||
case 64:
|
||||
action_name = X_("JACKLatency64");
|
||||
break;
|
||||
case 128:
|
||||
action_name = X_("JACKLatency128");
|
||||
break;
|
||||
case 512:
|
||||
action_name = X_("JACKLatency512");
|
||||
break;
|
||||
case 1024:
|
||||
action_name = X_("JACKLatency1024");
|
||||
break;
|
||||
case 2048:
|
||||
action_name = X_("JACKLatency2048");
|
||||
break;
|
||||
case 4096:
|
||||
action_name = X_("JACKLatency4096");
|
||||
break;
|
||||
case 8192:
|
||||
action_name = X_("JACKLatency8192");
|
||||
break;
|
||||
default:
|
||||
/* XXX can we do anything useful ? */
|
||||
break;
|
||||
}
|
||||
|
||||
if (action_name) {
|
||||
|
||||
action = ActionManager::get_action (X_("JACK"), action_name);
|
||||
|
||||
if (action) {
|
||||
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
|
||||
ract->set_active ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
|
||||
{
|
||||
if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
|
||||
/* we can't rely on the original string continuing to exist when we are called
|
||||
again in the GUI thread, so make a copy and note that we need to
|
||||
free it later.
|
||||
*/
|
||||
char *copy = strdup (reason);
|
||||
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
|
||||
return;
|
||||
}
|
||||
|
||||
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
|
||||
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
|
||||
|
||||
update_sample_rate (0);
|
||||
|
||||
string msgstr;
|
||||
|
||||
/* if the reason is a non-empty string, it means that the backend was shutdown
|
||||
rather than just Ardour.
|
||||
*/
|
||||
|
||||
if (strlen (reason)) {
|
||||
msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
|
||||
} else {
|
||||
msgstr = string_compose (_("\
|
||||
JACK has either been shutdown or it\n\
|
||||
disconnected %1 because %1\n\
|
||||
was not fast enough. Try to restart\n\
|
||||
JACK, reconnect and save the session."), PROGRAM_NAME);
|
||||
}
|
||||
|
||||
MessageDialog msg (*editor, msgstr);
|
||||
pop_back_splash (msg);
|
||||
msg.set_keep_above (true);
|
||||
msg.run ();
|
||||
|
||||
if (free_reason) {
|
||||
free (const_cast<char*> (reason));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
ARDOUR_UI::do_engine_start ()
|
||||
{
|
||||
try {
|
||||
engine->start();
|
||||
}
|
||||
|
||||
catch (...) {
|
||||
engine->stop ();
|
||||
error << _("Unable to start the session running")
|
||||
<< endmsg;
|
||||
unload_session ();
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::update_clocks ()
|
||||
{
|
||||
|
|
@ -2702,10 +2690,6 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
|
|||
}
|
||||
}
|
||||
|
||||
if (create_engine ()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
|
||||
|
||||
if (likely_new && !nsm) {
|
||||
|
|
@ -2801,25 +2785,23 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
|
|||
int unload_status;
|
||||
int retval = -1;
|
||||
|
||||
if (_session) {
|
||||
unload_status = unload_session ();
|
||||
|
||||
if (unload_status < 0) {
|
||||
goto out;
|
||||
} else if (unload_status > 0) {
|
||||
retval = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
session_loaded = false;
|
||||
|
||||
if (!check_audioengine()) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
unload_status = unload_session ();
|
||||
|
||||
if (unload_status < 0) {
|
||||
goto out;
|
||||
} else if (unload_status > 0) {
|
||||
retval = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
|
||||
|
||||
try {
|
||||
new_session = new Session (*engine, path, snap_name, 0, mix_template);
|
||||
new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
|
||||
}
|
||||
|
||||
/* this one is special */
|
||||
|
|
@ -2920,12 +2902,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
|
|||
Session *new_session;
|
||||
int x;
|
||||
|
||||
if (!check_audioengine()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session_loaded = false;
|
||||
|
||||
x = unload_session ();
|
||||
|
||||
if (x < 0) {
|
||||
|
|
@ -2937,7 +2914,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
|
|||
_session_is_new = true;
|
||||
|
||||
try {
|
||||
new_session = new Session (*engine, path, snap_name, &bus_profile);
|
||||
new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
|
||||
}
|
||||
|
||||
catch (...) {
|
||||
|
|
@ -3832,31 +3809,33 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ARDOUR_UI::disconnect_from_jack ()
|
||||
ARDOUR_UI::disconnect_from_engine ()
|
||||
{
|
||||
if (engine) {
|
||||
if (engine->disconnect_from_jack ()) {
|
||||
MessageDialog msg (*editor, _("Could not disconnect from JACK"));
|
||||
msg.run ();
|
||||
}
|
||||
/* drop connection to AudioEngine::Halted so that we don't act
|
||||
* as if the engine unexpectedly shut down
|
||||
*/
|
||||
halt_connection.disconnect ();
|
||||
|
||||
update_sample_rate (0);
|
||||
if (AudioEngine::instance()->stop ()) {
|
||||
MessageDialog msg (*editor, _("Could not disconnect from JACK"));
|
||||
msg.run ();
|
||||
} else {
|
||||
AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
|
||||
}
|
||||
|
||||
update_sample_rate (0);
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::reconnect_to_jack ()
|
||||
ARDOUR_UI::reconnect_to_engine ()
|
||||
{
|
||||
if (engine) {
|
||||
if (engine->reconnect_to_jack ()) {
|
||||
MessageDialog msg (*editor, _("Could not reconnect to JACK"));
|
||||
msg.run ();
|
||||
}
|
||||
|
||||
update_sample_rate (0);
|
||||
if (AudioEngine::instance()->start ()) {
|
||||
MessageDialog msg (*editor, _("Could not reconnect to JACK"));
|
||||
msg.run ();
|
||||
}
|
||||
|
||||
update_sample_rate (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4163,3 +4142,49 @@ ARDOUR_UI::reset_route_peak_display (Route* route)
|
|||
reset_peak_display ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::toggle_audio_midi_setup ()
|
||||
{
|
||||
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-audio-midi-setup"));
|
||||
if (!act) {
|
||||
return;
|
||||
}
|
||||
|
||||
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
|
||||
|
||||
if (tact->get_active()) {
|
||||
launch_audio_midi_setup ();
|
||||
} else {
|
||||
_audio_midi_setup->hide ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::launch_audio_midi_setup ()
|
||||
{
|
||||
if (!_audio_midi_setup) {
|
||||
_audio_midi_setup = new EngineControl ();
|
||||
}
|
||||
|
||||
_audio_midi_setup->present ();
|
||||
}
|
||||
|
||||
int
|
||||
ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
|
||||
{
|
||||
launch_audio_midi_setup ();
|
||||
|
||||
_audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
|
||||
|
||||
int r = _audio_midi_setup->run ();
|
||||
|
||||
switch (r) {
|
||||
case Gtk::RESPONSE_OK:
|
||||
return 0;
|
||||
case Gtk::RESPONSE_APPLY:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ class BigClockWindow;
|
|||
class BundleManager;
|
||||
class ButtonJoiner;
|
||||
class ConnectionEditor;
|
||||
class EngineControl;
|
||||
class KeyEditor;
|
||||
class LocationUIWindow;
|
||||
class MainClock;
|
||||
|
|
@ -264,7 +265,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
session_add_midi_route (false);
|
||||
}*/
|
||||
|
||||
int create_engine ();
|
||||
void attach_to_engine ();
|
||||
void post_engine ();
|
||||
|
||||
gint exit_on_main_window_close (GdkEventAny *);
|
||||
|
|
@ -302,19 +303,18 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
void reenable_hide_loop_punch_ruler_if_appropriate ();
|
||||
void toggle_auto_return ();
|
||||
void toggle_click ();
|
||||
|
||||
void toggle_audio_midi_setup ();
|
||||
void toggle_session_auto_loop ();
|
||||
|
||||
void toggle_rc_options_window ();
|
||||
void toggle_session_options_window ();
|
||||
|
||||
private:
|
||||
ArdourStartup* _startup;
|
||||
ARDOUR::AudioEngine *engine;
|
||||
Gtk::Tooltips _tooltips;
|
||||
NSM_Client *nsm;
|
||||
bool _was_dirty;
|
||||
bool _mixer_on_top;
|
||||
bool first_time_engine_run;
|
||||
|
||||
void goto_editor_window ();
|
||||
void goto_mixer_window ();
|
||||
|
|
@ -667,9 +667,9 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
int pending_state_dialog ();
|
||||
int sr_mismatch_dialog (ARDOUR::framecnt_t, ARDOUR::framecnt_t);
|
||||
|
||||
void disconnect_from_jack ();
|
||||
void reconnect_to_jack ();
|
||||
void set_jack_buffer_size (ARDOUR::pframes_t);
|
||||
void disconnect_from_engine ();
|
||||
void reconnect_to_engine ();
|
||||
void set_engine_buffer_size (ARDOUR::pframes_t);
|
||||
|
||||
Gtk::MenuItem* jack_disconnect_item;
|
||||
Gtk::MenuItem* jack_reconnect_item;
|
||||
|
|
@ -710,6 +710,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
void loading_message (const std::string& msg);
|
||||
|
||||
PBD::ScopedConnectionList forever_connections;
|
||||
PBD::ScopedConnection halt_connection;
|
||||
|
||||
void step_edit_status_change (bool);
|
||||
|
||||
|
|
@ -746,6 +747,10 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
|
||||
std::string _announce_string;
|
||||
void check_announcements ();
|
||||
|
||||
EngineControl* _audio_midi_setup;
|
||||
void launch_audio_midi_setup ();
|
||||
int do_audio_midi_setup (uint32_t);
|
||||
};
|
||||
|
||||
#endif /* __ardour_gui_h__ */
|
||||
|
|
|
|||
|
|
@ -165,10 +165,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.
|
||||
*/
|
||||
|
||||
|
|
@ -283,7 +279,10 @@ ARDOUR_UI::unload_session (bool hide_stuff)
|
|||
rec_button.set_sensitive (false);
|
||||
|
||||
WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
|
||||
ARDOUR_UI::instance()->video_timeline->close_session();
|
||||
|
||||
if (ARDOUR_UI::instance()->video_timeline) {
|
||||
ARDOUR_UI::instance()->video_timeline->close_session();
|
||||
}
|
||||
|
||||
stop_blinking ();
|
||||
stop_clocking ();
|
||||
|
|
|
|||
|
|
@ -183,38 +183,38 @@ ARDOUR_UI::install_actions ()
|
|||
ActionManager::write_sensitive_actions.push_back (act);
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
/* JACK actions for controlling ... JACK */
|
||||
/* AudioEngine actions */
|
||||
|
||||
Glib::RefPtr<ActionGroup> jack_actions = ActionGroup::create (X_("JACK"));
|
||||
ActionManager::register_action (jack_actions, X_("JACK"), _("JACK"));
|
||||
ActionManager::register_action (jack_actions, X_("Latency"), _("Latency"));
|
||||
Glib::RefPtr<ActionGroup> engine_actions = ActionGroup::create (X_("Audio"));
|
||||
ActionManager::register_action (engine_actions, X_("JACK"), _("JACK"));
|
||||
ActionManager::register_action (engine_actions, X_("Latency"), _("Latency"));
|
||||
|
||||
act = ActionManager::register_action (jack_actions, X_("JACKReconnect"), _("Reconnect"), sigc::mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::reconnect_to_jack));
|
||||
ActionManager::jack_opposite_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (engine_actions, X_("EngineReconnect"), _("Reconnect"), sigc::mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::reconnect_to_engine));
|
||||
ActionManager::engine_opposite_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (jack_actions, X_("JACKDisconnect"), _("Disconnect"), sigc::mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::disconnect_from_jack));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (engine_actions, X_("EngineDisconnect"), _("Disconnect"), sigc::mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::disconnect_from_engine));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
|
||||
RadioAction::Group jack_latency_group;
|
||||
RadioAction::Group latency_group;
|
||||
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency32"), X_("32"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 32));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency64"), X_("64"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 64));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency128"), X_("128"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 128));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency256"), X_("256"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 256));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency512"), X_("512"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 512));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency1024"), X_("1024"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 1024));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency2048"), X_("2048"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 2048));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency4096"), X_("4096"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 4096));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (jack_actions, jack_latency_group, X_("JACKLatency8192"), X_("8192"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_jack_buffer_size), (pframes_t) 8192));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency32"), X_("32"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 32));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency64"), X_("64"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 64));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency128"), X_("128"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 128));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency256"), X_("256"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 256));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency512"), X_("512"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 512));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency1024"), X_("1024"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 1024));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency2048"), X_("2048"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 2048));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency4096"), X_("4096"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 4096));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_radio_action (engine_actions, latency_group, X_("EngineLatency8192"), X_("8192"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::set_engine_buffer_size), (pframes_t) 8192));
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
|
||||
/* these actions are intended to be shared across all windows */
|
||||
|
||||
|
|
@ -230,6 +230,7 @@ ARDOUR_UI::install_actions ()
|
|||
ActionManager::register_toggle_action (common_actions, X_("toggle-mixer"), S_("Window|Mixer"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_mixer_window));
|
||||
ActionManager::register_action (common_actions, X_("toggle-editor-mixer"), _("Toggle Editor+Mixer"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_editor_mixer));
|
||||
ActionManager::register_toggle_action (common_actions, X_("toggle-meterbridge"), S_("Window|Meterbridge"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_meterbridge));
|
||||
ActionManager::register_toggle_action (common_actions, X_("toggle-audio-midi-setup"), S_("Window|Audio/MIDI Setup"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_audio_midi_setup));
|
||||
|
||||
act = ActionManager::register_action (common_actions, X_("NewMIDITracer"), _("MIDI Tracer"), sigc::mem_fun(*this, &ARDOUR_UI::new_midi_tracer_window));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
|
@ -421,7 +422,7 @@ ARDOUR_UI::install_actions ()
|
|||
|
||||
ActionManager::add_action_group (shuttle_actions);
|
||||
ActionManager::add_action_group (option_actions);
|
||||
ActionManager::add_action_group (jack_actions);
|
||||
ActionManager::add_action_group (engine_actions);
|
||||
ActionManager::add_action_group (transport_actions);
|
||||
ActionManager::add_action_group (main_actions);
|
||||
ActionManager::add_action_group (main_menu_actions);
|
||||
|
|
@ -430,38 +431,38 @@ ARDOUR_UI::install_actions ()
|
|||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::set_jack_buffer_size (pframes_t nframes)
|
||||
ARDOUR_UI::set_engine_buffer_size (pframes_t nframes)
|
||||
{
|
||||
Glib::RefPtr<Action> action;
|
||||
const char* action_name = 0;
|
||||
|
||||
switch (nframes) {
|
||||
case 32:
|
||||
action_name = X_("JACKLatency32");
|
||||
action_name = X_("EngineLatency32");
|
||||
break;
|
||||
case 64:
|
||||
action_name = X_("JACKLatency64");
|
||||
action_name = X_("EngineLatency64");
|
||||
break;
|
||||
case 128:
|
||||
action_name = X_("JACKLatency128");
|
||||
action_name = X_("EngineLatency128");
|
||||
break;
|
||||
case 256:
|
||||
action_name = X_("JACKLatency256");
|
||||
action_name = X_("EngineLatency256");
|
||||
break;
|
||||
case 512:
|
||||
action_name = X_("JACKLatency512");
|
||||
action_name = X_("EngineLatency512");
|
||||
break;
|
||||
case 1024:
|
||||
action_name = X_("JACKLatency1024");
|
||||
action_name = X_("EngineLatency1024");
|
||||
break;
|
||||
case 2048:
|
||||
action_name = X_("JACKLatency2048");
|
||||
action_name = X_("EngineLatency2048");
|
||||
break;
|
||||
case 4096:
|
||||
action_name = X_("JACKLatency4096");
|
||||
action_name = X_("EngineLatency4096");
|
||||
break;
|
||||
case 8192:
|
||||
action_name = X_("JACKLatency8192");
|
||||
action_name = X_("EngineLatency8192");
|
||||
break;
|
||||
default:
|
||||
/* XXX can we do anything useful ? */
|
||||
|
|
@ -476,7 +477,7 @@ ARDOUR_UI::set_jack_buffer_size (pframes_t nframes)
|
|||
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
|
||||
|
||||
if (ract && ract->get_active()) {
|
||||
engine->request_buffer_size (nframes);
|
||||
AudioEngine::instance()->request_buffer_size (nframes);
|
||||
update_sample_rate (0);
|
||||
}
|
||||
}
|
||||
|
|
@ -647,11 +648,10 @@ ARDOUR_UI::save_ardour_state ()
|
|||
window_node->add_child_nocopy (*tearoff_node);
|
||||
|
||||
Config->add_extra_xml (*window_node);
|
||||
Config->add_extra_xml (_audio_midi_setup->get_state());
|
||||
|
||||
if (_startup && _startup->engine_control() && _startup->engine_control()->was_used()) {
|
||||
Config->add_extra_xml (_startup->engine_control()->get_state());
|
||||
}
|
||||
Config->save_state();
|
||||
|
||||
if (ui_config->dirty()) {
|
||||
ui_config->save_state ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
|
|||
export ARDOUR_RUNNING_UNDER_VALGRIND=TRUE
|
||||
exec valgrind --tool=memcheck \
|
||||
$VALGRIND_OPTIONS \
|
||||
--track-origins=yes \
|
||||
--suppressions=`dirname "$0"`/../tools/valgrind.supp \
|
||||
$TOP/$EXECUTABLE --novst "$@"
|
||||
|
|
|
|||
|
|
@ -1258,7 +1258,8 @@ Editor::set_session (Session *t)
|
|||
|
||||
/* These signals can all be emitted by a non-GUI thread. Therefore the
|
||||
handlers for them must not attempt to directly interact with the GUI,
|
||||
but use Gtkmm2ext::UI::instance()->call_slot();
|
||||
but use PBD::Signal<T>::connect() which accepts an event loop
|
||||
("context") where the handler will be asked to run.
|
||||
*/
|
||||
|
||||
_session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
|
||||
|
|
|
|||
|
|
@ -2371,9 +2371,14 @@ CursorDrag::fake_locate (framepos_t t)
|
|||
Session* s = _editor->session ();
|
||||
if (s->timecode_transmission_suspended ()) {
|
||||
framepos_t const f = _editor->playhead_cursor->current_frame;
|
||||
/* This is asynchronous so it will be sent "now"
|
||||
*/
|
||||
s->send_mmc_locate (f);
|
||||
s->send_full_time_code (f);
|
||||
s->send_song_position_pointer (f);
|
||||
/* These are synchronous and will be sent during the next
|
||||
process cycle
|
||||
*/
|
||||
s->queue_full_time_code ();
|
||||
s->queue_song_position_pointer ();
|
||||
}
|
||||
|
||||
show_verbose_cursor_time (t);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include <gtkmm/checkbutton.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/notebook.h>
|
||||
#include <gtkmm/comboboxtext.h>
|
||||
#include <gtkmm/table.h>
|
||||
#include <gtkmm/expander.h>
|
||||
|
|
@ -34,93 +33,149 @@
|
|||
#include <gtkmm/buttonbox.h>
|
||||
#include <gtkmm/button.h>
|
||||
|
||||
class EngineControl : public Gtk::VBox {
|
||||
#include "pbd/signals.h"
|
||||
|
||||
#include "ardour_dialog.h"
|
||||
|
||||
class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
|
||||
public:
|
||||
EngineControl ();
|
||||
~EngineControl ();
|
||||
EngineControl ();
|
||||
~EngineControl ();
|
||||
|
||||
static bool need_setup ();
|
||||
int setup_engine ();
|
||||
static bool need_setup ();
|
||||
|
||||
bool was_used() const { return _used; }
|
||||
XMLNode& get_state ();
|
||||
void set_state (const XMLNode&);
|
||||
XMLNode& get_state ();
|
||||
void set_state (const XMLNode&);
|
||||
|
||||
void set_desired_sample_rate (uint32_t);
|
||||
|
||||
private:
|
||||
Gtk::Adjustment periods_adjustment;
|
||||
Gtk::SpinButton periods_spinner;
|
||||
Gtk::Adjustment ports_adjustment;
|
||||
Gtk::SpinButton ports_spinner;
|
||||
Gtk::Adjustment input_latency_adjustment;
|
||||
Gtk::SpinButton input_latency;
|
||||
Gtk::Adjustment output_latency_adjustment;
|
||||
Gtk::SpinButton output_latency;
|
||||
Gtk::Label latency_label;
|
||||
Gtk::Notebook notebook;
|
||||
|
||||
Gtk::CheckButton realtime_button;
|
||||
Gtk::CheckButton no_memory_lock_button;
|
||||
Gtk::CheckButton unlock_memory_button;
|
||||
Gtk::CheckButton soft_mode_button;
|
||||
Gtk::CheckButton monitor_button;
|
||||
Gtk::CheckButton force16bit_button;
|
||||
Gtk::CheckButton hw_monitor_button;
|
||||
Gtk::CheckButton hw_meter_button;
|
||||
Gtk::CheckButton verbose_output_button;
|
||||
/* core fields used by all backends */
|
||||
|
||||
Gtk::Button start_button;
|
||||
Gtk::Button stop_button;
|
||||
Gtk::HButtonBox button_box;
|
||||
Gtk::ComboBoxText backend_combo;
|
||||
Gtk::ComboBoxText sample_rate_combo;
|
||||
Gtk::ComboBoxText buffer_size_combo;
|
||||
Gtk::Label buffer_size_duration_label;
|
||||
Gtk::Adjustment input_latency_adjustment;
|
||||
Gtk::SpinButton input_latency;
|
||||
Gtk::Adjustment output_latency_adjustment;
|
||||
Gtk::SpinButton output_latency;
|
||||
Gtk::Adjustment input_channels_adjustment;
|
||||
Gtk::SpinButton input_channels;
|
||||
Gtk::Adjustment output_channels_adjustment;
|
||||
Gtk::SpinButton output_channels;
|
||||
Gtk::Adjustment ports_adjustment;
|
||||
Gtk::SpinButton ports_spinner;
|
||||
|
||||
Gtk::ComboBoxText sample_rate_combo;
|
||||
Gtk::ComboBoxText period_size_combo;
|
||||
Gtk::Button control_app_button;
|
||||
|
||||
Gtk::ComboBoxText preset_combo;
|
||||
Gtk::ComboBoxText serverpath_combo;
|
||||
Gtk::ComboBoxText driver_combo;
|
||||
Gtk::ComboBoxText interface_combo;
|
||||
Gtk::ComboBoxText timeout_combo;
|
||||
Gtk::ComboBoxText dither_mode_combo;
|
||||
Gtk::ComboBoxText audio_mode_combo;
|
||||
Gtk::ComboBoxText input_device_combo;
|
||||
Gtk::ComboBoxText output_device_combo;
|
||||
Gtk::ComboBoxText midi_driver_combo;
|
||||
/* latency measurement */
|
||||
|
||||
Gtk::Table basic_packer;
|
||||
Gtk::Table options_packer;
|
||||
Gtk::Table device_packer;
|
||||
Gtk::HBox basic_hbox;
|
||||
Gtk::HBox options_hbox;
|
||||
Gtk::HBox device_hbox;
|
||||
Gtk::Notebook notebook;
|
||||
Gtk::ComboBoxText lm_output_channel_combo;
|
||||
Gtk::ComboBoxText lm_input_channel_combo;
|
||||
Gtk::ToggleButton lm_measure_button;
|
||||
Gtk::Button lm_use_button;
|
||||
Gtk::Label lm_title;
|
||||
Gtk::Label lm_preamble;
|
||||
Gtk::Label lm_results;
|
||||
Gtk::Table lm_table;
|
||||
Gtk::VBox lm_vbox;
|
||||
|
||||
bool _used;
|
||||
/* JACK specific */
|
||||
|
||||
static bool engine_running ();
|
||||
Gtk::CheckButton realtime_button;
|
||||
Gtk::CheckButton no_memory_lock_button;
|
||||
Gtk::CheckButton unlock_memory_button;
|
||||
Gtk::CheckButton soft_mode_button;
|
||||
Gtk::CheckButton monitor_button;
|
||||
Gtk::CheckButton force16bit_button;
|
||||
Gtk::CheckButton hw_monitor_button;
|
||||
Gtk::CheckButton hw_meter_button;
|
||||
Gtk::CheckButton verbose_output_button;
|
||||
|
||||
void driver_changed ();
|
||||
void build_command_line (std::vector<std::string>&);
|
||||
Gtk::ComboBoxText preset_combo;
|
||||
Gtk::ComboBoxText serverpath_combo;
|
||||
Gtk::ComboBoxText driver_combo;
|
||||
Gtk::ComboBoxText device_combo;
|
||||
Gtk::ComboBoxText timeout_combo;
|
||||
Gtk::ComboBoxText dither_mode_combo;
|
||||
Gtk::ComboBoxText audio_mode_combo;
|
||||
Gtk::ComboBoxText midi_driver_combo;
|
||||
|
||||
std::map<std::string,std::vector<std::string> > devices;
|
||||
std::vector<std::string> backend_devs;
|
||||
void enumerate_devices (const std::string& driver);
|
||||
Gtk::Table basic_packer;
|
||||
Gtk::Table midi_packer;
|
||||
Gtk::HBox basic_hbox;
|
||||
Gtk::VBox basic_vbox;
|
||||
Gtk::HBox midi_hbox;
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::vector<std::string> enumerate_coreaudio_devices ();
|
||||
#else
|
||||
std::vector<std::string> enumerate_alsa_devices ();
|
||||
std::vector<std::string> enumerate_oss_devices ();
|
||||
std::vector<std::string> enumerate_netjack_devices ();
|
||||
std::vector<std::string> enumerate_freebob_devices ();
|
||||
std::vector<std::string> enumerate_ffado_devices ();
|
||||
std::vector<std::string> enumerate_dummy_devices ();
|
||||
#endif
|
||||
uint32_t ignore_changes;
|
||||
|
||||
void redisplay_latency ();
|
||||
uint32_t get_rate();
|
||||
void audio_mode_changed ();
|
||||
std::vector<std::string> server_strings;
|
||||
void find_jack_servers (std::vector<std::string>&);
|
||||
std::string get_device_name (const std::string& driver, const std::string& human_readable_name);
|
||||
static bool engine_running ();
|
||||
|
||||
void driver_changed ();
|
||||
void backend_changed ();
|
||||
void sample_rate_changed ();
|
||||
void buffer_size_changed ();
|
||||
|
||||
uint32_t get_rate() const;
|
||||
uint32_t get_buffer_size() const;
|
||||
uint32_t get_input_channels() const;
|
||||
uint32_t get_output_channels() const;
|
||||
uint32_t get_input_latency() const;
|
||||
uint32_t get_output_latency() const;
|
||||
std::string get_device_name() const;
|
||||
std::string get_driver() const;
|
||||
|
||||
void device_changed ();
|
||||
void list_devices ();
|
||||
void show_buffer_duration ();
|
||||
|
||||
struct State {
|
||||
std::string backend;
|
||||
std::string driver;
|
||||
std::string device;
|
||||
std::string sample_rate;
|
||||
std::string buffer_size;
|
||||
uint32_t input_latency;
|
||||
uint32_t output_latency;
|
||||
uint32_t input_channels;
|
||||
uint32_t output_channels;
|
||||
bool active;
|
||||
|
||||
State() : active (false) {};
|
||||
};
|
||||
|
||||
typedef std::list<State> StateList;
|
||||
|
||||
StateList states;
|
||||
|
||||
State* get_matching_state (const std::string& backend,
|
||||
const std::string& driver,
|
||||
const std::string& device);
|
||||
State* get_current_state ();
|
||||
void maybe_display_saved_state ();
|
||||
void save_state ();
|
||||
|
||||
static bool print_channel_count (Gtk::SpinButton*);
|
||||
|
||||
void build_notebook ();
|
||||
|
||||
void on_response (int);
|
||||
void control_app_button_clicked ();
|
||||
void use_latency_button_clicked ();
|
||||
void manage_control_app_sensitivity ();
|
||||
int push_state_to_backend (bool start);
|
||||
uint32_t _desired_sample_rate;
|
||||
|
||||
/* latency measurement */
|
||||
void latency_button_toggled ();
|
||||
bool check_latency_measurement ();
|
||||
void update_latency_display ();
|
||||
sigc::connection latency_timeout;
|
||||
void enable_latency_tab ();
|
||||
void disable_latency_tab ();
|
||||
};
|
||||
|
||||
#endif /* __gtk2_ardour_engine_dialog_h__ */
|
||||
|
|
|
|||
|
|
@ -259,8 +259,7 @@ ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
|
|||
video_codec_combo.append_text("mjpeg");
|
||||
video_codec_combo.append_text("mpeg2video");
|
||||
video_codec_combo.append_text("mpeg4");
|
||||
video_codec_combo.append_text("x264 (baseline)");
|
||||
video_codec_combo.append_text("x264 (hq)");
|
||||
video_codec_combo.append_text("h264");
|
||||
video_codec_combo.append_text("vpx (webm)");
|
||||
video_codec_combo.append_text("copy");
|
||||
video_codec_combo.set_active(4);
|
||||
|
|
@ -614,13 +613,8 @@ ExportVideoDialog::encode_pass (int pass)
|
|||
ffs["-strict"] = "-2";
|
||||
}
|
||||
|
||||
if (video_codec_combo.get_active_text() == "x264 (hq)" ) {
|
||||
if (video_codec_combo.get_active_text() == "h264" ) {
|
||||
ffs["-vcodec"] = "libx264";
|
||||
ffs["-vprofile"] = "high";
|
||||
}
|
||||
else if (video_codec_combo.get_active_text() == "x264 (baseline)" ) {
|
||||
ffs["-vcodec"] = "libx264";
|
||||
ffs["-vpre"] = "baseline";
|
||||
}
|
||||
else if (video_codec_combo.get_active_text() == "vpx (webm)" ) {
|
||||
ffs["-vcodec"] = "libvpx";
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include <gtkmm2ext/fastmeter.h>
|
||||
#include <gtkmm2ext/barcontroller.h>
|
||||
#include <gtkmm2ext/gtk_ui.h>
|
||||
#include "midi++/manager.h"
|
||||
#include "pbd/fastlog.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
|
|
@ -280,14 +279,15 @@ GainMeterBase::setup_meters (int len)
|
|||
case Wide:
|
||||
meter_ticks1_area.show();
|
||||
meter_ticks2_area.show();
|
||||
meter_metric_area.show();
|
||||
if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
|
||||
meter_width = 10;
|
||||
}
|
||||
break;
|
||||
case Narrow:
|
||||
meter_width = 2;
|
||||
meter_ticks1_area.hide();
|
||||
meter_ticks2_area.hide();
|
||||
meter_metric_area.hide();
|
||||
break;
|
||||
}
|
||||
level_meter->setup_meters(len, meter_width);
|
||||
|
|
@ -864,7 +864,7 @@ GainMeterBase::update_meters()
|
|||
}
|
||||
}
|
||||
|
||||
void GainMeterBase::color_handler(bool /* dpi */)
|
||||
void GainMeterBase::color_handler(bool /*dpi*/)
|
||||
{
|
||||
setup_meters();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@
|
|||
#include <gtkmm2ext/doi.h>
|
||||
#include <gtkmm2ext/slider_controller.h>
|
||||
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/plugin.h"
|
||||
#include "ardour/plugin_insert.h"
|
||||
#include "ardour/session.h"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <gtkmm/image.h>
|
||||
#include <gtkmm/stock.h>
|
||||
|
||||
#include "global_port_matrix.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
@ -82,9 +83,9 @@ GlobalPortMatrix::set_state (BundleChannel c[2], bool s)
|
|||
} else {
|
||||
/* two non-Ardour ports */
|
||||
if (s) {
|
||||
jack_connect (_session->engine().jack (), j->c_str(), i->c_str());
|
||||
AudioEngine::instance()->connect (*j, *i);
|
||||
} else {
|
||||
jack_disconnect (_session->engine().jack (), j->c_str(), i->c_str());
|
||||
AudioEngine::instance()->disconnect (*j, *i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -113,33 +114,25 @@ GlobalPortMatrix::get_state (BundleChannel c[2]) const
|
|||
for (Bundle::PortList::const_iterator i = in_ports.begin(); i != in_ports.end(); ++i) {
|
||||
for (Bundle::PortList::const_iterator j = out_ports.begin(); j != out_ports.end(); ++j) {
|
||||
|
||||
boost::shared_ptr<Port> p = _session->engine().get_port_by_name (*i);
|
||||
boost::shared_ptr<Port> q = _session->engine().get_port_by_name (*j);
|
||||
boost::shared_ptr<Port> p = AudioEngine::instance()->get_port_by_name (*i);
|
||||
boost::shared_ptr<Port> q = AudioEngine::instance()->get_port_by_name (*j);
|
||||
|
||||
if (!p && !q) {
|
||||
/* two non-Ardour ports; things are slightly more involved */
|
||||
/* XXX: is this the easiest way to do this? */
|
||||
/* XXX: isn't this very inefficient? */
|
||||
|
||||
jack_client_t* jack = _session->engine().jack ();
|
||||
jack_port_t* jp = jack_port_by_name (jack, i->c_str());
|
||||
if (jp == 0) {
|
||||
/* get a port handle for one of them .. */
|
||||
|
||||
PortEngine::PortHandle ph = AudioEngine::instance()->port_engine().get_port_by_name (*i);
|
||||
if (!ph) {
|
||||
return PortMatrixNode::NOT_ASSOCIATED;
|
||||
}
|
||||
|
||||
char const ** c = jack_port_get_all_connections (jack, jp);
|
||||
/* see if it is connected to the other one ... */
|
||||
|
||||
char const ** p = c;
|
||||
|
||||
while (p && *p != 0) {
|
||||
if (strcmp (*p, j->c_str()) == 0) {
|
||||
free (c);
|
||||
return PortMatrixNode::ASSOCIATED;
|
||||
}
|
||||
++p;
|
||||
if (AudioEngine::instance()->port_engine().connected_to (ph, *j, false)) {
|
||||
return PortMatrixNode::ASSOCIATED;
|
||||
}
|
||||
|
||||
free (c);
|
||||
return PortMatrixNode::NOT_ASSOCIATED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include <gtkmm2ext/utils.h>
|
||||
#include <gtkmm2ext/barcontroller.h>
|
||||
#include "midi++/manager.h"
|
||||
#include "pbd/fastlog.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
|
|
|
|||
|
|
@ -373,34 +373,30 @@ static void load_custom_fonts() {
|
|||
#endif
|
||||
|
||||
static gboolean
|
||||
tell_about_jack_death (void* /* ignored */)
|
||||
tell_about_backend_death (void* /* ignored */)
|
||||
{
|
||||
if (AudioEngine::instance()->processed_frames() == 0) {
|
||||
/* died during startup */
|
||||
MessageDialog msg (_("JACK exited"), false);
|
||||
MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
|
||||
msg.set_position (Gtk::WIN_POS_CENTER);
|
||||
msg.set_secondary_text (string_compose (_(
|
||||
"JACK exited unexpectedly, and without notifying %1.\n\
|
||||
"%2 exited unexpectedly, and without notifying %1.\n\
|
||||
\n\
|
||||
This could be due to misconfiguration or to an error inside JACK.\n\
|
||||
This could be due to misconfiguration or to an error inside %2.\n\
|
||||
\n\
|
||||
Click OK to exit %1."), PROGRAM_NAME));
|
||||
Click OK to exit %1."), PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
|
||||
|
||||
msg.run ();
|
||||
_exit (0);
|
||||
|
||||
} else {
|
||||
|
||||
/* engine has already run, so this is a mid-session JACK death */
|
||||
/* engine has already run, so this is a mid-session backend death */
|
||||
|
||||
MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false));
|
||||
msg->set_secondary_text (string_compose (_(
|
||||
"JACK exited unexpectedly, and without notifying %1.\n\
|
||||
\n\
|
||||
This is probably due to an error inside JACK. You should restart JACK\n\
|
||||
and reconnect %1 to it, or exit %1 now. You cannot save your\n\
|
||||
session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
|
||||
msg->present ();
|
||||
MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
|
||||
msg.set_secondary_text (string_compose (_("%2 exited unexpectedly, and without notifying %1."),
|
||||
PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
|
||||
msg.present ();
|
||||
}
|
||||
return false; /* do not call again */
|
||||
}
|
||||
|
|
@ -408,15 +404,15 @@ session at this time, because we would lose your connection information.\n"), PR
|
|||
static void
|
||||
sigpipe_handler (int /*signal*/)
|
||||
{
|
||||
/* XXX fix this so that we do this again after a reconnect to JACK
|
||||
/* XXX fix this so that we do this again after a reconnect to the backend
|
||||
*/
|
||||
|
||||
static bool done_the_jack_thing = false;
|
||||
static bool done_the_backend_thing = false;
|
||||
|
||||
if (!done_the_jack_thing) {
|
||||
if (!done_the_backend_thing) {
|
||||
AudioEngine::instance()->died ();
|
||||
g_idle_add (tell_about_jack_death, 0);
|
||||
done_the_jack_thing = true;
|
||||
g_idle_add (tell_about_backend_death, 0);
|
||||
done_the_backend_thing = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -702,11 +702,11 @@ Meterbridge::sync_order_keys (RouteSortOrderKey)
|
|||
|
||||
MeterType nmt = (*i).s->meter_type();
|
||||
if (nmt == MeterKrms) nmt = MeterPeak; // identical metrics
|
||||
if (pos == 0) {
|
||||
if (vis == 1) {
|
||||
(*i).s->set_tick_bar(1);
|
||||
}
|
||||
|
||||
if ((*i).visible && nmt != lmt && pos == 0) {
|
||||
if ((*i).visible && nmt != lmt && vis == 1) {
|
||||
lmt = nmt;
|
||||
metrics_left.set_metric_mode(1, lmt);
|
||||
} else if ((*i).visible && nmt != lmt) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@
|
|||
#include "pbd/timersub.h"
|
||||
|
||||
#include "midi++/parser.h"
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/async_midi_port.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/audioengine.h"
|
||||
|
||||
#include "midi_tracer.h"
|
||||
#include "gui_thread.h"
|
||||
|
|
@ -56,7 +59,8 @@ MidiTracer::MidiTracer ()
|
|||
, collect_button (_("Enabled"))
|
||||
, delta_time_button (_("Delta times"))
|
||||
{
|
||||
Manager::instance()->PortsChanged.connect (_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context());
|
||||
ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect
|
||||
(_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context());
|
||||
|
||||
_last_receipt.tv_sec = 0;
|
||||
_last_receipt.tv_usec = 0;
|
||||
|
|
@ -130,23 +134,57 @@ MidiTracer::ports_changed ()
|
|||
string const c = _port_combo.get_active_text ();
|
||||
_port_combo.clear ();
|
||||
|
||||
boost::shared_ptr<const Manager::PortList> p = Manager::instance()->get_midi_ports ();
|
||||
for (Manager::PortList::const_iterator i = p->begin(); i != p->end(); ++i) {
|
||||
ARDOUR::PortManager::PortList pl;
|
||||
ARDOUR::AudioEngine::instance()->get_ports (ARDOUR::DataType::MIDI, pl);
|
||||
|
||||
if (pl.empty()) {
|
||||
_port_combo.set_active_text ("");
|
||||
return;
|
||||
}
|
||||
|
||||
for (ARDOUR::PortManager::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
|
||||
_port_combo.append_text ((*i)->name());
|
||||
}
|
||||
|
||||
_port_combo.set_active_text (c);
|
||||
if (c.empty()) {
|
||||
_port_combo.set_active_text (pl.front()->name());
|
||||
} else {
|
||||
_port_combo.set_active_text (c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiTracer::port_changed ()
|
||||
{
|
||||
using namespace ARDOUR;
|
||||
|
||||
disconnect ();
|
||||
|
||||
Port* p = Manager::instance()->port (_port_combo.get_active_text());
|
||||
boost::shared_ptr<ARDOUR::Port> p = AudioEngine::instance()->get_port_by_name (_port_combo.get_active_text());
|
||||
|
||||
if (p) {
|
||||
p->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3));
|
||||
if (!p) {
|
||||
std::cerr << "port not found\n";
|
||||
return;
|
||||
}
|
||||
|
||||
/* The inheritance heirarchy makes this messy. AsyncMIDIPort has two
|
||||
* available MIDI::Parsers what we could connect to, ::self_parser()
|
||||
* (from ARDOUR::MidiPort) and ::parser() from MIDI::Port. One day,
|
||||
* this mess will all go away ...
|
||||
*/
|
||||
|
||||
boost::shared_ptr<AsyncMIDIPort> async = boost::dynamic_pointer_cast<AsyncMIDIPort> (p);
|
||||
|
||||
if (!async) {
|
||||
|
||||
boost::shared_ptr<ARDOUR::MidiPort> mp = boost::dynamic_pointer_cast<ARDOUR::MidiPort> (p);
|
||||
|
||||
if (mp) {
|
||||
mp->self_parser().any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
} else {
|
||||
async->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -369,9 +407,9 @@ MidiTracer::tracer (Parser&, byte* msg, size_t len)
|
|||
|
||||
fifo.write (&buf, 1);
|
||||
|
||||
if (g_atomic_int_get (&_update_queued) == 0) {
|
||||
if (g_atomic_int_get (const_cast<gint*> (&_update_queued)) == 0) {
|
||||
gui_context()->call_slot (invalidator (*this), boost::bind (&MidiTracer::update, this));
|
||||
g_atomic_int_inc (&_update_queued);
|
||||
g_atomic_int_inc (const_cast<gint*> (&_update_queued));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +417,7 @@ void
|
|||
MidiTracer::update ()
|
||||
{
|
||||
bool updated = false;
|
||||
g_atomic_int_dec_and_test (&_update_queued);
|
||||
g_atomic_int_dec_and_test (const_cast<gint*> (&_update_queued));
|
||||
|
||||
RefPtr<TextBuffer> buf (text.get_buffer());
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ NSM_Client::command_open(const char* name,
|
|||
int r = ERR_OK;
|
||||
|
||||
ARDOUR_COMMAND_LINE::session_name = name;
|
||||
ARDOUR_COMMAND_LINE::jack_client_name = client_id;
|
||||
ARDOUR_COMMAND_LINE::backend_client_name = client_id;
|
||||
|
||||
if (ARDOUR_UI::instance()->get_session_parameters(true, false, "")) {
|
||||
return ERR_GENERAL;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@
|
|||
using namespace std;
|
||||
|
||||
string ARDOUR_COMMAND_LINE::session_name = "";
|
||||
string ARDOUR_COMMAND_LINE::jack_client_name = "ardour";
|
||||
string ARDOUR_COMMAND_LINE::backend_client_name = "ardour";
|
||||
string ARDOUR_COMMAND_LINE::backend_session_uuid;
|
||||
bool ARDOUR_COMMAND_LINE::show_key_actions = false;
|
||||
bool ARDOUR_COMMAND_LINE::no_splash = false;
|
||||
bool ARDOUR_COMMAND_LINE::just_version = false;
|
||||
|
|
@ -45,7 +46,6 @@ string ARDOUR_COMMAND_LINE::keybindings_path = ""; /* empty means use builtin de
|
|||
std::string ARDOUR_COMMAND_LINE::menus_file = "ardour.menus";
|
||||
bool ARDOUR_COMMAND_LINE::finder_invoked_ardour = false;
|
||||
string ARDOUR_COMMAND_LINE::immediate_save;
|
||||
string ARDOUR_COMMAND_LINE::jack_session_uuid;
|
||||
string ARDOUR_COMMAND_LINE::load_template;
|
||||
bool ARDOUR_COMMAND_LINE::check_announcements = true;
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ print_help (const char *execname)
|
|||
<< _(" -h, --help Print this message\n")
|
||||
<< _(" -a, --no-announcements Do not contact website for announcements\n")
|
||||
<< _(" -b, --bindings Print all possible keyboard binding names\n")
|
||||
<< _(" -c, --name <name> Use a specific jack client name, default is ardour\n")
|
||||
<< _(" -c, --name <name> Use a specific backend client name, default is ardour\n")
|
||||
<< _(" -d, --disable-plugins Disable all plugins in an existing session\n")
|
||||
<< _(" -D, --debug <options> Set debug flags. Use \"-D list\" to see available options\n")
|
||||
<< _(" -n, --no-splash Do not show splash screen\n")
|
||||
|
|
@ -199,7 +199,7 @@ ARDOUR_COMMAND_LINE::parse_opts (int argc, char *argv[])
|
|||
break;
|
||||
|
||||
case 'c':
|
||||
jack_client_name = optarg;
|
||||
backend_client_name = optarg;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
|
|
@ -215,7 +215,7 @@ ARDOUR_COMMAND_LINE::parse_opts (int argc, char *argv[])
|
|||
break;
|
||||
|
||||
case 'U':
|
||||
jack_session_uuid = optarg;
|
||||
backend_session_uuid = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ extern std::string session_name;
|
|||
extern bool show_key_actions;
|
||||
extern bool no_splash;
|
||||
extern bool just_version;
|
||||
extern std::string jack_client_name;
|
||||
extern std::string backend_client_name;
|
||||
extern std::string backend_session_uuid;
|
||||
extern bool use_vst;
|
||||
extern bool new_session;
|
||||
extern char* curvetest_file;
|
||||
|
|
@ -39,7 +40,6 @@ extern std::string keybindings_path;
|
|||
extern std::string menus_file;
|
||||
extern bool finder_invoked_ardour;
|
||||
extern std::string immediate_save;
|
||||
extern std::string jack_session_uuid;
|
||||
extern std::string load_template;
|
||||
extern bool check_announcements;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include <gtkmm2ext/utils.h>
|
||||
#include <gtkmm2ext/barcontroller.h>
|
||||
|
||||
#include "midi++/manager.h"
|
||||
#include "pbd/fastlog.h"
|
||||
|
||||
#include "ardour/pannable.h"
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
#include <gtkmm2ext/slider_controller.h>
|
||||
#include <gtkmm2ext/application.h>
|
||||
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/plugin.h"
|
||||
#include "ardour/plugin_insert.h"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "midi++/manager.h"
|
||||
#include "midi++/mmc.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
|
|
@ -29,9 +28,12 @@
|
|||
#include "ardour/bundle.h"
|
||||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/io_processor.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/user_bundle.h"
|
||||
#include "ardour/port.h"
|
||||
|
||||
#include "control_protocol/control_protocol.h"
|
||||
|
||||
#include "gui_thread.h"
|
||||
|
|
@ -452,37 +454,35 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
|
||||
/* Ardour's sync ports */
|
||||
|
||||
MIDI::Manager* midi_manager = MIDI::Manager::instance ();
|
||||
if (midi_manager && (type == DataType::MIDI || type == DataType::NIL)) {
|
||||
if ((type == DataType::MIDI || type == DataType::NIL)) {
|
||||
boost::shared_ptr<Bundle> sync (new Bundle (_("Sync"), inputs));
|
||||
MIDI::MachineControl* mmc = midi_manager->mmc ();
|
||||
AudioEngine& ae = session->engine ();
|
||||
AudioEngine* ae = AudioEngine::instance();
|
||||
|
||||
if (inputs) {
|
||||
sync->add_channel (
|
||||
_("MTC in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->mtc_input_port()->name())
|
||||
_("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (session->mtc_input_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MIDI control in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_input_port()->name())
|
||||
_("MIDI control in"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_input_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MIDI clock in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_clock_input_port()->name())
|
||||
_("MIDI clock in"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_clock_input_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MMC in"), DataType::MIDI, ae.make_port_name_non_relative (mmc->input_port()->name())
|
||||
_("MMC in"), DataType::MIDI, ae->make_port_name_non_relative (session->mmc_input_port()->name())
|
||||
);
|
||||
} else {
|
||||
sync->add_channel (
|
||||
_("MTC out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->mtc_output_port()->name())
|
||||
_("MTC out"), DataType::MIDI, ae->make_port_name_non_relative (session->mtc_output_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MIDI control out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_output_port()->name())
|
||||
_("MIDI control out"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_output_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MIDI clock out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_clock_output_port()->name())
|
||||
_("MIDI clock out"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_clock_output_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MMC out"), DataType::MIDI, ae.make_port_name_non_relative (mmc->output_port()->name())
|
||||
_("MMC out"), DataType::MIDI, ae->make_port_name_non_relative (session->mmc_output_port()->name())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -499,20 +499,12 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
string lpnc = lpn;
|
||||
lpnc += ':';
|
||||
|
||||
const char ** ports = 0;
|
||||
if (type == DataType::NIL) {
|
||||
ports = session->engine().get_ports ("", "", inputs ? JackPortIsInput : JackPortIsOutput);
|
||||
} else {
|
||||
ports = session->engine().get_ports ("", type.to_jack_type(), inputs ? JackPortIsInput : JackPortIsOutput);
|
||||
}
|
||||
vector<string> ports;
|
||||
if (AudioEngine::instance()->get_ports ("", type, inputs ? IsInput : IsOutput, ports) > 0) {
|
||||
|
||||
if (ports) {
|
||||
for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ) {
|
||||
|
||||
int n = 0;
|
||||
|
||||
while (ports[n]) {
|
||||
|
||||
std::string const p = ports[n];
|
||||
std::string const p = *s;
|
||||
|
||||
if (!system->has_port(p) &&
|
||||
!bus->has_port(p) &&
|
||||
|
|
@ -526,7 +518,7 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
*/
|
||||
|
||||
if (p.find ("Midi-Through") != string::npos) {
|
||||
++n;
|
||||
++s;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -539,15 +531,15 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
|
||||
if ((lp.find (N_(":monitor")) != string::npos) &&
|
||||
(lp.find (lpn) != string::npos)) {
|
||||
++n;
|
||||
++s;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* can't use the audio engine for this as we are looking at non-Ardour ports */
|
||||
|
||||
jack_port_t* jp = jack_port_by_name (session->engine().jack(), p.c_str());
|
||||
if (jp) {
|
||||
DataType t (jack_port_type (jp));
|
||||
PortEngine::PortHandle ph = AudioEngine::instance()->port_engine().get_port_by_name (p);
|
||||
if (ph) {
|
||||
DataType t (AudioEngine::instance()->port_engine().port_data_type (ph));
|
||||
if (t != DataType::NIL) {
|
||||
if (port_has_prefix (p, N_("system:")) ||
|
||||
port_has_prefix (p, N_("alsa_pcm")) ||
|
||||
|
|
@ -560,10 +552,8 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
}
|
||||
}
|
||||
|
||||
++n;
|
||||
++s;
|
||||
}
|
||||
|
||||
free (ports);
|
||||
}
|
||||
|
||||
for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ PortInsertUI::PortInsertUI (Gtk::Window* parent, ARDOUR::Session* sess, boost::s
|
|||
void
|
||||
PortInsertUI::update_latency_display ()
|
||||
{
|
||||
framecnt_t const sample_rate = input_selector.session()->engine().frame_rate();
|
||||
framecnt_t const sample_rate = AudioEngine::instance()->sample_rate();
|
||||
if (sample_rate == 0) {
|
||||
latency_display.set_text (_("Disconnected from audio engine"));
|
||||
} else {
|
||||
|
|
@ -93,7 +93,7 @@ PortInsertUI::check_latency_measurement ()
|
|||
}
|
||||
|
||||
char buf[128];
|
||||
framecnt_t const sample_rate = AudioEngine::instance()->frame_rate();
|
||||
framecnt_t const sample_rate = AudioEngine::instance()->sample_rate();
|
||||
|
||||
if (sample_rate == 0) {
|
||||
latency_display.set_text (_("Disconnected from audio engine"));
|
||||
|
|
|
|||
|
|
@ -2202,10 +2202,10 @@ ProcessorBox::register_actions ()
|
|||
|
||||
act = ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),
|
||||
sigc::ptr_fun (ProcessorBox::rb_choose_insert));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New External Send ..."),
|
||||
sigc::ptr_fun (ProcessorBox::rb_choose_send));
|
||||
ActionManager::jack_sensitive_actions.push_back (act);
|
||||
ActionManager::engine_sensitive_actions.push_back (act);
|
||||
|
||||
ActionManager::register_action (popup_act_grp, X_("newaux"), _("New Aux Send ..."));
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@
|
|||
#include "pbd/fpu.h"
|
||||
#include "pbd/cpus.h"
|
||||
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/dB.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
|
|
@ -1468,8 +1466,8 @@ RCOptionEditor::RCOptionEditor ()
|
|||
|
||||
#ifndef __APPLE__
|
||||
/* no JACK monitoring on CoreAudio */
|
||||
if (AudioEngine::instance()->can_request_hardware_monitoring()) {
|
||||
mm->add (HardwareMonitoring, _("JACK"));
|
||||
if (AudioEngine::instance()->port_engine().can_monitor_input()) {
|
||||
mm->add (HardwareMonitoring, _("via Audio Driver"));
|
||||
}
|
||||
#endif
|
||||
mm->add (SoftwareMonitoring, _("ardour"));
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ RouteParams_UI::cleanup_latency_frame ()
|
|||
void
|
||||
RouteParams_UI::setup_latency_frame ()
|
||||
{
|
||||
latency_widget = new LatencyGUI (*(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
|
||||
latency_widget = new LatencyGUI (*(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
|
||||
|
||||
char buf[128];
|
||||
snprintf (buf, sizeof (buf), _("Playback delay: %" PRId64 " samples"), _route->initial_delay());
|
||||
|
|
|
|||
|
|
@ -1692,7 +1692,7 @@ RouteUI::map_frozen ()
|
|||
void
|
||||
RouteUI::adjust_latency ()
|
||||
{
|
||||
LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
|
||||
LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "pbd/stacktrace.h"
|
||||
#include "pbd/openuri.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/recent_sessions.h"
|
||||
#include "ardour/session.h"
|
||||
|
|
@ -74,7 +75,6 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name,
|
|||
, monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n"
|
||||
"%1 will play NO role in monitoring"), PROGRAM_NAME))
|
||||
, monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME))
|
||||
, engine_dialog (0)
|
||||
, new_folder_chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||
, more_new_session_options_button (_("I'd like more options for this session"))
|
||||
, _output_limit_count_adj (1, 0, 100, 1, 10, 0)
|
||||
|
|
@ -91,13 +91,12 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name,
|
|||
, _existing_session_chooser_used (false)
|
||||
{
|
||||
new_user = !Glib::file_test (been_here_before_path(), Glib::FILE_TEST_EXISTS);
|
||||
need_audio_setup = EngineControl::need_setup ();
|
||||
need_session_info = (session_name.empty() || require_new);
|
||||
|
||||
_provided_session_name = session_name;
|
||||
_provided_session_path = session_path;
|
||||
|
||||
if (need_audio_setup || need_session_info || new_user) {
|
||||
if (need_session_info || new_user) {
|
||||
|
||||
use_template_button.set_group (session_template_group);
|
||||
use_session_as_template_button.set_group (session_template_group);
|
||||
|
|
@ -139,18 +138,10 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name,
|
|||
setup_monitoring_choice_page ();
|
||||
setup_monitor_section_choice_page ();
|
||||
|
||||
if (need_audio_setup) {
|
||||
setup_audio_page ();
|
||||
}
|
||||
|
||||
ic_new_session_button.set_active (true); // always create new session on first run
|
||||
|
||||
} else {
|
||||
|
||||
if (need_audio_setup) {
|
||||
setup_audio_page ();
|
||||
}
|
||||
|
||||
setup_initial_choice_page ();
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +174,7 @@ ArdourStartup::~ArdourStartup ()
|
|||
bool
|
||||
ArdourStartup::ready_without_display () const
|
||||
{
|
||||
return !new_user && !need_audio_setup && !need_session_info;
|
||||
return !new_user && !need_session_info;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -310,24 +301,6 @@ ArdourStartup::session_folder ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArdourStartup::setup_audio_page ()
|
||||
{
|
||||
engine_dialog = manage (new EngineControl);
|
||||
|
||||
engine_dialog->set_border_width (12);
|
||||
|
||||
engine_dialog->show_all ();
|
||||
|
||||
audio_page_index = append_page (*engine_dialog);
|
||||
set_page_type (*engine_dialog, ASSISTANT_PAGE_CONTENT);
|
||||
set_page_title (*engine_dialog, _("Audio / MIDI Setup"));
|
||||
|
||||
/* the default parameters should work, so the page is potentially complete */
|
||||
|
||||
set_page_complete (*engine_dialog, true);
|
||||
}
|
||||
|
||||
void
|
||||
ArdourStartup::setup_new_user_page ()
|
||||
{
|
||||
|
|
@ -403,8 +376,6 @@ Where would you like new %1 sessions to be stored by default?\n\n\
|
|||
vbox->pack_start (*txt, false, false);
|
||||
vbox->pack_start (*hbox, false, true);
|
||||
|
||||
cerr << "Setting defaultDIR session dir to [" << Config->get_default_session_parent_dir() << "]\n";
|
||||
|
||||
default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
|
||||
default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
|
||||
default_dir_chooser->show ();
|
||||
|
|
@ -661,13 +632,6 @@ ArdourStartup::on_delete_event (GdkEventAny*)
|
|||
void
|
||||
ArdourStartup::on_apply ()
|
||||
{
|
||||
if (engine_dialog) {
|
||||
if (engine_dialog->setup_engine ()) {
|
||||
set_current_page (audio_page_index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_modified) {
|
||||
|
||||
if (default_dir_chooser) {
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ class ArdourStartup : public Gtk::Assistant {
|
|||
bool use_session_template();
|
||||
std::string session_template_name();
|
||||
|
||||
EngineControl* engine_control() { return engine_dialog; }
|
||||
|
||||
// advanced session options
|
||||
|
||||
bool create_master_bus() const;
|
||||
|
|
@ -82,7 +80,6 @@ class ArdourStartup : public Gtk::Assistant {
|
|||
gint _response;
|
||||
bool config_modified;
|
||||
bool new_user;
|
||||
bool need_audio_setup;
|
||||
bool need_session_info;
|
||||
bool new_only;
|
||||
std::string _provided_session_name;
|
||||
|
|
@ -175,11 +172,6 @@ class ArdourStartup : public Gtk::Assistant {
|
|||
|
||||
void existing_session_selected ();
|
||||
|
||||
/* audio setup page */
|
||||
|
||||
void setup_audio_page ();
|
||||
EngineControl* engine_dialog;
|
||||
|
||||
/* new sessions */
|
||||
|
||||
void setup_new_session_page ();
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ emulate_key_event (Gtk::Widget* w, unsigned int keyval)
|
|||
ev.state = 0;
|
||||
ev.keyval = keyval;
|
||||
ev.length = 0;
|
||||
ev.string = "";
|
||||
ev.string = (const gchar*) "";
|
||||
ev.hardware_keycode = keymapkey[0].keycode;
|
||||
ev.group = keymapkey[0].group;
|
||||
g_free(keymapkey);
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ ProxyBase::hide ()
|
|||
}
|
||||
|
||||
bool
|
||||
ProxyBase::handle_win_event (GdkEventAny *ev)
|
||||
ProxyBase::handle_win_event (GdkEventAny* /*ev*/)
|
||||
{
|
||||
hide();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -520,6 +520,7 @@ def build(bld):
|
|||
'SMALLER' : '9',
|
||||
'SMALL' : '10',
|
||||
'NORMAL' : '11',
|
||||
'BIG' : '13',
|
||||
'BIGGER' : '17',
|
||||
'LARGE' : '18',
|
||||
'LARGER' : '28',
|
||||
|
|
@ -545,6 +546,7 @@ def build(bld):
|
|||
'SMALLER' : '8',
|
||||
'SMALL' : '9',
|
||||
'NORMAL' : '10',
|
||||
'BIG' : '14',
|
||||
'BIGGER' : '17',
|
||||
'LARGE' : '18',
|
||||
'LARGER' : '24',
|
||||
|
|
|
|||
|
|
@ -75,9 +75,7 @@ namespace ARDOUR {
|
|||
bool translations_are_enabled ();
|
||||
bool set_translations_enabled (bool);
|
||||
|
||||
static inline microseconds_t get_microseconds () {
|
||||
return (microseconds_t) jack_get_time();
|
||||
}
|
||||
microseconds_t get_microseconds ();
|
||||
|
||||
void setup_fpu ();
|
||||
std::vector<SyncSource> get_available_sync_options();
|
||||
|
|
|
|||
|
|
@ -16,14 +16,12 @@
|
|||
|
||||
*/
|
||||
|
||||
#ifndef __libmidi_port_h__
|
||||
#define __libmidi_port_h__
|
||||
#ifndef __libardour_async_midiport_h__
|
||||
#define __libardour_async_midiport_h__
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <jack/types.h>
|
||||
|
||||
#include "pbd/xml++.h"
|
||||
#include "pbd/crossthread.h"
|
||||
#include "pbd/signals.h"
|
||||
|
|
@ -36,26 +34,26 @@
|
|||
#include "midi++/parser.h"
|
||||
#include "midi++/port.h"
|
||||
|
||||
namespace MIDI {
|
||||
#include "ardour/midi_port.h"
|
||||
|
||||
class Channel;
|
||||
class PortRequest;
|
||||
namespace ARDOUR {
|
||||
|
||||
class AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port {
|
||||
|
||||
class JackMIDIPort : public Port {
|
||||
public:
|
||||
JackMIDIPort (std::string const &, Port::Flags, jack_client_t *);
|
||||
JackMIDIPort (const XMLNode&, jack_client_t *);
|
||||
~JackMIDIPort ();
|
||||
AsyncMIDIPort (std::string const &, PortFlags);
|
||||
~AsyncMIDIPort ();
|
||||
|
||||
XMLNode& get_state () const;
|
||||
void set_state (const XMLNode&);
|
||||
/* called from an RT context */
|
||||
|
||||
void cycle_start (pframes_t nframes);
|
||||
void cycle_end ();
|
||||
void cycle_end (pframes_t nframes);
|
||||
|
||||
/* called from non-RT context */
|
||||
|
||||
void parse (framecnt_t timestamp);
|
||||
int write (const byte *msg, size_t msglen, timestamp_t timestamp);
|
||||
int read (byte *buf, size_t bufsize);
|
||||
int write (const MIDI::byte *msg, size_t msglen, MIDI::timestamp_t timestamp);
|
||||
int read (MIDI::byte *buf, size_t bufsize);
|
||||
void drain (int check_interval_usecs);
|
||||
int selectable () const {
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
|
@ -65,26 +63,15 @@ class JackMIDIPort : public Port {
|
|||
#endif
|
||||
}
|
||||
|
||||
pframes_t nframes_this_cycle() const { return _nframes_this_cycle; }
|
||||
|
||||
void reestablish (jack_client_t *);
|
||||
void reconnect ();
|
||||
|
||||
static void set_process_thread (pthread_t);
|
||||
static pthread_t get_process_thread () { return _process_thread; }
|
||||
static bool is_process_thread();
|
||||
|
||||
static PBD::Signal0<void> MakeConnections;
|
||||
static PBD::Signal0<void> JackHalted;
|
||||
|
||||
private:
|
||||
bool _currently_in_cycle;
|
||||
pframes_t _nframes_this_cycle;
|
||||
jack_client_t* _jack_client;
|
||||
jack_port_t* _jack_port;
|
||||
timestamp_t _last_write_timestamp;
|
||||
private:
|
||||
bool _currently_in_cycle;
|
||||
MIDI::timestamp_t _last_write_timestamp;
|
||||
RingBuffer< Evoral::Event<double> > output_fifo;
|
||||
Evoral::EventRingBuffer<timestamp_t> input_fifo;
|
||||
Evoral::EventRingBuffer<MIDI::timestamp_t> input_fifo;
|
||||
Glib::Threads::Mutex output_fifo_lock;
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
CrossThreadChannel xthread;
|
||||
|
|
@ -102,10 +89,11 @@ private:
|
|||
void make_connections ();
|
||||
void init (std::string const &, Flags);
|
||||
|
||||
static pthread_t _process_thread;
|
||||
void flush_output_fifo (pframes_t);
|
||||
|
||||
static pthread_t _process_thread;
|
||||
};
|
||||
|
||||
} // namespace MIDI
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif // __libmidi_port_h__
|
||||
#endif /* __libardour_async_midiport_h__ */
|
||||
432
libs/ardour/ardour/audio_backend.h
Normal file
432
libs/ardour/ardour/audio_backend.h
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __libardour_audiobackend_h__
|
||||
#define __libardour_audiobackend_h__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AudioEngine;
|
||||
class PortEngine;
|
||||
class PortManager;
|
||||
|
||||
class AudioBackend {
|
||||
public:
|
||||
|
||||
AudioBackend (AudioEngine& e) : engine (e){}
|
||||
virtual ~AudioBackend () {}
|
||||
|
||||
/** Return the name of this backend.
|
||||
*
|
||||
* Should use a well-known, unique term. Expected examples
|
||||
* might include "JACK", "CoreAudio", "ASIO" etc.
|
||||
*/
|
||||
virtual std::string name() const = 0;
|
||||
|
||||
/** Return a private, type-free pointer to any data
|
||||
* that might be useful to a concrete implementation
|
||||
*/
|
||||
virtual void* private_handle() const = 0;
|
||||
|
||||
/** Return true if the underlying mechanism/API is still available
|
||||
* for us to utilize. return false if some or all of the AudioBackend
|
||||
* API can no longer be effectively used.
|
||||
*/
|
||||
virtual bool connected() const = 0;
|
||||
|
||||
/** Return true if the callback from the underlying mechanism/API
|
||||
* (CoreAudio, JACK, ASIO etc.) occurs in a thread subject to realtime
|
||||
* constraints. Return false otherwise.
|
||||
*/
|
||||
virtual bool is_realtime () const = 0;
|
||||
|
||||
/* Discovering devices and parameters */
|
||||
|
||||
/** Return true if this backend requires the selection of a "driver"
|
||||
* before any device can be selected. Return false otherwise.
|
||||
*
|
||||
* Intended mainly to differentiate between meta-APIs like JACK
|
||||
* which can still expose different backends (such as ALSA or CoreAudio
|
||||
* or FFADO or netjack) and those like ASIO or CoreAudio which
|
||||
* do not.
|
||||
*/
|
||||
virtual bool requires_driver_selection() const { return false; }
|
||||
|
||||
/** If the return value of requires_driver_selection() is true,
|
||||
* then this function can return the list of known driver names.
|
||||
*
|
||||
* If the return value of requires_driver_selection() is false,
|
||||
* then this function should not be called. If it is called
|
||||
* its return value is an empty vector of strings.
|
||||
*/
|
||||
virtual std::vector<std::string> enumerate_drivers() const { return std::vector<std::string>(); }
|
||||
|
||||
/** Returns zero if the backend can successfully use @param name as the
|
||||
* driver, non-zero otherwise.
|
||||
*
|
||||
* Should not be used unless the backend returns true from
|
||||
* requires_driver_selection()
|
||||
*/
|
||||
virtual int set_driver (const std::string& /*drivername*/) { return 0; }
|
||||
|
||||
/** used to list device names along with whether or not they are currently
|
||||
* available.
|
||||
*/
|
||||
struct DeviceStatus {
|
||||
std::string name;
|
||||
bool available;
|
||||
|
||||
DeviceStatus (const std::string& s, bool avail) : name (s), available (avail) {}
|
||||
};
|
||||
|
||||
/** Returns a collection of DeviceStatuses identifying devices discovered
|
||||
* by this backend since the start of the process.
|
||||
*
|
||||
* Any of the names in each DeviceStatus may be used to identify a
|
||||
* device in other calls to the backend, though any of them may become
|
||||
* invalid at any time.
|
||||
*/
|
||||
virtual std::vector<DeviceStatus> enumerate_devices () const = 0;
|
||||
|
||||
/** Returns a collection of float identifying sample rates that are
|
||||
* potentially usable with the hardware identified by @param device.
|
||||
* Any of these values may be supplied in other calls to this backend
|
||||
* as the desired sample rate to use with the name device, but the
|
||||
* requested sample rate may turn out to be unavailable, or become invalid
|
||||
* at any time.
|
||||
*/
|
||||
virtual std::vector<float> available_sample_rates (const std::string& device) const = 0;
|
||||
/** Returns a collection of uint32 identifying buffer sizes that are
|
||||
* potentially usable with the hardware identified by @param device.
|
||||
* Any of these values may be supplied in other calls to this backend
|
||||
* as the desired buffer size to use with the name device, but the
|
||||
* requested buffer size may turn out to be unavailable, or become invalid
|
||||
* at any time.
|
||||
*/
|
||||
virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const = 0;
|
||||
|
||||
/** Returns the maximum number of input channels that are potentially
|
||||
* usable with the hardware identified by @param device. Any number from 1
|
||||
* to the value returned may be supplied in other calls to this backend as
|
||||
* the input channel count to use with the name device, but the requested
|
||||
* count may turn out to be unavailable, or become invalid at any time.
|
||||
*/
|
||||
virtual uint32_t available_input_channel_count (const std::string& device) const = 0;
|
||||
|
||||
/** Returns the maximum number of output channels that are potentially
|
||||
* usable with the hardware identified by @param device. Any number from 1
|
||||
* to the value returned may be supplied in other calls to this backend as
|
||||
* the output channel count to use with the name device, but the requested
|
||||
* count may turn out to be unavailable, or become invalid at any time.
|
||||
*/
|
||||
virtual uint32_t available_output_channel_count (const std::string& device) const = 0;
|
||||
|
||||
/* Return true if the derived class can change the sample rate of the
|
||||
* device in use while the device is already being used. Return false
|
||||
* otherwise. (example: JACK cannot do this as of September 2013)
|
||||
*/
|
||||
virtual bool can_change_sample_rate_when_running () const = 0;
|
||||
/* Return true if the derived class can change the buffer size of the
|
||||
* device in use while the device is already being used. Return false
|
||||
* otherwise.
|
||||
*/
|
||||
virtual bool can_change_buffer_size_when_running () const = 0;
|
||||
|
||||
/* Set the hardware parameters.
|
||||
*
|
||||
* If called when the current state is stopped or paused,
|
||||
* the changes will not take effect until the state changes to running.
|
||||
*
|
||||
* If called while running, the state will change as fast as the
|
||||
* implementation allows.
|
||||
*
|
||||
* All set_*() methods return zero on success, non-zero otherwise.
|
||||
*/
|
||||
|
||||
/** Set the name of the device to be used
|
||||
*/
|
||||
virtual int set_device_name (const std::string&) = 0;
|
||||
/** Set the sample rate to be used
|
||||
*/
|
||||
virtual int set_sample_rate (float) = 0;
|
||||
/** Set the buffer size to be used.
|
||||
*
|
||||
* The device is assumed to use a double buffering scheme, so that one
|
||||
* buffer's worth of data can be processed by hardware while software works
|
||||
* on the other buffer. All known suitable audio APIs support this model
|
||||
* (though ALSA allows for alternate numbers of buffers, and CoreAudio
|
||||
* doesn't directly expose the concept).
|
||||
*/
|
||||
virtual int set_buffer_size (uint32_t) = 0;
|
||||
/** Set the preferred underlying hardware sample format
|
||||
*
|
||||
* This does not change the sample format (32 bit float) read and
|
||||
* written to the device via the Port API.
|
||||
*/
|
||||
virtual int set_sample_format (SampleFormat) = 0;
|
||||
/** Set the preferred underlying hardware data layout.
|
||||
* If @param yn is true, then the hardware will interleave
|
||||
* samples for successive channels; otherwise, the hardware will store
|
||||
* samples for a single channel contiguously.
|
||||
*
|
||||
* Setting this does not change the fact that all data streams
|
||||
* to and from Ports are mono (essentially, non-interleaved)
|
||||
*/
|
||||
virtual int set_interleaved (bool yn) = 0;
|
||||
/** Set the number of input channels that should be used
|
||||
*/
|
||||
virtual int set_input_channels (uint32_t) = 0;
|
||||
/** Set the number of output channels that should be used
|
||||
*/
|
||||
virtual int set_output_channels (uint32_t) = 0;
|
||||
/** Set the (additional) input latency that cannot be determined via
|
||||
* the implementation's underlying code (e.g. latency from
|
||||
* external D-A/D-A converters. Units are samples.
|
||||
*/
|
||||
virtual int set_systemic_input_latency (uint32_t) = 0;
|
||||
/** Set the (additional) output latency that cannot be determined via
|
||||
* the implementation's underlying code (e.g. latency from
|
||||
* external D-A/D-A converters. Units are samples.
|
||||
*/
|
||||
virtual int set_systemic_output_latency (uint32_t) = 0;
|
||||
|
||||
/* Retrieving parameters */
|
||||
|
||||
virtual std::string device_name () const = 0;
|
||||
virtual float sample_rate () const = 0;
|
||||
virtual uint32_t buffer_size () const = 0;
|
||||
virtual SampleFormat sample_format () const = 0;
|
||||
virtual bool interleaved () const = 0;
|
||||
virtual uint32_t input_channels () const = 0;
|
||||
virtual uint32_t output_channels () const = 0;
|
||||
virtual uint32_t systemic_input_latency () const = 0;
|
||||
virtual uint32_t systemic_output_latency () const = 0;
|
||||
|
||||
/** Return the name of a control application for the
|
||||
* selected/in-use device. If no such application exists,
|
||||
* or if no device has been selected or is in-use,
|
||||
* return an empty string.
|
||||
*/
|
||||
virtual std::string control_app_name() const = 0;
|
||||
/** Launch the control app for the currently in-use or
|
||||
* selected device. May do nothing if the control
|
||||
* app is undefined or cannot be launched.
|
||||
*/
|
||||
virtual void launch_control_app () = 0;
|
||||
/* Basic state control */
|
||||
|
||||
/** Start using the device named in the most recent call
|
||||
* to set_device(), with the parameters set by various
|
||||
* the most recent calls to set_sample_rate() etc. etc.
|
||||
*
|
||||
* At some undetermined time after this function is successfully called,
|
||||
* the backend will start calling the ::process_callback() method of
|
||||
* the AudioEngine referenced by @param engine. These calls will
|
||||
* occur in a thread created by and/or under the control of the backend.
|
||||
*
|
||||
* Return zero if successful, negative values otherwise.
|
||||
*/
|
||||
virtual int start () = 0;
|
||||
|
||||
/** Stop using the device currently in use.
|
||||
*
|
||||
* If the function is successfully called, no subsequent calls to the
|
||||
* process_callback() of @param engine will be made after the function
|
||||
* returns, until parameters are reset and start() are called again.
|
||||
*
|
||||
* The backend is considered to be un-configured after a successful
|
||||
* return, and requires calls to set hardware parameters before it can be
|
||||
* start()-ed again. See pause() for a way to avoid this. stop() should
|
||||
* only be used when reconfiguration is required OR when there are no
|
||||
* plans to use the backend in the future with a reconfiguration.
|
||||
*
|
||||
* Return zero if successful, 1 if the device is not in use, negative values on error
|
||||
*/
|
||||
virtual int stop () = 0;
|
||||
|
||||
/** Temporarily cease using the device named in the most recent call to set_parameters().
|
||||
*
|
||||
* If the function is successfully called, no subsequent calls to the
|
||||
* process_callback() of @param engine will be made after the function
|
||||
* returns, until start() is called again.
|
||||
*
|
||||
* The backend will retain its existing parameter configuration after a successful
|
||||
* return, and does NOT require any calls to set hardware parameters before it can be
|
||||
* start()-ed again.
|
||||
*
|
||||
* Return zero if successful, 1 if the device is not in use, negative values on error
|
||||
*/
|
||||
virtual int pause () = 0;
|
||||
|
||||
/** While remaining connected to the device, and without changing its
|
||||
* configuration, start (or stop) calling the process_callback() of @param engine
|
||||
* without waiting for the device. Once process_callback() has returned, it
|
||||
* will be called again immediately, thus allowing for faster-than-realtime
|
||||
* processing.
|
||||
*
|
||||
* All registered ports remain in existence and all connections remain
|
||||
* unaltered. However, any physical ports should NOT be used by the
|
||||
* process_callback() during freewheeling - the data behaviour is undefined.
|
||||
*
|
||||
* If @param start_stop is true, begin this behaviour; otherwise cease this
|
||||
* behaviour if it currently occuring, and return to calling
|
||||
* process_callback() of @param engine by waiting for the device.
|
||||
*
|
||||
* Return zero on success, non-zero otherwise.
|
||||
*/
|
||||
virtual int freewheel (bool start_stop) = 0;
|
||||
|
||||
/** return the fraction of the time represented by the current buffer
|
||||
* size that is being used for each buffer process cycle, as a value
|
||||
* from 0.0 to 1.0
|
||||
*
|
||||
* E.g. if the buffer size represents 5msec and current processing
|
||||
* takes 1msec, the returned value should be 0.2.
|
||||
*
|
||||
* Implementations can feel free to smooth the values returned over
|
||||
* time (e.g. high pass filtering, or its equivalent).
|
||||
*/
|
||||
virtual float cpu_load() const = 0;
|
||||
|
||||
/* Transport Control (JACK is the only audio API that currently offers
|
||||
the concept of shared transport control)
|
||||
*/
|
||||
|
||||
/** Attempt to change the transport state to TransportRolling.
|
||||
*/
|
||||
virtual void transport_start () {}
|
||||
/** Attempt to change the transport state to TransportStopped.
|
||||
*/
|
||||
virtual void transport_stop () {}
|
||||
/** return the current transport state
|
||||
*/
|
||||
virtual TransportState transport_state () const { return TransportStopped; }
|
||||
/** Attempt to locate the transport to @param pos
|
||||
*/
|
||||
virtual void transport_locate (framepos_t /*pos*/) {}
|
||||
/** Return the current transport location, in samples measured
|
||||
* from the origin (defined by the transport time master)
|
||||
*/
|
||||
virtual framepos_t transport_frame() const { return 0; }
|
||||
|
||||
/** If @param yn is true, become the time master for any inter-application transport
|
||||
* timebase, otherwise cease to be the time master for the same.
|
||||
*
|
||||
* Return zero on success, non-zero otherwise
|
||||
*
|
||||
* JACK is the only currently known audio API with the concept of a shared
|
||||
* transport timebase.
|
||||
*/
|
||||
virtual int set_time_master (bool /*yn*/) { return 0; }
|
||||
|
||||
virtual int usecs_per_cycle () const { return 1000000 * (buffer_size() / sample_rate()); }
|
||||
virtual size_t raw_buffer_size (DataType t) = 0;
|
||||
|
||||
/* Process time */
|
||||
|
||||
/** return the time according to the sample clock in use, measured in
|
||||
* samples since an arbitrary zero time in the past. The value should
|
||||
* increase monotonically and linearly, without interruption from any
|
||||
* source (including CPU frequency scaling).
|
||||
*
|
||||
* 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
|
||||
* able to accurately determine the correct sample time.
|
||||
*
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
virtual pframes_t sample_time () = 0;
|
||||
|
||||
/** Return the time according to the sample clock in use when the most
|
||||
* recent buffer process cycle began. Can be called from any thread.
|
||||
*/
|
||||
virtual pframes_t sample_time_at_cycle_start () = 0;
|
||||
|
||||
/** Return the time since the current buffer process cycle started,
|
||||
* in samples, according to the sample clock in use.
|
||||
*
|
||||
* 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 samples_since_cycle_start () = 0;
|
||||
|
||||
/** Return true if it possible to determine the offset in samples of the
|
||||
* first video frame that starts within the current buffer process cycle,
|
||||
* measured from the first sample of the cycle. If returning true,
|
||||
* set @param offset to that offset.
|
||||
*
|
||||
* Eg. if it can be determined that the first video frame within the cycle
|
||||
* starts 28 samples after the first sample of the cycle, then this method
|
||||
* should return true and set @param offset to 28.
|
||||
*
|
||||
* May be impossible to support outside of JACK, which has specific support
|
||||
* (in some cases, hardware support) for this feature.
|
||||
*
|
||||
* Can ONLY be called from within a process() callback tree (which implies
|
||||
* that it can only be called by a process thread)
|
||||
*/
|
||||
virtual bool get_sync_offset (pframes_t& /*offset*/) const { return false; }
|
||||
|
||||
/** Create a new thread suitable for running part of the buffer process
|
||||
* cycle (i.e. Realtime scheduling, memory allocation, etc. etc are all
|
||||
* correctly setup), with a stack size given in bytes by specified @param
|
||||
* stacksize. The thread will begin executing @param func, and will exit
|
||||
* when that function returns.
|
||||
*/
|
||||
virtual int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize) = 0;
|
||||
|
||||
virtual void update_latencies () = 0;
|
||||
|
||||
protected:
|
||||
AudioEngine& engine;
|
||||
};
|
||||
|
||||
struct AudioBackendInfo {
|
||||
const char* name;
|
||||
|
||||
int (*instantiate) (const std::string& arg1, const std::string& arg2);
|
||||
int (*deinstantiate) (void);
|
||||
|
||||
boost::shared_ptr<AudioBackend> (*backend_factory) (AudioEngine&);
|
||||
boost::shared_ptr<PortEngine> (*portengine_factory) (PortManager&);
|
||||
|
||||
/** Return true if the underlying mechanism/API has been
|
||||
* configured and does not need (re)configuration in order
|
||||
* to be usable. Return false otherwise.
|
||||
*
|
||||
* Note that this may return true if (re)configuration, even though
|
||||
* not currently required, is still possible.
|
||||
*/
|
||||
bool (*already_configured)();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif /* __libardour_audiobackend_h__ */
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ class AudioDiskstream : public Diskstream
|
|||
XMLNode& get_state(void);
|
||||
int set_state(const XMLNode& node, int version);
|
||||
|
||||
void request_jack_monitors_input (bool);
|
||||
void request_input_monitoring (bool);
|
||||
|
||||
static void swap_by_ptr (Sample *first, Sample *last) {
|
||||
while (first < last) {
|
||||
|
|
@ -160,7 +160,7 @@ class AudioDiskstream : public Diskstream
|
|||
std::string name;
|
||||
|
||||
bool is_physical () const;
|
||||
void request_jack_monitors_input (bool) const;
|
||||
void request_input_monitoring (bool) const;
|
||||
};
|
||||
|
||||
/** Information about one of our channels */
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ class AudioPort : public Port
|
|||
AudioBuffer& get_audio_buffer (pframes_t nframes);
|
||||
|
||||
protected:
|
||||
friend class AudioEngine;
|
||||
friend class PortManager;
|
||||
AudioPort (std::string const &, PortFlags);
|
||||
|
||||
AudioPort (std::string const &, Flags);
|
||||
/* special access for engine only */
|
||||
/* special access for PortManager only (hah, C++) */
|
||||
Sample* engine_get_whole_audio_buffer ();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -33,29 +33,22 @@
|
|||
|
||||
#include <glibmm/threads.h>
|
||||
|
||||
#include "pbd/rcu.h"
|
||||
#include "pbd/signals.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#include <jack/weakjack.h>
|
||||
#endif
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/transport.h>
|
||||
#include <jack/thread.h>
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
|
||||
#include "ardour/data_type.h"
|
||||
#include "ardour/session_handle.h"
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/chan_count.h"
|
||||
#include "ardour/port_manager.h"
|
||||
|
||||
#ifdef HAVE_JACK_SESSION
|
||||
#include <jack/session.h>
|
||||
#endif
|
||||
|
||||
class MTDM;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class InternalPort;
|
||||
|
|
@ -63,298 +56,188 @@ class MidiPort;
|
|||
class Port;
|
||||
class Session;
|
||||
class ProcessThread;
|
||||
class AudioBackend;
|
||||
class AudioBackendInfo;
|
||||
|
||||
class AudioEngine : public SessionHandlePtr
|
||||
class AudioEngine : public SessionHandlePtr, public PortManager
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
|
||||
|
||||
AudioEngine (std::string client_name, std::string session_uuid);
|
||||
virtual ~AudioEngine ();
|
||||
static AudioEngine* create ();
|
||||
|
||||
jack_client_t* jack() const;
|
||||
bool connected() const { return _jack != 0; }
|
||||
virtual ~AudioEngine ();
|
||||
|
||||
bool is_realtime () const;
|
||||
int discover_backends();
|
||||
std::vector<const AudioBackendInfo*> available_backends() const;
|
||||
std::string current_backend_name () const;
|
||||
boost::shared_ptr<AudioBackend> set_backend (const std::string&, const std::string& arg1, const std::string& arg2);
|
||||
boost::shared_ptr<AudioBackend> current_backend() const { return _backend; }
|
||||
bool setup_required () const;
|
||||
|
||||
ProcessThread* main_thread() const { return _main_thread; }
|
||||
ProcessThread* main_thread() const { return _main_thread; }
|
||||
|
||||
std::string client_name() const { return jack_client_name; }
|
||||
/* START BACKEND PROXY API
|
||||
*
|
||||
* See audio_backend.h for full documentation and semantics. These wrappers
|
||||
* just forward to a backend implementation.
|
||||
*/
|
||||
|
||||
int start ();
|
||||
int stop ();
|
||||
int pause ();
|
||||
int freewheel (bool start_stop);
|
||||
float get_cpu_load() const ;
|
||||
void transport_start ();
|
||||
void transport_stop ();
|
||||
TransportState transport_state ();
|
||||
void transport_locate (framepos_t pos);
|
||||
framepos_t transport_frame();
|
||||
framecnt_t sample_rate () const;
|
||||
pframes_t samples_per_cycle () const;
|
||||
int usecs_per_cycle () const;
|
||||
size_t raw_buffer_size (DataType t);
|
||||
pframes_t sample_time ();
|
||||
pframes_t sample_time_at_cycle_start ();
|
||||
pframes_t samples_since_cycle_start ();
|
||||
bool get_sync_offset (pframes_t& offset) const;
|
||||
int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize);
|
||||
bool is_realtime() const;
|
||||
bool connected() const;
|
||||
|
||||
int reconnect_to_jack ();
|
||||
int disconnect_from_jack();
|
||||
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 */
|
||||
|
||||
bool freewheeling() const { return _freewheeling; }
|
||||
bool running() const { return _running; }
|
||||
|
||||
Glib::Threads::Mutex& process_lock() { return _process_lock; }
|
||||
|
||||
int request_buffer_size (pframes_t samples) {
|
||||
return set_buffer_size (samples);
|
||||
}
|
||||
|
||||
framecnt_t processed_frames() const { return _processed_frames; }
|
||||
|
||||
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"; }
|
||||
};
|
||||
|
||||
void split_cycle (pframes_t offset);
|
||||
|
||||
int reset_timebase ();
|
||||
|
||||
void update_latencies ();
|
||||
|
||||
/* this signal is sent for every process() cycle while freewheeling.
|
||||
(the regular process() call to session->process() is not made)
|
||||
*/
|
||||
|
||||
PBD::Signal1<int, pframes_t> Freewheel;
|
||||
|
||||
PBD::Signal0<void> Xrun;
|
||||
|
||||
/* this signal is emitted if the sample rate changes */
|
||||
|
||||
PBD::Signal1<void, framecnt_t> SampleRateChanged;
|
||||
|
||||
/* this signal is sent if the backend ever disconnects us */
|
||||
|
||||
PBD::Signal1<void,const char*> Halted;
|
||||
|
||||
/* these two are emitted when the engine itself is
|
||||
started and stopped
|
||||
*/
|
||||
|
||||
PBD::Signal0<void> Running;
|
||||
PBD::Signal0<void> Stopped;
|
||||
|
||||
static AudioEngine* instance() { return _instance; }
|
||||
static void destroy();
|
||||
void died ();
|
||||
|
||||
/* The backend will cause these at the appropriate time(s)
|
||||
*/
|
||||
int process_callback (pframes_t nframes);
|
||||
int buffer_size_change (pframes_t nframes);
|
||||
int sample_rate_change (pframes_t nframes);
|
||||
void freewheel_callback (bool);
|
||||
void timebase_callback (TransportState state, pframes_t nframes, framepos_t pos, int new_position);
|
||||
int sync_callback (TransportState state, framepos_t position);
|
||||
int port_registration_callback ();
|
||||
void latency_callback (bool for_playback);
|
||||
void halted_callback (const char* reason);
|
||||
|
||||
/* sets up the process callback thread */
|
||||
static void thread_init_callback (void *);
|
||||
|
||||
/* latency measurement */
|
||||
|
||||
MTDM* mtdm();
|
||||
void start_latency_detection ();
|
||||
void stop_latency_detection ();
|
||||
void set_latency_input_port (const std::string&);
|
||||
void set_latency_output_port (const std::string&);
|
||||
uint32_t latency_signal_delay () const { return _latency_signal_latency; }
|
||||
|
||||
private:
|
||||
AudioEngine ();
|
||||
|
||||
static AudioEngine* _instance;
|
||||
|
||||
boost::shared_ptr<AudioBackend> _backend;
|
||||
|
||||
Glib::Threads::Mutex _process_lock;
|
||||
Glib::Threads::Cond session_removed;
|
||||
bool session_remove_pending;
|
||||
frameoffset_t session_removal_countdown;
|
||||
gain_t session_removal_gain;
|
||||
gain_t session_removal_gain_step;
|
||||
bool _running;
|
||||
bool _freewheeling;
|
||||
/// number of frames between each check for changes in monitor input
|
||||
framecnt_t monitor_check_interval;
|
||||
/// time of the last monitor check in frames
|
||||
framecnt_t last_monitor_check;
|
||||
/// the number of frames processed since start() was called
|
||||
framecnt_t _processed_frames;
|
||||
Glib::Threads::Thread* m_meter_thread;
|
||||
ProcessThread* _main_thread;
|
||||
MTDM* _mtdm;
|
||||
bool _measuring_latency;
|
||||
PortEngine::PortHandle _latency_input_port;
|
||||
PortEngine::PortHandle _latency_output_port;
|
||||
framecnt_t _latency_flush_frames;
|
||||
std::string _latency_input_name;
|
||||
std::string _latency_output_name;
|
||||
framecnt_t _latency_signal_latency;
|
||||
|
||||
int stop (bool forever = false);
|
||||
int start ();
|
||||
bool running() const { return _running; }
|
||||
|
||||
Glib::Threads::Mutex& process_lock() { return _process_lock; }
|
||||
|
||||
framecnt_t frame_rate () const;
|
||||
pframes_t frames_per_cycle () const;
|
||||
|
||||
size_t raw_buffer_size(DataType t);
|
||||
|
||||
int usecs_per_cycle () const { return _usecs_per_cycle; }
|
||||
|
||||
bool get_sync_offset (pframes_t & offset) const;
|
||||
|
||||
pframes_t frames_since_cycle_start () {
|
||||
jack_client_t* _priv_jack = _jack;
|
||||
if (!_running || !_priv_jack) {
|
||||
return 0;
|
||||
}
|
||||
return jack_frames_since_cycle_start (_priv_jack);
|
||||
}
|
||||
|
||||
pframes_t frame_time () {
|
||||
jack_client_t* _priv_jack = _jack;
|
||||
if (!_running || !_priv_jack) {
|
||||
return 0;
|
||||
}
|
||||
return jack_frame_time (_priv_jack);
|
||||
}
|
||||
|
||||
pframes_t frame_time_at_cycle_start () {
|
||||
jack_client_t* _priv_jack = _jack;
|
||||
if (!_running || !_priv_jack) {
|
||||
return 0;
|
||||
}
|
||||
return jack_last_frame_time (_priv_jack);
|
||||
}
|
||||
|
||||
pframes_t transport_frame () const {
|
||||
const jack_client_t* _priv_jack = _jack;
|
||||
if (!_running || !_priv_jack) {
|
||||
return 0;
|
||||
}
|
||||
return jack_get_current_transport_frame (_priv_jack);
|
||||
}
|
||||
|
||||
int request_buffer_size (pframes_t);
|
||||
|
||||
framecnt_t processed_frames() const { return _processed_frames; }
|
||||
|
||||
float get_cpu_load() {
|
||||
jack_client_t* _priv_jack = _jack;
|
||||
if (!_running || !_priv_jack) {
|
||||
return 0;
|
||||
}
|
||||
return jack_cpu_load (_priv_jack);
|
||||
}
|
||||
|
||||
void set_session (Session *);
|
||||
void remove_session (); // not a replacement for SessionHandle::session_going_away()
|
||||
|
||||
class PortRegistrationFailure : public std::exception {
|
||||
public:
|
||||
PortRegistrationFailure (std::string const & why = "")
|
||||
: reason (why) {}
|
||||
|
||||
~PortRegistrationFailure () throw () {}
|
||||
|
||||
virtual const char *what() const throw () { return reason.c_str(); }
|
||||
|
||||
private:
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
class NoBackendAvailable : public std::exception {
|
||||
public:
|
||||
virtual const char *what() const throw() { return "could not connect to engine backend"; }
|
||||
};
|
||||
|
||||
boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname);
|
||||
boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname);
|
||||
int unregister_port (boost::shared_ptr<Port>);
|
||||
|
||||
bool port_is_physical (const std::string&) const;
|
||||
void request_jack_monitors_input (const std::string&, bool) const;
|
||||
|
||||
void split_cycle (pframes_t offset);
|
||||
|
||||
int connect (const std::string& source, const std::string& destination);
|
||||
int disconnect (const std::string& source, const std::string& destination);
|
||||
int disconnect (boost::shared_ptr<Port>);
|
||||
|
||||
const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags);
|
||||
|
||||
bool can_request_hardware_monitoring ();
|
||||
|
||||
ChanCount n_physical_outputs () const;
|
||||
ChanCount n_physical_inputs () const;
|
||||
|
||||
void get_physical_outputs (DataType type, std::vector<std::string>&);
|
||||
void get_physical_inputs (DataType type, std::vector<std::string>&);
|
||||
|
||||
boost::shared_ptr<Port> get_port_by_name (const std::string &);
|
||||
void port_renamed (const std::string&, const std::string&);
|
||||
|
||||
enum TransportState {
|
||||
TransportStopped = JackTransportStopped,
|
||||
TransportRolling = JackTransportRolling,
|
||||
TransportLooping = JackTransportLooping,
|
||||
TransportStarting = JackTransportStarting
|
||||
};
|
||||
|
||||
void transport_start ();
|
||||
void transport_stop ();
|
||||
void transport_locate (framepos_t);
|
||||
TransportState transport_state ();
|
||||
|
||||
int reset_timebase ();
|
||||
|
||||
void update_latencies ();
|
||||
|
||||
/* start/stop freewheeling */
|
||||
|
||||
int freewheel (bool onoff);
|
||||
bool freewheeling() const { return _freewheeling; }
|
||||
|
||||
/* this signal is sent for every process() cycle while freewheeling.
|
||||
_ the regular process() call to session->process() is not made.
|
||||
*/
|
||||
|
||||
PBD::Signal1<int, pframes_t> Freewheel;
|
||||
|
||||
PBD::Signal0<void> Xrun;
|
||||
|
||||
/* this signal is if JACK notifies us of a graph order event */
|
||||
|
||||
PBD::Signal0<void> GraphReordered;
|
||||
|
||||
#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;
|
||||
|
||||
/* this signal is sent if JACK ever disconnects us */
|
||||
|
||||
PBD::Signal1<void,const char*> Halted;
|
||||
|
||||
/* these two are emitted when the engine itself is
|
||||
started and stopped
|
||||
*/
|
||||
|
||||
PBD::Signal0<void> Running;
|
||||
PBD::Signal0<void> Stopped;
|
||||
|
||||
/** Emitted if a JACK port is registered or unregistered */
|
||||
PBD::Signal0<void> PortRegisteredOrUnregistered;
|
||||
|
||||
/** Emitted if a JACK port is connected or disconnected.
|
||||
* The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour.
|
||||
* The std::string parameters are the (long) port names.
|
||||
* The bool parameter is true if ports were connected, or false for disconnected.
|
||||
*/
|
||||
PBD::Signal5<void, boost::weak_ptr<Port>, std::string, boost::weak_ptr<Port>, std::string, bool> PortConnectedOrDisconnected;
|
||||
|
||||
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 void destroy();
|
||||
void died ();
|
||||
|
||||
int create_process_thread (boost::function<void()>, jack_native_thread_t*, size_t stacksize);
|
||||
bool stop_process_thread (jack_native_thread_t);
|
||||
|
||||
private:
|
||||
static AudioEngine* _instance;
|
||||
|
||||
jack_client_t* volatile _jack; /* could be reset to null by SIGPIPE or another thread */
|
||||
std::string jack_client_name;
|
||||
Glib::Threads::Mutex _process_lock;
|
||||
Glib::Threads::Cond session_removed;
|
||||
bool session_remove_pending;
|
||||
frameoffset_t session_removal_countdown;
|
||||
gain_t session_removal_gain;
|
||||
gain_t session_removal_gain_step;
|
||||
bool _running;
|
||||
bool _has_run;
|
||||
mutable framecnt_t _buffer_size;
|
||||
std::map<DataType,size_t> _raw_buffer_sizes;
|
||||
mutable framecnt_t _frame_rate;
|
||||
/// number of frames between each check for changes in monitor input
|
||||
framecnt_t monitor_check_interval;
|
||||
/// time of the last monitor check in frames
|
||||
framecnt_t last_monitor_check;
|
||||
/// the number of frames processed since start() was called
|
||||
framecnt_t _processed_frames;
|
||||
bool _freewheeling;
|
||||
bool _pre_freewheel_mmc_enabled;
|
||||
int _usecs_per_cycle;
|
||||
bool port_remove_in_progress;
|
||||
Glib::Threads::Thread* m_meter_thread;
|
||||
ProcessThread* _main_thread;
|
||||
|
||||
SerializedRCUManager<Ports> ports;
|
||||
|
||||
boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);
|
||||
|
||||
int process_callback (pframes_t nframes);
|
||||
void* process_thread ();
|
||||
void remove_all_ports ();
|
||||
|
||||
ChanCount n_physical (unsigned long) const;
|
||||
void get_physical (DataType, unsigned long, std::vector<std::string> &);
|
||||
|
||||
void port_registration_failure (const std::string& portname);
|
||||
|
||||
static int _xrun_callback (void *arg);
|
||||
#ifdef HAVE_JACK_SESSION
|
||||
static void _session_callback (jack_session_event_t *event, void *arg);
|
||||
#endif
|
||||
static int _graph_order_callback (void *arg);
|
||||
static void* _process_thread (void *arg);
|
||||
static int _sample_rate_callback (pframes_t nframes, void *arg);
|
||||
static int _bufsize_callback (pframes_t nframes, void *arg);
|
||||
static void _jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int, void*);
|
||||
static int _jack_sync_callback (jack_transport_state_t, jack_position_t*, void *arg);
|
||||
static void _freewheel_callback (int , void *arg);
|
||||
static void _registration_callback (jack_port_id_t, int, void *);
|
||||
static void _connect_callback (jack_port_id_t, jack_port_id_t, int, void *);
|
||||
|
||||
void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
|
||||
int jack_sync_callback (jack_transport_state_t, jack_position_t*);
|
||||
int jack_bufsize_callback (pframes_t);
|
||||
int jack_sample_rate_callback (pframes_t);
|
||||
void freewheel_callback (int);
|
||||
void connect_callback (jack_port_id_t, jack_port_id_t, int);
|
||||
|
||||
void set_jack_callbacks ();
|
||||
|
||||
static void _latency_callback (jack_latency_callback_mode_t, void*);
|
||||
void jack_latency_callback (jack_latency_callback_mode_t);
|
||||
|
||||
int connect_to_jack (std::string client_name, std::string session_uuid);
|
||||
|
||||
static void halted (void *);
|
||||
static void halted_info (jack_status_t,const char*,void *);
|
||||
|
||||
void meter_thread ();
|
||||
void start_metering_thread ();
|
||||
void stop_metering_thread ();
|
||||
|
||||
static gint m_meter_exit;
|
||||
|
||||
struct ThreadData {
|
||||
AudioEngine* engine;
|
||||
boost::function<void()> f;
|
||||
size_t stacksize;
|
||||
|
||||
ThreadData (AudioEngine* ae, boost::function<void()> fp, size_t stacksz)
|
||||
: engine (ae) , f (fp) , stacksize (stacksz) {}
|
||||
};
|
||||
|
||||
static void* _start_process_thread (void*);
|
||||
void parameter_changed (const std::string&);
|
||||
PBD::ScopedConnection config_connection;
|
||||
void meter_thread ();
|
||||
void start_metering_thread ();
|
||||
void stop_metering_thread ();
|
||||
|
||||
static gint m_meter_exit;
|
||||
|
||||
void parameter_changed (const std::string&);
|
||||
PBD::ScopedConnection config_connection;
|
||||
|
||||
typedef std::map<std::string,AudioBackendInfo*> BackendMap;
|
||||
BackendMap _backends;
|
||||
AudioBackendInfo* backend_discover (const std::string&);
|
||||
void drop_backend ();
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
|||
39
libs/ardour/ardour/backend_search_path.h
Normal file
39
libs/ardour/ardour/backend_search_path.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_backend_search_path_h__
|
||||
#define __ardour_backend_search_path_h__
|
||||
|
||||
#include "pbd/search_path.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
/**
|
||||
* return a SearchPath containing directories in which to look for
|
||||
* backend plugins.
|
||||
*
|
||||
* If ARDOUR_BACKEND_PATH is defined then the SearchPath returned
|
||||
* will contain only those directories specified in it, otherwise it will
|
||||
* contain the user and system directories which may contain audio/MIDI
|
||||
* backends.
|
||||
*/
|
||||
PBD::Searchpath backend_search_path ();
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif /* __ardour_backend_search_path_h__ */
|
||||
|
|
@ -70,7 +70,7 @@ public:
|
|||
void clear();
|
||||
|
||||
void attach_buffers (PortSet& ports);
|
||||
void get_jack_port_addresses (PortSet &, framecnt_t);
|
||||
void get_backend_port_addresses (PortSet &, framecnt_t);
|
||||
|
||||
/* the capacity here is a size_t and has a different interpretation depending
|
||||
on the DataType of the buffers. for audio, its a frame count. for MIDI
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@
|
|||
#define __ardour_data_type_h__
|
||||
|
||||
#include <string>
|
||||
#include <jack/jack.h>
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
||||
/** A type of Data Ardour is capable of processing.
|
||||
*
|
||||
* The majority of this class is dedicated to conversion to and from various
|
||||
|
|
@ -61,30 +61,22 @@ public:
|
|||
|
||||
/** Construct from a string (Used for loading from XML and Ports)
|
||||
* The string can be as in an XML file (eg "audio" or "midi"), or a
|
||||
* Jack type string (from jack_port_type) */
|
||||
*/
|
||||
DataType(const std::string& str)
|
||||
: _symbol(NIL) {
|
||||
if (str == "audio" || str == JACK_DEFAULT_AUDIO_TYPE)
|
||||
if (!g_ascii_strncasecmp(str.c_str(), "audio", str.length())) {
|
||||
_symbol = AUDIO;
|
||||
else if (str == "midi" || str == JACK_DEFAULT_MIDI_TYPE)
|
||||
} else if (!g_ascii_strncasecmp(str.c_str(), "midi", str.length())) {
|
||||
_symbol = MIDI;
|
||||
}
|
||||
|
||||
/** Get the Jack type this DataType corresponds to */
|
||||
const char* to_jack_type() const {
|
||||
switch (_symbol) {
|
||||
case AUDIO: return JACK_DEFAULT_AUDIO_TYPE;
|
||||
case MIDI: return JACK_DEFAULT_MIDI_TYPE;
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
/** Inverse of the from-string constructor */
|
||||
const char* to_string() const {
|
||||
switch (_symbol) {
|
||||
case AUDIO: return "audio";
|
||||
case MIDI: return "midi";
|
||||
default: return "unknown"; // reeeally shouldn't ever happen
|
||||
case AUDIO: return "audio";
|
||||
case MIDI: return "midi";
|
||||
default: return "unknown"; // reeeally shouldn't ever happen
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +117,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif // __ardour_data_type_h__
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ namespace PBD {
|
|||
extern uint64_t OrderKeys;
|
||||
extern uint64_t Automation;
|
||||
extern uint64_t WiimoteControl;
|
||||
extern uint64_t Ports;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ extern const char* const surfaces_dir_name;
|
|||
extern const char* const ladspa_dir_name;
|
||||
extern const char* const user_config_dir_name;
|
||||
extern const char* const panner_dir_name;
|
||||
extern const char* const backend_dir_name;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ class Diskstream : public SessionObject, public PublicDiskstream
|
|||
virtual XMLNode& get_state(void);
|
||||
virtual int set_state(const XMLNode&, int version);
|
||||
|
||||
virtual void request_jack_monitors_input (bool) {}
|
||||
virtual void ensure_jack_monitors_input (bool) {}
|
||||
virtual void request_input_monitoring (bool) {}
|
||||
virtual void ensure_input_monitoring (bool) {}
|
||||
|
||||
framecnt_t capture_offset() const { return _capture_offset; }
|
||||
virtual void set_capture_offset ();
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ protected:
|
|||
virtual void session_going_away ();
|
||||
|
||||
private:
|
||||
std::list<jack_native_thread_t> _thread_list;
|
||||
std::list<pthread_t> _thread_list;
|
||||
volatile bool _quit_threads;
|
||||
|
||||
void reset_thread_list ();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ public:
|
|||
void copy(const MidiBuffer& copy);
|
||||
|
||||
bool push_back(const Evoral::MIDIEvent<TimeType>& event);
|
||||
bool push_back(const jack_midi_event_t& event);
|
||||
bool push_back(TimeType time, size_t size, const uint8_t* data);
|
||||
uint8_t* reserve(TimeType time, size_t size);
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class MidiDiskstream : public Diskstream
|
|||
XMLNode& get_state(void);
|
||||
int set_state(const XMLNode&, int version);
|
||||
|
||||
void ensure_jack_monitors_input (bool);
|
||||
void ensure_input_monitoring (bool);
|
||||
|
||||
boost::shared_ptr<SMFSource> write_source () { return _write_source; }
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#ifndef __ardour_midi_port_h__
|
||||
#define __ardour_midi_port_h__
|
||||
|
||||
#include "midi++/parser.h"
|
||||
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
#include "ardour/midi_state_tracker.h"
|
||||
|
|
@ -56,18 +58,35 @@ class MidiPort : public Port {
|
|||
|
||||
MidiBuffer& get_midi_buffer (pframes_t nframes);
|
||||
|
||||
protected:
|
||||
friend class AudioEngine;
|
||||
void set_always_parse (bool yn);
|
||||
MIDI::Parser& self_parser() { return _self_parser; }
|
||||
|
||||
MidiPort (const std::string& name, Flags);
|
||||
protected:
|
||||
friend class PortManager;
|
||||
|
||||
MidiPort (const std::string& name, PortFlags);
|
||||
|
||||
private:
|
||||
MidiBuffer* _buffer;
|
||||
bool _has_been_mixed_down;
|
||||
bool _resolve_required;
|
||||
bool _input_active;
|
||||
bool _always_parse;
|
||||
|
||||
void resolve_notes (void* jack_buffer, MidiBuffer::TimeType when);
|
||||
/* Naming this is tricky. AsyncMIDIPort inherits (for now, aug 2013) from
|
||||
* both MIDI::Port, which has _parser, and this (ARDOUR::MidiPort). We
|
||||
* need parsing support in this object, independently of what the
|
||||
* MIDI::Port/AsyncMIDIPort stuff does. Rather than risk errors coming
|
||||
* from not explicitly naming which _parser we want, we will call this
|
||||
* _self_parser for now.
|
||||
*
|
||||
* Ultimately, MIDI::Port should probably go away or be fully integrated
|
||||
* into this object, somehow.
|
||||
*/
|
||||
|
||||
MIDI::Parser _self_parser;
|
||||
|
||||
void resolve_notes (void* buffer, MidiBuffer::TimeType when);
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
|||
|
|
@ -26,13 +26,11 @@
|
|||
#include "pbd/signals.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
namespace MIDI {
|
||||
class Port;
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
class AsyncMIDIPort;
|
||||
|
||||
/* this is mostly a placeholder because I suspect that at some
|
||||
point we will want to add more members to accomodate
|
||||
|
|
@ -67,7 +65,7 @@ class MidiControlUI : public AbstractUI<MidiUIRequest>
|
|||
ARDOUR::Session& _session;
|
||||
PBD::ScopedConnection rebind_connection;
|
||||
|
||||
bool midi_input_handler (Glib::IOCondition, MIDI::Port*);
|
||||
bool midi_input_handler (Glib::IOCondition, AsyncMIDIPort*);
|
||||
void reset_ports ();
|
||||
void clear_ports ();
|
||||
|
||||
|
|
|
|||
99
libs/ardour/ardour/midiport_manager.h
Normal file
99
libs/ardour/ardour/midiport_manager.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright (C) 1998 Paul Barton-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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __midiport_manager_h__
|
||||
#define __midiport_manager_h__
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "pbd/rcu.h"
|
||||
|
||||
#include "midi++/types.h"
|
||||
#include "midi++/port.h"
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class MidiPort;
|
||||
class Port;
|
||||
|
||||
class MidiPortManager {
|
||||
public:
|
||||
MidiPortManager();
|
||||
virtual ~MidiPortManager ();
|
||||
|
||||
/* Ports used for control. These are read/written to outside of the
|
||||
* process callback (asynchronously with respect to when data
|
||||
* actually arrives).
|
||||
*
|
||||
* More detail: we do actually read/write data for these ports
|
||||
* inside the process callback, but incoming data is only parsed
|
||||
* and outgoing data is only generated *outside* the process
|
||||
* callback.
|
||||
*/
|
||||
|
||||
MIDI::Port* midi_input_port () const { return _midi_input_port; }
|
||||
MIDI::Port* midi_output_port () const { return _midi_output_port; }
|
||||
MIDI::Port* mmc_input_port () const { return _mmc_input_port; }
|
||||
MIDI::Port* mmc_output_port () const { return _mmc_output_port; }
|
||||
|
||||
/* Ports used for synchronization. These have their I/O handled inside the
|
||||
* process callback.
|
||||
*/
|
||||
|
||||
boost::shared_ptr<MidiPort> mtc_input_port() const { return _mtc_input_port; }
|
||||
boost::shared_ptr<MidiPort> mtc_output_port() const { return _mtc_output_port; }
|
||||
boost::shared_ptr<MidiPort> midi_clock_input_port() const { return _midi_clock_input_port; }
|
||||
boost::shared_ptr<MidiPort> midi_clock_output_port() const { return _midi_clock_output_port; }
|
||||
|
||||
void set_midi_port_states (const XMLNodeList&);
|
||||
std::list<XMLNode*> get_midi_port_states () const;
|
||||
|
||||
PBD::Signal0<void> PortsChanged;
|
||||
|
||||
protected:
|
||||
/* asynchronously handled ports: MIDI::Port */
|
||||
MIDI::Port* _midi_input_port;
|
||||
MIDI::Port* _midi_output_port;
|
||||
MIDI::Port* _mmc_input_port;
|
||||
MIDI::Port* _mmc_output_port;
|
||||
/* these point to the same objects as the 4 members above,
|
||||
but cast to their ARDOUR::Port base class
|
||||
*/
|
||||
boost::shared_ptr<Port> _midi_in;
|
||||
boost::shared_ptr<Port> _midi_out;
|
||||
boost::shared_ptr<Port> _mmc_in;
|
||||
boost::shared_ptr<Port> _mmc_out;
|
||||
|
||||
/* synchronously handled ports: ARDOUR::MidiPort */
|
||||
boost::shared_ptr<MidiPort> _mtc_input_port;
|
||||
boost::shared_ptr<MidiPort> _mtc_output_port;
|
||||
boost::shared_ptr<MidiPort> _midi_clock_input_port;
|
||||
boost::shared_ptr<MidiPort> _midi_clock_output_port;
|
||||
|
||||
void create_ports ();
|
||||
|
||||
};
|
||||
|
||||
} // namespace MIDI
|
||||
|
||||
#endif // __midi_port_manager_h__
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include "pbd/signals.h"
|
||||
|
||||
#include "ardour/data_type.h"
|
||||
#include "ardour/port_engine.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
|
@ -40,11 +41,6 @@ class Buffer;
|
|||
class Port : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
enum Flags {
|
||||
IsInput = JackPortIsInput,
|
||||
IsOutput = JackPortIsOutput,
|
||||
};
|
||||
|
||||
virtual ~Port ();
|
||||
|
||||
static void set_connecting_blocked( bool yn ) {
|
||||
|
|
@ -62,7 +58,7 @@ public:
|
|||
int set_name (std::string const &);
|
||||
|
||||
/** @return flags */
|
||||
Flags flags () const {
|
||||
PortFlags flags () const {
|
||||
return _flags;
|
||||
}
|
||||
|
||||
|
|
@ -90,24 +86,24 @@ public:
|
|||
virtual int connect (Port *);
|
||||
int disconnect (Port *);
|
||||
|
||||
void ensure_jack_monitors_input (bool);
|
||||
bool jack_monitoring_input () const;
|
||||
void request_input_monitoring (bool);
|
||||
void ensure_input_monitoring (bool);
|
||||
bool monitoring_input () const;
|
||||
int reestablish ();
|
||||
int reconnect ();
|
||||
void request_jack_monitors_input (bool);
|
||||
|
||||
bool last_monitor() const { return _last_monitor; }
|
||||
void set_last_monitor (bool yn) { _last_monitor = yn; }
|
||||
|
||||
jack_port_t* jack_port() const { return _jack_port; }
|
||||
PortEngine::PortHandle port_handle() { return _port_handle; }
|
||||
|
||||
void get_connected_latency_range (jack_latency_range_t& range, bool playback) const;
|
||||
void get_connected_latency_range (LatencyRange& range, bool playback) const;
|
||||
|
||||
void set_private_latency_range (jack_latency_range_t& range, bool playback);
|
||||
const jack_latency_range_t& private_latency_range (bool playback) const;
|
||||
void set_private_latency_range (LatencyRange& range, bool playback);
|
||||
const LatencyRange& private_latency_range (bool playback) const;
|
||||
|
||||
void set_public_latency_range (jack_latency_range_t& range, bool playback) const;
|
||||
jack_latency_range_t public_latency_range (bool playback) const;
|
||||
void set_public_latency_range (LatencyRange& range, bool playback) const;
|
||||
LatencyRange public_latency_range (bool playback) const;
|
||||
|
||||
virtual void reset ();
|
||||
|
||||
|
|
@ -122,8 +118,6 @@ public:
|
|||
|
||||
bool physically_connected () const;
|
||||
|
||||
static void set_engine (AudioEngine *);
|
||||
|
||||
PBD::Signal1<void,bool> MonitorInputChanged;
|
||||
static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect;
|
||||
static PBD::Signal0<void> PortDrop;
|
||||
|
|
@ -141,11 +135,16 @@ public:
|
|||
|
||||
virtual void increment_port_buffer_offset (pframes_t n);
|
||||
|
||||
virtual XMLNode& get_state (void) const;
|
||||
virtual int set_state (const XMLNode&, int version);
|
||||
|
||||
static std::string state_node_name;
|
||||
|
||||
protected:
|
||||
|
||||
Port (std::string const &, DataType, Flags);
|
||||
Port (std::string const &, DataType, PortFlags);
|
||||
|
||||
jack_port_t* _jack_port; ///< JACK port
|
||||
PortEngine::PortHandle _port_handle;
|
||||
|
||||
static bool _connecting_blocked;
|
||||
static pframes_t _global_port_buffer_offset; /* access only from process() tree */
|
||||
|
|
@ -153,18 +152,16 @@ protected:
|
|||
|
||||
framecnt_t _port_buffer_offset; /* access only from process() tree */
|
||||
|
||||
jack_latency_range_t _private_playback_latency;
|
||||
jack_latency_range_t _private_capture_latency;
|
||||
|
||||
static AudioEngine* _engine; ///< the AudioEngine
|
||||
LatencyRange _private_playback_latency;
|
||||
LatencyRange _private_capture_latency;
|
||||
|
||||
private:
|
||||
std::string _name; ///< port short name
|
||||
Flags _flags; ///< flags
|
||||
PortFlags _flags; ///< flags
|
||||
bool _last_monitor;
|
||||
|
||||
/** ports that we are connected to, kept so that we can
|
||||
reconnect to JACK when required
|
||||
reconnect to the backend when required
|
||||
*/
|
||||
std::set<std::string> _connections;
|
||||
|
||||
|
|
|
|||
345
libs/ardour/ardour/port_engine.h
Normal file
345
libs/ardour/ardour/port_engine.h
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __libardour_port_engine_h__
|
||||
#define __libardour_port_engine_h__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ardour/data_type.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class PortManager;
|
||||
|
||||
/** PortEngine is an abstract base class that defines the functionality
|
||||
* required by Ardour.
|
||||
*
|
||||
* A Port is basically an endpoint for a datastream (which can either be
|
||||
* continuous, like audio, or event-based, like MIDI). Ports have buffers
|
||||
* associated with them into which data can be written (if they are output
|
||||
* ports) and from which data can be read (if they input ports). Ports can be
|
||||
* connected together so that data written to an output port can be read from
|
||||
* an input port. These connections can be 1:1, 1:N OR N:1.
|
||||
*
|
||||
* Ports may be associated with software only, or with hardware. Hardware
|
||||
* related ports are often referred to as physical, and correspond to some
|
||||
* relevant physical entity on a hardware device, such as an audio jack or a
|
||||
* MIDI connector. Physical ports may be potentially asked to monitor their
|
||||
* inputs, though some implementations may not support this.
|
||||
*
|
||||
* Most physical ports will also be considered "terminal", which means that
|
||||
* data delivered there or read from there will go to or comes from a system
|
||||
* outside of the PortEngine implementation's control (e.g. the analog domain
|
||||
* for audio, or external MIDI devices for MIDI). Non-physical ports can also
|
||||
* be considered "terminal". For example, the output port of a software
|
||||
* synthesizer is a terminal port, because the data contained in its buffer
|
||||
* does not and cannot be considered to come from any other port - it is
|
||||
* synthesized by its owner.
|
||||
*
|
||||
* Ports also have latency associated with them. Each port has a playback
|
||||
* latency and a capture latency:
|
||||
*
|
||||
* <b>capture latency</b>: how long since the data read from the buffer of a
|
||||
* port arrived at at a terminal port. The data will have
|
||||
* come from the "outside world" if the terminal port is also
|
||||
* physical, or will have been synthesized by the entity that
|
||||
* owns the terminal port.
|
||||
*
|
||||
* <b>playback latency</b>: how long until the data written to the buffer of
|
||||
* port will reach a terminal port.
|
||||
*
|
||||
*
|
||||
* For more detailed questions about the PortEngine API, consult the JACK API
|
||||
* documentation, on which this entire object is based.
|
||||
*/
|
||||
|
||||
class PortEngine {
|
||||
public:
|
||||
PortEngine (PortManager& pm) : manager (pm) {}
|
||||
virtual ~PortEngine() {}
|
||||
|
||||
/* We use void* here so that the API can be defined for any implementation.
|
||||
*
|
||||
* We could theoretically use a template (PortEngine<T>) and define
|
||||
* PortHandle as T, but this complicates the desired inheritance
|
||||
* pattern in which FooPortEngine handles things for the Foo API,
|
||||
* rather than being a derivative of PortEngine<Foo>.
|
||||
*/
|
||||
|
||||
typedef void* PortHandle;
|
||||
|
||||
/** Return a typeless pointer to an object that may be of interest
|
||||
* that understands the internals of a particular PortEngine
|
||||
* implementation.
|
||||
*
|
||||
* XXX the existence of this method is a band-aid over some design
|
||||
* issues and will it will be removed in the future
|
||||
*/
|
||||
virtual void* private_handle() const = 0;
|
||||
|
||||
virtual bool connected() const = 0;
|
||||
|
||||
/** Return the name of this process as used by the port manager
|
||||
* when naming ports.
|
||||
*/
|
||||
virtual const std::string& my_name() const = 0;
|
||||
|
||||
/** Return the maximum size of a port name
|
||||
*/
|
||||
virtual uint32_t port_name_size() const = 0;
|
||||
|
||||
/** Returns zero if the port referred to by @param port was set to @param
|
||||
* name. Return non-zero otherwise.
|
||||
*/
|
||||
virtual int set_port_name (PortHandle port, const std::string& name) = 0;
|
||||
/** Return the name of the port referred to by @param port. If the port
|
||||
* does not exist, return an empty string.
|
||||
*/
|
||||
virtual std::string get_port_name (PortHandle) const = 0;
|
||||
/** Return a reference to a port with the fullname @param name. Return
|
||||
* a null pointer if no such port exists.
|
||||
*/
|
||||
virtual PortHandle* get_port_by_name (const std::string&) const = 0;
|
||||
|
||||
/** Find the set of ports whose names, types and flags match
|
||||
* specified values, place the names of each port into @param ports,
|
||||
* and return the count of the number found.
|
||||
*
|
||||
* To avoid selecting by name, pass an empty string for @param
|
||||
* port_name_pattern.
|
||||
*
|
||||
* To avoid selecting by type, pass DataType::NIL as @param type.
|
||||
*
|
||||
* To avoid selecting by flags, pass PortFlags (0) as @param flags.
|
||||
*/
|
||||
virtual int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& ports) const = 0;
|
||||
|
||||
/** Return the Ardour data type handled by the port referred to by @param
|
||||
* port. Returns DataType::NIL if the port does not exist.
|
||||
*/
|
||||
virtual DataType port_data_type (PortHandle port) const = 0;
|
||||
|
||||
/** Create a new port whose fullname will be the conjuction of my_name(),
|
||||
* ":" and @param shortname. The port will handle data specified by @param
|
||||
* type and will have the flags given by @param flags. If successfull,
|
||||
* return a reference to the port, otherwise return a null pointer.
|
||||
*/
|
||||
virtual PortHandle register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags) = 0;
|
||||
|
||||
/* Destroy the port referred to by @param port, including all resources
|
||||
* associated with it. This will also disconnect @param port from any ports it
|
||||
* is connected to.
|
||||
*/
|
||||
virtual void unregister_port (PortHandle) = 0;
|
||||
|
||||
/* Connection management */
|
||||
|
||||
/** Ensure that data written to the port named by @param src will be
|
||||
* readable from the port named by @param dst. Return zero on success,
|
||||
* non-zero otherwise.
|
||||
*/
|
||||
virtual int connect (const std::string& src, const std::string& dst) = 0;
|
||||
|
||||
/** Remove any existing connection between the ports named by @param src and
|
||||
* @param dst. Return zero on success, non-zero otherwise.
|
||||
*/
|
||||
virtual int disconnect (const std::string& src, const std::string& dst) = 0;
|
||||
|
||||
|
||||
/** Ensure that data written to the port referenced by @param portwill be
|
||||
* readable from the port named by @param dst. Return zero on success,
|
||||
* non-zero otherwise.
|
||||
*/
|
||||
virtual int connect (PortHandle src, const std::string& dst) = 0;
|
||||
/** Remove any existing connection between the port referenced by @param src and
|
||||
* the port named @param dst. Return zero on success, non-zero otherwise.
|
||||
*/
|
||||
virtual int disconnect (PortHandle src, const std::string& dst) = 0;
|
||||
|
||||
/** Remove all connections between the port referred to by @param port and
|
||||
* any other ports. Return zero on success, non-zero otherwise.
|
||||
*/
|
||||
virtual int disconnect_all (PortHandle port) = 0;
|
||||
|
||||
/** Return true if the port referred to by @param port has any connections
|
||||
* to other ports. Return false otherwise.
|
||||
*/
|
||||
virtual bool connected (PortHandle port, bool process_callback_safe = true) = 0;
|
||||
/** Return true if the port referred to by @param port is connected to
|
||||
* the port named by @param name. Return false otherwise.
|
||||
*/
|
||||
virtual bool connected_to (PortHandle, const std::string& name, bool process_callback_safe = true) = 0;
|
||||
|
||||
/** Return true if the port referred to by @param port has any connections
|
||||
* to ports marked with the PortFlag IsPhysical. Return false otherwise.
|
||||
*/
|
||||
virtual bool physically_connected (PortHandle port, bool process_callback_safe = true) = 0;
|
||||
|
||||
/** Place the names of all ports connected to the port named by @param
|
||||
* ports into @param names, and return the number of connections.
|
||||
*/
|
||||
virtual int get_connections (PortHandle port, std::vector<std::string>& names, bool process_callback_safe = true) = 0;
|
||||
|
||||
/* MIDI */
|
||||
|
||||
/** Retrieve a MIDI event from the data at @param port_buffer. The event
|
||||
number to be retrieved is given by @param event_index (a value of zero
|
||||
indicates that the first event in the port_buffer should be retrieved).
|
||||
*
|
||||
* The data associated with the event will be copied into the buffer at
|
||||
* @param buf and the number of bytes written will be stored in @param
|
||||
* size. The timestamp of the event (which is always relative to the start
|
||||
* of the current process cycle, in samples) will be stored in @param
|
||||
* timestamp
|
||||
*/
|
||||
virtual int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0;
|
||||
|
||||
/** Place a MIDI event consisting of @param size bytes copied from the data
|
||||
* at @param buf into the port buffer referred to by @param
|
||||
* port_buffer. The MIDI event will be marked with a time given by @param
|
||||
* timestamp. Return zero on success, non-zero otherwise.
|
||||
*
|
||||
* Events must be added monotonically to a port buffer. An attempt to
|
||||
* add a non-monotonic event (e.g. out-of-order) will cause this method
|
||||
* to return a failure status.
|
||||
*/
|
||||
virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) = 0;
|
||||
|
||||
/** Return the number of MIDI events in the data at @param port_buffer
|
||||
*/
|
||||
virtual uint32_t get_midi_event_count (void* port_buffer) = 0;
|
||||
|
||||
/** Clear the buffer at @param port_buffer of all MIDI events.
|
||||
*
|
||||
* After a call to this method, an immediate, subsequent call to
|
||||
* get_midi_event_count() with the same @param port_buffer argument must
|
||||
* return zero.
|
||||
*/
|
||||
virtual void midi_clear (void* port_buffer) = 0;
|
||||
|
||||
/* Monitoring */
|
||||
|
||||
/** Return true if the implementation can offer input monitoring.
|
||||
*
|
||||
* Input monitoring involves the (selective) routing of incoming data
|
||||
* to an outgoing data stream, without the data being passed to the CPU.
|
||||
*
|
||||
* Only certain audio hardware can provide this, and only certain audio
|
||||
* APIs can offer it.
|
||||
*/
|
||||
virtual bool can_monitor_input() const = 0;
|
||||
/** Increment or decrement the number of requests to monitor the input
|
||||
* of the hardware channel represented by the port referred to by @param
|
||||
* port.
|
||||
*
|
||||
* If the number of requests rises above zero, input monitoring will
|
||||
* be enabled (if can_monitor_input() returns true for the implementation).
|
||||
*
|
||||
* If the number of requests falls to zero, input monitoring will be
|
||||
* disabled (if can_monitor_input() returns true for the implementation)
|
||||
*/
|
||||
virtual int request_input_monitoring (PortHandle port, bool yn) = 0;
|
||||
/* Force input monitoring of the hardware channel represented by the port
|
||||
* referred to by @param port to be on or off, depending on the true/false
|
||||
* status of @param yn. The request count is ignored when using this
|
||||
* method, so if this is called with yn set to false, input monitoring will
|
||||
* be disabled regardless of the number of requests to enable it.
|
||||
*/
|
||||
virtual int ensure_input_monitoring (PortHandle port, bool yn) = 0;
|
||||
/** Return true if input monitoring is enabled for the hardware channel
|
||||
* represented by the port referred to by @param port. Return false
|
||||
* otherwise.
|
||||
*/
|
||||
virtual bool monitoring_input (PortHandle port) = 0;
|
||||
|
||||
/* Latency management
|
||||
*/
|
||||
|
||||
/** Set the latency range for the port referred to by @param port to @param
|
||||
* r. The playback range will be set if @param for_playback is true,
|
||||
* otherwise the capture range will be set.
|
||||
*/
|
||||
virtual void set_latency_range (PortHandle port, bool for_playback, LatencyRange r) = 0;
|
||||
/** Return the latency range for the port referred to by @param port.
|
||||
* The playback range will be returned if @param for_playback is true,
|
||||
* otherwise the capture range will be returned.
|
||||
*/
|
||||
virtual LatencyRange get_latency_range (PortHandle port, bool for_playback) = 0;
|
||||
|
||||
/* Discovering physical ports */
|
||||
|
||||
/** Return true if the port referred to by @param port has the IsPhysical
|
||||
* flag set. Return false otherwise.
|
||||
*/
|
||||
virtual bool port_is_physical (PortHandle port) const = 0;
|
||||
|
||||
/** Store into @param names the names of all ports with the IsOutput and
|
||||
* IsPhysical flag set, that handle data of type @param type.
|
||||
*
|
||||
* This can be used to discover outputs associated with hardware devices.
|
||||
*/
|
||||
virtual void get_physical_outputs (DataType type, std::vector<std::string>& names) = 0;
|
||||
/** Store into @param names the names of all ports with the IsInput and
|
||||
* IsPhysical flags set, that handle data of type @param type.
|
||||
*
|
||||
* This can be used to discover inputs associated with hardware devices.
|
||||
*/
|
||||
virtual void get_physical_inputs (DataType type, std::vector<std::string>& names) = 0;
|
||||
/** Return the total count (possibly mixed between different data types)
|
||||
of the number of ports with the IsPhysical and IsOutput flags set.
|
||||
*/
|
||||
virtual ChanCount n_physical_outputs () const = 0;
|
||||
/** Return the total count (possibly mixed between different data types)
|
||||
of the number of ports with the IsPhysical and IsInput flags set.
|
||||
*/
|
||||
virtual ChanCount n_physical_inputs () const = 0;
|
||||
|
||||
/** Return the address of the memory area where data for the port can be
|
||||
* written (if the port has the PortFlag IsOutput set) or read (if the port
|
||||
* has the PortFlag IsInput set).
|
||||
*
|
||||
* The return value is untyped because buffers containing different data
|
||||
* depending on the port type.
|
||||
*/
|
||||
virtual void* get_buffer (PortHandle, pframes_t) = 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.
|
||||
*
|
||||
* XXX to be removed after some more design cleanup.
|
||||
*/
|
||||
virtual pframes_t sample_time_at_cycle_start () = 0;
|
||||
|
||||
protected:
|
||||
PortManager& manager;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __libardour_port_engine_h__ */
|
||||
169
libs/ardour/ardour/port_manager.h
Normal file
169
libs/ardour/ardour/port_manager.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __libardour_port_manager_h__
|
||||
#define __libardour_port_manager_h__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "pbd/rcu.h"
|
||||
|
||||
#include "ardour/chan_count.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/port_engine.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class PortManager
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
|
||||
typedef std::list<boost::shared_ptr<Port> > PortList;
|
||||
|
||||
PortManager ();
|
||||
virtual ~PortManager() {}
|
||||
|
||||
void set_port_engine (PortEngine& pe);
|
||||
PortEngine& port_engine() { return *_impl; }
|
||||
|
||||
uint32_t port_name_size() const;
|
||||
std::string my_name() const;
|
||||
|
||||
/* Port registration */
|
||||
|
||||
boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname, bool async = false);
|
||||
boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname, bool async = false);
|
||||
int unregister_port (boost::shared_ptr<Port>);
|
||||
|
||||
/* Port connectivity */
|
||||
|
||||
int connect (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 reestablish_ports ();
|
||||
int reconnect_ports ();
|
||||
|
||||
bool connected (const std::string&);
|
||||
bool connected_to (const std::string&, const std::string&);
|
||||
bool physically_connected (const std::string&);
|
||||
int get_connections (const std::string&, std::vector<std::string>&);
|
||||
|
||||
/* Naming */
|
||||
|
||||
boost::shared_ptr<Port> get_port_by_name (const std::string &);
|
||||
void port_renamed (const std::string&, const std::string&);
|
||||
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;
|
||||
|
||||
/* other Port management */
|
||||
|
||||
bool port_is_physical (const std::string&) const;
|
||||
void get_physical_outputs (DataType type, std::vector<std::string>&);
|
||||
void get_physical_inputs (DataType type, std::vector<std::string>&);
|
||||
ChanCount n_physical_outputs () const;
|
||||
ChanCount n_physical_inputs () const;
|
||||
|
||||
int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&);
|
||||
int get_ports (DataType, PortList&);
|
||||
|
||||
void remove_all_ports ();
|
||||
|
||||
/* per-Port monitoring */
|
||||
|
||||
bool can_request_input_monitoring () const;
|
||||
void request_input_monitoring (const std::string&, bool) const;
|
||||
void ensure_input_monitoring (const std::string&, bool) const;
|
||||
|
||||
class PortRegistrationFailure : public std::exception {
|
||||
public:
|
||||
PortRegistrationFailure (std::string const & why = "")
|
||||
: reason (why) {}
|
||||
|
||||
~PortRegistrationFailure () throw () {}
|
||||
|
||||
const char *what() const throw () { return reason.c_str(); }
|
||||
|
||||
private:
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
/* the port engine will invoke these callbacks when the time is right */
|
||||
|
||||
void registration_callback ();
|
||||
int graph_order_callback ();
|
||||
void connect_callback (const std::string&, const std::string&, bool connection);
|
||||
|
||||
bool port_remove_in_progress() const { return _port_remove_in_progress; }
|
||||
|
||||
/** Emitted if the backend notifies us of a graph order event */
|
||||
PBD::Signal0<void> GraphReordered;
|
||||
|
||||
/** Emitted if a Port is registered or unregistered */
|
||||
PBD::Signal0<void> PortRegisteredOrUnregistered;
|
||||
|
||||
/** Emitted if a Port is connected or disconnected.
|
||||
* The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour.
|
||||
* The std::string parameters are the (long) port names.
|
||||
* The bool parameter is true if ports were connected, or false for disconnected.
|
||||
*/
|
||||
PBD::Signal5<void, boost::weak_ptr<Port>, std::string, boost::weak_ptr<Port>, std::string, bool> PortConnectedOrDisconnected;
|
||||
|
||||
protected:
|
||||
boost::shared_ptr<PortEngine> _impl;
|
||||
SerializedRCUManager<Ports> ports;
|
||||
bool _port_remove_in_progress;
|
||||
|
||||
boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input, bool async = false);
|
||||
void port_registration_failure (const std::string& portname);
|
||||
|
||||
/** List of ports to be used between ::cycle_start() and ::cycle_end()
|
||||
*/
|
||||
boost::shared_ptr<Ports> _cycle_ports;
|
||||
|
||||
void fade_out (gain_t, gain_t, pframes_t);
|
||||
void silence (pframes_t nframes);
|
||||
void check_monitoring ();
|
||||
/** Signal the start of an audio cycle.
|
||||
* This MUST be called before any reading/writing for this cycle.
|
||||
* Realtime safe.
|
||||
*/
|
||||
void cycle_start (pframes_t nframes);
|
||||
|
||||
/** Signal the end of an audio cycle.
|
||||
* This signifies that the cycle began with @ref cycle_start has ended.
|
||||
* This MUST be called at the end of each cycle.
|
||||
* Realtime safe.
|
||||
*/
|
||||
void cycle_end (pframes_t nframes);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif /* __libardour_port_manager_h__ */
|
||||
|
|
@ -33,8 +33,8 @@ public:
|
|||
virtual ~PublicDiskstream() {}
|
||||
|
||||
virtual boost::shared_ptr<Playlist> playlist () = 0;
|
||||
virtual void request_jack_monitors_input (bool) = 0;
|
||||
virtual void ensure_jack_monitors_input (bool) = 0;
|
||||
virtual void request_input_monitoring (bool) = 0;
|
||||
virtual void ensure_input_monitoring (bool) = 0;
|
||||
virtual bool destructive () const = 0;
|
||||
virtual std::list<boost::shared_ptr<Source> > & last_capture_sources () = 0;
|
||||
virtual void set_capture_offset () = 0;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ class RCConfiguration : public Configuration
|
|||
XMLNode * instant_xml (const std::string& str);
|
||||
|
||||
XMLNode* control_protocol_state () { return _control_protocol_state; }
|
||||
std::list<XMLNode*> midi_port_states () { return _midi_port_states; }
|
||||
|
||||
/* define accessor methods */
|
||||
|
||||
|
|
@ -81,11 +80,6 @@ class RCConfiguration : public Configuration
|
|||
#undef CONFIG_VARIABLE_SPECIAL
|
||||
|
||||
XMLNode* _control_protocol_state;
|
||||
|
||||
/** MIDI port nodes from the RC configuration. We store them so that we can set their
|
||||
state once the audio engine and hence ports are up.
|
||||
*/
|
||||
std::list<XMLNode*> _midi_port_states;
|
||||
};
|
||||
|
||||
/* XXX: rename this */
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ class IOProcessor;
|
|||
class ImportStatus;
|
||||
class MidiClockTicker;
|
||||
class MidiControlUI;
|
||||
class MidiPortManager;
|
||||
class MidiPort;
|
||||
class MidiRegion;
|
||||
class MidiSource;
|
||||
class MidiTrack;
|
||||
|
|
@ -381,9 +383,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);
|
||||
|
|
@ -556,6 +555,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
|
||||
int remove_last_capture ();
|
||||
|
||||
/** handlers should return 0 for "everything OK", and any other value for
|
||||
* "cannot setup audioengine".
|
||||
*/
|
||||
static PBD::Signal1<int,uint32_t> AudioEngineSetupRequired;
|
||||
|
||||
/** handlers should return -1 for "stop cleanup",
|
||||
0 for "yes, delete this playlist",
|
||||
1 for "no, don't delete this playlist".
|
||||
|
|
@ -813,8 +817,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
boost::shared_ptr<SessionPlaylists> playlists;
|
||||
|
||||
void send_mmc_locate (framepos_t);
|
||||
int send_full_time_code (framepos_t);
|
||||
void send_song_position_pointer (framepos_t);
|
||||
void queue_full_time_code () { _send_timecode_update = true; }
|
||||
void queue_song_position_pointer () { /* currently does nothing */ }
|
||||
|
||||
bool step_editing() const { return (_step_editors > 0); }
|
||||
|
||||
|
|
@ -863,6 +867,27 @@ 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; }
|
||||
|
||||
MIDI::Port* midi_input_port () const;
|
||||
MIDI::Port* midi_output_port () const;
|
||||
MIDI::Port* mmc_output_port () const;
|
||||
MIDI::Port* mmc_input_port () const;
|
||||
|
||||
boost::shared_ptr<MidiPort> midi_clock_output_port () const;
|
||||
boost::shared_ptr<MidiPort> midi_clock_input_port () const;
|
||||
boost::shared_ptr<MidiPort> mtc_output_port () const;
|
||||
boost::shared_ptr<MidiPort> mtc_input_port () const;
|
||||
|
||||
MIDI::MachineControl& mmc() { return *_mmc; }
|
||||
|
||||
/* 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);
|
||||
|
|
@ -1046,7 +1071,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
boost::scoped_ptr<SessionDirectory> _session_dir;
|
||||
|
||||
void hookup_io ();
|
||||
void when_engine_running ();
|
||||
int when_engine_running ();
|
||||
void graph_reordered ();
|
||||
|
||||
/** current snapshot name, without the .ardour suffix */
|
||||
|
|
@ -1112,8 +1137,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
void auto_loop_changed (Location *);
|
||||
void auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
|
||||
|
||||
void first_stage_init (std::string path, std::string snapshot_name);
|
||||
int second_stage_init ();
|
||||
void pre_engine_init (std::string path);
|
||||
int post_engine_init ();
|
||||
void remove_empty_sounds ();
|
||||
|
||||
void setup_midi_control ();
|
||||
|
|
@ -1216,7 +1241,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
framepos_t ltc_timecode_offset;
|
||||
bool ltc_timecode_negative_offset;
|
||||
|
||||
jack_latency_range_t ltc_out_latency;
|
||||
LatencyRange ltc_out_latency;
|
||||
|
||||
void ltc_tx_initialize();
|
||||
void ltc_tx_cleanup();
|
||||
|
|
@ -1261,6 +1286,13 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
void engine_halted ();
|
||||
void xrun_recovery ();
|
||||
|
||||
/* These are synchronous and so can only be called from within the process
|
||||
* cycle
|
||||
*/
|
||||
|
||||
int send_full_time_code (framepos_t, pframes_t nframes);
|
||||
void send_song_position_pointer (framepos_t);
|
||||
|
||||
TempoMap *_tempo_map;
|
||||
void tempo_map_changed (const PBD::PropertyChange&);
|
||||
|
||||
|
|
@ -1429,9 +1461,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
*/
|
||||
std::list<GQuark> _current_trans_quarks;
|
||||
|
||||
void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
|
||||
int jack_sync_callback (jack_transport_state_t, jack_position_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);
|
||||
|
|
@ -1585,6 +1616,14 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
|
||||
void reconnect_ltc_input ();
|
||||
void reconnect_ltc_output ();
|
||||
|
||||
/* persistent, non-track related MIDI ports */
|
||||
MidiPortManager* _midi_ports;
|
||||
MIDI::MachineControl* _mmc;
|
||||
|
||||
void setup_ltc ();
|
||||
void setup_click ();
|
||||
void setup_bundles ();
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
|||
|
|
@ -40,14 +40,12 @@
|
|||
#define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") )
|
||||
#define LEADINGZERO(A) ( (A)<10 ? " " : (A)<100 ? " " : (A)<1000 ? " " : "" )
|
||||
|
||||
namespace MIDI {
|
||||
class Port;
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class TempoMap;
|
||||
class Session;
|
||||
class AudioEngine;
|
||||
class MidiPort;
|
||||
|
||||
/**
|
||||
* @class Slave
|
||||
|
|
@ -252,10 +250,10 @@ class TimecodeSlave : public Slave {
|
|||
|
||||
class MTC_Slave : public TimecodeSlave {
|
||||
public:
|
||||
MTC_Slave (Session&, MIDI::Port&);
|
||||
MTC_Slave (Session&, MidiPort&);
|
||||
~MTC_Slave ();
|
||||
|
||||
void rebind (MIDI::Port&);
|
||||
void rebind (MidiPort&);
|
||||
bool speed_and_position (double&, framepos_t&);
|
||||
|
||||
bool locked() const;
|
||||
|
|
@ -273,7 +271,7 @@ class MTC_Slave : public TimecodeSlave {
|
|||
|
||||
private:
|
||||
Session& session;
|
||||
MIDI::Port* port;
|
||||
MidiPort* port;
|
||||
PBD::ScopedConnectionList port_connections;
|
||||
PBD::ScopedConnection config_connection;
|
||||
bool can_notify_on_unknown_rate;
|
||||
|
|
@ -354,7 +352,7 @@ public:
|
|||
std::string approximate_current_delta() const;
|
||||
|
||||
private:
|
||||
void parse_ltc(const jack_nframes_t, const jack_default_audio_sample_t * const, const framecnt_t);
|
||||
void parse_ltc(const pframes_t, const Sample* const, const framecnt_t);
|
||||
void process_ltc(framepos_t const);
|
||||
void init_engine_dll (framepos_t, int32_t);
|
||||
bool detect_discontinuity(LTCFrameExt *, int, bool);
|
||||
|
|
@ -391,7 +389,7 @@ public:
|
|||
|
||||
PBD::ScopedConnectionList port_connections;
|
||||
PBD::ScopedConnection config_connection;
|
||||
jack_latency_range_t ltc_slave_latency;
|
||||
LatencyRange ltc_slave_latency;
|
||||
|
||||
/* DLL - chase LTC */
|
||||
int transport_direction;
|
||||
|
|
@ -404,13 +402,13 @@ public:
|
|||
|
||||
class MIDIClock_Slave : public Slave {
|
||||
public:
|
||||
MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
|
||||
MIDIClock_Slave (Session&, MidiPort&, int ppqn = 24);
|
||||
|
||||
/// Constructor for unit tests
|
||||
MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
|
||||
~MIDIClock_Slave ();
|
||||
|
||||
void rebind (MIDI::Port&);
|
||||
void rebind (MidiPort&);
|
||||
bool speed_and_position (double&, framepos_t&);
|
||||
|
||||
bool locked() const;
|
||||
|
|
@ -426,7 +424,6 @@ class MIDIClock_Slave : public Slave {
|
|||
|
||||
protected:
|
||||
ISlaveSessionProxy* session;
|
||||
MIDI::Port* port;
|
||||
PBD::ScopedConnectionList port_connections;
|
||||
|
||||
/// pulses per quarter note for one MIDI clock frame (default 24)
|
||||
|
|
@ -492,7 +489,7 @@ class MIDIClock_Slave : public Slave {
|
|||
class JACK_Slave : public Slave
|
||||
{
|
||||
public:
|
||||
JACK_Slave (jack_client_t*);
|
||||
JACK_Slave (AudioEngine&);
|
||||
~JACK_Slave ();
|
||||
|
||||
bool speed_and_position (double& speed, framepos_t& pos);
|
||||
|
|
@ -502,11 +499,10 @@ class JACK_Slave : public Slave
|
|||
bool ok() const;
|
||||
framecnt_t resolution () const { return 1; }
|
||||
bool requires_seekahead () const { return false; }
|
||||
void reset_client (jack_client_t* jack);
|
||||
bool is_always_synced() const { return true; }
|
||||
|
||||
private:
|
||||
jack_client_t* jack;
|
||||
AudioEngine& engine;
|
||||
double speed;
|
||||
bool _starting;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,17 +27,13 @@
|
|||
#include "ardour/session_handle.h"
|
||||
|
||||
|
||||
#ifndef TICKER_H_
|
||||
#define TICKER_H_
|
||||
#ifndef __libardour_ticker_h__
|
||||
#define __libardour_ticker_h__
|
||||
|
||||
namespace MIDI {
|
||||
class Port;
|
||||
}
|
||||
|
||||
namespace ARDOUR
|
||||
{
|
||||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
class MidiPort;
|
||||
|
||||
class MidiClockTicker : public SessionHandlePtr, boost::noncopyable
|
||||
{
|
||||
|
|
@ -45,7 +41,7 @@ public:
|
|||
MidiClockTicker ();
|
||||
virtual ~MidiClockTicker();
|
||||
|
||||
void tick (const framepos_t& transport_frames);
|
||||
void tick (const framepos_t& transport_frames, pframes_t nframes);
|
||||
|
||||
bool has_midi_port() const { return _midi_port != 0; }
|
||||
|
||||
|
|
@ -58,9 +54,6 @@ public:
|
|||
/// slot for the signal session::TransportStateChange
|
||||
void transport_state_changed();
|
||||
|
||||
/// slot for the signal session::PositionChanged
|
||||
void position_changed (framepos_t position);
|
||||
|
||||
/// slot for the signal session::TransportLooped
|
||||
void transport_looped();
|
||||
|
||||
|
|
@ -70,23 +63,25 @@ public:
|
|||
/// pulses per quarter note (default 24)
|
||||
void set_ppqn(int ppqn) { _ppqn = ppqn; }
|
||||
|
||||
private:
|
||||
MIDI::Port* _midi_port;
|
||||
int _ppqn;
|
||||
double _last_tick;
|
||||
private:
|
||||
boost::shared_ptr<MidiPort> _midi_port;
|
||||
int _ppqn;
|
||||
double _last_tick;
|
||||
bool _send_pos;
|
||||
bool _send_state;
|
||||
|
||||
class Position;
|
||||
boost::scoped_ptr<Position> _pos;
|
||||
class Position;
|
||||
boost::scoped_ptr<Position> _pos;
|
||||
|
||||
double one_ppqn_in_frames (framepos_t transport_position);
|
||||
double one_ppqn_in_frames (framepos_t transport_position);
|
||||
|
||||
void send_midi_clock_event (pframes_t offset);
|
||||
void send_start_event (pframes_t offset);
|
||||
void send_continue_event (pframes_t offset);
|
||||
void send_stop_event (pframes_t offset);
|
||||
void send_position_event (uint32_t midi_clocks, pframes_t offset);
|
||||
void send_midi_clock_event (pframes_t offset, pframes_t nframes);
|
||||
void send_start_event (pframes_t offset, pframes_t nframes);
|
||||
void send_continue_event (pframes_t offset, pframes_t nframes);
|
||||
void send_stop_event (pframes_t offset, pframes_t nframes);
|
||||
void send_position_event (uint32_t midi_clocks, pframes_t offset, pframes_t nframes);
|
||||
};
|
||||
|
||||
}
|
||||
// namespace
|
||||
|
||||
#endif /* TICKER_H_ */
|
||||
#endif /* __libardour_ticker_h__ */
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@ class Track : public Route, public PublicDiskstream
|
|||
|
||||
/* PublicDiskstream interface */
|
||||
boost::shared_ptr<Playlist> playlist ();
|
||||
void request_jack_monitors_input (bool);
|
||||
void ensure_jack_monitors_input (bool);
|
||||
void request_input_monitoring (bool);
|
||||
void ensure_input_monitoring (bool);
|
||||
bool destructive () const;
|
||||
std::list<boost::shared_ptr<Source> > & last_capture_sources ();
|
||||
void set_capture_offset ();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <jack/types.h>
|
||||
#include <jack/midiport.h>
|
||||
|
||||
#include "timecode/bbt_time.h"
|
||||
#include "timecode/time.h"
|
||||
|
|
@ -53,12 +51,12 @@ namespace ARDOUR {
|
|||
class Route;
|
||||
class Region;
|
||||
|
||||
typedef jack_default_audio_sample_t Sample;
|
||||
typedef float pan_t;
|
||||
typedef float gain_t;
|
||||
typedef uint32_t layer_t;
|
||||
typedef uint64_t microseconds_t;
|
||||
typedef jack_nframes_t pframes_t;
|
||||
typedef float Sample;
|
||||
typedef float pan_t;
|
||||
typedef float gain_t;
|
||||
typedef uint32_t layer_t;
|
||||
typedef uint64_t microseconds_t;
|
||||
typedef uint32_t pframes_t;
|
||||
|
||||
/* Any position measured in audio frames.
|
||||
Assumed to be non-negative but not enforced.
|
||||
|
|
@ -585,6 +583,32 @@ namespace ARDOUR {
|
|||
FadeSymmetric,
|
||||
};
|
||||
|
||||
enum TransportState {
|
||||
/* these values happen to match the constants used by JACK but
|
||||
this equality cannot be assumed.
|
||||
*/
|
||||
TransportStopped = 0,
|
||||
TransportRolling = 1,
|
||||
TransportLooping = 2,
|
||||
TransportStarting = 3,
|
||||
};
|
||||
|
||||
enum PortFlags {
|
||||
/* these values happen to match the constants used by JACK but
|
||||
this equality cannot be assumed.
|
||||
*/
|
||||
IsInput = 0x1,
|
||||
IsOutput = 0x2,
|
||||
IsPhysical = 0x4,
|
||||
CanMonitor = 0x8,
|
||||
IsTerminal = 0x10
|
||||
};
|
||||
|
||||
struct LatencyRange {
|
||||
uint32_t min; //< samples
|
||||
uint32_t max; //< samples
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
|
||||
|
|
|
|||
303
libs/ardour/async_midi_port.cc
Normal file
303
libs/ardour/async_midi_port.cc
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
Copyright (C) 1998 Paul Barton-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.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include "midi++/types.h"
|
||||
|
||||
#include "ardour/async_midi_port.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
|
||||
using namespace MIDI;
|
||||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
|
||||
namespace Evoral {
|
||||
template class EventRingBuffer<MIDI::timestamp_t>;
|
||||
}
|
||||
|
||||
pthread_t AsyncMIDIPort::_process_thread;
|
||||
|
||||
#define port_engine AudioEngine::instance()->port_engine()
|
||||
|
||||
AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
|
||||
: MidiPort (name, flags)
|
||||
, MIDI::Port (name, MIDI::Port::Flags (0))
|
||||
, _currently_in_cycle (false)
|
||||
, _last_write_timestamp (0)
|
||||
, output_fifo (512)
|
||||
, input_fifo (1024)
|
||||
, xthread (true)
|
||||
{
|
||||
}
|
||||
|
||||
AsyncMIDIPort::~AsyncMIDIPort ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AsyncMIDIPort::flush_output_fifo (pframes_t nframes)
|
||||
{
|
||||
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
|
||||
size_t written;
|
||||
|
||||
output_fifo.get_read_vector (&vec);
|
||||
|
||||
MidiBuffer& mb (get_midi_buffer (nframes));
|
||||
|
||||
if (vec.len[0]) {
|
||||
Evoral::Event<double>* evp = vec.buf[0];
|
||||
|
||||
for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
|
||||
mb.push_back (evp->time(), evp->size(), evp->buffer());
|
||||
}
|
||||
}
|
||||
|
||||
if (vec.len[1]) {
|
||||
Evoral::Event<double>* evp = vec.buf[1];
|
||||
|
||||
for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
|
||||
mb.push_back (evp->time(), evp->size(), evp->buffer());
|
||||
}
|
||||
}
|
||||
|
||||
if ((written = vec.len[0] + vec.len[1]) != 0) {
|
||||
output_fifo.increment_read_idx (written);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncMIDIPort::cycle_start (pframes_t nframes)
|
||||
{
|
||||
_currently_in_cycle = true;
|
||||
MidiPort::cycle_start (nframes);
|
||||
|
||||
/* dump anything waiting in the output FIFO at the start of the port
|
||||
* buffer
|
||||
*/
|
||||
|
||||
if (ARDOUR::Port::sends_output()) {
|
||||
flush_output_fifo (nframes);
|
||||
}
|
||||
|
||||
/* copy incoming data from the port buffer into the input FIFO
|
||||
and if necessary wakeup the reader
|
||||
*/
|
||||
|
||||
if (ARDOUR::Port::receives_input()) {
|
||||
MidiBuffer& mb (get_midi_buffer (nframes));
|
||||
pframes_t when = AudioEngine::instance()->sample_time_at_cycle_start();
|
||||
|
||||
for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
|
||||
input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer());
|
||||
}
|
||||
|
||||
if (!mb.empty()) {
|
||||
xthread.wakeup ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AsyncMIDIPort::cycle_end (pframes_t nframes)
|
||||
{
|
||||
if (ARDOUR::Port::sends_output()) {
|
||||
/* move any additional data from output FIFO into the port
|
||||
buffer.
|
||||
*/
|
||||
flush_output_fifo (nframes);
|
||||
}
|
||||
|
||||
MidiPort::cycle_end (nframes);
|
||||
|
||||
_currently_in_cycle = false;
|
||||
}
|
||||
|
||||
/** wait for the output FIFO to be emptied by successive process() callbacks.
|
||||
*
|
||||
* Cannot be called from a processing thread.
|
||||
*/
|
||||
void
|
||||
AsyncMIDIPort::drain (int check_interval_usecs)
|
||||
{
|
||||
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
|
||||
|
||||
if (!AudioEngine::instance()->running() || AudioEngine::instance()->session() == 0) {
|
||||
/* no more process calls - it will never drain */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (is_process_thread()) {
|
||||
error << "Process thread called MIDI::AsyncMIDIPort::drain() - this cannot work" << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
output_fifo.get_write_vector (&vec);
|
||||
if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) {
|
||||
break;
|
||||
}
|
||||
usleep (check_interval_usecs);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t timestamp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!ARDOUR::Port::sends_output()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!is_process_thread()) {
|
||||
|
||||
/* this is the best estimate of "when" this MIDI data is being
|
||||
* delivered
|
||||
*/
|
||||
|
||||
_parser->set_timestamp (AudioEngine::instance()->sample_time() + timestamp);
|
||||
for (size_t n = 0; n < msglen; ++n) {
|
||||
_parser->scanner (msg[n]);
|
||||
}
|
||||
|
||||
Glib::Threads::Mutex::Lock lm (output_fifo_lock);
|
||||
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
|
||||
|
||||
output_fifo.get_write_vector (&vec);
|
||||
|
||||
if (vec.len[0] + vec.len[1] < 1) {
|
||||
error << "no space in FIFO for non-process thread MIDI write" << endmsg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec.len[0]) {
|
||||
if (!vec.buf[0]->owns_buffer()) {
|
||||
vec.buf[0]->set_buffer (0, 0, true);
|
||||
}
|
||||
vec.buf[0]->set (msg, msglen, timestamp);
|
||||
} else {
|
||||
if (!vec.buf[1]->owns_buffer()) {
|
||||
vec.buf[1]->set_buffer (0, 0, true);
|
||||
}
|
||||
vec.buf[1]->set (msg, msglen, timestamp);
|
||||
}
|
||||
|
||||
output_fifo.increment_write_idx (1);
|
||||
|
||||
ret = msglen;
|
||||
|
||||
} else {
|
||||
|
||||
_parser->set_timestamp (AudioEngine::instance()->sample_time_at_cycle_start() + timestamp);
|
||||
for (size_t n = 0; n < msglen; ++n) {
|
||||
_parser->scanner (msg[n]);
|
||||
}
|
||||
|
||||
if (timestamp >= _cycle_nframes) {
|
||||
std::cerr << "attempting to write MIDI event of " << msglen << " MIDI::bytes at time "
|
||||
<< timestamp << " of " << _cycle_nframes
|
||||
<< " (this will not work - needs a code fix)"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/* This is the process thread, which makes checking
|
||||
* _currently_in_cycle atomic and safe, since it is only
|
||||
* set from cycle_start() and cycle_end(), also called
|
||||
* only from the process thread.
|
||||
*/
|
||||
|
||||
if (_currently_in_cycle) {
|
||||
|
||||
MidiBuffer& mb (get_midi_buffer (_cycle_nframes));
|
||||
|
||||
if (timestamp == 0) {
|
||||
timestamp = _last_write_timestamp;
|
||||
}
|
||||
|
||||
if (mb.push_back (timestamp, msglen, msg)) {
|
||||
ret = msglen;
|
||||
_last_write_timestamp = timestamp;
|
||||
|
||||
} else {
|
||||
cerr << "AsyncMIDIPort (" << ARDOUR::Port::name() << "): write of " << msglen << " @ " << timestamp << " failed\n" << endl;
|
||||
PBD::stacktrace (cerr, 20);
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
|
||||
PBD::stacktrace (cerr, 20);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
AsyncMIDIPort::read (MIDI::byte *, size_t)
|
||||
{
|
||||
if (!ARDOUR::Port::receives_input()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
timestamp_t time;
|
||||
Evoral::EventType type;
|
||||
uint32_t size;
|
||||
MIDI::byte buffer[input_fifo.capacity()];
|
||||
|
||||
while (input_fifo.read (&time, &type, &size, buffer)) {
|
||||
_parser->set_timestamp (time);
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
_parser->scanner (buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
AsyncMIDIPort::parse (framecnt_t)
|
||||
{
|
||||
MIDI::byte buf[1];
|
||||
|
||||
/* see ::read() to realize why buf is not used */
|
||||
read (buf, sizeof (buf));
|
||||
}
|
||||
|
||||
void
|
||||
AsyncMIDIPort::set_process_thread (pthread_t thr)
|
||||
{
|
||||
_process_thread = thr;
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncMIDIPort::is_process_thread()
|
||||
{
|
||||
return pthread_equal (pthread_self(), _process_thread);
|
||||
}
|
||||
|
||||
|
|
@ -1752,7 +1752,7 @@ AudioDiskstream::prep_record_enable ()
|
|||
if (Config->get_monitoring_model() == HardwareMonitoring) {
|
||||
|
||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||
(*chan)->source.request_jack_monitors_input (!(_session.config.get_auto_input() && rolling));
|
||||
(*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling));
|
||||
capturing_sources.push_back ((*chan)->write_source);
|
||||
(*chan)->write_source->mark_streaming_write_started ();
|
||||
}
|
||||
|
|
@ -1773,7 +1773,7 @@ AudioDiskstream::prep_record_disable ()
|
|||
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||
if (Config->get_monitoring_model() == HardwareMonitoring) {
|
||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||
(*chan)->source.request_jack_monitors_input (false);
|
||||
(*chan)->source.request_input_monitoring (false);
|
||||
}
|
||||
}
|
||||
capturing_sources.clear ();
|
||||
|
|
@ -2039,12 +2039,12 @@ AudioDiskstream::allocate_temporary_buffers ()
|
|||
}
|
||||
|
||||
void
|
||||
AudioDiskstream::request_jack_monitors_input (bool yn)
|
||||
AudioDiskstream::request_input_monitoring (bool yn)
|
||||
{
|
||||
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||
|
||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||
(*chan)->source.request_jack_monitors_input (yn);
|
||||
(*chan)->source.request_input_monitoring (yn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2367,13 +2367,13 @@ AudioDiskstream::ChannelSource::is_physical () const
|
|||
}
|
||||
|
||||
void
|
||||
AudioDiskstream::ChannelSource::request_jack_monitors_input (bool yn) const
|
||||
AudioDiskstream::ChannelSource::request_input_monitoring (bool yn) const
|
||||
{
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return AudioEngine::instance()->request_jack_monitors_input (name, yn);
|
||||
return AudioEngine::instance()->request_input_monitoring (name, yn);
|
||||
}
|
||||
|
||||
AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size)
|
||||
|
|
|
|||
|
|
@ -21,13 +21,17 @@
|
|||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include "ardour/audio_buffer.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/audio_port.h"
|
||||
#include "ardour/data_type.h"
|
||||
#include "ardour/port_engine.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
|
||||
AudioPort::AudioPort (const std::string& name, Flags flags)
|
||||
#define port_engine AudioEngine::instance()->port_engine()
|
||||
|
||||
AudioPort::AudioPort (const std::string& name, PortFlags flags)
|
||||
: Port (name, DataType::AUDIO, flags)
|
||||
, _buffer (new AudioBuffer (0))
|
||||
{
|
||||
|
|
@ -73,7 +77,7 @@ AudioBuffer&
|
|||
AudioPort::get_audio_buffer (pframes_t nframes)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
|
||||
_buffer->set_data ((Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes) +
|
||||
_global_port_buffer_offset + _port_buffer_offset, nframes);
|
||||
return *_buffer;
|
||||
}
|
||||
|
|
@ -82,7 +86,7 @@ Sample*
|
|||
AudioPort::engine_get_whole_audio_buffer ()
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes);
|
||||
return (Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ AudioTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
|
|||
}
|
||||
|
||||
_diskstream->set_record_enabled (false);
|
||||
_diskstream->request_jack_monitors_input (false);
|
||||
_diskstream->request_input_monitoring (false);
|
||||
|
||||
DiskstreamChanged (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
45
libs/ardour/backend_search_path.cc
Normal file
45
libs/ardour/backend_search_path.cc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
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 <glibmm/miscutils.h>
|
||||
|
||||
#include "ardour/backend_search_path.h"
|
||||
#include "ardour/directory_names.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
|
||||
namespace {
|
||||
const char * const backend_env_variable_name = "ARDOUR_BACKEND_PATH";
|
||||
} // anonymous
|
||||
|
||||
using namespace PBD;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
Searchpath
|
||||
backend_search_path ()
|
||||
{
|
||||
Searchpath spath(user_config_directory ());
|
||||
spath += ardour_dll_directory ();
|
||||
spath.add_subdirectory_to_paths(backend_dir_name);
|
||||
|
||||
spath += Searchpath(Glib::getenv(backend_env_variable_name));
|
||||
return spath;
|
||||
}
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
@ -90,7 +90,7 @@ BufferSet::clear()
|
|||
|
||||
/** Set up this BufferSet so that its data structures mirror a PortSet's buffers.
|
||||
* This is quite expensive and not RT-safe, so it should not be called in a process context;
|
||||
* get_jack_port_addresses() will fill in a structure set up by this method.
|
||||
* get_backend_port_addresses() will fill in a structure set up by this method.
|
||||
*
|
||||
* XXX: this *is* called in a process context; I'm not sure quite what `should not' means above.
|
||||
*/
|
||||
|
|
@ -114,13 +114,13 @@ BufferSet::attach_buffers (PortSet& ports)
|
|||
_is_mirror = true;
|
||||
}
|
||||
|
||||
/** Write the JACK port addresses from a PortSet into our data structures. This
|
||||
/** Write the backend port addresses from a PortSet into our data structures. This
|
||||
* call assumes that attach_buffers() has already been called for the same PortSet.
|
||||
* Does not allocate, so RT-safe BUT you can only call Port::get_buffer() from
|
||||
* the process() callback tree anyway, so this has to be called in RT context.
|
||||
*/
|
||||
void
|
||||
BufferSet::get_jack_port_addresses (PortSet& ports, framecnt_t nframes)
|
||||
BufferSet::get_backend_port_addresses (PortSet& ports, framecnt_t nframes)
|
||||
{
|
||||
assert (_count == ports.count ());
|
||||
assert (_available == ports.count ());
|
||||
|
|
|
|||
|
|
@ -443,27 +443,26 @@ Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine)
|
|||
return true;
|
||||
}
|
||||
|
||||
/** This must not be called in code executed as a response to a JACK event,
|
||||
* as it uses jack_port_get_all_connections().
|
||||
/** This must not be called in code executed as a response to a backend event,
|
||||
* as it uses the backend port_get_all_connections().
|
||||
* @return true if any of this bundle's channels are connected to anything.
|
||||
*/
|
||||
bool
|
||||
Bundle::connected_to_anything (AudioEngine& engine)
|
||||
{
|
||||
PortManager& pm (engine);
|
||||
|
||||
for (uint32_t i = 0; i < nchannels().n_total(); ++i) {
|
||||
Bundle::PortList const & ports = channel_ports (i);
|
||||
|
||||
for (uint32_t j = 0; j < ports.size(); ++j) {
|
||||
/* ports[j] may not be an Ardour port, so use JACK directly
|
||||
|
||||
/* ports[j] may not be an Ardour port, so use the port manager directly
|
||||
rather than doing it with Port.
|
||||
*/
|
||||
jack_port_t* jp = jack_port_by_name (engine.jack(), ports[j].c_str());
|
||||
if (jp) {
|
||||
const char ** c = jack_port_get_all_connections (engine.jack(), jp);
|
||||
if (c) {
|
||||
jack_free (c);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pm.connected (ports[j])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace ARDOUR {
|
|||
|
||||
CapturingProcessor::CapturingProcessor (Session & session)
|
||||
: Processor (session, X_("capture point"))
|
||||
, block_size (session.engine().frames_per_cycle())
|
||||
, block_size (AudioEngine::instance()->samples_per_cycle())
|
||||
{
|
||||
realloc_buffers ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,6 @@ uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap");
|
|||
uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys");
|
||||
uint64_t PBD::DEBUG::Automation = PBD::new_debug_bit ("automation");
|
||||
uint64_t PBD::DEBUG::WiimoteControl = PBD::new_debug_bit ("wiimotecontrol");
|
||||
uint64_t PBD::DEBUG::Ports = PBD::new_debug_bit ("Ports");
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pf
|
|||
processing pathway that wants to use this->output_buffers() for some reason.
|
||||
*/
|
||||
|
||||
output_buffers().get_jack_port_addresses (ports, nframes);
|
||||
output_buffers().get_backend_port_addresses (ports, nframes);
|
||||
|
||||
// this Delivery processor is not a derived type, and thus we assume
|
||||
// we really can modify the buffers passed in (it is almost certainly
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ const char* const route_templates_dir_name = X_("route_templates");
|
|||
const char* const surfaces_dir_name = X_("surfaces");
|
||||
const char* const ladspa_dir_name = X_("ladspa");
|
||||
const char* const panner_dir_name = X_("panners");
|
||||
const char* const backend_dir_name = X_("backends");
|
||||
|
||||
/* these should end up using variants of PROGRAM_NAME */
|
||||
#ifdef __APPLE__
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ RegionExportChannelFactory::RegionExportChannelFactory (Session * session, Audio
|
|||
: region (region)
|
||||
, track (track)
|
||||
, type (type)
|
||||
, frames_per_cycle (session->engine().frames_per_cycle ())
|
||||
, frames_per_cycle (session->engine().samples_per_cycle ())
|
||||
, buffers_up_to_date (false)
|
||||
, region_start (region.position())
|
||||
, position (region_start)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ ExportGraphBuilder::ExportGraphBuilder (Session const & session)
|
|||
: session (session)
|
||||
, thread_pool (hardware_concurrency())
|
||||
{
|
||||
process_buffer_frames = session.engine().frames_per_cycle();
|
||||
process_buffer_frames = session.engine().samples_per_cycle();
|
||||
}
|
||||
|
||||
ExportGraphBuilder::~ExportGraphBuilder ()
|
||||
|
|
@ -507,7 +507,7 @@ ExportGraphBuilder::ChannelConfig::ChannelConfig (ExportGraphBuilder & parent, F
|
|||
|
||||
config = new_config;
|
||||
|
||||
framecnt_t max_frames = parent.session.engine().frames_per_cycle();
|
||||
framecnt_t max_frames = parent.session.engine().samples_per_cycle();
|
||||
interleaver.reset (new Interleaver<Sample> ());
|
||||
interleaver->init (new_config.channel_config->get_n_chans(), max_frames);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
#include <fst.h>
|
||||
|
|
@ -74,11 +75,11 @@
|
|||
#include "pbd/basename.h"
|
||||
|
||||
#include "midi++/port.h"
|
||||
#include "midi++/manager.h"
|
||||
#include "midi++/mmc.h"
|
||||
|
||||
#include "ardour/analyser.h"
|
||||
#include "ardour/audio_library.h"
|
||||
#include "ardour/audio_backend.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/audioplaylist.h"
|
||||
#include "ardour/audioregion.h"
|
||||
|
|
@ -86,6 +87,7 @@
|
|||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/midi_region.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
#include "ardour/mix.h"
|
||||
#include "ardour/panner_manager.h"
|
||||
#include "ardour/plugin_manager.h"
|
||||
|
|
@ -342,6 +344,8 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
|
|||
EventTypeMap::instance().new_parameter(EnvelopeAutomation);
|
||||
EventTypeMap::instance().new_parameter(MidiCCAutomation);
|
||||
|
||||
ARDOUR::AudioEngine::create ();
|
||||
|
||||
libardour_initialized = true;
|
||||
|
||||
return true;
|
||||
|
|
@ -350,9 +354,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
|
|||
void
|
||||
ARDOUR::init_post_engine ()
|
||||
{
|
||||
/* the MIDI Manager is needed by the ControlProtocolManager */
|
||||
MIDI::Manager::create (AudioEngine::instance()->jack());
|
||||
|
||||
ControlProtocolManager::instance().discover_control_protocols ();
|
||||
|
||||
XMLNode* node;
|
||||
|
|
@ -550,3 +551,43 @@ ARDOUR::get_available_sync_options ()
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Return a monotonic value for the number of microseconds that have elapsed
|
||||
* since an arbitrary zero origin.
|
||||
*/
|
||||
|
||||
#ifdef __MACH__
|
||||
/* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
|
||||
*/
|
||||
#include <mach/mach_time.h>
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_MONOTONIC 0
|
||||
int
|
||||
clock_gettime (int /*clk_id*/, struct timespec *t)
|
||||
{
|
||||
static bool initialized = false;
|
||||
static mach_timebase_info_data_t timebase;
|
||||
if (!initialized) {
|
||||
mach_timebase_info(&timebase);
|
||||
initialized = true;
|
||||
}
|
||||
uint64_t time;
|
||||
time = mach_absolute_time();
|
||||
double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
|
||||
double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
|
||||
t->tv_sec = seconds;
|
||||
t->tv_nsec = nseconds;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
microseconds_t
|
||||
ARDOUR::get_microseconds ()
|
||||
{
|
||||
struct timespec ts;
|
||||
if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
|
||||
/* EEEK! */
|
||||
return 0;
|
||||
}
|
||||
return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ bool
|
|||
InternalSend::configure_io (ChanCount in, ChanCount out)
|
||||
{
|
||||
bool ret = Send::configure_io (in, out);
|
||||
set_block_size (_session.engine().frames_per_cycle());
|
||||
set_block_size (_session.engine().samples_per_cycle());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1344,7 +1344,7 @@ IO::bundle_changed (Bundle::Change /*c*/)
|
|||
string
|
||||
IO::build_legal_port_name (DataType type)
|
||||
{
|
||||
const int name_size = jack_port_name_size();
|
||||
const int name_size = AudioEngine::instance()->port_name_size();
|
||||
int limit;
|
||||
string suffix;
|
||||
|
||||
|
|
@ -1378,7 +1378,7 @@ IO::build_legal_port_name (DataType type)
|
|||
|
||||
// allow up to 4 digits for the output port number, plus the slash, suffix and extra space
|
||||
|
||||
limit = name_size - _session.engine().client_name().length() - (suffix.length() + 5);
|
||||
limit = name_size - AudioEngine::instance()->my_name().length() - (suffix.length() + 5);
|
||||
|
||||
std::vector<char> buf1(name_size+1);
|
||||
std::vector<char> buf2(name_size+1);
|
||||
|
|
@ -1411,7 +1411,7 @@ IO::find_port_hole (const char* base)
|
|||
*/
|
||||
|
||||
for (n = 1; n < 9999; ++n) {
|
||||
std::vector<char> buf(jack_port_name_size());
|
||||
std::vector<char> buf (AudioEngine::instance()->port_name_size());
|
||||
PortSet::iterator i = _ports.begin();
|
||||
|
||||
snprintf (&buf[0], jack_port_name_size(), _("%s %u"), base, n);
|
||||
|
|
@ -1645,7 +1645,7 @@ IO::process_input (boost::shared_ptr<Processor> proc, framepos_t start_frame, fr
|
|||
return;
|
||||
}
|
||||
|
||||
_buffers.get_jack_port_addresses (_ports, nframes);
|
||||
_buffers.get_backend_port_addresses (_ports, nframes);
|
||||
if (proc) {
|
||||
proc->run (_buffers, start_frame, end_frame, nframes, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,16 +20,14 @@
|
|||
#include <iostream>
|
||||
#include <cerrno>
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/transport.h>
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/slave.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
|
||||
JACK_Slave::JACK_Slave (jack_client_t* j)
|
||||
: jack (j)
|
||||
JACK_Slave::JACK_Slave (AudioEngine& e)
|
||||
: engine (e)
|
||||
{
|
||||
double x;
|
||||
framepos_t p;
|
||||
|
|
@ -41,12 +39,6 @@ JACK_Slave::~JACK_Slave ()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
JACK_Slave::reset_client (jack_client_t* j)
|
||||
{
|
||||
jack = j;
|
||||
}
|
||||
|
||||
bool
|
||||
JACK_Slave::locked() const
|
||||
{
|
||||
|
|
@ -62,33 +54,26 @@ JACK_Slave::ok() const
|
|||
bool
|
||||
JACK_Slave::speed_and_position (double& sp, framepos_t& position)
|
||||
{
|
||||
jack_position_t pos;
|
||||
jack_transport_state_t state;
|
||||
|
||||
state = jack_transport_query (jack, &pos);
|
||||
|
||||
switch (state) {
|
||||
case JackTransportStopped:
|
||||
switch (engine.transport_state()) {
|
||||
case TransportStopped:
|
||||
speed = 0;
|
||||
_starting = false;
|
||||
break;
|
||||
case JackTransportRolling:
|
||||
case TransportRolling:
|
||||
speed = 1.0;
|
||||
_starting = false;
|
||||
break;
|
||||
case JackTransportLooping:
|
||||
case TransportLooping:
|
||||
speed = 1.0;
|
||||
_starting = false;
|
||||
break;
|
||||
case JackTransportStarting:
|
||||
case TransportStarting:
|
||||
_starting = true;
|
||||
// don't adjust speed here, just leave it as it was
|
||||
break;
|
||||
default:
|
||||
cerr << "WARNING: Unknown JACK transport state: " << state << endl;
|
||||
}
|
||||
|
||||
sp = speed;
|
||||
position = pos.frame;
|
||||
position = engine.transport_frame();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,6 @@
|
|||
#include "pbd/xml++.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/ladspa_plugin.h"
|
||||
#include "ardour/buffer_set.h"
|
||||
|
|
@ -129,7 +127,9 @@ LadspaPlugin::init (string module_path, uint32_t index, framecnt_t rate)
|
|||
port_cnt = parameter_count();
|
||||
|
||||
_control_data = new LADSPA_Data[port_cnt];
|
||||
memset (_control_data, 0, sizeof (LADSPA_Data) * port_cnt);
|
||||
_shadow_data = new LADSPA_Data[port_cnt];
|
||||
memset (_shadow_data, 0, sizeof (LADSPA_Data) * port_cnt);
|
||||
|
||||
for (i = 0; i < port_cnt; ++i) {
|
||||
if (LADSPA_IS_PORT_CONTROL(port_descriptor (i))) {
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ LTC_Slave::resync_latency()
|
|||
|
||||
if (!session.deletion_in_progress() && session.ltc_output_io()) { /* check if Port exits */
|
||||
boost::shared_ptr<Port> ltcport = session.ltc_input_port();
|
||||
ltcport->get_connected_latency_range(ltc_slave_latency, false);
|
||||
ltcport->get_connected_latency_range (ltc_slave_latency, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,9 +150,9 @@ LTC_Slave::reset()
|
|||
}
|
||||
|
||||
void
|
||||
LTC_Slave::parse_ltc(const jack_nframes_t nframes, const jack_default_audio_sample_t * const in, const ARDOUR::framecnt_t posinfo)
|
||||
LTC_Slave::parse_ltc(const pframes_t nframes, const Sample* const in, const framecnt_t posinfo)
|
||||
{
|
||||
jack_nframes_t i;
|
||||
pframes_t i;
|
||||
unsigned char sound[8192];
|
||||
if (nframes > 8192) {
|
||||
/* TODO warn once or wrap, loop conversion below
|
||||
|
|
@ -413,22 +413,22 @@ LTC_Slave::init_engine_dll (framepos_t pos, int32_t inc)
|
|||
}
|
||||
|
||||
/* main entry point from session_process.cc
|
||||
* called from jack_process callback context
|
||||
* so it is OK to use jack_port_get_buffer()
|
||||
* called from process callback context
|
||||
* so it is OK to use get_buffer()
|
||||
*/
|
||||
bool
|
||||
LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||
{
|
||||
bool engine_init_called = false;
|
||||
framepos_t now = session.engine().frame_time_at_cycle_start();
|
||||
framepos_t now = session.engine().sample_time_at_cycle_start();
|
||||
framepos_t sess_pos = session.transport_frame(); // corresponds to now
|
||||
framecnt_t nframes = session.engine().frames_per_cycle();
|
||||
framecnt_t nframes = session.engine().samples_per_cycle();
|
||||
|
||||
jack_default_audio_sample_t *in;
|
||||
Sample* in;
|
||||
|
||||
boost::shared_ptr<Port> ltcport = session.ltc_input_port();
|
||||
|
||||
in = (jack_default_audio_sample_t*) jack_port_get_buffer (ltcport->jack_port(), nframes);
|
||||
in = (Sample*) AudioEngine::instance()->port_engine().get_buffer (ltcport->port_handle(), nframes);
|
||||
|
||||
frameoffset_t skip = now - (monotonic_cnt + nframes);
|
||||
monotonic_cnt = now;
|
||||
|
|
@ -441,7 +441,7 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
|||
else if (engine_dll_initstate != transport_direction && ltc_speed != 0) {
|
||||
engine_dll_initstate = transport_direction;
|
||||
init_engine_dll(last_ltc_frame + rint(ltc_speed * double(2 * nframes + now - last_timestamp)),
|
||||
session.engine().frames_per_cycle());
|
||||
session.engine().samples_per_cycle());
|
||||
engine_init_called = true;
|
||||
}
|
||||
|
||||
|
|
@ -521,8 +521,8 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
|||
t0 = t1;
|
||||
t1 += b * e + e2;
|
||||
e2 += c * e;
|
||||
speed_flt = (t1 - t0) / double(session.engine().frames_per_cycle());
|
||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().frames_per_cycle() ));
|
||||
speed_flt = (t1 - t0) / double(session.engine().samples_per_cycle());
|
||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().samples_per_cycle() ));
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC adjusting elapsed (no DLL) from %1 by %2\n", elapsed, (2 * nframes * ltc_speed)));
|
||||
speed_flt = 0;
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
|
|||
_latency_control_port = 0;
|
||||
_next_cycle_start = std::numeric_limits<framepos_t>::max();
|
||||
_next_cycle_speed = 1.0;
|
||||
_block_length = _engine.frames_per_cycle();
|
||||
_block_length = _engine.samples_per_cycle();
|
||||
_seq_size = _engine.raw_buffer_size(DataType::MIDI);
|
||||
_state_version = 0;
|
||||
_was_activated = false;
|
||||
|
|
@ -1925,7 +1925,7 @@ LV2Plugin::Impl::designated_input (const char* uri, void** bufptrs[], void** buf
|
|||
return port;
|
||||
}
|
||||
|
||||
static bool lv2_filter (const string& str, void * /* arg*/)
|
||||
static bool lv2_filter (const string& str, void* /*arg*/)
|
||||
{
|
||||
/* Not a dotfile, has a prefix before a period, suffix is "lv2" */
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "pbd/malign.h"
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/debug.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
|
|
@ -133,6 +134,7 @@ MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
|
|||
|
||||
if (_size + stamp_size + ev.size() >= _capacity) {
|
||||
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
|
||||
PBD::stacktrace (cerr, 20);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +173,9 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
|
|||
#endif
|
||||
|
||||
if (_size + stamp_size + size >= _capacity) {
|
||||
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
|
||||
cerr << "MidiBuffer::push_back2 failed (buffer is full; _size = " << _size << " capacity "
|
||||
<< _capacity << " stamp " << stamp_size << " size = " << size << ")" << endl;
|
||||
PBD::stacktrace (cerr, 20);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -190,55 +194,6 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Push an event into the buffer.
|
||||
*
|
||||
* Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
|
||||
* That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
|
||||
* Realtime safe.
|
||||
* @return false if operation failed (not enough room)
|
||||
*/
|
||||
bool
|
||||
MidiBuffer::push_back(const jack_midi_event_t& ev)
|
||||
{
|
||||
const size_t stamp_size = sizeof(TimeType);
|
||||
|
||||
if (_size + stamp_size + ev.size >= _capacity) {
|
||||
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Evoral::midi_event_is_valid(ev.buffer, ev.size)) {
|
||||
cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (DEBUG::MidiIO & PBD::debug_bits) {
|
||||
DEBUG_STR_DECL(a);
|
||||
DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push jack event @ %2 sz %3 ", this, ev.time, ev.size));
|
||||
for (size_t i=0; i < ev.size; ++i) {
|
||||
DEBUG_STR_APPEND(a,hex);
|
||||
DEBUG_STR_APPEND(a,"0x");
|
||||
DEBUG_STR_APPEND(a,(int)ev.buffer[i]);
|
||||
DEBUG_STR_APPEND(a,' ');
|
||||
}
|
||||
DEBUG_STR_APPEND(a,'\n');
|
||||
DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t* const write_loc = _data + _size;
|
||||
*((TimeType*)write_loc) = ev.time;
|
||||
memcpy(write_loc + stamp_size, ev.buffer, ev.size);
|
||||
|
||||
_size += stamp_size + ev.size;
|
||||
_silent = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Reserve space for a new event in the buffer.
|
||||
*
|
||||
* This call is for copying MIDI directly into the buffer, the data location
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include "midi++/port.h"
|
||||
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/slave.h"
|
||||
#include "ardour/tempo.h"
|
||||
|
||||
|
|
@ -40,7 +42,7 @@ using namespace ARDOUR;
|
|||
using namespace MIDI;
|
||||
using namespace PBD;
|
||||
|
||||
MIDIClock_Slave::MIDIClock_Slave (Session& s, MIDI::Port& p, int ppqn)
|
||||
MIDIClock_Slave::MIDIClock_Slave (Session& s, MidiPort& p, int ppqn)
|
||||
: ppqn (ppqn)
|
||||
, bandwidth (10.0 / 60.0) // 1 BpM = 1 / 60 Hz
|
||||
{
|
||||
|
|
@ -63,19 +65,18 @@ MIDIClock_Slave::~MIDIClock_Slave()
|
|||
}
|
||||
|
||||
void
|
||||
MIDIClock_Slave::rebind (MIDI::Port& p)
|
||||
MIDIClock_Slave::rebind (MidiPort& port)
|
||||
{
|
||||
port_connections.drop_connections();
|
||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave: connecting to port %1\n", port.name()));
|
||||
|
||||
port = &p;
|
||||
port_connections.drop_connections ();
|
||||
|
||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave: connecting to port %1\n", port->name()));
|
||||
port.self_parser().timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2));
|
||||
port.self_parser().start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2));
|
||||
port.self_parser().contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2));
|
||||
port.self_parser().stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2));
|
||||
port.self_parser().position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3));
|
||||
|
||||
port->parser()->timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2));
|
||||
port->parser()->start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2));
|
||||
port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2));
|
||||
port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2));
|
||||
port->parser()->position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ MidiDiskstream::non_realtime_input_change ()
|
|||
seek (_session.transport_frame());
|
||||
}
|
||||
|
||||
g_atomic_int_set(&_frames_pending_write, 0);
|
||||
g_atomic_int_set(&_num_captured_loops, 0);
|
||||
g_atomic_int_set(const_cast<gint*> (&_frames_pending_write), 0);
|
||||
g_atomic_int_set(const_cast<gint*> (&_num_captured_loops), 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -375,8 +375,8 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
|
|||
}
|
||||
_write_source->mark_write_starting_now(
|
||||
capture_start_frame, capture_captured, loop_length);
|
||||
g_atomic_int_set(&_frames_pending_write, 0);
|
||||
g_atomic_int_set(&_num_captured_loops, 0);
|
||||
g_atomic_int_set(const_cast<gint*> (&_frames_pending_write), 0);
|
||||
g_atomic_int_set(const_cast<gint*> (&_num_captured_loops), 0);
|
||||
was_recording = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -445,7 +445,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
|
|||
break;
|
||||
}
|
||||
}
|
||||
g_atomic_int_add(&_frames_pending_write, nframes);
|
||||
g_atomic_int_add(const_cast<gint*> (&_frames_pending_write), nframes);
|
||||
|
||||
if (buf.size() != 0) {
|
||||
Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex, Glib::Threads::TRY_LOCK);
|
||||
|
|
@ -798,7 +798,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const framecnt_t total = g_atomic_int_get(&_frames_pending_write);
|
||||
const framecnt_t total = g_atomic_int_get(const_cast<gint*> (&_frames_pending_write));
|
||||
|
||||
if (total == 0 ||
|
||||
_capture_buf->read_space() == 0 ||
|
||||
|
|
@ -833,7 +833,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
|
|||
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
g_atomic_int_add(&_frames_pending_write, -to_write);
|
||||
g_atomic_int_add(const_cast<gint*> (&_frames_pending_write), -to_write);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -1043,7 +1043,7 @@ MidiDiskstream::transport_looped (framepos_t)
|
|||
the Source and/or entirely after the capture is finished.
|
||||
*/
|
||||
if (was_recording) {
|
||||
g_atomic_int_add(&_num_captured_loops, 1);
|
||||
g_atomic_int_add(const_cast<gint*> (&_num_captured_loops), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1110,7 +1110,7 @@ MidiDiskstream::prep_record_enable ()
|
|||
boost::shared_ptr<MidiPort> sp = _source_port.lock ();
|
||||
|
||||
if (sp && Config->get_monitoring_model() == HardwareMonitoring) {
|
||||
sp->request_jack_monitors_input (!(_session.config.get_auto_input() && rolling));
|
||||
sp->request_input_monitoring (!(_session.config.get_auto_input() && rolling));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1258,12 +1258,12 @@ MidiDiskstream::allocate_temporary_buffers ()
|
|||
}
|
||||
|
||||
void
|
||||
MidiDiskstream::ensure_jack_monitors_input (bool yn)
|
||||
MidiDiskstream::ensure_input_monitoring (bool yn)
|
||||
{
|
||||
boost::shared_ptr<MidiPort> sp = _source_port.lock ();
|
||||
|
||||
if (sp) {
|
||||
sp->ensure_jack_monitors_input (yn);
|
||||
sp->ensure_input_monitoring (yn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,14 @@
|
|||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
|
||||
MidiPort::MidiPort (const std::string& name, Flags flags)
|
||||
#define port_engine AudioEngine::instance()->port_engine()
|
||||
|
||||
MidiPort::MidiPort (const std::string& name, PortFlags flags)
|
||||
: Port (name, DataType::MIDI, flags)
|
||||
, _has_been_mixed_down (false)
|
||||
, _resolve_required (false)
|
||||
, _input_active (true)
|
||||
, _always_parse (false)
|
||||
{
|
||||
_buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI));
|
||||
}
|
||||
|
|
@ -43,12 +46,32 @@ MidiPort::~MidiPort()
|
|||
void
|
||||
MidiPort::cycle_start (pframes_t nframes)
|
||||
{
|
||||
framepos_t now = AudioEngine::instance()->sample_time_at_cycle_start();
|
||||
|
||||
Port::cycle_start (nframes);
|
||||
|
||||
_buffer->clear ();
|
||||
|
||||
if (sends_output ()) {
|
||||
jack_midi_clear_buffer (jack_port_get_buffer (_jack_port, nframes));
|
||||
port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes));
|
||||
}
|
||||
|
||||
if (_always_parse) {
|
||||
MidiBuffer& mb (get_midi_buffer (nframes));
|
||||
|
||||
/* dump incoming MIDI to parser */
|
||||
|
||||
for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
|
||||
uint8_t* buf = (*b).buffer();
|
||||
|
||||
_self_parser.set_timestamp (now + (*b).time());
|
||||
|
||||
uint32_t limit = (*b).size();
|
||||
|
||||
for (size_t n = 0; n < limit; ++n) {
|
||||
_self_parser.scanner (buf[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,31 +86,33 @@ MidiPort::get_midi_buffer (pframes_t nframes)
|
|||
|
||||
if (_input_active) {
|
||||
|
||||
void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
|
||||
const pframes_t event_count = jack_midi_get_event_count (jack_buffer);
|
||||
void* buffer = port_engine.get_buffer (_port_handle, nframes);
|
||||
const pframes_t event_count = port_engine.get_midi_event_count (buffer);
|
||||
|
||||
/* suck all relevant MIDI events from the JACK MIDI port buffer
|
||||
/* suck all relevant MIDI events from the MIDI port buffer
|
||||
into our MidiBuffer
|
||||
*/
|
||||
|
||||
for (pframes_t i = 0; i < event_count; ++i) {
|
||||
|
||||
jack_midi_event_t ev;
|
||||
pframes_t timestamp;
|
||||
size_t size;
|
||||
uint8_t* buf;
|
||||
|
||||
jack_midi_event_get (&ev, jack_buffer, i);
|
||||
port_engine.midi_event_get (timestamp, size, &buf, buffer, i);
|
||||
|
||||
if (ev.buffer[0] == 0xfe) {
|
||||
if (buf[0] == 0xfe) {
|
||||
/* throw away active sensing */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check that the event is in the acceptable time range */
|
||||
|
||||
if ((ev.time >= (_global_port_buffer_offset + _port_buffer_offset)) &&
|
||||
(ev.time < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
|
||||
_buffer->push_back (ev);
|
||||
if ((timestamp >= (_global_port_buffer_offset + _port_buffer_offset)) &&
|
||||
(timestamp < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
|
||||
_buffer->push_back (timestamp, size, buf);
|
||||
} else {
|
||||
cerr << "Dropping incoming MIDI at time " << ev.time << "; offset="
|
||||
cerr << "Dropping incoming MIDI at time " << timestamp << "; offset="
|
||||
<< _global_port_buffer_offset << " limit="
|
||||
<< (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n";
|
||||
}
|
||||
|
|
@ -121,7 +146,7 @@ MidiPort::cycle_split ()
|
|||
}
|
||||
|
||||
void
|
||||
MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when)
|
||||
MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when)
|
||||
{
|
||||
for (uint8_t channel = 0; channel <= 0xF; channel++) {
|
||||
|
||||
|
|
@ -132,13 +157,13 @@ MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when)
|
|||
* that prioritize sustain over AllNotesOff
|
||||
*/
|
||||
|
||||
if (jack_midi_event_write (jack_buffer, when, ev, 3) != 0) {
|
||||
if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
|
||||
cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl;
|
||||
}
|
||||
|
||||
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
|
||||
|
||||
if (jack_midi_event_write (jack_buffer, 0, ev, 3) != 0) {
|
||||
if (port_engine.midi_event_put (port_buffer, 0, ev, 3) != 0) {
|
||||
cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl;
|
||||
}
|
||||
}
|
||||
|
|
@ -149,11 +174,11 @@ MidiPort::flush_buffers (pframes_t nframes)
|
|||
{
|
||||
if (sends_output ()) {
|
||||
|
||||
void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
|
||||
void* port_buffer = port_engine.get_buffer (_port_handle, nframes);
|
||||
|
||||
if (_resolve_required) {
|
||||
/* resolve all notes at the start of the buffer */
|
||||
resolve_notes (jack_buffer, 0);
|
||||
resolve_notes (port_buffer, 0);
|
||||
_resolve_required = false;
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +191,7 @@ MidiPort::flush_buffers (pframes_t nframes)
|
|||
assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset));
|
||||
|
||||
if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) {
|
||||
if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
|
||||
if (port_engine.midi_event_put (port_buffer, (pframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
|
||||
cerr << "write failed, drop flushed note off on the floor, time "
|
||||
<< ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl;
|
||||
}
|
||||
|
|
@ -202,6 +227,7 @@ MidiPort::reset ()
|
|||
{
|
||||
Port::reset ();
|
||||
delete _buffer;
|
||||
cerr << name() << " new MIDI buffer of size " << AudioEngine::instance()->raw_buffer_size (DataType::MIDI) << endl;
|
||||
_buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI));
|
||||
}
|
||||
|
||||
|
|
@ -210,3 +236,9 @@ MidiPort::set_input_active (bool yn)
|
|||
{
|
||||
_input_active = yn;
|
||||
}
|
||||
|
||||
void
|
||||
MidiPort::set_always_parse (bool yn)
|
||||
{
|
||||
_always_parse = yn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@
|
|||
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
#include "midi++/manager.h"
|
||||
#include "midi++/port.h"
|
||||
|
||||
#include "ardour/async_midi_port.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
#include "ardour/midi_ui.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/session_event.h"
|
||||
|
|
@ -48,7 +48,6 @@ MidiControlUI::MidiControlUI (Session& s)
|
|||
: AbstractUI<MidiUIRequest> (X_("midiui"))
|
||||
, _session (s)
|
||||
{
|
||||
MIDI::Manager::instance()->PortsChanged.connect_same_thread (rebind_connection, boost::bind (&MidiControlUI::change_midi_ports, this));
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
|
|
@ -83,20 +82,10 @@ MidiControlUI::do_request (MidiUIRequest* req)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiControlUI::change_midi_ports ()
|
||||
{
|
||||
MidiUIRequest* req = get_request (PortChange);
|
||||
if (req == 0) {
|
||||
return;
|
||||
}
|
||||
send_request (req);
|
||||
}
|
||||
|
||||
bool
|
||||
MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port)
|
||||
MidiControlUI::midi_input_handler (IOCondition ioc, AsyncMIDIPort* port)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", port->name()));
|
||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", ((ARDOUR::Port*)port)->name()));
|
||||
|
||||
if (ioc & ~IO_IN) {
|
||||
return false;
|
||||
|
|
@ -108,8 +97,8 @@ MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port)
|
|||
CrossThreadChannel::drain (port->selectable());
|
||||
#endif
|
||||
|
||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name()));
|
||||
framepos_t now = _session.engine().frame_time();
|
||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", ((ARDOUR::Port*)port)->name()));
|
||||
framepos_t now = _session.engine().sample_time();
|
||||
port->parse (now);
|
||||
}
|
||||
|
||||
|
|
@ -130,22 +119,19 @@ MidiControlUI::clear_ports ()
|
|||
void
|
||||
MidiControlUI::reset_ports ()
|
||||
{
|
||||
clear_ports ();
|
||||
if (port_sources.empty()) {
|
||||
AsyncMIDIPort* async = dynamic_cast<AsyncMIDIPort*> (_session.midi_input_port());
|
||||
|
||||
boost::shared_ptr<const MIDI::Manager::PortList> plist = MIDI::Manager::instance()->get_midi_ports ();
|
||||
|
||||
for (MIDI::Manager::PortList::const_iterator i = plist->begin(); i != plist->end(); ++i) {
|
||||
|
||||
if (!(*i)->centrally_parsed()) {
|
||||
continue;
|
||||
if (!async) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fd;
|
||||
|
||||
if ((fd = (*i)->selectable ()) >= 0) {
|
||||
if ((fd = async->selectable ()) >= 0) {
|
||||
Glib::RefPtr<IOSource> psrc = IOSource::create (fd, IO_IN|IO_HUP|IO_ERR);
|
||||
|
||||
psrc->connect (sigc::bind (sigc::mem_fun (this, &MidiControlUI::midi_input_handler), *i));
|
||||
psrc->connect (sigc::bind (sigc::mem_fun (this, &MidiControlUI::midi_input_handler), async));
|
||||
psrc->attach (_main_loop->get_context());
|
||||
|
||||
// glibmm hack: for now, store only the GSource*
|
||||
|
|
|
|||
170
libs/ardour/midiport_manager.cc
Normal file
170
libs/ardour/midiport_manager.cc
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
Copyright (C) 1998-99 Paul Barton-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.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/async_midi_port.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
using namespace MIDI;
|
||||
using namespace PBD;
|
||||
|
||||
|
||||
MidiPortManager::MidiPortManager ()
|
||||
{
|
||||
create_ports ();
|
||||
}
|
||||
|
||||
MidiPortManager::~MidiPortManager ()
|
||||
{
|
||||
if (_midi_in) {
|
||||
AudioEngine::instance()->unregister_port (_midi_in);
|
||||
}
|
||||
if (_midi_in) {
|
||||
AudioEngine::instance()->unregister_port (_midi_in);
|
||||
}
|
||||
if (_mtc_input_port) {
|
||||
AudioEngine::instance()->unregister_port (_mtc_input_port);
|
||||
}
|
||||
if (_mtc_output_port) {
|
||||
AudioEngine::instance()->unregister_port (_mtc_output_port);
|
||||
}
|
||||
if (_midi_clock_input_port) {
|
||||
AudioEngine::instance()->unregister_port (_midi_clock_input_port);
|
||||
}
|
||||
if (_midi_clock_output_port) {
|
||||
AudioEngine::instance()->unregister_port (_midi_clock_output_port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MidiPortManager::create_ports ()
|
||||
{
|
||||
/* this method is idempotent
|
||||
*/
|
||||
|
||||
if (_midi_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
_midi_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("MIDI control in"), true);
|
||||
_midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MIDI control out"), true);
|
||||
|
||||
_mmc_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("MMC in"), true);
|
||||
_mmc_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MMC out"), true);
|
||||
|
||||
/* XXX nasty type conversion needed because of the mixed inheritance
|
||||
* required to integrate MIDI::IPMidiPort and ARDOUR::AsyncMIDIPort.
|
||||
*
|
||||
* At some point, we'll move IPMidiPort into Ardour and make it
|
||||
* inherit from ARDOUR::MidiPort not MIDI::Port, and then this
|
||||
* mess can go away
|
||||
*/
|
||||
|
||||
_midi_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_midi_in).get();
|
||||
_midi_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_midi_out).get();
|
||||
|
||||
_mmc_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_mmc_in).get();
|
||||
_mmc_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_mmc_out).get();
|
||||
|
||||
/* Now register ports used for sync (MTC and MIDI Clock)
|
||||
*/
|
||||
|
||||
boost::shared_ptr<ARDOUR::Port> p;
|
||||
|
||||
p = AudioEngine::instance()->register_input_port (DataType::MIDI, _("MTC in"));
|
||||
_mtc_input_port = boost::dynamic_pointer_cast<MidiPort> (p);
|
||||
p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MTC out"));
|
||||
_mtc_output_port= boost::dynamic_pointer_cast<MidiPort> (p);
|
||||
|
||||
p = AudioEngine::instance()->register_input_port (DataType::MIDI, _("MIDI Clock in"));
|
||||
_midi_clock_input_port = boost::dynamic_pointer_cast<MidiPort> (p);
|
||||
p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MIDI Clock out"));
|
||||
_midi_clock_output_port= boost::dynamic_pointer_cast<MidiPort> (p);
|
||||
|
||||
/* These ports all need their incoming data handled in
|
||||
* Port::cycle_start() and so ...
|
||||
*/
|
||||
|
||||
_mtc_input_port->set_always_parse (true);
|
||||
_mtc_output_port->set_always_parse (true);
|
||||
_midi_clock_input_port->set_always_parse (true);
|
||||
_midi_clock_output_port->set_always_parse (true);
|
||||
}
|
||||
|
||||
void
|
||||
MidiPortManager::set_midi_port_states (const XMLNodeList&nodes)
|
||||
{
|
||||
XMLProperty* prop;
|
||||
typedef map<std::string,boost::shared_ptr<Port> > PortMap;
|
||||
PortMap ports;
|
||||
const int version = 0;
|
||||
|
||||
ports.insert (make_pair (_mtc_input_port->name(), _mtc_input_port));
|
||||
ports.insert (make_pair (_mtc_output_port->name(), _mtc_output_port));
|
||||
ports.insert (make_pair (_midi_clock_input_port->name(), _midi_clock_input_port));
|
||||
ports.insert (make_pair (_midi_clock_output_port->name(), _midi_clock_output_port));
|
||||
ports.insert (make_pair (_midi_input_port->name(), _midi_in));
|
||||
ports.insert (make_pair (_midi_output_port->name(), _midi_out));
|
||||
ports.insert (make_pair (_mmc_input_port->name(), _mmc_in));
|
||||
ports.insert (make_pair (_mmc_output_port->name(), _mmc_out));
|
||||
|
||||
for (XMLNodeList::const_iterator n = nodes.begin(); n != nodes.end(); ++n) {
|
||||
if ((prop = (*n)->property (X_("name"))) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PortMap::iterator p = ports.find (prop->value());
|
||||
if (p == ports.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p->second->set_state (**n, version);
|
||||
}
|
||||
}
|
||||
|
||||
list<XMLNode*>
|
||||
MidiPortManager::get_midi_port_states () const
|
||||
{
|
||||
typedef map<std::string,boost::shared_ptr<Port> > PortMap;
|
||||
PortMap ports;
|
||||
list<XMLNode*> s;
|
||||
|
||||
ports.insert (make_pair (_mtc_input_port->name(), _mtc_input_port));
|
||||
ports.insert (make_pair (_mtc_output_port->name(), _mtc_output_port));
|
||||
ports.insert (make_pair (_midi_clock_input_port->name(), _midi_clock_input_port));
|
||||
ports.insert (make_pair (_midi_clock_output_port->name(), _midi_clock_output_port));
|
||||
ports.insert (make_pair (_midi_input_port->name(), _midi_in));
|
||||
ports.insert (make_pair (_midi_output_port->name(), _midi_out));
|
||||
ports.insert (make_pair (_mmc_input_port->name(), _mmc_in));
|
||||
ports.insert (make_pair (_mmc_output_port->name(), _mmc_out));
|
||||
|
||||
for (PortMap::const_iterator p = ports.begin(); p != ports.end(); ++p) {
|
||||
s.push_back (&p->second->get_state());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -25,11 +25,12 @@
|
|||
#include "pbd/error.h"
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
#include "midi++/port.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/slave.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/slave.h"
|
||||
|
||||
#include <glibmm/timer.h>
|
||||
|
||||
|
|
@ -50,8 +51,9 @@ using namespace Timecode;
|
|||
*/
|
||||
const int MTC_Slave::frame_tolerance = 2;
|
||||
|
||||
MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
|
||||
MTC_Slave::MTC_Slave (Session& s, MidiPort& p)
|
||||
: session (s)
|
||||
, port (&p)
|
||||
{
|
||||
can_notify_on_unknown_rate = true;
|
||||
did_reset_tc_format = false;
|
||||
|
|
@ -72,7 +74,10 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
|
|||
session.config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_Slave::parameter_changed, this, _1));
|
||||
parse_timecode_offset();
|
||||
reset (true);
|
||||
rebind (p);
|
||||
|
||||
port->self_parser().mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
|
||||
port->self_parser().mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
|
||||
port->self_parser().mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
|
||||
}
|
||||
|
||||
MTC_Slave::~MTC_Slave()
|
||||
|
|
@ -96,15 +101,12 @@ MTC_Slave::~MTC_Slave()
|
|||
}
|
||||
|
||||
void
|
||||
MTC_Slave::rebind (MIDI::Port& p)
|
||||
MTC_Slave::rebind (MidiPort& p)
|
||||
{
|
||||
port_connections.drop_connections ();
|
||||
|
||||
port = &p;
|
||||
|
||||
port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
|
||||
port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
|
||||
port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -156,7 +158,8 @@ MTC_Slave::outside_window (framepos_t pos) const
|
|||
bool
|
||||
MTC_Slave::locked () const
|
||||
{
|
||||
return port->parser()->mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0;
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2 initstate %3\n", port->self_parser().mtc_locked(), last_inbound_frame, engine_dll_initstate));
|
||||
return port->self_parser().mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -257,7 +260,6 @@ MTC_Slave::init_mtc_dll(framepos_t tme, double qtr)
|
|||
DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
|
||||
}
|
||||
|
||||
|
||||
/* called from MIDI parser */
|
||||
void
|
||||
MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now)
|
||||
|
|
@ -308,7 +310,7 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now
|
|||
a locate command via MMC.
|
||||
*/
|
||||
|
||||
//DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
|
||||
TimecodeFormat tc_format;
|
||||
bool reset_tc = true;
|
||||
|
||||
|
|
@ -424,7 +426,7 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now
|
|||
now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
|
||||
|
||||
if (was_full || outside_window (mtc_frame)) {
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", pthread_name()));
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2\n", was_full, outside_window (mtc_frame)));
|
||||
session.request_locate (mtc_frame, false);
|
||||
session.request_transport_speed (0);
|
||||
update_mtc_status (MIDI::MTC_Stopped);
|
||||
|
|
@ -448,7 +450,7 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now
|
|||
DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
|
||||
mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
|
||||
|
||||
switch (port->parser()->mtc_running()) {
|
||||
switch (port->self_parser().mtc_running()) {
|
||||
case MTC_Backward:
|
||||
mtc_frame -= mtc_off;
|
||||
qtr *= -1.0;
|
||||
|
|
@ -528,9 +530,10 @@ MTC_Slave::reset_window (framepos_t root)
|
|||
of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
|
||||
ahead of the window root (taking direction into account).
|
||||
*/
|
||||
|
||||
framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
|
||||
|
||||
switch (port->parser()->mtc_running()) {
|
||||
switch (port->self_parser().mtc_running()) {
|
||||
case MTC_Forward:
|
||||
window_begin = root;
|
||||
transport_direction = 1;
|
||||
|
|
@ -553,7 +556,7 @@ MTC_Slave::reset_window (framepos_t root)
|
|||
break;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -577,11 +580,11 @@ MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
|
|||
}
|
||||
|
||||
/* main entry point from session_process.cc
|
||||
* in jack_process callback context */
|
||||
xo * in process callback context */
|
||||
bool
|
||||
MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||
{
|
||||
framepos_t now = session.engine().frame_time_at_cycle_start();
|
||||
framepos_t now = session.engine().sample_time_at_cycle_start();
|
||||
framepos_t sess_pos = session.transport_frame(); // corresponds to now
|
||||
//sess_pos -= session.engine().frames_since_cycle_start();
|
||||
|
||||
|
|
@ -591,11 +594,21 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
|||
|
||||
read_current (&last);
|
||||
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 initstate %3 dir %4 tpos %5 now %6 last-in %7\n",
|
||||
last.timestamp,
|
||||
last.speed,
|
||||
engine_dll_initstate,
|
||||
transport_direction,
|
||||
sess_pos,
|
||||
now,
|
||||
last_inbound_frame));
|
||||
|
||||
/* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
|
||||
if (last.timestamp == 0) { engine_dll_initstate = 0; }
|
||||
else if (engine_dll_initstate != transport_direction && last.speed != 0) {
|
||||
if (last.timestamp == 0) {
|
||||
engine_dll_initstate = 0;
|
||||
} else if (engine_dll_initstate != transport_direction && last.speed != 0) {
|
||||
engine_dll_initstate = transport_direction;
|
||||
init_engine_dll(last.position, session.engine().frames_per_cycle());
|
||||
init_engine_dll(last.position, session.engine().samples_per_cycle());
|
||||
engine_dll_reinitialized = true;
|
||||
}
|
||||
|
||||
|
|
@ -627,9 +640,7 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
|||
/* interpolate position according to speed and time since last quarter-frame*/
|
||||
if (speed_flt == 0.0f) {
|
||||
elapsed = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* scale elapsed time by the current MTC speed */
|
||||
elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
|
||||
if (give_slave_full_control_over_transport_speed() && !engine_dll_reinitialized) {
|
||||
|
|
@ -645,8 +656,8 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
|||
te0 = te1;
|
||||
te1 += be * e + ee2;
|
||||
ee2 += ce * e;
|
||||
speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().frames_per_cycle() ));
|
||||
speed_flt = (te1 - te0) / double(session.engine().samples_per_cycle());
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().samples_per_cycle() ));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -659,14 +670,13 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
|||
*/
|
||||
if (!session.actively_recording()
|
||||
&& speed != 0
|
||||
&& ( (pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()) )
|
||||
) {
|
||||
&& ((pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()))) {
|
||||
engine_dll_initstate = 0;
|
||||
queue_reset (false);
|
||||
}
|
||||
|
||||
/* provide a .1% deadzone to lock the speed */
|
||||
if (fabs(speed - 1.0) <= 0.001)
|
||||
if (fabs (speed - 1.0) <= 0.001)
|
||||
speed = 1.0;
|
||||
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ PannerManager::discover_panners ()
|
|||
panner_discover (*i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PannerManager::panner_discover (string path)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "ardour/audioengine.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/port_engine.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
|
@ -42,13 +43,19 @@ using namespace PBD;
|
|||
PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
|
||||
PBD::Signal0<void> Port::PortDrop;
|
||||
|
||||
AudioEngine* Port::_engine = 0;
|
||||
bool Port::_connecting_blocked = false;
|
||||
pframes_t Port::_global_port_buffer_offset = 0;
|
||||
pframes_t Port::_cycle_nframes = 0;
|
||||
std::string Port::state_node_name = X_("Port");
|
||||
|
||||
/* a handy define to shorten what would otherwise be a needlessly verbose
|
||||
* repeated phrase
|
||||
*/
|
||||
#define port_engine AudioEngine::instance()->port_engine()
|
||||
#define port_manager AudioEngine::instance()
|
||||
|
||||
/** @param n Port short name */
|
||||
Port::Port (std::string const & n, DataType t, Flags f)
|
||||
Port::Port (std::string const & n, DataType t, PortFlags f)
|
||||
: _port_buffer_offset (0)
|
||||
, _name (n)
|
||||
, _flags (f)
|
||||
|
|
@ -60,18 +67,14 @@ Port::Port (std::string const & n, DataType t, Flags f)
|
|||
_private_capture_latency.max = 0;
|
||||
|
||||
/* Unfortunately we have to pass the DataType into this constructor so that
|
||||
we can create the right kind of JACK port; aside from this we'll use the
|
||||
we can create the right kind of port; aside from this we'll use the
|
||||
virtual function type () to establish type.
|
||||
*/
|
||||
|
||||
assert (_name.find_first_of (':') == std::string::npos);
|
||||
|
||||
if (!_engine->connected()) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
|
||||
cerr << "Failed to register JACK port \"" << _name << "\", reason is unknown from here\n";
|
||||
if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
|
||||
cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
|
|
@ -87,11 +90,10 @@ Port::~Port ()
|
|||
void
|
||||
Port::drop ()
|
||||
{
|
||||
if (_jack_port) {
|
||||
if (_engine->jack ()) {
|
||||
jack_port_unregister (_engine->jack (), _jack_port);
|
||||
}
|
||||
_jack_port = 0;
|
||||
if (_port_handle) {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
|
||||
port_engine.unregister_port (_port_handle);
|
||||
_port_handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,18 +101,18 @@ Port::drop ()
|
|||
bool
|
||||
Port::connected () const
|
||||
{
|
||||
return (jack_port_connected (_jack_port) != 0);
|
||||
return (port_engine.connected (_port_handle) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
Port::disconnect_all ()
|
||||
{
|
||||
jack_port_disconnect (_engine->jack(), _jack_port);
|
||||
port_engine.disconnect_all (_port_handle);
|
||||
_connections.clear ();
|
||||
|
||||
/* a cheaper, less hacky way to do boost::shared_from_this() ...
|
||||
*/
|
||||
boost::shared_ptr<Port> pself = _engine->get_port_by_name (name());
|
||||
boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
|
||||
PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
|
||||
|
||||
return 0;
|
||||
|
|
@ -122,48 +124,29 @@ Port::disconnect_all ()
|
|||
bool
|
||||
Port::connected_to (std::string const & o) const
|
||||
{
|
||||
if (!_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 JACK.
|
||||
*/
|
||||
if (!port_engine.connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return jack_port_connected_to (_jack_port,
|
||||
_engine->make_port_name_non_relative(o).c_str ());
|
||||
return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
|
||||
}
|
||||
|
||||
/** @param o Filled in with port full names of ports that we are connected to */
|
||||
int
|
||||
Port::get_connections (std::vector<std::string> & c) const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (_engine->connected()) {
|
||||
const char** jc = jack_port_get_connections (_jack_port);
|
||||
if (jc) {
|
||||
for (int i = 0; jc[i]; ++i) {
|
||||
c.push_back (jc[i]);
|
||||
++n;
|
||||
}
|
||||
|
||||
if (jack_free) {
|
||||
jack_free (jc);
|
||||
} else {
|
||||
free (jc);
|
||||
}
|
||||
}
|
||||
if (!port_engine.connected()) {
|
||||
c.insert (c.end(), _connections.begin(), _connections.end());
|
||||
return c.size();
|
||||
}
|
||||
|
||||
return n;
|
||||
return port_engine.get_connections (_port_handle, c);
|
||||
}
|
||||
|
||||
int
|
||||
Port::connect (std::string const & other)
|
||||
{
|
||||
std::string const other_shrt = _engine->make_port_name_non_relative (other);
|
||||
std::string const this_shrt = _engine->make_port_name_non_relative (_name);
|
||||
std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
|
||||
std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
|
||||
|
||||
int r = 0;
|
||||
|
||||
|
|
@ -172,9 +155,11 @@ Port::connect (std::string const & other)
|
|||
}
|
||||
|
||||
if (sends_output ()) {
|
||||
r = jack_connect (_engine->jack (), this_shrt.c_str (), other_shrt.c_str ());
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
|
||||
r = port_engine.connect (our_name, other_name);
|
||||
} else {
|
||||
r = jack_connect (_engine->jack (), other_shrt.c_str (), this_shrt.c_str());
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
|
||||
r = port_engine.connect (other_name, our_name);
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
|
|
@ -187,15 +172,15 @@ Port::connect (std::string const & other)
|
|||
int
|
||||
Port::disconnect (std::string const & other)
|
||||
{
|
||||
std::string const other_fullname = _engine->make_port_name_non_relative (other);
|
||||
std::string const this_fullname = _engine->make_port_name_non_relative (_name);
|
||||
std::string const other_fullname = port_manager->make_port_name_non_relative (other);
|
||||
std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
|
||||
|
||||
int r = 0;
|
||||
|
||||
if (sends_output ()) {
|
||||
r = jack_disconnect (_engine->jack (), this_fullname.c_str (), other_fullname.c_str ());
|
||||
r = port_engine.disconnect (this_fullname, other_fullname);
|
||||
} else {
|
||||
r = jack_disconnect (_engine->jack (), other_fullname.c_str (), this_fullname.c_str ());
|
||||
r = port_engine.disconnect (other_fullname, this_fullname);
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
|
|
@ -204,8 +189,8 @@ Port::disconnect (std::string const & other)
|
|||
|
||||
/* a cheaper, less hacky way to do boost::shared_from_this() ...
|
||||
*/
|
||||
boost::shared_ptr<Port> pself = _engine->get_port_by_name (name());
|
||||
boost::shared_ptr<Port> pother = _engine->get_port_by_name (other);
|
||||
boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
|
||||
boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
|
||||
|
||||
if (pself && pother) {
|
||||
/* Disconnecting from another Ardour port: need to allow
|
||||
|
|
@ -238,21 +223,22 @@ Port::disconnect (Port* o)
|
|||
}
|
||||
|
||||
void
|
||||
Port::set_engine (AudioEngine* e)
|
||||
Port::request_input_monitoring (bool yn)
|
||||
{
|
||||
_engine = e;
|
||||
port_engine.request_input_monitoring (_port_handle, yn);
|
||||
}
|
||||
|
||||
void
|
||||
Port::ensure_jack_monitors_input (bool yn)
|
||||
Port::ensure_input_monitoring (bool yn)
|
||||
{
|
||||
jack_port_ensure_monitor (_jack_port, yn);
|
||||
port_engine.ensure_input_monitoring (_port_handle, yn);
|
||||
}
|
||||
|
||||
bool
|
||||
Port::jack_monitoring_input () const
|
||||
Port::monitoring_input () const
|
||||
{
|
||||
return jack_port_monitoring_input (_jack_port);
|
||||
|
||||
return port_engine.monitoring_input (_port_handle);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -274,28 +260,23 @@ Port::increment_port_buffer_offset (pframes_t nframes)
|
|||
}
|
||||
|
||||
void
|
||||
Port::set_public_latency_range (jack_latency_range_t& range, bool playback) const
|
||||
Port::set_public_latency_range (LatencyRange& range, bool playback) const
|
||||
{
|
||||
/* this sets the visible latency that the rest of JACK sees. because we do latency
|
||||
compensation, all (most) of our visible port latency values are identical.
|
||||
/* this sets the visible latency that the rest of the port system
|
||||
sees. because we do latency compensation, all (most) of our visible
|
||||
port latency values are identical.
|
||||
*/
|
||||
|
||||
if (!jack_port_set_latency_range) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency,
|
||||
string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
|
||||
name(), range.min, range.max,
|
||||
(playback ? "PLAYBACK" : "CAPTURE")));;
|
||||
|
||||
jack_port_set_latency_range (_jack_port,
|
||||
(playback ? JackPlaybackLatency : JackCaptureLatency),
|
||||
&range);
|
||||
port_engine.set_latency_range (_port_handle, playback, range);
|
||||
}
|
||||
|
||||
void
|
||||
Port::set_private_latency_range (jack_latency_range_t& range, bool playback)
|
||||
Port::set_private_latency_range (LatencyRange& range, bool playback)
|
||||
{
|
||||
if (playback) {
|
||||
_private_playback_latency = range;
|
||||
|
|
@ -313,12 +294,12 @@ Port::set_private_latency_range (jack_latency_range_t& range, bool playback)
|
|||
_private_capture_latency.max));
|
||||
}
|
||||
|
||||
/* push to public (JACK) location so that everyone else can see it */
|
||||
/* push to public (port system) location so that everyone else can see it */
|
||||
|
||||
set_public_latency_range (range, playback);
|
||||
}
|
||||
|
||||
const jack_latency_range_t&
|
||||
const LatencyRange&
|
||||
Port::private_latency_range (bool playback) const
|
||||
{
|
||||
if (playback) {
|
||||
|
|
@ -338,14 +319,13 @@ Port::private_latency_range (bool playback) const
|
|||
}
|
||||
}
|
||||
|
||||
jack_latency_range_t
|
||||
LatencyRange
|
||||
Port::public_latency_range (bool /*playback*/) const
|
||||
{
|
||||
jack_latency_range_t r;
|
||||
LatencyRange r;
|
||||
|
||||
r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
|
||||
|
||||
jack_port_get_latency_range (_jack_port,
|
||||
sends_output() ? JackPlaybackLatency : JackCaptureLatency,
|
||||
&r);
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose (
|
||||
"GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
|
||||
name(), r.min, r.max,
|
||||
|
|
@ -354,27 +334,15 @@ Port::public_latency_range (bool /*playback*/) const
|
|||
}
|
||||
|
||||
void
|
||||
Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) const
|
||||
Port::get_connected_latency_range (LatencyRange& range, bool playback) const
|
||||
{
|
||||
if (!jack_port_get_latency_range) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<string> connections;
|
||||
jack_client_t* jack = _engine->jack();
|
||||
|
||||
if (!jack) {
|
||||
range.min = 0;
|
||||
range.max = 0;
|
||||
PBD::warning << _("get_connected_latency_range() called while disconnected from JACK") << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
get_connections (connections);
|
||||
|
||||
if (!connections.empty()) {
|
||||
|
||||
range.min = ~((jack_nframes_t) 0);
|
||||
range.min = ~((pframes_t) 0);
|
||||
range.max = 0;
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
|
||||
|
|
@ -382,21 +350,18 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c
|
|||
for (vector<string>::const_iterator c = connections.begin();
|
||||
c != connections.end(); ++c) {
|
||||
|
||||
jack_latency_range_t lr;
|
||||
LatencyRange lr;
|
||||
|
||||
if (!AudioEngine::instance()->port_is_mine (*c)) {
|
||||
|
||||
/* port belongs to some other JACK client, use
|
||||
* JACK to lookup its latency information.
|
||||
/* port belongs to some other port-system client, use
|
||||
* the port engine to lookup its latency information.
|
||||
*/
|
||||
|
||||
jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str());
|
||||
PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
|
||||
|
||||
if (remote_port) {
|
||||
jack_port_get_latency_range (
|
||||
remote_port,
|
||||
(playback ? JackPlaybackLatency : JackCaptureLatency),
|
||||
&lr);
|
||||
lr = port_engine.get_latency_range (remote_port, playback);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose (
|
||||
"\t%1 <-> %2 : latter has latency range %3 .. %4\n",
|
||||
|
|
@ -440,15 +405,10 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c
|
|||
int
|
||||
Port::reestablish ()
|
||||
{
|
||||
jack_client_t* jack = _engine->jack();
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
|
||||
_port_handle = port_engine.register_port (_name, type(), _flags);
|
||||
|
||||
if (!jack) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_jack_port = jack_port_register (jack, _name.c_str(), type().to_jack_type(), _flags, 0);
|
||||
|
||||
if (_jack_port == 0) {
|
||||
if (_port_handle == 0) {
|
||||
PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -464,6 +424,8 @@ Port::reconnect ()
|
|||
{
|
||||
/* caller must hold process lock; intended to be used only after reestablish() */
|
||||
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
|
||||
|
||||
for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
|
||||
if (connect (*i)) {
|
||||
return -1;
|
||||
|
|
@ -473,7 +435,7 @@ Port::reconnect ()
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** @param n Short port name (no JACK client name) */
|
||||
/** @param n Short port name (no port-system client name) */
|
||||
int
|
||||
Port::set_name (std::string const & n)
|
||||
{
|
||||
|
|
@ -481,10 +443,10 @@ Port::set_name (std::string const & n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int const r = jack_port_set_name (_jack_port, n.c_str());
|
||||
int const r = port_engine.set_port_name (_port_handle, n);
|
||||
|
||||
if (r == 0) {
|
||||
_engine->port_renamed (_name, n);
|
||||
AudioEngine::instance()->port_renamed (_name, n);
|
||||
_name = n;
|
||||
}
|
||||
|
||||
|
|
@ -492,38 +454,67 @@ Port::set_name (std::string const & n)
|
|||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
Port::request_jack_monitors_input (bool yn)
|
||||
{
|
||||
jack_port_request_monitor (_jack_port, yn);
|
||||
}
|
||||
|
||||
bool
|
||||
Port::physically_connected () const
|
||||
{
|
||||
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;
|
||||
return port_engine.physically_connected (_port_handle);
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
Port::get_state () const
|
||||
{
|
||||
XMLNode* root = new XMLNode (state_node_name);
|
||||
|
||||
root->add_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
|
||||
|
||||
if (receives_input()) {
|
||||
root->add_property (X_("direction"), X_("input"));
|
||||
} else {
|
||||
root->add_property (X_("direction"), X_("output"));
|
||||
}
|
||||
|
||||
vector<string> c;
|
||||
|
||||
get_connections (c);
|
||||
|
||||
for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
|
||||
XMLNode* child = new XMLNode (X_("Connection"));
|
||||
child->add_property (X_("other"), *i);
|
||||
root->add_child_nocopy (*child);
|
||||
}
|
||||
|
||||
return *root;
|
||||
}
|
||||
|
||||
int
|
||||
Port::set_state (const XMLNode& node, int)
|
||||
{
|
||||
const XMLProperty* prop;
|
||||
|
||||
if (node.name() != state_node_name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((prop = node.property (X_("name"))) != 0) {
|
||||
set_name (prop->value());
|
||||
}
|
||||
|
||||
const XMLNodeList& children (node.children());
|
||||
|
||||
_connections.clear ();
|
||||
|
||||
for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
|
||||
|
||||
if ((*c)->name() != X_("Connection")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((prop = (*c)->property (X_("other"))) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_connections.insert (prop->value());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ PortInsert::PortInsert (Session& s, boost::shared_ptr<Pannable> pannable, boost:
|
|||
{
|
||||
_mtdm = 0;
|
||||
_latency_detect = false;
|
||||
_latency_flush_frames = false;
|
||||
_latency_flush_frames = 0;
|
||||
_measured_latency = 0;
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ PortInsert::start_latency_detection ()
|
|||
{
|
||||
delete _mtdm;
|
||||
_mtdm = new MTDM (_session.frame_rate());
|
||||
_latency_flush_frames = false;
|
||||
_latency_flush_frames = 0;
|
||||
_latency_detect = true;
|
||||
_measured_latency = 0;
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ PortInsert::start_latency_detection ()
|
|||
void
|
||||
PortInsert::stop_latency_detection ()
|
||||
{
|
||||
_latency_flush_frames = signal_latency() + _session.engine().frames_per_cycle();
|
||||
_latency_flush_frames = signal_latency() + _session.engine().samples_per_cycle();
|
||||
_latency_detect = false;
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ PortInsert::latency() const
|
|||
*/
|
||||
|
||||
if (_measured_latency == 0) {
|
||||
return _session.engine().frames_per_cycle() + _input->latency();
|
||||
return _session.engine().samples_per_cycle() + _input->latency();
|
||||
} else {
|
||||
return _measured_latency;
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ PortInsert::signal_latency() const
|
|||
*/
|
||||
|
||||
if (_measured_latency == 0) {
|
||||
return _session.engine().frames_per_cycle() + _input->signal_latency();
|
||||
return _session.engine().samples_per_cycle() + _input->signal_latency();
|
||||
} else {
|
||||
return _measured_latency;
|
||||
}
|
||||
|
|
|
|||
659
libs/ardour/port_manager.cc
Normal file
659
libs/ardour/port_manager.cc
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
/*
|
||||
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 "pbd/error.h"
|
||||
|
||||
#include "ardour/async_midi_port.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/port_manager.h"
|
||||
#include "ardour/audio_port.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
PortManager::PortManager ()
|
||||
: ports (new Ports)
|
||||
, _port_remove_in_progress (false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::remove_all_ports ()
|
||||
{
|
||||
/* make sure that JACK callbacks that will be invoked as we cleanup
|
||||
* ports know that they have nothing to do.
|
||||
*/
|
||||
|
||||
_port_remove_in_progress = true;
|
||||
|
||||
/* process lock MUST be held by caller
|
||||
*/
|
||||
|
||||
{
|
||||
RCUWriter<Ports> writer (ports);
|
||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
||||
ps->clear ();
|
||||
}
|
||||
|
||||
/* clear dead wood list in RCU */
|
||||
|
||||
ports.flush ();
|
||||
|
||||
_port_remove_in_progress = false;
|
||||
}
|
||||
|
||||
|
||||
string
|
||||
PortManager::make_port_name_relative (const string& portname) const
|
||||
{
|
||||
if (!_impl) {
|
||||
return portname;
|
||||
}
|
||||
|
||||
string::size_type len;
|
||||
string::size_type n;
|
||||
string self = _impl->my_name();
|
||||
|
||||
len = portname.length();
|
||||
|
||||
for (n = 0; n < len; ++n) {
|
||||
if (portname[n] == ':') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((n != len) && (portname.substr (0, n) == self)) {
|
||||
return portname.substr (n+1);
|
||||
}
|
||||
|
||||
return portname;
|
||||
}
|
||||
|
||||
string
|
||||
PortManager::make_port_name_non_relative (const string& portname) const
|
||||
{
|
||||
string str;
|
||||
|
||||
if (portname.find_first_of (':') != string::npos) {
|
||||
return portname;
|
||||
}
|
||||
|
||||
str = _impl->my_name();
|
||||
str += ':';
|
||||
str += portname;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool
|
||||
PortManager::port_is_mine (const string& portname) const
|
||||
{
|
||||
if (!_impl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
string self = _impl->my_name();
|
||||
|
||||
if (portname.find_first_of (':') != string::npos) {
|
||||
if (portname.substr (0, self.length ()) != self) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PortManager::port_is_physical (const std::string& portname) const
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PortEngine::PortHandle ph = _impl->get_port_by_name (portname);
|
||||
if (!ph) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->port_is_physical (ph);
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
|
||||
{
|
||||
if (!_impl) {
|
||||
return;
|
||||
}
|
||||
_impl->get_physical_outputs (type, s);
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
|
||||
{
|
||||
if (!_impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
_impl->get_physical_inputs (type, s);
|
||||
}
|
||||
|
||||
ChanCount
|
||||
PortManager::n_physical_outputs () const
|
||||
{
|
||||
if (!_impl) {
|
||||
return ChanCount::ZERO;
|
||||
}
|
||||
|
||||
return _impl->n_physical_outputs ();
|
||||
}
|
||||
|
||||
ChanCount
|
||||
PortManager::n_physical_inputs () const
|
||||
{
|
||||
if (!_impl) {
|
||||
return ChanCount::ZERO;
|
||||
}
|
||||
return _impl->n_physical_inputs ();
|
||||
}
|
||||
|
||||
/** @param name Full or short name of port
|
||||
* @return Corresponding Port or 0.
|
||||
*/
|
||||
|
||||
boost::shared_ptr<Port>
|
||||
PortManager::get_port_by_name (const string& portname)
|
||||
{
|
||||
if (!_impl) {
|
||||
return boost::shared_ptr<Port>();
|
||||
}
|
||||
|
||||
if (!port_is_mine (portname)) {
|
||||
/* not an ardour port */
|
||||
return boost::shared_ptr<Port> ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Ports> pr = ports.reader();
|
||||
std::string rel = make_port_name_relative (portname);
|
||||
Ports::iterator x = pr->find (rel);
|
||||
|
||||
if (x != pr->end()) {
|
||||
/* its possible that the port was renamed by some 3rd party and
|
||||
we don't know about it. check for this (the check is quick
|
||||
and cheap), and if so, rename the port (which will alter
|
||||
the port map as a side effect).
|
||||
*/
|
||||
const std::string check = make_port_name_relative (_impl->get_port_name (x->second->port_handle()));
|
||||
if (check != rel) {
|
||||
x->second->set_name (check);
|
||||
}
|
||||
return x->second;
|
||||
}
|
||||
|
||||
return boost::shared_ptr<Port> ();
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
|
||||
{
|
||||
RCUWriter<Ports> writer (ports);
|
||||
boost::shared_ptr<Ports> p = writer.get_copy();
|
||||
Ports::iterator x = p->find (old_relative_name);
|
||||
|
||||
if (x != p->end()) {
|
||||
boost::shared_ptr<Port> port = x->second;
|
||||
p->erase (x);
|
||||
p->insert (make_pair (new_relative_name, port));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::get_ports (DataType type, PortList& pl)
|
||||
{
|
||||
boost::shared_ptr<Ports> plist = ports.reader();
|
||||
for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
|
||||
if (p->second->type() == type) {
|
||||
pl.push_back (p->second);
|
||||
}
|
||||
}
|
||||
return pl.size();
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
|
||||
{
|
||||
if (!_impl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _impl->get_ports (port_name_pattern, type, flags, s);
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::port_registration_failure (const std::string& portname)
|
||||
{
|
||||
if (!_impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
string full_portname = _impl->my_name();
|
||||
full_portname += ':';
|
||||
full_portname += portname;
|
||||
|
||||
|
||||
PortEngine::PortHandle p = _impl->get_port_by_name (full_portname);
|
||||
string reason;
|
||||
|
||||
if (p) {
|
||||
reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
|
||||
} else {
|
||||
reason = string_compose (_("No more ports are available. You will need to stop %1 and restart with more ports if you need this many tracks."), PROGRAM_NAME);
|
||||
}
|
||||
|
||||
throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
|
||||
}
|
||||
|
||||
boost::shared_ptr<Port>
|
||||
PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
|
||||
{
|
||||
boost::shared_ptr<Port> newport;
|
||||
|
||||
try {
|
||||
if (dtype == DataType::AUDIO) {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
|
||||
portname, input));
|
||||
newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
|
||||
} else if (dtype == DataType::MIDI) {
|
||||
if (async) {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
|
||||
portname, input));
|
||||
newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
|
||||
portname, input));
|
||||
newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
|
||||
}
|
||||
} else {
|
||||
throw PortRegistrationFailure("unable to create port (unknown type)");
|
||||
}
|
||||
|
||||
RCUWriter<Ports> writer (ports);
|
||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
||||
ps->insert (make_pair (make_port_name_relative (portname), newport));
|
||||
|
||||
/* writer goes out of scope, forces update */
|
||||
|
||||
}
|
||||
|
||||
catch (PortRegistrationFailure& err) {
|
||||
throw err;
|
||||
} catch (std::exception& e) {
|
||||
throw PortRegistrationFailure(string_compose(
|
||||
_("unable to create port: %1"), e.what()).c_str());
|
||||
} catch (...) {
|
||||
throw PortRegistrationFailure("unable to create port (unknown error)");
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
|
||||
return newport;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Port>
|
||||
PortManager::register_input_port (DataType type, const string& portname, bool async)
|
||||
{
|
||||
return register_port (type, portname, true, async);
|
||||
}
|
||||
|
||||
boost::shared_ptr<Port>
|
||||
PortManager::register_output_port (DataType type, const string& portname, bool async)
|
||||
{
|
||||
return register_port (type, portname, false, async);
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::unregister_port (boost::shared_ptr<Port> port)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
|
||||
{
|
||||
RCUWriter<Ports> writer (ports);
|
||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
||||
Ports::iterator x = ps->find (make_port_name_relative (port->name()));
|
||||
|
||||
if (x != ps->end()) {
|
||||
ps->erase (x);
|
||||
}
|
||||
|
||||
/* writer goes out of scope, forces update */
|
||||
}
|
||||
|
||||
ports.flush ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
PortManager::connected (const string& port_name)
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PortEngine::PortHandle handle = _impl->get_port_by_name (port_name);
|
||||
|
||||
if (!handle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->connected (handle);
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::connect (const string& source, const string& destination)
|
||||
{
|
||||
int ret;
|
||||
|
||||
string s = make_port_name_non_relative (source);
|
||||
string d = make_port_name_non_relative (destination);
|
||||
|
||||
boost::shared_ptr<Port> src = get_port_by_name (s);
|
||||
boost::shared_ptr<Port> dst = get_port_by_name (d);
|
||||
|
||||
if (src) {
|
||||
ret = src->connect (d);
|
||||
} else if (dst) {
|
||||
ret = dst->connect (s);
|
||||
} else {
|
||||
/* neither port is known to us ...hand-off to the PortEngine
|
||||
*/
|
||||
if (_impl) {
|
||||
ret = _impl->connect (s, d);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* already exists - no error, no warning */
|
||||
} else if (ret < 0) {
|
||||
error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
|
||||
source, s, destination, d)
|
||||
<< endmsg;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::disconnect (const string& source, const string& destination)
|
||||
{
|
||||
int ret;
|
||||
|
||||
string s = make_port_name_non_relative (source);
|
||||
string d = make_port_name_non_relative (destination);
|
||||
|
||||
boost::shared_ptr<Port> src = get_port_by_name (s);
|
||||
boost::shared_ptr<Port> dst = get_port_by_name (d);
|
||||
|
||||
if (src) {
|
||||
ret = src->disconnect (d);
|
||||
} else if (dst) {
|
||||
ret = dst->disconnect (s);
|
||||
} else {
|
||||
/* neither port is known to us ...hand-off to the PortEngine
|
||||
*/
|
||||
if (_impl) {
|
||||
ret = _impl->disconnect (s, d);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::disconnect (boost::shared_ptr<Port> port)
|
||||
{
|
||||
return port->disconnect_all ();
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::reestablish_ports ()
|
||||
{
|
||||
Ports::iterator i;
|
||||
|
||||
boost::shared_ptr<Ports> p = ports.reader ();
|
||||
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
|
||||
|
||||
for (i = p->begin(); i != p->end(); ++i) {
|
||||
if (i->second->reestablish ()) {
|
||||
error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
|
||||
cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != p->end()) {
|
||||
/* failed */
|
||||
remove_all_ports ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::reconnect_ports ()
|
||||
{
|
||||
boost::shared_ptr<Ports> p = ports.reader ();
|
||||
|
||||
/* re-establish connections */
|
||||
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
|
||||
|
||||
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
||||
i->second->reconnect ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::connect_callback (const string& a, const string& b, bool conn)
|
||||
{
|
||||
boost::shared_ptr<Port> port_a;
|
||||
boost::shared_ptr<Port> port_b;
|
||||
Ports::iterator x;
|
||||
boost::shared_ptr<Ports> pr = ports.reader ();
|
||||
|
||||
x = pr->find (make_port_name_relative (a));
|
||||
if (x != pr->end()) {
|
||||
port_a = x->second;
|
||||
}
|
||||
|
||||
x = pr->find (make_port_name_relative (b));
|
||||
if (x != pr->end()) {
|
||||
port_b = x->second;
|
||||
}
|
||||
|
||||
PortConnectedOrDisconnected (
|
||||
port_a, a,
|
||||
port_b, b,
|
||||
conn
|
||||
); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::registration_callback ()
|
||||
{
|
||||
if (!_port_remove_in_progress) {
|
||||
PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PortManager::can_request_input_monitoring () const
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->can_monitor_input ();
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::request_input_monitoring (const string& name, bool yn) const
|
||||
{
|
||||
if (!_impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!_impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
PortEngine::PortHandle ph = _impl->get_port_by_name (name);
|
||||
|
||||
if (ph) {
|
||||
_impl->ensure_input_monitoring (ph, yn);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PortManager::port_name_size() const
|
||||
{
|
||||
if (!_impl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _impl->port_name_size ();
|
||||
}
|
||||
|
||||
string
|
||||
PortManager::my_name() const
|
||||
{
|
||||
if (!_impl) {
|
||||
return string();
|
||||
}
|
||||
|
||||
return _impl->my_name();
|
||||
}
|
||||
|
||||
int
|
||||
PortManager::graph_order_callback ()
|
||||
{
|
||||
if (!_port_remove_in_progress) {
|
||||
GraphReordered(); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::cycle_start (pframes_t nframes)
|
||||
{
|
||||
Port::set_global_port_buffer_offset (0);
|
||||
Port::set_cycle_framecnt (nframes);
|
||||
|
||||
_cycle_ports = ports.reader ();
|
||||
|
||||
for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
|
||||
p->second->cycle_start (nframes);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::cycle_end (pframes_t nframes)
|
||||
{
|
||||
for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
|
||||
p->second->cycle_end (nframes);
|
||||
}
|
||||
|
||||
for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
|
||||
p->second->flush_buffers (nframes);
|
||||
}
|
||||
|
||||
_cycle_ports.reset ();
|
||||
|
||||
/* we are done */
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::silence (pframes_t nframes)
|
||||
{
|
||||
for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
|
||||
if (i->second->sends_output()) {
|
||||
i->second->get_buffer(nframes).silence(nframes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::check_monitoring ()
|
||||
{
|
||||
for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
|
||||
|
||||
bool x;
|
||||
|
||||
if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
|
||||
i->second->set_last_monitor (x);
|
||||
/* XXX I think this is dangerous, due to
|
||||
a likely mutex in the signal handlers ...
|
||||
*/
|
||||
i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
|
||||
{
|
||||
for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
|
||||
|
||||
if (i->second->sends_output()) {
|
||||
|
||||
boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
|
||||
if (ap) {
|
||||
Sample* s = ap->engine_get_whole_audio_buffer ();
|
||||
gain_t g = base_gain;
|
||||
|
||||
for (pframes_t n = 0; n < nframes; ++n) {
|
||||
*s++ *= g;
|
||||
g -= gain_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,11 +27,11 @@
|
|||
#include "pbd/xml++.h"
|
||||
#include "pbd/file_utils.h"
|
||||
|
||||
#include "midi++/manager.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/diskstream.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/session_metadata.h"
|
||||
|
||||
|
|
@ -63,13 +63,8 @@ RCConfiguration::RCConfiguration ()
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
RCConfiguration::~RCConfiguration ()
|
||||
{
|
||||
for (list<XMLNode*>::iterator i = _midi_port_states.begin(); i != _midi_port_states.end(); ++i) {
|
||||
delete *i;
|
||||
}
|
||||
|
||||
delete _control_protocol_state;
|
||||
}
|
||||
|
||||
|
|
@ -177,16 +172,6 @@ RCConfiguration::get_state ()
|
|||
|
||||
root = new XMLNode("Ardour");
|
||||
|
||||
MIDI::Manager* mm = MIDI::Manager::instance();
|
||||
|
||||
if (mm) {
|
||||
boost::shared_ptr<const MIDI::Manager::PortList> ports = mm->get_midi_ports();
|
||||
|
||||
for (MIDI::Manager::PortList::const_iterator i = ports->begin(); i != ports->end(); ++i) {
|
||||
root->add_child_nocopy((*i)->get_state());
|
||||
}
|
||||
}
|
||||
|
||||
root->add_child_nocopy (get_variables ());
|
||||
|
||||
root->add_child_nocopy (SessionMetadata::Metadata()->get_user_state());
|
||||
|
|
@ -232,12 +217,6 @@ RCConfiguration::set_state (const XMLNode& root, int version)
|
|||
XMLNodeConstIterator niter;
|
||||
XMLNode *node;
|
||||
|
||||
for (list<XMLNode*>::iterator i = _midi_port_states.begin(); i != _midi_port_states.end(); ++i) {
|
||||
delete *i;
|
||||
}
|
||||
|
||||
_midi_port_states.clear ();
|
||||
|
||||
Stateful::save_extra_xml (root);
|
||||
|
||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||
|
|
@ -250,8 +229,6 @@ RCConfiguration::set_state (const XMLNode& root, int version)
|
|||
SessionMetadata::Metadata()->set_state (*node, version);
|
||||
} else if (node->name() == ControlProtocolManager::state_node_name) {
|
||||
_control_protocol_state = new XMLNode (*node);
|
||||
} else if (node->name() == MIDI::Port::state_node_name) {
|
||||
_midi_port_states.push_back (new XMLNode (*node));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue