diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2010-05-20 22:38:12 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2010-05-20 22:38:12 +0000 |
commit | a196405da9fab534b5ece4d165e871d02d671b36 (patch) | |
tree | 17cf937e579046c2fb84c30db5c09bb87def6451 | |
parent | e58f6752af39d5aa032b45eca1c8f392fd874b16 (diff) |
various minor MIDI fixes: prevent duplicate note entry with mouse, show note info more often with verbose cursor, fix some crashes from click+move on notes ... lots more where this comes from
git-svn-id: svn://localhost/ardour2/branches/3.0@7128 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 11 | ||||
-rw-r--r-- | gtk2_ardour/editor_mouse.cc | 1 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 17 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 2 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 32 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 12 | ||||
-rw-r--r-- | libs/evoral/evoral/Sequence.hpp | 3 | ||||
-rw-r--r-- | libs/evoral/src/Sequence.cpp | 28 |
9 files changed, 90 insertions, 21 deletions
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<CanvasNoteEvent*>(_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<NoteType> 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<MidiSource> source, Evoral::MusicalTime begin = Evoral::MinMusicalTime, - Evoral::MusicalTime end = Evoral::MaxMusicalTime); + bool write_to(boost::shared_ptr<MidiSource> source); + bool write_section_to(boost::shared_ptr<MidiSource> 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<MidiModel> model() { return _model; } void set_model(boost::shared_ptr<MidiModel> 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<MidiSource> 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<TimeType>::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<MidiSource> source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time) +MidiModel::write_section_to (boost::shared_ptr<MidiSource> 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<MidiSource>(); @@ -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<Time> > note); + bool contains (const boost::shared_ptr< Note<Time> > ev) const; + bool add_note_unlocked(const boost::shared_ptr< Note<Time> > note); void remove_note_unlocked(const boost::shared_ptr< const Note<Time> > note); uint8_t lowest_note() const { return _lowest_note; } diff --git a/libs/evoral/src/Sequence.cpp b/libs/evoral/src/Sequence.cpp index 281aec514b..523643665f 100644 --- a/libs/evoral/src/Sequence.cpp +++ b/libs/evoral/src/Sequence.cpp @@ -730,12 +730,38 @@ Sequence<Time>::append_sysex_unlocked(const MIDIEvent<Time>& ev) } template<typename Time> -void +bool +Sequence<Time>::contains(const boost::shared_ptr< Note<Time> > note) const +{ + ReadLock lock (read_lock()); + + for (typename Sequence<Time>::Notes::const_iterator i = note_lower_bound(note->time()); + i != _notes.end() && (*i)->time() == note->time(); ++i) { + if (*i == note) { + cerr << "Existing note matches: " << *i << endl; + return true; + } + } + cerr << "No matching note for " << note << endl; + return false; +} + +template<typename Time> +bool Sequence<Time>::add_note_unlocked(const boost::shared_ptr< Note<Time> > note) { DUMP(format("%1% add note %2% @ %3%\n") % this % (int)note->note() % note->time()); + + for (typename Sequence<Time>::Notes::iterator i = note_lower_bound(note->time()); + i != _notes.end() && (*i)->time() == note->time(); ++i) { + if (*i == note) { + return false; + } + } + _edited = true; _notes.insert(note); + return true; } template<typename Time> |