mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
fix merge conflicts with master
This commit is contained in:
commit
7a30e63eaa
213 changed files with 29641 additions and 21838 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"
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,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"
|
||||
|
|
@ -158,10 +157,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 */
|
||||
|
||||
|
|
@ -203,7 +202,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);
|
||||
|
||||
|
|
@ -214,15 +213,17 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
}
|
||||
|
||||
ui_config = new UIConfiguration();
|
||||
|
||||
ui_config->ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
|
||||
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
|
||||
ui_config->map_parameters (pc);
|
||||
|
||||
_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;
|
||||
|
|
@ -270,6 +271,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));
|
||||
|
|
@ -368,6 +373,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*
|
||||
|
|
@ -379,46 +386,139 @@ 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()
|
||||
|
||||
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()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
|
||||
ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
|
||||
}
|
||||
|
||||
post_engine ();
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
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 ();
|
||||
|
||||
/* connect to important signals */
|
||||
|
||||
AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
|
||||
AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
|
||||
AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
|
||||
|
||||
_tooltips.enable();
|
||||
|
||||
ActionManager::load_menus ();
|
||||
|
|
@ -480,25 +580,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 ()
|
||||
|
|
@ -684,6 +768,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));
|
||||
|
||||
|
|
@ -778,7 +863,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;
|
||||
|
|
@ -918,7 +1003,8 @@ If you still wish to quit, please use the\n\n\
|
|||
_session = 0;
|
||||
}
|
||||
|
||||
engine->stop (true);
|
||||
halt_connection.disconnect ();
|
||||
AudioEngine::instance()->stop ();
|
||||
quit ();
|
||||
}
|
||||
|
||||
|
|
@ -1047,22 +1133,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 (rate == 0) {
|
||||
/* no sample rate available */
|
||||
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
|
||||
} else {
|
||||
|
||||
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);
|
||||
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), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
|
||||
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
|
||||
rate/1000,
|
||||
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
|
||||
(AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1132,7 +1224,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);
|
||||
}
|
||||
|
|
@ -1186,6 +1278,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>"));
|
||||
|
|
@ -1448,10 +1545,9 @@ ARDOUR_UI::open_recent_session ()
|
|||
bool
|
||||
ARDOUR_UI::check_audioengine ()
|
||||
{
|
||||
if (engine) {
|
||||
if (!engine->connected()) {
|
||||
if (!AudioEngine::instance()->connected()) {
|
||||
MessageDialog msg (string_compose (
|
||||
_("%1 is not connected to JACK\n"
|
||||
_("%1 is not connected to any audio backend.\n"
|
||||
"You cannot open or close sessions in this condition"),
|
||||
PROGRAM_NAME));
|
||||
pop_back_splash (msg);
|
||||
|
|
@ -1459,9 +1555,6 @@ ARDOUR_UI::check_audioengine ()
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1668,9 +1761,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 ());
|
||||
|
||||
|
|
@ -2030,127 +2130,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 ()
|
||||
{
|
||||
|
|
@ -2701,10 +2680,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) {
|
||||
|
|
@ -2800,12 +2775,7 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
|
|||
int unload_status;
|
||||
int retval = -1;
|
||||
|
||||
session_loaded = false;
|
||||
|
||||
if (!check_audioengine()) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (_session) {
|
||||
unload_status = unload_session ();
|
||||
|
||||
if (unload_status < 0) {
|
||||
|
|
@ -2814,11 +2784,14 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
|
|||
retval = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
session_loaded = false;
|
||||
|
||||
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 */
|
||||
|
|
@ -2919,12 +2892,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) {
|
||||
|
|
@ -2936,7 +2904,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 (...) {
|
||||
|
|
@ -3823,31 +3791,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 ()) {
|
||||
/* drop connection to AudioEngine::Halted so that we don't act
|
||||
* as if the engine unexpectedly shut down
|
||||
*/
|
||||
halt_connection.disconnect ();
|
||||
|
||||
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 ()) {
|
||||
if (AudioEngine::instance()->start ()) {
|
||||
MessageDialog msg (*editor, _("Could not reconnect to JACK"));
|
||||
msg.run ();
|
||||
}
|
||||
|
||||
update_sample_rate (0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4154,3 +4124,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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ class BigClockWindow;
|
|||
class BundleManager;
|
||||
class ButtonJoiner;
|
||||
class ConnectionEditor;
|
||||
class EngineControl;
|
||||
class KeyEditor;
|
||||
class LocationUIWindow;
|
||||
class MainClock;
|
||||
|
|
@ -263,7 +264,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 *);
|
||||
|
|
@ -301,19 +302,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 ();
|
||||
|
|
@ -666,9 +666,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;
|
||||
|
|
@ -709,6 +709,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);
|
||||
|
||||
|
|
@ -745,6 +746,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__ */
|
||||
|
|
|
|||
|
|
@ -161,10 +161,6 @@ ARDOUR_UI::set_session (Session *s)
|
|||
_session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
|
||||
_session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
|
||||
|
||||
#ifdef HAVE_JACK_SESSION
|
||||
engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
|
||||
#endif
|
||||
|
||||
/* Clocks are on by default after we are connected to a session, so show that here.
|
||||
*/
|
||||
|
||||
|
|
@ -279,7 +275,10 @@ ARDOUR_UI::unload_session (bool hide_stuff)
|
|||
rec_button.set_sensitive (false);
|
||||
|
||||
WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
|
||||
|
||||
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 "$@"
|
||||
|
|
|
|||
|
|
@ -1260,7 +1260,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());
|
||||
|
|
|
|||
|
|
@ -962,7 +962,5 @@ void *
|
|||
Editor::import_thread ()
|
||||
{
|
||||
_session->import_files (import_status);
|
||||
pthread_exit_pbd (0);
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2377,9 +2377,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);
|
||||
|
|
|
|||
|
|
@ -125,7 +125,8 @@ Editor::export_video ()
|
|||
break;
|
||||
}
|
||||
}
|
||||
ExportVideoDialog dialog (*this, _session);
|
||||
dialog.run();
|
||||
ExportVideoDialog dialog (_session, get_selection().time);
|
||||
Gtk::ResponseType r = (Gtk::ResponseType) dialog.run();
|
||||
(void) r; // keep gcc quiet
|
||||
dialog.hide();
|
||||
}
|
||||
|
|
|
|||
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,28 +33,57 @@
|
|||
#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 ();
|
||||
|
||||
static bool need_setup ();
|
||||
int setup_engine ();
|
||||
|
||||
bool was_used() const { return _used; }
|
||||
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::Notebook notebook;
|
||||
|
||||
/* core fields used by all backends */
|
||||
|
||||
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::Label latency_label;
|
||||
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::Button control_app_button;
|
||||
|
||||
/* latency measurement */
|
||||
|
||||
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;
|
||||
|
||||
/* JACK specific */
|
||||
|
||||
Gtk::CheckButton realtime_button;
|
||||
Gtk::CheckButton no_memory_lock_button;
|
||||
|
|
@ -67,60 +95,89 @@ class EngineControl : public Gtk::VBox {
|
|||
Gtk::CheckButton hw_meter_button;
|
||||
Gtk::CheckButton verbose_output_button;
|
||||
|
||||
Gtk::Button start_button;
|
||||
Gtk::Button stop_button;
|
||||
Gtk::HButtonBox button_box;
|
||||
|
||||
Gtk::ComboBoxText sample_rate_combo;
|
||||
Gtk::ComboBoxText period_size_combo;
|
||||
|
||||
Gtk::ComboBoxText preset_combo;
|
||||
Gtk::ComboBoxText serverpath_combo;
|
||||
Gtk::ComboBoxText driver_combo;
|
||||
Gtk::ComboBoxText interface_combo;
|
||||
Gtk::ComboBoxText device_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;
|
||||
|
||||
Gtk::Table basic_packer;
|
||||
Gtk::Table options_packer;
|
||||
Gtk::Table device_packer;
|
||||
Gtk::Table midi_packer;
|
||||
Gtk::HBox basic_hbox;
|
||||
Gtk::HBox options_hbox;
|
||||
Gtk::HBox device_hbox;
|
||||
Gtk::Notebook notebook;
|
||||
Gtk::VBox basic_vbox;
|
||||
Gtk::HBox midi_hbox;
|
||||
|
||||
bool _used;
|
||||
uint32_t ignore_changes;
|
||||
|
||||
static bool engine_running ();
|
||||
|
||||
void driver_changed ();
|
||||
void build_command_line (std::vector<std::string>&);
|
||||
void backend_changed ();
|
||||
void sample_rate_changed ();
|
||||
void buffer_size_changed ();
|
||||
void parameter_changed ();
|
||||
|
||||
std::map<std::string,std::vector<std::string> > devices;
|
||||
std::vector<std::string> backend_devs;
|
||||
void enumerate_devices (const std::string& driver);
|
||||
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;
|
||||
|
||||
#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
|
||||
void device_changed ();
|
||||
void list_devices ();
|
||||
void show_buffer_duration ();
|
||||
|
||||
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);
|
||||
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_saved_state_for_currently_displayed_backend_and_device ();
|
||||
void maybe_display_saved_state ();
|
||||
State* 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 ();
|
||||
sigc::connection latency_timeout;
|
||||
void enable_latency_tab ();
|
||||
void disable_latency_tab ();
|
||||
|
||||
void on_switch_page (GtkNotebookPage*, guint page_num);
|
||||
};
|
||||
|
||||
#endif /* __gtk2_ardour_engine_dialog_h__ */
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ using namespace PBD;
|
|||
using namespace ARDOUR;
|
||||
using namespace VideoUtils;
|
||||
|
||||
ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
|
||||
ExportVideoDialog::ExportVideoDialog (Session* s, TimeSelection &tme)
|
||||
: ArdourDialog (_("Export Video File "))
|
||||
, editor (ed)
|
||||
, export_range (tme)
|
||||
, outfn_path_label (_("File:"), Gtk::ALIGN_LEFT)
|
||||
, outfn_browse_button (_("Browse"))
|
||||
, invid_path_label (_("Video:"), Gtk::ALIGN_LEFT)
|
||||
|
|
@ -150,6 +150,9 @@ ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
|
|||
} else {
|
||||
insnd_combo.append_text (_("from the video's start to the video's end"));
|
||||
}
|
||||
if (!export_range.empty()) {
|
||||
insnd_combo.append_text (_("Selected range")); // TODO show export_range.start() -> export_range.end_frame()
|
||||
}
|
||||
insnd_combo.set_active(0);
|
||||
|
||||
outfn_path_entry.set_width_chars(38);
|
||||
|
|
@ -165,7 +168,7 @@ ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
|
|||
filenameset = true;
|
||||
}
|
||||
}
|
||||
else if (!filenameset
|
||||
if (!filenameset
|
||||
&& node->property(X_("Filename"))
|
||||
&& node->property(X_("LocalFile"))
|
||||
&& node->property(X_("LocalFile"))->value() == X_("1")
|
||||
|
|
@ -179,6 +182,9 @@ ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
|
|||
filenameset = true;
|
||||
}
|
||||
}
|
||||
if (!filenameset) {
|
||||
invid_path_entry.set_text (X_(""));
|
||||
}
|
||||
}
|
||||
|
||||
l = manage (new Label (_("<b>Settings:</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
|
||||
|
|
@ -254,8 +260,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);
|
||||
|
|
@ -505,6 +510,11 @@ ExportVideoDialog::launch_export ()
|
|||
}
|
||||
end += av_offset;
|
||||
}
|
||||
else if (insnd_combo.get_active_row_number() == 2) {
|
||||
// TODO quantize to video-frame ?!
|
||||
start = export_range.start();
|
||||
end = export_range.end_frame();
|
||||
}
|
||||
if (end <= 0) {
|
||||
start = _session->current_start_frame();
|
||||
end = _session->current_end_frame();
|
||||
|
|
@ -609,13 +619,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";
|
||||
|
|
@ -697,9 +702,14 @@ ExportVideoDialog::encode_pass (int pass)
|
|||
double duration_s = 0;
|
||||
|
||||
if (insnd_combo.get_active_row_number() == 0) {
|
||||
/* session start to session end */
|
||||
framecnt_t duration_f = _session->current_end_frame() - _session->current_start_frame();
|
||||
duration_s = (double)duration_f / (double)_session->nominal_frame_rate();
|
||||
} else if (insnd_combo.get_active_row_number() == 2) {
|
||||
/* selected range */
|
||||
duration_s = export_range.length() / (double)_session->nominal_frame_rate();
|
||||
} else {
|
||||
/* video start to end */
|
||||
framecnt_t duration_f = ARDOUR_UI::instance()->video_timeline->get_duration();
|
||||
if (av_offset < 0 ) {
|
||||
duration_f += av_offset;
|
||||
|
|
@ -715,10 +725,16 @@ ExportVideoDialog::encode_pass (int pass)
|
|||
transcoder->set_duration(duration_s * transcoder->get_fps());
|
||||
}
|
||||
|
||||
if (insnd_combo.get_active_row_number() == 0) {
|
||||
const framepos_t start = _session->current_start_frame();
|
||||
const framepos_t snend = _session->current_end_frame();
|
||||
if (insnd_combo.get_active_row_number() == 0 || insnd_combo.get_active_row_number() == 2) {
|
||||
framepos_t start, snend;
|
||||
const frameoffset_t vid_duration = ARDOUR_UI::instance()->video_timeline->get_duration();
|
||||
if (insnd_combo.get_active_row_number() == 0) {
|
||||
start = _session->current_start_frame();
|
||||
snend = _session->current_end_frame();
|
||||
} else {
|
||||
start = export_range.start();
|
||||
snend = export_range.end_frame();
|
||||
}
|
||||
|
||||
#if 0 /* DEBUG */
|
||||
printf("AV offset: %lld Vid-len: %lld Vid-end: %lld || start:%lld || end:%lld\n",
|
||||
|
|
@ -733,9 +749,17 @@ ExportVideoDialog::encode_pass (int pass)
|
|||
} else if (av_offset + vid_duration < snend) {
|
||||
transcoder->set_leadinout(0, (snend - (av_offset + vid_duration)) / (double)_session->nominal_frame_rate());
|
||||
transcoder->set_avoffset((av_offset - start) / (double)_session->nominal_frame_rate());
|
||||
} else {
|
||||
}
|
||||
#if 0
|
||||
else if (start > av_offset) {
|
||||
std::ostringstream osstream; osstream << ((start - av_offset) / (double)_session->nominal_frame_rate());
|
||||
ffs["-ss"] = osstream.str();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
transcoder->set_avoffset((av_offset - start) / (double)_session->nominal_frame_rate());
|
||||
}
|
||||
|
||||
} else if (av_offset < 0) {
|
||||
/* from 00:00:00:00 to video-end */
|
||||
transcoder->set_avoffset(av_offset / (double)_session->nominal_frame_rate());
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "ardour/template_utils.h"
|
||||
#include "ardour_dialog.h"
|
||||
|
||||
#include "time_selection.h"
|
||||
#include "transcode_ffmpeg.h"
|
||||
|
||||
/** @class ExportVideoDialog
|
||||
|
|
@ -40,13 +41,13 @@
|
|||
class ExportVideoDialog : public ArdourDialog , public PBD::ScopedConnectionList
|
||||
{
|
||||
public:
|
||||
ExportVideoDialog (PublicEditor&, ARDOUR::Session*);
|
||||
ExportVideoDialog (ARDOUR::Session*, TimeSelection &tme);
|
||||
~ExportVideoDialog ();
|
||||
|
||||
std::string get_exported_filename () { return outfn_path_entry.get_text(); }
|
||||
|
||||
private:
|
||||
PublicEditor& editor;
|
||||
TimeSelection &export_range;
|
||||
|
||||
void on_show ();
|
||||
void abort_clicked ();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
@ -278,16 +277,20 @@ GainMeterBase::setup_meters (int len)
|
|||
|
||||
switch (_width) {
|
||||
case Wide:
|
||||
meter_ticks1_area.show();
|
||||
meter_ticks2_area.show();
|
||||
//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();
|
||||
if (_route && _route->shared_peak_meter()->input_streams().n_total() > 1) {
|
||||
meter_width = 4;
|
||||
}
|
||||
//meter_ticks1_area.hide();
|
||||
//meter_ticks2_area.hide();
|
||||
meter_metric_area.hide();
|
||||
break;
|
||||
}
|
||||
level_meter->setup_meters(len, meter_width);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
if (AudioEngine::instance()->port_engine().connected_to (ph, *j, false)) {
|
||||
return PortMatrixNode::ASSOCIATED;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
/** UI extension suitable for out-of-process UIs */
|
||||
#define LV2_EXTERNAL_UI_URI "http://lv2plug.in/ns/extensions/ui#external"
|
||||
|
||||
#define LV2_EXTERNAL_UI_KX__Host "http://kxstudio.sf.net/ns/lv2ext/external-ui#Host"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ LV2PluginUI::update_timeout()
|
|||
void
|
||||
LV2PluginUI::on_external_ui_closed(void* controller)
|
||||
{
|
||||
//printf("LV2PluginUI::on_external_ui_closed\n");
|
||||
LV2PluginUI* me = (LV2PluginUI*)controller;
|
||||
me->_screen_update_connection.disconnect();
|
||||
me->_external_ui_ptr = NULL;
|
||||
|
|
@ -167,6 +168,19 @@ LV2PluginUI::output_update()
|
|||
//cout << "output_update" << endl;
|
||||
if (_external_ui_ptr) {
|
||||
LV2_EXTERNAL_UI_RUN(_external_ui_ptr);
|
||||
if (_lv2->is_external_kx() && !_external_ui_ptr) {
|
||||
// clean up external UI if it closes itself via
|
||||
// on_external_ui_closed() during run()
|
||||
//printf("LV2PluginUI::output_update -- UI was closed\n");
|
||||
//_screen_update_connection.disconnect();
|
||||
_message_update_connection.disconnect();
|
||||
if (_inst) {
|
||||
suil_instance_free((SuilInstance*)_inst);
|
||||
}
|
||||
_inst = NULL;
|
||||
_external_ui_ptr = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME only works with control output ports (which is all we support now anyway) */
|
||||
|
|
@ -218,12 +232,16 @@ LV2PluginUI::lv2ui_instantiate(const std::string& title)
|
|||
_external_ui_feature.URI = LV2_EXTERNAL_UI_URI;
|
||||
_external_ui_feature.data = &_external_ui_host;
|
||||
|
||||
_external_kxui_feature.URI = LV2_EXTERNAL_UI_KX__Host;
|
||||
_external_kxui_feature.data = &_external_ui_host;
|
||||
|
||||
++features_count;
|
||||
features = (LV2_Feature**)malloc(
|
||||
sizeof(LV2_Feature*) * (features_count + 1));
|
||||
for (size_t i = 0; i < features_count - 1; ++i) {
|
||||
sizeof(LV2_Feature*) * (features_count + 2));
|
||||
for (size_t i = 0; i < features_count - 2; ++i) {
|
||||
features[i] = features_src[i];
|
||||
}
|
||||
features[features_count - 2] = &_external_kxui_feature;
|
||||
features[features_count - 1] = &_external_ui_feature;
|
||||
features[features_count] = NULL;
|
||||
} else {
|
||||
|
|
@ -260,6 +278,10 @@ LV2PluginUI::lv2ui_instantiate(const std::string& title)
|
|||
? NS_UI "external"
|
||||
: NS_UI "GtkUI";
|
||||
|
||||
if (_lv2->has_message_output()) {
|
||||
_lv2->enable_ui_emmission();
|
||||
}
|
||||
|
||||
const LilvUI* ui = (const LilvUI*)_lv2->c_ui();
|
||||
_inst = suil_instance_new(
|
||||
ui_host,
|
||||
|
|
@ -322,8 +344,7 @@ LV2PluginUI::lv2ui_instantiate(const std::string& title)
|
|||
}
|
||||
|
||||
if (_lv2->has_message_output()) {
|
||||
_lv2->enable_ui_emmission();
|
||||
ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect(
|
||||
_message_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect(
|
||||
sigc::mem_fun(*this, &LV2PluginUI::update_timeout));
|
||||
}
|
||||
}
|
||||
|
|
@ -350,17 +371,14 @@ LV2PluginUI::~LV2PluginUI ()
|
|||
delete[] _values;
|
||||
}
|
||||
|
||||
/* Close and delete GUI. */
|
||||
lv2ui_free();
|
||||
|
||||
_message_update_connection.disconnect();
|
||||
_screen_update_connection.disconnect();
|
||||
|
||||
if (_lv2->is_external_ui()) {
|
||||
/* External UI is no longer valid.
|
||||
on_window_hide() will not try to use it if is NULL.
|
||||
*/
|
||||
_external_ui_ptr = NULL;
|
||||
if (_external_ui_ptr && _lv2->is_external_kx()) {
|
||||
LV2_EXTERNAL_UI_HIDE(_external_ui_ptr);
|
||||
}
|
||||
lv2ui_free();
|
||||
_external_ui_ptr = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -423,7 +441,15 @@ LV2PluginUI::on_window_show(const std::string& title)
|
|||
|
||||
if (_lv2->is_external_ui()) {
|
||||
if (_external_ui_ptr) {
|
||||
_screen_update_connection.disconnect();
|
||||
_message_update_connection.disconnect();
|
||||
LV2_EXTERNAL_UI_SHOW(_external_ui_ptr);
|
||||
_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
|
||||
(sigc::mem_fun(*this, &LV2PluginUI::output_update));
|
||||
if (_lv2->has_message_output()) {
|
||||
_message_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect(
|
||||
sigc::mem_fun(*this, &LV2PluginUI::update_timeout));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
lv2ui_instantiate(title);
|
||||
|
|
@ -431,10 +457,15 @@ LV2PluginUI::on_window_show(const std::string& title)
|
|||
return false;
|
||||
}
|
||||
|
||||
LV2_EXTERNAL_UI_SHOW(_external_ui_ptr);
|
||||
_screen_update_connection.disconnect();
|
||||
_message_update_connection.disconnect();
|
||||
LV2_EXTERNAL_UI_SHOW(_external_ui_ptr);
|
||||
_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
|
||||
(sigc::mem_fun(*this, &LV2PluginUI::output_update));
|
||||
if (_lv2->has_message_output()) {
|
||||
_message_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect(
|
||||
sigc::mem_fun(*this, &LV2PluginUI::update_timeout));
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
lv2ui_instantiate("gtk2gui");
|
||||
|
|
@ -446,13 +477,17 @@ LV2PluginUI::on_window_show(const std::string& title)
|
|||
void
|
||||
LV2PluginUI::on_window_hide()
|
||||
{
|
||||
//cout << "on_window_hide" << endl; flush(cout);
|
||||
//printf("LV2PluginUI::on_window_hide\n");
|
||||
_message_update_connection.disconnect();
|
||||
|
||||
if (_external_ui_ptr) {
|
||||
if (_lv2->is_external_ui()) {
|
||||
if (!_external_ui_ptr) { return; }
|
||||
LV2_EXTERNAL_UI_HIDE(_external_ui_ptr);
|
||||
//slv2_ui_instance_get_descriptor(_inst)->cleanup(_inst);
|
||||
//_external_ui_ptr = NULL;
|
||||
//_screen_update_connection.disconnect();
|
||||
if (!_lv2->is_external_kx()) { return ; }
|
||||
_screen_update_connection.disconnect();
|
||||
_external_ui_ptr = NULL;
|
||||
suil_instance_free((SuilInstance*)_inst);
|
||||
_inst = NULL;
|
||||
} else {
|
||||
lv2ui_free();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox
|
|||
boost::shared_ptr<ARDOUR::LV2Plugin> _lv2;
|
||||
std::vector<int> _output_ports;
|
||||
sigc::connection _screen_update_connection;
|
||||
sigc::connection _message_update_connection;
|
||||
Gtk::Widget* _gui_widget;
|
||||
/** a box containing the focus, bypass, delete, save / add preset buttons etc. */
|
||||
Gtk::HBox _ardour_buttons_box;
|
||||
|
|
@ -78,6 +79,7 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox
|
|||
std::vector<ControllableRef> _controllables;
|
||||
struct lv2_external_ui_host _external_ui_host;
|
||||
LV2_Feature _external_ui_feature;
|
||||
LV2_Feature _external_kxui_feature;
|
||||
struct lv2_external_ui* _external_ui_ptr;
|
||||
LV2_Feature _parent_feature;
|
||||
Gtk::Window* _win_ptr;
|
||||
|
|
|
|||
|
|
@ -372,34 +372,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 */
|
||||
}
|
||||
|
|
@ -407,15 +403,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) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@
|
|||
#include <time.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"
|
||||
|
|
@ -53,7 +56,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;
|
||||
|
|
@ -127,23 +131,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());
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,9 +404,9 @@ MidiTracer::tracer (Parser&, byte* msg, size_t len)
|
|||
|
||||
fifo.write (&buf, 1);
|
||||
|
||||
if (g_atomic_int_get (const_cast<gint*>(&_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 (const_cast<gint*>(&_update_queued));
|
||||
g_atomic_int_inc (const_cast<gint*> (&_update_queued));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +414,7 @@ void
|
|||
MidiTracer::update ()
|
||||
{
|
||||
bool updated = false;
|
||||
g_atomic_int_dec_and_test (const_cast<gint*>(&_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"
|
||||
|
|
|
|||
2961
gtk2_ardour/po/cs.po
2961
gtk2_ardour/po/cs.po
File diff suppressed because it is too large
Load diff
1223
gtk2_ardour/po/de.po
1223
gtk2_ardour/po/de.po
File diff suppressed because it is too large
Load diff
2596
gtk2_ardour/po/el.po
2596
gtk2_ardour/po/el.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2552
gtk2_ardour/po/es.po
2552
gtk2_ardour/po/es.po
File diff suppressed because it is too large
Load diff
2555
gtk2_ardour/po/fr.po
2555
gtk2_ardour/po/fr.po
File diff suppressed because it is too large
Load diff
2558
gtk2_ardour/po/it.po
2558
gtk2_ardour/po/it.po
File diff suppressed because it is too large
Load diff
2564
gtk2_ardour/po/nn.po
2564
gtk2_ardour/po/nn.po
File diff suppressed because it is too large
Load diff
2550
gtk2_ardour/po/pl.po
2550
gtk2_ardour/po/pl.po
File diff suppressed because it is too large
Load diff
2562
gtk2_ardour/po/pt.po
2562
gtk2_ardour/po/pt.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1875
gtk2_ardour/po/ru.po
1875
gtk2_ardour/po/ru.po
File diff suppressed because it is too large
Load diff
2560
gtk2_ardour/po/sv.po
2560
gtk2_ardour/po/sv.po
File diff suppressed because it is too large
Load diff
2548
gtk2_ardour/po/zh.po
2548
gtk2_ardour/po/zh.po
File diff suppressed because it is too large
Load diff
|
|
@ -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"
|
||||
|
|
@ -1460,8 +1458,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
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ SendUI::update ()
|
|||
void
|
||||
SendUI::fast_update ()
|
||||
{
|
||||
if (!is_mapped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config->get_meter_falloff() > 0.0f) {
|
||||
_gpm.update_meters ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -343,8 +343,15 @@ set_color (Gdk::Color& c, int rgb)
|
|||
bool
|
||||
relay_key_press (GdkEventKey* ev, Gtk::Window* win)
|
||||
{
|
||||
PublicEditor& ed (PublicEditor::instance());
|
||||
|
||||
if (&ed == 0) {
|
||||
/* early key press in pre-main-window-dialogs, no editor yet */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!key_press_focus_accelerator_handler (*win, ev)) {
|
||||
return PublicEditor::instance().on_key_press_event(ev);
|
||||
return ed.on_key_press_event(ev);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,6 @@ VolumeController::adjust (double control_delta)
|
|||
double v;
|
||||
|
||||
if (!_linear) {
|
||||
|
||||
/* we map back into the linear/fractional slider position,
|
||||
* because this kind of control goes all the way down
|
||||
* to -inf dB, and we want this occur in a reasonable way in
|
||||
|
|
@ -150,7 +149,7 @@ VolumeController::adjust (double control_delta)
|
|||
* gain coefficient domain (or dB domain), the lower end of the
|
||||
* control range (getting close to -inf dB) takes forever.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* convert to linear/fractional slider position domain */
|
||||
v = gain_to_slider_position_with_max (_controllable->get_value (), _controllable->upper());
|
||||
/* increment in this domain */
|
||||
|
|
@ -171,6 +170,57 @@ VolumeController::adjust (double control_delta)
|
|||
}
|
||||
/* and return it */
|
||||
return dB_to_coefficient (v);
|
||||
#else
|
||||
/* ^^ Above algorithm is not symmetric. Scroll up to steps, scoll down two steps, -> different gain.
|
||||
*
|
||||
* see ./libs/gtkmm2ext/gtkmm2ext/motionfeedback.h and gtk2_ardour/monitor_section.cc:
|
||||
* min-delta (corr) = MIN(0.01 * page inc, 1 * size_inc) // (gain_control uses size_inc=0.01, page_inc=0.1)
|
||||
* range corr: 0..2 -> -inf..+6dB
|
||||
* step sizes [0.01, 0.10, 0.20] * page_inc, [1,2,10,100] * step_inc. [1,2,10,100] * page_inc
|
||||
*
|
||||
* 0.001, 0.01, 0.02, 0.1, .2, 1, 10
|
||||
* -> 1k steps between -inf..0dB
|
||||
* -> 1k steps between 0..+dB
|
||||
*
|
||||
* IOW:
|
||||
* the range is from *0 (-inf dB) to *2.0 ( +6dB)
|
||||
* the knob is configured to to go in steps of 0.001 - that's 2000 steps between 0 and 2.
|
||||
* or 1000 steps between 0 and 1.
|
||||
*
|
||||
* we cannot round to .01dB steps because
|
||||
* There are only 600 possible values between +0db and +6dB when going in steps of .01dB
|
||||
* 1000/600 = 1.66666...
|
||||
*
|
||||
******
|
||||
* idea: make the 'controllable use a fixed range of dB.
|
||||
* do a 1:1 mapping between values. :et's stick with the range of 0..2 in 0.001 steps
|
||||
*
|
||||
* "-80" becomes 0 and "+6" becomes 2000. (NB +6dB is actually 1995, but we clamp that to the top)
|
||||
*
|
||||
* This approach is better (more consistet) but not good. At least the dial does not annoy me as much
|
||||
* anymore as it did before.
|
||||
*
|
||||
* const double stretchfactor = rint((_controllable->upper() - _controllable->lower()) / 0.001); // 2000;
|
||||
* const double logfactor = stretchfactor / ((20.0 * log10( _controllable->upper())) + 80.0); // = 23.250244732
|
||||
*/
|
||||
v = _controllable->get_value ();
|
||||
/* assume everything below -60dB is silent (.001 ^= -60dB)
|
||||
* but map range -80db..+6dB to a scale of 0..2000
|
||||
* 80db was motivated because 2000/((20.0 * log(1)) + 80.0) is an integer value. "0dB" is included on the scale.
|
||||
* but this leaves a dead area at the bottom of the meter..
|
||||
*/
|
||||
double arange = (v >= 0.001) ? ( ((20.0 * log10(v)) + 80.0) * 23.250244732 ) : ( 0 );
|
||||
/* add the delta */
|
||||
v = rint(arange) + rint(control_delta * 1000.0); // (min steps is 1.0/0.001 == 1000.0)
|
||||
/* catch bottom -80..-60 db in one step */
|
||||
if (v < 466) v = (control_delta > 0) ? 0.001 : 0;
|
||||
/* reverse operation (pow(10, .05 * ((v / 23.250244732) - 80.0)))
|
||||
* can be simplified to :*/
|
||||
else v = pow(10, (v * 0.00215051499) - 4.0);
|
||||
/* clamp value in coefficient domain */
|
||||
v = std::max (_controllable->lower(), std::min (_controllable->upper(), v));
|
||||
return v;
|
||||
#endif
|
||||
} else {
|
||||
double mult;
|
||||
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ ProxyBase::hide ()
|
|||
}
|
||||
|
||||
bool
|
||||
ProxyBase::handle_win_event (GdkEventAny *ev)
|
||||
ProxyBase::handle_win_event (GdkEventAny* /*ev*/)
|
||||
{
|
||||
hide();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -506,6 +506,7 @@ def build(bld):
|
|||
'SMALLER' : '9',
|
||||
'SMALL' : '10',
|
||||
'NORMAL' : '11',
|
||||
'BIG' : '13',
|
||||
'BIGGER' : '17',
|
||||
'LARGE' : '18',
|
||||
'LARGER' : '28',
|
||||
|
|
@ -531,6 +532,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,68 +34,46 @@
|
|||
#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 { return xthread.selectable(); }
|
||||
|
||||
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:
|
||||
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;
|
||||
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;
|
||||
CrossThreadChannel xthread;
|
||||
|
||||
int create_port ();
|
||||
|
||||
/** Channel used to signal to the MidiControlUI that input has arrived */
|
||||
|
||||
std::string _connections;
|
||||
PBD::ScopedConnection connect_connection;
|
||||
PBD::ScopedConnection halt_connection;
|
||||
void flush (void* jack_port_buffer);
|
||||
void jack_halted ();
|
||||
void make_connections ();
|
||||
void init (std::string const &, Flags);
|
||||
void flush_output_fifo (pframes_t);
|
||||
|
||||
static pthread_t _process_thread;
|
||||
|
||||
};
|
||||
|
||||
} // namespace MIDI
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif // __libmidi_port_h__
|
||||
#endif /* __libardour_async_midiport_h__ */
|
||||
444
libs/ardour/ardour/audio_backend.h
Normal file
444
libs/ardour/ardour/audio_backend.h
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
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"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/port_engine.h"
|
||||
#include "ardour/visibility.h"
|
||||
|
||||
#ifdef ARDOURBACKEND_DLL_EXPORTS // defined if we are building the ARDOUR Panners DLLs (instead of using them)
|
||||
#define ARDOURBACKEND_API LIBARDOUR_HELPER_DLL_EXPORT
|
||||
#else
|
||||
#define ARDOURBACKEND_API LIBARDOUR_HELPER_DLL_IMPORT
|
||||
#endif
|
||||
#define ARDOURBACKEND_LOCAL LIBARDOUR_HELPER_DLL_LOCAL
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AudioBackend : public PortEngine {
|
||||
public:
|
||||
|
||||
AudioBackend (AudioEngine& e) : PortEngine (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 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, AudioBackendNativeThread*, size_t stacksize) = 0;
|
||||
|
||||
/** Wait for the thread specified by @param thread to exit.
|
||||
*
|
||||
* Return zero on success, non-zero on failure.
|
||||
*/
|
||||
virtual int wait_for_process_thread_exit (AudioBackendNativeThread thread) = 0;
|
||||
|
||||
virtual void update_latencies () = 0;
|
||||
|
||||
protected:
|
||||
AudioEngine& engine;
|
||||
};
|
||||
|
||||
struct AudioBackendInfo {
|
||||
const char* name;
|
||||
|
||||
/** Using arg1 and arg2, initialize this audiobackend.
|
||||
*
|
||||
* Returns zero on success, non-zero otherwise.
|
||||
*/
|
||||
int (*instantiate) (const std::string& arg1, const std::string& arg2);
|
||||
|
||||
/** Release all resources associated with this audiobackend
|
||||
*/
|
||||
int (*deinstantiate) (void);
|
||||
|
||||
/** Factory method to create an AudioBackend-derived class.
|
||||
*
|
||||
* Returns a valid shared_ptr to the object if successfull,
|
||||
* or a "null" shared_ptr otherwise.
|
||||
*/
|
||||
boost::shared_ptr<AudioBackend> (*factory) (AudioEngine&);
|
||||
|
||||
/** 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,26 +33,22 @@
|
|||
|
||||
#include <glibmm/threads.h>
|
||||
|
||||
#include "pbd/rcu.h"
|
||||
#include "pbd/signals.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include <jack/weakjack.h>
|
||||
#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;
|
||||
|
|
@ -60,176 +56,106 @@ 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);
|
||||
static AudioEngine* create ();
|
||||
|
||||
virtual ~AudioEngine ();
|
||||
|
||||
jack_client_t* jack() const;
|
||||
bool connected() const { return _jack != 0; }
|
||||
|
||||
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; }
|
||||
|
||||
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 reconnect_to_jack ();
|
||||
int disconnect_from_jack();
|
||||
|
||||
int stop (bool forever = false);
|
||||
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, AudioBackendNativeThread*, size_t stacksize);
|
||||
int wait_for_process_thread_exit (AudioBackendNativeThread);
|
||||
bool is_realtime() const;
|
||||
bool connected() const;
|
||||
|
||||
int set_device_name (const std::string&);
|
||||
int set_sample_rate (float);
|
||||
int set_buffer_size (uint32_t);
|
||||
int set_sample_format (SampleFormat);
|
||||
int set_interleaved (bool yn);
|
||||
int set_input_channels (uint32_t);
|
||||
int set_output_channels (uint32_t);
|
||||
int set_systemic_input_latency (uint32_t);
|
||||
int set_systemic_output_latency (uint32_t);
|
||||
|
||||
/* END BACKEND PROXY API */
|
||||
|
||||
bool freewheeling() const { return _freewheeling; }
|
||||
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;
|
||||
int request_buffer_size (pframes_t samples) {
|
||||
return set_buffer_size (samples);
|
||||
}
|
||||
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;
|
||||
};
|
||||
Session* session() const { return _session; }
|
||||
|
||||
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.
|
||||
(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 */
|
||||
/* this signal is sent if the backend ever disconnects us */
|
||||
|
||||
PBD::Signal1<void,const char*> Halted;
|
||||
|
||||
|
|
@ -240,31 +166,40 @@ _ the regular process() call to session->process() is not made.
|
|||
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()>, pthread_t*, size_t stacksize);
|
||||
/* 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();
|
||||
int prepare_for_latency_measurement ();
|
||||
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 ();
|
||||
|
||||
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;
|
||||
|
|
@ -272,66 +207,24 @@ private:
|
|||
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;
|
||||
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;
|
||||
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 *);
|
||||
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;
|
||||
bool _started_for_latency;
|
||||
|
||||
void meter_thread ();
|
||||
void start_metering_thread ();
|
||||
|
|
@ -339,18 +232,13 @@ private:
|
|||
|
||||
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;
|
||||
|
||||
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,22 +61,14 @@ 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 */
|
||||
|
|
@ -125,7 +117,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif // __ardour_data_type_h__
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ namespace PBD {
|
|||
extern uint64_t OrderKeys;
|
||||
extern uint64_t Automation;
|
||||
extern uint64_t WiimoteControl;
|
||||
extern uint64_t Ports;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ extern const char* const route_templates_dir_name;
|
|||
extern const char* const surfaces_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 ();
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class ExportFormatBase {
|
|||
F_None = 0,
|
||||
F_WAV = SF_FORMAT_WAV,
|
||||
F_W64 = SF_FORMAT_W64,
|
||||
F_CAF = SF_FORMAT_CAF,
|
||||
F_AIFF = SF_FORMAT_AIFF,
|
||||
F_AU = SF_FORMAT_AU,
|
||||
F_IRCAM = SF_FORMAT_IRCAM,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "pbd/semutils.h"
|
||||
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/audio_backend.h"
|
||||
#include "ardour/session_handle.h"
|
||||
|
||||
namespace ARDOUR
|
||||
|
|
@ -92,7 +93,7 @@ protected:
|
|||
virtual void session_going_away ();
|
||||
|
||||
private:
|
||||
std::list<pthread_t> _thread_list;
|
||||
std::list<AudioBackendNativeThread> _thread_list;
|
||||
volatile bool _quit_threads;
|
||||
|
||||
void reset_thread_list ();
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||
const void* c_ui_type();
|
||||
|
||||
bool is_external_ui () const;
|
||||
bool is_external_kx () const;
|
||||
bool ui_is_resizable () const;
|
||||
|
||||
const char* port_symbol (uint32_t port) const;
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
||||
/** Return a private, type-free pointer to any data
|
||||
* that might be useful to a concrete implementation
|
||||
*/
|
||||
virtual void* private_handle() const = 0;
|
||||
|
||||
/* 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 the name of this process as used by the port manager
|
||||
* when naming ports.
|
||||
*/
|
||||
virtual const std::string& my_name() 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 available() 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__ */
|
||||
170
libs/ardour/ardour/port_manager.h
Normal file
170
libs/ardour/ardour/port_manager.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class PortEngine;
|
||||
class AudioBackend;
|
||||
|
||||
class PortManager
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
|
||||
typedef std::list<boost::shared_ptr<Port> > PortList;
|
||||
|
||||
PortManager ();
|
||||
virtual ~PortManager() {}
|
||||
|
||||
PortEngine& port_engine();
|
||||
|
||||
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<AudioBackend> _backend;
|
||||
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,15 @@ 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 ();
|
||||
int ensure_engine (uint32_t desired_sample_rate);
|
||||
};
|
||||
|
||||
} // 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;
|
||||
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;
|
||||
|
||||
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 ();
|
||||
|
|
|
|||
|
|
@ -26,10 +26,9 @@
|
|||
#include <boost/shared_ptr.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <jack/types.h>
|
||||
#include <jack/midiport.h>
|
||||
|
||||
#include "timecode/bbt_time.h"
|
||||
#include "timecode/time.h"
|
||||
|
|
@ -53,12 +52,12 @@ namespace ARDOUR {
|
|||
class Route;
|
||||
class Region;
|
||||
|
||||
typedef jack_default_audio_sample_t Sample;
|
||||
typedef float 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 uint32_t pframes_t;
|
||||
|
||||
/* Any position measured in audio frames.
|
||||
Assumed to be non-negative but not enforced.
|
||||
|
|
@ -585,6 +584,42 @@ 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
|
||||
};
|
||||
|
||||
/* PLATFORM SPECIFIC #ifdef's here */
|
||||
|
||||
/** Define the native thread type used on the platform */
|
||||
typedef pthread_t AudioBackendNativeThread;
|
||||
static inline bool self_thread_equal (AudioBackendNativeThread thr) {
|
||||
return pthread_equal (thr, pthread_self());
|
||||
}
|
||||
|
||||
/* PLATFORM SPECIFIC #endif's here */
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
|
||||
|
|
|
|||
44
libs/ardour/ardour/visibility.h
Normal file
44
libs/ardour/ardour/visibility.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
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_visibility_h__
|
||||
#define __libardour_visibility_h__
|
||||
|
||||
/* _WIN32 is defined by most compilers targetting Windows, but within the
|
||||
* ardour source tree, we also define COMPILER_MSVC or COMPILER_MINGW depending
|
||||
* on how a Windows build is built.
|
||||
*/
|
||||
|
||||
#if defined _WIN32 || defined __CYGWIN__ || defined(COMPILER_MSVC) || defined(COMPILER_MINGW)
|
||||
#define LIBARDOUR_HELPER_DLL_IMPORT __declspec(dllimport)
|
||||
#define LIBARDOUR_HELPER_DLL_EXPORT __declspec(dllexport)
|
||||
#define LIBARDOUR_HELPER_DLL_LOCAL
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#define LIBARDOUR_HELPER_DLL_IMPORT __attribute__ ((visibility ("default")))
|
||||
#define LIBARDOUR_HELPER_DLL_EXPORT __attribute__ ((visibility ("default")))
|
||||
#define LIBARDOUR_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define LIBARDOUR_HELPER_DLL_IMPORT
|
||||
#define LIBARDOUR_HELPER_DLL_EXPORT
|
||||
#define LIBARDOUR_HELPER_DLL_LOCAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __libardour_visibility_h__ */
|
||||
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<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 byte * msg, size_t msglen, 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 << " 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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -925,7 +925,7 @@ AudioDiskstream::internal_playback_seek (framecnt_t distance)
|
|||
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||
|
||||
for (chan = c->begin(); chan != c->end(); ++chan) {
|
||||
(*chan)->playback_buf->increment_read_ptr (llabs(distance));
|
||||
(*chan)->playback_buf->increment_read_ptr (std::llabs(distance));
|
||||
}
|
||||
|
||||
if (first_recordable_frame < max_framepos) {
|
||||
|
|
@ -1754,7 +1754,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 ();
|
||||
}
|
||||
|
|
@ -1775,7 +1775,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 ();
|
||||
|
|
@ -2041,12 +2041,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2369,13 +2369,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 */
|
||||
}
|
||||
|
|
@ -315,7 +315,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
|
|||
if (!lm.locked()) {
|
||||
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
|
||||
framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes);
|
||||
if (can_internal_playback_seek(llabs(playback_distance))) {
|
||||
if (can_internal_playback_seek(std::llabs(playback_distance))) {
|
||||
/* TODO should declick */
|
||||
internal_playback_seek(playback_distance);
|
||||
}
|
||||
|
|
|
|||
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,30 +443,29 @@ 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);
|
||||
|
||||
if (pm.connected (ports[j])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
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