move all marker/midi related code into Editor (since the visual elements in the GUI are all part of the Editor window, and populate/alter dropdowns as necessary.

We connect to the PortManager signals to indicate when ports are connected/registered/disconnected/unregistered.

Still to do: ensure initial visual state is consistent with actual backend state
This commit is contained in:
Paul Davis 2014-10-01 17:50:50 -04:00
parent d6afce9c0f
commit c4be44fe6e
6 changed files with 211 additions and 131 deletions

View file

@ -257,13 +257,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
void update_sample_rate_dropdown ();
void update_frame_rate_button ();
WavesDropdown* _midi_input_dropdown;
WavesDropdown* _midi_output_dropdown;
void populate_midi_inout_dropdowns ();
void populate_midi_inout_dropdown (bool playback);
PBD::ScopedConnectionList update_connections_to_toolbar_buttons;
TimeInfoBox* time_info_box;
@ -759,9 +752,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
void parameter_changed (std::string);
void session_parameter_changed (const std::string& param);
void midi_input_chosen (WavesDropdown*, void*);
void midi_output_chosen (WavesDropdown*, void*);
bool first_idle ();
void check_memory_locking ();

View file

@ -55,18 +55,18 @@
#include "location_ui.h"
#include "main_clock.h"
#include "time_info_box.h"
#include "utils.h"
#include "gui_thread.h"
#include <gtkmm2ext/application.h>
#include "ardour/session.h"
#include "ardour/profile.h"
#include "ardour/audioengine.h"
#include "ardour/engine_state_controller.h"
#include "control_protocol/control_protocol.h"
#include "i18n.h"
#include "utils.h"
using namespace std;
using namespace ARDOUR;
@ -81,45 +81,37 @@ ARDOUR_UI::create_editor ()
try {
editor = new Editor ();
_dsp_load_adjustment = &editor->get_adjustment ("dsp_load_adjustment");
_hd_load_adjustment = &editor->get_adjustment("hd_load_adjustment");
_dsp_load_label = &editor->get_label("dsp_load_label");
_hd_load_label = &editor->get_label("hd_load_label");
_hd_remained_time_label = &editor->get_label("hd_remained_time");
_bit_depth_button = &editor->get_waves_button("bit_depth_button");
_frame_rate_button = &editor->get_waves_button("frame_rate_button");
_sample_rate_dropdown = &editor->get_waves_dropdown("sample_rate_dropdown");
_display_format_dropdown = &editor->get_waves_dropdown("display_format_dropdown");
_timecode_source_dropdown = &editor->get_waves_dropdown("timecode_selector_dropdown");
_tracks_button = &editor->get_waves_button("tracks_button");
_midi_input_dropdown = &editor->get_waves_dropdown ("midi_input_dropdown");
_midi_output_dropdown = &editor->get_waves_dropdown ("midi_output_dropdown");
_hd_load_adjustment = &editor->get_adjustment("hd_load_adjustment");
_dsp_load_label = &editor->get_label("dsp_load_label");
_hd_load_label = &editor->get_label("hd_load_label");
_hd_remained_time_label = &editor->get_label("hd_remained_time");
_bit_depth_button = &editor->get_waves_button("bit_depth_button");
_frame_rate_button = &editor->get_waves_button("frame_rate_button");
_sample_rate_dropdown = &editor->get_waves_dropdown("sample_rate_dropdown");
_display_format_dropdown = &editor->get_waves_dropdown("display_format_dropdown");
_timecode_source_dropdown = &editor->get_waves_dropdown("timecode_selector_dropdown");
_tracks_button = &editor->get_waves_button("tracks_button");
}
catch (failed_constructor& err) {
return -1;
}
_bit_depth_button->signal_clicked.connect(sigc::mem_fun (*this, &ARDOUR_UI::on_bit_depth_button));
_frame_rate_button->signal_clicked.connect(sigc::mem_fun (*this, &ARDOUR_UI::on_frame_rate_button));
_tracks_button->signal_clicked.connect(sigc::mem_fun (*this, &ARDOUR_UI::on_tracks_button));
_sample_rate_dropdown->selected_item_changed.connect (mem_fun(*this, &ARDOUR_UI::on_sample_rate_dropdown_item_clicked ));
_display_format_dropdown->selected_item_changed.connect (mem_fun(*this, &ARDOUR_UI::on_display_format_dropdown_item_clicked ));
_timecode_source_dropdown->selected_item_changed.connect (mem_fun(*this, &ARDOUR_UI::on_timecode_source_dropdown_item_clicked ));
_bit_depth_button->signal_clicked.connect(sigc::mem_fun (*this, &ARDOUR_UI::on_bit_depth_button));
_frame_rate_button->signal_clicked.connect(sigc::mem_fun (*this, &ARDOUR_UI::on_frame_rate_button));
_tracks_button->signal_clicked.connect(sigc::mem_fun (*this, &ARDOUR_UI::on_tracks_button));
_sample_rate_dropdown->selected_item_changed.connect (mem_fun(*this, &ARDOUR_UI::on_sample_rate_dropdown_item_clicked ));
_display_format_dropdown->selected_item_changed.connect (mem_fun(*this, &ARDOUR_UI::on_display_format_dropdown_item_clicked ));
_timecode_source_dropdown->selected_item_changed.connect (mem_fun(*this, &ARDOUR_UI::on_timecode_source_dropdown_item_clicked ));
editor->Realized.connect (sigc::mem_fun (*this, &ARDOUR_UI::editor_realized));
editor->signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::main_window_state_event_handler), true));
_midi_input_dropdown->selected_item_changed.connect (sigc::mem_fun (*this, &ARDOUR_UI::midi_input_chosen));
_midi_output_dropdown->selected_item_changed.connect (sigc::mem_fun (*this, &ARDOUR_UI::midi_output_chosen));
populate_midi_inout_dropdowns ();
return 0;
return 0;
}
void
@ -897,84 +889,3 @@ ARDOUR_UI::focus_on_clock ()
}
}
void
ARDOUR_UI::midi_input_chosen (WavesDropdown*, void* full_name_of_chosen_port)
{
if( !_session )
return;
_session->scene_in()->disconnect_all ();
if (full_name_of_chosen_port != 0) {
_session->scene_in()->connect ((char*) full_name_of_chosen_port);
}
}
void
ARDOUR_UI::midi_output_chosen (WavesDropdown*, void* full_name_of_chosen_port)
{
if( !_session )
return;
_session->scene_out()->disconnect_all ();
if (full_name_of_chosen_port != 0) {
_session->scene_out()->connect ((char *) full_name_of_chosen_port);
}
}
void
ARDOUR_UI::populate_midi_inout_dropdowns ()
{
// these two calls should occure every time
// the list of available midi inputs/outputs
// is changed.
populate_midi_inout_dropdown (false);
populate_midi_inout_dropdown (true);
}
void
ARDOUR_UI::populate_midi_inout_dropdown (bool playback)
{
WavesDropdown& dropdown = *(playback ? _midi_output_dropdown : _midi_input_dropdown);
using namespace ARDOUR;
std::vector<EngineStateController::PortState> midi_states;
static const char* midi_port_name_prefix = "system_midi:";
const char* midi_type_suffix;
bool have_first = false;
if (playback) {
EngineStateController::instance()->get_physical_midi_output_states(midi_states);
midi_type_suffix = X_(" playback");
} else {
EngineStateController::instance()->get_physical_midi_input_states(midi_states);
midi_type_suffix = X_(" capture");
}
dropdown.clear_items ();
/* add a "none" entry */
dropdown.add_radio_menu_item (_("None"), 0);
std::vector<EngineStateController::PortState>::const_iterator state_iter;
for (state_iter = midi_states.begin(); state_iter != midi_states.end(); ++state_iter) {
// strip the device name from input port name
std::string device_name;
ARDOUR::remove_pattern_from_string(state_iter->name, midi_port_name_prefix, device_name);
ARDOUR::remove_pattern_from_string(device_name, midi_type_suffix, device_name);
if (state_iter->active) {
dropdown.add_radio_menu_item (device_name, strdup (state_iter->name.c_str()));
if (!have_first) {
dropdown.set_text (device_name);
have_first = true;
}
}
}
}

0
gtk2_ardour/arval Normal file → Executable file
View file

View file

@ -70,6 +70,7 @@
#include "ardour/engine_state_controller.h"
#include "ardour/audioregion.h"
#include "ardour/location.h"
#include "ardour/midi_scene_changer.h"
#include "ardour/profile.h"
#include "ardour/route_group.h"
#include "ardour/session_playlists.h"
@ -320,6 +321,8 @@ Editor::Editor ()
, current_mixer_strip (0)
, _master_bus_ui (0)
, _set_session_in_progress(false)
, _midi_input_dropdown (get_waves_dropdown ("midi_input_dropdown"))
, _midi_output_dropdown (get_waves_dropdown ("midi_output_dropdown"))
, midi_marker_input_activity_image (get_image ("midi_input_activity_indicator"))
, midi_marker_output_activity_image (get_image ("midi_output_activity_indicator"))
, midi_marker_input_enabled_image (get_image ("midi_input_enabled_indicator"))
@ -327,7 +330,7 @@ Editor::Editor ()
, midi_marker_output_enabled_image (get_image ("midi_output_enabled_indicator"))
, midi_marker_output_disabled_image (get_image ("midi_output_disabled_indicator"))
{
constructed = false;
constructed = false;
/* we are a singleton */
@ -522,6 +525,12 @@ Editor::Editor ()
selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
EngineStateController::instance()->OutputConnectionModeChanged.connect (*this, invalidator (*this), boost::bind (&Editor::output_connection_mode_changed, this), gui_context() );
/* Connect to relevant signal so that we will be notified of port registration changes */
ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (port_registration_connection, invalidator (*this), boost::bind (&Editor::port_registration_handler, this), gui_context());
/* Connect to relevant signal so that we will be notified of port connection changes */
ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection_connection, invalidator (*this), boost::bind (&Editor::port_connection_handler, this, _1, _2, _3, _4, _5), gui_context());
editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
@ -1390,6 +1399,23 @@ Editor::set_session (Session *t)
XMLNode* node = ARDOUR_UI::instance()->editor_settings();
set_state (*node, Stateful::loading_state_version);
/* signal connections related to MIDI/scene change */
_midi_input_dropdown.selected_item_changed.connect (sigc::mem_fun (*this, &Editor::midi_input_chosen));
_midi_output_dropdown.selected_item_changed.connect (sigc::mem_fun (*this, &Editor::midi_output_chosen));
/* listen for incoming scene change messages so we can indicate relevant MIDI activity in the GUI */
MIDISceneChanger* msc = dynamic_cast<MIDISceneChanger*> (_session->scene_changer());
if (msc) {
msc->MIDIInputActivity.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_midi_input_activity, this), gui_context());
msc->MIDIOutputActivity.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_midi_output_activity, this), gui_context());
}
reset_marker_midi_images (false);
reset_marker_midi_images (true);
/* catch up with the playhead */
_session->request_locate (playhead_cursor->current_frame ());
@ -5820,3 +5846,30 @@ Editor::global_rec_clicked (WavesButton*)
_global_rec_button.set_active(!all_tracks_are_record_armed);
}
void
Editor::port_registration_handler ()
{
if (!_session) {
cerr << "PRH, early\n";
return;
}
populate_midi_inout_dropdowns ();
}
void
Editor::port_connection_handler (boost::weak_ptr<Port> wa, std::string, boost::weak_ptr<Port> wb, std::string, bool connected)
{
if (!_session) {
cerr << "PCH, early\n";
return;
}
/* we could investigate the types of ports involved in this connection/disconnection,
but since this really doesn't cost a lot (hide/show of various images, no redraw)
the benefit of doing so doesn't seem that great.
*/
reset_marker_midi_images (true);
reset_marker_midi_images (false);
}

View file

@ -2146,7 +2146,20 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, std::string name);
void bring_all_sources_into_session ();
void port_registration_handler ();
void port_connection_handler (boost::weak_ptr<ARDOUR::Port> wa, std::string, boost::weak_ptr<ARDOUR::Port> wb, std::string, bool connected);
PBD::ScopedConnection port_registration_connection;
PBD::ScopedConnection port_connection_connection;
/* members and methods associated with MIDI + markers */
WavesDropdown& _midi_input_dropdown;
WavesDropdown& _midi_output_dropdown;
void midi_input_chosen (WavesDropdown*, void*);
void midi_output_chosen (WavesDropdown*, void*);
void populate_midi_inout_dropdowns ();
void populate_midi_inout_dropdown (bool playback);
Gtk::Image& midi_marker_input_activity_image;
Gtk::Image& midi_marker_output_activity_image;
Gtk::Image& midi_marker_input_enabled_image;
@ -2156,8 +2169,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void marker_midi_input_activity ();
void marker_midi_output_activity ();
bool hide_marker_midi_image (Gtk::Widget*);
void display_marker_midi_port_status ();
bool reset_marker_midi_images (bool input);
friend class Drag;
friend class RegionDrag;

View file

@ -22,10 +22,14 @@
#include <gtkmm2ext/gtk_ui.h>
#include "pbd/memento_command.h"
#include "ardour/session.h"
#include "ardour/location.h"
#include "ardour/midi_port.h"
#include "ardour/profile.h"
#include "pbd/memento_command.h"
#include "ardour/engine_state_controller.h"
#include "ardour/audioengine.h"
#include "canvas/canvas.h"
#include "canvas/item.h"
@ -1327,9 +1331,11 @@ void
Editor::marker_midi_input_activity ()
{
if (!midi_marker_input_activity_image.is_visible ()) {
midi_marker_input_disabled_image.hide ();
midi_marker_input_enabled_image.hide ();
midi_marker_input_activity_image.show ();
/* hide the image again in 1/2 second */
Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::hide_marker_midi_image), &midi_marker_input_activity_image), 500);
Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::reset_marker_midi_images), true), 500);
}
}
@ -1337,16 +1343,124 @@ void
Editor::marker_midi_output_activity ()
{
if (!midi_marker_output_activity_image.is_visible ()) {
midi_marker_output_disabled_image.hide ();
midi_marker_output_enabled_image.hide ();
midi_marker_output_activity_image.show ();
/* hide the image again in 1/2 second */
Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::hide_marker_midi_image), &midi_marker_output_activity_image), 500);
Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::reset_marker_midi_images), false), 500);
}
}
bool
Editor::hide_marker_midi_image (Gtk::Widget* img)
Editor::reset_marker_midi_images (bool input)
{
img->hide ();
if (!_session) {
return false;
}
if (input) {
if (_session->scene_in()->connected()) {
midi_marker_input_enabled_image.show ();
midi_marker_input_disabled_image.hide ();
} else {
midi_marker_input_enabled_image.hide ();
midi_marker_input_disabled_image.show ();
}
midi_marker_input_activity_image.hide ();
} else {
if (_session->scene_out()->connected()) {
midi_marker_output_enabled_image.show ();
midi_marker_output_disabled_image.hide ();
} else {
midi_marker_output_enabled_image.hide ();
midi_marker_output_disabled_image.show ();
}
midi_marker_output_activity_image.hide ();
}
return false; /* do not call again */
}
/* MIDI/scene change Markers */
void
Editor::midi_input_chosen (WavesDropdown*, void* full_name_of_chosen_port)
{
if (!_session) {
return;
}
_session->scene_in()->disconnect_all ();
if (full_name_of_chosen_port != 0) {
_session->scene_in()->connect ((char*) full_name_of_chosen_port);
}
}
void
Editor::midi_output_chosen (WavesDropdown*, void* full_name_of_chosen_port)
{
if (!_session) {
return;
}
_session->scene_out()->disconnect_all ();
if (full_name_of_chosen_port != 0) {
_session->scene_out()->connect ((char *) full_name_of_chosen_port);
}
}
void
Editor::populate_midi_inout_dropdowns ()
{
populate_midi_inout_dropdown (false);
populate_midi_inout_dropdown (true);
}
void
Editor::populate_midi_inout_dropdown (bool playback)
{
using namespace ARDOUR;
WavesDropdown* dropdown = playback ? &_midi_output_dropdown : &_midi_input_dropdown;
std::vector<EngineStateController::PortState> midi_states;
static const char* midi_port_name_prefix = "system_midi:";
const char* midi_type_suffix;
bool have_first = false;
if (playback) {
EngineStateController::instance()->get_physical_midi_output_states(midi_states);
midi_type_suffix = X_(" playback");
} else {
EngineStateController::instance()->get_physical_midi_input_states(midi_states);
midi_type_suffix = X_(" capture");
}
dropdown->clear_items ();
/* add a "none" entry */
dropdown->add_radio_menu_item (_("None"), 0);
std::vector<EngineStateController::PortState>::const_iterator state_iter;
for (state_iter = midi_states.begin(); state_iter != midi_states.end(); ++state_iter) {
// strip the device name from input port name
std::string device_name;
ARDOUR::remove_pattern_from_string(state_iter->name, midi_port_name_prefix, device_name);
ARDOUR::remove_pattern_from_string(device_name, midi_type_suffix, device_name);
if (state_iter->active) {
dropdown->add_radio_menu_item (device_name, strdup (state_iter->name.c_str()));
if (!have_first) {
dropdown->set_text (device_name);
have_first = true;
}
}
}
}