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);
4821 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4822 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4824 playlist->clear_changes ();
4825 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4826 _session->add_command(new StatefulDiffCommand (playlist));
4832 commit_reversible_command ();
4834 set_canvas_cursor (current_canvas_cursor);
4838 Editor::quantize_region ()
4840 int selected_midi_region_cnt = 0;
4846 RegionSelection rs = get_regions_from_selection_and_entered ();
4852 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4853 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4855 selected_midi_region_cnt++;
4859 if (selected_midi_region_cnt == 0) {
4863 QuantizeDialog* qd = new QuantizeDialog (*this);
4866 const int r = qd->run ();
4869 if (r == Gtk::RESPONSE_OK) {
4870 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4871 qd->start_grid_size(), qd->end_grid_size(),
4872 qd->strength(), qd->swing(), qd->threshold());
4874 apply_midi_note_edit_op (quant);
4879 Editor::insert_patch_change (bool from_context)
4881 RegionSelection rs = get_regions_from_selection_and_entered ();
4887 const framepos_t p = get_preferred_edit_position (false, from_context);
4889 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4890 there may be more than one, but the PatchChangeDialog can only offer
4891 one set of patch menus.
4893 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4895 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4896 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4898 if (d.run() == RESPONSE_CANCEL) {
4902 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4903 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4905 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4906 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4913 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4915 RegionSelection rs = get_regions_from_selection_and_entered ();
4921 begin_reversible_command (command);
4923 set_canvas_cursor (_cursors->wait);
4927 int const N = rs.size ();
4929 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4930 RegionSelection::iterator tmp = r;
4933 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4935 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4938 progress->descend (1.0 / N);
4941 if (arv->audio_region()->apply (filter, progress) == 0) {
4943 playlist->clear_changes ();
4944 playlist->clear_owned_changes ();
4946 if (filter.results.empty ()) {
4948 /* no regions returned; remove the old one */
4949 playlist->remove_region (arv->region ());
4953 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4955 /* first region replaces the old one */
4956 playlist->replace_region (arv->region(), *res, (*res)->position());
4960 while (res != filter.results.end()) {
4961 playlist->add_region (*res, (*res)->position());
4967 /* We might have removed regions, which alters other regions' layering_index,
4968 so we need to do a recursive diff here.
4970 vector<Command*> cmds;
4971 playlist->rdiff (cmds);
4972 _session->add_commands (cmds);
4974 _session->add_command(new StatefulDiffCommand (playlist));
4980 progress->ascend ();
4988 commit_reversible_command ();
4991 set_canvas_cursor (current_canvas_cursor);
4995 Editor::external_edit_region ()
5001 Editor::reset_region_gain_envelopes ()
5003 RegionSelection rs = get_regions_from_selection_and_entered ();
5005 if (!_session || rs.empty()) {
5009 _session->begin_reversible_command (_("reset region gain"));
5011 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5012 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5014 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5015 XMLNode& before (alist->get_state());
5017 arv->audio_region()->set_default_envelope ();
5018 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5022 _session->commit_reversible_command ();
5026 Editor::set_region_gain_visibility (RegionView* rv)
5028 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5030 arv->update_envelope_visibility();
5035 Editor::set_gain_envelope_visibility ()
5041 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5042 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5044 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5050 Editor::toggle_gain_envelope_active ()
5052 if (_ignore_region_action) {
5056 RegionSelection rs = get_regions_from_selection_and_entered ();
5058 if (!_session || rs.empty()) {
5062 _session->begin_reversible_command (_("region gain envelope active"));
5064 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5065 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5067 arv->region()->clear_changes ();
5068 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5069 _session->add_command (new StatefulDiffCommand (arv->region()));
5073 _session->commit_reversible_command ();
5077 Editor::toggle_region_lock ()
5079 if (_ignore_region_action) {
5083 RegionSelection rs = get_regions_from_selection_and_entered ();
5085 if (!_session || rs.empty()) {
5089 _session->begin_reversible_command (_("toggle region lock"));
5091 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5092 (*i)->region()->clear_changes ();
5093 (*i)->region()->set_locked (!(*i)->region()->locked());
5094 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5097 _session->commit_reversible_command ();
5101 Editor::toggle_region_video_lock ()
5103 if (_ignore_region_action) {
5107 RegionSelection rs = get_regions_from_selection_and_entered ();
5109 if (!_session || rs.empty()) {
5113 _session->begin_reversible_command (_("Toggle Video Lock"));
5115 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5116 (*i)->region()->clear_changes ();
5117 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5118 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5121 _session->commit_reversible_command ();
5125 Editor::toggle_region_lock_style ()
5127 if (_ignore_region_action) {
5131 RegionSelection rs = get_regions_from_selection_and_entered ();
5133 if (!_session || rs.empty()) {
5137 _session->begin_reversible_command (_("region lock style"));
5139 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5140 (*i)->region()->clear_changes ();
5141 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5142 (*i)->region()->set_position_lock_style (ns);
5143 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5146 _session->commit_reversible_command ();
5150 Editor::toggle_opaque_region ()
5152 if (_ignore_region_action) {
5156 RegionSelection rs = get_regions_from_selection_and_entered ();
5158 if (!_session || rs.empty()) {
5162 _session->begin_reversible_command (_("change region opacity"));
5164 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5165 (*i)->region()->clear_changes ();
5166 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5167 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5170 _session->commit_reversible_command ();
5174 Editor::toggle_record_enable ()
5176 bool new_state = false;
5178 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5179 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5182 if (!rtav->is_track())
5186 new_state = !rtav->track()->record_enabled();
5190 rtav->track()->set_record_enabled (new_state, this);
5195 Editor::toggle_solo ()
5197 bool new_state = false;
5199 boost::shared_ptr<RouteList> rl (new RouteList);
5201 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5202 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5209 new_state = !rtav->route()->soloed ();
5213 rl->push_back (rtav->route());
5216 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5220 Editor::toggle_mute ()
5222 bool new_state = false;
5224 boost::shared_ptr<RouteList> rl (new RouteList);
5226 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5227 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5234 new_state = !rtav->route()->muted();
5238 rl->push_back (rtav->route());
5241 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5245 Editor::toggle_solo_isolate ()
5250 Editor::set_fade_length (bool in)
5252 RegionSelection rs = get_regions_from_selection_and_entered ();
5258 /* we need a region to measure the offset from the start */
5260 RegionView* rv = rs.front ();
5262 framepos_t pos = get_preferred_edit_position();
5266 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5267 /* edit point is outside the relevant region */
5272 if (pos <= rv->region()->position()) {
5276 len = pos - rv->region()->position();
5277 cmd = _("set fade in length");
5279 if (pos >= rv->region()->last_frame()) {
5283 len = rv->region()->last_frame() - pos;
5284 cmd = _("set fade out length");
5287 begin_reversible_command (cmd);
5289 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5290 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5296 boost::shared_ptr<AutomationList> alist;
5298 alist = tmp->audio_region()->fade_in();
5300 alist = tmp->audio_region()->fade_out();
5303 XMLNode &before = alist->get_state();
5306 tmp->audio_region()->set_fade_in_length (len);
5307 tmp->audio_region()->set_fade_in_active (true);
5309 tmp->audio_region()->set_fade_out_length (len);
5310 tmp->audio_region()->set_fade_out_active (true);
5313 XMLNode &after = alist->get_state();
5314 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5317 commit_reversible_command ();
5321 Editor::set_fade_in_shape (FadeShape shape)
5323 RegionSelection rs = get_regions_from_selection_and_entered ();
5329 begin_reversible_command (_("set fade in shape"));
5331 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5332 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5338 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5339 XMLNode &before = alist->get_state();
5341 tmp->audio_region()->set_fade_in_shape (shape);
5343 XMLNode &after = alist->get_state();
5344 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5347 commit_reversible_command ();
5352 Editor::set_fade_out_shape (FadeShape shape)
5354 RegionSelection rs = get_regions_from_selection_and_entered ();
5360 begin_reversible_command (_("set fade out shape"));
5362 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5363 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5369 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5370 XMLNode &before = alist->get_state();
5372 tmp->audio_region()->set_fade_out_shape (shape);
5374 XMLNode &after = alist->get_state();
5375 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5378 commit_reversible_command ();
5382 Editor::set_fade_in_active (bool yn)
5384 RegionSelection rs = get_regions_from_selection_and_entered ();
5390 begin_reversible_command (_("set fade in active"));
5392 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5393 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5400 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5402 ar->clear_changes ();
5403 ar->set_fade_in_active (yn);
5404 _session->add_command (new StatefulDiffCommand (ar));
5407 commit_reversible_command ();
5411 Editor::set_fade_out_active (bool yn)
5413 RegionSelection rs = get_regions_from_selection_and_entered ();
5419 begin_reversible_command (_("set fade out active"));
5421 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5422 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5428 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5430 ar->clear_changes ();
5431 ar->set_fade_out_active (yn);
5432 _session->add_command(new StatefulDiffCommand (ar));
5435 commit_reversible_command ();
5439 Editor::toggle_region_fades (int dir)
5441 if (_ignore_region_action) {
5445 boost::shared_ptr<AudioRegion> ar;
5448 RegionSelection rs = get_regions_from_selection_and_entered ();
5454 RegionSelection::iterator i;
5455 for (i = rs.begin(); i != rs.end(); ++i) {
5456 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5458 yn = ar->fade_out_active ();
5460 yn = ar->fade_in_active ();
5466 if (i == rs.end()) {
5470 /* XXX should this undo-able? */
5472 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5473 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5476 if (dir == 1 || dir == 0) {
5477 ar->set_fade_in_active (!yn);
5480 if (dir == -1 || dir == 0) {
5481 ar->set_fade_out_active (!yn);
5487 /** Update region fade visibility after its configuration has been changed */
5489 Editor::update_region_fade_visibility ()
5491 bool _fade_visibility = _session->config.get_show_region_fades ();
5493 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5494 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5496 if (_fade_visibility) {
5497 v->audio_view()->show_all_fades ();
5499 v->audio_view()->hide_all_fades ();
5506 Editor::set_edit_point ()
5511 if (!mouse_frame (where, ignored)) {
5517 if (selection->markers.empty()) {
5519 mouse_add_new_marker (where);
5524 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5527 loc->move_to (where);
5533 Editor::set_playhead_cursor ()
5535 if (entered_marker) {
5536 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5541 if (!mouse_frame (where, ignored)) {
5548 _session->request_locate (where, _session->transport_rolling());
5552 if ( Config->get_always_play_range() )
5553 cancel_time_selection();
5557 Editor::split_region ()
5559 if ( !selection->time.empty()) {
5560 separate_regions_between (selection->time);
5564 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5566 framepos_t where = get_preferred_edit_position ();
5572 split_regions_at (where, rs);
5575 struct EditorOrderRouteSorter {
5576 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5577 return a->order_key () < b->order_key ();
5582 Editor::select_next_route()
5584 if (selection->tracks.empty()) {
5585 selection->set (track_views.front());
5589 TimeAxisView* current = selection->tracks.front();
5593 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5594 if (*i == current) {
5596 if (i != track_views.end()) {
5599 current = (*(track_views.begin()));
5600 //selection->set (*(track_views.begin()));
5605 rui = dynamic_cast<RouteUI *>(current);
5606 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5608 selection->set(current);
5610 ensure_track_visible(current);
5614 Editor::select_prev_route()
5616 if (selection->tracks.empty()) {
5617 selection->set (track_views.front());
5621 TimeAxisView* current = selection->tracks.front();
5625 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5626 if (*i == current) {
5628 if (i != track_views.rend()) {
5631 current = *(track_views.rbegin());
5636 rui = dynamic_cast<RouteUI *>(current);
5637 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5639 selection->set (current);
5641 ensure_track_visible(current);
5645 Editor::ensure_track_visible(TimeAxisView *track)
5647 if (track->hidden())
5650 double const current_view_min_y = vertical_adjustment.get_value();
5651 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5653 double const track_min_y = track->y_position ();
5654 double const track_max_y = track->y_position () + track->effective_height ();
5656 if (track_min_y >= current_view_min_y &&
5657 track_max_y <= current_view_max_y) {
5663 if (track_min_y < current_view_min_y) {
5664 // Track is above the current view
5665 new_value = track_min_y;
5667 // Track is below the current view
5668 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5671 vertical_adjustment.set_value(new_value);
5675 Editor::set_loop_from_selection (bool play)
5677 if (_session == 0 || selection->time.empty()) {
5681 framepos_t start = selection->time[clicked_selection].start;
5682 framepos_t end = selection->time[clicked_selection].end;
5684 set_loop_range (start, end, _("set loop range from selection"));
5687 _session->request_play_loop (true);
5688 _session->request_locate (start, true);
5693 Editor::set_loop_from_edit_range (bool play)
5695 if (_session == 0) {
5702 if (!get_edit_op_range (start, end)) {
5706 set_loop_range (start, end, _("set loop range from edit range"));
5709 _session->request_play_loop (true);
5710 _session->request_locate (start, true);
5715 Editor::set_loop_from_region (bool play)
5717 framepos_t start = max_framepos;
5720 RegionSelection rs = get_regions_from_selection_and_entered ();
5726 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5727 if ((*i)->region()->position() < start) {
5728 start = (*i)->region()->position();
5730 if ((*i)->region()->last_frame() + 1 > end) {
5731 end = (*i)->region()->last_frame() + 1;
5735 set_loop_range (start, end, _("set loop range from region"));
5738 _session->request_play_loop (true);
5739 _session->request_locate (start, true);
5744 Editor::set_punch_from_selection ()
5746 if (_session == 0 || selection->time.empty()) {
5750 framepos_t start = selection->time[clicked_selection].start;
5751 framepos_t end = selection->time[clicked_selection].end;
5753 set_punch_range (start, end, _("set punch range from selection"));
5757 Editor::set_punch_from_edit_range ()
5759 if (_session == 0) {
5766 if (!get_edit_op_range (start, end)) {
5770 set_punch_range (start, end, _("set punch range from edit range"));
5774 Editor::set_punch_from_region ()
5776 framepos_t start = max_framepos;
5779 RegionSelection rs = get_regions_from_selection_and_entered ();
5785 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5786 if ((*i)->region()->position() < start) {
5787 start = (*i)->region()->position();
5789 if ((*i)->region()->last_frame() + 1 > end) {
5790 end = (*i)->region()->last_frame() + 1;
5794 set_punch_range (start, end, _("set punch range from region"));
5798 Editor::pitch_shift_region ()
5800 RegionSelection rs = get_regions_from_selection_and_entered ();
5802 RegionSelection audio_rs;
5803 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5804 if (dynamic_cast<AudioRegionView*> (*i)) {
5805 audio_rs.push_back (*i);
5809 if (audio_rs.empty()) {
5813 pitch_shift (audio_rs, 1.2);
5817 Editor::transpose_region ()
5819 RegionSelection rs = get_regions_from_selection_and_entered ();
5821 list<MidiRegionView*> midi_region_views;
5822 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5823 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5825 midi_region_views.push_back (mrv);
5830 int const r = d.run ();
5831 if (r != RESPONSE_ACCEPT) {
5835 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5836 (*i)->midi_region()->transpose (d.semitones ());
5841 Editor::set_tempo_from_region ()
5843 RegionSelection rs = get_regions_from_selection_and_entered ();
5845 if (!_session || rs.empty()) {
5849 RegionView* rv = rs.front();
5851 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5855 Editor::use_range_as_bar ()
5857 framepos_t start, end;
5858 if (get_edit_op_range (start, end)) {
5859 define_one_bar (start, end);
5864 Editor::define_one_bar (framepos_t start, framepos_t end)
5866 framepos_t length = end - start;
5868 const Meter& m (_session->tempo_map().meter_at (start));
5870 /* length = 1 bar */
5872 /* now we want frames per beat.
5873 we have frames per bar, and beats per bar, so ...
5876 /* XXXX METER MATH */
5878 double frames_per_beat = length / m.divisions_per_bar();
5880 /* beats per minute = */
5882 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5884 /* now decide whether to:
5886 (a) set global tempo
5887 (b) add a new tempo marker
5891 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5893 bool do_global = false;
5895 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5897 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5898 at the start, or create a new marker
5901 vector<string> options;
5902 options.push_back (_("Cancel"));
5903 options.push_back (_("Add new marker"));
5904 options.push_back (_("Set global tempo"));
5907 _("Define one bar"),
5908 _("Do you want to set the global tempo or add a new tempo marker?"),
5912 c.set_default_response (2);
5928 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5929 if the marker is at the region starter, change it, otherwise add
5934 begin_reversible_command (_("set tempo from region"));
5935 XMLNode& before (_session->tempo_map().get_state());
5938 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5939 } else if (t.frame() == start) {
5940 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5942 Timecode::BBT_Time bbt;
5943 _session->tempo_map().bbt_time (start, bbt);
5944 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5947 XMLNode& after (_session->tempo_map().get_state());
5949 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5950 commit_reversible_command ();
5954 Editor::split_region_at_transients ()
5956 AnalysisFeatureList positions;
5958 RegionSelection rs = get_regions_from_selection_and_entered ();
5960 if (!_session || rs.empty()) {
5964 _session->begin_reversible_command (_("split regions"));
5966 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5968 RegionSelection::iterator tmp;
5973 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5975 if (ar && (ar->get_transients (positions) == 0)) {
5976 split_region_at_points ((*i)->region(), positions, true);
5983 _session->commit_reversible_command ();
5988 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5990 bool use_rhythmic_rodent = false;
5992 boost::shared_ptr<Playlist> pl = r->playlist();
5994 list<boost::shared_ptr<Region> > new_regions;
6000 if (positions.empty()) {
6005 if (positions.size() > 20 && can_ferret) {
6006 std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6007 MessageDialog msg (msgstr,
6010 Gtk::BUTTONS_OK_CANCEL);
6013 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6014 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6016 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6019 msg.set_title (_("Excessive split?"));
6022 int response = msg.run();
6028 case RESPONSE_APPLY:
6029 use_rhythmic_rodent = true;
6036 if (use_rhythmic_rodent) {
6037 show_rhythm_ferret ();
6041 AnalysisFeatureList::const_iterator x;
6043 pl->clear_changes ();
6044 pl->clear_owned_changes ();
6046 x = positions.begin();
6048 if (x == positions.end()) {
6053 pl->remove_region (r);
6057 while (x != positions.end()) {
6059 /* deal with positons that are out of scope of present region bounds */
6060 if (*x <= 0 || *x > r->length()) {
6065 /* file start = original start + how far we from the initial position ?
6068 framepos_t file_start = r->start() + pos;
6070 /* length = next position - current position
6073 framepos_t len = (*x) - pos;
6075 /* XXX we do we really want to allow even single-sample regions?
6076 shouldn't we have some kind of lower limit on region size?
6085 if (RegionFactory::region_name (new_name, r->name())) {
6089 /* do NOT announce new regions 1 by one, just wait till they are all done */
6093 plist.add (ARDOUR::Properties::start, file_start);
6094 plist.add (ARDOUR::Properties::length, len);
6095 plist.add (ARDOUR::Properties::name, new_name);
6096 plist.add (ARDOUR::Properties::layer, 0);
6098 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6099 /* because we set annouce to false, manually add the new region to the
6102 RegionFactory::map_add (nr);
6104 pl->add_region (nr, r->position() + pos);
6107 new_regions.push_front(nr);
6116 RegionFactory::region_name (new_name, r->name());
6118 /* Add the final region */
6121 plist.add (ARDOUR::Properties::start, r->start() + pos);
6122 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6123 plist.add (ARDOUR::Properties::name, new_name);
6124 plist.add (ARDOUR::Properties::layer, 0);
6126 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6127 /* because we set annouce to false, manually add the new region to the
6130 RegionFactory::map_add (nr);
6131 pl->add_region (nr, r->position() + pos);
6134 new_regions.push_front(nr);
6139 /* We might have removed regions, which alters other regions' layering_index,
6140 so we need to do a recursive diff here.
6142 vector<Command*> cmds;
6144 _session->add_commands (cmds);
6146 _session->add_command (new StatefulDiffCommand (pl));
6150 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6151 set_selected_regionview_from_region_list ((*i), Selection::Add);
6157 Editor::place_transient()
6163 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6169 framepos_t where = get_preferred_edit_position();
6171 _session->begin_reversible_command (_("place transient"));
6173 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6174 framepos_t position = (*r)->region()->position();
6175 (*r)->region()->add_transient(where - position);
6178 _session->commit_reversible_command ();
6182 Editor::remove_transient(ArdourCanvas::Item* item)
6188 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6191 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6192 _arv->remove_transient (*(float*) _line->get_data ("position"));
6196 Editor::snap_regions_to_grid ()
6198 list <boost::shared_ptr<Playlist > > used_playlists;
6200 RegionSelection rs = get_regions_from_selection_and_entered ();
6202 if (!_session || rs.empty()) {
6206 _session->begin_reversible_command (_("snap regions to grid"));
6208 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6210 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6212 if (!pl->frozen()) {
6213 /* we haven't seen this playlist before */
6215 /* remember used playlists so we can thaw them later */
6216 used_playlists.push_back(pl);
6220 framepos_t start_frame = (*r)->region()->first_frame ();
6221 snap_to (start_frame);
6222 (*r)->region()->set_position (start_frame);
6225 while (used_playlists.size() > 0) {
6226 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6228 used_playlists.pop_front();
6231 _session->commit_reversible_command ();
6235 Editor::close_region_gaps ()
6237 list <boost::shared_ptr<Playlist > > used_playlists;
6239 RegionSelection rs = get_regions_from_selection_and_entered ();
6241 if (!_session || rs.empty()) {
6245 Dialog dialog (_("Close Region Gaps"));
6248 table.set_spacings (12);
6249 table.set_border_width (12);
6250 Label* l = manage (left_aligned_label (_("Crossfade length")));
6251 table.attach (*l, 0, 1, 0, 1);
6253 SpinButton spin_crossfade (1, 0);
6254 spin_crossfade.set_range (0, 15);
6255 spin_crossfade.set_increments (1, 1);
6256 spin_crossfade.set_value (5);
6257 table.attach (spin_crossfade, 1, 2, 0, 1);
6259 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6261 l = manage (left_aligned_label (_("Pull-back length")));
6262 table.attach (*l, 0, 1, 1, 2);
6264 SpinButton spin_pullback (1, 0);
6265 spin_pullback.set_range (0, 100);
6266 spin_pullback.set_increments (1, 1);
6267 spin_pullback.set_value(30);
6268 table.attach (spin_pullback, 1, 2, 1, 2);
6270 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6272 dialog.get_vbox()->pack_start (table);
6273 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6274 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6277 if (dialog.run () == RESPONSE_CANCEL) {
6281 framepos_t crossfade_len = spin_crossfade.get_value();
6282 framepos_t pull_back_frames = spin_pullback.get_value();
6284 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6285 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6287 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6289 _session->begin_reversible_command (_("close region gaps"));
6292 boost::shared_ptr<Region> last_region;
6294 rs.sort_by_position_and_track();
6296 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6298 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6300 if (!pl->frozen()) {
6301 /* we haven't seen this playlist before */
6303 /* remember used playlists so we can thaw them later */
6304 used_playlists.push_back(pl);
6308 framepos_t position = (*r)->region()->position();
6310 if (idx == 0 || position < last_region->position()){
6311 last_region = (*r)->region();
6316 (*r)->region()->trim_front( (position - pull_back_frames));
6317 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6319 last_region = (*r)->region();
6324 while (used_playlists.size() > 0) {
6325 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6327 used_playlists.pop_front();
6330 _session->commit_reversible_command ();
6334 Editor::tab_to_transient (bool forward)
6336 AnalysisFeatureList positions;
6338 RegionSelection rs = get_regions_from_selection_and_entered ();
6344 framepos_t pos = _session->audible_frame ();
6346 if (!selection->tracks.empty()) {
6348 /* don't waste time searching for transients in duplicate playlists.
6351 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6353 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6355 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6358 boost::shared_ptr<Track> tr = rtv->track();
6360 boost::shared_ptr<Playlist> pl = tr->playlist ();
6362 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6365 positions.push_back (result);
6378 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6379 (*r)->region()->get_transients (positions);
6383 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6386 AnalysisFeatureList::iterator x;
6388 for (x = positions.begin(); x != positions.end(); ++x) {
6394 if (x != positions.end ()) {
6395 _session->request_locate (*x);
6399 AnalysisFeatureList::reverse_iterator x;
6401 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6407 if (x != positions.rend ()) {
6408 _session->request_locate (*x);
6414 Editor::playhead_forward_to_grid ()
6420 framepos_t pos = playhead_cursor->current_frame ();
6421 if (pos < max_framepos - 1) {
6423 snap_to_internal (pos, 1, false);
6424 _session->request_locate (pos);
6430 Editor::playhead_backward_to_grid ()
6436 framepos_t pos = playhead_cursor->current_frame ();
6439 snap_to_internal (pos, -1, false);
6440 _session->request_locate (pos);
6445 Editor::set_track_height (Height h)
6447 TrackSelection& ts (selection->tracks);
6449 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6450 (*x)->set_height_enum (h);
6455 Editor::toggle_tracks_active ()
6457 TrackSelection& ts (selection->tracks);
6459 bool target = false;
6465 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6466 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6470 target = !rtv->_route->active();
6473 rtv->_route->set_active (target, this);
6479 Editor::remove_tracks ()
6481 TrackSelection& ts (selection->tracks);
6487 vector<string> choices;
6491 const char* trackstr;
6493 vector<boost::shared_ptr<Route> > routes;
6494 bool special_bus = false;
6496 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6497 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6499 if (rtv->is_track()) {
6505 routes.push_back (rtv->_route);
6507 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6512 if (special_bus && !Config->get_allow_special_bus_removal()) {
6513 MessageDialog msg (_("That would be bad news ...."),
6517 msg.set_secondary_text (string_compose (_(
6518 "Removing the master or monitor bus is such a bad idea\n\
6519 that %1 is not going to allow it.\n\
6521 If you really want to do this sort of thing\n\
6522 edit your ardour.rc file to set the\n\
6523 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6530 if (ntracks + nbusses == 0) {
6535 trackstr = _("tracks");
6537 trackstr = _("track");
6541 busstr = _("busses");
6548 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6549 "(You may also lose the playlists associated with the %2)\n\n"
6550 "This action cannot be undone, and the session file will be overwritten!"),
6551 ntracks, trackstr, nbusses, busstr);
6553 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6554 "(You may also lose the playlists associated with the %2)\n\n"
6555 "This action cannot be undone, and the session file will be overwritten!"),
6558 } else if (nbusses) {
6559 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6560 "This action cannot be undon, and the session file will be overwritten"),
6564 choices.push_back (_("No, do nothing."));
6565 if (ntracks + nbusses > 1) {
6566 choices.push_back (_("Yes, remove them."));
6568 choices.push_back (_("Yes, remove it."));
6573 title = string_compose (_("Remove %1"), trackstr);
6575 title = string_compose (_("Remove %1"), busstr);
6578 Choice prompter (title, prompt, choices);
6580 if (prompter.run () != 1) {
6584 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6585 _session->remove_route (*x);
6590 Editor::do_insert_time ()
6592 if (selection->tracks.empty()) {
6596 InsertTimeDialog d (*this);
6597 int response = d.run ();
6599 if (response != RESPONSE_OK) {
6603 if (d.distance() == 0) {
6607 InsertTimeOption opt = d.intersected_region_action ();
6610 get_preferred_edit_position(),
6616 d.move_glued_markers(),
6617 d.move_locked_markers(),
6623 Editor::insert_time (
6624 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6625 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6628 bool commit = false;
6630 if (Config->get_edit_mode() == Lock) {
6634 begin_reversible_command (_("insert time"));
6636 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6638 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6642 /* don't operate on any playlist more than once, which could
6643 * happen if "all playlists" is enabled, but there is more
6644 * than 1 track using playlists "from" a given track.
6647 set<boost::shared_ptr<Playlist> > pl;
6649 if (all_playlists) {
6650 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6652 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6653 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6658 if ((*x)->playlist ()) {
6659 pl.insert ((*x)->playlist ());
6663 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6665 (*i)->clear_changes ();
6666 (*i)->clear_owned_changes ();
6668 if (opt == SplitIntersected) {
6672 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6674 vector<Command*> cmds;
6676 _session->add_commands (cmds);
6678 _session->add_command (new StatefulDiffCommand (*i));
6683 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6685 rtav->route ()->shift (pos, frames);
6693 XMLNode& before (_session->locations()->get_state());
6694 Locations::LocationList copy (_session->locations()->list());
6696 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6698 Locations::LocationList::const_iterator tmp;
6700 bool const was_locked = (*i)->locked ();
6701 if (locked_markers_too) {
6705 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6707 if ((*i)->start() >= pos) {
6708 (*i)->set_start ((*i)->start() + frames);
6709 if (!(*i)->is_mark()) {
6710 (*i)->set_end ((*i)->end() + frames);
6723 XMLNode& after (_session->locations()->get_state());
6724 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6729 _session->tempo_map().insert_time (pos, frames);
6733 commit_reversible_command ();
6738 Editor::fit_selected_tracks ()
6740 if (!selection->tracks.empty()) {
6741 fit_tracks (selection->tracks);
6745 /* no selected tracks - use tracks with selected regions */
6747 if (!selection->regions.empty()) {
6748 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6749 tvl.push_back (&(*r)->get_time_axis_view ());
6755 } else if (internal_editing()) {
6756 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6759 if (entered_track) {
6760 tvl.push_back (entered_track);
6768 Editor::fit_tracks (TrackViewList & tracks)
6770 if (tracks.empty()) {
6774 uint32_t child_heights = 0;
6775 int visible_tracks = 0;
6777 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6779 if (!(*t)->marked_for_display()) {
6783 child_heights += (*t)->effective_height() - (*t)->current_height();
6787 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6788 double first_y_pos = DBL_MAX;
6790 if (h < TimeAxisView::preset_height (HeightSmall)) {
6791 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6792 /* too small to be displayed */
6796 undo_visual_stack.push_back (current_visual_state (true));
6797 no_save_visual = true;
6799 /* build a list of all tracks, including children */
6802 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6804 TimeAxisView::Children c = (*i)->get_child_list ();
6805 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6806 all.push_back (j->get());
6810 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6812 bool prev_was_selected = false;
6813 bool is_selected = tracks.contains (all.front());
6814 bool next_is_selected;
6816 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6818 TrackViewList::iterator next;
6823 if (next != all.end()) {
6824 next_is_selected = tracks.contains (*next);
6826 next_is_selected = false;
6829 if ((*t)->marked_for_display ()) {
6831 (*t)->set_height (h);
6832 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6834 if (prev_was_selected && next_is_selected) {
6835 hide_track_in_display (*t);
6840 prev_was_selected = is_selected;
6841 is_selected = next_is_selected;
6845 set the controls_layout height now, because waiting for its size
6846 request signal handler will cause the vertical adjustment setting to fail
6849 controls_layout.property_height () = _full_canvas_height;
6850 vertical_adjustment.set_value (first_y_pos);
6852 redo_visual_stack.push_back (current_visual_state (true));
6856 Editor::save_visual_state (uint32_t n)
6858 while (visual_states.size() <= n) {
6859 visual_states.push_back (0);
6862 if (visual_states[n] != 0) {
6863 delete visual_states[n];
6866 visual_states[n] = current_visual_state (true);
6871 Editor::goto_visual_state (uint32_t n)
6873 if (visual_states.size() <= n) {
6877 if (visual_states[n] == 0) {
6881 use_visual_state (*visual_states[n]);
6885 Editor::start_visual_state_op (uint32_t n)
6887 save_visual_state (n);
6889 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6891 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6892 pup->set_text (buf);
6897 Editor::cancel_visual_state_op (uint32_t n)
6899 goto_visual_state (n);
6903 Editor::toggle_region_mute ()
6905 if (_ignore_region_action) {
6909 RegionSelection rs = get_regions_from_selection_and_entered ();
6915 if (rs.size() > 1) {
6916 begin_reversible_command (_("mute regions"));
6918 begin_reversible_command (_("mute region"));
6921 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6923 (*i)->region()->playlist()->clear_changes ();
6924 (*i)->region()->set_muted (!(*i)->region()->muted ());
6925 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6929 commit_reversible_command ();
6933 Editor::combine_regions ()
6935 /* foreach track with selected regions, take all selected regions
6936 and join them into a new region containing the subregions (as a
6940 typedef set<RouteTimeAxisView*> RTVS;
6943 if (selection->regions.empty()) {
6947 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6948 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6951 tracks.insert (rtv);
6955 begin_reversible_command (_("combine regions"));
6957 vector<RegionView*> new_selection;
6959 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6962 if ((rv = (*i)->combine_regions ()) != 0) {
6963 new_selection.push_back (rv);
6967 selection->clear_regions ();
6968 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6969 selection->add (*i);
6972 commit_reversible_command ();
6976 Editor::uncombine_regions ()
6978 typedef set<RouteTimeAxisView*> RTVS;
6981 if (selection->regions.empty()) {
6985 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6986 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6989 tracks.insert (rtv);
6993 begin_reversible_command (_("uncombine regions"));
6995 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6996 (*i)->uncombine_regions ();
6999 commit_reversible_command ();
7003 Editor::toggle_midi_input_active (bool flip_others)
7006 boost::shared_ptr<RouteList> rl (new RouteList);
7008 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7009 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7015 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7018 rl->push_back (rtav->route());
7019 onoff = !mt->input_active();
7023 _session->set_exclusive_input_active (rl, onoff, flip_others);