/*
Copyright (C) 2001-2007 Paul Davis
- Author: Dave Robillard
+ Author: David Robillard
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
#include "automation_time_axis.h"
#include "canvas-hit.h"
#include "canvas-note.h"
-#include "canvas-program-change.h"
+#include "canvas_patch_change.h"
+#include "debug.h"
#include "editor.h"
#include "ghostregion.h"
#include "gui_thread.h"
#include "midi_region_view.h"
#include "midi_streamview.h"
#include "midi_time_axis.h"
-#include "midi_time_axis.h"
#include "midi_util.h"
#include "note_player.h"
#include "public_editor.h"
#include "streamview.h"
#include "utils.h"
#include "mouse_cursors.h"
+#include "patch_change_dialog.h"
#include "i18n.h"
, _model_name(string())
, _custom_device_mode(string())
, _active_notes(0)
- , _note_group(new ArdourCanvas::Group(*parent))
- , _diff_command(0)
+ , _note_group(new ArdourCanvas::Group(*group))
+ , _note_diff_command (0)
, _ghost_note(0)
, _drag_rect (0)
, _step_edit_cursor (0)
, _step_edit_cursor_width (1.0)
, _step_edit_cursor_position (0.0)
+ , _channel_selection_scoped_note (0)
+ , _temporary_note_group (0)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, no_sound_notes (false)
+ , _last_event_x (0)
+ , _last_event_y (0)
, pre_enter_cursor (0)
{
_note_group->raise_to_top();
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
- , _diff_command(0)
+ , _note_diff_command (0)
, _ghost_note(0)
, _drag_rect (0)
, _step_edit_cursor (0)
, _step_edit_cursor_width (1.0)
, _step_edit_cursor_position (0.0)
+ , _channel_selection_scoped_note (0)
+ , _temporary_note_group (0)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, no_sound_notes (false)
+ , _last_event_x (0)
+ , _last_event_y (0)
{
_note_group->raise_to_top();
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*get_canvas_group()))
- , _diff_command(0)
+ , _note_diff_command (0)
, _ghost_note(0)
, _drag_rect (0)
, _step_edit_cursor (0)
, _step_edit_cursor_width (1.0)
, _step_edit_cursor_position (0.0)
+ , _channel_selection_scoped_note (0)
+ , _temporary_note_group (0)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, no_sound_notes (false)
+ , _last_event_x (0)
+ , _last_event_y (0)
{
Gdk::Color c;
int r,g,b,a;
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*get_canvas_group()))
- , _diff_command(0)
+ , _note_diff_command (0)
, _ghost_note(0)
, _drag_rect (0)
, _step_edit_cursor (0)
, _step_edit_cursor_width (1.0)
, _step_edit_cursor_position (0.0)
+ , _channel_selection_scoped_note (0)
+ , _temporary_note_group (0)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, no_sound_notes (false)
+ , _last_event_x (0)
+ , _last_event_y (0)
{
Gdk::Color c;
int r,g,b,a;
bool
MidiRegionView::canvas_event(GdkEvent* ev)
{
+ switch (ev->type) {
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ _last_event_x = ev->crossing.x;
+ _last_event_y = ev->crossing.y;
+ break;
+ case GDK_MOTION_NOTIFY:
+ _last_event_x = ev->motion.x;
+ _last_event_y = ev->motion.y;
+ break;
+ default:
+ break;
+ }
+
if (!trackview.editor().internal_editing()) {
return false;
}
- /* XXX: note that until version 2.30, the GnomeCanvas did not propagate scroll events
- to its items, which means that ev->type == GDK_SCROLL will never be seen
- */
-
switch (ev->type) {
case GDK_SCROLL:
return scroll (&ev->scroll);
return false;
}
+void
+MidiRegionView::remove_ghost_note ()
+{
+ delete _ghost_note;
+ _ghost_note = 0;
+}
+
bool
MidiRegionView::enter_notify (GdkEventCrossing* ev)
{
- /* FIXME: do this on switch to note tool, too, if the pointer is already in */
+ trackview.editor().MouseModeChanged.connect (
+ _mouse_mode_connection, invalidator (*this), ui_bind (&MidiRegionView::mouse_mode_changed, this), gui_context ()
+ );
Keyboard::magic_widget_grab_focus();
group->grab_focus();
-
- if (trackview.editor().current_mouse_mode() == MouseRange) {
- create_ghost_note (ev->x, ev->y);
- }
+
+ if (trackview.editor().current_mouse_mode() == MouseRange) {
+ create_ghost_note (ev->x, ev->y);
+ }
return false;
}
bool
MidiRegionView::leave_notify (GdkEventCrossing*)
{
+ _mouse_mode_connection.disconnect ();
+
trackview.editor().hide_verbose_canvas_cursor ();
- delete _ghost_note;
- _ghost_note = 0;
+ remove_ghost_note ();
return false;
}
+void
+MidiRegionView::mouse_mode_changed ()
+{
+ if (trackview.editor().current_mouse_mode() == MouseRange && trackview.editor().internal_editing()) {
+ create_ghost_note (_last_event_x, _last_event_y);
+ } else {
+ remove_ghost_note ();
+ trackview.editor().hide_verbose_canvas_cursor ();
+ }
+}
+
bool
MidiRegionView::button_press (GdkEventButton* ev)
{
+ if (ev->button != 1) {
+ return false;
+ }
+
_last_x = ev->x;
_last_y = ev->y;
+
group->w2i (_last_x, _last_y);
- if (_mouse_state != SelectTouchDragging && ev->button == 1) {
+ if (_mouse_state != SelectTouchDragging) {
+
_pressed_button = ev->button;
_mouse_state = Pressed;
+
return true;
}
double event_x, event_y;
framepos_t event_frame = 0;
+ if (ev->button != 1) {
+ return false;
+ }
+
event_x = ev->x;
event_y = ev->y;
+
group->w2i(event_x, event_y);
group->ungrab(ev->time);
- event_frame = trackview.editor().pixel_to_frame(event_x);
-
- if (ev->button == 3) {
- return false;
- } else if (_pressed_button != 1) {
- return false;
- }
+
+ event_frame = trackview.editor().pixel_to_frame(event_x);
switch (_mouse_state) {
- case Pressed: // Clicked
+ case Pressed: // Clicked
+
switch (trackview.editor().current_mouse_mode()) {
case MouseObject:
case MouseTimeFX:
+ {
clear_selection();
- maybe_select_by_position (ev, event_x, event_y);
- break;
+
+ if (Keyboard::is_insert_note_event(ev)){
+
+ double event_x, event_y;
+
+ event_x = ev->x;
+ event_y = ev->y;
+ group->w2i(event_x, event_y);
+ bool success;
+ Evoral::MusicalTime beats = trackview.editor().get_grid_type_as_beats (success, trackview.editor().pixel_to_frame (event_x));
+
+ if (!success) {
+ beats = 1;
+ }
+
+ create_note_at (event_x, event_y, beats, true);
+ }
+
+ break;
+ }
case MouseRange:
{
bool success;
Evoral::MusicalTime beats = trackview.editor().get_grid_type_as_beats (success, trackview.editor().pixel_to_frame (event_x));
- if (!success) {
+
+ if (!success) {
beats = 1;
}
+
create_note_at (event_x, event_y, beats, true);
- break;
+
+ break;
}
default:
break;
}
+
_mouse_state = None;
break;
+
case SelectRectDragging: // Select drag done
+
_mouse_state = None;
delete _drag_rect;
_drag_rect = 0;
break;
case AddDragging: // Add drag done
+
_mouse_state = None;
- if (_drag_rect->property_x2() > _drag_rect->property_x1() + 2) {
- const double x = _drag_rect->property_x1();
- const double length = trackview.editor().pixel_to_frame
- (_drag_rect->property_x2() - _drag_rect->property_x1());
+
+ if (Keyboard::is_insert_note_event(ev) || trackview.editor().current_mouse_mode() == MouseRange){
+
+ if (_drag_rect->property_x2() > _drag_rect->property_x1() + 2) {
+
+ const double x = _drag_rect->property_x1();
+ const double length = trackview.editor().pixel_to_frame (_drag_rect->property_x2() - _drag_rect->property_x1());
- create_note_at (x, _drag_rect->property_y1(), frames_to_beats(length), false);
+ create_note_at (x, _drag_rect->property_y1(), frames_to_beats(length), true);
+ }
}
delete _drag_rect;
_drag_rect = 0;
create_ghost_note (ev->x, ev->y);
-
+
default:
break;
}
// convert event_x to global frame
event_frame = trackview.editor().pixel_to_frame(event_x) + _region->position();
trackview.editor().snap_to(event_frame);
- // convert event_frame back to local coordinates relative to position
+
+ // convert event_frame back to local coordinates relative to position
event_frame -= _region->position();
- if (_ghost_note) {
+ if (!_ghost_note && trackview.editor().current_mouse_mode() != MouseRange
+ && Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())
+ && _mouse_state != AddDragging){
+
+ create_ghost_note (ev->x, ev->y);
+ }
+ else if (_ghost_note && trackview.editor().current_mouse_mode() != MouseRange
+ && Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())){
+
+ update_ghost_note (ev->x, ev->y);
+ }
+ else if (_ghost_note && trackview.editor().current_mouse_mode() != MouseRange){
+
+ delete _ghost_note;
+ _ghost_note = 0;
+
+ trackview.editor().hide_verbose_canvas_cursor ();
+ }
+ else if (_ghost_note && trackview.editor().current_mouse_mode() == MouseRange) {
update_ghost_note (ev->x, ev->y);
}
switch (_mouse_state) {
case Pressed: // Maybe start a drag, if we've moved a bit
-
+
if (fabs (event_x - _last_x) < 1 && fabs (event_y - _last_y) < 1) {
/* no appreciable movement since the button was pressed */
return false;
}
// Select drag start
- if (_pressed_button == 1 && trackview.editor().current_mouse_mode() == MouseObject) {
- group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+ if (_pressed_button == 1 && trackview.editor().current_mouse_mode() == MouseObject
+ && !Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
+
+ group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
Gdk::Cursor(Gdk::FLEUR), ev->time);
+
_last_x = event_x;
_last_y = event_y;
_drag_start_x = event_x;
group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
Gdk::Cursor(Gdk::FLEUR), ev->time);
+
_last_x = event_x;
_last_y = event_y;
_drag_start_x = event_x;
_drag_rect->property_fill_color_rgba() = 0xFFFFFF66;
_mouse_state = AddDragging;
+
+ if (_ghost_note){
+
+ delete _ghost_note;
+ _ghost_note = 0;
+
+ trackview.editor().hide_verbose_canvas_cursor ();
+ }
+
return true;
}
case SelectRectDragging: // Select drag motion
case AddDragging: // Add note drag motion
+
if (ev->is_hint) {
int t_x;
int t_y;
event_y = t_y;
}
- if (_mouse_state == AddDragging)
+ if (_mouse_state == AddDragging){
event_x = trackview.editor().frame_to_pixel(event_frame);
+ }
if (_drag_rect) {
- if (event_x > _drag_start_x)
+
+ if (event_x > _drag_start_x){
_drag_rect->property_x2() = event_x;
- else
+ }
+ else {
_drag_rect->property_x1() = event_x;
+ }
}
if (_drag_rect && _mouse_state == SelectRectDragging) {
- if (event_y > _drag_start_y)
+
+ if (event_y > _drag_start_y){
_drag_rect->property_y2() = event_y;
- else
+ }
+ else {
_drag_rect->property_y1() = event_y;
+ }
- update_drag_selection(_drag_start_x, event_x, _drag_start_y, event_y);
+ update_drag_selection(_drag_start_x, event_x, _drag_start_y, event_y);
}
_last_x = event_x;
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
MidiStreamView* const view = mtv->midi_view();
- double note = midi_stream_view()->y_to_note(y);
+ double note = view->y_to_note(y);
assert(note >= 0.0);
assert(note <= 127.0);
length = frames_to_beats (beats_to_frames (length) - 1);
}
- uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
- int chn_cnt = 0;
- uint8_t channel = 0;
-
- /* pick the highest selected channel, unless all channels are selected,
- which is interpreted to mean channel 1 (zero)
- */
-
- for (uint16_t i = 0; i < 16; ++i) {
- if (chn_mask & (1<<i)) {
- channel = i;
- chn_cnt++;
- }
- }
-
- if (chn_cnt == 16) {
- channel = 0;
- }
-
- const boost::shared_ptr<NoteType> new_note (new NoteType (channel,
+ const boost::shared_ptr<NoteType> new_note (new NoteType (get_channel_for_add (),
frames_to_beats(start_frames + _region->start()), length,
(uint8_t)note, 0x40));
view->update_note_range(new_note->note());
- MidiModel::DiffCommand* cmd = _model->new_diff_command("add note");
- cmd->add(new_note);
+ MidiModel::NoteDiffCommand* cmd = _model->new_note_diff_command("add note");
+ cmd->add (new_note);
_model->apply_command(*trackview.session(), cmd);
play_midi_note (new_note);
}
_events.clear();
- _pgm_changes.clear();
+ _patch_changes.clear();
_sys_exes.clear();
_optimization_iterator = _events.end();
}
}
void
-MidiRegionView::start_diff_command(string name)
+MidiRegionView::start_note_diff_command (string name)
{
- if (!_diff_command) {
- _diff_command = _model->new_diff_command(name);
+ if (!_note_diff_command) {
+ _note_diff_command = _model->new_note_diff_command (name);
}
}
void
-MidiRegionView::diff_add_note(const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity)
+MidiRegionView::note_diff_add_note (const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity)
{
- if (_diff_command) {
- _diff_command->add(note);
+ if (_note_diff_command) {
+ _note_diff_command->add (note);
}
if (selected) {
_marked_for_selection.insert(note);
}
void
-MidiRegionView::diff_remove_note(ArdourCanvas::CanvasNoteEvent* ev)
+MidiRegionView::note_diff_remove_note (ArdourCanvas::CanvasNoteEvent* ev)
{
- if (_diff_command && ev->note()) {
- _diff_command->remove(ev->note());
+ if (_note_diff_command && ev->note()) {
+ _note_diff_command->remove(ev->note());
}
}
void
-MidiRegionView::diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
- MidiModel::DiffCommand::Property property,
- uint8_t val)
+MidiRegionView::note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
+ MidiModel::NoteDiffCommand::Property property,
+ uint8_t val)
{
- if (_diff_command) {
- _diff_command->change (ev->note(), property, val);
+ if (_note_diff_command) {
+ _note_diff_command->change (ev->note(), property, val);
}
}
void
-MidiRegionView::diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
- MidiModel::DiffCommand::Property property,
- Evoral::MusicalTime val)
+MidiRegionView::note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
+ MidiModel::NoteDiffCommand::Property property,
+ Evoral::MusicalTime val)
{
- if (_diff_command) {
- _diff_command->change (ev->note(), property, val);
+ if (_note_diff_command) {
+ _note_diff_command->change (ev->note(), property, val);
}
}
void
-MidiRegionView::apply_diff ()
+MidiRegionView::apply_diff (bool as_subcommand)
{
bool add_or_remove;
- if (!_diff_command) {
+ if (!_note_diff_command) {
return;
}
- if ((add_or_remove = _diff_command->adds_or_removes())) {
+ if ((add_or_remove = _note_diff_command->adds_or_removes())) {
// Mark all selected notes for selection when model reloads
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
_marked_for_selection.insert((*i)->note());
}
}
- _model->apply_command(*trackview.session(), _diff_command);
- _diff_command = 0;
+ if (as_subcommand) {
+ _model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
+ } else {
+ _model->apply_command (*trackview.session(), _note_diff_command);
+ }
+
+ _note_diff_command = 0;
midi_view()->midi_track()->playlist_modified();
if (add_or_remove) {
_marked_for_velocity.clear();
}
-void
-MidiRegionView::apply_diff_as_subcommand()
-{
- bool add_or_remove;
-
- if (!_diff_command) {
- return;
- }
-
- if ((add_or_remove = _diff_command->adds_or_removes())) {
- // Mark all selected notes for selection when model reloads
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- _marked_for_selection.insert((*i)->note());
- }
- }
-
- _model->apply_command_as_subcommand(*trackview.session(), _diff_command);
- _diff_command = 0;
- midi_view()->midi_track()->playlist_modified();
-
- if (add_or_remove) {
- _marked_for_selection.clear();
- }
- _marked_for_velocity.clear();
-}
-
-
void
MidiRegionView::abort_command()
{
- delete _diff_command;
- _diff_command = 0;
+ delete _note_diff_command;
+ _note_diff_command = 0;
clear_selection();
}
}
if (!_model) {
- cerr << "MidiRegionView::redisplay_model called without a model" << endmsg;
return;
}
}
}
- _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 ();
}
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));
-
- if (!control) {
- return;
- }
+ for (MidiModel::PatchChanges::const_iterator i = _model->patch_changes().begin(); i != _model->patch_changes().end(); ++i) {
- 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_pgm_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_pgm_change(program_change, buf);
+ char buf[16];
+ /* program and bank numbers are zero-based: convert to one-based */
+ snprintf (buf, 16, "%d\n%d", (*i)->program() + 1, (*i)->bank() + 1);
+ add_canvas_patch_change (*i, buf);
}
}
}
}
string text = str.str();
- ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
-
const double x = trackview.editor().frame_to_pixel(beats_to_frames(time));
double height = midi_stream_view()->contents_height();
boost::shared_ptr<CanvasSysEx> sysex = boost::shared_ptr<CanvasSysEx>(
- new CanvasSysEx(*this, *group, text, height, x, 1.0));
+ 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 {
clear_events();
delete _note_group;
- delete _diff_command;
+ delete _note_diff_command;
delete _step_edit_cursor;
+ delete _temporary_note_group;
}
void
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());
}
ghost = new MidiGhostRegion (tv, trackview, unit_position);
}
- ghost->set_height ();
- ghost->set_duration (_region->length() / samples_per_unit);
- ghosts.push_back (ghost);
-
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
if ((note = dynamic_cast<CanvasNote*>(*i)) != 0) {
ghost->add_note(note);
}
}
+ ghost->set_height ();
+ ghost->set_duration (_region->length() / samples_per_unit);
+ ghosts.push_back (ghost);
+
GhostRegion::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&RegionView::remove_ghost, this, _1), gui_context());
return ghost;
}
if (_active_notes && _active_notes[note]) {
- const framepos_t end_time_frames = beats_to_frames(end_time) - _region->start();
+
+ const framepos_t end_time_frames = beats_to_frames(end_time);
+
_active_notes[note]->property_x2() = trackview.editor().frame_to_pixel(end_time_frames);
_active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
_active_notes[note] = 0;
return !outside;
}
+/** Update a canvas note's size from its model note.
+ * @param ev Canvas note to update.
+ * @param update_ghost_regions true to update the note in any ghost regions that we have, otherwise false.
+ */
void
-MidiRegionView::update_note (CanvasNote* ev)
+MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
{
boost::shared_ptr<NoteType> note = ev->note();
ev->property_x1() = x;
ev->property_y1() = y1;
+
if (note->length() > 0) {
ev->property_x2() = note_endpixel;
} else {
ev->property_x2() = trackview.editor().frame_to_pixel(_region->length());
}
+
ev->property_y2() = y1 + floor(midi_stream_view()->note_height());
if (note->length() == 0) {
/* outline all edges */
ev->property_outline_what() = (guint32) 0xF;
}
+
+ if (update_ghost_regions) {
+ for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
+ MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
+ if (gr) {
+ gr->update_note (ev);
+ }
+ }
+ }
}
double
assert(note->time() >= 0);
assert(midi_view()->note_mode() == Sustained || midi_view()->note_mode() == Percussive);
- ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
+ //ArdourCanvas::Group* const group = (ArdourCanvas::Group*) get_canvas_group();
if (midi_view()->note_mode() == Sustained) {
- CanvasNote* ev_rect = new CanvasNote(*this, *group, note);
+ CanvasNote* ev_rect = new CanvasNote(*this, *_note_group, note);
update_note (ev_rect);
const double diamond_size = midi_stream_view()->note_height() / 2.0;
- CanvasHit* ev_diamond = new CanvasHit(*this, *group, diamond_size, note);
+ CanvasHit* ev_diamond = new CanvasHit(*this, *_note_group, diamond_size, note);
update_hit (ev_diamond);
if (_marked_for_velocity.find(note) != _marked_for_velocity.end()) {
event->show_velocity();
}
+
event->on_channel_selection_change(_last_channel_selection);
_events.push_back(event);
event->hide ();
}
}
+
+ MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ MidiStreamView* const view = mtv->midi_view();
+
+ view->update_note_range(note->note());
}
void
if (end_frame > region_end) {
_region->set_length (end_frame - _region->position(), this);
}
+
+ MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ MidiStreamView* const view = mtv->midi_view();
+
+ view->update_note_range(new_note->note());
_marked_for_selection.clear ();
clear_selection ();
- start_diff_command (_("step add"));
- diff_add_note (new_note, true, false);
+ start_note_diff_command (_("step add"));
+ note_diff_add_note (new_note, true, false);
apply_diff();
// last_step_edit_note = new_note;
}
void
-MidiRegionView::add_pgm_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);
- ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
- 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, *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));
+ MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time);
+ while (i != _model->patch_changes().end() && (*i)->channel() != channel) {
+ ++i;
}
+
+ 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;
+ }
+
+ assert (key.is_sane());
+}
+
- 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);
+void
+MidiRegionView::change_patch_change (CanvasPatchChange& pc, const MIDI::Name::PatchPrimaryKey& new_patch)
+{
+ 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);
}
- 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);
+ int const new_bank = (new_patch.msb << 7) | new_patch.lsb;
+ if (pc.patch()->bank() != new_bank) {
+ c->change_bank (pc.patch (), new_bank);
}
- 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());
-}
+ _model->apply_command (*trackview.session(), c);
+ _patch_changes.clear ();
+ display_patch_changes ();
+}
void
-MidiRegionView::alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch)
+MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange<Evoral::MusicalTime> & new_change)
{
- // 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 (old_change->time() != new_change.time()) {
+ c->change_time (old_change, new_change.time());
}
- // 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);
+ if (old_change->channel() != new_change.channel()) {
+ c->change_channel (old_change, new_change.channel());
+ }
+
+ if (old_change->program() != new_change.program()) {
+ c->change_program (old_change, new_change.program());
}
- Evoral::Parameter program_change(MidiPgmChangeAutomation, old_program.channel, 0);
- boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
+ if (old_change->bank() != new_change.bank()) {
+ c->change_bank (old_change, new_change.bank());
+ }
- 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 ();
}
+/** 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::program_selected(CanvasProgramChange& program, const MIDI::Name::PatchPrimaryKey& new_patch)
+MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::MusicalTime> const & patch)
{
- 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 (_("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::previous_program(CanvasProgramChange& program)
+MidiRegionView::move_patch_change (CanvasPatchChange& pc, Evoral::MusicalTime t)
{
- if (program.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());
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change"));
+ c->change_time (pc.patch (), t);
+ _model->apply_command (*trackview.session(), c);
+ _patch_changes.clear ();
+ display_patch_changes ();
+}
+
+void
+MidiRegionView::delete_patch_change (CanvasPatchChange* pc)
+{
+ 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_patch (CanvasPatchChange& patch)
+{
+ if (patch.patch()->program() < 127) {
+ MIDI::Name::PatchPrimaryKey key;
+ 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);
}
}
return;
}
- start_diff_command (_("delete selection"));
+ start_note_diff_command (_("delete selection"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->selected()) {
- _diff_command->remove((*i)->note());
+ _note_diff_command->remove((*i)->note());
}
}
void
MidiRegionView::delete_note (boost::shared_ptr<NoteType> n)
{
- start_diff_command (_("delete note"));
- _diff_command->remove (n);
+ start_note_diff_command (_("delete note"));
+ _note_diff_command->remove (n);
apply_diff ();
trackview.editor().hide_verbose_canvas_cursor ();
}
}
+void
+MidiRegionView::select_all_notes ()
+{
+ clear_selection ();
+
+ for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+ add_to_selection (*i);
+ }
+}
+
void
MidiRegionView::select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend)
{
highest_note_difference = highest_note_in_selection - 127;
}
- start_diff_command(_("move notes"));
+ start_note_diff_command (_("move notes"));
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
continue;
}
- diff_add_change (*i, MidiModel::DiffCommand::StartTime, new_time);
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time);
uint8_t original_pitch = (*i)->note()->note();
uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
- diff_add_change (*i, MidiModel::DiffCommand::NoteNumber, new_pitch);
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
}
apply_diff();
// create a new SimpleRect from the note which will be the resize preview
SimpleRect *resize_rect = new SimpleRect(
- *group, note->x1(), note->y1(), note->x2(), note->y2());
+ *_note_group, note->x1(), note->y1(), note->x2(), note->y2());
// calculate the colors: get the color settings
uint32_t fill_color = UINT_RGBA_CHANGE_A(
* as the \a primary note.
*/
void
-MidiRegionView::update_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
+MidiRegionView::update_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at_front, double delta_x, bool relative)
{
bool cursor_set = false;
* Parameters the same as for \a update_resizing().
*/
void
-MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
+MidiRegionView::commit_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at_front, double delta_x, bool relative)
{
- start_diff_command(_("resize notes"));
+ start_note_diff_command (_("resize notes"));
for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
CanvasNote* canvas_note = (*i)->canvas_note;
current_x = frames_to_beats (current_x);
if (at_front && current_x < canvas_note->note()->end_time()) {
- diff_add_change (canvas_note, MidiModel::DiffCommand::StartTime, current_x);
+ note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::StartTime, current_x);
double len = canvas_note->note()->time() - current_x;
len += canvas_note->note()->length();
if (len > 0) {
/* XXX convert to beats */
- diff_add_change (canvas_note, MidiModel::DiffCommand::Length, len);
+ note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::Length, len);
}
}
if (len > 0) {
/* XXX convert to beats */
- diff_add_change (canvas_note, MidiModel::DiffCommand::Length, len);
+ note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::Length, len);
}
}
void
MidiRegionView::change_note_channel (CanvasNoteEvent* event, int8_t channel)
{
- diff_add_change (event, MidiModel::DiffCommand::Channel, (uint8_t) channel);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::Channel, (uint8_t) channel);
}
void
event->set_selected (event->selected()); // change color
- diff_add_change (event, MidiModel::DiffCommand::Velocity, new_velocity);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::Velocity, new_velocity);
}
void
}
clamp_to_0_127 (new_note);
- diff_add_change (event, MidiModel::DiffCommand::NoteNumber, new_note);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::NoteNumber, new_note);
}
void
}
if (change_start) {
- diff_add_change (event, MidiModel::DiffCommand::StartTime, new_start);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::StartTime, new_start);
}
if (change_length) {
- diff_add_change (event, MidiModel::DiffCommand::Length, new_length);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, new_length);
}
}
new_time = delta;
}
- diff_add_change (event, MidiModel::DiffCommand::StartTime, new_time);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::StartTime, new_time);
}
void
MidiRegionView::change_note_length (CanvasNoteEvent* event, Evoral::MusicalTime t)
{
- diff_add_change (event, MidiModel::DiffCommand::Length, t);
+ note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, t);
}
void
}
}
- start_diff_command(_("change velocities"));
+ start_note_diff_command (_("change velocities"));
for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
Selection::iterator next = i;
}
}
- start_diff_command (_("transpose"));
+ start_note_diff_command (_("transpose"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
Selection::iterator next = i;
delta = -delta;
}
- start_diff_command (_("change note lengths"));
+ start_note_diff_command (_("change note lengths"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
Selection::iterator next = i;
delta = -delta;
}
- start_diff_command (_("nudge"));
+ start_note_diff_command (_("nudge"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
Selection::iterator next = i;
void
MidiRegionView::change_channel(uint8_t channel)
{
- start_diff_command(_("change channel"));
+ start_note_diff_command(_("change channel"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- diff_add_change (*i, MidiModel::DiffCommand::Channel, channel);
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::Channel, channel);
}
apply_diff();
}
}
+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());
-
+
if (x_fraction > 0.0 && x_fraction < 0.25) {
editor->set_canvas_cursor (editor->cursors()->left_side_trim);
} else if (x_fraction >= 0.75 && x_fraction < 1.0) {
void
MidiRegionView::set_frame_color()
{
- if (frame) {
- if (_selected && should_show_selection) {
- frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get();
- } else {
- frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiFrameBase.get();
- }
+ uint32_t f;
+
+ TimeAxisViewItem::set_frame_color ();
+
+ if (!frame) {
+ return;
}
+
+ if (_selected) {
+ f = ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get();
+ } else if (high_enough_for_name) {
+ f= ARDOUR_UI::config()->canvasvar_MidiFrameBase.get();
+ } else {
+ f = fill_color;
+ }
+
+ if (!rect_visible) {
+ f = UINT_RGBA_CHANGE_A (f, 0);
+ }
+
+ frame->property_fill_color_rgba() = f;
}
void
}
_last_channel_selection = mask;
+
+ _patch_changes.clear ();
+ display_patch_changes ();
}
void
if (op != Copy) {
- start_diff_command();
+ start_note_diff_command();
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
switch (op) {
break;
case Cut:
case Clear:
- diff_remove_note (*i);
+ note_diff_remove_note (*i);
break;
}
}
return cb;
}
+/** This method handles undo */
void
MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
{
return;
}
- start_diff_command (_("paste"));
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("MIDI paste @ %1 times %2\n", pos, times));
+
+ trackview.session()->begin_reversible_command (_("paste"));
+
+ start_note_diff_command (_("paste"));
Evoral::MusicalTime beat_delta;
Evoral::MusicalTime paste_pos_beats;
beat_delta = (*mcb.notes().begin())->time() - paste_pos_beats;
paste_pos_beats = 0;
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6 ; beat delta = %7\n",
+ (*mcb.notes().begin())->time(),
+ (*mcb.notes().rbegin())->end_time(),
+ duration, pos, _region->position(),
+ paste_pos_beats, beat_delta));
+
clear_selection ();
for (int n = 0; n < (int) times; ++n) {
/* make all newly added notes selected */
- diff_add_note (copied_note, true);
+ note_diff_add_note (copied_note, true);
end_point = copied_note->end_time();
}
if (end_frame > region_end) {
- trackview.session()->begin_reversible_command (_("paste"));
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame));
_region->clear_changes ();
_region->set_length (end_frame, this);
trackview.session()->add_command (new StatefulDiffCommand (_region));
}
- apply_diff ();
+ apply_diff (true);
+
+ trackview.session()->commit_reversible_command ();
}
struct EventNoteTimeEarlyFirstComparator {
_last_ghost_x = x;
_last_ghost_y = y;
- group->w2i (x, y);
+ _note_group->w2i (x, y);
framepos_t f = trackview.editor().pixel_to_frame (x) + _region->position ();
trackview.editor().snap_to (f);
f -= _region->position ();
bool success;
Evoral::MusicalTime beats = trackview.editor().get_grid_type_as_beats (success, f);
+
if (!success) {
beats = 1;
}
_ghost_note->note()->set_length (length);
_ghost_note->note()->set_note (midi_stream_view()->y_to_note (y));
- update_note (_ghost_note);
+ /* the ghost note does not appear in ghost regions, so pass false in here */
+ update_note (_ghost_note, false);
show_verbose_canvas_cursor (_ghost_note->note ());
}
_ghost_note = 0;
boost::shared_ptr<NoteType> g (new NoteType);
- _ghost_note = new NoEventCanvasNote (*this, *group, g);
+ _ghost_note = new NoEventCanvasNote (*this, *_note_group, g);
+ _ghost_note->property_outline_color_rgba() = 0x000000aa;
update_ghost_note (x, y);
_ghost_note->show ();
double note = midi_stream_view()->y_to_note(y);
Events e;
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
-
- cerr << "Selecting by position\n";
uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
if (ev.type() == MIDI_CMD_NOTE_ON) {
- boost::shared_ptr<Evoral::Note<Evoral::MusicalTime> > note (
- new Evoral::Note<Evoral::MusicalTime> (ev.channel(), time_beats, 0, ev.note(), ev.velocity())
+ boost::shared_ptr<NoteType> note (
+ new NoteType (ev.channel(), time_beats, 0, ev.note(), ev.velocity())
);
add_note (note, true);
midi_stream_view()->check_record_layers (region(), back);
}
+
+void
+MidiRegionView::trim_front_starting ()
+{
+ /* Reparent the note group to the region view's parent, so that it doesn't change
+ when the region view is trimmed.
+ */
+ _temporary_note_group = new ArdourCanvas::Group (*group->property_parent ());
+ _temporary_note_group->move (group->property_x(), group->property_y());
+ _note_group->reparent (*_temporary_note_group);
+}
+
+void
+MidiRegionView::trim_front_ending ()
+{
+ _note_group->reparent (*group);
+ delete _temporary_note_group;
+ _temporary_note_group = 0;
+
+ if (_region->start() < 0) {
+ /* Trim drag made start time -ve; fix this */
+ midi_region()->fix_negative_start ();
+ }
+}
+
+/** @return channel (counted from 0) to add an event to, based on the current setting
+ * of the channel selector.
+ */
+uint8_t
+MidiRegionView::get_channel_for_add () const
+{
+ MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ uint16_t const chn_mask = mtv->channel_selector().get_selected_channels();
+ int chn_cnt = 0;
+ uint8_t channel = 0;
+
+ /* pick the highest selected channel, unless all channels are selected,
+ which is interpreted to mean channel 1 (zero)
+ */
+
+ for (uint16_t i = 0; i < 16; ++i) {
+ if (chn_mask & (1<<i)) {
+ channel = i;
+ chn_cnt++;
+ }
+ }
+
+ if (chn_cnt == 16) {
+ channel = 0;
+ }
+
+ 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 ());
+}