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;
66 gain_t* DestructiveFileSource::out_coefficient = 0;
67 gain_t* DestructiveFileSource::in_coefficient = 0;
68 jack_nframes_t DestructiveFileSource::xfade_frames = 64;
70 DestructiveFileSource::DestructiveFileSource (string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags)
71 : SndFileSource (path, samp_format, hdr_format, rate, flags)
73 xfade_buf = new Sample[xfade_frames];
75 _capture_start = false;
80 DestructiveFileSource::DestructiveFileSource (const XMLNode& node)
81 : SndFileSource (node)
83 xfade_buf = new Sample[xfade_frames];
85 _capture_start = false;
90 DestructiveFileSource::~DestructiveFileSource()
96 DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate)
98 /* This static method is assumed to have been called by the Session
99 before any DFS's are created.
102 xfade_frames = (jack_nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
104 if (out_coefficient) {
105 delete [] out_coefficient;
108 if (in_coefficient) {
109 delete [] in_coefficient;
112 out_coefficient = new gain_t[xfade_frames];
113 in_coefficient = new gain_t[xfade_frames];
115 for (jack_nframes_t n = 0; n < xfade_frames; ++n) {
117 /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
119 in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */
120 out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */
125 DestructiveFileSource::mark_capture_start (jack_nframes_t pos)
127 _capture_start = true;
128 capture_start_frame = pos;
132 DestructiveFileSource::mark_capture_end()
138 DestructiveFileSource::clear_capture_marks ()
140 _capture_start = false;
141 _capture_end = false;
145 DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf)
147 jack_nframes_t xfade = min (xfade_frames, cnt);
148 jack_nframes_t nofade = cnt - xfade;
149 Sample* fade_data = 0;
150 jack_nframes_t fade_position = 0; // in frames
152 jack_nframes_t file_cnt;
155 fade_position = file_pos;
158 fade_position = file_pos + nofade;
159 fade_data = data + nofade;
162 if (fade_position > _length) {
164 /* read starts beyond end of data, just memset to zero */
168 } else if (fade_position + xfade > _length) {
170 /* read ends beyond end of data, read some, memset the rest */
172 file_cnt = _length - fade_position;
176 /* read is entirely within data */
182 if ((retval = write_float (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
183 if (retval >= 0 && errno == EAGAIN) {
184 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
185 * short or no data there */
186 memset (xfade_buf, 0, xfade * sizeof(Sample));
188 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
194 if (file_cnt != xfade) {
195 jack_nframes_t delta = xfade - file_cnt;
196 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
199 if (nofade && !fade_in) {
200 if (write_float (data, file_pos, nofade) != nofade) {
201 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
206 if (xfade == xfade_frames) {
210 /* use the standard xfade curve */
214 /* fade new material in */
216 for (n = 0; n < xfade; ++n) {
217 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
223 /* fade new material out */
225 for (n = 0; n < xfade; ++n) {
226 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
232 /* short xfade, compute custom curve */
234 /* XXX COMPUTE THE CURVE, DAMMIT! */
236 for (jack_nframes_t n = 0; n < xfade; ++n) {
237 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
242 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
243 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
248 if (fade_in && nofade) {
249 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
250 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
259 DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * workbuf)
261 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) {
296 _capture_start = false;
297 _capture_end = false;
299 /* move to the correct location place */
300 file_pos = capture_start_frame;
302 if (crossfade (data, cnt, 1, workbuf) != cnt) {
306 } else if (_capture_end) {
308 _capture_start = false;
309 _capture_end = false;
311 if (crossfade (data, cnt, 0, workbuf) != cnt) {
317 if (write_float (data, file_pos, cnt) != cnt) {
322 old_file_pos = file_pos;
323 update_length (file_pos, cnt);
326 if (_build_peakfiles) {
327 PeakBuildRecord *pbr = 0;
329 if (pending_peak_builds.size()) {
330 pbr = pending_peak_builds.back();
333 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
335 /* the last PBR extended to the start of the current write,
336 so just extend it again.
341 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
344 _peaks_built = false;
347 if (_build_peakfiles) {
348 queue_for_peaks (*this);
355 DestructiveFileSource::last_capture_start_frame () const
357 return capture_start_frame;
361 DestructiveFileSource::get_state ()
363 XMLNode& node = AudioFileSource::get_state ();
364 node.add_property (X_("destructive"), "true");
369 DestructiveFileSource::set_timeline_position (jack_nframes_t pos)
371 /* destructive tracks always start at where our reference frame zero is */
372 timeline_position = 0;