diff --git a/gtk2_ardour/beatbox_gui.cc b/gtk2_ardour/beatbox_gui.cc new file mode 100644 index 0000000000..8e0789d4b9 --- /dev/null +++ b/gtk2_ardour/beatbox_gui.cc @@ -0,0 +1,601 @@ +/* + Copyright (C) 2017 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "pbd/compose.h" +#include "pbd/i18n.h" + +#include "ardour/beatbox.h" +#include "ardour/session.h" +#include "ardour/smf_source.h" +#include "ardour/source_factory.h" +#include "ardour/region.h" +#include "ardour/region_factory.h" +#include "ardour/utils.h" + +#include "canvas/canvas.h" +#include "canvas/grid.h" +#include "canvas/box.h" +#include "canvas/rectangle.h" +#include "canvas/step_button.h" +#include "canvas/text.h" +#include "canvas/widget.h" + +#include "gtkmm2ext/utils.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")) + , export_as_region_button (_(">Region")) + , quantize_off (quantize_group, "None") + , quantize_32nd (quantize_group, "ThirtySecond") + , quantize_16th (quantize_group, "Sixteenth") + , quantize_8th (quantize_group, "Eighth") + , quantize_quarter (quantize_group, "Quarter") + , quantize_half (quantize_group, "Half") + , quantize_whole (quantize_group, "Whole") + , play_button ("Run") + , clear_button ("Clear") + , tempo_adjustment (bb->tempo(), 1, 300, 1, 10) + , tempo_spinner (tempo_adjustment) +{ + srandom (time(0)); + setup_pad_canvas (); + setup_switch_canvas (); + setup_roll_canvas (); + + tabs.append_page (switch_canvas); + tabs.append_page (pad_canvas); + tabs.append_page (roll_canvas); + tabs.set_show_tabs (false); + tabs.set_show_border (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)); + quantize_8th.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 8)); + quantize_quarter.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 4)); + quantize_half.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 2)); + quantize_whole.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &BBGUI::set_quantize), 1)); + + quantize_button_box.pack_start (quantize_off); + quantize_button_box.pack_start (quantize_32nd); + quantize_button_box.pack_start (quantize_16th); + quantize_button_box.pack_start (quantize_8th); + quantize_button_box.pack_start (quantize_quarter); + quantize_button_box.pack_start (quantize_half); + quantize_button_box.pack_start (quantize_whole); + + play_button.signal_toggled().connect (sigc::mem_fun (*this, &BBGUI::toggle_play)); + clear_button.signal_clicked().connect (sigc::mem_fun (*this, &BBGUI::clear)); + + 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), &switch_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()->set_spacing (12); + get_vbox()->pack_start (misc_button_box, false, false); + get_vbox()->pack_start (tabs, false, false); + get_vbox()->pack_start (quantize_button_box, true, true); + + + export_as_region_button.signal_clicked.connect (sigc::mem_fun (*this, &BBGUI::export_as_region)); + get_action_area()->pack_end (export_as_region_button); + + show_all (); +} + +BBGUI::~BBGUI () +{ + for (SwitchRows::iterator s = switch_rows.begin(); s != switch_rows.end(); ++s) { + delete *s; + } + + switch_rows.clear (); +} + +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 () +{ + Timecode::BBT_Time bbt; + + if (!bbox->running()) { + switches_off (); + return; + } + + 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); + } +} + +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)->button->set_highlight (true); + } else { + (*p)->button->set_highlight (false); + } + } +} + +void +BBGUI::pads_off () +{ + for (Pads::iterator p = pads.begin(); p != pads.end(); ++p) { + (*p)->button->set_highlight (false); + } +} + +void +BBGUI::switches_off () +{ +#if 0 + for (Switches::iterator s = switches.begin(); s != switches.end(); ++s) { + (*s)->off (); + } +#endif +} + +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) + : button (new ArdourCanvas::StepButton (canvas, pad_width, pad_height, 0)) + , _row (row) + , _col (col) + , _note (note) + , _label (txt) +{ +} + +int +BBGUI::Pad::velocity () const +{ + return button->value(); +} + +//static std::string show_color (Gtkmm2ext::Color c) { double r, g, b, a; color_to_rgba (c, r, g, b, a); return string_compose ("%1:%2:%3:%4", r, g, b, a); } + +void +BBGUI::setup_pad_canvas () +{ + pad_canvas.set_background_color (Gtkmm2ext::rgba_to_color (0.32, 0.47, 0.89, 1.0)); + pad_grid = new ArdourCanvas::Grid (&pad_canvas); + pad_canvas.root()->add (pad_grid); + + 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_rows = rows; + pad_cols = cols; + + Gtkmm2ext::Color c = Gtkmm2ext::rgba_to_color (0.525, 0, 0, 1.0); + + 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)); + /* This is the "off" color */ + pad_grid->place (p->button, col, row, 1, 1); + p->button->set_color (c); + p->button->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) +{ + Pad* p = pads[row*pad_cols + col]; + Timecode::BBT_Time at; + + at.bars = col / bbox->meter_beats(); + at.beats = col % bbox->meter_beats(); + at.ticks = 0; + + at.bars++; + at.beats++; + + if (ev->type == GDK_BUTTON_PRESS) { + /* XXX on/off should be done by model changes */ + if (p->button->value()) { + bbox->remove_note (pads[row * pad_cols + col]->note(), at); + p->button->set_value (0); + } else { + bbox->add_note (pads[row * pad_cols + col]->note(), 127, at); + p->button->set_value (64); + return true; + } + } + + return false; +} + +void +BBGUI::setup_switch_canvas () +{ + switch_canvas.set_background_color (Gtkmm2ext::rgba_to_color (0.1, 0.09, 0.12, 1.0)); + switch_vbox = new ArdourCanvas::VBox (&switch_canvas); + switch_vbox->name = "swvbox"; + + size_switches (8, 8); + + switch_canvas.root()->add (switch_vbox); +} + +int BBGUI::Switch::switch_width = 50; +int BBGUI::Switch::switch_height = 50; + +BBGUI::Switch::Switch (ArdourCanvas::Canvas* canvas, int row, int col, int note, Gtkmm2ext::Color c, std::string const& txt) + : button (new ArdourCanvas::StepButton (canvas, switch_width, switch_height, c)) + , _row (row) + , _col (col) + , _note (note) + , _label (txt) + , _on (false) + , _flashed (false) +{ +} + +//static std::string show_color (Gtkmm2ext::Color c) { double r, g, b, a; color_to_rgba (c, r, g, b, a); return string_compose ("%1:%2:%3:%4", r, g, b, a); } + +BBGUI::SwitchRow::SwitchRow (BBGUI& bbg, ArdourCanvas::Item* parent, int r, int cols) + : owner (bbg) + , row (r) + , clear_row_button (new ArdourWidgets::ArdourButton ("C")) + , row_note_button (new ArdourWidgets::ArdourDropdown) + , clear_row_item (new ArdourCanvas::Widget (parent->canvas(), *clear_row_button)) + , row_note_item (new ArdourCanvas::Widget (parent->canvas(), *row_note_button)) +{ + /* populate note dropdown */ + for (int n = 0; n < 127; ++n) { + row_note_button->AddMenuElem (Gtk::Menu_Helpers::MenuElem (print_midi_note (n), sigc::bind (sigc::mem_fun (*this, &BBGUI::SwitchRow::set_note), n))); + } + +#define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5) + set_size_request_to_display_given_text (*row_note_button, "G#-1\n127", COMBO_TRIANGLE_WIDTH, 2); + note = 130; /* invalid value to force change in set_note() */ + set_note (r + 64); + + switch_grid = new ArdourCanvas::Grid (parent->canvas()); + switch_grid->name = string_compose ("Grid for row %1", r); + //switch_grid->set_border_width (0); + //switch_grid->set_col_spacing (0); + + row_note_item->name = string_compose ("row note for %1", r); + switch_grid->place (row_note_item, 0, r, 2, 1); + + resize (cols); + + parent->add (switch_grid); +} + +std::string +BBGUI::SwitchRow::print_midi_note (int n) +{ + return string_compose ("%1\n%2", ParameterDescriptor::midi_note_name (n), n+1); +} + +void +BBGUI::SwitchRow::resize (int cols) +{ + const Gtkmm2ext::Color c = Gtkmm2ext::rgba_to_color (0.525, 0.1, 0.0, 1.0); + + switch_grid->remove (clear_row_item); + + Switches::size_type n = switches.size(); + + while (n > (Switches::size_type) cols) { + Switch* s = switches.back (); + switch_grid->remove (s->button); + delete s; + switches.pop_back (); + --n; + } + + while (n < (Switches::size_type) cols) { + Switch* s = new Switch (switch_grid->canvas(), row, n, note, c, string_compose ("%1", note)); + s->button->Event.connect (sigc::bind (sigc::mem_fun (*this, &SwitchRow::switch_event), n)); + s->button->name = string_compose ("switch %1,%2", n, row); + switch_grid->place (s->button, 2 + n, row, 1, 1); + switches.push_back (s); + ++n; + } + + clear_row_item->name = string_compose ("clear for %1", row); + switch_grid->place (clear_row_item, 2 + cols, row, 1, 1); +} + +BBGUI::SwitchRow::~SwitchRow() +{ + drop_switches (); +} + +void +BBGUI::SwitchRow::drop_switches () +{ + for (Switches::iterator s = switches.begin(); s != switches.end(); ++s) { + delete *s; + } + + switches.clear (); +} + +void +BBGUI::SwitchRow::update (int current_col) +{ + for (Switches::iterator s = switches.begin(); s != switches.end(); ++s) { + if ((*s)->col() == current_col) { + (*s)->button->set_highlight (true); + } else { + (*s)->button->set_highlight (false); + } + } +} + +void +BBGUI::size_switches (int cols, int rows) +{ + switch_cols = cols; + + for (int row = 0; row < rows; ++row) { + SwitchRow*sr = new SwitchRow (*this, switch_vbox, row, cols); + switch_rows.push_back (sr); + } +} + +bool +BBGUI::SwitchRow::switch_event (GdkEvent* ev, int col) +{ + Timecode::BBT_Time at; + + const int beats_per_bar = owner.bbox->meter_beats(); + + at.bars = col / beats_per_bar; + at.beats = col % beats_per_bar; + at.ticks = 0; + + at.bars++; + at.beats++; + + Switch* s = switches[col]; + + if (ev->type == GDK_BUTTON_PRESS) { + /* XXX changes hould be driven by model */ + if (s->button->value()) { + owner.bbox->remove_note (note, at); + s->button->set_value (0); + } else { + s->button->set_value (64); + owner.bbox->add_note (note, rint (s->button->value()), at); + } + return true; + } else if (ev->type == GDK_SCROLL) { + switch (ev->scroll.direction) { + case GDK_SCROLL_UP: + case GDK_SCROLL_RIGHT: + s->button->set_value (s->button->value() + 1); + break; + case GDK_SCROLL_DOWN: + case GDK_SCROLL_LEFT: + s->button->set_value (s->button->value() - 1); + break; + } + return true; + } + + return false; +} + +void +BBGUI::SwitchRow::set_note (int n) +{ + if (n < 0) { + n = 0; + } else if (n > 127) { + n = 127; + } + + if (note == n) { + return; + } + + int old_note = note; + + note = n; + + owner.bbox->edit_note_number (old_note, note); + row_note_button->set_text (print_midi_note (note)); +} + +void +BBGUI::setup_roll_canvas () +{ +} + +void +BBGUI::tempo_changed () +{ + float t = tempo_adjustment.get_value(); + bbox->set_tempo (t); +} + +void +BBGUI::set_quantize (int divisor) +{ + bbox->set_quantize (divisor); +} + +void +BBGUI::clear () +{ + bbox->clear (); +} + +void +BBGUI::toggle_play () +{ + if (bbox->running()) { + bbox->stop (); + } else { + bbox->start (); + } +} + +void +BBGUI::export_as_region () +{ + std::string path = bbox->session().new_midi_source_path (bbox->owner()->name()); + + boost::shared_ptr src; + + /* caller must check for pre-existing file */ + + assert (!path.empty()); + assert (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)); + + src = boost::dynamic_pointer_cast(SourceFactory::createWritable (DataType::MIDI, bbox->session(), path, false, bbox->session().sample_rate())); + + try { + if (src->create (path)) { + return; + } + } catch (...) { + return; + } + + if (!bbox->fill_source (src)) { + + return; + } + + std::string region_name = region_name_from_path (src->name(), true); + + PBD::PropertyList plist; + + plist.add (ARDOUR::Properties::start, 0); + plist.add (ARDOUR::Properties::length, src->length (0)); + plist.add (ARDOUR::Properties::name, region_name); + plist.add (ARDOUR::Properties::layer, 0); + plist.add (ARDOUR::Properties::whole_file, true); + plist.add (ARDOUR::Properties::external, false); + + boost::shared_ptr region = RegionFactory::create (src, plist, true); +} diff --git a/gtk2_ardour/beatbox_gui.h b/gtk2_ardour/beatbox_gui.h new file mode 100644 index 0000000000..978b905e28 --- /dev/null +++ b/gtk2_ardour/beatbox_gui.h @@ -0,0 +1,224 @@ +/* + Copyright (C) 2017 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtk2_ardour_beatbox_gui_h__ +#define __gtk2_ardour_beatbox_gui_h__ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "gtkmm2ext/colors.h" + +#include "canvas/canvas.h" + +#include "widgets/ardour_button.h" +#include "widgets/ardour_dropdown.h" +#include "ardour_dialog.h" + +namespace ArdourCanvas { +class Grid; +class Item; +class Rectangle; +class StepButton; +class Text; +class VBox; +class Widget; +} + +namespace ARDOUR { +class BeatBox; +} + +class BBGUI : public ArdourDialog { + public: + BBGUI (boost::shared_ptr bb); + ~BBGUI (); + + protected: + void on_map (); + void on_unmap (); + + private: + friend class SwitchRow; + boost::shared_ptr bbox; + + ArdourCanvas::GtkCanvas switch_canvas; + ArdourCanvas::GtkCanvas pad_canvas; + ArdourCanvas::GtkCanvas roll_canvas; + + ArdourCanvas::Grid* pad_grid; + + 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::StepButton* button; + + 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; } + int velocity() const; + + private: + int _row; + int _col; + int _note; + std::string _label; + }; + + typedef std::vector Pads; + Pads pads; + int pad_rows; + int pad_cols; + + + struct Switch { + Switch (ArdourCanvas::Canvas*, int x, int y, int note, Gtkmm2ext::Color, std::string const & txt); + void set_color (Gtkmm2ext::Color); + + bool is_on () const { return _on; } + bool is_off () const { return !_on; } + bool is_flashed() const { return _flashed; } + + void on (); + void off (); + void flash_on (); + void flash_off (); + + ArdourCanvas::StepButton* button; + + static int switch_width; + static int switch_height; + static int switch_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; + Gtkmm2ext::HSV hsv; + bool _on; + bool _flashed; + }; + + typedef std::vector Switches; + + struct SwitchRow { + BBGUI& owner; + int row; + int note; + ArdourCanvas::Grid* switch_grid; + Switches switches; + ArdourWidgets::ArdourButton* clear_row_button; + ArdourWidgets::ArdourDropdown* row_note_button; + ArdourCanvas::Widget* clear_row_item; + ArdourCanvas::Widget* row_note_item; + + SwitchRow (BBGUI&, ArdourCanvas::Item*, int row, int cols); + ~SwitchRow (); + + void set_note (int note_number); + void update (int current_row); + + private: + void resize (int cols); + void drop_switches (); + bool switch_event (GdkEvent*, int col); + std::string print_midi_note (int note); + }; + + typedef std::vector SwitchRows; + + ArdourCanvas::VBox* switch_vbox; + + SwitchRows switch_rows; + int switch_cols; + + ArdourCanvas::Item* add_row_button; + + void size_switches (int cols, int rows); + + Gtk::Notebook tabs; + + ArdourWidgets::ArdourButton export_as_region_button; + void export_as_region (); + + Gtk::RadioButtonGroup quantize_group; + Gtk::RadioButton quantize_off; + Gtk::RadioButton quantize_32nd; + Gtk::RadioButton quantize_16th; + Gtk::RadioButton quantize_8th; + Gtk::RadioButton quantize_quarter; + Gtk::RadioButton quantize_half; + Gtk::RadioButton quantize_whole; + + Gtk::ToggleButton play_button; + Gtk::Button clear_button; + + Gtk::Adjustment tempo_adjustment; + Gtk::SpinButton tempo_spinner; + + Gtk::VBox quantize_button_box; + Gtk::HBox misc_button_box; + + + void set_quantize (int divisor); + void toggle_play (); + void clear (); + void tempo_changed (); + + void setup_switch_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 switches_off (); + void update (); + void update_pads (); + void update_steps (); + void update_roll (); + + bool pad_event (GdkEvent*, int col, int row); + +}; + +#endif /* __gtk2_ardour_beatbox_gui_h__ */ diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index 39edf04520..d860cb2695 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -56,6 +56,7 @@ #include "ardour/amp.h" #include "ardour/audio_track.h" #include "ardour/audioengine.h" +#include "ardour/beatbox.h" #include "ardour/internal_return.h" #include "ardour/internal_send.h" #include "ardour/luaproc.h" @@ -2937,6 +2938,9 @@ ProcessorBox::maybe_add_processor_to_ui_list (boost::weak_ptr w) have_ui = true; } } + else if (boost::dynamic_pointer_cast (p)) { + have_ui = true; + } if (!have_ui) { return; @@ -3006,13 +3010,27 @@ ProcessorBox::add_processor_to_display (boost::weak_ptr p) boost::shared_ptr send = boost::dynamic_pointer_cast (processor); boost::shared_ptr ext = boost::dynamic_pointer_cast (processor); + boost::shared_ptr bb = boost::dynamic_pointer_cast (processor); boost::shared_ptr stub = boost::dynamic_pointer_cast (processor); //faders and meters are not deletable, copy/paste-able, so they shouldn't be selectable - if (!send && !plugin_insert && !ext && !stub) { + + if (!send && !plugin_insert && !ext && !stub && !bb) { e->set_selectable(false); } + bool mark_send_visible = false; + if (send && _parent_strip) { + /* show controls of new sends by default */ + GUIObjectState& st = _parent_strip->gui_object_state (); + XMLNode* strip = st.get_or_add_node (_parent_strip->state_id ()); + assert (strip); + /* check if state exists, if not it must be a new send */ + if (!st.get_node(strip, e->state_id())) { + mark_send_visible = true; + } + } + /* Set up this entry's state from the GUIObjectState */ XMLNode* proc = entry_gui_object_state (e); if (proc) { @@ -3590,6 +3608,8 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr } p.reset (pi); + } else if (type->value() == "beatbox") { + /* XXX do something */ } else { /* XXX its a bit limiting to assume that everything else is a plugin. @@ -3786,6 +3806,7 @@ ProcessorBox::get_editor_window (boost::shared_ptr processor, bool us boost::shared_ptr retrn; boost::shared_ptr plugin_insert; boost::shared_ptr port_insert; + boost::shared_ptr beatbox; Window* gidget = 0; /* This method may or may not return a Window, but if it does not it @@ -3890,6 +3911,20 @@ ProcessorBox::get_editor_window (boost::shared_ptr processor, bool us } gidget = io_selector; + + } else if ((beatbox = boost::dynamic_pointer_cast (processor)) != 0) { + + Window* w = get_processor_ui (beatbox); + BBGUI* bbg = 0; + + if (!w) { + bbg = new BBGUI (beatbox); + set_processor_ui (beatbox, bbg); + } else { + bbg = dynamic_cast (w); + } + + gidget = bbg; } return gidget; diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index da46a15143..eb00f2ce25 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -60,6 +60,7 @@ gtk2_ardour_sources = [ 'automation_streamview.cc', 'automation_time_axis.cc', 'axis_view.cc', + 'beatbox.cc', 'big_clock_window.cc', 'big_transport_window.cc', 'bundle_manager.cc',