work to make destructive recording actually do something vaguely close to correct
git-svn-id: svn://localhost/trunk/ardour2@305 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
60dc0ef48f
commit
1de6e1a626
@ -36,7 +36,8 @@ class DestructiveFileSource : public FileSource {
|
|||||||
~DestructiveFileSource ();
|
~DestructiveFileSource ();
|
||||||
|
|
||||||
int seek (jack_nframes_t frame);
|
int seek (jack_nframes_t frame);
|
||||||
void mark_capture_start ();
|
jack_nframes_t last_capture_start_frame() const;
|
||||||
|
void mark_capture_start (jack_nframes_t);
|
||||||
void mark_capture_end ();
|
void mark_capture_end ();
|
||||||
void clear_capture_marks();
|
void clear_capture_marks();
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ class DestructiveFileSource : public FileSource {
|
|||||||
|
|
||||||
bool _capture_start;
|
bool _capture_start;
|
||||||
bool _capture_end;
|
bool _capture_end;
|
||||||
|
jack_nframes_t capture_start_frame;
|
||||||
jack_nframes_t file_pos;
|
jack_nframes_t file_pos;
|
||||||
Sample* xfade_buf;
|
Sample* xfade_buf;
|
||||||
|
|
||||||
|
@ -56,6 +56,12 @@ class FileSource : public Source {
|
|||||||
string old_peak_path(string audio_path);
|
string old_peak_path(string audio_path);
|
||||||
string path() const { return _path; }
|
string path() const { return _path; }
|
||||||
|
|
||||||
|
virtual int seek (jack_nframes_t frame) {return 0; }
|
||||||
|
virtual jack_nframes_t last_capture_start_frame() const { return 0; }
|
||||||
|
virtual void mark_capture_start (jack_nframes_t) {}
|
||||||
|
virtual void mark_capture_end () {}
|
||||||
|
virtual void clear_capture_marks() {}
|
||||||
|
|
||||||
int update_header (jack_nframes_t when, struct tm&, time_t);
|
int update_header (jack_nframes_t when, struct tm&, time_t);
|
||||||
|
|
||||||
int move_to_trash (const string trash_dir_name);
|
int move_to_trash (const string trash_dir_name);
|
||||||
|
@ -52,6 +52,7 @@ typedef off_t off64_t;
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <pbd/error.h>
|
#include <pbd/error.h>
|
||||||
#include <ardour/destructive_filesource.h>
|
#include <ardour/destructive_filesource.h>
|
||||||
@ -108,22 +109,24 @@ DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate)
|
|||||||
|
|
||||||
/* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
|
/* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
|
||||||
|
|
||||||
out_coefficient[n] = n/(gain_t) xfade_frames;
|
in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */
|
||||||
in_coefficient[n] = 1.0 - out_coefficient[n];
|
out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
DestructiveFileSource::seek (jack_nframes_t frame)
|
DestructiveFileSource::seek (jack_nframes_t frame)
|
||||||
{
|
{
|
||||||
file_pos = data_offset + (sizeof (Sample) * frame);
|
// file_pos = data_offset + (sizeof (Sample) * frame);
|
||||||
|
cerr << _name << " Seek to " << frame << " = " << data_offset + (sizeof (Sample) * frame) << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DestructiveFileSource::mark_capture_start ()
|
DestructiveFileSource::mark_capture_start (jack_nframes_t pos)
|
||||||
{
|
{
|
||||||
_capture_start = true;
|
_capture_start = true;
|
||||||
|
capture_start_frame = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -140,67 +143,97 @@ DestructiveFileSource::clear_capture_marks ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
jack_nframes_t
|
jack_nframes_t
|
||||||
DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int dir)
|
DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in)
|
||||||
{
|
{
|
||||||
jack_nframes_t xfade = min (xfade_frames, cnt);
|
jack_nframes_t xfade = min (xfade_frames, cnt);
|
||||||
jack_nframes_t xfade_bytes = xfade * sizeof (Sample);
|
jack_nframes_t xfade_bytes = xfade * sizeof (Sample);
|
||||||
|
jack_nframes_t nofade = cnt - xfade;
|
||||||
|
jack_nframes_t nofade_bytes = nofade * sizeof (Sample);
|
||||||
|
Sample* fade_data = 0;
|
||||||
|
off_t fade_position = 0;
|
||||||
|
|
||||||
if (::pread64 (fd, (char *) xfade_buf, xfade_bytes, file_pos) != (off64_t) xfade_bytes) {
|
if (fade_in) {
|
||||||
error << string_compose(_("FileSource: \"%1\" bad read (%2)"), _path, strerror (errno)) << endmsg;
|
fade_position = file_pos;
|
||||||
return 0;
|
fade_data = data;
|
||||||
}
|
|
||||||
|
|
||||||
if (xfade == xfade_frames) {
|
|
||||||
|
|
||||||
/* use the standard xfade curve */
|
|
||||||
|
|
||||||
if (dir) {
|
|
||||||
|
|
||||||
/* fade new material in */
|
|
||||||
|
|
||||||
for (jack_nframes_t n = 0; n < xfade; ++n) {
|
|
||||||
xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (data[n] * in_coefficient[n]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* fade new material out */
|
|
||||||
|
|
||||||
|
|
||||||
for (jack_nframes_t n = 0; n < xfade; ++n) {
|
|
||||||
xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (data[n] * out_coefficient[n]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
fade_position = file_pos + nofade_bytes;
|
||||||
|
fade_data = data + nofade;
|
||||||
|
}
|
||||||
|
|
||||||
/* short xfade, compute custom curve */
|
if (::pread64 (fd, (char *) xfade_buf, xfade_bytes, fade_position) != (off64_t) xfade_bytes) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
/* no data there, so no xfade */
|
||||||
|
|
||||||
for (jack_nframes_t n = 0; n < xfade; ++n) {
|
xfade = 0;
|
||||||
xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (data[n] * in_coefficient[n]);
|
xfade_bytes = 0;
|
||||||
|
nofade = cnt;
|
||||||
|
nofade_bytes = nofade * sizeof (Sample);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
error << string_compose(_("FileSource: \"%1\" bad read (%2: %3)"), _path, errno, strerror (errno)) << endmsg;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::pwrite64 (fd, (char *) xfade_buf, xfade, file_pos) != (off64_t) xfade_bytes) {
|
if (nofade && !fade_in) {
|
||||||
error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
|
cerr << "write " << nofade_bytes << " of prefade OUT data to " << file_pos << " .. " << file_pos + nofade_bytes << endl;
|
||||||
return 0;
|
if (::pwrite64 (fd, (char *) data, nofade_bytes, file_pos) != (off64_t) nofade_bytes) {
|
||||||
}
|
|
||||||
|
|
||||||
/* don't advance file_pos here; if the write fails, we want it left where it was before the overall
|
|
||||||
write, not in the middle of it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (xfade < cnt) {
|
|
||||||
jack_nframes_t remaining = (cnt - xfade);
|
|
||||||
int32_t bytes = remaining * sizeof (Sample);
|
|
||||||
|
|
||||||
if (::pwrite64 (fd, (char *) data + remaining, bytes, file_pos) != (off64_t) bytes) {
|
|
||||||
error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
|
error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file_pos += cnt;
|
if (xfade == xfade_frames) {
|
||||||
|
|
||||||
|
jack_nframes_t n;
|
||||||
|
|
||||||
|
/* use the standard xfade curve */
|
||||||
|
|
||||||
|
if (fade_in) {
|
||||||
|
|
||||||
|
/* fade new material in */
|
||||||
|
|
||||||
|
for (n = 0; n < xfade; ++n) {
|
||||||
|
xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
/* fade new material out */
|
||||||
|
|
||||||
|
for (n = 0; n < xfade; ++n) {
|
||||||
|
xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (xfade) {
|
||||||
|
|
||||||
|
/* short xfade, compute custom curve */
|
||||||
|
|
||||||
|
/* XXX COMPUTE THE CURVE, DAMMIT! */
|
||||||
|
|
||||||
|
for (jack_nframes_t n = 0; n < xfade; ++n) {
|
||||||
|
xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[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;
|
||||||
|
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;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
@ -208,6 +241,8 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int dir)
|
|||||||
jack_nframes_t
|
jack_nframes_t
|
||||||
DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
|
DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
|
||||||
{
|
{
|
||||||
|
cerr << _name << ": write " << cnt << " to " << file_pos << " start ? " << _capture_start << " end ? " << _capture_end << endl;
|
||||||
|
|
||||||
{
|
{
|
||||||
LockMonitor lm (_lock, __LINE__, __FILE__);
|
LockMonitor lm (_lock, __LINE__, __FILE__);
|
||||||
|
|
||||||
@ -216,11 +251,21 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
|
|||||||
|
|
||||||
if (_capture_start) {
|
if (_capture_start) {
|
||||||
_capture_start = false;
|
_capture_start = false;
|
||||||
|
_capture_end = false;
|
||||||
|
|
||||||
|
/* move to the correct location place */
|
||||||
|
file_pos = data_offset + (capture_start_frame * sizeof (Sample));
|
||||||
|
|
||||||
|
cerr << "First byte of capture will be at " << file_pos << endl;
|
||||||
|
|
||||||
if (crossfade (data, cnt, 1) != cnt) {
|
if (crossfade (data, cnt, 1) != cnt) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (_capture_end) {
|
} else if (_capture_end) {
|
||||||
|
_capture_start = false;
|
||||||
_capture_end = false;
|
_capture_end = false;
|
||||||
|
|
||||||
if (crossfade (data, cnt, 0) != cnt) {
|
if (crossfade (data, cnt, 0) != cnt) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -231,13 +276,15 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldlen = file_pos;
|
oldlen = _length;
|
||||||
if (file_pos + cnt > _length) {
|
if (file_pos + cnt > _length) {
|
||||||
_length += cnt;
|
_length += cnt;
|
||||||
}
|
}
|
||||||
_write_data_count = byte_cnt;
|
_write_data_count = byte_cnt;
|
||||||
file_pos += byte_cnt;
|
file_pos += byte_cnt;
|
||||||
|
|
||||||
|
cerr << "at end of write, file_pos = " << file_pos << endl;
|
||||||
|
|
||||||
if (_build_peakfiles) {
|
if (_build_peakfiles) {
|
||||||
PeakBuildRecord *pbr = 0;
|
PeakBuildRecord *pbr = 0;
|
||||||
|
|
||||||
@ -269,3 +316,8 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jack_nframes_t
|
||||||
|
DestructiveFileSource::last_capture_start_frame () const
|
||||||
|
{
|
||||||
|
return capture_start_frame;
|
||||||
|
}
|
||||||
|
@ -614,6 +614,13 @@ DiskStream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_flags & Recordable) {
|
||||||
|
cerr << "START RECORD @ " << capture_start_frame << " = " << capture_start_frame * sizeof (Sample) << endl;
|
||||||
|
for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
|
||||||
|
(*chan).write_source->mark_capture_start (capture_start_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (!record_enabled() || !can_record) {
|
} else if (!record_enabled() || !can_record) {
|
||||||
|
|
||||||
/* stop recording */
|
/* stop recording */
|
||||||
@ -1060,11 +1067,8 @@ DiskStream::seek (jack_nframes_t frame, bool complete_refill)
|
|||||||
for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
|
for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
|
||||||
(*chan).playback_buf->reset ();
|
(*chan).playback_buf->reset ();
|
||||||
(*chan).capture_buf->reset ();
|
(*chan).capture_buf->reset ();
|
||||||
if (destructive()) {
|
if ((*chan).write_source) {
|
||||||
DestructiveFileSource* dfs = dynamic_cast<DestructiveFileSource*> ((*chan).write_source);
|
(*chan).write_source->seek (frame);
|
||||||
if (dfs) {
|
|
||||||
dfs->seek (frame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1616,7 +1620,7 @@ DiskStream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
region = new AudioRegion (srcs, 0, total_capture,
|
region = new AudioRegion (srcs, channels[0].write_source->last_capture_start_frame(), total_capture,
|
||||||
region_name_from_path (channels[0].write_source->name()),
|
region_name_from_path (channels[0].write_source->name()),
|
||||||
0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile));
|
0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile));
|
||||||
|
|
||||||
@ -1635,7 +1639,7 @@ DiskStream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture
|
|||||||
_session.add_undo (_playlist->get_memento());
|
_session.add_undo (_playlist->get_memento());
|
||||||
_playlist->freeze ();
|
_playlist->freeze ();
|
||||||
|
|
||||||
for (buffer_position = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
|
for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
|
||||||
|
|
||||||
string region_name;
|
string region_name;
|
||||||
_session.region_name (region_name, _name, false);
|
_session.region_name (region_name, _name, false);
|
||||||
@ -1683,6 +1687,13 @@ DiskStream::finish_capture (bool rec_monitors_input)
|
|||||||
{
|
{
|
||||||
was_recording = false;
|
was_recording = false;
|
||||||
|
|
||||||
|
if (_flags & Recordable) {
|
||||||
|
cerr << "STOP CAPTURE\n";
|
||||||
|
for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
|
||||||
|
(*chan).write_source->mark_capture_end ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (capture_captured == 0) {
|
if (capture_captured == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1320,6 +1320,10 @@ Session::maybe_enable_record ()
|
|||||||
{
|
{
|
||||||
atomic_set (&_record_status, Enabled);
|
atomic_set (&_record_status, Enabled);
|
||||||
|
|
||||||
|
/* XXX this save should really happen in another thread. its needed so that
|
||||||
|
pending capture state can be recovered if we crash.
|
||||||
|
*/
|
||||||
|
|
||||||
save_state ("", true);
|
save_state ("", true);
|
||||||
|
|
||||||
if (_transport_speed) {
|
if (_transport_speed) {
|
||||||
|
@ -595,7 +595,7 @@ UI::send_request (Request *req)
|
|||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl;
|
// cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl;
|
||||||
rbuf->increment_write_ptr (1);
|
rbuf->increment_write_ptr (1);
|
||||||
write (signal_pipe[1], &c, 1);
|
write (signal_pipe[1], &c, 1);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user