diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index 1d06c4ee49..007f5282d0 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -268,6 +268,18 @@ class DiskStream : public Stateful, public sigc::trackable ~DiskStream(); + enum TransitionType { + CaptureStart = 0, + CaptureEnd + }; + + struct CaptureTransition { + + TransitionType type; + // the start or end file frame pos + jack_nframes_t capture_val; + }; + struct ChannelInfo { Sample *playback_wrap_buffer; @@ -292,10 +304,15 @@ class DiskStream : public Stateful, public sigc::trackable RingBufferNPT::rw_vector playback_vector; RingBufferNPT::rw_vector capture_vector; + + RingBufferNPT * capture_transition_buf; + // the following are used in the butler thread only + jack_nframes_t curr_capture_cnt; }; typedef vector ChannelList; + string _name; ARDOUR::Session& _session; ARDOUR::IO* _io; diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index bce8d5fb42..33beaaadcb 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -77,6 +77,7 @@ DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, _capture_start = false; _capture_end = false; + file_pos = 0; } DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate) @@ -90,6 +91,7 @@ DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_ _capture_start = false; _capture_end = false; + file_pos = 0; } 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 >= 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 */ - - xfade = retval; - nofade = cnt - xfade; + * 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; @@ -244,12 +244,40 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt, char * workbuf) 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_end = false; /* move to the correct location place */ - //file_pos = data_offset + (capture_start_frame * sizeof (Sample)); file_pos = capture_start_frame; cerr << "First frame of capture will be at " << file_pos << endl; diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index a3daaf2ff0..1dc9d74aa4 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -104,10 +104,13 @@ DiskStream::init_channel (ChannelInfo &chan) chan.source = 0; chan.current_capture_buffer = 0; chan.current_playback_buffer = 0; + chan.curr_capture_cnt = 0; chan.playback_buf = new RingBufferNPT (_session.diskstream_buffer_size()); chan.capture_buf = new RingBufferNPT (_session.diskstream_buffer_size()); - + chan.capture_transition_buf = new RingBufferNPT (128); + + /* touch the ringbuffer buffers, which will cause them to be mapped into locked physical RAM if we're running with mlockall(). this doesn't do @@ -115,6 +118,7 @@ DiskStream::init_channel (ChannelInfo &chan) */ 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_transition_buf->buffer(), 0, sizeof (CaptureTransition) * chan.capture_transition_buf->bufsize()); } @@ -196,7 +200,8 @@ DiskStream::destroy_channel (ChannelInfo &chan) delete chan.playback_buf; delete chan.capture_buf; - + delete chan.capture_transition_buf; + chan.playback_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) { - 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) { - (*chan).write_source->mark_capture_start (capture_start_frame); - } + + RingBufferNPT::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) { @@ -1442,6 +1460,7 @@ DiskStream::do_flush (char * workbuf, bool force_flush) uint32_t to_write; int32_t ret = 0; RingBufferNPT::rw_vector vector; + RingBufferNPT::rw_vector transvec; jack_nframes_t total; /* 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]; + if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) { goto out; } + /* if there are 2+ chunks of disk i/o possible for this track, let the caller know so that it can arrange for us to be called again, ASAP. @@ -1482,15 +1503,86 @@ DiskStream::do_flush (char * workbuf, bool force_flush) } 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) { error << string_compose(_("DiskStream %1: cannot write to disk"), _id) << endmsg; return -1; } (*chan).capture_buf->increment_read_ptr (to_write); - - if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames)) { + (*chan).curr_capture_cnt += to_write; + + 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 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(); (*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; - if (_flags & Recordable) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - (*chan).write_source->mark_capture_end (); - } - } - if (capture_captured == 0) { 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::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; ci->start = capture_start_frame; diff --git a/libs/ardour/filesource.cc b/libs/ardour/filesource.cc index 681c8b43a6..5c97cd8dee 100644 --- a/libs/ardour/filesource.cc +++ b/libs/ardour/filesource.cc @@ -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) { - cerr << "FileSource: \"" + cerr << "May be OK - FileSource: \"" << _path << "\" bad 24bit read at frame " << start