lots of fidgety work to get track renaming to work correctly now that we have to...
[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 <ardour/destructive_filesource.h>
59
60 #include "i18n.h"
61
62 using namespace std;
63 using namespace ARDOUR;
64
65 gain_t* DestructiveFileSource::out_coefficient = 0;
66 gain_t* DestructiveFileSource::in_coefficient = 0;
67 jack_nframes_t DestructiveFileSource::xfade_frames = 64;
68
69 DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, bool repair_first, SampleFormat samp_format)
70         : FileSource (path, rate, repair_first, samp_format)
71 {
72         if (out_coefficient == 0) {
73                 setup_standard_crossfades (rate);
74         }
75
76         xfade_buf = new Sample[xfade_frames];
77
78         _capture_start = false;
79         _capture_end = false;
80         file_pos = 0;
81 }
82
83 DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate)
84         : FileSource (node, rate)
85 {
86         if (out_coefficient == 0) {
87                 setup_standard_crossfades (rate);
88         }
89
90         xfade_buf = new Sample[xfade_frames];
91
92         _capture_start = false;
93         _capture_end = false;
94         file_pos = 0;
95 }
96
97 DestructiveFileSource::~DestructiveFileSource()
98 {
99         delete xfade_buf;
100 }
101
102 void
103 DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate)
104 {
105         xfade_frames = (jack_nframes_t) floor ((/*Config->get_destructive_crossfade_msecs()*/ 64 / 1000.0) * rate);
106
107         out_coefficient = new gain_t[xfade_frames];
108         in_coefficient = new gain_t[xfade_frames];
109
110         for (jack_nframes_t n = 0; n < xfade_frames; ++n) {
111
112                 /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
113
114                 in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */
115                 out_coefficient[n] = 1.0 - in_coefficient[n];    /* 1 .. 0 */
116         }
117 }
118
119 int
120 DestructiveFileSource::seek (jack_nframes_t frame)
121 {
122         return 0;
123 }
124
125 void
126 DestructiveFileSource::mark_capture_start (jack_nframes_t pos)
127 {
128         _capture_start = true;
129         capture_start_frame = pos;
130 }
131
132 void
133 DestructiveFileSource::mark_capture_end()
134 {
135         _capture_end = true;
136 }
137
138 void
139 DestructiveFileSource::clear_capture_marks ()
140 {
141         _capture_start = false;
142         _capture_end = false;
143 }       
144
145 jack_nframes_t
146 DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf)
147 {
148         jack_nframes_t xfade = min (xfade_frames, cnt);
149         jack_nframes_t nofade = cnt - xfade;
150         Sample* fade_data = 0;
151         jack_nframes_t fade_position = 0; // in frames
152         ssize_t retval;
153         jack_nframes_t file_cnt;
154
155         if (fade_in) {
156                 fade_position = file_pos;
157                 fade_data = data;
158         } else {
159                 fade_position = file_pos + nofade;
160                 fade_data = data + nofade;
161         }
162
163         if (fade_position > _length) {
164                 
165                 /* read starts beyond end of data, just memset to zero */
166                 
167                 file_cnt = 0;
168
169         } else if (fade_position + xfade > _length) {
170                 
171                 /* read ends beyond end of data, read some, memset the rest */
172                 
173                 file_cnt = _length - fade_position;
174
175         } else {
176                 
177                 /* read is entirely within data */
178
179                 file_cnt = xfade;
180         }
181
182         if (file_cnt) {
183                 if ((retval = file_read (xfade_buf, fade_position, file_cnt, workbuf)) != (ssize_t) file_cnt) {
184                         if (retval >= 0 && errno == EAGAIN) {
185                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
186                                  * short or no data there */
187                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
188                         } else {
189                                 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
190                                 return 0;
191                         }
192                 }
193         } 
194
195         if (file_cnt != xfade) {
196                 jack_nframes_t delta = xfade - file_cnt;
197                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
198         }
199         
200         if (nofade && !fade_in) {
201                 if (file_write (data, file_pos, nofade, workbuf) != (ssize_t) nofade) {
202                         error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
203                         return 0;
204                 }
205         }
206
207         if (xfade == xfade_frames) {
208
209                 jack_nframes_t n;
210
211                 /* use the standard xfade curve */
212                 
213                 if (fade_in) {
214
215                         /* fade new material in */
216                         
217                         for (n = 0; n < xfade; ++n) {
218                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
219                         }
220
221                 } else {
222
223
224                         /* fade new material out */
225                         
226                         for (n = 0; n < xfade; ++n) {
227                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
228                         }
229                 }
230
231         } else if (xfade) {
232
233                 /* short xfade, compute custom curve */
234
235                 /* XXX COMPUTE THE CURVE, DAMMIT! */
236
237                 for (jack_nframes_t n = 0; n < xfade; ++n) {
238                         xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
239                 }
240         }
241
242         if (xfade) {
243                 if (file_write (xfade_buf, fade_position, xfade, workbuf) != (ssize_t) xfade) {
244                         error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
245                         return 0;
246                 }
247         }
248         
249         if (fade_in && nofade) {
250                 if (file_write (data + xfade, file_pos + xfade, nofade, workbuf) != (ssize_t) nofade) {
251                         error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
252                         return 0;
253                 }
254         }
255
256         return cnt;
257 }
258
259 jack_nframes_t
260 DestructiveFileSource::write (Sample* data, jack_nframes_t cnt, char * workbuf)
261 {
262         {
263                 LockMonitor lm (_lock, __LINE__, __FILE__);
264                 
265                 jack_nframes_t old_file_pos;
266
267                 if (_capture_start && _capture_end) {
268                         _capture_start = false;
269                         _capture_end = false;
270
271                         /* move to the correct location place */
272                         file_pos = capture_start_frame;
273                         
274                         // split cnt in half
275                         jack_nframes_t subcnt = cnt / 2;
276                         jack_nframes_t ofilepos = file_pos;
277                         
278                         // fade in
279                         if (crossfade (data, subcnt, 1, workbuf) != subcnt) {
280                                 return 0;
281                         }
282
283                         file_pos += subcnt;
284                         Sample * tmpdata = data + subcnt;
285                         
286                         // fade out
287                         subcnt = cnt - subcnt;
288                         if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) {
289                                 return 0;
290                         }
291
292                         file_pos = ofilepos; // adjusted below
293                 }
294                 else if (_capture_start) {
295                         _capture_start = false;
296                         _capture_end = false;
297
298                         /* move to the correct location place */
299                         file_pos = capture_start_frame;
300                         
301                         if (crossfade (data, cnt, 1, workbuf) != cnt) {
302                                 return 0;
303                         }
304
305                 } else if (_capture_end) {
306                         _capture_start = false;
307                         _capture_end = false;
308
309                         if (crossfade (data, cnt, 0, workbuf) != cnt) {
310                                 return 0;
311                         }
312                 } else {
313                         if (file_write(data, file_pos, cnt, workbuf) != (ssize_t) cnt) {
314                                 return 0;
315                         }
316                 }
317
318                 old_file_pos = file_pos;
319                 if (file_pos + cnt > _length) {
320                         _length = file_pos + cnt;
321                 }
322                 file_pos += cnt;
323                 
324                 if (_build_peakfiles) {
325                         PeakBuildRecord *pbr = 0;
326                         
327                         if (pending_peak_builds.size()) {
328                                 pbr = pending_peak_builds.back();
329                         }
330                         
331                         if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
332                                 
333                                 /* the last PBR extended to the start of the current write,
334                                    so just extend it again.
335                                 */
336
337                                 pbr->cnt += cnt;
338                         } else {
339                                 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
340                         }
341                         
342                         _peaks_built = false;
343                 }
344         }
345
346         if (_build_peakfiles) {
347                 queue_for_peaks (*this);
348         }
349
350         return cnt;
351 }
352
353 jack_nframes_t
354 DestructiveFileSource::last_capture_start_frame () const
355 {
356         return capture_start_frame;
357 }
358
359 XMLNode& 
360 DestructiveFileSource::get_state ()
361 {
362         XMLNode& node = FileSource::get_state ();
363         node.add_property (X_("destructive"), "true");
364         return node;
365 }