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;
138 list<boost::shared_ptr<Playlist> > used_playlists;
139 list<RouteTimeAxisView*> used_trackviews;
141 if (regions.empty()) {
145 begin_reversible_command (_("split"));
147 // if splitting a single region, and snap-to is using
148 // region boundaries, don't pay attention to them
150 if (regions.size() == 1) {
151 switch (_snap_type) {
152 case SnapToRegionStart:
153 case SnapToRegionSync:
154 case SnapToRegionEnd:
163 EditorFreeze(); /* Emit Signal */
166 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
168 RegionSelection::iterator tmp;
170 /* XXX this test needs to be more complicated, to make sure we really
171 have something to split.
174 if (!(*a)->region()->covers (where)) {
182 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
190 /* we haven't seen this playlist before */
192 /* remember used playlists so we can thaw them later */
193 used_playlists.push_back(pl);
195 TimeAxisView& tv = (*a)->get_time_axis_view();
196 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
198 used_trackviews.push_back (rtv);
205 pl->clear_changes ();
206 pl->split_region ((*a)->region(), where);
207 _session->add_command (new StatefulDiffCommand (pl));
213 vector<sigc::connection> region_added_connections;
215 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
216 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
219 latest_regionviews.clear ();
221 while (used_playlists.size() > 0) {
222 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
224 used_playlists.pop_front();
227 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
231 commit_reversible_command ();
234 EditorThaw(); /* Emit Signal */
237 //IFF we were working on selected regions, then we should select both sides of the new region after the split.
238 if( !pre_selected_regions.empty() ) {
239 selection->add (latest_regionviews); //these are the new regions, created after the split
240 selection->add (pre_selected_regions); //these were the old selected regions, they got lost in the freeze/thaw
245 /** Move one extreme of the current range selection. If more than one range is selected,
246 * the start of the earliest range or the end of the latest range is moved.
248 * @param move_end true to move the end of the current range selection, false to move
250 * @param next true to move the extreme to the next region boundary, false to move to
254 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
256 if (selection->time.start() == selection->time.end_frame()) {
260 framepos_t start = selection->time.start ();
261 framepos_t end = selection->time.end_frame ();
263 /* the position of the thing we may move */
264 framepos_t pos = move_end ? end : start;
265 int dir = next ? 1 : -1;
267 /* so we don't find the current region again */
268 if (dir > 0 || pos > 0) {
272 framepos_t const target = get_region_boundary (pos, dir, true, false);
287 begin_reversible_command (_("alter selection"));
288 selection->set_preserving_all_ranges (start, end);
289 commit_reversible_command ();
293 Editor::nudge_forward_release (GdkEventButton* ev)
295 if (ev->state & Keyboard::PrimaryModifier) {
296 nudge_forward (false, true);
298 nudge_forward (false, false);
304 Editor::nudge_backward_release (GdkEventButton* ev)
306 if (ev->state & Keyboard::PrimaryModifier) {
307 nudge_backward (false, true);
309 nudge_backward (false, false);
316 Editor::nudge_forward (bool next, bool force_playhead)
319 framepos_t next_distance;
325 RegionSelection rs = get_regions_from_selection_and_entered ();
327 if (!force_playhead && !rs.empty()) {
329 begin_reversible_command (_("nudge regions forward"));
331 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
332 boost::shared_ptr<Region> r ((*i)->region());
334 distance = get_nudge_distance (r->position(), next_distance);
337 distance = next_distance;
341 r->set_position (r->position() + distance);
342 _session->add_command (new StatefulDiffCommand (r));
345 commit_reversible_command ();
348 } else if (!force_playhead && !selection->markers.empty()) {
352 begin_reversible_command (_("nudge location forward"));
354 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
356 Location* loc = find_location_from_marker ((*i), is_start);
360 XMLNode& before (loc->get_state());
363 distance = get_nudge_distance (loc->start(), next_distance);
365 distance = next_distance;
367 if (max_framepos - distance > loc->start() + loc->length()) {
368 loc->set_start (loc->start() + distance);
370 loc->set_start (max_framepos - loc->length());
373 distance = get_nudge_distance (loc->end(), next_distance);
375 distance = next_distance;
377 if (max_framepos - distance > loc->end()) {
378 loc->set_end (loc->end() + distance);
380 loc->set_end (max_framepos);
383 XMLNode& after (loc->get_state());
384 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
388 commit_reversible_command ();
391 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
392 _session->request_locate (playhead_cursor->current_frame () + distance);
397 Editor::nudge_backward (bool next, bool force_playhead)
400 framepos_t next_distance;
406 RegionSelection rs = get_regions_from_selection_and_entered ();
408 if (!force_playhead && !rs.empty()) {
410 begin_reversible_command (_("nudge regions backward"));
412 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
413 boost::shared_ptr<Region> r ((*i)->region());
415 distance = get_nudge_distance (r->position(), next_distance);
418 distance = next_distance;
423 if (r->position() > distance) {
424 r->set_position (r->position() - distance);
428 _session->add_command (new StatefulDiffCommand (r));
431 commit_reversible_command ();
433 } else if (!force_playhead && !selection->markers.empty()) {
437 begin_reversible_command (_("nudge location forward"));
439 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
441 Location* loc = find_location_from_marker ((*i), is_start);
445 XMLNode& before (loc->get_state());
448 distance = get_nudge_distance (loc->start(), next_distance);
450 distance = next_distance;
452 if (distance < loc->start()) {
453 loc->set_start (loc->start() - distance);
458 distance = get_nudge_distance (loc->end(), next_distance);
461 distance = next_distance;
464 if (distance < loc->end() - loc->length()) {
465 loc->set_end (loc->end() - distance);
467 loc->set_end (loc->length());
471 XMLNode& after (loc->get_state());
472 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
476 commit_reversible_command ();
480 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
482 if (playhead_cursor->current_frame () > distance) {
483 _session->request_locate (playhead_cursor->current_frame () - distance);
485 _session->goto_start();
491 Editor::nudge_forward_capture_offset ()
493 RegionSelection rs = get_regions_from_selection_and_entered ();
495 if (!_session || rs.empty()) {
499 begin_reversible_command (_("nudge forward"));
501 framepos_t const distance = _session->worst_output_latency();
503 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
504 boost::shared_ptr<Region> r ((*i)->region());
507 r->set_position (r->position() + distance);
508 _session->add_command(new StatefulDiffCommand (r));
511 commit_reversible_command ();
515 Editor::nudge_backward_capture_offset ()
517 RegionSelection rs = get_regions_from_selection_and_entered ();
519 if (!_session || rs.empty()) {
523 begin_reversible_command (_("nudge backward"));
525 framepos_t const distance = _session->worst_output_latency();
527 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
528 boost::shared_ptr<Region> r ((*i)->region());
532 if (r->position() > distance) {
533 r->set_position (r->position() - distance);
537 _session->add_command(new StatefulDiffCommand (r));
540 commit_reversible_command ();
543 struct RegionSelectionPositionSorter {
544 bool operator() (RegionView* a, RegionView* b) {
545 return a->region()->position() < b->region()->position();
550 Editor::sequence_regions ()
553 framepos_t r_end_prev;
561 RegionSelection rs = get_regions_from_selection_and_entered ();
562 rs.sort(RegionSelectionPositionSorter());
566 begin_reversible_command (_("sequence regions"));
567 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
568 boost::shared_ptr<Region> r ((*i)->region());
576 if(r->position_locked())
583 r->set_position(r_end_prev);
586 _session->add_command (new StatefulDiffCommand (r));
588 r_end=r->position() + r->length();
592 commit_reversible_command ();
600 Editor::move_to_start ()
602 _session->goto_start ();
606 Editor::move_to_end ()
609 _session->request_locate (_session->current_end_frame());
613 Editor::build_region_boundary_cache ()
616 vector<RegionPoint> interesting_points;
617 boost::shared_ptr<Region> r;
618 TrackViewList tracks;
621 region_boundary_cache.clear ();
627 switch (_snap_type) {
628 case SnapToRegionStart:
629 interesting_points.push_back (Start);
631 case SnapToRegionEnd:
632 interesting_points.push_back (End);
634 case SnapToRegionSync:
635 interesting_points.push_back (SyncPoint);
637 case SnapToRegionBoundary:
638 interesting_points.push_back (Start);
639 interesting_points.push_back (End);
642 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
647 TimeAxisView *ontrack = 0;
650 if (!selection->tracks.empty()) {
651 tlist = selection->tracks.filter_to_unique_playlists ();
653 tlist = track_views.filter_to_unique_playlists ();
656 while (pos < _session->current_end_frame() && !at_end) {
659 framepos_t lpos = max_framepos;
661 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
663 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
664 if (*p == interesting_points.back()) {
667 /* move to next point type */
673 rpos = r->first_frame();
677 rpos = r->last_frame();
681 rpos = r->sync_position ();
689 RouteTimeAxisView *rtav;
691 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
692 if (rtav->track() != 0) {
693 speed = rtav->track()->speed();
697 rpos = track_frame_to_session_frame (rpos, speed);
703 /* prevent duplicates, but we don't use set<> because we want to be able
707 vector<framepos_t>::iterator ri;
709 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
715 if (ri == region_boundary_cache.end()) {
716 region_boundary_cache.push_back (rpos);
723 /* finally sort to be sure that the order is correct */
725 sort (region_boundary_cache.begin(), region_boundary_cache.end());
728 boost::shared_ptr<Region>
729 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
731 TrackViewList::iterator i;
732 framepos_t closest = max_framepos;
733 boost::shared_ptr<Region> ret;
737 framepos_t track_frame;
738 RouteTimeAxisView *rtav;
740 for (i = tracks.begin(); i != tracks.end(); ++i) {
743 boost::shared_ptr<Region> r;
746 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
747 if (rtav->track()!=0)
748 track_speed = rtav->track()->speed();
751 track_frame = session_frame_to_track_frame(frame, track_speed);
753 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
759 rpos = r->first_frame ();
763 rpos = r->last_frame ();
767 rpos = r->sync_position ();
771 // rpos is a "track frame", converting it to "_session frame"
772 rpos = track_frame_to_session_frame(rpos, track_speed);
775 distance = rpos - frame;
777 distance = frame - rpos;
780 if (distance < closest) {
792 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
794 framecnt_t distance = max_framepos;
795 framepos_t current_nearest = -1;
797 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
798 framepos_t contender;
801 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
807 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
811 d = ::llabs (pos - contender);
814 current_nearest = contender;
819 return current_nearest;
823 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
828 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
830 if (!selection->tracks.empty()) {
832 target = find_next_region_boundary (pos, dir, selection->tracks);
836 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
837 get_onscreen_tracks (tvl);
838 target = find_next_region_boundary (pos, dir, tvl);
840 target = find_next_region_boundary (pos, dir, track_views);
846 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
847 get_onscreen_tracks (tvl);
848 target = find_next_region_boundary (pos, dir, tvl);
850 target = find_next_region_boundary (pos, dir, track_views);
858 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
860 framepos_t pos = playhead_cursor->current_frame ();
867 // so we don't find the current region again..
868 if (dir > 0 || pos > 0) {
872 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
876 _session->request_locate (target);
880 Editor::cursor_to_next_region_boundary (bool with_selection)
882 cursor_to_region_boundary (with_selection, 1);
886 Editor::cursor_to_previous_region_boundary (bool with_selection)
888 cursor_to_region_boundary (with_selection, -1);
892 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
894 boost::shared_ptr<Region> r;
895 framepos_t pos = cursor->current_frame ();
901 TimeAxisView *ontrack = 0;
903 // so we don't find the current region again..
907 if (!selection->tracks.empty()) {
909 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
911 } else if (clicked_axisview) {
914 t.push_back (clicked_axisview);
916 r = find_next_region (pos, point, dir, t, &ontrack);
920 r = find_next_region (pos, point, dir, track_views, &ontrack);
929 pos = r->first_frame ();
933 pos = r->last_frame ();
937 pos = r->sync_position ();
942 RouteTimeAxisView *rtav;
944 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
945 if (rtav->track() != 0) {
946 speed = rtav->track()->speed();
950 pos = track_frame_to_session_frame(pos, speed);
952 if (cursor == playhead_cursor) {
953 _session->request_locate (pos);
955 cursor->set_position (pos);
960 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
962 cursor_to_region_point (cursor, point, 1);
966 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
968 cursor_to_region_point (cursor, point, -1);
972 Editor::cursor_to_selection_start (EditorCursor *cursor)
976 switch (mouse_mode) {
978 if (!selection->regions.empty()) {
979 pos = selection->regions.start();
984 if (!selection->time.empty()) {
985 pos = selection->time.start ();
993 if (cursor == playhead_cursor) {
994 _session->request_locate (pos);
996 cursor->set_position (pos);
1001 Editor::cursor_to_selection_end (EditorCursor *cursor)
1005 switch (mouse_mode) {
1007 if (!selection->regions.empty()) {
1008 pos = selection->regions.end_frame();
1013 if (!selection->time.empty()) {
1014 pos = selection->time.end_frame ();
1022 if (cursor == playhead_cursor) {
1023 _session->request_locate (pos);
1025 cursor->set_position (pos);
1030 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1040 if (selection->markers.empty()) {
1044 if (!mouse_frame (mouse, ignored)) {
1048 add_location_mark (mouse);
1051 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1055 framepos_t pos = loc->start();
1057 // so we don't find the current region again..
1058 if (dir > 0 || pos > 0) {
1062 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1066 loc->move_to (target);
1070 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1072 selected_marker_to_region_boundary (with_selection, 1);
1076 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1078 selected_marker_to_region_boundary (with_selection, -1);
1082 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1084 boost::shared_ptr<Region> r;
1089 if (!_session || selection->markers.empty()) {
1093 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1097 TimeAxisView *ontrack = 0;
1101 // so we don't find the current region again..
1105 if (!selection->tracks.empty()) {
1107 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1111 r = find_next_region (pos, point, dir, track_views, &ontrack);
1120 pos = r->first_frame ();
1124 pos = r->last_frame ();
1128 pos = r->adjust_to_sync (r->first_frame());
1133 RouteTimeAxisView *rtav;
1135 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1136 if (rtav->track() != 0) {
1137 speed = rtav->track()->speed();
1141 pos = track_frame_to_session_frame(pos, speed);
1147 Editor::selected_marker_to_next_region_point (RegionPoint point)
1149 selected_marker_to_region_point (point, 1);
1153 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1155 selected_marker_to_region_point (point, -1);
1159 Editor::selected_marker_to_selection_start ()
1165 if (!_session || selection->markers.empty()) {
1169 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1173 switch (mouse_mode) {
1175 if (!selection->regions.empty()) {
1176 pos = selection->regions.start();
1181 if (!selection->time.empty()) {
1182 pos = selection->time.start ();
1194 Editor::selected_marker_to_selection_end ()
1200 if (!_session || selection->markers.empty()) {
1204 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1208 switch (mouse_mode) {
1210 if (!selection->regions.empty()) {
1211 pos = selection->regions.end_frame();
1216 if (!selection->time.empty()) {
1217 pos = selection->time.end_frame ();
1229 Editor::scroll_playhead (bool forward)
1231 framepos_t pos = playhead_cursor->current_frame ();
1232 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1235 if (pos == max_framepos) {
1239 if (pos < max_framepos - delta) {
1258 _session->request_locate (pos);
1262 Editor::cursor_align (bool playhead_to_edit)
1268 if (playhead_to_edit) {
1270 if (selection->markers.empty()) {
1274 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1277 /* move selected markers to playhead */
1279 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1282 Location* loc = find_location_from_marker (*i, ignored);
1284 if (loc->is_mark()) {
1285 loc->set_start (playhead_cursor->current_frame ());
1287 loc->set (playhead_cursor->current_frame (),
1288 playhead_cursor->current_frame () + loc->length());
1295 Editor::scroll_backward (float pages)
1297 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1298 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1301 if (leftmost_frame < cnt) {
1304 frame = leftmost_frame - cnt;
1307 reset_x_origin (frame);
1311 Editor::scroll_forward (float pages)
1313 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1314 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1317 if (max_framepos - cnt < leftmost_frame) {
1318 frame = max_framepos - cnt;
1320 frame = leftmost_frame + cnt;
1323 reset_x_origin (frame);
1327 Editor::scroll_tracks_down ()
1329 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1330 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1331 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1334 vertical_adjustment.set_value (vert_value);
1338 Editor::scroll_tracks_up ()
1340 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1344 Editor::scroll_tracks_down_line ()
1346 double vert_value = vertical_adjustment.get_value() + 60;
1348 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1349 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1352 vertical_adjustment.set_value (vert_value);
1356 Editor::scroll_tracks_up_line ()
1358 reset_y_origin (vertical_adjustment.get_value() - 60);
1362 Editor::scroll_down_one_track ()
1364 TrackViewList::reverse_iterator next = track_views.rend();
1365 std::pair<TimeAxisView*,double> res;
1366 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1368 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1369 if ((*t)->hidden()) {
1373 /* If this is the bottom visible trackview, we want to display
1377 res = (*t)->covers_y_position (bottom_of_trackviews);
1383 ++next; // moves "next" towards the "front" since it is a reverse iterator
1386 /* move to the track below the first one that covers the */
1388 if (next != track_views.rend()) {
1389 ensure_time_axis_view_is_visible (**next);
1397 Editor::scroll_up_one_track ()
1399 double vertical_pos = vertical_adjustment.get_value ();
1401 TrackViewList::iterator prev = track_views.end();
1402 std::pair<TimeAxisView*,double> res;
1404 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1406 if ((*t)->hidden()) {
1410 /* find the trackview at the top of the trackview group */
1411 res = (*t)->covers_y_position (vertical_pos);
1414 cerr << res.first->name() << " covers the top\n";
1421 if (prev != track_views.end()) {
1422 ensure_time_axis_view_is_visible (**prev);
1432 Editor::tav_zoom_step (bool coarser)
1434 DisplaySuspender ds;
1438 if (selection->tracks.empty()) {
1441 ts = &selection->tracks;
1444 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1445 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1446 tv->step_height (coarser);
1451 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1453 DisplaySuspender ds;
1457 if (selection->tracks.empty() || force_all) {
1460 ts = &selection->tracks;
1463 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1464 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1465 uint32_t h = tv->current_height ();
1470 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1475 tv->set_height (h + 5);
1482 Editor::temporal_zoom_step (bool coarser)
1484 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1486 framecnt_t nspp = samples_per_pixel;
1494 temporal_zoom (nspp);
1498 Editor::temporal_zoom (framecnt_t fpp)
1504 framepos_t current_page = current_page_samples();
1505 framepos_t current_leftmost = leftmost_frame;
1506 framepos_t current_rightmost;
1507 framepos_t current_center;
1508 framepos_t new_page_size;
1509 framepos_t half_page_size;
1510 framepos_t leftmost_after_zoom = 0;
1512 bool in_track_canvas;
1516 if (fpp == samples_per_pixel) {
1520 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1521 // segfaults for lack of memory. If somebody decides this is not high enough I
1522 // believe it can be raisen to higher values but some limit must be in place.
1524 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1525 // all of which is used for the editor track displays. The whole day
1526 // would be 4147200000 samples, so 2592000 samples per pixel.
1528 nfpp = min (fpp, (framecnt_t) 2592000);
1529 nfpp = max ((framecnt_t) 1, fpp);
1531 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1532 half_page_size = new_page_size / 2;
1534 switch (zoom_focus) {
1536 leftmost_after_zoom = current_leftmost;
1539 case ZoomFocusRight:
1540 current_rightmost = leftmost_frame + current_page;
1541 if (current_rightmost < new_page_size) {
1542 leftmost_after_zoom = 0;
1544 leftmost_after_zoom = current_rightmost - new_page_size;
1548 case ZoomFocusCenter:
1549 current_center = current_leftmost + (current_page/2);
1550 if (current_center < half_page_size) {
1551 leftmost_after_zoom = 0;
1553 leftmost_after_zoom = current_center - half_page_size;
1557 case ZoomFocusPlayhead:
1558 /* centre playhead */
1559 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1562 leftmost_after_zoom = 0;
1563 } else if (l > max_framepos) {
1564 leftmost_after_zoom = max_framepos - new_page_size;
1566 leftmost_after_zoom = (framepos_t) l;
1570 case ZoomFocusMouse:
1571 /* try to keep the mouse over the same point in the display */
1573 if (!mouse_frame (where, in_track_canvas)) {
1574 /* use playhead instead */
1575 where = playhead_cursor->current_frame ();
1577 if (where < half_page_size) {
1578 leftmost_after_zoom = 0;
1580 leftmost_after_zoom = where - half_page_size;
1585 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1588 leftmost_after_zoom = 0;
1589 } else if (l > max_framepos) {
1590 leftmost_after_zoom = max_framepos - new_page_size;
1592 leftmost_after_zoom = (framepos_t) l;
1599 /* try to keep the edit point in the same place */
1600 where = get_preferred_edit_position ();
1604 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1607 leftmost_after_zoom = 0;
1608 } else if (l > max_framepos) {
1609 leftmost_after_zoom = max_framepos - new_page_size;
1611 leftmost_after_zoom = (framepos_t) l;
1615 /* edit point not defined */
1622 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1624 reposition_and_zoom (leftmost_after_zoom, nfpp);
1628 Editor::temporal_zoom_region (bool both_axes)
1630 framepos_t start = max_framepos;
1632 set<TimeAxisView*> tracks;
1634 RegionSelection rs = get_regions_from_selection_and_entered ();
1640 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1642 if ((*i)->region()->position() < start) {
1643 start = (*i)->region()->position();
1646 if ((*i)->region()->last_frame() + 1 > end) {
1647 end = (*i)->region()->last_frame() + 1;
1650 tracks.insert (&((*i)->get_time_axis_view()));
1653 /* now comes an "interesting" hack ... make sure we leave a little space
1654 at each end of the editor so that the zoom doesn't fit the region
1655 precisely to the screen.
1658 GdkScreen* screen = gdk_screen_get_default ();
1659 gint pixwidth = gdk_screen_get_width (screen);
1660 gint mmwidth = gdk_screen_get_width_mm (screen);
1661 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1662 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1664 if ((start == 0 && end == 0) || end < start) {
1668 framepos_t range = end - start;
1669 double new_fpp = (double) range / (double) _visible_canvas_width;
1670 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1672 if (start > extra_samples) {
1673 start -= extra_samples;
1678 if (max_framepos - extra_samples > end) {
1679 end += extra_samples;
1684 /* if we're zooming on both axes we need to save track heights etc.
1687 undo_visual_stack.push_back (current_visual_state (both_axes));
1689 PBD::Unwinder<bool> nsv (no_save_visual, true);
1691 temporal_zoom_by_frame (start, end);
1694 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1696 /* set visible track heights appropriately */
1698 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1699 (*t)->set_height (per_track_height);
1702 /* hide irrelevant tracks */
1704 DisplaySuspender ds;
1706 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1707 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1708 hide_track_in_display (*i);
1712 vertical_adjustment.set_value (0.0);
1715 redo_visual_stack.push_back (current_visual_state (both_axes));
1719 Editor::zoom_to_region (bool both_axes)
1721 temporal_zoom_region (both_axes);
1725 Editor::temporal_zoom_selection ()
1727 if (!selection) return;
1729 if (selection->time.empty()) {
1733 framepos_t start = selection->time[clicked_selection].start;
1734 framepos_t end = selection->time[clicked_selection].end;
1736 temporal_zoom_by_frame (start, end);
1740 Editor::temporal_zoom_session ()
1742 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1745 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1746 double s = _session->current_start_frame() - l * 0.01;
1750 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1751 temporal_zoom_by_frame (framecnt_t (s), e);
1756 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1758 if (!_session) return;
1760 if ((start == 0 && end == 0) || end < start) {
1764 framepos_t range = end - start;
1766 double const new_fpp = (double) range / (double) _visible_canvas_width;
1768 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1769 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1770 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1772 if (new_leftmost > middle) {
1776 if (new_leftmost < 0) {
1780 reposition_and_zoom (new_leftmost, new_fpp);
1784 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1790 framecnt_t range_before = frame - leftmost_frame;
1794 if (samples_per_pixel <= 1) {
1797 new_spp = samples_per_pixel + (samples_per_pixel/2);
1799 range_before += range_before/2;
1801 if (samples_per_pixel >= 1) {
1802 new_spp = samples_per_pixel - (samples_per_pixel/2);
1804 /* could bail out here since we cannot zoom any finer,
1805 but leave that to the equality test below
1807 new_spp = samples_per_pixel;
1810 range_before -= range_before/2;
1813 if (new_spp == samples_per_pixel) {
1817 /* zoom focus is automatically taken as @param frame when this
1821 framepos_t new_leftmost = frame - (framepos_t)range_before;
1823 if (new_leftmost > frame) {
1827 if (new_leftmost < 0) {
1831 reposition_and_zoom (new_leftmost, new_spp);
1836 Editor::choose_new_marker_name(string &name) {
1838 if (!Config->get_name_new_markers()) {
1839 /* don't prompt user for a new name */
1843 ArdourPrompter dialog (true);
1845 dialog.set_prompt (_("New Name:"));
1847 dialog.set_title (_("New Location Marker"));
1849 dialog.set_name ("MarkNameWindow");
1850 dialog.set_size_request (250, -1);
1851 dialog.set_position (Gtk::WIN_POS_MOUSE);
1853 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1854 dialog.set_initial_text (name);
1858 switch (dialog.run ()) {
1859 case RESPONSE_ACCEPT:
1865 dialog.get_result(name);
1872 Editor::add_location_from_selection ()
1876 if (selection->time.empty()) {
1880 if (_session == 0 || clicked_axisview == 0) {
1884 framepos_t start = selection->time[clicked_selection].start;
1885 framepos_t end = selection->time[clicked_selection].end;
1887 _session->locations()->next_available_name(rangename,"selection");
1888 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1890 _session->begin_reversible_command (_("add marker"));
1891 XMLNode &before = _session->locations()->get_state();
1892 _session->locations()->add (location, true);
1893 XMLNode &after = _session->locations()->get_state();
1894 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1895 _session->commit_reversible_command ();
1899 Editor::add_location_mark (framepos_t where)
1903 select_new_marker = true;
1905 _session->locations()->next_available_name(markername,"mark");
1906 if (!choose_new_marker_name(markername)) {
1909 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1910 _session->begin_reversible_command (_("add marker"));
1911 XMLNode &before = _session->locations()->get_state();
1912 _session->locations()->add (location, true);
1913 XMLNode &after = _session->locations()->get_state();
1914 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1915 _session->commit_reversible_command ();
1919 Editor::add_location_from_playhead_cursor ()
1921 add_location_mark (_session->audible_frame());
1925 Editor::remove_location_at_playhead_cursor ()
1930 _session->begin_reversible_command (_("remove marker"));
1931 XMLNode &before = _session->locations()->get_state();
1932 bool removed = false;
1934 //find location(s) at this time
1935 Locations::LocationList locs;
1936 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1937 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1938 if ((*i)->is_mark()) {
1939 _session->locations()->remove (*i);
1946 XMLNode &after = _session->locations()->get_state();
1947 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1948 _session->commit_reversible_command ();
1953 /** Add a range marker around each selected region */
1955 Editor::add_locations_from_region ()
1957 RegionSelection rs = get_regions_from_selection_and_entered ();
1963 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1964 XMLNode &before = _session->locations()->get_state();
1966 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1968 boost::shared_ptr<Region> region = (*i)->region ();
1970 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1972 _session->locations()->add (location, true);
1975 XMLNode &after = _session->locations()->get_state();
1976 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1977 _session->commit_reversible_command ();
1980 /** Add a single range marker around all selected regions */
1982 Editor::add_location_from_region ()
1984 RegionSelection rs = get_regions_from_selection_and_entered ();
1990 _session->begin_reversible_command (_("add marker"));
1991 XMLNode &before = _session->locations()->get_state();
1995 if (rs.size() > 1) {
1996 _session->locations()->next_available_name(markername, "regions");
1998 RegionView* rv = *(rs.begin());
1999 boost::shared_ptr<Region> region = rv->region();
2000 markername = region->name();
2003 if (!choose_new_marker_name(markername)) {
2007 // single range spanning all selected
2008 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2009 _session->locations()->add (location, true);
2011 XMLNode &after = _session->locations()->get_state();
2012 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2013 _session->commit_reversible_command ();
2019 Editor::jump_forward_to_mark ()
2025 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2031 _session->request_locate (pos, _session->transport_rolling());
2035 Editor::jump_backward_to_mark ()
2041 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2047 _session->request_locate (pos, _session->transport_rolling());
2053 framepos_t const pos = _session->audible_frame ();
2056 _session->locations()->next_available_name (markername, "mark");
2058 if (!choose_new_marker_name (markername)) {
2062 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2066 Editor::clear_markers ()
2069 _session->begin_reversible_command (_("clear markers"));
2070 XMLNode &before = _session->locations()->get_state();
2071 _session->locations()->clear_markers ();
2072 XMLNode &after = _session->locations()->get_state();
2073 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2074 _session->commit_reversible_command ();
2079 Editor::clear_ranges ()
2082 _session->begin_reversible_command (_("clear ranges"));
2083 XMLNode &before = _session->locations()->get_state();
2085 Location * looploc = _session->locations()->auto_loop_location();
2086 Location * punchloc = _session->locations()->auto_punch_location();
2087 Location * sessionloc = _session->locations()->session_range_location();
2089 _session->locations()->clear_ranges ();
2091 if (looploc) _session->locations()->add (looploc);
2092 if (punchloc) _session->locations()->add (punchloc);
2093 if (sessionloc) _session->locations()->add (sessionloc);
2095 XMLNode &after = _session->locations()->get_state();
2096 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2097 _session->commit_reversible_command ();
2102 Editor::clear_locations ()
2104 _session->begin_reversible_command (_("clear locations"));
2105 XMLNode &before = _session->locations()->get_state();
2106 _session->locations()->clear ();
2107 XMLNode &after = _session->locations()->get_state();
2108 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2109 _session->commit_reversible_command ();
2110 _session->locations()->clear ();
2114 Editor::unhide_markers ()
2116 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2117 Location *l = (*i).first;
2118 if (l->is_hidden() && l->is_mark()) {
2119 l->set_hidden(false, this);
2125 Editor::unhide_ranges ()
2127 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2128 Location *l = (*i).first;
2129 if (l->is_hidden() && l->is_range_marker()) {
2130 l->set_hidden(false, this);
2135 /* INSERT/REPLACE */
2138 Editor::insert_region_list_selection (float times)
2140 RouteTimeAxisView *tv = 0;
2141 boost::shared_ptr<Playlist> playlist;
2143 if (clicked_routeview != 0) {
2144 tv = clicked_routeview;
2145 } else if (!selection->tracks.empty()) {
2146 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2149 } else if (entered_track != 0) {
2150 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2157 if ((playlist = tv->playlist()) == 0) {
2161 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2166 begin_reversible_command (_("insert region"));
2167 playlist->clear_changes ();
2168 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2169 if (Config->get_edit_mode() == Ripple)
2170 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2172 _session->add_command(new StatefulDiffCommand (playlist));
2173 commit_reversible_command ();
2176 /* BUILT-IN EFFECTS */
2179 Editor::reverse_selection ()
2184 /* GAIN ENVELOPE EDITING */
2187 Editor::edit_envelope ()
2194 Editor::transition_to_rolling (bool fwd)
2200 if (_session->config.get_external_sync()) {
2201 switch (Config->get_sync_source()) {
2205 /* transport controlled by the master */
2210 if (_session->is_auditioning()) {
2211 _session->cancel_audition ();
2215 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2219 Editor::play_from_start ()
2221 _session->request_locate (_session->current_start_frame(), true);
2225 Editor::play_from_edit_point ()
2227 _session->request_locate (get_preferred_edit_position(), true);
2231 Editor::play_from_edit_point_and_return ()
2233 framepos_t start_frame;
2234 framepos_t return_frame;
2236 start_frame = get_preferred_edit_position (true);
2238 if (_session->transport_rolling()) {
2239 _session->request_locate (start_frame, false);
2243 /* don't reset the return frame if its already set */
2245 if ((return_frame = _session->requested_return_frame()) < 0) {
2246 return_frame = _session->audible_frame();
2249 if (start_frame >= 0) {
2250 _session->request_roll_at_and_return (start_frame, return_frame);
2255 Editor::play_selection ()
2257 if (selection->time.empty()) {
2261 _session->request_play_range (&selection->time, true);
2265 Editor::get_preroll ()
2267 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2272 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2274 if ( _session->transport_rolling() || !Config->get_follow_edits() )
2277 location -= get_preroll();
2279 //don't try to locate before the beginning of time
2283 //if follow_playhead is on, keep the playhead on the screen
2284 if ( _follow_playhead )
2285 if ( location < leftmost_frame )
2286 location = leftmost_frame;
2288 _session->request_locate( location );
2292 Editor::play_with_preroll ()
2294 if (selection->time.empty()) {
2297 framepos_t preroll = get_preroll();
2299 framepos_t start = 0;
2300 if (selection->time[clicked_selection].start > preroll)
2301 start = selection->time[clicked_selection].start - preroll;
2303 framepos_t end = selection->time[clicked_selection].end + preroll;
2305 AudioRange ar (start, end, 0);
2306 list<AudioRange> lar;
2309 _session->request_play_range (&lar, true);
2314 Editor::play_location (Location& location)
2316 if (location.start() <= location.end()) {
2320 _session->request_bounded_roll (location.start(), location.end());
2324 Editor::loop_location (Location& location)
2326 if (location.start() <= location.end()) {
2332 if ((tll = transport_loop_location()) != 0) {
2333 tll->set (location.start(), location.end());
2335 // enable looping, reposition and start rolling
2336 _session->request_play_loop (true);
2337 _session->request_locate (tll->start(), true);
2342 Editor::do_layer_operation (LayerOperation op)
2344 if (selection->regions.empty ()) {
2348 bool const multiple = selection->regions.size() > 1;
2352 begin_reversible_command (_("raise regions"));
2354 begin_reversible_command (_("raise region"));
2360 begin_reversible_command (_("raise regions to top"));
2362 begin_reversible_command (_("raise region to top"));
2368 begin_reversible_command (_("lower regions"));
2370 begin_reversible_command (_("lower region"));
2376 begin_reversible_command (_("lower regions to bottom"));
2378 begin_reversible_command (_("lower region"));
2383 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2384 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2385 (*i)->clear_owned_changes ();
2388 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2389 boost::shared_ptr<Region> r = (*i)->region ();
2401 r->lower_to_bottom ();
2405 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2406 vector<Command*> cmds;
2408 _session->add_commands (cmds);
2411 commit_reversible_command ();
2415 Editor::raise_region ()
2417 do_layer_operation (Raise);
2421 Editor::raise_region_to_top ()
2423 do_layer_operation (RaiseToTop);
2427 Editor::lower_region ()
2429 do_layer_operation (Lower);
2433 Editor::lower_region_to_bottom ()
2435 do_layer_operation (LowerToBottom);
2438 /** Show the region editor for the selected regions */
2440 Editor::show_region_properties ()
2442 selection->foreach_regionview (&RegionView::show_region_editor);
2445 /** Show the midi list editor for the selected MIDI regions */
2447 Editor::show_midi_list_editor ()
2449 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2453 Editor::rename_region ()
2455 RegionSelection rs = get_regions_from_selection_and_entered ();
2461 ArdourDialog d (*this, _("Rename Region"), true, false);
2463 Label label (_("New name:"));
2466 hbox.set_spacing (6);
2467 hbox.pack_start (label, false, false);
2468 hbox.pack_start (entry, true, true);
2470 d.get_vbox()->set_border_width (12);
2471 d.get_vbox()->pack_start (hbox, false, false);
2473 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2474 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2476 d.set_size_request (300, -1);
2478 entry.set_text (rs.front()->region()->name());
2479 entry.select_region (0, -1);
2481 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2487 int const ret = d.run();
2491 if (ret != RESPONSE_OK) {
2495 std::string str = entry.get_text();
2496 strip_whitespace_edges (str);
2498 rs.front()->region()->set_name (str);
2499 _regions->redisplay ();
2504 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2506 if (_session->is_auditioning()) {
2507 _session->cancel_audition ();
2510 // note: some potential for creativity here, because region doesn't
2511 // have to belong to the playlist that Route is handling
2513 // bool was_soloed = route.soloed();
2515 route.set_solo (true, this);
2517 _session->request_bounded_roll (region->position(), region->position() + region->length());
2519 /* XXX how to unset the solo state ? */
2522 /** Start an audition of the first selected region */
2524 Editor::play_edit_range ()
2526 framepos_t start, end;
2528 if (get_edit_op_range (start, end)) {
2529 _session->request_bounded_roll (start, end);
2534 Editor::play_selected_region ()
2536 framepos_t start = max_framepos;
2539 RegionSelection rs = get_regions_from_selection_and_entered ();
2545 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2546 if ((*i)->region()->position() < start) {
2547 start = (*i)->region()->position();
2549 if ((*i)->region()->last_frame() + 1 > end) {
2550 end = (*i)->region()->last_frame() + 1;
2554 _session->request_bounded_roll (start, end);
2558 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2560 _session->audition_region (region);
2564 Editor::region_from_selection ()
2566 if (clicked_axisview == 0) {
2570 if (selection->time.empty()) {
2574 framepos_t start = selection->time[clicked_selection].start;
2575 framepos_t end = selection->time[clicked_selection].end;
2577 TrackViewList tracks = get_tracks_for_range_action ();
2579 framepos_t selection_cnt = end - start + 1;
2581 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2582 boost::shared_ptr<Region> current;
2583 boost::shared_ptr<Playlist> pl;
2584 framepos_t internal_start;
2587 if ((pl = (*i)->playlist()) == 0) {
2591 if ((current = pl->top_region_at (start)) == 0) {
2595 internal_start = start - current->position();
2596 RegionFactory::region_name (new_name, current->name(), true);
2600 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2601 plist.add (ARDOUR::Properties::length, selection_cnt);
2602 plist.add (ARDOUR::Properties::name, new_name);
2603 plist.add (ARDOUR::Properties::layer, 0);
2605 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2610 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2612 if (selection->time.empty() || selection->tracks.empty()) {
2616 framepos_t start = selection->time[clicked_selection].start;
2617 framepos_t end = selection->time[clicked_selection].end;
2619 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2620 sort_track_selection (ts);
2622 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2623 boost::shared_ptr<Region> current;
2624 boost::shared_ptr<Playlist> playlist;
2625 framepos_t internal_start;
2628 if ((playlist = (*i)->playlist()) == 0) {
2632 if ((current = playlist->top_region_at(start)) == 0) {
2636 internal_start = start - current->position();
2637 RegionFactory::region_name (new_name, current->name(), true);
2641 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2642 plist.add (ARDOUR::Properties::length, end - start + 1);
2643 plist.add (ARDOUR::Properties::name, new_name);
2645 new_regions.push_back (RegionFactory::create (current, plist));
2650 Editor::split_multichannel_region ()
2652 RegionSelection rs = get_regions_from_selection_and_entered ();
2658 vector< boost::shared_ptr<Region> > v;
2660 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2661 (*x)->region()->separate_by_channel (*_session, v);
2666 Editor::new_region_from_selection ()
2668 region_from_selection ();
2669 cancel_selection ();
2673 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2675 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2676 case Evoral::OverlapNone:
2684 * - selected tracks, or if there are none...
2685 * - tracks containing selected regions, or if there are none...
2690 Editor::get_tracks_for_range_action () const
2694 if (selection->tracks.empty()) {
2696 /* use tracks with selected regions */
2698 RegionSelection rs = selection->regions;
2700 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2701 TimeAxisView* tv = &(*i)->get_time_axis_view();
2703 if (!t.contains (tv)) {
2709 /* no regions and no tracks: use all tracks */
2715 t = selection->tracks;
2718 return t.filter_to_unique_playlists();
2722 Editor::separate_regions_between (const TimeSelection& ts)
2724 bool in_command = false;
2725 boost::shared_ptr<Playlist> playlist;
2726 RegionSelection new_selection;
2728 TrackViewList tmptracks = get_tracks_for_range_action ();
2729 sort_track_selection (tmptracks);
2731 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2733 RouteTimeAxisView* rtv;
2735 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2737 if (rtv->is_track()) {
2739 /* no edits to destructive tracks */
2741 if (rtv->track()->destructive()) {
2745 if ((playlist = rtv->playlist()) != 0) {
2747 playlist->clear_changes ();
2749 /* XXX need to consider musical time selections here at some point */
2751 double speed = rtv->track()->speed();
2754 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2756 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2757 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2759 latest_regionviews.clear ();
2761 playlist->partition ((framepos_t)((*t).start * speed),
2762 (framepos_t)((*t).end * speed), false);
2766 if (!latest_regionviews.empty()) {
2768 rtv->view()->foreach_regionview (sigc::bind (
2769 sigc::ptr_fun (add_if_covered),
2770 &(*t), &new_selection));
2773 begin_reversible_command (_("separate"));
2777 /* pick up changes to existing regions */
2779 vector<Command*> cmds;
2780 playlist->rdiff (cmds);
2781 _session->add_commands (cmds);
2783 /* pick up changes to the playlist itself (adds/removes)
2786 _session->add_command(new StatefulDiffCommand (playlist));
2795 // selection->set (new_selection);
2797 commit_reversible_command ();
2801 struct PlaylistState {
2802 boost::shared_ptr<Playlist> playlist;
2806 /** Take tracks from get_tracks_for_range_action and cut any regions
2807 * on those tracks so that the tracks are empty over the time
2811 Editor::separate_region_from_selection ()
2813 /* preferentially use *all* ranges in the time selection if we're in range mode
2814 to allow discontiguous operation, since get_edit_op_range() currently
2815 returns a single range.
2818 if (!selection->time.empty()) {
2820 separate_regions_between (selection->time);
2827 if (get_edit_op_range (start, end)) {
2829 AudioRange ar (start, end, 1);
2833 separate_regions_between (ts);
2839 Editor::separate_region_from_punch ()
2841 Location* loc = _session->locations()->auto_punch_location();
2843 separate_regions_using_location (*loc);
2848 Editor::separate_region_from_loop ()
2850 Location* loc = _session->locations()->auto_loop_location();
2852 separate_regions_using_location (*loc);
2857 Editor::separate_regions_using_location (Location& loc)
2859 if (loc.is_mark()) {
2863 AudioRange ar (loc.start(), loc.end(), 1);
2868 separate_regions_between (ts);
2871 /** Separate regions under the selected region */
2873 Editor::separate_under_selected_regions ()
2875 vector<PlaylistState> playlists;
2879 rs = get_regions_from_selection_and_entered();
2881 if (!_session || rs.empty()) {
2885 begin_reversible_command (_("separate region under"));
2887 list<boost::shared_ptr<Region> > regions_to_remove;
2889 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2890 // we can't just remove the region(s) in this loop because
2891 // this removes them from the RegionSelection, and they thus
2892 // disappear from underneath the iterator, and the ++i above
2893 // SEGVs in a puzzling fashion.
2895 // so, first iterate over the regions to be removed from rs and
2896 // add them to the regions_to_remove list, and then
2897 // iterate over the list to actually remove them.
2899 regions_to_remove.push_back ((*i)->region());
2902 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2904 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2907 // is this check necessary?
2911 vector<PlaylistState>::iterator i;
2913 //only take state if this is a new playlist.
2914 for (i = playlists.begin(); i != playlists.end(); ++i) {
2915 if ((*i).playlist == playlist) {
2920 if (i == playlists.end()) {
2922 PlaylistState before;
2923 before.playlist = playlist;
2924 before.before = &playlist->get_state();
2926 playlist->freeze ();
2927 playlists.push_back(before);
2930 //Partition on the region bounds
2931 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2933 //Re-add region that was just removed due to the partition operation
2934 playlist->add_region( (*rl), (*rl)->first_frame() );
2937 vector<PlaylistState>::iterator pl;
2939 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2940 (*pl).playlist->thaw ();
2941 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2944 commit_reversible_command ();
2948 Editor::crop_region_to_selection ()
2950 if (!selection->time.empty()) {
2952 crop_region_to (selection->time.start(), selection->time.end_frame());
2959 if (get_edit_op_range (start, end)) {
2960 crop_region_to (start, end);
2967 Editor::crop_region_to (framepos_t start, framepos_t end)
2969 vector<boost::shared_ptr<Playlist> > playlists;
2970 boost::shared_ptr<Playlist> playlist;
2973 if (selection->tracks.empty()) {
2974 ts = track_views.filter_to_unique_playlists();
2976 ts = selection->tracks.filter_to_unique_playlists ();
2979 sort_track_selection (ts);
2981 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2983 RouteTimeAxisView* rtv;
2985 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2987 boost::shared_ptr<Track> t = rtv->track();
2989 if (t != 0 && ! t->destructive()) {
2991 if ((playlist = rtv->playlist()) != 0) {
2992 playlists.push_back (playlist);
2998 if (playlists.empty()) {
3002 framepos_t the_start;
3006 begin_reversible_command (_("trim to selection"));
3008 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3010 boost::shared_ptr<Region> region;
3014 if ((region = (*i)->top_region_at(the_start)) == 0) {
3018 /* now adjust lengths to that we do the right thing
3019 if the selection extends beyond the region
3022 the_start = max (the_start, (framepos_t) region->position());
3023 if (max_framepos - the_start < region->length()) {
3024 the_end = the_start + region->length() - 1;
3026 the_end = max_framepos;
3028 the_end = min (end, the_end);
3029 cnt = the_end - the_start + 1;
3031 region->clear_changes ();
3032 region->trim_to (the_start, cnt);
3033 _session->add_command (new StatefulDiffCommand (region));
3036 commit_reversible_command ();
3040 Editor::region_fill_track ()
3042 RegionSelection rs = get_regions_from_selection_and_entered ();
3044 if (!_session || rs.empty()) {
3048 framepos_t const end = _session->current_end_frame ();
3050 begin_reversible_command (Operations::region_fill);
3052 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3054 boost::shared_ptr<Region> region ((*i)->region());
3056 boost::shared_ptr<Playlist> pl = region->playlist();
3058 if (end <= region->last_frame()) {
3062 double times = (double) (end - region->last_frame()) / (double) region->length();
3068 pl->clear_changes ();
3069 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3070 _session->add_command (new StatefulDiffCommand (pl));
3073 commit_reversible_command ();
3077 Editor::region_fill_selection ()
3079 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3083 if (selection->time.empty()) {
3087 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3092 framepos_t start = selection->time[clicked_selection].start;
3093 framepos_t end = selection->time[clicked_selection].end;
3095 boost::shared_ptr<Playlist> playlist;
3097 if (selection->tracks.empty()) {
3101 framepos_t selection_length = end - start;
3102 float times = (float)selection_length / region->length();
3104 begin_reversible_command (Operations::fill_selection);
3106 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3108 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3110 if ((playlist = (*i)->playlist()) == 0) {
3114 playlist->clear_changes ();
3115 playlist->add_region (RegionFactory::create (region, true), start, times);
3116 _session->add_command (new StatefulDiffCommand (playlist));
3119 commit_reversible_command ();
3123 Editor::set_region_sync_position ()
3125 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3129 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3131 bool in_command = false;
3133 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3135 if (!(*r)->region()->covers (where)) {
3139 boost::shared_ptr<Region> region ((*r)->region());
3142 begin_reversible_command (_("set sync point"));
3146 region->clear_changes ();
3147 region->set_sync_position (where);
3148 _session->add_command(new StatefulDiffCommand (region));
3152 commit_reversible_command ();
3156 /** Remove the sync positions of the selection */
3158 Editor::remove_region_sync ()
3160 RegionSelection rs = get_regions_from_selection_and_entered ();
3166 begin_reversible_command (_("remove region sync"));
3168 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3170 (*i)->region()->clear_changes ();
3171 (*i)->region()->clear_sync_position ();
3172 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3175 commit_reversible_command ();
3179 Editor::naturalize_region ()
3181 RegionSelection rs = get_regions_from_selection_and_entered ();
3187 if (rs.size() > 1) {
3188 begin_reversible_command (_("move regions to original position"));
3190 begin_reversible_command (_("move region to original position"));
3193 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3194 (*i)->region()->clear_changes ();
3195 (*i)->region()->move_to_natural_position ();
3196 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3199 commit_reversible_command ();
3203 Editor::align_regions (RegionPoint what)
3205 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3211 begin_reversible_command (_("align selection"));
3213 framepos_t const position = get_preferred_edit_position ();
3215 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3216 align_region_internal ((*i)->region(), what, position);
3219 commit_reversible_command ();
3222 struct RegionSortByTime {
3223 bool operator() (const RegionView* a, const RegionView* b) {
3224 return a->region()->position() < b->region()->position();
3229 Editor::align_regions_relative (RegionPoint point)
3231 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3237 framepos_t const position = get_preferred_edit_position ();
3239 framepos_t distance = 0;
3243 list<RegionView*> sorted;
3244 rs.by_position (sorted);
3246 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3251 if (position > r->position()) {
3252 distance = position - r->position();
3254 distance = r->position() - position;
3260 if (position > r->last_frame()) {
3261 distance = position - r->last_frame();
3262 pos = r->position() + distance;
3264 distance = r->last_frame() - position;
3265 pos = r->position() - distance;
3271 pos = r->adjust_to_sync (position);
3272 if (pos > r->position()) {
3273 distance = pos - r->position();
3275 distance = r->position() - pos;
3281 if (pos == r->position()) {
3285 begin_reversible_command (_("align selection (relative)"));
3287 /* move first one specially */
3289 r->clear_changes ();
3290 r->set_position (pos);
3291 _session->add_command(new StatefulDiffCommand (r));
3293 /* move rest by the same amount */
3297 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3299 boost::shared_ptr<Region> region ((*i)->region());
3301 region->clear_changes ();
3304 region->set_position (region->position() + distance);
3306 region->set_position (region->position() - distance);
3309 _session->add_command(new StatefulDiffCommand (region));
3313 commit_reversible_command ();
3317 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3319 begin_reversible_command (_("align region"));
3320 align_region_internal (region, point, position);
3321 commit_reversible_command ();
3325 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3327 region->clear_changes ();
3331 region->set_position (region->adjust_to_sync (position));
3335 if (position > region->length()) {
3336 region->set_position (position - region->length());
3341 region->set_position (position);
3345 _session->add_command(new StatefulDiffCommand (region));
3349 Editor::trim_region_front ()
3355 Editor::trim_region_back ()
3357 trim_region (false);
3361 Editor::trim_region (bool front)
3363 framepos_t where = get_preferred_edit_position();
3364 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3370 begin_reversible_command (front ? _("trim front") : _("trim back"));
3372 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3373 if (!(*i)->region()->locked()) {
3375 (*i)->region()->clear_changes ();
3378 (*i)->region()->trim_front (where);
3379 maybe_locate_with_edit_preroll ( where );
3381 (*i)->region()->trim_end (where);
3382 maybe_locate_with_edit_preroll ( where );
3385 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3389 commit_reversible_command ();
3392 /** Trim the end of the selected regions to the position of the edit cursor */
3394 Editor::trim_region_to_loop ()
3396 Location* loc = _session->locations()->auto_loop_location();
3400 trim_region_to_location (*loc, _("trim to loop"));
3404 Editor::trim_region_to_punch ()
3406 Location* loc = _session->locations()->auto_punch_location();
3410 trim_region_to_location (*loc, _("trim to punch"));
3414 Editor::trim_region_to_location (const Location& loc, const char* str)
3416 RegionSelection rs = get_regions_from_selection_and_entered ();
3418 begin_reversible_command (str);
3420 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3421 RegionView* rv = (*x);
3423 /* require region to span proposed trim */
3424 switch (rv->region()->coverage (loc.start(), loc.end())) {
3425 case Evoral::OverlapInternal:
3431 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3440 if (tav->track() != 0) {
3441 speed = tav->track()->speed();
3444 start = session_frame_to_track_frame (loc.start(), speed);
3445 end = session_frame_to_track_frame (loc.end(), speed);
3447 rv->region()->clear_changes ();
3448 rv->region()->trim_to (start, (end - start));
3449 _session->add_command(new StatefulDiffCommand (rv->region()));
3452 commit_reversible_command ();
3456 Editor::trim_region_to_previous_region_end ()
3458 return trim_to_region(false);
3462 Editor::trim_region_to_next_region_start ()
3464 return trim_to_region(true);
3468 Editor::trim_to_region(bool forward)
3470 RegionSelection rs = get_regions_from_selection_and_entered ();
3472 begin_reversible_command (_("trim to region"));
3474 boost::shared_ptr<Region> next_region;
3476 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3478 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3484 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3492 if (atav->track() != 0) {
3493 speed = atav->track()->speed();
3497 boost::shared_ptr<Region> region = arv->region();
3498 boost::shared_ptr<Playlist> playlist (region->playlist());
3500 region->clear_changes ();
3504 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3510 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3511 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3515 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3521 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3523 arv->region_changed (ARDOUR::bounds_change);
3526 _session->add_command(new StatefulDiffCommand (region));
3529 commit_reversible_command ();
3533 Editor::unfreeze_route ()
3535 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3539 clicked_routeview->track()->unfreeze ();
3543 Editor::_freeze_thread (void* arg)
3545 return static_cast<Editor*>(arg)->freeze_thread ();
3549 Editor::freeze_thread ()
3551 /* create event pool because we may need to talk to the session */
3552 SessionEvent::create_per_thread_pool ("freeze events", 64);
3553 /* create per-thread buffers for process() tree to use */
3554 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3555 current_interthread_info->done = true;
3560 Editor::freeze_route ()
3566 /* stop transport before we start. this is important */
3568 _session->request_transport_speed (0.0);
3570 /* wait for just a little while, because the above call is asynchronous */
3572 Glib::usleep (250000);
3574 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3578 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3580 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3581 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3583 d.set_title (_("Cannot freeze"));
3588 if (clicked_routeview->track()->has_external_redirects()) {
3589 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"
3590 "Freezing will only process the signal as far as the first send/insert/return."),
3591 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3593 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3594 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3595 d.set_title (_("Freeze Limits"));
3597 int response = d.run ();
3600 case Gtk::RESPONSE_CANCEL:
3607 InterThreadInfo itt;
3608 current_interthread_info = &itt;
3610 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3612 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3614 set_canvas_cursor (_cursors->wait);
3616 while (!itt.done && !itt.cancel) {
3617 gtk_main_iteration ();
3620 current_interthread_info = 0;
3621 set_canvas_cursor (current_canvas_cursor);
3625 Editor::bounce_range_selection (bool replace, bool enable_processing)
3627 if (selection->time.empty()) {
3631 TrackSelection views = selection->tracks;
3633 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3635 if (enable_processing) {
3637 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3639 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3641 _("You can't perform this operation because the processing of the signal "
3642 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3643 "You can do this without processing, which is a different operation.")
3645 d.set_title (_("Cannot bounce"));
3652 framepos_t start = selection->time[clicked_selection].start;
3653 framepos_t end = selection->time[clicked_selection].end;
3654 framepos_t cnt = end - start + 1;
3656 begin_reversible_command (_("bounce range"));
3658 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3660 RouteTimeAxisView* rtv;
3662 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3666 boost::shared_ptr<Playlist> playlist;
3668 if ((playlist = rtv->playlist()) == 0) {
3672 InterThreadInfo itt;
3674 playlist->clear_changes ();
3675 playlist->clear_owned_changes ();
3677 boost::shared_ptr<Region> r;
3679 if (enable_processing) {
3680 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3682 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3690 list<AudioRange> ranges;
3691 ranges.push_back (AudioRange (start, start+cnt, 0));
3692 playlist->cut (ranges); // discard result
3693 playlist->add_region (r, start);
3696 vector<Command*> cmds;
3697 playlist->rdiff (cmds);
3698 _session->add_commands (cmds);
3700 _session->add_command (new StatefulDiffCommand (playlist));
3703 commit_reversible_command ();
3706 /** Delete selected regions, automation points or a time range */
3713 /** Cut selected regions, automation points or a time range */
3720 /** Copy selected regions, automation points or a time range */
3728 /** @return true if a Cut, Copy or Clear is possible */
3730 Editor::can_cut_copy () const
3732 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3739 /** Cut, copy or clear selected regions, automation points or a time range.
3740 * @param op Operation (Delete, Cut, Copy or Clear)
3743 Editor::cut_copy (CutCopyOp op)
3745 /* only cancel selection if cut/copy is successful.*/
3751 opname = _("delete");
3760 opname = _("clear");
3764 /* if we're deleting something, and the mouse is still pressed,
3765 the thing we started a drag for will be gone when we release
3766 the mouse button(s). avoid this. see part 2 at the end of
3770 if (op == Delete || op == Cut || op == Clear) {
3771 if (_drags->active ()) {
3776 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3777 cut_buffer->clear ();
3779 if (entered_marker) {
3781 /* cut/delete op while pointing at a marker */
3784 Location* loc = find_location_from_marker (entered_marker, ignored);
3786 if (_session && loc) {
3787 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3794 if (internal_editing()) {
3796 switch (effective_mouse_mode()) {
3799 begin_reversible_command (opname + ' ' + X_("MIDI"));
3801 commit_reversible_command ();
3810 bool did_edit = false;
3812 if (!selection->points.empty()) {
3813 begin_reversible_command (opname + _(" points"));
3815 cut_copy_points (op);
3816 if (op == Cut || op == Delete) {
3817 selection->clear_points ();
3819 } else if (!selection->regions.empty() || !selection->points.empty()) {
3823 if (selection->regions.empty()) {
3824 thing_name = _("points");
3825 } else if (selection->points.empty()) {
3826 thing_name = _("regions");
3828 thing_name = _("objects");
3831 begin_reversible_command (opname + ' ' + thing_name);
3834 if (!selection->regions.empty()) {
3835 cut_copy_regions (op, selection->regions);
3837 if (op == Cut || op == Delete) {
3838 selection->clear_regions ();
3842 if (!selection->points.empty()) {
3843 cut_copy_points (op);
3845 if (op == Cut || op == Delete) {
3846 selection->clear_points ();
3849 } else if (selection->time.empty()) {
3850 framepos_t start, end;
3851 /* no time selection, see if we can get an edit range
3854 if (get_edit_op_range (start, end)) {
3855 selection->set (start, end);
3857 } else if (!selection->time.empty()) {
3858 begin_reversible_command (opname + _(" range"));
3861 cut_copy_ranges (op);
3863 if (op == Cut || op == Delete) {
3864 selection->clear_time ();
3869 commit_reversible_command ();
3872 if (op == Delete || op == Cut || op == Clear) {
3877 struct AutomationRecord {
3878 AutomationRecord () : state (0) {}
3879 AutomationRecord (XMLNode* s) : state (s) {}
3881 XMLNode* state; ///< state before any operation
3882 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3885 /** Cut, copy or clear selected automation points.
3886 * @param op Operation (Cut, Copy or Clear)
3889 Editor::cut_copy_points (CutCopyOp op)
3891 if (selection->points.empty ()) {
3895 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3896 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3898 /* Keep a record of the AutomationLists that we end up using in this operation */
3899 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3902 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3903 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3904 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3905 if (lists.find (al) == lists.end ()) {
3906 /* We haven't seen this list yet, so make a record for it. This includes
3907 taking a copy of its current state, in case this is needed for undo later.
3909 lists[al] = AutomationRecord (&al->get_state ());
3913 if (op == Cut || op == Copy) {
3914 /* This operation will involve putting things in the cut buffer, so create an empty
3915 ControlList for each of our source lists to put the cut buffer data in.
3917 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3918 i->second.copy = i->first->create (i->first->parameter ());
3921 /* Add all selected points to the relevant copy ControlLists */
3922 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3923 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3924 AutomationList::const_iterator j = (*i)->model ();
3925 lists[al].copy->add ((*j)->when, (*j)->value);
3928 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3929 /* Correct this copy list so that it starts at time 0 */
3930 double const start = i->second.copy->front()->when;
3931 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3932 (*j)->when -= start;
3935 /* And add it to the cut buffer */
3936 cut_buffer->add (i->second.copy);
3940 if (op == Delete || op == Cut) {
3941 /* This operation needs to remove things from the main AutomationList, so do that now */
3943 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3944 i->first->freeze ();
3947 /* Remove each selected point from its AutomationList */
3948 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3949 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3950 al->erase ((*i)->model ());
3953 /* Thaw the lists and add undo records for them */
3954 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3955 boost::shared_ptr<AutomationList> al = i->first;
3957 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3962 /** Cut, copy or clear selected automation points.
3963 * @param op Operation (Cut, Copy or Clear)
3966 Editor::cut_copy_midi (CutCopyOp op)
3968 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3969 MidiRegionView* mrv = *i;
3970 mrv->cut_copy_clear (op);
3976 struct lt_playlist {
3977 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3978 return a.playlist < b.playlist;
3982 struct PlaylistMapping {
3984 boost::shared_ptr<Playlist> pl;
3986 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3989 /** Remove `clicked_regionview' */
3991 Editor::remove_clicked_region ()
3993 if (clicked_routeview == 0 || clicked_regionview == 0) {
3997 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3999 playlist->clear_changes ();
4000 playlist->clear_owned_changes ();
4001 playlist->remove_region (clicked_regionview->region());
4002 if (Config->get_edit_mode() == Ripple)
4003 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4005 /* We might have removed regions, which alters other regions' layering_index,
4006 so we need to do a recursive diff here.
4008 vector<Command*> cmds;
4009 playlist->rdiff (cmds);
4010 _session->add_commands (cmds);
4012 _session->add_command(new StatefulDiffCommand (playlist));
4013 commit_reversible_command ();
4017 /** Remove the selected regions */
4019 Editor::remove_selected_regions ()
4021 RegionSelection rs = get_regions_from_selection_and_entered ();
4023 if (!_session || rs.empty()) {
4027 begin_reversible_command (_("remove region"));
4029 list<boost::shared_ptr<Region> > regions_to_remove;
4031 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4032 // we can't just remove the region(s) in this loop because
4033 // this removes them from the RegionSelection, and they thus
4034 // disappear from underneath the iterator, and the ++i above
4035 // SEGVs in a puzzling fashion.
4037 // so, first iterate over the regions to be removed from rs and
4038 // add them to the regions_to_remove list, and then
4039 // iterate over the list to actually remove them.
4041 regions_to_remove.push_back ((*i)->region());
4044 vector<boost::shared_ptr<Playlist> > playlists;
4046 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4048 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4051 // is this check necessary?
4055 /* get_regions_from_selection_and_entered() guarantees that
4056 the playlists involved are unique, so there is no need
4060 playlists.push_back (playlist);
4062 playlist->clear_changes ();
4063 playlist->clear_owned_changes ();
4064 playlist->freeze ();
4065 playlist->remove_region (*rl);
4066 if (Config->get_edit_mode() == Ripple)
4067 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4071 vector<boost::shared_ptr<Playlist> >::iterator pl;
4073 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4076 /* We might have removed regions, which alters other regions' layering_index,
4077 so we need to do a recursive diff here.
4079 vector<Command*> cmds;
4080 (*pl)->rdiff (cmds);
4081 _session->add_commands (cmds);
4083 _session->add_command(new StatefulDiffCommand (*pl));
4086 commit_reversible_command ();
4089 /** Cut, copy or clear selected regions.
4090 * @param op Operation (Cut, Copy or Clear)
4093 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4095 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4096 a map when we want ordered access to both elements. i think.
4099 vector<PlaylistMapping> pmap;
4101 framepos_t first_position = max_framepos;
4103 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4104 FreezeList freezelist;
4106 /* get ordering correct before we cut/copy */
4108 rs.sort_by_position_and_track ();
4110 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4112 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4114 if (op == Cut || op == Clear || op == Delete) {
4115 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4118 FreezeList::iterator fl;
4120 // only take state if this is a new playlist.
4121 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4127 if (fl == freezelist.end()) {
4128 pl->clear_changes();
4129 pl->clear_owned_changes ();
4131 freezelist.insert (pl);
4136 TimeAxisView* tv = &(*x)->get_time_axis_view();
4137 vector<PlaylistMapping>::iterator z;
4139 for (z = pmap.begin(); z != pmap.end(); ++z) {
4140 if ((*z).tv == tv) {
4145 if (z == pmap.end()) {
4146 pmap.push_back (PlaylistMapping (tv));
4150 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4152 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4155 /* region not yet associated with a playlist (e.g. unfinished
4162 TimeAxisView& tv = (*x)->get_time_axis_view();
4163 boost::shared_ptr<Playlist> npl;
4164 RegionSelection::iterator tmp;
4171 vector<PlaylistMapping>::iterator z;
4173 for (z = pmap.begin(); z != pmap.end(); ++z) {
4174 if ((*z).tv == &tv) {
4179 assert (z != pmap.end());
4182 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4190 boost::shared_ptr<Region> r = (*x)->region();
4191 boost::shared_ptr<Region> _xx;
4197 pl->remove_region (r);
4198 if (Config->get_edit_mode() == Ripple)
4199 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4203 _xx = RegionFactory::create (r);
4204 npl->add_region (_xx, r->position() - first_position);
4205 pl->remove_region (r);
4206 if (Config->get_edit_mode() == Ripple)
4207 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4211 /* copy region before adding, so we're not putting same object into two different playlists */
4212 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4216 pl->remove_region (r);
4217 if (Config->get_edit_mode() == Ripple)
4218 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4227 list<boost::shared_ptr<Playlist> > foo;
4229 /* the pmap is in the same order as the tracks in which selected regions occured */
4231 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4234 foo.push_back ((*i).pl);
4239 cut_buffer->set (foo);
4243 _last_cut_copy_source_track = 0;
4245 _last_cut_copy_source_track = pmap.front().tv;
4249 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4252 /* We might have removed regions, which alters other regions' layering_index,
4253 so we need to do a recursive diff here.
4255 vector<Command*> cmds;
4256 (*pl)->rdiff (cmds);
4257 _session->add_commands (cmds);
4259 _session->add_command (new StatefulDiffCommand (*pl));
4264 Editor::cut_copy_ranges (CutCopyOp op)
4266 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4268 /* Sort the track selection now, so that it if is used, the playlists
4269 selected by the calls below to cut_copy_clear are in the order that
4270 their tracks appear in the editor. This makes things like paste
4271 of ranges work properly.
4274 sort_track_selection (ts);
4277 if (!entered_track) {
4280 ts.push_back (entered_track);
4283 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4284 (*i)->cut_copy_clear (*selection, op);
4289 Editor::paste (float times, bool from_context)
4291 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4293 paste_internal (get_preferred_edit_position (false, from_context), times);
4297 Editor::mouse_paste ()
4302 if (!mouse_frame (where, ignored)) {
4307 paste_internal (where, 1);
4311 Editor::paste_internal (framepos_t position, float times)
4313 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4315 if (internal_editing()) {
4316 if (cut_buffer->midi_notes.empty()) {
4320 if (cut_buffer->empty()) {
4325 if (position == max_framepos) {
4326 position = get_preferred_edit_position();
4327 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4331 TrackViewList::iterator i;
4334 /* get everything in the correct order */
4336 if (_edit_point == Editing::EditAtMouse && entered_track) {
4337 /* With the mouse edit point, paste onto the track under the mouse */
4338 ts.push_back (entered_track);
4339 } else if (!selection->tracks.empty()) {
4340 /* Otherwise, if there are some selected tracks, paste to them */
4341 ts = selection->tracks.filter_to_unique_playlists ();
4342 sort_track_selection (ts);
4343 } else if (_last_cut_copy_source_track) {
4344 /* Otherwise paste to the track that the cut/copy came from;
4345 see discussion in mantis #3333.
4347 ts.push_back (_last_cut_copy_source_track);
4350 if (internal_editing ()) {
4352 /* undo/redo is handled by individual tracks/regions */
4354 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4357 RegionSelection::iterator r;
4358 MidiNoteSelection::iterator cb;
4360 get_regions_at (rs, position, ts);
4362 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4363 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4364 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4366 mrv->paste (position, times, **cb);
4374 /* we do redo (do you do voodoo?) */
4376 begin_reversible_command (Operations::paste);
4378 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4379 (*i)->paste (position, times, *cut_buffer, nth);
4382 commit_reversible_command ();
4387 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4389 boost::shared_ptr<Playlist> playlist;
4390 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4391 RegionSelection foo;
4393 framepos_t const start_frame = regions.start ();
4394 framepos_t const end_frame = regions.end_frame ();
4396 begin_reversible_command (Operations::duplicate_region);
4398 selection->clear_regions ();
4400 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4402 boost::shared_ptr<Region> r ((*i)->region());
4404 TimeAxisView& tv = (*i)->get_time_axis_view();
4405 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4406 latest_regionviews.clear ();
4407 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4409 playlist = (*i)->region()->playlist();
4410 playlist->clear_changes ();
4411 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4412 _session->add_command(new StatefulDiffCommand (playlist));
4416 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4419 commit_reversible_command ();
4422 selection->set (foo);
4427 Editor::duplicate_selection (float times)
4429 if (selection->time.empty() || selection->tracks.empty()) {
4433 boost::shared_ptr<Playlist> playlist;
4434 vector<boost::shared_ptr<Region> > new_regions;
4435 vector<boost::shared_ptr<Region> >::iterator ri;
4437 create_region_from_selection (new_regions);
4439 if (new_regions.empty()) {
4443 begin_reversible_command (_("duplicate selection"));
4445 ri = new_regions.begin();
4447 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4449 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4450 if ((playlist = (*i)->playlist()) == 0) {
4453 playlist->clear_changes ();
4454 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4455 _session->add_command (new StatefulDiffCommand (playlist));
4458 if (ri == new_regions.end()) {
4463 commit_reversible_command ();
4466 /** Reset all selected points to the relevant default value */
4468 Editor::reset_point_selection ()
4470 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4471 ARDOUR::AutomationList::iterator j = (*i)->model ();
4472 (*j)->value = (*i)->line().the_list()->default_value ();
4477 Editor::center_playhead ()
4479 float const page = _visible_canvas_width * samples_per_pixel;
4480 center_screen_internal (playhead_cursor->current_frame (), page);
4484 Editor::center_edit_point ()
4486 float const page = _visible_canvas_width * samples_per_pixel;
4487 center_screen_internal (get_preferred_edit_position(), page);
4490 /** Caller must begin and commit a reversible command */
4492 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4494 playlist->clear_changes ();
4496 _session->add_command (new StatefulDiffCommand (playlist));
4500 Editor::nudge_track (bool use_edit, bool forwards)
4502 boost::shared_ptr<Playlist> playlist;
4503 framepos_t distance;
4504 framepos_t next_distance;
4508 start = get_preferred_edit_position();
4513 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4517 if (selection->tracks.empty()) {
4521 begin_reversible_command (_("nudge track"));
4523 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4525 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4527 if ((playlist = (*i)->playlist()) == 0) {
4531 playlist->clear_changes ();
4532 playlist->clear_owned_changes ();
4534 playlist->nudge_after (start, distance, forwards);
4536 vector<Command*> cmds;
4538 playlist->rdiff (cmds);
4539 _session->add_commands (cmds);
4541 _session->add_command (new StatefulDiffCommand (playlist));
4544 commit_reversible_command ();
4548 Editor::remove_last_capture ()
4550 vector<string> choices;
4557 if (Config->get_verify_remove_last_capture()) {
4558 prompt = _("Do you really want to destroy the last capture?"
4559 "\n(This is destructive and cannot be undone)");
4561 choices.push_back (_("No, do nothing."));
4562 choices.push_back (_("Yes, destroy it."));
4564 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4566 if (prompter.run () == 1) {
4567 _session->remove_last_capture ();
4568 _regions->redisplay ();
4572 _session->remove_last_capture();
4573 _regions->redisplay ();
4578 Editor::normalize_region ()
4584 RegionSelection rs = get_regions_from_selection_and_entered ();
4590 NormalizeDialog dialog (rs.size() > 1);
4592 if (dialog.run () == RESPONSE_CANCEL) {
4596 set_canvas_cursor (_cursors->wait);
4599 /* XXX: should really only count audio regions here */
4600 int const regions = rs.size ();
4602 /* Make a list of the selected audio regions' maximum amplitudes, and also
4603 obtain the maximum amplitude of them all.
4605 list<double> max_amps;
4607 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4608 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4610 dialog.descend (1.0 / regions);
4611 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4614 /* the user cancelled the operation */
4615 set_canvas_cursor (current_canvas_cursor);
4619 max_amps.push_back (a);
4620 max_amp = max (max_amp, a);
4625 begin_reversible_command (_("normalize"));
4627 list<double>::const_iterator a = max_amps.begin ();
4629 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4630 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4635 arv->region()->clear_changes ();
4637 double const amp = dialog.normalize_individually() ? *a : max_amp;
4639 arv->audio_region()->normalize (amp, dialog.target ());
4640 _session->add_command (new StatefulDiffCommand (arv->region()));
4645 commit_reversible_command ();
4646 set_canvas_cursor (current_canvas_cursor);
4651 Editor::reset_region_scale_amplitude ()
4657 RegionSelection rs = get_regions_from_selection_and_entered ();
4663 begin_reversible_command ("reset gain");
4665 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4666 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4669 arv->region()->clear_changes ();
4670 arv->audio_region()->set_scale_amplitude (1.0f);
4671 _session->add_command (new StatefulDiffCommand (arv->region()));
4674 commit_reversible_command ();
4678 Editor::adjust_region_gain (bool up)
4680 RegionSelection rs = get_regions_from_selection_and_entered ();
4682 if (!_session || rs.empty()) {
4686 begin_reversible_command ("adjust region gain");
4688 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4689 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4694 arv->region()->clear_changes ();
4696 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4704 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4705 _session->add_command (new StatefulDiffCommand (arv->region()));
4708 commit_reversible_command ();
4713 Editor::reverse_region ()
4719 Reverse rev (*_session);
4720 apply_filter (rev, _("reverse regions"));
4724 Editor::strip_region_silence ()
4730 RegionSelection rs = get_regions_from_selection_and_entered ();
4736 std::list<RegionView*> audio_only;
4738 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4739 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4741 audio_only.push_back (arv);
4745 StripSilenceDialog d (_session, audio_only);
4746 int const r = d.run ();
4750 if (r == Gtk::RESPONSE_OK) {
4751 ARDOUR::AudioIntervalMap silences;
4752 d.silences (silences);
4753 StripSilence s (*_session, silences, d.fade_length());
4754 apply_filter (s, _("strip silence"), &d);
4759 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4761 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4762 mrv.selection_as_notelist (selected, true);
4764 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4765 v.push_back (selected);
4767 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4768 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4770 return op (mrv.midi_region()->model(), pos_beats, v);
4774 Editor::apply_midi_note_edit_op (MidiOperator& op)
4778 RegionSelection rs = get_regions_from_selection_and_entered ();
4784 begin_reversible_command (op.name ());
4786 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4787 RegionSelection::iterator tmp = r;
4790 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4793 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4796 _session->add_command (cmd);
4803 commit_reversible_command ();
4807 Editor::fork_region ()
4809 RegionSelection rs = get_regions_from_selection_and_entered ();
4815 begin_reversible_command (_("Fork Region(s)"));
4817 set_canvas_cursor (_cursors->wait);
4820 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4821 RegionSelection::iterator tmp = r;
4824 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4828 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4829 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4830 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4832 playlist->clear_changes ();
4833 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4834 _session->add_command(new StatefulDiffCommand (playlist));
4836 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4843 commit_reversible_command ();
4845 set_canvas_cursor (current_canvas_cursor);
4849 Editor::quantize_region ()
4851 int selected_midi_region_cnt = 0;
4857 RegionSelection rs = get_regions_from_selection_and_entered ();
4863 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4864 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4866 selected_midi_region_cnt++;
4870 if (selected_midi_region_cnt == 0) {
4874 QuantizeDialog* qd = new QuantizeDialog (*this);
4877 const int r = qd->run ();
4880 if (r == Gtk::RESPONSE_OK) {
4881 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4882 qd->start_grid_size(), qd->end_grid_size(),
4883 qd->strength(), qd->swing(), qd->threshold());
4885 apply_midi_note_edit_op (quant);
4890 Editor::insert_patch_change (bool from_context)
4892 RegionSelection rs = get_regions_from_selection_and_entered ();
4898 const framepos_t p = get_preferred_edit_position (false, from_context);
4900 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4901 there may be more than one, but the PatchChangeDialog can only offer
4902 one set of patch menus.
4904 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4906 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4907 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4909 if (d.run() == RESPONSE_CANCEL) {
4913 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4914 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4916 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4917 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4924 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4926 RegionSelection rs = get_regions_from_selection_and_entered ();
4932 begin_reversible_command (command);
4934 set_canvas_cursor (_cursors->wait);
4938 int const N = rs.size ();
4940 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4941 RegionSelection::iterator tmp = r;
4944 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4946 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4949 progress->descend (1.0 / N);
4952 if (arv->audio_region()->apply (filter, progress) == 0) {
4954 playlist->clear_changes ();
4955 playlist->clear_owned_changes ();
4957 if (filter.results.empty ()) {
4959 /* no regions returned; remove the old one */
4960 playlist->remove_region (arv->region ());
4964 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4966 /* first region replaces the old one */
4967 playlist->replace_region (arv->region(), *res, (*res)->position());
4971 while (res != filter.results.end()) {
4972 playlist->add_region (*res, (*res)->position());
4978 /* We might have removed regions, which alters other regions' layering_index,
4979 so we need to do a recursive diff here.
4981 vector<Command*> cmds;
4982 playlist->rdiff (cmds);
4983 _session->add_commands (cmds);
4985 _session->add_command(new StatefulDiffCommand (playlist));
4991 progress->ascend ();
4999 commit_reversible_command ();
5002 set_canvas_cursor (current_canvas_cursor);
5006 Editor::external_edit_region ()
5012 Editor::reset_region_gain_envelopes ()
5014 RegionSelection rs = get_regions_from_selection_and_entered ();
5016 if (!_session || rs.empty()) {
5020 _session->begin_reversible_command (_("reset region gain"));
5022 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5023 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5025 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5026 XMLNode& before (alist->get_state());
5028 arv->audio_region()->set_default_envelope ();
5029 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5033 _session->commit_reversible_command ();
5037 Editor::set_region_gain_visibility (RegionView* rv)
5039 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5041 arv->update_envelope_visibility();
5046 Editor::set_gain_envelope_visibility ()
5052 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5053 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5055 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5061 Editor::toggle_gain_envelope_active ()
5063 if (_ignore_region_action) {
5067 RegionSelection rs = get_regions_from_selection_and_entered ();
5069 if (!_session || rs.empty()) {
5073 _session->begin_reversible_command (_("region gain envelope active"));
5075 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5076 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5078 arv->region()->clear_changes ();
5079 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5080 _session->add_command (new StatefulDiffCommand (arv->region()));
5084 _session->commit_reversible_command ();
5088 Editor::toggle_region_lock ()
5090 if (_ignore_region_action) {
5094 RegionSelection rs = get_regions_from_selection_and_entered ();
5096 if (!_session || rs.empty()) {
5100 _session->begin_reversible_command (_("toggle region lock"));
5102 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5103 (*i)->region()->clear_changes ();
5104 (*i)->region()->set_locked (!(*i)->region()->locked());
5105 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5108 _session->commit_reversible_command ();
5112 Editor::toggle_region_video_lock ()
5114 if (_ignore_region_action) {
5118 RegionSelection rs = get_regions_from_selection_and_entered ();
5120 if (!_session || rs.empty()) {
5124 _session->begin_reversible_command (_("Toggle Video Lock"));
5126 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5127 (*i)->region()->clear_changes ();
5128 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5129 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5132 _session->commit_reversible_command ();
5136 Editor::toggle_region_lock_style ()
5138 if (_ignore_region_action) {
5142 RegionSelection rs = get_regions_from_selection_and_entered ();
5144 if (!_session || rs.empty()) {
5148 _session->begin_reversible_command (_("region lock style"));
5150 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5151 (*i)->region()->clear_changes ();
5152 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5153 (*i)->region()->set_position_lock_style (ns);
5154 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5157 _session->commit_reversible_command ();
5161 Editor::toggle_opaque_region ()
5163 if (_ignore_region_action) {
5167 RegionSelection rs = get_regions_from_selection_and_entered ();
5169 if (!_session || rs.empty()) {
5173 _session->begin_reversible_command (_("change region opacity"));
5175 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5176 (*i)->region()->clear_changes ();
5177 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5178 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5181 _session->commit_reversible_command ();
5185 Editor::toggle_record_enable ()
5187 bool new_state = false;
5189 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5190 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5193 if (!rtav->is_track())
5197 new_state = !rtav->track()->record_enabled();
5201 rtav->track()->set_record_enabled (new_state, this);
5206 Editor::toggle_solo ()
5208 bool new_state = false;
5210 boost::shared_ptr<RouteList> rl (new RouteList);
5212 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5213 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5220 new_state = !rtav->route()->soloed ();
5224 rl->push_back (rtav->route());
5227 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5231 Editor::toggle_mute ()
5233 bool new_state = false;
5235 boost::shared_ptr<RouteList> rl (new RouteList);
5237 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5238 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5245 new_state = !rtav->route()->muted();
5249 rl->push_back (rtav->route());
5252 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5256 Editor::toggle_solo_isolate ()
5261 Editor::set_fade_length (bool in)
5263 RegionSelection rs = get_regions_from_selection_and_entered ();
5269 /* we need a region to measure the offset from the start */
5271 RegionView* rv = rs.front ();
5273 framepos_t pos = get_preferred_edit_position();
5277 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5278 /* edit point is outside the relevant region */
5283 if (pos <= rv->region()->position()) {
5287 len = pos - rv->region()->position();
5288 cmd = _("set fade in length");
5290 if (pos >= rv->region()->last_frame()) {
5294 len = rv->region()->last_frame() - pos;
5295 cmd = _("set fade out length");
5298 begin_reversible_command (cmd);
5300 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5301 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5307 boost::shared_ptr<AutomationList> alist;
5309 alist = tmp->audio_region()->fade_in();
5311 alist = tmp->audio_region()->fade_out();
5314 XMLNode &before = alist->get_state();
5317 tmp->audio_region()->set_fade_in_length (len);
5318 tmp->audio_region()->set_fade_in_active (true);
5320 tmp->audio_region()->set_fade_out_length (len);
5321 tmp->audio_region()->set_fade_out_active (true);
5324 XMLNode &after = alist->get_state();
5325 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5328 commit_reversible_command ();
5332 Editor::set_fade_in_shape (FadeShape shape)
5334 RegionSelection rs = get_regions_from_selection_and_entered ();
5340 begin_reversible_command (_("set fade in shape"));
5342 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5343 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5349 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5350 XMLNode &before = alist->get_state();
5352 tmp->audio_region()->set_fade_in_shape (shape);
5354 XMLNode &after = alist->get_state();
5355 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5358 commit_reversible_command ();
5363 Editor::set_fade_out_shape (FadeShape shape)
5365 RegionSelection rs = get_regions_from_selection_and_entered ();
5371 begin_reversible_command (_("set fade out shape"));
5373 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5374 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5380 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5381 XMLNode &before = alist->get_state();
5383 tmp->audio_region()->set_fade_out_shape (shape);
5385 XMLNode &after = alist->get_state();
5386 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5389 commit_reversible_command ();
5393 Editor::set_fade_in_active (bool yn)
5395 RegionSelection rs = get_regions_from_selection_and_entered ();
5401 begin_reversible_command (_("set fade in active"));
5403 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5404 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5411 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5413 ar->clear_changes ();
5414 ar->set_fade_in_active (yn);
5415 _session->add_command (new StatefulDiffCommand (ar));
5418 commit_reversible_command ();
5422 Editor::set_fade_out_active (bool yn)
5424 RegionSelection rs = get_regions_from_selection_and_entered ();
5430 begin_reversible_command (_("set fade out active"));
5432 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5433 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5439 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5441 ar->clear_changes ();
5442 ar->set_fade_out_active (yn);
5443 _session->add_command(new StatefulDiffCommand (ar));
5446 commit_reversible_command ();
5450 Editor::toggle_region_fades (int dir)
5452 if (_ignore_region_action) {
5456 boost::shared_ptr<AudioRegion> ar;
5459 RegionSelection rs = get_regions_from_selection_and_entered ();
5465 RegionSelection::iterator i;
5466 for (i = rs.begin(); i != rs.end(); ++i) {
5467 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5469 yn = ar->fade_out_active ();
5471 yn = ar->fade_in_active ();
5477 if (i == rs.end()) {
5481 /* XXX should this undo-able? */
5483 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5484 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5487 if (dir == 1 || dir == 0) {
5488 ar->set_fade_in_active (!yn);
5491 if (dir == -1 || dir == 0) {
5492 ar->set_fade_out_active (!yn);
5498 /** Update region fade visibility after its configuration has been changed */
5500 Editor::update_region_fade_visibility ()
5502 bool _fade_visibility = _session->config.get_show_region_fades ();
5504 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5505 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5507 if (_fade_visibility) {
5508 v->audio_view()->show_all_fades ();
5510 v->audio_view()->hide_all_fades ();
5517 Editor::set_edit_point ()
5522 if (!mouse_frame (where, ignored)) {
5528 if (selection->markers.empty()) {
5530 mouse_add_new_marker (where);
5535 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5538 loc->move_to (where);
5544 Editor::set_playhead_cursor ()
5546 if (entered_marker) {
5547 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5552 if (!mouse_frame (where, ignored)) {
5559 _session->request_locate (where, _session->transport_rolling());
5563 if ( Config->get_follow_edits() )
5564 cancel_time_selection();
5568 Editor::split_region ()
5570 if ( !selection->time.empty()) {
5571 separate_regions_between (selection->time);
5575 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5577 framepos_t where = get_preferred_edit_position ();
5583 split_regions_at (where, rs);
5586 struct EditorOrderRouteSorter {
5587 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5588 return a->order_key () < b->order_key ();
5593 Editor::select_next_route()
5595 if (selection->tracks.empty()) {
5596 selection->set (track_views.front());
5600 TimeAxisView* current = selection->tracks.front();
5604 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5605 if (*i == current) {
5607 if (i != track_views.end()) {
5610 current = (*(track_views.begin()));
5611 //selection->set (*(track_views.begin()));
5616 rui = dynamic_cast<RouteUI *>(current);
5617 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5619 selection->set(current);
5621 ensure_time_axis_view_is_visible (*current);
5625 Editor::select_prev_route()
5627 if (selection->tracks.empty()) {
5628 selection->set (track_views.front());
5632 TimeAxisView* current = selection->tracks.front();
5636 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5637 if (*i == current) {
5639 if (i != track_views.rend()) {
5642 current = *(track_views.rbegin());
5647 rui = dynamic_cast<RouteUI *>(current);
5648 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5650 selection->set (current);
5652 ensure_time_axis_view_is_visible (*current);
5656 Editor::set_loop_from_selection (bool play)
5658 if (_session == 0 || selection->time.empty()) {
5662 framepos_t start = selection->time[clicked_selection].start;
5663 framepos_t end = selection->time[clicked_selection].end;
5665 set_loop_range (start, end, _("set loop range from selection"));
5668 _session->request_play_loop (true);
5669 _session->request_locate (start, true);
5674 Editor::set_loop_from_edit_range (bool play)
5676 if (_session == 0) {
5683 if (!get_edit_op_range (start, end)) {
5687 set_loop_range (start, end, _("set loop range from edit range"));
5690 _session->request_play_loop (true);
5691 _session->request_locate (start, true);
5696 Editor::set_loop_from_region (bool play)
5698 framepos_t start = max_framepos;
5701 RegionSelection rs = get_regions_from_selection_and_entered ();
5707 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5708 if ((*i)->region()->position() < start) {
5709 start = (*i)->region()->position();
5711 if ((*i)->region()->last_frame() + 1 > end) {
5712 end = (*i)->region()->last_frame() + 1;
5716 set_loop_range (start, end, _("set loop range from region"));
5719 _session->request_play_loop (true);
5720 _session->request_locate (start, true);
5725 Editor::set_punch_from_selection ()
5727 if (_session == 0 || selection->time.empty()) {
5731 framepos_t start = selection->time[clicked_selection].start;
5732 framepos_t end = selection->time[clicked_selection].end;
5734 set_punch_range (start, end, _("set punch range from selection"));
5738 Editor::set_punch_from_edit_range ()
5740 if (_session == 0) {
5747 if (!get_edit_op_range (start, end)) {
5751 set_punch_range (start, end, _("set punch range from edit range"));
5755 Editor::set_punch_from_region ()
5757 framepos_t start = max_framepos;
5760 RegionSelection rs = get_regions_from_selection_and_entered ();
5766 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5767 if ((*i)->region()->position() < start) {
5768 start = (*i)->region()->position();
5770 if ((*i)->region()->last_frame() + 1 > end) {
5771 end = (*i)->region()->last_frame() + 1;
5775 set_punch_range (start, end, _("set punch range from region"));
5779 Editor::pitch_shift_region ()
5781 RegionSelection rs = get_regions_from_selection_and_entered ();
5783 RegionSelection audio_rs;
5784 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5785 if (dynamic_cast<AudioRegionView*> (*i)) {
5786 audio_rs.push_back (*i);
5790 if (audio_rs.empty()) {
5794 pitch_shift (audio_rs, 1.2);
5798 Editor::transpose_region ()
5800 RegionSelection rs = get_regions_from_selection_and_entered ();
5802 list<MidiRegionView*> midi_region_views;
5803 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5804 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5806 midi_region_views.push_back (mrv);
5811 int const r = d.run ();
5812 if (r != RESPONSE_ACCEPT) {
5816 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5817 (*i)->midi_region()->transpose (d.semitones ());
5822 Editor::set_tempo_from_region ()
5824 RegionSelection rs = get_regions_from_selection_and_entered ();
5826 if (!_session || rs.empty()) {
5830 RegionView* rv = rs.front();
5832 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5836 Editor::use_range_as_bar ()
5838 framepos_t start, end;
5839 if (get_edit_op_range (start, end)) {
5840 define_one_bar (start, end);
5845 Editor::define_one_bar (framepos_t start, framepos_t end)
5847 framepos_t length = end - start;
5849 const Meter& m (_session->tempo_map().meter_at (start));
5851 /* length = 1 bar */
5853 /* now we want frames per beat.
5854 we have frames per bar, and beats per bar, so ...
5857 /* XXXX METER MATH */
5859 double frames_per_beat = length / m.divisions_per_bar();
5861 /* beats per minute = */
5863 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5865 /* now decide whether to:
5867 (a) set global tempo
5868 (b) add a new tempo marker
5872 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5874 bool do_global = false;
5876 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5878 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5879 at the start, or create a new marker
5882 vector<string> options;
5883 options.push_back (_("Cancel"));
5884 options.push_back (_("Add new marker"));
5885 options.push_back (_("Set global tempo"));
5888 _("Define one bar"),
5889 _("Do you want to set the global tempo or add a new tempo marker?"),
5893 c.set_default_response (2);
5909 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5910 if the marker is at the region starter, change it, otherwise add
5915 begin_reversible_command (_("set tempo from region"));
5916 XMLNode& before (_session->tempo_map().get_state());
5919 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5920 } else if (t.frame() == start) {
5921 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5923 Timecode::BBT_Time bbt;
5924 _session->tempo_map().bbt_time (start, bbt);
5925 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5928 XMLNode& after (_session->tempo_map().get_state());
5930 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5931 commit_reversible_command ();
5935 Editor::split_region_at_transients ()
5937 AnalysisFeatureList positions;
5939 RegionSelection rs = get_regions_from_selection_and_entered ();
5941 if (!_session || rs.empty()) {
5945 _session->begin_reversible_command (_("split regions"));
5947 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5949 RegionSelection::iterator tmp;
5954 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5956 if (ar && (ar->get_transients (positions) == 0)) {
5957 split_region_at_points ((*i)->region(), positions, true);
5964 _session->commit_reversible_command ();
5969 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5971 bool use_rhythmic_rodent = false;
5973 boost::shared_ptr<Playlist> pl = r->playlist();
5975 list<boost::shared_ptr<Region> > new_regions;
5981 if (positions.empty()) {
5986 if (positions.size() > 20 && can_ferret) {
5987 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);
5988 MessageDialog msg (msgstr,
5991 Gtk::BUTTONS_OK_CANCEL);
5994 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5995 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5997 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6000 msg.set_title (_("Excessive split?"));
6003 int response = msg.run();
6009 case RESPONSE_APPLY:
6010 use_rhythmic_rodent = true;
6017 if (use_rhythmic_rodent) {
6018 show_rhythm_ferret ();
6022 AnalysisFeatureList::const_iterator x;
6024 pl->clear_changes ();
6025 pl->clear_owned_changes ();
6027 x = positions.begin();
6029 if (x == positions.end()) {
6034 pl->remove_region (r);
6038 while (x != positions.end()) {
6040 /* deal with positons that are out of scope of present region bounds */
6041 if (*x <= 0 || *x > r->length()) {
6046 /* file start = original start + how far we from the initial position ?
6049 framepos_t file_start = r->start() + pos;
6051 /* length = next position - current position
6054 framepos_t len = (*x) - pos;
6056 /* XXX we do we really want to allow even single-sample regions?
6057 shouldn't we have some kind of lower limit on region size?
6066 if (RegionFactory::region_name (new_name, r->name())) {
6070 /* do NOT announce new regions 1 by one, just wait till they are all done */
6074 plist.add (ARDOUR::Properties::start, file_start);
6075 plist.add (ARDOUR::Properties::length, len);
6076 plist.add (ARDOUR::Properties::name, new_name);
6077 plist.add (ARDOUR::Properties::layer, 0);
6079 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6080 /* because we set annouce to false, manually add the new region to the
6083 RegionFactory::map_add (nr);
6085 pl->add_region (nr, r->position() + pos);
6088 new_regions.push_front(nr);
6097 RegionFactory::region_name (new_name, r->name());
6099 /* Add the final region */
6102 plist.add (ARDOUR::Properties::start, r->start() + pos);
6103 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6104 plist.add (ARDOUR::Properties::name, new_name);
6105 plist.add (ARDOUR::Properties::layer, 0);
6107 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6108 /* because we set annouce to false, manually add the new region to the
6111 RegionFactory::map_add (nr);
6112 pl->add_region (nr, r->position() + pos);
6115 new_regions.push_front(nr);
6120 /* We might have removed regions, which alters other regions' layering_index,
6121 so we need to do a recursive diff here.
6123 vector<Command*> cmds;
6125 _session->add_commands (cmds);
6127 _session->add_command (new StatefulDiffCommand (pl));
6131 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6132 set_selected_regionview_from_region_list ((*i), Selection::Add);
6138 Editor::place_transient()
6144 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6150 framepos_t where = get_preferred_edit_position();
6152 _session->begin_reversible_command (_("place transient"));
6154 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6155 framepos_t position = (*r)->region()->position();
6156 (*r)->region()->add_transient(where - position);
6159 _session->commit_reversible_command ();
6163 Editor::remove_transient(ArdourCanvas::Item* item)
6169 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6172 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6173 _arv->remove_transient (*(float*) _line->get_data ("position"));
6177 Editor::snap_regions_to_grid ()
6179 list <boost::shared_ptr<Playlist > > used_playlists;
6181 RegionSelection rs = get_regions_from_selection_and_entered ();
6183 if (!_session || rs.empty()) {
6187 _session->begin_reversible_command (_("snap regions to grid"));
6189 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6191 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6193 if (!pl->frozen()) {
6194 /* we haven't seen this playlist before */
6196 /* remember used playlists so we can thaw them later */
6197 used_playlists.push_back(pl);
6201 framepos_t start_frame = (*r)->region()->first_frame ();
6202 snap_to (start_frame);
6203 (*r)->region()->set_position (start_frame);
6206 while (used_playlists.size() > 0) {
6207 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6209 used_playlists.pop_front();
6212 _session->commit_reversible_command ();
6216 Editor::close_region_gaps ()
6218 list <boost::shared_ptr<Playlist > > used_playlists;
6220 RegionSelection rs = get_regions_from_selection_and_entered ();
6222 if (!_session || rs.empty()) {
6226 Dialog dialog (_("Close Region Gaps"));
6229 table.set_spacings (12);
6230 table.set_border_width (12);
6231 Label* l = manage (left_aligned_label (_("Crossfade length")));
6232 table.attach (*l, 0, 1, 0, 1);
6234 SpinButton spin_crossfade (1, 0);
6235 spin_crossfade.set_range (0, 15);
6236 spin_crossfade.set_increments (1, 1);
6237 spin_crossfade.set_value (5);
6238 table.attach (spin_crossfade, 1, 2, 0, 1);
6240 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6242 l = manage (left_aligned_label (_("Pull-back length")));
6243 table.attach (*l, 0, 1, 1, 2);
6245 SpinButton spin_pullback (1, 0);
6246 spin_pullback.set_range (0, 100);
6247 spin_pullback.set_increments (1, 1);
6248 spin_pullback.set_value(30);
6249 table.attach (spin_pullback, 1, 2, 1, 2);
6251 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6253 dialog.get_vbox()->pack_start (table);
6254 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6255 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6258 if (dialog.run () == RESPONSE_CANCEL) {
6262 framepos_t crossfade_len = spin_crossfade.get_value();
6263 framepos_t pull_back_frames = spin_pullback.get_value();
6265 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6266 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6268 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6270 _session->begin_reversible_command (_("close region gaps"));
6273 boost::shared_ptr<Region> last_region;
6275 rs.sort_by_position_and_track();
6277 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6279 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6281 if (!pl->frozen()) {
6282 /* we haven't seen this playlist before */
6284 /* remember used playlists so we can thaw them later */
6285 used_playlists.push_back(pl);
6289 framepos_t position = (*r)->region()->position();
6291 if (idx == 0 || position < last_region->position()){
6292 last_region = (*r)->region();
6297 (*r)->region()->trim_front( (position - pull_back_frames));
6298 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6300 last_region = (*r)->region();
6305 while (used_playlists.size() > 0) {
6306 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6308 used_playlists.pop_front();
6311 _session->commit_reversible_command ();
6315 Editor::tab_to_transient (bool forward)
6317 AnalysisFeatureList positions;
6319 RegionSelection rs = get_regions_from_selection_and_entered ();
6325 framepos_t pos = _session->audible_frame ();
6327 if (!selection->tracks.empty()) {
6329 /* don't waste time searching for transients in duplicate playlists.
6332 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6334 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6336 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6339 boost::shared_ptr<Track> tr = rtv->track();
6341 boost::shared_ptr<Playlist> pl = tr->playlist ();
6343 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6346 positions.push_back (result);
6359 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6360 (*r)->region()->get_transients (positions);
6364 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6367 AnalysisFeatureList::iterator x;
6369 for (x = positions.begin(); x != positions.end(); ++x) {
6375 if (x != positions.end ()) {
6376 _session->request_locate (*x);
6380 AnalysisFeatureList::reverse_iterator x;
6382 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6388 if (x != positions.rend ()) {
6389 _session->request_locate (*x);
6395 Editor::playhead_forward_to_grid ()
6401 framepos_t pos = playhead_cursor->current_frame ();
6402 if (pos < max_framepos - 1) {
6404 snap_to_internal (pos, 1, false);
6405 _session->request_locate (pos);
6411 Editor::playhead_backward_to_grid ()
6417 framepos_t pos = playhead_cursor->current_frame ();
6420 snap_to_internal (pos, -1, false);
6421 _session->request_locate (pos);
6426 Editor::set_track_height (Height h)
6428 TrackSelection& ts (selection->tracks);
6430 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6431 (*x)->set_height_enum (h);
6436 Editor::toggle_tracks_active ()
6438 TrackSelection& ts (selection->tracks);
6440 bool target = false;
6446 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6447 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6451 target = !rtv->_route->active();
6454 rtv->_route->set_active (target, this);
6460 Editor::remove_tracks ()
6462 TrackSelection& ts (selection->tracks);
6468 vector<string> choices;
6472 const char* trackstr;
6474 vector<boost::shared_ptr<Route> > routes;
6475 bool special_bus = false;
6477 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6478 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6482 if (rtv->is_track()) {
6487 routes.push_back (rtv->_route);
6489 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6494 if (special_bus && !Config->get_allow_special_bus_removal()) {
6495 MessageDialog msg (_("That would be bad news ...."),
6499 msg.set_secondary_text (string_compose (_(
6500 "Removing the master or monitor bus is such a bad idea\n\
6501 that %1 is not going to allow it.\n\
6503 If you really want to do this sort of thing\n\
6504 edit your ardour.rc file to set the\n\
6505 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6512 if (ntracks + nbusses == 0) {
6517 trackstr = _("tracks");
6519 trackstr = _("track");
6523 busstr = _("busses");
6530 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6531 "(You may also lose the playlists associated with the %2)\n\n"
6532 "This action cannot be undone, and the session file will be overwritten!"),
6533 ntracks, trackstr, nbusses, busstr);
6535 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6536 "(You may also lose the playlists associated with the %2)\n\n"
6537 "This action cannot be undone, and the session file will be overwritten!"),
6540 } else if (nbusses) {
6541 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6542 "This action cannot be undon, and the session file will be overwritten"),
6546 choices.push_back (_("No, do nothing."));
6547 if (ntracks + nbusses > 1) {
6548 choices.push_back (_("Yes, remove them."));
6550 choices.push_back (_("Yes, remove it."));
6555 title = string_compose (_("Remove %1"), trackstr);
6557 title = string_compose (_("Remove %1"), busstr);
6560 Choice prompter (title, prompt, choices);
6562 if (prompter.run () != 1) {
6567 Session::StateProtector sp (_session);
6568 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6569 _session->remove_route (*x);
6575 Editor::do_insert_time ()
6577 if (selection->tracks.empty()) {
6581 InsertTimeDialog d (*this);
6582 int response = d.run ();
6584 if (response != RESPONSE_OK) {
6588 if (d.distance() == 0) {
6592 InsertTimeOption opt = d.intersected_region_action ();
6595 get_preferred_edit_position(),
6601 d.move_glued_markers(),
6602 d.move_locked_markers(),
6608 Editor::insert_time (
6609 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6610 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6613 bool commit = false;
6615 if (Config->get_edit_mode() == Lock) {
6619 begin_reversible_command (_("insert time"));
6621 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6623 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6627 /* don't operate on any playlist more than once, which could
6628 * happen if "all playlists" is enabled, but there is more
6629 * than 1 track using playlists "from" a given track.
6632 set<boost::shared_ptr<Playlist> > pl;
6634 if (all_playlists) {
6635 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6637 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6638 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6643 if ((*x)->playlist ()) {
6644 pl.insert ((*x)->playlist ());
6648 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6650 (*i)->clear_changes ();
6651 (*i)->clear_owned_changes ();
6653 if (opt == SplitIntersected) {
6657 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6659 vector<Command*> cmds;
6661 _session->add_commands (cmds);
6663 _session->add_command (new StatefulDiffCommand (*i));
6668 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6670 rtav->route ()->shift (pos, frames);
6678 XMLNode& before (_session->locations()->get_state());
6679 Locations::LocationList copy (_session->locations()->list());
6681 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6683 Locations::LocationList::const_iterator tmp;
6685 bool const was_locked = (*i)->locked ();
6686 if (locked_markers_too) {
6690 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6692 if ((*i)->start() >= pos) {
6693 (*i)->set_start ((*i)->start() + frames);
6694 if (!(*i)->is_mark()) {
6695 (*i)->set_end ((*i)->end() + frames);
6708 XMLNode& after (_session->locations()->get_state());
6709 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6714 _session->tempo_map().insert_time (pos, frames);
6718 commit_reversible_command ();
6723 Editor::fit_selected_tracks ()
6725 if (!selection->tracks.empty()) {
6726 fit_tracks (selection->tracks);
6730 /* no selected tracks - use tracks with selected regions */
6732 if (!selection->regions.empty()) {
6733 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6734 tvl.push_back (&(*r)->get_time_axis_view ());
6740 } else if (internal_editing()) {
6741 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6744 if (entered_track) {
6745 tvl.push_back (entered_track);
6753 Editor::fit_tracks (TrackViewList & tracks)
6755 if (tracks.empty()) {
6759 uint32_t child_heights = 0;
6760 int visible_tracks = 0;
6762 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6764 if (!(*t)->marked_for_display()) {
6768 child_heights += (*t)->effective_height() - (*t)->current_height();
6772 /* compute the per-track height from:
6774 total canvas visible height -
6775 height that will be taken by visible children of selected
6776 tracks - height of the ruler/hscroll area
6778 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6779 double first_y_pos = DBL_MAX;
6781 if (h < TimeAxisView::preset_height (HeightSmall)) {
6782 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6783 /* too small to be displayed */
6787 undo_visual_stack.push_back (current_visual_state (true));
6788 no_save_visual = true;
6790 /* build a list of all tracks, including children */
6793 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6795 TimeAxisView::Children c = (*i)->get_child_list ();
6796 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6797 all.push_back (j->get());
6801 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6803 bool within_selected = false;
6805 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6807 TrackViewList::iterator next;
6812 if ((*t)->marked_for_display ()) {
6813 if (tracks.contains (*t)) {
6814 (*t)->set_height (h);
6815 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6816 within_selected = true;
6817 } else if (within_selected) {
6818 hide_track_in_display (*t);
6824 set the controls_layout height now, because waiting for its size
6825 request signal handler will cause the vertical adjustment setting to fail
6828 controls_layout.property_height () = _full_canvas_height;
6829 vertical_adjustment.set_value (first_y_pos);
6831 redo_visual_stack.push_back (current_visual_state (true));
6835 Editor::save_visual_state (uint32_t n)
6837 while (visual_states.size() <= n) {
6838 visual_states.push_back (0);
6841 if (visual_states[n] != 0) {
6842 delete visual_states[n];
6845 visual_states[n] = current_visual_state (true);
6850 Editor::goto_visual_state (uint32_t n)
6852 if (visual_states.size() <= n) {
6856 if (visual_states[n] == 0) {
6860 use_visual_state (*visual_states[n]);
6864 Editor::start_visual_state_op (uint32_t n)
6866 save_visual_state (n);
6868 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6870 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6871 pup->set_text (buf);
6876 Editor::cancel_visual_state_op (uint32_t n)
6878 goto_visual_state (n);
6882 Editor::toggle_region_mute ()
6884 if (_ignore_region_action) {
6888 RegionSelection rs = get_regions_from_selection_and_entered ();
6894 if (rs.size() > 1) {
6895 begin_reversible_command (_("mute regions"));
6897 begin_reversible_command (_("mute region"));
6900 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6902 (*i)->region()->playlist()->clear_changes ();
6903 (*i)->region()->set_muted (!(*i)->region()->muted ());
6904 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6908 commit_reversible_command ();
6912 Editor::combine_regions ()
6914 /* foreach track with selected regions, take all selected regions
6915 and join them into a new region containing the subregions (as a
6919 typedef set<RouteTimeAxisView*> RTVS;
6922 if (selection->regions.empty()) {
6926 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6927 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6930 tracks.insert (rtv);
6934 begin_reversible_command (_("combine regions"));
6936 vector<RegionView*> new_selection;
6938 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6941 if ((rv = (*i)->combine_regions ()) != 0) {
6942 new_selection.push_back (rv);
6946 selection->clear_regions ();
6947 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6948 selection->add (*i);
6951 commit_reversible_command ();
6955 Editor::uncombine_regions ()
6957 typedef set<RouteTimeAxisView*> RTVS;
6960 if (selection->regions.empty()) {
6964 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6965 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6968 tracks.insert (rtv);
6972 begin_reversible_command (_("uncombine regions"));
6974 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6975 (*i)->uncombine_regions ();
6978 commit_reversible_command ();
6982 Editor::toggle_midi_input_active (bool flip_others)
6985 boost::shared_ptr<RouteList> rl (new RouteList);
6987 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6988 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6994 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6997 rl->push_back (rtav->route());
6998 onoff = !mt->input_active();
7002 _session->set_exclusive_input_active (rl, onoff, flip_others);
7009 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7011 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7012 lock_dialog->get_vbox()->pack_start (*padlock);
7014 ArdourButton* b = manage (new ArdourButton);
7015 b->set_name ("lock button");
7016 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7017 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7018 lock_dialog->get_vbox()->pack_start (*b);
7020 lock_dialog->get_vbox()->show_all ();
7021 lock_dialog->set_size_request (200, 200);
7025 /* The global menu bar continues to be accessible to applications
7026 with modal dialogs, which means that we need to desensitize
7027 all items in the menu bar. Since those items are really just
7028 proxies for actions, that means disabling all actions.
7030 ActionManager::disable_all_actions ();
7032 lock_dialog->present ();
7038 lock_dialog->hide ();
7041 ActionManager::pop_action_state ();
7044 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7045 start_lock_event_timing ();