X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_region_view.cc;h=0ac2dfc43afe5b7cc430e39be33e09318bd2816f;hb=4b5ee47d4471df0481ca7f52a0991c098cb8ae1d;hp=8e9008769729d2fd9ad2f9523d7cfdd4f0078ab6;hpb=430bc18ba29ca4cb0d60fc9da53c88661b690920;p=ardour.git diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 8e90087697..0ac2dfc43a 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -45,6 +45,8 @@ #include "public_editor.h" #include "ghostregion.h" #include "midi_time_axis.h" +#include "automation_time_axis.h" +#include "automation_region_view.h" #include "utils.h" #include "midi_util.h" #include "gui_thread.h" @@ -58,24 +60,31 @@ using namespace PBD; using namespace Editing; using namespace ArdourCanvas; -MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr r, double spu, - Gdk::Color& basic_color) +MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr r, double spu, Gdk::Color& basic_color) : RegionView (parent, tv, r, spu, basic_color) , _default_note_length(0.0) , _active_notes(0) + , _note_group(new ArdourCanvas::Group(*parent)) , _delta_command(NULL) - , _command_mode(None) + , _mouse_state(None) + , _pressed_button(0) { + group->lower_to_bottom(); + _note_group->raise_to_top(); + + frame->property_fill_color_rgba() = 0xff000033; } -MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr r, double spu, - Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility) +MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr r, double spu, Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility) : RegionView (parent, tv, r, spu, basic_color, visibility) , _default_note_length(0.0) , _active_notes(0) + , _note_group(new ArdourCanvas::Group(*parent)) , _delta_command(NULL) - , _command_mode(None) + , _mouse_state(None) + , _pressed_button(0) { + _note_group->raise_to_top(); } void @@ -84,8 +93,8 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd) if (wfd) midi_region()->midi_source(0)->load_model(); - const Meter& m = trackview.session().tempo_map().meter_at(_region->start()); - const Tempo& t = trackview.session().tempo_map().tempo_at(_region->start()); + const Meter& m = trackview.session().tempo_map().meter_at(_region->position()); + const Tempo& t = trackview.session().tempo_map().tempo_at(_region->position()); _default_note_length = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar(); @@ -116,6 +125,8 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd) } _model->ContentsChanged.connect(sigc::mem_fun(this, &MidiRegionView::redisplay_model)); } + + midi_region()->midi_source(0)->Switched.connect(sigc::mem_fun(this, &MidiRegionView::switch_source)); group->signal_event().connect (mem_fun (this, &MidiRegionView::canvas_event), false); @@ -124,40 +135,54 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd) bool MidiRegionView::canvas_event(GdkEvent* ev) { - enum State { None, Pressed, SelectDragging, AddDragging }; - static int press_button = 0; - static State _state; + static bool delete_mod = false; + static Editing::MidiEditMode original_mode; static double drag_start_x, drag_start_y; static double last_x, last_y; double event_x, event_y; + nframes_t event_frame = 0; static ArdourCanvas::SimpleRect* drag_rect = NULL; if (trackview.editor.current_mouse_mode() != MouseNote) return false; + // Mmmm, spaghetti + switch (ev->type) { case GDK_KEY_PRESS: - if (ev->key.keyval == GDK_Delete) { + cout << "KEY" << endl; + if (ev->key.keyval == GDK_Delete && !delete_mod) { + delete_mod = true; + original_mode = trackview.editor.current_midi_edit_mode(); trackview.editor.set_midi_edit_mode(MidiEditErase); start_remove_command(); + _mouse_state = EraseTouchDragging; + } else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) { + _mouse_state = SelectTouchDragging; } - break; + return true; case GDK_KEY_RELEASE: - if (_command_mode == Remove && ev->key.keyval == GDK_Delete) { - delete_selection(); - apply_command(); - trackview.editor.set_midi_edit_mode(MidiEditSelect); + if (ev->key.keyval == GDK_Delete) { + if (_mouse_state == EraseTouchDragging) { + delete_selection(); + apply_command(); + } + if (delete_mod) { + trackview.editor.set_midi_edit_mode(original_mode); + delete_mod = false; + } + } else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) { + _mouse_state = None; } - break; + return true; case GDK_BUTTON_PRESS: - //group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ev->button.time); - _state = Pressed; - press_button = ev->button.button; - //cerr << "PRESSED: " << press_button << endl; + if (_mouse_state != SelectTouchDragging && _mouse_state != EraseTouchDragging) + _mouse_state = Pressed; + _pressed_button = ev->button.button; return true; case GDK_ENTER_NOTIFY: @@ -170,11 +195,15 @@ MidiRegionView::canvas_event(GdkEvent* ev) event_x = ev->motion.x; event_y = ev->motion.y; group->w2i(event_x, event_y); + + event_frame = trackview.editor.pixel_to_frame(event_x); + trackview.editor.snap_to(event_frame); - switch (_state) { + switch (_mouse_state) { case Pressed: // Drag start - if (press_button == 1 && _command_mode != Remove) { // Select rect start + // Select drag start + if (_pressed_button == 1 && trackview.editor.current_midi_edit_mode() == MidiEditSelect) { group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, Gdk::Cursor(Gdk::FLEUR), ev->motion.time); last_x = event_x; @@ -193,22 +222,20 @@ MidiRegionView::canvas_event(GdkEvent* ev) drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiSelectRectFill.get(); - _state = SelectDragging; + _mouse_state = SelectRectDragging; return true; - } else if (press_button == 3) { // Add note drag start + // Add note drag start + } else if (trackview.editor.current_midi_edit_mode() == MidiEditPencil) { group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, Gdk::Cursor(Gdk::FLEUR), ev->motion.time); last_x = event_x; last_y = event_y; drag_start_x = event_x; drag_start_y = event_y; - - nframes_t event_frame = midi_view()->editor.pixel_to_frame(event_x); - midi_view()->editor.snap_to(event_frame); drag_rect = new ArdourCanvas::SimpleRect(*group); - drag_rect->property_x1() = midi_view()->editor.frame_to_pixel(event_frame); + drag_rect->property_x1() = trackview.editor.frame_to_pixel(event_frame); drag_rect->property_y1() = midi_stream_view()->note_to_y(midi_stream_view()->y_to_note(event_y)); drag_rect->property_x2() = event_x; @@ -218,14 +245,14 @@ MidiRegionView::canvas_event(GdkEvent* ev) drag_rect->property_fill_color_rgba() = 0xFFFFFF66; - _state = AddDragging; + _mouse_state = AddDragging; return true; } - break; + return false; - case SelectDragging: // Select rect motion - case AddDragging: // Add note rect motion + case SelectRectDragging: // Select drag motion + case AddDragging: // Add note drag motion if (ev->motion.is_hint) { int t_x; int t_y; @@ -235,27 +262,32 @@ MidiRegionView::canvas_event(GdkEvent* ev) event_y = t_y; } - if (_state == AddDragging) { - nframes_t event_frame = midi_view()->editor.pixel_to_frame(event_x); - midi_view()->editor.snap_to(event_frame); - event_x = midi_view()->editor.frame_to_pixel(event_frame); - } + if (_mouse_state == AddDragging) + event_x = trackview.editor.frame_to_pixel(event_frame); if (drag_rect) - drag_rect->property_x2() = event_x; - - if (drag_rect && _state == SelectDragging) { - drag_rect->property_y2() = event_y; - + if (event_x > drag_start_x) + drag_rect->property_x2() = event_x; + else + drag_rect->property_x1() = event_x; + + if (drag_rect && _mouse_state == SelectRectDragging) { + if (event_y > drag_start_y) + drag_rect->property_y2() = event_y; + else + drag_rect->property_y1() = event_y; + update_drag_selection(drag_start_x, event_x, drag_start_y, event_y); } last_x = event_x; last_y = event_y; - return true; + case EraseTouchDragging: + case SelectTouchDragging: + return false; + default: - _state = None; break; } break; @@ -265,25 +297,30 @@ MidiRegionView::canvas_event(GdkEvent* ev) event_y = ev->motion.y; group->w2i(event_x, event_y); group->ungrab(ev->button.time); - switch (_state) { + event_frame = trackview.editor.pixel_to_frame(event_x); + + switch (_mouse_state) { case Pressed: // Clicked - if (ev->button.button == 1) { + switch (trackview.editor.current_midi_edit_mode()) { + case MidiEditSelect: clear_selection(); - } else if (ev->button.button == 3) { - nframes_t event_frame = midi_view()->editor.pixel_to_frame(event_x); - midi_view()->editor.snap_to(event_frame); - event_x = midi_view()->editor.frame_to_pixel(event_frame); + break; + case MidiEditPencil: + trackview.editor.snap_to(event_frame, -1); + event_x = trackview.editor.frame_to_pixel(event_frame); create_note_at(event_x, event_y, _default_note_length); + default: + break; } - _state = None; + _mouse_state = None; return true; - case SelectDragging: // Select drag done - _state = None; + case SelectRectDragging: // Select drag done + _mouse_state = None; delete drag_rect; drag_rect = NULL; return true; case AddDragging: // Add drag done - _state = None; + _mouse_state = None; if (drag_rect->property_x2() > drag_rect->property_x1() + 2) { create_note_at(drag_rect->property_x1(), drag_rect->property_y1(), trackview.editor.pixel_to_frame( @@ -326,9 +363,9 @@ MidiRegionView::create_note_at(double x, double y, double dur) //double dur = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar(); // Add a 1 beat long note (for now) - const MidiModel::Note new_note(stamp, dur, (uint8_t)note, 0x40); + const boost::shared_ptr new_note(new Note(0, stamp, dur, (uint8_t)note, 0x40)); - view->update_bounds(new_note.note()); + view->update_bounds(new_note->note()); MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note"); cmd->add(new_note); @@ -344,6 +381,14 @@ MidiRegionView::clear_events() for (std::vector::iterator i = _events.begin(); i != _events.end(); ++i) delete *i; + MidiGhostRegion* gr; + + for(vector::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { + if((gr = dynamic_cast(*g)) != 0) { + gr->clear_events(); + } + } + _events.clear(); } @@ -361,17 +406,55 @@ MidiRegionView::display_model(boost::shared_ptr model) void MidiRegionView::redisplay_model() { - clear_events(); + // Don't redisplay the model if we're currently recording and displaying that + if (_active_notes) + return; if (_model) { + + clear_events(); begin_write(); + + _model->read_lock(); for (size_t i=0; i < _model->n_notes(); ++i) add_note(_model->note_at(i)); end_write(); + + /*for (Automatable::Controls::const_iterator i = _model->controls().begin(); + i != _model->controls().end(); ++i) { + + assert(i->second); + + boost::shared_ptr at + = midi_view()->automation_child(i->second->parameter()); + if (!at) + continue; + + Gdk::Color col = midi_stream_view()->get_region_color(); + + boost::shared_ptr arv; + + { + Glib::Mutex::Lock list_lock (i->second->list()->lock()); + + arv = boost::shared_ptr( + new AutomationRegionView(at->canvas_display, + *at.get(), _region, i->second->list(), + midi_stream_view()->get_samples_per_unit(), col)); + } + + arv->set_duration(_region->length(), this); + arv->init(col, true); + + _automation_children.insert(std::make_pair(i->second->parameter(), arv)); + }*/ + + _model->read_unlock(); + } else { - warning << "MidiRegionView::redisplay_model called without a model" << endmsg; + cerr << "MidiRegionView::redisplay_model called without a model" << endmsg; } } @@ -379,7 +462,10 @@ MidiRegionView::redisplay_model() MidiRegionView::~MidiRegionView () { in_destructor = true; - end_write(); + if (_active_notes) + end_write(); + + clear_events(); RegionViewGoingAway (this); /* EMIT_SIGNAL */ } @@ -421,8 +507,35 @@ MidiRegionView::set_y_position_and_height (double y, double h) { RegionView::set_y_position_and_height(y, h - 1); - if (_enable_display) - redisplay_model(); + if (_enable_display) { + + _model->read_lock(); + + for (std::vector::const_iterator i = _events.begin(); i != _events.end(); ++i) { + CanvasNote* note = dynamic_cast(*i); + if (note && note->note()) { + if(note->note()->note() < midi_stream_view()->lowest_note() || + note->note()->note() > midi_stream_view()->highest_note()) { + if(canvas_item_visible(note)) { + note->hide(); + } + } + else { + const double y1 = midi_stream_view()->note_to_y(note->note()->note()); + const double y2 = y1 + floor(midi_stream_view()->note_height()); + + if(!canvas_item_visible(note)) { + note->show(); + } + + note->property_y1() = y1; + note->property_y2() = y2; + } + } + } + + _model->read_unlock(); + } if (name_text) { name_text->raise_to_top(); @@ -430,18 +543,37 @@ MidiRegionView::set_y_position_and_height (double y, double h) } GhostRegion* -MidiRegionView::add_ghost (AutomationTimeAxisView& atv) +MidiRegionView::add_ghost (TimeAxisView& tv) { RouteTimeAxisView* rtv = dynamic_cast(&trackview); + CanvasNote* note; assert(rtv); double unit_position = _region->position () / samples_per_unit; - GhostRegion* ghost = new GhostRegion (atv, unit_position); + MidiTimeAxisView* mtv = dynamic_cast(&tv); + MidiGhostRegion* ghost; + + if(mtv && mtv->midi_view()) { + /* if ghost is inserted into midi track, use a dedicated midi ghost canvas group. + this is because it's nice to have midi notes on top of the note lines and + audio waveforms under it. + */ + ghost = new MidiGhostRegion (*mtv->midi_view(), trackview, unit_position); + } + else { + ghost = new MidiGhostRegion (tv, trackview, unit_position); + } ghost->set_height (); ghost->set_duration (_region->length() / samples_per_unit); ghosts.push_back (ghost); + for (std::vector::iterator i = _events.begin(); i != _events.end(); ++i) { + if((note = dynamic_cast(*i)) != 0) { + ghost->add_note(note); + } + } + ghost->GoingAway.connect (mem_fun(*this, &MidiRegionView::remove_ghost)); return ghost; @@ -453,6 +585,7 @@ MidiRegionView::add_ghost (AutomationTimeAxisView& atv) void MidiRegionView::begin_write() { + assert(!_active_notes); _active_notes = new CanvasNote*[128]; for (unsigned i=0; i < 128; ++i) _active_notes[i] = NULL; @@ -469,67 +602,18 @@ MidiRegionView::end_write() } -/** Add a MIDI event. - * - * This is used while recording, and handles displaying still-unresolved notes. - * Displaying an existing model is simpler, and done with add_note. +/** Resolve an active MIDI note (while recording). */ void -MidiRegionView::add_event (const MidiEvent& ev) +MidiRegionView::resolve_note(uint8_t note, double end_time) { - /*printf("Event, time = %f, size = %zu, data = ", ev.time, ev.size); - for (size_t i=0; i < ev.size; ++i) { - printf("%X ", ev.buffer[i]); - } - printf("\n\n");*/ - - ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); - - if (midi_view()->note_mode() == Sustained) { - if ((ev.buffer()[0] & 0xF0) == MIDI_CMD_NOTE_ON) { - const Byte& note = ev.buffer()[1]; - const double y1 = midi_stream_view()->note_to_y(note); - - CanvasNote* ev_rect = new CanvasNote(*this, *group); - ev_rect->property_x1() = trackview.editor.frame_to_pixel ( - (nframes_t)ev.time()); - ev_rect->property_y1() = y1; - ev_rect->property_x2() = trackview.editor.frame_to_pixel ( - _region->length()); - ev_rect->property_y2() = y1 + floor(midi_stream_view()->note_height()); - ev_rect->property_fill_color_rgba() = note_fill_color(ev.velocity()); - ev_rect->property_outline_color_rgba() = note_outline_color(ev.velocity()); - /* outline all but right edge */ - ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8); - - ev_rect->raise_to_top(); - - _events.push_back(ev_rect); - if (_active_notes) - _active_notes[note] = ev_rect; - - } else if ((ev.buffer()[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { - const Byte& note = ev.buffer()[1]; - if (_active_notes && _active_notes[note]) { - _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)ev.time()); - _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges - _active_notes[note] = NULL; - } - } - - } else if (midi_view()->note_mode() == Percussive) { - const Byte& note = ev.buffer()[1]; - const double diamond_size = midi_stream_view()->note_height() / 2.0; - const double x = trackview.editor.frame_to_pixel((nframes_t)ev.time()); - const double y = midi_stream_view()->note_to_y(note) + ((diamond_size-2) / 4.0); + if (midi_view()->note_mode() != Sustained) + return; - CanvasHit* ev_diamond = new CanvasHit(*this, *group, diamond_size); - ev_diamond->move(x, y); - ev_diamond->show(); - ev_diamond->property_fill_color_rgba() = note_fill_color(ev.velocity()); - ev_diamond->property_outline_color_rgba() = note_outline_color(ev.velocity()); - - _events.push_back(ev_diamond); + if (_active_notes && _active_notes[note]) { + _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)end_time); + _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges + _active_notes[note] = NULL; } } @@ -550,44 +634,74 @@ MidiRegionView::extend_active_notes() /** Add a MIDI note to the view (with duration). * - * This does no 'realtime' note resolution, notes from a MidiModel have a - * duration so they can be drawn in full immediately. + * If in sustained mode, notes with duration 0 will be considered active + * notes, and resolve_note should be called when the corresponding note off + * event arrives, to properly display the note. */ void -MidiRegionView::add_note (const MidiModel::Note& note) +MidiRegionView::add_note(const boost::shared_ptr note) { - assert(note.time() >= 0); - //assert(note.time() < _region->length()); + assert(note->time() >= 0); + //assert(note->time() < _region->length()); + assert(midi_view()->note_mode() == Sustained || midi_view()->note_mode() == Percussive); ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); if (midi_view()->note_mode() == Sustained) { - const double y1 = midi_stream_view()->note_to_y(note.note()); + + //cerr << "MRV::add_note sustained " << note->note() << " @ " << note->time() + // << " .. " << note->end_time() << endl; + + const double y1 = midi_stream_view()->note_to_y(note->note()); - CanvasNote* ev_rect = new CanvasNote(*this, *group, ¬e); - ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note.time()); + CanvasNote* ev_rect = new CanvasNote(*this, *group, note); + ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note->time()); ev_rect->property_y1() = y1; - ev_rect->property_x2() = trackview.editor.frame_to_pixel((nframes_t)(note.end_time())); + if (note->duration() > 0) + ev_rect->property_x2() = trackview.editor.frame_to_pixel((nframes_t)(note->end_time())); + else + ev_rect->property_x2() = trackview.editor.frame_to_pixel(_region->length()); ev_rect->property_y2() = y1 + floor(midi_stream_view()->note_height()); - ev_rect->property_fill_color_rgba() = note_fill_color(note.velocity()); - ev_rect->property_outline_color_rgba() = note_outline_color(note.velocity()); - ev_rect->property_outline_what() = (guint32) 0xF; // all edges + ev_rect->property_fill_color_rgba() = note_fill_color(note->velocity()); + ev_rect->property_outline_color_rgba() = note_outline_color(note->velocity()); + if (note->duration() == 0) { + _active_notes[note->note()] = ev_rect; + /* outline all but right edge */ + ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8); + } else { + /* outline all edges */ + ev_rect->property_outline_what() = (guint32) 0xF; + } + ev_rect->show(); _events.push_back(ev_rect); + MidiGhostRegion* gr; + + for(vector::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { + if((gr = dynamic_cast(*g)) != 0) { + gr->add_note(ev_rect); + } + } + } else if (midi_view()->note_mode() == Percussive) { + + //cerr << "MRV::add_note percussive " << note->note() << " @ " << note->time() + // << " .. " << note->end_time() << endl; + const double diamond_size = midi_stream_view()->note_height() / 2.0; - const double x = trackview.editor.frame_to_pixel((nframes_t)note.time()); - const double y = midi_stream_view()->note_to_y(note.note()) + ((diamond_size-2) / 4.0); + const double x = trackview.editor.frame_to_pixel((nframes_t)note->time()); + const double y = midi_stream_view()->note_to_y(note->note()) + ((diamond_size-2) / 4.0); CanvasHit* ev_diamond = new CanvasHit(*this, *group, diamond_size); ev_diamond->move(x, y); ev_diamond->show(); - ev_diamond->property_fill_color_rgba() = note_fill_color(note.velocity()); - ev_diamond->property_outline_color_rgba() = note_outline_color(note.velocity()); + ev_diamond->property_fill_color_rgba() = note_fill_color(note->velocity()); + ev_diamond->property_outline_color_rgba() = note_outline_color(note->velocity()); _events.push_back(ev_diamond); + } } @@ -598,7 +712,7 @@ MidiRegionView::delete_selection() for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) if ((*i)->selected()) - _delta_command->remove(*(*i)->note()); + _delta_command->remove((*i)->note()); _selection.clear(); } @@ -622,7 +736,9 @@ MidiRegionView::unique_select(ArdourCanvas::CanvasMidiEvent* ev) _selection.clear(); _selection.insert(ev); - ev->selected(true); + + if ( ! ev->selected()) + ev->selected(true); } void @@ -632,7 +748,9 @@ MidiRegionView::note_selected(ArdourCanvas::CanvasMidiEvent* ev, bool add) clear_selection_except(ev); _selection.insert(ev); - ev->selected(true); + + if ( ! ev->selected()) + ev->selected(true); } @@ -643,21 +761,39 @@ MidiRegionView::note_deselected(ArdourCanvas::CanvasMidiEvent* ev, bool add) clear_selection_except(ev); _selection.erase(ev); - ev->selected(false); + + if (ev->selected()) + ev->selected(false); } void -MidiRegionView::update_drag_selection(double last_x, double x, double last_y, double y) +MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2) { + const double last_y = std::min(y1, y2); + const double y = std::max(y1, y2); + // FIXME: so, so, so much slower than this should be - for (std::vector::iterator i = _events.begin(); i != _events.end(); ++i) { - if ((*i)->x1() >= last_x && (*i)->x1() <= x && (*i)->y1() >= last_y && (*i)->y1() <= y) { - (*i)->selected(true); - _selection.insert(*i); - } else { - (*i)->selected(false); - _selection.erase(*i); + + if (x1 < x2) { + for (std::vector::iterator i = _events.begin(); i != _events.end(); ++i) { + if ((*i)->x1() >= x1 && (*i)->x1() <= x2 && (*i)->y1() >= last_y && (*i)->y1() <= y) { + (*i)->selected(true); + _selection.insert(*i); + } else { + (*i)->selected(false); + _selection.erase(*i); + } + } + } else { + for (std::vector::iterator i = _events.begin(); i != _events.end(); ++i) { + if ((*i)->x2() <= x1 && (*i)->x2() >= x2 && (*i)->y1() >= last_y && (*i)->y1() <= y) { + (*i)->selected(true); + _selection.insert(*i); + } else { + (*i)->selected(false); + _selection.erase(*i); + } } } } @@ -670,6 +806,7 @@ MidiRegionView::move_selection(double dx, double dy) (*i)->item()->move(dx, dy); } + void MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote) { @@ -679,14 +816,47 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote) for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { command_remove_note(*i); - MidiModel::Note copy(*(*i)->note()); + const boost::shared_ptr copy(new Note(*(*i)->note().get())); - copy.set_time((*i)->note()->time() + dt); - copy.set_note((*i)->note()->note() + dnote); + copy->set_time((*i)->note()->time() + dt); + copy->set_note((*i)->note()->note() + dnote); command_add_note(copy); } apply_command(); } } + +void +MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev) +{ + if (ev->note() && _mouse_state == EraseTouchDragging) { + start_delta_command(); + ev->selected(true); + _delta_command->remove(ev->note()); + } else if (_mouse_state == SelectTouchDragging) { + note_selected(ev, true); + } +} + + +void +MidiRegionView::switch_source(boost::shared_ptr src) +{ + boost::shared_ptr msrc = boost::dynamic_pointer_cast(src); + if (msrc) + display_model(msrc->model()); +} + +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(); + } + } +}