2 * Copyright (C) 2011-2015 David Robillard <d@drobilla.net>
3 * Copyright (C) 2011-2017 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "libardour-config.h"
25 #include "pbd/error.h"
27 #include "ardour/midi_playlist.h"
28 #include "ardour/midi_playlist_source.h"
33 using namespace ARDOUR;
37 class MidiStateTracker;
39 template <typename T> class MidiRingBuffer;
43 template <typename T> class EventSink;
44 template <typename Time> class Event;
47 /*******************************************************************************
48 As of May 2011, it appears too complex to support compound regions for MIDI
49 because of the need to be able to edit the data represented by the region. It
50 seems that it would be a better idea to render the consituent regions into a
51 new MIDI file and create a new region based on that, an operation we have been
54 This code has been in place as a stub in case anyone gets any brilliant ideas
55 on other ways to approach this issue.
56 ********************************************************************************/
58 MidiPlaylistSource::MidiPlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<MidiPlaylist> p,
59 uint32_t /*chn*/, sampleoffset_t begin, samplecnt_t len, Source::Flag flags)
60 : Source (s, DataType::MIDI, name)
61 , MidiSource (s, name, flags)
62 , PlaylistSource (s, orig, name, p, DataType::MIDI, begin, len, flags)
66 MidiPlaylistSource::MidiPlaylistSource (Session& s, const XMLNode& node)
68 , MidiSource (s, node)
69 , PlaylistSource (s, node)
71 /* PlaylistSources are never writable, renameable, removable or destructive */
72 _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
74 /* ancestors have already called ::set_state() in their XML-based
78 if (set_state (node, Stateful::loading_state_version, false)) {
79 throw failed_constructor ();
83 MidiPlaylistSource::~MidiPlaylistSource ()
88 MidiPlaylistSource::get_state ()
90 XMLNode& node (MidiSource::get_state ());
92 /* merge PlaylistSource state */
94 PlaylistSource::add_state (node);
100 MidiPlaylistSource::set_state (const XMLNode& node, int version)
102 return set_state (node, version, true);
106 MidiPlaylistSource::set_state (const XMLNode& node, int version, bool with_descendants)
108 if (with_descendants) {
109 if (Source::set_state (node, version) ||
110 MidiSource::set_state (node, version) ||
111 PlaylistSource::set_state (node, version)) {
120 MidiPlaylistSource::length (samplepos_t) const
122 pair<samplepos_t,samplepos_t> extent = _playlist->get_extent();
123 return extent.second - extent.first;
127 MidiPlaylistSource::read_unlocked (const Lock& lock,
128 Evoral::EventSink<samplepos_t>& dst,
129 samplepos_t /*position*/,
132 Evoral::Range<samplepos_t>* loop_range,
134 MidiChannelFilter*) const
136 boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlist);
142 return mp->read (dst, start, cnt, loop_range);
146 MidiPlaylistSource::write_unlocked (const Lock&,
147 MidiRingBuffer<samplepos_t>&,
151 fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::write_unlocked() called - should be impossible") << endmsg;
152 abort(); /*NOTREACHED*/
157 MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<Temporal::Beats>& /*ev*/)
159 fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_beats() called - should be impossible") << endmsg;
160 abort(); /*NOTREACHED*/
164 MidiPlaylistSource::append_event_samples(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<samplepos_t>& /* ev */, samplepos_t /*source_start*/)
166 fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_samples() called - should be impossible") << endmsg;
167 abort(); /*NOTREACHED*/
171 MidiPlaylistSource::load_model (const Glib::Threads::Mutex::Lock&, bool)
177 MidiPlaylistSource::destroy_model (const Glib::Threads::Mutex::Lock&)
183 MidiPlaylistSource::flush_midi (const Lock& lock)
189 MidiPlaylistSource::empty () const
191 return !_playlist || _playlist->empty();