fix unset timeline position for destructive sources; fix duplicate, unmanaged wavevie...
[ardour.git] / libs / ardour / destructive_filesource.cc
1 /*
2     Copyright (C) 2006 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     $Id$
19 */
20
21 /* This is is very hacky way to get pread and pwrite declarations.
22    First, include <features.h> so that we can avoid its #undef __USE_UNIX98.
23    Then define __USE_UNIX98, include <unistd.h>, and then undef it
24    again. If #define _XOPEN_SOURCE actually worked, I'd use that, but
25    despite claims in the header that it does, it doesn't.
26
27    features.h isn't available on osx and it compiles fine without it.
28 */
29
30 #ifdef HAVE_FEATURES_H
31 #include <features.h>
32 #endif
33
34 #if __GNUC__ >= 3
35 // #define _XOPEN_SOURCE 500
36 #include <unistd.h>
37 #else
38 #define __USE_UNIX98
39 #include <unistd.h>
40 #undef  __USE_UNIX98
41 #endif
42
43 // darwin supports 64 by default and doesn't provide wrapper functions.
44 #if defined (__APPLE__)
45 typedef off_t off64_t;
46 #define open64 open
47 #define close64 close
48 #define lseek64 lseek
49 #define pread64 pread
50 #define pwrite64 pwrite
51 #endif
52
53 #include <errno.h>
54 #include <cmath>
55 #include <fcntl.h>
56
57 #include <pbd/error.h>
58 #include <pbd/stacktrace.h>
59 #include <ardour/destructive_filesource.h>
60 #include <ardour/utils.h>
61 #include <ardour/session.h>
62
63 #include "i18n.h"
64
65 using namespace std;
66 using namespace ARDOUR;
67 using namespace PBD;
68
69 gain_t* DestructiveFileSource::out_coefficient = 0;
70 gain_t* DestructiveFileSource::in_coefficient = 0;
71 nframes_t DestructiveFileSource::xfade_frames = 64;
72
73 DestructiveFileSource::DestructiveFileSource (Session& s, string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, Flag flags)
74         : SndFileSource (s, path, samp_format, hdr_format, rate, flags)
75 {
76         init ();
77 }
78
79
80 DestructiveFileSource::DestructiveFileSource (Session& s, string path, Flag flags)
81         : SndFileSource (s, path, flags)
82 {
83         init ();
84 }
85
86 DestructiveFileSource::DestructiveFileSource (Session& s, const XMLNode& node)
87         : SndFileSource (s, node)
88 {
89         init ();
90 }
91
92 void
93 DestructiveFileSource::init ()
94 {
95         xfade_buf = new Sample[xfade_frames];
96
97         _capture_start = false;
98         _capture_end = false;
99         file_pos = 0;
100
101         timeline_position = header_position_offset;
102         AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &DestructiveFileSource::handle_header_position_change));
103 }
104
105 DestructiveFileSource::~DestructiveFileSource()
106 {
107         delete xfade_buf;
108 }
109
110 void
111 DestructiveFileSource::setup_standard_crossfades (nframes_t rate)
112 {
113         /* This static method is assumed to have been called by the Session
114            before any DFS's are created.
115         */
116
117         xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
118
119         if (out_coefficient) {
120                 delete [] out_coefficient;
121         }
122
123         if (in_coefficient) {
124                 delete [] in_coefficient;
125         }
126
127         out_coefficient = new gain_t[xfade_frames];
128         in_coefficient = new gain_t[xfade_frames];
129
130         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
131 }
132
133 void
134 DestructiveFileSource::mark_capture_start (nframes_t pos)
135 {
136         if (pos < timeline_position) {
137                 _capture_start = false;
138         } else {
139                 _capture_start = true;
140                 capture_start_frame = pos;
141         }
142 }
143
144 void
145 DestructiveFileSource::mark_capture_end()
146 {
147         _capture_end = true;
148 }
149
150 void
151 DestructiveFileSource::clear_capture_marks ()
152 {
153         _capture_start = false;
154         _capture_end = false;
155 }       
156
157 nframes_t
158 DestructiveFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
159 {
160         nframes_t xfade = min (xfade_frames, cnt);
161         nframes_t nofade = cnt - xfade;
162         Sample* fade_data = 0;
163         nframes_t fade_position = 0; // in frames
164         ssize_t retval;
165         nframes_t file_cnt;
166
167         if (fade_in) {
168                 fade_position = file_pos;
169                 fade_data = data;
170         } else {
171                 fade_position = file_pos + nofade;
172                 fade_data = data + nofade;
173         }
174
175         if (fade_position > _length) {
176                 
177                 /* read starts beyond end of data, just memset to zero */
178                 
179                 file_cnt = 0;
180
181         } else if (fade_position + xfade > _length) {
182                 
183                 /* read ends beyond end of data, read some, memset the rest */
184                 
185                 file_cnt = _length - fade_position;
186
187         } else {
188                 
189                 /* read is entirely within data */
190
191                 file_cnt = xfade;
192         }
193
194         if (file_cnt) {
195                 
196                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
197                         if (retval >= 0 && errno == EAGAIN) {
198                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
199                                  * short or no data there */
200                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
201                         } else {
202                                 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
203                                 return 0;
204                         }
205                 }
206         } 
207
208         if (file_cnt != xfade) {
209                 nframes_t delta = xfade - file_cnt;
210                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
211         }
212         
213         if (nofade && !fade_in) {
214                 if (write_float (data, file_pos, nofade) != nofade) {
215                         error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
216                         return 0;
217                 }
218         }
219
220         if (xfade == xfade_frames) {
221
222                 nframes_t n;
223
224                 /* use the standard xfade curve */
225                 
226                 if (fade_in) {
227
228                         /* fade new material in */
229                         
230                         for (n = 0; n < xfade; ++n) {
231                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
232                         }
233
234                 } else {
235
236
237                         /* fade new material out */
238                         
239                         for (n = 0; n < xfade; ++n) {
240                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
241                         }
242                 }
243
244         } else if (xfade) {
245
246                 gain_t in[xfade];
247                 gain_t out[xfade];
248
249                 /* short xfade, compute custom curve */
250
251                 compute_equal_power_fades (xfade, in, out);
252
253                 for (nframes_t n = 0; n < xfade; ++n) {
254                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);                
255                 }
256         }
257
258         if (xfade) {
259                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
260                         error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
261                         return 0;
262                 }
263         }
264         
265         if (fade_in && nofade) {
266                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
267                         error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
268                         return 0;
269                 }
270         }
271
272         return cnt;
273 }
274
275 nframes_t
276 DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt)
277 {
278         nframes_t old_file_pos;
279
280         if (!writable()) {
281                 return 0;
282         }
283
284         if (_capture_start && _capture_end) {
285
286                 /* start and end of capture both occur within the data we are writing,
287                    so do both crossfades.
288                 */
289
290                 _capture_start = false;
291                 _capture_end = false;
292                 
293                 /* move to the correct location place */
294                 file_pos = capture_start_frame - timeline_position;
295                 
296                 // split cnt in half
297                 nframes_t subcnt = cnt / 2;
298                 nframes_t ofilepos = file_pos;
299                 
300                 // fade in
301                 if (crossfade (data, subcnt, 1) != subcnt) {
302                         return 0;
303                 }
304                 
305                 file_pos += subcnt;
306                 Sample * tmpdata = data + subcnt;
307                 
308                 // fade out
309                 subcnt = cnt - subcnt;
310                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
311                         return 0;
312                 }
313                 
314                 file_pos = ofilepos; // adjusted below
315
316         } else if (_capture_start) {
317
318                 /* start of capture both occur within the data we are writing,
319                    so do the fade in
320                 */
321
322                 _capture_start = false;
323                 _capture_end = false;
324                 
325                 /* move to the correct location place */
326                 file_pos = capture_start_frame - timeline_position;
327
328                 if (crossfade (data, cnt, 1) != cnt) {
329                         return 0;
330                 }
331                 
332         } else if (_capture_end) {
333
334                 /* end of capture both occur within the data we are writing,
335                    so do the fade out
336                 */
337
338                 _capture_start = false;
339                 _capture_end = false;
340                 
341                 if (crossfade (data, cnt, 0) != cnt) {
342                         return 0;
343                 }
344
345         } else {
346
347                 /* in the middle of recording */
348
349                 if (write_float (data, file_pos, cnt) != cnt) {
350                         return 0;
351                 }
352         }
353
354         old_file_pos = file_pos;
355         update_length (file_pos, cnt);
356         file_pos += cnt;
357
358         if (_build_peakfiles) {
359                 PeakBuildRecord *pbr = 0;
360                 
361                 if (pending_peak_builds.size()) {
362                         pbr = pending_peak_builds.back();
363                 }
364                 
365                 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
366                         
367                         /* the last PBR extended to the start of the current write,
368                            so just extend it again.
369                         */
370                         
371                         pbr->cnt += cnt;
372                 } else {
373                         pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
374                 }
375                 
376                 _peaks_built = false;
377         }
378
379         if (_build_peakfiles) {
380                 queue_for_peaks (shared_from_this ());
381         }
382         
383         return cnt;
384 }
385
386 nframes_t
387 DestructiveFileSource::last_capture_start_frame () const
388 {
389         return capture_start_frame;
390 }
391
392 XMLNode& 
393 DestructiveFileSource::get_state ()
394 {
395         XMLNode& node = AudioFileSource::get_state ();
396         node.add_property (X_("destructive"), "true");
397         return node;
398 }
399
400 void
401 DestructiveFileSource::handle_header_position_change ()
402 {
403         if ( _length != 0 ) {
404                 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
405                 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
406         } else if (writable()) {
407                 timeline_position = header_position_offset;
408                 set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
409         }
410 }
411
412 void
413 DestructiveFileSource::set_timeline_position (nframes_t pos)
414 {
415         //destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes
416 }
417
418 int
419 DestructiveFileSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const
420 {
421         // cerr << _name << " read peaks at " << start << " for " << cnt << " tpos = " << timeline_position << endl;
422         return AudioFileSource::read_peaks (peaks, npeaks, start, cnt, samples_per_unit);
423 }
424