diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2010-01-01 18:14:32 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2010-01-01 18:14:32 +0000 |
commit | 6572f421a40b30112dbe11a4eace115a6af1c83e (patch) | |
tree | f56d12cd4332940f807dc391d66fd2b55a86f86f /libs | |
parent | 732ac7756ad9caa2ab4b0b181b78e103b967d0fc (diff) |
provide limited momentary note on/off MIDI binding option; remove some debugging output; add bank selector to generic MIDI UI
git-svn-id: svn://localhost/ardour2/branches/3.0@6430 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/route.cc | 18 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 3 | ||||
-rw-r--r-- | libs/pbd/controllable_descriptor.cc | 12 | ||||
-rw-r--r-- | libs/surfaces/control_protocol/basic_ui.cc | 95 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/generic_midi_control_protocol.cc | 15 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/gmcp_gui.cc | 35 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.cc | 89 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.h | 6 |
8 files changed, 211 insertions, 62 deletions
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 29cc32bf24..3ae5e90b7b 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -2852,14 +2852,30 @@ void Route::SoloControllable::set_value (float val) { bool bval = ((val >= 0.5f) ? true: false); +# if 0 + this is how it should be done + boost::shared_ptr<RouteList> rl (new RouteList); + rl->push_back (route); + + if (Config->get_solo_control_is_listen_control()) { + _session.set_listen (rl, bval); + } else { + _session.set_solo (rl, bval); + } +#else route.set_solo (bval, this); +#endif } float Route::SoloControllable::get_value (void) const { - return route.self_soloed() ? 1.0f : 0.0f; + if (Config->get_solo_control_is_listen_control()) { + return route.listening() ? 1.0f : 0.0f; + } else { + return route.self_soloed() ? 1.0f : 0.0f; + } } void diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 3533e48956..e222de2221 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -146,10 +146,8 @@ Session::first_stage_init (string fullpath, string snapshot_name) } if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS) && ::access (_path.c_str(), W_OK)) { - cerr << "Session non-writable based on " << _path << endl; _writable = false; } else { - cerr << "Session writable based on " << _path << endl; _writable = true; } @@ -2713,6 +2711,7 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc) case ControllableDescriptor::Gain: c = r->gain_control (); break; + case ControllableDescriptor::Solo: c = r->solo_control(); break; diff --git a/libs/pbd/controllable_descriptor.cc b/libs/pbd/controllable_descriptor.cc index 2f84d706b4..86f96bb50c 100644 --- a/libs/pbd/controllable_descriptor.cc +++ b/libs/pbd/controllable_descriptor.cc @@ -49,18 +49,6 @@ ControllableDescriptor::set (const std::string& str) return -1; } - cerr << "Path: " << endl; - for (vector<string>::iterator x = path.begin(); x != path.end(); ++x) { - cerr << '[' << (*x) << "] "; - } - cerr << endl; - - cerr << "Rest: " << endl; - for (vector<string>::iterator x = rest.begin(); x != rest.end(); ++x) { - cerr << '[' << (*x) << "] "; - } - cerr << endl; - if (path[0] == "route" || path[0] == "rid") { _top_level_type = RemoteControlID; diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc index 8c3eb02982..a21da95bb1 100644 --- a/libs/surfaces/control_protocol/basic_ui.cc +++ b/libs/surfaces/control_protocol/basic_ui.cc @@ -296,3 +296,98 @@ BasicUI::sample_to_timecode (nframes_t sample, Timecode::Time& timecode, bool us session->sample_to_timecode (sample, *((Timecode::Time*)&timecode), use_offset, use_subframes); } +#if 0 +this stuff is waiting to go in so that all UI's can offer complex solo/mute functionality + +void +BasicUI::solo_release (boost::shared_ptr<Route> r) +{ +} + +void +BasicUI::solo_press (boost::shared_ptr<Route> r, bool momentary, bool global, bool exclusive, bool isolate, bool solo_group) +{ + if (momentary) { + _solo_release = new SoloMuteRelease (_route->soloed()); + } + + if (global) { + + if (_solo_release) { + _solo_release->routes = _session->get_routes (); + } + + if (Config->get_solo_control_is_listen_control()) { + _session->set_listen (_session->get_routes(), !_route->listening(), Session::rt_cleanup, true); + } else { + _session->set_solo (_session->get_routes(), !_route->soloed(), Session::rt_cleanup, true); + } + + } else if (exclusive) { + + if (_solo_release) { + _solo_release->exclusive = true; + + boost::shared_ptr<RouteList> routes = _session->get_routes(); + + for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + if ((*i)->soloed ()) { + _solo_release->routes_on->push_back (*i); + } else { + _solo_release->routes_off->push_back (*i); + } + } + } + + if (Config->get_solo_control_is_listen_control()) { + /* ??? we need a just_one_listen() method */ + } else { + _session->set_just_one_solo (_route, true); + } + + } else if (isolate) { + + // shift-click: toggle solo isolated status + + _route->set_solo_isolated (!_route->solo_isolated(), this); + delete _solo_release; + _solo_release = 0; + + } else if (solo_group) { + + /* Primary-button1: solo mix group. + NOTE: Primary-button2 is MIDI learn. + */ + + if (_route->route_group()) { + + if (_solo_release) { + _solo_release->routes = _route->route_group()->route_list(); + } + + if (Config->get_solo_control_is_listen_control()) { + _session->set_listen (_route->route_group()->route_list(), !_route->listening(), Session::rt_cleanup, true); + } else { + _session->set_solo (_route->route_group()->route_list(), !_route->soloed(), Session::rt_cleanup, true); + } + } + + } else { + + /* click: solo this route */ + + boost::shared_ptr<RouteList> rl (new RouteList); + rl->push_back (route()); + + if (_solo_release) { + _solo_release->routes = rl; + } + + if (Config->get_solo_control_is_listen_control()) { + _session->set_listen (rl, !_route->listening()); + } else { + _session->set_solo (rl, !_route->soloed()); + } + } +} +#endif diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index f092fabb59..51c1b119eb 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -315,7 +315,7 @@ GenericMidiControlProtocol::start_learning (Controllable* c) } if (!mc) { - mc = new MIDIControllable (*_port, *c); + mc = new MIDIControllable (*_port, *c, false); } { @@ -410,7 +410,7 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, MIDI::byte value = control_number; // Create a MIDIControllable - MIDIControllable* mc = new MIDIControllable (*_port, *control); + MIDIControllable* mc = new MIDIControllable (*_port, *control, false); // Remove any old binding for this midi channel/type/value pair // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information @@ -520,7 +520,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node, int version) c = session->controllable_by_id (id); if (c) { - MIDIControllable* mc = new MIDIControllable (*_port, *c); + MIDIControllable* mc = new MIDIControllable (*_port, *c, false); if (mc->set_state (**niter, version) == 0) { controllables.push_back (mc); @@ -655,6 +655,7 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) string uri; MIDI::eventType ev; int intval; + bool momentary; if ((prop = node.property (X_("ctl"))) != 0) { ev = MIDI::controller; @@ -684,11 +685,17 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) if (channel > 0) { channel -= 1; } + + if ((prop = node.property (X_("momentary"))) != 0) { + momentary = string_is_affirmative (prop->value()); + } else { + momentary = false; + } prop = node.property (X_("uri")); uri = prop->value(); - MIDIControllable* mc = new MIDIControllable (*_port, false); + MIDIControllable* mc = new MIDIControllable (*_port, momentary); if (mc->init (uri)) { delete mc; diff --git a/libs/surfaces/generic_midi/gmcp_gui.cc b/libs/surfaces/generic_midi/gmcp_gui.cc index 38bbdbe00a..c5ffce369d 100644 --- a/libs/surfaces/generic_midi/gmcp_gui.cc +++ b/libs/surfaces/generic_midi/gmcp_gui.cc @@ -5,6 +5,8 @@ #include <gtkmm/comboboxtext.h> #include <gtkmm/label.h> #include <gtkmm/box.h> +#include <gtkmm/adjustment.h> +#include <gtkmm/spinbutton.h> #include "gtkmm2ext/utils.h" @@ -21,8 +23,11 @@ public: private: GenericMidiControlProtocol& cp; Gtk::ComboBoxText map_combo; + Gtk::Adjustment bank_adjustment; + Gtk::SpinButton bank_spinner; void binding_changed (); + void bank_change (); }; using namespace PBD; @@ -56,6 +61,8 @@ GenericMidiControlProtocol::build_gui () GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p) : cp (p) + , bank_adjustment (1, 1, 100, 1, 10) + , bank_spinner (bank_adjustment) { vector<string> popdowns; popdowns.push_back (_("Reset All")); @@ -74,6 +81,7 @@ GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p) map_combo.signal_changed().connect (sigc::mem_fun (*this, &GMCPGUI::binding_changed)); + set_spacing (6); set_border_width (12); Label* label = manage (new Label (_("Available MIDI bindings:"))); @@ -83,11 +91,29 @@ GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p) hpack->pack_start (*label, false, false); hpack->pack_start (map_combo, false, false); + map_combo.show (); + label->show (); + hpack->show (); + pack_start (*hpack, false, false); - map_combo.show (); + + bank_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &GMCPGUI::bank_change)); + + label = manage (new Label (_("Current Bank:"))); + hpack = manage (new HBox); + + hpack->set_spacing (6); + hpack->pack_start (*label, false, false); + hpack->pack_start (bank_spinner, false, false); + + + bank_spinner.show (); label->show (); hpack->show (); + + pack_start (*hpack, false, false); + } GMCPGUI::~GMCPGUI () @@ -95,6 +121,13 @@ GMCPGUI::~GMCPGUI () } void +GMCPGUI::bank_change () +{ + int new_bank = bank_adjustment.get_value() - 1; + cp.set_current_bank (new_bank); +} + +void GMCPGUI::binding_changed () { string str = map_combo.get_active_text (); diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index d960140958..e5173c5345 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -19,8 +19,7 @@ #define __STDC_FORMAT_MACROS 1 #include <stdint.h> - -#include <cstdio> /* for sprintf, sigh */ +#include <cmath> #include <climits> #include "pbd/error.h" @@ -40,11 +39,11 @@ using namespace MIDI; using namespace PBD; using namespace ARDOUR; -MIDIControllable::MIDIControllable (Port& p, bool is_bistate) +MIDIControllable::MIDIControllable (Port& p, bool m) : controllable (0) , _descriptor (0) , _port (p) - , bistate (is_bistate) + , _momentary (m) { _learned = false; /* from URI */ setting = false; @@ -55,12 +54,11 @@ MIDIControllable::MIDIControllable (Port& p, bool is_bistate) feedback = true; // for now } -MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate) +MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool m) : controllable (&c) , _descriptor (0) , _port (p) - , bistate (is_bistate) - + , _momentary (m) { _learned = true; /* from controllable */ setting = false; @@ -187,23 +185,23 @@ MIDIControllable::midi_sense_note_off (Parser &p, EventTwoBytes *tb) } void -MIDIControllable::midi_sense_note (Parser &, EventTwoBytes *msg, bool is_on) +MIDIControllable::midi_sense_note (Parser &, EventTwoBytes *msg, bool /* is_on */) { if (!controllable) { return; } - if (!bistate) { + + if (!controllable->is_toggle()) { controllable->set_value (msg->note_number/127.0); } else { - /* Note: parser handles the use of zero velocity to - mean note off. if we get called with is_on=true, then we - got a *real* note on. - */ - - if (msg->note_number == control_additional) { - controllable->set_value (is_on ? 1 : 0); + if (control_additional == msg->note_number) { + /* Note: parser handles the use of zero velocity to + mean note off. if we get called with is_on=true, then we + got a *real* note on. + */ + controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f); } } @@ -222,10 +220,11 @@ MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg) } if (control_additional == msg->controller_number) { - if (!bistate) { - controllable->set_value (midi_to_control(msg->value)); + + if (!controllable->is_toggle()) { + controllable->set_value (midi_to_control (msg->value)); } else { - if (msg->value > 64.0) { + if (msg->value > 64.0f) { controllable->set_value (1); } else { controllable->set_value (0); @@ -242,12 +241,14 @@ MIDIControllable::midi_sense_program_change (Parser &, byte msg) if (!controllable) { return; } - /* XXX program change messages make no sense for bistates */ - if (!bistate) { + if (!controllable->is_toggle()) { controllable->set_value (msg/127.0); - last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights + } else { + controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f); } + + last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights } void @@ -257,11 +258,14 @@ MIDIControllable::midi_sense_pitchbend (Parser &, pitchbend_t pb) return; } - /* pitchbend messages make no sense for bistates */ - /* XXX gack - get rid of assumption about typeof pitchbend_t */ + if (!controllable->is_toggle()) { + /* XXX gack - get rid of assumption about typeof pitchbend_t */ + controllable->set_value ((pb/(float) SHRT_MAX)); + } else { + controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f); + } - controllable->set_value ((pb/(float) SHRT_MAX)); last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights } @@ -307,11 +311,11 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) case MIDI::off: p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); - /* if this is a bistate, connect to noteOn as well, + /* if this is a togglee, connect to noteOn as well, and we'll toggle back and forth between the two. */ - if (bistate) { + if (_momentary) { p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); } @@ -320,7 +324,7 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) case MIDI::on: p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); - if (bistate) { + if (_momentary) { p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); } _control_description = "MIDI control: NoteOn"; @@ -333,17 +337,13 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) break; case MIDI::program: - if (!bistate) { - p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_program_change, this, _1, _2)); - _control_description = "MIDI control: ProgramChange"; - } + p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_program_change, this, _1, _2)); + _control_description = "MIDI control: ProgramChange"; break; case MIDI::pitchbend: - if (!bistate) { - p.channel_pitchbend[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_pitchbend, this, _1, _2)); - _control_description = "MIDI control: Pitchbend"; - } + p.channel_pitchbend[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_pitchbend, this, _1, _2)); + _control_description = "MIDI control: Pitchbend"; break; default: @@ -356,13 +356,18 @@ MIDIControllable::send_feedback () { byte msg[3]; - if (setting || !feedback || control_type == none) { + if (!_learned || setting || !feedback || control_type == none) { return; } msg[0] = (control_type & 0xF0) | (control_channel & 0xF); msg[1] = control_additional; - msg[2] = (byte) (control_to_midi(controllable->get_value())); + + if (controllable->is_gain_like()) { + msg[2] = (byte) lrintf (gain_to_slider_position (controllable->get_value()) * 127.0f); + } else { + msg[2] = (byte) (control_to_midi(controllable->get_value())); + } _port.write (msg, 3, 0); } @@ -372,7 +377,13 @@ MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool /*forc { if (control_type != none && feedback && bufsize > 2) { - MIDI::byte gm = (MIDI::byte) (control_to_midi(controllable->get_value())); + MIDI::byte gm; + + if (controllable->is_gain_like()) { + gm = (byte) lrintf (gain_to_slider_position (controllable->get_value()) * 127.0f); + } else { + gm = (byte) (control_to_midi(controllable->get_value())); + } if (gm != last_value) { *buf++ = (0xF0 & control_type) | (0xF & control_channel); diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index 0ce28ecabd..2e70e98a75 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -43,8 +43,8 @@ namespace MIDI { class MIDIControllable : public PBD::Stateful { public: - MIDIControllable (MIDI::Port&, PBD::Controllable&, bool bistate = false); - MIDIControllable (MIDI::Port&, bool bistate = false); + MIDIControllable (MIDI::Port&, PBD::Controllable&, bool momentary); + MIDIControllable (MIDI::Port&, bool momentary = false); virtual ~MIDIControllable (); int init (const std::string&); @@ -95,7 +95,7 @@ class MIDIControllable : public PBD::Stateful MIDI::Port& _port; bool setting; MIDI::byte last_value; - bool bistate; + bool _momentary; bool _is_gain_controller; bool _learned; int midi_msg_id; /* controller ID or note number */ |