diff --git a/libs/surfaces/push2/gui.cc b/libs/surfaces/push2/gui.cc index 2606418eab..78772aeefd 100644 --- a/libs/surfaces/push2/gui.cc +++ b/libs/surfaces/push2/gui.cc @@ -32,6 +32,8 @@ #include "ardour/audioengine.h" #include "ardour/filesystem_paths.h" +#include "evoral/midi_util.h" + #include "push2.h" #include "gui.h" @@ -125,12 +127,26 @@ P2GUI::P2GUI (Push2& p) hpacker.pack_start (table, true, true); + pad_table.set_spacings (3); build_pad_table (); + root_note_selector.set_model (build_note_columns()); + root_note_selector.pack_start (note_columns.name); + + mode_selector.set_model (build_mode_columns()); + mode_selector.pack_start (mode_columns.name); + + mode_packer.pack_start (root_note_selector, false, false); + mode_packer.pack_start (mode_selector, false, false); + + pad_notebook.append_page (pad_table, _("Pad Layout")); + pad_notebook.append_page (mode_packer, _("Modes/Scales")); + pad_notebook.append_page (custom_packer, _("Custom")); + set_spacing (12); pack_start (hpacker, false, false); - pack_start (pad_table, true, true); + pack_start (pad_notebook); /* update the port connection combos */ @@ -413,10 +429,192 @@ P2GUI::build_pad_table () for (int row = 0; row < 8; ++row) { for (int col = 0; col < 8; ++col) { - Gtk::Button* b = manage (new Button (string_compose ("%1", (int) p2.pad_note (row, col)))); + int n = (int) 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); } } } + +Glib::RefPtr +P2GUI::build_mode_columns () +{ + Glib::RefPtr 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 = *store->append(); + row[mode_columns.name] = _("Phrygian"); + row[mode_columns.mode] = MusicalMode::Phrygian; + + row = *store->append(); + row[mode_columns.name] = _("Lydian"); + row[mode_columns.mode] = MusicalMode::Lydian; + + row = *store->append(); + row[mode_columns.name] = _("Mixolydian"); + row[mode_columns.mode] = MusicalMode::Mixolydian; + + row = *store->append(); + row[mode_columns.name] = _("Aeolian (\"Major\")"); + row[mode_columns.mode] = MusicalMode::Aeolian; + + row = *store->append(); + row[mode_columns.name] = _("Locrian"); + row[mode_columns.mode] = MusicalMode::Locrian; + + row = *store->append(); + row[mode_columns.name] = _("Pentatonic Major"); + row[mode_columns.mode] = MusicalMode::PentatonicMajor; + + row = *store->append(); + 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; + + row = *store->append(); + row[mode_columns.name] = _("Blues Scale"); + row[mode_columns.mode] = MusicalMode::BluesScale; + + row = *store->append(); + row[mode_columns.name] = _("Neapolitan Minor"); + row[mode_columns.mode] = MusicalMode::NeapolitanMinor; + + row = *store->append(); + row[mode_columns.name] = _("Neapolitan Major"); + row[mode_columns.mode] = MusicalMode::NeapolitanMajor; + + row = *store->append(); + row[mode_columns.name] = _("Oriental"); + row[mode_columns.mode] = MusicalMode::Oriental; + + row = *store->append(); + row[mode_columns.name] = _("Double Harmonic"); + row[mode_columns.mode] = MusicalMode::DoubleHarmonic; + + row = *store->append(); + row[mode_columns.name] = _("Enigmatic"); + row[mode_columns.mode] = MusicalMode::Enigmatic; + + row = *store->append(); + row[mode_columns.name] = _("Hirajoshi"); + row[mode_columns.mode] = MusicalMode::Hirajoshi; + + row = *store->append(); + row[mode_columns.name] = _("Hungarian Minor"); + row[mode_columns.mode] = MusicalMode::HungarianMinor; + + row = *store->append(); + row[mode_columns.name] = _("Hungarian Major"); + row[mode_columns.mode] = MusicalMode::HungarianMajor; + + row = *store->append(); + row[mode_columns.name] = _("Kumoi"); + row[mode_columns.mode] = MusicalMode::Kumoi; + + row = *store->append(); + row[mode_columns.name] = _("Iwato"); + row[mode_columns.mode] = MusicalMode::Iwato; + + row = *store->append(); + row[mode_columns.name] = _("Hindu"); + row[mode_columns.mode] = MusicalMode::Hindu; + + row = *store->append(); + row[mode_columns.name] = _("Spanish 8 Tone"); + row[mode_columns.mode] = MusicalMode::Spanish8Tone; + + row = *store->append(); + row[mode_columns.name] = _("Pelog"); + row[mode_columns.mode] = MusicalMode::Pelog; + + row = *store->append(); + row[mode_columns.name] = _("Hungarian Gypsy"); + row[mode_columns.mode] = MusicalMode::HungarianGypsy; + + row = *store->append(); + row[mode_columns.name] = _("Overtone"); + row[mode_columns.mode] = MusicalMode::Overtone; + + row = *store->append(); + row[mode_columns.name] = _("Leading Whole Tone"); + row[mode_columns.mode] = MusicalMode::LeadingWholeTone; + + row = *store->append(); + row[mode_columns.name] = _("Arabian"); + row[mode_columns.mode] = MusicalMode::Arabian; + + row = *store->append(); + row[mode_columns.name] = _("Balinese"); + row[mode_columns.mode] = MusicalMode::Balinese; + + row = *store->append(); + row[mode_columns.name] = _("Gypsy"); + row[mode_columns.mode] = MusicalMode::Gypsy; + + row = *store->append(); + row[mode_columns.name] = _("Mohammedan"); + row[mode_columns.mode] = MusicalMode::Mohammedan; + + row = *store->append(); + row[mode_columns.name] = _("Javanese"); + row[mode_columns.mode] = MusicalMode::Javanese; + + row = *store->append(); + row[mode_columns.name] = _("Persian"); + row[mode_columns.mode] = MusicalMode::Persian; + + row = *store->append(); + row[mode_columns.name] = _("Algerian"); + row[mode_columns.mode] = MusicalMode::Algerian; + + return store; +} + +Glib::RefPtr +P2GUI::build_note_columns () +{ + Glib::RefPtr 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); + } + + return store; +} diff --git a/libs/surfaces/push2/gui.h b/libs/surfaces/push2/gui.h index 314e8081c6..2ec6281a52 100644 --- a/libs/surfaces/push2/gui.h +++ b/libs/surfaces/push2/gui.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace Gtk { class CellRendererCombo; @@ -35,6 +36,7 @@ namespace Gtk { } #include "push2.h" +#include "mode.h" namespace ArdourSurface { @@ -94,6 +96,38 @@ private: /* Pads */ Gtk::Table pad_table; + + /* root notes */ + + struct NoteColumns : public Gtk::TreeModel::ColumnRecord { + NoteColumns () { + add (number); + add (name); + } + Gtk::TreeModelColumn number; + Gtk::TreeModelColumn name; + }; + NoteColumns note_columns; + Glib::RefPtr build_note_columns (); + Gtk::ComboBox root_note_selector; + + /* modes/scales */ + + struct ModeColumns : public Gtk::TreeModel::ColumnRecord { + ModeColumns () { + add (mode); + add (name); + } + Gtk::TreeModelColumn mode; + Gtk::TreeModelColumn name; + }; + ModeColumns mode_columns; + Glib::RefPtr build_mode_columns (); + Gtk::ComboBox mode_selector; + + Gtk::Notebook pad_notebook; + Gtk::VBox mode_packer; + Gtk::VBox custom_packer; }; } diff --git a/libs/surfaces/push2/mode.cc b/libs/surfaces/push2/mode.cc new file mode 100644 index 0000000000..324c53caba --- /dev/null +++ b/libs/surfaces/push2/mode.cc @@ -0,0 +1,313 @@ +#include "mode.h" + +MusicalMode::MusicalMode (MusicalMode::Type t) +{ + fill (*this, t); +} + +MusicalMode::~MusicalMode() +{ +} + +void +MusicalMode::fill (MusicalMode& m, MusicalMode::Type t) +{ + m.steps.clear (); + + /* scales/modes as distances from root, expressed + in fractional whole tones. + */ + + 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); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (4.5); + break; + case Ionian: + 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.5); + break; + case Phrygian: + m.steps.push_back (0.5); + 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 Lydian: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.5); + m.steps.push_back (5.5); + break; + case Mixolydian: + 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 Aeolian: + 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 Locrian: + m.steps.push_back (0.5); + m.steps.push_back (1.5); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + break; + case PentatonicMajor: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + break; + case PentatonicMinor: + m.steps.push_back (1.5); + m.steps.push_back (2.5); + 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); + m.steps.push_back (1.5); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (4.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 NeapolitanMinor: + m.steps.push_back (0.5); + m.steps.push_back (1.5); + m.steps.push_back (2.5); + m.steps.push_back (2.5); + m.steps.push_back (4.0); + m.steps.push_back (5.5); + break; + case NeapolitanMajor: + m.steps.push_back (0.5); + 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 Oriental: + m.steps.push_back (0.5); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.0); + m.steps.push_back (4.5); + m.steps.push_back (5.0); + break; + case DoubleHarmonic: + m.steps.push_back (0.5); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.5); + break; + case Enigmatic: + m.steps.push_back (0.5); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + m.steps.push_back (5.5); + break; + case Hirajoshi: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + break; + case HungarianMinor: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.5); + break; + case HungarianMajor: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + break; + case Kumoi: + m.steps.push_back (0.5); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + break; + case Iwato: + m.steps.push_back (0.5); + m.steps.push_back (2.5); + m.steps.push_back (3.0); + m.steps.push_back (5.0); + break; + case Hindu: + 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.0); + m.steps.push_back (5.0); + break; + case Spanish8Tone: + m.steps.push_back (0.5); + m.steps.push_back (1.5); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + break; + case Pelog: + m.steps.push_back (0.5); + m.steps.push_back (1.5); + m.steps.push_back (3.5); + m.steps.push_back (5.0); + break; + case HungarianGypsy: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + break; + case Overtone: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.5); + m.steps.push_back (5.0); + break; + case LeadingWholeTone: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + m.steps.push_back (5.5); + break; + case Arabian: + m.steps.push_back (1.0); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (5.0); + break; + case Balinese: + m.steps.push_back (0.5); + m.steps.push_back (1.5); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + break; + case Gypsy: + m.steps.push_back (0.5); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.5); + break; + case Mohammedan: + 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.5); + break; + case Javanese: + m.steps.push_back (0.5); + 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.0); + break; + case Persian: + m.steps.push_back (0.5); + m.steps.push_back (2.0); + m.steps.push_back (2.5); + m.steps.push_back (3.0); + m.steps.push_back (4.0); + m.steps.push_back (5.5); + break; + case Algerian: + m.steps.push_back (1.0); + m.steps.push_back (1.5); + m.steps.push_back (3.0); + m.steps.push_back (3.5); + m.steps.push_back (4.0); + m.steps.push_back (5.5); + m.steps.push_back (6.0); + m.steps.push_back (7.0); + m.steps.push_back (7.5); + m.steps.push_back (8.5); + break; + } +} diff --git a/libs/surfaces/push2/mode.h b/libs/surfaces/push2/mode.h new file mode 100644 index 0000000000..e638d53164 --- /dev/null +++ b/libs/surfaces/push2/mode.h @@ -0,0 +1,60 @@ +#ifndef __ardour_push2_mode_h__ +#define __ardour_push2_mode_h__ + +#include + +class MusicalMode +{ + public: + enum Type { + Random, + Dorian, + Ionian, + Phrygian, + Lydian, + Mixolydian, + Aeolian, + Locrian, + PentatonicMajor, + PentatonicMinor, + MajorChord, + MinorChord, + Min7, + Sus4, + Chromatic, + BluesScale, + NeapolitanMinor, + NeapolitanMajor, + Oriental, + DoubleHarmonic, + Enigmatic, + Hirajoshi, + HungarianMinor, + HungarianMajor, + Kumoi, + Iwato, + Hindu, + Spanish8Tone, + Pelog, + HungarianGypsy, + Overtone, + LeadingWholeTone, + Arabian, + Balinese, + Gypsy, + Mohammedan, + Javanese, + Persian, + Algerian + }; + + MusicalMode (Type t); + ~MusicalMode (); + + std::vector steps; + + private: + static void fill (MusicalMode&, Type); +}; + +#endif /* __ardour_push2_mode_h__ */ diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index 0eb1d6cfc7..273c14a3b3 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -1508,9 +1508,12 @@ Push2::pad_filter (MidiBuffer& in, MidiBuffer& out) const for (MidiBuffer::iterator ev = in.begin(); ev != in.end(); ++ev) { if ((*ev).is_note_on() || (*ev).is_note_off()) { - /* encoder touch start/touch end use note 0-10 */ - if ((*ev).note() > 10) { + /* encoder touch start/touch end use note + * 0-10. touchstrip uses note 12 + */ + + if ((*ev).note() > 10 && (*ev).note() != 12) { int n = (*ev).note (); @@ -1600,8 +1603,10 @@ Push2::input_port() void Push2::build_pad_table () { - for (int i = 36; i < 99; ++i) { - pad_map[i] = i + (octave_shift*12); + 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); + } } PadChange (); /* emit signal */ diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript index 2a76b10648..322b08f07e 100644 --- a/libs/surfaces/push2/wscript +++ b/libs/surfaces/push2/wscript @@ -35,7 +35,7 @@ def build(bld): obj.name = 'libardour_push2' obj.target = 'ardour_push2' obj.uselib = 'CAIROMM PANGOMM USB GTKMM' - obj.use = 'libardour libardour_cp libgtkmm2ext libpbd libtimecode' + obj.use = 'libardour libardour_cp libgtkmm2ext libpbd libevoral libtimecode' obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces') def shutdown():