2 Copyright (C) 2011 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "libardour-config.h"
26 #include <glibmm/fileutils.h>
27 #include <glibmm/miscutils.h>
29 #include "pbd/error.h"
30 #include "pbd/convert.h"
31 #include "pbd/enumwriter.h"
33 #include "ardour/audioplaylist.h"
34 #include "ardour/audio_playlist_source.h"
35 #include "ardour/audioregion.h"
36 #include "ardour/debug.h"
37 #include "ardour/session.h"
38 #include "ardour/session_directory.h"
39 #include "ardour/session_playlists.h"
40 #include "ardour/source_factory.h"
45 using namespace ARDOUR;
48 AudioPlaylistSource::AudioPlaylistSource (Session& s, const std::string& name, boost::shared_ptr<AudioPlaylist> p,
49 uint32_t chn, frameoffset_t begin, framecnt_t len, Source::Flag flags)
50 : Source (s, DataType::AUDIO, name)
51 , AudioSource (s, name)
52 , PlaylistSource (s, name, p, DataType::AUDIO, begin, len, flags)
53 , _playlist_channel (chn)
55 _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name);
57 AudioSource::_length = len;
58 ensure_buffers_for_level (_level);
61 AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
62 : Source (s, DataType::AUDIO, "toBeRenamed")
63 , AudioSource (s, node)
64 , PlaylistSource (s, node)
66 /* PlaylistSources are never writable, renameable, removable or destructive */
67 _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
69 /* ancestors have already called ::set_state() in their XML-based
73 if (set_state (node, Stateful::loading_state_version, false)) {
74 throw failed_constructor ();
78 AudioPlaylistSource::~AudioPlaylistSource ()
83 AudioPlaylistSource::get_state ()
85 XMLNode& node (AudioSource::get_state ());
88 /* merge PlaylistSource state */
90 PlaylistSource::add_state (node);
92 snprintf (buf, sizeof (buf), "%" PRIu32, _playlist_channel);
93 node.add_property ("channel", buf);
94 node.add_property ("peak-path", _peak_path);
101 AudioPlaylistSource::set_state (const XMLNode& node, int version)
103 return set_state (node, version, true);
107 AudioPlaylistSource::set_state (const XMLNode& node, int version, bool with_descendants)
109 if (with_descendants) {
110 if (Source::set_state (node, version) ||
111 AudioSource::set_state (node, version) ||
112 PlaylistSource::set_state (node, version)) {
117 const XMLProperty* prop;
118 pair<framepos_t,framepos_t> extent = _playlist->get_extent();
119 AudioSource::_length = extent.second - extent.first;
121 if ((prop = node.property (X_("channel"))) == 0) {
122 throw failed_constructor ();
125 sscanf (prop->value().c_str(), "%" PRIu32, &_playlist_channel);
127 if ((prop = node.property (X_("peak-path"))) == 0) {
128 throw failed_constructor ();
131 _peak_path = prop->value ();
133 ensure_buffers_for_level (_level);
139 AudioPlaylistSource::read_unlocked (Sample* dst, framepos_t start, framecnt_t cnt) const
145 pair<framepos_t,framepos_t> extent = _playlist->get_extent();
147 /* we must be careful not to read beyond the end of our "section" of
148 * the playlist, because otherwise we may read data that exists, but
149 * is not supposed be part of our data.
152 if (cnt > _playlist_length - start) {
153 to_read = _playlist_length - start;
154 to_zero = cnt - to_read;
161 /* Don't need to hold the lock for the actual read, and
162 actually, we cannot, but we do want to interlock
163 with any changes to the list of buffers caused
164 by creating new nested playlists/sources
166 Glib::Mutex::Lock lm (_level_buffer_lock);
167 sbuf = _mixdown_buffers[_level-1];
168 gbuf = _gain_buffers[_level-1];
171 boost::dynamic_pointer_cast<AudioPlaylist>(_playlist)->read (dst, sbuf, gbuf, start+_playlist_offset, to_read, _playlist_channel);
174 memset (dst+to_read, 0, sizeof (Sample) * to_zero);
181 AudioPlaylistSource::write_unlocked (Sample *src, framecnt_t cnt)
183 fatal << string_compose (_("programming error: %1"), "AudioPlaylistSource::write() called - should be impossible") << endmsg;
189 AudioPlaylistSource::empty () const
191 return !_playlist || _playlist->empty();
195 AudioPlaylistSource::n_channels () const
197 /* use just the first region to decide */
203 boost::shared_ptr<Region> r = _playlist->region_list().front ();
204 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
206 return ar->audio_source()->n_channels ();
210 AudioPlaylistSource::sample_rate () const
212 /* use just the first region to decide */
215 _session.frame_rate ();
218 boost::shared_ptr<Region> r = _playlist->region_list().front ();
219 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
221 return ar->audio_source()->sample_rate ();
225 AudioPlaylistSource::setup_peakfile ()
227 /* the peak data is setup once and once only
230 if (!Glib::file_test (_peak_path, Glib::FILE_TEST_EXISTS)) {
231 /* the 2nd argument here will be passed
232 in to ::peak_path, and is irrelevant
233 since our peak file path is fixed and
234 not dependent on anything.
236 return initialize_peakfile (false, string());
243 AudioPlaylistSource::peak_path (string /*audio_path*/)