From c0a1aec51693a87cacfe12ec0bafda38d42a9ef5 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 17 Oct 2019 23:16:55 -0600 Subject: start removal of NoteFixer code Plan is to always read MIDI directly from rendered version. MidiPlaylistSource needs attention before MidiPlaylist::read() can be removed --- libs/ardour/ardour/midi_playlist.h | 15 +--- libs/ardour/ardour/note_fixer.h | 104 --------------------------- libs/ardour/midi_playlist.cc | 65 ++--------------- libs/ardour/note_fixer.cc | 144 ------------------------------------- libs/ardour/wscript | 1 - 5 files changed, 6 insertions(+), 323 deletions(-) delete mode 100644 libs/ardour/ardour/note_fixer.h delete mode 100644 libs/ardour/note_fixer.cc (limited to 'libs') diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h index ddbbcf7b5e..83ba5ecb61 100644 --- a/libs/ardour/ardour/midi_playlist.h +++ b/libs/ardour/ardour/midi_playlist.h @@ -28,11 +28,12 @@ #include +#include "evoral/Parameter.hpp" + #include "ardour/ardour.h" #include "ardour/midi_cursor.h" #include "ardour/midi_model.h" #include "ardour/midi_state_tracker.h" -#include "ardour/note_fixer.h" #include "ardour/playlist.h" #include "evoral/Note.hpp" #include "evoral/Parameter.hpp" @@ -116,20 +117,8 @@ protected: void region_going_away (boost::weak_ptr region); private: - typedef Evoral::Note Note; - typedef Evoral::Event Event; - - struct RegionTracker : public boost::noncopyable { - MidiCursor cursor; ///< Cursor (iterator and read state) - MidiStateTracker tracker; ///< Active note tracker - NoteFixer fixer; ///< Edit compensation - }; - - typedef std::map< Region*, boost::shared_ptr > NoteTrackers; - void dump () const; - NoteTrackers _note_trackers; NoteMode _note_mode; samplepos_t _read_end; diff --git a/libs/ardour/ardour/note_fixer.h b/libs/ardour/ardour/note_fixer.h deleted file mode 100644 index 3e6fea6551..0000000000 --- a/libs/ardour/ardour/note_fixer.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2017 Paul Davis - * Copyright (C) 2019 Robin Gareus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __ardour_note_fixer_h__ -#define __ardour_note_fixer_h__ - -#include - -#include - -#include "temporal/beats.h" - -#include "evoral/Note.hpp" - -#include "ardour/midi_model.h" -#include "ardour/types.h" - -namespace Evoral { template class EventSink; } - -namespace ARDOUR { - -class BeatsSamplesConverter; -class MidiStateTracker; -class TempoMap; - -/** A tracker and compensator for note edit operations. - * - * This monitors edit operations sent to a model that affect active notes - * during a read, and maintains a queue of synthetic events that should be sent - * at the start of the next read to maintain coherent MIDI state. - */ -class NoteFixer : public boost::noncopyable -{ -public: - typedef Evoral::Note Note; - - ~NoteFixer(); - - /** Clear all internal state. */ - void clear(); - - /** Handle a region edit during read. - * - * This must be called before the command is applied to the model. Events - * are enqueued to compensate for edits which should be later sent with - * emit() at the start of the next read. - * - * @param tempo_map The tempo-map - * @param cmd Command to compensate for. - * @param origin Timeline position of edited source. - * @param pos Current read position (last read end). - * @param active_notes currently active notes (read/write) - */ - void prepare(TempoMap& tempo_map, - const MidiModel::NoteDiffCommand* cmd, - samplepos_t origin, - samplepos_t pos, - std::set< boost::weak_ptr >& active_notes); - - /** Emit any pending edit compensation events. - * - * @param dst Destination for events. - * @param pos Timestamp to be used for every event, should be the start of - * the read block immediately following any calls to prepare(). - * @param tracker Tracker to update with emitted events. - */ - void emit(Evoral::EventSink& dst, - samplepos_t pos, - MidiStateTracker& tracker); - -private: - typedef Evoral::Event Event; - typedef std::list Events; - - /** Copy a beats event to a samples event with the given time stamp. */ - Event* copy_event(samplepos_t time, const Evoral::Event& ev); - - /** Return true iff `note` is active at `pos`. */ - bool note_is_active(const BeatsSamplesConverter& converter, - boost::shared_ptr note, - samplepos_t pos); - - Events _events; -}; - -} /* namespace ARDOUR */ - -#endif /* __ardour_note_fixer_h__ */ diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 9144742510..a7092c45ba 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -123,14 +123,7 @@ MidiPlaylist::read (Evoral::EventSink& dst, Playlist::RegionReadLock rl (this); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, - string_compose ("---- MidiPlaylist::read %1 .. %2 (%3 trackers) ----\n", - start, start + dur, _note_trackers.size())); - - /* First, emit any queued edit fixup events at start. */ - for (NoteTrackers::iterator t = _note_trackers.begin(); t != _note_trackers.end(); ++t) { - t->second->fixer.emit(dst, _read_end, t->second->tracker); - } + DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("---- MidiPlaylist::read %1 .. %2 ----\n", start, start + dur)); /* Find relevant regions that overlap [start..end] */ const samplepos_t end = start + dur - 1; @@ -184,52 +177,20 @@ MidiPlaylist::read (Evoral::EventSink& dst, continue; } - /* Get the existing note tracker for this region, or create a new one. */ - NoteTrackers::iterator t = _note_trackers.find (mr.get()); - bool new_tracker = false; - boost::shared_ptr tracker; - if (t == _note_trackers.end()) { - tracker = boost::shared_ptr(new RegionTracker); - new_tracker = true; - DEBUG_TRACE (DEBUG::MidiPlaylistIO, - string_compose ("\tPre-read %1 (%2 .. %3): new tracker\n", - mr->name(), mr->position(), mr->last_sample())); - } else { - tracker = t->second; - DEBUG_TRACE (DEBUG::MidiPlaylistIO, - string_compose ("\tPre-read %1 (%2 .. %3): %4 active notes\n", - mr->name(), mr->position(), mr->last_sample(), tracker->tracker.on())); - } + MidiCursor cursor; // XXX remove me /* Read from region into target. */ DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("read from %1 at %2 for %3 LR %4 .. %5\n", mr->name(), start, dur, (loop_range ? loop_range->from : -1), (loop_range ? loop_range->to : -1))); - mr->read_at (tgt, start, dur, loop_range, tracker->cursor, chan_n, _note_mode, &tracker->tracker, filter); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, - string_compose ("\tPost-read: %1 active notes\n", tracker->tracker.on())); + mr->read_at (tgt, start, dur, loop_range, cursor, chan_n, _note_mode, 0, filter); if (find (ended.begin(), ended.end(), *i) != ended.end()) { /* Region ended within the read range, so resolve any active notes (either stuck notes in the data, or notes that end after the end of the region). */ - DEBUG_TRACE (DEBUG::MidiPlaylistIO, - string_compose ("\t%1 ended, resolve notes and delete (%2) tracker\n", - mr->name(), ((new_tracker) ? "new" : "old"))); - - tracker->tracker.resolve_notes (tgt, loop_range ? loop_range->squish ((*i)->last_sample()) : (*i)->last_sample()); - tracker->cursor.invalidate (false); - if (!new_tracker) { - _note_trackers.erase (t); - } - - } else { - - if (new_tracker) { - _note_trackers.insert (make_pair (mr.get(), tracker)); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n"); - } + DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1 ended, resolve notes and delete\n", mr->name())); } } @@ -254,29 +215,16 @@ MidiPlaylist::read (Evoral::EventSink& dst, void MidiPlaylist::reset_note_trackers () { - Playlist::RegionWriteLock rl (this, false); - - DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 reset all note trackers\n", name())); - _note_trackers.clear (); } void MidiPlaylist::resolve_note_trackers (Evoral::EventSink& dst, samplepos_t time) { - Playlist::RegionWriteLock rl (this, false); - - for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) { - n->second->tracker.resolve_notes(dst, time); - } - DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 resolve all note trackers\n", name())); - _note_trackers.clear (); } void MidiPlaylist::remove_dependents (boost::shared_ptr region) { - /* MIDI regions have no dependents (crossfades) but we might be tracking notes */ - _note_trackers.erase(region.get()); } void @@ -353,11 +301,6 @@ MidiPlaylist::destroy_region (boost::shared_ptr region) i = tmp; } - - NoteTrackers::iterator t = _note_trackers.find(region.get()); - if (t != _note_trackers.end()) { - _note_trackers.erase(t); - } } if (changed) { diff --git a/libs/ardour/note_fixer.cc b/libs/ardour/note_fixer.cc deleted file mode 100644 index 0c6c94bf34..0000000000 --- a/libs/ardour/note_fixer.cc +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2017 Paul Davis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "evoral/EventList.hpp" - -#include "ardour/beats_samples_converter.h" -#include "ardour/midi_state_tracker.h" -#include "ardour/note_fixer.h" -#include "ardour/tempo.h" - -namespace ARDOUR { - -NoteFixer::~NoteFixer() -{ - clear(); -} - -void -NoteFixer::clear() -{ - for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { - delete *i; - } -} - -void -NoteFixer::prepare(TempoMap& tempo_map, - const MidiModel::NoteDiffCommand* cmd, - const samplepos_t origin, - const samplepos_t pos, - std::set< boost::weak_ptr >& active_notes) -{ - typedef MidiModel::NoteDiffCommand Command; - - BeatsSamplesConverter converter(tempo_map, origin); - - for (Command::NoteList::const_iterator i = cmd->removed_notes().begin(); - i != cmd->removed_notes().end(); ++i) { - if (note_is_active(converter, *i, pos)) { - /* Deleted note spans the end of the latest read, so we will never - read its off event. Emit a note off to prevent a stuck note. */ - _events.push_back(copy_event(pos, (*i)->off_event())); - active_notes.erase(*i); - } - } - - for (Command::NoteList::const_iterator i = cmd->added_notes().begin(); - i != cmd->added_notes().end(); ++i) { - if (note_is_active(converter, *i, pos)) { - /* Added note spans the end of the latest read, so we missed its on - event. Emit note on immediately to make the state consistent. */ - _events.push_back(copy_event(pos, (*i)->on_event())); - active_notes.insert(*i); - } - } - - for (Command::ChangeList::const_iterator i = cmd->changes().begin(); - i != cmd->changes().end(); ++i) { - if (!note_is_active(converter, i->note, pos)) { - /* Note is not currently active, no compensation needed. */ - continue; - } - - /* Changed note spans the end of the latest read. */ - if (i->property == Command::NoteNumber) { - /* Note number has changed, end the old note. */ - _events.push_back(copy_event(pos, i->note->off_event())); - - /* Start a new note on the new note number. The same note object - is active, so we leave active_notes alone. */ - Event* on = copy_event(pos, i->note->on_event()); - on->buffer()[1] = (uint8_t)i->new_value.get_int(); - _events.push_back(on); - } else if (i->property == Command::StartTime && - converter.to(i->new_value.get_beats()) >= pos) { - /* Start time has moved from before to after the end of the - latest read, end the old note. */ - _events.push_back(copy_event(pos, i->note->off_event())); - active_notes.erase(i->note); - } else if (i->property == Command::Length && - converter.to(i->note->time() + i->new_value.get_beats()) < pos) { - /* Length has shortened to before the end of the latest read, - end the note. */ - _events.push_back(copy_event(pos, i->note->off_event())); - active_notes.erase(i->note); - } else if (i->property == Command::Channel) { - /* Channel has changed, end the old note. */ - _events.push_back(copy_event(pos, i->note->off_event())); - - /* Start a new note on the new channel. See number change above. */ - Event* on = copy_event(pos, i->note->on_event()); - on->buffer()[0] &= 0xF0; - on->buffer()[0] |= (uint8_t)i->new_value.get_int(); - _events.push_back(on); - } - } -} - -void -NoteFixer::emit(Evoral::EventSink& dst, - samplepos_t pos, - MidiStateTracker& tracker) -{ - for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { - dst.write(pos, (*i)->event_type(), (*i)->size(), (*i)->buffer()); - tracker.track(**i); - delete *i; - } - _events.clear(); -} - -NoteFixer::Event* -NoteFixer::copy_event(samplepos_t time, const Evoral::Event& ev) -{ - return new Event(ev.event_type(), time, ev.size(), ev.buffer()); -} - -bool -NoteFixer::note_is_active(const BeatsSamplesConverter& converter, - boost::shared_ptr note, - samplepos_t pos) -{ - const samplepos_t start_time = converter.to(note->time()); - const samplepos_t end_time = converter.to(note->end_time()); - - return (start_time < pos && end_time >= pos); -} - -} // namespace ARDOUR diff --git a/libs/ardour/wscript b/libs/ardour/wscript index b66c3cf8c0..27fc0ba3e8 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -153,7 +153,6 @@ libardour_sources = [ 'muteable.cc', 'mute_control.cc', 'mute_master.cc', - 'note_fixer.cc', 'onset_detector.cc', 'operations.cc', 'pan_controllable.cc', -- cgit v1.2.3