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