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"
60 #include "ardour_ui.h"
61 #include "audio_region_view.h"
62 #include "audio_streamview.h"
63 #include "audio_time_axis.h"
64 #include "automation_time_axis.h"
65 #include "control_point.h"
69 #include "editor_cursors.h"
70 #include "editor_drag.h"
71 #include "editor_regions.h"
72 #include "editor_routes.h"
73 #include "gtk-custom-hruler.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"
97 using namespace ARDOUR;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
102 using Gtkmm2ext::Keyboard;
104 /***********************************************************************
106 ***********************************************************************/
109 Editor::undo (uint32_t n)
111 if (_drags->active ()) {
121 Editor::redo (uint32_t n)
123 if (_drags->active ()) {
133 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
137 list <boost::shared_ptr<Playlist > > used_playlists;
139 if (regions.empty()) {
143 begin_reversible_command (_("split"));
145 // if splitting a single region, and snap-to is using
146 // region boundaries, don't pay attention to them
148 if (regions.size() == 1) {
149 switch (_snap_type) {
150 case SnapToRegionStart:
151 case SnapToRegionSync:
152 case SnapToRegionEnd:
161 EditorFreeze(); /* Emit Signal */
164 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
166 RegionSelection::iterator tmp;
168 /* XXX this test needs to be more complicated, to make sure we really
169 have something to split.
172 if (!(*a)->region()->covers (where)) {
180 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
188 /* we haven't seen this playlist before */
190 /* remember used playlists so we can thaw them later */
191 used_playlists.push_back(pl);
196 pl->clear_changes ();
197 pl->split_region ((*a)->region(), where);
198 _session->add_command (new StatefulDiffCommand (pl));
204 while (used_playlists.size() > 0) {
205 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
207 used_playlists.pop_front();
210 commit_reversible_command ();
213 EditorThaw(); /* Emit Signal */
217 /** Move one extreme of the current range selection. If more than one range is selected,
218 * the start of the earliest range or the end of the latest range is moved.
220 * @param move_end true to move the end of the current range selection, false to move
222 * @param next true to move the extreme to the next region boundary, false to move to
226 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
228 if (selection->time.start() == selection->time.end_frame()) {
232 framepos_t start = selection->time.start ();
233 framepos_t end = selection->time.end_frame ();
235 /* the position of the thing we may move */
236 framepos_t pos = move_end ? end : start;
237 int dir = next ? 1 : -1;
239 /* so we don't find the current region again */
240 if (dir > 0 || pos > 0) {
244 framepos_t const target = get_region_boundary (pos, dir, true, false);
259 begin_reversible_command (_("alter selection"));
260 selection->set_preserving_all_ranges (start, end);
261 commit_reversible_command ();
265 Editor::nudge_forward_release (GdkEventButton* ev)
267 if (ev->state & Keyboard::PrimaryModifier) {
268 nudge_forward (false, true);
270 nudge_forward (false, false);
276 Editor::nudge_backward_release (GdkEventButton* ev)
278 if (ev->state & Keyboard::PrimaryModifier) {
279 nudge_backward (false, true);
281 nudge_backward (false, false);
288 Editor::nudge_forward (bool next, bool force_playhead)
291 framepos_t next_distance;
297 RegionSelection rs = get_regions_from_selection_and_entered ();
299 if (!force_playhead && !rs.empty()) {
301 begin_reversible_command (_("nudge regions forward"));
303 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
304 boost::shared_ptr<Region> r ((*i)->region());
306 distance = get_nudge_distance (r->position(), next_distance);
309 distance = next_distance;
313 r->set_position (r->position() + distance);
314 _session->add_command (new StatefulDiffCommand (r));
317 commit_reversible_command ();
320 } else if (!force_playhead && !selection->markers.empty()) {
324 begin_reversible_command (_("nudge location forward"));
326 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
328 Location* loc = find_location_from_marker ((*i), is_start);
332 XMLNode& before (loc->get_state());
335 distance = get_nudge_distance (loc->start(), next_distance);
337 distance = next_distance;
339 if (max_framepos - distance > loc->start() + loc->length()) {
340 loc->set_start (loc->start() + distance);
342 loc->set_start (max_framepos - loc->length());
345 distance = get_nudge_distance (loc->end(), next_distance);
347 distance = next_distance;
349 if (max_framepos - distance > loc->end()) {
350 loc->set_end (loc->end() + distance);
352 loc->set_end (max_framepos);
355 XMLNode& after (loc->get_state());
356 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
360 commit_reversible_command ();
363 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
364 _session->request_locate (playhead_cursor->current_frame () + distance);
369 Editor::nudge_backward (bool next, bool force_playhead)
372 framepos_t next_distance;
378 RegionSelection rs = get_regions_from_selection_and_entered ();
380 if (!force_playhead && !rs.empty()) {
382 begin_reversible_command (_("nudge regions backward"));
384 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
385 boost::shared_ptr<Region> r ((*i)->region());
387 distance = get_nudge_distance (r->position(), next_distance);
390 distance = next_distance;
395 if (r->position() > distance) {
396 r->set_position (r->position() - distance);
400 _session->add_command (new StatefulDiffCommand (r));
403 commit_reversible_command ();
405 } else if (!force_playhead && !selection->markers.empty()) {
409 begin_reversible_command (_("nudge location forward"));
411 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
413 Location* loc = find_location_from_marker ((*i), is_start);
417 XMLNode& before (loc->get_state());
420 distance = get_nudge_distance (loc->start(), next_distance);
422 distance = next_distance;
424 if (distance < loc->start()) {
425 loc->set_start (loc->start() - distance);
430 distance = get_nudge_distance (loc->end(), next_distance);
433 distance = next_distance;
436 if (distance < loc->end() - loc->length()) {
437 loc->set_end (loc->end() - distance);
439 loc->set_end (loc->length());
443 XMLNode& after (loc->get_state());
444 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
448 commit_reversible_command ();
452 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
454 if (playhead_cursor->current_frame () > distance) {
455 _session->request_locate (playhead_cursor->current_frame () - distance);
457 _session->goto_start();
463 Editor::nudge_forward_capture_offset ()
465 RegionSelection rs = get_regions_from_selection_and_entered ();
467 if (!_session || rs.empty()) {
471 begin_reversible_command (_("nudge forward"));
473 framepos_t const distance = _session->worst_output_latency();
475 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
476 boost::shared_ptr<Region> r ((*i)->region());
479 r->set_position (r->position() + distance);
480 _session->add_command(new StatefulDiffCommand (r));
483 commit_reversible_command ();
487 Editor::nudge_backward_capture_offset ()
489 RegionSelection rs = get_regions_from_selection_and_entered ();
491 if (!_session || rs.empty()) {
495 begin_reversible_command (_("nudge backward"));
497 framepos_t const distance = _session->worst_output_latency();
499 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
500 boost::shared_ptr<Region> r ((*i)->region());
504 if (r->position() > distance) {
505 r->set_position (r->position() - distance);
509 _session->add_command(new StatefulDiffCommand (r));
512 commit_reversible_command ();
518 Editor::move_to_start ()
520 _session->goto_start ();
524 Editor::move_to_end ()
527 _session->request_locate (_session->current_end_frame());
531 Editor::build_region_boundary_cache ()
534 vector<RegionPoint> interesting_points;
535 boost::shared_ptr<Region> r;
536 TrackViewList tracks;
539 region_boundary_cache.clear ();
545 switch (_snap_type) {
546 case SnapToRegionStart:
547 interesting_points.push_back (Start);
549 case SnapToRegionEnd:
550 interesting_points.push_back (End);
552 case SnapToRegionSync:
553 interesting_points.push_back (SyncPoint);
555 case SnapToRegionBoundary:
556 interesting_points.push_back (Start);
557 interesting_points.push_back (End);
560 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
565 TimeAxisView *ontrack = 0;
568 if (!selection->tracks.empty()) {
569 tlist = selection->tracks.filter_to_unique_playlists ();
571 tlist = track_views.filter_to_unique_playlists ();
574 while (pos < _session->current_end_frame() && !at_end) {
577 framepos_t lpos = max_framepos;
579 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
581 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
582 if (*p == interesting_points.back()) {
585 /* move to next point type */
591 rpos = r->first_frame();
595 rpos = r->last_frame();
599 rpos = r->sync_position ();
607 RouteTimeAxisView *rtav;
609 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
610 if (rtav->track() != 0) {
611 speed = rtav->track()->speed();
615 rpos = track_frame_to_session_frame (rpos, speed);
621 /* prevent duplicates, but we don't use set<> because we want to be able
625 vector<framepos_t>::iterator ri;
627 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
633 if (ri == region_boundary_cache.end()) {
634 region_boundary_cache.push_back (rpos);
641 /* finally sort to be sure that the order is correct */
643 sort (region_boundary_cache.begin(), region_boundary_cache.end());
646 boost::shared_ptr<Region>
647 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
649 TrackViewList::iterator i;
650 framepos_t closest = max_framepos;
651 boost::shared_ptr<Region> ret;
655 framepos_t track_frame;
656 RouteTimeAxisView *rtav;
658 for (i = tracks.begin(); i != tracks.end(); ++i) {
661 boost::shared_ptr<Region> r;
664 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
665 if (rtav->track()!=0)
666 track_speed = rtav->track()->speed();
669 track_frame = session_frame_to_track_frame(frame, track_speed);
671 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
677 rpos = r->first_frame ();
681 rpos = r->last_frame ();
685 rpos = r->sync_position ();
689 // rpos is a "track frame", converting it to "_session frame"
690 rpos = track_frame_to_session_frame(rpos, track_speed);
693 distance = rpos - frame;
695 distance = frame - rpos;
698 if (distance < closest) {
710 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
712 framecnt_t distance = max_framepos;
713 framepos_t current_nearest = -1;
715 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
716 framepos_t contender;
719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
725 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
729 d = ::llabs (pos - contender);
732 current_nearest = contender;
737 return current_nearest;
741 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
746 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
748 if (!selection->tracks.empty()) {
750 target = find_next_region_boundary (pos, dir, selection->tracks);
754 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
755 get_onscreen_tracks (tvl);
756 target = find_next_region_boundary (pos, dir, tvl);
758 target = find_next_region_boundary (pos, dir, track_views);
764 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
765 get_onscreen_tracks (tvl);
766 target = find_next_region_boundary (pos, dir, tvl);
768 target = find_next_region_boundary (pos, dir, track_views);
776 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
778 framepos_t pos = playhead_cursor->current_frame ();
785 // so we don't find the current region again..
786 if (dir > 0 || pos > 0) {
790 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
794 _session->request_locate (target);
798 Editor::cursor_to_next_region_boundary (bool with_selection)
800 cursor_to_region_boundary (with_selection, 1);
804 Editor::cursor_to_previous_region_boundary (bool with_selection)
806 cursor_to_region_boundary (with_selection, -1);
810 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
812 boost::shared_ptr<Region> r;
813 framepos_t pos = cursor->current_frame ();
819 TimeAxisView *ontrack = 0;
821 // so we don't find the current region again..
825 if (!selection->tracks.empty()) {
827 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
829 } else if (clicked_axisview) {
832 t.push_back (clicked_axisview);
834 r = find_next_region (pos, point, dir, t, &ontrack);
838 r = find_next_region (pos, point, dir, track_views, &ontrack);
847 pos = r->first_frame ();
851 pos = r->last_frame ();
855 pos = r->sync_position ();
860 RouteTimeAxisView *rtav;
862 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
863 if (rtav->track() != 0) {
864 speed = rtav->track()->speed();
868 pos = track_frame_to_session_frame(pos, speed);
870 if (cursor == playhead_cursor) {
871 _session->request_locate (pos);
873 cursor->set_position (pos);
878 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
880 cursor_to_region_point (cursor, point, 1);
884 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
886 cursor_to_region_point (cursor, point, -1);
890 Editor::cursor_to_selection_start (EditorCursor *cursor)
894 switch (mouse_mode) {
896 if (!selection->regions.empty()) {
897 pos = selection->regions.start();
902 if (!selection->time.empty()) {
903 pos = selection->time.start ();
911 if (cursor == playhead_cursor) {
912 _session->request_locate (pos);
914 cursor->set_position (pos);
919 Editor::cursor_to_selection_end (EditorCursor *cursor)
923 switch (mouse_mode) {
925 if (!selection->regions.empty()) {
926 pos = selection->regions.end_frame();
931 if (!selection->time.empty()) {
932 pos = selection->time.end_frame ();
940 if (cursor == playhead_cursor) {
941 _session->request_locate (pos);
943 cursor->set_position (pos);
948 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
958 if (selection->markers.empty()) {
962 if (!mouse_frame (mouse, ignored)) {
966 add_location_mark (mouse);
969 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
973 framepos_t pos = loc->start();
975 // so we don't find the current region again..
976 if (dir > 0 || pos > 0) {
980 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
984 loc->move_to (target);
988 Editor::selected_marker_to_next_region_boundary (bool with_selection)
990 selected_marker_to_region_boundary (with_selection, 1);
994 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
996 selected_marker_to_region_boundary (with_selection, -1);
1000 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1002 boost::shared_ptr<Region> r;
1007 if (!_session || selection->markers.empty()) {
1011 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1015 TimeAxisView *ontrack = 0;
1019 // so we don't find the current region again..
1023 if (!selection->tracks.empty()) {
1025 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1029 r = find_next_region (pos, point, dir, track_views, &ontrack);
1038 pos = r->first_frame ();
1042 pos = r->last_frame ();
1046 pos = r->adjust_to_sync (r->first_frame());
1051 RouteTimeAxisView *rtav;
1053 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1054 if (rtav->track() != 0) {
1055 speed = rtav->track()->speed();
1059 pos = track_frame_to_session_frame(pos, speed);
1065 Editor::selected_marker_to_next_region_point (RegionPoint point)
1067 selected_marker_to_region_point (point, 1);
1071 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1073 selected_marker_to_region_point (point, -1);
1077 Editor::selected_marker_to_selection_start ()
1083 if (!_session || selection->markers.empty()) {
1087 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1091 switch (mouse_mode) {
1093 if (!selection->regions.empty()) {
1094 pos = selection->regions.start();
1099 if (!selection->time.empty()) {
1100 pos = selection->time.start ();
1112 Editor::selected_marker_to_selection_end ()
1118 if (!_session || selection->markers.empty()) {
1122 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1126 switch (mouse_mode) {
1128 if (!selection->regions.empty()) {
1129 pos = selection->regions.end_frame();
1134 if (!selection->time.empty()) {
1135 pos = selection->time.end_frame ();
1147 Editor::scroll_playhead (bool forward)
1149 framepos_t pos = playhead_cursor->current_frame ();
1150 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1153 if (pos == max_framepos) {
1157 if (pos < max_framepos - delta) {
1176 _session->request_locate (pos);
1180 Editor::cursor_align (bool playhead_to_edit)
1186 if (playhead_to_edit) {
1188 if (selection->markers.empty()) {
1192 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1195 /* move selected markers to playhead */
1197 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1200 Location* loc = find_location_from_marker (*i, ignored);
1202 if (loc->is_mark()) {
1203 loc->set_start (playhead_cursor->current_frame ());
1205 loc->set (playhead_cursor->current_frame (),
1206 playhead_cursor->current_frame () + loc->length());
1213 Editor::scroll_backward (float pages)
1215 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1216 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1219 if (leftmost_frame < cnt) {
1222 frame = leftmost_frame - cnt;
1225 reset_x_origin (frame);
1229 Editor::scroll_forward (float pages)
1231 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1232 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1235 if (max_framepos - cnt < leftmost_frame) {
1236 frame = max_framepos - cnt;
1238 frame = leftmost_frame + cnt;
1241 reset_x_origin (frame);
1245 Editor::scroll_tracks_down ()
1247 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1248 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1249 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1252 vertical_adjustment.set_value (vert_value);
1256 Editor::scroll_tracks_up ()
1258 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1262 Editor::scroll_tracks_down_line ()
1264 double vert_value = vertical_adjustment.get_value() + 60;
1266 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1267 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1270 vertical_adjustment.set_value (vert_value);
1274 Editor::scroll_tracks_up_line ()
1276 reset_y_origin (vertical_adjustment.get_value() - 60);
1280 Editor::scroll_down_one_track ()
1282 double vertical_pos = vertical_adjustment.get_value () + vertical_adjustment.get_page_size() - 1.0;
1284 TrackViewList::reverse_iterator next = track_views.rend();
1285 std::pair<TimeAxisView*,double> res;
1287 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1288 if ((*t)->hidden()) {
1292 res = (*t)->covers_y_position (vertical_pos);
1301 /* move to the track below the first one that covers the */
1303 if (next != track_views.rend()) {
1304 ensure_track_visible (*next);
1312 Editor::scroll_up_one_track ()
1314 double vertical_pos = vertical_adjustment.get_value ();
1316 TrackViewList::iterator prev = track_views.end();
1317 std::pair<TimeAxisView*,double> res;
1319 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1321 if ((*t)->hidden()) {
1325 res = (*t)->covers_y_position(vertical_pos);
1334 if (prev != track_views.end()) {
1335 ensure_track_visible (*prev);
1345 Editor::tav_zoom_step (bool coarser)
1347 _routes->suspend_redisplay ();
1351 if (selection->tracks.empty()) {
1354 ts = &selection->tracks;
1357 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1358 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1359 tv->step_height (coarser);
1362 _routes->resume_redisplay ();
1366 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1368 _routes->suspend_redisplay ();
1372 if (selection->tracks.empty() || force_all) {
1375 ts = &selection->tracks;
1378 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1379 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1380 uint32_t h = tv->current_height ();
1385 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1390 tv->set_height (h + 5);
1394 _routes->resume_redisplay ();
1398 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1400 bool clamped = false;
1407 if (max_framepos / fpp < 800) {
1408 fpp = max_framepos / 800;
1416 Editor::temporal_zoom_step (bool coarser)
1418 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1420 framecnt_t nspp = samples_per_pixel;
1428 temporal_zoom (nspp);
1432 Editor::temporal_zoom (framecnt_t fpp)
1438 framepos_t current_page = current_page_samples();
1439 framepos_t current_leftmost = leftmost_frame;
1440 framepos_t current_rightmost;
1441 framepos_t current_center;
1442 framepos_t new_page_size;
1443 framepos_t half_page_size;
1444 framepos_t leftmost_after_zoom = 0;
1446 bool in_track_canvas;
1450 clamp_samples_per_pixel (fpp);
1451 if (fpp == samples_per_pixel) {
1455 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1456 // segfaults for lack of memory. If somebody decides this is not high enough I
1457 // believe it can be raisen to higher values but some limit must be in place.
1459 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1460 // all of which is used for the editor track displays. The whole day
1461 // would be 4147200000 samples, so 2592000 samples per pixel.
1463 nfpp = min (fpp, (framecnt_t) 2592000);
1464 nfpp = max ((framecnt_t) 1, fpp);
1466 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1467 half_page_size = new_page_size / 2;
1469 switch (zoom_focus) {
1471 leftmost_after_zoom = current_leftmost;
1474 case ZoomFocusRight:
1475 current_rightmost = leftmost_frame + current_page;
1476 if (current_rightmost < new_page_size) {
1477 leftmost_after_zoom = 0;
1479 leftmost_after_zoom = current_rightmost - new_page_size;
1483 case ZoomFocusCenter:
1484 current_center = current_leftmost + (current_page/2);
1485 if (current_center < half_page_size) {
1486 leftmost_after_zoom = 0;
1488 leftmost_after_zoom = current_center - half_page_size;
1492 case ZoomFocusPlayhead:
1493 /* centre playhead */
1494 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1497 leftmost_after_zoom = 0;
1498 } else if (l > max_framepos) {
1499 leftmost_after_zoom = max_framepos - new_page_size;
1501 leftmost_after_zoom = (framepos_t) l;
1505 case ZoomFocusMouse:
1506 /* try to keep the mouse over the same point in the display */
1508 if (!mouse_frame (where, in_track_canvas)) {
1509 /* use playhead instead */
1510 where = playhead_cursor->current_frame ();
1512 if (where < half_page_size) {
1513 leftmost_after_zoom = 0;
1515 leftmost_after_zoom = where - half_page_size;
1520 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1523 leftmost_after_zoom = 0;
1524 } else if (l > max_framepos) {
1525 leftmost_after_zoom = max_framepos - new_page_size;
1527 leftmost_after_zoom = (framepos_t) l;
1534 /* try to keep the edit point in the same place */
1535 where = get_preferred_edit_position ();
1539 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1542 leftmost_after_zoom = 0;
1543 } else if (l > max_framepos) {
1544 leftmost_after_zoom = max_framepos - new_page_size;
1546 leftmost_after_zoom = (framepos_t) l;
1550 /* edit point not defined */
1557 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1559 reposition_and_zoom (leftmost_after_zoom, nfpp);
1563 Editor::temporal_zoom_region (bool both_axes)
1565 framepos_t start = max_framepos;
1567 set<TimeAxisView*> tracks;
1569 RegionSelection rs = get_regions_from_selection_and_entered ();
1575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1577 if ((*i)->region()->position() < start) {
1578 start = (*i)->region()->position();
1581 if ((*i)->region()->last_frame() + 1 > end) {
1582 end = (*i)->region()->last_frame() + 1;
1585 tracks.insert (&((*i)->get_time_axis_view()));
1588 /* now comes an "interesting" hack ... make sure we leave a little space
1589 at each end of the editor so that the zoom doesn't fit the region
1590 precisely to the screen.
1593 GdkScreen* screen = gdk_screen_get_default ();
1594 gint pixwidth = gdk_screen_get_width (screen);
1595 gint mmwidth = gdk_screen_get_width_mm (screen);
1596 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1597 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1599 if ((start == 0 && end == 0) || end < start) {
1603 framepos_t range = end - start;
1604 double new_fpp = (double) range / (double) _visible_canvas_width;
1605 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1607 if (start > extra_samples) {
1608 start -= extra_samples;
1613 if (max_framepos - extra_samples > end) {
1614 end += extra_samples;
1619 /* if we're zooming on both axes we need to save track heights etc.
1622 undo_visual_stack.push_back (current_visual_state (both_axes));
1624 PBD::Unwinder<bool> nsv (no_save_visual, true);
1626 temporal_zoom_by_frame (start, end);
1629 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1631 /* set visible track heights appropriately */
1633 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1634 (*t)->set_height (per_track_height);
1637 /* hide irrelevant tracks */
1639 _routes->suspend_redisplay ();
1641 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1642 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1643 hide_track_in_display (*i);
1647 _routes->resume_redisplay ();
1649 vertical_adjustment.set_value (0.0);
1652 redo_visual_stack.push_back (current_visual_state (both_axes));
1656 Editor::zoom_to_region (bool both_axes)
1658 temporal_zoom_region (both_axes);
1662 Editor::temporal_zoom_selection ()
1664 if (!selection) return;
1666 if (selection->time.empty()) {
1670 framepos_t start = selection->time[clicked_selection].start;
1671 framepos_t end = selection->time[clicked_selection].end;
1673 temporal_zoom_by_frame (start, end);
1677 Editor::temporal_zoom_session ()
1679 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1682 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1683 double s = _session->current_start_frame() - l * 0.01;
1687 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1688 temporal_zoom_by_frame (framecnt_t (s), e);
1693 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1695 if (!_session) return;
1697 if ((start == 0 && end == 0) || end < start) {
1701 framepos_t range = end - start;
1703 double const new_fpp = (double) range / (double) _visible_canvas_width;
1705 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1706 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1707 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1709 if (new_leftmost > middle) {
1713 if (new_leftmost < 0) {
1717 reposition_and_zoom (new_leftmost, new_fpp);
1721 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1726 double range_before = frame - leftmost_frame;
1729 new_fpp = samples_per_pixel;
1732 new_fpp *= 1.61803399;
1733 range_before *= 1.61803399;
1735 new_fpp = max(1.0,(new_fpp/1.61803399));
1736 range_before /= 1.61803399;
1739 if (new_fpp == samples_per_pixel) {
1743 framepos_t new_leftmost = frame - (framepos_t)range_before;
1745 if (new_leftmost > frame) {
1749 if (new_leftmost < 0) {
1753 reposition_and_zoom (new_leftmost, new_fpp);
1758 Editor::choose_new_marker_name(string &name) {
1760 if (!Config->get_name_new_markers()) {
1761 /* don't prompt user for a new name */
1765 ArdourPrompter dialog (true);
1767 dialog.set_prompt (_("New Name:"));
1769 dialog.set_title (_("New Location Marker"));
1771 dialog.set_name ("MarkNameWindow");
1772 dialog.set_size_request (250, -1);
1773 dialog.set_position (Gtk::WIN_POS_MOUSE);
1775 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1776 dialog.set_initial_text (name);
1780 switch (dialog.run ()) {
1781 case RESPONSE_ACCEPT:
1787 dialog.get_result(name);
1794 Editor::add_location_from_selection ()
1798 if (selection->time.empty()) {
1802 if (_session == 0 || clicked_axisview == 0) {
1806 framepos_t start = selection->time[clicked_selection].start;
1807 framepos_t end = selection->time[clicked_selection].end;
1809 _session->locations()->next_available_name(rangename,"selection");
1810 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1812 _session->begin_reversible_command (_("add marker"));
1813 XMLNode &before = _session->locations()->get_state();
1814 _session->locations()->add (location, true);
1815 XMLNode &after = _session->locations()->get_state();
1816 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1817 _session->commit_reversible_command ();
1821 Editor::add_location_mark (framepos_t where)
1825 select_new_marker = true;
1827 _session->locations()->next_available_name(markername,"mark");
1828 if (!choose_new_marker_name(markername)) {
1831 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1832 _session->begin_reversible_command (_("add marker"));
1833 XMLNode &before = _session->locations()->get_state();
1834 _session->locations()->add (location, true);
1835 XMLNode &after = _session->locations()->get_state();
1836 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1837 _session->commit_reversible_command ();
1841 Editor::add_location_from_playhead_cursor ()
1843 add_location_mark (_session->audible_frame());
1846 /** Add a range marker around each selected region */
1848 Editor::add_locations_from_region ()
1850 RegionSelection rs = get_regions_from_selection_and_entered ();
1856 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1857 XMLNode &before = _session->locations()->get_state();
1859 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1861 boost::shared_ptr<Region> region = (*i)->region ();
1863 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1865 _session->locations()->add (location, true);
1868 XMLNode &after = _session->locations()->get_state();
1869 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1870 _session->commit_reversible_command ();
1873 /** Add a single range marker around all selected regions */
1875 Editor::add_location_from_region ()
1877 RegionSelection rs = get_regions_from_selection_and_entered ();
1883 _session->begin_reversible_command (_("add marker"));
1884 XMLNode &before = _session->locations()->get_state();
1888 if (rs.size() > 1) {
1889 _session->locations()->next_available_name(markername, "regions");
1891 RegionView* rv = *(rs.begin());
1892 boost::shared_ptr<Region> region = rv->region();
1893 markername = region->name();
1896 if (!choose_new_marker_name(markername)) {
1900 // single range spanning all selected
1901 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1902 _session->locations()->add (location, true);
1904 XMLNode &after = _session->locations()->get_state();
1905 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1906 _session->commit_reversible_command ();
1912 Editor::jump_forward_to_mark ()
1918 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1924 _session->request_locate (pos, _session->transport_rolling());
1928 Editor::jump_backward_to_mark ()
1934 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1940 _session->request_locate (pos, _session->transport_rolling());
1946 framepos_t const pos = _session->audible_frame ();
1949 _session->locations()->next_available_name (markername, "mark");
1951 if (!choose_new_marker_name (markername)) {
1955 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1959 Editor::clear_markers ()
1962 _session->begin_reversible_command (_("clear markers"));
1963 XMLNode &before = _session->locations()->get_state();
1964 _session->locations()->clear_markers ();
1965 XMLNode &after = _session->locations()->get_state();
1966 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1967 _session->commit_reversible_command ();
1972 Editor::clear_ranges ()
1975 _session->begin_reversible_command (_("clear ranges"));
1976 XMLNode &before = _session->locations()->get_state();
1978 Location * looploc = _session->locations()->auto_loop_location();
1979 Location * punchloc = _session->locations()->auto_punch_location();
1980 Location * sessionloc = _session->locations()->session_range_location();
1982 _session->locations()->clear_ranges ();
1984 if (looploc) _session->locations()->add (looploc);
1985 if (punchloc) _session->locations()->add (punchloc);
1986 if (sessionloc) _session->locations()->add (sessionloc);
1988 XMLNode &after = _session->locations()->get_state();
1989 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1990 _session->commit_reversible_command ();
1995 Editor::clear_locations ()
1997 _session->begin_reversible_command (_("clear locations"));
1998 XMLNode &before = _session->locations()->get_state();
1999 _session->locations()->clear ();
2000 XMLNode &after = _session->locations()->get_state();
2001 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2002 _session->commit_reversible_command ();
2003 _session->locations()->clear ();
2007 Editor::unhide_markers ()
2009 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2010 Location *l = (*i).first;
2011 if (l->is_hidden() && l->is_mark()) {
2012 l->set_hidden(false, this);
2018 Editor::unhide_ranges ()
2020 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2021 Location *l = (*i).first;
2022 if (l->is_hidden() && l->is_range_marker()) {
2023 l->set_hidden(false, this);
2028 /* INSERT/REPLACE */
2031 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
2035 RouteTimeAxisView *rtv = 0;
2036 boost::shared_ptr<Playlist> playlist;
2039 event.type = GDK_BUTTON_RELEASE;
2043 where = window_event_sample (&event, &cx, &cy);
2045 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
2046 /* clearly outside canvas area */
2050 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
2051 if (tv.first == 0) {
2055 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2059 if ((playlist = rtv->playlist()) == 0) {
2065 begin_reversible_command (_("insert dragged region"));
2066 playlist->clear_changes ();
2067 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2068 _session->add_command(new StatefulDiffCommand (playlist));
2069 commit_reversible_command ();
2073 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2076 RouteTimeAxisView *dest_rtv = 0;
2077 RouteTimeAxisView *source_rtv = 0;
2080 event.type = GDK_BUTTON_RELEASE;
2084 window_event_sample (&event, &cx, &cy);
2086 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2087 if (tv.first == 0) {
2091 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2095 /* use this drag source to add underlay to a track. But we really don't care
2096 about the Route, only the view of the route, so find it first */
2097 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2098 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2102 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2103 dest_rtv->add_underlay(source_rtv->view());
2110 Editor::insert_region_list_selection (float times)
2112 RouteTimeAxisView *tv = 0;
2113 boost::shared_ptr<Playlist> playlist;
2115 if (clicked_routeview != 0) {
2116 tv = clicked_routeview;
2117 } else if (!selection->tracks.empty()) {
2118 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2121 } else if (entered_track != 0) {
2122 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2129 if ((playlist = tv->playlist()) == 0) {
2133 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2138 begin_reversible_command (_("insert region"));
2139 playlist->clear_changes ();
2140 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2141 _session->add_command(new StatefulDiffCommand (playlist));
2142 commit_reversible_command ();
2145 /* BUILT-IN EFFECTS */
2148 Editor::reverse_selection ()
2153 /* GAIN ENVELOPE EDITING */
2156 Editor::edit_envelope ()
2163 Editor::transition_to_rolling (bool fwd)
2169 if (_session->config.get_external_sync()) {
2170 switch (Config->get_sync_source()) {
2174 /* transport controlled by the master */
2179 if (_session->is_auditioning()) {
2180 _session->cancel_audition ();
2184 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2188 Editor::play_from_start ()
2190 _session->request_locate (_session->current_start_frame(), true);
2194 Editor::play_from_edit_point ()
2196 _session->request_locate (get_preferred_edit_position(), true);
2200 Editor::play_from_edit_point_and_return ()
2202 framepos_t start_frame;
2203 framepos_t return_frame;
2205 start_frame = get_preferred_edit_position (true);
2207 if (_session->transport_rolling()) {
2208 _session->request_locate (start_frame, false);
2212 /* don't reset the return frame if its already set */
2214 if ((return_frame = _session->requested_return_frame()) < 0) {
2215 return_frame = _session->audible_frame();
2218 if (start_frame >= 0) {
2219 _session->request_roll_at_and_return (start_frame, return_frame);
2224 Editor::play_selection ()
2226 if (selection->time.empty()) {
2230 _session->request_play_range (&selection->time, true);
2234 Editor::get_preroll ()
2236 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2241 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2243 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2246 location -= get_preroll();
2248 //don't try to locate before the beginning of time
2252 //if follow_playhead is on, keep the playhead on the screen
2253 if ( _follow_playhead )
2254 if ( location < leftmost_frame )
2255 location = leftmost_frame;
2257 _session->request_locate( location );
2261 Editor::play_with_preroll ()
2263 if (selection->time.empty()) {
2266 framepos_t preroll = get_preroll();
2268 framepos_t start = 0;
2269 if (selection->time[clicked_selection].start > preroll)
2270 start = selection->time[clicked_selection].start - preroll;
2272 framepos_t end = selection->time[clicked_selection].end + preroll;
2274 AudioRange ar (start, end, 0);
2275 list<AudioRange> lar;
2278 _session->request_play_range (&lar, true);
2283 Editor::play_location (Location& location)
2285 if (location.start() <= location.end()) {
2289 _session->request_bounded_roll (location.start(), location.end());
2293 Editor::loop_location (Location& location)
2295 if (location.start() <= location.end()) {
2301 if ((tll = transport_loop_location()) != 0) {
2302 tll->set (location.start(), location.end());
2304 // enable looping, reposition and start rolling
2305 _session->request_play_loop (true);
2306 _session->request_locate (tll->start(), true);
2311 Editor::do_layer_operation (LayerOperation op)
2313 if (selection->regions.empty ()) {
2317 bool const multiple = selection->regions.size() > 1;
2321 begin_reversible_command (_("raise regions"));
2323 begin_reversible_command (_("raise region"));
2329 begin_reversible_command (_("raise regions to top"));
2331 begin_reversible_command (_("raise region to top"));
2337 begin_reversible_command (_("lower regions"));
2339 begin_reversible_command (_("lower region"));
2345 begin_reversible_command (_("lower regions to bottom"));
2347 begin_reversible_command (_("lower region"));
2352 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2353 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2354 (*i)->clear_owned_changes ();
2357 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2358 boost::shared_ptr<Region> r = (*i)->region ();
2370 r->lower_to_bottom ();
2374 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2375 vector<Command*> cmds;
2377 _session->add_commands (cmds);
2380 commit_reversible_command ();
2384 Editor::raise_region ()
2386 do_layer_operation (Raise);
2390 Editor::raise_region_to_top ()
2392 do_layer_operation (RaiseToTop);
2396 Editor::lower_region ()
2398 do_layer_operation (Lower);
2402 Editor::lower_region_to_bottom ()
2404 do_layer_operation (LowerToBottom);
2407 /** Show the region editor for the selected regions */
2409 Editor::show_region_properties ()
2411 selection->foreach_regionview (&RegionView::show_region_editor);
2414 /** Show the midi list editor for the selected MIDI regions */
2416 Editor::show_midi_list_editor ()
2418 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2422 Editor::rename_region ()
2424 RegionSelection rs = get_regions_from_selection_and_entered ();
2430 ArdourDialog d (*this, _("Rename Region"), true, false);
2432 Label label (_("New name:"));
2435 hbox.set_spacing (6);
2436 hbox.pack_start (label, false, false);
2437 hbox.pack_start (entry, true, true);
2439 d.get_vbox()->set_border_width (12);
2440 d.get_vbox()->pack_start (hbox, false, false);
2442 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2443 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2445 d.set_size_request (300, -1);
2447 entry.set_text (rs.front()->region()->name());
2448 entry.select_region (0, -1);
2450 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2456 int const ret = d.run();
2460 if (ret != RESPONSE_OK) {
2464 std::string str = entry.get_text();
2465 strip_whitespace_edges (str);
2467 rs.front()->region()->set_name (str);
2468 _regions->redisplay ();
2473 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2475 if (_session->is_auditioning()) {
2476 _session->cancel_audition ();
2479 // note: some potential for creativity here, because region doesn't
2480 // have to belong to the playlist that Route is handling
2482 // bool was_soloed = route.soloed();
2484 route.set_solo (true, this);
2486 _session->request_bounded_roll (region->position(), region->position() + region->length());
2488 /* XXX how to unset the solo state ? */
2491 /** Start an audition of the first selected region */
2493 Editor::play_edit_range ()
2495 framepos_t start, end;
2497 if (get_edit_op_range (start, end)) {
2498 _session->request_bounded_roll (start, end);
2503 Editor::play_selected_region ()
2505 framepos_t start = max_framepos;
2508 RegionSelection rs = get_regions_from_selection_and_entered ();
2514 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2515 if ((*i)->region()->position() < start) {
2516 start = (*i)->region()->position();
2518 if ((*i)->region()->last_frame() + 1 > end) {
2519 end = (*i)->region()->last_frame() + 1;
2523 _session->request_bounded_roll (start, end);
2527 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2529 _session->audition_region (region);
2533 Editor::region_from_selection ()
2535 if (clicked_axisview == 0) {
2539 if (selection->time.empty()) {
2543 framepos_t start = selection->time[clicked_selection].start;
2544 framepos_t end = selection->time[clicked_selection].end;
2546 TrackViewList tracks = get_tracks_for_range_action ();
2548 framepos_t selection_cnt = end - start + 1;
2550 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2551 boost::shared_ptr<Region> current;
2552 boost::shared_ptr<Playlist> pl;
2553 framepos_t internal_start;
2556 if ((pl = (*i)->playlist()) == 0) {
2560 if ((current = pl->top_region_at (start)) == 0) {
2564 internal_start = start - current->position();
2565 RegionFactory::region_name (new_name, current->name(), true);
2569 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2570 plist.add (ARDOUR::Properties::length, selection_cnt);
2571 plist.add (ARDOUR::Properties::name, new_name);
2572 plist.add (ARDOUR::Properties::layer, 0);
2574 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2579 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2581 if (selection->time.empty() || selection->tracks.empty()) {
2585 framepos_t start = selection->time[clicked_selection].start;
2586 framepos_t end = selection->time[clicked_selection].end;
2588 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2589 sort_track_selection (ts);
2591 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2592 boost::shared_ptr<Region> current;
2593 boost::shared_ptr<Playlist> playlist;
2594 framepos_t internal_start;
2597 if ((playlist = (*i)->playlist()) == 0) {
2601 if ((current = playlist->top_region_at(start)) == 0) {
2605 internal_start = start - current->position();
2606 RegionFactory::region_name (new_name, current->name(), true);
2610 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2611 plist.add (ARDOUR::Properties::length, end - start + 1);
2612 plist.add (ARDOUR::Properties::name, new_name);
2614 new_regions.push_back (RegionFactory::create (current, plist));
2619 Editor::split_multichannel_region ()
2621 RegionSelection rs = get_regions_from_selection_and_entered ();
2627 vector< boost::shared_ptr<Region> > v;
2629 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2630 (*x)->region()->separate_by_channel (*_session, v);
2635 Editor::new_region_from_selection ()
2637 region_from_selection ();
2638 cancel_selection ();
2642 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2644 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2645 case Evoral::OverlapNone:
2653 * - selected tracks, or if there are none...
2654 * - tracks containing selected regions, or if there are none...
2659 Editor::get_tracks_for_range_action () const
2663 if (selection->tracks.empty()) {
2665 /* use tracks with selected regions */
2667 RegionSelection rs = selection->regions;
2669 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2670 TimeAxisView* tv = &(*i)->get_time_axis_view();
2672 if (!t.contains (tv)) {
2678 /* no regions and no tracks: use all tracks */
2684 t = selection->tracks;
2687 return t.filter_to_unique_playlists();
2691 Editor::separate_regions_between (const TimeSelection& ts)
2693 bool in_command = false;
2694 boost::shared_ptr<Playlist> playlist;
2695 RegionSelection new_selection;
2697 TrackViewList tmptracks = get_tracks_for_range_action ();
2698 sort_track_selection (tmptracks);
2700 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2702 RouteTimeAxisView* rtv;
2704 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2706 if (rtv->is_track()) {
2708 /* no edits to destructive tracks */
2710 if (rtv->track()->destructive()) {
2714 if ((playlist = rtv->playlist()) != 0) {
2716 playlist->clear_changes ();
2718 /* XXX need to consider musical time selections here at some point */
2720 double speed = rtv->track()->speed();
2723 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2725 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2726 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2728 latest_regionviews.clear ();
2730 playlist->partition ((framepos_t)((*t).start * speed),
2731 (framepos_t)((*t).end * speed), false);
2735 if (!latest_regionviews.empty()) {
2737 rtv->view()->foreach_regionview (sigc::bind (
2738 sigc::ptr_fun (add_if_covered),
2739 &(*t), &new_selection));
2742 begin_reversible_command (_("separate"));
2746 /* pick up changes to existing regions */
2748 vector<Command*> cmds;
2749 playlist->rdiff (cmds);
2750 _session->add_commands (cmds);
2752 /* pick up changes to the playlist itself (adds/removes)
2755 _session->add_command(new StatefulDiffCommand (playlist));
2764 selection->set (new_selection);
2765 set_mouse_mode (MouseObject);
2767 commit_reversible_command ();
2771 struct PlaylistState {
2772 boost::shared_ptr<Playlist> playlist;
2776 /** Take tracks from get_tracks_for_range_action and cut any regions
2777 * on those tracks so that the tracks are empty over the time
2781 Editor::separate_region_from_selection ()
2783 /* preferentially use *all* ranges in the time selection if we're in range mode
2784 to allow discontiguous operation, since get_edit_op_range() currently
2785 returns a single range.
2788 if (!selection->time.empty()) {
2790 separate_regions_between (selection->time);
2797 if (get_edit_op_range (start, end)) {
2799 AudioRange ar (start, end, 1);
2803 separate_regions_between (ts);
2809 Editor::separate_region_from_punch ()
2811 Location* loc = _session->locations()->auto_punch_location();
2813 separate_regions_using_location (*loc);
2818 Editor::separate_region_from_loop ()
2820 Location* loc = _session->locations()->auto_loop_location();
2822 separate_regions_using_location (*loc);
2827 Editor::separate_regions_using_location (Location& loc)
2829 if (loc.is_mark()) {
2833 AudioRange ar (loc.start(), loc.end(), 1);
2838 separate_regions_between (ts);
2841 /** Separate regions under the selected region */
2843 Editor::separate_under_selected_regions ()
2845 vector<PlaylistState> playlists;
2849 rs = get_regions_from_selection_and_entered();
2851 if (!_session || rs.empty()) {
2855 begin_reversible_command (_("separate region under"));
2857 list<boost::shared_ptr<Region> > regions_to_remove;
2859 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2860 // we can't just remove the region(s) in this loop because
2861 // this removes them from the RegionSelection, and they thus
2862 // disappear from underneath the iterator, and the ++i above
2863 // SEGVs in a puzzling fashion.
2865 // so, first iterate over the regions to be removed from rs and
2866 // add them to the regions_to_remove list, and then
2867 // iterate over the list to actually remove them.
2869 regions_to_remove.push_back ((*i)->region());
2872 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2874 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2877 // is this check necessary?
2881 vector<PlaylistState>::iterator i;
2883 //only take state if this is a new playlist.
2884 for (i = playlists.begin(); i != playlists.end(); ++i) {
2885 if ((*i).playlist == playlist) {
2890 if (i == playlists.end()) {
2892 PlaylistState before;
2893 before.playlist = playlist;
2894 before.before = &playlist->get_state();
2896 playlist->freeze ();
2897 playlists.push_back(before);
2900 //Partition on the region bounds
2901 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2903 //Re-add region that was just removed due to the partition operation
2904 playlist->add_region( (*rl), (*rl)->first_frame() );
2907 vector<PlaylistState>::iterator pl;
2909 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2910 (*pl).playlist->thaw ();
2911 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2914 commit_reversible_command ();
2918 Editor::crop_region_to_selection ()
2920 if (!selection->time.empty()) {
2922 crop_region_to (selection->time.start(), selection->time.end_frame());
2929 if (get_edit_op_range (start, end)) {
2930 crop_region_to (start, end);
2937 Editor::crop_region_to (framepos_t start, framepos_t end)
2939 vector<boost::shared_ptr<Playlist> > playlists;
2940 boost::shared_ptr<Playlist> playlist;
2943 if (selection->tracks.empty()) {
2944 ts = track_views.filter_to_unique_playlists();
2946 ts = selection->tracks.filter_to_unique_playlists ();
2949 sort_track_selection (ts);
2951 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2953 RouteTimeAxisView* rtv;
2955 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2957 boost::shared_ptr<Track> t = rtv->track();
2959 if (t != 0 && ! t->destructive()) {
2961 if ((playlist = rtv->playlist()) != 0) {
2962 playlists.push_back (playlist);
2968 if (playlists.empty()) {
2972 framepos_t the_start;
2976 begin_reversible_command (_("trim to selection"));
2978 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2980 boost::shared_ptr<Region> region;
2984 if ((region = (*i)->top_region_at(the_start)) == 0) {
2988 /* now adjust lengths to that we do the right thing
2989 if the selection extends beyond the region
2992 the_start = max (the_start, (framepos_t) region->position());
2993 if (max_framepos - the_start < region->length()) {
2994 the_end = the_start + region->length() - 1;
2996 the_end = max_framepos;
2998 the_end = min (end, the_end);
2999 cnt = the_end - the_start + 1;
3001 region->clear_changes ();
3002 region->trim_to (the_start, cnt);
3003 _session->add_command (new StatefulDiffCommand (region));
3006 commit_reversible_command ();
3010 Editor::region_fill_track ()
3012 RegionSelection rs = get_regions_from_selection_and_entered ();
3014 if (!_session || rs.empty()) {
3018 framepos_t const end = _session->current_end_frame ();
3020 begin_reversible_command (Operations::region_fill);
3022 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3024 boost::shared_ptr<Region> region ((*i)->region());
3026 boost::shared_ptr<Playlist> pl = region->playlist();
3028 if (end <= region->last_frame()) {
3032 double times = (double) (end - region->last_frame()) / (double) region->length();
3038 pl->clear_changes ();
3039 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3040 _session->add_command (new StatefulDiffCommand (pl));
3043 commit_reversible_command ();
3047 Editor::region_fill_selection ()
3049 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3053 if (selection->time.empty()) {
3057 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3062 framepos_t start = selection->time[clicked_selection].start;
3063 framepos_t end = selection->time[clicked_selection].end;
3065 boost::shared_ptr<Playlist> playlist;
3067 if (selection->tracks.empty()) {
3071 framepos_t selection_length = end - start;
3072 float times = (float)selection_length / region->length();
3074 begin_reversible_command (Operations::fill_selection);
3076 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3078 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3080 if ((playlist = (*i)->playlist()) == 0) {
3084 playlist->clear_changes ();
3085 playlist->add_region (RegionFactory::create (region, true), start, times);
3086 _session->add_command (new StatefulDiffCommand (playlist));
3089 commit_reversible_command ();
3093 Editor::set_region_sync_position ()
3095 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3099 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3101 bool in_command = false;
3103 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3105 if (!(*r)->region()->covers (where)) {
3109 boost::shared_ptr<Region> region ((*r)->region());
3112 begin_reversible_command (_("set sync point"));
3116 region->clear_changes ();
3117 region->set_sync_position (where);
3118 _session->add_command(new StatefulDiffCommand (region));
3122 commit_reversible_command ();
3126 /** Remove the sync positions of the selection */
3128 Editor::remove_region_sync ()
3130 RegionSelection rs = get_regions_from_selection_and_entered ();
3136 begin_reversible_command (_("remove region sync"));
3138 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3140 (*i)->region()->clear_changes ();
3141 (*i)->region()->clear_sync_position ();
3142 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3145 commit_reversible_command ();
3149 Editor::naturalize_region ()
3151 RegionSelection rs = get_regions_from_selection_and_entered ();
3157 if (rs.size() > 1) {
3158 begin_reversible_command (_("move regions to original position"));
3160 begin_reversible_command (_("move region to original position"));
3163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3164 (*i)->region()->clear_changes ();
3165 (*i)->region()->move_to_natural_position ();
3166 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3169 commit_reversible_command ();
3173 Editor::align_regions (RegionPoint what)
3175 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3181 begin_reversible_command (_("align selection"));
3183 framepos_t const position = get_preferred_edit_position ();
3185 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3186 align_region_internal ((*i)->region(), what, position);
3189 commit_reversible_command ();
3192 struct RegionSortByTime {
3193 bool operator() (const RegionView* a, const RegionView* b) {
3194 return a->region()->position() < b->region()->position();
3199 Editor::align_regions_relative (RegionPoint point)
3201 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3207 framepos_t const position = get_preferred_edit_position ();
3209 framepos_t distance = 0;
3213 list<RegionView*> sorted;
3214 rs.by_position (sorted);
3216 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3221 if (position > r->position()) {
3222 distance = position - r->position();
3224 distance = r->position() - position;
3230 if (position > r->last_frame()) {
3231 distance = position - r->last_frame();
3232 pos = r->position() + distance;
3234 distance = r->last_frame() - position;
3235 pos = r->position() - distance;
3241 pos = r->adjust_to_sync (position);
3242 if (pos > r->position()) {
3243 distance = pos - r->position();
3245 distance = r->position() - pos;
3251 if (pos == r->position()) {
3255 begin_reversible_command (_("align selection (relative)"));
3257 /* move first one specially */
3259 r->clear_changes ();
3260 r->set_position (pos);
3261 _session->add_command(new StatefulDiffCommand (r));
3263 /* move rest by the same amount */
3267 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3269 boost::shared_ptr<Region> region ((*i)->region());
3271 region->clear_changes ();
3274 region->set_position (region->position() + distance);
3276 region->set_position (region->position() - distance);
3279 _session->add_command(new StatefulDiffCommand (region));
3283 commit_reversible_command ();
3287 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3289 begin_reversible_command (_("align region"));
3290 align_region_internal (region, point, position);
3291 commit_reversible_command ();
3295 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3297 region->clear_changes ();
3301 region->set_position (region->adjust_to_sync (position));
3305 if (position > region->length()) {
3306 region->set_position (position - region->length());
3311 region->set_position (position);
3315 _session->add_command(new StatefulDiffCommand (region));
3319 Editor::trim_region_front ()
3325 Editor::trim_region_back ()
3327 trim_region (false);
3331 Editor::trim_region (bool front)
3333 framepos_t where = get_preferred_edit_position();
3334 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3340 begin_reversible_command (front ? _("trim front") : _("trim back"));
3342 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3343 if (!(*i)->region()->locked()) {
3345 (*i)->region()->clear_changes ();
3348 (*i)->region()->trim_front (where);
3349 maybe_locate_with_edit_preroll ( where );
3351 (*i)->region()->trim_end (where);
3352 maybe_locate_with_edit_preroll ( where );
3355 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3359 commit_reversible_command ();
3362 /** Trim the end of the selected regions to the position of the edit cursor */
3364 Editor::trim_region_to_loop ()
3366 Location* loc = _session->locations()->auto_loop_location();
3370 trim_region_to_location (*loc, _("trim to loop"));
3374 Editor::trim_region_to_punch ()
3376 Location* loc = _session->locations()->auto_punch_location();
3380 trim_region_to_location (*loc, _("trim to punch"));
3384 Editor::trim_region_to_location (const Location& loc, const char* str)
3386 RegionSelection rs = get_regions_from_selection_and_entered ();
3388 begin_reversible_command (str);
3390 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3391 RegionView* rv = (*x);
3393 /* require region to span proposed trim */
3394 switch (rv->region()->coverage (loc.start(), loc.end())) {
3395 case Evoral::OverlapInternal:
3401 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3410 if (tav->track() != 0) {
3411 speed = tav->track()->speed();
3414 start = session_frame_to_track_frame (loc.start(), speed);
3415 end = session_frame_to_track_frame (loc.end(), speed);
3417 rv->region()->clear_changes ();
3418 rv->region()->trim_to (start, (end - start));
3419 _session->add_command(new StatefulDiffCommand (rv->region()));
3422 commit_reversible_command ();
3426 Editor::trim_region_to_previous_region_end ()
3428 return trim_to_region(false);
3432 Editor::trim_region_to_next_region_start ()
3434 return trim_to_region(true);
3438 Editor::trim_to_region(bool forward)
3440 RegionSelection rs = get_regions_from_selection_and_entered ();
3442 begin_reversible_command (_("trim to region"));
3444 boost::shared_ptr<Region> next_region;
3446 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3448 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3454 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3462 if (atav->track() != 0) {
3463 speed = atav->track()->speed();
3467 boost::shared_ptr<Region> region = arv->region();
3468 boost::shared_ptr<Playlist> playlist (region->playlist());
3470 region->clear_changes ();
3474 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3480 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3481 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3485 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3491 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3493 arv->region_changed (ARDOUR::bounds_change);
3496 _session->add_command(new StatefulDiffCommand (region));
3499 commit_reversible_command ();
3503 Editor::unfreeze_route ()
3505 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3509 clicked_routeview->track()->unfreeze ();
3513 Editor::_freeze_thread (void* arg)
3515 return static_cast<Editor*>(arg)->freeze_thread ();
3519 Editor::freeze_thread ()
3521 /* create event pool because we may need to talk to the session */
3522 SessionEvent::create_per_thread_pool ("freeze events", 64);
3523 /* create per-thread buffers for process() tree to use */
3524 current_interthread_info->process_thread.get_buffers ();
3525 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3526 current_interthread_info->done = true;
3527 current_interthread_info->process_thread.drop_buffers();
3532 Editor::freeze_route ()
3538 /* stop transport before we start. this is important */
3540 _session->request_transport_speed (0.0);
3542 /* wait for just a little while, because the above call is asynchronous */
3544 Glib::usleep (250000);
3546 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3550 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3552 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3553 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3555 d.set_title (_("Cannot freeze"));
3560 if (clicked_routeview->track()->has_external_redirects()) {
3561 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"
3562 "Freezing will only process the signal as far as the first send/insert/return."),
3563 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3565 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3566 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3567 d.set_title (_("Freeze Limits"));
3569 int response = d.run ();
3572 case Gtk::RESPONSE_CANCEL:
3579 InterThreadInfo itt;
3580 current_interthread_info = &itt;
3582 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3584 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3586 set_canvas_cursor (_cursors->wait);
3588 while (!itt.done && !itt.cancel) {
3589 gtk_main_iteration ();
3592 current_interthread_info = 0;
3593 set_canvas_cursor (current_canvas_cursor);
3597 Editor::bounce_range_selection (bool replace, bool enable_processing)
3599 if (selection->time.empty()) {
3603 TrackSelection views = selection->tracks;
3605 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3607 if (enable_processing) {
3609 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3611 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3613 _("You can't perform this operation because the processing of the signal "
3614 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3615 "You can do this without processing, which is a different operation.")
3617 d.set_title (_("Cannot bounce"));
3624 framepos_t start = selection->time[clicked_selection].start;
3625 framepos_t end = selection->time[clicked_selection].end;
3626 framepos_t cnt = end - start + 1;
3628 begin_reversible_command (_("bounce range"));
3630 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3632 RouteTimeAxisView* rtv;
3634 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3638 boost::shared_ptr<Playlist> playlist;
3640 if ((playlist = rtv->playlist()) == 0) {
3644 InterThreadInfo itt;
3646 playlist->clear_changes ();
3647 playlist->clear_owned_changes ();
3649 boost::shared_ptr<Region> r;
3651 if (enable_processing) {
3652 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3654 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3662 list<AudioRange> ranges;
3663 ranges.push_back (AudioRange (start, start+cnt, 0));
3664 playlist->cut (ranges); // discard result
3665 playlist->add_region (r, start);
3668 vector<Command*> cmds;
3669 playlist->rdiff (cmds);
3670 _session->add_commands (cmds);
3672 _session->add_command (new StatefulDiffCommand (playlist));
3675 commit_reversible_command ();
3678 /** Delete selected regions, automation points or a time range */
3685 /** Cut selected regions, automation points or a time range */
3692 /** Copy selected regions, automation points or a time range */
3700 /** @return true if a Cut, Copy or Clear is possible */
3702 Editor::can_cut_copy () const
3704 switch (effective_mouse_mode()) {
3707 if (!selection->regions.empty() || !selection->points.empty()) {
3713 if (!selection->time.empty()) {
3726 /** Cut, copy or clear selected regions, automation points or a time range.
3727 * @param op Operation (Cut, Copy or Clear)
3730 Editor::cut_copy (CutCopyOp op)
3732 /* only cancel selection if cut/copy is successful.*/
3738 opname = _("delete");
3747 opname = _("clear");
3751 /* if we're deleting something, and the mouse is still pressed,
3752 the thing we started a drag for will be gone when we release
3753 the mouse button(s). avoid this. see part 2 at the end of
3757 if (op == Delete || op == Cut || op == Clear) {
3758 if (_drags->active ()) {
3763 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3764 cut_buffer->clear ();
3766 if (entered_marker) {
3768 /* cut/delete op while pointing at a marker */
3771 Location* loc = find_location_from_marker (entered_marker, ignored);
3773 if (_session && loc) {
3774 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3781 if (internal_editing()) {
3783 switch (effective_mouse_mode()) {
3786 begin_reversible_command (opname + ' ' + X_("MIDI"));
3788 commit_reversible_command ();
3797 bool did_edit = false;
3799 switch (effective_mouse_mode()) {
3801 if (!selection->points.empty()) {
3802 begin_reversible_command (opname + _(" points"));
3804 cut_copy_points (op);
3805 if (op == Cut || op == Delete) {
3806 selection->clear_points ();
3813 if (!selection->regions.empty() || !selection->points.empty()) {
3817 if (selection->regions.empty()) {
3818 thing_name = _("points");
3819 } else if (selection->points.empty()) {
3820 thing_name = _("regions");
3822 thing_name = _("objects");
3825 begin_reversible_command (opname + ' ' + thing_name);
3828 if (!selection->regions.empty()) {
3829 cut_copy_regions (op, selection->regions);
3831 if (op == Cut || op == Delete) {
3832 selection->clear_regions ();
3836 if (!selection->points.empty()) {
3837 cut_copy_points (op);
3839 if (op == Cut || op == Delete) {
3840 selection->clear_points ();
3847 if (selection->time.empty()) {
3848 framepos_t start, end;
3849 /* no time selection, see if we can get an edit range
3852 if (get_edit_op_range (start, end)) {
3853 selection->set (start, end);
3856 if (!selection->time.empty()) {
3857 begin_reversible_command (opname + _(" range"));
3860 cut_copy_ranges (op);
3862 if (op == Cut || op == Delete) {
3863 selection->clear_time ();
3873 commit_reversible_command ();
3876 if (op == Delete || op == Cut || op == Clear) {
3881 struct AutomationRecord {
3882 AutomationRecord () : state (0) {}
3883 AutomationRecord (XMLNode* s) : state (s) {}
3885 XMLNode* state; ///< state before any operation
3886 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3889 /** Cut, copy or clear selected automation points.
3890 * @param op Operation (Cut, Copy or Clear)
3893 Editor::cut_copy_points (CutCopyOp op)
3895 if (selection->points.empty ()) {
3899 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3900 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3902 /* Keep a record of the AutomationLists that we end up using in this operation */
3903 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3906 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3907 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3908 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3909 if (lists.find (al) == lists.end ()) {
3910 /* We haven't seen this list yet, so make a record for it. This includes
3911 taking a copy of its current state, in case this is needed for undo later.
3913 lists[al] = AutomationRecord (&al->get_state ());
3917 if (op == Cut || op == Copy) {
3918 /* This operation will involve putting things in the cut buffer, so create an empty
3919 ControlList for each of our source lists to put the cut buffer data in.
3921 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3922 i->second.copy = i->first->create (i->first->parameter ());
3925 /* Add all selected points to the relevant copy ControlLists */
3926 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3927 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3928 AutomationList::const_iterator j = (*i)->model ();
3929 lists[al].copy->add ((*j)->when, (*j)->value);
3932 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3933 /* Correct this copy list so that it starts at time 0 */
3934 double const start = i->second.copy->front()->when;
3935 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3936 (*j)->when -= start;
3939 /* And add it to the cut buffer */
3940 cut_buffer->add (i->second.copy);
3944 if (op == Delete || op == Cut) {
3945 /* This operation needs to remove things from the main AutomationList, so do that now */
3947 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3948 i->first->freeze ();
3951 /* Remove each selected point from its AutomationList */
3952 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3953 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3954 al->erase ((*i)->model ());
3957 /* Thaw the lists and add undo records for them */
3958 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3959 boost::shared_ptr<AutomationList> al = i->first;
3961 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3966 /** Cut, copy or clear selected automation points.
3967 * @param op Operation (Cut, Copy or Clear)
3970 Editor::cut_copy_midi (CutCopyOp op)
3972 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3973 MidiRegionView* mrv = *i;
3974 mrv->cut_copy_clear (op);
3980 struct lt_playlist {
3981 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3982 return a.playlist < b.playlist;
3986 struct PlaylistMapping {
3988 boost::shared_ptr<Playlist> pl;
3990 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3993 /** Remove `clicked_regionview' */
3995 Editor::remove_clicked_region ()
3997 if (clicked_routeview == 0 || clicked_regionview == 0) {
4001 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4003 begin_reversible_command (_("remove region"));
4004 playlist->clear_changes ();
4005 playlist->clear_owned_changes ();
4006 playlist->remove_region (clicked_regionview->region());
4008 /* We might have removed regions, which alters other regions' layering_index,
4009 so we need to do a recursive diff here.
4011 vector<Command*> cmds;
4012 playlist->rdiff (cmds);
4013 _session->add_commands (cmds);
4015 _session->add_command(new StatefulDiffCommand (playlist));
4016 commit_reversible_command ();
4020 /** Remove the selected regions */
4022 Editor::remove_selected_regions ()
4024 RegionSelection rs = get_regions_from_selection_and_entered ();
4026 if (!_session || rs.empty()) {
4030 begin_reversible_command (_("remove region"));
4032 list<boost::shared_ptr<Region> > regions_to_remove;
4034 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4035 // we can't just remove the region(s) in this loop because
4036 // this removes them from the RegionSelection, and they thus
4037 // disappear from underneath the iterator, and the ++i above
4038 // SEGVs in a puzzling fashion.
4040 // so, first iterate over the regions to be removed from rs and
4041 // add them to the regions_to_remove list, and then
4042 // iterate over the list to actually remove them.
4044 regions_to_remove.push_back ((*i)->region());
4047 vector<boost::shared_ptr<Playlist> > playlists;
4049 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4051 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4054 // is this check necessary?
4058 /* get_regions_from_selection_and_entered() guarantees that
4059 the playlists involved are unique, so there is no need
4063 playlists.push_back (playlist);
4065 playlist->clear_changes ();
4066 playlist->clear_owned_changes ();
4067 playlist->freeze ();
4068 playlist->remove_region (*rl);
4071 vector<boost::shared_ptr<Playlist> >::iterator pl;
4073 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4076 /* We might have removed regions, which alters other regions' layering_index,
4077 so we need to do a recursive diff here.
4079 vector<Command*> cmds;
4080 (*pl)->rdiff (cmds);
4081 _session->add_commands (cmds);
4083 _session->add_command(new StatefulDiffCommand (*pl));
4086 commit_reversible_command ();
4089 /** Cut, copy or clear selected regions.
4090 * @param op Operation (Cut, Copy or Clear)
4093 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4095 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4096 a map when we want ordered access to both elements. i think.
4099 vector<PlaylistMapping> pmap;
4101 framepos_t first_position = max_framepos;
4103 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4104 FreezeList freezelist;
4106 /* get ordering correct before we cut/copy */
4108 rs.sort_by_position_and_track ();
4110 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4112 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4114 if (op == Cut || op == Clear || op == Delete) {
4115 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4118 FreezeList::iterator fl;
4120 // only take state if this is a new playlist.
4121 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4127 if (fl == freezelist.end()) {
4128 pl->clear_changes();
4129 pl->clear_owned_changes ();
4131 freezelist.insert (pl);
4136 TimeAxisView* tv = &(*x)->get_time_axis_view();
4137 vector<PlaylistMapping>::iterator z;
4139 for (z = pmap.begin(); z != pmap.end(); ++z) {
4140 if ((*z).tv == tv) {
4145 if (z == pmap.end()) {
4146 pmap.push_back (PlaylistMapping (tv));
4150 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4152 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4155 /* region not yet associated with a playlist (e.g. unfinished
4162 TimeAxisView& tv = (*x)->get_time_axis_view();
4163 boost::shared_ptr<Playlist> npl;
4164 RegionSelection::iterator tmp;
4171 vector<PlaylistMapping>::iterator z;
4173 for (z = pmap.begin(); z != pmap.end(); ++z) {
4174 if ((*z).tv == &tv) {
4179 assert (z != pmap.end());
4182 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4190 boost::shared_ptr<Region> r = (*x)->region();
4191 boost::shared_ptr<Region> _xx;
4197 pl->remove_region (r);
4201 _xx = RegionFactory::create (r);
4202 npl->add_region (_xx, r->position() - first_position);
4203 pl->remove_region (r);
4207 /* copy region before adding, so we're not putting same object into two different playlists */
4208 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4212 pl->remove_region (r);
4221 list<boost::shared_ptr<Playlist> > foo;
4223 /* the pmap is in the same order as the tracks in which selected regions occured */
4225 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4228 foo.push_back ((*i).pl);
4233 cut_buffer->set (foo);
4237 _last_cut_copy_source_track = 0;
4239 _last_cut_copy_source_track = pmap.front().tv;
4243 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4246 /* We might have removed regions, which alters other regions' layering_index,
4247 so we need to do a recursive diff here.
4249 vector<Command*> cmds;
4250 (*pl)->rdiff (cmds);
4251 _session->add_commands (cmds);
4253 _session->add_command (new StatefulDiffCommand (*pl));
4258 Editor::cut_copy_ranges (CutCopyOp op)
4260 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4262 /* Sort the track selection now, so that it if is used, the playlists
4263 selected by the calls below to cut_copy_clear are in the order that
4264 their tracks appear in the editor. This makes things like paste
4265 of ranges work properly.
4268 sort_track_selection (ts);
4271 if (!entered_track) {
4274 ts.push_back (entered_track);
4277 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4278 (*i)->cut_copy_clear (*selection, op);
4283 Editor::paste (float times, bool from_context)
4285 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4287 paste_internal (get_preferred_edit_position (false, from_context), times);
4291 Editor::mouse_paste ()
4296 if (!mouse_frame (where, ignored)) {
4301 paste_internal (where, 1);
4305 Editor::paste_internal (framepos_t position, float times)
4307 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4309 if (internal_editing()) {
4310 if (cut_buffer->midi_notes.empty()) {
4314 if (cut_buffer->empty()) {
4319 if (position == max_framepos) {
4320 position = get_preferred_edit_position();
4321 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4325 TrackViewList::iterator i;
4328 /* get everything in the correct order */
4330 if (_edit_point == Editing::EditAtMouse && entered_track) {
4331 /* With the mouse edit point, paste onto the track under the mouse */
4332 ts.push_back (entered_track);
4333 } else if (!selection->tracks.empty()) {
4334 /* Otherwise, if there are some selected tracks, paste to them */
4335 ts = selection->tracks.filter_to_unique_playlists ();
4336 sort_track_selection (ts);
4337 } else if (_last_cut_copy_source_track) {
4338 /* Otherwise paste to the track that the cut/copy came from;
4339 see discussion in mantis #3333.
4341 ts.push_back (_last_cut_copy_source_track);
4344 if (internal_editing ()) {
4346 /* undo/redo is handled by individual tracks/regions */
4348 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4351 RegionSelection::iterator r;
4352 MidiNoteSelection::iterator cb;
4354 get_regions_at (rs, position, ts);
4356 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4357 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4358 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4360 mrv->paste (position, times, **cb);
4368 /* we do redo (do you do voodoo?) */
4370 begin_reversible_command (Operations::paste);
4372 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4373 (*i)->paste (position, times, *cut_buffer, nth);
4376 commit_reversible_command ();
4381 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4383 boost::shared_ptr<Playlist> playlist;
4384 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4385 RegionSelection foo;
4387 framepos_t const start_frame = regions.start ();
4388 framepos_t const end_frame = regions.end_frame ();
4390 begin_reversible_command (Operations::duplicate_region);
4392 selection->clear_regions ();
4394 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4396 boost::shared_ptr<Region> r ((*i)->region());
4398 TimeAxisView& tv = (*i)->get_time_axis_view();
4399 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4400 latest_regionviews.clear ();
4401 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4403 playlist = (*i)->region()->playlist();
4404 playlist->clear_changes ();
4405 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4406 _session->add_command(new StatefulDiffCommand (playlist));
4410 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4413 commit_reversible_command ();
4416 selection->set (foo);
4421 Editor::duplicate_selection (float times)
4423 if (selection->time.empty() || selection->tracks.empty()) {
4427 boost::shared_ptr<Playlist> playlist;
4428 vector<boost::shared_ptr<Region> > new_regions;
4429 vector<boost::shared_ptr<Region> >::iterator ri;
4431 create_region_from_selection (new_regions);
4433 if (new_regions.empty()) {
4437 begin_reversible_command (_("duplicate selection"));
4439 ri = new_regions.begin();
4441 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4443 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4444 if ((playlist = (*i)->playlist()) == 0) {
4447 playlist->clear_changes ();
4448 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4449 _session->add_command (new StatefulDiffCommand (playlist));
4452 if (ri == new_regions.end()) {
4457 commit_reversible_command ();
4460 /** Reset all selected points to the relevant default value */
4462 Editor::reset_point_selection ()
4464 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4465 ARDOUR::AutomationList::iterator j = (*i)->model ();
4466 (*j)->value = (*i)->line().the_list()->default_value ();
4471 Editor::center_playhead ()
4473 float const page = _visible_canvas_width * samples_per_pixel;
4474 center_screen_internal (playhead_cursor->current_frame (), page);
4478 Editor::center_edit_point ()
4480 float const page = _visible_canvas_width * samples_per_pixel;
4481 center_screen_internal (get_preferred_edit_position(), page);
4484 /** Caller must begin and commit a reversible command */
4486 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4488 playlist->clear_changes ();
4490 _session->add_command (new StatefulDiffCommand (playlist));
4494 Editor::nudge_track (bool use_edit, bool forwards)
4496 boost::shared_ptr<Playlist> playlist;
4497 framepos_t distance;
4498 framepos_t next_distance;
4502 start = get_preferred_edit_position();
4507 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4511 if (selection->tracks.empty()) {
4515 begin_reversible_command (_("nudge track"));
4517 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4519 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4521 if ((playlist = (*i)->playlist()) == 0) {
4525 playlist->clear_changes ();
4526 playlist->clear_owned_changes ();
4528 playlist->nudge_after (start, distance, forwards);
4530 vector<Command*> cmds;
4532 playlist->rdiff (cmds);
4533 _session->add_commands (cmds);
4535 _session->add_command (new StatefulDiffCommand (playlist));
4538 commit_reversible_command ();
4542 Editor::remove_last_capture ()
4544 vector<string> choices;
4551 if (Config->get_verify_remove_last_capture()) {
4552 prompt = _("Do you really want to destroy the last capture?"
4553 "\n(This is destructive and cannot be undone)");
4555 choices.push_back (_("No, do nothing."));
4556 choices.push_back (_("Yes, destroy it."));
4558 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4560 if (prompter.run () == 1) {
4561 _session->remove_last_capture ();
4562 _regions->redisplay ();
4566 _session->remove_last_capture();
4567 _regions->redisplay ();
4572 Editor::normalize_region ()
4578 RegionSelection rs = get_regions_from_selection_and_entered ();
4584 NormalizeDialog dialog (rs.size() > 1);
4586 if (dialog.run () == RESPONSE_CANCEL) {
4590 set_canvas_cursor (_cursors->wait);
4593 /* XXX: should really only count audio regions here */
4594 int const regions = rs.size ();
4596 /* Make a list of the selected audio regions' maximum amplitudes, and also
4597 obtain the maximum amplitude of them all.
4599 list<double> max_amps;
4601 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4602 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4604 dialog.descend (1.0 / regions);
4605 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4608 /* the user cancelled the operation */
4609 set_canvas_cursor (current_canvas_cursor);
4613 max_amps.push_back (a);
4614 max_amp = max (max_amp, a);
4619 begin_reversible_command (_("normalize"));
4621 list<double>::const_iterator a = max_amps.begin ();
4623 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4624 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4629 arv->region()->clear_changes ();
4631 double const amp = dialog.normalize_individually() ? *a : max_amp;
4633 arv->audio_region()->normalize (amp, dialog.target ());
4634 _session->add_command (new StatefulDiffCommand (arv->region()));
4639 commit_reversible_command ();
4640 set_canvas_cursor (current_canvas_cursor);
4645 Editor::reset_region_scale_amplitude ()
4651 RegionSelection rs = get_regions_from_selection_and_entered ();
4657 begin_reversible_command ("reset gain");
4659 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4660 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4663 arv->region()->clear_changes ();
4664 arv->audio_region()->set_scale_amplitude (1.0f);
4665 _session->add_command (new StatefulDiffCommand (arv->region()));
4668 commit_reversible_command ();
4672 Editor::adjust_region_gain (bool up)
4674 RegionSelection rs = get_regions_from_selection_and_entered ();
4676 if (!_session || rs.empty()) {
4680 begin_reversible_command ("adjust region gain");
4682 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4683 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4688 arv->region()->clear_changes ();
4690 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4698 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4699 _session->add_command (new StatefulDiffCommand (arv->region()));
4702 commit_reversible_command ();
4707 Editor::reverse_region ()
4713 Reverse rev (*_session);
4714 apply_filter (rev, _("reverse regions"));
4718 Editor::strip_region_silence ()
4724 RegionSelection rs = get_regions_from_selection_and_entered ();
4730 std::list<RegionView*> audio_only;
4732 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4733 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4735 audio_only.push_back (arv);
4739 StripSilenceDialog d (_session, audio_only);
4740 int const r = d.run ();
4744 if (r == Gtk::RESPONSE_OK) {
4745 ARDOUR::AudioIntervalMap silences;
4746 d.silences (silences);
4747 StripSilence s (*_session, silences, d.fade_length());
4748 apply_filter (s, _("strip silence"), &d);
4753 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4755 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4756 mrv.selection_as_notelist (selected, true);
4758 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4759 v.push_back (selected);
4761 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4762 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4764 return op (mrv.midi_region()->model(), pos_beats, v);
4768 Editor::apply_midi_note_edit_op (MidiOperator& op)
4772 RegionSelection rs = get_regions_from_selection_and_entered ();
4778 begin_reversible_command (op.name ());
4780 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4781 RegionSelection::iterator tmp = r;
4784 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4787 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4790 _session->add_command (cmd);
4797 commit_reversible_command ();
4801 Editor::fork_region ()
4803 RegionSelection rs = get_regions_from_selection_and_entered ();
4809 begin_reversible_command (_("Fork Region(s)"));
4811 set_canvas_cursor (_cursors->wait);
4814 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4815 RegionSelection::iterator tmp = r;
4818 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4822 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4823 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4824 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4826 playlist->clear_changes ();
4827 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4828 _session->add_command(new StatefulDiffCommand (playlist));
4830 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4837 commit_reversible_command ();
4839 set_canvas_cursor (current_canvas_cursor);
4843 Editor::quantize_region ()
4845 int selected_midi_region_cnt = 0;
4851 RegionSelection rs = get_regions_from_selection_and_entered ();
4857 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4858 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4860 selected_midi_region_cnt++;
4864 if (selected_midi_region_cnt == 0) {
4868 QuantizeDialog* qd = new QuantizeDialog (*this);
4871 const int r = qd->run ();
4874 if (r == Gtk::RESPONSE_OK) {
4875 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4876 qd->start_grid_size(), qd->end_grid_size(),
4877 qd->strength(), qd->swing(), qd->threshold());
4879 apply_midi_note_edit_op (quant);
4884 Editor::insert_patch_change (bool from_context)
4886 RegionSelection rs = get_regions_from_selection_and_entered ();
4892 const framepos_t p = get_preferred_edit_position (false, from_context);
4894 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4895 there may be more than one, but the PatchChangeDialog can only offer
4896 one set of patch menus.
4898 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4900 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4901 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4903 if (d.run() == RESPONSE_CANCEL) {
4907 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4908 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4910 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4911 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4918 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4920 RegionSelection rs = get_regions_from_selection_and_entered ();
4926 begin_reversible_command (command);
4928 set_canvas_cursor (_cursors->wait);
4932 int const N = rs.size ();
4934 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4935 RegionSelection::iterator tmp = r;
4938 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4940 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4943 progress->descend (1.0 / N);
4946 if (arv->audio_region()->apply (filter, progress) == 0) {
4948 playlist->clear_changes ();
4949 playlist->clear_owned_changes ();
4951 if (filter.results.empty ()) {
4953 /* no regions returned; remove the old one */
4954 playlist->remove_region (arv->region ());
4958 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4960 /* first region replaces the old one */
4961 playlist->replace_region (arv->region(), *res, (*res)->position());
4965 while (res != filter.results.end()) {
4966 playlist->add_region (*res, (*res)->position());
4972 /* We might have removed regions, which alters other regions' layering_index,
4973 so we need to do a recursive diff here.
4975 vector<Command*> cmds;
4976 playlist->rdiff (cmds);
4977 _session->add_commands (cmds);
4979 _session->add_command(new StatefulDiffCommand (playlist));
4985 progress->ascend ();
4993 commit_reversible_command ();
4996 set_canvas_cursor (current_canvas_cursor);
5000 Editor::external_edit_region ()
5006 Editor::reset_region_gain_envelopes ()
5008 RegionSelection rs = get_regions_from_selection_and_entered ();
5010 if (!_session || rs.empty()) {
5014 _session->begin_reversible_command (_("reset region gain"));
5016 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5017 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5019 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5020 XMLNode& before (alist->get_state());
5022 arv->audio_region()->set_default_envelope ();
5023 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5027 _session->commit_reversible_command ();
5031 Editor::set_region_gain_visibility (RegionView* rv)
5033 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5035 arv->update_envelope_visibility();
5040 Editor::set_gain_envelope_visibility ()
5046 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5047 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5049 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5055 Editor::toggle_gain_envelope_active ()
5057 if (_ignore_region_action) {
5061 RegionSelection rs = get_regions_from_selection_and_entered ();
5063 if (!_session || rs.empty()) {
5067 _session->begin_reversible_command (_("region gain envelope active"));
5069 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5070 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5072 arv->region()->clear_changes ();
5073 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5074 _session->add_command (new StatefulDiffCommand (arv->region()));
5078 _session->commit_reversible_command ();
5082 Editor::toggle_region_lock ()
5084 if (_ignore_region_action) {
5088 RegionSelection rs = get_regions_from_selection_and_entered ();
5090 if (!_session || rs.empty()) {
5094 _session->begin_reversible_command (_("toggle region lock"));
5096 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5097 (*i)->region()->clear_changes ();
5098 (*i)->region()->set_locked (!(*i)->region()->locked());
5099 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5102 _session->commit_reversible_command ();
5106 Editor::toggle_region_video_lock ()
5108 if (_ignore_region_action) {
5112 RegionSelection rs = get_regions_from_selection_and_entered ();
5114 if (!_session || rs.empty()) {
5118 _session->begin_reversible_command (_("Toggle Video Lock"));
5120 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5121 (*i)->region()->clear_changes ();
5122 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5123 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5126 _session->commit_reversible_command ();
5130 Editor::toggle_region_lock_style ()
5132 if (_ignore_region_action) {
5136 RegionSelection rs = get_regions_from_selection_and_entered ();
5138 if (!_session || rs.empty()) {
5142 _session->begin_reversible_command (_("region lock style"));
5144 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5145 (*i)->region()->clear_changes ();
5146 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5147 (*i)->region()->set_position_lock_style (ns);
5148 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5151 _session->commit_reversible_command ();
5155 Editor::toggle_opaque_region ()
5157 if (_ignore_region_action) {
5161 RegionSelection rs = get_regions_from_selection_and_entered ();
5163 if (!_session || rs.empty()) {
5167 _session->begin_reversible_command (_("change region opacity"));
5169 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5170 (*i)->region()->clear_changes ();
5171 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5172 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5175 _session->commit_reversible_command ();
5179 Editor::toggle_record_enable ()
5181 bool new_state = false;
5183 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5184 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5187 if (!rtav->is_track())
5191 new_state = !rtav->track()->record_enabled();
5195 rtav->track()->set_record_enabled (new_state, this);
5200 Editor::toggle_solo ()
5202 bool new_state = false;
5204 boost::shared_ptr<RouteList> rl (new RouteList);
5206 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5207 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5214 new_state = !rtav->route()->soloed ();
5218 rl->push_back (rtav->route());
5221 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5225 Editor::toggle_mute ()
5227 bool new_state = false;
5229 boost::shared_ptr<RouteList> rl (new RouteList);
5231 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5232 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5239 new_state = !rtav->route()->muted();
5243 rl->push_back (rtav->route());
5246 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5250 Editor::toggle_solo_isolate ()
5255 Editor::set_fade_length (bool in)
5257 RegionSelection rs = get_regions_from_selection_and_entered ();
5263 /* we need a region to measure the offset from the start */
5265 RegionView* rv = rs.front ();
5267 framepos_t pos = get_preferred_edit_position();
5271 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5272 /* edit point is outside the relevant region */
5277 if (pos <= rv->region()->position()) {
5281 len = pos - rv->region()->position();
5282 cmd = _("set fade in length");
5284 if (pos >= rv->region()->last_frame()) {
5288 len = rv->region()->last_frame() - pos;
5289 cmd = _("set fade out length");
5292 begin_reversible_command (cmd);
5294 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5295 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5301 boost::shared_ptr<AutomationList> alist;
5303 alist = tmp->audio_region()->fade_in();
5305 alist = tmp->audio_region()->fade_out();
5308 XMLNode &before = alist->get_state();
5311 tmp->audio_region()->set_fade_in_length (len);
5312 tmp->audio_region()->set_fade_in_active (true);
5314 tmp->audio_region()->set_fade_out_length (len);
5315 tmp->audio_region()->set_fade_out_active (true);
5318 XMLNode &after = alist->get_state();
5319 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5322 commit_reversible_command ();
5326 Editor::set_fade_in_shape (FadeShape shape)
5328 RegionSelection rs = get_regions_from_selection_and_entered ();
5334 begin_reversible_command (_("set fade in shape"));
5336 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5337 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5343 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5344 XMLNode &before = alist->get_state();
5346 tmp->audio_region()->set_fade_in_shape (shape);
5348 XMLNode &after = alist->get_state();
5349 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5352 commit_reversible_command ();
5357 Editor::set_fade_out_shape (FadeShape shape)
5359 RegionSelection rs = get_regions_from_selection_and_entered ();
5365 begin_reversible_command (_("set fade out shape"));
5367 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5368 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5374 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5375 XMLNode &before = alist->get_state();
5377 tmp->audio_region()->set_fade_out_shape (shape);
5379 XMLNode &after = alist->get_state();
5380 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5383 commit_reversible_command ();
5387 Editor::set_fade_in_active (bool yn)
5389 RegionSelection rs = get_regions_from_selection_and_entered ();
5395 begin_reversible_command (_("set fade in active"));
5397 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5398 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5405 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5407 ar->clear_changes ();
5408 ar->set_fade_in_active (yn);
5409 _session->add_command (new StatefulDiffCommand (ar));
5412 commit_reversible_command ();
5416 Editor::set_fade_out_active (bool yn)
5418 RegionSelection rs = get_regions_from_selection_and_entered ();
5424 begin_reversible_command (_("set fade out active"));
5426 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5427 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5433 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5435 ar->clear_changes ();
5436 ar->set_fade_out_active (yn);
5437 _session->add_command(new StatefulDiffCommand (ar));
5440 commit_reversible_command ();
5444 Editor::toggle_region_fades (int dir)
5446 if (_ignore_region_action) {
5450 boost::shared_ptr<AudioRegion> ar;
5453 RegionSelection rs = get_regions_from_selection_and_entered ();
5459 RegionSelection::iterator i;
5460 for (i = rs.begin(); i != rs.end(); ++i) {
5461 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5463 yn = ar->fade_out_active ();
5465 yn = ar->fade_in_active ();
5471 if (i == rs.end()) {
5475 /* XXX should this undo-able? */
5477 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5478 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5481 if (dir == 1 || dir == 0) {
5482 ar->set_fade_in_active (!yn);
5485 if (dir == -1 || dir == 0) {
5486 ar->set_fade_out_active (!yn);
5492 /** Update region fade visibility after its configuration has been changed */
5494 Editor::update_region_fade_visibility ()
5496 bool _fade_visibility = _session->config.get_show_region_fades ();
5498 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5499 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5501 if (_fade_visibility) {
5502 v->audio_view()->show_all_fades ();
5504 v->audio_view()->hide_all_fades ();
5511 Editor::set_edit_point ()
5516 if (!mouse_frame (where, ignored)) {
5522 if (selection->markers.empty()) {
5524 mouse_add_new_marker (where);
5529 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5532 loc->move_to (where);
5538 Editor::set_playhead_cursor ()
5540 if (entered_marker) {
5541 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5546 if (!mouse_frame (where, ignored)) {
5553 _session->request_locate (where, _session->transport_rolling());
5557 if ( Config->get_always_play_range() )
5558 cancel_time_selection();
5562 Editor::split_region ()
5564 if ( !selection->time.empty()) {
5565 separate_regions_between (selection->time);
5569 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5571 framepos_t where = get_preferred_edit_position ();
5577 split_regions_at (where, rs);
5580 struct EditorOrderRouteSorter {
5581 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5582 return a->order_key () < b->order_key ();
5587 Editor::select_next_route()
5589 if (selection->tracks.empty()) {
5590 selection->set (track_views.front());
5594 TimeAxisView* current = selection->tracks.front();
5598 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5599 if (*i == current) {
5601 if (i != track_views.end()) {
5604 current = (*(track_views.begin()));
5605 //selection->set (*(track_views.begin()));
5610 rui = dynamic_cast<RouteUI *>(current);
5611 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5613 selection->set(current);
5615 ensure_track_visible(current);
5619 Editor::select_prev_route()
5621 if (selection->tracks.empty()) {
5622 selection->set (track_views.front());
5626 TimeAxisView* current = selection->tracks.front();
5630 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5631 if (*i == current) {
5633 if (i != track_views.rend()) {
5636 current = *(track_views.rbegin());
5641 rui = dynamic_cast<RouteUI *>(current);
5642 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5644 selection->set (current);
5646 ensure_track_visible(current);
5650 Editor::ensure_track_visible(TimeAxisView *track)
5652 if (track->hidden())
5655 double const current_view_min_y = vertical_adjustment.get_value();
5656 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5658 double const track_min_y = track->y_position ();
5659 double const track_max_y = track->y_position () + track->effective_height ();
5661 if (track_min_y >= current_view_min_y &&
5662 track_max_y <= current_view_max_y) {
5668 if (track_min_y < current_view_min_y) {
5669 // Track is above the current view
5670 new_value = track_min_y;
5672 // Track is below the current view
5673 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5676 vertical_adjustment.set_value(new_value);
5680 Editor::set_loop_from_selection (bool play)
5682 if (_session == 0 || selection->time.empty()) {
5686 framepos_t start = selection->time[clicked_selection].start;
5687 framepos_t end = selection->time[clicked_selection].end;
5689 set_loop_range (start, end, _("set loop range from selection"));
5692 _session->request_play_loop (true);
5693 _session->request_locate (start, true);
5698 Editor::set_loop_from_edit_range (bool play)
5700 if (_session == 0) {
5707 if (!get_edit_op_range (start, end)) {
5711 set_loop_range (start, end, _("set loop range from edit range"));
5714 _session->request_play_loop (true);
5715 _session->request_locate (start, true);
5720 Editor::set_loop_from_region (bool play)
5722 framepos_t start = max_framepos;
5725 RegionSelection rs = get_regions_from_selection_and_entered ();
5731 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5732 if ((*i)->region()->position() < start) {
5733 start = (*i)->region()->position();
5735 if ((*i)->region()->last_frame() + 1 > end) {
5736 end = (*i)->region()->last_frame() + 1;
5740 set_loop_range (start, end, _("set loop range from region"));
5743 _session->request_play_loop (true);
5744 _session->request_locate (start, true);
5749 Editor::set_punch_from_selection ()
5751 if (_session == 0 || selection->time.empty()) {
5755 framepos_t start = selection->time[clicked_selection].start;
5756 framepos_t end = selection->time[clicked_selection].end;
5758 set_punch_range (start, end, _("set punch range from selection"));
5762 Editor::set_punch_from_edit_range ()
5764 if (_session == 0) {
5771 if (!get_edit_op_range (start, end)) {
5775 set_punch_range (start, end, _("set punch range from edit range"));
5779 Editor::set_punch_from_region ()
5781 framepos_t start = max_framepos;
5784 RegionSelection rs = get_regions_from_selection_and_entered ();
5790 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5791 if ((*i)->region()->position() < start) {
5792 start = (*i)->region()->position();
5794 if ((*i)->region()->last_frame() + 1 > end) {
5795 end = (*i)->region()->last_frame() + 1;
5799 set_punch_range (start, end, _("set punch range from region"));
5803 Editor::pitch_shift_region ()
5805 RegionSelection rs = get_regions_from_selection_and_entered ();
5807 RegionSelection audio_rs;
5808 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5809 if (dynamic_cast<AudioRegionView*> (*i)) {
5810 audio_rs.push_back (*i);
5814 if (audio_rs.empty()) {
5818 pitch_shift (audio_rs, 1.2);
5822 Editor::transpose_region ()
5824 RegionSelection rs = get_regions_from_selection_and_entered ();
5826 list<MidiRegionView*> midi_region_views;
5827 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5828 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5830 midi_region_views.push_back (mrv);
5835 int const r = d.run ();
5836 if (r != RESPONSE_ACCEPT) {
5840 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5841 (*i)->midi_region()->transpose (d.semitones ());
5846 Editor::set_tempo_from_region ()
5848 RegionSelection rs = get_regions_from_selection_and_entered ();
5850 if (!_session || rs.empty()) {
5854 RegionView* rv = rs.front();
5856 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5860 Editor::use_range_as_bar ()
5862 framepos_t start, end;
5863 if (get_edit_op_range (start, end)) {
5864 define_one_bar (start, end);
5869 Editor::define_one_bar (framepos_t start, framepos_t end)
5871 framepos_t length = end - start;
5873 const Meter& m (_session->tempo_map().meter_at (start));
5875 /* length = 1 bar */
5877 /* now we want frames per beat.
5878 we have frames per bar, and beats per bar, so ...
5881 /* XXXX METER MATH */
5883 double frames_per_beat = length / m.divisions_per_bar();
5885 /* beats per minute = */
5887 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5889 /* now decide whether to:
5891 (a) set global tempo
5892 (b) add a new tempo marker
5896 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5898 bool do_global = false;
5900 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5902 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5903 at the start, or create a new marker
5906 vector<string> options;
5907 options.push_back (_("Cancel"));
5908 options.push_back (_("Add new marker"));
5909 options.push_back (_("Set global tempo"));
5912 _("Define one bar"),
5913 _("Do you want to set the global tempo or add a new tempo marker?"),
5917 c.set_default_response (2);
5933 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5934 if the marker is at the region starter, change it, otherwise add
5939 begin_reversible_command (_("set tempo from region"));
5940 XMLNode& before (_session->tempo_map().get_state());
5943 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5944 } else if (t.frame() == start) {
5945 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5947 Timecode::BBT_Time bbt;
5948 _session->tempo_map().bbt_time (start, bbt);
5949 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5952 XMLNode& after (_session->tempo_map().get_state());
5954 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5955 commit_reversible_command ();
5959 Editor::split_region_at_transients ()
5961 AnalysisFeatureList positions;
5963 RegionSelection rs = get_regions_from_selection_and_entered ();
5965 if (!_session || rs.empty()) {
5969 _session->begin_reversible_command (_("split regions"));
5971 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5973 RegionSelection::iterator tmp;
5978 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5980 if (ar && (ar->get_transients (positions) == 0)) {
5981 split_region_at_points ((*i)->region(), positions, true);
5988 _session->commit_reversible_command ();
5993 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5995 bool use_rhythmic_rodent = false;
5997 boost::shared_ptr<Playlist> pl = r->playlist();
5999 list<boost::shared_ptr<Region> > new_regions;
6005 if (positions.empty()) {
6010 if (positions.size() > 20 && can_ferret) {
6011 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);
6012 MessageDialog msg (msgstr,
6015 Gtk::BUTTONS_OK_CANCEL);
6018 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6019 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6021 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6024 msg.set_title (_("Excessive split?"));
6027 int response = msg.run();
6033 case RESPONSE_APPLY:
6034 use_rhythmic_rodent = true;
6041 if (use_rhythmic_rodent) {
6042 show_rhythm_ferret ();
6046 AnalysisFeatureList::const_iterator x;
6048 pl->clear_changes ();
6049 pl->clear_owned_changes ();
6051 x = positions.begin();
6053 if (x == positions.end()) {
6058 pl->remove_region (r);
6062 while (x != positions.end()) {
6064 /* deal with positons that are out of scope of present region bounds */
6065 if (*x <= 0 || *x > r->length()) {
6070 /* file start = original start + how far we from the initial position ?
6073 framepos_t file_start = r->start() + pos;
6075 /* length = next position - current position
6078 framepos_t len = (*x) - pos;
6080 /* XXX we do we really want to allow even single-sample regions?
6081 shouldn't we have some kind of lower limit on region size?
6090 if (RegionFactory::region_name (new_name, r->name())) {
6094 /* do NOT announce new regions 1 by one, just wait till they are all done */
6098 plist.add (ARDOUR::Properties::start, file_start);
6099 plist.add (ARDOUR::Properties::length, len);
6100 plist.add (ARDOUR::Properties::name, new_name);
6101 plist.add (ARDOUR::Properties::layer, 0);
6103 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6104 /* because we set annouce to false, manually add the new region to the
6107 RegionFactory::map_add (nr);
6109 pl->add_region (nr, r->position() + pos);
6112 new_regions.push_front(nr);
6121 RegionFactory::region_name (new_name, r->name());
6123 /* Add the final region */
6126 plist.add (ARDOUR::Properties::start, r->start() + pos);
6127 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6128 plist.add (ARDOUR::Properties::name, new_name);
6129 plist.add (ARDOUR::Properties::layer, 0);
6131 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6132 /* because we set annouce to false, manually add the new region to the
6135 RegionFactory::map_add (nr);
6136 pl->add_region (nr, r->position() + pos);
6139 new_regions.push_front(nr);
6144 /* We might have removed regions, which alters other regions' layering_index,
6145 so we need to do a recursive diff here.
6147 vector<Command*> cmds;
6149 _session->add_commands (cmds);
6151 _session->add_command (new StatefulDiffCommand (pl));
6155 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6156 set_selected_regionview_from_region_list ((*i), Selection::Add);
6162 Editor::place_transient()
6168 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6174 framepos_t where = get_preferred_edit_position();
6176 _session->begin_reversible_command (_("place transient"));
6178 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6179 framepos_t position = (*r)->region()->position();
6180 (*r)->region()->add_transient(where - position);
6183 _session->commit_reversible_command ();
6187 Editor::remove_transient(ArdourCanvas::Item* item)
6193 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6196 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6197 _arv->remove_transient (*(float*) _line->get_data ("position"));
6201 Editor::snap_regions_to_grid ()
6203 list <boost::shared_ptr<Playlist > > used_playlists;
6205 RegionSelection rs = get_regions_from_selection_and_entered ();
6207 if (!_session || rs.empty()) {
6211 _session->begin_reversible_command (_("snap regions to grid"));
6213 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6215 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6217 if (!pl->frozen()) {
6218 /* we haven't seen this playlist before */
6220 /* remember used playlists so we can thaw them later */
6221 used_playlists.push_back(pl);
6225 framepos_t start_frame = (*r)->region()->first_frame ();
6226 snap_to (start_frame);
6227 (*r)->region()->set_position (start_frame);
6230 while (used_playlists.size() > 0) {
6231 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6233 used_playlists.pop_front();
6236 _session->commit_reversible_command ();
6240 Editor::close_region_gaps ()
6242 list <boost::shared_ptr<Playlist > > used_playlists;
6244 RegionSelection rs = get_regions_from_selection_and_entered ();
6246 if (!_session || rs.empty()) {
6250 Dialog dialog (_("Close Region Gaps"));
6253 table.set_spacings (12);
6254 table.set_border_width (12);
6255 Label* l = manage (left_aligned_label (_("Crossfade length")));
6256 table.attach (*l, 0, 1, 0, 1);
6258 SpinButton spin_crossfade (1, 0);
6259 spin_crossfade.set_range (0, 15);
6260 spin_crossfade.set_increments (1, 1);
6261 spin_crossfade.set_value (5);
6262 table.attach (spin_crossfade, 1, 2, 0, 1);
6264 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6266 l = manage (left_aligned_label (_("Pull-back length")));
6267 table.attach (*l, 0, 1, 1, 2);
6269 SpinButton spin_pullback (1, 0);
6270 spin_pullback.set_range (0, 100);
6271 spin_pullback.set_increments (1, 1);
6272 spin_pullback.set_value(30);
6273 table.attach (spin_pullback, 1, 2, 1, 2);
6275 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6277 dialog.get_vbox()->pack_start (table);
6278 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6279 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6282 if (dialog.run () == RESPONSE_CANCEL) {
6286 framepos_t crossfade_len = spin_crossfade.get_value();
6287 framepos_t pull_back_frames = spin_pullback.get_value();
6289 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6290 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6292 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6294 _session->begin_reversible_command (_("close region gaps"));
6297 boost::shared_ptr<Region> last_region;
6299 rs.sort_by_position_and_track();
6301 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6303 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6305 if (!pl->frozen()) {
6306 /* we haven't seen this playlist before */
6308 /* remember used playlists so we can thaw them later */
6309 used_playlists.push_back(pl);
6313 framepos_t position = (*r)->region()->position();
6315 if (idx == 0 || position < last_region->position()){
6316 last_region = (*r)->region();
6321 (*r)->region()->trim_front( (position - pull_back_frames));
6322 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6324 last_region = (*r)->region();
6329 while (used_playlists.size() > 0) {
6330 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6332 used_playlists.pop_front();
6335 _session->commit_reversible_command ();
6339 Editor::tab_to_transient (bool forward)
6341 AnalysisFeatureList positions;
6343 RegionSelection rs = get_regions_from_selection_and_entered ();
6349 framepos_t pos = _session->audible_frame ();
6351 if (!selection->tracks.empty()) {
6353 /* don't waste time searching for transients in duplicate playlists.
6356 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6358 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6360 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6363 boost::shared_ptr<Track> tr = rtv->track();
6365 boost::shared_ptr<Playlist> pl = tr->playlist ();
6367 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6370 positions.push_back (result);
6383 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6384 (*r)->region()->get_transients (positions);
6388 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6391 AnalysisFeatureList::iterator x;
6393 for (x = positions.begin(); x != positions.end(); ++x) {
6399 if (x != positions.end ()) {
6400 _session->request_locate (*x);
6404 AnalysisFeatureList::reverse_iterator x;
6406 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6412 if (x != positions.rend ()) {
6413 _session->request_locate (*x);
6419 Editor::playhead_forward_to_grid ()
6425 framepos_t pos = playhead_cursor->current_frame ();
6426 if (pos < max_framepos - 1) {
6428 snap_to_internal (pos, 1, false);
6429 _session->request_locate (pos);
6435 Editor::playhead_backward_to_grid ()
6441 framepos_t pos = playhead_cursor->current_frame ();
6444 snap_to_internal (pos, -1, false);
6445 _session->request_locate (pos);
6450 Editor::set_track_height (Height h)
6452 TrackSelection& ts (selection->tracks);
6454 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6455 (*x)->set_height_enum (h);
6460 Editor::toggle_tracks_active ()
6462 TrackSelection& ts (selection->tracks);
6464 bool target = false;
6470 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6471 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6475 target = !rtv->_route->active();
6478 rtv->_route->set_active (target, this);
6484 Editor::remove_tracks ()
6486 TrackSelection& ts (selection->tracks);
6492 vector<string> choices;
6496 const char* trackstr;
6498 vector<boost::shared_ptr<Route> > routes;
6499 bool special_bus = false;
6501 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6502 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6506 if (rtv->is_track()) {
6511 routes.push_back (rtv->_route);
6513 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6518 if (special_bus && !Config->get_allow_special_bus_removal()) {
6519 MessageDialog msg (_("That would be bad news ...."),
6523 msg.set_secondary_text (string_compose (_(
6524 "Removing the master or monitor bus is such a bad idea\n\
6525 that %1 is not going to allow it.\n\
6527 If you really want to do this sort of thing\n\
6528 edit your ardour.rc file to set the\n\
6529 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6536 if (ntracks + nbusses == 0) {
6541 trackstr = _("tracks");
6543 trackstr = _("track");
6547 busstr = _("busses");
6554 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6555 "(You may also lose the playlists associated with the %2)\n\n"
6556 "This action cannot be undone, and the session file will be overwritten!"),
6557 ntracks, trackstr, nbusses, busstr);
6559 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6560 "(You may also lose the playlists associated with the %2)\n\n"
6561 "This action cannot be undone, and the session file will be overwritten!"),
6564 } else if (nbusses) {
6565 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6566 "This action cannot be undon, and the session file will be overwritten"),
6570 choices.push_back (_("No, do nothing."));
6571 if (ntracks + nbusses > 1) {
6572 choices.push_back (_("Yes, remove them."));
6574 choices.push_back (_("Yes, remove it."));
6579 title = string_compose (_("Remove %1"), trackstr);
6581 title = string_compose (_("Remove %1"), busstr);
6584 Choice prompter (title, prompt, choices);
6586 if (prompter.run () != 1) {
6590 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6591 _session->remove_route (*x);
6596 Editor::do_insert_time ()
6598 if (selection->tracks.empty()) {
6602 InsertTimeDialog d (*this);
6603 int response = d.run ();
6605 if (response != RESPONSE_OK) {
6609 if (d.distance() == 0) {
6613 InsertTimeOption opt = d.intersected_region_action ();
6616 get_preferred_edit_position(),
6622 d.move_glued_markers(),
6623 d.move_locked_markers(),
6629 Editor::insert_time (
6630 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6631 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6634 bool commit = false;
6636 if (Config->get_edit_mode() == Lock) {
6640 begin_reversible_command (_("insert time"));
6642 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6644 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6648 /* don't operate on any playlist more than once, which could
6649 * happen if "all playlists" is enabled, but there is more
6650 * than 1 track using playlists "from" a given track.
6653 set<boost::shared_ptr<Playlist> > pl;
6655 if (all_playlists) {
6656 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6658 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6659 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6664 if ((*x)->playlist ()) {
6665 pl.insert ((*x)->playlist ());
6669 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6671 (*i)->clear_changes ();
6672 (*i)->clear_owned_changes ();
6674 if (opt == SplitIntersected) {
6678 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6680 vector<Command*> cmds;
6682 _session->add_commands (cmds);
6684 _session->add_command (new StatefulDiffCommand (*i));
6689 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6691 rtav->route ()->shift (pos, frames);
6699 XMLNode& before (_session->locations()->get_state());
6700 Locations::LocationList copy (_session->locations()->list());
6702 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6704 Locations::LocationList::const_iterator tmp;
6706 bool const was_locked = (*i)->locked ();
6707 if (locked_markers_too) {
6711 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6713 if ((*i)->start() >= pos) {
6714 (*i)->set_start ((*i)->start() + frames);
6715 if (!(*i)->is_mark()) {
6716 (*i)->set_end ((*i)->end() + frames);
6729 XMLNode& after (_session->locations()->get_state());
6730 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6735 _session->tempo_map().insert_time (pos, frames);
6739 commit_reversible_command ();
6744 Editor::fit_selected_tracks ()
6746 if (!selection->tracks.empty()) {
6747 fit_tracks (selection->tracks);
6751 /* no selected tracks - use tracks with selected regions */
6753 if (!selection->regions.empty()) {
6754 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6755 tvl.push_back (&(*r)->get_time_axis_view ());
6761 } else if (internal_editing()) {
6762 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6765 if (entered_track) {
6766 tvl.push_back (entered_track);
6774 Editor::fit_tracks (TrackViewList & tracks)
6776 if (tracks.empty()) {
6780 uint32_t child_heights = 0;
6781 int visible_tracks = 0;
6783 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6785 if (!(*t)->marked_for_display()) {
6789 child_heights += (*t)->effective_height() - (*t)->current_height();
6793 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6794 double first_y_pos = DBL_MAX;
6796 if (h < TimeAxisView::preset_height (HeightSmall)) {
6797 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6798 /* too small to be displayed */
6802 undo_visual_stack.push_back (current_visual_state (true));
6803 no_save_visual = true;
6805 /* build a list of all tracks, including children */
6808 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6810 TimeAxisView::Children c = (*i)->get_child_list ();
6811 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6812 all.push_back (j->get());
6816 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6818 bool prev_was_selected = false;
6819 bool is_selected = tracks.contains (all.front());
6820 bool next_is_selected;
6822 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6824 TrackViewList::iterator next;
6829 if (next != all.end()) {
6830 next_is_selected = tracks.contains (*next);
6832 next_is_selected = false;
6835 if ((*t)->marked_for_display ()) {
6837 (*t)->set_height (h);
6838 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6840 if (prev_was_selected && next_is_selected) {
6841 hide_track_in_display (*t);
6846 prev_was_selected = is_selected;
6847 is_selected = next_is_selected;
6851 set the controls_layout height now, because waiting for its size
6852 request signal handler will cause the vertical adjustment setting to fail
6855 controls_layout.property_height () = _full_canvas_height;
6856 vertical_adjustment.set_value (first_y_pos);
6858 redo_visual_stack.push_back (current_visual_state (true));
6862 Editor::save_visual_state (uint32_t n)
6864 while (visual_states.size() <= n) {
6865 visual_states.push_back (0);
6868 if (visual_states[n] != 0) {
6869 delete visual_states[n];
6872 visual_states[n] = current_visual_state (true);
6877 Editor::goto_visual_state (uint32_t n)
6879 if (visual_states.size() <= n) {
6883 if (visual_states[n] == 0) {
6887 use_visual_state (*visual_states[n]);
6891 Editor::start_visual_state_op (uint32_t n)
6893 save_visual_state (n);
6895 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6897 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6898 pup->set_text (buf);
6903 Editor::cancel_visual_state_op (uint32_t n)
6905 goto_visual_state (n);
6909 Editor::toggle_region_mute ()
6911 if (_ignore_region_action) {
6915 RegionSelection rs = get_regions_from_selection_and_entered ();
6921 if (rs.size() > 1) {
6922 begin_reversible_command (_("mute regions"));
6924 begin_reversible_command (_("mute region"));
6927 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6929 (*i)->region()->playlist()->clear_changes ();
6930 (*i)->region()->set_muted (!(*i)->region()->muted ());
6931 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6935 commit_reversible_command ();
6939 Editor::combine_regions ()
6941 /* foreach track with selected regions, take all selected regions
6942 and join them into a new region containing the subregions (as a
6946 typedef set<RouteTimeAxisView*> RTVS;
6949 if (selection->regions.empty()) {
6953 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6954 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6957 tracks.insert (rtv);
6961 begin_reversible_command (_("combine regions"));
6963 vector<RegionView*> new_selection;
6965 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6968 if ((rv = (*i)->combine_regions ()) != 0) {
6969 new_selection.push_back (rv);
6973 selection->clear_regions ();
6974 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6975 selection->add (*i);
6978 commit_reversible_command ();
6982 Editor::uncombine_regions ()
6984 typedef set<RouteTimeAxisView*> RTVS;
6987 if (selection->regions.empty()) {
6991 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6992 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6995 tracks.insert (rtv);
6999 begin_reversible_command (_("uncombine regions"));
7001 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7002 (*i)->uncombine_regions ();
7005 commit_reversible_command ();
7009 Editor::toggle_midi_input_active (bool flip_others)
7012 boost::shared_ptr<RouteList> rl (new RouteList);
7014 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7015 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7021 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7024 rl->push_back (rtav->route());
7025 onoff = !mt->input_active();
7029 _session->set_exclusive_input_active (rl, onoff, flip_others);