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 */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
61 #include "ardour_ui.h"
62 #include "audio_region_view.h"
63 #include "audio_streamview.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "control_point.h"
70 #include "editor_cursors.h"
71 #include "editor_drag.h"
72 #include "editor_regions.h"
73 #include "editor_routes.h"
74 #include "gui_thread.h"
75 #include "insert_time_dialog.h"
76 #include "interthread_progress_window.h"
78 #include "midi_region_view.h"
79 #include "mouse_cursors.h"
80 #include "normalize_dialog.h"
81 #include "patch_change_dialog.h"
82 #include "quantize_dialog.h"
83 #include "region_gain_line.h"
84 #include "rgb_macros.h"
85 #include "route_time_axis.h"
86 #include "selection.h"
87 #include "selection_templates.h"
88 #include "streamview.h"
89 #include "strip_silence_dialog.h"
90 #include "time_axis_view.h"
91 #include "transpose_dialog.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 RegionSelection pre_selected_regions = selection->regions;
137 bool working_on_selection = !pre_selected_regions.empty();
139 list<boost::shared_ptr<Playlist> > used_playlists;
140 list<RouteTimeAxisView*> used_trackviews;
142 if (regions.empty()) {
146 begin_reversible_command (_("split"));
148 // if splitting a single region, and snap-to is using
149 // region boundaries, don't pay attention to them
151 if (regions.size() == 1) {
152 switch (_snap_type) {
153 case SnapToRegionStart:
154 case SnapToRegionSync:
155 case SnapToRegionEnd:
164 EditorFreeze(); /* Emit Signal */
167 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
169 RegionSelection::iterator tmp;
171 /* XXX this test needs to be more complicated, to make sure we really
172 have something to split.
175 if (!(*a)->region()->covers (where)) {
183 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
191 /* we haven't seen this playlist before */
193 /* remember used playlists so we can thaw them later */
194 used_playlists.push_back(pl);
196 TimeAxisView& tv = (*a)->get_time_axis_view();
197 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
199 used_trackviews.push_back (rtv);
206 pl->clear_changes ();
207 pl->split_region ((*a)->region(), where);
208 _session->add_command (new StatefulDiffCommand (pl));
214 vector<sigc::connection> region_added_connections;
216 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
217 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
220 latest_regionviews.clear ();
222 while (used_playlists.size() > 0) {
223 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
225 used_playlists.pop_front();
228 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
232 commit_reversible_command ();
235 EditorThaw(); /* Emit Signal */
238 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
239 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
240 if( working_on_selection ) {
241 selection->add ( pre_selected_regions );
242 selection->add (latest_regionviews); //these are the new regions created after the split
244 _ignore_follow_edits = false;
248 /** Move one extreme of the current range selection. If more than one range is selected,
249 * the start of the earliest range or the end of the latest range is moved.
251 * @param move_end true to move the end of the current range selection, false to move
253 * @param next true to move the extreme to the next region boundary, false to move to
257 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
259 if (selection->time.start() == selection->time.end_frame()) {
263 framepos_t start = selection->time.start ();
264 framepos_t end = selection->time.end_frame ();
266 /* the position of the thing we may move */
267 framepos_t pos = move_end ? end : start;
268 int dir = next ? 1 : -1;
270 /* so we don't find the current region again */
271 if (dir > 0 || pos > 0) {
275 framepos_t const target = get_region_boundary (pos, dir, true, false);
290 begin_reversible_command (_("alter selection"));
291 selection->set_preserving_all_ranges (start, end);
292 commit_reversible_command ();
296 Editor::nudge_forward_release (GdkEventButton* ev)
298 if (ev->state & Keyboard::PrimaryModifier) {
299 nudge_forward (false, true);
301 nudge_forward (false, false);
307 Editor::nudge_backward_release (GdkEventButton* ev)
309 if (ev->state & Keyboard::PrimaryModifier) {
310 nudge_backward (false, true);
312 nudge_backward (false, false);
319 Editor::nudge_forward (bool next, bool force_playhead)
322 framepos_t next_distance;
328 RegionSelection rs = get_regions_from_selection_and_entered ();
330 if (!force_playhead && !rs.empty()) {
332 begin_reversible_command (_("nudge regions forward"));
334 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
335 boost::shared_ptr<Region> r ((*i)->region());
337 distance = get_nudge_distance (r->position(), next_distance);
340 distance = next_distance;
344 r->set_position (r->position() + distance);
345 _session->add_command (new StatefulDiffCommand (r));
348 commit_reversible_command ();
351 } else if (!force_playhead && !selection->markers.empty()) {
355 begin_reversible_command (_("nudge location forward"));
357 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
359 Location* loc = find_location_from_marker ((*i), is_start);
363 XMLNode& before (loc->get_state());
366 distance = get_nudge_distance (loc->start(), next_distance);
368 distance = next_distance;
370 if (max_framepos - distance > loc->start() + loc->length()) {
371 loc->set_start (loc->start() + distance);
373 loc->set_start (max_framepos - loc->length());
376 distance = get_nudge_distance (loc->end(), next_distance);
378 distance = next_distance;
380 if (max_framepos - distance > loc->end()) {
381 loc->set_end (loc->end() + distance);
383 loc->set_end (max_framepos);
386 XMLNode& after (loc->get_state());
387 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
391 commit_reversible_command ();
394 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
395 _session->request_locate (playhead_cursor->current_frame () + distance);
400 Editor::nudge_backward (bool next, bool force_playhead)
403 framepos_t next_distance;
409 RegionSelection rs = get_regions_from_selection_and_entered ();
411 if (!force_playhead && !rs.empty()) {
413 begin_reversible_command (_("nudge regions backward"));
415 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
416 boost::shared_ptr<Region> r ((*i)->region());
418 distance = get_nudge_distance (r->position(), next_distance);
421 distance = next_distance;
426 if (r->position() > distance) {
427 r->set_position (r->position() - distance);
431 _session->add_command (new StatefulDiffCommand (r));
434 commit_reversible_command ();
436 } else if (!force_playhead && !selection->markers.empty()) {
440 begin_reversible_command (_("nudge location forward"));
442 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
444 Location* loc = find_location_from_marker ((*i), is_start);
448 XMLNode& before (loc->get_state());
451 distance = get_nudge_distance (loc->start(), next_distance);
453 distance = next_distance;
455 if (distance < loc->start()) {
456 loc->set_start (loc->start() - distance);
461 distance = get_nudge_distance (loc->end(), next_distance);
464 distance = next_distance;
467 if (distance < loc->end() - loc->length()) {
468 loc->set_end (loc->end() - distance);
470 loc->set_end (loc->length());
474 XMLNode& after (loc->get_state());
475 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
479 commit_reversible_command ();
483 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
485 if (playhead_cursor->current_frame () > distance) {
486 _session->request_locate (playhead_cursor->current_frame () - distance);
488 _session->goto_start();
494 Editor::nudge_forward_capture_offset ()
496 RegionSelection rs = get_regions_from_selection_and_entered ();
498 if (!_session || rs.empty()) {
502 begin_reversible_command (_("nudge forward"));
504 framepos_t const distance = _session->worst_output_latency();
506 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
507 boost::shared_ptr<Region> r ((*i)->region());
510 r->set_position (r->position() + distance);
511 _session->add_command(new StatefulDiffCommand (r));
514 commit_reversible_command ();
518 Editor::nudge_backward_capture_offset ()
520 RegionSelection rs = get_regions_from_selection_and_entered ();
522 if (!_session || rs.empty()) {
526 begin_reversible_command (_("nudge backward"));
528 framepos_t const distance = _session->worst_output_latency();
530 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
531 boost::shared_ptr<Region> r ((*i)->region());
535 if (r->position() > distance) {
536 r->set_position (r->position() - distance);
540 _session->add_command(new StatefulDiffCommand (r));
543 commit_reversible_command ();
546 struct RegionSelectionPositionSorter {
547 bool operator() (RegionView* a, RegionView* b) {
548 return a->region()->position() < b->region()->position();
553 Editor::sequence_regions ()
556 framepos_t r_end_prev;
564 RegionSelection rs = get_regions_from_selection_and_entered ();
565 rs.sort(RegionSelectionPositionSorter());
569 begin_reversible_command (_("sequence regions"));
570 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
571 boost::shared_ptr<Region> r ((*i)->region());
579 if(r->position_locked())
586 r->set_position(r_end_prev);
589 _session->add_command (new StatefulDiffCommand (r));
591 r_end=r->position() + r->length();
595 commit_reversible_command ();
603 Editor::move_to_start ()
605 _session->goto_start ();
609 Editor::move_to_end ()
612 _session->request_locate (_session->current_end_frame());
616 Editor::build_region_boundary_cache ()
619 vector<RegionPoint> interesting_points;
620 boost::shared_ptr<Region> r;
621 TrackViewList tracks;
624 region_boundary_cache.clear ();
630 switch (_snap_type) {
631 case SnapToRegionStart:
632 interesting_points.push_back (Start);
634 case SnapToRegionEnd:
635 interesting_points.push_back (End);
637 case SnapToRegionSync:
638 interesting_points.push_back (SyncPoint);
640 case SnapToRegionBoundary:
641 interesting_points.push_back (Start);
642 interesting_points.push_back (End);
645 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
650 TimeAxisView *ontrack = 0;
653 if (!selection->tracks.empty()) {
654 tlist = selection->tracks.filter_to_unique_playlists ();
656 tlist = track_views.filter_to_unique_playlists ();
659 while (pos < _session->current_end_frame() && !at_end) {
662 framepos_t lpos = max_framepos;
664 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
666 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
667 if (*p == interesting_points.back()) {
670 /* move to next point type */
676 rpos = r->first_frame();
680 rpos = r->last_frame();
684 rpos = r->sync_position ();
692 RouteTimeAxisView *rtav;
694 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
695 if (rtav->track() != 0) {
696 speed = rtav->track()->speed();
700 rpos = track_frame_to_session_frame (rpos, speed);
706 /* prevent duplicates, but we don't use set<> because we want to be able
710 vector<framepos_t>::iterator ri;
712 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
718 if (ri == region_boundary_cache.end()) {
719 region_boundary_cache.push_back (rpos);
726 /* finally sort to be sure that the order is correct */
728 sort (region_boundary_cache.begin(), region_boundary_cache.end());
731 boost::shared_ptr<Region>
732 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
734 TrackViewList::iterator i;
735 framepos_t closest = max_framepos;
736 boost::shared_ptr<Region> ret;
740 framepos_t track_frame;
741 RouteTimeAxisView *rtav;
743 for (i = tracks.begin(); i != tracks.end(); ++i) {
746 boost::shared_ptr<Region> r;
749 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
750 if (rtav->track()!=0)
751 track_speed = rtav->track()->speed();
754 track_frame = session_frame_to_track_frame(frame, track_speed);
756 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
762 rpos = r->first_frame ();
766 rpos = r->last_frame ();
770 rpos = r->sync_position ();
774 // rpos is a "track frame", converting it to "_session frame"
775 rpos = track_frame_to_session_frame(rpos, track_speed);
778 distance = rpos - frame;
780 distance = frame - rpos;
783 if (distance < closest) {
795 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
797 framecnt_t distance = max_framepos;
798 framepos_t current_nearest = -1;
800 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
801 framepos_t contender;
804 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
810 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
814 d = ::llabs (pos - contender);
817 current_nearest = contender;
822 return current_nearest;
826 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
831 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
833 if (!selection->tracks.empty()) {
835 target = find_next_region_boundary (pos, dir, selection->tracks);
839 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
840 get_onscreen_tracks (tvl);
841 target = find_next_region_boundary (pos, dir, tvl);
843 target = find_next_region_boundary (pos, dir, track_views);
849 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
850 get_onscreen_tracks (tvl);
851 target = find_next_region_boundary (pos, dir, tvl);
853 target = find_next_region_boundary (pos, dir, track_views);
861 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
863 framepos_t pos = playhead_cursor->current_frame ();
870 // so we don't find the current region again..
871 if (dir > 0 || pos > 0) {
875 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
879 _session->request_locate (target);
883 Editor::cursor_to_next_region_boundary (bool with_selection)
885 cursor_to_region_boundary (with_selection, 1);
889 Editor::cursor_to_previous_region_boundary (bool with_selection)
891 cursor_to_region_boundary (with_selection, -1);
895 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
897 boost::shared_ptr<Region> r;
898 framepos_t pos = cursor->current_frame ();
904 TimeAxisView *ontrack = 0;
906 // so we don't find the current region again..
910 if (!selection->tracks.empty()) {
912 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
914 } else if (clicked_axisview) {
917 t.push_back (clicked_axisview);
919 r = find_next_region (pos, point, dir, t, &ontrack);
923 r = find_next_region (pos, point, dir, track_views, &ontrack);
932 pos = r->first_frame ();
936 pos = r->last_frame ();
940 pos = r->sync_position ();
945 RouteTimeAxisView *rtav;
947 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
948 if (rtav->track() != 0) {
949 speed = rtav->track()->speed();
953 pos = track_frame_to_session_frame(pos, speed);
955 if (cursor == playhead_cursor) {
956 _session->request_locate (pos);
958 cursor->set_position (pos);
963 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
965 cursor_to_region_point (cursor, point, 1);
969 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
971 cursor_to_region_point (cursor, point, -1);
975 Editor::cursor_to_selection_start (EditorCursor *cursor)
979 switch (mouse_mode) {
981 if (!selection->regions.empty()) {
982 pos = selection->regions.start();
987 if (!selection->time.empty()) {
988 pos = selection->time.start ();
996 if (cursor == playhead_cursor) {
997 _session->request_locate (pos);
999 cursor->set_position (pos);
1004 Editor::cursor_to_selection_end (EditorCursor *cursor)
1008 switch (mouse_mode) {
1010 if (!selection->regions.empty()) {
1011 pos = selection->regions.end_frame();
1016 if (!selection->time.empty()) {
1017 pos = selection->time.end_frame ();
1025 if (cursor == playhead_cursor) {
1026 _session->request_locate (pos);
1028 cursor->set_position (pos);
1033 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1043 if (selection->markers.empty()) {
1047 if (!mouse_frame (mouse, ignored)) {
1051 add_location_mark (mouse);
1054 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1058 framepos_t pos = loc->start();
1060 // so we don't find the current region again..
1061 if (dir > 0 || pos > 0) {
1065 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1069 loc->move_to (target);
1073 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1075 selected_marker_to_region_boundary (with_selection, 1);
1079 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1081 selected_marker_to_region_boundary (with_selection, -1);
1085 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1087 boost::shared_ptr<Region> r;
1092 if (!_session || selection->markers.empty()) {
1096 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1100 TimeAxisView *ontrack = 0;
1104 // so we don't find the current region again..
1108 if (!selection->tracks.empty()) {
1110 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1114 r = find_next_region (pos, point, dir, track_views, &ontrack);
1123 pos = r->first_frame ();
1127 pos = r->last_frame ();
1131 pos = r->adjust_to_sync (r->first_frame());
1136 RouteTimeAxisView *rtav;
1138 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1139 if (rtav->track() != 0) {
1140 speed = rtav->track()->speed();
1144 pos = track_frame_to_session_frame(pos, speed);
1150 Editor::selected_marker_to_next_region_point (RegionPoint point)
1152 selected_marker_to_region_point (point, 1);
1156 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1158 selected_marker_to_region_point (point, -1);
1162 Editor::selected_marker_to_selection_start ()
1168 if (!_session || selection->markers.empty()) {
1172 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1176 switch (mouse_mode) {
1178 if (!selection->regions.empty()) {
1179 pos = selection->regions.start();
1184 if (!selection->time.empty()) {
1185 pos = selection->time.start ();
1197 Editor::selected_marker_to_selection_end ()
1203 if (!_session || selection->markers.empty()) {
1207 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1211 switch (mouse_mode) {
1213 if (!selection->regions.empty()) {
1214 pos = selection->regions.end_frame();
1219 if (!selection->time.empty()) {
1220 pos = selection->time.end_frame ();
1232 Editor::scroll_playhead (bool forward)
1234 framepos_t pos = playhead_cursor->current_frame ();
1235 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1238 if (pos == max_framepos) {
1242 if (pos < max_framepos - delta) {
1261 _session->request_locate (pos);
1265 Editor::cursor_align (bool playhead_to_edit)
1271 if (playhead_to_edit) {
1273 if (selection->markers.empty()) {
1277 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1280 /* move selected markers to playhead */
1282 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1285 Location* loc = find_location_from_marker (*i, ignored);
1287 if (loc->is_mark()) {
1288 loc->set_start (playhead_cursor->current_frame ());
1290 loc->set (playhead_cursor->current_frame (),
1291 playhead_cursor->current_frame () + loc->length());
1298 Editor::scroll_backward (float pages)
1300 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1301 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1304 if (leftmost_frame < cnt) {
1307 frame = leftmost_frame - cnt;
1310 reset_x_origin (frame);
1314 Editor::scroll_forward (float pages)
1316 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1317 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1320 if (max_framepos - cnt < leftmost_frame) {
1321 frame = max_framepos - cnt;
1323 frame = leftmost_frame + cnt;
1326 reset_x_origin (frame);
1330 Editor::scroll_tracks_down ()
1332 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1333 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1334 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1337 vertical_adjustment.set_value (vert_value);
1341 Editor::scroll_tracks_up ()
1343 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1347 Editor::scroll_tracks_down_line ()
1349 double vert_value = vertical_adjustment.get_value() + 60;
1351 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1352 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1355 vertical_adjustment.set_value (vert_value);
1359 Editor::scroll_tracks_up_line ()
1361 reset_y_origin (vertical_adjustment.get_value() - 60);
1365 Editor::scroll_down_one_track ()
1367 TrackViewList::reverse_iterator next = track_views.rend();
1368 std::pair<TimeAxisView*,double> res;
1369 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1371 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1372 if ((*t)->hidden()) {
1376 /* If this is the bottom visible trackview, we want to display
1380 res = (*t)->covers_y_position (bottom_of_trackviews);
1386 ++next; // moves "next" towards the "front" since it is a reverse iterator
1389 /* move to the track below the first one that covers the */
1391 if (next != track_views.rend()) {
1392 ensure_time_axis_view_is_visible (**next);
1400 Editor::scroll_up_one_track ()
1402 double vertical_pos = vertical_adjustment.get_value ();
1404 TrackViewList::iterator prev = track_views.end();
1405 std::pair<TimeAxisView*,double> res;
1407 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1409 if ((*t)->hidden()) {
1413 /* find the trackview at the top of the trackview group */
1414 res = (*t)->covers_y_position (vertical_pos);
1417 cerr << res.first->name() << " covers the top\n";
1424 if (prev != track_views.end()) {
1425 ensure_time_axis_view_is_visible (**prev);
1435 Editor::tav_zoom_step (bool coarser)
1437 DisplaySuspender ds;
1441 if (selection->tracks.empty()) {
1444 ts = &selection->tracks;
1447 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1448 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1449 tv->step_height (coarser);
1454 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1456 DisplaySuspender ds;
1460 if (selection->tracks.empty() || force_all) {
1463 ts = &selection->tracks;
1466 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1467 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1468 uint32_t h = tv->current_height ();
1473 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1478 tv->set_height (h + 5);
1485 Editor::temporal_zoom_step (bool coarser)
1487 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1489 framecnt_t nspp = samples_per_pixel;
1497 temporal_zoom (nspp);
1501 Editor::temporal_zoom (framecnt_t fpp)
1507 framepos_t current_page = current_page_samples();
1508 framepos_t current_leftmost = leftmost_frame;
1509 framepos_t current_rightmost;
1510 framepos_t current_center;
1511 framepos_t new_page_size;
1512 framepos_t half_page_size;
1513 framepos_t leftmost_after_zoom = 0;
1515 bool in_track_canvas;
1519 if (fpp == samples_per_pixel) {
1523 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1524 // segfaults for lack of memory. If somebody decides this is not high enough I
1525 // believe it can be raisen to higher values but some limit must be in place.
1527 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1528 // all of which is used for the editor track displays. The whole day
1529 // would be 4147200000 samples, so 2592000 samples per pixel.
1531 nfpp = min (fpp, (framecnt_t) 2592000);
1532 nfpp = max ((framecnt_t) 1, fpp);
1534 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1535 half_page_size = new_page_size / 2;
1537 switch (zoom_focus) {
1539 leftmost_after_zoom = current_leftmost;
1542 case ZoomFocusRight:
1543 current_rightmost = leftmost_frame + current_page;
1544 if (current_rightmost < new_page_size) {
1545 leftmost_after_zoom = 0;
1547 leftmost_after_zoom = current_rightmost - new_page_size;
1551 case ZoomFocusCenter:
1552 current_center = current_leftmost + (current_page/2);
1553 if (current_center < half_page_size) {
1554 leftmost_after_zoom = 0;
1556 leftmost_after_zoom = current_center - half_page_size;
1560 case ZoomFocusPlayhead:
1561 /* centre playhead */
1562 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1565 leftmost_after_zoom = 0;
1566 } else if (l > max_framepos) {
1567 leftmost_after_zoom = max_framepos - new_page_size;
1569 leftmost_after_zoom = (framepos_t) l;
1573 case ZoomFocusMouse:
1574 /* try to keep the mouse over the same point in the display */
1576 if (!mouse_frame (where, in_track_canvas)) {
1577 /* use playhead instead */
1578 where = playhead_cursor->current_frame ();
1580 if (where < half_page_size) {
1581 leftmost_after_zoom = 0;
1583 leftmost_after_zoom = where - half_page_size;
1588 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1591 leftmost_after_zoom = 0;
1592 } else if (l > max_framepos) {
1593 leftmost_after_zoom = max_framepos - new_page_size;
1595 leftmost_after_zoom = (framepos_t) l;
1602 /* try to keep the edit point in the same place */
1603 where = get_preferred_edit_position ();
1607 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1610 leftmost_after_zoom = 0;
1611 } else if (l > max_framepos) {
1612 leftmost_after_zoom = max_framepos - new_page_size;
1614 leftmost_after_zoom = (framepos_t) l;
1618 /* edit point not defined */
1625 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1627 reposition_and_zoom (leftmost_after_zoom, nfpp);
1631 Editor::temporal_zoom_region (bool both_axes)
1633 framepos_t start = max_framepos;
1635 set<TimeAxisView*> tracks;
1637 RegionSelection rs = get_regions_from_selection_and_entered ();
1643 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1645 if ((*i)->region()->position() < start) {
1646 start = (*i)->region()->position();
1649 if ((*i)->region()->last_frame() + 1 > end) {
1650 end = (*i)->region()->last_frame() + 1;
1653 tracks.insert (&((*i)->get_time_axis_view()));
1656 /* now comes an "interesting" hack ... make sure we leave a little space
1657 at each end of the editor so that the zoom doesn't fit the region
1658 precisely to the screen.
1661 GdkScreen* screen = gdk_screen_get_default ();
1662 gint pixwidth = gdk_screen_get_width (screen);
1663 gint mmwidth = gdk_screen_get_width_mm (screen);
1664 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1665 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1667 if ((start == 0 && end == 0) || end < start) {
1671 framepos_t range = end - start;
1672 double new_fpp = (double) range / (double) _visible_canvas_width;
1673 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1675 if (start > extra_samples) {
1676 start -= extra_samples;
1681 if (max_framepos - extra_samples > end) {
1682 end += extra_samples;
1687 /* if we're zooming on both axes we need to save track heights etc.
1690 undo_visual_stack.push_back (current_visual_state (both_axes));
1692 PBD::Unwinder<bool> nsv (no_save_visual, true);
1694 temporal_zoom_by_frame (start, end);
1697 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1699 /* set visible track heights appropriately */
1701 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1702 (*t)->set_height (per_track_height);
1705 /* hide irrelevant tracks */
1707 DisplaySuspender ds;
1709 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1710 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1711 hide_track_in_display (*i);
1715 vertical_adjustment.set_value (0.0);
1718 redo_visual_stack.push_back (current_visual_state (both_axes));
1722 Editor::zoom_to_region (bool both_axes)
1724 temporal_zoom_region (both_axes);
1728 Editor::temporal_zoom_selection ()
1730 if (!selection) return;
1732 if (selection->time.empty()) {
1736 framepos_t start = selection->time[clicked_selection].start;
1737 framepos_t end = selection->time[clicked_selection].end;
1739 temporal_zoom_by_frame (start, end);
1743 Editor::temporal_zoom_session ()
1745 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1748 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1749 double s = _session->current_start_frame() - l * 0.01;
1753 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1754 temporal_zoom_by_frame (framecnt_t (s), e);
1759 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1761 if (!_session) return;
1763 if ((start == 0 && end == 0) || end < start) {
1767 framepos_t range = end - start;
1769 double const new_fpp = (double) range / (double) _visible_canvas_width;
1771 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1772 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1773 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1775 if (new_leftmost > middle) {
1779 if (new_leftmost < 0) {
1783 reposition_and_zoom (new_leftmost, new_fpp);
1787 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1793 framecnt_t range_before = frame - leftmost_frame;
1797 if (samples_per_pixel <= 1) {
1800 new_spp = samples_per_pixel + (samples_per_pixel/2);
1802 range_before += range_before/2;
1804 if (samples_per_pixel >= 1) {
1805 new_spp = samples_per_pixel - (samples_per_pixel/2);
1807 /* could bail out here since we cannot zoom any finer,
1808 but leave that to the equality test below
1810 new_spp = samples_per_pixel;
1813 range_before -= range_before/2;
1816 if (new_spp == samples_per_pixel) {
1820 /* zoom focus is automatically taken as @param frame when this
1824 framepos_t new_leftmost = frame - (framepos_t)range_before;
1826 if (new_leftmost > frame) {
1830 if (new_leftmost < 0) {
1834 reposition_and_zoom (new_leftmost, new_spp);
1839 Editor::choose_new_marker_name(string &name) {
1841 if (!Config->get_name_new_markers()) {
1842 /* don't prompt user for a new name */
1846 ArdourPrompter dialog (true);
1848 dialog.set_prompt (_("New Name:"));
1850 dialog.set_title (_("New Location Marker"));
1852 dialog.set_name ("MarkNameWindow");
1853 dialog.set_size_request (250, -1);
1854 dialog.set_position (Gtk::WIN_POS_MOUSE);
1856 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1857 dialog.set_initial_text (name);
1861 switch (dialog.run ()) {
1862 case RESPONSE_ACCEPT:
1868 dialog.get_result(name);
1875 Editor::add_location_from_selection ()
1879 if (selection->time.empty()) {
1883 if (_session == 0 || clicked_axisview == 0) {
1887 framepos_t start = selection->time[clicked_selection].start;
1888 framepos_t end = selection->time[clicked_selection].end;
1890 _session->locations()->next_available_name(rangename,"selection");
1891 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1893 _session->begin_reversible_command (_("add marker"));
1894 XMLNode &before = _session->locations()->get_state();
1895 _session->locations()->add (location, true);
1896 XMLNode &after = _session->locations()->get_state();
1897 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1898 _session->commit_reversible_command ();
1902 Editor::add_location_mark (framepos_t where)
1906 select_new_marker = true;
1908 _session->locations()->next_available_name(markername,"mark");
1909 if (!choose_new_marker_name(markername)) {
1912 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1913 _session->begin_reversible_command (_("add marker"));
1914 XMLNode &before = _session->locations()->get_state();
1915 _session->locations()->add (location, true);
1916 XMLNode &after = _session->locations()->get_state();
1917 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1918 _session->commit_reversible_command ();
1922 Editor::add_location_from_playhead_cursor ()
1924 add_location_mark (_session->audible_frame());
1928 Editor::remove_location_at_playhead_cursor ()
1933 _session->begin_reversible_command (_("remove marker"));
1934 XMLNode &before = _session->locations()->get_state();
1935 bool removed = false;
1937 //find location(s) at this time
1938 Locations::LocationList locs;
1939 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1940 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1941 if ((*i)->is_mark()) {
1942 _session->locations()->remove (*i);
1949 XMLNode &after = _session->locations()->get_state();
1950 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1951 _session->commit_reversible_command ();
1956 /** Add a range marker around each selected region */
1958 Editor::add_locations_from_region ()
1960 RegionSelection rs = get_regions_from_selection_and_entered ();
1966 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1967 XMLNode &before = _session->locations()->get_state();
1969 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1971 boost::shared_ptr<Region> region = (*i)->region ();
1973 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1975 _session->locations()->add (location, true);
1978 XMLNode &after = _session->locations()->get_state();
1979 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1980 _session->commit_reversible_command ();
1983 /** Add a single range marker around all selected regions */
1985 Editor::add_location_from_region ()
1987 RegionSelection rs = get_regions_from_selection_and_entered ();
1993 _session->begin_reversible_command (_("add marker"));
1994 XMLNode &before = _session->locations()->get_state();
1998 if (rs.size() > 1) {
1999 _session->locations()->next_available_name(markername, "regions");
2001 RegionView* rv = *(rs.begin());
2002 boost::shared_ptr<Region> region = rv->region();
2003 markername = region->name();
2006 if (!choose_new_marker_name(markername)) {
2010 // single range spanning all selected
2011 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2012 _session->locations()->add (location, true);
2014 XMLNode &after = _session->locations()->get_state();
2015 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2016 _session->commit_reversible_command ();
2022 Editor::jump_forward_to_mark ()
2028 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2034 _session->request_locate (pos, _session->transport_rolling());
2038 Editor::jump_backward_to_mark ()
2044 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2050 _session->request_locate (pos, _session->transport_rolling());
2056 framepos_t const pos = _session->audible_frame ();
2059 _session->locations()->next_available_name (markername, "mark");
2061 if (!choose_new_marker_name (markername)) {
2065 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2069 Editor::clear_markers ()
2072 _session->begin_reversible_command (_("clear markers"));
2073 XMLNode &before = _session->locations()->get_state();
2074 _session->locations()->clear_markers ();
2075 XMLNode &after = _session->locations()->get_state();
2076 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2077 _session->commit_reversible_command ();
2082 Editor::clear_ranges ()
2085 _session->begin_reversible_command (_("clear ranges"));
2086 XMLNode &before = _session->locations()->get_state();
2088 Location * looploc = _session->locations()->auto_loop_location();
2089 Location * punchloc = _session->locations()->auto_punch_location();
2090 Location * sessionloc = _session->locations()->session_range_location();
2092 _session->locations()->clear_ranges ();
2094 if (looploc) _session->locations()->add (looploc);
2095 if (punchloc) _session->locations()->add (punchloc);
2096 if (sessionloc) _session->locations()->add (sessionloc);
2098 XMLNode &after = _session->locations()->get_state();
2099 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2100 _session->commit_reversible_command ();
2105 Editor::clear_locations ()
2107 _session->begin_reversible_command (_("clear locations"));
2108 XMLNode &before = _session->locations()->get_state();
2109 _session->locations()->clear ();
2110 XMLNode &after = _session->locations()->get_state();
2111 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2112 _session->commit_reversible_command ();
2113 _session->locations()->clear ();
2117 Editor::unhide_markers ()
2119 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2120 Location *l = (*i).first;
2121 if (l->is_hidden() && l->is_mark()) {
2122 l->set_hidden(false, this);
2128 Editor::unhide_ranges ()
2130 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2131 Location *l = (*i).first;
2132 if (l->is_hidden() && l->is_range_marker()) {
2133 l->set_hidden(false, this);
2138 /* INSERT/REPLACE */
2141 Editor::insert_region_list_selection (float times)
2143 RouteTimeAxisView *tv = 0;
2144 boost::shared_ptr<Playlist> playlist;
2146 if (clicked_routeview != 0) {
2147 tv = clicked_routeview;
2148 } else if (!selection->tracks.empty()) {
2149 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2152 } else if (entered_track != 0) {
2153 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2160 if ((playlist = tv->playlist()) == 0) {
2164 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2169 begin_reversible_command (_("insert region"));
2170 playlist->clear_changes ();
2171 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2172 if (Config->get_edit_mode() == Ripple)
2173 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2175 _session->add_command(new StatefulDiffCommand (playlist));
2176 commit_reversible_command ();
2179 /* BUILT-IN EFFECTS */
2182 Editor::reverse_selection ()
2187 /* GAIN ENVELOPE EDITING */
2190 Editor::edit_envelope ()
2197 Editor::transition_to_rolling (bool fwd)
2203 if (_session->config.get_external_sync()) {
2204 switch (Config->get_sync_source()) {
2208 /* transport controlled by the master */
2213 if (_session->is_auditioning()) {
2214 _session->cancel_audition ();
2218 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2222 Editor::play_from_start ()
2224 _session->request_locate (_session->current_start_frame(), true);
2228 Editor::play_from_edit_point ()
2230 _session->request_locate (get_preferred_edit_position(), true);
2234 Editor::play_from_edit_point_and_return ()
2236 framepos_t start_frame;
2237 framepos_t return_frame;
2239 start_frame = get_preferred_edit_position (true);
2241 if (_session->transport_rolling()) {
2242 _session->request_locate (start_frame, false);
2246 /* don't reset the return frame if its already set */
2248 if ((return_frame = _session->requested_return_frame()) < 0) {
2249 return_frame = _session->audible_frame();
2252 if (start_frame >= 0) {
2253 _session->request_roll_at_and_return (start_frame, return_frame);
2258 Editor::play_selection ()
2260 if (selection->time.empty()) {
2264 _session->request_play_range (&selection->time, true);
2268 Editor::get_preroll ()
2270 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2275 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2277 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2280 location -= get_preroll();
2282 //don't try to locate before the beginning of time
2286 //if follow_playhead is on, keep the playhead on the screen
2287 if ( _follow_playhead )
2288 if ( location < leftmost_frame )
2289 location = leftmost_frame;
2291 _session->request_locate( location );
2295 Editor::play_with_preroll ()
2297 if (selection->time.empty()) {
2300 framepos_t preroll = get_preroll();
2302 framepos_t start = 0;
2303 if (selection->time[clicked_selection].start > preroll)
2304 start = selection->time[clicked_selection].start - preroll;
2306 framepos_t end = selection->time[clicked_selection].end + preroll;
2308 AudioRange ar (start, end, 0);
2309 list<AudioRange> lar;
2312 _session->request_play_range (&lar, true);
2317 Editor::play_location (Location& location)
2319 if (location.start() <= location.end()) {
2323 _session->request_bounded_roll (location.start(), location.end());
2327 Editor::loop_location (Location& location)
2329 if (location.start() <= location.end()) {
2335 if ((tll = transport_loop_location()) != 0) {
2336 tll->set (location.start(), location.end());
2338 // enable looping, reposition and start rolling
2339 _session->request_play_loop (true);
2340 _session->request_locate (tll->start(), true);
2345 Editor::do_layer_operation (LayerOperation op)
2347 if (selection->regions.empty ()) {
2351 bool const multiple = selection->regions.size() > 1;
2355 begin_reversible_command (_("raise regions"));
2357 begin_reversible_command (_("raise region"));
2363 begin_reversible_command (_("raise regions to top"));
2365 begin_reversible_command (_("raise region to top"));
2371 begin_reversible_command (_("lower regions"));
2373 begin_reversible_command (_("lower region"));
2379 begin_reversible_command (_("lower regions to bottom"));
2381 begin_reversible_command (_("lower region"));
2386 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2387 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2388 (*i)->clear_owned_changes ();
2391 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2392 boost::shared_ptr<Region> r = (*i)->region ();
2404 r->lower_to_bottom ();
2408 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2409 vector<Command*> cmds;
2411 _session->add_commands (cmds);
2414 commit_reversible_command ();
2418 Editor::raise_region ()
2420 do_layer_operation (Raise);
2424 Editor::raise_region_to_top ()
2426 do_layer_operation (RaiseToTop);
2430 Editor::lower_region ()
2432 do_layer_operation (Lower);
2436 Editor::lower_region_to_bottom ()
2438 do_layer_operation (LowerToBottom);
2441 /** Show the region editor for the selected regions */
2443 Editor::show_region_properties ()
2445 selection->foreach_regionview (&RegionView::show_region_editor);
2448 /** Show the midi list editor for the selected MIDI regions */
2450 Editor::show_midi_list_editor ()
2452 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2456 Editor::rename_region ()
2458 RegionSelection rs = get_regions_from_selection_and_entered ();
2464 ArdourDialog d (*this, _("Rename Region"), true, false);
2466 Label label (_("New name:"));
2469 hbox.set_spacing (6);
2470 hbox.pack_start (label, false, false);
2471 hbox.pack_start (entry, true, true);
2473 d.get_vbox()->set_border_width (12);
2474 d.get_vbox()->pack_start (hbox, false, false);
2476 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2477 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2479 d.set_size_request (300, -1);
2481 entry.set_text (rs.front()->region()->name());
2482 entry.select_region (0, -1);
2484 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2490 int const ret = d.run();
2494 if (ret != RESPONSE_OK) {
2498 std::string str = entry.get_text();
2499 strip_whitespace_edges (str);
2501 rs.front()->region()->set_name (str);
2502 _regions->redisplay ();
2507 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2509 if (_session->is_auditioning()) {
2510 _session->cancel_audition ();
2513 // note: some potential for creativity here, because region doesn't
2514 // have to belong to the playlist that Route is handling
2516 // bool was_soloed = route.soloed();
2518 route.set_solo (true, this);
2520 _session->request_bounded_roll (region->position(), region->position() + region->length());
2522 /* XXX how to unset the solo state ? */
2525 /** Start an audition of the first selected region */
2527 Editor::play_edit_range ()
2529 framepos_t start, end;
2531 if (get_edit_op_range (start, end)) {
2532 _session->request_bounded_roll (start, end);
2537 Editor::play_selected_region ()
2539 framepos_t start = max_framepos;
2542 RegionSelection rs = get_regions_from_selection_and_entered ();
2548 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2549 if ((*i)->region()->position() < start) {
2550 start = (*i)->region()->position();
2552 if ((*i)->region()->last_frame() + 1 > end) {
2553 end = (*i)->region()->last_frame() + 1;
2557 _session->request_bounded_roll (start, end);
2561 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2563 _session->audition_region (region);
2567 Editor::region_from_selection ()
2569 if (clicked_axisview == 0) {
2573 if (selection->time.empty()) {
2577 framepos_t start = selection->time[clicked_selection].start;
2578 framepos_t end = selection->time[clicked_selection].end;
2580 TrackViewList tracks = get_tracks_for_range_action ();
2582 framepos_t selection_cnt = end - start + 1;
2584 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2585 boost::shared_ptr<Region> current;
2586 boost::shared_ptr<Playlist> pl;
2587 framepos_t internal_start;
2590 if ((pl = (*i)->playlist()) == 0) {
2594 if ((current = pl->top_region_at (start)) == 0) {
2598 internal_start = start - current->position();
2599 RegionFactory::region_name (new_name, current->name(), true);
2603 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2604 plist.add (ARDOUR::Properties::length, selection_cnt);
2605 plist.add (ARDOUR::Properties::name, new_name);
2606 plist.add (ARDOUR::Properties::layer, 0);
2608 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2613 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2615 if (selection->time.empty() || selection->tracks.empty()) {
2619 framepos_t start = selection->time[clicked_selection].start;
2620 framepos_t end = selection->time[clicked_selection].end;
2622 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2623 sort_track_selection (ts);
2625 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2626 boost::shared_ptr<Region> current;
2627 boost::shared_ptr<Playlist> playlist;
2628 framepos_t internal_start;
2631 if ((playlist = (*i)->playlist()) == 0) {
2635 if ((current = playlist->top_region_at(start)) == 0) {
2639 internal_start = start - current->position();
2640 RegionFactory::region_name (new_name, current->name(), true);
2644 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2645 plist.add (ARDOUR::Properties::length, end - start + 1);
2646 plist.add (ARDOUR::Properties::name, new_name);
2648 new_regions.push_back (RegionFactory::create (current, plist));
2653 Editor::split_multichannel_region ()
2655 RegionSelection rs = get_regions_from_selection_and_entered ();
2661 vector< boost::shared_ptr<Region> > v;
2663 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2664 (*x)->region()->separate_by_channel (*_session, v);
2669 Editor::new_region_from_selection ()
2671 region_from_selection ();
2672 cancel_selection ();
2676 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2678 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2679 case Evoral::OverlapNone:
2687 * - selected tracks, or if there are none...
2688 * - tracks containing selected regions, or if there are none...
2693 Editor::get_tracks_for_range_action () const
2697 if (selection->tracks.empty()) {
2699 /* use tracks with selected regions */
2701 RegionSelection rs = selection->regions;
2703 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2704 TimeAxisView* tv = &(*i)->get_time_axis_view();
2706 if (!t.contains (tv)) {
2712 /* no regions and no tracks: use all tracks */
2718 t = selection->tracks;
2721 return t.filter_to_unique_playlists();
2725 Editor::separate_regions_between (const TimeSelection& ts)
2727 bool in_command = false;
2728 boost::shared_ptr<Playlist> playlist;
2729 RegionSelection new_selection;
2731 TrackViewList tmptracks = get_tracks_for_range_action ();
2732 sort_track_selection (tmptracks);
2734 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2736 RouteTimeAxisView* rtv;
2738 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2740 if (rtv->is_track()) {
2742 /* no edits to destructive tracks */
2744 if (rtv->track()->destructive()) {
2748 if ((playlist = rtv->playlist()) != 0) {
2750 playlist->clear_changes ();
2752 /* XXX need to consider musical time selections here at some point */
2754 double speed = rtv->track()->speed();
2757 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2759 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2760 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2762 latest_regionviews.clear ();
2764 playlist->partition ((framepos_t)((*t).start * speed),
2765 (framepos_t)((*t).end * speed), false);
2769 if (!latest_regionviews.empty()) {
2771 rtv->view()->foreach_regionview (sigc::bind (
2772 sigc::ptr_fun (add_if_covered),
2773 &(*t), &new_selection));
2776 begin_reversible_command (_("separate"));
2780 /* pick up changes to existing regions */
2782 vector<Command*> cmds;
2783 playlist->rdiff (cmds);
2784 _session->add_commands (cmds);
2786 /* pick up changes to the playlist itself (adds/removes)
2789 _session->add_command(new StatefulDiffCommand (playlist));
2798 // selection->set (new_selection);
2800 commit_reversible_command ();
2804 struct PlaylistState {
2805 boost::shared_ptr<Playlist> playlist;
2809 /** Take tracks from get_tracks_for_range_action and cut any regions
2810 * on those tracks so that the tracks are empty over the time
2814 Editor::separate_region_from_selection ()
2816 /* preferentially use *all* ranges in the time selection if we're in range mode
2817 to allow discontiguous operation, since get_edit_op_range() currently
2818 returns a single range.
2821 if (!selection->time.empty()) {
2823 separate_regions_between (selection->time);
2830 if (get_edit_op_range (start, end)) {
2832 AudioRange ar (start, end, 1);
2836 separate_regions_between (ts);
2842 Editor::separate_region_from_punch ()
2844 Location* loc = _session->locations()->auto_punch_location();
2846 separate_regions_using_location (*loc);
2851 Editor::separate_region_from_loop ()
2853 Location* loc = _session->locations()->auto_loop_location();
2855 separate_regions_using_location (*loc);
2860 Editor::separate_regions_using_location (Location& loc)
2862 if (loc.is_mark()) {
2866 AudioRange ar (loc.start(), loc.end(), 1);
2871 separate_regions_between (ts);
2874 /** Separate regions under the selected region */
2876 Editor::separate_under_selected_regions ()
2878 vector<PlaylistState> playlists;
2882 rs = get_regions_from_selection_and_entered();
2884 if (!_session || rs.empty()) {
2888 begin_reversible_command (_("separate region under"));
2890 list<boost::shared_ptr<Region> > regions_to_remove;
2892 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2893 // we can't just remove the region(s) in this loop because
2894 // this removes them from the RegionSelection, and they thus
2895 // disappear from underneath the iterator, and the ++i above
2896 // SEGVs in a puzzling fashion.
2898 // so, first iterate over the regions to be removed from rs and
2899 // add them to the regions_to_remove list, and then
2900 // iterate over the list to actually remove them.
2902 regions_to_remove.push_back ((*i)->region());
2905 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2907 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2910 // is this check necessary?
2914 vector<PlaylistState>::iterator i;
2916 //only take state if this is a new playlist.
2917 for (i = playlists.begin(); i != playlists.end(); ++i) {
2918 if ((*i).playlist == playlist) {
2923 if (i == playlists.end()) {
2925 PlaylistState before;
2926 before.playlist = playlist;
2927 before.before = &playlist->get_state();
2929 playlist->freeze ();
2930 playlists.push_back(before);
2933 //Partition on the region bounds
2934 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2936 //Re-add region that was just removed due to the partition operation
2937 playlist->add_region( (*rl), (*rl)->first_frame() );
2940 vector<PlaylistState>::iterator pl;
2942 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2943 (*pl).playlist->thaw ();
2944 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2947 commit_reversible_command ();
2951 Editor::crop_region_to_selection ()
2953 if (!selection->time.empty()) {
2955 crop_region_to (selection->time.start(), selection->time.end_frame());
2962 if (get_edit_op_range (start, end)) {
2963 crop_region_to (start, end);
2970 Editor::crop_region_to (framepos_t start, framepos_t end)
2972 vector<boost::shared_ptr<Playlist> > playlists;
2973 boost::shared_ptr<Playlist> playlist;
2976 if (selection->tracks.empty()) {
2977 ts = track_views.filter_to_unique_playlists();
2979 ts = selection->tracks.filter_to_unique_playlists ();
2982 sort_track_selection (ts);
2984 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2986 RouteTimeAxisView* rtv;
2988 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2990 boost::shared_ptr<Track> t = rtv->track();
2992 if (t != 0 && ! t->destructive()) {
2994 if ((playlist = rtv->playlist()) != 0) {
2995 playlists.push_back (playlist);
3001 if (playlists.empty()) {
3005 framepos_t the_start;
3009 begin_reversible_command (_("trim to selection"));
3011 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3013 boost::shared_ptr<Region> region;
3017 if ((region = (*i)->top_region_at(the_start)) == 0) {
3021 /* now adjust lengths to that we do the right thing
3022 if the selection extends beyond the region
3025 the_start = max (the_start, (framepos_t) region->position());
3026 if (max_framepos - the_start < region->length()) {
3027 the_end = the_start + region->length() - 1;
3029 the_end = max_framepos;
3031 the_end = min (end, the_end);
3032 cnt = the_end - the_start + 1;
3034 region->clear_changes ();
3035 region->trim_to (the_start, cnt);
3036 _session->add_command (new StatefulDiffCommand (region));
3039 commit_reversible_command ();
3043 Editor::region_fill_track ()
3045 RegionSelection rs = get_regions_from_selection_and_entered ();
3047 if (!_session || rs.empty()) {
3051 framepos_t const end = _session->current_end_frame ();
3053 begin_reversible_command (Operations::region_fill);
3055 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3057 boost::shared_ptr<Region> region ((*i)->region());
3059 boost::shared_ptr<Playlist> pl = region->playlist();
3061 if (end <= region->last_frame()) {
3065 double times = (double) (end - region->last_frame()) / (double) region->length();
3071 pl->clear_changes ();
3072 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3073 _session->add_command (new StatefulDiffCommand (pl));
3076 commit_reversible_command ();
3080 Editor::region_fill_selection ()
3082 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3086 if (selection->time.empty()) {
3090 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3095 framepos_t start = selection->time[clicked_selection].start;
3096 framepos_t end = selection->time[clicked_selection].end;
3098 boost::shared_ptr<Playlist> playlist;
3100 if (selection->tracks.empty()) {
3104 framepos_t selection_length = end - start;
3105 float times = (float)selection_length / region->length();
3107 begin_reversible_command (Operations::fill_selection);
3109 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3111 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3113 if ((playlist = (*i)->playlist()) == 0) {
3117 playlist->clear_changes ();
3118 playlist->add_region (RegionFactory::create (region, true), start, times);
3119 _session->add_command (new StatefulDiffCommand (playlist));
3122 commit_reversible_command ();
3126 Editor::set_region_sync_position ()
3128 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3132 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3134 bool in_command = false;
3136 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3138 if (!(*r)->region()->covers (where)) {
3142 boost::shared_ptr<Region> region ((*r)->region());
3145 begin_reversible_command (_("set sync point"));
3149 region->clear_changes ();
3150 region->set_sync_position (where);
3151 _session->add_command(new StatefulDiffCommand (region));
3155 commit_reversible_command ();
3159 /** Remove the sync positions of the selection */
3161 Editor::remove_region_sync ()
3163 RegionSelection rs = get_regions_from_selection_and_entered ();
3169 begin_reversible_command (_("remove region sync"));
3171 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3173 (*i)->region()->clear_changes ();
3174 (*i)->region()->clear_sync_position ();
3175 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3178 commit_reversible_command ();
3182 Editor::naturalize_region ()
3184 RegionSelection rs = get_regions_from_selection_and_entered ();
3190 if (rs.size() > 1) {
3191 begin_reversible_command (_("move regions to original position"));
3193 begin_reversible_command (_("move region to original position"));
3196 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3197 (*i)->region()->clear_changes ();
3198 (*i)->region()->move_to_natural_position ();
3199 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3202 commit_reversible_command ();
3206 Editor::align_regions (RegionPoint what)
3208 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3214 begin_reversible_command (_("align selection"));
3216 framepos_t const position = get_preferred_edit_position ();
3218 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3219 align_region_internal ((*i)->region(), what, position);
3222 commit_reversible_command ();
3225 struct RegionSortByTime {
3226 bool operator() (const RegionView* a, const RegionView* b) {
3227 return a->region()->position() < b->region()->position();
3232 Editor::align_regions_relative (RegionPoint point)
3234 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3240 framepos_t const position = get_preferred_edit_position ();
3242 framepos_t distance = 0;
3246 list<RegionView*> sorted;
3247 rs.by_position (sorted);
3249 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3254 if (position > r->position()) {
3255 distance = position - r->position();
3257 distance = r->position() - position;
3263 if (position > r->last_frame()) {
3264 distance = position - r->last_frame();
3265 pos = r->position() + distance;
3267 distance = r->last_frame() - position;
3268 pos = r->position() - distance;
3274 pos = r->adjust_to_sync (position);
3275 if (pos > r->position()) {
3276 distance = pos - r->position();
3278 distance = r->position() - pos;
3284 if (pos == r->position()) {
3288 begin_reversible_command (_("align selection (relative)"));
3290 /* move first one specially */
3292 r->clear_changes ();
3293 r->set_position (pos);
3294 _session->add_command(new StatefulDiffCommand (r));
3296 /* move rest by the same amount */
3300 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3302 boost::shared_ptr<Region> region ((*i)->region());
3304 region->clear_changes ();
3307 region->set_position (region->position() + distance);
3309 region->set_position (region->position() - distance);
3312 _session->add_command(new StatefulDiffCommand (region));
3316 commit_reversible_command ();
3320 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3322 begin_reversible_command (_("align region"));
3323 align_region_internal (region, point, position);
3324 commit_reversible_command ();
3328 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3330 region->clear_changes ();
3334 region->set_position (region->adjust_to_sync (position));
3338 if (position > region->length()) {
3339 region->set_position (position - region->length());
3344 region->set_position (position);
3348 _session->add_command(new StatefulDiffCommand (region));
3352 Editor::trim_region_front ()
3358 Editor::trim_region_back ()
3360 trim_region (false);
3364 Editor::trim_region (bool front)
3366 framepos_t where = get_preferred_edit_position();
3367 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3373 begin_reversible_command (front ? _("trim front") : _("trim back"));
3375 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3376 if (!(*i)->region()->locked()) {
3378 (*i)->region()->clear_changes ();
3381 (*i)->region()->trim_front (where);
3382 maybe_locate_with_edit_preroll ( where );
3384 (*i)->region()->trim_end (where);
3385 maybe_locate_with_edit_preroll ( where );
3388 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3392 commit_reversible_command ();
3395 /** Trim the end of the selected regions to the position of the edit cursor */
3397 Editor::trim_region_to_loop ()
3399 Location* loc = _session->locations()->auto_loop_location();
3403 trim_region_to_location (*loc, _("trim to loop"));
3407 Editor::trim_region_to_punch ()
3409 Location* loc = _session->locations()->auto_punch_location();
3413 trim_region_to_location (*loc, _("trim to punch"));
3417 Editor::trim_region_to_location (const Location& loc, const char* str)
3419 RegionSelection rs = get_regions_from_selection_and_entered ();
3421 begin_reversible_command (str);
3423 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3424 RegionView* rv = (*x);
3426 /* require region to span proposed trim */
3427 switch (rv->region()->coverage (loc.start(), loc.end())) {
3428 case Evoral::OverlapInternal:
3434 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3443 if (tav->track() != 0) {
3444 speed = tav->track()->speed();
3447 start = session_frame_to_track_frame (loc.start(), speed);
3448 end = session_frame_to_track_frame (loc.end(), speed);
3450 rv->region()->clear_changes ();
3451 rv->region()->trim_to (start, (end - start));
3452 _session->add_command(new StatefulDiffCommand (rv->region()));
3455 commit_reversible_command ();
3459 Editor::trim_region_to_previous_region_end ()
3461 return trim_to_region(false);
3465 Editor::trim_region_to_next_region_start ()
3467 return trim_to_region(true);
3471 Editor::trim_to_region(bool forward)
3473 RegionSelection rs = get_regions_from_selection_and_entered ();
3475 begin_reversible_command (_("trim to region"));
3477 boost::shared_ptr<Region> next_region;
3479 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3481 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3487 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3495 if (atav->track() != 0) {
3496 speed = atav->track()->speed();
3500 boost::shared_ptr<Region> region = arv->region();
3501 boost::shared_ptr<Playlist> playlist (region->playlist());
3503 region->clear_changes ();
3507 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3513 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3514 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3518 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3524 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3526 arv->region_changed (ARDOUR::bounds_change);
3529 _session->add_command(new StatefulDiffCommand (region));
3532 commit_reversible_command ();
3536 Editor::unfreeze_route ()
3538 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3542 clicked_routeview->track()->unfreeze ();
3546 Editor::_freeze_thread (void* arg)
3548 return static_cast<Editor*>(arg)->freeze_thread ();
3552 Editor::freeze_thread ()
3554 /* create event pool because we may need to talk to the session */
3555 SessionEvent::create_per_thread_pool ("freeze events", 64);
3556 /* create per-thread buffers for process() tree to use */
3557 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3558 current_interthread_info->done = true;
3563 Editor::freeze_route ()
3569 /* stop transport before we start. this is important */
3571 _session->request_transport_speed (0.0);
3573 /* wait for just a little while, because the above call is asynchronous */
3575 Glib::usleep (250000);
3577 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3581 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3583 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3584 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3586 d.set_title (_("Cannot freeze"));
3591 if (clicked_routeview->track()->has_external_redirects()) {
3592 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"
3593 "Freezing will only process the signal as far as the first send/insert/return."),
3594 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3596 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3597 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3598 d.set_title (_("Freeze Limits"));
3600 int response = d.run ();
3603 case Gtk::RESPONSE_CANCEL:
3610 InterThreadInfo itt;
3611 current_interthread_info = &itt;
3613 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3615 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3617 set_canvas_cursor (_cursors->wait);
3619 while (!itt.done && !itt.cancel) {
3620 gtk_main_iteration ();
3623 current_interthread_info = 0;
3624 set_canvas_cursor (current_canvas_cursor);
3628 Editor::bounce_range_selection (bool replace, bool enable_processing)
3630 if (selection->time.empty()) {
3634 TrackSelection views = selection->tracks;
3636 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3638 if (enable_processing) {
3640 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3642 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3644 _("You can't perform this operation because the processing of the signal "
3645 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3646 "You can do this without processing, which is a different operation.")
3648 d.set_title (_("Cannot bounce"));
3655 framepos_t start = selection->time[clicked_selection].start;
3656 framepos_t end = selection->time[clicked_selection].end;
3657 framepos_t cnt = end - start + 1;
3659 begin_reversible_command (_("bounce range"));
3661 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3663 RouteTimeAxisView* rtv;
3665 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3669 boost::shared_ptr<Playlist> playlist;
3671 if ((playlist = rtv->playlist()) == 0) {
3675 InterThreadInfo itt;
3677 playlist->clear_changes ();
3678 playlist->clear_owned_changes ();
3680 boost::shared_ptr<Region> r;
3682 if (enable_processing) {
3683 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3685 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3693 list<AudioRange> ranges;
3694 ranges.push_back (AudioRange (start, start+cnt, 0));
3695 playlist->cut (ranges); // discard result
3696 playlist->add_region (r, start);
3699 vector<Command*> cmds;
3700 playlist->rdiff (cmds);
3701 _session->add_commands (cmds);
3703 _session->add_command (new StatefulDiffCommand (playlist));
3706 commit_reversible_command ();
3709 /** Delete selected regions, automation points or a time range */
3716 /** Cut selected regions, automation points or a time range */
3723 /** Copy selected regions, automation points or a time range */
3731 /** @return true if a Cut, Copy or Clear is possible */
3733 Editor::can_cut_copy () const
3735 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3742 /** Cut, copy or clear selected regions, automation points or a time range.
3743 * @param op Operation (Delete, Cut, Copy or Clear)
3746 Editor::cut_copy (CutCopyOp op)
3748 /* only cancel selection if cut/copy is successful.*/
3754 opname = _("delete");
3763 opname = _("clear");
3767 /* if we're deleting something, and the mouse is still pressed,
3768 the thing we started a drag for will be gone when we release
3769 the mouse button(s). avoid this. see part 2 at the end of
3773 if (op == Delete || op == Cut || op == Clear) {
3774 if (_drags->active ()) {
3779 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3780 cut_buffer->clear ();
3782 if (entered_marker) {
3784 /* cut/delete op while pointing at a marker */
3787 Location* loc = find_location_from_marker (entered_marker, ignored);
3789 if (_session && loc) {
3790 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3797 if (internal_editing()) {
3799 switch (effective_mouse_mode()) {
3802 begin_reversible_command (opname + ' ' + X_("MIDI"));
3804 commit_reversible_command ();
3813 bool did_edit = false;
3815 if (!selection->points.empty()) {
3816 begin_reversible_command (opname + _(" points"));
3818 cut_copy_points (op);
3819 if (op == Cut || op == Delete) {
3820 selection->clear_points ();
3822 } else if (!selection->regions.empty() || !selection->points.empty()) {
3826 if (selection->regions.empty()) {
3827 thing_name = _("points");
3828 } else if (selection->points.empty()) {
3829 thing_name = _("regions");
3831 thing_name = _("objects");
3834 begin_reversible_command (opname + ' ' + thing_name);
3837 if (!selection->regions.empty()) {
3838 cut_copy_regions (op, selection->regions);
3840 if (op == Cut || op == Delete) {
3841 selection->clear_regions ();
3845 if (!selection->points.empty()) {
3846 cut_copy_points (op);
3848 if (op == Cut || op == Delete) {
3849 selection->clear_points ();
3852 } else if (selection->time.empty()) {
3853 framepos_t start, end;
3854 /* no time selection, see if we can get an edit range
3857 if (get_edit_op_range (start, end)) {
3858 selection->set (start, end);
3860 } else if (!selection->time.empty()) {
3861 begin_reversible_command (opname + _(" range"));
3864 cut_copy_ranges (op);
3866 if (op == Cut || op == Delete) {
3867 selection->clear_time ();
3872 commit_reversible_command ();
3875 if (op == Delete || op == Cut || op == Clear) {
3880 struct AutomationRecord {
3881 AutomationRecord () : state (0) {}
3882 AutomationRecord (XMLNode* s) : state (s) {}
3884 XMLNode* state; ///< state before any operation
3885 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3888 /** Cut, copy or clear selected automation points.
3889 * @param op Operation (Cut, Copy or Clear)
3892 Editor::cut_copy_points (CutCopyOp op)
3894 if (selection->points.empty ()) {
3898 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3899 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3901 /* Keep a record of the AutomationLists that we end up using in this operation */
3902 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3905 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3906 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3907 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3908 if (lists.find (al) == lists.end ()) {
3909 /* We haven't seen this list yet, so make a record for it. This includes
3910 taking a copy of its current state, in case this is needed for undo later.
3912 lists[al] = AutomationRecord (&al->get_state ());
3916 if (op == Cut || op == Copy) {
3917 /* This operation will involve putting things in the cut buffer, so create an empty
3918 ControlList for each of our source lists to put the cut buffer data in.
3920 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3921 i->second.copy = i->first->create (i->first->parameter ());
3924 /* Add all selected points to the relevant copy ControlLists */
3925 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3926 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3927 AutomationList::const_iterator j = (*i)->model ();
3928 lists[al].copy->add ((*j)->when, (*j)->value);
3931 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3932 /* Correct this copy list so that it starts at time 0 */
3933 double const start = i->second.copy->front()->when;
3934 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3935 (*j)->when -= start;
3938 /* And add it to the cut buffer */
3939 cut_buffer->add (i->second.copy);
3943 if (op == Delete || op == Cut) {
3944 /* This operation needs to remove things from the main AutomationList, so do that now */
3946 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3947 i->first->freeze ();
3950 /* Remove each selected point from its AutomationList */
3951 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3952 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3953 al->erase ((*i)->model ());
3956 /* Thaw the lists and add undo records for them */
3957 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3958 boost::shared_ptr<AutomationList> al = i->first;
3960 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3965 /** Cut, copy or clear selected automation points.
3966 * @param op Operation (Cut, Copy or Clear)
3969 Editor::cut_copy_midi (CutCopyOp op)
3971 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3972 MidiRegionView* mrv = *i;
3973 mrv->cut_copy_clear (op);
3979 struct lt_playlist {
3980 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3981 return a.playlist < b.playlist;
3985 struct PlaylistMapping {
3987 boost::shared_ptr<Playlist> pl;
3989 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3992 /** Remove `clicked_regionview' */
3994 Editor::remove_clicked_region ()
3996 if (clicked_routeview == 0 || clicked_regionview == 0) {
4000 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4002 playlist->clear_changes ();
4003 playlist->clear_owned_changes ();
4004 playlist->remove_region (clicked_regionview->region());
4005 if (Config->get_edit_mode() == Ripple)
4006 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4008 /* We might have removed regions, which alters other regions' layering_index,
4009 so we need to do a recursive diff here.
4011 vector<Command*> cmds;
4012 playlist->rdiff (cmds);
4013 _session->add_commands (cmds);
4015 _session->add_command(new StatefulDiffCommand (playlist));
4016 commit_reversible_command ();
4020 /** Remove the selected regions */
4022 Editor::remove_selected_regions ()
4024 RegionSelection rs = get_regions_from_selection_and_entered ();
4026 if (!_session || rs.empty()) {
4030 begin_reversible_command (_("remove region"));
4032 list<boost::shared_ptr<Region> > regions_to_remove;
4034 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4035 // we can't just remove the region(s) in this loop because
4036 // this removes them from the RegionSelection, and they thus
4037 // disappear from underneath the iterator, and the ++i above
4038 // SEGVs in a puzzling fashion.
4040 // so, first iterate over the regions to be removed from rs and
4041 // add them to the regions_to_remove list, and then
4042 // iterate over the list to actually remove them.
4044 regions_to_remove.push_back ((*i)->region());
4047 vector<boost::shared_ptr<Playlist> > playlists;
4049 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4051 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4054 // is this check necessary?
4058 /* get_regions_from_selection_and_entered() guarantees that
4059 the playlists involved are unique, so there is no need
4063 playlists.push_back (playlist);
4065 playlist->clear_changes ();
4066 playlist->clear_owned_changes ();
4067 playlist->freeze ();
4068 playlist->remove_region (*rl);
4069 if (Config->get_edit_mode() == Ripple)
4070 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4074 vector<boost::shared_ptr<Playlist> >::iterator pl;
4076 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4079 /* We might have removed regions, which alters other regions' layering_index,
4080 so we need to do a recursive diff here.
4082 vector<Command*> cmds;
4083 (*pl)->rdiff (cmds);
4084 _session->add_commands (cmds);
4086 _session->add_command(new StatefulDiffCommand (*pl));
4089 commit_reversible_command ();
4092 /** Cut, copy or clear selected regions.
4093 * @param op Operation (Cut, Copy or Clear)
4096 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4098 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4099 a map when we want ordered access to both elements. i think.
4102 vector<PlaylistMapping> pmap;
4104 framepos_t first_position = max_framepos;
4106 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4107 FreezeList freezelist;
4109 /* get ordering correct before we cut/copy */
4111 rs.sort_by_position_and_track ();
4113 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4115 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4117 if (op == Cut || op == Clear || op == Delete) {
4118 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4121 FreezeList::iterator fl;
4123 // only take state if this is a new playlist.
4124 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4130 if (fl == freezelist.end()) {
4131 pl->clear_changes();
4132 pl->clear_owned_changes ();
4134 freezelist.insert (pl);
4139 TimeAxisView* tv = &(*x)->get_time_axis_view();
4140 vector<PlaylistMapping>::iterator z;
4142 for (z = pmap.begin(); z != pmap.end(); ++z) {
4143 if ((*z).tv == tv) {
4148 if (z == pmap.end()) {
4149 pmap.push_back (PlaylistMapping (tv));
4153 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4155 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4158 /* region not yet associated with a playlist (e.g. unfinished
4165 TimeAxisView& tv = (*x)->get_time_axis_view();
4166 boost::shared_ptr<Playlist> npl;
4167 RegionSelection::iterator tmp;
4174 vector<PlaylistMapping>::iterator z;
4176 for (z = pmap.begin(); z != pmap.end(); ++z) {
4177 if ((*z).tv == &tv) {
4182 assert (z != pmap.end());
4185 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4193 boost::shared_ptr<Region> r = (*x)->region();
4194 boost::shared_ptr<Region> _xx;
4200 pl->remove_region (r);
4201 if (Config->get_edit_mode() == Ripple)
4202 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4206 _xx = RegionFactory::create (r);
4207 npl->add_region (_xx, r->position() - first_position);
4208 pl->remove_region (r);
4209 if (Config->get_edit_mode() == Ripple)
4210 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4214 /* copy region before adding, so we're not putting same object into two different playlists */
4215 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4219 pl->remove_region (r);
4220 if (Config->get_edit_mode() == Ripple)
4221 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4230 list<boost::shared_ptr<Playlist> > foo;
4232 /* the pmap is in the same order as the tracks in which selected regions occured */
4234 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4237 foo.push_back ((*i).pl);
4242 cut_buffer->set (foo);
4246 _last_cut_copy_source_track = 0;
4248 _last_cut_copy_source_track = pmap.front().tv;
4252 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4255 /* We might have removed regions, which alters other regions' layering_index,
4256 so we need to do a recursive diff here.
4258 vector<Command*> cmds;
4259 (*pl)->rdiff (cmds);
4260 _session->add_commands (cmds);
4262 _session->add_command (new StatefulDiffCommand (*pl));
4267 Editor::cut_copy_ranges (CutCopyOp op)
4269 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4271 /* Sort the track selection now, so that it if is used, the playlists
4272 selected by the calls below to cut_copy_clear are in the order that
4273 their tracks appear in the editor. This makes things like paste
4274 of ranges work properly.
4277 sort_track_selection (ts);
4280 if (!entered_track) {
4283 ts.push_back (entered_track);
4286 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4287 (*i)->cut_copy_clear (*selection, op);
4292 Editor::paste (float times, bool from_context)
4294 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4296 paste_internal (get_preferred_edit_position (false, from_context), times);
4300 Editor::mouse_paste ()
4305 if (!mouse_frame (where, ignored)) {
4310 paste_internal (where, 1);
4314 Editor::paste_internal (framepos_t position, float times)
4316 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4318 if (internal_editing()) {
4319 if (cut_buffer->midi_notes.empty()) {
4323 if (cut_buffer->empty()) {
4328 if (position == max_framepos) {
4329 position = get_preferred_edit_position();
4330 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4334 TrackViewList::iterator i;
4337 /* get everything in the correct order */
4339 if (_edit_point == Editing::EditAtMouse && entered_track) {
4340 /* With the mouse edit point, paste onto the track under the mouse */
4341 ts.push_back (entered_track);
4342 } else if (!selection->tracks.empty()) {
4343 /* Otherwise, if there are some selected tracks, paste to them */
4344 ts = selection->tracks.filter_to_unique_playlists ();
4345 sort_track_selection (ts);
4346 } else if (_last_cut_copy_source_track) {
4347 /* Otherwise paste to the track that the cut/copy came from;
4348 see discussion in mantis #3333.
4350 ts.push_back (_last_cut_copy_source_track);
4353 if (internal_editing ()) {
4355 /* undo/redo is handled by individual tracks/regions */
4357 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4360 RegionSelection::iterator r;
4361 MidiNoteSelection::iterator cb;
4363 get_regions_at (rs, position, ts);
4365 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4366 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4367 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4369 mrv->paste (position, times, **cb);
4377 /* we do redo (do you do voodoo?) */
4379 begin_reversible_command (Operations::paste);
4381 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4382 (*i)->paste (position, times, *cut_buffer, nth);
4385 commit_reversible_command ();
4390 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4392 boost::shared_ptr<Playlist> playlist;
4393 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4394 RegionSelection foo;
4396 framepos_t const start_frame = regions.start ();
4397 framepos_t const end_frame = regions.end_frame ();
4399 begin_reversible_command (Operations::duplicate_region);
4401 selection->clear_regions ();
4403 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4405 boost::shared_ptr<Region> r ((*i)->region());
4407 TimeAxisView& tv = (*i)->get_time_axis_view();
4408 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4409 latest_regionviews.clear ();
4410 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4412 playlist = (*i)->region()->playlist();
4413 playlist->clear_changes ();
4414 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4415 _session->add_command(new StatefulDiffCommand (playlist));
4419 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4422 commit_reversible_command ();
4425 selection->set (foo);
4430 Editor::duplicate_selection (float times)
4432 if (selection->time.empty() || selection->tracks.empty()) {
4436 boost::shared_ptr<Playlist> playlist;
4437 vector<boost::shared_ptr<Region> > new_regions;
4438 vector<boost::shared_ptr<Region> >::iterator ri;
4440 create_region_from_selection (new_regions);
4442 if (new_regions.empty()) {
4446 begin_reversible_command (_("duplicate selection"));
4448 ri = new_regions.begin();
4450 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4452 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4453 if ((playlist = (*i)->playlist()) == 0) {
4456 playlist->clear_changes ();
4457 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4458 _session->add_command (new StatefulDiffCommand (playlist));
4461 if (ri == new_regions.end()) {
4466 commit_reversible_command ();
4469 /** Reset all selected points to the relevant default value */
4471 Editor::reset_point_selection ()
4473 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4474 ARDOUR::AutomationList::iterator j = (*i)->model ();
4475 (*j)->value = (*i)->line().the_list()->default_value ();
4480 Editor::center_playhead ()
4482 float const page = _visible_canvas_width * samples_per_pixel;
4483 center_screen_internal (playhead_cursor->current_frame (), page);
4487 Editor::center_edit_point ()
4489 float const page = _visible_canvas_width * samples_per_pixel;
4490 center_screen_internal (get_preferred_edit_position(), page);
4493 /** Caller must begin and commit a reversible command */
4495 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4497 playlist->clear_changes ();
4499 _session->add_command (new StatefulDiffCommand (playlist));
4503 Editor::nudge_track (bool use_edit, bool forwards)
4505 boost::shared_ptr<Playlist> playlist;
4506 framepos_t distance;
4507 framepos_t next_distance;
4511 start = get_preferred_edit_position();
4516 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4520 if (selection->tracks.empty()) {
4524 begin_reversible_command (_("nudge track"));
4526 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4528 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4530 if ((playlist = (*i)->playlist()) == 0) {
4534 playlist->clear_changes ();
4535 playlist->clear_owned_changes ();
4537 playlist->nudge_after (start, distance, forwards);
4539 vector<Command*> cmds;
4541 playlist->rdiff (cmds);
4542 _session->add_commands (cmds);
4544 _session->add_command (new StatefulDiffCommand (playlist));
4547 commit_reversible_command ();
4551 Editor::remove_last_capture ()
4553 vector<string> choices;
4560 if (Config->get_verify_remove_last_capture()) {
4561 prompt = _("Do you really want to destroy the last capture?"
4562 "\n(This is destructive and cannot be undone)");
4564 choices.push_back (_("No, do nothing."));
4565 choices.push_back (_("Yes, destroy it."));
4567 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4569 if (prompter.run () == 1) {
4570 _session->remove_last_capture ();
4571 _regions->redisplay ();
4575 _session->remove_last_capture();
4576 _regions->redisplay ();
4581 Editor::normalize_region ()
4587 RegionSelection rs = get_regions_from_selection_and_entered ();
4593 NormalizeDialog dialog (rs.size() > 1);
4595 if (dialog.run () == RESPONSE_CANCEL) {
4599 set_canvas_cursor (_cursors->wait);
4602 /* XXX: should really only count audio regions here */
4603 int const regions = rs.size ();
4605 /* Make a list of the selected audio regions' maximum amplitudes, and also
4606 obtain the maximum amplitude of them all.
4608 list<double> max_amps;
4610 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4611 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4613 dialog.descend (1.0 / regions);
4614 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4617 /* the user cancelled the operation */
4618 set_canvas_cursor (current_canvas_cursor);
4622 max_amps.push_back (a);
4623 max_amp = max (max_amp, a);
4628 begin_reversible_command (_("normalize"));
4630 list<double>::const_iterator a = max_amps.begin ();
4632 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4633 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4638 arv->region()->clear_changes ();
4640 double const amp = dialog.normalize_individually() ? *a : max_amp;
4642 arv->audio_region()->normalize (amp, dialog.target ());
4643 _session->add_command (new StatefulDiffCommand (arv->region()));
4648 commit_reversible_command ();
4649 set_canvas_cursor (current_canvas_cursor);
4654 Editor::reset_region_scale_amplitude ()
4660 RegionSelection rs = get_regions_from_selection_and_entered ();
4666 begin_reversible_command ("reset gain");
4668 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4669 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4672 arv->region()->clear_changes ();
4673 arv->audio_region()->set_scale_amplitude (1.0f);
4674 _session->add_command (new StatefulDiffCommand (arv->region()));
4677 commit_reversible_command ();
4681 Editor::adjust_region_gain (bool up)
4683 RegionSelection rs = get_regions_from_selection_and_entered ();
4685 if (!_session || rs.empty()) {
4689 begin_reversible_command ("adjust region gain");
4691 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4692 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4697 arv->region()->clear_changes ();
4699 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4707 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4708 _session->add_command (new StatefulDiffCommand (arv->region()));
4711 commit_reversible_command ();
4716 Editor::reverse_region ()
4722 Reverse rev (*_session);
4723 apply_filter (rev, _("reverse regions"));
4727 Editor::strip_region_silence ()
4733 RegionSelection rs = get_regions_from_selection_and_entered ();
4739 std::list<RegionView*> audio_only;
4741 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4742 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4744 audio_only.push_back (arv);
4748 StripSilenceDialog d (_session, audio_only);
4749 int const r = d.run ();
4753 if (r == Gtk::RESPONSE_OK) {
4754 ARDOUR::AudioIntervalMap silences;
4755 d.silences (silences);
4756 StripSilence s (*_session, silences, d.fade_length());
4757 apply_filter (s, _("strip silence"), &d);
4762 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4764 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4765 mrv.selection_as_notelist (selected, true);
4767 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4768 v.push_back (selected);
4770 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4771 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4773 return op (mrv.midi_region()->model(), pos_beats, v);
4777 Editor::apply_midi_note_edit_op (MidiOperator& op)
4781 RegionSelection rs = get_regions_from_selection_and_entered ();
4787 begin_reversible_command (op.name ());
4789 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4790 RegionSelection::iterator tmp = r;
4793 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4796 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4799 _session->add_command (cmd);
4806 commit_reversible_command ();
4810 Editor::fork_region ()
4812 RegionSelection rs = get_regions_from_selection_and_entered ();
4818 begin_reversible_command (_("Fork Region(s)"));
4820 set_canvas_cursor (_cursors->wait);
4823 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4824 RegionSelection::iterator tmp = r;
4827 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4831 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4832 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4833 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4835 playlist->clear_changes ();
4836 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4837 _session->add_command(new StatefulDiffCommand (playlist));
4839 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4846 commit_reversible_command ();
4848 set_canvas_cursor (current_canvas_cursor);
4852 Editor::quantize_region ()
4854 int selected_midi_region_cnt = 0;
4860 RegionSelection rs = get_regions_from_selection_and_entered ();
4866 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4867 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4869 selected_midi_region_cnt++;
4873 if (selected_midi_region_cnt == 0) {
4877 QuantizeDialog* qd = new QuantizeDialog (*this);
4880 const int r = qd->run ();
4883 if (r == Gtk::RESPONSE_OK) {
4884 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4885 qd->start_grid_size(), qd->end_grid_size(),
4886 qd->strength(), qd->swing(), qd->threshold());
4888 apply_midi_note_edit_op (quant);
4893 Editor::insert_patch_change (bool from_context)
4895 RegionSelection rs = get_regions_from_selection_and_entered ();
4901 const framepos_t p = get_preferred_edit_position (false, from_context);
4903 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4904 there may be more than one, but the PatchChangeDialog can only offer
4905 one set of patch menus.
4907 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4909 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4910 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4912 if (d.run() == RESPONSE_CANCEL) {
4916 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4917 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4919 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4920 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4927 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4929 RegionSelection rs = get_regions_from_selection_and_entered ();
4935 begin_reversible_command (command);
4937 set_canvas_cursor (_cursors->wait);
4941 int const N = rs.size ();
4943 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4944 RegionSelection::iterator tmp = r;
4947 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4949 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4952 progress->descend (1.0 / N);
4955 if (arv->audio_region()->apply (filter, progress) == 0) {
4957 playlist->clear_changes ();
4958 playlist->clear_owned_changes ();
4960 if (filter.results.empty ()) {
4962 /* no regions returned; remove the old one */
4963 playlist->remove_region (arv->region ());
4967 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4969 /* first region replaces the old one */
4970 playlist->replace_region (arv->region(), *res, (*res)->position());
4974 while (res != filter.results.end()) {
4975 playlist->add_region (*res, (*res)->position());
4981 /* We might have removed regions, which alters other regions' layering_index,
4982 so we need to do a recursive diff here.
4984 vector<Command*> cmds;
4985 playlist->rdiff (cmds);
4986 _session->add_commands (cmds);
4988 _session->add_command(new StatefulDiffCommand (playlist));
4994 progress->ascend ();
5002 commit_reversible_command ();
5005 set_canvas_cursor (current_canvas_cursor);
5009 Editor::external_edit_region ()
5015 Editor::reset_region_gain_envelopes ()
5017 RegionSelection rs = get_regions_from_selection_and_entered ();
5019 if (!_session || rs.empty()) {
5023 _session->begin_reversible_command (_("reset region gain"));
5025 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5026 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5028 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5029 XMLNode& before (alist->get_state());
5031 arv->audio_region()->set_default_envelope ();
5032 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5036 _session->commit_reversible_command ();
5040 Editor::set_region_gain_visibility (RegionView* rv)
5042 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5044 arv->update_envelope_visibility();
5049 Editor::set_gain_envelope_visibility ()
5055 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5056 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5058 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5064 Editor::toggle_gain_envelope_active ()
5066 if (_ignore_region_action) {
5070 RegionSelection rs = get_regions_from_selection_and_entered ();
5072 if (!_session || rs.empty()) {
5076 _session->begin_reversible_command (_("region gain envelope active"));
5078 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5079 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5081 arv->region()->clear_changes ();
5082 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5083 _session->add_command (new StatefulDiffCommand (arv->region()));
5087 _session->commit_reversible_command ();
5091 Editor::toggle_region_lock ()
5093 if (_ignore_region_action) {
5097 RegionSelection rs = get_regions_from_selection_and_entered ();
5099 if (!_session || rs.empty()) {
5103 _session->begin_reversible_command (_("toggle region lock"));
5105 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5106 (*i)->region()->clear_changes ();
5107 (*i)->region()->set_locked (!(*i)->region()->locked());
5108 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5111 _session->commit_reversible_command ();
5115 Editor::toggle_region_video_lock ()
5117 if (_ignore_region_action) {
5121 RegionSelection rs = get_regions_from_selection_and_entered ();
5123 if (!_session || rs.empty()) {
5127 _session->begin_reversible_command (_("Toggle Video Lock"));
5129 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5130 (*i)->region()->clear_changes ();
5131 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5132 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5135 _session->commit_reversible_command ();
5139 Editor::toggle_region_lock_style ()
5141 if (_ignore_region_action) {
5145 RegionSelection rs = get_regions_from_selection_and_entered ();
5147 if (!_session || rs.empty()) {
5151 _session->begin_reversible_command (_("region lock style"));
5153 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5154 (*i)->region()->clear_changes ();
5155 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5156 (*i)->region()->set_position_lock_style (ns);
5157 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5160 _session->commit_reversible_command ();
5164 Editor::toggle_opaque_region ()
5166 if (_ignore_region_action) {
5170 RegionSelection rs = get_regions_from_selection_and_entered ();
5172 if (!_session || rs.empty()) {
5176 _session->begin_reversible_command (_("change region opacity"));
5178 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5179 (*i)->region()->clear_changes ();
5180 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5181 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5184 _session->commit_reversible_command ();
5188 Editor::toggle_record_enable ()
5190 bool new_state = false;
5192 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5193 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5196 if (!rtav->is_track())
5200 new_state = !rtav->track()->record_enabled();
5204 rtav->track()->set_record_enabled (new_state, this);
5209 Editor::toggle_solo ()
5211 bool new_state = false;
5213 boost::shared_ptr<RouteList> rl (new RouteList);
5215 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5216 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5223 new_state = !rtav->route()->soloed ();
5227 rl->push_back (rtav->route());
5230 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5234 Editor::toggle_mute ()
5236 bool new_state = false;
5238 boost::shared_ptr<RouteList> rl (new RouteList);
5240 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5241 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5248 new_state = !rtav->route()->muted();
5252 rl->push_back (rtav->route());
5255 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5259 Editor::toggle_solo_isolate ()
5265 Editor::fade_range ()
5267 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5269 begin_reversible_command (_("fade range"));
5271 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5272 (*i)->fade_range (selection->time);
5275 commit_reversible_command ();
5280 Editor::set_fade_length (bool in)
5282 RegionSelection rs = get_regions_from_selection_and_entered ();
5288 /* we need a region to measure the offset from the start */
5290 RegionView* rv = rs.front ();
5292 framepos_t pos = get_preferred_edit_position();
5296 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5297 /* edit point is outside the relevant region */
5302 if (pos <= rv->region()->position()) {
5306 len = pos - rv->region()->position();
5307 cmd = _("set fade in length");
5309 if (pos >= rv->region()->last_frame()) {
5313 len = rv->region()->last_frame() - pos;
5314 cmd = _("set fade out length");
5317 begin_reversible_command (cmd);
5319 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5320 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5326 boost::shared_ptr<AutomationList> alist;
5328 alist = tmp->audio_region()->fade_in();
5330 alist = tmp->audio_region()->fade_out();
5333 XMLNode &before = alist->get_state();
5336 tmp->audio_region()->set_fade_in_length (len);
5337 tmp->audio_region()->set_fade_in_active (true);
5339 tmp->audio_region()->set_fade_out_length (len);
5340 tmp->audio_region()->set_fade_out_active (true);
5343 XMLNode &after = alist->get_state();
5344 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5347 commit_reversible_command ();
5351 Editor::set_fade_in_shape (FadeShape shape)
5353 RegionSelection rs = get_regions_from_selection_and_entered ();
5359 begin_reversible_command (_("set fade in shape"));
5361 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5362 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5368 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5369 XMLNode &before = alist->get_state();
5371 tmp->audio_region()->set_fade_in_shape (shape);
5373 XMLNode &after = alist->get_state();
5374 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5377 commit_reversible_command ();
5382 Editor::set_fade_out_shape (FadeShape shape)
5384 RegionSelection rs = get_regions_from_selection_and_entered ();
5390 begin_reversible_command (_("set fade out shape"));
5392 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5393 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5399 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5400 XMLNode &before = alist->get_state();
5402 tmp->audio_region()->set_fade_out_shape (shape);
5404 XMLNode &after = alist->get_state();
5405 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5408 commit_reversible_command ();
5412 Editor::set_fade_in_active (bool yn)
5414 RegionSelection rs = get_regions_from_selection_and_entered ();
5420 begin_reversible_command (_("set fade in active"));
5422 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5423 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5430 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5432 ar->clear_changes ();
5433 ar->set_fade_in_active (yn);
5434 _session->add_command (new StatefulDiffCommand (ar));
5437 commit_reversible_command ();
5441 Editor::set_fade_out_active (bool yn)
5443 RegionSelection rs = get_regions_from_selection_and_entered ();
5449 begin_reversible_command (_("set fade out active"));
5451 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5452 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5458 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5460 ar->clear_changes ();
5461 ar->set_fade_out_active (yn);
5462 _session->add_command(new StatefulDiffCommand (ar));
5465 commit_reversible_command ();
5469 Editor::toggle_region_fades (int dir)
5471 if (_ignore_region_action) {
5475 boost::shared_ptr<AudioRegion> ar;
5478 RegionSelection rs = get_regions_from_selection_and_entered ();
5484 RegionSelection::iterator i;
5485 for (i = rs.begin(); i != rs.end(); ++i) {
5486 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5488 yn = ar->fade_out_active ();
5490 yn = ar->fade_in_active ();
5496 if (i == rs.end()) {
5500 /* XXX should this undo-able? */
5502 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5503 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5506 if (dir == 1 || dir == 0) {
5507 ar->set_fade_in_active (!yn);
5510 if (dir == -1 || dir == 0) {
5511 ar->set_fade_out_active (!yn);
5517 /** Update region fade visibility after its configuration has been changed */
5519 Editor::update_region_fade_visibility ()
5521 bool _fade_visibility = _session->config.get_show_region_fades ();
5523 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5524 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5526 if (_fade_visibility) {
5527 v->audio_view()->show_all_fades ();
5529 v->audio_view()->hide_all_fades ();
5536 Editor::set_edit_point ()
5541 if (!mouse_frame (where, ignored)) {
5547 if (selection->markers.empty()) {
5549 mouse_add_new_marker (where);
5554 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5557 loc->move_to (where);
5563 Editor::set_playhead_cursor ()
5565 if (entered_marker) {
5566 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5571 if (!mouse_frame (where, ignored)) {
5578 _session->request_locate (where, _session->transport_rolling());
5582 if ( Config->get_follow_edits() )
5583 cancel_time_selection();
5587 Editor::split_region ()
5589 if ( !selection->time.empty()) {
5590 separate_regions_between (selection->time);
5594 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5596 framepos_t where = get_preferred_edit_position ();
5602 split_regions_at (where, rs);
5605 struct EditorOrderRouteSorter {
5606 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5607 return a->order_key () < b->order_key ();
5612 Editor::select_next_route()
5614 if (selection->tracks.empty()) {
5615 selection->set (track_views.front());
5619 TimeAxisView* current = selection->tracks.front();
5623 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5624 if (*i == current) {
5626 if (i != track_views.end()) {
5629 current = (*(track_views.begin()));
5630 //selection->set (*(track_views.begin()));
5635 rui = dynamic_cast<RouteUI *>(current);
5636 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5638 selection->set(current);
5640 ensure_time_axis_view_is_visible (*current);
5644 Editor::select_prev_route()
5646 if (selection->tracks.empty()) {
5647 selection->set (track_views.front());
5651 TimeAxisView* current = selection->tracks.front();
5655 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5656 if (*i == current) {
5658 if (i != track_views.rend()) {
5661 current = *(track_views.rbegin());
5666 rui = dynamic_cast<RouteUI *>(current);
5667 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5669 selection->set (current);
5671 ensure_time_axis_view_is_visible (*current);
5675 Editor::set_loop_from_selection (bool play)
5677 if (_session == 0 || selection->time.empty()) {
5681 framepos_t start = selection->time[clicked_selection].start;
5682 framepos_t end = selection->time[clicked_selection].end;
5684 set_loop_range (start, end, _("set loop range from selection"));
5687 _session->request_play_loop (true);
5688 _session->request_locate (start, true);
5693 Editor::set_loop_from_edit_range (bool play)
5695 if (_session == 0) {
5702 if (!get_edit_op_range (start, end)) {
5706 set_loop_range (start, end, _("set loop range from edit range"));
5709 _session->request_play_loop (true);
5710 _session->request_locate (start, true);
5715 Editor::set_loop_from_region (bool play)
5717 framepos_t start = max_framepos;
5720 RegionSelection rs = get_regions_from_selection_and_entered ();
5726 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5727 if ((*i)->region()->position() < start) {
5728 start = (*i)->region()->position();
5730 if ((*i)->region()->last_frame() + 1 > end) {
5731 end = (*i)->region()->last_frame() + 1;
5735 set_loop_range (start, end, _("set loop range from region"));
5738 _session->request_play_loop (true);
5739 _session->request_locate (start, true);
5744 Editor::set_punch_from_selection ()
5746 if (_session == 0 || selection->time.empty()) {
5750 framepos_t start = selection->time[clicked_selection].start;
5751 framepos_t end = selection->time[clicked_selection].end;
5753 set_punch_range (start, end, _("set punch range from selection"));
5757 Editor::set_punch_from_edit_range ()
5759 if (_session == 0) {
5766 if (!get_edit_op_range (start, end)) {
5770 set_punch_range (start, end, _("set punch range from edit range"));
5774 Editor::set_punch_from_region ()
5776 framepos_t start = max_framepos;
5779 RegionSelection rs = get_regions_from_selection_and_entered ();
5785 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5786 if ((*i)->region()->position() < start) {
5787 start = (*i)->region()->position();
5789 if ((*i)->region()->last_frame() + 1 > end) {
5790 end = (*i)->region()->last_frame() + 1;
5794 set_punch_range (start, end, _("set punch range from region"));
5798 Editor::pitch_shift_region ()
5800 RegionSelection rs = get_regions_from_selection_and_entered ();
5802 RegionSelection audio_rs;
5803 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5804 if (dynamic_cast<AudioRegionView*> (*i)) {
5805 audio_rs.push_back (*i);
5809 if (audio_rs.empty()) {
5813 pitch_shift (audio_rs, 1.2);
5817 Editor::transpose_region ()
5819 RegionSelection rs = get_regions_from_selection_and_entered ();
5821 list<MidiRegionView*> midi_region_views;
5822 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5823 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5825 midi_region_views.push_back (mrv);
5830 int const r = d.run ();
5831 if (r != RESPONSE_ACCEPT) {
5835 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5836 (*i)->midi_region()->transpose (d.semitones ());
5841 Editor::set_tempo_from_region ()
5843 RegionSelection rs = get_regions_from_selection_and_entered ();
5845 if (!_session || rs.empty()) {
5849 RegionView* rv = rs.front();
5851 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5855 Editor::use_range_as_bar ()
5857 framepos_t start, end;
5858 if (get_edit_op_range (start, end)) {
5859 define_one_bar (start, end);
5864 Editor::define_one_bar (framepos_t start, framepos_t end)
5866 framepos_t length = end - start;
5868 const Meter& m (_session->tempo_map().meter_at (start));
5870 /* length = 1 bar */
5872 /* now we want frames per beat.
5873 we have frames per bar, and beats per bar, so ...
5876 /* XXXX METER MATH */
5878 double frames_per_beat = length / m.divisions_per_bar();
5880 /* beats per minute = */
5882 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5884 /* now decide whether to:
5886 (a) set global tempo
5887 (b) add a new tempo marker
5891 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5893 bool do_global = false;
5895 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5897 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5898 at the start, or create a new marker
5901 vector<string> options;
5902 options.push_back (_("Cancel"));
5903 options.push_back (_("Add new marker"));
5904 options.push_back (_("Set global tempo"));
5907 _("Define one bar"),
5908 _("Do you want to set the global tempo or add a new tempo marker?"),
5912 c.set_default_response (2);
5928 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5929 if the marker is at the region starter, change it, otherwise add
5934 begin_reversible_command (_("set tempo from region"));
5935 XMLNode& before (_session->tempo_map().get_state());
5938 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5939 } else if (t.frame() == start) {
5940 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5942 Timecode::BBT_Time bbt;
5943 _session->tempo_map().bbt_time (start, bbt);
5944 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5947 XMLNode& after (_session->tempo_map().get_state());
5949 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5950 commit_reversible_command ();
5954 Editor::split_region_at_transients ()
5956 AnalysisFeatureList positions;
5958 RegionSelection rs = get_regions_from_selection_and_entered ();
5960 if (!_session || rs.empty()) {
5964 _session->begin_reversible_command (_("split regions"));
5966 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5968 RegionSelection::iterator tmp;
5973 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5975 if (ar && (ar->get_transients (positions) == 0)) {
5976 split_region_at_points ((*i)->region(), positions, true);
5983 _session->commit_reversible_command ();
5988 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5990 bool use_rhythmic_rodent = false;
5992 boost::shared_ptr<Playlist> pl = r->playlist();
5994 list<boost::shared_ptr<Region> > new_regions;
6000 if (positions.empty()) {
6005 if (positions.size() > 20 && can_ferret) {
6006 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);
6007 MessageDialog msg (msgstr,
6010 Gtk::BUTTONS_OK_CANCEL);
6013 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6014 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6016 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6019 msg.set_title (_("Excessive split?"));
6022 int response = msg.run();
6028 case RESPONSE_APPLY:
6029 use_rhythmic_rodent = true;
6036 if (use_rhythmic_rodent) {
6037 show_rhythm_ferret ();
6041 AnalysisFeatureList::const_iterator x;
6043 pl->clear_changes ();
6044 pl->clear_owned_changes ();
6046 x = positions.begin();
6048 if (x == positions.end()) {
6053 pl->remove_region (r);
6057 while (x != positions.end()) {
6059 /* deal with positons that are out of scope of present region bounds */
6060 if (*x <= 0 || *x > r->length()) {
6065 /* file start = original start + how far we from the initial position ?
6068 framepos_t file_start = r->start() + pos;
6070 /* length = next position - current position
6073 framepos_t len = (*x) - pos;
6075 /* XXX we do we really want to allow even single-sample regions?
6076 shouldn't we have some kind of lower limit on region size?
6085 if (RegionFactory::region_name (new_name, r->name())) {
6089 /* do NOT announce new regions 1 by one, just wait till they are all done */
6093 plist.add (ARDOUR::Properties::start, file_start);
6094 plist.add (ARDOUR::Properties::length, len);
6095 plist.add (ARDOUR::Properties::name, new_name);
6096 plist.add (ARDOUR::Properties::layer, 0);
6098 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6099 /* because we set annouce to false, manually add the new region to the
6102 RegionFactory::map_add (nr);
6104 pl->add_region (nr, r->position() + pos);
6107 new_regions.push_front(nr);
6116 RegionFactory::region_name (new_name, r->name());
6118 /* Add the final region */
6121 plist.add (ARDOUR::Properties::start, r->start() + pos);
6122 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6123 plist.add (ARDOUR::Properties::name, new_name);
6124 plist.add (ARDOUR::Properties::layer, 0);
6126 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6127 /* because we set annouce to false, manually add the new region to the
6130 RegionFactory::map_add (nr);
6131 pl->add_region (nr, r->position() + pos);
6134 new_regions.push_front(nr);
6139 /* We might have removed regions, which alters other regions' layering_index,
6140 so we need to do a recursive diff here.
6142 vector<Command*> cmds;
6144 _session->add_commands (cmds);
6146 _session->add_command (new StatefulDiffCommand (pl));
6150 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6151 set_selected_regionview_from_region_list ((*i), Selection::Add);
6157 Editor::place_transient()
6163 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6169 framepos_t where = get_preferred_edit_position();
6171 _session->begin_reversible_command (_("place transient"));
6173 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6174 framepos_t position = (*r)->region()->position();
6175 (*r)->region()->add_transient(where - position);
6178 _session->commit_reversible_command ();
6182 Editor::remove_transient(ArdourCanvas::Item* item)
6188 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6191 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6192 _arv->remove_transient (*(float*) _line->get_data ("position"));
6196 Editor::snap_regions_to_grid ()
6198 list <boost::shared_ptr<Playlist > > used_playlists;
6200 RegionSelection rs = get_regions_from_selection_and_entered ();
6202 if (!_session || rs.empty()) {
6206 _session->begin_reversible_command (_("snap regions to grid"));
6208 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6210 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6212 if (!pl->frozen()) {
6213 /* we haven't seen this playlist before */
6215 /* remember used playlists so we can thaw them later */
6216 used_playlists.push_back(pl);
6220 framepos_t start_frame = (*r)->region()->first_frame ();
6221 snap_to (start_frame);
6222 (*r)->region()->set_position (start_frame);
6225 while (used_playlists.size() > 0) {
6226 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6228 used_playlists.pop_front();
6231 _session->commit_reversible_command ();
6235 Editor::close_region_gaps ()
6237 list <boost::shared_ptr<Playlist > > used_playlists;
6239 RegionSelection rs = get_regions_from_selection_and_entered ();
6241 if (!_session || rs.empty()) {
6245 Dialog dialog (_("Close Region Gaps"));
6248 table.set_spacings (12);
6249 table.set_border_width (12);
6250 Label* l = manage (left_aligned_label (_("Crossfade length")));
6251 table.attach (*l, 0, 1, 0, 1);
6253 SpinButton spin_crossfade (1, 0);
6254 spin_crossfade.set_range (0, 15);
6255 spin_crossfade.set_increments (1, 1);
6256 spin_crossfade.set_value (5);
6257 table.attach (spin_crossfade, 1, 2, 0, 1);
6259 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6261 l = manage (left_aligned_label (_("Pull-back length")));
6262 table.attach (*l, 0, 1, 1, 2);
6264 SpinButton spin_pullback (1, 0);
6265 spin_pullback.set_range (0, 100);
6266 spin_pullback.set_increments (1, 1);
6267 spin_pullback.set_value(30);
6268 table.attach (spin_pullback, 1, 2, 1, 2);
6270 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6272 dialog.get_vbox()->pack_start (table);
6273 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6274 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6277 if (dialog.run () == RESPONSE_CANCEL) {
6281 framepos_t crossfade_len = spin_crossfade.get_value();
6282 framepos_t pull_back_frames = spin_pullback.get_value();
6284 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6285 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6287 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6289 _session->begin_reversible_command (_("close region gaps"));
6292 boost::shared_ptr<Region> last_region;
6294 rs.sort_by_position_and_track();
6296 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6298 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6300 if (!pl->frozen()) {
6301 /* we haven't seen this playlist before */
6303 /* remember used playlists so we can thaw them later */
6304 used_playlists.push_back(pl);
6308 framepos_t position = (*r)->region()->position();
6310 if (idx == 0 || position < last_region->position()){
6311 last_region = (*r)->region();
6316 (*r)->region()->trim_front( (position - pull_back_frames));
6317 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6319 last_region = (*r)->region();
6324 while (used_playlists.size() > 0) {
6325 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6327 used_playlists.pop_front();
6330 _session->commit_reversible_command ();
6334 Editor::tab_to_transient (bool forward)
6336 AnalysisFeatureList positions;
6338 RegionSelection rs = get_regions_from_selection_and_entered ();
6344 framepos_t pos = _session->audible_frame ();
6346 if (!selection->tracks.empty()) {
6348 /* don't waste time searching for transients in duplicate playlists.
6351 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6353 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6355 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6358 boost::shared_ptr<Track> tr = rtv->track();
6360 boost::shared_ptr<Playlist> pl = tr->playlist ();
6362 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6365 positions.push_back (result);
6378 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6379 (*r)->region()->get_transients (positions);
6383 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6386 AnalysisFeatureList::iterator x;
6388 for (x = positions.begin(); x != positions.end(); ++x) {
6394 if (x != positions.end ()) {
6395 _session->request_locate (*x);
6399 AnalysisFeatureList::reverse_iterator x;
6401 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6407 if (x != positions.rend ()) {
6408 _session->request_locate (*x);
6414 Editor::playhead_forward_to_grid ()
6420 framepos_t pos = playhead_cursor->current_frame ();
6421 if (pos < max_framepos - 1) {
6423 snap_to_internal (pos, 1, false);
6424 _session->request_locate (pos);
6430 Editor::playhead_backward_to_grid ()
6436 framepos_t pos = playhead_cursor->current_frame ();
6439 snap_to_internal (pos, -1, false);
6440 _session->request_locate (pos);
6445 Editor::set_track_height (Height h)
6447 TrackSelection& ts (selection->tracks);
6449 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6450 (*x)->set_height_enum (h);
6455 Editor::toggle_tracks_active ()
6457 TrackSelection& ts (selection->tracks);
6459 bool target = false;
6465 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6466 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6470 target = !rtv->_route->active();
6473 rtv->_route->set_active (target, this);
6479 Editor::remove_tracks ()
6481 TrackSelection& ts (selection->tracks);
6487 vector<string> choices;
6491 const char* trackstr;
6493 vector<boost::shared_ptr<Route> > routes;
6494 bool special_bus = false;
6496 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6497 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6501 if (rtv->is_track()) {
6506 routes.push_back (rtv->_route);
6508 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6513 if (special_bus && !Config->get_allow_special_bus_removal()) {
6514 MessageDialog msg (_("That would be bad news ...."),
6518 msg.set_secondary_text (string_compose (_(
6519 "Removing the master or monitor bus is such a bad idea\n\
6520 that %1 is not going to allow it.\n\
6522 If you really want to do this sort of thing\n\
6523 edit your ardour.rc file to set the\n\
6524 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6531 if (ntracks + nbusses == 0) {
6536 trackstr = _("tracks");
6538 trackstr = _("track");
6542 busstr = _("busses");
6549 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6550 "(You may also lose the playlists associated with the %2)\n\n"
6551 "This action cannot be undone, and the session file will be overwritten!"),
6552 ntracks, trackstr, nbusses, busstr);
6554 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6555 "(You may also lose the playlists associated with the %2)\n\n"
6556 "This action cannot be undone, and the session file will be overwritten!"),
6559 } else if (nbusses) {
6560 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6561 "This action cannot be undon, and the session file will be overwritten"),
6565 choices.push_back (_("No, do nothing."));
6566 if (ntracks + nbusses > 1) {
6567 choices.push_back (_("Yes, remove them."));
6569 choices.push_back (_("Yes, remove it."));
6574 title = string_compose (_("Remove %1"), trackstr);
6576 title = string_compose (_("Remove %1"), busstr);
6579 Choice prompter (title, prompt, choices);
6581 if (prompter.run () != 1) {
6586 Session::StateProtector sp (_session);
6587 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6588 _session->remove_route (*x);
6594 Editor::do_insert_time ()
6596 if (selection->tracks.empty()) {
6600 InsertTimeDialog d (*this);
6601 int response = d.run ();
6603 if (response != RESPONSE_OK) {
6607 if (d.distance() == 0) {
6611 InsertTimeOption opt = d.intersected_region_action ();
6614 get_preferred_edit_position(),
6620 d.move_glued_markers(),
6621 d.move_locked_markers(),
6627 Editor::insert_time (
6628 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6629 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6632 bool commit = false;
6634 if (Config->get_edit_mode() == Lock) {
6638 begin_reversible_command (_("insert time"));
6640 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6642 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6646 /* don't operate on any playlist more than once, which could
6647 * happen if "all playlists" is enabled, but there is more
6648 * than 1 track using playlists "from" a given track.
6651 set<boost::shared_ptr<Playlist> > pl;
6653 if (all_playlists) {
6654 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6656 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6657 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6662 if ((*x)->playlist ()) {
6663 pl.insert ((*x)->playlist ());
6667 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6669 (*i)->clear_changes ();
6670 (*i)->clear_owned_changes ();
6672 if (opt == SplitIntersected) {
6676 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6678 vector<Command*> cmds;
6680 _session->add_commands (cmds);
6682 _session->add_command (new StatefulDiffCommand (*i));
6687 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6689 rtav->route ()->shift (pos, frames);
6697 XMLNode& before (_session->locations()->get_state());
6698 Locations::LocationList copy (_session->locations()->list());
6700 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6702 Locations::LocationList::const_iterator tmp;
6704 bool const was_locked = (*i)->locked ();
6705 if (locked_markers_too) {
6709 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6711 if ((*i)->start() >= pos) {
6712 (*i)->set_start ((*i)->start() + frames);
6713 if (!(*i)->is_mark()) {
6714 (*i)->set_end ((*i)->end() + frames);
6727 XMLNode& after (_session->locations()->get_state());
6728 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6733 _session->tempo_map().insert_time (pos, frames);
6737 commit_reversible_command ();
6742 Editor::fit_selected_tracks ()
6744 if (!selection->tracks.empty()) {
6745 fit_tracks (selection->tracks);
6749 /* no selected tracks - use tracks with selected regions */
6751 if (!selection->regions.empty()) {
6752 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6753 tvl.push_back (&(*r)->get_time_axis_view ());
6759 } else if (internal_editing()) {
6760 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6763 if (entered_track) {
6764 tvl.push_back (entered_track);
6772 Editor::fit_tracks (TrackViewList & tracks)
6774 if (tracks.empty()) {
6778 uint32_t child_heights = 0;
6779 int visible_tracks = 0;
6781 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6783 if (!(*t)->marked_for_display()) {
6787 child_heights += (*t)->effective_height() - (*t)->current_height();
6791 /* compute the per-track height from:
6793 total canvas visible height -
6794 height that will be taken by visible children of selected
6795 tracks - height of the ruler/hscroll area
6797 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6798 double first_y_pos = DBL_MAX;
6800 if (h < TimeAxisView::preset_height (HeightSmall)) {
6801 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6802 /* too small to be displayed */
6806 undo_visual_stack.push_back (current_visual_state (true));
6807 no_save_visual = true;
6809 /* build a list of all tracks, including children */
6812 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6814 TimeAxisView::Children c = (*i)->get_child_list ();
6815 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6816 all.push_back (j->get());
6820 bool prev_was_selected = false;
6821 bool is_selected = tracks.contains (all.front());
6822 bool next_is_selected;
6824 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6826 TrackViewList::iterator next;
6831 if (next != all.end()) {
6832 next_is_selected = tracks.contains (*next);
6834 next_is_selected = false;
6837 if ((*t)->marked_for_display ()) {
6839 (*t)->set_height (h);
6840 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6842 if (prev_was_selected && next_is_selected) {
6843 hide_track_in_display (*t);
6848 prev_was_selected = is_selected;
6849 is_selected = next_is_selected;
6853 set the controls_layout height now, because waiting for its size
6854 request signal handler will cause the vertical adjustment setting to fail
6857 controls_layout.property_height () = _full_canvas_height;
6858 vertical_adjustment.set_value (first_y_pos);
6860 redo_visual_stack.push_back (current_visual_state (true));
6864 Editor::save_visual_state (uint32_t n)
6866 while (visual_states.size() <= n) {
6867 visual_states.push_back (0);
6870 if (visual_states[n] != 0) {
6871 delete visual_states[n];
6874 visual_states[n] = current_visual_state (true);
6879 Editor::goto_visual_state (uint32_t n)
6881 if (visual_states.size() <= n) {
6885 if (visual_states[n] == 0) {
6889 use_visual_state (*visual_states[n]);
6893 Editor::start_visual_state_op (uint32_t n)
6895 save_visual_state (n);
6897 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6899 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6900 pup->set_text (buf);
6905 Editor::cancel_visual_state_op (uint32_t n)
6907 goto_visual_state (n);
6911 Editor::toggle_region_mute ()
6913 if (_ignore_region_action) {
6917 RegionSelection rs = get_regions_from_selection_and_entered ();
6923 if (rs.size() > 1) {
6924 begin_reversible_command (_("mute regions"));
6926 begin_reversible_command (_("mute region"));
6929 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6931 (*i)->region()->playlist()->clear_changes ();
6932 (*i)->region()->set_muted (!(*i)->region()->muted ());
6933 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6937 commit_reversible_command ();
6941 Editor::combine_regions ()
6943 /* foreach track with selected regions, take all selected regions
6944 and join them into a new region containing the subregions (as a
6948 typedef set<RouteTimeAxisView*> RTVS;
6951 if (selection->regions.empty()) {
6955 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6956 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6959 tracks.insert (rtv);
6963 begin_reversible_command (_("combine regions"));
6965 vector<RegionView*> new_selection;
6967 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6970 if ((rv = (*i)->combine_regions ()) != 0) {
6971 new_selection.push_back (rv);
6975 selection->clear_regions ();
6976 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6977 selection->add (*i);
6980 commit_reversible_command ();
6984 Editor::uncombine_regions ()
6986 typedef set<RouteTimeAxisView*> RTVS;
6989 if (selection->regions.empty()) {
6993 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6994 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6997 tracks.insert (rtv);
7001 begin_reversible_command (_("uncombine regions"));
7003 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7004 (*i)->uncombine_regions ();
7007 commit_reversible_command ();
7011 Editor::toggle_midi_input_active (bool flip_others)
7014 boost::shared_ptr<RouteList> rl (new RouteList);
7016 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7017 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7023 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7026 rl->push_back (rtav->route());
7027 onoff = !mt->input_active();
7031 _session->set_exclusive_input_active (rl, onoff, flip_others);
7038 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7040 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7041 lock_dialog->get_vbox()->pack_start (*padlock);
7043 ArdourButton* b = manage (new ArdourButton);
7044 b->set_name ("lock button");
7045 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7046 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7047 lock_dialog->get_vbox()->pack_start (*b);
7049 lock_dialog->get_vbox()->show_all ();
7050 lock_dialog->set_size_request (200, 200);
7054 /* The global menu bar continues to be accessible to applications
7055 with modal dialogs, which means that we need to desensitize
7056 all items in the menu bar. Since those items are really just
7057 proxies for actions, that means disabling all actions.
7059 ActionManager::disable_all_actions ();
7061 lock_dialog->present ();
7067 lock_dialog->hide ();
7070 ActionManager::pop_action_state ();
7073 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7074 start_lock_event_timing ();
7079 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7081 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7085 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7087 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7088 Gtkmm2ext::UI::instance()->flush_pending ();
7092 Editor::bring_all_sources_into_session ()
7099 ArdourDialog w (_("Moving embedded files into session folder"));
7100 w.get_vbox()->pack_start (msg);
7103 /* flush all pending GUI events because we're about to start copying
7107 Gtkmm2ext::UI::instance()->flush_pending ();
7111 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));