summaryrefslogtreecommitdiff
path: root/libs/surfaces/push2
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-07-07 15:53:19 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2016-09-27 14:59:30 -0500
commit70477e6fedee80a4e785d4da65c873329d06f76a (patch)
treeaa35d35bcf352a96b8b9c421f817c16d8483d8e0 /libs/surfaces/push2
parent2aec2161f9a0124fc5ad5a7843e03a1507a24627 (diff)
push2: almost fully operational ableton style pad mapping, etc
Diffstat (limited to 'libs/surfaces/push2')
-rw-r--r--libs/surfaces/push2/gui.cc23
-rw-r--r--libs/surfaces/push2/gui.h3
-rw-r--r--libs/surfaces/push2/push2.cc215
-rw-r--r--libs/surfaces/push2/push2.h10
4 files changed, 195 insertions, 56 deletions
diff --git a/libs/surfaces/push2/gui.cc b/libs/surfaces/push2/gui.cc
index 8398132d3e..0c417276c4 100644
--- a/libs/surfaces/push2/gui.cc
+++ b/libs/surfaces/push2/gui.cc
@@ -86,10 +86,11 @@ P2GUI::P2GUI (Push2& p)
, 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)
+ , root_note_octave_label (_("Octave"))
+ , root_note_label (_("Root"))
+ , mode_label (_("Mode (Scale)"))
+ , inkey_button (_("In-Key Mode"))
+ , mode_packer (3, 3)
{
set_border_width (12);
@@ -156,6 +157,8 @@ P2GUI::P2GUI (Push2& p)
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);
+ mode_packer.attach (inkey_button, 1, 2, 3, 4, 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"));
@@ -163,6 +166,7 @@ P2GUI::P2GUI (Push2& p)
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));
+ inkey_button.signal_clicked().connect (sigc::mem_fun (*this, &P2GUI::reprogram_pad_scale));
set_spacing (12);
@@ -447,15 +451,15 @@ P2GUI::build_pad_table ()
{
container_clear (pad_table);
- for (int row = 0; row < 8; ++row) {
+ for (int row = 7; row >= 0; --row) {
for (int col = 0; col < 8; ++col) {
- int n = (int) p2.pad_note (row, col);
+ int n = p2.pad_note (row, col);
Gtk::Button* b = manage (new Button (string_compose ("%1 (%2)", Evoral::midi_note_name (n), n)));
b->show ();
- pad_table.attach (*b, col, col+1, row, row + 1);
+ pad_table.attach (*b, col, col+1, (7-row), (8-row));
}
}
}
@@ -684,6 +688,7 @@ P2GUI::reprogram_pad_scale ()
int root;
int octave;
MusicalMode::Type mode;
+ bool inkey;
Gtk::TreeModel::iterator iter = root_note_selector.get_active();
if (iter) {
@@ -711,5 +716,7 @@ P2GUI::reprogram_pad_scale ()
mode = MusicalMode::IonianMajor;
}
- p2.set_pad_scale (root, octave, mode);
+ inkey = inkey_button.get_active ();
+
+ p2.set_pad_scale (root, octave, mode, inkey);
}
diff --git a/libs/surfaces/push2/gui.h b/libs/surfaces/push2/gui.h
index 1c38a16c2d..b472698fee 100644
--- a/libs/surfaces/push2/gui.h
+++ b/libs/surfaces/push2/gui.h
@@ -24,6 +24,7 @@
#include <string>
#include <gtkmm/box.h>
+#include <gtkmm/button.h>
#include <gtkmm/combobox.h>
#include <gtkmm/image.h>
#include <gtkmm/table.h>
@@ -136,6 +137,8 @@ private:
Gtk::ComboBox mode_selector;
Gtk::Label mode_label;
+ Gtk::CheckButton inkey_button;
+
Gtk::Notebook pad_notebook;
Gtk::Table mode_packer;
Gtk::VBox custom_packer;
diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc
index a9de0aee01..d5672fe886 100644
--- a/libs/surfaces/push2/push2.cc
+++ b/libs/surfaces/push2/push2.cc
@@ -26,6 +26,7 @@
#include "pbd/failed_constructor.h"
#include "pbd/file_utils.h"
#include "pbd/search_path.h"
+#include "pbd/enumwriter.h"
#include "midi++/parser.h"
#include "timecode/time.h"
@@ -61,6 +62,59 @@ const int Push2::pixels_per_row = 1024;
#define ABLETON 0x2982
#define PUSH2 0x1967
+__attribute__((constructor)) static void
+register_enums ()
+{
+ EnumWriter& enum_writer (EnumWriter::instance());
+ vector<int> i;
+ vector<string> s;
+
+ MusicalMode::Type mode;
+
+#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
+#define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
+
+ REGISTER_CLASS_ENUM (MusicalMode,Dorian);
+ REGISTER_CLASS_ENUM (MusicalMode, IonianMajor);
+ REGISTER_CLASS_ENUM (MusicalMode, Minor);
+ REGISTER_CLASS_ENUM (MusicalMode, HarmonicMinor);
+ REGISTER_CLASS_ENUM (MusicalMode, MelodicMinorAscending);
+ REGISTER_CLASS_ENUM (MusicalMode, MelodicMinorDescending);
+ REGISTER_CLASS_ENUM (MusicalMode, Phrygian);
+ REGISTER_CLASS_ENUM (MusicalMode, Lydian);
+ REGISTER_CLASS_ENUM (MusicalMode, Mixolydian);
+ REGISTER_CLASS_ENUM (MusicalMode, Aeolian);
+ REGISTER_CLASS_ENUM (MusicalMode, Locrian);
+ REGISTER_CLASS_ENUM (MusicalMode, PentatonicMajor);
+ REGISTER_CLASS_ENUM (MusicalMode, PentatonicMinor);
+ REGISTER_CLASS_ENUM (MusicalMode, Chromatic);
+ REGISTER_CLASS_ENUM (MusicalMode, BluesScale);
+ REGISTER_CLASS_ENUM (MusicalMode, NeapolitanMinor);
+ REGISTER_CLASS_ENUM (MusicalMode, NeapolitanMajor);
+ REGISTER_CLASS_ENUM (MusicalMode, Oriental);
+ REGISTER_CLASS_ENUM (MusicalMode, DoubleHarmonic);
+ REGISTER_CLASS_ENUM (MusicalMode, Enigmatic);
+ REGISTER_CLASS_ENUM (MusicalMode, Hirajoshi);
+ REGISTER_CLASS_ENUM (MusicalMode, HungarianMinor);
+ REGISTER_CLASS_ENUM (MusicalMode, HungarianMajor);
+ REGISTER_CLASS_ENUM (MusicalMode, Kumoi);
+ REGISTER_CLASS_ENUM (MusicalMode, Iwato);
+ REGISTER_CLASS_ENUM (MusicalMode, Hindu);
+ REGISTER_CLASS_ENUM (MusicalMode, Spanish8Tone);
+ REGISTER_CLASS_ENUM (MusicalMode, Pelog);
+ REGISTER_CLASS_ENUM (MusicalMode, HungarianGypsy);
+ REGISTER_CLASS_ENUM (MusicalMode, Overtone);
+ REGISTER_CLASS_ENUM (MusicalMode, LeadingWholeTone);
+ REGISTER_CLASS_ENUM (MusicalMode, Arabian);
+ REGISTER_CLASS_ENUM (MusicalMode, Balinese);
+ REGISTER_CLASS_ENUM (MusicalMode, Gypsy);
+ REGISTER_CLASS_ENUM (MusicalMode, Mohammedan);
+ REGISTER_CLASS_ENUM (MusicalMode, Javanese);
+ REGISTER_CLASS_ENUM (MusicalMode, Persian);
+ REGISTER_CLASS_ENUM (MusicalMode, Algerian);
+ REGISTER (mode);
+}
+
Push2::Push2 (ARDOUR::Session& s)
: ControlProtocol (s, string (X_("Ableton Push 2")))
, AbstractUI<Push2Request> (name())
@@ -72,6 +126,10 @@ Push2::Push2 (ARDOUR::Session& s)
, bank_start (0)
, connection_state (ConnectionState (0))
, gui (0)
+ , mode (MusicalMode::IonianMajor)
+ , scale_root (36)
+ , root_octave (3)
+ , in_key (true)
, octave_shift (0)
{
context = Cairo::Context::create (frame_buffer);
@@ -292,12 +350,14 @@ Push2::init_buttons (bool startup)
}
}
- for (NNPadMap::iterator pi = nn_pad_map.begin(); pi != nn_pad_map.end(); ++pi) {
- Pad* pad = pi->second;
+ if (!startup) {
+ for (NNPadMap::iterator pi = nn_pad_map.begin(); pi != nn_pad_map.end(); ++pi) {
+ Pad* pad = pi->second;
- pad->set_color (LED::Black);
- pad->set_state (LED::OneShot24th);
- write (pad->state_msg());
+ pad->set_color (LED::Black);
+ pad->set_state (LED::OneShot24th);
+ write (pad->state_msg());
+ }
}
}
@@ -591,6 +651,7 @@ Push2::set_active (bool yn)
init_buttons (true);
init_touch_strip ();
+ set_pad_scale (scale_root, root_octave, mode, in_key);
switch_bank (0);
splash ();
@@ -1053,6 +1114,11 @@ Push2::get_state()
child->add_child_nocopy (_async_out->get_state());
node.add_child_nocopy (*child);
+ node.add_property ("root", to_string (scale_root, std::dec));
+ node.add_property ("root_octave", to_string (root_octave, std::dec));
+ node.add_property ("in_key", in_key ? X_("yes") : X_("no"));
+ node.add_property ("mode", enum_2_string (mode));
+
return node;
}
@@ -1656,51 +1722,39 @@ Push2::build_pad_table ()
PadChange (); /* emit signal */
}
-uint8_t
+int
Push2::pad_note (int row, int col) const
{
- map<int,int>::const_iterator ni = pad_map.find (row*8+col);
+ NNPadMap::const_iterator nni = nn_pad_map.find (36+(row*8)+col);
- if (ni != pad_map.end()) {
- return ni->second;
+ if (nni != nn_pad_map.end()) {
+ return nni->second->filtered;
}
return 0;
}
void
-Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode)
+Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey)
{
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;
+ const int original_root = root;
interval = m.steps.begin();
root += (octave*12);
note = root;
- set<int> mode_map; /* contains only notes in mode */
+ const int root_start = root;
+
+ set<int> mode_map; /* contains only notes in mode, O(logN) lookup */
+ vector<int> mode_vector; /* sorted in note order */
mode_map.insert (note);
+ mode_vector.push_back (note);
while (note < 128) {
@@ -1714,37 +1768,106 @@ Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode)
interval = m.steps.begin();
root += 12;
mode_map.insert (root);
+ mode_vector.push_back (root);
} else {
note = (int) floor (root + (2.0 * (*interval)));
interval++;
mode_map.insert (note);
+ mode_vector.push_back (note);
}
}
- for (note = 36; note < 100; ++note) {
- Pad* pad = nn_pad_map[note];
+ if (inkey) {
- 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;
+ vector<int>::iterator notei;
+ int row_offset = 0;
+ for (int row = 0; row < 8; ++row) {
+
+ /* Ableton's grid layout wraps the available notes in the scale
+ * by offsetting 3 notes per row (from the bottom)
+ */
+
+ notei = mode_vector.begin();
+ notei += row_offset;
+ row_offset += 3;
+
+ for (int col = 0; col < 8; ++col) {
+ int index = 36 + (row*8) + col;
+ Pad* pad = nn_pad_map[index];
+ int notenum;
+ if (notei != mode_vector.end()) {
+
+ notenum = *notei;
+ pad->filtered = notenum;
+
+ if ((notenum % 12) == original_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;
+ notei++;
+
+ } else {
+
+ pad->set_color (LED::Black);
+ pad->do_when_pressed = Pad::Nothing;
+ pad->filtered = -1;
+ }
+
+ write (pad->state_msg());
}
- 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());
+ } else {
+
+ /* chromatic: all notes available, but highlight those in the scale */
+
+ for (note = 36; note < 100; ++note) {
+
+ Pad* pad = nn_pad_map[note];
+
+ /* Chromatic: all pads play, half-tone steps. Light
+ * those in the scale, and highlight root notes
+ */
+
+ pad->filtered = root_start + (note - 36);
+
+ if (mode_map.find (note) != mode_map.end()) {
+
+ if ((note % 12) == original_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;
+
+ } else {
+
+ /* note is not in mode, turn it off */
+
+ pad->do_when_pressed = Pad::FlashOn;
+ pad->set_color (LED::Black);
+
+ }
+
+ write (pad->state_msg());
+ }
}
PadChange (); /* EMIT SIGNAL */
+
+ /* store state */
+
+ scale_root = root;
+ root_octave = octave;
+ in_key = inkey;
+ mode = mode;
}
diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h
index 806d5d0ad1..e39c07e76c 100644
--- a/libs/surfaces/push2/push2.h
+++ b/libs/surfaces/push2/push2.h
@@ -95,10 +95,10 @@ class Push2 : public ARDOUR::ControlProtocol
boost::shared_ptr<ARDOUR::Port> input_port();
boost::shared_ptr<ARDOUR::Port> output_port();
- uint8_t pad_note (int row, int col) const;
+ int pad_note (int row, int col) const;
PBD::Signal0<void> PadChange;
- void set_pad_scale (int root, int octave, MusicalMode::Type mode);
+ void set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey);
private:
libusb_device_handle *handle;
@@ -513,6 +513,12 @@ class Push2 : public ARDOUR::ControlProtocol
std::map<int,int> pad_map;
void build_pad_table();
+
+ MusicalMode::Type mode;
+ int scale_root;
+ int root_octave;
+ bool in_key;
+
int octave_shift;
};