very basic Join (regions) editing operation. not finished yet, no undoable, no sensib...
[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, bool copy, Source::Flag flags)
50         : Source (s, DataType::AUDIO, name)
51         , AudioSource (s, name)
52         , _playlist (p)
53         , _playlist_channel (chn)
54 {
55         /* PlaylistSources are never writable, renameable, removable or destructive */
56         _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
57
58         if (!copy) {
59                 _playlist = p;
60                 _playlist_offset = begin;
61                 _playlist_length = len;
62         } else {
63                 _playlist.reset (new AudioPlaylist (p, begin, len, "XXXNAMEXXX", true));
64                 _playlist_offset = 0;
65                 _playlist_length = len;
66         }
67
68         _length = len;
69         _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name);
70         _level = _playlist->max_source_level () + 1;
71         ensure_buffers_for_level (_level);
72 }
73
74 AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
75         : Source (s, DataType::AUDIO, "toBeRenamed")
76         , AudioSource (s, node)
77 {
78         /* PlaylistSources are never writable, renameable, removable or destructive */
79         _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
80         
81         set_state (node, 3000);
82 }
83
84 AudioPlaylistSource::~AudioPlaylistSource ()
85 {
86 }
87
88 XMLNode&
89 AudioPlaylistSource::get_state ()
90 {
91         XMLNode& node (AudioSource::get_state ());
92         char buf[64];
93         snprintf (buf, sizeof (buf), "%" PRIi64, _playlist_offset);
94         node.add_property ("offset", buf);
95         snprintf (buf, sizeof (buf), "%" PRIu64, _playlist_length);
96         node.add_property ("length", buf);
97         snprintf (buf, sizeof (buf), "%" PRIu32, _playlist_channel);
98         node.add_property ("channel", buf);
99         node.add_property ("name", name());
100         node.add_property ("peak-path", _peak_path);
101
102         return node;
103 }
104
105 int
106 AudioPlaylistSource::set_state (const XMLNode& node, int /* version */) 
107 {
108         /* get playlist ID */
109
110         const XMLProperty *prop = node.property (X_("playlist"));
111
112         if (!prop) {
113                 throw failed_constructor ();
114         }
115
116         PBD::ID id (prop->value());
117
118         /* get playlist */
119
120         boost::shared_ptr<Playlist> p = _session.playlists->by_id (id);
121         _playlist = boost::dynamic_pointer_cast<AudioPlaylist>(p);
122
123         if (!_playlist) {
124                 throw failed_constructor ();
125         }
126
127         pair<framepos_t,framepos_t> extent = _playlist->get_extent();
128         _length = extent.second - extent.first;
129
130         /* other properties */
131
132         if ((prop = node.property (X_("name"))) == 0) {
133                 throw failed_constructor ();
134         }
135         
136         set_name (prop->value());
137
138         if ((prop = node.property (X_("offset"))) == 0) {
139                 throw failed_constructor ();
140         }
141         sscanf (prop->value().c_str(), "%" PRIi64, &_playlist_offset);
142
143         if ((prop = node.property (X_("length"))) == 0) {
144                 throw failed_constructor ();
145         }
146
147         sscanf (prop->value().c_str(), "%" PRIu64, &_playlist_length);
148
149         if ((prop = node.property (X_("channel"))) == 0) {
150                 throw failed_constructor ();
151         }
152
153         sscanf (prop->value().c_str(), "%" PRIu32, &_playlist_channel);
154
155         if ((prop = node.property (X_("peak-path"))) == 0) {
156                 throw failed_constructor ();
157         }
158
159         _peak_path = prop->value ();
160
161         _level = _playlist->max_source_level ();
162         ensure_buffers_for_level (_level);
163
164         return 0;
165 }
166
167 framecnt_t 
168 AudioPlaylistSource::read_unlocked (Sample* dst, framepos_t start, framecnt_t cnt) const
169 {
170         framecnt_t to_read;
171         framecnt_t to_zero;
172         pair<framepos_t,framepos_t> extent = _playlist->get_extent();
173
174         /* we must be careful not to read beyond the end of our "section" of
175          * the playlist, because otherwise we may read data that exists, but
176          * is not supposed be part of our data.
177          */
178
179         if (cnt > _playlist_length - start) {
180                 to_read = _playlist_length - start;
181                 to_zero = cnt - to_read;
182         } else {
183                 to_read = cnt;
184                 to_zero = 0;
185         }
186
187         { 
188                 Glib::Mutex::Lock lm (_level_buffer_lock);
189                 _playlist->read (dst, _mixdown_buffers[_level-1], _gain_buffers[_level-1], start+_playlist_offset, to_read, _playlist_channel);
190         }
191
192         if (to_zero) {
193                 memset (dst+to_read, 0, sizeof (Sample) * to_zero);
194         }
195
196         return cnt;
197 }
198
199 framecnt_t 
200 AudioPlaylistSource::write_unlocked (Sample *src, framecnt_t cnt) 
201 {
202         fatal << string_compose (_("programming error: %1"), "AudioPlaylistSource::write() called - should be impossible") << endmsg;
203         /*NOTREACHED*/
204         return 0;
205 }
206
207 bool
208 AudioPlaylistSource::empty () const
209 {
210         return !_playlist || _playlist->empty();
211 }
212
213 uint32_t
214 AudioPlaylistSource::n_channels () const
215 {
216         /* use just the first region to decide */
217
218         if (empty()) {
219                 return 1;
220         }
221
222         boost::shared_ptr<Region> r = _playlist->region_list().front ();
223         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
224
225         return ar->audio_source()->n_channels ();
226 }
227
228 float
229 AudioPlaylistSource::sample_rate () const
230 {
231         /* use just the first region to decide */
232
233         if (empty()) {
234                 _session.frame_rate ();
235         }
236
237         boost::shared_ptr<Region> r = _playlist->region_list().front ();
238         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
239
240         return ar->audio_source()->sample_rate ();
241 }
242
243 int
244 AudioPlaylistSource::setup_peakfile ()
245 {
246         /* the peak data is setup once and once only 
247          */
248         
249         cerr << "looking for peakfile " << _peak_path << endl;
250
251
252         if (!Glib::file_test (_peak_path, Glib::FILE_TEST_EXISTS)) {
253                 /* the 2nd argument here will be passed
254                    in to ::peak_path, and is irrelevant
255                    since our peak file path is fixed and
256                    not dependent on anything.
257                 */
258                 cerr << "build it!\n";
259                 return initialize_peakfile (false, string());
260         } else {
261                 cerr << "exists!\n";
262         }
263
264         return 0;
265 }
266
267 string
268 AudioPlaylistSource::peak_path (string /*audio_path*/)
269 {
270         return _peak_path;
271 }
272