+ StopGesture.emit(); /* EMIT SIGNAL */
+}
+
+void
+AutomationController::toggled ()
+{
+ ArdourButton* but = dynamic_cast<ArdourButton*>(_widget);
+ if (but) {
+ if (_controllable->session().transport_rolling()) {
+ if (_controllable->automation_state() == Touch) {
+ _controllable->set_automation_state(Write);
+ }
+ if (_controllable->list()) {
+ _controllable->list()->set_in_write_pass(true, false, _controllable->session().audible_frame());
+ }
+ }
+ const bool was_active = _controllable->get_value() >= 0.5;
+ if (was_active && but->get_active()) {
+ _adjustment->set_value(0.0);
+ but->set_active(false);
+ } else if (!was_active && !but->get_active()) {
+ _adjustment->set_value(1.0);
+ but->set_active(true);
+ }
+ }
+}
+
+static double
+midi_note_to_hz(int note)
+{
+ const double tuning = 440.0;
+ return tuning * pow(2, (note - 69.0) / 12.0);
+}
+
+static double
+clamp(double val, double min, double max)
+{
+ if (val < min) {
+ return min;
+ } else if (val > max) {
+ return max;
+ }
+ return val;
+}
+
+void
+AutomationController::run_note_select_dialog()
+{
+ const ARDOUR::ParameterDescriptor& desc = _controllable->desc();
+ NoteSelectDialog* dialog = new NoteSelectDialog();
+ if (dialog->run() == Gtk::RESPONSE_ACCEPT) {
+ const double value = ((_controllable->desc().unit == ARDOUR::ParameterDescriptor::HZ)
+ ? midi_note_to_hz(dialog->note_number())
+ : dialog->note_number());
+ _controllable->set_value(clamp(value, desc.lower, desc.upper));
+ }
+ delete dialog;
+}
+
+void
+AutomationController::set_freq_beats(double beats)
+{
+ const ARDOUR::ParameterDescriptor& desc = _controllable->desc();
+ const ARDOUR::Session& session = _controllable->session();
+ const framepos_t pos = session.transport_frame();
+ const ARDOUR::Tempo& tempo = session.tempo_map().tempo_at(pos);
+ const double bpm = tempo.beats_per_minute();
+ const double bps = bpm / 60.0;
+ const double freq = bps / beats;
+ _controllable->set_value(clamp(freq, desc.lower, desc.upper));
+}
+
+void
+AutomationController::set_ratio(double ratio)
+{
+ const ARDOUR::ParameterDescriptor& desc = _controllable->desc();
+ const double value = _controllable->get_value() * ratio;
+ _controllable->set_value(clamp(value, desc.lower, desc.upper));
+}
+
+bool
+AutomationController::on_button_release(GdkEventButton* ev)
+{
+ using namespace Gtk::Menu_Helpers;
+
+ if (ev->button != 3) {
+ return false;
+ }
+
+ const ARDOUR::ParameterDescriptor& desc = _controllable->desc();
+ if (desc.unit == ARDOUR::ParameterDescriptor::MIDI_NOTE) {
+ Gtk::Menu* menu = manage(new Menu());
+ MenuList& items = menu->items();
+ items.push_back(MenuElem(_("Select Note..."),
+ sigc::mem_fun(*this, &AutomationController::run_note_select_dialog)));
+ menu->popup(1, ev->time);
+ return true;
+ } else if (desc.unit == ARDOUR::ParameterDescriptor::HZ) {
+ Gtk::Menu* menu = manage(new Menu());
+ MenuList& items = menu->items();
+ items.push_back(MenuElem(_("Halve"),
+ sigc::bind(sigc::mem_fun(*this, &AutomationController::set_ratio),
+ 0.5)));
+ items.push_back(MenuElem(_("Double"),
+ sigc::bind(sigc::mem_fun(*this, &AutomationController::set_ratio),
+ 2.0)));
+ const bool is_audible = desc.upper > 40.0;
+ const bool is_low = desc.lower < 1.0;
+ if (is_audible) {
+ items.push_back(MenuElem(_("Select Note..."),
+ sigc::mem_fun(*this, &AutomationController::run_note_select_dialog)));
+ }
+ if (is_low) {
+ for (double beats = 1.0; beats <= 16; ++beats) {
+ items.push_back(MenuElem(string_compose(_("Set to %1 beat(s)"), (int)beats),
+ sigc::bind(sigc::mem_fun(*this, &AutomationController::set_freq_beats),
+ beats)));
+ }
+ }
+ menu->popup(1, ev->time);
+ return true;
+ }
+
+ return false;