diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index a35357884a..66c67c0c37 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3243,7 +3243,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) } else { /* new selection */ - if (!_editor->selection->selected (_editor->clicked_axisview)) { + if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { _editor->selection->set (_editor->clicked_axisview); } @@ -3361,7 +3361,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) _editor->selection->clear_time(); } - if (!_editor->selection->selected (_editor->clicked_axisview)) { + if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { _editor->selection->set (_editor->clicked_axisview); } @@ -3747,9 +3747,10 @@ NoteDrag::motion (GdkEvent*, bool) region->move_selection (dx, dy); CanvasNoteEvent* cnote = dynamic_cast(_item); - char buf[4]; - snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note); - //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note())); + + char buf[12]; + snprintf (buf, sizeof (buf), "%s (%g)", Evoral::midi_note_name (cnote->note()->note()).c_str(), + (int) cnote->note()->note() + drag_delta_note); _editor->show_verbose_canvas_cursor_with (buf); } } diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 75e81a64d6..d60edaccc2 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -669,7 +669,6 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT switch (item_type) { case NoteItem: if (internal_editing()) { - /* Note: we don't get here if not in internal_editing() mode */ _drags->set (new NoteDrag (this, item), event); return true; } diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index d1c1656ce3..d81c0d76d9 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -41,6 +41,7 @@ #include "evoral/Parameter.hpp" #include "evoral/Control.hpp" +#include "evoral/midi_util.h" #include "automation_region_view.h" #include "automation_time_axis.h" @@ -566,6 +567,10 @@ MidiRegionView::create_note_at(double x, double y, double length) frames_to_beats(start_frames + _region->start()), length, (uint8_t)note, 0x40)); + if (_model->contains (new_note)) { + return; + } + view->update_note_range(new_note->note()); MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note"); @@ -797,8 +802,6 @@ MidiRegionView::redisplay_model() MidiModel::Notes& notes (_model->notes()); _optimization_iterator = _events.begin(); - cerr << "++++++++++ MIDI REdisplay\n"; - for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) { boost::shared_ptr note (*n); @@ -2394,12 +2397,10 @@ MidiRegionView::note_entered(ArdourCanvas::CanvasNoteEvent* ev) note_selected(ev, true); } - char buf[4]; - snprintf (buf, sizeof (buf), "%d", (int) ev->note()->note()); - // This causes an infinite loop on note add sometimes - //PublicEditor& editor (trackview.editor()); - //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note())); - //editor.show_verbose_canvas_cursor_with (buf); + char buf[12]; + snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (ev->note()->note()).c_str(), (int) ev->note()->note()); + PublicEditor& editor (trackview.editor()); + editor.show_verbose_canvas_cursor_with (buf); } void diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index 8d949cadbb..b3a4d746a1 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -151,8 +151,9 @@ public: void apply_command(Session& session, Command* cmd); void apply_command_as_subcommand(Session& session, Command* cmd); - bool write_to(boost::shared_ptr source, Evoral::MusicalTime begin = Evoral::MinMusicalTime, - Evoral::MusicalTime end = Evoral::MaxMusicalTime); + bool write_to(boost::shared_ptr source); + bool write_section_to(boost::shared_ptr source, Evoral::MusicalTime begin = Evoral::MinMusicalTime, + Evoral::MusicalTime end = Evoral::MaxMusicalTime); // MidiModel doesn't use the normal AutomationList serialisation code // since controller data is stored in the .mid diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 2484d3575a..c418559d6e 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -111,7 +111,7 @@ class MidiSource : virtual public Source boost::shared_ptr model() { return _model; } void set_model(boost::shared_ptr m) { _model = m; } - void drop_model() { _model.reset(); } + void drop_model(); protected: virtual void flush_midi() = 0; diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 88ef60e8e5..3b258eab09 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -676,6 +676,36 @@ MidiModel::DiffCommand::get_state () return *diff_command; } +/** Write all of the model to a MidiSource (i.e. save the model). + * This is different from manually using read to write to a source in that + * note off events are written regardless of the track mode. This is so the + * user can switch a recorded track (with note durations from some instrument) + * to percussive, save, reload, then switch it back to sustained without + * destroying the original note durations. + */ +bool +MidiModel::write_to (boost::shared_ptr source) +{ + ReadLock lock(read_lock()); + + const bool old_percussive = percussive(); + set_percussive(false); + + source->drop_model(); + source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position()); + + for (Evoral::Sequence::const_iterator i = begin(); i != end(); ++i) { + source->append_event_unlocked_beats(*i); + } + + set_percussive(old_percussive); + source->mark_streaming_write_completed(); + + set_edited(false); + + return true; +} + /** Write part or all of the model to a MidiSource (i.e. save the model). * This is different from manually using read to write to a source in that * note off events are written regardless of the track mode. This is so the @@ -684,7 +714,7 @@ MidiModel::DiffCommand::get_state () * destroying the original note durations. */ bool -MidiModel::write_to (boost::shared_ptr source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time) +MidiModel::write_section_to (boost::shared_ptr source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time) { ReadLock lock(read_lock()); MidiStateTracker mst; diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 5e8bda1ea2..0c66879330 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -250,7 +250,11 @@ MidiSource::clone (Evoral::MusicalTime begin, Evoral::MusicalTime end) newsrc->set_timeline_position(_timeline_position); if (_model) { - _model->write_to (newsrc, begin, end); + if (begin == Evoral::MinMusicalTime && end == Evoral::MaxMusicalTime) { + _model->write_to (newsrc); + } else { + _model->write_section_to (newsrc, begin, end); + } } else { error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()")); return boost::shared_ptr(); @@ -290,3 +294,9 @@ MidiSource::set_note_mode(NoteMode mode) } } +void +MidiSource::drop_model () +{ + cerr << name() << " drop model\n"; + _model.reset(); +} diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp index 3aafb15312..038cf2c344 100644 --- a/libs/evoral/evoral/Sequence.hpp +++ b/libs/evoral/evoral/Sequence.hpp @@ -202,7 +202,8 @@ public: bool edited() const { return _edited; } void set_edited(bool yn) { _edited = yn; } - void add_note_unlocked(const boost::shared_ptr< Note