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
This commit is contained in:
Paul Davis 2010-05-20 22:38:12 +00:00
parent e58f6752af
commit a196405da9
9 changed files with 90 additions and 21 deletions

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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; }

View File

@ -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>