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_xfade_msecs () / 1000.0) * rate);
107 if (out_coefficient) {
108 delete [] out_coefficient;
111 if (in_coefficient) {
112 delete [] in_coefficient;
115 out_coefficient = new gain_t[xfade_frames];
116 in_coefficient = new gain_t[xfade_frames];
118 for (jack_nframes_t n = 0; n < xfade_frames; ++n) {
120 /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
122 in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */
123 out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */
128 DestructiveFileSource::seek (jack_nframes_t frame)
134 DestructiveFileSource::mark_capture_start (jack_nframes_t pos)
136 _capture_start = true;
137 capture_start_frame = pos;
141 DestructiveFileSource::mark_capture_end()
147 DestructiveFileSource::clear_capture_marks ()
149 _capture_start = false;
150 _capture_end = false;
154 DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf)
156 jack_nframes_t xfade = min (xfade_frames, cnt);
157 jack_nframes_t nofade = cnt - xfade;
158 Sample* fade_data = 0;
159 jack_nframes_t fade_position = 0; // in frames
161 jack_nframes_t file_cnt;
164 fade_position = file_pos;
167 fade_position = file_pos + nofade;
168 fade_data = data + nofade;
171 if (fade_position > _length) {
173 /* read starts beyond end of data, just memset to zero */
177 } else if (fade_position + xfade > _length) {
179 /* read ends beyond end of data, read some, memset the rest */
181 file_cnt = _length - fade_position;
185 /* read is entirely within data */
191 if ((retval = file_read (xfade_buf, fade_position, file_cnt, workbuf)) != (ssize_t) file_cnt) {
192 if (retval >= 0 && errno == EAGAIN) {
193 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
194 * short or no data there */
195 memset (xfade_buf, 0, xfade * sizeof(Sample));
197 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
203 if (file_cnt != xfade) {
204 jack_nframes_t delta = xfade - file_cnt;
205 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
208 if (nofade && !fade_in) {
209 if (file_write (data, file_pos, nofade, workbuf) != (ssize_t) nofade) {
210 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
215 if (xfade == xfade_frames) {
219 /* use the standard xfade curve */
223 /* fade new material in */
225 for (n = 0; n < xfade; ++n) {
226 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
232 /* fade new material out */
234 for (n = 0; n < xfade; ++n) {
235 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
241 /* short xfade, compute custom curve */
243 /* XXX COMPUTE THE CURVE, DAMMIT! */
245 for (jack_nframes_t n = 0; n < xfade; ++n) {
246 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
251 if (file_write (xfade_buf, fade_position, xfade, workbuf) != (ssize_t) xfade) {
252 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
257 if (fade_in && nofade) {
258 if (file_write (data + xfade, file_pos + xfade, nofade, workbuf) != (ssize_t) nofade) {
259 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
268 DestructiveFileSource::write (Sample* data, jack_nframes_t cnt, char * workbuf)
271 Glib::Mutex::Lock lm (_lock);
273 jack_nframes_t old_file_pos;
275 if (_capture_start && _capture_end) {
276 _capture_start = false;
277 _capture_end = false;
279 /* move to the correct location place */
280 file_pos = capture_start_frame;
283 jack_nframes_t subcnt = cnt / 2;
284 jack_nframes_t ofilepos = file_pos;
287 if (crossfade (data, subcnt, 1, workbuf) != subcnt) {
292 Sample * tmpdata = data + subcnt;
295 subcnt = cnt - subcnt;
296 if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) {
300 file_pos = ofilepos; // adjusted below
302 else if (_capture_start) {
303 _capture_start = false;
304 _capture_end = false;
306 /* move to the correct location place */
307 file_pos = capture_start_frame;
309 if (crossfade (data, cnt, 1, workbuf) != cnt) {
313 } else if (_capture_end) {
314 _capture_start = false;
315 _capture_end = false;
317 if (crossfade (data, cnt, 0, workbuf) != cnt) {
321 if (file_write(data, file_pos, cnt, workbuf) != (ssize_t) cnt) {
326 old_file_pos = file_pos;
327 if (file_pos + cnt > _length) {
328 _length = file_pos + cnt;
332 if (_build_peakfiles) {
333 PeakBuildRecord *pbr = 0;
335 if (pending_peak_builds.size()) {
336 pbr = pending_peak_builds.back();
339 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
341 /* the last PBR extended to the start of the current write,
342 so just extend it again.
347 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
350 _peaks_built = false;
354 if (_build_peakfiles) {
355 queue_for_peaks (*this);
362 DestructiveFileSource::last_capture_start_frame () const
364 return capture_start_frame;
368 DestructiveFileSource::get_state ()
370 XMLNode& node = FileSource::get_state ();
371 node.add_property (X_("destructive"), "true");