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