summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-05-20 22:38:12 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-05-20 22:38:12 +0000
commita196405da9fab534b5ece4d165e871d02d671b36 (patch)
tree17cf937e579046c2fb84c30db5c09bb87def6451
parente58f6752af39d5aa032b45eca1c8f392fd874b16 (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.cc11
-rw-r--r--gtk2_ardour/editor_mouse.cc1
-rw-r--r--gtk2_ardour/midi_region_view.cc17
-rw-r--r--libs/ardour/ardour/midi_model.h5
-rw-r--r--libs/ardour/ardour/midi_source.h2
-rw-r--r--libs/ardour/midi_model.cc32
-rw-r--r--libs/ardour/midi_source.cc12
-rw-r--r--libs/evoral/evoral/Sequence.hpp3
-rw-r--r--libs/evoral/src/Sequence.cpp28
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>