2
Copyright (C) 2000-2004 Paul Davis
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
/* Note: public Editor methods are documented in public_editor.h */
31
#include <gtkmm/messagedialog.h>
33
#include "pbd/error.h"
34
#include "pbd/basename.h"
35
#include "pbd/pthread_utils.h"
36
#include "pbd/memento_command.h"
37
#include "pbd/unwind.h"
38
#include "pbd/whitespace.h"
39
#include "pbd/stateful_diff_command.h"
41
#include "gtkmm2ext/utils.h"
43
#include "widgets/choice.h"
44
#include "widgets/popup.h"
45
#include "widgets/prompter.h"
47
#include "ardour/audio_track.h"
48
#include "ardour/audioregion.h"
49
#include "ardour/boost_debug.h"
50
#include "ardour/dB.h"
51
#include "ardour/location.h"
52
#include "ardour/midi_region.h"
53
#include "ardour/midi_track.h"
54
#include "ardour/operations.h"
55
#include "ardour/playlist_factory.h"
56
#include "ardour/profile.h"
57
#include "ardour/quantize.h"
58
#include "ardour/legatize.h"
59
#include "ardour/region_factory.h"
60
#include "ardour/reverse.h"
61
#include "ardour/session.h"
62
#include "ardour/session_playlists.h"
63
#include "ardour/strip_silence.h"
64
#include "ardour/transient_detector.h"
65
#include "ardour/transpose.h"
66
#include "ardour/vca_manager.h"
68
#include "canvas/canvas.h"
71
#include "audio_region_view.h"
72
#include "audio_streamview.h"
73
#include "audio_time_axis.h"
74
#include "automation_region_view.h"
75
#include "automation_time_axis.h"
76
#include "control_point.h"
80
#include "editor_cursors.h"
81
#include "editor_drag.h"
82
#include "editor_regions.h"
83
#include "editor_routes.h"
84
#include "gui_thread.h"
85
#include "insert_remove_time_dialog.h"
86
#include "interthread_progress_window.h"
87
#include "item_counts.h"
89
#include "midi_region_view.h"
91
#include "mixer_strip.h"
92
#include "mouse_cursors.h"
93
#include "normalize_dialog.h"
95
#include "paste_context.h"
96
#include "patch_change_dialog.h"
97
#include "quantize_dialog.h"
98
#include "region_gain_line.h"
99
#include "rgb_macros.h"
100
#include "route_time_axis.h"
101
#include "selection.h"
102
#include "selection_templates.h"
103
#include "streamview.h"
104
#include "strip_silence_dialog.h"
105
#include "time_axis_view.h"
107
#include "transpose_dialog.h"
108
#include "transform_dialog.h"
109
#include "ui_config.h"
110
#include "vca_time_axis.h"
112
#include "pbd/i18n.h"
115
using namespace ARDOUR;
118
using namespace Gtkmm2ext;
119
using namespace ArdourWidgets;
120
using namespace Editing;
121
using Gtkmm2ext::Keyboard;
123
/***********************************************************************
125
***********************************************************************/
128
Editor::undo (uint32_t n)
130
if (_session && _session->actively_recording()) {
131
/* no undo allowed while recording. Session will check also,
132
but we don't even want to get to that.
137
if (_drags->active ()) {
143
if (_session->undo_depth() == 0) {
144
undo_action->set_sensitive(false);
146
redo_action->set_sensitive(true);
147
begin_selection_op_history ();
152
Editor::redo (uint32_t n)
154
if (_session && _session->actively_recording()) {
155
/* no redo allowed while recording. Session will check also,
156
but we don't even want to get to that.
161
if (_drags->active ()) {
167
if (_session->redo_depth() == 0) {
168
redo_action->set_sensitive(false);
170
undo_action->set_sensitive(true);
171
begin_selection_op_history ();
176
Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
180
RegionSelection pre_selected_regions = selection->regions;
181
bool working_on_selection = !pre_selected_regions.empty();
183
list<boost::shared_ptr<Playlist> > used_playlists;
184
list<RouteTimeAxisView*> used_trackviews;
186
if (regions.empty()) {
190
begin_reversible_command (_("split"));
192
// if splitting a single region, and snap-to is using
193
// region boundaries, don't pay attention to them
195
if (regions.size() == 1) {
196
switch (_snap_type) {
197
case SnapToRegionStart:
198
case SnapToRegionSync:
199
case SnapToRegionEnd:
212
EditorFreeze(); /* Emit Signal */
215
for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
217
RegionSelection::iterator tmp;
219
/* XXX this test needs to be more complicated, to make sure we really
220
have something to split.
223
if (!(*a)->region()->covers (where.frame)) {
231
boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
239
/* we haven't seen this playlist before */
241
/* remember used playlists so we can thaw them later */
242
used_playlists.push_back(pl);
244
TimeAxisView& tv = (*a)->get_time_axis_view();
245
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
247
used_trackviews.push_back (rtv);
254
pl->clear_changes ();
255
pl->split_region ((*a)->region(), where);
256
_session->add_command (new StatefulDiffCommand (pl));
262
latest_regionviews.clear ();
264
vector<sigc::connection> region_added_connections;
266
for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
267
region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
270
while (used_playlists.size() > 0) {
271
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
273
used_playlists.pop_front();
276
for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
281
EditorThaw(); /* Emit Signal */
284
if (working_on_selection) {
285
// IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
287
RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
288
/* There are three classes of regions that we might want selected after
289
splitting selected regions:
290
- regions selected before the split operation, and unaffected by it
291
- newly-created regions before the split
292
- newly-created regions after the split
295
if (rsas & Existing) {
296
// region selections that existed before the split.
297
selection->add ( pre_selected_regions );
300
for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
301
if ((*ri)->region()->position() < where.frame) {
302
// new regions created before the split
303
if (rsas & NewlyCreatedLeft) {
304
selection->add (*ri);
307
// new regions created after the split
308
if (rsas & NewlyCreatedRight) {
309
selection->add (*ri);
314
if( working_on_selection ) {
315
selection->add (latest_regionviews); //these are the new regions created after the split
319
commit_reversible_command ();
322
/** Move one extreme of the current range selection. If more than one range is selected,
323
* the start of the earliest range or the end of the latest range is moved.
325
* @param move_end true to move the end of the current range selection, false to move
327
* @param next true to move the extreme to the next region boundary, false to move to
331
Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
333
if (selection->time.start() == selection->time.end_frame()) {
337
framepos_t start = selection->time.start ();
338
framepos_t end = selection->time.end_frame ();
340
/* the position of the thing we may move */
341
framepos_t pos = move_end ? end : start;
342
int dir = next ? 1 : -1;
344
/* so we don't find the current region again */
345
if (dir > 0 || pos > 0) {
349
framepos_t const target = get_region_boundary (pos, dir, true, false);
364
begin_reversible_selection_op (_("alter selection"));
365
selection->set_preserving_all_ranges (start, end);
366
commit_reversible_selection_op ();
370
Editor::nudge_forward_release (GdkEventButton* ev)
372
if (ev->state & Keyboard::PrimaryModifier) {
373
nudge_forward (false, true);
375
nudge_forward (false, false);
381
Editor::nudge_backward_release (GdkEventButton* ev)
383
if (ev->state & Keyboard::PrimaryModifier) {
384
nudge_backward (false, true);
386
nudge_backward (false, false);
393
Editor::nudge_forward (bool next, bool force_playhead)
396
framepos_t next_distance;
402
RegionSelection rs = get_regions_from_selection_and_entered ();
404
if (!force_playhead && !rs.empty()) {
406
begin_reversible_command (_("nudge regions forward"));
408
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
409
boost::shared_ptr<Region> r ((*i)->region());
411
distance = get_nudge_distance (r->position(), next_distance);
414
distance = next_distance;
418
r->set_position (r->position() + distance);
419
_session->add_command (new StatefulDiffCommand (r));
422
commit_reversible_command ();
425
} else if (!force_playhead && !selection->markers.empty()) {
428
bool in_command = false;
429
const int32_t divisions = get_grid_music_divisions (0);
431
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
433
Location* loc = find_location_from_marker ((*i), is_start);
437
XMLNode& before (loc->get_state());
440
distance = get_nudge_distance (loc->start(), next_distance);
442
distance = next_distance;
444
if (max_framepos - distance > loc->start() + loc->length()) {
445
loc->set_start (loc->start() + distance, false, true, divisions);
447
loc->set_start (max_framepos - loc->length(), false, true, divisions);
450
distance = get_nudge_distance (loc->end(), next_distance);
452
distance = next_distance;
454
if (max_framepos - distance > loc->end()) {
455
loc->set_end (loc->end() + distance, false, true, divisions);
457
loc->set_end (max_framepos, false, true, divisions);
459
if (loc->is_session_range()) {
460
_session->set_end_is_free (false);
464
begin_reversible_command (_("nudge location forward"));
467
XMLNode& after (loc->get_state());
468
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
473
commit_reversible_command ();
476
distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
477
_session->request_locate (playhead_cursor->current_frame () + distance);
482
Editor::nudge_backward (bool next, bool force_playhead)
485
framepos_t next_distance;
491
RegionSelection rs = get_regions_from_selection_and_entered ();
493
if (!force_playhead && !rs.empty()) {
495
begin_reversible_command (_("nudge regions backward"));
497
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
498
boost::shared_ptr<Region> r ((*i)->region());
500
distance = get_nudge_distance (r->position(), next_distance);
503
distance = next_distance;
508
if (r->position() > distance) {
509
r->set_position (r->position() - distance);
513
_session->add_command (new StatefulDiffCommand (r));
516
commit_reversible_command ();
518
} else if (!force_playhead && !selection->markers.empty()) {
521
bool in_command = false;
523
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
525
Location* loc = find_location_from_marker ((*i), is_start);
529
XMLNode& before (loc->get_state());
532
distance = get_nudge_distance (loc->start(), next_distance);
534
distance = next_distance;
536
if (distance < loc->start()) {
537
loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
539
loc->set_start (0, false, true, get_grid_music_divisions(0));
542
distance = get_nudge_distance (loc->end(), next_distance);
545
distance = next_distance;
548
if (distance < loc->end() - loc->length()) {
549
loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
551
loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
553
if (loc->is_session_range()) {
554
_session->set_end_is_free (false);
558
begin_reversible_command (_("nudge location forward"));
561
XMLNode& after (loc->get_state());
562
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
566
commit_reversible_command ();
571
distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
573
if (playhead_cursor->current_frame () > distance) {
574
_session->request_locate (playhead_cursor->current_frame () - distance);
576
_session->goto_start();
582
Editor::nudge_forward_capture_offset ()
584
RegionSelection rs = get_regions_from_selection_and_entered ();
586
if (!_session || rs.empty()) {
590
begin_reversible_command (_("nudge forward"));
592
framepos_t const distance = _session->worst_output_latency();
594
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
595
boost::shared_ptr<Region> r ((*i)->region());
598
r->set_position (r->position() + distance);
599
_session->add_command(new StatefulDiffCommand (r));
602
commit_reversible_command ();
606
Editor::nudge_backward_capture_offset ()
608
RegionSelection rs = get_regions_from_selection_and_entered ();
610
if (!_session || rs.empty()) {
614
begin_reversible_command (_("nudge backward"));
616
framepos_t const distance = _session->worst_output_latency();
618
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
619
boost::shared_ptr<Region> r ((*i)->region());
623
if (r->position() > distance) {
624
r->set_position (r->position() - distance);
628
_session->add_command(new StatefulDiffCommand (r));
631
commit_reversible_command ();
634
struct RegionSelectionPositionSorter {
635
bool operator() (RegionView* a, RegionView* b) {
636
return a->region()->position() < b->region()->position();
641
Editor::sequence_regions ()
644
framepos_t r_end_prev;
652
RegionSelection rs = get_regions_from_selection_and_entered ();
653
rs.sort(RegionSelectionPositionSorter());
657
bool in_command = false;
659
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
660
boost::shared_ptr<Region> r ((*i)->region());
668
if(r->position_locked())
675
r->set_position(r_end_prev);
679
begin_reversible_command (_("sequence regions"));
682
_session->add_command (new StatefulDiffCommand (r));
684
r_end=r->position() + r->length();
690
commit_reversible_command ();
699
Editor::move_to_start ()
701
_session->goto_start ();
705
Editor::move_to_end ()
708
_session->request_locate (_session->current_end_frame());
712
Editor::build_region_boundary_cache ()
715
vector<RegionPoint> interesting_points;
716
boost::shared_ptr<Region> r;
717
TrackViewList tracks;
720
region_boundary_cache.clear ();
726
bool maybe_first_frame = false;
728
switch (_snap_type) {
729
case SnapToRegionStart:
730
interesting_points.push_back (Start);
731
maybe_first_frame = true;
733
case SnapToRegionEnd:
734
interesting_points.push_back (End);
736
case SnapToRegionSync:
737
interesting_points.push_back (SyncPoint);
739
case SnapToRegionBoundary:
740
interesting_points.push_back (Start);
741
interesting_points.push_back (End);
742
maybe_first_frame = true;
745
fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
746
abort(); /*NOTREACHED*/
750
TimeAxisView *ontrack = 0;
753
if (!selection->tracks.empty()) {
754
tlist = selection->tracks.filter_to_unique_playlists ();
756
tlist = track_views.filter_to_unique_playlists ();
759
if (maybe_first_frame) {
760
TrackViewList::const_iterator i;
761
for (i = tlist.begin(); i != tlist.end(); ++i) {
762
boost::shared_ptr<Playlist> pl = (*i)->playlist();
763
if (pl && pl->count_regions_at (0)) {
764
region_boundary_cache.push_back (0);
770
while (pos < _session->current_end_frame() && !at_end) {
773
framepos_t lpos = max_framepos;
775
for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
777
if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
778
if (*p == interesting_points.back()) {
781
/* move to next point type */
787
rpos = r->first_frame();
791
rpos = r->last_frame();
795
rpos = r->sync_position ();
806
/* prevent duplicates, but we don't use set<> because we want to be able
810
vector<framepos_t>::iterator ri;
812
for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
818
if (ri == region_boundary_cache.end()) {
819
region_boundary_cache.push_back (rpos);
826
/* finally sort to be sure that the order is correct */
828
sort (region_boundary_cache.begin(), region_boundary_cache.end());
831
boost::shared_ptr<Region>
832
Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
834
TrackViewList::iterator i;
835
framepos_t closest = max_framepos;
836
boost::shared_ptr<Region> ret;
839
framepos_t track_frame;
840
RouteTimeAxisView *rtav;
842
for (i = tracks.begin(); i != tracks.end(); ++i) {
845
boost::shared_ptr<Region> r;
849
if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
855
rpos = r->first_frame ();
859
rpos = r->last_frame ();
863
rpos = r->sync_position ();
868
distance = rpos - frame;
870
distance = frame - rpos;
873
if (distance < closest) {
885
Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
887
framecnt_t distance = max_framepos;
888
framepos_t current_nearest = -1;
890
for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
891
framepos_t contender;
894
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
900
if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
904
d = ::llabs (pos - contender);
907
current_nearest = contender;
912
return current_nearest;
916
Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
921
if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
923
if (!selection->tracks.empty()) {
925
target = find_next_region_boundary (pos, dir, selection->tracks);
929
if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
930
get_onscreen_tracks (tvl);
931
target = find_next_region_boundary (pos, dir, tvl);
933
target = find_next_region_boundary (pos, dir, track_views);
939
if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
940
get_onscreen_tracks (tvl);
941
target = find_next_region_boundary (pos, dir, tvl);
943
target = find_next_region_boundary (pos, dir, track_views);
951
Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
953
framepos_t pos = playhead_cursor->current_frame ();
960
// so we don't find the current region again..
961
if (dir > 0 || pos > 0) {
965
if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
969
_session->request_locate (target);
973
Editor::cursor_to_next_region_boundary (bool with_selection)
975
cursor_to_region_boundary (with_selection, 1);
979
Editor::cursor_to_previous_region_boundary (bool with_selection)
981
cursor_to_region_boundary (with_selection, -1);
985
Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
987
boost::shared_ptr<Region> r;
988
framepos_t pos = cursor->current_frame ();
994
TimeAxisView *ontrack = 0;
996
// so we don't find the current region again..
1000
if (!selection->tracks.empty()) {
1002
r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1004
} else if (clicked_axisview) {
1007
t.push_back (clicked_axisview);
1009
r = find_next_region (pos, point, dir, t, &ontrack);
1013
r = find_next_region (pos, point, dir, track_views, &ontrack);
1022
pos = r->first_frame ();
1026
pos = r->last_frame ();
1030
pos = r->sync_position ();
1034
if (cursor == playhead_cursor) {
1035
_session->request_locate (pos);
1037
cursor->set_position (pos);
1042
Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1044
cursor_to_region_point (cursor, point, 1);
1048
Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1050
cursor_to_region_point (cursor, point, -1);
1054
Editor::cursor_to_selection_start (EditorCursor *cursor)
1058
switch (mouse_mode) {
1060
if (!selection->regions.empty()) {
1061
pos = selection->regions.start();
1066
if (!selection->time.empty()) {
1067
pos = selection->time.start ();
1075
if (cursor == playhead_cursor) {
1076
_session->request_locate (pos);
1078
cursor->set_position (pos);
1083
Editor::cursor_to_selection_end (EditorCursor *cursor)
1087
switch (mouse_mode) {
1089
if (!selection->regions.empty()) {
1090
pos = selection->regions.end_frame();
1095
if (!selection->time.empty()) {
1096
pos = selection->time.end_frame ();
1104
if (cursor == playhead_cursor) {
1105
_session->request_locate (pos);
1107
cursor->set_position (pos);
1112
Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1122
if (selection->markers.empty()) {
1126
if (!mouse_frame (mouse, ignored)) {
1130
add_location_mark (mouse);
1133
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1137
framepos_t pos = loc->start();
1139
// so we don't find the current region again..
1140
if (dir > 0 || pos > 0) {
1144
if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1148
loc->move_to (target, 0);
1152
Editor::selected_marker_to_next_region_boundary (bool with_selection)
1154
selected_marker_to_region_boundary (with_selection, 1);
1158
Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1160
selected_marker_to_region_boundary (with_selection, -1);
1164
Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1166
boost::shared_ptr<Region> r;
1171
if (!_session || selection->markers.empty()) {
1175
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1179
TimeAxisView *ontrack = 0;
1183
// so we don't find the current region again..
1187
if (!selection->tracks.empty()) {
1189
r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1193
r = find_next_region (pos, point, dir, track_views, &ontrack);
1202
pos = r->first_frame ();
1206
pos = r->last_frame ();
1210
pos = r->adjust_to_sync (r->first_frame());
1214
loc->move_to (pos, 0);
1218
Editor::selected_marker_to_next_region_point (RegionPoint point)
1220
selected_marker_to_region_point (point, 1);
1224
Editor::selected_marker_to_previous_region_point (RegionPoint point)
1226
selected_marker_to_region_point (point, -1);
1230
Editor::selected_marker_to_selection_start ()
1236
if (!_session || selection->markers.empty()) {
1240
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1244
switch (mouse_mode) {
1246
if (!selection->regions.empty()) {
1247
pos = selection->regions.start();
1252
if (!selection->time.empty()) {
1253
pos = selection->time.start ();
1261
loc->move_to (pos, 0);
1265
Editor::selected_marker_to_selection_end ()
1271
if (!_session || selection->markers.empty()) {
1275
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1279
switch (mouse_mode) {
1281
if (!selection->regions.empty()) {
1282
pos = selection->regions.end_frame();
1287
if (!selection->time.empty()) {
1288
pos = selection->time.end_frame ();
1296
loc->move_to (pos, 0);
1300
Editor::scroll_playhead (bool forward)
1302
framepos_t pos = playhead_cursor->current_frame ();
1303
framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1306
if (pos == max_framepos) {
1310
if (pos < max_framepos - delta) {
1329
_session->request_locate (pos);
1333
Editor::cursor_align (bool playhead_to_edit)
1339
if (playhead_to_edit) {
1341
if (selection->markers.empty()) {
1345
_session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1348
const int32_t divisions = get_grid_music_divisions (0);
1349
/* move selected markers to playhead */
1351
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1354
Location* loc = find_location_from_marker (*i, ignored);
1356
if (loc->is_mark()) {
1357
loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
1359
loc->set (playhead_cursor->current_frame (),
1360
playhead_cursor->current_frame () + loc->length(), true, divisions);
1367
Editor::scroll_backward (float pages)
1369
framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1370
framepos_t const cnt = (framepos_t) floor (pages * one_page);
1373
if (leftmost_frame < cnt) {
1376
frame = leftmost_frame - cnt;
1379
reset_x_origin (frame);
1383
Editor::scroll_forward (float pages)
1385
framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1386
framepos_t const cnt = (framepos_t) floor (pages * one_page);
1389
if (max_framepos - cnt < leftmost_frame) {
1390
frame = max_framepos - cnt;
1392
frame = leftmost_frame + cnt;
1395
reset_x_origin (frame);
1399
Editor::scroll_tracks_down ()
1401
double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1402
if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1403
vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1406
vertical_adjustment.set_value (vert_value);
1410
Editor::scroll_tracks_up ()
1412
vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1416
Editor::scroll_tracks_down_line ()
1418
double vert_value = vertical_adjustment.get_value() + 60;
1420
if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1421
vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1424
vertical_adjustment.set_value (vert_value);
1428
Editor::scroll_tracks_up_line ()
1430
reset_y_origin (vertical_adjustment.get_value() - 60);
1434
Editor::select_topmost_track ()
1436
const double top_of_trackviews = vertical_adjustment.get_value();
1437
for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1438
if ((*t)->hidden()) {
1441
std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1443
selection->set (*t);
1450
Editor::scroll_down_one_track (bool skip_child_views)
1452
TrackViewList::reverse_iterator next = track_views.rend();
1453
const double top_of_trackviews = vertical_adjustment.get_value();
1455
for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1456
if ((*t)->hidden()) {
1460
/* If this is the upper-most visible trackview, we want to display
1461
* the one above it (next)
1463
* Note that covers_y_position() is recursive and includes child views
1465
std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1468
if (skip_child_views) {
1471
/* automation lane (one level, non-recursive)
1473
* - if no automation lane exists -> move to next tack
1474
* - if the first (here: bottom-most) matches -> move to next tack
1475
* - if no y-axis match is found -> the current track is at the top
1476
* -> move to last (here: top-most) automation lane
1478
TimeAxisView::Children kids = (*t)->get_child_list();
1479
TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1481
for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1482
if ((*ci)->hidden()) {
1486
std::pair<TimeAxisView*,double> dev;
1487
dev = (*ci)->covers_y_position (top_of_trackviews);
1489
/* some automation lane is currently at the top */
1490
if (ci == kids.rbegin()) {
1491
/* first (bottom-most) autmation lane is at the top.
1492
* -> move to next track
1501
if (nkid != kids.rend()) {
1502
ensure_time_axis_view_is_visible (**nkid, true);
1510
/* move to the track below the first one that covers the */
1512
if (next != track_views.rend()) {
1513
ensure_time_axis_view_is_visible (**next, true);
1521
Editor::scroll_up_one_track (bool skip_child_views)
1523
TrackViewList::iterator prev = track_views.end();
1524
double top_of_trackviews = vertical_adjustment.get_value ();
1526
for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1528
if ((*t)->hidden()) {
1532
/* find the trackview at the top of the trackview group
1534
* Note that covers_y_position() is recursive and includes child views
1536
std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1539
if (skip_child_views) {
1542
/* automation lane (one level, non-recursive)
1544
* - if no automation lane exists -> move to prev tack
1545
* - if no y-axis match is found -> the current track is at the top -> move to prev track
1546
* (actually last automation lane of previous track, see below)
1547
* - if first (top-most) lane is at the top -> move to this track
1548
* - else move up one lane
1550
TimeAxisView::Children kids = (*t)->get_child_list();
1551
TimeAxisView::Children::iterator pkid = kids.end();
1553
for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1554
if ((*ci)->hidden()) {
1558
std::pair<TimeAxisView*,double> dev;
1559
dev = (*ci)->covers_y_position (top_of_trackviews);
1561
/* some automation lane is currently at the top */
1562
if (ci == kids.begin()) {
1563
/* first (top-most) autmation lane is at the top.
1564
* jump directly to this track's top
1566
ensure_time_axis_view_is_visible (**t, true);
1569
else if (pkid != kids.end()) {
1570
/* some other automation lane is at the top.
1571
* move up to prev automation lane.
1573
ensure_time_axis_view_is_visible (**pkid, true);
1576
assert(0); // not reached
1587
if (prev != track_views.end()) {
1588
// move to bottom-most automation-lane of the previous track
1589
TimeAxisView::Children kids = (*prev)->get_child_list();
1590
TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1591
if (!skip_child_views) {
1592
// find the last visible lane
1593
for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1594
if (!(*ci)->hidden()) {
1600
if (pkid != kids.rend()) {
1601
ensure_time_axis_view_is_visible (**pkid, true);
1603
ensure_time_axis_view_is_visible (**prev, true);
1612
Editor::scroll_left_step ()
1614
framepos_t xdelta = (current_page_samples() / 8);
1616
if (leftmost_frame > xdelta) {
1617
reset_x_origin (leftmost_frame - xdelta);
1625
Editor::scroll_right_step ()
1627
framepos_t xdelta = (current_page_samples() / 8);
1629
if (max_framepos - xdelta > leftmost_frame) {
1630
reset_x_origin (leftmost_frame + xdelta);
1632
reset_x_origin (max_framepos - current_page_samples());
1637
Editor::scroll_left_half_page ()
1639
framepos_t xdelta = (current_page_samples() / 2);
1640
if (leftmost_frame > xdelta) {
1641
reset_x_origin (leftmost_frame - xdelta);
1648
Editor::scroll_right_half_page ()
1650
framepos_t xdelta = (current_page_samples() / 2);
1651
if (max_framepos - xdelta > leftmost_frame) {
1652
reset_x_origin (leftmost_frame + xdelta);
1654
reset_x_origin (max_framepos - current_page_samples());
1661
Editor::tav_zoom_step (bool coarser)
1663
DisplaySuspender ds;
1667
if (selection->tracks.empty()) {
1670
ts = &selection->tracks;
1673
for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1674
TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1675
tv->step_height (coarser);
1680
Editor::tav_zoom_smooth (bool coarser, bool force_all)
1682
DisplaySuspender ds;
1686
if (selection->tracks.empty() || force_all) {
1689
ts = &selection->tracks;
1692
for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1693
TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1694
uint32_t h = tv->current_height ();
1699
if (h >= TimeAxisView::preset_height (HeightSmall)) {
1704
tv->set_height (h + 5);
1710
Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1712
Editing::ZoomFocus temp_focus = zoom_focus;
1713
zoom_focus = Editing::ZoomFocusMouse;
1714
temporal_zoom_step_scale (zoom_out, scale);
1715
zoom_focus = temp_focus;
1719
Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1721
temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1725
Editor::temporal_zoom_step (bool zoom_out)
1727
temporal_zoom_step_scale (zoom_out, 2.0);
1731
Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1733
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1735
framecnt_t nspp = samples_per_pixel;
1739
if (nspp == samples_per_pixel) {
1744
if (nspp == samples_per_pixel) {
1749
// ToDo: encapsulate all of this into something like editor::get_session_extents() or editor::leftmost(), rightmost()
1751
//ToDo: also incorporate automation regions (in case the session has no audio/midi but is just used for automating plugins or the like)
1753
//calculate the extents of all regions in every playlist
1754
framecnt_t session_extent_start = 0;
1755
framecnt_t session_extent_end = 0;
1757
boost::shared_ptr<RouteList> rl = _session->get_routes();
1758
for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1759
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*r);
1761
boost::shared_ptr<Playlist> pl = tr->playlist();
1763
pair<framepos_t, framepos_t> e;
1764
e = pl->get_extent();
1765
if (e.first < session_extent_start) {
1766
session_extent_start = e.first;
1768
if (e.second > session_extent_end) {
1769
session_extent_end = e.second;
1775
framecnt_t session_extents = session_extent_end - session_extent_start;
1777
//in a session with no regions, use the start/end markers to set max zoom
1778
framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
1779
if ( session_length > session_extents )
1780
session_extents = session_length;
1782
//in a session with no regions or start/end markers, use 2 minutes to set max zoom
1783
framecnt_t const min_length = _session->nominal_frame_rate()*60*2;
1784
if ( min_length > session_extents )
1785
session_extents = min_length;
1787
//convert to samples-per-pixel and limit our zoom to this value
1788
framecnt_t session_extents_pp = session_extents / _visible_canvas_width;
1789
if (nspp > session_extents_pp)
1790
nspp = session_extents_pp;
1793
temporal_zoom (nspp);
1797
Editor::temporal_zoom (framecnt_t fpp)
1803
framepos_t current_page = current_page_samples();
1804
framepos_t current_leftmost = leftmost_frame;
1805
framepos_t current_rightmost;
1806
framepos_t current_center;
1807
framepos_t new_page_size;
1808
framepos_t half_page_size;
1809
framepos_t leftmost_after_zoom = 0;
1811
bool in_track_canvas;
1812
bool use_mouse_frame = true;
1816
if (fpp == samples_per_pixel) {
1820
// Imposing an arbitrary limit to zoom out as too much zoom out produces
1821
// segfaults for lack of memory. If somebody decides this is not high enough I
1822
// believe it can be raisen to higher values but some limit must be in place.
1824
// This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1825
// all of which is used for the editor track displays. The whole day
1826
// would be 4147200000 samples, so 2592000 samples per pixel.
1828
nfpp = min (fpp, (framecnt_t) 2592000);
1829
nfpp = max ((framecnt_t) 1, nfpp);
1831
new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1832
half_page_size = new_page_size / 2;
1834
switch (zoom_focus) {
1836
leftmost_after_zoom = current_leftmost;
1839
case ZoomFocusRight:
1840
current_rightmost = leftmost_frame + current_page;
1841
if (current_rightmost < new_page_size) {
1842
leftmost_after_zoom = 0;
1844
leftmost_after_zoom = current_rightmost - new_page_size;
1848
case ZoomFocusCenter:
1849
current_center = current_leftmost + (current_page/2);
1850
if (current_center < half_page_size) {
1851
leftmost_after_zoom = 0;
1853
leftmost_after_zoom = current_center - half_page_size;
1857
case ZoomFocusPlayhead:
1858
/* centre playhead */
1859
l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1862
leftmost_after_zoom = 0;
1863
} else if (l > max_framepos) {
1864
leftmost_after_zoom = max_framepos - new_page_size;
1866
leftmost_after_zoom = (framepos_t) l;
1870
case ZoomFocusMouse:
1871
/* try to keep the mouse over the same point in the display */
1873
if (_drags->active()) {
1874
where = _drags->current_pointer_frame ();
1875
} else if (!mouse_frame (where, in_track_canvas)) {
1876
use_mouse_frame = false;
1879
if (use_mouse_frame) {
1880
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1883
leftmost_after_zoom = 0;
1884
} else if (l > max_framepos) {
1885
leftmost_after_zoom = max_framepos - new_page_size;
1887
leftmost_after_zoom = (framepos_t) l;
1890
/* use playhead instead */
1891
where = playhead_cursor->current_frame ();
1893
if (where < half_page_size) {
1894
leftmost_after_zoom = 0;
1896
leftmost_after_zoom = where - half_page_size;
1902
/* try to keep the edit point in the same place */
1903
where = get_preferred_edit_position ();
1907
double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1910
leftmost_after_zoom = 0;
1911
} else if (l > max_framepos) {
1912
leftmost_after_zoom = max_framepos - new_page_size;
1914
leftmost_after_zoom = (framepos_t) l;
1918
/* edit point not defined */
1925
// leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1927
reposition_and_zoom (leftmost_after_zoom, nfpp);
1931
Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1933
/* this func helps make sure we leave a little space
1934
at each end of the editor so that the zoom doesn't fit the region
1935
precisely to the screen.
1938
GdkScreen* screen = gdk_screen_get_default ();
1939
const gint pixwidth = gdk_screen_get_width (screen);
1940
const gint mmwidth = gdk_screen_get_width_mm (screen);
1941
const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1942
const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1944
const framepos_t range = end - start;
1945
const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1946
const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1948
if (start > extra_samples) {
1949
start -= extra_samples;
1954
if (max_framepos - extra_samples > end) {
1955
end += extra_samples;
1962
Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1964
start = max_framepos;
1968
//ToDo: if notes are selected, set extents to that selection
1970
//ToDo: if control points are selected, set extents to that selection
1972
if ( !selection->regions.empty() ) {
1973
RegionSelection rs = get_regions_from_selection_and_entered ();
1975
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1977
if ((*i)->region()->position() < start) {
1978
start = (*i)->region()->position();
1981
if ((*i)->region()->last_frame() + 1 > end) {
1982
end = (*i)->region()->last_frame() + 1;
1986
} else if (!selection->time.empty()) {
1987
start = selection->time.start();
1988
end = selection->time.end_frame();
1990
ret = false; //no selection found
1993
if ((start == 0 && end == 0) || end < start) {
2002
Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
2004
if (!selection) return;
2006
//ToDo: if notes are selected, zoom to that
2008
//ToDo: if control points are selected, zoom to that
2010
if (axes == Horizontal || axes == Both) {
2012
framepos_t start, end;
2013
if (get_selection_extents (start, end)) {
2014
calc_extra_zoom_edges (start, end);
2015
temporal_zoom_by_frame (start, end);
2019
if (axes == Vertical || axes == Both) {
2025
Editor::temporal_zoom_session ()
2027
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2030
framecnt_t start = _session->current_start_frame();
2031
framecnt_t end = _session->current_end_frame();
2033
if (_session->actively_recording () ) {
2034
framepos_t cur = playhead_cursor->current_frame ();
2036
/* recording beyond the end marker; zoom out
2037
* by 5 seconds more so that if 'follow
2038
* playhead' is active we don't immediately
2041
end = cur + _session->frame_rate() * 5;
2045
if ((start == 0 && end == 0) || end < start) {
2049
calc_extra_zoom_edges(start, end);
2051
temporal_zoom_by_frame (start, end);
2056
Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2058
if (!_session) return;
2060
if ((start == 0 && end == 0) || end < start) {
2064
framepos_t range = end - start;
2066
const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2068
framepos_t new_page = range;
2069
framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2070
framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2072
if (new_leftmost > middle) {
2076
if (new_leftmost < 0) {
2080
reposition_and_zoom (new_leftmost, new_fpp);
2084
Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2090
framecnt_t range_before = frame - leftmost_frame;
2094
if (samples_per_pixel <= 1) {
2097
new_spp = samples_per_pixel + (samples_per_pixel/2);
2099
range_before += range_before/2;
2101
if (samples_per_pixel >= 1) {
2102
new_spp = samples_per_pixel - (samples_per_pixel/2);
2104
/* could bail out here since we cannot zoom any finer,
2105
but leave that to the equality test below
2107
new_spp = samples_per_pixel;
2110
range_before -= range_before/2;
2113
if (new_spp == samples_per_pixel) {
2117
/* zoom focus is automatically taken as @param frame when this
2121
framepos_t new_leftmost = frame - (framepos_t)range_before;
2123
if (new_leftmost > frame) {
2127
if (new_leftmost < 0) {
2131
reposition_and_zoom (new_leftmost, new_spp);
2136
Editor::choose_new_marker_name(string &name) {
2138
if (!UIConfiguration::instance().get_name_new_markers()) {
2139
/* don't prompt user for a new name */
2143
Prompter dialog (true);
2145
dialog.set_prompt (_("New Name:"));
2147
dialog.set_title (_("New Location Marker"));
2149
dialog.set_name ("MarkNameWindow");
2150
dialog.set_size_request (250, -1);
2151
dialog.set_position (Gtk::WIN_POS_MOUSE);
2153
dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2154
dialog.set_initial_text (name);
2158
switch (dialog.run ()) {
2159
case RESPONSE_ACCEPT:
2165
dialog.get_result(name);
2172
Editor::add_location_from_selection ()
2176
if (selection->time.empty()) {
2180
if (_session == 0 || clicked_axisview == 0) {
2184
framepos_t start = selection->time[clicked_selection].start;
2185
framepos_t end = selection->time[clicked_selection].end;
2187
_session->locations()->next_available_name(rangename,"selection");
2188
Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2190
begin_reversible_command (_("add marker"));
2192
XMLNode &before = _session->locations()->get_state();
2193
_session->locations()->add (location, true);
2194
XMLNode &after = _session->locations()->get_state();
2195
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2197
commit_reversible_command ();
2201
Editor::add_location_mark (framepos_t where)
2205
select_new_marker = true;
2207
_session->locations()->next_available_name(markername,"mark");
2208
if (!choose_new_marker_name(markername)) {
2211
Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2212
begin_reversible_command (_("add marker"));
2214
XMLNode &before = _session->locations()->get_state();
2215
_session->locations()->add (location, true);
2216
XMLNode &after = _session->locations()->get_state();
2217
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2219
commit_reversible_command ();
2223
Editor::set_session_start_from_playhead ()
2229
if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2230
_session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2232
XMLNode &before = loc->get_state();
2234
_session->set_session_extents ( _session->audible_frame(), loc->end() );
2236
XMLNode &after = loc->get_state();
2238
begin_reversible_command (_("Set session start"));
2240
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2242
commit_reversible_command ();
2247
Editor::set_session_end_from_playhead ()
2253
if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2254
_session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2256
XMLNode &before = loc->get_state();
2258
_session->set_session_extents ( loc->start(), _session->audible_frame() );
2260
XMLNode &after = loc->get_state();
2262
begin_reversible_command (_("Set session start"));
2264
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2266
commit_reversible_command ();
2269
_session->set_end_is_free (false);
2274
Editor::toggle_location_at_playhead_cursor ()
2276
if (!do_remove_location_at_playhead_cursor())
2278
add_location_from_playhead_cursor();
2283
Editor::add_location_from_playhead_cursor ()
2285
add_location_mark (_session->audible_frame());
2289
Editor::do_remove_location_at_playhead_cursor ()
2291
bool removed = false;
2294
XMLNode &before = _session->locations()->get_state();
2296
//find location(s) at this time
2297
Locations::LocationList locs;
2298
_session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2299
for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2300
if ((*i)->is_mark()) {
2301
_session->locations()->remove (*i);
2308
begin_reversible_command (_("remove marker"));
2309
XMLNode &after = _session->locations()->get_state();
2310
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2311
commit_reversible_command ();
2318
Editor::remove_location_at_playhead_cursor ()
2320
do_remove_location_at_playhead_cursor ();
2323
/** Add a range marker around each selected region */
2325
Editor::add_locations_from_region ()
2327
RegionSelection rs = get_regions_from_selection_and_entered ();
2332
bool commit = false;
2334
XMLNode &before = _session->locations()->get_state();
2336
for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2338
boost::shared_ptr<Region> region = (*i)->region ();
2340
Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2342
_session->locations()->add (location, true);
2347
begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2348
XMLNode &after = _session->locations()->get_state();
2349
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2350
commit_reversible_command ();
2354
/** Add a single range marker around all selected regions */
2356
Editor::add_location_from_region ()
2358
RegionSelection rs = get_regions_from_selection_and_entered ();
2364
XMLNode &before = _session->locations()->get_state();
2368
if (rs.size() > 1) {
2369
_session->locations()->next_available_name(markername, "regions");
2371
RegionView* rv = *(rs.begin());
2372
boost::shared_ptr<Region> region = rv->region();
2373
markername = region->name();
2376
if (!choose_new_marker_name(markername)) {
2380
// single range spanning all selected
2381
Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2382
_session->locations()->add (location, true);
2384
begin_reversible_command (_("add marker"));
2385
XMLNode &after = _session->locations()->get_state();
2386
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2387
commit_reversible_command ();
2393
Editor::jump_forward_to_mark ()
2399
framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2405
_session->request_locate (pos, _session->transport_rolling());
2409
Editor::jump_backward_to_mark ()
2415
framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2417
//handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
2418
if ( _session->transport_rolling() ) {
2419
if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2420
framepos_t prior = _session->locations()->first_mark_before ( pos );
2429
_session->request_locate (pos, _session->transport_rolling());
2435
framepos_t const pos = _session->audible_frame ();
2438
_session->locations()->next_available_name (markername, "mark");
2440
if (!choose_new_marker_name (markername)) {
2444
_session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2448
Editor::clear_markers ()
2451
begin_reversible_command (_("clear markers"));
2453
XMLNode &before = _session->locations()->get_state();
2454
_session->locations()->clear_markers ();
2455
XMLNode &after = _session->locations()->get_state();
2456
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2458
commit_reversible_command ();
2463
Editor::clear_ranges ()
2466
begin_reversible_command (_("clear ranges"));
2468
XMLNode &before = _session->locations()->get_state();
2470
_session->locations()->clear_ranges ();
2472
XMLNode &after = _session->locations()->get_state();
2473
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2475
commit_reversible_command ();
2480
Editor::clear_locations ()
2482
begin_reversible_command (_("clear locations"));
2484
XMLNode &before = _session->locations()->get_state();
2485
_session->locations()->clear ();
2486
XMLNode &after = _session->locations()->get_state();
2487
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2489
commit_reversible_command ();
2493
Editor::unhide_markers ()
2495
for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2496
Location *l = (*i).first;
2497
if (l->is_hidden() && l->is_mark()) {
2498
l->set_hidden(false, this);
2504
Editor::unhide_ranges ()
2506
for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2507
Location *l = (*i).first;
2508
if (l->is_hidden() && l->is_range_marker()) {
2509
l->set_hidden(false, this);
2514
/* INSERT/REPLACE */
2517
Editor::insert_region_list_selection (float times)
2519
RouteTimeAxisView *tv = 0;
2520
boost::shared_ptr<Playlist> playlist;
2522
if (clicked_routeview != 0) {
2523
tv = clicked_routeview;
2524
} else if (!selection->tracks.empty()) {
2525
if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2528
} else if (entered_track != 0) {
2529
if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2536
if ((playlist = tv->playlist()) == 0) {
2540
boost::shared_ptr<Region> region = _regions->get_single_selection ();
2545
begin_reversible_command (_("insert region"));
2546
playlist->clear_changes ();
2547
playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2548
if (Config->get_edit_mode() == Ripple)
2549
playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2551
_session->add_command(new StatefulDiffCommand (playlist));
2552
commit_reversible_command ();
2555
/* BUILT-IN EFFECTS */
2558
Editor::reverse_selection ()
2563
/* GAIN ENVELOPE EDITING */
2566
Editor::edit_envelope ()
2573
Editor::transition_to_rolling (bool fwd)
2579
if (_session->config.get_external_sync()) {
2580
switch (Config->get_sync_source()) {
2584
/* transport controlled by the master */
2589
if (_session->is_auditioning()) {
2590
_session->cancel_audition ();
2594
_session->request_transport_speed (fwd ? 1.0f : -1.0f);
2598
Editor::play_from_start ()
2600
_session->request_locate (_session->current_start_frame(), true);
2604
Editor::play_from_edit_point ()
2606
_session->request_locate (get_preferred_edit_position(), true);
2610
Editor::play_from_edit_point_and_return ()
2612
framepos_t start_frame;
2613
framepos_t return_frame;
2615
start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2617
if (_session->transport_rolling()) {
2618
_session->request_locate (start_frame, false);
2622
/* don't reset the return frame if its already set */
2624
if ((return_frame = _session->requested_return_frame()) < 0) {
2625
return_frame = _session->audible_frame();
2628
if (start_frame >= 0) {
2629
_session->request_roll_at_and_return (start_frame, return_frame);
2634
Editor::play_selection ()
2636
framepos_t start, end;
2637
if (!get_selection_extents ( start, end))
2640
AudioRange ar (start, end, 0);
2641
list<AudioRange> lar;
2644
_session->request_play_range (&lar, true);
2649
Editor::maybe_locate_with_edit_preroll (framepos_t location)
2651
if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2654
location -= _session->preroll_samples (location);
2656
//don't try to locate before the beginning of time
2661
//if follow_playhead is on, keep the playhead on the screen
2662
if ( _follow_playhead )
2663
if ( location < leftmost_frame )
2664
location = leftmost_frame;
2666
_session->request_locate( location );
2670
Editor::play_with_preroll ()
2672
framepos_t start, end;
2673
if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2674
const framepos_t preroll = _session->preroll_samples (start);
2676
framepos_t ret = start;
2678
if (start > preroll) {
2679
start = start - preroll;
2682
end = end + preroll; //"post-roll"
2684
AudioRange ar (start, end, 0);
2685
list<AudioRange> lar;
2688
_session->request_play_range (&lar, true);
2689
_session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2691
framepos_t ph = playhead_cursor->current_frame ();
2692
const framepos_t preroll = _session->preroll_samples (ph);
2695
start = ph - preroll;
2699
_session->request_locate (start, true);
2700
_session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2705
Editor::rec_with_preroll ()
2707
framepos_t ph = playhead_cursor->current_frame ();
2708
framepos_t preroll = _session->preroll_samples (ph);
2709
_session->request_preroll_record_trim (ph, preroll);
2713
Editor::rec_with_count_in ()
2715
_session->request_count_in_record ();
2719
Editor::play_location (Location& location)
2721
if (location.start() <= location.end()) {
2725
_session->request_bounded_roll (location.start(), location.end());
2729
Editor::loop_location (Location& location)
2731
if (location.start() <= location.end()) {
2737
if ((tll = transport_loop_location()) != 0) {
2738
tll->set (location.start(), location.end());
2740
// enable looping, reposition and start rolling
2741
_session->request_locate (tll->start(), true);
2742
_session->request_play_loop (true);
2747
Editor::do_layer_operation (LayerOperation op)
2749
if (selection->regions.empty ()) {
2753
bool const multiple = selection->regions.size() > 1;
2757
begin_reversible_command (_("raise regions"));
2759
begin_reversible_command (_("raise region"));
2765
begin_reversible_command (_("raise regions to top"));
2767
begin_reversible_command (_("raise region to top"));
2773
begin_reversible_command (_("lower regions"));
2775
begin_reversible_command (_("lower region"));
2781
begin_reversible_command (_("lower regions to bottom"));
2783
begin_reversible_command (_("lower region"));
2788
set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2789
for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2790
(*i)->clear_owned_changes ();
2793
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2794
boost::shared_ptr<Region> r = (*i)->region ();
2806
r->lower_to_bottom ();
2810
for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2811
vector<Command*> cmds;
2813
_session->add_commands (cmds);
2816
commit_reversible_command ();
2820
Editor::raise_region ()
2822
do_layer_operation (Raise);
2826
Editor::raise_region_to_top ()
2828
do_layer_operation (RaiseToTop);
2832
Editor::lower_region ()
2834
do_layer_operation (Lower);
2838
Editor::lower_region_to_bottom ()
2840
do_layer_operation (LowerToBottom);
2843
/** Show the region editor for the selected regions */
2845
Editor::show_region_properties ()
2847
selection->foreach_regionview (&RegionView::show_region_editor);
2850
/** Show the midi list editor for the selected MIDI regions */
2852
Editor::show_midi_list_editor ()
2854
selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2858
Editor::rename_region ()
2860
RegionSelection rs = get_regions_from_selection_and_entered ();
2866
ArdourDialog d (_("Rename Region"), true, false);
2868
Label label (_("New name:"));
2871
hbox.set_spacing (6);
2872
hbox.pack_start (label, false, false);
2873
hbox.pack_start (entry, true, true);
2875
d.get_vbox()->set_border_width (12);
2876
d.get_vbox()->pack_start (hbox, false, false);
2878
d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2879
d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2881
d.set_size_request (300, -1);
2883
entry.set_text (rs.front()->region()->name());
2884
entry.select_region (0, -1);
2886
entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2892
int const ret = d.run();
2896
if (ret != RESPONSE_OK) {
2900
std::string str = entry.get_text();
2901
strip_whitespace_edges (str);
2903
rs.front()->region()->set_name (str);
2904
_regions->redisplay ();
2908
/** Start an audition of the first selected region */
2910
Editor::play_edit_range ()
2912
framepos_t start, end;
2914
if (get_edit_op_range (start, end)) {
2915
_session->request_bounded_roll (start, end);
2920
Editor::play_selected_region ()
2922
framepos_t start = max_framepos;
2925
RegionSelection rs = get_regions_from_selection_and_entered ();
2931
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2932
if ((*i)->region()->position() < start) {
2933
start = (*i)->region()->position();
2935
if ((*i)->region()->last_frame() + 1 > end) {
2936
end = (*i)->region()->last_frame() + 1;
2940
_session->request_bounded_roll (start, end);
2944
Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2946
_session->audition_region (region);
2950
Editor::region_from_selection ()
2952
if (clicked_axisview == 0) {
2956
if (selection->time.empty()) {
2960
framepos_t start = selection->time[clicked_selection].start;
2961
framepos_t end = selection->time[clicked_selection].end;
2963
TrackViewList tracks = get_tracks_for_range_action ();
2965
framepos_t selection_cnt = end - start + 1;
2967
for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2968
boost::shared_ptr<Region> current;
2969
boost::shared_ptr<Playlist> pl;
2970
framepos_t internal_start;
2973
if ((pl = (*i)->playlist()) == 0) {
2977
if ((current = pl->top_region_at (start)) == 0) {
2981
internal_start = start - current->position();
2982
RegionFactory::region_name (new_name, current->name(), true);
2986
plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2987
plist.add (ARDOUR::Properties::length, selection_cnt);
2988
plist.add (ARDOUR::Properties::name, new_name);
2989
plist.add (ARDOUR::Properties::layer, 0);
2991
boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2996
Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2998
if (selection->time.empty() || selection->tracks.empty()) {
3002
framepos_t start, end;
3003
if (clicked_selection) {
3004
start = selection->time[clicked_selection].start;
3005
end = selection->time[clicked_selection].end;
3007
start = selection->time.start();
3008
end = selection->time.end_frame();
3011
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3012
sort_track_selection (ts);
3014
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3015
boost::shared_ptr<Region> current;
3016
boost::shared_ptr<Playlist> playlist;
3017
framepos_t internal_start;
3020
if ((playlist = (*i)->playlist()) == 0) {
3024
if ((current = playlist->top_region_at(start)) == 0) {
3028
internal_start = start - current->position();
3029
RegionFactory::region_name (new_name, current->name(), true);
3033
plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3034
plist.add (ARDOUR::Properties::length, end - start + 1);
3035
plist.add (ARDOUR::Properties::name, new_name);
3037
new_regions.push_back (RegionFactory::create (current, plist));
3042
Editor::split_multichannel_region ()
3044
RegionSelection rs = get_regions_from_selection_and_entered ();
3050
vector< boost::shared_ptr<Region> > v;
3052
for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3053
(*x)->region()->separate_by_channel (*_session, v);
3058
Editor::new_region_from_selection ()
3060
region_from_selection ();
3061
cancel_selection ();
3065
add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3067
switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3068
// n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3069
case Evoral::OverlapNone:
3077
* - selected tracks, or if there are none...
3078
* - tracks containing selected regions, or if there are none...
3083
Editor::get_tracks_for_range_action () const
3087
if (selection->tracks.empty()) {
3089
/* use tracks with selected regions */
3091
RegionSelection rs = selection->regions;
3093
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3094
TimeAxisView* tv = &(*i)->get_time_axis_view();
3096
if (!t.contains (tv)) {
3102
/* no regions and no tracks: use all tracks */
3108
t = selection->tracks;
3111
return t.filter_to_unique_playlists();
3115
Editor::separate_regions_between (const TimeSelection& ts)
3117
bool in_command = false;
3118
boost::shared_ptr<Playlist> playlist;
3119
RegionSelection new_selection;
3121
TrackViewList tmptracks = get_tracks_for_range_action ();
3122
sort_track_selection (tmptracks);
3124
for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3126
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3132
if (!rtv->is_track()) {
3136
/* no edits to destructive tracks */
3138
if (rtv->track()->destructive()) {
3142
if ((playlist = rtv->playlist()) != 0) {
3144
playlist->clear_changes ();
3146
/* XXX need to consider musical time selections here at some point */
3148
for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3150
sigc::connection c = rtv->view()->RegionViewAdded.connect (
3151
sigc::mem_fun(*this, &Editor::collect_new_region_view));
3153
latest_regionviews.clear ();
3155
playlist->partition ((*t).start, (*t).end, false);
3159
if (!latest_regionviews.empty()) {
3161
rtv->view()->foreach_regionview (sigc::bind (
3162
sigc::ptr_fun (add_if_covered),
3163
&(*t), &new_selection));
3166
begin_reversible_command (_("separate"));
3170
/* pick up changes to existing regions */
3172
vector<Command*> cmds;
3173
playlist->rdiff (cmds);
3174
_session->add_commands (cmds);
3176
/* pick up changes to the playlist itself (adds/removes)
3179
_session->add_command(new StatefulDiffCommand (playlist));
3186
// selection->set (new_selection);
3188
commit_reversible_command ();
3192
struct PlaylistState {
3193
boost::shared_ptr<Playlist> playlist;
3197
/** Take tracks from get_tracks_for_range_action and cut any regions
3198
* on those tracks so that the tracks are empty over the time
3202
Editor::separate_region_from_selection ()
3204
/* preferentially use *all* ranges in the time selection if we're in range mode
3205
to allow discontiguous operation, since get_edit_op_range() currently
3206
returns a single range.
3209
if (!selection->time.empty()) {
3211
separate_regions_between (selection->time);
3218
if (get_edit_op_range (start, end)) {
3220
AudioRange ar (start, end, 1);
3224
separate_regions_between (ts);
3230
Editor::separate_region_from_punch ()
3232
Location* loc = _session->locations()->auto_punch_location();
3234
separate_regions_using_location (*loc);
3239
Editor::separate_region_from_loop ()
3241
Location* loc = _session->locations()->auto_loop_location();
3243
separate_regions_using_location (*loc);
3248
Editor::separate_regions_using_location (Location& loc)
3250
if (loc.is_mark()) {
3254
AudioRange ar (loc.start(), loc.end(), 1);
3259
separate_regions_between (ts);
3262
/** Separate regions under the selected region */
3264
Editor::separate_under_selected_regions ()
3266
vector<PlaylistState> playlists;
3270
rs = get_regions_from_selection_and_entered();
3272
if (!_session || rs.empty()) {
3276
begin_reversible_command (_("separate region under"));
3278
list<boost::shared_ptr<Region> > regions_to_remove;
3280
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3281
// we can't just remove the region(s) in this loop because
3282
// this removes them from the RegionSelection, and they thus
3283
// disappear from underneath the iterator, and the ++i above
3284
// SEGVs in a puzzling fashion.
3286
// so, first iterate over the regions to be removed from rs and
3287
// add them to the regions_to_remove list, and then
3288
// iterate over the list to actually remove them.
3290
regions_to_remove.push_back ((*i)->region());
3293
for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3295
boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3298
// is this check necessary?
3302
vector<PlaylistState>::iterator i;
3304
//only take state if this is a new playlist.
3305
for (i = playlists.begin(); i != playlists.end(); ++i) {
3306
if ((*i).playlist == playlist) {
3311
if (i == playlists.end()) {
3313
PlaylistState before;
3314
before.playlist = playlist;
3315
before.before = &playlist->get_state();
3316
playlist->clear_changes ();
3317
playlist->freeze ();
3318
playlists.push_back(before);
3321
//Partition on the region bounds
3322
playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3324
//Re-add region that was just removed due to the partition operation
3325
playlist->add_region( (*rl), (*rl)->first_frame() );
3328
vector<PlaylistState>::iterator pl;
3330
for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3331
(*pl).playlist->thaw ();
3332
_session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3335
commit_reversible_command ();
3339
Editor::crop_region_to_selection ()
3341
if (!selection->time.empty()) {
3343
begin_reversible_command (_("Crop Regions to Time Selection"));
3344
for (std::list<AudioRange>::iterator i = selection->time.begin(); i != selection->time.end(); ++i) {
3345
crop_region_to ((*i).start, (*i).end);
3347
commit_reversible_command();
3353
if (get_edit_op_range (start, end)) {
3354
begin_reversible_command (_("Crop Regions to Edit Range"));
3356
crop_region_to (start, end);
3358
commit_reversible_command();
3365
Editor::crop_region_to (framepos_t start, framepos_t end)
3367
vector<boost::shared_ptr<Playlist> > playlists;
3368
boost::shared_ptr<Playlist> playlist;
3371
if (selection->tracks.empty()) {
3372
ts = track_views.filter_to_unique_playlists();
3374
ts = selection->tracks.filter_to_unique_playlists ();
3377
sort_track_selection (ts);
3379
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3381
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3387
boost::shared_ptr<Track> t = rtv->track();
3389
if (t != 0 && ! t->destructive()) {
3391
if ((playlist = rtv->playlist()) != 0) {
3392
playlists.push_back (playlist);
3397
if (playlists.empty()) {
3402
framepos_t new_start;
3404
framecnt_t new_length;
3406
for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3408
/* Only the top regions at start and end have to be cropped */
3409
boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3410
boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3412
vector<boost::shared_ptr<Region> > regions;
3414
if (region_at_start != 0) {
3415
regions.push_back (region_at_start);
3417
if (region_at_end != 0) {
3418
regions.push_back (region_at_end);
3421
/* now adjust lengths */
3422
for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3424
pos = (*i)->position();
3425
new_start = max (start, pos);
3426
if (max_framepos - pos > (*i)->length()) {
3427
new_end = pos + (*i)->length() - 1;
3429
new_end = max_framepos;
3431
new_end = min (end, new_end);
3432
new_length = new_end - new_start + 1;
3434
(*i)->clear_changes ();
3435
(*i)->trim_to (new_start, new_length);
3436
_session->add_command (new StatefulDiffCommand (*i));
3442
Editor::region_fill_track ()
3444
boost::shared_ptr<Playlist> playlist;
3445
RegionSelection regions = get_regions_from_selection_and_entered ();
3446
RegionSelection foo;
3448
framepos_t const end = _session->current_end_frame ();
3450
if (regions.empty () || regions.end_frame () + 1 >= end) {
3454
framepos_t const start_frame = regions.start ();
3455
framepos_t const end_frame = regions.end_frame ();
3456
framecnt_t const gap = end_frame - start_frame + 1;
3458
begin_reversible_command (Operations::region_fill);
3460
selection->clear_regions ();
3462
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3464
boost::shared_ptr<Region> r ((*i)->region());
3466
TimeAxisView& tv = (*i)->get_time_axis_view();
3467
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3468
latest_regionviews.clear ();
3469
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3471
framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3472
playlist = (*i)->region()->playlist();
3473
playlist->clear_changes ();
3474
playlist->duplicate_until (r, position, gap, end);
3475
_session->add_command(new StatefulDiffCommand (playlist));
3479
foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3483
selection->set (foo);
3486
commit_reversible_command ();
3490
Editor::set_region_sync_position ()
3492
set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3496
Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3498
bool in_command = false;
3500
for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3502
if (!(*r)->region()->covers (where)) {
3506
boost::shared_ptr<Region> region ((*r)->region());
3509
begin_reversible_command (_("set sync point"));
3513
region->clear_changes ();
3514
region->set_sync_position (where);
3515
_session->add_command(new StatefulDiffCommand (region));
3519
commit_reversible_command ();
3523
/** Remove the sync positions of the selection */
3525
Editor::remove_region_sync ()
3527
RegionSelection rs = get_regions_from_selection_and_entered ();
3533
begin_reversible_command (_("remove region sync"));
3535
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3537
(*i)->region()->clear_changes ();
3538
(*i)->region()->clear_sync_position ();
3539
_session->add_command(new StatefulDiffCommand ((*i)->region()));
3542
commit_reversible_command ();
3546
Editor::naturalize_region ()
3548
RegionSelection rs = get_regions_from_selection_and_entered ();
3554
if (rs.size() > 1) {
3555
begin_reversible_command (_("move regions to original position"));
3557
begin_reversible_command (_("move region to original position"));
3560
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3561
(*i)->region()->clear_changes ();
3562
(*i)->region()->move_to_natural_position ();
3563
_session->add_command (new StatefulDiffCommand ((*i)->region()));
3566
commit_reversible_command ();
3570
Editor::align_regions (RegionPoint what)
3572
RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3578
begin_reversible_command (_("align selection"));
3580
framepos_t const position = get_preferred_edit_position ();
3582
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3583
align_region_internal ((*i)->region(), what, position);
3586
commit_reversible_command ();
3589
struct RegionSortByTime {
3590
bool operator() (const RegionView* a, const RegionView* b) {
3591
return a->region()->position() < b->region()->position();
3596
Editor::align_regions_relative (RegionPoint point)
3598
RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3604
framepos_t const position = get_preferred_edit_position ();
3606
framepos_t distance = 0;
3610
list<RegionView*> sorted;
3611
rs.by_position (sorted);
3613
boost::shared_ptr<Region> r ((*sorted.begin())->region());
3618
if (position > r->position()) {
3619
distance = position - r->position();
3621
distance = r->position() - position;
3627
if (position > r->last_frame()) {
3628
distance = position - r->last_frame();
3629
pos = r->position() + distance;
3631
distance = r->last_frame() - position;
3632
pos = r->position() - distance;
3638
pos = r->adjust_to_sync (position);
3639
if (pos > r->position()) {
3640
distance = pos - r->position();
3642
distance = r->position() - pos;
3648
if (pos == r->position()) {
3652
begin_reversible_command (_("align selection (relative)"));
3654
/* move first one specially */
3656
r->clear_changes ();
3657
r->set_position (pos);
3658
_session->add_command(new StatefulDiffCommand (r));
3660
/* move rest by the same amount */
3664
for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3666
boost::shared_ptr<Region> region ((*i)->region());
3668
region->clear_changes ();
3671
region->set_position (region->position() + distance);
3673
region->set_position (region->position() - distance);
3676
_session->add_command(new StatefulDiffCommand (region));
3680
commit_reversible_command ();
3684
Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3686
begin_reversible_command (_("align region"));
3687
align_region_internal (region, point, position);
3688
commit_reversible_command ();
3692
Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3694
region->clear_changes ();
3698
region->set_position (region->adjust_to_sync (position));
3702
if (position > region->length()) {
3703
region->set_position (position - region->length());
3708
region->set_position (position);
3712
_session->add_command(new StatefulDiffCommand (region));
3716
Editor::trim_region_front ()
3722
Editor::trim_region_back ()
3724
trim_region (false);
3728
Editor::trim_region (bool front)
3730
framepos_t where = get_preferred_edit_position();
3731
RegionSelection rs = get_regions_from_selection_and_edit_point ();
3737
begin_reversible_command (front ? _("trim front") : _("trim back"));
3739
for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3740
if (!(*i)->region()->locked()) {
3742
(*i)->region()->clear_changes ();
3745
(*i)->region()->trim_front (where);
3747
(*i)->region()->trim_end (where);
3750
_session->add_command (new StatefulDiffCommand ((*i)->region()));
3754
commit_reversible_command ();
3757
/** Trim the end of the selected regions to the position of the edit cursor */
3759
Editor::trim_region_to_loop ()
3761
Location* loc = _session->locations()->auto_loop_location();
3765
trim_region_to_location (*loc, _("trim to loop"));
3769
Editor::trim_region_to_punch ()
3771
Location* loc = _session->locations()->auto_punch_location();
3775
trim_region_to_location (*loc, _("trim to punch"));
3779
Editor::trim_region_to_location (const Location& loc, const char* str)
3781
RegionSelection rs = get_regions_from_selection_and_entered ();
3782
bool in_command = false;
3784
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3785
RegionView* rv = (*x);
3787
/* require region to span proposed trim */
3788
switch (rv->region()->coverage (loc.start(), loc.end())) {
3789
case Evoral::OverlapInternal:
3795
RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3803
start = loc.start();
3806
rv->region()->clear_changes ();
3807
rv->region()->trim_to (start, (end - start));
3810
begin_reversible_command (str);
3813
_session->add_command(new StatefulDiffCommand (rv->region()));
3817
commit_reversible_command ();
3822
Editor::trim_region_to_previous_region_end ()
3824
return trim_to_region(false);
3828
Editor::trim_region_to_next_region_start ()
3830
return trim_to_region(true);
3834
Editor::trim_to_region(bool forward)
3836
RegionSelection rs = get_regions_from_selection_and_entered ();
3837
bool in_command = false;
3839
boost::shared_ptr<Region> next_region;
3841
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3843
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3849
AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3855
boost::shared_ptr<Region> region = arv->region();
3856
boost::shared_ptr<Playlist> playlist (region->playlist());
3858
region->clear_changes ();
3862
next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3868
region->trim_end (next_region->first_frame() - 1);
3869
arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3873
next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3879
region->trim_front (next_region->last_frame() + 1);
3880
arv->region_changed (ARDOUR::bounds_change);
3884
begin_reversible_command (_("trim to region"));
3887
_session->add_command(new StatefulDiffCommand (region));
3891
commit_reversible_command ();
3896
Editor::unfreeze_route ()
3898
if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3902
clicked_routeview->track()->unfreeze ();
3906
Editor::_freeze_thread (void* arg)
3908
return static_cast<Editor*>(arg)->freeze_thread ();
3912
Editor::freeze_thread ()
3914
/* create event pool because we may need to talk to the session */
3915
SessionEvent::create_per_thread_pool ("freeze events", 64);
3916
/* create per-thread buffers for process() tree to use */
3917
clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3918
current_interthread_info->done = true;
3923
Editor::freeze_route ()
3929
/* stop transport before we start. this is important */
3931
_session->request_transport_speed (0.0);
3933
/* wait for just a little while, because the above call is asynchronous */
3935
Glib::usleep (250000);
3937
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3941
if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3943
_("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3944
"This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3946
d.set_title (_("Cannot freeze"));
3951
if (clicked_routeview->track()->has_external_redirects()) {
3952
MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3953
"Freezing will only process the signal as far as the first send/insert/return."),
3954
clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3956
d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3957
d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3958
d.set_title (_("Freeze Limits"));
3960
int response = d.run ();
3963
case Gtk::RESPONSE_CANCEL:
3970
InterThreadInfo itt;
3971
current_interthread_info = &itt;
3973
InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3975
pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3977
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3979
while (!itt.done && !itt.cancel) {
3980
gtk_main_iteration ();
3983
pthread_join (itt.thread, 0);
3984
current_interthread_info = 0;
3988
Editor::bounce_range_selection (bool replace, bool enable_processing)
3990
if (selection->time.empty()) {
3994
TrackSelection views = selection->tracks;
3996
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3998
if (enable_processing) {
4000
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4002
if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4004
_("You can't perform this operation because the processing of the signal "
4005
"will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4006
"You can do this without processing, which is a different operation.")
4008
d.set_title (_("Cannot bounce"));
4015
framepos_t start = selection->time[clicked_selection].start;
4016
framepos_t end = selection->time[clicked_selection].end;
4017
framepos_t cnt = end - start + 1;
4018
bool in_command = false;
4020
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4022
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4028
boost::shared_ptr<Playlist> playlist;
4030
if ((playlist = rtv->playlist()) == 0) {
4034
InterThreadInfo itt;
4036
playlist->clear_changes ();
4037
playlist->clear_owned_changes ();
4039
boost::shared_ptr<Region> r;
4041
if (enable_processing) {
4042
r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4044
r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4052
list<AudioRange> ranges;
4053
ranges.push_back (AudioRange (start, start+cnt, 0));
4054
playlist->cut (ranges); // discard result
4055
playlist->add_region (r, start);
4059
begin_reversible_command (_("bounce range"));
4062
vector<Command*> cmds;
4063
playlist->rdiff (cmds);
4064
_session->add_commands (cmds);
4066
_session->add_command (new StatefulDiffCommand (playlist));
4070
commit_reversible_command ();
4074
/** Delete selected regions, automation points or a time range */
4078
//special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4079
//we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4080
bool deleted = false;
4081
if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4082
deleted = current_mixer_strip->delete_processors ();
4088
/** Cut selected regions, automation points or a time range */
4095
/** Copy selected regions, automation points or a time range */
4103
/** @return true if a Cut, Copy or Clear is possible */
4105
Editor::can_cut_copy () const
4107
if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4114
/** Cut, copy or clear selected regions, automation points or a time range.
4115
* @param op Operation (Delete, Cut, Copy or Clear)
4118
Editor::cut_copy (CutCopyOp op)
4120
/* only cancel selection if cut/copy is successful.*/
4126
opname = _("delete");
4135
opname = _("clear");
4139
/* if we're deleting something, and the mouse is still pressed,
4140
the thing we started a drag for will be gone when we release
4141
the mouse button(s). avoid this. see part 2 at the end of
4145
if (op == Delete || op == Cut || op == Clear) {
4146
if (_drags->active ()) {
4151
if ( op != Delete ) { //"Delete" doesn't change copy/paste buf
4152
cut_buffer->clear ();
4155
if (entered_marker) {
4157
/* cut/delete op while pointing at a marker */
4160
Location* loc = find_location_from_marker (entered_marker, ignored);
4162
if (_session && loc) {
4163
entered_marker = NULL;
4164
Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4171
switch (mouse_mode) {
4174
begin_reversible_command (opname + ' ' + X_("MIDI"));
4176
commit_reversible_command ();
4182
bool did_edit = false;
4184
if (!selection->regions.empty() || !selection->points.empty()) {
4185
begin_reversible_command (opname + ' ' + _("objects"));
4188
if (!selection->regions.empty()) {
4189
cut_copy_regions (op, selection->regions);
4191
if (op == Cut || op == Delete) {
4192
selection->clear_regions ();
4196
if (!selection->points.empty()) {
4197
cut_copy_points (op);
4199
if (op == Cut || op == Delete) {
4200
selection->clear_points ();
4203
} else if (selection->time.empty()) {
4204
framepos_t start, end;
4205
/* no time selection, see if we can get an edit range
4208
if (get_edit_op_range (start, end)) {
4209
selection->set (start, end);
4211
} else if (!selection->time.empty()) {
4212
begin_reversible_command (opname + ' ' + _("range"));
4215
cut_copy_ranges (op);
4217
if (op == Cut || op == Delete) {
4218
selection->clear_time ();
4223
/* reset repeated paste state */
4225
last_paste_pos = -1;
4226
commit_reversible_command ();
4229
if (op == Delete || op == Cut || op == Clear) {
4235
struct AutomationRecord {
4236
AutomationRecord () : state (0) , line(NULL) {}
4237
AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4239
XMLNode* state; ///< state before any operation
4240
const AutomationLine* line; ///< line this came from
4241
boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4244
struct PointsSelectionPositionSorter {
4245
bool operator() (ControlPoint* a, ControlPoint* b) {
4246
return (*(a->model()))->when < (*(b->model()))->when;
4250
/** Cut, copy or clear selected automation points.
4251
* @param op Operation (Cut, Copy or Clear)
4254
Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4256
if (selection->points.empty ()) {
4260
/* XXX: not ideal, as there may be more than one track involved in the point selection */
4261
_last_cut_copy_source_track = &selection->points.front()->line().trackview;
4263
/* Keep a record of the AutomationLists that we end up using in this operation */
4264
typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4267
/* user could select points in any order */
4268
selection->points.sort(PointsSelectionPositionSorter ());
4270
/* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4271
for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4272
const AutomationLine& line = (*sel_point)->line();
4273
const boost::shared_ptr<AutomationList> al = line.the_list();
4274
if (lists.find (al) == lists.end ()) {
4275
/* We haven't seen this list yet, so make a record for it. This includes
4276
taking a copy of its current state, in case this is needed for undo later.
4278
lists[al] = AutomationRecord (&al->get_state (), &line);
4282
if (op == Cut || op == Copy) {
4283
/* This operation will involve putting things in the cut buffer, so create an empty
4284
ControlList for each of our source lists to put the cut buffer data in.
4286
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4287
i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4290
/* Add all selected points to the relevant copy ControlLists */
4291
MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4292
for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4293
boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4294
AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4296
lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4298
/* Update earliest MIDI start time in beats */
4299
earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4301
/* Update earliest session start time in frames */
4302
start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4306
/* Snap start time backwards, so copy/paste is snap aligned. */
4308
if (earliest == Evoral::Beats::max()) {
4309
earliest = Evoral::Beats(); // Weird... don't offset
4311
earliest.round_down_to_beat();
4313
if (start.frame == std::numeric_limits<double>::max()) {
4314
start.frame = 0; // Weird... don't offset
4316
snap_to(start, RoundDownMaybe);
4319
const double line_offset = midi ? earliest.to_double() : start.frame;
4320
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4321
/* Correct this copy list so that it is relative to the earliest
4322
start time, so relative ordering between points is preserved
4323
when copying from several lists and the paste starts at the
4324
earliest copied piece of data. */
4325
boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4326
for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4327
(*ctrl_evt)->when -= line_offset;
4330
/* And add it to the cut buffer */
4331
cut_buffer->add (al_cpy);
4335
if (op == Delete || op == Cut) {
4336
/* This operation needs to remove things from the main AutomationList, so do that now */
4338
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4339
i->first->freeze ();
4342
/* Remove each selected point from its AutomationList */
4343
for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4344
AutomationLine& line = (*sel_point)->line ();
4345
boost::shared_ptr<AutomationList> al = line.the_list();
4349
if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4350
/* removing of first and last gain point in region gain lines is prohibited*/
4351
if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4357
al->erase ((*sel_point)->model ());
4361
/* Thaw the lists and add undo records for them */
4362
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4363
boost::shared_ptr<AutomationList> al = i->first;
4365
_session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4370
/** Cut, copy or clear selected automation points.
4371
* @param op Operation (Cut, Copy or Clear)
4374
Editor::cut_copy_midi (CutCopyOp op)
4376
Evoral::Beats earliest = Evoral::Beats::max();
4377
for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4378
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4380
if (!mrv->selection().empty()) {
4381
earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4383
mrv->cut_copy_clear (op);
4385
/* XXX: not ideal, as there may be more than one track involved in the selection */
4386
_last_cut_copy_source_track = &mrv->get_time_axis_view();
4390
if (!selection->points.empty()) {
4391
cut_copy_points (op, earliest, true);
4392
if (op == Cut || op == Delete) {
4393
selection->clear_points ();
4398
struct lt_playlist {
4399
bool operator () (const PlaylistState& a, const PlaylistState& b) {
4400
return a.playlist < b.playlist;
4404
struct PlaylistMapping {
4406
boost::shared_ptr<Playlist> pl;
4408
PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4411
/** Remove `clicked_regionview' */
4413
Editor::remove_clicked_region ()
4415
if (clicked_routeview == 0 || clicked_regionview == 0) {
4419
begin_reversible_command (_("remove region"));
4421
boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4423
playlist->clear_changes ();
4424
playlist->clear_owned_changes ();
4425
playlist->remove_region (clicked_regionview->region());
4426
if (Config->get_edit_mode() == Ripple)
4427
playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4429
/* We might have removed regions, which alters other regions' layering_index,
4430
so we need to do a recursive diff here.
4432
vector<Command*> cmds;
4433
playlist->rdiff (cmds);
4434
_session->add_commands (cmds);
4436
_session->add_command(new StatefulDiffCommand (playlist));
4437
commit_reversible_command ();
4441
/** Remove the selected regions */
4443
Editor::remove_selected_regions ()
4445
RegionSelection rs = get_regions_from_selection_and_entered ();
4447
if (!_session || rs.empty()) {
4451
list<boost::shared_ptr<Region> > regions_to_remove;
4453
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4454
// we can't just remove the region(s) in this loop because
4455
// this removes them from the RegionSelection, and they thus
4456
// disappear from underneath the iterator, and the ++i above
4457
// SEGVs in a puzzling fashion.
4459
// so, first iterate over the regions to be removed from rs and
4460
// add them to the regions_to_remove list, and then
4461
// iterate over the list to actually remove them.
4463
regions_to_remove.push_back ((*i)->region());
4466
vector<boost::shared_ptr<Playlist> > playlists;
4468
for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4470
boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4473
// is this check necessary?
4477
/* get_regions_from_selection_and_entered() guarantees that
4478
the playlists involved are unique, so there is no need
4482
playlists.push_back (playlist);
4484
playlist->clear_changes ();
4485
playlist->clear_owned_changes ();
4486
playlist->freeze ();
4487
playlist->remove_region (*rl);
4488
if (Config->get_edit_mode() == Ripple)
4489
playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4493
vector<boost::shared_ptr<Playlist> >::iterator pl;
4494
bool in_command = false;
4496
for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4499
/* We might have removed regions, which alters other regions' layering_index,
4500
so we need to do a recursive diff here.
4504
begin_reversible_command (_("remove region"));
4507
vector<Command*> cmds;
4508
(*pl)->rdiff (cmds);
4509
_session->add_commands (cmds);
4511
_session->add_command(new StatefulDiffCommand (*pl));
4515
commit_reversible_command ();
4519
/** Cut, copy or clear selected regions.
4520
* @param op Operation (Cut, Copy or Clear)
4523
Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4525
/* we can't use a std::map here because the ordering is important, and we can't trivially sort
4526
a map when we want ordered access to both elements. i think.
4529
vector<PlaylistMapping> pmap;
4531
framepos_t first_position = max_framepos;
4533
typedef set<boost::shared_ptr<Playlist> > FreezeList;
4534
FreezeList freezelist;
4536
/* get ordering correct before we cut/copy */
4538
rs.sort_by_position_and_track ();
4540
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4542
first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4544
if (op == Cut || op == Clear || op == Delete) {
4545
boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4548
FreezeList::iterator fl;
4550
// only take state if this is a new playlist.
4551
for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4557
if (fl == freezelist.end()) {
4558
pl->clear_changes();
4559
pl->clear_owned_changes ();
4561
freezelist.insert (pl);
4566
TimeAxisView* tv = &(*x)->get_time_axis_view();
4567
vector<PlaylistMapping>::iterator z;
4569
for (z = pmap.begin(); z != pmap.end(); ++z) {
4570
if ((*z).tv == tv) {
4575
if (z == pmap.end()) {
4576
pmap.push_back (PlaylistMapping (tv));
4580
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4582
boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4585
/* region not yet associated with a playlist (e.g. unfinished
4592
TimeAxisView& tv = (*x)->get_time_axis_view();
4593
boost::shared_ptr<Playlist> npl;
4594
RegionSelection::iterator tmp;
4601
vector<PlaylistMapping>::iterator z;
4603
for (z = pmap.begin(); z != pmap.end(); ++z) {
4604
if ((*z).tv == &tv) {
4609
assert (z != pmap.end());
4612
npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4620
boost::shared_ptr<Region> r = (*x)->region();
4621
boost::shared_ptr<Region> _xx;
4627
pl->remove_region (r);
4628
if (Config->get_edit_mode() == Ripple)
4629
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4633
_xx = RegionFactory::create (r);
4634
npl->add_region (_xx, r->position() - first_position);
4635
pl->remove_region (r);
4636
if (Config->get_edit_mode() == Ripple)
4637
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4641
/* copy region before adding, so we're not putting same object into two different playlists */
4642
npl->add_region (RegionFactory::create (r), r->position() - first_position);
4646
pl->remove_region (r);
4647
if (Config->get_edit_mode() == Ripple)
4648
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4657
list<boost::shared_ptr<Playlist> > foo;
4659
/* the pmap is in the same order as the tracks in which selected regions occurred */
4661
for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4664
foo.push_back ((*i).pl);
4669
cut_buffer->set (foo);
4673
_last_cut_copy_source_track = 0;
4675
_last_cut_copy_source_track = pmap.front().tv;
4679
for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4682
/* We might have removed regions, which alters other regions' layering_index,
4683
so we need to do a recursive diff here.
4685
vector<Command*> cmds;
4686
(*pl)->rdiff (cmds);
4687
_session->add_commands (cmds);
4689
_session->add_command (new StatefulDiffCommand (*pl));
4694
Editor::cut_copy_ranges (CutCopyOp op)
4696
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4698
/* Sort the track selection now, so that it if is used, the playlists
4699
selected by the calls below to cut_copy_clear are in the order that
4700
their tracks appear in the editor. This makes things like paste
4701
of ranges work properly.
4704
sort_track_selection (ts);
4707
if (!entered_track) {
4710
ts.push_back (entered_track);
4713
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4714
(*i)->cut_copy_clear (*selection, op);
4719
Editor::paste (float times, bool from_context)
4721
DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4722
MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4723
paste_internal (where.frame, times, 0);
4727
Editor::mouse_paste ()
4729
MusicFrame where (0, 0);
4731
if (!mouse_frame (where.frame, ignored)) {
4736
paste_internal (where.frame, 1, where.division);
4740
Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4742
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4744
if (cut_buffer->empty(internal_editing())) {
4748
if (position == max_framepos) {
4749
position = get_preferred_edit_position();
4750
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4753
if (position == last_paste_pos) {
4754
/* repeated paste in the same position */
4757
/* paste in new location, reset repeated paste state */
4759
last_paste_pos = position;
4762
/* get everything in the correct order */
4765
if (!selection->tracks.empty()) {
4766
/* If there is a track selection, paste into exactly those tracks and
4767
* only those tracks. This allows the user to be explicit and override
4768
* the below "do the reasonable thing" logic. */
4769
ts = selection->tracks.filter_to_unique_playlists ();
4770
sort_track_selection (ts);
4772
/* Figure out which track to base the paste at. */
4773
TimeAxisView* base_track = NULL;
4774
if (_edit_point == Editing::EditAtMouse && entered_track) {
4775
/* With the mouse edit point, paste onto the track under the mouse. */
4776
base_track = entered_track;
4777
} else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4778
/* With the mouse edit point, paste onto the track of the region under the mouse. */
4779
base_track = &entered_regionview->get_time_axis_view();
4780
} else if (_last_cut_copy_source_track) {
4781
/* Paste to the track that the cut/copy came from (see mantis #333). */
4782
base_track = _last_cut_copy_source_track;
4784
/* This is "impossible" since we've copied... well, do nothing. */
4788
/* Walk up to parent if necessary, so base track is a route. */
4789
while (base_track->get_parent()) {
4790
base_track = base_track->get_parent();
4793
/* Add base track and all tracks below it. The paste logic will select
4794
the appropriate object types from the cut buffer in relative order. */
4795
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4796
if ((*i)->order() >= base_track->order()) {
4801
/* Sort tracks so the nth track of type T will pick the nth object of type T. */
4802
sort_track_selection (ts);
4804
/* Add automation children of each track in order, for pasting several lines. */
4805
for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4806
/* Add any automation children for pasting several lines */
4807
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4812
typedef RouteTimeAxisView::AutomationTracks ATracks;
4813
const ATracks& atracks = rtv->automation_tracks();
4814
for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4815
i = ts.insert(i, a->second.get());
4820
/* We now have a list of trackviews starting at base_track, including
4821
automation children, in the order shown in the editor, e.g. R1,
4822
R1.A1, R1.A2, R2, R2.A1, ... */
4825
begin_reversible_command (Operations::paste);
4827
if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4828
dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4829
/* Only one line copied, and one automation track selected. Do a
4830
"greedy" paste from one automation type to another. */
4832
PasteContext ctx(paste_count, times, ItemCounts(), true);
4833
ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4837
/* Paste into tracks */
4839
PasteContext ctx(paste_count, times, ItemCounts(), false);
4840
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4841
(*i)->paste (position, *cut_buffer, ctx, sub_num);
4845
commit_reversible_command ();
4849
Editor::duplicate_regions (float times)
4851
RegionSelection rs (get_regions_from_selection_and_entered());
4852
duplicate_some_regions (rs, times);
4856
Editor::duplicate_some_regions (RegionSelection& regions, float times)
4858
if (regions.empty ()) {
4862
boost::shared_ptr<Playlist> playlist;
4863
RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4864
RegionSelection foo;
4866
framepos_t const start_frame = regions.start ();
4867
framepos_t const end_frame = regions.end_frame ();
4868
framecnt_t const gap = end_frame - start_frame + 1;
4870
begin_reversible_command (Operations::duplicate_region);
4872
selection->clear_regions ();
4874
for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4876
boost::shared_ptr<Region> r ((*i)->region());
4878
TimeAxisView& tv = (*i)->get_time_axis_view();
4879
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4880
latest_regionviews.clear ();
4881
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4883
framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4884
playlist = (*i)->region()->playlist();
4885
playlist->clear_changes ();
4886
playlist->duplicate (r, position, gap, times);
4887
_session->add_command(new StatefulDiffCommand (playlist));
4891
foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4895
selection->set (foo);
4898
commit_reversible_command ();
4902
Editor::duplicate_selection (float times)
4904
if (selection->time.empty() || selection->tracks.empty()) {
4908
boost::shared_ptr<Playlist> playlist;
4910
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4912
bool in_command = false;
4914
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4915
if ((playlist = (*i)->playlist()) == 0) {
4918
playlist->clear_changes ();
4920
if (clicked_selection) {
4921
playlist->duplicate_range (selection->time[clicked_selection], times);
4923
playlist->duplicate_ranges (selection->time, times);
4927
begin_reversible_command (_("duplicate range selection"));
4930
_session->add_command (new StatefulDiffCommand (playlist));
4935
if (times == 1.0f) {
4936
// now "move" range selection to after the current range selection
4937
framecnt_t distance = 0;
4939
if (clicked_selection) {
4941
selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4943
distance = selection->time.end_frame () - selection->time.start ();
4946
selection->move_time (distance);
4948
commit_reversible_command ();
4952
/** Reset all selected points to the relevant default value */
4954
Editor::reset_point_selection ()
4956
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4957
ARDOUR::AutomationList::iterator j = (*i)->model ();
4958
(*j)->value = (*i)->line().the_list()->descriptor ().normal;
4963
Editor::center_playhead ()
4965
float const page = _visible_canvas_width * samples_per_pixel;
4966
center_screen_internal (playhead_cursor->current_frame (), page);
4970
Editor::center_edit_point ()
4972
float const page = _visible_canvas_width * samples_per_pixel;
4973
center_screen_internal (get_preferred_edit_position(), page);
4976
/** Caller must begin and commit a reversible command */
4978
Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4980
playlist->clear_changes ();
4982
_session->add_command (new StatefulDiffCommand (playlist));
4986
Editor::nudge_track (bool use_edit, bool forwards)
4988
boost::shared_ptr<Playlist> playlist;
4989
framepos_t distance;
4990
framepos_t next_distance;
4994
start = get_preferred_edit_position();
4999
if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5003
if (selection->tracks.empty()) {
5007
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5008
bool in_command = false;
5010
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5012
if ((playlist = (*i)->playlist()) == 0) {
5016
playlist->clear_changes ();
5017
playlist->clear_owned_changes ();
5019
playlist->nudge_after (start, distance, forwards);
5022
begin_reversible_command (_("nudge track"));
5025
vector<Command*> cmds;
5027
playlist->rdiff (cmds);
5028
_session->add_commands (cmds);
5030
_session->add_command (new StatefulDiffCommand (playlist));
5034
commit_reversible_command ();
5039
Editor::remove_last_capture ()
5041
vector<string> choices;
5048
if (Config->get_verify_remove_last_capture()) {
5049
prompt = _("Do you really want to destroy the last capture?"
5050
"\n(This is destructive and cannot be undone)");
5052
choices.push_back (_("No, do nothing."));
5053
choices.push_back (_("Yes, destroy it."));
5055
Choice prompter (_("Destroy last capture"), prompt, choices);
5057
if (prompter.run () == 1) {
5058
_session->remove_last_capture ();
5059
_regions->redisplay ();
5063
_session->remove_last_capture();
5064
_regions->redisplay ();
5069
Editor::normalize_region ()
5075
RegionSelection rs = get_regions_from_selection_and_entered ();
5081
NormalizeDialog dialog (rs.size() > 1);
5083
if (dialog.run () != RESPONSE_ACCEPT) {
5087
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5090
/* XXX: should really only count audio regions here */
5091
int const regions = rs.size ();
5093
/* Make a list of the selected audio regions' maximum amplitudes, and also
5094
obtain the maximum amplitude of them all.
5096
list<double> max_amps;
5097
list<double> rms_vals;
5100
bool use_rms = dialog.constrain_rms ();
5102
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5103
AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5107
dialog.descend (1.0 / regions);
5108
double const a = arv->audio_region()->maximum_amplitude (&dialog);
5110
double r = arv->audio_region()->rms (&dialog);
5111
max_rms = max (max_rms, r);
5112
rms_vals.push_back (r);
5116
/* the user cancelled the operation */
5120
max_amps.push_back (a);
5121
max_amp = max (max_amp, a);
5125
list<double>::const_iterator a = max_amps.begin ();
5126
list<double>::const_iterator l = rms_vals.begin ();
5127
bool in_command = false;
5129
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5130
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5135
arv->region()->clear_changes ();
5137
double amp = dialog.normalize_individually() ? *a : max_amp;
5138
double target = dialog.target_peak (); // dB
5141
double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5142
const double t_rms = dialog.target_rms ();
5143
const gain_t c_peak = dB_to_coefficient (target);
5144
const gain_t c_rms = dB_to_coefficient (t_rms);
5145
if ((amp_rms / c_rms) > (amp / c_peak)) {
5151
arv->audio_region()->normalize (amp, target);
5154
begin_reversible_command (_("normalize"));
5157
_session->add_command (new StatefulDiffCommand (arv->region()));
5164
commit_reversible_command ();
5170
Editor::reset_region_scale_amplitude ()
5176
RegionSelection rs = get_regions_from_selection_and_entered ();
5182
bool in_command = false;
5184
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5185
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5188
arv->region()->clear_changes ();
5189
arv->audio_region()->set_scale_amplitude (1.0f);
5192
begin_reversible_command ("reset gain");
5195
_session->add_command (new StatefulDiffCommand (arv->region()));
5199
commit_reversible_command ();
5204
Editor::adjust_region_gain (bool up)
5206
RegionSelection rs = get_regions_from_selection_and_entered ();
5208
if (!_session || rs.empty()) {
5212
bool in_command = false;
5214
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5215
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5220
arv->region()->clear_changes ();
5222
double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5230
arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5233
begin_reversible_command ("adjust region gain");
5236
_session->add_command (new StatefulDiffCommand (arv->region()));
5240
commit_reversible_command ();
5245
Editor::reset_region_gain ()
5247
RegionSelection rs = get_regions_from_selection_and_entered ();
5249
if (!_session || rs.empty()) {
5253
bool in_command = false;
5255
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5256
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5261
arv->region()->clear_changes ();
5263
arv->audio_region()->set_scale_amplitude (1.0f);
5266
begin_reversible_command ("reset region gain");
5269
_session->add_command (new StatefulDiffCommand (arv->region()));
5273
commit_reversible_command ();
5278
Editor::reverse_region ()
5284
Reverse rev (*_session);
5285
apply_filter (rev, _("reverse regions"));
5289
Editor::strip_region_silence ()
5295
RegionSelection rs = get_regions_from_selection_and_entered ();
5301
std::list<RegionView*> audio_only;
5303
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5304
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5306
audio_only.push_back (arv);
5310
assert (!audio_only.empty());
5312
StripSilenceDialog d (_session, audio_only);
5313
int const r = d.run ();
5317
if (r == Gtk::RESPONSE_OK) {
5318
ARDOUR::AudioIntervalMap silences;
5319
d.silences (silences);
5320
StripSilence s (*_session, silences, d.fade_length());
5322
apply_filter (s, _("strip silence"), &d);
5327
Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5329
Evoral::Sequence<Evoral::Beats>::Notes selected;
5330
mrv.selection_as_notelist (selected, true);
5332
vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5333
v.push_back (selected);
5335
Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5337
return op (mrv.midi_region()->model(), pos_beats, v);
5341
Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5347
bool in_command = false;
5349
for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5350
RegionSelection::const_iterator tmp = r;
5353
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5356
Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5359
begin_reversible_command (op.name ());
5363
_session->add_command (cmd);
5371
commit_reversible_command ();
5376
Editor::fork_region ()
5378
RegionSelection rs = get_regions_from_selection_and_entered ();
5384
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5385
bool in_command = false;
5389
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5390
RegionSelection::iterator tmp = r;
5393
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5397
boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5398
boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5399
boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5402
begin_reversible_command (_("Fork Region(s)"));
5405
playlist->clear_changes ();
5406
playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5407
_session->add_command(new StatefulDiffCommand (playlist));
5409
error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5417
commit_reversible_command ();
5422
Editor::quantize_region ()
5425
quantize_regions(get_regions_from_selection_and_entered ());
5430
Editor::quantize_regions (const RegionSelection& rs)
5432
if (rs.n_midi_regions() == 0) {
5436
if (!quantize_dialog) {
5437
quantize_dialog = new QuantizeDialog (*this);
5440
if (quantize_dialog->is_mapped()) {
5441
/* in progress already */
5445
quantize_dialog->present ();
5446
const int r = quantize_dialog->run ();
5447
quantize_dialog->hide ();
5449
if (r == Gtk::RESPONSE_OK) {
5450
Quantize quant (quantize_dialog->snap_start(),
5451
quantize_dialog->snap_end(),
5452
quantize_dialog->start_grid_size(),
5453
quantize_dialog->end_grid_size(),
5454
quantize_dialog->strength(),
5455
quantize_dialog->swing(),
5456
quantize_dialog->threshold());
5458
apply_midi_note_edit_op (quant, rs);
5463
Editor::legatize_region (bool shrink_only)
5466
legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5471
Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5473
if (rs.n_midi_regions() == 0) {
5477
Legatize legatize(shrink_only);
5478
apply_midi_note_edit_op (legatize, rs);
5482
Editor::transform_region ()
5485
transform_regions(get_regions_from_selection_and_entered ());
5490
Editor::transform_regions (const RegionSelection& rs)
5492
if (rs.n_midi_regions() == 0) {
5499
const int r = td.run();
5502
if (r == Gtk::RESPONSE_OK) {
5503
Transform transform(td.get());
5504
apply_midi_note_edit_op(transform, rs);
5509
Editor::transpose_region ()
5512
transpose_regions(get_regions_from_selection_and_entered ());
5517
Editor::transpose_regions (const RegionSelection& rs)
5519
if (rs.n_midi_regions() == 0) {
5524
int const r = d.run ();
5526
if (r == RESPONSE_ACCEPT) {
5527
Transpose transpose(d.semitones ());
5528
apply_midi_note_edit_op (transpose, rs);
5533
Editor::insert_patch_change (bool from_context)
5535
RegionSelection rs = get_regions_from_selection_and_entered ();
5541
const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5543
/* XXX: bit of a hack; use the MIDNAM from the first selected region;
5544
there may be more than one, but the PatchChangeDialog can only offer
5545
one set of patch menus.
5547
MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5549
Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5550
PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5552
if (d.run() == RESPONSE_CANCEL) {
5556
for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5557
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5559
if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5560
mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5567
Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5569
RegionSelection rs = get_regions_from_selection_and_entered ();
5575
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5576
bool in_command = false;
5581
int const N = rs.size ();
5583
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5584
RegionSelection::iterator tmp = r;
5587
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5589
boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5592
progress->descend (1.0 / N);
5595
if (arv->audio_region()->apply (filter, progress) == 0) {
5597
playlist->clear_changes ();
5598
playlist->clear_owned_changes ();
5601
begin_reversible_command (command);
5605
if (filter.results.empty ()) {
5607
/* no regions returned; remove the old one */
5608
playlist->remove_region (arv->region ());
5612
std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5614
/* first region replaces the old one */
5615
playlist->replace_region (arv->region(), *res, (*res)->position());
5619
while (res != filter.results.end()) {
5620
playlist->add_region (*res, (*res)->position());
5626
/* We might have removed regions, which alters other regions' layering_index,
5627
so we need to do a recursive diff here.
5629
vector<Command*> cmds;
5630
playlist->rdiff (cmds);
5631
_session->add_commands (cmds);
5633
_session->add_command(new StatefulDiffCommand (playlist));
5637
progress->ascend ();
5646
commit_reversible_command ();
5651
Editor::external_edit_region ()
5657
Editor::reset_region_gain_envelopes ()
5659
RegionSelection rs = get_regions_from_selection_and_entered ();
5661
if (!_session || rs.empty()) {
5665
bool in_command = false;
5667
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5668
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5670
boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5671
XMLNode& before (alist->get_state());
5673
arv->audio_region()->set_default_envelope ();
5676
begin_reversible_command (_("reset region gain"));
5679
_session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5684
commit_reversible_command ();
5689
Editor::set_region_gain_visibility (RegionView* rv)
5691
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5693
arv->update_envelope_visibility();
5698
Editor::set_gain_envelope_visibility ()
5704
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5705
AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5707
v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5713
Editor::toggle_gain_envelope_active ()
5715
if (_ignore_region_action) {
5719
RegionSelection rs = get_regions_from_selection_and_entered ();
5721
if (!_session || rs.empty()) {
5725
bool in_command = false;
5727
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5728
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5730
arv->region()->clear_changes ();
5731
arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5734
begin_reversible_command (_("region gain envelope active"));
5737
_session->add_command (new StatefulDiffCommand (arv->region()));
5742
commit_reversible_command ();
5747
Editor::toggle_region_lock ()
5749
if (_ignore_region_action) {
5753
RegionSelection rs = get_regions_from_selection_and_entered ();
5755
if (!_session || rs.empty()) {
5759
begin_reversible_command (_("toggle region lock"));
5761
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5762
(*i)->region()->clear_changes ();
5763
(*i)->region()->set_locked (!(*i)->region()->locked());
5764
_session->add_command (new StatefulDiffCommand ((*i)->region()));
5767
commit_reversible_command ();
5771
Editor::toggle_region_video_lock ()
5773
if (_ignore_region_action) {
5777
RegionSelection rs = get_regions_from_selection_and_entered ();
5779
if (!_session || rs.empty()) {
5783
begin_reversible_command (_("Toggle Video Lock"));
5785
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5786
(*i)->region()->clear_changes ();
5787
(*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5788
_session->add_command (new StatefulDiffCommand ((*i)->region()));
5791
commit_reversible_command ();
5795
Editor::toggle_region_lock_style ()
5797
if (_ignore_region_action) {
5801
RegionSelection rs = get_regions_from_selection_and_entered ();
5803
if (!_session || rs.empty()) {
5807
Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5808
vector<Widget*> proxies = a->get_proxies();
5809
Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5813
begin_reversible_command (_("toggle region lock style"));
5815
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5816
(*i)->region()->clear_changes ();
5817
PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5818
(*i)->region()->set_position_lock_style (ns);
5819
_session->add_command (new StatefulDiffCommand ((*i)->region()));
5822
commit_reversible_command ();
5826
Editor::toggle_opaque_region ()
5828
if (_ignore_region_action) {
5832
RegionSelection rs = get_regions_from_selection_and_entered ();
5834
if (!_session || rs.empty()) {
5838
begin_reversible_command (_("change region opacity"));
5840
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5841
(*i)->region()->clear_changes ();
5842
(*i)->region()->set_opaque (!(*i)->region()->opaque());
5843
_session->add_command (new StatefulDiffCommand ((*i)->region()));
5846
commit_reversible_command ();
5850
Editor::toggle_record_enable ()
5852
bool new_state = false;
5854
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5855
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5858
if (!rtav->is_track())
5862
new_state = !rtav->track()->rec_enable_control()->get_value();
5866
rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5871
Editor::toggle_solo ()
5873
bool new_state = false;
5875
boost::shared_ptr<ControlList> cl (new ControlList);
5877
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5878
StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5880
if (!stav || !stav->stripable()->solo_control()) {
5885
new_state = !stav->stripable()->solo_control()->soloed ();
5889
cl->push_back (stav->stripable()->solo_control());
5892
_session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5896
Editor::toggle_mute ()
5898
bool new_state = false;
5900
boost::shared_ptr<ControlList> cl (new ControlList);
5902
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5903
StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5905
if (!stav || !stav->stripable()->mute_control()) {
5910
new_state = !stav->stripable()->mute_control()->muted();
5914
cl->push_back (stav->stripable()->mute_control());
5917
_session->set_controls (cl, new_state, Controllable::UseGroup);
5921
Editor::toggle_solo_isolate ()
5927
Editor::fade_range ()
5929
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5931
begin_reversible_command (_("fade range"));
5933
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5934
(*i)->fade_range (selection->time);
5937
commit_reversible_command ();
5942
Editor::set_fade_length (bool in)
5944
RegionSelection rs = get_regions_from_selection_and_entered ();
5950
/* we need a region to measure the offset from the start */
5952
RegionView* rv = rs.front ();
5954
framepos_t pos = get_preferred_edit_position();
5958
if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5959
/* edit point is outside the relevant region */
5964
if (pos <= rv->region()->position()) {
5968
len = pos - rv->region()->position();
5969
cmd = _("set fade in length");
5971
if (pos >= rv->region()->last_frame()) {
5975
len = rv->region()->last_frame() - pos;
5976
cmd = _("set fade out length");
5979
bool in_command = false;
5981
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5982
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5988
boost::shared_ptr<AutomationList> alist;
5990
alist = tmp->audio_region()->fade_in();
5992
alist = tmp->audio_region()->fade_out();
5995
XMLNode &before = alist->get_state();
5998
tmp->audio_region()->set_fade_in_length (len);
5999
tmp->audio_region()->set_fade_in_active (true);
6001
tmp->audio_region()->set_fade_out_length (len);
6002
tmp->audio_region()->set_fade_out_active (true);
6006
begin_reversible_command (cmd);
6009
XMLNode &after = alist->get_state();
6010
_session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
6014
commit_reversible_command ();
6019
Editor::set_fade_in_shape (FadeShape shape)
6021
RegionSelection rs = get_regions_from_selection_and_entered ();
6026
bool in_command = false;
6028
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6029
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6035
boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6036
XMLNode &before = alist->get_state();
6038
tmp->audio_region()->set_fade_in_shape (shape);
6041
begin_reversible_command (_("set fade in shape"));
6044
XMLNode &after = alist->get_state();
6045
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6049
commit_reversible_command ();
6054
Editor::set_fade_out_shape (FadeShape shape)
6056
RegionSelection rs = get_regions_from_selection_and_entered ();
6061
bool in_command = false;
6063
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6064
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6070
boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6071
XMLNode &before = alist->get_state();
6073
tmp->audio_region()->set_fade_out_shape (shape);
6076
begin_reversible_command (_("set fade out shape"));
6079
XMLNode &after = alist->get_state();
6080
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6084
commit_reversible_command ();
6089
Editor::set_fade_in_active (bool yn)
6091
RegionSelection rs = get_regions_from_selection_and_entered ();
6096
bool in_command = false;
6098
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6099
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6106
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6108
ar->clear_changes ();
6109
ar->set_fade_in_active (yn);
6112
begin_reversible_command (_("set fade in active"));
6115
_session->add_command (new StatefulDiffCommand (ar));
6119
commit_reversible_command ();
6124
Editor::set_fade_out_active (bool yn)
6126
RegionSelection rs = get_regions_from_selection_and_entered ();
6131
bool in_command = false;
6133
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6134
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6140
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6142
ar->clear_changes ();
6143
ar->set_fade_out_active (yn);
6146
begin_reversible_command (_("set fade out active"));
6149
_session->add_command(new StatefulDiffCommand (ar));
6153
commit_reversible_command ();
6158
Editor::toggle_region_fades (int dir)
6160
if (_ignore_region_action) {
6164
boost::shared_ptr<AudioRegion> ar;
6167
RegionSelection rs = get_regions_from_selection_and_entered ();
6173
RegionSelection::iterator i;
6174
for (i = rs.begin(); i != rs.end(); ++i) {
6175
if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6177
yn = ar->fade_out_active ();
6179
yn = ar->fade_in_active ();
6185
if (i == rs.end()) {
6189
/* XXX should this undo-able? */
6190
bool in_command = false;
6192
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6193
if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6196
ar->clear_changes ();
6198
if (dir == 1 || dir == 0) {
6199
ar->set_fade_in_active (!yn);
6202
if (dir == -1 || dir == 0) {
6203
ar->set_fade_out_active (!yn);
6206
begin_reversible_command (_("toggle fade active"));
6209
_session->add_command(new StatefulDiffCommand (ar));
6213
commit_reversible_command ();
6218
/** Update region fade visibility after its configuration has been changed */
6220
Editor::update_region_fade_visibility ()
6222
bool _fade_visibility = _session->config.get_show_region_fades ();
6224
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6225
AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6227
if (_fade_visibility) {
6228
v->audio_view()->show_all_fades ();
6230
v->audio_view()->hide_all_fades ();
6237
Editor::set_edit_point ()
6240
MusicFrame where (0, 0);
6242
if (!mouse_frame (where.frame, ignored)) {
6248
if (selection->markers.empty()) {
6250
mouse_add_new_marker (where.frame);
6255
Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6258
loc->move_to (where.frame, where.division);
6264
Editor::set_playhead_cursor ()
6266
if (entered_marker) {
6267
_session->request_locate (entered_marker->position(), _session->transport_rolling());
6269
MusicFrame where (0, 0);
6272
if (!mouse_frame (where.frame, ignored)) {
6279
_session->request_locate (where.frame, _session->transport_rolling());
6283
//not sure what this was for; remove it for now.
6284
// if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6285
// cancel_time_selection();
6291
Editor::split_region ()
6293
if (_drags->active ()) {
6297
//if a range is selected, separate it
6298
if ( !selection->time.empty()) {
6299
separate_regions_between (selection->time);
6303
//if no range was selected, try to find some regions to split
6304
if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6306
RegionSelection rs = get_regions_from_selection_and_edit_point ();
6307
const framepos_t pos = get_preferred_edit_position();
6308
const int32_t division = get_grid_music_divisions (0);
6309
MusicFrame where (pos, division);
6315
split_regions_at (where, rs);
6321
Editor::select_next_stripable (bool routes_only)
6323
if (selection->tracks.empty()) {
6324
selection->set (track_views.front());
6328
TimeAxisView* current = selection->tracks.front();
6332
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6334
if (*i == current) {
6336
if (i != track_views.end()) {
6339
current = (*(track_views.begin()));
6340
//selection->set (*(track_views.begin()));
6347
RouteUI* rui = dynamic_cast<RouteUI *>(current);
6348
valid = rui && rui->route()->active();
6350
valid = 0 != current->stripable ().get();
6353
} while (current->hidden() || !valid);
6355
selection->set (current);
6357
ensure_time_axis_view_is_visible (*current, false);
6361
Editor::select_prev_stripable (bool routes_only)
6363
if (selection->tracks.empty()) {
6364
selection->set (track_views.front());
6368
TimeAxisView* current = selection->tracks.front();
6372
for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6374
if (*i == current) {
6376
if (i != track_views.rend()) {
6379
current = *(track_views.rbegin());
6385
RouteUI* rui = dynamic_cast<RouteUI *>(current);
6386
valid = rui && rui->route()->active();
6388
valid = 0 != current->stripable ().get();
6391
} while (current->hidden() || !valid);
6393
selection->set (current);
6395
ensure_time_axis_view_is_visible (*current, false);
6399
Editor::set_loop_from_selection (bool play)
6401
if (_session == 0) {
6405
framepos_t start, end;
6406
if (!get_selection_extents ( start, end))
6409
set_loop_range (start, end, _("set loop range from selection"));
6412
_session->request_play_loop (true, true);
6417
Editor::set_loop_from_region (bool play)
6419
framepos_t start, end;
6420
if (!get_selection_extents ( start, end))
6423
set_loop_range (start, end, _("set loop range from region"));
6426
_session->request_locate (start, true);
6427
_session->request_play_loop (true);
6432
Editor::set_punch_from_selection ()
6434
if (_session == 0) {
6438
framepos_t start, end;
6439
if (!get_selection_extents ( start, end))
6442
set_punch_range (start, end, _("set punch range from selection"));
6446
Editor::set_auto_punch_range ()
6448
// auto punch in/out button from a single button
6449
// If Punch In is unset, set punch range from playhead to end, enable punch in
6450
// If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6451
// rewound beyond the Punch In marker, in which case that marker will be moved back
6452
// to the current playhead position.
6453
// If punch out is set, it clears the punch range and Punch In/Out buttons
6455
if (_session == 0) {
6459
Location* tpl = transport_punch_location();
6460
framepos_t now = playhead_cursor->current_frame();
6461
framepos_t begin = now;
6462
framepos_t end = _session->current_end_frame();
6464
if (!_session->config.get_punch_in()) {
6465
// First Press - set punch in and create range from here to eternity
6466
set_punch_range (begin, end, _("Auto Punch In"));
6467
_session->config.set_punch_in(true);
6468
} else if (tpl && !_session->config.get_punch_out()) {
6469
// Second press - update end range marker and set punch_out
6470
if (now < tpl->start()) {
6471
// playhead has been rewound - move start back and pretend nothing happened
6473
set_punch_range (begin, end, _("Auto Punch In/Out"));
6475
// normal case for 2nd press - set the punch out
6476
end = playhead_cursor->current_frame ();
6477
set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6478
_session->config.set_punch_out(true);
6481
if (_session->config.get_punch_out()) {
6482
_session->config.set_punch_out(false);
6485
if (_session->config.get_punch_in()) {
6486
_session->config.set_punch_in(false);
6491
// third press - unset punch in/out and remove range
6492
_session->locations()->remove(tpl);
6499
Editor::set_session_extents_from_selection ()
6501
if (_session == 0) {
6505
framepos_t start, end;
6506
if (!get_selection_extents ( start, end))
6510
if ((loc = _session->locations()->session_range_location()) == 0) {
6511
_session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6513
XMLNode &before = loc->get_state();
6515
_session->set_session_extents (start, end);
6517
XMLNode &after = loc->get_state();
6519
begin_reversible_command (_("set session start/end from selection"));
6521
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6523
commit_reversible_command ();
6526
_session->set_end_is_free (false);
6530
Editor::set_punch_start_from_edit_point ()
6534
MusicFrame start (0, 0);
6535
framepos_t end = max_framepos;
6537
//use the existing punch end, if any
6538
Location* tpl = transport_punch_location();
6543
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6544
start.frame = _session->audible_frame();
6546
start.frame = get_preferred_edit_position();
6549
//snap the selection start/end
6552
//if there's not already a sensible selection endpoint, go "forever"
6553
if (start.frame > end ) {
6557
set_punch_range (start.frame, end, _("set punch start from EP"));
6563
Editor::set_punch_end_from_edit_point ()
6567
framepos_t start = 0;
6568
MusicFrame end (max_framepos, 0);
6570
//use the existing punch start, if any
6571
Location* tpl = transport_punch_location();
6573
start = tpl->start();
6576
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6577
end.frame = _session->audible_frame();
6579
end.frame = get_preferred_edit_position();
6582
//snap the selection start/end
6585
set_punch_range (start, end.frame, _("set punch end from EP"));
6591
Editor::set_loop_start_from_edit_point ()
6595
MusicFrame start (0, 0);
6596
framepos_t end = max_framepos;
6598
//use the existing loop end, if any
6599
Location* tpl = transport_loop_location();
6604
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6605
start.frame = _session->audible_frame();
6607
start.frame = get_preferred_edit_position();
6610
//snap the selection start/end
6613
//if there's not already a sensible selection endpoint, go "forever"
6614
if (start.frame > end ) {
6618
set_loop_range (start.frame, end, _("set loop start from EP"));
6624
Editor::set_loop_end_from_edit_point ()
6628
framepos_t start = 0;
6629
MusicFrame end (max_framepos, 0);
6631
//use the existing loop start, if any
6632
Location* tpl = transport_loop_location();
6634
start = tpl->start();
6637
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6638
end.frame = _session->audible_frame();
6640
end.frame = get_preferred_edit_position();
6643
//snap the selection start/end
6646
set_loop_range (start, end.frame, _("set loop end from EP"));
6651
Editor::set_punch_from_region ()
6653
framepos_t start, end;
6654
if (!get_selection_extents ( start, end))
6657
set_punch_range (start, end, _("set punch range from region"));
6661
Editor::pitch_shift_region ()
6663
RegionSelection rs = get_regions_from_selection_and_entered ();
6665
RegionSelection audio_rs;
6666
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6667
if (dynamic_cast<AudioRegionView*> (*i)) {
6668
audio_rs.push_back (*i);
6672
if (audio_rs.empty()) {
6676
pitch_shift (audio_rs, 1.2);
6680
Editor::set_tempo_from_region ()
6682
RegionSelection rs = get_regions_from_selection_and_entered ();
6684
if (!_session || rs.empty()) {
6688
RegionView* rv = rs.front();
6690
define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6694
Editor::use_range_as_bar ()
6696
framepos_t start, end;
6697
if (get_edit_op_range (start, end)) {
6698
define_one_bar (start, end);
6703
Editor::define_one_bar (framepos_t start, framepos_t end)
6705
framepos_t length = end - start;
6707
const Meter& m (_session->tempo_map().meter_at_frame (start));
6709
/* length = 1 bar */
6711
/* We're going to deliver a constant tempo here,
6712
so we can use frames per beat to determine length.
6713
now we want frames per beat.
6714
we have frames per bar, and beats per bar, so ...
6717
/* XXXX METER MATH */
6719
double frames_per_beat = length / m.divisions_per_bar();
6721
/* beats per minute = */
6723
double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6725
/* now decide whether to:
6727
(a) set global tempo
6728
(b) add a new tempo marker
6732
const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6734
bool do_global = false;
6736
if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6738
/* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6739
at the start, or create a new marker
6742
vector<string> options;
6743
options.push_back (_("Cancel"));
6744
options.push_back (_("Add new marker"));
6745
options.push_back (_("Set global tempo"));
6748
_("Define one bar"),
6749
_("Do you want to set the global tempo or add a new tempo marker?"),
6753
c.set_default_response (2);
6769
/* more than 1 tempo and/or meter section already, go ahead do the "usual":
6770
if the marker is at the region starter, change it, otherwise add
6775
begin_reversible_command (_("set tempo from region"));
6776
XMLNode& before (_session->tempo_map().get_state());
6779
_session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6780
} else if (t.frame() == start) {
6781
_session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6783
/* constant tempo */
6784
const Tempo tempo (beats_per_minute, t.note_type());
6785
_session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6788
XMLNode& after (_session->tempo_map().get_state());
6790
_session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6791
commit_reversible_command ();
6795
Editor::split_region_at_transients ()
6797
AnalysisFeatureList positions;
6799
RegionSelection rs = get_regions_from_selection_and_entered ();
6801
if (!_session || rs.empty()) {
6805
begin_reversible_command (_("split regions"));
6807
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6809
RegionSelection::iterator tmp;
6814
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6817
ar->transients (positions);
6818
split_region_at_points ((*i)->region(), positions, true);
6825
commit_reversible_command ();
6830
Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6832
bool use_rhythmic_rodent = false;
6834
boost::shared_ptr<Playlist> pl = r->playlist();
6836
list<boost::shared_ptr<Region> > new_regions;
6842
if (positions.empty()) {
6846
if (positions.size() > 20 && can_ferret) {
6847
std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6848
MessageDialog msg (msgstr,
6851
Gtk::BUTTONS_OK_CANCEL);
6854
msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6855
msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6857
msg.set_secondary_text (_("Press OK to continue with this split operation"));
6860
msg.set_title (_("Excessive split?"));
6863
int response = msg.run();
6869
case RESPONSE_APPLY:
6870
use_rhythmic_rodent = true;
6877
if (use_rhythmic_rodent) {
6878
show_rhythm_ferret ();
6882
AnalysisFeatureList::const_iterator x;
6884
pl->clear_changes ();
6885
pl->clear_owned_changes ();
6887
x = positions.begin();
6889
if (x == positions.end()) {
6894
pl->remove_region (r);
6898
framepos_t rstart = r->first_frame ();
6899
framepos_t rend = r->last_frame ();
6901
while (x != positions.end()) {
6903
/* deal with positons that are out of scope of present region bounds */
6904
if (*x <= rstart || *x > rend) {
6909
/* file start = original start + how far we from the initial position ? */
6911
framepos_t file_start = r->start() + pos;
6913
/* length = next position - current position */
6915
framepos_t len = (*x) - pos - rstart;
6917
/* XXX we do we really want to allow even single-sample regions?
6918
* shouldn't we have some kind of lower limit on region size?
6927
if (RegionFactory::region_name (new_name, r->name())) {
6931
/* do NOT announce new regions 1 by one, just wait till they are all done */
6935
plist.add (ARDOUR::Properties::start, file_start);
6936
plist.add (ARDOUR::Properties::length, len);
6937
plist.add (ARDOUR::Properties::name, new_name);
6938
plist.add (ARDOUR::Properties::layer, 0);
6939
// TODO set transients_offset
6941
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6942
/* because we set annouce to false, manually add the new region to the
6945
RegionFactory::map_add (nr);
6947
pl->add_region (nr, rstart + pos);
6950
new_regions.push_front(nr);
6959
RegionFactory::region_name (new_name, r->name());
6961
/* Add the final region */
6964
plist.add (ARDOUR::Properties::start, r->start() + pos);
6965
plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6966
plist.add (ARDOUR::Properties::name, new_name);
6967
plist.add (ARDOUR::Properties::layer, 0);
6969
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6970
/* because we set annouce to false, manually add the new region to the
6973
RegionFactory::map_add (nr);
6974
pl->add_region (nr, r->position() + pos);
6977
new_regions.push_front(nr);
6982
/* We might have removed regions, which alters other regions' layering_index,
6983
so we need to do a recursive diff here.
6985
vector<Command*> cmds;
6987
_session->add_commands (cmds);
6989
_session->add_command (new StatefulDiffCommand (pl));
6993
for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6994
set_selected_regionview_from_region_list ((*i), Selection::Add);
7000
Editor::place_transient()
7006
RegionSelection rs = get_regions_from_selection_and_edit_point ();
7012
framepos_t where = get_preferred_edit_position();
7014
begin_reversible_command (_("place transient"));
7016
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7017
(*r)->region()->add_transient(where);
7020
commit_reversible_command ();
7024
Editor::remove_transient(ArdourCanvas::Item* item)
7030
ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
7033
AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7034
_arv->remove_transient (*(float*) _line->get_data ("position"));
7038
Editor::snap_regions_to_grid ()
7040
list <boost::shared_ptr<Playlist > > used_playlists;
7042
RegionSelection rs = get_regions_from_selection_and_entered ();
7044
if (!_session || rs.empty()) {
7048
begin_reversible_command (_("snap regions to grid"));
7050
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7052
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7054
if (!pl->frozen()) {
7055
/* we haven't seen this playlist before */
7057
/* remember used playlists so we can thaw them later */
7058
used_playlists.push_back(pl);
7061
(*r)->region()->clear_changes ();
7063
MusicFrame start ((*r)->region()->first_frame (), 0);
7065
(*r)->region()->set_position (start.frame, start.division);
7066
_session->add_command(new StatefulDiffCommand ((*r)->region()));
7069
while (used_playlists.size() > 0) {
7070
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7072
used_playlists.pop_front();
7075
commit_reversible_command ();
7079
Editor::close_region_gaps ()
7081
list <boost::shared_ptr<Playlist > > used_playlists;
7083
RegionSelection rs = get_regions_from_selection_and_entered ();
7085
if (!_session || rs.empty()) {
7089
Dialog dialog (_("Close Region Gaps"));
7092
table.set_spacings (12);
7093
table.set_border_width (12);
7094
Label* l = manage (left_aligned_label (_("Crossfade length")));
7095
table.attach (*l, 0, 1, 0, 1);
7097
SpinButton spin_crossfade (1, 0);
7098
spin_crossfade.set_range (0, 15);
7099
spin_crossfade.set_increments (1, 1);
7100
spin_crossfade.set_value (5);
7101
table.attach (spin_crossfade, 1, 2, 0, 1);
7103
table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7105
l = manage (left_aligned_label (_("Pull-back length")));
7106
table.attach (*l, 0, 1, 1, 2);
7108
SpinButton spin_pullback (1, 0);
7109
spin_pullback.set_range (0, 100);
7110
spin_pullback.set_increments (1, 1);
7111
spin_pullback.set_value(30);
7112
table.attach (spin_pullback, 1, 2, 1, 2);
7114
table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7116
dialog.get_vbox()->pack_start (table);
7117
dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7118
dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7121
if (dialog.run () == RESPONSE_CANCEL) {
7125
framepos_t crossfade_len = spin_crossfade.get_value();
7126
framepos_t pull_back_frames = spin_pullback.get_value();
7128
crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7129
pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7131
/* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7133
begin_reversible_command (_("close region gaps"));
7136
boost::shared_ptr<Region> last_region;
7138
rs.sort_by_position_and_track();
7140
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7142
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7144
if (!pl->frozen()) {
7145
/* we haven't seen this playlist before */
7147
/* remember used playlists so we can thaw them later */
7148
used_playlists.push_back(pl);
7152
framepos_t position = (*r)->region()->position();
7154
if (idx == 0 || position < last_region->position()){
7155
last_region = (*r)->region();
7160
(*r)->region()->clear_changes ();
7161
(*r)->region()->trim_front( (position - pull_back_frames));
7163
last_region->clear_changes ();
7164
last_region->trim_end( (position - pull_back_frames + crossfade_len));
7166
_session->add_command (new StatefulDiffCommand ((*r)->region()));
7167
_session->add_command (new StatefulDiffCommand (last_region));
7169
last_region = (*r)->region();
7173
while (used_playlists.size() > 0) {
7174
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7176
used_playlists.pop_front();
7179
commit_reversible_command ();
7183
Editor::tab_to_transient (bool forward)
7185
AnalysisFeatureList positions;
7187
RegionSelection rs = get_regions_from_selection_and_entered ();
7193
framepos_t pos = _session->audible_frame ();
7195
if (!selection->tracks.empty()) {
7197
/* don't waste time searching for transients in duplicate playlists.
7200
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7202
for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7204
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7207
boost::shared_ptr<Track> tr = rtv->track();
7209
boost::shared_ptr<Playlist> pl = tr->playlist ();
7211
framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7214
positions.push_back (result);
7227
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7228
(*r)->region()->get_transients (positions);
7232
TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7235
AnalysisFeatureList::iterator x;
7237
for (x = positions.begin(); x != positions.end(); ++x) {
7243
if (x != positions.end ()) {
7244
_session->request_locate (*x);
7248
AnalysisFeatureList::reverse_iterator x;
7250
for (x = positions.rbegin(); x != positions.rend(); ++x) {
7256
if (x != positions.rend ()) {
7257
_session->request_locate (*x);
7263
Editor::playhead_forward_to_grid ()
7269
MusicFrame pos (playhead_cursor->current_frame (), 0);
7271
if (pos.frame < max_framepos - 1) {
7273
snap_to_internal (pos, RoundUpAlways, false, true);
7274
_session->request_locate (pos.frame);
7280
Editor::playhead_backward_to_grid ()
7286
MusicFrame pos (playhead_cursor->current_frame (), 0);
7288
if (pos.frame > 2) {
7290
snap_to_internal (pos, RoundDownAlways, false, true);
7291
_session->request_locate (pos.frame);
7296
Editor::set_track_height (Height h)
7298
TrackSelection& ts (selection->tracks);
7300
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7301
(*x)->set_height_enum (h);
7306
Editor::toggle_tracks_active ()
7308
TrackSelection& ts (selection->tracks);
7310
bool target = false;
7316
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7317
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7321
target = !rtv->_route->active();
7324
rtv->_route->set_active (target, this);
7330
Editor::remove_tracks ()
7332
/* this will delete GUI objects that may be the subject of an event
7333
handler in which this method is called. Defer actual deletion to the
7334
next idle callback, when all event handling is finished.
7336
Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7340
Editor::idle_remove_tracks ()
7342
Session::StateProtector sp (_session);
7344
return false; /* do not call again */
7348
Editor::_remove_tracks ()
7350
TrackSelection& ts (selection->tracks);
7356
vector<string> choices;
7361
const char* trackstr;
7364
vector<boost::shared_ptr<Route> > routes;
7365
vector<boost::shared_ptr<VCA> > vcas;
7366
bool special_bus = false;
7368
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7369
VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
7371
vcas.push_back (vtv->vca());
7375
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7379
if (rtv->is_track()) {
7384
routes.push_back (rtv->_route);
7386
if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7391
if (special_bus && !Config->get_allow_special_bus_removal()) {
7392
MessageDialog msg (_("That would be bad news ...."),
7396
msg.set_secondary_text (string_compose (_(
7397
"Removing the master or monitor bus is such a bad idea\n\
7398
that %1 is not going to allow it.\n\
7400
If you really want to do this sort of thing\n\
7401
edit your ardour.rc file to set the\n\
7402
\"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7409
if (ntracks + nbusses + nvcas == 0) {
7415
trackstr = P_("track", "tracks", ntracks);
7416
busstr = P_("bus", "busses", nbusses);
7417
vcastr = P_("VCA", "VCAs", nvcas);
7419
if (ntracks > 0 && nbusses > 0 && nvcas > 0) {
7420
title = _("Remove various strips");
7421
prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"),
7422
ntracks, trackstr, nbusses, busstr, nvcas, vcastr);
7424
else if (ntracks > 0 && nbusses > 0) {
7425
title = string_compose (_("Remove %1 and %2"), trackstr, busstr);
7426
prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7427
ntracks, trackstr, nbusses, busstr);
7429
else if (ntracks > 0 && nvcas > 0) {
7430
title = string_compose (_("Remove %1 and %2"), trackstr, vcastr);
7431
prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7432
ntracks, trackstr, nvcas, vcastr);
7434
else if (nbusses > 0 && nvcas > 0) {
7435
title = string_compose (_("Remove %1 and %2"), busstr, vcastr);
7436
prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7437
nbusses, busstr, nvcas, vcastr);
7439
else if (ntracks > 0) {
7440
title = string_compose (_("Remove %1"), trackstr);
7441
prompt = string_compose (_("Do you really want to remove %1 %2?"),
7444
else if (nbusses > 0) {
7445
title = string_compose (_("Remove %1"), busstr);
7446
prompt = string_compose (_("Do you really want to remove %1 %2?"),
7449
else if (nvcas > 0) {
7450
title = string_compose (_("Remove %1"), vcastr);
7451
prompt = string_compose (_("Do you really want to remove %1 %2?"),
7459
prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n";
7462
prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!"));
7464
choices.push_back (_("No, do nothing."));
7465
if (ntracks + nbusses + nvcas > 1) {
7466
choices.push_back (_("Yes, remove them."));
7468
choices.push_back (_("Yes, remove it."));
7471
Choice prompter (title, prompt, choices);
7473
if (prompter.run () != 1) {
7477
if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7478
/* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7479
* route). If the deleted route is currently displayed in the Editor-Mixer (highly
7480
* likely because deletion requires selection) this will call
7481
* Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7482
* It's likewise likely that the route that has just been displayed in the
7483
* Editor-Mixer will be next in line for deletion.
7485
* So simply switch to the master-bus (if present)
7487
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7488
if ((*i)->stripable ()->is_master ()) {
7489
set_selected_mixer_strip (*(*i));
7496
PresentationInfo::ChangeSuspender cs;
7497
DisplaySuspender ds;
7499
boost::shared_ptr<RouteList> rl (new RouteList);
7500
for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7503
_session->remove_routes (rl);
7505
for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
7506
_session->vca_manager().remove_vca (*x);
7510
/* TrackSelection and RouteList leave scope,
7511
* destructors are called,
7512
* diskstream drops references, save_state is called (again for every track)
7517
Editor::do_insert_time ()
7519
if (selection->tracks.empty()) {
7523
InsertRemoveTimeDialog d (*this);
7524
int response = d.run ();
7526
if (response != RESPONSE_OK) {
7530
if (d.distance() == 0) {
7537
d.intersected_region_action (),
7541
d.move_glued_markers(),
7542
d.move_locked_markers(),
7548
Editor::insert_time (
7549
framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7550
bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7554
if (Config->get_edit_mode() == Lock) {
7557
bool in_command = false;
7559
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7561
for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7565
/* don't operate on any playlist more than once, which could
7566
* happen if "all playlists" is enabled, but there is more
7567
* than 1 track using playlists "from" a given track.
7570
set<boost::shared_ptr<Playlist> > pl;
7572
if (all_playlists) {
7573
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7574
if (rtav && rtav->track ()) {
7575
vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7576
for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7581
if ((*x)->playlist ()) {
7582
pl.insert ((*x)->playlist ());
7586
for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7588
(*i)->clear_changes ();
7589
(*i)->clear_owned_changes ();
7592
begin_reversible_command (_("insert time"));
7596
if (opt == SplitIntersected) {
7597
/* non musical split */
7598
(*i)->split (MusicFrame (pos, 0));
7601
(*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7603
vector<Command*> cmds;
7605
_session->add_commands (cmds);
7607
_session->add_command (new StatefulDiffCommand (*i));
7611
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7614
begin_reversible_command (_("insert time"));
7617
rtav->route ()->shift (pos, frames);
7624
const int32_t divisions = get_grid_music_divisions (0);
7625
XMLNode& before (_session->locations()->get_state());
7626
Locations::LocationList copy (_session->locations()->list());
7628
for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7630
Locations::LocationList::const_iterator tmp;
7632
if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7633
bool const was_locked = (*i)->locked ();
7634
if (locked_markers_too) {
7638
if ((*i)->start() >= pos) {
7639
// move end first, in case we're moving by more than the length of the range
7640
if (!(*i)->is_mark()) {
7641
(*i)->set_end ((*i)->end() + frames, false, true, divisions);
7643
(*i)->set_start ((*i)->start() + frames, false, true, divisions);
7655
begin_reversible_command (_("insert time"));
7658
XMLNode& after (_session->locations()->get_state());
7659
_session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7665
begin_reversible_command (_("insert time"));
7668
XMLNode& before (_session->tempo_map().get_state());
7669
_session->tempo_map().insert_time (pos, frames);
7670
XMLNode& after (_session->tempo_map().get_state());
7671
_session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7675
commit_reversible_command ();
7680
Editor::do_remove_time ()
7682
if (selection->tracks.empty()) {
7686
InsertRemoveTimeDialog d (*this, true);
7688
int response = d.run ();
7690
if (response != RESPONSE_OK) {
7694
framecnt_t distance = d.distance();
7696
if (distance == 0) {
7706
d.move_glued_markers(),
7707
d.move_locked_markers(),
7713
Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7714
bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7716
if (Config->get_edit_mode() == Lock) {
7717
error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7720
bool in_command = false;
7722
for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7724
boost::shared_ptr<Playlist> pl = (*x)->playlist();
7728
XMLNode &before = pl->get_state();
7731
begin_reversible_command (_("remove time"));
7735
std::list<AudioRange> rl;
7736
AudioRange ar(pos, pos+frames, 0);
7739
pl->shift (pos, -frames, true, ignore_music_glue);
7741
XMLNode &after = pl->get_state();
7743
_session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7747
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7750
begin_reversible_command (_("remove time"));
7753
rtav->route ()->shift (pos, -frames);
7757
const int32_t divisions = get_grid_music_divisions (0);
7758
std::list<Location*> loc_kill_list;
7763
XMLNode& before (_session->locations()->get_state());
7764
Locations::LocationList copy (_session->locations()->list());
7766
for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7767
if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7769
bool const was_locked = (*i)->locked ();
7770
if (locked_markers_too) {
7774
if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7775
if ((*i)->end() >= pos
7776
&& (*i)->end() < pos+frames
7777
&& (*i)->start() >= pos
7778
&& (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7780
loc_kill_list.push_back(*i);
7781
} else { // only start or end is included, try to do the right thing
7782
// move start before moving end, to avoid trying to move the end to before the start
7783
// if we're removing more time than the length of the range
7784
if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7785
// start is within cut
7786
(*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7788
} else if ((*i)->start() >= pos+frames) {
7789
// start (and thus entire range) lies beyond end of cut
7790
(*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7793
if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7794
// end is inside cut
7795
(*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7797
} else if ((*i)->end() >= pos+frames) {
7798
// end is beyond end of cut
7799
(*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7804
} else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7805
loc_kill_list.push_back(*i);
7807
} else if ((*i)->start() >= pos) {
7808
(*i)->set_start ((*i)->start() -frames, false, true, divisions);
7818
for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7819
_session->locations()->remove( *i );
7824
begin_reversible_command (_("remove time"));
7827
XMLNode& after (_session->locations()->get_state());
7828
_session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7833
XMLNode& before (_session->tempo_map().get_state());
7835
if (_session->tempo_map().remove_time (pos, frames) ) {
7837
begin_reversible_command (_("remove time"));
7840
XMLNode& after (_session->tempo_map().get_state());
7841
_session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7846
commit_reversible_command ();
7851
Editor::fit_selection ()
7853
if (!selection->tracks.empty()) {
7854
fit_tracks (selection->tracks);
7858
/* no selected tracks - use tracks with selected regions */
7860
if (!selection->regions.empty()) {
7861
for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7862
tvl.push_back (&(*r)->get_time_axis_view ());
7868
} else if (internal_editing()) {
7869
/* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7872
if (entered_track) {
7873
tvl.push_back (entered_track);
7881
Editor::fit_tracks (TrackViewList & tracks)
7883
if (tracks.empty()) {
7887
uint32_t child_heights = 0;
7888
int visible_tracks = 0;
7890
for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7892
if (!(*t)->marked_for_display()) {
7896
child_heights += (*t)->effective_height() - (*t)->current_height();
7900
/* compute the per-track height from:
7902
* total canvas visible height
7903
* - height that will be taken by visible children of selected tracks
7904
* - height of the ruler/hscroll area
7906
uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7907
double first_y_pos = DBL_MAX;
7909
if (h < TimeAxisView::preset_height (HeightSmall)) {
7910
MessageDialog msg (_("There are too many tracks to fit in the current window"));
7911
/* too small to be displayed */
7915
undo_visual_stack.push_back (current_visual_state (true));
7916
PBD::Unwinder<bool> nsv (no_save_visual, true);
7918
/* build a list of all tracks, including children */
7921
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7923
TimeAxisView::Children c = (*i)->get_child_list ();
7924
for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7925
all.push_back (j->get());
7930
// find selection range.
7931
// if someone knows how to user TrackViewList::iterator for this
7933
int selected_top = -1;
7934
int selected_bottom = -1;
7936
for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7937
if ((*t)->marked_for_display ()) {
7938
if (tracks.contains(*t)) {
7939
if (selected_top == -1) {
7942
selected_bottom = i;
7948
for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7949
if ((*t)->marked_for_display ()) {
7950
if (tracks.contains(*t)) {
7951
(*t)->set_height (h);
7952
first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7954
if (i > selected_top && i < selected_bottom) {
7955
hide_track_in_display (*t);
7962
set the controls_layout height now, because waiting for its size
7963
request signal handler will cause the vertical adjustment setting to fail
7966
controls_layout.property_height () = _full_canvas_height;
7967
vertical_adjustment.set_value (first_y_pos);
7969
redo_visual_stack.push_back (current_visual_state (true));
7971
visible_tracks_selector.set_text (_("Sel"));
7975
Editor::save_visual_state (uint32_t n)
7977
while (visual_states.size() <= n) {
7978
visual_states.push_back (0);
7981
if (visual_states[n] != 0) {
7982
delete visual_states[n];
7985
visual_states[n] = current_visual_state (true);
7990
Editor::goto_visual_state (uint32_t n)
7992
if (visual_states.size() <= n) {
7996
if (visual_states[n] == 0) {
8000
use_visual_state (*visual_states[n]);
8004
Editor::start_visual_state_op (uint32_t n)
8006
save_visual_state (n);
8008
PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
8010
snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
8011
pup->set_text (buf);
8016
Editor::cancel_visual_state_op (uint32_t n)
8018
goto_visual_state (n);
8022
Editor::toggle_region_mute ()
8024
if (_ignore_region_action) {
8028
RegionSelection rs = get_regions_from_selection_and_entered ();
8034
if (rs.size() > 1) {
8035
begin_reversible_command (_("mute regions"));
8037
begin_reversible_command (_("mute region"));
8040
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
8042
(*i)->region()->playlist()->clear_changes ();
8043
(*i)->region()->set_muted (!(*i)->region()->muted ());
8044
_session->add_command (new StatefulDiffCommand ((*i)->region()));
8048
commit_reversible_command ();
8052
Editor::combine_regions ()
8054
/* foreach track with selected regions, take all selected regions
8055
and join them into a new region containing the subregions (as a
8059
typedef set<RouteTimeAxisView*> RTVS;
8062
if (selection->regions.empty()) {
8066
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8067
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8070
tracks.insert (rtv);
8074
begin_reversible_command (_("combine regions"));
8076
vector<RegionView*> new_selection;
8078
for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8081
if ((rv = (*i)->combine_regions ()) != 0) {
8082
new_selection.push_back (rv);
8086
selection->clear_regions ();
8087
for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8088
selection->add (*i);
8091
commit_reversible_command ();
8095
Editor::uncombine_regions ()
8097
typedef set<RouteTimeAxisView*> RTVS;
8100
if (selection->regions.empty()) {
8104
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8105
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8108
tracks.insert (rtv);
8112
begin_reversible_command (_("uncombine regions"));
8114
for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8115
(*i)->uncombine_regions ();
8118
commit_reversible_command ();
8122
Editor::toggle_midi_input_active (bool flip_others)
8125
boost::shared_ptr<RouteList> rl (new RouteList);
8127
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8128
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8134
boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8137
rl->push_back (rtav->route());
8138
onoff = !mt->input_active();
8142
_session->set_exclusive_input_active (rl, onoff, flip_others);
8145
static bool ok_fine (GdkEventAny*) { return true; }
8151
lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8153
Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8154
lock_dialog->get_vbox()->pack_start (*padlock);
8155
lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8157
ArdourButton* b = manage (new ArdourButton);
8158
b->set_name ("lock button");
8159
b->set_text (_("Click to unlock"));
8160
b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8161
lock_dialog->get_vbox()->pack_start (*b);
8163
lock_dialog->get_vbox()->show_all ();
8164
lock_dialog->set_size_request (200, 200);
8167
delete _main_menu_disabler;
8168
_main_menu_disabler = new MainMenuDisabler;
8170
lock_dialog->present ();
8172
lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8178
lock_dialog->hide ();
8180
delete _main_menu_disabler;
8181
_main_menu_disabler = 0;
8183
if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8184
start_lock_event_timing ();
8189
Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8191
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8195
Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8197
Timers::TimerSuspender t;
8198
label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8199
Gtkmm2ext::UI::instance()->flush_pending (1);
8203
Editor::bring_all_sources_into_session ()
8210
ArdourDialog w (_("Moving embedded files into session folder"));
8211
w.get_vbox()->pack_start (msg);
8214
/* flush all pending GUI events because we're about to start copying
8218
Timers::TimerSuspender t;
8219
Gtkmm2ext::UI::instance()->flush_pending (3);
8223
_session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));