diskstream fixups for destructive track captures. crossfade fixes for destructive sources.

git-svn-id: svn://localhost/trunk/ardour2@336 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Jesse Chappell 2006-02-17 06:19:24 +00:00
parent 9a92c195e3
commit 5c47492d88
4 changed files with 175 additions and 22 deletions

View file

@ -268,6 +268,18 @@ class DiskStream : public Stateful, public sigc::trackable
~DiskStream(); ~DiskStream();
enum TransitionType {
CaptureStart = 0,
CaptureEnd
};
struct CaptureTransition {
TransitionType type;
// the start or end file frame pos
jack_nframes_t capture_val;
};
struct ChannelInfo { struct ChannelInfo {
Sample *playback_wrap_buffer; Sample *playback_wrap_buffer;
@ -292,10 +304,15 @@ class DiskStream : public Stateful, public sigc::trackable
RingBufferNPT<Sample>::rw_vector playback_vector; RingBufferNPT<Sample>::rw_vector playback_vector;
RingBufferNPT<Sample>::rw_vector capture_vector; RingBufferNPT<Sample>::rw_vector capture_vector;
RingBufferNPT<CaptureTransition> * capture_transition_buf;
// the following are used in the butler thread only
jack_nframes_t curr_capture_cnt;
}; };
typedef vector<ChannelInfo> ChannelList; typedef vector<ChannelInfo> ChannelList;
string _name; string _name;
ARDOUR::Session& _session; ARDOUR::Session& _session;
ARDOUR::IO* _io; ARDOUR::IO* _io;

View file

@ -77,6 +77,7 @@ DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate,
_capture_start = false; _capture_start = false;
_capture_end = false; _capture_end = false;
file_pos = 0;
} }
DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate) DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate)
@ -90,6 +91,7 @@ DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_
_capture_start = false; _capture_start = false;
_capture_end = false; _capture_end = false;
file_pos = 0;
} }
DestructiveFileSource::~DestructiveFileSource() DestructiveFileSource::~DestructiveFileSource()
@ -160,10 +162,8 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in,
if ((retval = file_read (xfade_buf, fade_position, xfade, workbuf)) != (ssize_t) xfade) { if ((retval = file_read (xfade_buf, fade_position, xfade, workbuf)) != (ssize_t) xfade) {
if (retval >= 0 && errno == EAGAIN) { if (retval >= 0 && errno == EAGAIN) {
/* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you. /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
/* short or no data there */ * short or no data there */
memset (xfade_buf, 0, xfade * sizeof(Sample));
xfade = retval;
nofade = cnt - xfade;
} else { } else {
error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg; error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
return 0; return 0;
@ -244,12 +244,40 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt, char * workbuf)
jack_nframes_t oldlen; jack_nframes_t oldlen;
if (_capture_start) { if (_capture_start && _capture_end) {
_capture_start = false;
_capture_end = false;
/* move to the correct location place */
file_pos = capture_start_frame;
cerr << "First frame of capture will be at " << file_pos << " and last at: " << file_pos + cnt << endl;
// split cnt in half
jack_nframes_t subcnt = cnt / 2;
jack_nframes_t ofilepos = file_pos;
// fade in
if (crossfade (data, subcnt, 1, workbuf) != subcnt) {
return 0;
}
file_pos += subcnt;
Sample * tmpdata = data + subcnt;
// fade out
subcnt = cnt - subcnt;
if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) {
return 0;
}
file_pos = ofilepos; // adjusted below
}
else if (_capture_start) {
_capture_start = false; _capture_start = false;
_capture_end = false; _capture_end = false;
/* move to the correct location place */ /* move to the correct location place */
//file_pos = data_offset + (capture_start_frame * sizeof (Sample));
file_pos = capture_start_frame; file_pos = capture_start_frame;
cerr << "First frame of capture will be at " << file_pos << endl; cerr << "First frame of capture will be at " << file_pos << endl;

View file

@ -104,9 +104,12 @@ DiskStream::init_channel (ChannelInfo &chan)
chan.source = 0; chan.source = 0;
chan.current_capture_buffer = 0; chan.current_capture_buffer = 0;
chan.current_playback_buffer = 0; chan.current_playback_buffer = 0;
chan.curr_capture_cnt = 0;
chan.playback_buf = new RingBufferNPT<Sample> (_session.diskstream_buffer_size()); chan.playback_buf = new RingBufferNPT<Sample> (_session.diskstream_buffer_size());
chan.capture_buf = new RingBufferNPT<Sample> (_session.diskstream_buffer_size()); chan.capture_buf = new RingBufferNPT<Sample> (_session.diskstream_buffer_size());
chan.capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
/* touch the ringbuffer buffers, which will cause /* touch the ringbuffer buffers, which will cause
them to be mapped into locked physical RAM if them to be mapped into locked physical RAM if
@ -115,6 +118,7 @@ DiskStream::init_channel (ChannelInfo &chan)
*/ */
memset (chan.playback_buf->buffer(), 0, sizeof (Sample) * chan.playback_buf->bufsize()); memset (chan.playback_buf->buffer(), 0, sizeof (Sample) * chan.playback_buf->bufsize());
memset (chan.capture_buf->buffer(), 0, sizeof (Sample) * chan.capture_buf->bufsize()); memset (chan.capture_buf->buffer(), 0, sizeof (Sample) * chan.capture_buf->bufsize());
memset (chan.capture_transition_buf->buffer(), 0, sizeof (CaptureTransition) * chan.capture_transition_buf->bufsize());
} }
@ -196,6 +200,7 @@ DiskStream::destroy_channel (ChannelInfo &chan)
delete chan.playback_buf; delete chan.playback_buf;
delete chan.capture_buf; delete chan.capture_buf;
delete chan.capture_transition_buf;
chan.playback_buf = 0; chan.playback_buf = 0;
chan.capture_buf = 0; chan.capture_buf = 0;
@ -615,10 +620,23 @@ DiskStream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t
} }
if (_flags & Recordable) { if (_flags & Recordable) {
cerr << "START RECORD @ " << capture_start_frame << " = " << capture_start_frame * sizeof (Sample) << endl; cerr << "START RECORD @ " << capture_start_frame << endl;
for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
(*chan).write_source->mark_capture_start (capture_start_frame);
} RingBufferNPT<CaptureTransition>::rw_vector transvec;
(*chan).capture_transition_buf->get_write_vector(&transvec);
if (transvec.len[0] > 0) {
transvec.buf[0]->type = CaptureStart;
transvec.buf[0]->capture_val = capture_start_frame;
(*chan).capture_transition_buf->increment_write_ptr(1);
}
else {
// bad!
cerr << "capture_transition_buf is full on rec start! inconceivable!" << endl;
}
}
} }
} else if (!record_enabled() || !can_record) { } else if (!record_enabled() || !can_record) {
@ -1442,6 +1460,7 @@ DiskStream::do_flush (char * workbuf, bool force_flush)
uint32_t to_write; uint32_t to_write;
int32_t ret = 0; int32_t ret = 0;
RingBufferNPT<Sample>::rw_vector vector; RingBufferNPT<Sample>::rw_vector vector;
RingBufferNPT<CaptureTransition>::rw_vector transvec;
jack_nframes_t total; jack_nframes_t total;
/* important note: this function will write *AT MOST* /* important note: this function will write *AT MOST*
@ -1462,10 +1481,12 @@ DiskStream::do_flush (char * workbuf, bool force_flush)
total = vector.len[0] + vector.len[1]; total = vector.len[0] + vector.len[1];
if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) { if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
goto out; goto out;
} }
/* if there are 2+ chunks of disk i/o possible for /* if there are 2+ chunks of disk i/o possible for
this track, let the caller know so that it can arrange this track, let the caller know so that it can arrange
for us to be called again, ASAP. for us to be called again, ASAP.
@ -1483,14 +1504,85 @@ DiskStream::do_flush (char * workbuf, bool force_flush)
to_write = min (disk_io_chunk_frames, (jack_nframes_t) vector.len[0]); to_write = min (disk_io_chunk_frames, (jack_nframes_t) vector.len[0]);
// check the transition buffer when recording destructive
// important that we get this after the capture buf
if (destructive()) {
(*chan).capture_transition_buf->get_read_vector(&transvec);
size_t transcount = transvec.len[0] + transvec.len[1];
bool have_start = false;
size_t ti;
for (ti=0; ti < transcount; ++ti) {
CaptureTransition & captrans = (ti < transvec.len[0]) ? transvec.buf[0][ti] : transvec.buf[1][ti-transvec.len[0]];
if (captrans.type == CaptureStart) {
// by definition, the first data we got above represents the given capture pos
cerr << "DS " << name() << " got CaptureStart at " << captrans.capture_val << endl;
(*chan).write_source->mark_capture_start (captrans.capture_val);
(*chan).curr_capture_cnt = 0;
have_start = true;
}
else if (captrans.type == CaptureEnd) {
// capture end, the capture_val represents total frames in capture
if (captrans.capture_val <= (*chan).curr_capture_cnt + to_write) {
cerr << "DS " << name() << " got CaptureEnd with " << captrans.capture_val << endl;
// shorten to make the write a perfect fit
uint32_t nto_write = (captrans.capture_val - (*chan).curr_capture_cnt);
if (have_start) {
// starts and ends within same chunk we're processing
cerr << "Starts and ends within same chunk: adjusting to_write from: "
<< to_write << " to: " << nto_write << endl;
}
else {
cerr << "Ends within chunk: adjusting to_write to: "
<< to_write << " to: " << nto_write << endl;
}
if (nto_write < to_write) {
ret = 1; // should we?
}
to_write = nto_write;
(*chan).write_source->mark_capture_end ();
// increment past this transition, but go no further
++ti;
break;
}
else {
// actually ends just beyond this chunk, so force more work
cerr << "DS " << name() << " got CaptureEnd beyond our chunk, cnt of: "
<< captrans.capture_val << " leaving on queue" << endl;
ret = 1;
break;
}
}
}
if (ti > 0) {
(*chan).capture_transition_buf->increment_read_ptr(ti);
}
}
if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write, workbuf) != to_write) { if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write, workbuf) != to_write) {
error << string_compose(_("DiskStream %1: cannot write to disk"), _id) << endmsg; error << string_compose(_("DiskStream %1: cannot write to disk"), _id) << endmsg;
return -1; return -1;
} }
(*chan).capture_buf->increment_read_ptr (to_write); (*chan).capture_buf->increment_read_ptr (to_write);
(*chan).curr_capture_cnt += to_write;
if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames)) { if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames) && !destructive()) {
/* we wrote all of vector.len[0] but it wasn't an entire /* we wrote all of vector.len[0] but it wasn't an entire
disk_io_chunk_frames of data, so arrange for some part disk_io_chunk_frames of data, so arrange for some part
@ -1507,6 +1599,7 @@ DiskStream::do_flush (char * workbuf, bool force_flush)
_write_data_count += (*chan).write_source->write_data_count(); _write_data_count += (*chan).write_source->write_data_count();
(*chan).capture_buf->increment_read_ptr (to_write); (*chan).capture_buf->increment_read_ptr (to_write);
(*chan).curr_capture_cnt += to_write;
} }
} }
@ -1700,16 +1793,31 @@ DiskStream::finish_capture (bool rec_monitors_input)
{ {
was_recording = false; was_recording = false;
if (_flags & Recordable) {
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;
} }
if ((_flags & Recordable) && destructive()) {
cerr << "RECORD END @ " << capture_start_frame + capture_captured << endl;
for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
RingBufferNPT<CaptureTransition>::rw_vector transvec;
(*chan).capture_transition_buf->get_write_vector(&transvec);
if (transvec.len[0] > 0) {
transvec.buf[0]->type = CaptureEnd;
transvec.buf[0]->capture_val = capture_captured;
(*chan).capture_transition_buf->increment_write_ptr(1);
}
else {
// bad!
cerr << "capture_transition_buf is full when stopping record! inconceivable!" << endl;
}
}
}
CaptureInfo* ci = new CaptureInfo; CaptureInfo* ci = new CaptureInfo;
ci->start = capture_start_frame; ci->start = capture_start_frame;

View file

@ -1125,7 +1125,7 @@ FileSource::read_pcm_24 (Sample *dst, jack_nframes_t start, jack_nframes_t cnt,
if ((nread = pread (fd, (char *) workbuf, byte_cnt, data_offset + (start * _sample_size))) != byte_cnt) { if ((nread = pread (fd, (char *) workbuf, byte_cnt, data_offset + (start * _sample_size))) != byte_cnt) {
cerr << "FileSource: \"" cerr << "May be OK - FileSource: \""
<< _path << _path
<< "\" bad 24bit read at frame " << "\" bad 24bit read at frame "
<< start << start