summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-09-21 15:25:24 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2016-09-27 14:59:31 -0500
commitb6ecc56e7a724097ebf6c0589ce64fe1cb409db9 (patch)
tree18dff5728370fc2286db4fbbaabf46341f2254cb
parent9cc40aafa0dd06f1449c81fcbccd4a5eb971115d (diff)
push2: scale selection and display on video display now working
-rw-r--r--libs/surfaces/push2/scale.cc643
-rw-r--r--libs/surfaces/push2/scale.h36
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 */