diff options
author | Carl Hetherington <carl@carlh.net> | 2010-12-28 18:19:40 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2010-12-28 18:19:40 +0000 |
commit | f8ebb4582d4d881fbda75a6bc9cd9c50f5c921f3 (patch) | |
tree | 90608a3cb424866b2a164c354d1665a7b0a9d79a /gtk2_ardour | |
parent | 390f18c1152f2007b790a77c873b50ef48209f44 (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.in | 4 | ||||
-rw-r--r-- | gtk2_ardour/ardour3_ui_default.conf | 4 | ||||
-rw-r--r-- | gtk2_ardour/canvas_vars.h | 4 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_actions.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 24 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.h | 10 | ||||
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 14 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 279 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 62 | ||||
-rw-r--r-- | gtk2_ardour/midi_time_axis.cc | 9 | ||||
-rw-r--r-- | gtk2_ardour/wscript | 4 |
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', |