implement time-stretch from left of region
Make click & drag in the left-hand half of a region with the Timestretch tool stretch the region on its left, leaving the end position of the new time-stretched region in the same place as the end of the original.
This commit is contained in:
parent
96eb7652c9
commit
72850d456f
@ -2251,9 +2251,9 @@ private:
|
||||
|
||||
TimeFXDialog* current_timefx;
|
||||
static void* timefx_thread (void* arg);
|
||||
void do_timefx ();
|
||||
void do_timefx (bool fixed_end);
|
||||
|
||||
int time_stretch (RegionSelection&, Temporal::ratio_t const & fraction);
|
||||
int time_stretch (RegionSelection&, Temporal::ratio_t const & fraction, bool fixed_end);
|
||||
int pitch_shift (RegionSelection&, float cents);
|
||||
void pitch_shift_region ();
|
||||
|
||||
@ -2486,7 +2486,7 @@ private:
|
||||
void set_show_touched_automation (bool);
|
||||
bool _show_touched_automation;
|
||||
|
||||
int time_fx (ARDOUR::RegionList&, Temporal::ratio_t ratio, bool pitching);
|
||||
int time_fx (ARDOUR::RegionList&, Temporal::ratio_t ratio, bool pitching, bool fixed_end);
|
||||
void note_edit_done (int, EditNoteDialog*);
|
||||
void toggle_sound_midi_notes ();
|
||||
|
||||
|
@ -5302,7 +5302,9 @@ TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||
timepos_t where (_primary->region ()->position ());
|
||||
setup_snap_delta (_primary->region ()->position ());
|
||||
|
||||
show_verbose_cursor_duration (where, adjusted_current_time (event), 0);
|
||||
timepos_t clicked_pos = adjusted_current_time (event);
|
||||
show_verbose_cursor_duration (where, clicked_pos, 0);
|
||||
_dragging_start = clicked_pos < _primary->region ()->position () + _primary->region ()->length ().scale(ratio_t(1, 2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -5319,8 +5321,15 @@ TimeFXDrag::motion (GdkEvent* event, bool)
|
||||
_editor->snap_to_with_modifier (pf, event);
|
||||
pf.shift_earlier (snap_delta (event->button.state));
|
||||
|
||||
if (pf > rv->region ()->position ()) {
|
||||
rv->get_time_axis_view ().show_timestretch (rv->region ()->position (), pf, layers, layer);
|
||||
if (_dragging_start) {
|
||||
if (pf < rv->region ()->end ()) {
|
||||
rv->get_time_axis_view ().show_timestretch (pf, rv->region ()->end (), layers, layer);
|
||||
|
||||
}
|
||||
} else {
|
||||
if (pf > rv->region ()->position ()) {
|
||||
rv->get_time_axis_view ().show_timestretch (rv->region ()->position (), pf, layers, layer);
|
||||
}
|
||||
}
|
||||
|
||||
show_verbose_cursor_duration (_primary->region ()->position (), pf);
|
||||
@ -5342,7 +5351,7 @@ TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
if (!movement_occurred) {
|
||||
_primary->get_time_axis_view ().hide_timestretch ();
|
||||
|
||||
if (_editor->time_stretch (_editor->get_selection ().regions, ratio_t (1, 1)) == -1) {
|
||||
if (_editor->time_stretch (_editor->get_selection ().regions, ratio_t (1, 1), false) == -1) {
|
||||
error << _("An error occurred while executing time stretch operation") << endmsg;
|
||||
}
|
||||
return;
|
||||
@ -5355,13 +5364,22 @@ TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
_primary->get_time_axis_view ().hide_timestretch ();
|
||||
|
||||
timepos_t adjusted_pos = adjusted_current_time (event);
|
||||
timecnt_t newlen;
|
||||
|
||||
if (adjusted_pos < _primary->region ()->position ()) {
|
||||
/* backwards drag of the left edge - not usable */
|
||||
return;
|
||||
if (_dragging_start) {
|
||||
if (adjusted_pos > _primary->region ()->end ()) {
|
||||
/* forwards drag of the right edge - not usable */
|
||||
return;
|
||||
}
|
||||
newlen = _primary->region ()->end ().distance (adjusted_pos);
|
||||
} else {
|
||||
if (adjusted_pos < _primary->region ()->position ()) {
|
||||
/* backwards drag of the left edge - not usable */
|
||||
return;
|
||||
}
|
||||
newlen = _primary->region ()->position ().distance (adjusted_pos);
|
||||
}
|
||||
|
||||
timecnt_t newlen = _primary->region ()->position ().distance (adjusted_pos);
|
||||
|
||||
if (_primary->region ()->length ().time_domain () == Temporal::BeatTime) {
|
||||
ratio = ratio_t (newlen.ticks (), _primary->region ()->length ().ticks ());
|
||||
@ -5383,7 +5401,7 @@ TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
selection.
|
||||
*/
|
||||
|
||||
if (_editor->time_stretch (_editor->get_selection ().regions, ratio) == -1) {
|
||||
if (_editor->time_stretch (_editor->get_selection ().regions, ratio, _dragging_start) == -1) {
|
||||
error << _("An error occurred while executing time stretch operation") << endmsg;
|
||||
}
|
||||
}
|
||||
|
@ -1335,6 +1335,8 @@ public:
|
||||
void motion (GdkEvent *, bool);
|
||||
void finished (GdkEvent *, bool);
|
||||
void aborted (bool);
|
||||
private:
|
||||
bool _dragging_start;
|
||||
};
|
||||
|
||||
/** Scrub drag in audition mode */
|
||||
|
@ -66,7 +66,7 @@ using namespace Gtkmm2ext;
|
||||
|
||||
/** @return -1 in case of error, 1 if operation was cancelled by the user, 0 if everything went ok */
|
||||
int
|
||||
Editor::time_stretch (RegionSelection& regions, Temporal::ratio_t const & ratio)
|
||||
Editor::time_stretch (RegionSelection& regions, Temporal::ratio_t const & ratio, bool fixed_end)
|
||||
{
|
||||
RegionList audio;
|
||||
RegionList midi;
|
||||
@ -81,7 +81,7 @@ Editor::time_stretch (RegionSelection& regions, Temporal::ratio_t const & ratio)
|
||||
}
|
||||
}
|
||||
|
||||
int aret = time_fx (audio, ratio, false);
|
||||
int aret = time_fx (audio, ratio, false, fixed_end);
|
||||
if (aret < 0) {
|
||||
abort_reversible_command ();
|
||||
return aret;
|
||||
@ -111,8 +111,14 @@ Editor::time_stretch (RegionSelection& regions, Temporal::ratio_t const & ratio)
|
||||
MidiStretch stretch (*_session, request);
|
||||
stretch.run (*i);
|
||||
|
||||
playlist->replace_region (regions.front()->region(), stretch.results[0],
|
||||
regions.front()->region()->position());
|
||||
timepos_t newpos;
|
||||
|
||||
if (fixed_end)
|
||||
newpos = regions.front()->region()->end().earlier(stretch.results[0]->length());
|
||||
else
|
||||
newpos = regions.front()->region()->position();
|
||||
|
||||
playlist->replace_region (regions.front()->region(), stretch.results[0], newpos);
|
||||
midi_playlists_affected.insert (playlist);
|
||||
}
|
||||
|
||||
@ -144,7 +150,7 @@ Editor::pitch_shift (RegionSelection& regions, float fraction)
|
||||
|
||||
begin_reversible_command (_("pitch shift"));
|
||||
|
||||
int ret = time_fx (rl, fraction, true);
|
||||
int ret = time_fx (rl, fraction, true, false);
|
||||
|
||||
if (ret > 0) {
|
||||
commit_reversible_command ();
|
||||
@ -159,7 +165,7 @@ Editor::pitch_shift (RegionSelection& regions, float fraction)
|
||||
* @param pitching true to pitch shift, false to time stretch.
|
||||
* @return -1 in case of error, otherwise number of regions processed */
|
||||
int
|
||||
Editor::time_fx (RegionList& regions, Temporal::ratio_t ratio, bool pitching)
|
||||
Editor::time_fx (RegionList& regions, Temporal::ratio_t ratio, bool pitching, bool fixed_end)
|
||||
{
|
||||
delete current_timefx;
|
||||
|
||||
@ -172,7 +178,7 @@ Editor::time_fx (RegionList& regions, Temporal::ratio_t ratio, bool pitching)
|
||||
const timecnt_t newlen = regions.front()->length().scale (ratio);
|
||||
const timepos_t pos = regions.front()->position ();
|
||||
|
||||
current_timefx = new TimeFXDialog (*this, pitching, oldlen, newlen, ratio, pos);
|
||||
current_timefx = new TimeFXDialog (*this, pitching, oldlen, newlen, ratio, pos, fixed_end);
|
||||
current_timefx->regions = regions;
|
||||
|
||||
switch (current_timefx->run ()) {
|
||||
@ -355,7 +361,7 @@ Editor::time_fx (RegionList& regions, Temporal::ratio_t ratio, bool pitching)
|
||||
}
|
||||
|
||||
void
|
||||
Editor::do_timefx ()
|
||||
Editor::do_timefx (bool fixed_end)
|
||||
{
|
||||
typedef std::map<std::shared_ptr<Region>, std::shared_ptr<Region> > ResultMap;
|
||||
ResultMap results;
|
||||
@ -426,7 +432,11 @@ Editor::do_timefx ()
|
||||
std::shared_ptr<Playlist> playlist = region->playlist();
|
||||
|
||||
playlist->clear_changes ();
|
||||
playlist->replace_region (region, new_region, region->position());
|
||||
if (fixed_end)
|
||||
playlist->replace_region (region, new_region, region->end ().earlier(new_region->length ()));
|
||||
else
|
||||
playlist->replace_region (region, new_region, region->position());
|
||||
|
||||
PBD::StatefulDiffCommand* cmd = new StatefulDiffCommand (playlist);
|
||||
_session->add_command (cmd);
|
||||
if (!cmd->empty ()) {
|
||||
@ -449,7 +459,7 @@ Editor::timefx_thread (void *arg)
|
||||
|
||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
||||
|
||||
tsd->editor.do_timefx ();
|
||||
tsd->editor.do_timefx (tsd->fixed_end);
|
||||
|
||||
/* GACK! HACK! sleep for a bit so that our request buffer for the GUI
|
||||
event loop doesn't die before any changes we made are processed
|
||||
|
@ -55,7 +55,7 @@ using namespace PBD;
|
||||
using namespace Gtk;
|
||||
using namespace Gtkmm2ext;
|
||||
|
||||
TimeFXDialog::TimeFXDialog (Editor& e, bool pitch, timecnt_t const & oldlen, timecnt_t const & new_length, Temporal::ratio_t const & ratio, timepos_t const & position)
|
||||
TimeFXDialog::TimeFXDialog (Editor& e, bool pitch, timecnt_t const & oldlen, timecnt_t const & new_length, Temporal::ratio_t const & ratio, timepos_t const & position, bool fixed_end)
|
||||
: ArdourDialog (X_("time fx dialog"))
|
||||
, editor (e)
|
||||
, pitching (pitch)
|
||||
@ -64,6 +64,7 @@ TimeFXDialog::TimeFXDialog (Editor& e, bool pitch, timecnt_t const & oldlen, tim
|
||||
, stretch_opts_label (_("Contents"))
|
||||
, precise_button (_("Minimize time distortion"))
|
||||
, preserve_formants_button(_("Preserve Formants"))
|
||||
, fixed_end (fixed_end)
|
||||
, original_length (oldlen)
|
||||
, pitch_octave_adjustment (0.0, -4.0, 4.0, 1, 2.0)
|
||||
, pitch_semitone_adjustment (0.0, -12.0, 12.0, 1.0, 4.0)
|
||||
|
@ -42,7 +42,7 @@ class TimeFXDialog : public ArdourDialog, public ProgressReporter
|
||||
{
|
||||
public:
|
||||
/* We need a position so that BBT mode in the clock can function */
|
||||
TimeFXDialog (Editor& e, bool for_pitch, Temporal::timecnt_t const & old_length, Temporal::timecnt_t const & new_length, Temporal::ratio_t const &, Temporal::timepos_t const & position);
|
||||
TimeFXDialog (Editor& e, bool for_pitch, Temporal::timecnt_t const & old_length, Temporal::timecnt_t const & new_length, Temporal::ratio_t const &, Temporal::timepos_t const & position, bool fixed_end);
|
||||
|
||||
ARDOUR::TimeFXRequest request;
|
||||
Editor& editor;
|
||||
@ -65,6 +65,7 @@ public:
|
||||
Gtk::Button* action_button;
|
||||
Gtk::VBox packer;
|
||||
int status;
|
||||
bool fixed_end;
|
||||
|
||||
sigc::connection first_cancel;
|
||||
sigc::connection first_delete;
|
||||
|
Loading…
Reference in New Issue
Block a user