diff --git a/libs/ardour/ardour/cliprec.h b/libs/ardour/ardour/cliprec.h index 965c7fa63f..18632e88d4 100644 --- a/libs/ardour/ardour/cliprec.h +++ b/libs/ardour/ardour/cliprec.h @@ -23,7 +23,7 @@ #include "pbd/ringbufferNPT.h" #include "pbd/signals.h" -#include "ardour/processor.h" +#include "ardour/disk_io.h" namespace PBD { class Thread; @@ -38,7 +38,7 @@ class Track; template class MidiRingBuffer; -class LIBARDOUR_API ClipRecProcessor : public Processor +class LIBARDOUR_API ClipRecProcessor : public DiskIOProcessor { public: ClipRecProcessor (Session&, Track&, std::string const & name); @@ -48,41 +48,14 @@ class LIBARDOUR_API ClipRecProcessor : public Processor bool armed() const { return _armed; } void set_armed (bool yn); PBD::Signal0 ArmedChanged; - + + float buffer_load () const; + void adjust_buffering (); + void configuration_changed (); + private: - Track& _track; bool _armed; - /** Information about one audio channel, playback or capture - * (depending on the derived class) - */ - struct ChannelInfo : public boost::noncopyable { - - ChannelInfo (samplecnt_t buffer_size); - virtual ~ChannelInfo (); - - /** A ringbuffer for data to be recorded back, written to in the - * process thread, read from in the butler thread. - */ - PBD::RingBufferNPT* buf; - PBD::RingBufferNPT::rw_vector rw_vector; - - /* used only by capture */ - boost::shared_ptr write_source; - - /* used in the butler thread only */ - samplecnt_t curr_capture_cnt; - - virtual void resize (samplecnt_t) = 0; - }; - - typedef std::vector ChannelList; - SerializedRCUManager channels; - - /* The MIDI stuff */ - - MidiRingBuffer* _midi_buf; - /* private (to class) butler thread */ static PBD::Thread* _thread; @@ -91,7 +64,9 @@ class LIBARDOUR_API ClipRecProcessor : public Processor static void thread_work (); static ClipRecProcessor* currently_recording; - void pull_data (); + int pull_data (); + void start_recording (); + void finish_recording (); }; } /* namespace */ diff --git a/libs/ardour/cliprec.cc b/libs/ardour/cliprec.cc index 3af81bdacd..043871f2f3 100644 --- a/libs/ardour/cliprec.cc +++ b/libs/ardour/cliprec.cc @@ -22,9 +22,12 @@ #include "pbd/semutils.h" #include "ardour/audio_buffer.h" +#include "ardour/audiofilesource.h" +#include "ardour/butler.h" #include "ardour/cliprec.h" #include "ardour/debug.h" #include "ardour/midi_track.h" +#include "ardour/session.h" #include "pbd/i18n.h" @@ -36,10 +39,8 @@ bool ClipRecProcessor::thread_should_run (false); PBD::Semaphore* ClipRecProcessor::_semaphore (0); ClipRecProcessor::ClipRecProcessor (Session& s, Track& t, std::string const & name) - : Processor (s, name, Temporal::BeatTime) - , _track (t) + : DiskIOProcessor (s, t,name, DiskIOProcessor::Recordable, Temporal::BeatTime) , _armed (false) - , channels (new ChannelList) { if (!_thread) { thread_should_run = true; @@ -52,18 +53,47 @@ void ClipRecProcessor::set_armed (bool yn) { if (_armed == yn) { - assert (currently_recording == this); + if (_armed) { + assert (currently_recording == this); + } return; } - if (yn) { - if (currently_recording) { - currently_recording->set_armed (false); - currently_recording = 0; - } - _armed = true; - currently_recording = this; + if (!yn) { + finish_recording (); + assert (currently_recording == this); + _armed = false; + currently_recording = 0; + ArmedChanged (); // EMIT SIGNAL + return; } + + if (currently_recording) { + currently_recording->set_armed (false); + currently_recording = 0; + } + + _armed = true; + currently_recording = this; + start_recording (); + ArmedChanged (); // EMIT SIGNAL +} + +void +ClipRecProcessor::start_recording () +{ +} + +void +ClipRecProcessor::finish_recording () +{ + boost::shared_ptr c = channels.reader(); + for (auto & chan : *c) { + Source::WriterLock lock((chan)->write_source->mutex()); + (chan)->write_source->mark_streaming_write_completed (lock); + (chan)->write_source->done_with_peakfile_writes (); + } + } void @@ -73,14 +103,101 @@ ClipRecProcessor::thread_work () _semaphore->wait (); ClipRecProcessor* crp = currently_recording; if (crp) { - crp->pull_data (); + (void) crp->pull_data (); } } } -void +int ClipRecProcessor::pull_data () { + uint32_t to_write; + int ret = 0; + RingBufferNPT::rw_vector vector; + + vector.buf[0] = 0; + vector.buf[1] = 0; + + boost::shared_ptr c = channels.reader(); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + + (*chan)->wbuf->get_read_vector (&vector); + + if (vector.len[0] + vector.len[1] == 0) { + goto out; + } + + to_write = vector.len[0]; + + if ((!(*chan)->write_source) || (*chan)->write_source->write (vector.buf[0], to_write) != to_write) { + error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg; + return -1; + } + + (*chan)->wbuf->increment_read_ptr (to_write); + // (*chan)->curr_capture_cnt += to_write; + + to_write = vector.len[1]; + + DEBUG_TRACE (DEBUG::ClipRecording, string_compose ("%1 additional write of %2\n", name(), to_write)); + + if ((*chan)->write_source->write (vector.buf[1], to_write) != to_write) { + error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg; + return -1; + } + + (*chan)->wbuf->increment_read_ptr (to_write); + //(*chan)->curr_capture_cnt += to_write; + } + +#if 0 + /* MIDI*/ + + if (_midi_write_source && _midi_buf) { + + const samplecnt_t total = g_atomic_int_get(&_samples_pending_write); + + if (total == 0 || + _midi_buf->read_space() == 0 || + (!force_flush && (total < _chunk_samples) && _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. + + if we are forcing a flush, then if there is* any* extra + work, let the caller know. + + if we are no longer recording and there is any extra work, + let the caller know too. + */ + + if (total >= 2 * _chunk_samples || ((force_flush || !_was_recording) && total > _chunk_samples)) { + ret = 1; + } + + if (force_flush) { + /* push out everything we have, right now */ + to_write = UINT32_MAX; + } else { + to_write = _chunk_samples; + } + + if ((total > _chunk_samples) || force_flush) { + Source::WriterLock lm(_midi_write_source->mutex()); + if (_midi_write_source->midi_write (lm, *_midi_buf, timepos_t (get_capture_start_sample (0)), timecnt_t (to_write)) != to_write) { + error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg; + return -1; + } + g_atomic_int_add(&_samples_pending_write, -to_write); + } + } +#endif + + out: + return ret; } bool @@ -118,7 +235,7 @@ ClipRecProcessor::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t en ChannelInfo* chaninfo (*chan); AudioBuffer& buf (bufs.get_audio (n%n_buffers)); - chaninfo->buf->get_write_vector (&chaninfo->rw_vector); + chaninfo->wbuf->get_write_vector (&chaninfo->rw_vector); if (nframes <= (samplecnt_t) chaninfo->rw_vector.len[0]) { @@ -142,9 +259,9 @@ ClipRecProcessor::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t en memcpy (chaninfo->rw_vector.buf[1], incoming + first, sizeof (Sample) * (nframes - first)); } - chaninfo->buf->increment_write_ptr (nframes); + chaninfo->wbuf->increment_write_ptr (nframes); - if (chaninfo->buf->read_space() > 10) { + if (chaninfo->wbuf->read_space() > 10) { _semaphore->signal (); } } @@ -163,7 +280,7 @@ ClipRecProcessor::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t en for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { Evoral::Event ev (*i, false); - if (ev.time() > nframes) { + if (ev.time() > nframes) { break; } @@ -186,3 +303,35 @@ ClipRecProcessor::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t en } } } + +float +ClipRecProcessor::buffer_load () const +{ + boost::shared_ptr c = channels.reader(); + + if (c->empty ()) { + return 1.0; + } + + return (float) ((double) c->front()->wbuf->write_space()/ + (double) c->front()->wbuf->bufsize()); +} + +void +ClipRecProcessor::adjust_buffering () +{ + boost::shared_ptr c = channels.reader(); + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + (*chan)->resize (_session.butler()->audio_capture_buffer_size()); + } +} + +void +ClipRecProcessor::configuration_changed () +{ + /* nothing to do */ +} + + +