diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2016-09-21 15:25:24 -0500 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2016-09-27 14:59:31 -0500 |
commit | b6ecc56e7a724097ebf6c0589ce64fe1cb409db9 (patch) | |
tree | 18dff5728370fc2286db4fbbaabf46341f2254cb /libs | |
parent | 9cc40aafa0dd06f1449c81fcbccd4a5eb971115d (diff) |
push2: scale selection and display on video display now working
Diffstat (limited to 'libs')
-rw-r--r-- | libs/surfaces/push2/scale.cc | 643 | ||||
-rw-r--r-- | libs/surfaces/push2/scale.h | 36 |
2 files changed, 622 insertions, 57 deletions
diff --git a/libs/surfaces/push2/scale.cc b/libs/surfaces/push2/scale.cc index 5596aa7029..9aa938a470 100644 --- a/libs/surfaces/push2/scale.cc +++ b/libs/surfaces/push2/scale.cc @@ -16,37 +16,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <cairomm/region.h> -#include <pangomm/layout.h> - -#include "pbd/compose.h" -#include "pbd/convert.h" -#include "pbd/debug.h" -#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" -#include "timecode/bbt_time.h" - -#include "ardour/async_midi_port.h" -#include "ardour/audioengine.h" -#include "ardour/debug.h" -#include "ardour/filesystem_paths.h" -#include "ardour/midiport_manager.h" -#include "ardour/midi_track.h" -#include "ardour/midi_port.h" -#include "ardour/session.h" -#include "ardour/tempo.h" +#include "pbd/i18n.h" + +#include "gtkmm2ext/gui_thread.h" + +#include "canvas/colors.h" +#include "canvas/rectangle.h" +#include "canvas/text.h" +#include "canvas.h" #include "menu.h" #include "push2.h" #include "scale.h" -#include "pbd/i18n.h" - using namespace ARDOUR; using namespace std; using namespace PBD; @@ -54,10 +36,127 @@ using namespace Glib; using namespace ArdourSurface; using namespace ArdourCanvas; +static double unselected_root_alpha = 0.5; + ScaleLayout::ScaleLayout (Push2& p, Session& s) : Push2Layout (p, s) + , last_vpot (-1) + , vpot_delta_cnt (0) + , root_button (0) { + Pango::FontDescription fd ("Sans 10"); + + /* background */ + + bg = new Rectangle (this); + bg->set (Rect (0, 0, display_width(), display_height())); + bg->set_fill_color (p2.get_color (Push2::DarkBackground)); + + left_scroll_text = new Text (this); + left_scroll_text->set_font_description (fd); + left_scroll_text->set_position (Duple (10, 5)); + left_scroll_text->set_color (p2.get_color (Push2::LightBackground)); + + close_text = new Text (this); + close_text->set_font_description (fd); + close_text->set_position (Duple (25, 5)); + close_text->set_color (p2.get_color (Push2::LightBackground)); + close_text->set (_("Close")); + + right_scroll_text = new Text (this); + right_scroll_text->set_font_description (fd); + right_scroll_text->set_position (Duple (10 + (7 * Push2Canvas::inter_button_spacing()), 5)); + right_scroll_text->set_color (p2.get_color (Push2::LightBackground)); + + Pango::FontDescription fd2 ("Sans 8"); + inkey_text = new Text (this); + inkey_text->set_font_description (fd2); + inkey_text->set_position (Duple (10, 140)); + inkey_text->set_color (p2.get_color (Push2::LightBackground)); + inkey_text->set (_("InKey")); + + chromatic_text = new Text (this); + chromatic_text->set_font_description (fd2); + chromatic_text->set_position (Duple (45, 140)); + chromatic_text->set_color (p2.get_color (Push2::LightBackground)); + chromatic_text->set (_("Chromatic")); + + fixed_text = new Text (this); + fixed_text->set_font_description (fd2); + fixed_text->set_position (Duple (10 + (7 * Push2Canvas::inter_button_spacing()), 140)); + fixed_text->set_color (p2.get_color (Push2::LightBackground)); + fixed_text->set (_("Fixed")); + + for (int n = 0; n < 8; ++n) { + + /* text labels for root notes etc.*/ + + Text* t = new Text (this); + t->set_font_description (fd); + t->set_color (change_alpha (p2.get_color (Push2::LightBackground), unselected_root_alpha)); + t->set_position (Duple (10 + (n * Push2Canvas::inter_button_spacing()), 5)); + + switch (n) { + case 0: + /* zeroth element is a dummy */ + break; + case 1: + t->set (S_("Note|C")); + break; + case 2: + t->set (S_("Note|G")); + break; + case 3: + t->set (S_("Note|D")); + break; + case 4: + t->set (S_("Note|A")); + break; + case 5: + t->set (S_("Note|E")); + break; + case 6: + t->set (S_("Note|B")); + break; + } + + upper_text.push_back (t); + + t = new Text (this); + t->set_font_description (fd); + t->set_color (change_alpha (p2.get_color (Push2::LightBackground), unselected_root_alpha)); + t->set_position (Duple (10 + (n*Push2Canvas::inter_button_spacing()), 140)); + + switch (n) { + case 0: + /* zeroth element is a dummy */ + break; + case 1: + t->set (S_("Note|F")); + break; + case 2: + t->set (S_("Note|B\u266D/A\u266F")); + break; + case 3: + t->set (S_("Note|E\u266D/D\u266F")); + break; + case 4: + t->set (S_("Note|A\u266D/G\u266F")); + break; + case 5: + t->set (S_("Note|D\u266D/C\u266F")); + break; + case 6: + t->set (S_("Note|G\u266D/F\u266F")); + break; + } + + lower_text.push_back (t); + } + build_scale_menu (); + + p2.ScaleChange.connect (p2_connections, invalidator (*this), boost::bind (&ScaleLayout::show_root_state, this), &p2); } ScaleLayout::~ScaleLayout () @@ -67,37 +166,196 @@ ScaleLayout::~ScaleLayout () void ScaleLayout::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const { - DEBUG_TRACE (DEBUG::Push2, string_compose ("scale render %1\n", area)); - - context->set_source_rgb (0.764, 0.882, 0.882); - context->rectangle (0, 0, 960, 160); - context->fill (); - - scale_menu->render (area, context); + render_children (area, context); } void ScaleLayout::button_upper (uint32_t n) { + if (n == 0) { + if (scale_menu->can_scroll_left()) { + scale_menu->scroll (Push2Menu::DirectionLeft, true); + } else { + p2.use_previous_layout (); + } + return; + } + + if (n == 7) { + scale_menu->scroll (Push2Menu::DirectionRight, true); + return; + } + + int root; + + switch (n) { + case 1: + /* C */ + root = 0; + break; + case 2: + /* G */ + root = 7; + break; + case 3: + /* D */ + root = 2; + break; + case 4: + /* A */ + root = 9; + break; + case 5: + /* E */ + root = 4; + break; + case 6: + /* B */ + root = 11; + break; + case 7: + /* unused */ + return; + } + + p2.set_pad_scale (root, p2.root_octave(), p2.mode(), p2.in_key()); } void ScaleLayout::button_lower (uint32_t n) { + if (n == 0) { + p2.set_pad_scale (p2.scale_root(), p2.root_octave(), p2.mode(), !p2.in_key()); + return; + } + + int root; + + switch (n) { + case 1: + /* F */ + root = 5; + break; + case 2: + /* B-flat */ + root = 10; + break; + case 3: + /* E flat */ + root = 3; + break; + case 4: + /* A flat */ + root = 8; + break; + case 5: + /* D flat */ + root = 1; + break; + case 6: + /* G flat */ + root = 6; + break; + case 7: + /* fixed mode */ + return; + } + + p2.set_pad_scale (root, p2.root_octave(), p2.mode(), p2.in_key()); +} + +void +ScaleLayout::button_up () +{ + scale_menu->scroll (Push2Menu::DirectionUp); } void -ScaleLayout::strip_vpot (int n, int delta) +ScaleLayout::button_down () { - if (n == 0) { - scale_menu->step_active (n, delta); - return; + scale_menu->scroll (Push2Menu::DirectionDown); +} + +void +ScaleLayout::button_left () +{ + scale_menu->scroll (Push2Menu::DirectionLeft); +} + +void +ScaleLayout::button_right () +{ + scale_menu->scroll (Push2Menu::DirectionRight); +} + +void +ScaleLayout::show () +{ + last_vpot = -1; + + /* all root buttons should be dimly lit */ + + Push2::ButtonID root_buttons[] = { Push2::Upper2, Push2::Upper3, Push2::Upper4, Push2::Upper5, Push2::Upper6, Push2::Upper7, + Push2::Lower2, Push2::Lower3, Push2::Lower4, Push2::Lower5, Push2::Lower6, Push2::Lower7, }; + + for (size_t n = 0; n < sizeof (root_buttons) / sizeof (root_buttons[0]); ++n) { + Push2::Button* b = p2.button_by_id (root_buttons[n]); + + b->set_color (Push2::LED::DarkGray); + b->set_state (Push2::LED::OneShot24th); + p2.write (b->state_msg()); } + + show_root_state (); + + Container::show (); } void -ScaleLayout::strip_vpot_touch (int, bool) +ScaleLayout::strip_vpot (int n, int delta) { + /* menu starts under the 2nd-from-left vpot */ + + if (n == 0) { + return; + } + + if (last_vpot != n) { + uint32_t effective_column = n - 1; + uint32_t active = scale_menu->active (); + + if (active / scale_menu->rows() != effective_column) { + /* knob turned is different than the current active column. + Just change that. + */ + scale_menu->set_active (effective_column * scale_menu->rows()); /* top entry of that column */ + return; + } + + /* new vpot, reset delta cnt */ + + vpot_delta_cnt = 0; + } + + if ((delta < 0 && vpot_delta_cnt > 0) || (delta > 0 && vpot_delta_cnt < 0)) { + /* direction changed, reset */ + vpot_delta_cnt = 0; + } + + vpot_delta_cnt += delta; + last_vpot = n; + + /* this thins out vpot delta events so that we don't scroll so fast + through the menu. + */ + + const int vpot_slowdown_factor = 4; + + if ((vpot_delta_cnt < 0) && (vpot_delta_cnt % vpot_slowdown_factor == 0)) { + scale_menu->scroll (Push2Menu::DirectionUp); + } else if (vpot_delta_cnt % vpot_slowdown_factor == 0) { + scale_menu->scroll (Push2Menu::DirectionDown); + } } void @@ -105,39 +363,40 @@ ScaleLayout::build_scale_menu () { vector<string> v; - scale_menu = new Push2Menu (this); + /* must match in which enums are declared in push2.h + */ v.push_back ("Dorian"); - v.push_back ("IonianMajor"); + v.push_back ("Ionian (Major)"); v.push_back ("Minor"); - v.push_back ("HarmonicMinor"); - v.push_back ("MelodicMinorAscending"); - v.push_back ("MelodicMinorDescending"); + v.push_back ("Harmonic Minor"); + v.push_back ("MelodicMinor Asc."); + v.push_back ("MelodicMinor Desc."); v.push_back ("Phrygian"); v.push_back ("Lydian"); v.push_back ("Mixolydian"); v.push_back ("Aeolian"); v.push_back ("Locrian"); - v.push_back ("PentatonicMajor"); - v.push_back ("PentatonicMinor"); + v.push_back ("Pentatonic Major"); + v.push_back ("Pentatonic Minor"); v.push_back ("Chromatic"); v.push_back ("BluesScale"); - v.push_back ("NeapolitanMinor"); - v.push_back ("NeapolitanMajor"); + v.push_back ("Neapolitan Minor"); + v.push_back ("Neapolitan Major"); v.push_back ("Oriental"); - v.push_back ("DoubleHarmonic"); + v.push_back ("Double Harmonic"); v.push_back ("Enigmatic"); v.push_back ("Hirajoshi"); - v.push_back ("HungarianMinor"); - v.push_back ("HungarianMajor"); + v.push_back ("Hungarian Minor"); + v.push_back ("Hungarian Major"); v.push_back ("Kumoi"); v.push_back ("Iwato"); v.push_back ("Hindu"); - v.push_back ("Spanish8Tone"); + v.push_back ("Spanish 8 Tone"); v.push_back ("Pelog"); - v.push_back ("HungarianGypsy"); + v.push_back ("Hungarian Gypsy"); v.push_back ("Overtone"); - v.push_back ("LeadingWholeTone"); + v.push_back ("Leading Whole Tone"); v.push_back ("Arabian"); v.push_back ("Balinese"); v.push_back ("Gypsy"); @@ -146,7 +405,281 @@ ScaleLayout::build_scale_menu () v.push_back ("Persian"); v.push_back ("Algeria"); - scale_menu->fill_column (0, v); + scale_menu = new Push2Menu (this, v); + scale_menu->Rearranged.connect (menu_connections, invalidator (*this), boost::bind (&ScaleLayout::menu_rearranged, this), &p2); - v.clear (); + scale_menu->set_layout (6, 6); + scale_menu->set_text_color (p2.get_color (Push2::ParameterName)); + scale_menu->set_active_color (p2.get_color (Push2::LightBackground)); + + Pango::FontDescription fd ("Sans Bold 8"); + scale_menu->set_font_description (fd); + + /* move menu into position so that its leftmost column is in the + * 2nd-from-left column of the display/button layout. + */ + + scale_menu->set_position (Duple (10 + Push2Canvas::inter_button_spacing(), 40)); + + /* listen for changes */ + + scale_menu->ActiveChanged.connect (menu_connections, invalidator (*this), boost::bind (&ScaleLayout::mode_changed, this), &p2); +} + +void +ScaleLayout::show_root_state () +{ + if (!parent()) { + /* don't do this stuff if we're not visible */ + return; + } + + if (p2.in_key()) { + chromatic_text->set_color (change_alpha (chromatic_text->color(), unselected_root_alpha)); + inkey_text->set_color (change_alpha (inkey_text->color(), 1.0)); + } else { + inkey_text->set_color (change_alpha (chromatic_text->color(), unselected_root_alpha)); + chromatic_text->set_color (change_alpha (inkey_text->color(), 1.0)); + } + + Pango::FontDescription fd_bold ("Sans Bold 10"); + Pango::FontDescription fd ("Sans 10"); + + uint32_t highlight_text = 0; + vector<Text*>* none_text_array; + vector<Text*>* one_text_array; + Push2::ButtonID bid; + + switch (p2.scale_root()) { + case 0: + highlight_text = 1; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Upper2; + break; + case 1: + highlight_text = 5; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Lower6; + break; + case 2: + highlight_text = 3; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Upper4; + break; + case 3: + highlight_text = 3; + none_text_array = &upper_text; + one_text_array = &lower_text; + bid = Push2::Lower4; + break; + case 4: + highlight_text = 5; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Upper6; + break; + case 5: + highlight_text = 1; + none_text_array = &upper_text; + one_text_array = &lower_text; + bid = Push2::Lower2; + break; + case 6: + highlight_text = 6; + none_text_array = &upper_text; + one_text_array = &lower_text; + bid = Push2::Lower7; + break; + case 7: + highlight_text = 2; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Upper3; + break; + case 8: + highlight_text = 4; + none_text_array = &upper_text; + one_text_array = &lower_text; + bid = Push2::Lower5; + break; + case 9: + highlight_text = 4; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Upper5; + break; + case 10: + highlight_text = 2; + none_text_array = &upper_text; + one_text_array = &lower_text; + bid = Push2::Lower3; + break; + case 11: + highlight_text = 6; + none_text_array = &lower_text; + one_text_array = &upper_text; + bid = Push2::Upper7; + break; + } + + if (none_text_array) { + + for (uint32_t nn = 1; nn < 7; ++nn) { + (*none_text_array)[nn]->set_font_description (fd); + (*none_text_array)[nn]->set_color (change_alpha ((*none_text_array)[nn]->color(), unselected_root_alpha)); + + if (nn == highlight_text) { + (*one_text_array)[nn]->set_font_description (fd_bold); + (*one_text_array)[nn]->set_color (change_alpha ((*one_text_array)[nn]->color(), 1.0)); + } else { + (*one_text_array)[nn]->set_font_description (fd); + (*one_text_array)[nn]->set_color (change_alpha ((*one_text_array)[nn]->color(), unselected_root_alpha)); + } + } + + } + + Push2::Button* b = p2.button_by_id (bid); + + if (b != root_button) { + if (root_button) { + /* turn the old one off (but not totally) */ + root_button->set_color (Push2::LED::DarkGray); + root_button->set_state (Push2::LED::OneShot24th); + p2.write (root_button->state_msg()); + } + + root_button = b; + + if (root_button) { + /* turn the new one on */ + root_button->set_color (Push2::LED::White); + root_button->set_state (Push2::LED::OneShot24th); + p2.write (root_button->state_msg()); + } + } + + scale_menu->set_active ((uint32_t) p2.mode ()); +} + +void +ScaleLayout::mode_changed () +{ + MusicalMode::Type m = (MusicalMode::Type) scale_menu->active(); + p2.set_pad_scale (p2.scale_root(), p2.root_octave(), m, p2.in_key()); +} + +void +ScaleLayout::menu_rearranged () +{ + if (scale_menu->can_scroll_left()) { + left_scroll_text->set ("<"); + close_text->hide (); + } else { + left_scroll_text->set (string()); + close_text->show (); + } + + if (scale_menu->can_scroll_right()) { + right_scroll_text->set (">"); + } else { + right_scroll_text->set (string()); + } +} + +void +ScaleLayout::update_cursor_buttons () +{ + Push2::Button* b; + bool change; + + b = p2.button_by_id (Push2::Up); + change = false; + + if (scale_menu->active() == 0) { + if (b->color_index() != Push2::LED::Black) { + b->set_color (Push2::LED::Black); + change = true; + } + } else { + if (b->color_index() != Push2::LED::White) { + b->set_color (Push2::LED::White); + change = true; + } + } + + if (change) { + b->set_state (Push2::LED::OneShot24th); + p2.write (b->state_msg()); + } + + /* down */ + + b = p2.button_by_id (Push2::Down); + change = false; + + if (scale_menu->active() == scale_menu->items() - 1) { + if (b->color_index() != Push2::LED::Black) { + b->set_color (Push2::LED::Black); + change = true; + } + } else { + if (b->color_index() != Push2::LED::White) { + b->set_color (Push2::LED::White); + change = true; + } + + } + if (change) { + b->set_color (Push2::LED::OneShot24th); + p2.write (b->state_msg()); + } + + /* left */ + + b = p2.button_by_id (Push2::Left); + change = false; + + if (scale_menu->active() < scale_menu->rows()) { + if (b->color_index() != Push2::LED::Black) { + b->set_color (Push2::LED::Black); + change = true; + } + } else { + if (b->color_index() != Push2::LED::White) { + b->set_color (Push2::LED::White); + change = true; + } + + } + if (change) { + b->set_color (Push2::LED::OneShot24th); + p2.write (b->state_msg()); + } + + /* right */ + + b = p2.button_by_id (Push2::Right); + change = false; + + if (scale_menu->active() > (scale_menu->items() - scale_menu->rows())) { + if (b->color_index() != Push2::LED::Black) { + b->set_color (Push2::LED::Black); + change = true; + } + } else { + if (b->color_index() != Push2::LED::White) { + b->set_color (Push2::LED::White); + change = true; + } + + } + + if (change) { + b->set_color (Push2::LED::OneShot24th); + p2.write (b->state_msg()); + } } diff --git a/libs/surfaces/push2/scale.h b/libs/surfaces/push2/scale.h index 7d7b1f870a..ffa95fe241 100644 --- a/libs/surfaces/push2/scale.h +++ b/libs/surfaces/push2/scale.h @@ -19,12 +19,18 @@ #ifndef __ardour_push2_scale_layout_h__ #define __ardour_push2_scale_layout_h__ +#include <vector> + #include "layout.h" namespace ARDOUR { class Stripable; } +namespace ArdourCanvas { + class Rectangle; +} + namespace ArdourSurface { class ScaleLayout : public Push2Layout @@ -35,15 +41,41 @@ class ScaleLayout : public Push2Layout void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const; + void show (); + void button_upper (uint32_t n); void button_lower (uint32_t n); - + void button_up (); + void button_down (); + void button_left (); + void button_right (); void strip_vpot (int, int); - void strip_vpot_touch (int, bool); + + void strip_vpot_touch (int, bool) {} private: + ArdourCanvas::Rectangle* bg; + std::vector<ArdourCanvas::Text*> upper_text; + std::vector<ArdourCanvas::Text*> lower_text; + ArdourCanvas::Text* left_scroll_text; + ArdourCanvas::Text* right_scroll_text; + ArdourCanvas::Text* inkey_text; + ArdourCanvas::Text* chromatic_text; + ArdourCanvas::Text* close_text; + ArdourCanvas::Text* fixed_text; + ArdourCanvas::Rectangle* root_bg; Push2Menu* scale_menu; + int last_vpot; + int vpot_delta_cnt; + Push2::Button* root_button; + void build_scale_menu (); + PBD::ScopedConnectionList menu_connections; + PBD::ScopedConnectionList p2_connections; + void mode_changed (); + void menu_rearranged (); + void show_root_state (); + void update_cursor_buttons (); }; } /* namespace */ |