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 bool operating_on_region_selection = !selection->regions.empty();
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 had a selected region, then we should select both sides of the new region after the split.
238 //(if there is no region selection then we are working on a range selection, so no changes to region selection are necessary)
239 if( operating_on_region_selection ) {
240 if (!latest_regionviews.empty()) {
241 selection->add (latest_regionviews);
247 /** Move one extreme of the current range selection. If more than one range is selected,
248 * the start of the earliest range or the end of the latest range is moved.
250 * @param move_end true to move the end of the current range selection, false to move
252 * @param next true to move the extreme to the next region boundary, false to move to
256 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
258 if (selection->time.start() == selection->time.end_frame()) {
262 framepos_t start = selection->time.start ();
263 framepos_t end = selection->time.end_frame ();
265 /* the position of the thing we may move */
266 framepos_t pos = move_end ? end : start;
267 int dir = next ? 1 : -1;
269 /* so we don't find the current region again */
270 if (dir > 0 || pos > 0) {
274 framepos_t const target = get_region_boundary (pos, dir, true, false);
289 begin_reversible_command (_("alter selection"));
290 selection->set_preserving_all_ranges (start, end);
291 commit_reversible_command ();
295 Editor::nudge_forward_release (GdkEventButton* ev)
297 if (ev->state & Keyboard::PrimaryModifier) {
298 nudge_forward (false, true);
300 nudge_forward (false, false);
306 Editor::nudge_backward_release (GdkEventButton* ev)
308 if (ev->state & Keyboard::PrimaryModifier) {
309 nudge_backward (false, true);
311 nudge_backward (false, false);
318 Editor::nudge_forward (bool next, bool force_playhead)
321 framepos_t next_distance;
327 RegionSelection rs = get_regions_from_selection_and_entered ();
329 if (!force_playhead && !rs.empty()) {
331 begin_reversible_command (_("nudge regions forward"));
333 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
334 boost::shared_ptr<Region> r ((*i)->region());
336 distance = get_nudge_distance (r->position(), next_distance);
339 distance = next_distance;
343 r->set_position (r->position() + distance);
344 _session->add_command (new StatefulDiffCommand (r));
347 commit_reversible_command ();
350 } else if (!force_playhead && !selection->markers.empty()) {
354 begin_reversible_command (_("nudge location forward"));
356 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
358 Location* loc = find_location_from_marker ((*i), is_start);
362 XMLNode& before (loc->get_state());
365 distance = get_nudge_distance (loc->start(), next_distance);
367 distance = next_distance;
369 if (max_framepos - distance > loc->start() + loc->length()) {
370 loc->set_start (loc->start() + distance);
372 loc->set_start (max_framepos - loc->length());
375 distance = get_nudge_distance (loc->end(), next_distance);
377 distance = next_distance;
379 if (max_framepos - distance > loc->end()) {
380 loc->set_end (loc->end() + distance);
382 loc->set_end (max_framepos);
385 XMLNode& after (loc->get_state());
386 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
390 commit_reversible_command ();
393 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
394 _session->request_locate (playhead_cursor->current_frame () + distance);
399 Editor::nudge_backward (bool next, bool force_playhead)
402 framepos_t next_distance;
408 RegionSelection rs = get_regions_from_selection_and_entered ();
410 if (!force_playhead && !rs.empty()) {
412 begin_reversible_command (_("nudge regions backward"));
414 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
415 boost::shared_ptr<Region> r ((*i)->region());
417 distance = get_nudge_distance (r->position(), next_distance);
420 distance = next_distance;
425 if (r->position() > distance) {
426 r->set_position (r->position() - distance);
430 _session->add_command (new StatefulDiffCommand (r));
433 commit_reversible_command ();
435 } else if (!force_playhead && !selection->markers.empty()) {
439 begin_reversible_command (_("nudge location forward"));
441 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
443 Location* loc = find_location_from_marker ((*i), is_start);
447 XMLNode& before (loc->get_state());
450 distance = get_nudge_distance (loc->start(), next_distance);
452 distance = next_distance;
454 if (distance < loc->start()) {
455 loc->set_start (loc->start() - distance);
460 distance = get_nudge_distance (loc->end(), next_distance);
463 distance = next_distance;
466 if (distance < loc->end() - loc->length()) {
467 loc->set_end (loc->end() - distance);
469 loc->set_end (loc->length());
473 XMLNode& after (loc->get_state());
474 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
478 commit_reversible_command ();
482 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
484 if (playhead_cursor->current_frame () > distance) {
485 _session->request_locate (playhead_cursor->current_frame () - distance);
487 _session->goto_start();
493 Editor::nudge_forward_capture_offset ()
495 RegionSelection rs = get_regions_from_selection_and_entered ();
497 if (!_session || rs.empty()) {
501 begin_reversible_command (_("nudge forward"));
503 framepos_t const distance = _session->worst_output_latency();
505 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
506 boost::shared_ptr<Region> r ((*i)->region());
509 r->set_position (r->position() + distance);
510 _session->add_command(new StatefulDiffCommand (r));
513 commit_reversible_command ();
517 Editor::nudge_backward_capture_offset ()
519 RegionSelection rs = get_regions_from_selection_and_entered ();
521 if (!_session || rs.empty()) {
525 begin_reversible_command (_("nudge backward"));
527 framepos_t const distance = _session->worst_output_latency();
529 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
530 boost::shared_ptr<Region> r ((*i)->region());
534 if (r->position() > distance) {
535 r->set_position (r->position() - distance);
539 _session->add_command(new StatefulDiffCommand (r));
542 commit_reversible_command ();
545 struct RegionSelectionPositionSorter {
546 bool operator() (RegionView* a, RegionView* b) {
547 return a->region()->position() < b->region()->position();
552 Editor::sequence_regions ()
555 framepos_t r_end_prev;
563 RegionSelection rs = get_regions_from_selection_and_entered ();
564 rs.sort(RegionSelectionPositionSorter());
568 begin_reversible_command (_("sequence regions"));
569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
570 boost::shared_ptr<Region> r ((*i)->region());
578 if(r->position_locked())
585 r->set_position(r_end_prev);
588 _session->add_command (new StatefulDiffCommand (r));
590 r_end=r->position() + r->length();
594 commit_reversible_command ();
602 Editor::move_to_start ()
604 _session->goto_start ();
608 Editor::move_to_end ()
611 _session->request_locate (_session->current_end_frame());
615 Editor::build_region_boundary_cache ()
618 vector<RegionPoint> interesting_points;
619 boost::shared_ptr<Region> r;
620 TrackViewList tracks;
623 region_boundary_cache.clear ();
629 switch (_snap_type) {
630 case SnapToRegionStart:
631 interesting_points.push_back (Start);
633 case SnapToRegionEnd:
634 interesting_points.push_back (End);
636 case SnapToRegionSync:
637 interesting_points.push_back (SyncPoint);
639 case SnapToRegionBoundary:
640 interesting_points.push_back (Start);
641 interesting_points.push_back (End);
644 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
649 TimeAxisView *ontrack = 0;
652 if (!selection->tracks.empty()) {
653 tlist = selection->tracks.filter_to_unique_playlists ();
655 tlist = track_views.filter_to_unique_playlists ();
658 while (pos < _session->current_end_frame() && !at_end) {
661 framepos_t lpos = max_framepos;
663 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
665 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
666 if (*p == interesting_points.back()) {
669 /* move to next point type */
675 rpos = r->first_frame();
679 rpos = r->last_frame();
683 rpos = r->sync_position ();
691 RouteTimeAxisView *rtav;
693 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
694 if (rtav->track() != 0) {
695 speed = rtav->track()->speed();
699 rpos = track_frame_to_session_frame (rpos, speed);
705 /* prevent duplicates, but we don't use set<> because we want to be able
709 vector<framepos_t>::iterator ri;
711 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
717 if (ri == region_boundary_cache.end()) {
718 region_boundary_cache.push_back (rpos);
725 /* finally sort to be sure that the order is correct */
727 sort (region_boundary_cache.begin(), region_boundary_cache.end());
730 boost::shared_ptr<Region>
731 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
733 TrackViewList::iterator i;
734 framepos_t closest = max_framepos;
735 boost::shared_ptr<Region> ret;
739 framepos_t track_frame;
740 RouteTimeAxisView *rtav;
742 for (i = tracks.begin(); i != tracks.end(); ++i) {
745 boost::shared_ptr<Region> r;
748 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
749 if (rtav->track()!=0)
750 track_speed = rtav->track()->speed();
753 track_frame = session_frame_to_track_frame(frame, track_speed);
755 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
761 rpos = r->first_frame ();
765 rpos = r->last_frame ();
769 rpos = r->sync_position ();
773 // rpos is a "track frame", converting it to "_session frame"
774 rpos = track_frame_to_session_frame(rpos, track_speed);
777 distance = rpos - frame;
779 distance = frame - rpos;
782 if (distance < closest) {
794 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
796 framecnt_t distance = max_framepos;
797 framepos_t current_nearest = -1;
799 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
800 framepos_t contender;
803 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
809 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
813 d = ::llabs (pos - contender);
816 current_nearest = contender;
821 return current_nearest;
825 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
830 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
832 if (!selection->tracks.empty()) {
834 target = find_next_region_boundary (pos, dir, selection->tracks);
838 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
839 get_onscreen_tracks (tvl);
840 target = find_next_region_boundary (pos, dir, tvl);
842 target = find_next_region_boundary (pos, dir, track_views);
848 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
849 get_onscreen_tracks (tvl);
850 target = find_next_region_boundary (pos, dir, tvl);
852 target = find_next_region_boundary (pos, dir, track_views);
860 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
862 framepos_t pos = playhead_cursor->current_frame ();
869 // so we don't find the current region again..
870 if (dir > 0 || pos > 0) {
874 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
878 _session->request_locate (target);
882 Editor::cursor_to_next_region_boundary (bool with_selection)
884 cursor_to_region_boundary (with_selection, 1);
888 Editor::cursor_to_previous_region_boundary (bool with_selection)
890 cursor_to_region_boundary (with_selection, -1);
894 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
896 boost::shared_ptr<Region> r;
897 framepos_t pos = cursor->current_frame ();
903 TimeAxisView *ontrack = 0;
905 // so we don't find the current region again..
909 if (!selection->tracks.empty()) {
911 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
913 } else if (clicked_axisview) {
916 t.push_back (clicked_axisview);
918 r = find_next_region (pos, point, dir, t, &ontrack);
922 r = find_next_region (pos, point, dir, track_views, &ontrack);
931 pos = r->first_frame ();
935 pos = r->last_frame ();
939 pos = r->sync_position ();
944 RouteTimeAxisView *rtav;
946 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
947 if (rtav->track() != 0) {
948 speed = rtav->track()->speed();
952 pos = track_frame_to_session_frame(pos, speed);
954 if (cursor == playhead_cursor) {
955 _session->request_locate (pos);
957 cursor->set_position (pos);
962 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
964 cursor_to_region_point (cursor, point, 1);
968 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
970 cursor_to_region_point (cursor, point, -1);
974 Editor::cursor_to_selection_start (EditorCursor *cursor)
978 switch (mouse_mode) {
980 if (!selection->regions.empty()) {
981 pos = selection->regions.start();
986 if (!selection->time.empty()) {
987 pos = selection->time.start ();
995 if (cursor == playhead_cursor) {
996 _session->request_locate (pos);
998 cursor->set_position (pos);
1003 Editor::cursor_to_selection_end (EditorCursor *cursor)
1007 switch (mouse_mode) {
1009 if (!selection->regions.empty()) {
1010 pos = selection->regions.end_frame();
1015 if (!selection->time.empty()) {
1016 pos = selection->time.end_frame ();
1024 if (cursor == playhead_cursor) {
1025 _session->request_locate (pos);
1027 cursor->set_position (pos);
1032 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1042 if (selection->markers.empty()) {
1046 if (!mouse_frame (mouse, ignored)) {
1050 add_location_mark (mouse);
1053 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1057 framepos_t pos = loc->start();
1059 // so we don't find the current region again..
1060 if (dir > 0 || pos > 0) {
1064 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1068 loc->move_to (target);
1072 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1074 selected_marker_to_region_boundary (with_selection, 1);
1078 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1080 selected_marker_to_region_boundary (with_selection, -1);
1084 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1086 boost::shared_ptr<Region> r;
1091 if (!_session || selection->markers.empty()) {
1095 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1099 TimeAxisView *ontrack = 0;
1103 // so we don't find the current region again..
1107 if (!selection->tracks.empty()) {
1109 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1113 r = find_next_region (pos, point, dir, track_views, &ontrack);
1122 pos = r->first_frame ();
1126 pos = r->last_frame ();
1130 pos = r->adjust_to_sync (r->first_frame());
1135 RouteTimeAxisView *rtav;
1137 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1138 if (rtav->track() != 0) {
1139 speed = rtav->track()->speed();
1143 pos = track_frame_to_session_frame(pos, speed);
1149 Editor::selected_marker_to_next_region_point (RegionPoint point)
1151 selected_marker_to_region_point (point, 1);
1155 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1157 selected_marker_to_region_point (point, -1);
1161 Editor::selected_marker_to_selection_start ()
1167 if (!_session || selection->markers.empty()) {
1171 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1175 switch (mouse_mode) {
1177 if (!selection->regions.empty()) {
1178 pos = selection->regions.start();
1183 if (!selection->time.empty()) {
1184 pos = selection->time.start ();
1196 Editor::selected_marker_to_selection_end ()
1202 if (!_session || selection->markers.empty()) {
1206 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1210 switch (mouse_mode) {
1212 if (!selection->regions.empty()) {
1213 pos = selection->regions.end_frame();
1218 if (!selection->time.empty()) {
1219 pos = selection->time.end_frame ();
1231 Editor::scroll_playhead (bool forward)
1233 framepos_t pos = playhead_cursor->current_frame ();
1234 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1237 if (pos == max_framepos) {
1241 if (pos < max_framepos - delta) {
1260 _session->request_locate (pos);
1264 Editor::cursor_align (bool playhead_to_edit)
1270 if (playhead_to_edit) {
1272 if (selection->markers.empty()) {
1276 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1279 /* move selected markers to playhead */
1281 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1284 Location* loc = find_location_from_marker (*i, ignored);
1286 if (loc->is_mark()) {
1287 loc->set_start (playhead_cursor->current_frame ());
1289 loc->set (playhead_cursor->current_frame (),
1290 playhead_cursor->current_frame () + loc->length());
1297 Editor::scroll_backward (float pages)
1299 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1300 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1303 if (leftmost_frame < cnt) {
1306 frame = leftmost_frame - cnt;
1309 reset_x_origin (frame);
1313 Editor::scroll_forward (float pages)
1315 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1316 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1319 if (max_framepos - cnt < leftmost_frame) {
1320 frame = max_framepos - cnt;
1322 frame = leftmost_frame + cnt;
1325 reset_x_origin (frame);
1329 Editor::scroll_tracks_down ()
1331 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1332 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1333 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1336 vertical_adjustment.set_value (vert_value);
1340 Editor::scroll_tracks_up ()
1342 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1346 Editor::scroll_tracks_down_line ()
1348 double vert_value = vertical_adjustment.get_value() + 60;
1350 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1351 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1354 vertical_adjustment.set_value (vert_value);
1358 Editor::scroll_tracks_up_line ()
1360 reset_y_origin (vertical_adjustment.get_value() - 60);
1364 Editor::scroll_down_one_track ()
1366 TrackViewList::reverse_iterator next = track_views.rend();
1367 std::pair<TimeAxisView*,double> res;
1368 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1370 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1371 if ((*t)->hidden()) {
1375 /* If this is the bottom visible trackview, we want to display
1379 res = (*t)->covers_y_position (bottom_of_trackviews);
1385 ++next; // moves "next" towards the "front" since it is a reverse iterator
1388 /* move to the track below the first one that covers the */
1390 if (next != track_views.rend()) {
1391 ensure_time_axis_view_is_visible (**next);
1399 Editor::scroll_up_one_track ()
1401 double vertical_pos = vertical_adjustment.get_value ();
1403 TrackViewList::iterator prev = track_views.end();
1404 std::pair<TimeAxisView*,double> res;
1406 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1408 if ((*t)->hidden()) {
1412 /* find the trackview at the top of the trackview group */
1413 res = (*t)->covers_y_position (vertical_pos);
1416 cerr << res.first->name() << " covers the top\n";
1423 if (prev != track_views.end()) {
1424 ensure_time_axis_view_is_visible (**prev);
1434 Editor::tav_zoom_step (bool coarser)
1436 DisplaySuspender ds;
1440 if (selection->tracks.empty()) {
1443 ts = &selection->tracks;
1446 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1447 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1448 tv->step_height (coarser);
1453 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1455 DisplaySuspender ds;
1459 if (selection->tracks.empty() || force_all) {
1462 ts = &selection->tracks;
1465 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1466 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1467 uint32_t h = tv->current_height ();
1472 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1477 tv->set_height (h + 5);
1484 Editor::temporal_zoom_step (bool coarser)
1486 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1488 framecnt_t nspp = samples_per_pixel;
1496 temporal_zoom (nspp);
1500 Editor::temporal_zoom (framecnt_t fpp)
1506 framepos_t current_page = current_page_samples();
1507 framepos_t current_leftmost = leftmost_frame;
1508 framepos_t current_rightmost;
1509 framepos_t current_center;
1510 framepos_t new_page_size;
1511 framepos_t half_page_size;
1512 framepos_t leftmost_after_zoom = 0;
1514 bool in_track_canvas;
1518 if (fpp == samples_per_pixel) {
1522 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1523 // segfaults for lack of memory. If somebody decides this is not high enough I
1524 // believe it can be raisen to higher values but some limit must be in place.
1526 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1527 // all of which is used for the editor track displays. The whole day
1528 // would be 4147200000 samples, so 2592000 samples per pixel.
1530 nfpp = min (fpp, (framecnt_t) 2592000);
1531 nfpp = max ((framecnt_t) 1, fpp);
1533 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1534 half_page_size = new_page_size / 2;
1536 switch (zoom_focus) {
1538 leftmost_after_zoom = current_leftmost;
1541 case ZoomFocusRight:
1542 current_rightmost = leftmost_frame + current_page;
1543 if (current_rightmost < new_page_size) {
1544 leftmost_after_zoom = 0;
1546 leftmost_after_zoom = current_rightmost - new_page_size;
1550 case ZoomFocusCenter:
1551 current_center = current_leftmost + (current_page/2);
1552 if (current_center < half_page_size) {
1553 leftmost_after_zoom = 0;
1555 leftmost_after_zoom = current_center - half_page_size;
1559 case ZoomFocusPlayhead:
1560 /* centre playhead */
1561 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1564 leftmost_after_zoom = 0;
1565 } else if (l > max_framepos) {
1566 leftmost_after_zoom = max_framepos - new_page_size;
1568 leftmost_after_zoom = (framepos_t) l;
1572 case ZoomFocusMouse:
1573 /* try to keep the mouse over the same point in the display */
1575 if (!mouse_frame (where, in_track_canvas)) {
1576 /* use playhead instead */
1577 where = playhead_cursor->current_frame ();
1579 if (where < half_page_size) {
1580 leftmost_after_zoom = 0;
1582 leftmost_after_zoom = where - half_page_size;
1587 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1590 leftmost_after_zoom = 0;
1591 } else if (l > max_framepos) {
1592 leftmost_after_zoom = max_framepos - new_page_size;
1594 leftmost_after_zoom = (framepos_t) l;
1601 /* try to keep the edit point in the same place */
1602 where = get_preferred_edit_position ();
1606 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1609 leftmost_after_zoom = 0;
1610 } else if (l > max_framepos) {
1611 leftmost_after_zoom = max_framepos - new_page_size;
1613 leftmost_after_zoom = (framepos_t) l;
1617 /* edit point not defined */
1624 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1626 reposition_and_zoom (leftmost_after_zoom, nfpp);
1630 Editor::temporal_zoom_region (bool both_axes)
1632 framepos_t start = max_framepos;
1634 set<TimeAxisView*> tracks;
1636 RegionSelection rs = get_regions_from_selection_and_entered ();
1642 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1644 if ((*i)->region()->position() < start) {
1645 start = (*i)->region()->position();
1648 if ((*i)->region()->last_frame() + 1 > end) {
1649 end = (*i)->region()->last_frame() + 1;
1652 tracks.insert (&((*i)->get_time_axis_view()));
1655 /* now comes an "interesting" hack ... make sure we leave a little space
1656 at each end of the editor so that the zoom doesn't fit the region
1657 precisely to the screen.
1660 GdkScreen* screen = gdk_screen_get_default ();
1661 gint pixwidth = gdk_screen_get_width (screen);
1662 gint mmwidth = gdk_screen_get_width_mm (screen);
1663 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1664 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1666 if ((start == 0 && end == 0) || end < start) {
1670 framepos_t range = end - start;
1671 double new_fpp = (double) range / (double) _visible_canvas_width;
1672 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1674 if (start > extra_samples) {
1675 start -= extra_samples;
1680 if (max_framepos - extra_samples > end) {
1681 end += extra_samples;
1686 /* if we're zooming on both axes we need to save track heights etc.
1689 undo_visual_stack.push_back (current_visual_state (both_axes));
1691 PBD::Unwinder<bool> nsv (no_save_visual, true);
1693 temporal_zoom_by_frame (start, end);
1696 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1698 /* set visible track heights appropriately */
1700 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1701 (*t)->set_height (per_track_height);
1704 /* hide irrelevant tracks */
1706 DisplaySuspender ds;
1708 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1709 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1710 hide_track_in_display (*i);
1714 vertical_adjustment.set_value (0.0);
1717 redo_visual_stack.push_back (current_visual_state (both_axes));
1721 Editor::zoom_to_region (bool both_axes)
1723 temporal_zoom_region (both_axes);
1727 Editor::temporal_zoom_selection ()
1729 if (!selection) return;
1731 if (selection->time.empty()) {
1735 framepos_t start = selection->time[clicked_selection].start;
1736 framepos_t end = selection->time[clicked_selection].end;
1738 temporal_zoom_by_frame (start, end);
1742 Editor::temporal_zoom_session ()
1744 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1747 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1748 double s = _session->current_start_frame() - l * 0.01;
1752 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1753 temporal_zoom_by_frame (framecnt_t (s), e);
1758 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1760 if (!_session) return;
1762 if ((start == 0 && end == 0) || end < start) {
1766 framepos_t range = end - start;
1768 double const new_fpp = (double) range / (double) _visible_canvas_width;
1770 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1771 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1772 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1774 if (new_leftmost > middle) {
1778 if (new_leftmost < 0) {
1782 reposition_and_zoom (new_leftmost, new_fpp);
1786 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1792 framecnt_t range_before = frame - leftmost_frame;
1796 if (samples_per_pixel <= 1) {
1799 new_spp = samples_per_pixel + (samples_per_pixel/2);
1801 range_before += range_before/2;
1803 if (samples_per_pixel >= 1) {
1804 new_spp = samples_per_pixel - (samples_per_pixel/2);
1806 /* could bail out here since we cannot zoom any finer,
1807 but leave that to the equality test below
1809 new_spp = samples_per_pixel;
1812 range_before -= range_before/2;
1815 if (new_spp == samples_per_pixel) {
1819 /* zoom focus is automatically taken as @param frame when this
1823 framepos_t new_leftmost = frame - (framepos_t)range_before;
1825 if (new_leftmost > frame) {
1829 if (new_leftmost < 0) {
1833 reposition_and_zoom (new_leftmost, new_spp);
1838 Editor::choose_new_marker_name(string &name) {
1840 if (!Config->get_name_new_markers()) {
1841 /* don't prompt user for a new name */
1845 ArdourPrompter dialog (true);
1847 dialog.set_prompt (_("New Name:"));
1849 dialog.set_title (_("New Location Marker"));
1851 dialog.set_name ("MarkNameWindow");
1852 dialog.set_size_request (250, -1);
1853 dialog.set_position (Gtk::WIN_POS_MOUSE);
1855 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1856 dialog.set_initial_text (name);
1860 switch (dialog.run ()) {
1861 case RESPONSE_ACCEPT:
1867 dialog.get_result(name);
1874 Editor::add_location_from_selection ()
1878 if (selection->time.empty()) {
1882 if (_session == 0 || clicked_axisview == 0) {
1886 framepos_t start = selection->time[clicked_selection].start;
1887 framepos_t end = selection->time[clicked_selection].end;
1889 _session->locations()->next_available_name(rangename,"selection");
1890 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1892 _session->begin_reversible_command (_("add marker"));
1893 XMLNode &before = _session->locations()->get_state();
1894 _session->locations()->add (location, true);
1895 XMLNode &after = _session->locations()->get_state();
1896 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1897 _session->commit_reversible_command ();
1901 Editor::add_location_mark (framepos_t where)
1905 select_new_marker = true;
1907 _session->locations()->next_available_name(markername,"mark");
1908 if (!choose_new_marker_name(markername)) {
1911 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1912 _session->begin_reversible_command (_("add marker"));
1913 XMLNode &before = _session->locations()->get_state();
1914 _session->locations()->add (location, true);
1915 XMLNode &after = _session->locations()->get_state();
1916 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1917 _session->commit_reversible_command ();
1921 Editor::add_location_from_playhead_cursor ()
1923 add_location_mark (_session->audible_frame());
1927 Editor::remove_location_at_playhead_cursor ()
1932 _session->begin_reversible_command (_("remove marker"));
1933 XMLNode &before = _session->locations()->get_state();
1934 bool removed = false;
1936 //find location(s) at this time
1937 Locations::LocationList locs;
1938 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1939 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1940 if ((*i)->is_mark()) {
1941 _session->locations()->remove (*i);
1948 XMLNode &after = _session->locations()->get_state();
1949 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1950 _session->commit_reversible_command ();
1955 /** Add a range marker around each selected region */
1957 Editor::add_locations_from_region ()
1959 RegionSelection rs = get_regions_from_selection_and_entered ();
1965 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1966 XMLNode &before = _session->locations()->get_state();
1968 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1970 boost::shared_ptr<Region> region = (*i)->region ();
1972 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1974 _session->locations()->add (location, true);
1977 XMLNode &after = _session->locations()->get_state();
1978 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1979 _session->commit_reversible_command ();
1982 /** Add a single range marker around all selected regions */
1984 Editor::add_location_from_region ()
1986 RegionSelection rs = get_regions_from_selection_and_entered ();
1992 _session->begin_reversible_command (_("add marker"));
1993 XMLNode &before = _session->locations()->get_state();
1997 if (rs.size() > 1) {
1998 _session->locations()->next_available_name(markername, "regions");
2000 RegionView* rv = *(rs.begin());
2001 boost::shared_ptr<Region> region = rv->region();
2002 markername = region->name();
2005 if (!choose_new_marker_name(markername)) {
2009 // single range spanning all selected
2010 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2011 _session->locations()->add (location, true);
2013 XMLNode &after = _session->locations()->get_state();
2014 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2015 _session->commit_reversible_command ();
2021 Editor::jump_forward_to_mark ()
2027 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2033 _session->request_locate (pos, _session->transport_rolling());
2037 Editor::jump_backward_to_mark ()
2043 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2049 _session->request_locate (pos, _session->transport_rolling());
2055 framepos_t const pos = _session->audible_frame ();
2058 _session->locations()->next_available_name (markername, "mark");
2060 if (!choose_new_marker_name (markername)) {
2064 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2068 Editor::clear_markers ()
2071 _session->begin_reversible_command (_("clear markers"));
2072 XMLNode &before = _session->locations()->get_state();
2073 _session->locations()->clear_markers ();
2074 XMLNode &after = _session->locations()->get_state();
2075 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2076 _session->commit_reversible_command ();
2081 Editor::clear_ranges ()
2084 _session->begin_reversible_command (_("clear ranges"));
2085 XMLNode &before = _session->locations()->get_state();
2087 Location * looploc = _session->locations()->auto_loop_location();
2088 Location * punchloc = _session->locations()->auto_punch_location();
2089 Location * sessionloc = _session->locations()->session_range_location();
2091 _session->locations()->clear_ranges ();
2093 if (looploc) _session->locations()->add (looploc);
2094 if (punchloc) _session->locations()->add (punchloc);
2095 if (sessionloc) _session->locations()->add (sessionloc);
2097 XMLNode &after = _session->locations()->get_state();
2098 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2099 _session->commit_reversible_command ();
2104 Editor::clear_locations ()
2106 _session->begin_reversible_command (_("clear locations"));
2107 XMLNode &before = _session->locations()->get_state();
2108 _session->locations()->clear ();
2109 XMLNode &after = _session->locations()->get_state();
2110 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2111 _session->commit_reversible_command ();
2112 _session->locations()->clear ();
2116 Editor::unhide_markers ()
2118 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2119 Location *l = (*i).first;
2120 if (l->is_hidden() && l->is_mark()) {
2121 l->set_hidden(false, this);
2127 Editor::unhide_ranges ()
2129 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2130 Location *l = (*i).first;
2131 if (l->is_hidden() && l->is_range_marker()) {
2132 l->set_hidden(false, this);
2137 /* INSERT/REPLACE */
2140 Editor::insert_region_list_selection (float times)
2142 RouteTimeAxisView *tv = 0;
2143 boost::shared_ptr<Playlist> playlist;
2145 if (clicked_routeview != 0) {
2146 tv = clicked_routeview;
2147 } else if (!selection->tracks.empty()) {
2148 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2151 } else if (entered_track != 0) {
2152 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2159 if ((playlist = tv->playlist()) == 0) {
2163 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2168 begin_reversible_command (_("insert region"));
2169 playlist->clear_changes ();
2170 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2171 if (Config->get_edit_mode() == Ripple)
2172 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2174 _session->add_command(new StatefulDiffCommand (playlist));
2175 commit_reversible_command ();
2178 /* BUILT-IN EFFECTS */
2181 Editor::reverse_selection ()
2186 /* GAIN ENVELOPE EDITING */
2189 Editor::edit_envelope ()
2196 Editor::transition_to_rolling (bool fwd)
2202 if (_session->config.get_external_sync()) {
2203 switch (Config->get_sync_source()) {
2207 /* transport controlled by the master */
2212 if (_session->is_auditioning()) {
2213 _session->cancel_audition ();
2217 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2221 Editor::play_from_start ()
2223 _session->request_locate (_session->current_start_frame(), true);
2227 Editor::play_from_edit_point ()
2229 _session->request_locate (get_preferred_edit_position(), true);
2233 Editor::play_from_edit_point_and_return ()
2235 framepos_t start_frame;
2236 framepos_t return_frame;
2238 start_frame = get_preferred_edit_position (true);
2240 if (_session->transport_rolling()) {
2241 _session->request_locate (start_frame, false);
2245 /* don't reset the return frame if its already set */
2247 if ((return_frame = _session->requested_return_frame()) < 0) {
2248 return_frame = _session->audible_frame();
2251 if (start_frame >= 0) {
2252 _session->request_roll_at_and_return (start_frame, return_frame);
2257 Editor::play_selection ()
2259 if (selection->time.empty()) {
2263 _session->request_play_range (&selection->time, true);
2267 Editor::get_preroll ()
2269 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2274 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2276 if ( _session->transport_rolling() || !Config->get_follow_edits() )
2279 location -= get_preroll();
2281 //don't try to locate before the beginning of time
2285 //if follow_playhead is on, keep the playhead on the screen
2286 if ( _follow_playhead )
2287 if ( location < leftmost_frame )
2288 location = leftmost_frame;
2290 _session->request_locate( location );
2294 Editor::play_with_preroll ()
2296 if (selection->time.empty()) {
2299 framepos_t preroll = get_preroll();
2301 framepos_t start = 0;
2302 if (selection->time[clicked_selection].start > preroll)
2303 start = selection->time[clicked_selection].start - preroll;
2305 framepos_t end = selection->time[clicked_selection].end + preroll;
2307 AudioRange ar (start, end, 0);
2308 list<AudioRange> lar;
2311 _session->request_play_range (&lar, true);
2316 Editor::play_location (Location& location)
2318 if (location.start() <= location.end()) {
2322 _session->request_bounded_roll (location.start(), location.end());
2326 Editor::loop_location (Location& location)
2328 if (location.start() <= location.end()) {
2334 if ((tll = transport_loop_location()) != 0) {
2335 tll->set (location.start(), location.end());
2337 // enable looping, reposition and start rolling
2338 _session->request_play_loop (true);
2339 _session->request_locate (tll->start(), true);
2344 Editor::do_layer_operation (LayerOperation op)
2346 if (selection->regions.empty ()) {
2350 bool const multiple = selection->regions.size() > 1;
2354 begin_reversible_command (_("raise regions"));
2356 begin_reversible_command (_("raise region"));
2362 begin_reversible_command (_("raise regions to top"));
2364 begin_reversible_command (_("raise region to top"));
2370 begin_reversible_command (_("lower regions"));
2372 begin_reversible_command (_("lower region"));
2378 begin_reversible_command (_("lower regions to bottom"));
2380 begin_reversible_command (_("lower region"));
2385 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2386 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2387 (*i)->clear_owned_changes ();
2390 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2391 boost::shared_ptr<Region> r = (*i)->region ();
2403 r->lower_to_bottom ();
2407 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2408 vector<Command*> cmds;
2410 _session->add_commands (cmds);
2413 commit_reversible_command ();
2417 Editor::raise_region ()
2419 do_layer_operation (Raise);
2423 Editor::raise_region_to_top ()
2425 do_layer_operation (RaiseToTop);
2429 Editor::lower_region ()
2431 do_layer_operation (Lower);
2435 Editor::lower_region_to_bottom ()
2437 do_layer_operation (LowerToBottom);
2440 /** Show the region editor for the selected regions */
2442 Editor::show_region_properties ()
2444 selection->foreach_regionview (&RegionView::show_region_editor);
2447 /** Show the midi list editor for the selected MIDI regions */
2449 Editor::show_midi_list_editor ()
2451 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2455 Editor::rename_region ()
2457 RegionSelection rs = get_regions_from_selection_and_entered ();
2463 ArdourDialog d (*this, _("Rename Region"), true, false);
2465 Label label (_("New name:"));
2468 hbox.set_spacing (6);
2469 hbox.pack_start (label, false, false);
2470 hbox.pack_start (entry, true, true);
2472 d.get_vbox()->set_border_width (12);
2473 d.get_vbox()->pack_start (hbox, false, false);
2475 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2476 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2478 d.set_size_request (300, -1);
2480 entry.set_text (rs.front()->region()->name());
2481 entry.select_region (0, -1);
2483 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2489 int const ret = d.run();
2493 if (ret != RESPONSE_OK) {
2497 std::string str = entry.get_text();
2498 strip_whitespace_edges (str);
2500 rs.front()->region()->set_name (str);
2501 _regions->redisplay ();
2506 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2508 if (_session->is_auditioning()) {
2509 _session->cancel_audition ();
2512 // note: some potential for creativity here, because region doesn't
2513 // have to belong to the playlist that Route is handling
2515 // bool was_soloed = route.soloed();
2517 route.set_solo (true, this);
2519 _session->request_bounded_roll (region->position(), region->position() + region->length());
2521 /* XXX how to unset the solo state ? */
2524 /** Start an audition of the first selected region */
2526 Editor::play_edit_range ()
2528 framepos_t start, end;
2530 if (get_edit_op_range (start, end)) {
2531 _session->request_bounded_roll (start, end);
2536 Editor::play_selected_region ()
2538 framepos_t start = max_framepos;
2541 RegionSelection rs = get_regions_from_selection_and_entered ();
2547 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2548 if ((*i)->region()->position() < start) {
2549 start = (*i)->region()->position();
2551 if ((*i)->region()->last_frame() + 1 > end) {
2552 end = (*i)->region()->last_frame() + 1;
2556 _session->request_bounded_roll (start, end);
2560 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2562 _session->audition_region (region);
2566 Editor::region_from_selection ()
2568 if (clicked_axisview == 0) {
2572 if (selection->time.empty()) {
2576 framepos_t start = selection->time[clicked_selection].start;
2577 framepos_t end = selection->time[clicked_selection].end;
2579 TrackViewList tracks = get_tracks_for_range_action ();
2581 framepos_t selection_cnt = end - start + 1;
2583 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2584 boost::shared_ptr<Region> current;
2585 boost::shared_ptr<Playlist> pl;
2586 framepos_t internal_start;
2589 if ((pl = (*i)->playlist()) == 0) {
2593 if ((current = pl->top_region_at (start)) == 0) {
2597 internal_start = start - current->position();
2598 RegionFactory::region_name (new_name, current->name(), true);
2602 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2603 plist.add (ARDOUR::Properties::length, selection_cnt);
2604 plist.add (ARDOUR::Properties::name, new_name);
2605 plist.add (ARDOUR::Properties::layer, 0);
2607 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2612 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2614 if (selection->time.empty() || selection->tracks.empty()) {
2618 framepos_t start = selection->time[clicked_selection].start;
2619 framepos_t end = selection->time[clicked_selection].end;
2621 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2622 sort_track_selection (ts);
2624 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2625 boost::shared_ptr<Region> current;
2626 boost::shared_ptr<Playlist> playlist;
2627 framepos_t internal_start;
2630 if ((playlist = (*i)->playlist()) == 0) {
2634 if ((current = playlist->top_region_at(start)) == 0) {
2638 internal_start = start - current->position();
2639 RegionFactory::region_name (new_name, current->name(), true);
2643 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2644 plist.add (ARDOUR::Properties::length, end - start + 1);
2645 plist.add (ARDOUR::Properties::name, new_name);
2647 new_regions.push_back (RegionFactory::create (current, plist));
2652 Editor::split_multichannel_region ()
2654 RegionSelection rs = get_regions_from_selection_and_entered ();
2660 vector< boost::shared_ptr<Region> > v;
2662 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2663 (*x)->region()->separate_by_channel (*_session, v);
2668 Editor::new_region_from_selection ()
2670 region_from_selection ();
2671 cancel_selection ();
2675 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2677 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2678 case Evoral::OverlapNone:
2686 * - selected tracks, or if there are none...
2687 * - tracks containing selected regions, or if there are none...
2692 Editor::get_tracks_for_range_action () const
2696 if (selection->tracks.empty()) {
2698 /* use tracks with selected regions */
2700 RegionSelection rs = selection->regions;
2702 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2703 TimeAxisView* tv = &(*i)->get_time_axis_view();
2705 if (!t.contains (tv)) {
2711 /* no regions and no tracks: use all tracks */
2717 t = selection->tracks;
2720 return t.filter_to_unique_playlists();
2724 Editor::separate_regions_between (const TimeSelection& ts)
2726 bool in_command = false;
2727 boost::shared_ptr<Playlist> playlist;
2728 RegionSelection new_selection;
2730 TrackViewList tmptracks = get_tracks_for_range_action ();
2731 sort_track_selection (tmptracks);
2733 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2735 RouteTimeAxisView* rtv;
2737 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2739 if (rtv->is_track()) {
2741 /* no edits to destructive tracks */
2743 if (rtv->track()->destructive()) {
2747 if ((playlist = rtv->playlist()) != 0) {
2749 playlist->clear_changes ();
2751 /* XXX need to consider musical time selections here at some point */
2753 double speed = rtv->track()->speed();
2756 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2758 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2759 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2761 latest_regionviews.clear ();
2763 playlist->partition ((framepos_t)((*t).start * speed),
2764 (framepos_t)((*t).end * speed), false);
2768 if (!latest_regionviews.empty()) {
2770 rtv->view()->foreach_regionview (sigc::bind (
2771 sigc::ptr_fun (add_if_covered),
2772 &(*t), &new_selection));
2775 begin_reversible_command (_("separate"));
2779 /* pick up changes to existing regions */
2781 vector<Command*> cmds;
2782 playlist->rdiff (cmds);
2783 _session->add_commands (cmds);
2785 /* pick up changes to the playlist itself (adds/removes)
2788 _session->add_command(new StatefulDiffCommand (playlist));
2797 // selection->set (new_selection);
2799 commit_reversible_command ();
2803 struct PlaylistState {
2804 boost::shared_ptr<Playlist> playlist;
2808 /** Take tracks from get_tracks_for_range_action and cut any regions
2809 * on those tracks so that the tracks are empty over the time
2813 Editor::separate_region_from_selection ()
2815 /* preferentially use *all* ranges in the time selection if we're in range mode
2816 to allow discontiguous operation, since get_edit_op_range() currently
2817 returns a single range.
2820 if (!selection->time.empty()) {
2822 separate_regions_between (selection->time);
2829 if (get_edit_op_range (start, end)) {
2831 AudioRange ar (start, end, 1);
2835 separate_regions_between (ts);
2841 Editor::separate_region_from_punch ()
2843 Location* loc = _session->locations()->auto_punch_location();
2845 separate_regions_using_location (*loc);
2850 Editor::separate_region_from_loop ()
2852 Location* loc = _session->locations()->auto_loop_location();
2854 separate_regions_using_location (*loc);
2859 Editor::separate_regions_using_location (Location& loc)
2861 if (loc.is_mark()) {
2865 AudioRange ar (loc.start(), loc.end(), 1);
2870 separate_regions_between (ts);
2873 /** Separate regions under the selected region */
2875 Editor::separate_under_selected_regions ()
2877 vector<PlaylistState> playlists;
2881 rs = get_regions_from_selection_and_entered();
2883 if (!_session || rs.empty()) {
2887 begin_reversible_command (_("separate region under"));
2889 list<boost::shared_ptr<Region> > regions_to_remove;
2891 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2892 // we can't just remove the region(s) in this loop because
2893 // this removes them from the RegionSelection, and they thus
2894 // disappear from underneath the iterator, and the ++i above
2895 // SEGVs in a puzzling fashion.
2897 // so, first iterate over the regions to be removed from rs and
2898 // add them to the regions_to_remove list, and then
2899 // iterate over the list to actually remove them.
2901 regions_to_remove.push_back ((*i)->region());
2904 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2906 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2909 // is this check necessary?
2913 vector<PlaylistState>::iterator i;
2915 //only take state if this is a new playlist.
2916 for (i = playlists.begin(); i != playlists.end(); ++i) {
2917 if ((*i).playlist == playlist) {
2922 if (i == playlists.end()) {
2924 PlaylistState before;
2925 before.playlist = playlist;
2926 before.before = &playlist->get_state();
2928 playlist->freeze ();
2929 playlists.push_back(before);
2932 //Partition on the region bounds
2933 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2935 //Re-add region that was just removed due to the partition operation
2936 playlist->add_region( (*rl), (*rl)->first_frame() );
2939 vector<PlaylistState>::iterator pl;
2941 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2942 (*pl).playlist->thaw ();
2943 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2946 commit_reversible_command ();
2950 Editor::crop_region_to_selection ()
2952 if (!selection->time.empty()) {
2954 crop_region_to (selection->time.start(), selection->time.end_frame());
2961 if (get_edit_op_range (start, end)) {
2962 crop_region_to (start, end);
2969 Editor::crop_region_to (framepos_t start, framepos_t end)
2971 vector<boost::shared_ptr<Playlist> > playlists;
2972 boost::shared_ptr<Playlist> playlist;
2975 if (selection->tracks.empty()) {
2976 ts = track_views.filter_to_unique_playlists();
2978 ts = selection->tracks.filter_to_unique_playlists ();
2981 sort_track_selection (ts);
2983 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2985 RouteTimeAxisView* rtv;
2987 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2989 boost::shared_ptr<Track> t = rtv->track();
2991 if (t != 0 && ! t->destructive()) {
2993 if ((playlist = rtv->playlist()) != 0) {
2994 playlists.push_back (playlist);
3000 if (playlists.empty()) {
3004 framepos_t the_start;
3008 begin_reversible_command (_("trim to selection"));
3010 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3012 boost::shared_ptr<Region> region;
3016 if ((region = (*i)->top_region_at(the_start)) == 0) {
3020 /* now adjust lengths to that we do the right thing
3021 if the selection extends beyond the region
3024 the_start = max (the_start, (framepos_t) region->position());
3025 if (max_framepos - the_start < region->length()) {
3026 the_end = the_start + region->length() - 1;
3028 the_end = max_framepos;
3030 the_end = min (end, the_end);
3031 cnt = the_end - the_start + 1;
3033 region->clear_changes ();
3034 region->trim_to (the_start, cnt);
3035 _session->add_command (new StatefulDiffCommand (region));
3038 commit_reversible_command ();
3042 Editor::region_fill_track ()
3044 RegionSelection rs = get_regions_from_selection_and_entered ();
3046 if (!_session || rs.empty()) {
3050 framepos_t const end = _session->current_end_frame ();
3052 begin_reversible_command (Operations::region_fill);
3054 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3056 boost::shared_ptr<Region> region ((*i)->region());
3058 boost::shared_ptr<Playlist> pl = region->playlist();
3060 if (end <= region->last_frame()) {
3064 double times = (double) (end - region->last_frame()) / (double) region->length();
3070 pl->clear_changes ();
3071 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3072 _session->add_command (new StatefulDiffCommand (pl));
3075 commit_reversible_command ();
3079 Editor::region_fill_selection ()
3081 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3085 if (selection->time.empty()) {
3089 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3094 framepos_t start = selection->time[clicked_selection].start;
3095 framepos_t end = selection->time[clicked_selection].end;
3097 boost::shared_ptr<Playlist> playlist;
3099 if (selection->tracks.empty()) {
3103 framepos_t selection_length = end - start;
3104 float times = (float)selection_length / region->length();
3106 begin_reversible_command (Operations::fill_selection);
3108 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3110 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3112 if ((playlist = (*i)->playlist()) == 0) {
3116 playlist->clear_changes ();
3117 playlist->add_region (RegionFactory::create (region, true), start, times);
3118 _session->add_command (new StatefulDiffCommand (playlist));
3121 commit_reversible_command ();
3125 Editor::set_region_sync_position ()
3127 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3131 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3133 bool in_command = false;
3135 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3137 if (!(*r)->region()->covers (where)) {
3141 boost::shared_ptr<Region> region ((*r)->region());
3144 begin_reversible_command (_("set sync point"));
3148 region->clear_changes ();
3149 region->set_sync_position (where);
3150 _session->add_command(new StatefulDiffCommand (region));
3154 commit_reversible_command ();
3158 /** Remove the sync positions of the selection */
3160 Editor::remove_region_sync ()
3162 RegionSelection rs = get_regions_from_selection_and_entered ();
3168 begin_reversible_command (_("remove region sync"));
3170 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3172 (*i)->region()->clear_changes ();
3173 (*i)->region()->clear_sync_position ();
3174 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3177 commit_reversible_command ();
3181 Editor::naturalize_region ()
3183 RegionSelection rs = get_regions_from_selection_and_entered ();
3189 if (rs.size() > 1) {
3190 begin_reversible_command (_("move regions to original position"));
3192 begin_reversible_command (_("move region to original position"));
3195 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3196 (*i)->region()->clear_changes ();
3197 (*i)->region()->move_to_natural_position ();
3198 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3201 commit_reversible_command ();
3205 Editor::align_regions (RegionPoint what)
3207 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3213 begin_reversible_command (_("align selection"));
3215 framepos_t const position = get_preferred_edit_position ();
3217 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3218 align_region_internal ((*i)->region(), what, position);
3221 commit_reversible_command ();
3224 struct RegionSortByTime {
3225 bool operator() (const RegionView* a, const RegionView* b) {
3226 return a->region()->position() < b->region()->position();
3231 Editor::align_regions_relative (RegionPoint point)
3233 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3239 framepos_t const position = get_preferred_edit_position ();
3241 framepos_t distance = 0;
3245 list<RegionView*> sorted;
3246 rs.by_position (sorted);
3248 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3253 if (position > r->position()) {
3254 distance = position - r->position();
3256 distance = r->position() - position;
3262 if (position > r->last_frame()) {
3263 distance = position - r->last_frame();
3264 pos = r->position() + distance;
3266 distance = r->last_frame() - position;
3267 pos = r->position() - distance;
3273 pos = r->adjust_to_sync (position);
3274 if (pos > r->position()) {
3275 distance = pos - r->position();
3277 distance = r->position() - pos;
3283 if (pos == r->position()) {
3287 begin_reversible_command (_("align selection (relative)"));
3289 /* move first one specially */
3291 r->clear_changes ();
3292 r->set_position (pos);
3293 _session->add_command(new StatefulDiffCommand (r));
3295 /* move rest by the same amount */
3299 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3301 boost::shared_ptr<Region> region ((*i)->region());
3303 region->clear_changes ();
3306 region->set_position (region->position() + distance);
3308 region->set_position (region->position() - distance);
3311 _session->add_command(new StatefulDiffCommand (region));
3315 commit_reversible_command ();
3319 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3321 begin_reversible_command (_("align region"));
3322 align_region_internal (region, point, position);
3323 commit_reversible_command ();
3327 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3329 region->clear_changes ();
3333 region->set_position (region->adjust_to_sync (position));
3337 if (position > region->length()) {
3338 region->set_position (position - region->length());
3343 region->set_position (position);
3347 _session->add_command(new StatefulDiffCommand (region));
3351 Editor::trim_region_front ()
3357 Editor::trim_region_back ()
3359 trim_region (false);
3363 Editor::trim_region (bool front)
3365 framepos_t where = get_preferred_edit_position();
3366 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3372 begin_reversible_command (front ? _("trim front") : _("trim back"));
3374 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3375 if (!(*i)->region()->locked()) {
3377 (*i)->region()->clear_changes ();
3380 (*i)->region()->trim_front (where);
3381 maybe_locate_with_edit_preroll ( where );
3383 (*i)->region()->trim_end (where);
3384 maybe_locate_with_edit_preroll ( where );
3387 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3391 commit_reversible_command ();
3394 /** Trim the end of the selected regions to the position of the edit cursor */
3396 Editor::trim_region_to_loop ()
3398 Location* loc = _session->locations()->auto_loop_location();
3402 trim_region_to_location (*loc, _("trim to loop"));
3406 Editor::trim_region_to_punch ()
3408 Location* loc = _session->locations()->auto_punch_location();
3412 trim_region_to_location (*loc, _("trim to punch"));
3416 Editor::trim_region_to_location (const Location& loc, const char* str)
3418 RegionSelection rs = get_regions_from_selection_and_entered ();
3420 begin_reversible_command (str);
3422 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3423 RegionView* rv = (*x);
3425 /* require region to span proposed trim */
3426 switch (rv->region()->coverage (loc.start(), loc.end())) {
3427 case Evoral::OverlapInternal:
3433 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3442 if (tav->track() != 0) {
3443 speed = tav->track()->speed();
3446 start = session_frame_to_track_frame (loc.start(), speed);
3447 end = session_frame_to_track_frame (loc.end(), speed);
3449 rv->region()->clear_changes ();
3450 rv->region()->trim_to (start, (end - start));
3451 _session->add_command(new StatefulDiffCommand (rv->region()));
3454 commit_reversible_command ();
3458 Editor::trim_region_to_previous_region_end ()
3460 return trim_to_region(false);
3464 Editor::trim_region_to_next_region_start ()
3466 return trim_to_region(true);
3470 Editor::trim_to_region(bool forward)
3472 RegionSelection rs = get_regions_from_selection_and_entered ();
3474 begin_reversible_command (_("trim to region"));
3476 boost::shared_ptr<Region> next_region;
3478 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3480 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3486 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3494 if (atav->track() != 0) {
3495 speed = atav->track()->speed();
3499 boost::shared_ptr<Region> region = arv->region();
3500 boost::shared_ptr<Playlist> playlist (region->playlist());
3502 region->clear_changes ();
3506 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3512 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3513 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3517 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3523 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3525 arv->region_changed (ARDOUR::bounds_change);
3528 _session->add_command(new StatefulDiffCommand (region));
3531 commit_reversible_command ();
3535 Editor::unfreeze_route ()
3537 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3541 clicked_routeview->track()->unfreeze ();
3545 Editor::_freeze_thread (void* arg)
3547 return static_cast<Editor*>(arg)->freeze_thread ();
3551 Editor::freeze_thread ()
3553 /* create event pool because we may need to talk to the session */
3554 SessionEvent::create_per_thread_pool ("freeze events", 64);
3555 /* create per-thread buffers for process() tree to use */
3556 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3557 current_interthread_info->done = true;
3562 Editor::freeze_route ()
3568 /* stop transport before we start. this is important */
3570 _session->request_transport_speed (0.0);
3572 /* wait for just a little while, because the above call is asynchronous */
3574 Glib::usleep (250000);
3576 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3580 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3582 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3583 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3585 d.set_title (_("Cannot freeze"));
3590 if (clicked_routeview->track()->has_external_redirects()) {
3591 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"
3592 "Freezing will only process the signal as far as the first send/insert/return."),
3593 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3595 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3596 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3597 d.set_title (_("Freeze Limits"));
3599 int response = d.run ();
3602 case Gtk::RESPONSE_CANCEL:
3609 InterThreadInfo itt;
3610 current_interthread_info = &itt;
3612 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3614 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3616 set_canvas_cursor (_cursors->wait);
3618 while (!itt.done && !itt.cancel) {
3619 gtk_main_iteration ();
3622 current_interthread_info = 0;
3623 set_canvas_cursor (current_canvas_cursor);
3627 Editor::bounce_range_selection (bool replace, bool enable_processing)
3629 if (selection->time.empty()) {
3633 TrackSelection views = selection->tracks;
3635 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3637 if (enable_processing) {
3639 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3641 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3643 _("You can't perform this operation because the processing of the signal "
3644 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3645 "You can do this without processing, which is a different operation.")
3647 d.set_title (_("Cannot bounce"));
3654 framepos_t start = selection->time[clicked_selection].start;
3655 framepos_t end = selection->time[clicked_selection].end;
3656 framepos_t cnt = end - start + 1;
3658 begin_reversible_command (_("bounce range"));
3660 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3662 RouteTimeAxisView* rtv;
3664 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3668 boost::shared_ptr<Playlist> playlist;
3670 if ((playlist = rtv->playlist()) == 0) {
3674 InterThreadInfo itt;
3676 playlist->clear_changes ();
3677 playlist->clear_owned_changes ();
3679 boost::shared_ptr<Region> r;
3681 if (enable_processing) {
3682 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3684 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3692 list<AudioRange> ranges;
3693 ranges.push_back (AudioRange (start, start+cnt, 0));
3694 playlist->cut (ranges); // discard result
3695 playlist->add_region (r, start);
3698 vector<Command*> cmds;
3699 playlist->rdiff (cmds);
3700 _session->add_commands (cmds);
3702 _session->add_command (new StatefulDiffCommand (playlist));
3705 commit_reversible_command ();
3708 /** Delete selected regions, automation points or a time range */
3715 /** Cut selected regions, automation points or a time range */
3722 /** Copy selected regions, automation points or a time range */
3730 /** @return true if a Cut, Copy or Clear is possible */
3732 Editor::can_cut_copy () const
3734 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3741 /** Cut, copy or clear selected regions, automation points or a time range.
3742 * @param op Operation (Delete, Cut, Copy or Clear)
3745 Editor::cut_copy (CutCopyOp op)
3747 /* only cancel selection if cut/copy is successful.*/
3753 opname = _("delete");
3762 opname = _("clear");
3766 /* if we're deleting something, and the mouse is still pressed,
3767 the thing we started a drag for will be gone when we release
3768 the mouse button(s). avoid this. see part 2 at the end of
3772 if (op == Delete || op == Cut || op == Clear) {
3773 if (_drags->active ()) {
3778 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3779 cut_buffer->clear ();
3781 if (entered_marker) {
3783 /* cut/delete op while pointing at a marker */
3786 Location* loc = find_location_from_marker (entered_marker, ignored);
3788 if (_session && loc) {
3789 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3796 if (internal_editing()) {
3798 switch (effective_mouse_mode()) {
3801 begin_reversible_command (opname + ' ' + X_("MIDI"));
3803 commit_reversible_command ();
3812 bool did_edit = false;
3814 if (!selection->points.empty()) {
3815 begin_reversible_command (opname + _(" points"));
3817 cut_copy_points (op);
3818 if (op == Cut || op == Delete) {
3819 selection->clear_points ();
3821 } else if (!selection->regions.empty() || !selection->points.empty()) {
3825 if (selection->regions.empty()) {
3826 thing_name = _("points");
3827 } else if (selection->points.empty()) {
3828 thing_name = _("regions");
3830 thing_name = _("objects");
3833 begin_reversible_command (opname + ' ' + thing_name);
3836 if (!selection->regions.empty()) {
3837 cut_copy_regions (op, selection->regions);
3839 if (op == Cut || op == Delete) {
3840 selection->clear_regions ();
3844 if (!selection->points.empty()) {
3845 cut_copy_points (op);
3847 if (op == Cut || op == Delete) {
3848 selection->clear_points ();
3851 } else if (selection->time.empty()) {
3852 framepos_t start, end;
3853 /* no time selection, see if we can get an edit range
3856 if (get_edit_op_range (start, end)) {
3857 selection->set (start, end);
3859 } else if (!selection->time.empty()) {
3860 begin_reversible_command (opname + _(" range"));
3863 cut_copy_ranges (op);
3865 if (op == Cut || op == Delete) {
3866 selection->clear_time ();
3871 commit_reversible_command ();
3874 if (op == Delete || op == Cut || op == Clear) {
3879 struct AutomationRecord {
3880 AutomationRecord () : state (0) {}
3881 AutomationRecord (XMLNode* s) : state (s) {}
3883 XMLNode* state; ///< state before any operation
3884 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3887 /** Cut, copy or clear selected automation points.
3888 * @param op Operation (Cut, Copy or Clear)
3891 Editor::cut_copy_points (CutCopyOp op)
3893 if (selection->points.empty ()) {
3897 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3898 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3900 /* Keep a record of the AutomationLists that we end up using in this operation */
3901 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3904 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3905 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3906 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3907 if (lists.find (al) == lists.end ()) {
3908 /* We haven't seen this list yet, so make a record for it. This includes
3909 taking a copy of its current state, in case this is needed for undo later.
3911 lists[al] = AutomationRecord (&al->get_state ());
3915 if (op == Cut || op == Copy) {
3916 /* This operation will involve putting things in the cut buffer, so create an empty
3917 ControlList for each of our source lists to put the cut buffer data in.
3919 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3920 i->second.copy = i->first->create (i->first->parameter ());
3923 /* Add all selected points to the relevant copy ControlLists */
3924 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3925 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3926 AutomationList::const_iterator j = (*i)->model ();
3927 lists[al].copy->add ((*j)->when, (*j)->value);
3930 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3931 /* Correct this copy list so that it starts at time 0 */
3932 double const start = i->second.copy->front()->when;
3933 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3934 (*j)->when -= start;
3937 /* And add it to the cut buffer */
3938 cut_buffer->add (i->second.copy);
3942 if (op == Delete || op == Cut) {
3943 /* This operation needs to remove things from the main AutomationList, so do that now */
3945 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3946 i->first->freeze ();
3949 /* Remove each selected point from its AutomationList */
3950 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3951 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3952 al->erase ((*i)->model ());
3955 /* Thaw the lists and add undo records for them */
3956 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3957 boost::shared_ptr<AutomationList> al = i->first;
3959 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3964 /** Cut, copy or clear selected automation points.
3965 * @param op Operation (Cut, Copy or Clear)
3968 Editor::cut_copy_midi (CutCopyOp op)
3970 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3971 MidiRegionView* mrv = *i;
3972 mrv->cut_copy_clear (op);
3978 struct lt_playlist {
3979 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3980 return a.playlist < b.playlist;
3984 struct PlaylistMapping {
3986 boost::shared_ptr<Playlist> pl;
3988 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3991 /** Remove `clicked_regionview' */
3993 Editor::remove_clicked_region ()
3995 if (clicked_routeview == 0 || clicked_regionview == 0) {
3999 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4001 playlist->clear_changes ();
4002 playlist->clear_owned_changes ();
4003 playlist->remove_region (clicked_regionview->region());
4004 if (Config->get_edit_mode() == Ripple)
4005 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4007 /* We might have removed regions, which alters other regions' layering_index,
4008 so we need to do a recursive diff here.
4010 vector<Command*> cmds;
4011 playlist->rdiff (cmds);
4012 _session->add_commands (cmds);
4014 _session->add_command(new StatefulDiffCommand (playlist));
4015 commit_reversible_command ();
4019 /** Remove the selected regions */
4021 Editor::remove_selected_regions ()
4023 RegionSelection rs = get_regions_from_selection_and_entered ();
4025 if (!_session || rs.empty()) {
4029 begin_reversible_command (_("remove region"));
4031 list<boost::shared_ptr<Region> > regions_to_remove;
4033 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4034 // we can't just remove the region(s) in this loop because
4035 // this removes them from the RegionSelection, and they thus
4036 // disappear from underneath the iterator, and the ++i above
4037 // SEGVs in a puzzling fashion.
4039 // so, first iterate over the regions to be removed from rs and
4040 // add them to the regions_to_remove list, and then
4041 // iterate over the list to actually remove them.
4043 regions_to_remove.push_back ((*i)->region());
4046 vector<boost::shared_ptr<Playlist> > playlists;
4048 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4050 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4053 // is this check necessary?
4057 /* get_regions_from_selection_and_entered() guarantees that
4058 the playlists involved are unique, so there is no need
4062 playlists.push_back (playlist);
4064 playlist->clear_changes ();
4065 playlist->clear_owned_changes ();
4066 playlist->freeze ();
4067 playlist->remove_region (*rl);
4068 if (Config->get_edit_mode() == Ripple)
4069 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4073 vector<boost::shared_ptr<Playlist> >::iterator pl;
4075 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4078 /* We might have removed regions, which alters other regions' layering_index,
4079 so we need to do a recursive diff here.
4081 vector<Command*> cmds;
4082 (*pl)->rdiff (cmds);
4083 _session->add_commands (cmds);
4085 _session->add_command(new StatefulDiffCommand (*pl));
4088 commit_reversible_command ();
4091 /** Cut, copy or clear selected regions.
4092 * @param op Operation (Cut, Copy or Clear)
4095 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4097 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4098 a map when we want ordered access to both elements. i think.
4101 vector<PlaylistMapping> pmap;
4103 framepos_t first_position = max_framepos;
4105 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4106 FreezeList freezelist;
4108 /* get ordering correct before we cut/copy */
4110 rs.sort_by_position_and_track ();
4112 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4114 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4116 if (op == Cut || op == Clear || op == Delete) {
4117 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4120 FreezeList::iterator fl;
4122 // only take state if this is a new playlist.
4123 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4129 if (fl == freezelist.end()) {
4130 pl->clear_changes();
4131 pl->clear_owned_changes ();
4133 freezelist.insert (pl);
4138 TimeAxisView* tv = &(*x)->get_time_axis_view();
4139 vector<PlaylistMapping>::iterator z;
4141 for (z = pmap.begin(); z != pmap.end(); ++z) {
4142 if ((*z).tv == tv) {
4147 if (z == pmap.end()) {
4148 pmap.push_back (PlaylistMapping (tv));
4152 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4154 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4157 /* region not yet associated with a playlist (e.g. unfinished
4164 TimeAxisView& tv = (*x)->get_time_axis_view();
4165 boost::shared_ptr<Playlist> npl;
4166 RegionSelection::iterator tmp;
4173 vector<PlaylistMapping>::iterator z;
4175 for (z = pmap.begin(); z != pmap.end(); ++z) {
4176 if ((*z).tv == &tv) {
4181 assert (z != pmap.end());
4184 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4192 boost::shared_ptr<Region> r = (*x)->region();
4193 boost::shared_ptr<Region> _xx;
4199 pl->remove_region (r);
4200 if (Config->get_edit_mode() == Ripple)
4201 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4205 _xx = RegionFactory::create (r);
4206 npl->add_region (_xx, r->position() - first_position);
4207 pl->remove_region (r);
4208 if (Config->get_edit_mode() == Ripple)
4209 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4213 /* copy region before adding, so we're not putting same object into two different playlists */
4214 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4218 pl->remove_region (r);
4219 if (Config->get_edit_mode() == Ripple)
4220 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4229 list<boost::shared_ptr<Playlist> > foo;
4231 /* the pmap is in the same order as the tracks in which selected regions occured */
4233 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4236 foo.push_back ((*i).pl);
4241 cut_buffer->set (foo);
4245 _last_cut_copy_source_track = 0;
4247 _last_cut_copy_source_track = pmap.front().tv;
4251 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4254 /* We might have removed regions, which alters other regions' layering_index,
4255 so we need to do a recursive diff here.
4257 vector<Command*> cmds;
4258 (*pl)->rdiff (cmds);
4259 _session->add_commands (cmds);
4261 _session->add_command (new StatefulDiffCommand (*pl));
4266 Editor::cut_copy_ranges (CutCopyOp op)
4268 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4270 /* Sort the track selection now, so that it if is used, the playlists
4271 selected by the calls below to cut_copy_clear are in the order that
4272 their tracks appear in the editor. This makes things like paste
4273 of ranges work properly.
4276 sort_track_selection (ts);
4279 if (!entered_track) {
4282 ts.push_back (entered_track);
4285 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4286 (*i)->cut_copy_clear (*selection, op);
4291 Editor::paste (float times, bool from_context)
4293 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4295 paste_internal (get_preferred_edit_position (false, from_context), times);
4299 Editor::mouse_paste ()
4304 if (!mouse_frame (where, ignored)) {
4309 paste_internal (where, 1);
4313 Editor::paste_internal (framepos_t position, float times)
4315 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4317 if (internal_editing()) {
4318 if (cut_buffer->midi_notes.empty()) {
4322 if (cut_buffer->empty()) {
4327 if (position == max_framepos) {
4328 position = get_preferred_edit_position();
4329 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4333 TrackViewList::iterator i;
4336 /* get everything in the correct order */
4338 if (_edit_point == Editing::EditAtMouse && entered_track) {
4339 /* With the mouse edit point, paste onto the track under the mouse */
4340 ts.push_back (entered_track);
4341 } else if (!selection->tracks.empty()) {
4342 /* Otherwise, if there are some selected tracks, paste to them */
4343 ts = selection->tracks.filter_to_unique_playlists ();
4344 sort_track_selection (ts);
4345 } else if (_last_cut_copy_source_track) {
4346 /* Otherwise paste to the track that the cut/copy came from;
4347 see discussion in mantis #3333.
4349 ts.push_back (_last_cut_copy_source_track);
4352 if (internal_editing ()) {
4354 /* undo/redo is handled by individual tracks/regions */
4356 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4359 RegionSelection::iterator r;
4360 MidiNoteSelection::iterator cb;
4362 get_regions_at (rs, position, ts);
4364 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4365 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4366 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4368 mrv->paste (position, times, **cb);
4376 /* we do redo (do you do voodoo?) */
4378 begin_reversible_command (Operations::paste);
4380 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4381 (*i)->paste (position, times, *cut_buffer, nth);
4384 commit_reversible_command ();
4389 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4391 boost::shared_ptr<Playlist> playlist;
4392 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4393 RegionSelection foo;
4395 framepos_t const start_frame = regions.start ();
4396 framepos_t const end_frame = regions.end_frame ();
4398 begin_reversible_command (Operations::duplicate_region);
4400 selection->clear_regions ();
4402 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4404 boost::shared_ptr<Region> r ((*i)->region());
4406 TimeAxisView& tv = (*i)->get_time_axis_view();
4407 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4408 latest_regionviews.clear ();
4409 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4411 playlist = (*i)->region()->playlist();
4412 playlist->clear_changes ();
4413 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4414 _session->add_command(new StatefulDiffCommand (playlist));
4418 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4421 commit_reversible_command ();
4424 selection->set (foo);
4429 Editor::duplicate_selection (float times)
4431 if (selection->time.empty() || selection->tracks.empty()) {
4435 boost::shared_ptr<Playlist> playlist;
4436 vector<boost::shared_ptr<Region> > new_regions;
4437 vector<boost::shared_ptr<Region> >::iterator ri;
4439 create_region_from_selection (new_regions);
4441 if (new_regions.empty()) {
4445 begin_reversible_command (_("duplicate selection"));
4447 ri = new_regions.begin();
4449 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4451 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4452 if ((playlist = (*i)->playlist()) == 0) {
4455 playlist->clear_changes ();
4456 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4457 _session->add_command (new StatefulDiffCommand (playlist));
4460 if (ri == new_regions.end()) {
4465 commit_reversible_command ();
4468 /** Reset all selected points to the relevant default value */
4470 Editor::reset_point_selection ()
4472 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4473 ARDOUR::AutomationList::iterator j = (*i)->model ();
4474 (*j)->value = (*i)->line().the_list()->default_value ();
4479 Editor::center_playhead ()
4481 float const page = _visible_canvas_width * samples_per_pixel;
4482 center_screen_internal (playhead_cursor->current_frame (), page);
4486 Editor::center_edit_point ()
4488 float const page = _visible_canvas_width * samples_per_pixel;
4489 center_screen_internal (get_preferred_edit_position(), page);
4492 /** Caller must begin and commit a reversible command */
4494 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4496 playlist->clear_changes ();
4498 _session->add_command (new StatefulDiffCommand (playlist));
4502 Editor::nudge_track (bool use_edit, bool forwards)
4504 boost::shared_ptr<Playlist> playlist;
4505 framepos_t distance;
4506 framepos_t next_distance;
4510 start = get_preferred_edit_position();
4515 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4519 if (selection->tracks.empty()) {
4523 begin_reversible_command (_("nudge track"));
4525 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4527 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4529 if ((playlist = (*i)->playlist()) == 0) {
4533 playlist->clear_changes ();
4534 playlist->clear_owned_changes ();
4536 playlist->nudge_after (start, distance, forwards);
4538 vector<Command*> cmds;
4540 playlist->rdiff (cmds);
4541 _session->add_commands (cmds);
4543 _session->add_command (new StatefulDiffCommand (playlist));
4546 commit_reversible_command ();
4550 Editor::remove_last_capture ()
4552 vector<string> choices;
4559 if (Config->get_verify_remove_last_capture()) {
4560 prompt = _("Do you really want to destroy the last capture?"
4561 "\n(This is destructive and cannot be undone)");
4563 choices.push_back (_("No, do nothing."));
4564 choices.push_back (_("Yes, destroy it."));
4566 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4568 if (prompter.run () == 1) {
4569 _session->remove_last_capture ();
4570 _regions->redisplay ();
4574 _session->remove_last_capture();
4575 _regions->redisplay ();
4580 Editor::normalize_region ()
4586 RegionSelection rs = get_regions_from_selection_and_entered ();
4592 NormalizeDialog dialog (rs.size() > 1);
4594 if (dialog.run () == RESPONSE_CANCEL) {
4598 set_canvas_cursor (_cursors->wait);
4601 /* XXX: should really only count audio regions here */
4602 int const regions = rs.size ();
4604 /* Make a list of the selected audio regions' maximum amplitudes, and also
4605 obtain the maximum amplitude of them all.
4607 list<double> max_amps;
4609 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4610 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4612 dialog.descend (1.0 / regions);
4613 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4616 /* the user cancelled the operation */
4617 set_canvas_cursor (current_canvas_cursor);
4621 max_amps.push_back (a);
4622 max_amp = max (max_amp, a);
4627 begin_reversible_command (_("normalize"));
4629 list<double>::const_iterator a = max_amps.begin ();
4631 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4632 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4637 arv->region()->clear_changes ();
4639 double const amp = dialog.normalize_individually() ? *a : max_amp;
4641 arv->audio_region()->normalize (amp, dialog.target ());
4642 _session->add_command (new StatefulDiffCommand (arv->region()));
4647 commit_reversible_command ();
4648 set_canvas_cursor (current_canvas_cursor);
4653 Editor::reset_region_scale_amplitude ()
4659 RegionSelection rs = get_regions_from_selection_and_entered ();
4665 begin_reversible_command ("reset gain");
4667 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4668 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4671 arv->region()->clear_changes ();
4672 arv->audio_region()->set_scale_amplitude (1.0f);
4673 _session->add_command (new StatefulDiffCommand (arv->region()));
4676 commit_reversible_command ();
4680 Editor::adjust_region_gain (bool up)
4682 RegionSelection rs = get_regions_from_selection_and_entered ();
4684 if (!_session || rs.empty()) {
4688 begin_reversible_command ("adjust region gain");
4690 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4691 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4696 arv->region()->clear_changes ();
4698 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4706 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4707 _session->add_command (new StatefulDiffCommand (arv->region()));
4710 commit_reversible_command ();
4715 Editor::reverse_region ()
4721 Reverse rev (*_session);
4722 apply_filter (rev, _("reverse regions"));
4726 Editor::strip_region_silence ()
4732 RegionSelection rs = get_regions_from_selection_and_entered ();
4738 std::list<RegionView*> audio_only;
4740 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4741 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4743 audio_only.push_back (arv);
4747 StripSilenceDialog d (_session, audio_only);
4748 int const r = d.run ();
4752 if (r == Gtk::RESPONSE_OK) {
4753 ARDOUR::AudioIntervalMap silences;
4754 d.silences (silences);
4755 StripSilence s (*_session, silences, d.fade_length());
4756 apply_filter (s, _("strip silence"), &d);
4761 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4763 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4764 mrv.selection_as_notelist (selected, true);
4766 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4767 v.push_back (selected);
4769 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4770 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4772 return op (mrv.midi_region()->model(), pos_beats, v);
4776 Editor::apply_midi_note_edit_op (MidiOperator& op)
4780 RegionSelection rs = get_regions_from_selection_and_entered ();
4786 begin_reversible_command (op.name ());
4788 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4789 RegionSelection::iterator tmp = r;
4792 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4795 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4798 _session->add_command (cmd);
4805 commit_reversible_command ();
4809 Editor::fork_region ()
4811 RegionSelection rs = get_regions_from_selection_and_entered ();
4817 begin_reversible_command (_("Fork Region(s)"));
4819 set_canvas_cursor (_cursors->wait);
4822 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4823 RegionSelection::iterator tmp = r;
4826 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4830 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4831 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4832 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4834 playlist->clear_changes ();
4835 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4836 _session->add_command(new StatefulDiffCommand (playlist));
4838 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4845 commit_reversible_command ();
4847 set_canvas_cursor (current_canvas_cursor);
4851 Editor::quantize_region ()
4853 int selected_midi_region_cnt = 0;
4859 RegionSelection rs = get_regions_from_selection_and_entered ();
4865 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4866 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4868 selected_midi_region_cnt++;
4872 if (selected_midi_region_cnt == 0) {
4876 QuantizeDialog* qd = new QuantizeDialog (*this);
4879 const int r = qd->run ();
4882 if (r == Gtk::RESPONSE_OK) {
4883 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4884 qd->start_grid_size(), qd->end_grid_size(),
4885 qd->strength(), qd->swing(), qd->threshold());
4887 apply_midi_note_edit_op (quant);
4892 Editor::insert_patch_change (bool from_context)
4894 RegionSelection rs = get_regions_from_selection_and_entered ();
4900 const framepos_t p = get_preferred_edit_position (false, from_context);
4902 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4903 there may be more than one, but the PatchChangeDialog can only offer
4904 one set of patch menus.
4906 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4908 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4909 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4911 if (d.run() == RESPONSE_CANCEL) {
4915 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4916 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4918 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4919 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4926 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4928 RegionSelection rs = get_regions_from_selection_and_entered ();
4934 begin_reversible_command (command);
4936 set_canvas_cursor (_cursors->wait);
4940 int const N = rs.size ();
4942 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4943 RegionSelection::iterator tmp = r;
4946 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4948 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4951 progress->descend (1.0 / N);
4954 if (arv->audio_region()->apply (filter, progress) == 0) {
4956 playlist->clear_changes ();
4957 playlist->clear_owned_changes ();
4959 if (filter.results.empty ()) {
4961 /* no regions returned; remove the old one */
4962 playlist->remove_region (arv->region ());
4966 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4968 /* first region replaces the old one */
4969 playlist->replace_region (arv->region(), *res, (*res)->position());
4973 while (res != filter.results.end()) {
4974 playlist->add_region (*res, (*res)->position());
4980 /* We might have removed regions, which alters other regions' layering_index,
4981 so we need to do a recursive diff here.
4983 vector<Command*> cmds;
4984 playlist->rdiff (cmds);
4985 _session->add_commands (cmds);
4987 _session->add_command(new StatefulDiffCommand (playlist));
4993 progress->ascend ();
5001 commit_reversible_command ();
5004 set_canvas_cursor (current_canvas_cursor);
5008 Editor::external_edit_region ()
5014 Editor::reset_region_gain_envelopes ()
5016 RegionSelection rs = get_regions_from_selection_and_entered ();
5018 if (!_session || rs.empty()) {
5022 _session->begin_reversible_command (_("reset region gain"));
5024 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5025 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5027 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5028 XMLNode& before (alist->get_state());
5030 arv->audio_region()->set_default_envelope ();
5031 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5035 _session->commit_reversible_command ();
5039 Editor::set_region_gain_visibility (RegionView* rv)
5041 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5043 arv->update_envelope_visibility();
5048 Editor::set_gain_envelope_visibility ()
5054 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5055 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5057 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5063 Editor::toggle_gain_envelope_active ()
5065 if (_ignore_region_action) {
5069 RegionSelection rs = get_regions_from_selection_and_entered ();
5071 if (!_session || rs.empty()) {
5075 _session->begin_reversible_command (_("region gain envelope active"));
5077 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5078 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5080 arv->region()->clear_changes ();
5081 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5082 _session->add_command (new StatefulDiffCommand (arv->region()));
5086 _session->commit_reversible_command ();
5090 Editor::toggle_region_lock ()
5092 if (_ignore_region_action) {
5096 RegionSelection rs = get_regions_from_selection_and_entered ();
5098 if (!_session || rs.empty()) {
5102 _session->begin_reversible_command (_("toggle region lock"));
5104 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5105 (*i)->region()->clear_changes ();
5106 (*i)->region()->set_locked (!(*i)->region()->locked());
5107 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5110 _session->commit_reversible_command ();
5114 Editor::toggle_region_video_lock ()
5116 if (_ignore_region_action) {
5120 RegionSelection rs = get_regions_from_selection_and_entered ();
5122 if (!_session || rs.empty()) {
5126 _session->begin_reversible_command (_("Toggle Video Lock"));
5128 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5129 (*i)->region()->clear_changes ();
5130 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5131 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5134 _session->commit_reversible_command ();
5138 Editor::toggle_region_lock_style ()
5140 if (_ignore_region_action) {
5144 RegionSelection rs = get_regions_from_selection_and_entered ();
5146 if (!_session || rs.empty()) {
5150 _session->begin_reversible_command (_("region lock style"));
5152 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5153 (*i)->region()->clear_changes ();
5154 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5155 (*i)->region()->set_position_lock_style (ns);
5156 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5159 _session->commit_reversible_command ();
5163 Editor::toggle_opaque_region ()
5165 if (_ignore_region_action) {
5169 RegionSelection rs = get_regions_from_selection_and_entered ();
5171 if (!_session || rs.empty()) {
5175 _session->begin_reversible_command (_("change region opacity"));
5177 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5178 (*i)->region()->clear_changes ();
5179 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5180 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5183 _session->commit_reversible_command ();
5187 Editor::toggle_record_enable ()
5189 bool new_state = false;
5191 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5192 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5195 if (!rtav->is_track())
5199 new_state = !rtav->track()->record_enabled();
5203 rtav->track()->set_record_enabled (new_state, this);
5208 Editor::toggle_solo ()
5210 bool new_state = false;
5212 boost::shared_ptr<RouteList> rl (new RouteList);
5214 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5215 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5222 new_state = !rtav->route()->soloed ();
5226 rl->push_back (rtav->route());
5229 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5233 Editor::toggle_mute ()
5235 bool new_state = false;
5237 boost::shared_ptr<RouteList> rl (new RouteList);
5239 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5240 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5247 new_state = !rtav->route()->muted();
5251 rl->push_back (rtav->route());
5254 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5258 Editor::toggle_solo_isolate ()
5263 Editor::set_fade_length (bool in)
5265 RegionSelection rs = get_regions_from_selection_and_entered ();
5271 /* we need a region to measure the offset from the start */
5273 RegionView* rv = rs.front ();
5275 framepos_t pos = get_preferred_edit_position();
5279 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5280 /* edit point is outside the relevant region */
5285 if (pos <= rv->region()->position()) {
5289 len = pos - rv->region()->position();
5290 cmd = _("set fade in length");
5292 if (pos >= rv->region()->last_frame()) {
5296 len = rv->region()->last_frame() - pos;
5297 cmd = _("set fade out length");
5300 begin_reversible_command (cmd);
5302 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5303 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5309 boost::shared_ptr<AutomationList> alist;
5311 alist = tmp->audio_region()->fade_in();
5313 alist = tmp->audio_region()->fade_out();
5316 XMLNode &before = alist->get_state();
5319 tmp->audio_region()->set_fade_in_length (len);
5320 tmp->audio_region()->set_fade_in_active (true);
5322 tmp->audio_region()->set_fade_out_length (len);
5323 tmp->audio_region()->set_fade_out_active (true);
5326 XMLNode &after = alist->get_state();
5327 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5330 commit_reversible_command ();
5334 Editor::set_fade_in_shape (FadeShape shape)
5336 RegionSelection rs = get_regions_from_selection_and_entered ();
5342 begin_reversible_command (_("set fade in shape"));
5344 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5345 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5351 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5352 XMLNode &before = alist->get_state();
5354 tmp->audio_region()->set_fade_in_shape (shape);
5356 XMLNode &after = alist->get_state();
5357 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5360 commit_reversible_command ();
5365 Editor::set_fade_out_shape (FadeShape shape)
5367 RegionSelection rs = get_regions_from_selection_and_entered ();
5373 begin_reversible_command (_("set fade out shape"));
5375 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5376 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5382 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5383 XMLNode &before = alist->get_state();
5385 tmp->audio_region()->set_fade_out_shape (shape);
5387 XMLNode &after = alist->get_state();
5388 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5391 commit_reversible_command ();
5395 Editor::set_fade_in_active (bool yn)
5397 RegionSelection rs = get_regions_from_selection_and_entered ();
5403 begin_reversible_command (_("set fade in active"));
5405 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5406 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5413 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5415 ar->clear_changes ();
5416 ar->set_fade_in_active (yn);
5417 _session->add_command (new StatefulDiffCommand (ar));
5420 commit_reversible_command ();
5424 Editor::set_fade_out_active (bool yn)
5426 RegionSelection rs = get_regions_from_selection_and_entered ();
5432 begin_reversible_command (_("set fade out active"));
5434 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5435 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5441 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5443 ar->clear_changes ();
5444 ar->set_fade_out_active (yn);
5445 _session->add_command(new StatefulDiffCommand (ar));
5448 commit_reversible_command ();
5452 Editor::toggle_region_fades (int dir)
5454 if (_ignore_region_action) {
5458 boost::shared_ptr<AudioRegion> ar;
5461 RegionSelection rs = get_regions_from_selection_and_entered ();
5467 RegionSelection::iterator i;
5468 for (i = rs.begin(); i != rs.end(); ++i) {
5469 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5471 yn = ar->fade_out_active ();
5473 yn = ar->fade_in_active ();
5479 if (i == rs.end()) {
5483 /* XXX should this undo-able? */
5485 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5486 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5489 if (dir == 1 || dir == 0) {
5490 ar->set_fade_in_active (!yn);
5493 if (dir == -1 || dir == 0) {
5494 ar->set_fade_out_active (!yn);
5500 /** Update region fade visibility after its configuration has been changed */
5502 Editor::update_region_fade_visibility ()
5504 bool _fade_visibility = _session->config.get_show_region_fades ();
5506 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5507 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5509 if (_fade_visibility) {
5510 v->audio_view()->show_all_fades ();
5512 v->audio_view()->hide_all_fades ();
5519 Editor::set_edit_point ()
5524 if (!mouse_frame (where, ignored)) {
5530 if (selection->markers.empty()) {
5532 mouse_add_new_marker (where);
5537 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5540 loc->move_to (where);
5546 Editor::set_playhead_cursor ()
5548 if (entered_marker) {
5549 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5554 if (!mouse_frame (where, ignored)) {
5561 _session->request_locate (where, _session->transport_rolling());
5565 if ( Config->get_follow_edits() )
5566 cancel_time_selection();
5570 Editor::split_region ()
5572 if ( !selection->time.empty()) {
5573 separate_regions_between (selection->time);
5577 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5579 framepos_t where = get_preferred_edit_position ();
5585 split_regions_at (where, rs);
5588 struct EditorOrderRouteSorter {
5589 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5590 return a->order_key () < b->order_key ();
5595 Editor::select_next_route()
5597 if (selection->tracks.empty()) {
5598 selection->set (track_views.front());
5602 TimeAxisView* current = selection->tracks.front();
5606 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5607 if (*i == current) {
5609 if (i != track_views.end()) {
5612 current = (*(track_views.begin()));
5613 //selection->set (*(track_views.begin()));
5618 rui = dynamic_cast<RouteUI *>(current);
5619 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5621 selection->set(current);
5623 ensure_time_axis_view_is_visible (*current);
5627 Editor::select_prev_route()
5629 if (selection->tracks.empty()) {
5630 selection->set (track_views.front());
5634 TimeAxisView* current = selection->tracks.front();
5638 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5639 if (*i == current) {
5641 if (i != track_views.rend()) {
5644 current = *(track_views.rbegin());
5649 rui = dynamic_cast<RouteUI *>(current);
5650 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5652 selection->set (current);
5654 ensure_time_axis_view_is_visible (*current);
5658 Editor::set_loop_from_selection (bool play)
5660 if (_session == 0 || selection->time.empty()) {
5664 framepos_t start = selection->time[clicked_selection].start;
5665 framepos_t end = selection->time[clicked_selection].end;
5667 set_loop_range (start, end, _("set loop range from selection"));
5670 _session->request_play_loop (true);
5671 _session->request_locate (start, true);
5676 Editor::set_loop_from_edit_range (bool play)
5678 if (_session == 0) {
5685 if (!get_edit_op_range (start, end)) {
5689 set_loop_range (start, end, _("set loop range from edit range"));
5692 _session->request_play_loop (true);
5693 _session->request_locate (start, true);
5698 Editor::set_loop_from_region (bool play)
5700 framepos_t start = max_framepos;
5703 RegionSelection rs = get_regions_from_selection_and_entered ();
5709 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5710 if ((*i)->region()->position() < start) {
5711 start = (*i)->region()->position();
5713 if ((*i)->region()->last_frame() + 1 > end) {
5714 end = (*i)->region()->last_frame() + 1;
5718 set_loop_range (start, end, _("set loop range from region"));
5721 _session->request_play_loop (true);
5722 _session->request_locate (start, true);
5727 Editor::set_punch_from_selection ()
5729 if (_session == 0 || selection->time.empty()) {
5733 framepos_t start = selection->time[clicked_selection].start;
5734 framepos_t end = selection->time[clicked_selection].end;
5736 set_punch_range (start, end, _("set punch range from selection"));
5740 Editor::set_punch_from_edit_range ()
5742 if (_session == 0) {
5749 if (!get_edit_op_range (start, end)) {
5753 set_punch_range (start, end, _("set punch range from edit range"));
5757 Editor::set_punch_from_region ()
5759 framepos_t start = max_framepos;
5762 RegionSelection rs = get_regions_from_selection_and_entered ();
5768 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5769 if ((*i)->region()->position() < start) {
5770 start = (*i)->region()->position();
5772 if ((*i)->region()->last_frame() + 1 > end) {
5773 end = (*i)->region()->last_frame() + 1;
5777 set_punch_range (start, end, _("set punch range from region"));
5781 Editor::pitch_shift_region ()
5783 RegionSelection rs = get_regions_from_selection_and_entered ();
5785 RegionSelection audio_rs;
5786 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5787 if (dynamic_cast<AudioRegionView*> (*i)) {
5788 audio_rs.push_back (*i);
5792 if (audio_rs.empty()) {
5796 pitch_shift (audio_rs, 1.2);
5800 Editor::transpose_region ()
5802 RegionSelection rs = get_regions_from_selection_and_entered ();
5804 list<MidiRegionView*> midi_region_views;
5805 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5806 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5808 midi_region_views.push_back (mrv);
5813 int const r = d.run ();
5814 if (r != RESPONSE_ACCEPT) {
5818 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5819 (*i)->midi_region()->transpose (d.semitones ());
5824 Editor::set_tempo_from_region ()
5826 RegionSelection rs = get_regions_from_selection_and_entered ();
5828 if (!_session || rs.empty()) {
5832 RegionView* rv = rs.front();
5834 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5838 Editor::use_range_as_bar ()
5840 framepos_t start, end;
5841 if (get_edit_op_range (start, end)) {
5842 define_one_bar (start, end);
5847 Editor::define_one_bar (framepos_t start, framepos_t end)
5849 framepos_t length = end - start;
5851 const Meter& m (_session->tempo_map().meter_at (start));
5853 /* length = 1 bar */
5855 /* now we want frames per beat.
5856 we have frames per bar, and beats per bar, so ...
5859 /* XXXX METER MATH */
5861 double frames_per_beat = length / m.divisions_per_bar();
5863 /* beats per minute = */
5865 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5867 /* now decide whether to:
5869 (a) set global tempo
5870 (b) add a new tempo marker
5874 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5876 bool do_global = false;
5878 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5880 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5881 at the start, or create a new marker
5884 vector<string> options;
5885 options.push_back (_("Cancel"));
5886 options.push_back (_("Add new marker"));
5887 options.push_back (_("Set global tempo"));
5890 _("Define one bar"),
5891 _("Do you want to set the global tempo or add a new tempo marker?"),
5895 c.set_default_response (2);
5911 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5912 if the marker is at the region starter, change it, otherwise add
5917 begin_reversible_command (_("set tempo from region"));
5918 XMLNode& before (_session->tempo_map().get_state());
5921 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5922 } else if (t.frame() == start) {
5923 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5925 Timecode::BBT_Time bbt;
5926 _session->tempo_map().bbt_time (start, bbt);
5927 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5930 XMLNode& after (_session->tempo_map().get_state());
5932 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5933 commit_reversible_command ();
5937 Editor::split_region_at_transients ()
5939 AnalysisFeatureList positions;
5941 RegionSelection rs = get_regions_from_selection_and_entered ();
5943 if (!_session || rs.empty()) {
5947 _session->begin_reversible_command (_("split regions"));
5949 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5951 RegionSelection::iterator tmp;
5956 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5958 if (ar && (ar->get_transients (positions) == 0)) {
5959 split_region_at_points ((*i)->region(), positions, true);
5966 _session->commit_reversible_command ();
5971 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5973 bool use_rhythmic_rodent = false;
5975 boost::shared_ptr<Playlist> pl = r->playlist();
5977 list<boost::shared_ptr<Region> > new_regions;
5983 if (positions.empty()) {
5988 if (positions.size() > 20 && can_ferret) {
5989 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);
5990 MessageDialog msg (msgstr,
5993 Gtk::BUTTONS_OK_CANCEL);
5996 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5997 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5999 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6002 msg.set_title (_("Excessive split?"));
6005 int response = msg.run();
6011 case RESPONSE_APPLY:
6012 use_rhythmic_rodent = true;
6019 if (use_rhythmic_rodent) {
6020 show_rhythm_ferret ();
6024 AnalysisFeatureList::const_iterator x;
6026 pl->clear_changes ();
6027 pl->clear_owned_changes ();
6029 x = positions.begin();
6031 if (x == positions.end()) {
6036 pl->remove_region (r);
6040 while (x != positions.end()) {
6042 /* deal with positons that are out of scope of present region bounds */
6043 if (*x <= 0 || *x > r->length()) {
6048 /* file start = original start + how far we from the initial position ?
6051 framepos_t file_start = r->start() + pos;
6053 /* length = next position - current position
6056 framepos_t len = (*x) - pos;
6058 /* XXX we do we really want to allow even single-sample regions?
6059 shouldn't we have some kind of lower limit on region size?
6068 if (RegionFactory::region_name (new_name, r->name())) {
6072 /* do NOT announce new regions 1 by one, just wait till they are all done */
6076 plist.add (ARDOUR::Properties::start, file_start);
6077 plist.add (ARDOUR::Properties::length, len);
6078 plist.add (ARDOUR::Properties::name, new_name);
6079 plist.add (ARDOUR::Properties::layer, 0);
6081 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6082 /* because we set annouce to false, manually add the new region to the
6085 RegionFactory::map_add (nr);
6087 pl->add_region (nr, r->position() + pos);
6090 new_regions.push_front(nr);
6099 RegionFactory::region_name (new_name, r->name());
6101 /* Add the final region */
6104 plist.add (ARDOUR::Properties::start, r->start() + pos);
6105 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6106 plist.add (ARDOUR::Properties::name, new_name);
6107 plist.add (ARDOUR::Properties::layer, 0);
6109 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6110 /* because we set annouce to false, manually add the new region to the
6113 RegionFactory::map_add (nr);
6114 pl->add_region (nr, r->position() + pos);
6117 new_regions.push_front(nr);
6122 /* We might have removed regions, which alters other regions' layering_index,
6123 so we need to do a recursive diff here.
6125 vector<Command*> cmds;
6127 _session->add_commands (cmds);
6129 _session->add_command (new StatefulDiffCommand (pl));
6133 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6134 set_selected_regionview_from_region_list ((*i), Selection::Add);
6140 Editor::place_transient()
6146 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6152 framepos_t where = get_preferred_edit_position();
6154 _session->begin_reversible_command (_("place transient"));
6156 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6157 framepos_t position = (*r)->region()->position();
6158 (*r)->region()->add_transient(where - position);
6161 _session->commit_reversible_command ();
6165 Editor::remove_transient(ArdourCanvas::Item* item)
6171 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6174 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6175 _arv->remove_transient (*(float*) _line->get_data ("position"));
6179 Editor::snap_regions_to_grid ()
6181 list <boost::shared_ptr<Playlist > > used_playlists;
6183 RegionSelection rs = get_regions_from_selection_and_entered ();
6185 if (!_session || rs.empty()) {
6189 _session->begin_reversible_command (_("snap regions to grid"));
6191 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6193 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6195 if (!pl->frozen()) {
6196 /* we haven't seen this playlist before */
6198 /* remember used playlists so we can thaw them later */
6199 used_playlists.push_back(pl);
6203 framepos_t start_frame = (*r)->region()->first_frame ();
6204 snap_to (start_frame);
6205 (*r)->region()->set_position (start_frame);
6208 while (used_playlists.size() > 0) {
6209 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6211 used_playlists.pop_front();
6214 _session->commit_reversible_command ();
6218 Editor::close_region_gaps ()
6220 list <boost::shared_ptr<Playlist > > used_playlists;
6222 RegionSelection rs = get_regions_from_selection_and_entered ();
6224 if (!_session || rs.empty()) {
6228 Dialog dialog (_("Close Region Gaps"));
6231 table.set_spacings (12);
6232 table.set_border_width (12);
6233 Label* l = manage (left_aligned_label (_("Crossfade length")));
6234 table.attach (*l, 0, 1, 0, 1);
6236 SpinButton spin_crossfade (1, 0);
6237 spin_crossfade.set_range (0, 15);
6238 spin_crossfade.set_increments (1, 1);
6239 spin_crossfade.set_value (5);
6240 table.attach (spin_crossfade, 1, 2, 0, 1);
6242 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6244 l = manage (left_aligned_label (_("Pull-back length")));
6245 table.attach (*l, 0, 1, 1, 2);
6247 SpinButton spin_pullback (1, 0);
6248 spin_pullback.set_range (0, 100);
6249 spin_pullback.set_increments (1, 1);
6250 spin_pullback.set_value(30);
6251 table.attach (spin_pullback, 1, 2, 1, 2);
6253 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6255 dialog.get_vbox()->pack_start (table);
6256 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6257 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6260 if (dialog.run () == RESPONSE_CANCEL) {
6264 framepos_t crossfade_len = spin_crossfade.get_value();
6265 framepos_t pull_back_frames = spin_pullback.get_value();
6267 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6268 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6270 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6272 _session->begin_reversible_command (_("close region gaps"));
6275 boost::shared_ptr<Region> last_region;
6277 rs.sort_by_position_and_track();
6279 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6281 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6283 if (!pl->frozen()) {
6284 /* we haven't seen this playlist before */
6286 /* remember used playlists so we can thaw them later */
6287 used_playlists.push_back(pl);
6291 framepos_t position = (*r)->region()->position();
6293 if (idx == 0 || position < last_region->position()){
6294 last_region = (*r)->region();
6299 (*r)->region()->trim_front( (position - pull_back_frames));
6300 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6302 last_region = (*r)->region();
6307 while (used_playlists.size() > 0) {
6308 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6310 used_playlists.pop_front();
6313 _session->commit_reversible_command ();
6317 Editor::tab_to_transient (bool forward)
6319 AnalysisFeatureList positions;
6321 RegionSelection rs = get_regions_from_selection_and_entered ();
6327 framepos_t pos = _session->audible_frame ();
6329 if (!selection->tracks.empty()) {
6331 /* don't waste time searching for transients in duplicate playlists.
6334 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6336 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6338 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6341 boost::shared_ptr<Track> tr = rtv->track();
6343 boost::shared_ptr<Playlist> pl = tr->playlist ();
6345 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6348 positions.push_back (result);
6361 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6362 (*r)->region()->get_transients (positions);
6366 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6369 AnalysisFeatureList::iterator x;
6371 for (x = positions.begin(); x != positions.end(); ++x) {
6377 if (x != positions.end ()) {
6378 _session->request_locate (*x);
6382 AnalysisFeatureList::reverse_iterator x;
6384 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6390 if (x != positions.rend ()) {
6391 _session->request_locate (*x);
6397 Editor::playhead_forward_to_grid ()
6403 framepos_t pos = playhead_cursor->current_frame ();
6404 if (pos < max_framepos - 1) {
6406 snap_to_internal (pos, 1, false);
6407 _session->request_locate (pos);
6413 Editor::playhead_backward_to_grid ()
6419 framepos_t pos = playhead_cursor->current_frame ();
6422 snap_to_internal (pos, -1, false);
6423 _session->request_locate (pos);
6428 Editor::set_track_height (Height h)
6430 TrackSelection& ts (selection->tracks);
6432 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6433 (*x)->set_height_enum (h);
6438 Editor::toggle_tracks_active ()
6440 TrackSelection& ts (selection->tracks);
6442 bool target = false;
6448 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6449 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6453 target = !rtv->_route->active();
6456 rtv->_route->set_active (target, this);
6462 Editor::remove_tracks ()
6464 TrackSelection& ts (selection->tracks);
6470 vector<string> choices;
6474 const char* trackstr;
6476 vector<boost::shared_ptr<Route> > routes;
6477 bool special_bus = false;
6479 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6480 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6484 if (rtv->is_track()) {
6489 routes.push_back (rtv->_route);
6491 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6496 if (special_bus && !Config->get_allow_special_bus_removal()) {
6497 MessageDialog msg (_("That would be bad news ...."),
6501 msg.set_secondary_text (string_compose (_(
6502 "Removing the master or monitor bus is such a bad idea\n\
6503 that %1 is not going to allow it.\n\
6505 If you really want to do this sort of thing\n\
6506 edit your ardour.rc file to set the\n\
6507 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6514 if (ntracks + nbusses == 0) {
6519 trackstr = _("tracks");
6521 trackstr = _("track");
6525 busstr = _("busses");
6532 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6533 "(You may also lose the playlists associated with the %2)\n\n"
6534 "This action cannot be undone, and the session file will be overwritten!"),
6535 ntracks, trackstr, nbusses, busstr);
6537 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6538 "(You may also lose the playlists associated with the %2)\n\n"
6539 "This action cannot be undone, and the session file will be overwritten!"),
6542 } else if (nbusses) {
6543 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6544 "This action cannot be undon, and the session file will be overwritten"),
6548 choices.push_back (_("No, do nothing."));
6549 if (ntracks + nbusses > 1) {
6550 choices.push_back (_("Yes, remove them."));
6552 choices.push_back (_("Yes, remove it."));
6557 title = string_compose (_("Remove %1"), trackstr);
6559 title = string_compose (_("Remove %1"), busstr);
6562 Choice prompter (title, prompt, choices);
6564 if (prompter.run () != 1) {
6569 Session::StateProtector sp (_session);
6570 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6571 _session->remove_route (*x);
6577 Editor::do_insert_time ()
6579 if (selection->tracks.empty()) {
6583 InsertTimeDialog d (*this);
6584 int response = d.run ();
6586 if (response != RESPONSE_OK) {
6590 if (d.distance() == 0) {
6594 InsertTimeOption opt = d.intersected_region_action ();
6597 get_preferred_edit_position(),
6603 d.move_glued_markers(),
6604 d.move_locked_markers(),
6610 Editor::insert_time (
6611 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6612 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6615 bool commit = false;
6617 if (Config->get_edit_mode() == Lock) {
6621 begin_reversible_command (_("insert time"));
6623 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6625 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6629 /* don't operate on any playlist more than once, which could
6630 * happen if "all playlists" is enabled, but there is more
6631 * than 1 track using playlists "from" a given track.
6634 set<boost::shared_ptr<Playlist> > pl;
6636 if (all_playlists) {
6637 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6639 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6640 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6645 if ((*x)->playlist ()) {
6646 pl.insert ((*x)->playlist ());
6650 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6652 (*i)->clear_changes ();
6653 (*i)->clear_owned_changes ();
6655 if (opt == SplitIntersected) {
6659 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6661 vector<Command*> cmds;
6663 _session->add_commands (cmds);
6665 _session->add_command (new StatefulDiffCommand (*i));
6670 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6672 rtav->route ()->shift (pos, frames);
6680 XMLNode& before (_session->locations()->get_state());
6681 Locations::LocationList copy (_session->locations()->list());
6683 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6685 Locations::LocationList::const_iterator tmp;
6687 bool const was_locked = (*i)->locked ();
6688 if (locked_markers_too) {
6692 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6694 if ((*i)->start() >= pos) {
6695 (*i)->set_start ((*i)->start() + frames);
6696 if (!(*i)->is_mark()) {
6697 (*i)->set_end ((*i)->end() + frames);
6710 XMLNode& after (_session->locations()->get_state());
6711 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6716 _session->tempo_map().insert_time (pos, frames);
6720 commit_reversible_command ();
6725 Editor::fit_selected_tracks ()
6727 if (!selection->tracks.empty()) {
6728 fit_tracks (selection->tracks);
6732 /* no selected tracks - use tracks with selected regions */
6734 if (!selection->regions.empty()) {
6735 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6736 tvl.push_back (&(*r)->get_time_axis_view ());
6742 } else if (internal_editing()) {
6743 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6746 if (entered_track) {
6747 tvl.push_back (entered_track);
6755 Editor::fit_tracks (TrackViewList & tracks)
6757 if (tracks.empty()) {
6761 uint32_t child_heights = 0;
6762 int visible_tracks = 0;
6764 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6766 if (!(*t)->marked_for_display()) {
6770 child_heights += (*t)->effective_height() - (*t)->current_height();
6774 /* compute the per-track height from:
6776 total canvas visible height -
6777 height that will be taken by visible children of selected
6778 tracks - height of the ruler/hscroll area
6780 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6781 double first_y_pos = DBL_MAX;
6783 if (h < TimeAxisView::preset_height (HeightSmall)) {
6784 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6785 /* too small to be displayed */
6789 undo_visual_stack.push_back (current_visual_state (true));
6790 no_save_visual = true;
6792 /* build a list of all tracks, including children */
6795 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6797 TimeAxisView::Children c = (*i)->get_child_list ();
6798 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6799 all.push_back (j->get());
6803 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6805 bool within_selected = false;
6807 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6809 TrackViewList::iterator next;
6814 if ((*t)->marked_for_display ()) {
6815 if (tracks.contains (*t)) {
6816 (*t)->set_height (h);
6817 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6818 within_selected = true;
6819 } else if (within_selected) {
6820 hide_track_in_display (*t);
6826 set the controls_layout height now, because waiting for its size
6827 request signal handler will cause the vertical adjustment setting to fail
6830 controls_layout.property_height () = _full_canvas_height;
6831 vertical_adjustment.set_value (first_y_pos);
6833 redo_visual_stack.push_back (current_visual_state (true));
6837 Editor::save_visual_state (uint32_t n)
6839 while (visual_states.size() <= n) {
6840 visual_states.push_back (0);
6843 if (visual_states[n] != 0) {
6844 delete visual_states[n];
6847 visual_states[n] = current_visual_state (true);
6852 Editor::goto_visual_state (uint32_t n)
6854 if (visual_states.size() <= n) {
6858 if (visual_states[n] == 0) {
6862 use_visual_state (*visual_states[n]);
6866 Editor::start_visual_state_op (uint32_t n)
6868 save_visual_state (n);
6870 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6872 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6873 pup->set_text (buf);
6878 Editor::cancel_visual_state_op (uint32_t n)
6880 goto_visual_state (n);
6884 Editor::toggle_region_mute ()
6886 if (_ignore_region_action) {
6890 RegionSelection rs = get_regions_from_selection_and_entered ();
6896 if (rs.size() > 1) {
6897 begin_reversible_command (_("mute regions"));
6899 begin_reversible_command (_("mute region"));
6902 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6904 (*i)->region()->playlist()->clear_changes ();
6905 (*i)->region()->set_muted (!(*i)->region()->muted ());
6906 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6910 commit_reversible_command ();
6914 Editor::combine_regions ()
6916 /* foreach track with selected regions, take all selected regions
6917 and join them into a new region containing the subregions (as a
6921 typedef set<RouteTimeAxisView*> RTVS;
6924 if (selection->regions.empty()) {
6928 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6929 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6932 tracks.insert (rtv);
6936 begin_reversible_command (_("combine regions"));
6938 vector<RegionView*> new_selection;
6940 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6943 if ((rv = (*i)->combine_regions ()) != 0) {
6944 new_selection.push_back (rv);
6948 selection->clear_regions ();
6949 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6950 selection->add (*i);
6953 commit_reversible_command ();
6957 Editor::uncombine_regions ()
6959 typedef set<RouteTimeAxisView*> RTVS;
6962 if (selection->regions.empty()) {
6966 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6967 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6970 tracks.insert (rtv);
6974 begin_reversible_command (_("uncombine regions"));
6976 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6977 (*i)->uncombine_regions ();
6980 commit_reversible_command ();
6984 Editor::toggle_midi_input_active (bool flip_others)
6987 boost::shared_ptr<RouteList> rl (new RouteList);
6989 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6990 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6996 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6999 rl->push_back (rtav->route());
7000 onoff = !mt->input_active();
7004 _session->set_exclusive_input_active (rl, onoff, flip_others);
7011 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7013 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7014 lock_dialog->get_vbox()->pack_start (*padlock);
7016 ArdourButton* b = manage (new ArdourButton);
7017 b->set_name ("lock button");
7018 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7019 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7020 lock_dialog->get_vbox()->pack_start (*b);
7022 lock_dialog->get_vbox()->show_all ();
7023 lock_dialog->set_size_request (200, 200);
7027 /* The global menu bar continues to be accessible to applications
7028 with modal dialogs, which means that we need to desensitize
7029 all items in the menu bar. Since those items are really just
7030 proxies for actions, that means disabling all actions.
7032 ActionManager::disable_all_actions ();
7034 lock_dialog->present ();
7040 lock_dialog->hide ();
7043 ActionManager::pop_action_state ();
7046 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7047 start_lock_event_timing ();