2 Copyright (C) 2006 Paul Davis
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.
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.
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.
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.
27 features.h isn't available on osx and it compiles fine without it.
30 #ifdef HAVE_FEATURES_H
35 // #define _XOPEN_SOURCE 500
43 // darwin supports 64 by default and doesn't provide wrapper functions.
44 #if defined (__APPLE__)
45 typedef off_t off64_t;
50 #define pwrite64 pwrite
57 #include <pbd/error.h>
58 #include <ardour/destructive_filesource.h>
63 using namespace ARDOUR;
65 gain_t* DestructiveFileSource::out_coefficient = 0;
66 gain_t* DestructiveFileSource::in_coefficient = 0;
67 jack_nframes_t DestructiveFileSource::xfade_frames = 64;
69 DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, bool repair_first, SampleFormat samp_format)
70 : FileSource (path, rate, repair_first, samp_format)
72 if (out_coefficient == 0) {
73 setup_standard_crossfades (rate);
76 xfade_buf = new Sample[xfade_frames];
78 _capture_start = false;
83 DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate)
84 : FileSource (node, rate)
86 if (out_coefficient == 0) {
87 setup_standard_crossfades (rate);
90 xfade_buf = new Sample[xfade_frames];
92 _capture_start = false;
97 DestructiveFileSource::~DestructiveFileSource()
103 DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate)
105 xfade_frames = (jack_nframes_t) floor ((/*Config->get_destructive_crossfade_msecs()*/ 64 / 1000.0) * rate);
107 out_coefficient = new gain_t[xfade_frames];
108 in_coefficient = new gain_t[xfade_frames];
110 for (jack_nframes_t n = 0; n < xfade_frames; ++n) {
112 /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
114 in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */
115 out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */
120 DestructiveFileSource::seek (jack_nframes_t frame)
126 DestructiveFileSource::mark_capture_start (jack_nframes_t pos)
128 _capture_start = true;
129 capture_start_frame = pos;
133 DestructiveFileSource::mark_capture_end()
139 DestructiveFileSource::clear_capture_marks ()
141 _capture_start = false;
142 _capture_end = false;
146 DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf)
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
153 jack_nframes_t file_cnt;
156 fade_position = file_pos;
159 fade_position = file_pos + nofade;
160 fade_data = data + nofade;
163 if (fade_position > _length) {
165 /* read starts beyond end of data, just memset to zero */
169 } else if (fade_position + xfade > _length) {
171 /* read ends beyond end of data, read some, memset the rest */
173 file_cnt = _length - fade_position;
177 /* read is entirely within data */
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));
189 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
195 if (file_cnt != xfade) {
196 jack_nframes_t delta = xfade - file_cnt;
197 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
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;
207 if (xfade == xfade_frames) {
211 /* use the standard xfade curve */
215 /* fade new material in */
217 for (n = 0; n < xfade; ++n) {
218 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
224 /* fade new material out */
226 for (n = 0; n < xfade; ++n) {
227 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
233 /* short xfade, compute custom curve */
235 /* XXX COMPUTE THE CURVE, DAMMIT! */
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]);
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;
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;
260 DestructiveFileSource::write (Sample* data, jack_nframes_t cnt, char * workbuf)
263 LockMonitor lm (_lock, __LINE__, __FILE__);
265 jack_nframes_t old_file_pos;
267 if (_capture_start && _capture_end) {
268 _capture_start = false;
269 _capture_end = false;
271 /* move to the correct location place */
272 file_pos = capture_start_frame;
275 jack_nframes_t subcnt = cnt / 2;
276 jack_nframes_t ofilepos = file_pos;
279 if (crossfade (data, subcnt, 1, workbuf) != subcnt) {
284 Sample * tmpdata = data + subcnt;
287 subcnt = cnt - subcnt;
288 if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) {
292 file_pos = ofilepos; // adjusted below
294 else if (_capture_start) {
295 _capture_start = false;
296 _capture_end = false;
298 /* move to the correct location place */
299 file_pos = capture_start_frame;
301 if (crossfade (data, cnt, 1, workbuf) != cnt) {
305 } else if (_capture_end) {
306 _capture_start = false;
307 _capture_end = false;
309 if (crossfade (data, cnt, 0, workbuf) != cnt) {
313 if (file_write(data, file_pos, cnt, workbuf) != (ssize_t) cnt) {
318 old_file_pos = file_pos;
319 if (file_pos + cnt > _length) {
320 _length = file_pos + cnt;
324 if (_build_peakfiles) {
325 PeakBuildRecord *pbr = 0;
327 if (pending_peak_builds.size()) {
328 pbr = pending_peak_builds.back();
331 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
333 /* the last PBR extended to the start of the current write,
334 so just extend it again.
339 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
342 _peaks_built = false;
346 if (_build_peakfiles) {
347 queue_for_peaks (*this);
354 DestructiveFileSource::last_capture_start_frame () const
356 return capture_start_frame;
360 DestructiveFileSource::get_state ()
362 XMLNode& node = FileSource::get_state ();
363 node.add_property (X_("destructive"), "true");