summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-12-28 18:19:40 +0000
committerCarl Hetherington <carl@carlh.net>2010-12-28 18:19:40 +0000
commitf8ebb4582d4d881fbda75a6bc9cd9c50f5c921f3 (patch)
tree90608a3cb424866b2a164c354d1665a7b0a9d79a /gtk2_ardour
parent390f18c1152f2007b790a77c873b50ef48209f44 (diff)
Unify program change and bank handling so that they are manipulated together.
git-svn-id: svn://localhost/ardour2/branches/3.0@8346 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/ardour.menus.in4
-rw-r--r--gtk2_ardour/ardour3_ui_default.conf4
-rw-r--r--gtk2_ardour/canvas_vars.h4
-rw-r--r--gtk2_ardour/editor.h2
-rw-r--r--gtk2_ardour/editor_actions.cc2
-rw-r--r--gtk2_ardour/editor_drag.cc24
-rw-r--r--gtk2_ardour/editor_drag.h10
-rw-r--r--gtk2_ardour/editor_ops.cc14
-rw-r--r--gtk2_ardour/midi_region_view.cc279
-rw-r--r--gtk2_ardour/midi_region_view.h62
-rw-r--r--gtk2_ardour/midi_time_axis.cc9
-rw-r--r--gtk2_ardour/wscript4
12 files changed, 208 insertions, 210 deletions
diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in
index ffbdfcc131..428160c0f5 100644
--- a/gtk2_ardour/ardour.menus.in
+++ b/gtk2_ardour/ardour.menus.in
@@ -258,7 +258,7 @@
<menuitem action='lower-region-to-bottom'/>
</menu>
<menu action='RegionMenuMIDI'>
- <menuitem action='insert-program-change'/>
+ <menuitem action='insert-patch-change'/>
<menuitem action='quantize-region'/>
<menuitem action='fork-region'/>
<menuitem action='show-region-list-editor'/>
@@ -593,7 +593,7 @@
<menuitem action='lower-region-to-bottom'/>
</menu>
<menu action='RegionMenuMIDI'>
- <menuitem action='insert-program-change'/>
+ <menuitem action='insert-patch-change'/>
<menuitem action='quantize-region'/>
<menuitem action='fork-region'/>
<menuitem action='show-region-list-editor'/>
diff --git a/gtk2_ardour/ardour3_ui_default.conf b/gtk2_ardour/ardour3_ui_default.conf
index 438aad3c69..afd0f68979 100644
--- a/gtk2_ardour/ardour3_ui_default.conf
+++ b/gtk2_ardour/ardour3_ui_default.conf
@@ -71,8 +71,8 @@
<Option name="selected midi note color max" value="ff0000ff"/>
<Option name="midi note selected" value="ff3a48ff"/>
<Option name="midi note velocity text" value="f4f214bc"/>
- <Option name="midi program change fill" value="0000ffa0"/>
- <Option name="midi program change outline" value="a7a7d4ff"/>
+ <Option name="midi patch change fill" value="0000ffa0"/>
+ <Option name="midi patch change outline" value="a7a7d4ff"/>
<Option name="midi sysex fill" value="f1e139a0"/>
<Option name="midi sysex outline" value="a7a7d4ff"/>
<Option name="midi select rect fill" value="8888ff88"/>
diff --git a/gtk2_ardour/canvas_vars.h b/gtk2_ardour/canvas_vars.h
index a8d7b9cfa3..bfc4b0305c 100644
--- a/gtk2_ardour/canvas_vars.h
+++ b/gtk2_ardour/canvas_vars.h
@@ -65,8 +65,8 @@ CANVAS_VARIABLE(canvasvar_SelectedMidiNoteColorMid, "selected midi note color mi
CANVAS_VARIABLE(canvasvar_SelectedMidiNoteColorTop, "selected midi note color max")
CANVAS_VARIABLE(canvasvar_MidiNoteSelected, "midi note selected")
CANVAS_VARIABLE(canvasvar_MidiNoteVelocityText, "midi note velocity text")
-CANVAS_VARIABLE(canvasvar_MidiProgramChangeFill, "midi program change fill")
-CANVAS_VARIABLE(canvasvar_MidiProgramChangeOutline, "midi program change outline")
+CANVAS_VARIABLE(canvasvar_MidiPatchChangeFill, "midi patch change fill")
+CANVAS_VARIABLE(canvasvar_MidiPatchChangeOutline, "midi patch change outline")
CANVAS_VARIABLE(canvasvar_MidiSysExFill, "midi sysex fill")
CANVAS_VARIABLE(canvasvar_MidiSysExOutline, "midi sysex outline")
CANVAS_VARIABLE(canvasvar_MidiSelectRectFill, "midi select rect fill")
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 57bfd5205b..a7de0498a0 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1090,7 +1090,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void reset_region_scale_amplitude ();
void adjust_region_gain (bool up);
void quantize_region ();
- void insert_program_change ();
+ void insert_patch_change ();
void fork_region ();
void do_insert_time ();
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index e88f5c9c31..c2ff86d1a8 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -1469,7 +1469,7 @@ Editor::register_region_actions ()
);
reg_sens (_region_actions, "quantize-region", _("Quantize"), sigc::mem_fun (*this, &Editor::quantize_region));
- reg_sens (_region_actions, "insert-program-change", _("Insert Program Change..."), sigc::mem_fun (*this, &Editor::insert_program_change));
+ reg_sens (_region_actions, "insert-patch-change", _("Insert Patch Change..."), sigc::mem_fun (*this, &Editor::insert_patch_change));
reg_sens (_region_actions, "fork-region", _("Fork"), sigc::mem_fun (*this, &Editor::fork_region));
reg_sens (_region_actions, "strip-region-silence", _("Strip Silence..."), sigc::mem_fun (*this, &Editor::strip_region_silence));
reg_sens (_region_actions, "set-selection-from-region", _("Set Range Selection"), sigc::mem_fun (*this, &Editor::set_selection_from_region));
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 67367e8b65..07fe0ff09a 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -4093,17 +4093,17 @@ DraggingView::DraggingView (RegionView* v, RegionDrag* parent)
initial_end = v->region()->position () + v->region()->length ();
}
-ProgramChangeDrag::ProgramChangeDrag (Editor* e, CanvasProgramChange* i, MidiRegionView* r)
+PatchChangeDrag::PatchChangeDrag (Editor* e, CanvasPatchChange* i, MidiRegionView* r)
: Drag (e, i)
, _region_view (r)
- , _program_change (i)
+ , _patch_change (i)
, _cumulative_dx (0)
{
- DEBUG_TRACE (DEBUG::Drags, "New ProgramChangeDrag\n");
+ DEBUG_TRACE (DEBUG::Drags, "New PatchChangeDrag\n");
}
void
-ProgramChangeDrag::motion (GdkEvent* ev, bool)
+PatchChangeDrag::motion (GdkEvent* ev, bool)
{
framepos_t f = adjusted_current_frame (ev);
boost::shared_ptr<Region> r = _region_view->region ();
@@ -4112,12 +4112,12 @@ ProgramChangeDrag::motion (GdkEvent* ev, bool)
framecnt_t const dxf = f - grab_frame();
double const dxu = _editor->frame_to_unit (dxf);
- _program_change->move (dxu - _cumulative_dx, 0);
+ _patch_change->move (dxu - _cumulative_dx, 0);
_cumulative_dx = dxu;
}
void
-ProgramChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
+PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
{
if (!movement_occurred) {
return;
@@ -4129,22 +4129,22 @@ ProgramChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
f = max (f, r->position ());
f = min (f, r->last_frame ());
- _region_view->move_program_change (
- MidiRegionView::PCEvent (_program_change->event_time(), _program_change->program(), _program_change->channel()),
+ _region_view->move_patch_change (
+ *_patch_change,
_region_view->frames_to_beats (f - r->position() - r->start())
);
}
void
-ProgramChangeDrag::aborted ()
+PatchChangeDrag::aborted ()
{
- _program_change->move (-_cumulative_dx, 0);
+ _patch_change->move (-_cumulative_dx, 0);
}
void
-ProgramChangeDrag::setup_pointer_frame_offset ()
+PatchChangeDrag::setup_pointer_frame_offset ()
{
boost::shared_ptr<Region> region = _region_view->region ();
- _pointer_frame_offset = raw_grab_frame() - _region_view->beats_to_frames (_program_change->event_time()) - region->position() + region->start();
+ _pointer_frame_offset = raw_grab_frame() - _region_view->beats_to_frames (_patch_change->patch()->time()) - region->position() + region->start();
}
diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h
index 3323a8b741..1f6109bcd2 100644
--- a/gtk2_ardour/editor_drag.h
+++ b/gtk2_ardour/editor_drag.h
@@ -42,7 +42,7 @@ namespace PBD {
namespace Gnome {
namespace Canvas {
class CanvasNoteEvent;
- class CanvasProgramChange;
+ class CanvasPatchChange;
}
}
@@ -451,11 +451,11 @@ class NoteDrag : public Drag
double _note_height;
};
-/** Drag to move MIDI program changes */
-class ProgramChangeDrag : public Drag
+/** Drag to move MIDI patch changes */
+class PatchChangeDrag : public Drag
{
public:
- ProgramChangeDrag (Editor *, ArdourCanvas::CanvasProgramChange *, MidiRegionView *);
+ PatchChangeDrag (Editor *, ArdourCanvas::CanvasPatchChange *, MidiRegionView *);
void motion (GdkEvent *, bool);
void finished (GdkEvent *, bool);
@@ -469,7 +469,7 @@ public:
private:
MidiRegionView* _region_view;
- ArdourCanvas::CanvasProgramChange* _program_change;
+ ArdourCanvas::CanvasPatchChange* _patch_change;
double _cumulative_dx;
};
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index b70636f58b..ed903b9d7b 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -84,7 +84,7 @@
#include "normalize_dialog.h"
#include "editor_cursors.h"
#include "mouse_cursors.h"
-#include "program_change_dialog.h"
+#include "patch_change_dialog.h"
#include "i18n.h"
@@ -4706,25 +4706,27 @@ Editor::quantize_region ()
}
void
-Editor::insert_program_change ()
+Editor::insert_patch_change ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
if (rs.empty ()) {
return;
}
- ProgramChangeDialog d;
+ framepos_t const p = get_preferred_edit_position (false);
+
+ Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
+ PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
+
if (d.run() == RESPONSE_CANCEL) {
return;
}
- framepos_t const p = get_preferred_edit_position (false);
-
for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
if (mrv) {
if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
- mrv->add_program_change (p - mrv->region()->position(), d.program ());
+ mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
}
}
}
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index dced1cd3a8..3cf59eed2c 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -48,7 +48,7 @@
#include "automation_time_axis.h"
#include "canvas-hit.h"
#include "canvas-note.h"
-#include "canvas-program-change.h"
+#include "canvas_patch_change.h"
#include "editor.h"
#include "ghostregion.h"
#include "gui_thread.h"
@@ -67,6 +67,7 @@
#include "streamview.h"
#include "utils.h"
#include "mouse_cursors.h"
+#include "patch_change_dialog.h"
#include "i18n.h"
@@ -778,7 +779,7 @@ MidiRegionView::clear_events()
}
_events.clear();
- _pgm_changes.clear();
+ _patch_changes.clear();
_sys_exes.clear();
_optimization_iterator = _events.end();
}
@@ -1019,11 +1020,11 @@ MidiRegionView::redisplay_model()
}
}
- _pgm_changes.clear();
+ _patch_changes.clear();
_sys_exes.clear();
display_sysexes();
- display_program_changes();
+ display_patch_changes ();
_marked_for_selection.clear ();
_marked_for_velocity.clear ();
@@ -1037,66 +1038,40 @@ MidiRegionView::redisplay_model()
}
void
-MidiRegionView::display_program_changes()
+MidiRegionView::display_patch_changes ()
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
for (uint8_t i = 0; i < 16; ++i) {
if (chn_mask & (1<<i)) {
- display_program_changes_on_channel (i);
+ display_patch_changes_on_channel (i);
}
}
}
void
-MidiRegionView::display_program_changes_on_channel(uint8_t channel)
+MidiRegionView::display_patch_changes_on_channel (uint8_t channel)
{
- boost::shared_ptr<Evoral::Control> control =
- _model->control(Evoral::MIDI::ProgramChange (MidiPgmChangeAutomation, channel));
+ for (MidiModel::PatchChanges::const_iterator i = _model->patch_changes().begin(); i != _model->patch_changes().end(); ++i) {
- if (!control) {
- return;
- }
-
- Glib::Mutex::Lock lock (control->list()->lock());
-
- for (AutomationList::const_iterator event = control->list()->begin();
- event != control->list()->end(); ++event) {
- double event_time = (*event)->when;
- double program_number = floor((*event)->value + 0.5);
-
- // Get current value of bank select MSB at time of the program change
- Evoral::Parameter bank_select_msb(MidiCCAutomation, channel, MIDI_CTL_MSB_BANK);
- boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
- uint8_t msb = 0;
- if (msb_control != 0) {
- msb = uint8_t(floor(msb_control->get_double(true, event_time) + 0.5));
- }
-
- // Get current value of bank select LSB at time of the program change
- Evoral::Parameter bank_select_lsb(MidiCCAutomation, channel, MIDI_CTL_LSB_BANK);
- boost::shared_ptr<Evoral::Control> lsb_control = _model->control(bank_select_lsb);
- uint8_t lsb = 0;
- if (lsb_control != 0) {
- lsb = uint8_t(floor(lsb_control->get_double(true, event_time) + 0.5));
+ if ((*i)->channel() != channel) {
+ continue;
}
-
- MIDI::Name::PatchPrimaryKey patch_key(msb, lsb, program_number);
+
+ MIDI::Name::PatchPrimaryKey patch_key ((*i)->bank_msb (), (*i)->bank_lsb (), (*i)->program ());
boost::shared_ptr<MIDI::Name::Patch> patch =
MIDI::Name::MidiPatchManager::instance().find_patch(
_model_name, _custom_device_mode, channel, patch_key);
- PCEvent program_change(event_time, uint8_t(program_number), channel);
-
if (patch != 0) {
- add_canvas_program_change (program_change, patch->name());
+ add_canvas_patch_change (*i, patch->name());
} else {
char buf[4];
// program_number is zero-based: convert to one-based
- snprintf(buf, 4, "%d", int(program_number+1));
- add_canvas_program_change (program_change, buf);
+ snprintf (buf, 4, "%d", (*i)->program() + 1);
+ add_canvas_patch_change (*i, buf);
}
}
}
@@ -1125,7 +1100,7 @@ MidiRegionView::display_sysexes()
boost::shared_ptr<CanvasSysEx> sysex = boost::shared_ptr<CanvasSysEx>(
new CanvasSysEx(*this, *_note_group, text, height, x, 1.0));
- // Show unless program change is beyond the region bounds
+ // Show unless patch change is beyond the region bounds
if (time - _region->start() >= _region->length() || time < _region->start()) {
sysex->hide();
} else {
@@ -1205,7 +1180,7 @@ MidiRegionView::set_height (double height)
name_pixbuf->raise_to_top();
}
- for (PgmChanges::iterator x = _pgm_changes.begin(); x != _pgm_changes.end(); ++x) {
+ for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
(*x)->set_height (midi_stream_view()->contents_height());
}
@@ -1563,163 +1538,163 @@ MidiRegionView::step_sustain (Evoral::MusicalTime beats)
}
void
-MidiRegionView::add_canvas_program_change (PCEvent& program, const string& displaytext)
+MidiRegionView::add_canvas_patch_change (MidiModel::PatchChangePtr patch, const string& displaytext)
{
- assert(program.time >= 0);
+ assert (patch->time() >= 0);
- const double x = trackview.editor().frame_to_pixel(beats_to_frames(program.time));
+ const double x = trackview.editor().frame_to_pixel (beats_to_frames (patch->time()));
- double height = midi_stream_view()->contents_height();
+ double const height = midi_stream_view()->contents_height();
- boost::shared_ptr<CanvasProgramChange> pgm_change = boost::shared_ptr<CanvasProgramChange>(
- new CanvasProgramChange(*this, *_note_group,
+ boost::shared_ptr<CanvasPatchChange> patch_change = boost::shared_ptr<CanvasPatchChange>(
+ new CanvasPatchChange(*this, *_note_group,
displaytext,
height,
x, 1.0,
_model_name,
_custom_device_mode,
- program.time, program.channel, program.value));
+ patch)
+ );
- // Show unless program change is beyond the region bounds
- if (program.time - _region->start() >= _region->length() || program.time < _region->start()) {
- pgm_change->hide();
+ // Show unless patch change is beyond the region bounds
+ if (patch->time() - _region->start() >= _region->length() || patch->time() < _region->start()) {
+ patch_change->hide();
} else {
- pgm_change->show();
+ patch_change->show();
}
- _pgm_changes.push_back(pgm_change);
+ _patch_changes.push_back (patch_change);
}
void
-MidiRegionView::get_patch_key_at(double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key)
+MidiRegionView::get_patch_key_at (Evoral::MusicalTime time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key)
{
- Evoral::Parameter bank_select_msb(MidiCCAutomation, channel, MIDI_CTL_MSB_BANK);
- boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
- double msb = 0.0;
- if (msb_control != 0) {
- msb = int(msb_control->get_double(true, time));
- }
-
- Evoral::Parameter bank_select_lsb(MidiCCAutomation, channel, MIDI_CTL_LSB_BANK);
- boost::shared_ptr<Evoral::Control> lsb_control = _model->control(bank_select_lsb);
- double lsb = 0.0;
- if (lsb_control != 0) {
- lsb = lsb_control->get_double(true, time);
+ MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time);
+ while (i != _model->patch_changes().end() && (*i)->channel() != channel) {
+ ++i;
}
-
- Evoral::Parameter program_change(MidiPgmChangeAutomation, channel, 0);
- boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
- double program_number = -1.0;
- if (program_control != 0) {
- program_number = program_control->get_double(true, time);
+
+ if (i != _model->patch_changes().end()) {
+ key.msb = (*i)->bank_msb ();
+ key.lsb = (*i)->bank_lsb ();
+ key.program_number = (*i)->program ();
+ } else {
+ key.msb = key.lsb = key.program_number = 0;
}
-
- key.msb = (int) floor(msb + 0.5);
- key.lsb = (int) floor(lsb + 0.5);
- key.program_number = (int) floor(program_number + 0.5);
- assert(key.is_sane());
+
+ assert (key.is_sane());
}
void
-MidiRegionView::alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch)
+MidiRegionView::change_patch_change (CanvasPatchChange& pc, const MIDI::Name::PatchPrimaryKey& new_patch)
{
- // TODO: Get the real event here and alter them at the original times
- Evoral::Parameter bank_select_msb(MidiCCAutomation, old_program.channel, MIDI_CTL_MSB_BANK);
- boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
- if (msb_control != 0) {
- msb_control->set_double(double(new_patch.msb), true, old_program.time);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("alter patch change"));
+
+ if (pc.patch()->program() != new_patch.program_number) {
+ c->change_program (pc.patch (), new_patch.program_number);
}
- // TODO: Get the real event here and alter them at the original times
- Evoral::Parameter bank_select_lsb(MidiCCAutomation, old_program.channel, MIDI_CTL_LSB_BANK);
- boost::shared_ptr<Evoral::Control> lsb_control = _model->control(bank_select_lsb);
- if (lsb_control != 0) {
- lsb_control->set_double(double(new_patch.lsb), true, old_program.time);
+ int const new_bank = (new_patch.msb << 7) | new_patch.lsb;
+ if (pc.patch()->bank() != new_bank) {
+ c->change_bank (pc.patch (), new_bank);
}
- Evoral::Parameter program_change(MidiPgmChangeAutomation, old_program.channel, 0);
- boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
-
- assert(program_control != 0);
- program_control->set_double(float(new_patch.program_number), true, old_program.time);
+ _model->apply_command (*trackview.session(), c);
- _pgm_changes.clear ();
- display_program_changes (); // XXX would be nice to limit to just old_program.channel
+ _patch_changes.clear ();
+ display_patch_changes ();
}
-/** @param t Time in frames relative to region position */
void
-MidiRegionView::add_program_change (framecnt_t t, uint8_t value)
+MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange<Evoral::MusicalTime> & new_change)
{
- boost::shared_ptr<Evoral::Control> control = midi_region()->model()->control (
- Evoral::Parameter (MidiPgmChangeAutomation, get_channel_for_add (), 0), true
- );
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("alter patch change"));
+
+ if (old_change->time() != new_change.time()) {
+ c->change_time (old_change, new_change.time());
+ }
+
+ if (old_change->channel() != new_change.channel()) {
+ c->change_channel (old_change, new_change.channel());
+ }
- assert (control);
+ if (old_change->program() != new_change.program()) {
+ c->change_program (old_change, new_change.program());
+ }
- Evoral::MusicalTime const b = frames_to_beats (t + midi_region()->start());
+ if (old_change->bank() != new_change.bank()) {
+ c->change_bank (old_change, new_change.bank());
+ }
- control->list()->add (b, value);
+ _model->apply_command (*trackview.session(), c);
- _pgm_changes.clear ();
- display_program_changes ();
+ _patch_changes.clear ();
+ display_patch_changes ();
}
+/** Add a patch change to the region.
+ * @param t Time in frames relative to region position
+ * @param patch Patch to add; time and channel are ignored (time is converted from t, and channel comes from
+ * get_channel_for_add())
+ */
void
-MidiRegionView::move_program_change (PCEvent pc, Evoral::MusicalTime t)
+MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::MusicalTime> const & patch)
{
- boost::shared_ptr<Evoral::Control> control = _model->control (Evoral::Parameter (MidiPgmChangeAutomation, pc.channel, 0));
- assert (control);
-
- control->list()->erase (pc.time, pc.value);
- control->list()->add (t, pc.value);
-
- _pgm_changes.clear ();
- display_program_changes ();
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("add patch change"));
+ c->add (MidiModel::PatchChangePtr (
+ new Evoral::PatchChange<Evoral::MusicalTime> (
+ frames_to_beats (t + midi_region()->start()), get_channel_for_add(), patch.program(), patch.bank()
+ )
+ ));
+
+ _model->apply_command (*trackview.session(), c);
+
+ _patch_changes.clear ();
+ display_patch_changes ();
}
void
-MidiRegionView::delete_program_change (CanvasProgramChange* pc)
+MidiRegionView::move_patch_change (CanvasPatchChange& pc, Evoral::MusicalTime t)
{
- boost::shared_ptr<Evoral::Control> control = _model->control (Evoral::Parameter (MidiPgmChangeAutomation, pc->channel(), 0));
- assert (control);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change"));
+ c->change_time (pc.patch (), t);
+ _model->apply_command (*trackview.session(), c);
- control->list()->erase (pc->event_time(), pc->program());
- _pgm_changes.clear ();
- display_program_changes ();
+ _patch_changes.clear ();
+ display_patch_changes ();
}
void
-MidiRegionView::program_selected(CanvasProgramChange& program, const MIDI::Name::PatchPrimaryKey& new_patch)
+MidiRegionView::delete_patch_change (CanvasPatchChange* pc)
{
- PCEvent program_change_event(program.event_time(), program.program(), program.channel());
- alter_program_change(program_change_event, new_patch);
-}
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("delete patch change"));
+ c->remove (pc->patch ());
+ _model->apply_command (*trackview.session(), c);
+ _patch_changes.clear ();
+ display_patch_changes ();
+}
+
void
-MidiRegionView::previous_program(CanvasProgramChange& program)
+MidiRegionView::previous_patch (CanvasPatchChange& patch)
{
- if (program.program() < 127) {
+ if (patch.patch()->program() < 127) {
MIDI::Name::PatchPrimaryKey key;
- get_patch_key_at(program.event_time(), program.channel(), key);
- PCEvent program_change_event(program.event_time(), program.program(), program.channel());
-
+ get_patch_key_at (patch.patch()->time(), patch.patch()->channel(), key);
key.program_number++;
- alter_program_change(program_change_event, key);
+ change_patch_change (patch, key);
}
}
void
-MidiRegionView::next_program(CanvasProgramChange& program)
+MidiRegionView::next_patch (CanvasPatchChange& patch)
{
- if (program.program() > 0) {
+ if (patch.patch()->program() > 0) {
MIDI::Name::PatchPrimaryKey key;
- get_patch_key_at(program.event_time(), program.channel(), key);
- PCEvent program_change_event(program.event_time(), program.program(), program.channel());
-
+ get_patch_key_at (patch.patch()->time(), patch.patch()->channel(), key);
key.program_number--;
- alter_program_change(program_change_event, key);
+ change_patch_change (patch, key);
}
}
@@ -2760,6 +2735,20 @@ MidiRegionView::note_left (ArdourCanvas::CanvasNoteEvent*)
}
void
+MidiRegionView::patch_entered (ArdourCanvas::CanvasPatchChange* ev)
+{
+ ostringstream s;
+ s << ((int) ev->patch()->program() + 1) << ":" << (ev->patch()->bank() + 1);
+ trackview.editor().show_verbose_canvas_cursor_with (s.str().c_str(), 10, 20);
+}
+
+void
+MidiRegionView::patch_left (ArdourCanvas::CanvasPatchChange *)
+{
+ trackview.editor().hide_verbose_canvas_cursor ();
+}
+
+void
MidiRegionView::note_mouse_position (float x_fraction, float /*y_fraction*/, bool can_set_cursor)
{
Editor* editor = dynamic_cast<Editor*>(&trackview.editor());
@@ -2806,6 +2795,9 @@ MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
}
_last_channel_selection = mask;
+
+ _patch_changes.clear ();
+ display_patch_changes ();
}
void
@@ -3303,3 +3295,14 @@ MidiRegionView::get_channel_for_add () const
return channel;
}
+
+void
+MidiRegionView::edit_patch_change (ArdourCanvas::CanvasPatchChange* pc)
+{
+ PatchChangeDialog d (&_time_converter, trackview.session(), *pc->patch (), Gtk::Stock::APPLY);
+ if (d.run () != Gtk::RESPONSE_ACCEPT) {
+ return;
+ }
+
+ change_patch_change (pc->patch(), d.patch ());
+}
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index ed8e382c4f..42b544b97d 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -43,7 +43,7 @@
#include "canvas-hit.h"
#include "canvas-note.h"
#include "canvas-note-event.h"
-#include "canvas-program-change.h"
+#include "canvas_patch_change.h"
#include "canvas-sysex.h"
namespace ARDOUR {
@@ -120,57 +120,43 @@ class MidiRegionView : public RegionView
void cut_copy_clear (Editing::CutCopyOp);
void paste (framepos_t pos, float times, const MidiCutBuffer&);
- struct PCEvent {
- PCEvent(double a_time, uint8_t a_value, uint8_t a_channel)
- : time(a_time), value(a_value), channel(a_channel) {}
-
- double time;
- uint8_t value;
- uint8_t channel;
- };
-
- /** Add a new program change flag to the canvas.
- * @param program the MidiRegionView::PCEvent to add
+ /** Add a new patch change flag to the canvas.
+ * @param patch the patch change to add
* @param the text to display in the flag
*/
- void add_canvas_program_change (PCEvent& program, const std::string& displaytext);
+ void add_canvas_patch_change (ARDOUR::MidiModel::PatchChangePtr patch, const std::string& displaytext);
/** Look up the given time and channel in the 'automation' and set keys accordingly.
- * @param time the time of the program change event
+ * @param time the time of the patch change event
* @param channel the MIDI channel of the event
* @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will
* will be set according to the result of the lookup
*/
void get_patch_key_at(double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key);
- /** Change the 'automation' data of old_program to new values which correspond to new_patch.
- * @param old_program the program change event which is to be altered
- * @param new_patch the new lsb, msb and program number which are to be set
+ /** Change old_patch to new_patch.
+ * @param old_patch the canvas patch change which is to be altered
+ * @param new_patch new patch
*/
- void alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch);
+ void change_patch_change (ArdourCanvas::CanvasPatchChange& old_patch, const MIDI::Name::PatchPrimaryKey& new_patch);
+ void change_patch_change (ARDOUR::MidiModel::PatchChangePtr, Evoral::PatchChange<Evoral::MusicalTime> const &);
- void add_program_change (framecnt_t, uint8_t);
- void move_program_change (PCEvent, Evoral::MusicalTime);
- void delete_program_change (ArdourCanvas::CanvasProgramChange *);
-
- /** Alter a given program to the new given one.
- * (Called on context menu select on CanvasProgramChange)
- */
- void program_selected(
- ArdourCanvas::CanvasProgramChange& program,
- const MIDI::Name::PatchPrimaryKey& new_patch);
+ void add_patch_change (framecnt_t, Evoral::PatchChange<Evoral::MusicalTime> const &);
+ void move_patch_change (ArdourCanvas::CanvasPatchChange &, Evoral::MusicalTime);
+ void delete_patch_change (ArdourCanvas::CanvasPatchChange *);
+ void edit_patch_change (ArdourCanvas::CanvasPatchChange *);
- /** Alter a given program to be its predecessor in the MIDNAM file.
+ /** Alter a given patch to be its predecessor in the MIDNAM file.
*/
- void previous_program(ArdourCanvas::CanvasProgramChange& program);
+ void previous_patch (ArdourCanvas::CanvasPatchChange &);
- /** Alters a given program to be its successor in the MIDNAM file.
+ /** Alters a given patch to be its successor in the MIDNAM file.
*/
- void next_program(ArdourCanvas::CanvasProgramChange& program);
+ void next_patch (ArdourCanvas::CanvasPatchChange &);
- /** Displays all program change events in the region as flags on the canvas.
+ /** Displays all patch change events in the region as flags on the canvas.
*/
- void display_program_changes();
+ void display_patch_changes();
/** Displays all system exclusive events in the region as flags on the canvas.
*/
@@ -196,6 +182,8 @@ class MidiRegionView : public RegionView
void note_entered(ArdourCanvas::CanvasNoteEvent* ev);
void note_left(ArdourCanvas::CanvasNoteEvent* ev);
+ void patch_entered (ArdourCanvas::CanvasPatchChange *);
+ void patch_left (ArdourCanvas::CanvasPatchChange *);
void note_mouse_position (float xfraction, float yfraction, bool can_set_cursor=true);
void unique_select(ArdourCanvas::CanvasNoteEvent* ev);
void note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend=false);
@@ -360,12 +348,12 @@ class MidiRegionView : public RegionView
std::string _custom_device_mode;
typedef std::list<ArdourCanvas::CanvasNoteEvent*> Events;
- typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasProgramChange> > PgmChanges;
+ typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasPatchChange> > PatchChanges;
typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasSysEx> > SysExes;
boost::shared_ptr<ARDOUR::MidiModel> _model;
Events _events;
- PgmChanges _pgm_changes;
+ PatchChanges _patch_changes;
SysExes _sys_exes;
ArdourCanvas::CanvasNote** _active_notes;
ArdourCanvas::Group* _note_group;
@@ -444,7 +432,7 @@ class MidiRegionView : public RegionView
void maybe_select_by_position (GdkEventButton* ev, double x, double y);
void get_events (Events& e, Evoral::Sequence<Evoral::MusicalTime>::NoteOperator op, uint8_t val, int chan_mask = 0);
- void display_program_changes_on_channel (uint8_t);
+ void display_patch_changes_on_channel (uint8_t);
void connect_to_diskstream ();
void data_recorded (boost::shared_ptr<ARDOUR::MidiBuffer>, boost::weak_ptr<ARDOUR::MidiSource>);
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 6504c0429f..59cfe4abbd 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -591,7 +591,8 @@ MidiTimeAxisView::build_controller_menu ()
}
}
- /* loop over all 127 MIDI controllers, in groups of 16 */
+ /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
+ bank select controllers, as they are handled by the `patch' code */
for (int i = 0; i < 127; i += 16) {
@@ -603,6 +604,10 @@ MidiTimeAxisView::build_controller_menu ()
for (int ctl = i; ctl < i+16; ++ctl) {
+ if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
+ continue;
+ }
+
if (chn_cnt > 1) {
/* multiple channels - create a submenu, with 1 item per channel */
@@ -985,7 +990,7 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
no_redraw = false;
- /* TODO: Bender, PgmChange, Pressure */
+ /* TODO: Bender, Pressure */
/* invalidate the controller menu, so that we rebuilt it next time */
_controller_menu_map.clear ();
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 8b71a1fdd2..2d88f9ced7 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -55,7 +55,7 @@ gtk2_ardour_sources = [
'canvas-hit.cc',
'canvas-note-event.cc',
'canvas-note.cc',
- 'canvas-program-change.cc',
+ 'canvas_patch_change.cc',
'canvas-simpleline.c',
'canvas-simplerect.c',
'canvas-sysex.cc',
@@ -173,7 +173,7 @@ gtk2_ardour_sources = [
'port_matrix_labels.cc',
'port_matrix_row_labels.cc',
'processor_box.cc',
- 'program_change_dialog.cc',
+ 'patch_change_dialog.cc',
'progress_reporter.cc',
'prompter.cc',
'public_editor.cc',