773deb93ab68a2acbee30db59f04800293f9d3d5
[ardour.git] / libs / ardour / audio_playlist_source.cc
1 /*
2     Copyright (C) 2011 Paul Davis
3
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.
8
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.
13
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.
17 */
18
19 #ifdef WAF_BUILD
20 #include "libardour-config.h"
21 #endif
22
23 #include <vector>
24 #include <cstdio>
25
26 #include <glibmm/fileutils.h>
27 #include <glibmm/miscutils.h>
28
29 #include "pbd/error.h"
30 #include "pbd/convert.h"
31 #include "pbd/enumwriter.h"
32
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/filename_extensions.h"
38 #include "ardour/session.h"
39 #include "ardour/session_directory.h"
40 #include "ardour/session_playlists.h"
41 #include "ardour/source_factory.h"
42
43 #include "i18n.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48
49 AudioPlaylistSource::AudioPlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<AudioPlaylist> p,
50                                           uint32_t chn, frameoffset_t begin, framecnt_t len, Source::Flag flags)
51         : Source (s, DataType::AUDIO, name)
52         , PlaylistSource (s, orig, name, p, DataType::AUDIO, begin, len, flags)
53         , AudioSource (s, name)
54         , _playlist_channel (chn)
55 {
56         AudioSource::_length = len;
57         ensure_buffers_for_level (_level, _session.frame_rate());
58 }
59
60 AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
61         : Source (s, node)
62         , PlaylistSource (s, node)
63         , AudioSource (s, node)
64 {
65         /* PlaylistSources are never writable, renameable, removable or destructive */
66         _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
67
68         /* ancestors have already called ::set_state() in their XML-based
69            constructors.
70         */
71
72         if (set_state (node, Stateful::loading_state_version, false)) {
73                 throw failed_constructor ();
74         }
75
76         AudioSource::_length = _playlist_length;
77 }
78
79 AudioPlaylistSource::~AudioPlaylistSource ()
80 {
81 }
82
83 XMLNode&
84 AudioPlaylistSource::get_state ()
85 {
86         XMLNode& node (AudioSource::get_state ());
87         char buf[64];
88
89         /* merge PlaylistSource state */
90
91         PlaylistSource::add_state (node);
92
93         snprintf (buf, sizeof (buf), "%" PRIu32, _playlist_channel);
94         node.add_property ("channel", buf);
95
96         return node;
97 }
98
99 int
100 AudioPlaylistSource::set_state (const XMLNode& node, int version)
101 {
102         return set_state (node, version, true);
103 }
104
105 int
106 AudioPlaylistSource::set_state (const XMLNode& node, int version, bool with_descendants)
107 {
108         if (with_descendants) {
109                 if (Source::set_state (node, version) ||
110                     PlaylistSource::set_state (node, version) ||
111                     AudioSource::set_state (node, version)) {
112                         return -1;
113                 }
114         }
115
116         const XMLProperty* prop;
117         pair<framepos_t,framepos_t> extent = _playlist->get_extent();
118
119         AudioSource::_length = extent.second - extent.first;
120
121         if ((prop = node.property (X_("channel"))) == 0) {
122                 throw failed_constructor ();
123         }
124
125         sscanf (prop->value().c_str(), "%" PRIu32, &_playlist_channel);
126
127         ensure_buffers_for_level (_level, _session.frame_rate());
128
129         return 0;
130 }
131
132 framecnt_t
133 AudioPlaylistSource::read_unlocked (Sample* dst, framepos_t start, framecnt_t cnt) const
134 {
135         boost::shared_ptr<Sample> sbuf;
136         boost::shared_ptr<gain_t> gbuf;
137         framecnt_t to_read;
138         framecnt_t to_zero;
139         pair<framepos_t,framepos_t> extent = _playlist->get_extent();
140
141         /* we must be careful not to read beyond the end of our "section" of
142          * the playlist, because otherwise we may read data that exists, but
143          * is not supposed be part of our data.
144          */
145
146         if (cnt > _playlist_length - start) {
147                 to_read = _playlist_length - start;
148                 to_zero = cnt - to_read;
149         } else {
150                 to_read = cnt;
151                 to_zero = 0;
152         }
153
154         {
155                 /* Don't need to hold the lock for the actual read, and
156                    actually, we cannot, but we do want to interlock
157                    with any changes to the list of buffers caused
158                    by creating new nested playlists/sources
159                 */
160                 Glib::Mutex::Lock lm (_level_buffer_lock);
161                 sbuf = _mixdown_buffers[_level-1];
162                 gbuf = _gain_buffers[_level-1];
163         }
164
165         boost::dynamic_pointer_cast<AudioPlaylist>(_playlist)->read (dst, sbuf.get(), gbuf.get(), start+_playlist_offset, to_read, _playlist_channel);
166
167         if (to_zero) {
168                 memset (dst+to_read, 0, sizeof (Sample) * to_zero);
169         }
170
171         return cnt;
172 }
173
174 framecnt_t
175 AudioPlaylistSource::write_unlocked (Sample *src, framecnt_t cnt)
176 {
177         fatal << string_compose (_("programming error: %1"), "AudioPlaylistSource::write() called - should be impossible") << endmsg;
178         /*NOTREACHED*/
179         return 0;
180 }
181
182 bool
183 AudioPlaylistSource::empty () const
184 {
185         return !_playlist || _playlist->empty();
186 }
187
188 uint32_t
189 AudioPlaylistSource::n_channels () const
190 {
191         /* use just the first region to decide */
192
193         if (empty()) {
194                 return 1;
195         }
196
197         boost::shared_ptr<Region> r = _playlist->region_list().front ();
198         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
199
200         return ar->audio_source()->n_channels ();
201 }
202
203 float
204 AudioPlaylistSource::sample_rate () const
205 {
206         /* use just the first region to decide */
207
208         if (empty()) {
209                 _session.frame_rate ();
210         }
211
212         boost::shared_ptr<Region> r = _playlist->region_list().front ();
213         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
214
215         return ar->audio_source()->sample_rate ();
216 }
217
218 int
219 AudioPlaylistSource::setup_peakfile ()
220 {
221         _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name() + ARDOUR::peakfile_suffix);
222         return initialize_peakfile (false, string());
223 }
224
225 string
226 AudioPlaylistSource::peak_path (string /*audio_path_IGNORED*/)
227 {
228         return _peak_path;
229 }
230
231