mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
new transport slave/master implementation, gui edition
This commit is contained in:
parent
e6915e01de
commit
db385c2e3c
16 changed files with 655 additions and 167 deletions
|
|
@ -556,6 +556,7 @@
|
|||
#endif
|
||||
<menuitem action='toggle-big-clock'/>
|
||||
<menuitem action='toggle-big-transport'/>
|
||||
<menuitem action='toggle-transport-masters'/>
|
||||
#if 0
|
||||
<menuitem action='toggle-speaker-config'/>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@
|
|||
#include "ardour/session_state_utils.h"
|
||||
#include "ardour/session_utils.h"
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/slave.h"
|
||||
#include "ardour/transport_master.h"
|
||||
#include "ardour/transport_master_manager.h"
|
||||
#include "ardour/system_exec.h"
|
||||
#include "ardour/track.h"
|
||||
#include "ardour/vca_manager.h"
|
||||
|
|
@ -185,6 +186,7 @@ typedef uint64_t microseconds_t;
|
|||
#include "time_axis_view_item.h"
|
||||
#include "time_info_box.h"
|
||||
#include "timers.h"
|
||||
#include "transport_masters_dialog.h"
|
||||
#include "utils.h"
|
||||
#include "utils_videotl.h"
|
||||
#include "video_server_dialog.h"
|
||||
|
|
@ -314,6 +316,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
, export_video_dialog (X_("video-export"), _("Video Export Dialog"))
|
||||
, lua_script_window (X_("script-manager"), _("Script Manager"))
|
||||
, idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
|
||||
, transport_masters_dialog (X_("transport-masters"), _("Transport Masters"))
|
||||
, session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
|
||||
, add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
|
||||
, bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
|
||||
|
|
@ -473,6 +476,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
export_video_dialog.set_state (*ui_xml, 0);
|
||||
lua_script_window.set_state (*ui_xml, 0);
|
||||
idleometer.set_state (*ui_xml, 0);
|
||||
transport_masters_dialog.set_state (*ui_xml, 0);
|
||||
}
|
||||
|
||||
/* Separate windows */
|
||||
|
|
@ -494,6 +498,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||
WM::Manager::instance().register_window (&audio_port_matrix);
|
||||
WM::Manager::instance().register_window (&midi_port_matrix);
|
||||
WM::Manager::instance().register_window (&idleometer);
|
||||
WM::Manager::instance().register_window (&transport_masters_dialog);
|
||||
|
||||
/* do not retain position for add route dialog */
|
||||
add_route_dialog.set_state_mask (WindowProxy::Size);
|
||||
|
|
@ -1801,11 +1806,11 @@ ARDOUR_UI::update_timecode_format ()
|
|||
|
||||
if (_session) {
|
||||
bool matching;
|
||||
TimecodeSlave* tcslave;
|
||||
SyncSource sync_src = Config->get_sync_source();
|
||||
boost::shared_ptr<TimecodeTransportMaster> tcmaster;
|
||||
boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
|
||||
|
||||
if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
|
||||
matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
|
||||
if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
|
||||
matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
|
||||
} else {
|
||||
matching = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@
|
|||
#include "route_params_ui.h"
|
||||
#include "session_option_editor.h"
|
||||
#include "speaker_dialog.h"
|
||||
#include "transport_masters_dialog.h"
|
||||
#else
|
||||
class About;
|
||||
class AddRouteDialog;
|
||||
|
|
@ -119,6 +120,7 @@ class SessionOptionEditor;
|
|||
class SpeakerDialog;
|
||||
class GlobalPortMatrixWindow;
|
||||
class IdleOMeter;
|
||||
class TransportMastersDialog;
|
||||
#endif
|
||||
|
||||
class VideoTimeLine;
|
||||
|
|
@ -680,6 +682,7 @@ private:
|
|||
WM::Proxy<ExportVideoDialog> export_video_dialog;
|
||||
WM::Proxy<LuaScriptManager> lua_script_window;
|
||||
WM::Proxy<IdleOMeter> idleometer;
|
||||
WM::Proxy<TransportMastersDialog> transport_masters_dialog;
|
||||
|
||||
/* Windows/Dialogs that require a creator method */
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
#include "sfdb_ui.h"
|
||||
#include "time_info_box.h"
|
||||
#include "timers.h"
|
||||
#include "transport_masters_dialog.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
|
|
@ -127,6 +128,8 @@ ARDOUR_UI::set_session (Session *s)
|
|||
big_clock->set_session (s);
|
||||
video_timeline->set_session (s);
|
||||
lua_script_window->set_session (s);
|
||||
transport_masters_dialog->set_session (s);
|
||||
rc_option_editor->set_session (s);
|
||||
|
||||
/* sensitize menu bar options that are now valid */
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ when the pull up/down setting is non-zero."));
|
|||
* This is a UI limitation, imposed by audio-clock and
|
||||
* status displays which combine RC-config & session-properties.
|
||||
*
|
||||
* Notficy RCOptionEditor by emitting a signal if the active
|
||||
* Notify RCOptionEditor by emitting a signal if the active
|
||||
* status changed:
|
||||
*/
|
||||
Config->ParameterChanged("sync-source");
|
||||
|
|
@ -349,6 +349,8 @@ ARDOUR_UI::parameter_changed (std::string p)
|
|||
{
|
||||
if (p == "external-sync") {
|
||||
|
||||
/* session parameter */
|
||||
|
||||
ActionManager::map_some_state ("Transport", "ToggleExternalSync", sigc::mem_fun (_session->config, &SessionConfiguration::get_external_sync));
|
||||
|
||||
if (!_session->config.get_external_sync()) {
|
||||
|
|
@ -357,19 +359,27 @@ ARDOUR_UI::parameter_changed (std::string p)
|
|||
ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (true);
|
||||
ActionManager::get_action ("Transport", "ToggleFollowEdits")->set_sensitive (true);
|
||||
} else {
|
||||
sync_button.set_text (sync_source_to_string (Config->get_sync_source(), true));
|
||||
if (_session && _session->locations()->auto_loop_location()) {
|
||||
// disable looping with external sync.
|
||||
// This is not necessary because session-transport ignores the loop-state,
|
||||
// but makes it clear to the user that it's disabled.
|
||||
_session->request_play_loop (false, false);
|
||||
}
|
||||
/* XXX we need to make sure that auto-play is off as well as insensitive */
|
||||
ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (false);
|
||||
ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (false);
|
||||
ActionManager::get_action ("Transport", "ToggleFollowEdits")->set_sensitive (false);
|
||||
}
|
||||
|
||||
} else if (p == "sync-source") {
|
||||
|
||||
/* app parameter (RC config) */
|
||||
|
||||
if (_session) {
|
||||
if (!_session->config.get_external_sync()) {
|
||||
sync_button.set_text (S_("SyncSource|Int."));
|
||||
} else {
|
||||
sync_button.set_text (sync_source_to_string (Config->get_sync_source(), true));
|
||||
}
|
||||
} else {
|
||||
/* changing sync source without a session is unlikely/impossible , except during startup */
|
||||
sync_button.set_text (sync_source_to_string (Config->get_sync_source(), true));
|
||||
}
|
||||
|
||||
} else if (p == "follow-edits") {
|
||||
|
||||
ActionManager::map_some_state ("Transport", "ToggleFollowEdits", &UIConfiguration::get_follow_edits);
|
||||
|
|
@ -598,4 +608,3 @@ ARDOUR_UI::synchronize_sync_source_and_video_pullup ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include "ardour/profile.h"
|
||||
#include "ardour/lmath.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/slave.h"
|
||||
#include "ardour/transport_master.h"
|
||||
#include "ardour/tempo.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
|
|
@ -938,20 +938,21 @@ AudioClock::set_slave_info ()
|
|||
return;
|
||||
}
|
||||
|
||||
SyncSource sync_src = Config->get_sync_source();
|
||||
const SyncSource sync_src = Config->get_sync_source();
|
||||
|
||||
if (_session->config.get_external_sync()) {
|
||||
Slave* slave = _session->slave();
|
||||
if (_session->transport_master_is_external()) {
|
||||
|
||||
switch (sync_src) {
|
||||
boost::shared_ptr<TransportMaster> tm = _session->transport_master();
|
||||
|
||||
switch (tm->type()) {
|
||||
case Engine:
|
||||
_left_btn.set_text (sync_source_to_string (sync_src, true), true);
|
||||
_left_btn.set_text (tm->name(), true);
|
||||
_right_btn.set_text ("", true);
|
||||
break;
|
||||
case MIDIClock:
|
||||
if (slave) {
|
||||
_left_btn.set_text (sync_source_to_string (sync_src, true), true);
|
||||
_right_btn.set_text (slave->approximate_current_delta (), true);
|
||||
if (tm) {
|
||||
_left_btn.set_text (sync_source_to_string (tm->type(), true), true);
|
||||
_right_btn.set_text (tm->delta_string (), true);
|
||||
} else {
|
||||
_left_btn.set_text (_("--pending--"), true);
|
||||
_right_btn.set_text ("", true);
|
||||
|
|
@ -959,17 +960,17 @@ AudioClock::set_slave_info ()
|
|||
break;
|
||||
case LTC:
|
||||
case MTC:
|
||||
if (slave) {
|
||||
if (tm) {
|
||||
bool matching;
|
||||
TimecodeSlave* tcslave;
|
||||
if ((tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
|
||||
matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
|
||||
boost::shared_ptr<TimecodeTransportMaster> tcmaster;
|
||||
if ((tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
|
||||
matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
|
||||
_left_btn.set_text (string_compose ("%1<span face=\"monospace\" foreground=\"%3\">%2</span>",
|
||||
sync_source_to_string(sync_src, true)[0],
|
||||
dynamic_cast<TimecodeSlave*>(slave)->approximate_current_position (),
|
||||
sync_source_to_string(tm->type(), true)[0],
|
||||
tcmaster->position_string (),
|
||||
matching ? "#66ff66" : "#ff3333"
|
||||
), true);
|
||||
_right_btn.set_text (slave->approximate_current_delta (), true);
|
||||
_right_btn.set_text (tm->delta_string (), true);
|
||||
}
|
||||
} else {
|
||||
_left_btn.set_text (_("--pending--"), true);
|
||||
|
|
@ -978,8 +979,7 @@ AudioClock::set_slave_info ()
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
_left_btn.set_text (string_compose ("%1/%2",
|
||||
_("INT"), sync_source_to_string(sync_src, true)), true);
|
||||
_left_btn.set_text (string_compose ("%1/%2", _("INT"), sync_source_to_string (sync_src, true)), true);
|
||||
_right_btn.set_text ("", true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ MidiTracer::MidiTracer ()
|
|||
, line_count_adjustment (200, 1, 2000, 1, 10)
|
||||
, line_count_spinner (line_count_adjustment)
|
||||
, line_count_label (_("Line history: "))
|
||||
, _last_receipt (0)
|
||||
, autoscroll (true)
|
||||
, show_hex (true)
|
||||
, show_delta_time (false)
|
||||
|
|
@ -60,9 +61,6 @@ MidiTracer::MidiTracer ()
|
|||
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;
|
||||
|
||||
VBox* vbox = manage (new VBox);
|
||||
vbox->set_spacing (4);
|
||||
|
||||
|
|
@ -121,7 +119,6 @@ MidiTracer::MidiTracer ()
|
|||
port_changed ();
|
||||
}
|
||||
|
||||
|
||||
MidiTracer::~MidiTracer()
|
||||
{
|
||||
}
|
||||
|
|
@ -178,13 +175,13 @@ MidiTracer::port_changed ()
|
|||
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));
|
||||
mp->set_trace_on (true);
|
||||
my_parser.any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3, _4));
|
||||
mp->set_trace (&my_parser);
|
||||
traced_port = mp;
|
||||
}
|
||||
|
||||
} else {
|
||||
async->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3));
|
||||
async->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3, _4));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,40 +191,33 @@ MidiTracer::disconnect ()
|
|||
_parser_connection.disconnect ();
|
||||
|
||||
if (traced_port) {
|
||||
traced_port->set_trace_on (false);
|
||||
traced_port->set_trace (0);
|
||||
traced_port.reset ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiTracer::tracer (Parser&, byte* msg, size_t len)
|
||||
MidiTracer::tracer (Parser&, byte* msg, size_t len, samplecnt_t now)
|
||||
{
|
||||
stringstream ss;
|
||||
struct timeval tv;
|
||||
char* buf;
|
||||
struct tm now;
|
||||
size_t bufsize;
|
||||
size_t s;
|
||||
|
||||
gettimeofday (&tv, 0);
|
||||
std::cerr << "tracer msg " << len << " bytes, first = " << hex << (int) msg[0] << dec << std::endl;
|
||||
|
||||
buf = (char *) buffer_pool.alloc ();
|
||||
bufsize = buffer_size;
|
||||
|
||||
if (_last_receipt.tv_sec != 0 && show_delta_time) {
|
||||
struct timeval delta;
|
||||
timersub (&tv, &_last_receipt, &delta);
|
||||
s = snprintf (buf, bufsize, "+%02" PRId64 ":%06" PRId64, (int64_t) delta.tv_sec, (int64_t) delta.tv_usec);
|
||||
if (_last_receipt != 0 && show_delta_time) {
|
||||
s = snprintf (buf, bufsize, "+%12ld", now - _last_receipt);
|
||||
bufsize -= s;
|
||||
} else {
|
||||
localtime_r ((const time_t*)&tv.tv_sec, &now);
|
||||
s = strftime (buf, bufsize, "%H:%M:%S", &now);
|
||||
bufsize -= s;
|
||||
s += snprintf (&buf[s], bufsize, ".%06" PRId64, (int64_t) tv.tv_usec);
|
||||
s = snprintf (buf, bufsize, "%12ld", now);
|
||||
bufsize -= s;
|
||||
}
|
||||
|
||||
_last_receipt = tv;
|
||||
_last_receipt = now;
|
||||
|
||||
switch ((eventType) msg[0]&0xf0) {
|
||||
case off:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ private:
|
|||
Gtk::SpinButton line_count_spinner;
|
||||
Gtk::Label line_count_label;
|
||||
Gtk::HBox line_count_box;
|
||||
struct timeval _last_receipt;
|
||||
MIDI::samplecnt_t _last_receipt;
|
||||
|
||||
bool autoscroll;
|
||||
bool show_hex;
|
||||
|
|
@ -72,7 +72,7 @@ private:
|
|||
Pool buffer_pool;
|
||||
static const size_t buffer_size = 256;
|
||||
|
||||
void tracer (MIDI::Parser&, MIDI::byte*, size_t);
|
||||
void tracer (MIDI::Parser&, MIDI::byte*, size_t, MIDI::samplecnt_t);
|
||||
void update ();
|
||||
|
||||
Gtk::CheckButton autoscroll_button;
|
||||
|
|
@ -91,6 +91,7 @@ private:
|
|||
void disconnect ();
|
||||
PBD::ScopedConnection _parser_connection;
|
||||
PBD::ScopedConnection _manager_connection;
|
||||
MIDI::Parser my_parser;
|
||||
|
||||
boost::shared_ptr<ARDOUR::MidiPort> traced_port;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -608,6 +608,20 @@ ClockOption::set_session (Session* s)
|
|||
|
||||
/*--------------------------*/
|
||||
|
||||
WidgetOption::WidgetOption (string const & i, string const & n, Gtk::Widget& w)
|
||||
: Option (i, n)
|
||||
, _widget (&w)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
WidgetOption::add_to_page (OptionEditorPage* p)
|
||||
{
|
||||
add_widget_to_page (p, _widget);
|
||||
}
|
||||
|
||||
/*--------------------------*/
|
||||
|
||||
OptionEditorPage::OptionEditorPage ()
|
||||
: table (1, 3)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -558,6 +558,21 @@ private:
|
|||
sigc::slot<bool, ARDOUR::gain_t> _set;
|
||||
};
|
||||
|
||||
class WidgetOption : public Option
|
||||
{
|
||||
public:
|
||||
WidgetOption (std::string const & i, std::string const & n, Gtk::Widget& w);
|
||||
|
||||
void add_to_page (OptionEditorPage*);
|
||||
void parameter_changed (std::string const &) {}
|
||||
void set_state_from_config () {}
|
||||
|
||||
Gtk::Widget& tip_widget() { return *_widget; }
|
||||
|
||||
private:
|
||||
Gtk::Widget* _widget;
|
||||
};
|
||||
|
||||
class ClockOption : public Option
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -436,9 +436,10 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
ltc->add_channel (_("LTC Out"), DataType::AUDIO, session->engine().make_port_name_non_relative (session->ltc_output_port()->name()));
|
||||
program->add_bundle (ltc);
|
||||
} else {
|
||||
boost::shared_ptr<Bundle> ltc (new Bundle (_("LTC In"), inputs));
|
||||
ltc->add_channel (_("LTC In"), DataType::AUDIO, session->engine().make_port_name_non_relative (session->ltc_input_port()->name()));
|
||||
program->add_bundle (ltc);
|
||||
// XXX TRANSPORTMASTERS
|
||||
//boost::shared_ptr<Bundle> ltc (new Bundle (_("LTC In"), inputs));
|
||||
// ltc->add_channel (_("LTC In"), DataType::AUDIO, session->engine().make_port_name_non_relative (session->ltc_input_port()->name()));
|
||||
// program->add_bundle (ltc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -470,12 +471,13 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
|
|||
AudioEngine* ae = AudioEngine::instance();
|
||||
|
||||
if (inputs) {
|
||||
sync->add_channel (
|
||||
_("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (session->mtc_input_port()->name())
|
||||
);
|
||||
sync->add_channel (
|
||||
_("MIDI clock in"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_clock_input_port()->name())
|
||||
);
|
||||
// XXX TRANSPORTMASTER
|
||||
// sync->add_channel (
|
||||
// _("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (session->mtc_input_port()->name())
|
||||
// );
|
||||
// sync->add_channel (
|
||||
// _("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 (session->mmc_input_port()->name())
|
||||
);
|
||||
|
|
|
|||
|
|
@ -43,12 +43,14 @@
|
|||
|
||||
#include "ardour/audio_backend.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/dB.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/dB.h"
|
||||
#include "ardour/port_manager.h"
|
||||
#include "ardour/plugin_manager.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/transport_master_manager.h"
|
||||
|
||||
#include "control_protocol/control_protocol.h"
|
||||
|
||||
#include "waveview/wave_view.h"
|
||||
|
|
@ -66,6 +68,7 @@
|
|||
#include "midi_tracer.h"
|
||||
#include "rc_option_editor.h"
|
||||
#include "sfdb_ui.h"
|
||||
#include "transport_masters_dialog.h"
|
||||
#include "ui_config.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
@ -2109,14 +2112,7 @@ MidiPortOptions::pretty_name_edit (std::string const & path, string const & new_
|
|||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
|
||||
if (backend) {
|
||||
ARDOUR::PortEngine::PortHandle ph = backend->get_port_by_name ((*iter)[midi_port_columns.name]);
|
||||
if (ph) {
|
||||
backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", new_text, "");
|
||||
(*iter)[midi_port_columns.pretty_name] = new_text;
|
||||
}
|
||||
}
|
||||
AudioEngine::instance()->set_midi_port_pretty_name ((*iter)[midi_port_columns.name], new_text);
|
||||
}
|
||||
|
||||
/*============*/
|
||||
|
|
@ -3213,16 +3209,9 @@ RCOptionEditor::RCOptionEditor ()
|
|||
|
||||
/* SYNC */
|
||||
|
||||
add_option (_("Sync"), new OptionEditorHeading (_("External Synchronization")));
|
||||
add_option (_("Sync"), new OptionEditorHeading (_("Transport Masters")));
|
||||
|
||||
_sync_source = new ComboOption<SyncSource> (
|
||||
"sync-source",
|
||||
_("External timecode source"),
|
||||
sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
|
||||
sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
|
||||
);
|
||||
|
||||
add_option (_("Sync"), _sync_source);
|
||||
add_option (_("Sync"), new WidgetOption (X_("foo"), X_("Transport Masters"), _transport_masters_widget));
|
||||
|
||||
_sync_framerate = new BoolOption (
|
||||
"timecode-sync-frame-rate",
|
||||
|
|
@ -3240,45 +3229,6 @@ RCOptionEditor::RCOptionEditor ()
|
|||
|
||||
add_option (_("Sync"), _sync_framerate);
|
||||
|
||||
_sync_genlock = new BoolOption (
|
||||
"timecode-source-is-synced",
|
||||
_("Sync-lock timecode to clock (disable drift compensation)"),
|
||||
sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
|
||||
sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
|
||||
);
|
||||
Gtkmm2ext::UI::instance()->set_tip
|
||||
(_sync_genlock->tip_widget(),
|
||||
string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
|
||||
"Sync Lock indicates that the selected external timecode source shares clock-sync "
|
||||
"(Black & Burst, Wordclock, etc) with the audio interface. "
|
||||
"This option disables drift compensation. The transport speed is fixed at 1.0. "
|
||||
"Vari-speed LTC will be ignored and cause drift."
|
||||
"\n\n"
|
||||
"<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
|
||||
"timecode sources shares clock sync."
|
||||
), PROGRAM_NAME));
|
||||
|
||||
|
||||
add_option (_("Sync"), _sync_genlock);
|
||||
|
||||
_sync_source_2997 = new BoolOption (
|
||||
"timecode-source-2997",
|
||||
_("Lock to 29.9700 fps instead of 30000/1001"),
|
||||
sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
|
||||
sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
|
||||
);
|
||||
Gtkmm2ext::UI::instance()->set_tip
|
||||
(_sync_source_2997->tip_widget(),
|
||||
_("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
|
||||
"SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
|
||||
"drop-sample timecode has an accumulated error of -86ms over a 24-hour period.\n"
|
||||
"Drop-sample timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
|
||||
"That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
|
||||
"because the variant of using exactly 29.97 fps has zero timecode drift.\n"
|
||||
));
|
||||
|
||||
add_option (_("Sync"), _sync_source_2997);
|
||||
|
||||
add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Reader")));
|
||||
|
||||
_ltc_port = new ComboStringOption (
|
||||
|
|
@ -3293,9 +3243,6 @@ RCOptionEditor::RCOptionEditor ()
|
|||
AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
|
||||
_ltc_port->set_popdown_strings (physical_inputs);
|
||||
|
||||
populate_sync_options ();
|
||||
AudioEngine::instance()->Running.connect (engine_started_connection, MISSING_INVALIDATOR, boost::bind (&RCOptionEditor::populate_sync_options, this), gui_context());
|
||||
|
||||
add_option (_("Sync/LTC"), _ltc_port);
|
||||
|
||||
add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Generator")));
|
||||
|
|
@ -4058,6 +4005,13 @@ These settings will only take effect after %1 is restarted.\n\
|
|||
set_current_page (_("General"));
|
||||
}
|
||||
|
||||
void
|
||||
RCOptionEditor::set_session (Session *s)
|
||||
{
|
||||
SessionHandlePtr::set_session (s);
|
||||
_transport_masters_widget.set_session (s);
|
||||
}
|
||||
|
||||
void
|
||||
RCOptionEditor::parameter_changed (string const & p)
|
||||
{
|
||||
|
|
@ -4072,22 +4026,11 @@ RCOptionEditor::parameter_changed (string const & p)
|
|||
_solo_control_is_listen_control->set_sensitive (s);
|
||||
_listen_position->set_sensitive (s);
|
||||
} else if (p == "sync-source") {
|
||||
_sync_source->set_sensitive (true);
|
||||
if (_session) {
|
||||
_sync_source->set_sensitive (!_session->config.get_external_sync());
|
||||
}
|
||||
switch(Config->get_sync_source()) {
|
||||
case ARDOUR::MTC:
|
||||
case ARDOUR::LTC:
|
||||
_sync_genlock->set_sensitive (true);
|
||||
boost::shared_ptr<TransportMaster> tm (TransportMasterManager::instance().current());
|
||||
if (boost::dynamic_pointer_cast<TimecodeTransportMaster> (tm)) {
|
||||
_sync_framerate->set_sensitive (true);
|
||||
_sync_source_2997->set_sensitive (true);
|
||||
break;
|
||||
default:
|
||||
_sync_genlock->set_sensitive (false);
|
||||
} else {
|
||||
_sync_framerate->set_sensitive (false);
|
||||
_sync_source_2997->set_sensitive (false);
|
||||
break;
|
||||
}
|
||||
} else if (p == "send-ltc") {
|
||||
bool const s = Config->get_send_ltc ();
|
||||
|
|
@ -4164,29 +4107,6 @@ void RCOptionEditor::edit_vst_path () {
|
|||
delete pd;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RCOptionEditor::populate_sync_options ()
|
||||
{
|
||||
vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
|
||||
|
||||
_sync_source->clear ();
|
||||
|
||||
for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
|
||||
_sync_source->add (*i, sync_source_to_string (*i));
|
||||
}
|
||||
|
||||
if (sync_opts.empty()) {
|
||||
_sync_source->set_sensitive(false);
|
||||
} else {
|
||||
if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
|
||||
_rc_config->set_sync_source(sync_opts.front());
|
||||
}
|
||||
}
|
||||
|
||||
parameter_changed ("sync-source");
|
||||
}
|
||||
|
||||
Gtk::Window*
|
||||
RCOptionEditor::use_own_window (bool and_fill_it)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "option_editor.h"
|
||||
#include "visibility_group.h"
|
||||
#include "transport_masters_dialog.h"
|
||||
|
||||
/** @file rc_option_editor.h
|
||||
* @brief Editing of options which are obtained from and written back to one of the .rc files.
|
||||
|
|
@ -39,7 +40,7 @@ class RCOptionEditor : public OptionEditorContainer, public ARDOUR::SessionHandl
|
|||
public:
|
||||
RCOptionEditor ();
|
||||
|
||||
void populate_sync_options ();
|
||||
void set_session (ARDOUR::Session*);
|
||||
|
||||
Gtk::Window* use_own_window (bool and_fill_it);
|
||||
XMLNode& get_state ();
|
||||
|
|
@ -53,13 +54,12 @@ private:
|
|||
VisibilityGroup _mixer_strip_visibility;
|
||||
ComboOption<ARDOUR::SyncSource>* _sync_source;
|
||||
BoolOption* _sync_framerate;
|
||||
BoolOption* _sync_genlock;
|
||||
BoolOption* _sync_source_2997;
|
||||
ComboStringOption* _ltc_port;
|
||||
HSliderOption* _ltc_volume_slider;
|
||||
Gtk::Adjustment* _ltc_volume_adjustment;
|
||||
BoolOption* _ltc_send_continuously;
|
||||
BoolOption* _plugin_prefer_inline;
|
||||
TransportMastersWidget _transport_masters_widget;
|
||||
|
||||
PBD::ScopedConnection parameter_change_connection;
|
||||
PBD::ScopedConnection engine_started_connection;
|
||||
|
|
|
|||
395
gtk2_ardour/transport_masters_dialog.cc
Normal file
395
gtk2_ardour/transport_masters_dialog.cc
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
Copyright (C) 2018 Paul Davis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "pbd/enumwriter.h"
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
#include "temporal/time.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/transport_master.h"
|
||||
#include "ardour/transport_master_manager.h"
|
||||
|
||||
#include "widgets/tooltips.h"
|
||||
|
||||
#include "gtkmm2ext/utils.h"
|
||||
#include "gtkmm2ext/gui_thread.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "transport_masters_dialog.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Gtk;
|
||||
using namespace Gtkmm2ext;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace ArdourWidgets;
|
||||
|
||||
TransportMastersWidget::TransportMastersWidget ()
|
||||
: table (4, 9)
|
||||
{
|
||||
pack_start (table, PACK_EXPAND_WIDGET, 12);
|
||||
|
||||
col_title[0].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Name")));
|
||||
col_title[0].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Name")));
|
||||
col_title[1].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Type")));
|
||||
col_title[2].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Format")));
|
||||
col_title[3].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Current")));
|
||||
col_title[4].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Timestamp")));
|
||||
col_title[5].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Delta")));
|
||||
col_title[6].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Collect")));
|
||||
col_title[7].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Use")));
|
||||
col_title[8].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Data Source")));
|
||||
col_title[9].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Accept")));
|
||||
col_title[10].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Clock Synced")));
|
||||
col_title[11].set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("29.97/30")));
|
||||
|
||||
set_tooltip (col_title[11], _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
|
||||
"SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
|
||||
"drop-sample timecode has an accumulated error of -86ms over a 24-hour period.\n"
|
||||
"Drop-sample timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
|
||||
"That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
|
||||
"because the variant of using exactly 29.97 fps has zero timecode drift.\n"
|
||||
));
|
||||
|
||||
|
||||
table.set_spacings (6);
|
||||
|
||||
TransportMasterManager::instance().CurrentChanged.connect (current_connection, invalidator (*this), boost::bind (&TransportMastersWidget::current_changed, this, _1, _2), gui_context());
|
||||
|
||||
rebuild ();
|
||||
}
|
||||
|
||||
TransportMastersWidget::~TransportMastersWidget ()
|
||||
{
|
||||
for (vector<Row*>::iterator r = rows.begin(); r != rows.end(); ++r) {
|
||||
delete *r;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::current_changed (boost::shared_ptr<TransportMaster> old_master, boost::shared_ptr<TransportMaster> new_master)
|
||||
{
|
||||
cerr << "master changed to " << new_master << endl;
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::rebuild ()
|
||||
{
|
||||
TransportMasterManager::TransportMasters const & masters (TransportMasterManager::instance().transport_masters());
|
||||
|
||||
container_clear (table);
|
||||
|
||||
for (vector<Row*>::iterator r = rows.begin(); r != rows.end(); ++r) {
|
||||
delete *r;
|
||||
}
|
||||
|
||||
rows.clear ();
|
||||
table.resize (masters.size()+1, 12);
|
||||
|
||||
table.attach (col_title[0], 0, 1, 0, 1);
|
||||
table.attach (col_title[1], 1, 2, 0, 1);
|
||||
table.attach (col_title[2], 2, 3, 0, 1);
|
||||
table.attach (col_title[3], 3, 4, 0, 1);
|
||||
table.attach (col_title[4], 4, 5, 0, 1);
|
||||
table.attach (col_title[5], 5, 6, 0, 1);
|
||||
table.attach (col_title[6], 6, 7, 0, 1);
|
||||
table.attach (col_title[7], 7, 8, 0, 1);
|
||||
table.attach (col_title[8], 8, 9, 0, 1);
|
||||
table.attach (col_title[9], 9, 10, 0, 1);
|
||||
table.attach (col_title[10], 10, 11, 0, 1);
|
||||
table.attach (col_title[11], 11, 12, 0, 1);
|
||||
|
||||
uint32_t n = 1;
|
||||
|
||||
for (TransportMasterManager::TransportMasters::const_iterator m = masters.begin(); m != masters.end(); ++m, ++n) {
|
||||
|
||||
Row* r = new Row;
|
||||
rows.push_back (r);
|
||||
|
||||
r->tm = *m;
|
||||
r->label.set_text ((*m)->name());
|
||||
r->type.set_text (enum_2_string ((*m)->type()));
|
||||
|
||||
r->use_button.set_group (use_button_group);
|
||||
|
||||
if (TransportMasterManager::instance().current() == r->tm) {
|
||||
r->use_button.set_active (true);
|
||||
}
|
||||
|
||||
table.attach (r->type, 0, 1, n, n+1);
|
||||
table.attach (r->label, 1, 2, n, n+1);
|
||||
table.attach (r->format, 2, 3, n, n+1);
|
||||
table.attach (r->current, 3, 4, n, n+1);
|
||||
table.attach (r->timestamp, 4, 5, n, n+1);
|
||||
table.attach (r->delta, 5, 6, n, n+1);
|
||||
table.attach (r->collect_button, 6, 7, n, n+1);
|
||||
table.attach (r->use_button, 7, 8, n, n+1);
|
||||
table.attach (r->port_combo, 8, 9, n, n+1);
|
||||
table.attach (r->request_options, 9, 10, n, n+1);
|
||||
|
||||
if (boost::dynamic_pointer_cast<TimecodeTransportMaster> (r->tm)) {
|
||||
table.attach (r->sclock_synced_button, 10, 11, n, n+1);
|
||||
r->sclock_synced_button.set_active (r->tm->sample_clock_synced());
|
||||
r->sclock_synced_button.signal_toggled().connect (sigc::mem_fun (*r, &TransportMastersWidget::Row::sync_button_toggled));
|
||||
table.attach (r->fps_299730_button, 11, 12, n, n+1);
|
||||
}
|
||||
|
||||
r->port_combo.signal_changed().connect (sigc::mem_fun (*r, &TransportMastersWidget::Row::port_choice_changed));
|
||||
ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (*r, invalidator (*this), boost::bind (&TransportMastersWidget::Row::connection_handler, r), gui_context());
|
||||
|
||||
r->collect_button.set_active (r->tm->collect());
|
||||
|
||||
r->use_button.signal_toggled().connect (sigc::mem_fun (*r, &TransportMastersWidget::Row::use_button_toggled));
|
||||
r->collect_button.signal_toggled().connect (sigc::mem_fun (*r, &TransportMastersWidget::Row::collect_button_toggled));
|
||||
r->request_options.signal_button_press_event().connect (sigc::mem_fun (*r, &TransportMastersWidget::Row::request_option_press), false);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TransportMastersWidget::Row::Row ()
|
||||
: request_option_menu (0)
|
||||
, ignore_active_change (false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::use_button_toggled ()
|
||||
{
|
||||
if (use_button.get_active()) {
|
||||
Config->set_sync_source (tm->type());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::collect_button_toggled ()
|
||||
{
|
||||
tm->set_collect (collect_button.get_active());
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::sync_button_toggled ()
|
||||
{
|
||||
tm->set_sample_clock_synced (sclock_synced_button.get_active());
|
||||
}
|
||||
|
||||
bool
|
||||
TransportMastersWidget::Row::request_option_press (GdkEventButton* ev)
|
||||
{
|
||||
if (ev->button == 1) {
|
||||
if (!request_option_menu) {
|
||||
build_request_options ();
|
||||
}
|
||||
request_option_menu->popup (1, ev->time);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::build_request_options ()
|
||||
{
|
||||
using namespace Gtk::Menu_Helpers;
|
||||
|
||||
request_option_menu = manage (new Menu);
|
||||
|
||||
MenuList& items (request_option_menu->items());
|
||||
|
||||
items.push_back (CheckMenuElem (_("Accept speed-changing commands (start/stop)")));
|
||||
CheckMenuItem* i = dynamic_cast<CheckMenuItem *> (&items.back ());
|
||||
i->set_active (tm->request_mask() & TR_Speed);
|
||||
items.push_back (CheckMenuElem (_("Accept locate commands")));
|
||||
i = dynamic_cast<CheckMenuItem *> (&items.back ());
|
||||
i->set_active (tm->request_mask() & TR_Locate);
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::connection_handler ()
|
||||
{
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore>
|
||||
TransportMastersWidget::Row::build_port_list (vector<string> const & ports)
|
||||
{
|
||||
Glib::RefPtr<Gtk::ListStore> store = ListStore::create (port_columns);
|
||||
TreeModel::Row row;
|
||||
|
||||
row = *store->append ();
|
||||
row[port_columns.full_name] = string();
|
||||
row[port_columns.short_name] = _("Disconnected");
|
||||
|
||||
for (vector<string>::const_iterator p = ports.begin(); p != ports.end(); ++p) {
|
||||
|
||||
if (AudioEngine::instance()->port_is_mine (*p)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
row = *store->append ();
|
||||
row[port_columns.full_name] = *p;
|
||||
|
||||
std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p);
|
||||
if (pn.empty ()) {
|
||||
pn = (*p).substr ((*p).find (':') + 1);
|
||||
}
|
||||
row[port_columns.short_name] = pn;
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::populate_port_combo ()
|
||||
{
|
||||
if (!tm->port()) {
|
||||
port_combo.hide ();
|
||||
return;
|
||||
} else {
|
||||
port_combo.show ();
|
||||
}
|
||||
|
||||
vector<string> inputs;
|
||||
|
||||
if (tm->port()->type() == DataType::MIDI) {
|
||||
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput), inputs);
|
||||
} else {
|
||||
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::AUDIO, ARDOUR::PortFlags (ARDOUR::IsOutput), inputs);
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore> input = build_port_list (inputs);
|
||||
bool input_found = false;
|
||||
int n;
|
||||
|
||||
port_combo.set_model (input);
|
||||
|
||||
Gtk::TreeModel::Children children = input->children();
|
||||
Gtk::TreeModel::Children::iterator i;
|
||||
i = children.begin();
|
||||
++i; /* skip "Disconnected" */
|
||||
|
||||
|
||||
for (n = 1; i != children.end(); ++i, ++n) {
|
||||
string port_name = (*i)[port_columns.full_name];
|
||||
if (tm->port()->connected_to (port_name)) {
|
||||
port_combo.set_active (n);
|
||||
input_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!input_found) {
|
||||
port_combo.set_active (0); /* disconnected */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::port_choice_changed ()
|
||||
{
|
||||
if (ignore_active_change) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeModel::iterator active = port_combo.get_active ();
|
||||
string new_port = (*active)[port_columns.full_name];
|
||||
|
||||
if (new_port.empty()) {
|
||||
tm->port()->disconnect_all ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tm->port()->connected_to (new_port)) {
|
||||
tm->port()->disconnect_all ();
|
||||
tm->port()->connect (new_port);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::Row::update (Session* s, samplepos_t now)
|
||||
{
|
||||
using namespace Timecode;
|
||||
|
||||
samplepos_t pos;
|
||||
double speed;
|
||||
stringstream ss;
|
||||
Time t;
|
||||
boost::shared_ptr<TimecodeTransportMaster> ttm;
|
||||
boost::shared_ptr<MIDIClock_TransportMaster> mtm;
|
||||
|
||||
if (s) {
|
||||
|
||||
if (tm->speed_and_position (speed, pos, now)) {
|
||||
|
||||
sample_to_timecode (pos, t, false, false, 25, false, AudioEngine::instance()->sample_rate(), 100, false, 0);
|
||||
|
||||
if ((ttm = boost::dynamic_pointer_cast<TimecodeTransportMaster> (tm))) {
|
||||
format.set_text (timecode_format_name (ttm->apparent_timecode_format()));
|
||||
} else if ((mtm = boost::dynamic_pointer_cast<MIDIClock_TransportMaster> (tm))) {
|
||||
char buf[8];
|
||||
snprintf (buf, sizeof (buf), "%.1f", mtm->bpm());
|
||||
format.set_text (buf);
|
||||
} else {
|
||||
format.set_text ("");
|
||||
}
|
||||
current.set_text (Timecode::timecode_format_time (t));
|
||||
timestamp.set_markup (tm->position_string());
|
||||
delta.set_markup (tm->delta_string ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
populate_port_combo ();
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::update (samplepos_t audible)
|
||||
{
|
||||
samplepos_t now = AudioEngine::instance()->sample_time ();
|
||||
|
||||
for (vector<Row*>::iterator r = rows.begin(); r != rows.end(); ++r) {
|
||||
(*r)->update (_session, now);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::on_map ()
|
||||
{
|
||||
update_connection = ARDOUR_UI::Clock.connect (sigc::mem_fun (*this, &TransportMastersWidget::update));
|
||||
Gtk::VBox::on_map ();
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersWidget::on_unmap ()
|
||||
{
|
||||
update_connection.disconnect ();
|
||||
Gtk::VBox::on_unmap ();
|
||||
}
|
||||
|
||||
TransportMastersDialog::TransportMastersDialog ()
|
||||
: ArdourDialog (_("Transport Masters"))
|
||||
{
|
||||
get_vbox()->pack_start (w);
|
||||
w.show ();
|
||||
}
|
||||
|
||||
void
|
||||
TransportMastersDialog::set_session (ARDOUR::Session* s)
|
||||
{
|
||||
ArdourDialog::set_session (s);
|
||||
w.set_session (s);
|
||||
}
|
||||
129
gtk2_ardour/transport_masters_dialog.h
Normal file
129
gtk2_ardour/transport_masters_dialog.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Copyright (C) 2018 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_gtk_transport_masters_dialog_h__
|
||||
#define __ardour_gtk_transport_masters_dialog_h__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/radiobutton.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/table.h>
|
||||
#include <gtkmm/treestore.h>
|
||||
|
||||
#include "ardour_dialog.h"
|
||||
|
||||
namespace Gtk {
|
||||
class Menu;
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
class TransportMaster;
|
||||
}
|
||||
|
||||
class TransportMastersWidget : public Gtk::VBox, public ARDOUR::SessionHandlePtr
|
||||
{
|
||||
public:
|
||||
TransportMastersWidget ();
|
||||
~TransportMastersWidget ();
|
||||
|
||||
void update (ARDOUR::samplepos_t);
|
||||
|
||||
protected:
|
||||
void on_map ();
|
||||
void on_unmap ();
|
||||
|
||||
private:
|
||||
|
||||
struct Row : sigc::trackable, PBD::ScopedConnectionList {
|
||||
Gtk::Label label;
|
||||
Gtk::Label type;
|
||||
Gtk::Label format;
|
||||
Gtk::Label current;
|
||||
Gtk::Label timestamp;
|
||||
Gtk::Label delta;
|
||||
Gtk::CheckButton collect_button;
|
||||
Gtk::RadioButton use_button;
|
||||
Gtk::ComboBoxText port_combo;
|
||||
Gtk::CheckButton sclock_synced_button;
|
||||
Gtk::CheckButton fps_299730_button;
|
||||
Gtk::Button request_options;
|
||||
Gtk::Menu* request_option_menu;
|
||||
|
||||
void build_request_options();
|
||||
|
||||
boost::shared_ptr<ARDOUR::TransportMaster> tm;
|
||||
|
||||
void update (ARDOUR::Session*, ARDOUR::samplepos_t);
|
||||
|
||||
Row ();
|
||||
|
||||
struct PortColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
PortColumns() {
|
||||
add (short_name);
|
||||
add (full_name);
|
||||
}
|
||||
Gtk::TreeModelColumn<std::string> short_name;
|
||||
Gtk::TreeModelColumn<std::string> full_name;
|
||||
};
|
||||
|
||||
PortColumns port_columns;
|
||||
|
||||
void populate_port_combo ();
|
||||
Glib::RefPtr<Gtk::ListStore> build_port_list (std::vector<std::string> const & ports);
|
||||
|
||||
void use_button_toggled ();
|
||||
void collect_button_toggled ();
|
||||
void sync_button_toggled ();
|
||||
void port_choice_changed ();
|
||||
void connection_handler ();
|
||||
bool request_option_press (GdkEventButton*);
|
||||
|
||||
bool ignore_active_change;
|
||||
};
|
||||
|
||||
std::vector<Row*> rows;
|
||||
|
||||
Gtk::RadioButtonGroup use_button_group;
|
||||
Gtk::Table table;
|
||||
Gtk::Label col_title[12];
|
||||
|
||||
sigc::connection update_connection;
|
||||
PBD::ScopedConnection current_connection;
|
||||
|
||||
void rebuild ();
|
||||
void current_changed (boost::shared_ptr<ARDOUR::TransportMaster> old_master, boost::shared_ptr<ARDOUR::TransportMaster> new_master);
|
||||
|
||||
};
|
||||
|
||||
class TransportMastersDialog : public ArdourDialog
|
||||
{
|
||||
public:
|
||||
TransportMastersDialog ();
|
||||
|
||||
void set_session (ARDOUR::Session*);
|
||||
|
||||
private:
|
||||
TransportMastersWidget w;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ardour_gtk_transport_masters_dialog_h__ */
|
||||
|
|
@ -262,6 +262,7 @@ gtk2_ardour_sources = [
|
|||
'transform_dialog.cc',
|
||||
'transport_control.cc',
|
||||
'transport_control_ui.cc',
|
||||
'transport_masters_dialog.cc',
|
||||
'transpose_dialog.cc',
|
||||
'ui_config.cc',
|
||||
'utils.cc',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue