cliprec: add processor to tracks, and get MIDITrigger prepared for capture

This commit is contained in:
Paul Davis 2024-09-23 16:14:20 -06:00
parent 86b01a5d2f
commit 052ef18c4a
7 changed files with 156 additions and 69 deletions

View file

@ -51,9 +51,13 @@ class LIBARDOUR_API ClipRecProcessor : public DiskIOProcessor
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);
std::string display_name () const;
float buffer_load () const;
void adjust_buffering ();
void configuration_changed ();
int seek (samplepos_t, bool) { return 0; }
int add_channel_to (std::shared_ptr<ChannelList>, uint32_t how_many) { return 0; }
void arm_from_another_thread (Trigger& slot, samplepos_t, timecnt_t const & expected_duration, uint32_t chans);
void disarm();
@ -61,6 +65,9 @@ class LIBARDOUR_API ClipRecProcessor : public DiskIOProcessor
bool armed() const { return (bool) _arm_info.load(); }
PBD::Signal0<void> ArmedChanged;
int set_state (const XMLNode&, int version);
XMLNode& state () const;
private:
DataType _data_type;
std::atomic<SlotArmInfo*> _arm_info;

View file

@ -72,6 +72,7 @@ namespace ARDOUR {
class Amp;
class BeatBox;
class DelayLine;
class ClipRecProcessor;
class Delivery;
class DiskReader;
class DiskWriter;
@ -627,6 +628,7 @@ protected:
std::shared_ptr<Pannable> _pannable;
std::shared_ptr<DiskReader> _disk_reader;
std::shared_ptr<DiskWriter> _disk_writer;
std::shared_ptr<ClipRecProcessor> _clip_recorder;
#ifdef HAVE_BEATBOX
std::shared_ptr<BeatBox> _beatbox;
#endif

View file

@ -294,9 +294,9 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
timepos_t current_pos() const;
double position_as_fraction() const;
void captured (SlotArmInfo&);
void arm();
void disarm ();
virtual void captured (SlotArmInfo&) {}
virtual void arm() {}
virtual void disarm () {}
Temporal::BBT_Argument compute_start (Temporal::TempoMap::SharedPtr const &, samplepos_t start, samplepos_t end, Temporal::BBT_Offset const & q, samplepos_t& start_samples, bool& will_start);
virtual timepos_t compute_end (Temporal::TempoMap::SharedPtr const &, Temporal::BBT_Time const &, samplepos_t, Temporal::Beats &) = 0;
@ -579,6 +579,10 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
MIDITrigger (uint32_t index, TriggerBox&);
~MIDITrigger ();
void captured (SlotArmInfo&);
void arm();
void disarm ();
template<bool actually_run> pframes_t midi_run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats, pframes_t nframes, pframes_t offset, double bpm, pframes_t& quantize_offset);

View file

@ -43,6 +43,7 @@ ClipRecProcessor::ClipRecProcessor (Session& s, Track& t, std::string const & na
: DiskIOProcessor (s, t,name, DiskIOProcessor::Recordable, tdp)
, _data_type (dt)
{
_display_to_user = false;
}
SlotArmInfo::SlotArmInfo (Trigger& s)
@ -233,3 +234,27 @@ ClipRecProcessor::configuration_changed ()
{
/* nothing to do */
}
XMLNode&
ClipRecProcessor::state () const
{
XMLNode& node (DiskIOProcessor::state ());
node.set_property (X_("type"), X_("cliprec"));
return node;
}
int
ClipRecProcessor::set_state (const XMLNode& node, int version)
{
if (DiskIOProcessor::set_state (node, version)) {
return -1;
}
return 0;
}
std::string
ClipRecProcessor::display_name () const
{
return std::string (_("Cue Recorder"));
}

View file

@ -59,6 +59,7 @@
#include "ardour/buffer.h"
#include "ardour/buffer_set.h"
#include "ardour/capturing_processor.h"
#include "ardour/cliprec.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
#include "ardour/disk_reader.h"
@ -2803,6 +2804,9 @@ Route::set_state (const XMLNode& node, int version)
DiskIOPoint diop;
if (node.get_property (X_("disk-io-point"), diop)) {
if (_clip_recorder) {
_clip_recorder->set_display_to_user (diop == DiskIOCustom);
}
if (_disk_writer) {
_disk_writer->set_display_to_user (diop == DiskIOCustom);
}
@ -3233,6 +3237,9 @@ Route::set_processor_state (const XMLNode& node, int version)
} else if (prop->value() == "diskwriter" && _disk_writer) {
_disk_writer->set_state (**niter, version);
new_order.push_back (_disk_writer);
} else if (prop->value() == "cliprec" && _clip_recorder) {
_clip_recorder->set_state (**niter, version);
new_order.push_back (_clip_recorder);
} else if (prop->value() == "triggerbox") {
if (!_triggerbox) {
_triggerbox.reset (new TriggerBox (_session, _default_type));
@ -5421,7 +5428,7 @@ Route::setup_invisible_processors ()
/* DISK READER & WRITER (for Track objects) */
if (_disk_reader || _disk_writer) {
if (_disk_reader || _disk_writer || _clip_recorder) {
switch (_disk_io_point) {
case DiskIOPreFader:
if (trim != new_processors.end()) {
@ -5469,6 +5476,9 @@ Route::setup_invisible_processors ()
assert (writer_pos == find (new_processors.begin(), new_processors.end(), _disk_writer));
reader_pos = new_processors.insert (++writer_pos, _disk_reader);
}
if (_clip_recorder) {
new_processors.insert (reader_pos, _clip_recorder);
}
}
/* Polarity Invert */
@ -6088,6 +6098,10 @@ Route::set_disk_io_point (DiskIOPoint diop)
display = false;
}
if (_clip_recorder) {
_clip_recorder->set_display_to_user (display);
}
if (_disk_writer) {
_disk_writer->set_display_to_user (display);
}

View file

@ -28,6 +28,7 @@
#include "ardour/audiofilesource.h"
#include "ardour/audioplaylist.h"
#include "ardour/audioregion.h"
#include "ardour/cliprec.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
#include "ardour/disk_reader.h"
@ -89,6 +90,10 @@ Track::~Track ()
if (_disk_writer) {
_disk_writer.reset ();
}
if (_clip_recorder) {
_clip_recorder.reset ();
}
}
int
@ -113,6 +118,9 @@ Track::init ()
_disk_writer->set_block_size (_session.get_block_size ());
_disk_writer->set_owner (this);
_clip_recorder.reset (new ClipRecProcessor (_session, *this, name(), data_type(), *this));
_clip_recorder->set_owner (this);
/* no triggerbox for the auditioner, to avoid visual clutter in
* patchbays and elsewhere (or special-case code in those places)
*/
@ -989,6 +997,12 @@ Track::set_processor_state (XMLNode const& node, int version, XMLProperty const*
new_order.push_back (_disk_writer);
return true;
}
} else if (prop->value() == "cliprec") {
if (_clip_recorder) {
_clip_recorder->set_state (node, version);
new_order.push_back (_clip_recorder);
return true;
}
}
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;

View file

@ -1278,71 +1278,6 @@ AudioTrigger::~AudioTrigger ()
delete _stretcher;
}
void
MIDITrigger::check_edit_swap (timepos_t const & time, bool playing, BufferSet& bufs)
{
RTMidiBufferBeats* pending = pending_rt_midibuffer.load();
if (!pending) {
return;
}
if (playing) {
MidiBuffer& mbuf (bufs.get_midi (0));
MidiStateTracker post_edit_state;
/* Get the new MIDI state at the current time, and resolve any
* differences with the MIDI state held by the triggerbox we're
* in.
*/
/* note: transition_beats is the time of the most recent
* transition (e.g. loop point)
*/
Temporal::Beats p = time.beats() - transition_beats;
/* now determine the state at this time, which we need relative
* to the start of the loop within the data.
*/
pending->track_state (p - loop_start, post_edit_state);
_box.tracker->resolve_diff (post_edit_state, mbuf, time.samples());
}
old_rt_midibuffer = rt_midibuffer.exchange (pending);
if (iter < rt_midibuffer.load()->size()) {
/* shutdown */
}
RTMidiBufferBeats* ort = rt_midibuffer.load ();
first_event_index = std::numeric_limits<uint32_t>::min();
last_event_index = std::numeric_limits<uint32_t>::max();
for (uint32_t n = 0; n < ort->size(); ++n) {
if (first_event_index == std::numeric_limits<uint32_t>::min()) {
if ((*ort)[n].timestamp <= loop_start) {
first_event_index = n;
} else {
break;
}
}
}
for (uint32_t n = 0; n < ort->size(); ++n) {
if (last_event_index == std::numeric_limits<uint32_t>::max()) {
if ((*ort)[n].timestamp >= loop_end) {
last_event_index = n; /* exclusive end */
break;
}
}
}
pending_rt_midibuffer = nullptr;
}
void
AudioTrigger::set_stretch_mode (Trigger::StretchMode sm)
{
@ -2259,6 +2194,89 @@ MIDITrigger::~MIDITrigger ()
{
}
void
MIDITrigger::check_edit_swap (timepos_t const & time, bool playing, BufferSet& bufs)
{
RTMidiBufferBeats* pending = pending_rt_midibuffer.load();
if (!pending) {
return;
}
if (playing) {
MidiBuffer& mbuf (bufs.get_midi (0));
MidiStateTracker post_edit_state;
/* Get the new MIDI state at the current time, and resolve any
* differences with the MIDI state held by the triggerbox we're
* in.
*/
/* note: transition_beats is the time of the most recent
* transition (e.g. loop point)
*/
Temporal::Beats p = time.beats() - transition_beats;
/* now determine the state at this time, which we need relative
* to the start of the loop within the data.
*/
pending->track_state (p - loop_start, post_edit_state);
_box.tracker->resolve_diff (post_edit_state, mbuf, time.samples());
}
old_rt_midibuffer = rt_midibuffer.exchange (pending);
if (iter < rt_midibuffer.load()->size()) {
/* shutdown */
}
RTMidiBufferBeats* ort = rt_midibuffer.load ();
first_event_index = std::numeric_limits<uint32_t>::min();
last_event_index = std::numeric_limits<uint32_t>::max();
for (uint32_t n = 0; n < ort->size(); ++n) {
if (first_event_index == std::numeric_limits<uint32_t>::min()) {
if ((*ort)[n].timestamp <= loop_start) {
first_event_index = n;
} else {
break;
}
}
}
for (uint32_t n = 0; n < ort->size(); ++n) {
if (last_event_index == std::numeric_limits<uint32_t>::max()) {
if ((*ort)[n].timestamp >= loop_end) {
last_event_index = n; /* exclusive end */
break;
}
}
}
pending_rt_midibuffer = nullptr;
}
void
MIDITrigger::arm ()
{
}
void
MIDITrigger::disarm ()
{
}
void
MIDITrigger::captured (SlotArmInfo& ai)
{
RTMidiBufferBeats* rtmb = ai.midi_buf->convert ();
/* Note: the original MIDI buffer in ai is now invalid, all data has
* been moved to rtmb.
*/
}
void
MIDITrigger::set_used_channels (Evoral::SMF::UsedChannels used)
{
@ -2774,6 +2792,9 @@ MIDITrigger::set_region_in_worker_thread (std::shared_ptr<Region> r)
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 loaded midi region, span is %2\n", name(), data_length));
/* This is being used as a kind of shorthand for "everything" which is
pretty stupid
*/
send_property_change (ARDOUR::Properties::name);
return 0;