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>
59 #include <ardour/utils.h>
64 using namespace ARDOUR;
67 gain_t* DestructiveFileSource::out_coefficient = 0;
68 gain_t* DestructiveFileSource::in_coefficient = 0;
69 nframes_t DestructiveFileSource::xfade_frames = 64;
71 DestructiveFileSource::DestructiveFileSource (Session& s, string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, Flag flags)
72 : SndFileSource (s, path, samp_format, hdr_format, rate, flags)
78 DestructiveFileSource::DestructiveFileSource (Session& s, string path, Flag flags)
79 : SndFileSource (s, path, flags)
84 DestructiveFileSource::DestructiveFileSource (Session& s, const XMLNode& node)
85 : SndFileSource (s, node)
91 DestructiveFileSource::init ()
93 xfade_buf = new Sample[xfade_frames];
95 _capture_start = false;
99 timeline_position = header_position_offset;
100 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &DestructiveFileSource::handle_header_position_change));
103 DestructiveFileSource::~DestructiveFileSource()
109 DestructiveFileSource::setup_standard_crossfades (nframes_t rate)
111 /* This static method is assumed to have been called by the Session
112 before any DFS's are created.
115 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
117 if (out_coefficient) {
118 delete [] out_coefficient;
121 if (in_coefficient) {
122 delete [] in_coefficient;
125 out_coefficient = new gain_t[xfade_frames];
126 in_coefficient = new gain_t[xfade_frames];
128 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
132 DestructiveFileSource::mark_capture_start (nframes_t pos)
134 if (pos < timeline_position) {
135 _capture_start = false;
137 _capture_start = true;
138 capture_start_frame = pos;
143 DestructiveFileSource::mark_capture_end()
149 DestructiveFileSource::clear_capture_marks ()
151 _capture_start = false;
152 _capture_end = false;
156 DestructiveFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
158 nframes_t xfade = min (xfade_frames, cnt);
159 nframes_t nofade = cnt - xfade;
160 Sample* fade_data = 0;
161 nframes_t fade_position = 0; // in frames
166 fade_position = file_pos;
169 fade_position = file_pos + nofade;
170 fade_data = data + nofade;
173 if (fade_position > _length) {
175 /* read starts beyond end of data, just memset to zero */
179 } else if (fade_position + xfade > _length) {
181 /* read ends beyond end of data, read some, memset the rest */
183 file_cnt = _length - fade_position;
187 /* read is entirely within data */
194 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
195 if (retval >= 0 && errno == EAGAIN) {
196 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
197 * short or no data there */
198 memset (xfade_buf, 0, xfade * sizeof(Sample));
200 error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
206 if (file_cnt != xfade) {
207 nframes_t delta = xfade - file_cnt;
208 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
211 if (nofade && !fade_in) {
212 if (write_float (data, file_pos, nofade) != nofade) {
213 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
218 if (xfade == xfade_frames) {
222 /* use the standard xfade curve */
226 /* fade new material in */
228 for (n = 0; n < xfade; ++n) {
229 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
235 /* fade new material out */
237 for (n = 0; n < xfade; ++n) {
238 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
247 /* short xfade, compute custom curve */
249 compute_equal_power_fades (xfade, in, out);
251 for (nframes_t n = 0; n < xfade; ++n) {
252 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
257 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
258 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
263 if (fade_in && nofade) {
264 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
265 error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
274 DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt)
276 nframes_t old_file_pos;
282 if (_capture_start && _capture_end) {
284 /* start and end of capture both occur within the data we are writing,
285 so do both crossfades.
288 _capture_start = false;
289 _capture_end = false;
291 /* move to the correct location place */
292 file_pos = capture_start_frame;
295 nframes_t subcnt = cnt / 2;
296 nframes_t ofilepos = file_pos;
299 if (crossfade (data, subcnt, 1) != subcnt) {
304 Sample * tmpdata = data + subcnt;
307 subcnt = cnt - subcnt;
308 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
312 file_pos = ofilepos; // adjusted below
314 } else if (_capture_start) {
316 /* start of capture both occur within the data we are writing,
320 _capture_start = false;
321 _capture_end = false;
323 /* move to the correct location place */
324 file_pos = capture_start_frame - timeline_position;
326 if (crossfade (data, cnt, 1) != cnt) {
330 } else if (_capture_end) {
332 /* end of capture both occur within the data we are writing,
336 _capture_start = false;
337 _capture_end = false;
339 if (crossfade (data, cnt, 0) != cnt) {
345 /* in the middle of recording */
348 if (write_float (data, file_pos, cnt) != cnt) {
353 old_file_pos = file_pos;
354 update_length (file_pos, cnt);
357 if (_build_peakfiles) {
358 PeakBuildRecord *pbr = 0;
360 if (pending_peak_builds.size()) {
361 pbr = pending_peak_builds.back();
364 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
366 /* the last PBR extended to the start of the current write,
367 so just extend it again.
372 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
375 _peaks_built = false;
378 if (_build_peakfiles) {
379 queue_for_peaks (this);
386 DestructiveFileSource::last_capture_start_frame () const
388 return capture_start_frame;
392 DestructiveFileSource::get_state ()
394 XMLNode& node = AudioFileSource::get_state ();
395 node.add_property (X_("destructive"), "true");
400 DestructiveFileSource::handle_header_position_change ()
402 if ( _length != 0 ) {
403 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
404 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
405 } else if (writable()) {
406 timeline_position = header_position_offset;
407 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
412 DestructiveFileSource::set_timeline_position (nframes_t pos)
414 //destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes