diff --git a/gtk2_ardour/beatbox_gui.cc b/gtk2_ardour/beatbox_gui.cc index 7e55ed7c85..f7a35242ef 100644 --- a/gtk2_ardour/beatbox_gui.cc +++ b/gtk2_ardour/beatbox_gui.cc @@ -20,13 +20,22 @@ #include "pbd/i18n.h" #include "ardour/beatbox.h" + #include "beatbox_gui.h" +#include "timers.h" using namespace ARDOUR; +using namespace Gtkmm2ext; + +using std::cerr; +using std::endl; BBGUI::BBGUI (boost::shared_ptr bb) : ArdourDialog (_("BeatBox")) , bbox (bb) + , step_sequencer_tab_button (_("Steps")) + , pad_tab_button (_("Pads")) + , roll_tab_button (_("Roll")) , quantize_off (quantize_group, "None") , quantize_32nd (quantize_group, "ThirtySecond") , quantize_16th (quantize_group, "Sixteenth") @@ -39,6 +48,15 @@ BBGUI::BBGUI (boost::shared_ptr bb) , tempo_adjustment (bb->tempo(), 1, 300, 1, 10) , tempo_spinner (tempo_adjustment) { + setup_pad_canvas (); + setup_step_sequencer_canvas (); + setup_roll_canvas (); + + tabs.append_page (step_sequencer_canvas); + tabs.append_page (pad_canvas); + tabs.append_page (roll_canvas); + tabs.set_show_tabs (false); + quantize_off.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 0)); quantize_32nd.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 32)); quantize_16th.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 16)); @@ -60,12 +78,20 @@ BBGUI::BBGUI (boost::shared_ptr bb) misc_button_box.pack_start (play_button); misc_button_box.pack_start (clear_button); + misc_button_box.pack_start (step_sequencer_tab_button); + misc_button_box.pack_start (pad_tab_button); + misc_button_box.pack_start (roll_tab_button); + + step_sequencer_tab_button.signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::switch_tabs), &step_sequencer_canvas)); + pad_tab_button.signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::switch_tabs), &pad_canvas)); + roll_tab_button.signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::switch_tabs), &roll_canvas)); tempo_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BBGUI::tempo_changed)); misc_button_box.pack_start (tempo_spinner); - get_vbox()->pack_start (misc_button_box); + get_vbox()->pack_start (misc_button_box, false, false); + get_vbox()->pack_start (tabs, true, true); get_vbox()->pack_start (quantize_button_box, true, true); show_all (); @@ -75,6 +101,181 @@ BBGUI::~BBGUI () { } +void +BBGUI::update () +{ + switch (tabs.get_current_page()) { + case 0: + update_steps (); + break; + case 1: + update_pads (); + break; + case 2: + update_roll (); + break; + default: + return; + } +} + +void +BBGUI::update_steps () +{ +} + +void +BBGUI::update_roll () +{ +} + +void +BBGUI::update_pads () +{ + Timecode::BBT_Time bbt; + + if (!bbox->running()) { + pads_off (); + return; + } + + bbt = bbox->get_last_time (); + + int current_pad_column = (bbt.bars - 1) * bbox->meter_beats (); + current_pad_column += bbt.beats - 1; + + for (Pads::iterator p = pads.begin(); p != pads.end(); ++p) { + if ((*p)->col() == current_pad_column) { + (*p)->rect->set_outline_color (rgba_to_color (1.0, 0.0, 0.0, 1.0)); + } else { + (*p)->rect->set_outline_color (rgba_to_color (0.0, 0.0, 0.0, 1.0)); + } + } +} + +void +BBGUI::pads_off () +{ +} + +void +BBGUI::on_map () +{ + timer_connection = Timers::rapid_connect (sigc::mem_fun (*this, &BBGUI::update)); + ArdourDialog::on_map (); +} + +void +BBGUI::on_unmap () +{ + timer_connection.disconnect (); + ArdourDialog::on_unmap (); +} +void +BBGUI::switch_tabs (Gtk::Widget* w) +{ + tabs.set_current_page (tabs.page_num (*w)); +} + +int BBGUI::Pad::pad_width = 80; +int BBGUI::Pad::pad_height = 80; +int BBGUI::Pad::pad_spacing = 6; + +BBGUI::Pad::Pad (ArdourCanvas::Canvas* canvas, int row, int col, int note, std::string const& txt) + : rect (new ArdourCanvas::Rectangle (canvas, ArdourCanvas::Rect ((col * pad_spacing) + (col * (pad_width - pad_spacing)), (row * pad_spacing) + (row * (pad_height - pad_spacing)), + (col * pad_spacing) + ((col + 1) * (pad_width - pad_spacing)) , (row * pad_spacing) + ((row +1) * (pad_height - pad_spacing))))) + , text (new ArdourCanvas::Text (canvas)) + , _row (row) + , _col (col) + , _note (note) + , _label (txt) +{ + canvas->root()->add (rect); + canvas->root()->add (text); + + text->set (_label); + + const ArdourCanvas::Rect r (rect->get()); + text->set_position (ArdourCanvas::Duple (r.x0 + 10, r.y0 + 10)); +} + +void +BBGUI::Pad::set_color (Gtkmm2ext::Color c) +{ + rect->set_fill_color (c); + text->set_color (contrasting_text_color (c)); +} + +void +BBGUI::setup_pad_canvas () +{ + pad_canvas.set_background_color (Gtkmm2ext::rgba_to_color (0.32, 0.47, 0.89, 1.0)); + + size_pads (8, 8); +} + +void +BBGUI::size_pads (int cols, int rows) +{ + /* XXX 8 x 8 grid */ + + for (Pads::iterator p = pads.begin(); p != pads.end(); ++p) { + delete *p; + } + + pads.clear (); + pad_connections.drop_connections (); + + pad_rows = rows; + pad_cols = cols; + + for (int row = 0; row < pad_rows; ++row) { + + int note = random() % 128; + + for (int col = 0; col < pad_cols; ++col) { + Pad* p = new Pad (&pad_canvas, row, col, note, string_compose ("%1", note)); + p->set_color (Gtkmm2ext::rgba_to_color ((random() % 255) / 255.0, + (random() % 255) / 255.0, + (random() % 255) / 255.0, + (random() % 255) / 255.0)); + + p->rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::pad_event), col, row)); + pads.push_back (p); + } + } +} + +bool +BBGUI::pad_event (GdkEvent* ev, int col, int row) +{ + if (ev->type == GDK_BUTTON_PRESS) { + Timecode::BBT_Time at; + + at.bars = col / bbox->meter_beats(); + at.beats = col % bbox->meter_beats(); + at.ticks = 0; + + at.bars++; + at.beats++; + + bbox->inject_note (pads[row * pad_cols + col]->note(), 127, at); + return true; + } + + return false; +} + +void +BBGUI::setup_step_sequencer_canvas () +{ +} + +void +BBGUI::setup_roll_canvas () +{ +} + void BBGUI::tempo_changed () { diff --git a/gtk2_ardour/beatbox_gui.h b/gtk2_ardour/beatbox_gui.h index bf3abbd867..e6da3c631a 100644 --- a/gtk2_ardour/beatbox_gui.h +++ b/gtk2_ardour/beatbox_gui.h @@ -20,6 +20,7 @@ #ifndef __gtk2_ardour_beatbox_gui_h__ #define __gtk2_ardour_beatbox_gui_h__ +#include #include #include @@ -27,7 +28,15 @@ #include #include #include +#include +#include "gtkmm2ext/colors.h" + +#include "canvas/canvas.h" +#include "canvas/rectangle.h" +#include "canvas/text.h" + +#include "widgets/ardour_button.h" #include "ardour_dialog.h" namespace ARDOUR { @@ -39,9 +48,51 @@ class BBGUI : public ArdourDialog { BBGUI (boost::shared_ptr bb); ~BBGUI (); + protected: + void on_map (); + void on_unmap (); + private: boost::shared_ptr bbox; + ArdourCanvas::GtkCanvas step_sequencer_canvas; + ArdourCanvas::GtkCanvas pad_canvas; + ArdourCanvas::GtkCanvas roll_canvas; + + ArdourWidgets::ArdourButton step_sequencer_tab_button; + ArdourWidgets::ArdourButton pad_tab_button; + ArdourWidgets::ArdourButton roll_tab_button; + + sigc::connection timer_connection; + + struct Pad { + Pad (ArdourCanvas::Canvas* canvas, int x, int y, int note, std::string const & txt); + void set_color (Gtkmm2ext::Color); + + ArdourCanvas::Rectangle* rect; + ArdourCanvas::Text* text; + + static int pad_width; + static int pad_height; + static int pad_spacing; + + int row() const { return _row; } + int col() const { return _col; } + int note() const { return _note; } + private: + int _row; + int _col; + int _note; + std::string _label; + }; + + typedef std::vector Pads; + Pads pads; + int pad_rows; + int pad_cols; + + Gtk::Notebook tabs; + Gtk::RadioButtonGroup quantize_group; Gtk::RadioButton quantize_off; Gtk::RadioButton quantize_32nd; @@ -65,6 +116,22 @@ class BBGUI : public ArdourDialog { void toggle_play (); void clear (); void tempo_changed (); + + void setup_step_sequencer_canvas (); + void setup_pad_canvas (); + void setup_roll_canvas (); + + void size_pads (int cols, int rows); + + void switch_tabs (Gtk::Widget*); + void pads_off (); + void update (); + void update_pads (); + void update_steps (); + void update_roll (); + + bool pad_event (GdkEvent*, int col, int row); + PBD::ScopedConnectionList pad_connections; }; #endif /* __gtk2_ardour_beatbox_gui_h__ */