cliprec: ClipRecProcess IS-A DiskIOProcessor
This commit is contained in:
parent
17e14f090e
commit
59421e1d6d
|
@ -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<typename T> 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<void> 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<Sample>* buf;
|
||||
PBD::RingBufferNPT<Sample>::rw_vector rw_vector;
|
||||
|
||||
/* used only by capture */
|
||||
boost::shared_ptr<AudioFileSource> write_source;
|
||||
|
||||
/* used in the butler thread only */
|
||||
samplecnt_t curr_capture_cnt;
|
||||
|
||||
virtual void resize (samplecnt_t) = 0;
|
||||
};
|
||||
|
||||
typedef std::vector<ChannelInfo*> ChannelList;
|
||||
SerializedRCUManager<ChannelList> channels;
|
||||
|
||||
/* The MIDI stuff */
|
||||
|
||||
MidiRingBuffer<samplepos_t>* _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 */
|
||||
|
|
|
@ -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<ChannelList> 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<Sample>::rw_vector vector;
|
||||
|
||||
vector.buf[0] = 0;
|
||||
vector.buf[1] = 0;
|
||||
|
||||
boost::shared_ptr<ChannelList> 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<MidiBuffer::TimeType> 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<ChannelList> 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<ChannelList> 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 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue