mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-30 08:53:08 +01:00
a variety of fixes for MIDI clip recording, and extended API to specify capture period
This commit is contained in:
parent
62d47d63a6
commit
bb2812f272
2 changed files with 62 additions and 37 deletions
|
|
@ -297,7 +297,9 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
|||
double position_as_fraction() const;
|
||||
|
||||
virtual void captured (SlotArmInfo&, BufferSet&) {}
|
||||
virtual void arm();
|
||||
void arm (Temporal::BBT_Offset duration = Temporal::BBT_Offset()) {
|
||||
_arm (duration);
|
||||
}
|
||||
virtual void disarm ();
|
||||
bool armed() const { return _armed; }
|
||||
PBD::Signal<void()> ArmChanged;
|
||||
|
|
@ -501,6 +503,8 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
|||
|
||||
bool internal_use_follow_length() const;
|
||||
void send_property_change (PBD::PropertyChange pc);
|
||||
|
||||
virtual void _arm (Temporal::BBT_Offset const &);
|
||||
};
|
||||
|
||||
class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
|
|
@ -612,7 +616,6 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
|||
bool playable() const { return rt_midibuffer.load() || _region; }
|
||||
|
||||
void captured (SlotArmInfo&, BufferSet&);
|
||||
void arm();
|
||||
void disarm ();
|
||||
|
||||
template<bool actually_run> pframes_t midi_run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample,
|
||||
|
|
@ -682,6 +685,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
|||
|
||||
protected:
|
||||
void retrigger ();
|
||||
void _arm (Temporal::BBT_Offset const &);
|
||||
|
||||
private:
|
||||
PBD::ID data_source;
|
||||
|
|
@ -804,10 +808,12 @@ struct CueRecord {
|
|||
typedef PBD::RingBuffer<CueRecord> CueRecords;
|
||||
|
||||
struct SlotArmInfo {
|
||||
SlotArmInfo (Trigger& s);
|
||||
SlotArmInfo ();
|
||||
~SlotArmInfo();
|
||||
|
||||
Trigger& slot;
|
||||
void reset (Trigger&);
|
||||
|
||||
Trigger* slot;
|
||||
Temporal::Beats start_beats;
|
||||
samplepos_t start_samples;
|
||||
Temporal::Beats end_beats;
|
||||
|
|
@ -841,7 +847,7 @@ class LIBARDOUR_API TriggerBox : public Processor, public std::enable_shared_fro
|
|||
PBD::Signal<void()> RecEnableChanged;
|
||||
static PBD::Signal<void()> TriggerRecEnableChanged;
|
||||
|
||||
void arm_from_another_thread (Trigger& slot, samplepos_t, uint32_t chans);
|
||||
void arm_from_another_thread (Trigger& slot, samplepos_t, uint32_t chans, Temporal::BBT_Offset const &);
|
||||
void disarm();
|
||||
void disarm_all();
|
||||
bool armed() const { return (bool) _arm_info.load(); }
|
||||
|
|
@ -1062,6 +1068,7 @@ class LIBARDOUR_API TriggerBox : public Processor, public std::enable_shared_fro
|
|||
|
||||
PBD::ScopedConnection stop_all_connection;
|
||||
std::atomic<SlotArmInfo*> _arm_info;
|
||||
SlotArmInfo _the_arm_info;
|
||||
|
||||
/** A buffer that we use to put newly-arrived MIDI data in for
|
||||
* the GUI to read (so that it can update itself).
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "pbd/unwind.h"
|
||||
|
||||
#include "temporal/tempo.h"
|
||||
#include "temporal/bbt_time.h"
|
||||
|
||||
#include "ardour/amp.h"
|
||||
#include "ardour/async_midi_port.h"
|
||||
|
|
@ -253,7 +254,7 @@ Trigger::Trigger (uint32_t n, TriggerBox& b)
|
|||
, _beatcnt (0.)
|
||||
, _meter (4, 4)
|
||||
, expected_end_sample (0)
|
||||
, _pending ((Trigger*) 0)
|
||||
, _pending (nullptr)
|
||||
, last_property_generation (0)
|
||||
{
|
||||
add_property (_launch_style);
|
||||
|
|
@ -290,7 +291,7 @@ Trigger::request_trigger_delete (Trigger* t)
|
|||
}
|
||||
|
||||
void
|
||||
Trigger::arm ()
|
||||
Trigger::_arm (Temporal::BBT_Offset const & duration)
|
||||
{
|
||||
if (_box.record_enabled() == Recording) {
|
||||
return;
|
||||
|
|
@ -309,7 +310,7 @@ Trigger::arm ()
|
|||
chns = 0;
|
||||
}
|
||||
|
||||
_box.arm_from_another_thread (*this, _box.session().transport_sample(), chns);
|
||||
_box.arm_from_another_thread (*this, _box.session().transport_sample(), chns, duration);
|
||||
_armed = true;
|
||||
ArmChanged(); /* EMIT SIGNAL */
|
||||
TriggerArmChanged (this); /* EMIT SIGNAL */
|
||||
|
|
@ -1945,7 +1946,6 @@ AudioTrigger::captured (SlotArmInfo& ai, BufferSet&)
|
|||
/* Nothing captured */
|
||||
_armed = false;
|
||||
ArmChanged (); /* EMIT SIGNAL */
|
||||
delete &ai;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1977,14 +1977,10 @@ AudioTrigger::captured (SlotArmInfo& ai, BufferSet&)
|
|||
|
||||
/* adopt the previously allocated stretcher, with a ratio of 1.0 (no stretch) */
|
||||
|
||||
delete _stretcher;
|
||||
_stretcher = ai.stretcher;
|
||||
std::swap (_stretcher, ai.stretcher);
|
||||
_stretcher->setMaxProcessSize (rb_blocksize);
|
||||
_stretcher->setTimeRatio (1.0);
|
||||
|
||||
ai.stretcher = nullptr;
|
||||
delete &ai; // XXX delete is not RT-safe
|
||||
|
||||
_box.queue_explict (index());
|
||||
|
||||
TriggerBox::worker->request_build_source (this, timecnt_t (data.length));
|
||||
|
|
@ -2477,7 +2473,7 @@ MIDITrigger::setup_event_indices ()
|
|||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 first index %3 last index %4 of %5\n", _box.order(), index(), first_event_index, last_event_index, rt->size()));
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MIDITrigger::adjust_bounds (Temporal::Beats const & start, Temporal::Beats const & end, Temporal::Beats const & length, bool from_region)
|
||||
{
|
||||
if (!from_region && _region) {
|
||||
|
|
@ -2504,9 +2500,9 @@ MIDITrigger::adjust_bounds (Temporal::Beats const & start, Temporal::Beats const
|
|||
}
|
||||
|
||||
void
|
||||
MIDITrigger::arm ()
|
||||
MIDITrigger::_arm (Temporal::BBT_Offset const & duration)
|
||||
{
|
||||
Trigger::arm ();
|
||||
Trigger::_arm (duration);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2521,16 +2517,14 @@ MIDITrigger::captured (SlotArmInfo& ai, BufferSet& bufs)
|
|||
if (ai.midi_buf->size() == 0) {
|
||||
_armed = false;
|
||||
ArmChanged(); /* EMIT SIGNAL */
|
||||
delete &ai;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: the original MIDI buffer in ai is now invalid, all data has
|
||||
* been moved to rtmb.
|
||||
/* Move ownership of the MIDI buffer from the SlotArmInfo (where it was
|
||||
* captured) to our own rt_midibuffer pointer.
|
||||
*/
|
||||
|
||||
#warning what to do about the old RT midi buffer
|
||||
// old_rt_midibuffer = rt_midibuffer.exchange (ai.midi_buf);
|
||||
ai.midi_buf = rt_midibuffer.exchange (ai.midi_buf);
|
||||
|
||||
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
|
||||
timecnt_t dur = tmap->convert_duration (timecnt_t (ai.captured), timepos_t (ai.start_samples), Temporal::BeatTime);
|
||||
|
|
@ -2540,10 +2534,6 @@ MIDITrigger::captured (SlotArmInfo& ai, BufferSet& bufs)
|
|||
iter = 0;
|
||||
_follow_action0 = FollowAction::Again;
|
||||
|
||||
/* Mark ai.midi_buf as null so that it is not deleted */
|
||||
ai.midi_buf = nullptr;
|
||||
delete &ai;
|
||||
|
||||
/* start playing */
|
||||
_box.queue_explict (index());
|
||||
|
||||
|
|
@ -3543,8 +3533,8 @@ Trigger::make_property_quarks ()
|
|||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for queued = %1\n", Properties::queued.property_id));
|
||||
}
|
||||
|
||||
SlotArmInfo::SlotArmInfo (Trigger& s)
|
||||
: slot (s)
|
||||
SlotArmInfo::SlotArmInfo ()
|
||||
: slot (nullptr)
|
||||
, start_samples (0)
|
||||
, end_samples (0)
|
||||
, captured (0)
|
||||
|
|
@ -3559,6 +3549,22 @@ SlotArmInfo::~SlotArmInfo()
|
|||
delete stretcher;
|
||||
}
|
||||
|
||||
void
|
||||
SlotArmInfo::reset (Trigger& s)
|
||||
{
|
||||
slot = &s;
|
||||
delete midi_buf;
|
||||
midi_buf = nullptr;
|
||||
delete stretcher;
|
||||
stretcher = nullptr;
|
||||
start_samples = 0;
|
||||
end_samples = 0;
|
||||
start_beats = Temporal::Beats();
|
||||
end_beats = Temporal::Beats();
|
||||
captured = 0;
|
||||
}
|
||||
|
||||
|
||||
Temporal::BBT_Offset TriggerBox::_assumed_trigger_duration (4, 0, 0);
|
||||
TriggerBox::TriggerMidiMapMode TriggerBox::_midi_map_mode (TriggerBox::Custom);
|
||||
int TriggerBox::_first_midi_note = 60;
|
||||
|
|
@ -3652,11 +3658,17 @@ TriggerBox::TriggerBox (Session& s, DataType dt)
|
|||
}
|
||||
|
||||
void
|
||||
TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t chans)
|
||||
TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t chans, Temporal::BBT_Offset const & duration)
|
||||
{
|
||||
using namespace Temporal;
|
||||
|
||||
SlotArmInfo* ai = new SlotArmInfo (slot);
|
||||
SlotArmInfo* ai = &_the_arm_info;
|
||||
|
||||
/* Delete any dangling RTMidiBuffer and Stretcher from previous capture
|
||||
* passes
|
||||
*/
|
||||
|
||||
ai->reset (slot);
|
||||
|
||||
if (_data_type == DataType::MIDI) {
|
||||
ai->midi_buf = new RTMidiBufferBeats;
|
||||
|
|
@ -3682,7 +3694,12 @@ TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t ch
|
|||
ai->start_samples = t_samples;
|
||||
ai->start_beats = t_beats;
|
||||
|
||||
// std::cerr << "Will start at " << t_beats.str() << std::endl;
|
||||
if (!duration) {
|
||||
timepos_t sb (ai->start_beats);
|
||||
sb += duration;
|
||||
ai->end_beats = sb.beats ();
|
||||
ai->end_samples = timepos_t (ai->end_beats).samples();
|
||||
}
|
||||
|
||||
ai->captured = 0;
|
||||
|
||||
|
|
@ -3692,7 +3709,6 @@ TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t ch
|
|||
void
|
||||
TriggerBox::disarm ()
|
||||
{
|
||||
delete _arm_info;
|
||||
_arm_info = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -3713,7 +3729,7 @@ TriggerBox::finish_recording (BufferSet& bufs)
|
|||
/* This transfers responsibility for the SlotArmInfo object to the
|
||||
trigger
|
||||
*/
|
||||
ai->slot.captured (*ai, bufs);
|
||||
ai->slot->captured (*ai, bufs);
|
||||
_arm_info = nullptr;
|
||||
_record_state = Enabled;
|
||||
}
|
||||
|
|
@ -3732,8 +3748,8 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_
|
|||
pframes_t offset = 0;
|
||||
bool reached_end = false;
|
||||
|
||||
if (!ai->slot.armed()) {
|
||||
/* since _arm_info is set, we have been capturing for a lot,
|
||||
if (!ai->slot->armed()) {
|
||||
/* since _arm_info is set, we have been capturing for a slot,
|
||||
but now the slot is no longer armed.
|
||||
*/
|
||||
if (!ai->end_samples) {
|
||||
|
|
@ -3751,8 +3767,8 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_
|
|||
TempoMap::SharedPtr tmap (TempoMap::use());
|
||||
Beats now_beats = tmap->quarters_at (timepos_t (start_sample));
|
||||
|
||||
ai->slot.compute_quantized_transition (start_sample, now_beats, std::numeric_limits<Beats>::max(),
|
||||
t_bbt, t_beats, t_samples, tmap, ai->slot.quantization());
|
||||
ai->slot->compute_quantized_transition (start_sample, now_beats, std::numeric_limits<Beats>::max(),
|
||||
t_bbt, t_beats, t_samples, tmap, ai->slot->quantization());
|
||||
ai->end_samples = t_samples;
|
||||
ai->end_beats = t_beats;
|
||||
|
||||
|
|
@ -3769,6 +3785,8 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_
|
|||
return;
|
||||
}
|
||||
|
||||
std::cerr << "Ok, maybe here we go ...\n";
|
||||
|
||||
if (ai->end_samples != 0 && (start_sample > ai->end_samples)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue