diff --git a/libs/ardour/ardour/cliprec.h b/libs/ardour/ardour/cliprec.h index 9c3ee45e74..83fce5772e 100644 --- a/libs/ardour/ardour/cliprec.h +++ b/libs/ardour/ardour/cliprec.h @@ -28,18 +28,49 @@ namespace ARDOUR { class AudioFileSource; class Session; +class Track; template class MidiRingBuffer; class LIBARDOUR_API ClipRecProcessor : public Processor { public: - ClipRecProcessor (Session&, std::string const & name); + ClipRecProcessor (Session&, Track&, std::string const & name); void run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required); bool can_support_io_configuration (const ChanCount& in, ChanCount& out); private: + Track& _track; + /** 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; }; } /* namespace */ diff --git a/libs/ardour/cliprec.cc b/libs/ardour/cliprec.cc index 9f2089c75b..d19fc94ea9 100644 --- a/libs/ardour/cliprec.cc +++ b/libs/ardour/cliprec.cc @@ -16,12 +16,21 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "pbd/compose.h" +#include "pbd/debug.h" + +#include "ardour/audio_buffer.h" #include "ardour/cliprec.h" +#include "ardour/debug.h" +#include "ardour/midi_track.h" using namespace ARDOUR; +using namespace PBD; -ClipRecProcessor::ClipRecProcessor (Session& s, std::string const & name) +ClipRecProcessor::ClipRecProcessor (Session& s, Track& t, std::string const & name) : Processor (s, name, Temporal::BeatTime) + , _track (t) + , channels (new ChannelList) { } @@ -42,6 +51,85 @@ ClipRecProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& void ClipRecProcessor::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required) { - return; -} + if (!check_active()) { + return; + } + const size_t n_buffers = bufs.count().n_audio(); + boost::shared_ptr c = channels.reader(); + ChannelList::iterator chan; + size_t n; + + if (n_buffers) { + + /* AUDIO */ + + for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) { + + ChannelInfo* chaninfo (*chan); + AudioBuffer& buf (bufs.get_audio (n%n_buffers)); + + chaninfo->buf->get_write_vector (&chaninfo->rw_vector); + + if (nframes <= (samplecnt_t) chaninfo->rw_vector.len[0]) { + + Sample *incoming = buf.data (); + memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * nframes); + + } else { + + samplecnt_t total = chaninfo->rw_vector.len[0] + chaninfo->rw_vector.len[1]; + + if (nframes > total) { + DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 overrun in %2, rec_nframes = %3 total space = %4\n", + DEBUG_THREAD_SELF, name(), nframes, total)); + return; + } + + Sample *incoming = buf.data (); + samplecnt_t first = chaninfo->rw_vector.len[0]; + + memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * first); + memcpy (chaninfo->rw_vector.buf[1], incoming + first, sizeof (Sample) * (nframes - first)); + } + + chaninfo->buf->increment_write_ptr (nframes); + } + } + + /* MIDI */ + + if (_midi_buf) { + + // Pump entire port buffer into the ring buffer (TODO: split cycles?) + MidiBuffer& buf = bufs.get_midi (0); + MidiTrack* mt = dynamic_cast(&_track); + MidiChannelFilter* filter = mt ? &mt->capture_filter() : 0; + + assert (buf.size() == 0 || _midi_buf); + + for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { + Evoral::Event ev (*i, false); + if (ev.time() > nframes) { + break; + } + + bool skip_event = false; + + if (mt) { + /* skip injected immediate/out-of-band events */ + MidiBuffer const& ieb (mt->immediate_event_buffer()); + for (MidiBuffer::const_iterator j = ieb.begin(); j != ieb.end(); ++j) { + if (*j == ev) { + skip_event = true; + } + } + } + + if (!skip_event && (!filter || !filter->filter(ev.buffer(), ev.size()))) { + const samplepos_t event_time = start_sample + ev.time(); + _midi_buf->write (event_time, ev.event_type(), ev.size(), ev.buffer()); + } + } + } +} diff --git a/libs/ardour/wscript b/libs/ardour/wscript index e3428f76ae..ba2e215957 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -58,6 +58,7 @@ libardour_sources = [ 'chan_mapping.cc', 'circular_buffer.cc', 'clip_library.cc', + 'cliprec.cc', 'config_text.cc', 'control_group.cc', 'control_protocol_manager.cc',