X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_model.cc;h=3d53abaae5db6808a02d7de994facfcbfb95f7b1;hb=30af404def27675c8e85cea2e50db76c054af276;hp=f64a5f6d0c6c62deac07dd08551effad8ec84818;hpb=a7067557107fc2f01586a88bb8b0a097914798ea;p=ardour.git diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index f64a5f6d0c..3d53abaae5 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -164,84 +164,55 @@ MidiModel::NoteDiffCommand::side_effect_remove (const NotePtr note) side_effect_removals.insert (note); } -void -MidiModel::NoteDiffCommand::change (const NotePtr note, Property prop, - uint8_t new_value) +Variant +MidiModel::NoteDiffCommand::get_value (const NotePtr note, Property prop) { - assert (note); - - NoteChange change; - switch (prop) { case NoteNumber: - if (new_value == note->note()) { - return; - } - change.old_value = note->note(); - break; + return Variant(note->note()); case Velocity: - if (new_value == note->velocity()) { - return; - } - change.old_value = note->velocity(); - break; + return Variant(note->velocity()); case Channel: - if (new_value == note->channel()) { - return; - } - change.old_value = note->channel(); - break; - - + return Variant(note->channel()); case StartTime: - fatal << "MidiModel::DiffCommand::change() with integer argument called for start time" << endmsg; - abort(); /*NOTREACHED*/ - break; + return Variant(note->time()); case Length: - fatal << "MidiModel::DiffCommand::change() with integer argument called for length" << endmsg; - abort(); /*NOTREACHED*/ - break; + return Variant(note->length()); } - change.note = note; - change.property = prop; - change.new_value = new_value; - - _changes.push_back (change); + return Variant(); } -void -MidiModel::NoteDiffCommand::change (const NotePtr note, Property prop, - TimeType new_time) +Variant::Type +MidiModel::NoteDiffCommand::value_type(Property prop) { - assert (note); - - NoteChange change; - switch (prop) { case NoteNumber: - case Channel: case Velocity: - fatal << "MidiModel::NoteDiffCommand::change() with time argument called for note, channel or velocity" << endmsg; - break; - + case Channel: + return Variant::INT; case StartTime: - if (note->time() == new_time) { - return; - } - change.old_time = note->time(); - break; case Length: - if (note->length() == new_time) { - return; - } - change.old_time = note->length(); - break; + return Variant::BEATS; } - change.note = note; - change.property = prop; - change.new_time = new_time; + return Variant::NOTHING; +} + +void +MidiModel::NoteDiffCommand::change (const NotePtr note, + Property prop, + const Variant& new_value) +{ + assert (note); + + const NoteChange change = { + prop, note, 0, get_value(note, prop), new_value + }; + + if (change.old_value == new_value) { + return; + } _changes.push_back (change); } @@ -304,7 +275,7 @@ MidiModel::NoteDiffCommand::operator() () _model->remove_note_unlocked (i->note); temporary_removals.insert (i->note); } - i->note->set_note (i->new_value); + i->note->set_note (i->new_value.get_int()); break; case StartTime: @@ -312,7 +283,7 @@ MidiModel::NoteDiffCommand::operator() () _model->remove_note_unlocked (i->note); temporary_removals.insert (i->note); } - i->note->set_time (i->new_time); + i->note->set_time (i->new_value.get_beats()); break; case Channel: @@ -320,18 +291,18 @@ MidiModel::NoteDiffCommand::operator() () _model->remove_note_unlocked (i->note); temporary_removals.insert (i->note); } - i->note->set_channel (i->new_value); + i->note->set_channel (i->new_value.get_int()); break; /* no remove-then-add required for these properties, since we do not index them */ case Velocity: - i->note->set_velocity (i->new_value); + i->note->set_velocity (i->new_value.get_int()); break; case Length: - i->note->set_length (i->new_time); + i->note->set_length (i->new_value.get_beats()); break; } @@ -411,7 +382,7 @@ MidiModel::NoteDiffCommand::undo () _model->remove_note_unlocked (i->note); temporary_removals.insert (i->note); } - i->note->set_note (i->old_value); + i->note->set_note (i->old_value.get_int()); break; case StartTime: @@ -423,7 +394,7 @@ MidiModel::NoteDiffCommand::undo () _model->remove_note_unlocked (i->note); temporary_removals.insert (i->note); } - i->note->set_time (i->old_time); + i->note->set_time (i->old_value.get_beats()); break; case Channel: @@ -435,18 +406,18 @@ MidiModel::NoteDiffCommand::undo () _model->remove_note_unlocked (i->note); temporary_removals.insert (i->note); } - i->note->set_channel (i->old_value); + i->note->set_channel (i->old_value.get_int()); break; /* no remove-then-add required for these properties, since we do not index them */ case Velocity: - i->note->set_velocity (i->old_value); + i->note->set_velocity (i->old_value.get_int()); break; case Length: - i->note->set_length (i->old_time); + i->note->set_length (i->old_value.get_beats()); break; } } @@ -593,9 +564,9 @@ MidiModel::NoteDiffCommand::marshal_change (const NoteChange& change) { ostringstream old_value_str (ios::ate); if (change.property == StartTime || change.property == Length) { - old_value_str << change.old_time; + old_value_str << change.old_value.get_beats(); } else { - old_value_str << (unsigned int) change.old_value; + old_value_str << change.old_value.get_int(); } xml_change->add_property ("old", old_value_str.str()); } @@ -603,16 +574,24 @@ MidiModel::NoteDiffCommand::marshal_change (const NoteChange& change) { ostringstream new_value_str (ios::ate); if (change.property == StartTime || change.property == Length) { - new_value_str << change.new_time; + new_value_str << change.new_value.get_beats(); } else { - new_value_str << (unsigned int) change.new_value; + new_value_str << change.new_value.get_int(); } xml_change->add_property ("new", new_value_str.str()); } ostringstream id_str; - id_str << change.note->id(); - xml_change->add_property ("id", id_str.str()); + if (change.note) { + id_str << change.note->id(); + xml_change->add_property ("id", id_str.str()); + } else if (change.note_id) { + warning << _("Change has no note, using note ID") << endmsg; + id_str << change.note_id; + xml_change->add_property ("id", id_str.str()); + } else { + error << _("Change has no note or note ID") << endmsg; + } return *xml_change; } @@ -622,6 +601,7 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change) { XMLProperty* prop; NoteChange change; + change.note_id = 0; if ((prop = xml_change->property("property")) != 0) { change.property = (Property) string_2_enum (prop->value(), change.property); @@ -640,7 +620,9 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change) if ((prop = xml_change->property ("old")) != 0) { istringstream old_str (prop->value()); if (change.property == StartTime || change.property == Length) { - old_str >> change.old_time; + Evoral::Beats old_time; + old_str >> old_time; + change.old_value = old_time; } else { int integer_value_so_that_istream_does_the_right_thing; old_str >> integer_value_so_that_istream_does_the_right_thing; @@ -654,7 +636,9 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change) if ((prop = xml_change->property ("new")) != 0) { istringstream new_str (prop->value()); if (change.property == StartTime || change.property == Length) { - new_str >> change.new_time; + Evoral::Beats new_time; + new_str >> new_time; + change.new_value = Variant(new_time); } else { int integer_value_so_that_istream_does_the_right_thing; new_str >> integer_value_so_that_istream_does_the_right_thing; @@ -1252,14 +1236,15 @@ MidiModel::PatchChangePtr MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n) { XMLProperty* prop; + XMLProperty* prop_id; Evoral::event_id_t id = 0; - Evoral::MusicalTime time = Evoral::MusicalTime(); + Evoral::Beats time = Evoral::Beats(); int channel = 0; int program = 0; int bank = 0; - if ((prop = n->property ("id")) != 0) { - istringstream s (prop->value()); + if ((prop_id = n->property ("id")) != 0) { + istringstream s (prop_id->value()); s >> id; } @@ -1284,7 +1269,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n) } PatchChangePtr p (new Evoral::PatchChange (time, channel, program, bank)); - assert(id); + assert(prop_id); p->set_id (id); return p; } @@ -1468,6 +1453,11 @@ MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock) return false; } + /* Invalidate and store active notes, which will be picked up by the iterator + on the next roll if time progresses linearly. */ + ms->invalidate(source_lock, + ms->session().transport_rolling() ? &_active_notes : NULL); + ms->mark_streaming_midi_write_started (source_lock, note_mode()); for (Evoral::Sequence::const_iterator i = begin(TimeType(), true); i != end(); ++i) { @@ -1492,8 +1482,8 @@ MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock) bool MidiModel::write_section_to (boost::shared_ptr source, const Glib::Threads::Mutex::Lock& source_lock, - Evoral::MusicalTime begin_time, - Evoral::MusicalTime end_time) + Evoral::Beats begin_time, + Evoral::Beats end_time) { ReadLock lock(read_lock()); MidiStateTracker mst; @@ -1505,12 +1495,12 @@ MidiModel::write_section_to (boost::shared_ptr source, source->mark_streaming_midi_write_started (source_lock, note_mode()); for (Evoral::Sequence::const_iterator i = begin(TimeType(), true); i != end(); ++i) { - const Evoral::Event& ev (*i); + const Evoral::Event& ev (*i); if (ev.time() >= begin_time && ev.time() < end_time) { - const Evoral::MIDIEvent* mev = - static_cast* > (&ev); + const Evoral::MIDIEvent* mev = + static_cast* > (&ev); if (!mev) { continue; @@ -1627,25 +1617,19 @@ MidiModel::find_sysex (gint sysex_id) MidiModel::WriteLock MidiModel::edit_lock() { - boost::shared_ptr ms = _midi_source.lock (); - assert (ms); - - Glib::Threads::Mutex::Lock* source_lock = new Glib::Threads::Mutex::Lock (ms->mutex()); - ms->invalidate(*source_lock); // Release cached iterator's read lock on model - return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock)); -} + boost::shared_ptr ms = _midi_source.lock(); + Glib::Threads::Mutex::Lock* source_lock = 0; -/** Lock just the model, the source lock must already be held. - * This should only be called from libardour/evoral places - */ -MidiModel::WriteLock -MidiModel::write_lock() -{ - boost::shared_ptr ms = _midi_source.lock (); - assert (ms); + if (ms) { + /* Take source lock and invalidate iterator to release its lock on model. + Add currently active notes to _active_notes so we can restore them + if playback resumes at the same point after the edit. */ + source_lock = new Glib::Threads::Mutex::Lock(ms->mutex()); + ms->invalidate(*source_lock, + ms->session().transport_rolling() ? &_active_notes : NULL); + } - assert (!ms->mutex().trylock ()); - return WriteLock(new WriteLockImpl(0, _lock, _control_lock)); + return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock)); } int @@ -2042,7 +2026,7 @@ MidiModel::transpose (TimeType from, TimeType to, int semitones) void MidiModel::control_list_marked_dirty () { - AutomatableSequence::control_list_marked_dirty (); + AutomatableSequence::control_list_marked_dirty (); ContentsChanged (); /* EMIT SIGNAL */ }