From ca869eda42a733e94a17c640d62aad7e97230b03 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 5 Nov 2018 23:39:37 -0500 Subject: [PATCH] start on more structured code for step sequencer GUI --- gtk2_ardour/beatbox_gui.cc | 312 ++++++++++++++++++++++--------------- gtk2_ardour/beatbox_gui.h | 62 ++++++-- 2 files changed, 233 insertions(+), 141 deletions(-) diff --git a/gtk2_ardour/beatbox_gui.cc b/gtk2_ardour/beatbox_gui.cc index 686fdf7270..7f9e941979 100644 --- a/gtk2_ardour/beatbox_gui.cc +++ b/gtk2_ardour/beatbox_gui.cc @@ -42,12 +42,14 @@ #include "canvas/text.h" #include "canvas/widget.h" +#include "gtkmm2ext/gui_thread.h" #include "gtkmm2ext/utils.h" #include "beatbox_gui.h" #include "timers.h" #include "ui_config.h" +using namespace PBD; using namespace ARDOUR; using namespace Gtkmm2ext; using namespace ArdourCanvas; @@ -58,8 +60,6 @@ using std::endl; const int _nsteps = 32; const int _nrows = 8; const double _step_dimen = 25; -const double _width = _step_dimen * _nsteps; -const double _height = _step_dimen * _nrows; BBGUI::BBGUI (boost::shared_ptr bb) : ArdourDialog (_("BeatBox")) @@ -71,7 +71,6 @@ BBGUI::BBGUI (boost::shared_ptr bb) { _canvas_viewport = new GtkCanvasViewport (horizontal_adjustment, vertical_adjustment); - _canvas_viewport->set_size_request (_width, _height + _step_dimen); _canvas = _canvas_viewport->canvas(); _canvas->set_background_color (UIConfiguration::instance().color ("gtk_bright_color")); @@ -82,24 +81,15 @@ BBGUI::BBGUI (boost::shared_ptr bb) step_indicator_box = new ArdourCanvas::Container (no_scroll_group); step_indicator_bg = new ArdourCanvas::Rectangle (step_indicator_box); - step_indicator_bg->set (Rect (0, 0, _width, _step_dimen)); step_indicator_bg->set_fill_color (UIConfiguration::instance().color ("gtk_lightest")); step_indicator_bg->set_outline (false); - for (int n = 0; n < _nsteps; ++n) { - SequencerStepIndicator* ssi = new SequencerStepIndicator (step_indicator_box, n+1); - ssi->set (Rect (n * _step_dimen, 0, (n+1) * _step_dimen, _step_dimen)); - ssi->set_position (Duple (n * _step_dimen, 0.0)); - ssi->set_fill_color (random()); - } - v_scroll_group = new ScrollGroup (_canvas->root(), ScrollGroup::ScrollsVertically); _canvas->add_scroller (*v_scroll_group); - _sequencer = new SequencerGrid (v_scroll_group); + _sequencer = new SequencerGrid (bbox->sequencer(), v_scroll_group); _sequencer->set_position (Duple (0, _step_dimen)); _sequencer->set_fill_color (UIConfiguration::instance().color ("gtk_contrasting_indicator")); - _sequencer->Event.connect (sigc::mem_fun (*this, &BBGUI::grid_event)); srandom (time(0)); @@ -120,6 +110,9 @@ BBGUI::BBGUI (boost::shared_ptr bb) export_as_region_button.signal_clicked.connect (sigc::mem_fun (*this, &BBGUI::export_as_region)); get_action_area()->pack_end (export_as_region_button); + PropertyChange pc; + sequencer_changed (pc); + show_all (); } @@ -127,112 +120,6 @@ BBGUI::~BBGUI () { } -bool -BBGUI::grid_event (GdkEvent* ev) -{ - bool ret = false; - - cerr << "grid event, type: " << event_type_string (ev->type); - switch (ev->type) { - case GDK_MOTION_NOTIFY: - ret = grid_motion_event (&ev->motion); - cerr << ' ' << ev->motion.x << ',' << ev->motion.y << " state " << show_gdk_event_state (ev->motion.state); - break; - case GDK_BUTTON_PRESS: - cerr << ' ' << ev->button.x << ',' << ev->button.y << " state " << show_gdk_event_state (ev->button.state); - ret = grid_button_press_event (&ev->button); - break; - case GDK_BUTTON_RELEASE: - cerr << ' ' << ev->button.x << ',' << ev->button.y << " state " << show_gdk_event_state (ev->button.state); - ret = grid_button_release_event (&ev->button); - break; - case GDK_SCROLL: - cerr << ' ' << ev->scroll.direction << show_gdk_event_state (ev->scroll.state); - ret = grid_scroll_event (&ev->scroll); - default: - break; - } - cerr << endl; - - return ret; -} - - -bool -BBGUI::grid_motion_event (GdkEventMotion* ev) -{ - return true; -} - -bool -BBGUI::grid_button_press_event (GdkEventButton* ev) -{ - set_grab_step (ev->x, ev->y); - grab_at = std::make_pair (ev->x, ev->y); - return true; -} - -bool -BBGUI::grid_button_release_event (GdkEventButton* ev) -{ - return true; -} - -bool -BBGUI::grid_scroll_event (GdkEventScroll* ev) -{ - int step = ev->x / _step_dimen; - int seq = ev->y / _step_dimen; - int amt = 0; - - switch (ev->direction) { - case GDK_SCROLL_UP: - amt = 1; - break; - case GDK_SCROLL_LEFT: - amt = -1; - break; - case GDK_SCROLL_RIGHT: - amt = 1; - break; - case GDK_SCROLL_DOWN: - amt = -1; - break; - } - - if (ev->state & GDK_MOD1_MASK) { - cerr << "adjust pitch by " << amt << endl; - adjust_step_pitch (seq, step, amt); - } else { - cerr << "adjust velocity by " << amt << endl; - adjust_step_velocity (seq, step, amt); - } - - return true; -} - -void -BBGUI::set_grab_step (double x, double y) -{ - int step = x / _step_dimen; - int seq = y / _step_dimen; - - grab_step = std::make_pair (seq, step); -} - - -void -BBGUI::adjust_step_pitch (int seq, int step, int amt) -{ - bbox->sequencer().adjust_step_pitch (seq, step, amt); -} - -void -BBGUI::adjust_step_velocity (int seq, int step, int amt) -{ - bbox->sequencer().adjust_step_velocity (seq, step, amt); -} - void BBGUI::update () { @@ -376,15 +263,65 @@ BBGUI::export_as_region () boost::shared_ptr region = RegionFactory::create (src, plist, true); } -SequencerGrid::SequencerGrid (Canvas *c) - : Rectangle (c) +void +BBGUI::sequencer_changed (PropertyChange const &) { - set (Rect (0, 0, _width, _height)); + const size_t nsteps = bbox->sequencer().nsteps(); + const size_t nsequences = bbox->sequencer().nsequences(); + + _width = _step_dimen * nsteps; + _height = _step_dimen * nsequences; + + /* height is 1 step_dimen larger to accomodate the "step indicator" + * line at the top + */ + + _canvas_viewport->set_size_request (_width, _height + _step_dimen); + + step_indicator_bg->set (Rect (0, 0, _width, _step_dimen)); + step_indicator_box->clear (true); /* delete all existing step indicators */ + + /* indicator row */ + + for (size_t n = 0; n < nsteps; ++n) { + SequencerStepIndicator* ssi = new SequencerStepIndicator (step_indicator_box, n+1); + ssi->set (Rect (n * _step_dimen, 0, (n+1) * _step_dimen, _step_dimen)); + ssi->set_position (Duple (n * _step_dimen, 0.0)); + ssi->set_fill_color (random()); + } + + /* step views, one per step per sequence */ + + for (size_t s = 0; s < nsequences; ++s) { + for (size_t n = 0; n < nsteps; ++n) { + StepView* sv = new StepView (*this, bbox->sequencer().sequence (s).step (n), v_scroll_group); + //sv->set (Rect (n * _step_dimen + 1, (s+1) * _step_dimen + 1, (n+1) * _step_dimen - 1, (s+2) * _step_dimen - 1)); + sv->set_position (Duple (n * _step_dimen, (s+1) * _step_dimen)); + sv->set (Rect (1, 1, _step_dimen - 2, _step_dimen - 2)); + cerr << "step rect @ " << sv->get() << endl; + } + } } -SequencerGrid::SequencerGrid (Item *p) - : Rectangle (p) +/**/ + +SequencerGrid::SequencerGrid (StepSequencer& s, Item *parent) + : Rectangle (parent) + , _sequencer (s) { + PropertyChange pc; + + sequencer_changed (pc); +} + +void +SequencerGrid::sequencer_changed (PropertyChange const &) +{ + const size_t nsteps = _sequencer.nsteps(); + + _width = _step_dimen * nsteps; + _height = _step_dimen * _sequencer.nsequences (); + set (Rect (0, 0, _width, _height)); } @@ -432,8 +369,6 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr context) /* vertical bars for velocity */ - Gtkmm2ext::set_source_rgba (context, UIConfiguration::instance().color ("gtk_somewhat_bright_indicator")); - for (int r = 0; r < _nrows; ++r) { for (int c = 0; c < _nsteps; ++c) { const double velocity = random() % 127 / 127.0; @@ -451,7 +386,11 @@ SequencerStepIndicator::SequencerStepIndicator (Item *p, int n) set_outline (false); text = new Text (this); - text->set (string_compose ("%1", n)); + if (n == 7) { + text->set ("\u21a9"); + } else { + text->set (string_compose ("%1", n)); + } text->set_font_description (UIConfiguration::instance ().get_SmallFont ()); text->set_position (Duple ((_step_dimen/2.0) - (text->width()/2.0), 5.0)); @@ -472,3 +411,122 @@ SequencerStepIndicator::render (Rect const & area, Cairo::RefPtr context) const +{ + const double height = (_step_dimen - 2) * _step.velocity(); + cerr << _step.beat() << " From V = " << _step.velocity() << " h = " << height << " area = " << area; + Rect r (1, height, _step_dimen - 2, _step_dimen - height); + r = item_to_window (r); + cerr << " draw " << r << endl; + context->rectangle (r.x1, r.y1, r.width(), r.height()); + context->fill (); +} + +bool +StepView::on_event (GdkEvent *ev) +{ + bool ret = false; + + switch (ev->type) { + case GDK_MOTION_NOTIFY: + ret = motion_event (&ev->motion); + break; + case GDK_BUTTON_PRESS: + ret = button_press_event (&ev->button); + break; + case GDK_BUTTON_RELEASE: + ret = button_release_event (&ev->button); + break; + case GDK_SCROLL: + ret = scroll_event (&ev->scroll); + default: + break; + } + + return ret; +} + + +bool +StepView::motion_event (GdkEventMotion* ev) +{ + return true; +} + +bool +StepView::button_press_event (GdkEventButton* ev) +{ + grab_at = std::make_pair (ev->x, ev->y); + return true; +} + +bool +StepView::button_release_event (GdkEventButton* ev) +{ + return true; +} + +bool +StepView::scroll_event (GdkEventScroll* ev) +{ + int step = ev->x / _step_dimen; + int seq = ev->y / _step_dimen; + int amt = 0; + + switch (ev->direction) { + case GDK_SCROLL_UP: + amt = 1; + break; + case GDK_SCROLL_LEFT: + amt = -1; + break; + case GDK_SCROLL_RIGHT: + amt = 1; + break; + case GDK_SCROLL_DOWN: + amt = -1; + break; + } + + if (ev->state & GDK_MOD1_MASK) { + cerr << "adjust pitch by " << amt << endl; + adjust_step_pitch (amt); + } else { + cerr << "adjust velocity by " << amt << endl; + adjust_step_velocity (amt); + } + + return true; +} + +void +StepView::adjust_step_pitch (int amt) +{ + _step.adjust_pitch (amt); +} + +void +StepView::adjust_step_velocity (int amt) +{ + _step.adjust_velocity (amt); +} diff --git a/gtk2_ardour/beatbox_gui.h b/gtk2_ardour/beatbox_gui.h index 9d55e1fd67..0c7b61f265 100644 --- a/gtk2_ardour/beatbox_gui.h +++ b/gtk2_ardour/beatbox_gui.h @@ -41,6 +41,10 @@ #include "widgets/ardour_dropdown.h" #include "ardour_dialog.h" +namespace PBD { +class PropertyChange; +} + namespace ArdourCanvas { class Grid; class Item; @@ -53,14 +57,50 @@ class Widget; namespace ARDOUR { class BeatBox; +class Step; +class StepSequencer; } +class BBGUI; + +class StepView : public ArdourCanvas::Rectangle, public sigc::trackable { + public: + StepView (BBGUI&, ARDOUR::Step&, ArdourCanvas::Item*); + + void render (ArdourCanvas::Rect const &, Cairo::RefPtr) const; + bool on_event (GdkEvent*); + + private: + ARDOUR::Step& _step; + BBGUI& bbgui; + + std::pair grab_at; + + bool motion_event (GdkEventMotion*); + bool button_press_event (GdkEventButton*); + bool button_release_event (GdkEventButton*); + bool scroll_event (GdkEventScroll*); + + void adjust_step_pitch (int amt); + void adjust_step_velocity (int amt); + + void step_changed (PBD::PropertyChange const &); + PBD::ScopedConnection step_connection; +}; + class SequencerGrid : public ArdourCanvas::Rectangle { public: - SequencerGrid (ArdourCanvas::Canvas*); - SequencerGrid (ArdourCanvas::Item*); + SequencerGrid (ARDOUR::StepSequencer&, ArdourCanvas::Item* parent); void render (ArdourCanvas::Rect const &, Cairo::RefPtr) const; + + private: + ARDOUR::StepSequencer& _sequencer; + std::vector step_views; + double _width; + double _height; + + void sequencer_changed (PBD::PropertyChange const &); }; class SequencerStepIndicator : public ArdourCanvas::Rectangle { @@ -77,12 +117,17 @@ class BBGUI : public ArdourDialog { BBGUI (boost::shared_ptr bb); ~BBGUI (); + double width() const { return _width; } + double height() const { return _height; } + protected: void on_map (); void on_unmap (); private: boost::shared_ptr bbox; + double _width; + double _height; Gtk::Adjustment horizontal_adjustment; Gtk::Adjustment vertical_adjustment; @@ -113,18 +158,7 @@ class BBGUI : public ArdourDialog { sigc::connection timer_connection; - bool grid_event (GdkEvent*); - bool grid_motion_event (GdkEventMotion*); - bool grid_button_press_event (GdkEventButton*); - bool grid_button_release_event (GdkEventButton*); - bool grid_scroll_event (GdkEventScroll*); - - std::pair grab_step; - std::pair grab_at; - void set_grab_step (double x, double y); - - void adjust_step_pitch (int seq, int step, int amt); - void adjust_step_velocity (int seq, int step, int amt); + void sequencer_changed (PBD::PropertyChange const &); }; #endif /* __gtk2_ardour_beatbox_gui_h__ */