mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-03 12:19:33 +01:00
push2: almost fully operational ableton style pad mapping, etc
This commit is contained in:
parent
2aec2161f9
commit
70477e6fed
4 changed files with 195 additions and 56 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue