steps in the evolution of beatbox

This commit is contained in:
Paul Davis 2018-11-08 17:55:56 -05:00
parent 8fb67e15ea
commit e5ec4ab959
2 changed files with 297 additions and 91 deletions

View file

@ -44,6 +44,7 @@
#include "gtkmm2ext/gui_thread.h"
#include "gtkmm2ext/utils.h"
#include "gtkmm2ext/colors.h"
#include "beatbox_gui.h"
#include "timers.h"
@ -76,12 +77,11 @@ BBGUI::BBGUI (boost::shared_ptr<BeatBox> bb)
{
_canvas_viewport = new GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
_canvas = _canvas_viewport->canvas();
_canvas->set_background_color (UIConfiguration::instance().color ("gtk_bright_color"));
_canvas->set_background_color (UIConfiguration::instance().color ("gtk_bases"));
_canvas->use_nsglview ();
_sequencer = new SequencerGrid (bbox->sequencer(), _canvas);
_sequencer->set_position (Duple (0, _step_dimen));
_sequencer->set_fill_color (UIConfiguration::instance().color ("gtk_contrasting_indicator"));
srandom (time(0));
@ -135,28 +135,7 @@ BBGUI::mode_clicked (SequencerGrid::Mode m)
void
BBGUI::update ()
{
update_sequencer ();
}
void
BBGUI::update_sequencer ()
{
Timecode::BBT_Time bbt;
if (!bbox->running()) {
/* do something */
return;
}
#if 0
bbt = bbox->get_last_time ();
int current_switch_column = (bbt.bars - 1) * bbox->meter_beats ();
current_switch_column += bbt.beats - 1;
for (SwitchRows::iterator sr = switch_rows.begin(); sr != switch_rows.end(); ++sr) {
(*sr)->update (current_switch_column);
}
#endif
_sequencer->update ();
}
void
@ -301,10 +280,6 @@ SequencerGrid::SequencerGrid (StepSequencer& s, Canvas* c)
no_scroll_group = new ArdourCanvas::Container (_canvas->root());
step_indicator_box = new ArdourCanvas::Container (no_scroll_group);
step_indicator_bg = new ArdourCanvas::Rectangle (step_indicator_box);
step_indicator_bg->set_fill_color (UIConfiguration::instance().color ("gtk_lightest"));
step_indicator_bg->set_outline (false);
v_scroll_group = new ScrollGroup (_canvas->root(), ScrollGroup::ScrollsVertically);
_canvas->add_scroller (*v_scroll_group);
v_scroll_group->add (this);
@ -318,6 +293,28 @@ SequencerGrid::SequencerGrid (StepSequencer& s, Canvas* c)
}
}
void
SequencerGrid::update ()
{
bool running = true;
size_t step = _sequencer.last_step ();
if (!running) {
for (StepIndicators::iterator s = step_indicators.begin(); s != step_indicators.end(); ++s) {
(*s)->set_current (false);
}
} else {
size_t n = 0;
for (StepIndicators::iterator s = step_indicators.begin(); s != step_indicators.end(); ++s, ++n) {
if (n == step) {
(*s)->set_current (true);
} else {
(*s)->set_current (false);
}
}
}
}
void
SequencerGrid::sequencer_changed (PropertyChange const &)
{
@ -329,21 +326,28 @@ SequencerGrid::sequencer_changed (PropertyChange const &)
set (Rect (0, 0, _width, _height));
step_indicator_bg->set (Rect (0, 0, _width, _step_dimen));
step_indicator_box->clear (true); /* delete all existing step indicators */
step_indicators.clear ();
step_indicator_bg = new ArdourCanvas::Rectangle (step_indicator_box);
step_indicator_bg->set_fill_color (HSV (UIConfiguration::instance().color ("gtk_bases")).lighter (0.1));
step_indicator_bg->set_outline (false);
step_indicator_bg->set (Rect (0, 0, _width, _step_dimen));
/* indicator row */
for (size_t n = 0; n < nsteps; ++n) {
SequencerStepIndicator* ssi = new SequencerStepIndicator (step_indicator_box, n+1);
SequencerStepIndicator* ssi = new SequencerStepIndicator (*this, step_indicator_box, n);
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_indicators.push_back (ssi);
}
/* step views, one per step per sequence */
clear (true);
_step_views.clear ();
step_views.clear ();
for (size_t s = 0; s < nsequences; ++s) {
for (size_t n = 0; n < nsteps; ++n) {
@ -351,7 +355,7 @@ SequencerGrid::sequencer_changed (PropertyChange const &)
/* sequence row is 1-row down ... because of the step indicator row */
sv->set_position (Duple (n * _step_dimen, (s+1) * _step_dimen));
sv->set (Rect (1, 1, _step_dimen - 2, _step_dimen - 2));
_step_views.push_back (sv);
step_views.push_back (sv);
}
}
}
@ -361,7 +365,7 @@ SequencerGrid::set_mode (Mode m)
{
_mode = m;
for (StepViews::iterator s = _step_views.begin(); s != _step_views.end(); ++s) {
for (StepViews::iterator s = step_views.begin(); s != step_views.end(); ++s) {
(*s)->view_mode_changed ();
}
@ -391,7 +395,7 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
for (int n = 0; n < _nrows; ++n) {
double x = 0;
double y = n * _step_dimen;
Duple start = Duple (x, y).translate (_position).translate (Duple (0.5, 0.5));
Duple start = item_to_window (Duple (x, y).translate (Duple (0.5, 0.5)));
context->move_to (start.x, start.y);
context->line_to (start.x + _width, start.y);
@ -403,7 +407,7 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
for (int n = 0; n < _nsteps; ++n) {
double x = n * _step_dimen;
double y = 0;
Duple start = Duple (x, y).translate (_position).translate (Duple (0.5, 0.5));
Duple start = item_to_window (Duple (x, y).translate (Duple (0.5, 0.5)));
context->move_to (start.x, start.y);
context->line_to (start.x, start.y + _height);
@ -413,21 +417,27 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
render_children (area, context);
}
SequencerStepIndicator::SequencerStepIndicator (Item *p, int n)
Gtkmm2ext::Color SequencerStepIndicator::other_color = Gtkmm2ext::Color (0);
Gtkmm2ext::Color SequencerStepIndicator::current_color = Gtkmm2ext::Color (0);
Gtkmm2ext::Color SequencerStepIndicator::other_text_color = Gtkmm2ext::Color (0);
Gtkmm2ext::Color SequencerStepIndicator::current_text_color = Gtkmm2ext::Color (0);
int SequencerStepIndicator::dragging = 0;
SequencerStepIndicator::SequencerStepIndicator (SequencerGrid& s, Item *p, size_t n)
: Rectangle (p)
, grid (s)
, number (n)
{
if (current_color == 0) { /* zero alpha? not set */
other_color = UIConfiguration::instance().color ("gtk_bases");
current_color = UIConfiguration::instance().color ("gtk_bright_color");
other_text_color = contrasting_text_color (other_color);
current_text_color = contrasting_text_color (current_color);
}
set_fill (false);
set_outline (false);
text = new Text (this);
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));
poly = new Polygon (this);
Points points;
points.push_back (Duple (0.0, 0.0));
@ -436,7 +446,144 @@ SequencerStepIndicator::SequencerStepIndicator (Item *p, int n)
points.push_back (Duple (_step_dimen/2.0, _step_dimen));
points.push_back (Duple (0.0, _step_dimen/2.0));
poly->set (points);
poly->set_fill_color (Gtkmm2ext::color_at_alpha (random(), 0.4));
poly->set_fill_color (current_color);
poly->set_ignore_events (true);
text = new Text (this);
set_text ();
text->set_font_description (UIConfiguration::instance ().get_SmallFont ());
text->set_position (Duple ((_step_dimen/2.0) - (text->width()/2.0), 5.0));
text->set_color (other_text_color);
text->set_ignore_events (true);
Event.connect (sigc::mem_fun (*this, &SequencerStepIndicator::on_event));
}
void
SequencerStepIndicator::set_text ()
{
StepSequence& sequence = grid.sequencer().sequence (number / grid.sequencer().nsteps());
if (number == sequence.end_step()) {
text->set ("\u21a9");
} else if (number == sequence.start_step()) {
text->set ("\u21aa");
} else {
text->set (string_compose ("%1", number+1));
}
}
bool
SequencerStepIndicator::on_event (GdkEvent* ev)
{
bool ret = false;
switch (ev->type) {
case GDK_ENTER_NOTIFY:
switch (dragging) {
case 1: /* end */
text->set ("\u21a9");
poly->set_outline_color (current_color);
break;
case -1:
text->set ("\u21aa");
poly->set_outline_color (current_color);
break;
default:
text->set (string_compose ("%1", number+1));
poly->set_outline_color (other_color);
}
break;
case GDK_LEAVE_NOTIFY:
if (dragging) {
text->set (string_compose ("%1", number+1));
poly->set_outline_color (other_color);
}
break;
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
SequencerStepIndicator::motion_event (GdkEventMotion* ev)
{
//const double distance = last_motion.second - ev->y;
last_motion = std::make_pair (ev->x, ev->y);
return true;
}
bool
SequencerStepIndicator::button_press_event (GdkEventButton* ev)
{
StepSequence& sequence = grid.sequencer().sequence (number / grid.sequencer().nsteps());
if (number == sequence.end_step()) {
dragging = 1;
} else if (number == sequence.start_step()) {
dragging = -1;
}
return true;
}
bool
SequencerStepIndicator::button_release_event (GdkEventButton* ev)
{
dragging = 0;
return true;
}
bool
SequencerStepIndicator::scroll_event (GdkEventScroll* ev)
{
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;
}
return true;
}
void
SequencerStepIndicator::set_current (bool yn)
{
if (yn) {
poly->set_fill_color (current_color);
text->set_color (current_text_color);
} else {
poly->set_fill_color (other_color);
text->set_color (other_text_color);
}
}
void
@ -446,6 +593,9 @@ SequencerStepIndicator::render (Rect const & area, Cairo::RefPtr<Cairo::Context
render_children (area, context);
}
Gtkmm2ext::Color StepView::on_fill_color = Gtkmm2ext::Color (0);
Gtkmm2ext::Color StepView::off_fill_color = Gtkmm2ext::Color (0);
StepView::StepView (SequencerGrid& sg, Step& s, ArdourCanvas::Item* parent)
: ArdourCanvas::Rectangle (parent)
, _step (s)
@ -453,9 +603,16 @@ StepView::StepView (SequencerGrid& sg, Step& s, ArdourCanvas::Item* parent)
, text (new Text (this))
, grabbed (false)
{
set_fill_color (UIConfiguration::instance().color ("selection"));
if (on_fill_color == 0) {
on_fill_color = UIConfiguration::instance().color ("gtk_bases");
off_fill_color = HSV (on_fill_color).lighter (0.1);
}
text->set_fill_color (contrasting_text_color (fill_color()));
set_fill_color (off_fill_color);
set_outline_color (UIConfiguration::instance().color ("gtk_bright_color"));
set_outline (false);
text->set_color (contrasting_text_color (fill_color()));
text->set_font_description (UIConfiguration::instance ().get_SmallFont ());
text->hide ();
@ -466,56 +623,79 @@ StepView::StepView (SequencerGrid& sg, Step& s, ArdourCanvas::Item* parent)
void
StepView::view_mode_changed ()
{
cerr << "view mode changed\n";
if (_seq.mode() == SequencerGrid::Octave) {
cerr << "octave\n";
text->show ();
if (_step.octave_shift() >= 0) {
text->set (string_compose ("+%1", _step.octave_shift()));
} else {
text->set (string_compose ("%1", _step.octave_shift()));
}
const double w = text->width();
const double h = text->height();
cerr << "put octave text " << text->text() << " dimen " << w << " x " << h << " @ " << Duple (_step_dimen/2 - (w/2), _step_dimen/2 - (h/2)) << endl;
text->set_position (Duple (_step_dimen/2 - (w/2), _step_dimen/2 - (h/2)));
set_octave_text ();
} else if (_seq.mode() == SequencerGrid::Group) {
text->set (std::string());
text->show ();
set_group_text ();
} else {
text->hide ();
}
}
void
StepView::set_group_text ()
{
text->hide ();
}
void
StepView::set_octave_text ()
{
if (_step.octave_shift() > 0) {
text->set (string_compose ("+%1", _step.octave_shift()));
text->show ();
} else if (_step.octave_shift() == 0) {
text->hide ();
} else {
text->set (string_compose ("%1", _step.octave_shift()));
text->show ();
}
if (text->self_visible()) {
const double w = text->width();
const double h = text->height();
text->set_position (Duple (_step_dimen/2 - (w/2), _step_dimen/2 - (h/2)));
}
}
void
StepView::step_changed (PropertyChange const &)
{
if (_seq.mode() == SequencerGrid::Octave) {
set_octave_text ();
}
if (_step.velocity()) {
set_fill_color (on_fill_color);
} else {
set_fill_color (off_fill_color);
}
redraw ();
}
void
StepView::render (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
{
Rectangle::render (area, context);
if (_seq.mode() == SequencerGrid::Velocity) {
const double height = (_step_dimen - 4) * _step.velocity();
const Duple origin = item_to_window (Duple (0, 0));
set_source_rgba (context, outline_color());
context->rectangle (origin.x + 2, origin.y + (_step_dimen - height - 2), _step_dimen - 4, height);
context->fill ();
} else if (_seq.mode() == SequencerGrid::Pitch) {
const double height = (_step_dimen - 4) * (_step.note() / 128.0);
const Duple origin = item_to_window (Duple (0, 0));
set_source_rgba (context, outline_color());
context->rectangle (origin.x + 2, origin.y + (_step_dimen - height - 2), _step_dimen - 4, height);
context->fill ();
} else if (_seq.mode() == SequencerGrid::Duration) {
const Step::DurationRatio d (_step.duration());
const double height = ((_step_dimen - 4.0) * d.numerator()) / d.denominator();
const Duple origin = item_to_window (Duple (0, 0));
set_source_rgba (context, outline_color());
context->rectangle (origin.x + 2, origin.y + (_step_dimen - height - 2), _step_dimen - 4, height);
context->fill ();
}
@ -560,13 +740,10 @@ StepView::motion_event (GdkEventMotion* ev)
const double distance = last_motion.second - ev->y;
if ((ev->state & GDK_MOD1_MASK) || _seq.mode() == SequencerGrid::Pitch) {
cerr << "adjust pitch by " << distance << endl;
adjust_step_pitch (distance);
} else if (_seq.mode() == SequencerGrid::Velocity) {
cerr << "adjust velocity by " << distance << endl;
adjust_step_velocity (distance);
} else if (_seq.mode() == SequencerGrid::Duration) {
cerr << "adjust duration by " << Step::DurationRatio (distance, 32) << endl;
adjust_step_duration (Step::DurationRatio (distance, 32)); /* adjust by 1/32 of the sequencer step size */
} else if (_seq.mode() == SequencerGrid::Octave) {
adjust_step_octave (distance);
@ -598,16 +775,14 @@ StepView::button_release_event (GdkEventButton* ev)
if (fabs (last_motion.second - grab_at.second) < 4) {
/* just a click */
cerr << "just a click! " << last_motion.first << " grab at " << grab_at.first << endl;
if (_seq.mode() == SequencerGrid::Velocity) {
_step.set_velocity (1.0);
} else if (_seq.mode() == SequencerGrid::Octave) {
if (ev->button == 1) {
adjust_step_octave (1);
} else if (ev->button == 3) {
adjust_step_octave (-1);
if (_step.velocity()) {
_step.set_velocity (0.0);
} else {
_step.set_velocity (0.9);
}
} else if (_seq.mode() == SequencerGrid::Octave) {
_step.set_octave_shift (0);
}
}
}

View file

@ -79,7 +79,6 @@ class StepView : public ArdourCanvas::Rectangle, public sigc::trackable {
SequencerGrid& _seq;
ArdourCanvas::Text* text;
bool grabbed;
bool grab_motion;
std::pair<double,double> grab_at;
std::pair<double,double> last_motion;
@ -97,7 +96,43 @@ class StepView : public ArdourCanvas::Rectangle, public sigc::trackable {
void step_changed (PBD::PropertyChange const &);
PBD::ScopedConnection step_connection;
void make_text ();
void set_octave_text ();
void set_group_text ();
static Gtkmm2ext::Color on_fill_color;
static Gtkmm2ext::Color off_fill_color;
};
class SequencerStepIndicator : public ArdourCanvas::Rectangle {
public:
SequencerStepIndicator (SequencerGrid&, ArdourCanvas::Item *, size_t n);
void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
bool on_event (GdkEvent*);
void set_current (bool);
private:
SequencerGrid& grid;
size_t number;
ArdourCanvas::Polygon* poly;
ArdourCanvas::Text* text;
std::pair<double,double> grab_at;
std::pair<double,double> last_motion;
static int dragging;
bool motion_event (GdkEventMotion*);
bool button_press_event (GdkEventButton*);
bool button_release_event (GdkEventButton*);
bool scroll_event (GdkEventScroll*);
void set_text ();
static Gtkmm2ext::Color current_color;
static Gtkmm2ext::Color other_color;
static Gtkmm2ext::Color current_text_color;
static Gtkmm2ext::Color other_text_color;
};
class SequencerGrid : public ArdourCanvas::Rectangle, public sigc::trackable {
@ -112,15 +147,20 @@ class SequencerGrid : public ArdourCanvas::Rectangle, public sigc::trackable {
SequencerGrid (ARDOUR::StepSequencer&, ArdourCanvas::Canvas*);
ARDOUR::StepSequencer& sequencer() const { return _sequencer; }
Mode mode() const { return _mode; }
void set_mode (Mode m);
void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
void update ();
private:
ARDOUR::StepSequencer& _sequencer;
typedef std::vector<StepView*> StepViews;
StepViews _step_views;
StepViews step_views;
typedef std::vector<SequencerStepIndicator*> StepIndicators;
StepIndicators step_indicators;
double _width;
double _height;
Mode _mode;
@ -134,15 +174,6 @@ class SequencerGrid : public ArdourCanvas::Rectangle, public sigc::trackable {
PBD::ScopedConnection sequencer_connection;
};
class SequencerStepIndicator : public ArdourCanvas::Rectangle {
public:
SequencerStepIndicator (ArdourCanvas::Item *, int n);
void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
private:
ArdourCanvas::Polygon* poly;
ArdourCanvas::Text* text;
};
class BBGUI : public ArdourDialog {
public:
BBGUI (boost::shared_ptr<ARDOUR::BeatBox> bb);