From 3d0c3ffb6a9f809649ab1667d81692114a50d04c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 28 Dec 2010 18:43:22 +0000 Subject: Missing files. git-svn-id: svn://localhost/ardour2/branches/3.0@8347 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/canvas-program-change.cc | 175 ------------------------------ gtk2_ardour/canvas-program-change.h | 61 ----------- gtk2_ardour/canvas_patch_change.cc | 202 +++++++++++++++++++++++++++++++++++ gtk2_ardour/canvas_patch_change.h | 74 +++++++++++++ gtk2_ardour/patch_change_dialog.cc | 106 ++++++++++++++++++ gtk2_ardour/patch_change_dialog.h | 49 +++++++++ gtk2_ardour/program_change_dialog.cc | 52 --------- gtk2_ardour/program_change_dialog.h | 33 ------ libs/evoral/evoral/PatchChange.hpp | 166 ++++++++++++++++++++++++++++ 9 files changed, 597 insertions(+), 321 deletions(-) delete mode 100644 gtk2_ardour/canvas-program-change.cc delete mode 100644 gtk2_ardour/canvas-program-change.h create mode 100644 gtk2_ardour/canvas_patch_change.cc create mode 100644 gtk2_ardour/canvas_patch_change.h create mode 100644 gtk2_ardour/patch_change_dialog.cc create mode 100644 gtk2_ardour/patch_change_dialog.h delete mode 100644 gtk2_ardour/program_change_dialog.cc delete mode 100644 gtk2_ardour/program_change_dialog.h create mode 100644 libs/evoral/evoral/PatchChange.hpp diff --git a/gtk2_ardour/canvas-program-change.cc b/gtk2_ardour/canvas-program-change.cc deleted file mode 100644 index 4e178819f2..0000000000 --- a/gtk2_ardour/canvas-program-change.cc +++ /dev/null @@ -1,175 +0,0 @@ -#include - -#include - -#include "gtkmm2ext/keyboard.h" -#include "ardour/midi_patch_manager.h" -#include "ardour_ui.h" -#include "midi_region_view.h" -#include "canvas-program-change.h" -#include "editor.h" -#include "editor_drag.h" - -using namespace Gnome::Canvas; -using namespace MIDI::Name; -using namespace std; - -/** @param x x position in pixels. - * @param event_time PC time in beats, with respect to the start of the source. - */ -CanvasProgramChange::CanvasProgramChange( - MidiRegionView& region, - Group& parent, - const string& text, - double height, - double x, - double y, - string& model_name, - string& custom_device_mode, - double event_time, - uint8_t channel, - uint8_t program) - : CanvasFlag( - region, - parent, - height, - ARDOUR_UI::config()->canvasvar_MidiProgramChangeOutline.get(), - ARDOUR_UI::config()->canvasvar_MidiProgramChangeFill.get(), - x, - y) - , _model_name(model_name) - , _custom_device_mode(custom_device_mode) - , _event_time(event_time) - , _channel(channel) - , _program(program) - , _popup_initialized(false) -{ - set_text(text); -} - -CanvasProgramChange::~CanvasProgramChange() -{ -} - -void -CanvasProgramChange::initialize_popup_menus() -{ - boost::shared_ptr channel_name_set = - MidiPatchManager::instance() - .find_channel_name_set(_model_name, _custom_device_mode, _channel); - - if (!channel_name_set) { - return; - } - - const ChannelNameSet::PatchBanks& patch_banks = channel_name_set->patch_banks(); - - // fill popup menu: - Gtk::Menu::MenuList& patch_bank_menus = _popup.items(); - - for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin(); - bank != patch_banks.end(); - ++bank) { - Glib::RefPtr underscores = Glib::Regex::create("_"); - std::string replacement(" "); - - Gtk::Menu& patch_bank_menu = *manage(new Gtk::Menu()); - - const PatchBank::PatchNameList& patches = (*bank)->patch_name_list(); - Gtk::Menu::MenuList& patch_menus = patch_bank_menu.items(); - - for (PatchBank::PatchNameList::const_iterator patch = patches.begin(); - patch != patches.end(); - ++patch) { - std::string name = underscores->replace((*patch)->name().c_str(), -1, 0, replacement); - - patch_menus.push_back( - Gtk::Menu_Helpers::MenuElem( - name, - sigc::bind( - sigc::mem_fun(*this, &CanvasProgramChange::on_patch_menu_selected), - (*patch)->patch_primary_key())) ); - } - - - std::string name = underscores->replace((*bank)->name().c_str(), -1, 0, replacement); - - patch_bank_menus.push_back( - Gtk::Menu_Helpers::MenuElem( - name, - patch_bank_menu) ); - } -} - -void -CanvasProgramChange::on_patch_menu_selected(const PatchPrimaryKey& key) -{ - cerr << " got patch program number " << key.program_number << endl; - _region.program_selected(*this, key); -} - -bool -CanvasProgramChange::on_event (GdkEvent* ev) -{ - switch (ev->type) { - case GDK_BUTTON_PRESS: - { - /* XXX: icky dcast */ - Editor* e = dynamic_cast (&_region.get_time_axis_view().editor()); - if (e->current_mouse_mode() == Editing::MouseObject && e->internal_editing()) { - - if (Gtkmm2ext::Keyboard::is_delete_event (&ev->button)) { - - _region.delete_program_change (this); - return true; - - } else if (ev->button.button == 1) { - e->drags()->set (new ProgramChangeDrag (e, this, &_region), ev); - return true; - } - } - - if (ev->button.button == 3) { - if (!_popup_initialized) { - initialize_popup_menus(); - _popup_initialized = true; - } - _popup.popup(ev->button.button, ev->button.time); - return true; - } - break; - } - - case GDK_KEY_PRESS: - switch (ev->key.keyval) { - case GDK_Up: - case GDK_KP_Up: - case GDK_uparrow: - _region.previous_program(*this); - break; - case GDK_Down: - case GDK_KP_Down: - case GDK_downarrow: - _region.next_program(*this); - break; - default: - break; - } - break; - - case GDK_SCROLL: - if (ev->scroll.direction == GDK_SCROLL_UP) { - _region.previous_program(*this); - return true; - } else if (ev->scroll.direction == GDK_SCROLL_DOWN) { - _region.next_program(*this); - return true; - } - break; - - default: - break; - } - - return false; -} diff --git a/gtk2_ardour/canvas-program-change.h b/gtk2_ardour/canvas-program-change.h deleted file mode 100644 index 51a7d427e4..0000000000 --- a/gtk2_ardour/canvas-program-change.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef CANVASPROGRAMCHANGE_H_ -#define CANVASPROGRAMCHANGE_H_ - -#include "canvas-flag.h" - -class MidiRegionView; - -namespace MIDI { - namespace Name { - struct PatchPrimaryKey; - } -} - -namespace Gnome { -namespace Canvas { - -class CanvasProgramChange : public CanvasFlag -{ -public: - CanvasProgramChange( - MidiRegionView& region, - Group& parent, - const string& text, - double height, - double x, - double y, - string& model_name, - string& custom_device_mode, - double _event_time, - uint8_t channel, - uint8_t program - ); - - virtual ~CanvasProgramChange(); - - virtual bool on_event(GdkEvent* ev); - - string model_name () const { return _model_name; } - string custom_device_mode () const { return _custom_device_mode; } - double event_time () const { return _event_time; } - uint8_t program () const { return _program; } - uint8_t channel () const { return _channel; } - - void initialize_popup_menus(); - - void on_patch_menu_selected(const MIDI::Name::PatchPrimaryKey& key); - -private: - string _model_name; - string _custom_device_mode; - double _event_time; - uint8_t _channel; - uint8_t _program; - Gtk::Menu _popup; - bool _popup_initialized; -}; - -} // namespace Canvas -} // namespace Gnome - -#endif /*CANVASPROGRAMCHANGE_H_*/ diff --git a/gtk2_ardour/canvas_patch_change.cc b/gtk2_ardour/canvas_patch_change.cc new file mode 100644 index 0000000000..320f0c0d00 --- /dev/null +++ b/gtk2_ardour/canvas_patch_change.cc @@ -0,0 +1,202 @@ +/* + Copyright (C) 2000-2010 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 "gtkmm2ext/keyboard.h" +#include "ardour/midi_patch_manager.h" +#include "ardour_ui.h" +#include "midi_region_view.h" +#include "canvas_patch_change.h" +#include "editor.h" +#include "editor_drag.h" + +using namespace Gnome::Canvas; +using namespace MIDI::Name; +using namespace std; + +/** @param x x position in pixels. + */ +CanvasPatchChange::CanvasPatchChange( + MidiRegionView& region, + Group& parent, + const string& text, + double height, + double x, + double y, + string& model_name, + string& custom_device_mode, + ARDOUR::MidiModel::PatchChangePtr patch) + : CanvasFlag( + region, + parent, + height, + ARDOUR_UI::config()->canvasvar_MidiPatchChangeOutline.get(), + ARDOUR_UI::config()->canvasvar_MidiPatchChangeFill.get(), + x, + y) + , _model_name(model_name) + , _custom_device_mode(custom_device_mode) + , _patch (patch) + , _popup_initialized(false) +{ + set_text(text); +} + +CanvasPatchChange::~CanvasPatchChange() +{ +} + +void +CanvasPatchChange::initialize_popup_menus() +{ + boost::shared_ptr channel_name_set = + MidiPatchManager::instance() + .find_channel_name_set(_model_name, _custom_device_mode, _patch->channel()); + + if (!channel_name_set) { + return; + } + + const ChannelNameSet::PatchBanks& patch_banks = channel_name_set->patch_banks(); + + // fill popup menu: + Gtk::Menu::MenuList& patch_bank_menus = _popup.items(); + + for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin(); + bank != patch_banks.end(); + ++bank) { + Glib::RefPtr underscores = Glib::Regex::create("_"); + std::string replacement(" "); + + Gtk::Menu& patch_bank_menu = *manage(new Gtk::Menu()); + + const PatchBank::PatchNameList& patches = (*bank)->patch_name_list(); + Gtk::Menu::MenuList& patch_menus = patch_bank_menu.items(); + + for (PatchBank::PatchNameList::const_iterator patch = patches.begin(); + patch != patches.end(); + ++patch) { + std::string name = underscores->replace((*patch)->name().c_str(), -1, 0, replacement); + + patch_menus.push_back( + Gtk::Menu_Helpers::MenuElem( + name, + sigc::bind( + sigc::mem_fun(*this, &CanvasPatchChange::on_patch_menu_selected), + (*patch)->patch_primary_key())) ); + } + + + std::string name = underscores->replace((*bank)->name().c_str(), -1, 0, replacement); + + patch_bank_menus.push_back( + Gtk::Menu_Helpers::MenuElem( + name, + patch_bank_menu) ); + } +} + +void +CanvasPatchChange::on_patch_menu_selected(const PatchPrimaryKey& key) +{ + cerr << " got patch program number " << key.program_number << endl; + _region.change_patch_change (*this, key); +} + +bool +CanvasPatchChange::on_event (GdkEvent* ev) +{ + switch (ev->type) { + case GDK_BUTTON_PRESS: + { + /* XXX: icky dcast */ + Editor* e = dynamic_cast (&_region.get_time_axis_view().editor()); + if (e->current_mouse_mode() == Editing::MouseObject && e->internal_editing()) { + + if (Gtkmm2ext::Keyboard::is_delete_event (&ev->button)) { + + _region.delete_patch_change (this); + return true; + + } else if (Gtkmm2ext::Keyboard::is_edit_event (&ev->button)) { + + _region.edit_patch_change (this); + return true; + + } else if (ev->button.button == 1) { + e->drags()->set (new PatchChangeDrag (e, this, &_region), ev); + return true; + } + } + + if (ev->button.button == 3) { + if (!_popup_initialized) { + initialize_popup_menus(); + _popup_initialized = true; + } + _popup.popup(ev->button.button, ev->button.time); + return true; + } + break; + } + + case GDK_KEY_PRESS: + switch (ev->key.keyval) { + case GDK_Up: + case GDK_KP_Up: + case GDK_uparrow: + _region.previous_patch (*this); + break; + case GDK_Down: + case GDK_KP_Down: + case GDK_downarrow: + _region.next_patch (*this); + break; + default: + break; + } + break; + + case GDK_SCROLL: + if (ev->scroll.direction == GDK_SCROLL_UP) { + _region.previous_patch (*this); + return true; + } else if (ev->scroll.direction == GDK_SCROLL_DOWN) { + _region.next_patch (*this); + return true; + } + break; + + case GDK_ENTER_NOTIFY: + _region.patch_entered (this); + break; + + case GDK_LEAVE_NOTIFY: + _region.patch_left (this); + break; + + default: + break; + } + + return false; +} diff --git a/gtk2_ardour/canvas_patch_change.h b/gtk2_ardour/canvas_patch_change.h new file mode 100644 index 0000000000..79eb80dfae --- /dev/null +++ b/gtk2_ardour/canvas_patch_change.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2000-2010 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 CANVAS_PATCH_CHANGE_H_ +#define CANVAS_PATCH_CHANGE_H_ + +#include "canvas-flag.h" + +class MidiRegionView; + +namespace MIDI { + namespace Name { + struct PatchPrimaryKey; + } +} + +namespace Gnome { +namespace Canvas { + +class CanvasPatchChange : public CanvasFlag +{ +public: + CanvasPatchChange( + MidiRegionView& region, + Group& parent, + const string& text, + double height, + double x, + double y, + string& model_name, + string& custom_device_mode, + ARDOUR::MidiModel::PatchChangePtr patch + ); + + virtual ~CanvasPatchChange(); + + virtual bool on_event(GdkEvent* ev); + + string model_name () const { return _model_name; } + string custom_device_mode () const { return _custom_device_mode; } + ARDOUR::MidiModel::PatchChangePtr patch () const { return _patch; } + + void initialize_popup_menus(); + + void on_patch_menu_selected(const MIDI::Name::PatchPrimaryKey& key); + +private: + string _model_name; + string _custom_device_mode; + ARDOUR::MidiModel::PatchChangePtr _patch; + Gtk::Menu _popup; + bool _popup_initialized; +}; + +} // namespace Canvas +} // namespace Gnome + +#endif /*CANVASPROGRAMCHANGE_H_*/ diff --git a/gtk2_ardour/patch_change_dialog.cc b/gtk2_ardour/patch_change_dialog.cc new file mode 100644 index 0000000000..e4efdc2532 --- /dev/null +++ b/gtk2_ardour/patch_change_dialog.cc @@ -0,0 +1,106 @@ +/* + Copyright (C) 2010 Paul Davis + Author: Carl Hetherington + + 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 "ardour/beats_frames_converter.h" +#include "patch_change_dialog.h" + +using namespace Gtk; + +/** @param tc If non-0, a time converter for this patch change. If 0, time and channel controls will be desensitized */ +PatchChangeDialog::PatchChangeDialog ( + const ARDOUR::BeatsFramesConverter* tc, + ARDOUR::Session* session, + Evoral::PatchChange const & patch, + const Gtk::BuiltinStockID& ok + ) + : ArdourDialog (_("Patch Change"), true) + , _time_converter (tc) + , _time (X_("patchchangetime"), true, X_("PatchChangeTimeClock"), true, false) + , _channel (*manage (new Adjustment (1, 1, 16, 1, 4))) + , _program (*manage (new Adjustment (1, 1, 128, 1, 16))) + , _bank (*manage (new Adjustment (1, 1, 16384, 1, 64))) +{ + Table* t = manage (new Table (4, 2)); + t->set_spacings (6); + int r = 0; + + if (_time_converter) { + + Label* l = manage (new Label (_("Time"))); + l->set_alignment (0, 0.5); + t->attach (*l, 0, 1, r, r + 1); + t->attach (_time, 1, 2, r, r + 1); + ++r; + + _time.set_session (session); + _time.set_mode (AudioClock::BBT); + _time.set (_time_converter->to (patch.time ()), true); + + l = manage (new Label (_("Channel"))); + l->set_alignment (0, 0.5); + t->attach (*l, 0, 1, r, r + 1); + t->attach (_channel, 1, 2, r, r + 1); + ++r; + + _channel.set_value (patch.channel() + 1); + } + + Label* l = manage (new Label (_("Program"))); + l->set_alignment (0, 0.5); + t->attach (*l, 0, 1, r, r + 1); + t->attach (_program, 1, 2, r, r + 1); + ++r; + + _program.set_value (patch.program () + 1); + + l = manage (new Label (_("Bank"))); + l->set_alignment (0, 0.5); + t->attach (*l, 0, 1, r, r + 1); + t->attach (_bank, 1, 2, r, r + 1); + ++r; + + _bank.set_value (patch.bank() + 1); + + get_vbox()->add (*t); + + add_button (Stock::CANCEL, RESPONSE_CANCEL); + add_button (ok, RESPONSE_ACCEPT); + set_default_response (RESPONSE_ACCEPT); + + show_all (); +} + +Evoral::PatchChange +PatchChangeDialog::patch () const +{ + Evoral::MusicalTime t = 0; + if (_time_converter) { + t = _time_converter->from (_time.current_time ()); + } + + return Evoral::PatchChange ( + t, + _channel.get_value_as_int() - 1, + _program.get_value_as_int() - 1, + _bank.get_value_as_int() - 1 + ); +} diff --git a/gtk2_ardour/patch_change_dialog.h b/gtk2_ardour/patch_change_dialog.h new file mode 100644 index 0000000000..02eb311d48 --- /dev/null +++ b/gtk2_ardour/patch_change_dialog.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2010 Paul Davis + Author: Carl Hetherington + + 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 "evoral/PatchChange.hpp" +#include "ardour_dialog.h" +#include "audio_clock.h" + +namespace ARDOUR { + class BeatsFramesConverter; + class Session; +} + +class PatchChangeDialog : public ArdourDialog +{ +public: + PatchChangeDialog ( + const ARDOUR::BeatsFramesConverter *, + ARDOUR::Session *, + Evoral::PatchChange const &, + const Gtk::BuiltinStockID & + ); + + Evoral::PatchChange patch () const; + +private: + const ARDOUR::BeatsFramesConverter* _time_converter; + AudioClock _time; + Gtk::SpinButton _channel; + Gtk::SpinButton _program; + Gtk::SpinButton _bank; +}; diff --git a/gtk2_ardour/program_change_dialog.cc b/gtk2_ardour/program_change_dialog.cc deleted file mode 100644 index f333447f4a..0000000000 --- a/gtk2_ardour/program_change_dialog.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (C) 2010 Paul Davis - Author: Carl Hetherington - - 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 "program_change_dialog.h" - -using namespace Gtk; - -ProgramChangeDialog::ProgramChangeDialog () - : ArdourDialog (_("Add Program Change"), true) - , _program (*manage (new Adjustment (1, 1, 128, 1, 16))) -{ - Table* t = manage (new Table (1, 2)); - - Label* l = manage (new Label (_("Program"))); - l->set_alignment (0, 0.5); - t->attach (*l, 0, 1, 1, 2); - t->attach (_program, 1, 2, 1, 2); - - get_vbox()->add (*t); - - add_button (Stock::CANCEL, RESPONSE_CANCEL); - add_button (Stock::ADD, RESPONSE_ACCEPT); - set_default_response (RESPONSE_ACCEPT); - - show_all (); -} - -/** @return Program change number, counted from 0 */ -uint8_t -ProgramChangeDialog::program () const -{ - return _program.get_value_as_int () - 1; -} diff --git a/gtk2_ardour/program_change_dialog.h b/gtk2_ardour/program_change_dialog.h deleted file mode 100644 index 9da36ad6ed..0000000000 --- a/gtk2_ardour/program_change_dialog.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2010 Paul Davis - Author: Carl Hetherington - - 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 "ardour_dialog.h" - -class ProgramChangeDialog : public ArdourDialog -{ -public: - ProgramChangeDialog (); - - uint8_t program () const; - -private: - Gtk::SpinButton _program; -}; diff --git a/libs/evoral/evoral/PatchChange.hpp b/libs/evoral/evoral/PatchChange.hpp new file mode 100644 index 0000000000..576a1d2e98 --- /dev/null +++ b/libs/evoral/evoral/PatchChange.hpp @@ -0,0 +1,166 @@ +/* + Copyright (C) 2010 Paul Davis + Author: Carl Hetherington + + 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 EVORAL_PATCH_CHANGE_HPP +#define EVORAL_PATCH_CHANGE_HPP + +#include "evoral/Event.hpp" +#include "evoral/MIDIEvent.hpp" + +namespace Evoral { + +/** Event representing a `patch change', composed of a LSB and MSB + * bank select and then a program change. + */ +template +class PatchChange +{ +public: + /** @param t Time. + * @param c Channel. + * @param p Program change number (counted from 0). + * @param b Bank number (counted from 0, 14-bit). + */ + PatchChange (Time t, uint8_t c, uint8_t p, int b) + : _bank_change_msb (0, t, 3, 0, true) + , _bank_change_lsb (0, t, 3, 0, true) + , _program_change (0, t, 2, 0, true) + { + _bank_change_msb.buffer()[0] = MIDI_CMD_CONTROL | c; + _bank_change_msb.buffer()[1] = MIDI_CTL_MSB_BANK; + _bank_change_msb.buffer()[2] = (b >> 7) & 0x7f; + + _bank_change_lsb.buffer()[0] = MIDI_CMD_CONTROL | c; + _bank_change_lsb.buffer()[1] = MIDI_CTL_LSB_BANK; + _bank_change_lsb.buffer()[2] = b & 0x7f; + + _program_change.buffer()[0] = MIDI_CMD_PGM_CHANGE | c; + _program_change.buffer()[1] = p; + } + + PatchChange (const PatchChange & other) + : _bank_change_msb (other._bank_change_msb, true) + , _bank_change_lsb (other._bank_change_lsb, true) + , _program_change (other._program_change, true) + { + set_id (other.id ()); + } + + event_id_t id () const { + return _program_change.id (); + } + + void set_id (event_id_t id) { + _bank_change_msb.set_id (id); + _bank_change_lsb.set_id (id); + _program_change.set_id (id); + } + + Time time () const { + return _program_change.time (); + } + + void set_time (Time t) { + _bank_change_msb.set_time (t); + _bank_change_lsb.set_time (t); + _program_change.set_time (t); + } + + void set_channel (uint8_t c) { + _bank_change_msb.buffer()[0] &= 0xf0; + _bank_change_msb.buffer()[0] |= c; + _bank_change_lsb.buffer()[0] &= 0xf0; + _bank_change_lsb.buffer()[0] |= c; + _program_change.buffer()[0] &= 0xf0; + _program_change.buffer()[0] |= c; + } + + uint8_t program () const { + return _program_change.buffer()[1]; + } + + void set_program (uint8_t p) { + _program_change.buffer()[1] = p; + } + + int bank () const { + return (bank_msb() << 7) | bank_lsb(); + } + + void set_bank (int b) { + _bank_change_msb.buffer()[2] = (b >> 7) & 0x7f; + _bank_change_lsb.buffer()[2] = b & 0x7f; + } + + uint8_t bank_msb () const { + return _bank_change_msb.buffer()[2]; + } + + uint8_t bank_lsb () const { + return _bank_change_lsb.buffer()[2]; + } + + uint8_t channel () const { return _program_change.buffer()[0] & 0xf; } + + inline bool operator< (const PatchChange