1 /*
2  * Copyright (C) 2011-2012 David Robillard <d@drobilla.net>
3  * Copyright (C) 2011-2017 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2012-2016 Tim Mayberry <mojofunk@gmail.com>
5  * Copyright (C) 2014-2016 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #ifdef WAF_BUILD
23 #include "libardour-config.h"
24 #endif
25 
26 #include <vector>
27 #include <cstdio>
28 
29 #include <glibmm/fileutils.h>
30 #include <glibmm/miscutils.h>
31 
32 #include "pbd/error.h"
33 
34 #include "ardour/audioplaylist.h"
35 #include "ardour/audio_playlist_source.h"
36 #include "ardour/audioregion.h"
37 #include "ardour/filename_extensions.h"
38 #include "ardour/session.h"
39 #include "ardour/session_directory.h"
40 
41 #include "pbd/i18n.h"
42 
43 using namespace std;
44 using namespace ARDOUR;
45 using namespace PBD;
46 
AudioPlaylistSource(Session & s,const ID & orig,const std::string & name,boost::shared_ptr<AudioPlaylist> p,uint32_t chn,sampleoffset_t begin,samplecnt_t len,Source::Flag flags)47 AudioPlaylistSource::AudioPlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<AudioPlaylist> p,
48 					  uint32_t chn, sampleoffset_t begin, samplecnt_t len, Source::Flag flags)
49 	: Source (s, DataType::AUDIO, name)
50 	, PlaylistSource (s, orig, name, p, DataType::AUDIO, begin, len, flags)
51 	, AudioSource (s, name)
52 	, _playlist_channel (chn)
53 {
54 	AudioSource::_length = len;
55 }
56 
AudioPlaylistSource(Session & s,const XMLNode & node)57 AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
58 	: Source (s, node)
59 	, PlaylistSource (s, node)
60 	, AudioSource (s, node)
61 {
62 	/* PlaylistSources are never writable, renameable or removable */
63 	_flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy));
64 
65 	/* ancestors have already called ::set_state() in their XML-based
66 	   constructors.
67 	*/
68 
69 	if (set_state (node, Stateful::loading_state_version, false)) {
70 		throw failed_constructor ();
71 	}
72 
73 	AudioSource::_length = _playlist_length;
74 }
75 
~AudioPlaylistSource()76 AudioPlaylistSource::~AudioPlaylistSource ()
77 {
78 }
79 
80 XMLNode&
get_state()81 AudioPlaylistSource::get_state ()
82 {
83 	XMLNode& node (AudioSource::get_state ());
84 
85 	/* merge PlaylistSource state */
86 
87 	PlaylistSource::add_state (node);
88 
89 	node.set_property ("channel", _playlist_channel);
90 
91 	return node;
92 }
93 
94 int
set_state(const XMLNode & node,int version)95 AudioPlaylistSource::set_state (const XMLNode& node, int version)
96 {
97 	return set_state (node, version, true);
98 }
99 
100 int
set_state(const XMLNode & node,int version,bool with_descendants)101 AudioPlaylistSource::set_state (const XMLNode& node, int version, bool with_descendants)
102 {
103 	if (with_descendants) {
104 		if (Source::set_state (node, version) ||
105 		    PlaylistSource::set_state (node, version) ||
106 		    AudioSource::set_state (node, version)) {
107 			return -1;
108 		}
109 	}
110 
111 	pair<samplepos_t,samplepos_t> extent = _playlist->get_extent();
112 
113 	AudioSource::_length = extent.second - extent.first;
114 
115 	if (!node.get_property (X_("channel"), _playlist_channel)) {
116 		throw failed_constructor ();
117 	}
118 
119 	return 0;
120 }
121 
122 samplecnt_t
read_unlocked(Sample * dst,samplepos_t start,samplecnt_t cnt) const123 AudioPlaylistSource::read_unlocked (Sample* dst, samplepos_t start, samplecnt_t cnt) const
124 {
125 	samplecnt_t to_read;
126 	samplecnt_t to_zero;
127 
128 	/* we must be careful not to read beyond the end of our "section" of
129 	 * the playlist, because otherwise we may read data that exists, but
130 	 * is not supposed be part of our data.
131 	 */
132 
133 	if (cnt > _playlist_length - start) {
134 		to_read = _playlist_length - start;
135 		to_zero = cnt - to_read;
136 	} else {
137 		to_read = cnt;
138 		to_zero = 0;
139 	}
140 
141 	boost::scoped_array<float> sbuf(new float[to_read]);
142 	boost::scoped_array<gain_t> gbuf(new gain_t[to_read]);
143 
144 	boost::dynamic_pointer_cast<AudioPlaylist>(_playlist)->read (dst, sbuf.get(), gbuf.get(), start+_playlist_offset, to_read, _playlist_channel);
145 
146 	if (to_zero) {
147 		memset (dst+to_read, 0, sizeof (Sample) * to_zero);
148 	}
149 
150 	return cnt;
151 }
152 
153 samplecnt_t
write_unlocked(Sample *,samplecnt_t)154 AudioPlaylistSource::write_unlocked (Sample *, samplecnt_t)
155 {
156 	fatal << string_compose (_("programming error: %1"), "AudioPlaylistSource::write() called - should be impossible") << endmsg;
157 	abort(); /*NOTREACHED*/
158 	return 0;
159 }
160 
161 bool
empty() const162 AudioPlaylistSource::empty () const
163 {
164 	return !_playlist || _playlist->empty();
165 }
166 
167 uint32_t
n_channels() const168 AudioPlaylistSource::n_channels () const
169 {
170 	/* use just the first region to decide */
171 
172 	if (empty()) {
173 		return 1;
174 	}
175 
176 	boost::shared_ptr<Region> r = _playlist->region_list_property().front ();
177 	boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
178 
179 	return ar->audio_source()->n_channels ();
180 }
181 
182 float
sample_rate() const183 AudioPlaylistSource::sample_rate () const
184 {
185 	/* use just the first region to decide */
186 
187 	if (empty()) {
188 		_session.sample_rate ();
189 	}
190 
191 	boost::shared_ptr<Region> r = _playlist->region_list_property().front ();
192 	boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
193 
194 	return ar->audio_source()->sample_rate ();
195 }
196 
197 int
setup_peakfile()198 AudioPlaylistSource::setup_peakfile ()
199 {
200 	_peak_path = Glib::build_filename (_session.session_directory().peak_path(), name() + ARDOUR::peakfile_suffix);
201 	return initialize_peakfile (string());
202 }
203 
204 string
construct_peak_filepath(const string &,const bool,const bool) const205 AudioPlaylistSource::construct_peak_filepath (const string& /*audio_path_*/, const bool /* in_session */, const bool /* old_peak_name */) const
206 {
207 	return _peak_path;
208 }
209 
210 
211