fix merge conflicts with master

This commit is contained in:
Paul Davis 2013-09-14 16:42:40 -04:00
commit 7a30e63eaa
213 changed files with 29641 additions and 21838 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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'/>

View file

@ -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@"

View file

@ -1011,3 +1011,8 @@ style "meter_strip_sep" = "default"
{
bg[NORMAL] = { 0.0, 0.0, 0.0 }
}
style "settings_notebook" = "big_text"
{
}

View file

@ -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;
}
}

View file

@ -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__ */

View file

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

View file

@ -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 ();
}

View file

@ -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 "$@"

View file

@ -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());

View file

@ -962,7 +962,5 @@ void *
Editor::import_thread ()
{
_session->import_files (import_status);
pthread_exit_pbd (0);
/*NOTREACHED*/
return 0;
}

View file

@ -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);

View file

@ -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

View file

@ -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__ */

View file

@ -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());

View file

@ -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 ();

View file

@ -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);

View file

@ -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"

View file

@ -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;
}

View file

@ -23,7 +23,6 @@
#include <gtkmm2ext/utils.h>
#include <gtkmm2ext/barcontroller.h>
#include "midi++/manager.h"
#include "pbd/fastlog.h"
#include "ardour_ui.h"

View file

@ -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

View file

@ -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();
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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());

View file

@ -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;

View file

@ -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:

View file

@ -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;

View file

@ -21,7 +21,6 @@
#include <gtkmm2ext/utils.h>
#include <gtkmm2ext/barcontroller.h>
#include "midi++/manager.h"
#include "pbd/fastlog.h"
#include "ardour/pannable.h"

View file

@ -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"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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) {

View file

@ -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"));

View file

@ -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 ..."));

View file

@ -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"));

View file

@ -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());

View file

@ -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

View file

@ -113,6 +113,10 @@ SendUI::update ()
void
SendUI::fast_update ()
{
if (!is_mapped()) {
return;
}
if (Config->get_meter_falloff() > 0.0f) {
_gpm.update_meters ();
}

View file

@ -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) {

View file

@ -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 ();

View file

@ -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;
}

View file

@ -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;

View file

@ -410,7 +410,7 @@ ProxyBase::hide ()
}
bool
ProxyBase::handle_win_event (GdkEventAny *ev)
ProxyBase::handle_win_event (GdkEventAny* /*ev*/)
{
hide();
return true;

View file

@ -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',

View file

@ -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();

View file

@ -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__ */

View 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__ */

View file

@ -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 */

View file

@ -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:

View file

@ -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

View 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__ */

View file

@ -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

View file

@ -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__

View file

@ -63,6 +63,7 @@ namespace PBD {
extern uint64_t OrderKeys;
extern uint64_t Automation;
extern uint64_t WiimoteControl;
extern uint64_t Ports;
}
}

View file

@ -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;
};

View file

@ -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 ();

View file

@ -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,

View file

@ -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 ();

View file

@ -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;

View file

@ -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);

View file

@ -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; }

View file

@ -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

View file

@ -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 ();

View 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__

View file

@ -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;

View 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__ */

View 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__ */

View file

@ -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;

View file

@ -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 */

View file

@ -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

View file

@ -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;
};

View file

@ -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__ */

View file

@ -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 ();

View file

@ -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

View 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__ */

View 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);
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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

View 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

View file

@ -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 ());

View file

@ -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