X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fdestructive_filesource.cc;h=2f2e85ed5a088652ad7cd59f3c09de66af79d502;hb=f3e5450492109bb4fab898ae824e30ede28bf7b5;hp=6df6ff06afcc3306b4cf2263d1e7e6e1a1b401d4;hpb=1de6e1a626a8aad8a3fee8ea4508645c3272896d;p=ardour.git diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index 6df6ff06af..2f2e85ed5a 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -55,41 +55,51 @@ typedef off_t off64_t; #include #include +#include #include +#include +#include #include "i18n.h" using namespace std; using namespace ARDOUR; +using namespace PBD; gain_t* DestructiveFileSource::out_coefficient = 0; gain_t* DestructiveFileSource::in_coefficient = 0; -jack_nframes_t DestructiveFileSource::xfade_frames = 64; +nframes_t DestructiveFileSource::xfade_frames = 64; -DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, bool repair_first) - : FileSource (path, rate, repair_first) +DestructiveFileSource::DestructiveFileSource (Session& s, string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, Flag flags) + : SndFileSource (s, path, samp_format, hdr_format, rate, flags) { - if (out_coefficient == 0) { - setup_standard_crossfades (rate); - } + init (); +} - xfade_buf = new Sample[xfade_frames]; - _capture_start = false; - _capture_end = false; +DestructiveFileSource::DestructiveFileSource (Session& s, string path, Flag flags) + : SndFileSource (s, path, flags) +{ + init (); } -DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate) - : FileSource (node, rate) +DestructiveFileSource::DestructiveFileSource (Session& s, const XMLNode& node) + : SndFileSource (s, node) { - if (out_coefficient == 0) { - setup_standard_crossfades (rate); - } + init (); +} +void +DestructiveFileSource::init () +{ xfade_buf = new Sample[xfade_frames]; _capture_start = false; _capture_end = false; + file_pos = 0; + + timeline_position = header_position_offset; + AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &DestructiveFileSource::handle_header_position_change)); } DestructiveFileSource::~DestructiveFileSource() @@ -98,35 +108,37 @@ DestructiveFileSource::~DestructiveFileSource() } void -DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate) +DestructiveFileSource::setup_standard_crossfades (nframes_t rate) { - xfade_frames = (jack_nframes_t) floor ((/*Config->get_destructive_crossfade_msecs()*/ 64 / 1000.0) * rate); - - out_coefficient = new gain_t[xfade_frames]; - in_coefficient = new gain_t[xfade_frames]; + /* This static method is assumed to have been called by the Session + before any DFS's are created. + */ - for (jack_nframes_t n = 0; n < xfade_frames; ++n) { + xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate); - /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */ + if (out_coefficient) { + delete [] out_coefficient; + } - in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */ - out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */ + if (in_coefficient) { + delete [] in_coefficient; } -} -int -DestructiveFileSource::seek (jack_nframes_t frame) -{ -// file_pos = data_offset + (sizeof (Sample) * frame); - cerr << _name << " Seek to " << frame << " = " << data_offset + (sizeof (Sample) * frame) << endl; - return 0; + out_coefficient = new gain_t[xfade_frames]; + in_coefficient = new gain_t[xfade_frames]; + + compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient); } void -DestructiveFileSource::mark_capture_start (jack_nframes_t pos) +DestructiveFileSource::mark_capture_start (nframes_t pos) { - _capture_start = true; - capture_start_frame = pos; + if (pos < timeline_position) { + _capture_start = false; + } else { + _capture_start = true; + capture_start_frame = pos; + } } void @@ -142,50 +154,72 @@ DestructiveFileSource::clear_capture_marks () _capture_end = false; } -jack_nframes_t -DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in) +nframes_t +DestructiveFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in) { - jack_nframes_t xfade = min (xfade_frames, cnt); - jack_nframes_t xfade_bytes = xfade * sizeof (Sample); - jack_nframes_t nofade = cnt - xfade; - jack_nframes_t nofade_bytes = nofade * sizeof (Sample); + nframes_t xfade = min (xfade_frames, cnt); + nframes_t nofade = cnt - xfade; Sample* fade_data = 0; - off_t fade_position = 0; + nframes_t fade_position = 0; // in frames + ssize_t retval; + nframes_t file_cnt; if (fade_in) { fade_position = file_pos; fade_data = data; } else { - fade_position = file_pos + nofade_bytes; + fade_position = file_pos + nofade; fade_data = data + nofade; } - if (::pread64 (fd, (char *) xfade_buf, xfade_bytes, fade_position) != (off64_t) xfade_bytes) { - if (errno == EAGAIN) { - /* no data there, so no xfade */ + if (fade_position > _length) { + + /* read starts beyond end of data, just memset to zero */ + + file_cnt = 0; + + } else if (fade_position + xfade > _length) { + + /* read ends beyond end of data, read some, memset the rest */ + + file_cnt = _length - fade_position; + + } else { + + /* read is entirely within data */ - xfade = 0; - xfade_bytes = 0; - nofade = cnt; - nofade_bytes = nofade * sizeof (Sample); + file_cnt = xfade; + } - } else { - error << string_compose(_("FileSource: \"%1\" bad read (%2: %3)"), _path, errno, strerror (errno)) << endmsg; - return 0; + if (file_cnt) { + + if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) { + if (retval >= 0 && errno == EAGAIN) { + /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you. + * short or no data there */ + memset (xfade_buf, 0, xfade * sizeof(Sample)); + } else { + error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg; + return 0; + } } - } + } + if (file_cnt != xfade) { + nframes_t delta = xfade - file_cnt; + memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta); + } + if (nofade && !fade_in) { - cerr << "write " << nofade_bytes << " of prefade OUT data to " << file_pos << " .. " << file_pos + nofade_bytes << endl; - if (::pwrite64 (fd, (char *) data, nofade_bytes, file_pos) != (off64_t) nofade_bytes) { - error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + if (write_float (data, file_pos, nofade) != nofade) { + error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } } if (xfade == xfade_frames) { - jack_nframes_t n; + nframes_t n; /* use the standard xfade curve */ @@ -209,28 +243,28 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in) } else if (xfade) { + gain_t in[xfade]; + gain_t out[xfade]; + /* short xfade, compute custom curve */ - /* XXX COMPUTE THE CURVE, DAMMIT! */ + compute_equal_power_fades (xfade, in, out); - for (jack_nframes_t n = 0; n < xfade; ++n) { - xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]); + for (nframes_t n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]); } } if (xfade) { - cerr << "write " << xfade_bytes << " of xfade data to " << fade_position << " .. " << fade_position + xfade_bytes << endl; - if (::pwrite64 (fd, (char *) xfade_buf, xfade_bytes, fade_position) != (off64_t) xfade_bytes) { - error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + if (write_float (xfade_buf, fade_position, xfade) != xfade) { + error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } } if (fade_in && nofade) { - cerr << "write " << nofade_bytes << " of postfade IN data to " << file_pos + xfade_bytes << " .. " - << file_pos + xfade_bytes + nofade_bytes << endl; - if (::pwrite64 (fd, (char *) (data + xfade), nofade_bytes, file_pos + xfade_bytes) != (off64_t) nofade_bytes) { - error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) { + error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } } @@ -238,86 +272,153 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in) return cnt; } -jack_nframes_t -DestructiveFileSource::write (Sample* data, jack_nframes_t cnt) +nframes_t +DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt) { - cerr << _name << ": write " << cnt << " to " << file_pos << " start ? " << _capture_start << " end ? " << _capture_end << endl; + nframes_t old_file_pos; - { - LockMonitor lm (_lock, __LINE__, __FILE__); - - int32_t byte_cnt = cnt * sizeof (Sample); - jack_nframes_t oldlen; + if (!writable()) { + return 0; + } - if (_capture_start) { - _capture_start = false; - _capture_end = false; + if (_capture_start && _capture_end) { - /* move to the correct location place */ - file_pos = data_offset + (capture_start_frame * sizeof (Sample)); + /* start and end of capture both occur within the data we are writing, + so do both crossfades. + */ - cerr << "First byte of capture will be at " << file_pos << endl; - - if (crossfade (data, cnt, 1) != cnt) { - return 0; - } + _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = capture_start_frame - timeline_position; + + // split cnt in half + nframes_t subcnt = cnt / 2; + nframes_t ofilepos = file_pos; + + // fade in + if (crossfade (data, subcnt, 1) != subcnt) { + return 0; + } + + file_pos += subcnt; + Sample * tmpdata = data + subcnt; + + // fade out + subcnt = cnt - subcnt; + if (crossfade (tmpdata, subcnt, 0) != subcnt) { + return 0; + } + + file_pos = ofilepos; // adjusted below - } else if (_capture_end) { - _capture_start = false; - _capture_end = false; + } else if (_capture_start) { - if (crossfade (data, cnt, 0) != cnt) { - return 0; - } - } else { - if (::pwrite64 (fd, (char *) data, byte_cnt, file_pos) != (off64_t) byte_cnt) { - error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; - return 0; - } + /* start of capture both occur within the data we are writing, + so do the fade in + */ + + _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = capture_start_frame - timeline_position; + + if (crossfade (data, cnt, 1) != cnt) { + return 0; } + + } else if (_capture_end) { + + /* end of capture both occur within the data we are writing, + so do the fade out + */ - oldlen = _length; - if (file_pos + cnt > _length) { - _length += cnt; + _capture_start = false; + _capture_end = false; + + if (crossfade (data, cnt, 0) != cnt) { + return 0; } - _write_data_count = byte_cnt; - file_pos += byte_cnt; - cerr << "at end of write, file_pos = " << file_pos << endl; + } else { - if (_build_peakfiles) { - PeakBuildRecord *pbr = 0; - - if (pending_peak_builds.size()) { - pbr = pending_peak_builds.back(); - } - - if (pbr && pbr->frame + pbr->cnt == oldlen) { - - /* the last PBR extended to the start of the current write, - so just extend it again. - */ + /* in the middle of recording */ - pbr->cnt += cnt; - } else { - pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt)); - } - - _peaks_built = false; + if (write_float (data, file_pos, cnt) != cnt) { + return 0; } - } + old_file_pos = file_pos; + update_length (file_pos, cnt); + file_pos += cnt; if (_build_peakfiles) { - queue_for_peaks (*this); + PeakBuildRecord *pbr = 0; + + if (pending_peak_builds.size()) { + pbr = pending_peak_builds.back(); + } + + if (pbr && pbr->frame + pbr->cnt == old_file_pos) { + + /* the last PBR extended to the start of the current write, + so just extend it again. + */ + + pbr->cnt += cnt; + } else { + pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt)); + } + + _peaks_built = false; } + if (_build_peakfiles) { + queue_for_peaks (shared_from_this ()); + } + return cnt; } -jack_nframes_t +nframes_t DestructiveFileSource::last_capture_start_frame () const { return capture_start_frame; } + +XMLNode& +DestructiveFileSource::get_state () +{ + XMLNode& node = AudioFileSource::get_state (); + node.add_property (X_("destructive"), "true"); + return node; +} + +void +DestructiveFileSource::handle_header_position_change () +{ + if ( _length != 0 ) { + error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg; + //in the future, pop up a dialog here that allows user to regenerate file with new start offset + } else if (writable()) { + timeline_position = header_position_offset; + set_header_timeline_position (); //this will get flushed if/when the file is recorded to + } +} + +void +DestructiveFileSource::set_timeline_position (nframes_t pos) +{ + //destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes +} + +int +DestructiveFileSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const +{ + // cerr << _name << " read peaks at " << start << " for " << cnt << " tpos = " << timeline_position << endl; + return AudioFileSource::read_peaks (peaks, npeaks, start, cnt, samples_per_unit); +} +