mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-05 13:15:44 +01:00
cliprec: add processor to tracks, and get MIDITrigger prepared for capture
This commit is contained in:
parent
86b01a5d2f
commit
052ef18c4a
7 changed files with 156 additions and 69 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue