diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2016-07-07 14:26:55 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2016-09-27 14:59:30 -0500 |
commit | 2aec2161f9a0124fc5ad5a7843e03a1507a24627 (patch) | |
tree | 1e828528b15510f8c218749c6039238683230096 /libs | |
parent | 597c737ab57fda950768de19fffd6dd70fb2df49 (diff) |
push2: initial sort of working pad remapping
Diffstat (limited to 'libs')
-rw-r--r-- | libs/surfaces/push2/buttons.cc | 3 | ||||
-rw-r--r-- | libs/surfaces/push2/gui.cc | 153 | ||||
-rw-r--r-- | libs/surfaces/push2/gui.h | 15 | ||||
-rw-r--r-- | libs/surfaces/push2/mode.cc | 75 | ||||
-rw-r--r-- | libs/surfaces/push2/mode.h | 11 | ||||
-rw-r--r-- | libs/surfaces/push2/push2.cc | 133 | ||||
-rw-r--r-- | libs/surfaces/push2/push2.h | 20 | ||||
-rw-r--r-- | libs/surfaces/push2/wscript | 3 |
8 files changed, 323 insertions, 90 deletions
diff --git a/libs/surfaces/push2/buttons.cc b/libs/surfaces/push2/buttons.cc index 0c443cb1ec..7bcdff0d77 100644 --- a/libs/surfaces/push2/buttons.cc +++ b/libs/surfaces/push2/buttons.cc @@ -42,13 +42,14 @@ Push2::build_maps () nn_pad_map.insert (std::make_pair (pad->extra(), pad)); \ coord_pad_map.insert (std::make_pair (pad->coord(), pad)); + MAKE_PAD (0, 0, 92); MAKE_PAD (0, 1, 93); MAKE_PAD (0, 2, 94); MAKE_PAD (0, 3, 95); MAKE_PAD (0, 4, 96); MAKE_PAD (0, 5, 97); MAKE_PAD (0, 6, 98); - MAKE_PAD (0, 7, 90); + MAKE_PAD (0, 7, 99); MAKE_PAD (1, 0, 84); MAKE_PAD (1, 1, 85); MAKE_PAD (1, 2, 86); diff --git a/libs/surfaces/push2/gui.cc b/libs/surfaces/push2/gui.cc index 78772aeefd..8398132d3e 100644 --- a/libs/surfaces/push2/gui.cc +++ b/libs/surfaces/push2/gui.cc @@ -84,6 +84,12 @@ P2GUI::P2GUI (Push2& p) , action_table (5, 4) , ignore_active_change (false) , pad_table (8, 8) + , root_note_octave_adjustment (3, 0, 10, 1, 1) + , root_note_octave (root_note_octave_adjustment) + , root_note_octave_label (X_("Octave")) + , root_note_label (X_("Root")) + , mode_label (X_("Mode (Scale)")) + , mode_packer (3, 2) { set_border_width (12); @@ -132,17 +138,32 @@ P2GUI::P2GUI (Push2& p) root_note_selector.set_model (build_note_columns()); root_note_selector.pack_start (note_columns.name); + root_note_selector.set_active (0); mode_selector.set_model (build_mode_columns()); mode_selector.pack_start (mode_columns.name); + mode_selector.set_active (0); - mode_packer.pack_start (root_note_selector, false, false); - mode_packer.pack_start (mode_selector, false, false); + mode_packer.set_border_width (12); + mode_packer.set_spacings (12); + + mode_packer.attach (root_note_label, 0, 1, 0, 1, AttachOptions (FILL|EXPAND), SHRINK); + mode_packer.attach (root_note_selector, 1, 2, 0, 1, AttachOptions (FILL|EXPAND), SHRINK); + + mode_packer.attach (root_note_octave_label, 0, 1, 1, 2, AttachOptions (FILL|EXPAND), SHRINK); + mode_packer.attach (root_note_octave, 1, 2, 1, 2, AttachOptions (FILL|EXPAND), SHRINK); + + mode_packer.attach (mode_label, 0, 1, 2, 3, AttachOptions (FILL|EXPAND), SHRINK); + mode_packer.attach (mode_selector, 1, 2, 2, 3, AttachOptions (FILL|EXPAND), SHRINK); pad_notebook.append_page (pad_table, _("Pad Layout")); pad_notebook.append_page (mode_packer, _("Modes/Scales")); pad_notebook.append_page (custom_packer, _("Custom")); + root_note_octave_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &P2GUI::reprogram_pad_scale)); + root_note_selector.signal_changed().connect (sigc::mem_fun (*this, &P2GUI::reprogram_pad_scale)); + mode_selector.signal_changed().connect (sigc::mem_fun (*this, &P2GUI::reprogram_pad_scale)); + set_spacing (12); pack_start (hpacker, false, false); @@ -446,16 +467,28 @@ P2GUI::build_mode_columns () TreeModel::Row row; row = *store->append(); - row[mode_columns.name] = _("Random"); - row[mode_columns.mode] = MusicalMode::Random; - - row = *store->append(); row[mode_columns.name] = _("Dorian"); row[mode_columns.mode] = MusicalMode::Dorian; row = *store->append(); - row[mode_columns.name] = _("Ionian (\"Minor\")"); - row[mode_columns.mode] = MusicalMode::Ionian; + row[mode_columns.name] = _("Ionian (\"Major\")"); + row[mode_columns.mode] = MusicalMode::IonianMajor; + + row = *store->append(); + row[mode_columns.name] = _("Minor"); + row[mode_columns.mode] = MusicalMode::Minor; + + row = *store->append(); + row[mode_columns.name] = _("Harmonic Minor"); + row[mode_columns.mode] = MusicalMode::HarmonicMinor; + + row = *store->append(); + row[mode_columns.name] = _("Melodic Minor Ascending"); + row[mode_columns.mode] = MusicalMode::MelodicMinorAscending; + + row = *store->append(); + row[mode_columns.name] = _("Melodic Minor Descending"); + row[mode_columns.mode] = MusicalMode::MelodicMinorDescending; row = *store->append(); row[mode_columns.name] = _("Phrygian"); @@ -486,22 +519,6 @@ P2GUI::build_mode_columns () row[mode_columns.mode] = MusicalMode::PentatonicMinor; row = *store->append(); - row[mode_columns.name] = _("Major Chord"); - row[mode_columns.mode] = MusicalMode::MajorChord; - - row = *store->append(); - row[mode_columns.name] = _("Minor Chord"); - row[mode_columns.mode] = MusicalMode::MinorChord; - - row = *store->append(); - row[mode_columns.name] = _("Min7"); - row[mode_columns.mode] = MusicalMode::Min7; - - row = *store->append(); - row[mode_columns.name] = _("Sus4"); - row[mode_columns.mode] = MusicalMode::Sus4; - - row = *store->append(); row[mode_columns.name] = _("Chromatic"); row[mode_columns.mode] = MusicalMode::Chromatic; @@ -610,11 +627,89 @@ P2GUI::build_note_columns () Glib::RefPtr<Gtk::ListStore> store = ListStore::create (note_columns); TreeModel::Row row; - for (int n = 0; n < 127; ++n) { - row = *store->append (); - row[note_columns.number] = n; - row[note_columns.name] = Evoral::midi_note_name (n); - } + row = *store->append (); + row[note_columns.number] = 0; + row[note_columns.name] = "C"; + + row = *store->append (); + row[note_columns.number] = 1; + row[note_columns.name] = "C#"; + + row = *store->append (); + row[note_columns.number] = 2; + row[note_columns.name] = "D"; + + row = *store->append (); + row[note_columns.number] = 3; + row[note_columns.name] = "D#"; + + row = *store->append (); + row[note_columns.number] = 4; + row[note_columns.name] = "E"; + + row = *store->append (); + row[note_columns.number] = 5; + row[note_columns.name] = "F"; + + row = *store->append (); + row[note_columns.number] = 6; + row[note_columns.name] = "F#"; + + row = *store->append (); + row[note_columns.number] = 7; + row[note_columns.name] = "G"; + + row = *store->append (); + row[note_columns.number] = 8; + row[note_columns.name] = "G#"; + + row = *store->append (); + row[note_columns.number] = 9; + row[note_columns.name] = "A"; + + row = *store->append (); + row[note_columns.number] = 10; + row[note_columns.name] = "A#"; + + row = *store->append (); + row[note_columns.number] = 11; + row[note_columns.name] = "B"; return store; } + +void +P2GUI::reprogram_pad_scale () +{ + int root; + int octave; + MusicalMode::Type mode; + + Gtk::TreeModel::iterator iter = root_note_selector.get_active(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + if (row) { + root = row[note_columns.number]; + } else { + root = 5; + } + } else { + root = 5; + } + + octave = (int) floor (root_note_octave_adjustment.get_value ()); + + iter = mode_selector.get_active(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + if (row) { + mode = row[mode_columns.mode]; + } else { + mode = MusicalMode::IonianMajor; + } + } else { + mode = MusicalMode::IonianMajor; + } + + p2.set_pad_scale (root, octave, mode); +} diff --git a/libs/surfaces/push2/gui.h b/libs/surfaces/push2/gui.h index 2ec6281a52..1c38a16c2d 100644 --- a/libs/surfaces/push2/gui.h +++ b/libs/surfaces/push2/gui.h @@ -28,6 +28,7 @@ #include <gtkmm/image.h> #include <gtkmm/table.h> #include <gtkmm/treestore.h> +#include <gtkmm/spinbutton.h> #include <gtkmm/notebook.h> namespace Gtk { @@ -99,6 +100,12 @@ private: /* root notes */ + Gtk::Adjustment root_note_octave_adjustment; + Gtk::SpinButton root_note_octave; + Gtk::Label root_note_octave_label; + + void root_note_octave_adjustment_changed (); + struct NoteColumns : public Gtk::TreeModel::ColumnRecord { NoteColumns () { add (number); @@ -110,6 +117,9 @@ private: NoteColumns note_columns; Glib::RefPtr<Gtk::ListStore> build_note_columns (); Gtk::ComboBox root_note_selector; + Gtk::Label root_note_label; + + void root_note_changed (); /* modes/scales */ @@ -124,10 +134,13 @@ private: ModeColumns mode_columns; Glib::RefPtr<Gtk::ListStore> build_mode_columns (); Gtk::ComboBox mode_selector; + Gtk::Label mode_label; Gtk::Notebook pad_notebook; - Gtk::VBox mode_packer; + Gtk::Table mode_packer; Gtk::VBox custom_packer; + + void reprogram_pad_scale (); }; } diff --git a/libs/surfaces/push2/mode.cc b/libs/surfaces/push2/mode.cc index 324c53caba..99efc86c02 100644 --- a/libs/surfaces/push2/mode.cc +++ b/libs/surfaces/push2/mode.cc @@ -19,9 +19,6 @@ MusicalMode::fill (MusicalMode& m, MusicalMode::Type t) */ switch (t) { - case Random: - m.steps.push_back (0.0); // sekrit code for "random" - break; case Dorian: m.steps.push_back (1.0); m.steps.push_back (1.5); @@ -29,8 +26,9 @@ MusicalMode::fill (MusicalMode& m, MusicalMode::Type t) m.steps.push_back (3.0); m.steps.push_back (4.0); m.steps.push_back (4.5); + m.steps.push_back (5.5); break; - case Ionian: + case IonianMajor: m.steps.push_back (1.0); m.steps.push_back (2.0); m.steps.push_back (2.5); @@ -38,6 +36,48 @@ MusicalMode::fill (MusicalMode& m, MusicalMode::Type t) m.steps.push_back (4.5); m.steps.push_back (5.5); break; + case Minor: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + break; + case HarmonicMinor: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (5.0); + m.steps.push_back (5.5); + break; + case BluesScale: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (2.5); + m.steps.push_back (3); + m.steps.push_back (3.5); + m.steps.push_back (4.5); + m.steps.push_back (5.0); + m.steps.push_back (5.5); + break; + case MelodicMinorAscending: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (4.5); + m.steps.push_back (5.5); + break; + case MelodicMinorDescending: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (4.5); + m.steps.push_back (5.0); + break; case Phrygian: m.steps.push_back (0.5); m.steps.push_back (1.5); @@ -90,23 +130,6 @@ MusicalMode::fill (MusicalMode& m, MusicalMode::Type t) m.steps.push_back (3.5); m.steps.push_back (5.0); break; - case MajorChord: - m.steps.push_back (2.0); - m.steps.push_back (3.5); - break; - case MinorChord: - m.steps.push_back (1.5); - m.steps.push_back (3.5); - break; - case Min7: - m.steps.push_back (1.5); - m.steps.push_back (3.5); - m.steps.push_back (5.0); - break; - case Sus4: - m.steps.push_back (2.5); - m.steps.push_back (3.5); - break; case Chromatic: m.steps.push_back (0.5); m.steps.push_back (1.0); @@ -120,16 +143,6 @@ MusicalMode::fill (MusicalMode& m, MusicalMode::Type t) m.steps.push_back (5.0); m.steps.push_back (5.5); break; - case BluesScale: - m.steps.push_back (1.0); - m.steps.push_back (1.5); - m.steps.push_back (2.5); - m.steps.push_back (3); - m.steps.push_back (3.5); - m.steps.push_back (4.5); - m.steps.push_back (5.0); - m.steps.push_back (5.5); - break; case NeapolitanMinor: m.steps.push_back (0.5); m.steps.push_back (1.5); diff --git a/libs/surfaces/push2/mode.h b/libs/surfaces/push2/mode.h index e638d53164..4f570f998d 100644 --- a/libs/surfaces/push2/mode.h +++ b/libs/surfaces/push2/mode.h @@ -7,9 +7,12 @@ class MusicalMode { public: enum Type { - Random, Dorian, - Ionian, + IonianMajor, + Minor, + HarmonicMinor, + MelodicMinorAscending, + MelodicMinorDescending, Phrygian, Lydian, Mixolydian, @@ -17,10 +20,6 @@ class MusicalMode Locrian, PentatonicMajor, PentatonicMinor, - MajorChord, - MinorChord, - Min7, - Sus4, Chromatic, BluesScale, NeapolitanMinor, diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index 40a454211f..a9de0aee01 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -107,13 +107,13 @@ Push2::Push2 (ARDOUR::Session& s) StripableSelectionChanged.connect (selection_connection, MISSING_INVALIDATOR, boost::bind (&Push2::stripable_selection_change, this, _1), this); + /* catch arrival and departure of Push2 itself */ ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (port_reg_connection, MISSING_INVALIDATOR, boost::bind (&Push2::port_registration_handler, this), this); /* Catch port connections and disconnections */ ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&Push2::connection_handler, this, _1, _2, _3, _4, _5), this); /* ports might already be there */ - port_registration_handler (); } @@ -848,9 +848,15 @@ Push2::handle_midi_note_on_message (MIDI::Parser& parser, MIDI::EventTwoBytes* e Pad* pad = pi->second; - pad->set_color (LED::White); - pad->set_state (LED::OneShot24th); - write (pad->state_msg()); + if (pad->do_when_pressed == Pad::FlashOn) { + pad->set_color (LED::White); + pad->set_state (LED::OneShot24th); + write (pad->state_msg()); + } else if (pad->do_when_pressed == Pad::FlashOff) { + pad->set_color (LED::Black); + pad->set_state (LED::OneShot24th); + write (pad->state_msg()); + } } void @@ -874,9 +880,15 @@ Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev) Pad* pad = pi->second; - pad->set_color (LED::Black); - pad->set_state (LED::OneShot24th); - write (pad->state_msg()); + if (pad->do_when_pressed == Pad::FlashOn) { + pad->set_color (LED::Black); + pad->set_state (LED::OneShot24th); + write (pad->state_msg()); + } else if (pad->do_when_pressed == Pad::FlashOff) { + pad->set_color (pad->perma_color); + pad->set_state (LED::OneShot24th); + write (pad->state_msg()); + } } void @@ -1545,16 +1557,20 @@ Push2::pad_filter (MidiBuffer& in, MidiBuffer& out) const if ((*ev).note() > 10 && (*ev).note() != 12) { - int n = (*ev).note (); - - map<int,int>::const_iterator ni = pad_map.find (n); + const int n = (*ev).note (); + NNPadMap::const_iterator nni = nn_pad_map.find (n); - if (ni != pad_map.end()) { + if (nni != nn_pad_map.end()) { + Pad const * pad = nni->second; /* shift for output to the shadow port */ - (*ev).set_note (ni->second); - out.push_back (*ev); - /* shift back so that the pads light correctly */ - (*ev).set_note (n); + if (pad->filtered >= 0) { + (*ev).set_note (pad->filtered); + out.push_back (*ev); + /* shift back so that the pads light correctly */ + (*ev).set_note (n); + } else { + /* no mapping, don't send event */ + } } else { out.push_back (*ev); } @@ -1633,10 +1649,8 @@ Push2::input_port() void Push2::build_pad_table () { - for (int row = 0; row < 8; ++row) { - for (int col = 7; col >= 0; --col) { - pad_map[row*8+col] = 99 - (row*8+(7-col)) + (octave_shift*12); - } + for (int n = 36; n < 100; ++n) { + pad_map[n] = n + (octave_shift*12); } PadChange (); /* emit signal */ @@ -1653,3 +1667,84 @@ Push2::pad_note (int row, int col) const return 0; } + +void +Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode) +{ + cerr << "reset pad to r = " << root << " o = " << octave << " m = " << mode << endl; + + MusicalMode m (mode); + + if (mode == MusicalMode::Chromatic) { + /* back to "normal" */ + for (int note = 36; note < 100; ++note) { + Pad* pad = nn_pad_map[note]; + pad->do_when_pressed = Pad::FlashOn; + pad->set_color (LED::Black); + pad->perma_color = LED::Black; + pad->filtered = note; + write (pad->state_msg()); + } + + PadChange (); + return; + } + + vector<float>::iterator interval; + int note; + int keep_root = root; + + interval = m.steps.begin(); + root += (octave*12); + note = root; + + set<int> mode_map; /* contains only notes in mode */ + + mode_map.insert (note); + + while (note < 128) { + + if (interval == m.steps.end()) { + + /* last distance was the end of the scale, + so wrap, adding the next note at one + octave above the last root. + */ + + interval = m.steps.begin(); + root += 12; + mode_map.insert (root); + + } else { + note = (int) floor (root + (2.0 * (*interval))); + interval++; + mode_map.insert (note); + } + } + + for (note = 36; note < 100; ++note) { + Pad* pad = nn_pad_map[note]; + + if (mode_map.find (note) != mode_map.end()) { + if ((note % 12) == keep_root) { + pad->set_color (LED::Green); + pad->perma_color = LED::Green; + } else { + pad->set_color (LED::White); + pad->perma_color = LED::White; + } + pad->do_when_pressed = Pad::FlashOff; + /* Chromatic: all pads send their own note number */ + pad->filtered = note; + } else { + /* note is not in mode, turn it off */ + pad->do_when_pressed = Pad::Nothing; + pad->set_color (LED::Black); + pad->filtered = -1; + } + + write (pad->state_msg()); + } + + PadChange (); /* EMIT SIGNAL */ +} diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index e065dc590a..806d5d0ad1 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -39,6 +39,7 @@ #include "control_protocol/types.h" #include "midi_byte_array.h" +#include "mode.h" namespace Cairo { class ImageSurface; @@ -97,6 +98,8 @@ class Push2 : public ARDOUR::ControlProtocol uint8_t pad_note (int row, int col) const; PBD::Signal0<void> PadChange; + void set_pad_scale (int root, int octave, MusicalMode::Type mode); + private: libusb_device_handle *handle; uint8_t frame_header[16]; @@ -211,7 +214,7 @@ class Push2 : public ARDOUR::ControlProtocol White = 122 }; - LED (uint8_t e) : _extra (e), _color_index (0), _state (NoTransition) {} + LED (uint8_t e) : _extra (e), _color_index (Black), _state (NoTransition) {} virtual ~LED() {} uint8_t extra () const { return _extra; } @@ -230,10 +233,20 @@ class Push2 : public ARDOUR::ControlProtocol }; struct Pad : public LED { + enum WhenPressed { + Nothing, + FlashOn, + FlashOff, + }; + Pad (int xx, int yy, uint8_t ex) : LED (ex) , x (xx) - , y (yy) {} + , y (yy) + , do_when_pressed (FlashOn) + , filtered (ex) + , perma_color (LED::Black) + {} MidiByteArray state_msg () const { return MidiByteArray (3, 0x90|_state, _extra, _color_index); } @@ -242,6 +255,9 @@ class Push2 : public ARDOUR::ControlProtocol int x; int y; + int do_when_pressed; + int filtered; + int perma_color; }; struct Button : public LED { diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript index 322b08f07e..b69d4a22ce 100644 --- a/libs/surfaces/push2/wscript +++ b/libs/surfaces/push2/wscript @@ -25,7 +25,8 @@ def build(bld): interface.cc midi_byte_array.cc leds.cc - gui.cc + gui.cc + mode.cc ''' obj.export_includes = ['.'] obj.defines = [ 'PACKAGE="ardour_push2"' ] |