continued work on getting audio clip bounds editing to work
This commit is contained in:
@@ -436,7 +436,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||
static PBD::Signal<void(PBD::PropertyChange,Trigger*)> TriggerPropertyChange;
|
||||
|
||||
void region_property_change (PBD::PropertyChange const &);
|
||||
virtual void bounds_changed (Temporal::timepos_t const & start, Temporal::timepos_t const & end);
|
||||
virtual void bounds_changed (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & len);
|
||||
|
||||
protected:
|
||||
struct UIRequests {
|
||||
@@ -507,12 +507,11 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||
virtual void _arm (Temporal::BBT_Offset const &);
|
||||
|
||||
struct PendingSwap {
|
||||
Temporal::Beats play_start;
|
||||
Temporal::Beats play_end;
|
||||
Temporal::Beats loop_start;
|
||||
Temporal::Beats loop_end;
|
||||
Temporal::Beats length;
|
||||
|
||||
timepos_t play_start;
|
||||
timepos_t play_end;
|
||||
timepos_t loop_start;
|
||||
timepos_t loop_end;
|
||||
timecnt_t length;
|
||||
|
||||
virtual ~PendingSwap() {}
|
||||
};
|
||||
@@ -520,7 +519,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||
std::atomic<PendingSwap*> pending_swap;
|
||||
std::atomic<PendingSwap*> old_pending_swap;
|
||||
|
||||
virtual void adjust_bounds (Temporal::Beats const & start, Temporal::Beats const & end, Temporal::Beats const & length, bool from_region) = 0;
|
||||
virtual void adjust_bounds (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & length, bool from_region) = 0;
|
||||
};
|
||||
|
||||
class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
@@ -551,6 +550,7 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
void set_end (timepos_t const &);
|
||||
void set_legato_offset (timepos_t const &);
|
||||
void set_length (timecnt_t const &);
|
||||
void set_user_data_length (samplecnt_t);
|
||||
timepos_t start_offset () const; /* offset from start of data */
|
||||
timepos_t current_length() const; /* offset from start of data */
|
||||
timepos_t natural_length() const; /* offset from start of data */
|
||||
@@ -594,15 +594,17 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
|
||||
Sample const * audio_data (size_t n) const;
|
||||
size_t data_length() const { return data.length; }
|
||||
samplecnt_t user_data_length() const { return _user_data_length; }
|
||||
|
||||
void check_edit_swap (timepos_t const &, bool playing, BufferSet&);
|
||||
|
||||
protected:
|
||||
void retrigger ();
|
||||
void adjust_bounds (Temporal::Beats const & start, Temporal::Beats const & end, Temporal::Beats const & length, bool from_region);
|
||||
void adjust_bounds (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & length, bool from_region);
|
||||
|
||||
private:
|
||||
AudioData data;
|
||||
samplecnt_t _user_data_length;
|
||||
RubberBand::RubberBandStretcher* _stretcher;
|
||||
samplepos_t _start_offset;
|
||||
|
||||
@@ -703,7 +705,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
||||
protected:
|
||||
void retrigger ();
|
||||
void _arm (Temporal::BBT_Offset const &);
|
||||
void adjust_bounds (Temporal::Beats const & start, Temporal::Beats const & end, Temporal::Beats const & length, bool from_region);
|
||||
void adjust_bounds (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & length, bool from_region);
|
||||
|
||||
private:
|
||||
PBD::ID data_source;
|
||||
|
||||
@@ -757,11 +757,37 @@ Trigger::set_region_internal (std::shared_ptr<Region> r)
|
||||
void
|
||||
Trigger::region_property_change (PropertyChange const & what_changed)
|
||||
{
|
||||
//std::cerr << "region prop change\n";
|
||||
if (!_region) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (what_changed.contains (Properties::start) || what_changed.contains (Properties::length)) {
|
||||
//std::cerr << "bounds changed\n";
|
||||
//PBD::stacktrace (std::cerr, 23);
|
||||
bounds_changed (_region->start(), _region->end());
|
||||
bounds_changed (_region->start(), _region->end(), _region->length());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::bounds_changed (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & len)
|
||||
{
|
||||
PendingSwap* pending = new PendingSwap;
|
||||
|
||||
pending->play_start = start;
|
||||
pending->play_end = end;
|
||||
pending->loop_start = pending->play_start;
|
||||
pending->loop_end = pending->play_end;
|
||||
pending->length = len;
|
||||
|
||||
/* And set it. RT thread will find this and do what needs to be done */
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 pushed pending swap @ %3 for bounds change\n", _box.order(), index(), pending));
|
||||
pending_swap.store (pending);
|
||||
|
||||
/* Clean up a previous RT midi buffer swap (if there is one) */
|
||||
|
||||
PendingSwap* old = old_pending_swap.exchange (nullptr);
|
||||
|
||||
if (old) {
|
||||
delete old;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1345,31 +1371,6 @@ Trigger::start_and_roll_to (samplepos_t start_pos, samplepos_t end_position, Tri
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::bounds_changed (Temporal::timepos_t const & start, Temporal::timepos_t const & end)
|
||||
{
|
||||
PendingSwap* pending = new PendingSwap;
|
||||
|
||||
pending->play_start = start.beats();
|
||||
pending->play_end = end.beats();
|
||||
pending->loop_start = pending->play_start;
|
||||
pending->loop_end = pending->play_end;
|
||||
pending->length = pending->play_end - pending->play_start;
|
||||
|
||||
/* And set it. RT thread will find this and do what needs to be done */
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 pushed pending swap @ %3 for bounds change\n", _box.order(), index(), pending));
|
||||
pending_swap.store (pending);
|
||||
|
||||
/* Clean up a previous RT midi buffer swap (if there is one) */
|
||||
|
||||
PendingSwap* old = old_pending_swap.exchange (nullptr);
|
||||
|
||||
if (old) {
|
||||
delete old;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------*/
|
||||
|
||||
AudioTrigger::AudioData::~AudioData ()
|
||||
@@ -1607,8 +1608,8 @@ AudioTrigger::compute_end (Temporal::TempoMap::SharedPtr const & tmap, Temporal:
|
||||
/* Our task here is to set:
|
||||
|
||||
expected_end_sample: (TIMELINE!) the sample position where the data for the clip should run out (taking stretch into account)
|
||||
last_readable_sample: the sample in the data where we stop reading
|
||||
final_processed_sample: the sample where the trigger stops and the follow action if any takes effect
|
||||
last_readable_sample: (DATA RELATIVE!) the sample in the data where we stop reading
|
||||
final_processed_sample: (DATA RELATIVE!) the sample where the trigger stops and the follow action if any takes effect
|
||||
|
||||
Things that affect these values:
|
||||
|
||||
@@ -1620,19 +1621,27 @@ AudioTrigger::compute_end (Temporal::TempoMap::SharedPtr const & tmap, Temporal:
|
||||
|
||||
const Temporal::BBT_Argument transition_bba (superclock_t (0), transition_bbt);
|
||||
|
||||
samplepos_t end_by_follow_length = tmap->sample_at (tmap->bbt_walk (transition_bba, _follow_length));
|
||||
samplepos_t end_by_data_length = transition_sample + (data.length - _start_offset);
|
||||
/* this could still blow up if the data is less than 1 tick long, but
|
||||
we should handle that elsewhere.
|
||||
*/
|
||||
const Temporal::Beats bc (Temporal::Beats::from_double (_beatcnt));
|
||||
|
||||
samplepos_t end_by_follow_length = tmap->sample_at (tmap->bbt_walk (transition_bba, _follow_length));
|
||||
samplepos_t end_by_beatcnt = tmap->sample_at (tmap->bbt_walk (transition_bba, Temporal::BBT_Offset (0, bc.get_beats(), bc.get_ticks())));
|
||||
samplepos_t end_by_user_data_length = transition_sample + (_user_data_length - _start_offset);
|
||||
samplepos_t end_by_data_length = transition_sample + (data.length - _start_offset);
|
||||
samplepos_t end_by_fixed_samples = std::min (end_by_user_data_length, end_by_data_length);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 SO %9 @ %2 / %3 / %4 ends: FL %5 (from %6) BC %7 DL %8\n",
|
||||
index(), transition_sample, transition_beats, transition_bbt,
|
||||
end_by_follow_length, _follow_length, end_by_beatcnt, end_by_data_length, _start_offset));
|
||||
|
||||
if (stretching()) {
|
||||
/* NOTES: beatcnt here will reflect the stretch, which is OK
|
||||
Because we are stretching. But .. that's wrong when we're not
|
||||
stretching. So we really need another value: something like
|
||||
data_length but user-definable.
|
||||
*/
|
||||
if (internal_use_follow_length()) {
|
||||
expected_end_sample = std::min (end_by_follow_length, end_by_beatcnt);
|
||||
} else {
|
||||
@@ -1640,24 +1649,20 @@ AudioTrigger::compute_end (Temporal::TempoMap::SharedPtr const & tmap, Temporal:
|
||||
}
|
||||
} else {
|
||||
if (internal_use_follow_length()) {
|
||||
expected_end_sample = std::min (end_by_follow_length, end_by_data_length);
|
||||
expected_end_sample = std::min (end_by_follow_length, end_by_fixed_samples);
|
||||
} else {
|
||||
expected_end_sample = end_by_data_length;
|
||||
expected_end_sample = end_by_fixed_samples;
|
||||
}
|
||||
}
|
||||
|
||||
if (internal_use_follow_length()) {
|
||||
final_processed_sample = end_by_follow_length - transition_sample;
|
||||
} else {
|
||||
final_processed_sample = expected_end_sample - transition_sample;
|
||||
}
|
||||
final_processed_sample = expected_end_sample - transition_sample;
|
||||
|
||||
samplecnt_t usable_length;
|
||||
|
||||
if (internal_use_follow_length() && (end_by_follow_length < end_by_data_length)) {
|
||||
usable_length = end_by_follow_length - transition_samples;
|
||||
} else {
|
||||
usable_length = (data.length - _start_offset);
|
||||
usable_length = std::min ((end_by_beatcnt - transition_samples), (data.length - _start_offset));
|
||||
}
|
||||
|
||||
/* called from compute_end() when we know the time (audio &
|
||||
@@ -1696,7 +1701,14 @@ AudioTrigger::compute_end (Temporal::TempoMap::SharedPtr const & tmap, Temporal:
|
||||
void
|
||||
AudioTrigger::set_length (timecnt_t const & newlen)
|
||||
{
|
||||
/* XXX what? */
|
||||
/* XXX what */
|
||||
}
|
||||
|
||||
void
|
||||
AudioTrigger::set_user_data_length (samplecnt_t s)
|
||||
{
|
||||
_user_data_length = s;
|
||||
send_property_change (ARDOUR::Properties::length);
|
||||
}
|
||||
|
||||
timepos_t
|
||||
@@ -1763,7 +1775,7 @@ AudioTrigger::set_region_in_worker_thread_internal (std::shared_ptr<Region> r, b
|
||||
|
||||
/* given an initial tempo guess, we need to set our operating tempo and beat_cnt value.
|
||||
* this may be reset momentarily with user-settings (UIState) from a d+d operation */
|
||||
set_segment_tempo(_estimated_tempo);
|
||||
set_segment_tempo (_estimated_tempo);
|
||||
|
||||
if (!from_capture) {
|
||||
setup_stretcher ();
|
||||
@@ -1808,11 +1820,9 @@ AudioTrigger::set_region_in_worker_thread_internal (std::shared_ptr<Region> r, b
|
||||
void
|
||||
AudioTrigger::estimate_tempo ()
|
||||
{
|
||||
double beatcount;
|
||||
ARDOUR::estimate_audio_tempo_region (_region, data[0], data.length, _box.session().sample_rate(), _estimated_tempo, _meter, beatcount);
|
||||
ARDOUR::estimate_audio_tempo_region (_region, data[0], data.length, _box.session().sample_rate(), _estimated_tempo, _meter, _beatcnt);
|
||||
/* initialize our follow_length to match the beatcnt ... user can later change this value to have the clip end sooner or later than its data length */
|
||||
set_follow_length(Temporal::BBT_Offset( 0, rint(beatcount), 0));
|
||||
|
||||
set_follow_length (Temporal::BBT_Offset ( 0, floor (_beatcnt), 0));
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1821,8 +1831,8 @@ AudioTrigger::probably_oneshot () const
|
||||
assert (_segment_tempo != 0.);
|
||||
|
||||
if ((data.length < (_box.session().sample_rate()/2)) || //less than 1/2 second
|
||||
(_segment_tempo > 140) || //minibpm thinks this is really fast
|
||||
(_segment_tempo < 60)) { //minibpm thinks this is really slow
|
||||
(_segment_tempo > 140) || //minibpm thinks this is really fast
|
||||
(_segment_tempo < 60)) { //minibpm thinks this is really slow
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1902,6 +1912,7 @@ AudioTrigger::captured (SlotArmInfo& ai)
|
||||
|
||||
data.length = ai.audio_buf.length;
|
||||
data.capacity = ai.audio_buf.capacity;
|
||||
_user_data_length = data.length;
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 captured a total of %3\n", _box.order(), _index, data.length));
|
||||
|
||||
@@ -1958,6 +1969,7 @@ AudioTrigger::load_data (std::shared_ptr<AudioRegion> ar)
|
||||
}
|
||||
|
||||
data.length = len;
|
||||
_user_data_length = len;
|
||||
set_name (ar->name());
|
||||
|
||||
} catch (...) {
|
||||
@@ -2324,21 +2336,19 @@ AudioTrigger::check_edit_swap (timepos_t const & time, bool playing, BufferSet&
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 noticed pending swap @ %3\n", _box.order(), index(), pending));
|
||||
|
||||
adjust_bounds (pending->play_start, pending->play_end, pending->length, true);
|
||||
old_pending_swap.store (pending);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioTrigger::adjust_bounds (Temporal::Beats const & start, Temporal::Beats const & end, Temporal::Beats const & length, bool)
|
||||
AudioTrigger::adjust_bounds (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & length, bool)
|
||||
{
|
||||
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
|
||||
set_start (timepos_t (tmap->sample_at (start)));
|
||||
std::cerr << "Old beatcnt: " << _beatcnt;
|
||||
_beatcnt = Temporal::DoubleableBeats (end - start).to_double();
|
||||
std::cerr << " new " << _beatcnt << std::endl;
|
||||
|
||||
set_start (timepos_t (start.samples()));
|
||||
set_user_data_length (length.samples());
|
||||
/* XXX not 100% sure that we should set this here or not */
|
||||
_beatcnt = Temporal::DoubleableBeats (length.beats()).to_double();
|
||||
}
|
||||
|
||||
/*--------------------*/
|
||||
@@ -2461,29 +2471,29 @@ MIDITrigger::setup_event_indices ()
|
||||
}
|
||||
|
||||
void
|
||||
MIDITrigger::adjust_bounds (Temporal::Beats const & start, Temporal::Beats const & end, Temporal::Beats const & length, bool from_region)
|
||||
MIDITrigger::adjust_bounds (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Temporal::timecnt_t const & length, bool from_region)
|
||||
{
|
||||
if (!from_region && _region) {
|
||||
_region->set_length (timecnt_t (length, timepos_t (start)));
|
||||
}
|
||||
|
||||
_play_start = start;
|
||||
_play_end = end;
|
||||
_play_start = start.beats();
|
||||
_play_end = end.beats();
|
||||
|
||||
/* Note that in theory we may be able to get loop start/end from the
|
||||
* SMF and it could different from the data start/end
|
||||
*/
|
||||
|
||||
_loop_start = start;
|
||||
_loop_end = end;
|
||||
_loop_start = _play_start;
|
||||
_loop_end = _play_end;
|
||||
|
||||
data_length = length;
|
||||
_follow_length = Temporal::BBT_Offset (0, length.get_beats(), 0);
|
||||
data_length = length.beats();
|
||||
_follow_length = Temporal::BBT_Offset (0, data_length.get_beats(), 0);
|
||||
set_length (timecnt_t (length));
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 new bounds %3..%4 %5..%6 len %7 of %7\n", _box.order(), index(), _play_start, _play_end, _loop_start, _loop_end, length, rt_midibuffer.load()->size()));
|
||||
|
||||
setup_event_indices ();
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 new bounds %3..%4 %5..%6 len %7 of %7\n", _box.order(), index(), _play_start, _play_end, _loop_start, _loop_end, length, rt_midibuffer.load()->size()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2516,7 +2526,7 @@ MIDITrigger::captured (SlotArmInfo& ai)
|
||||
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
|
||||
timecnt_t dur = tmap->convert_duration (timecnt_t (ai.captured), timepos_t (ai.start_samples), Temporal::BeatTime);
|
||||
|
||||
adjust_bounds (Temporal::Beats(), dur.beats(), dur.beats(), false);
|
||||
adjust_bounds (timepos_t::zero (Temporal::BeatTime), timepos_t (dur.beats()), dur, false);
|
||||
|
||||
iter = 0;
|
||||
_follow_action0 = FollowAction::Again;
|
||||
|
||||
Reference in New Issue
Block a user