push2: initial sort of working pad remapping

This commit is contained in:
Paul Davis
2016-07-07 14:26:55 -04:00
parent 597c737ab5
commit 2aec2161f9
8 changed files with 323 additions and 90 deletions

View File

@@ -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);

View File

@@ -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);
@@ -445,17 +466,29 @@ P2GUI::build_mode_columns ()
Glib::RefPtr<Gtk::ListStore> store = ListStore::create (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");
@@ -485,22 +518,6 @@ P2GUI::build_mode_columns ()
row[mode_columns.name] = _("Pentatonic Minor");
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);
}

View File

@@ -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 ();
};
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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 ();
const int n = (*ev).note ();
NNPadMap::const_iterator nni = nn_pad_map.find (n);
map<int,int>::const_iterator ni = 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 */
}

View File

@@ -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 {

View File

@@ -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"' ]