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, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags)
70 : SndFileSource (path, samp_format, hdr_format, rate, flags)
72 xfade_buf = new Sample[xfade_frames];
74 _capture_start = false;
79 DestructiveFileSource::DestructiveFileSource (const XMLNode& node)
80 : SndFileSource (node)
82 xfade_buf = new Sample[xfade_frames];
84 _capture_start = false;
89 DestructiveFileSource::~DestructiveFileSource()
95 DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate)
97 /* This static method is assumed to have been called by the Session
98 before any DFS's are created.
101 xfade_frames = (jack_nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
103 if (out_coefficient) {
104 delete [] out_coefficient;
107 if (in_coefficient) {
108 delete [] in_coefficient;
111 out_coefficient = new gain_t[xfade_frames];
112 in_coefficient = new gain_t[xfade_frames];
114 for (jack_nframes_t n = 0; n < xfade_frames; ++n) {
116 /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
118 in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */
119 out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */
124 DestructiveFileSource::mark_capture_start (jack_nframes_t pos)
126 _capture_start = true;
127 capture_start_frame = pos;
131 DestructiveFileSource::mark_capture_end()
137 DestructiveFileSource::clear_capture_marks ()
139 _capture_start = false;
140 _capture_end = false;
144 DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf)
146 jack_nframes_t xfade = min (xfade_frames, cnt);
147 jack_nframes_t nofade = cnt - xfade;
148 Sample* fade_data = 0;
149 jack_nframes_t fade_position = 0; // in frames
151 jack_nframes_t file_cnt;
154 fade_position = file_pos;
157 fade_position = file_pos + nofade;
158 fade_data = data + nofade;
161 if (fade_position > _length) {
163 /* read starts beyond end of data, just memset to zero */
167 } else if (fade_position + xfade > _length) {
169 /* read ends beyond end of data, read some, memset the rest */
171 file_cnt = _length - fade_position;
175 /* read is entirely within data */
181 if ((retval = write_float (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
182 if (retval >= 0 && errno == EAGAIN) {
183 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
184 * short or no data there */
185 memset (xfade_buf, 0, xfade * sizeof(Sample));
187 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
193 if (file_cnt != xfade) {
194 jack_nframes_t delta = xfade - file_cnt;
195 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
198 if (nofade && !fade_in) {
199 if (write_float (data, file_pos, nofade) != nofade) {
200 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
205 if (xfade == xfade_frames) {
209 /* use the standard xfade curve */
213 /* fade new material in */
215 for (n = 0; n < xfade; ++n) {
216 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
222 /* fade new material out */
224 for (n = 0; n < xfade; ++n) {
225 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
231 /* short xfade, compute custom curve */
233 /* XXX COMPUTE THE CURVE, DAMMIT! */
235 for (jack_nframes_t n = 0; n < xfade; ++n) {
236 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
241 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
242 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
247 if (fade_in && nofade) {
248 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
249 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
258 DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t start, jack_nframes_t cnt, char * workbuf)
260 jack_nframes_t old_file_pos;
266 if (_capture_start && _capture_end) {
267 _capture_start = false;
268 _capture_end = false;
270 /* move to the correct location place */
271 file_pos = capture_start_frame;
274 jack_nframes_t subcnt = cnt / 2;
275 jack_nframes_t ofilepos = file_pos;
278 if (crossfade (data, subcnt, 1, workbuf) != subcnt) {
283 Sample * tmpdata = data + subcnt;
286 subcnt = cnt - subcnt;
287 if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) {
291 file_pos = ofilepos; // adjusted below
293 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) {
307 _capture_start = false;
308 _capture_end = false;
310 if (crossfade (data, cnt, 0, workbuf) != cnt) {
316 if (write_float (data, file_pos, cnt) != cnt) {
321 old_file_pos = file_pos;
322 if (file_pos + cnt > _length) {
323 _length = file_pos + cnt;
327 if (_build_peakfiles) {
328 PeakBuildRecord *pbr = 0;
330 if (pending_peak_builds.size()) {
331 pbr = pending_peak_builds.back();
334 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
336 /* the last PBR extended to the start of the current write,
337 so just extend it again.
342 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
345 _peaks_built = false;
348 if (_build_peakfiles) {
349 queue_for_peaks (*this);
356 DestructiveFileSource::last_capture_start_frame () const
358 return capture_start_frame;
362 DestructiveFileSource::get_state ()
364 XMLNode& node = AudioFileSource::get_state ();
365 node.add_property (X_("destructive"), "true");
370 DestructiveFileSource::set_timeline_position (jack_nframes_t pos)
372 /* destructive tracks always start at where our reference frame zero is */
373 timeline_position = 0;