refactor playlist sources to allow for MIDI and upcoming work on save/restore
[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/session.h"
38 #include "ardour/session_directory.h"
39 #include "ardour/session_playlists.h"
40 #include "ardour/source_factory.h"
41
42 #include "i18n.h"
43
44 using namespace std;
45 using namespace ARDOUR;
46 using namespace PBD;
47
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)
54 {
55         _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name);
56
57         AudioSource::_length = len;
58         ensure_buffers_for_level (_level);
59 }
60
61 AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
62         : Source (s, DataType::AUDIO, "toBeRenamed")
63         , AudioSource (s, node)
64         , PlaylistSource (s, node)
65 {
66         /* PlaylistSources are never writable, renameable, removable or destructive */
67         _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
68
69         /* ancestors have already called ::set_state() in their XML-based
70            constructors.
71         */
72         
73         if (set_state (node, Stateful::loading_state_version, false)) {
74                 throw failed_constructor ();
75         }
76 }
77
78 AudioPlaylistSource::~AudioPlaylistSource ()
79 {
80 }
81
82 XMLNode&
83 AudioPlaylistSource::get_state ()
84 {
85         XMLNode& node (AudioSource::get_state ());
86         char buf[64];
87
88         /* merge PlaylistSource state */
89
90         PlaylistSource::add_state (node);
91
92         snprintf (buf, sizeof (buf), "%" PRIu32, _playlist_channel);
93         node.add_property ("channel", buf);
94         node.add_property ("peak-path", _peak_path);
95
96         return node;
97 }
98
99         
100 int
101 AudioPlaylistSource::set_state (const XMLNode& node, int version) 
102 {
103         return set_state (node, version, true);
104 }
105
106 int
107 AudioPlaylistSource::set_state (const XMLNode& node, int version, bool with_descendants) 
108 {
109         if (with_descendants) {
110                 if (Source::set_state (node, version) || 
111                     AudioSource::set_state (node, version) ||
112                     PlaylistSource::set_state (node, version)) {
113                         return -1;
114                 }
115         }
116
117         const XMLProperty* prop;
118         pair<framepos_t,framepos_t> extent = _playlist->get_extent();
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         if ((prop = node.property (X_("peak-path"))) == 0) {
128                 throw failed_constructor ();
129         }
130
131         _peak_path = prop->value ();
132
133         ensure_buffers_for_level (_level);
134
135         return 0;
136 }
137
138 framecnt_t 
139 AudioPlaylistSource::read_unlocked (Sample* dst, framepos_t start, framecnt_t cnt) const
140 {
141         Sample* sbuf;
142         gain_t* gbuf;
143         framecnt_t to_read;
144         framecnt_t to_zero;
145         pair<framepos_t,framepos_t> extent = _playlist->get_extent();
146
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.
150          */
151
152         if (cnt > _playlist_length - start) {
153                 to_read = _playlist_length - start;
154                 to_zero = cnt - to_read;
155         } else {
156                 to_read = cnt;
157                 to_zero = 0;
158         }
159
160         { 
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
165                 */
166                 Glib::Mutex::Lock lm (_level_buffer_lock);
167                 sbuf = _mixdown_buffers[_level-1];
168                 gbuf = _gain_buffers[_level-1];
169         }
170
171         boost::dynamic_pointer_cast<AudioPlaylist>(_playlist)->read (dst, sbuf, gbuf, start+_playlist_offset, to_read, _playlist_channel);
172
173         if (to_zero) {
174                 memset (dst+to_read, 0, sizeof (Sample) * to_zero);
175         }
176
177         return cnt;
178 }
179
180 framecnt_t 
181 AudioPlaylistSource::write_unlocked (Sample *src, framecnt_t cnt) 
182 {
183         fatal << string_compose (_("programming error: %1"), "AudioPlaylistSource::write() called - should be impossible") << endmsg;
184         /*NOTREACHED*/
185         return 0;
186 }
187
188 bool
189 AudioPlaylistSource::empty () const
190 {
191         return !_playlist || _playlist->empty();
192 }
193
194 uint32_t
195 AudioPlaylistSource::n_channels () const
196 {
197         /* use just the first region to decide */
198
199         if (empty()) {
200                 return 1;
201         }
202
203         boost::shared_ptr<Region> r = _playlist->region_list().front ();
204         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
205
206         return ar->audio_source()->n_channels ();
207 }
208
209 float
210 AudioPlaylistSource::sample_rate () const
211 {
212         /* use just the first region to decide */
213
214         if (empty()) {
215                 _session.frame_rate ();
216         }
217
218         boost::shared_ptr<Region> r = _playlist->region_list().front ();
219         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
220
221         return ar->audio_source()->sample_rate ();
222 }
223
224 int
225 AudioPlaylistSource::setup_peakfile ()
226 {
227         /* the peak data is setup once and once only 
228          */
229         
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.
235                 */
236                 return initialize_peakfile (false, string());
237         }
238
239         return 0;
240 }
241
242 string
243 AudioPlaylistSource::peak_path (string /*audio_path*/)
244 {
245         return _peak_path;
246 }
247