2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
61 #include "ardour_ui.h"
62 #include "audio_region_view.h"
63 #include "audio_streamview.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "control_point.h"
70 #include "editor_cursors.h"
71 #include "editor_drag.h"
72 #include "editor_regions.h"
73 #include "editor_routes.h"
74 #include "gui_thread.h"
75 #include "insert_time_dialog.h"
76 #include "interthread_progress_window.h"
78 #include "midi_region_view.h"
79 #include "mixer_strip.h"
80 #include "mouse_cursors.h"
81 #include "normalize_dialog.h"
82 #include "patch_change_dialog.h"
83 #include "quantize_dialog.h"
84 #include "region_gain_line.h"
85 #include "rgb_macros.h"
86 #include "route_time_axis.h"
87 #include "selection.h"
88 #include "selection_templates.h"
89 #include "streamview.h"
90 #include "strip_silence_dialog.h"
91 #include "time_axis_view.h"
92 #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 RegionSelection pre_selected_regions = selection->regions;
138 bool working_on_selection = !pre_selected_regions.empty();
140 list<boost::shared_ptr<Playlist> > used_playlists;
141 list<RouteTimeAxisView*> used_trackviews;
143 if (regions.empty()) {
147 begin_reversible_command (_("split"));
149 // if splitting a single region, and snap-to is using
150 // region boundaries, don't pay attention to them
152 if (regions.size() == 1) {
153 switch (_snap_type) {
154 case SnapToRegionStart:
155 case SnapToRegionSync:
156 case SnapToRegionEnd:
165 EditorFreeze(); /* Emit Signal */
168 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
170 RegionSelection::iterator tmp;
172 /* XXX this test needs to be more complicated, to make sure we really
173 have something to split.
176 if (!(*a)->region()->covers (where)) {
184 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
192 /* we haven't seen this playlist before */
194 /* remember used playlists so we can thaw them later */
195 used_playlists.push_back(pl);
197 TimeAxisView& tv = (*a)->get_time_axis_view();
198 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
200 used_trackviews.push_back (rtv);
207 pl->clear_changes ();
208 pl->split_region ((*a)->region(), where);
209 _session->add_command (new StatefulDiffCommand (pl));
215 vector<sigc::connection> region_added_connections;
217 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
218 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
221 latest_regionviews.clear ();
223 while (used_playlists.size() > 0) {
224 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
226 used_playlists.pop_front();
229 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
233 commit_reversible_command ();
236 EditorThaw(); /* Emit Signal */
239 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
240 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
241 if( working_on_selection ) {
242 selection->add ( pre_selected_regions );
243 selection->add (latest_regionviews); //these are the new regions created after the split
245 _ignore_follow_edits = false;
249 /** Move one extreme of the current range selection. If more than one range is selected,
250 * the start of the earliest range or the end of the latest range is moved.
252 * @param move_end true to move the end of the current range selection, false to move
254 * @param next true to move the extreme to the next region boundary, false to move to
258 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
260 if (selection->time.start() == selection->time.end_frame()) {
264 framepos_t start = selection->time.start ();
265 framepos_t end = selection->time.end_frame ();
267 /* the position of the thing we may move */
268 framepos_t pos = move_end ? end : start;
269 int dir = next ? 1 : -1;
271 /* so we don't find the current region again */
272 if (dir > 0 || pos > 0) {
276 framepos_t const target = get_region_boundary (pos, dir, true, false);
291 begin_reversible_command (_("alter selection"));
292 selection->set_preserving_all_ranges (start, end);
293 commit_reversible_command ();
297 Editor::nudge_forward_release (GdkEventButton* ev)
299 if (ev->state & Keyboard::PrimaryModifier) {
300 nudge_forward (false, true);
302 nudge_forward (false, false);
308 Editor::nudge_backward_release (GdkEventButton* ev)
310 if (ev->state & Keyboard::PrimaryModifier) {
311 nudge_backward (false, true);
313 nudge_backward (false, false);
320 Editor::nudge_forward (bool next, bool force_playhead)
323 framepos_t next_distance;
329 RegionSelection rs = get_regions_from_selection_and_entered ();
331 if (!force_playhead && !rs.empty()) {
333 begin_reversible_command (_("nudge regions forward"));
335 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
336 boost::shared_ptr<Region> r ((*i)->region());
338 distance = get_nudge_distance (r->position(), next_distance);
341 distance = next_distance;
345 r->set_position (r->position() + distance);
346 _session->add_command (new StatefulDiffCommand (r));
349 commit_reversible_command ();
352 } else if (!force_playhead && !selection->markers.empty()) {
356 begin_reversible_command (_("nudge location forward"));
358 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
360 Location* loc = find_location_from_marker ((*i), is_start);
364 XMLNode& before (loc->get_state());
367 distance = get_nudge_distance (loc->start(), next_distance);
369 distance = next_distance;
371 if (max_framepos - distance > loc->start() + loc->length()) {
372 loc->set_start (loc->start() + distance);
374 loc->set_start (max_framepos - loc->length());
377 distance = get_nudge_distance (loc->end(), next_distance);
379 distance = next_distance;
381 if (max_framepos - distance > loc->end()) {
382 loc->set_end (loc->end() + distance);
384 loc->set_end (max_framepos);
387 XMLNode& after (loc->get_state());
388 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
392 commit_reversible_command ();
395 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
396 _session->request_locate (playhead_cursor->current_frame () + distance);
401 Editor::nudge_backward (bool next, bool force_playhead)
404 framepos_t next_distance;
410 RegionSelection rs = get_regions_from_selection_and_entered ();
412 if (!force_playhead && !rs.empty()) {
414 begin_reversible_command (_("nudge regions backward"));
416 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
417 boost::shared_ptr<Region> r ((*i)->region());
419 distance = get_nudge_distance (r->position(), next_distance);
422 distance = next_distance;
427 if (r->position() > distance) {
428 r->set_position (r->position() - distance);
432 _session->add_command (new StatefulDiffCommand (r));
435 commit_reversible_command ();
437 } else if (!force_playhead && !selection->markers.empty()) {
441 begin_reversible_command (_("nudge location forward"));
443 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
445 Location* loc = find_location_from_marker ((*i), is_start);
449 XMLNode& before (loc->get_state());
452 distance = get_nudge_distance (loc->start(), next_distance);
454 distance = next_distance;
456 if (distance < loc->start()) {
457 loc->set_start (loc->start() - distance);
462 distance = get_nudge_distance (loc->end(), next_distance);
465 distance = next_distance;
468 if (distance < loc->end() - loc->length()) {
469 loc->set_end (loc->end() - distance);
471 loc->set_end (loc->length());
475 XMLNode& after (loc->get_state());
476 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
480 commit_reversible_command ();
484 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
486 if (playhead_cursor->current_frame () > distance) {
487 _session->request_locate (playhead_cursor->current_frame () - distance);
489 _session->goto_start();
495 Editor::nudge_forward_capture_offset ()
497 RegionSelection rs = get_regions_from_selection_and_entered ();
499 if (!_session || rs.empty()) {
503 begin_reversible_command (_("nudge forward"));
505 framepos_t const distance = _session->worst_output_latency();
507 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
508 boost::shared_ptr<Region> r ((*i)->region());
511 r->set_position (r->position() + distance);
512 _session->add_command(new StatefulDiffCommand (r));
515 commit_reversible_command ();
519 Editor::nudge_backward_capture_offset ()
521 RegionSelection rs = get_regions_from_selection_and_entered ();
523 if (!_session || rs.empty()) {
527 begin_reversible_command (_("nudge backward"));
529 framepos_t const distance = _session->worst_output_latency();
531 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
532 boost::shared_ptr<Region> r ((*i)->region());
536 if (r->position() > distance) {
537 r->set_position (r->position() - distance);
541 _session->add_command(new StatefulDiffCommand (r));
544 commit_reversible_command ();
547 struct RegionSelectionPositionSorter {
548 bool operator() (RegionView* a, RegionView* b) {
549 return a->region()->position() < b->region()->position();
554 Editor::sequence_regions ()
557 framepos_t r_end_prev;
565 RegionSelection rs = get_regions_from_selection_and_entered ();
566 rs.sort(RegionSelectionPositionSorter());
570 begin_reversible_command (_("sequence regions"));
571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
572 boost::shared_ptr<Region> r ((*i)->region());
580 if(r->position_locked())
587 r->set_position(r_end_prev);
590 _session->add_command (new StatefulDiffCommand (r));
592 r_end=r->position() + r->length();
596 commit_reversible_command ();
604 Editor::move_to_start ()
606 _session->goto_start ();
610 Editor::move_to_end ()
613 _session->request_locate (_session->current_end_frame());
617 Editor::build_region_boundary_cache ()
620 vector<RegionPoint> interesting_points;
621 boost::shared_ptr<Region> r;
622 TrackViewList tracks;
625 region_boundary_cache.clear ();
631 switch (_snap_type) {
632 case SnapToRegionStart:
633 interesting_points.push_back (Start);
635 case SnapToRegionEnd:
636 interesting_points.push_back (End);
638 case SnapToRegionSync:
639 interesting_points.push_back (SyncPoint);
641 case SnapToRegionBoundary:
642 interesting_points.push_back (Start);
643 interesting_points.push_back (End);
646 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
651 TimeAxisView *ontrack = 0;
654 if (!selection->tracks.empty()) {
655 tlist = selection->tracks.filter_to_unique_playlists ();
657 tlist = track_views.filter_to_unique_playlists ();
660 while (pos < _session->current_end_frame() && !at_end) {
663 framepos_t lpos = max_framepos;
665 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
667 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
668 if (*p == interesting_points.back()) {
671 /* move to next point type */
677 rpos = r->first_frame();
681 rpos = r->last_frame();
685 rpos = r->sync_position ();
693 RouteTimeAxisView *rtav;
695 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
696 if (rtav->track() != 0) {
697 speed = rtav->track()->speed();
701 rpos = track_frame_to_session_frame (rpos, speed);
707 /* prevent duplicates, but we don't use set<> because we want to be able
711 vector<framepos_t>::iterator ri;
713 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
719 if (ri == region_boundary_cache.end()) {
720 region_boundary_cache.push_back (rpos);
727 /* finally sort to be sure that the order is correct */
729 sort (region_boundary_cache.begin(), region_boundary_cache.end());
732 boost::shared_ptr<Region>
733 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
735 TrackViewList::iterator i;
736 framepos_t closest = max_framepos;
737 boost::shared_ptr<Region> ret;
741 framepos_t track_frame;
742 RouteTimeAxisView *rtav;
744 for (i = tracks.begin(); i != tracks.end(); ++i) {
747 boost::shared_ptr<Region> r;
750 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
751 if (rtav->track()!=0)
752 track_speed = rtav->track()->speed();
755 track_frame = session_frame_to_track_frame(frame, track_speed);
757 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
763 rpos = r->first_frame ();
767 rpos = r->last_frame ();
771 rpos = r->sync_position ();
775 // rpos is a "track frame", converting it to "_session frame"
776 rpos = track_frame_to_session_frame(rpos, track_speed);
779 distance = rpos - frame;
781 distance = frame - rpos;
784 if (distance < closest) {
796 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
798 framecnt_t distance = max_framepos;
799 framepos_t current_nearest = -1;
801 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
802 framepos_t contender;
805 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
811 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
815 d = ::llabs (pos - contender);
818 current_nearest = contender;
823 return current_nearest;
827 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
832 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
834 if (!selection->tracks.empty()) {
836 target = find_next_region_boundary (pos, dir, selection->tracks);
840 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
841 get_onscreen_tracks (tvl);
842 target = find_next_region_boundary (pos, dir, tvl);
844 target = find_next_region_boundary (pos, dir, track_views);
850 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
851 get_onscreen_tracks (tvl);
852 target = find_next_region_boundary (pos, dir, tvl);
854 target = find_next_region_boundary (pos, dir, track_views);
862 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
864 framepos_t pos = playhead_cursor->current_frame ();
871 // so we don't find the current region again..
872 if (dir > 0 || pos > 0) {
876 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
880 _session->request_locate (target);
884 Editor::cursor_to_next_region_boundary (bool with_selection)
886 cursor_to_region_boundary (with_selection, 1);
890 Editor::cursor_to_previous_region_boundary (bool with_selection)
892 cursor_to_region_boundary (with_selection, -1);
896 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
898 boost::shared_ptr<Region> r;
899 framepos_t pos = cursor->current_frame ();
905 TimeAxisView *ontrack = 0;
907 // so we don't find the current region again..
911 if (!selection->tracks.empty()) {
913 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
915 } else if (clicked_axisview) {
918 t.push_back (clicked_axisview);
920 r = find_next_region (pos, point, dir, t, &ontrack);
924 r = find_next_region (pos, point, dir, track_views, &ontrack);
933 pos = r->first_frame ();
937 pos = r->last_frame ();
941 pos = r->sync_position ();
946 RouteTimeAxisView *rtav;
948 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
949 if (rtav->track() != 0) {
950 speed = rtav->track()->speed();
954 pos = track_frame_to_session_frame(pos, speed);
956 if (cursor == playhead_cursor) {
957 _session->request_locate (pos);
959 cursor->set_position (pos);
964 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
966 cursor_to_region_point (cursor, point, 1);
970 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
972 cursor_to_region_point (cursor, point, -1);
976 Editor::cursor_to_selection_start (EditorCursor *cursor)
980 switch (mouse_mode) {
982 if (!selection->regions.empty()) {
983 pos = selection->regions.start();
988 if (!selection->time.empty()) {
989 pos = selection->time.start ();
997 if (cursor == playhead_cursor) {
998 _session->request_locate (pos);
1000 cursor->set_position (pos);
1005 Editor::cursor_to_selection_end (EditorCursor *cursor)
1009 switch (mouse_mode) {
1011 if (!selection->regions.empty()) {
1012 pos = selection->regions.end_frame();
1017 if (!selection->time.empty()) {
1018 pos = selection->time.end_frame ();
1026 if (cursor == playhead_cursor) {
1027 _session->request_locate (pos);
1029 cursor->set_position (pos);
1034 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1044 if (selection->markers.empty()) {
1048 if (!mouse_frame (mouse, ignored)) {
1052 add_location_mark (mouse);
1055 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1059 framepos_t pos = loc->start();
1061 // so we don't find the current region again..
1062 if (dir > 0 || pos > 0) {
1066 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1070 loc->move_to (target);
1074 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1076 selected_marker_to_region_boundary (with_selection, 1);
1080 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1082 selected_marker_to_region_boundary (with_selection, -1);
1086 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1088 boost::shared_ptr<Region> r;
1093 if (!_session || selection->markers.empty()) {
1097 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1101 TimeAxisView *ontrack = 0;
1105 // so we don't find the current region again..
1109 if (!selection->tracks.empty()) {
1111 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1115 r = find_next_region (pos, point, dir, track_views, &ontrack);
1124 pos = r->first_frame ();
1128 pos = r->last_frame ();
1132 pos = r->adjust_to_sync (r->first_frame());
1137 RouteTimeAxisView *rtav;
1139 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1140 if (rtav->track() != 0) {
1141 speed = rtav->track()->speed();
1145 pos = track_frame_to_session_frame(pos, speed);
1151 Editor::selected_marker_to_next_region_point (RegionPoint point)
1153 selected_marker_to_region_point (point, 1);
1157 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1159 selected_marker_to_region_point (point, -1);
1163 Editor::selected_marker_to_selection_start ()
1169 if (!_session || selection->markers.empty()) {
1173 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1177 switch (mouse_mode) {
1179 if (!selection->regions.empty()) {
1180 pos = selection->regions.start();
1185 if (!selection->time.empty()) {
1186 pos = selection->time.start ();
1198 Editor::selected_marker_to_selection_end ()
1204 if (!_session || selection->markers.empty()) {
1208 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1212 switch (mouse_mode) {
1214 if (!selection->regions.empty()) {
1215 pos = selection->regions.end_frame();
1220 if (!selection->time.empty()) {
1221 pos = selection->time.end_frame ();
1233 Editor::scroll_playhead (bool forward)
1235 framepos_t pos = playhead_cursor->current_frame ();
1236 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1239 if (pos == max_framepos) {
1243 if (pos < max_framepos - delta) {
1262 _session->request_locate (pos);
1266 Editor::cursor_align (bool playhead_to_edit)
1272 if (playhead_to_edit) {
1274 if (selection->markers.empty()) {
1278 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1281 /* move selected markers to playhead */
1283 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1286 Location* loc = find_location_from_marker (*i, ignored);
1288 if (loc->is_mark()) {
1289 loc->set_start (playhead_cursor->current_frame ());
1291 loc->set (playhead_cursor->current_frame (),
1292 playhead_cursor->current_frame () + loc->length());
1299 Editor::scroll_backward (float pages)
1301 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1302 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1305 if (leftmost_frame < cnt) {
1308 frame = leftmost_frame - cnt;
1311 reset_x_origin (frame);
1315 Editor::scroll_forward (float pages)
1317 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1318 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1321 if (max_framepos - cnt < leftmost_frame) {
1322 frame = max_framepos - cnt;
1324 frame = leftmost_frame + cnt;
1327 reset_x_origin (frame);
1331 Editor::scroll_tracks_down ()
1333 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1334 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1335 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1338 vertical_adjustment.set_value (vert_value);
1342 Editor::scroll_tracks_up ()
1344 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1348 Editor::scroll_tracks_down_line ()
1350 double vert_value = vertical_adjustment.get_value() + 60;
1352 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1353 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1356 vertical_adjustment.set_value (vert_value);
1360 Editor::scroll_tracks_up_line ()
1362 reset_y_origin (vertical_adjustment.get_value() - 60);
1366 Editor::scroll_down_one_track ()
1368 TrackViewList::reverse_iterator next = track_views.rbegin();
1369 std::pair<TimeAxisView*,double> res;
1370 const double top_of_trackviews = vertical_adjustment.get_value();
1372 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1373 if ((*t)->hidden()) {
1378 if (next != track_views.rbegin()) {
1379 --next; // moves "next" towards the lower/later tracks since it is a reverse iterator
1382 /* If this is the upper-most visible trackview, we want to display
1383 the one above it (next)
1386 res = (*t)->covers_y_position (top_of_trackviews);
1393 /* move to the track below the first one that covers the */
1395 if (next != track_views.rbegin()) {
1396 ensure_time_axis_view_is_visible (**next, true);
1404 Editor::scroll_up_one_track ()
1406 TrackViewList::iterator prev = track_views.end();
1407 std::pair<TimeAxisView*,double> res;
1408 double top_of_trackviews = vertical_adjustment.get_value ();
1410 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1412 if ((*t)->hidden()) {
1416 /* find the trackview at the top of the trackview group */
1417 res = (*t)->covers_y_position (top_of_trackviews);
1426 if (prev != track_views.end()) {
1427 ensure_time_axis_view_is_visible (**prev, true);
1437 Editor::tav_zoom_step (bool coarser)
1439 DisplaySuspender ds;
1443 if (selection->tracks.empty()) {
1446 ts = &selection->tracks;
1449 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1450 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1451 tv->step_height (coarser);
1456 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1458 DisplaySuspender ds;
1462 if (selection->tracks.empty() || force_all) {
1465 ts = &selection->tracks;
1468 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1469 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1470 uint32_t h = tv->current_height ();
1475 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1480 tv->set_height (h + 5);
1487 Editor::temporal_zoom_step (bool coarser)
1489 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1491 framecnt_t nspp = samples_per_pixel;
1499 temporal_zoom (nspp);
1503 Editor::temporal_zoom (framecnt_t fpp)
1509 framepos_t current_page = current_page_samples();
1510 framepos_t current_leftmost = leftmost_frame;
1511 framepos_t current_rightmost;
1512 framepos_t current_center;
1513 framepos_t new_page_size;
1514 framepos_t half_page_size;
1515 framepos_t leftmost_after_zoom = 0;
1517 bool in_track_canvas;
1521 if (fpp == samples_per_pixel) {
1525 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1526 // segfaults for lack of memory. If somebody decides this is not high enough I
1527 // believe it can be raisen to higher values but some limit must be in place.
1529 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1530 // all of which is used for the editor track displays. The whole day
1531 // would be 4147200000 samples, so 2592000 samples per pixel.
1533 nfpp = min (fpp, (framecnt_t) 2592000);
1534 nfpp = max ((framecnt_t) 1, fpp);
1536 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1537 half_page_size = new_page_size / 2;
1539 switch (zoom_focus) {
1541 leftmost_after_zoom = current_leftmost;
1544 case ZoomFocusRight:
1545 current_rightmost = leftmost_frame + current_page;
1546 if (current_rightmost < new_page_size) {
1547 leftmost_after_zoom = 0;
1549 leftmost_after_zoom = current_rightmost - new_page_size;
1553 case ZoomFocusCenter:
1554 current_center = current_leftmost + (current_page/2);
1555 if (current_center < half_page_size) {
1556 leftmost_after_zoom = 0;
1558 leftmost_after_zoom = current_center - half_page_size;
1562 case ZoomFocusPlayhead:
1563 /* centre playhead */
1564 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1567 leftmost_after_zoom = 0;
1568 } else if (l > max_framepos) {
1569 leftmost_after_zoom = max_framepos - new_page_size;
1571 leftmost_after_zoom = (framepos_t) l;
1575 case ZoomFocusMouse:
1576 /* try to keep the mouse over the same point in the display */
1578 if (!mouse_frame (where, in_track_canvas)) {
1579 /* use playhead instead */
1580 where = playhead_cursor->current_frame ();
1582 if (where < half_page_size) {
1583 leftmost_after_zoom = 0;
1585 leftmost_after_zoom = where - half_page_size;
1590 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1593 leftmost_after_zoom = 0;
1594 } else if (l > max_framepos) {
1595 leftmost_after_zoom = max_framepos - new_page_size;
1597 leftmost_after_zoom = (framepos_t) l;
1604 /* try to keep the edit point in the same place */
1605 where = get_preferred_edit_position ();
1609 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1612 leftmost_after_zoom = 0;
1613 } else if (l > max_framepos) {
1614 leftmost_after_zoom = max_framepos - new_page_size;
1616 leftmost_after_zoom = (framepos_t) l;
1620 /* edit point not defined */
1627 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1629 reposition_and_zoom (leftmost_after_zoom, nfpp);
1633 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1635 /* this func helps make sure we leave a little space
1636 at each end of the editor so that the zoom doesn't fit the region
1637 precisely to the screen.
1640 GdkScreen* screen = gdk_screen_get_default ();
1641 gint pixwidth = gdk_screen_get_width (screen);
1642 gint mmwidth = gdk_screen_get_width_mm (screen);
1643 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1644 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1646 framepos_t range = end - start;
1647 double new_fpp = (double) range / (double) _visible_canvas_width;
1648 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1650 if (start > extra_samples) {
1651 start -= extra_samples;
1656 if (max_framepos - extra_samples > end) {
1657 end += extra_samples;
1665 Editor::temporal_zoom_region (bool both_axes)
1667 framepos_t start = max_framepos;
1669 set<TimeAxisView*> tracks;
1671 RegionSelection rs = get_regions_from_selection_and_entered ();
1677 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1679 if ((*i)->region()->position() < start) {
1680 start = (*i)->region()->position();
1683 if ((*i)->region()->last_frame() + 1 > end) {
1684 end = (*i)->region()->last_frame() + 1;
1687 tracks.insert (&((*i)->get_time_axis_view()));
1690 if ((start == 0 && end == 0) || end < start) {
1694 calc_extra_zoom_edges(start, end);
1696 /* if we're zooming on both axes we need to save track heights etc.
1699 undo_visual_stack.push_back (current_visual_state (both_axes));
1701 PBD::Unwinder<bool> nsv (no_save_visual, true);
1703 temporal_zoom_by_frame (start, end);
1706 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1708 /* set visible track heights appropriately */
1710 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1711 (*t)->set_height (per_track_height);
1714 /* hide irrelevant tracks */
1716 DisplaySuspender ds;
1718 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1719 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1720 hide_track_in_display (*i);
1724 vertical_adjustment.set_value (0.0);
1727 redo_visual_stack.push_back (current_visual_state (both_axes));
1731 Editor::zoom_to_region (bool both_axes)
1733 temporal_zoom_region (both_axes);
1737 Editor::temporal_zoom_selection (bool both_axes)
1739 if (!selection) return;
1741 //if a range is selected, zoom to that
1742 if (!selection->time.empty()) {
1744 framepos_t start = selection->time.start();
1745 framepos_t end = selection->time.end_frame();
1747 calc_extra_zoom_edges(start, end);
1749 temporal_zoom_by_frame (start, end);
1752 fit_selected_tracks();
1755 temporal_zoom_region(both_axes);
1762 Editor::temporal_zoom_session ()
1764 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1767 framecnt_t start = _session->current_start_frame();
1768 framecnt_t end = _session->current_end_frame();
1770 if (_session->actively_recording () ) {
1771 framepos_t cur = playhead_cursor->current_frame ();
1773 /* recording beyond the end marker; zoom out
1774 * by 5 seconds more so that if 'follow
1775 * playhead' is active we don't immediately
1778 end = cur + _session->frame_rate() * 5;
1782 if ((start == 0 && end == 0) || end < start) {
1786 calc_extra_zoom_edges(start, end);
1788 temporal_zoom_by_frame (start, end);
1793 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1795 if (!_session) return;
1797 if ((start == 0 && end == 0) || end < start) {
1801 framepos_t range = end - start;
1803 double const new_fpp = (double) range / (double) _visible_canvas_width;
1805 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1806 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1807 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1809 if (new_leftmost > middle) {
1813 if (new_leftmost < 0) {
1817 reposition_and_zoom (new_leftmost, new_fpp);
1821 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1827 framecnt_t range_before = frame - leftmost_frame;
1831 if (samples_per_pixel <= 1) {
1834 new_spp = samples_per_pixel + (samples_per_pixel/2);
1836 range_before += range_before/2;
1838 if (samples_per_pixel >= 1) {
1839 new_spp = samples_per_pixel - (samples_per_pixel/2);
1841 /* could bail out here since we cannot zoom any finer,
1842 but leave that to the equality test below
1844 new_spp = samples_per_pixel;
1847 range_before -= range_before/2;
1850 if (new_spp == samples_per_pixel) {
1854 /* zoom focus is automatically taken as @param frame when this
1858 framepos_t new_leftmost = frame - (framepos_t)range_before;
1860 if (new_leftmost > frame) {
1864 if (new_leftmost < 0) {
1868 reposition_and_zoom (new_leftmost, new_spp);
1873 Editor::choose_new_marker_name(string &name) {
1875 if (!Config->get_name_new_markers()) {
1876 /* don't prompt user for a new name */
1880 ArdourPrompter dialog (true);
1882 dialog.set_prompt (_("New Name:"));
1884 dialog.set_title (_("New Location Marker"));
1886 dialog.set_name ("MarkNameWindow");
1887 dialog.set_size_request (250, -1);
1888 dialog.set_position (Gtk::WIN_POS_MOUSE);
1890 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1891 dialog.set_initial_text (name);
1895 switch (dialog.run ()) {
1896 case RESPONSE_ACCEPT:
1902 dialog.get_result(name);
1909 Editor::add_location_from_selection ()
1913 if (selection->time.empty()) {
1917 if (_session == 0 || clicked_axisview == 0) {
1921 framepos_t start = selection->time[clicked_selection].start;
1922 framepos_t end = selection->time[clicked_selection].end;
1924 _session->locations()->next_available_name(rangename,"selection");
1925 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1927 _session->begin_reversible_command (_("add marker"));
1928 XMLNode &before = _session->locations()->get_state();
1929 _session->locations()->add (location, true);
1930 XMLNode &after = _session->locations()->get_state();
1931 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1932 _session->commit_reversible_command ();
1936 Editor::add_location_mark (framepos_t where)
1940 select_new_marker = true;
1942 _session->locations()->next_available_name(markername,"mark");
1943 if (!choose_new_marker_name(markername)) {
1946 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1947 _session->begin_reversible_command (_("add marker"));
1948 XMLNode &before = _session->locations()->get_state();
1949 _session->locations()->add (location, true);
1950 XMLNode &after = _session->locations()->get_state();
1951 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1952 _session->commit_reversible_command ();
1956 Editor::add_location_from_playhead_cursor ()
1958 add_location_mark (_session->audible_frame());
1962 Editor::remove_location_at_playhead_cursor ()
1967 _session->begin_reversible_command (_("remove marker"));
1968 XMLNode &before = _session->locations()->get_state();
1969 bool removed = false;
1971 //find location(s) at this time
1972 Locations::LocationList locs;
1973 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1974 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1975 if ((*i)->is_mark()) {
1976 _session->locations()->remove (*i);
1983 XMLNode &after = _session->locations()->get_state();
1984 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1985 _session->commit_reversible_command ();
1990 /** Add a range marker around each selected region */
1992 Editor::add_locations_from_region ()
1994 RegionSelection rs = get_regions_from_selection_and_entered ();
2000 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2001 XMLNode &before = _session->locations()->get_state();
2003 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2005 boost::shared_ptr<Region> region = (*i)->region ();
2007 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2009 _session->locations()->add (location, true);
2012 XMLNode &after = _session->locations()->get_state();
2013 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2014 _session->commit_reversible_command ();
2017 /** Add a single range marker around all selected regions */
2019 Editor::add_location_from_region ()
2021 RegionSelection rs = get_regions_from_selection_and_entered ();
2027 _session->begin_reversible_command (_("add marker"));
2028 XMLNode &before = _session->locations()->get_state();
2032 if (rs.size() > 1) {
2033 _session->locations()->next_available_name(markername, "regions");
2035 RegionView* rv = *(rs.begin());
2036 boost::shared_ptr<Region> region = rv->region();
2037 markername = region->name();
2040 if (!choose_new_marker_name(markername)) {
2044 // single range spanning all selected
2045 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2046 _session->locations()->add (location, true);
2048 XMLNode &after = _session->locations()->get_state();
2049 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2050 _session->commit_reversible_command ();
2056 Editor::jump_forward_to_mark ()
2062 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2068 _session->request_locate (pos, _session->transport_rolling());
2072 Editor::jump_backward_to_mark ()
2078 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2084 _session->request_locate (pos, _session->transport_rolling());
2090 framepos_t const pos = _session->audible_frame ();
2093 _session->locations()->next_available_name (markername, "mark");
2095 if (!choose_new_marker_name (markername)) {
2099 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2103 Editor::clear_markers ()
2106 _session->begin_reversible_command (_("clear markers"));
2107 XMLNode &before = _session->locations()->get_state();
2108 _session->locations()->clear_markers ();
2109 XMLNode &after = _session->locations()->get_state();
2110 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2111 _session->commit_reversible_command ();
2116 Editor::clear_ranges ()
2119 _session->begin_reversible_command (_("clear ranges"));
2120 XMLNode &before = _session->locations()->get_state();
2122 _session->locations()->clear_ranges ();
2124 XMLNode &after = _session->locations()->get_state();
2125 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2126 _session->commit_reversible_command ();
2131 Editor::clear_locations ()
2133 _session->begin_reversible_command (_("clear locations"));
2134 XMLNode &before = _session->locations()->get_state();
2135 _session->locations()->clear ();
2136 XMLNode &after = _session->locations()->get_state();
2137 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2138 _session->commit_reversible_command ();
2139 _session->locations()->clear ();
2143 Editor::unhide_markers ()
2145 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2146 Location *l = (*i).first;
2147 if (l->is_hidden() && l->is_mark()) {
2148 l->set_hidden(false, this);
2154 Editor::unhide_ranges ()
2156 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2157 Location *l = (*i).first;
2158 if (l->is_hidden() && l->is_range_marker()) {
2159 l->set_hidden(false, this);
2164 /* INSERT/REPLACE */
2167 Editor::insert_region_list_selection (float times)
2169 RouteTimeAxisView *tv = 0;
2170 boost::shared_ptr<Playlist> playlist;
2172 if (clicked_routeview != 0) {
2173 tv = clicked_routeview;
2174 } else if (!selection->tracks.empty()) {
2175 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2178 } else if (entered_track != 0) {
2179 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2186 if ((playlist = tv->playlist()) == 0) {
2190 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2195 begin_reversible_command (_("insert region"));
2196 playlist->clear_changes ();
2197 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2198 if (Config->get_edit_mode() == Ripple)
2199 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2201 _session->add_command(new StatefulDiffCommand (playlist));
2202 commit_reversible_command ();
2205 /* BUILT-IN EFFECTS */
2208 Editor::reverse_selection ()
2213 /* GAIN ENVELOPE EDITING */
2216 Editor::edit_envelope ()
2223 Editor::transition_to_rolling (bool fwd)
2229 if (_session->config.get_external_sync()) {
2230 switch (Config->get_sync_source()) {
2234 /* transport controlled by the master */
2239 if (_session->is_auditioning()) {
2240 _session->cancel_audition ();
2244 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2248 Editor::play_from_start ()
2250 _session->request_locate (_session->current_start_frame(), true);
2254 Editor::play_from_edit_point ()
2256 _session->request_locate (get_preferred_edit_position(), true);
2260 Editor::play_from_edit_point_and_return ()
2262 framepos_t start_frame;
2263 framepos_t return_frame;
2265 start_frame = get_preferred_edit_position (true);
2267 if (_session->transport_rolling()) {
2268 _session->request_locate (start_frame, false);
2272 /* don't reset the return frame if its already set */
2274 if ((return_frame = _session->requested_return_frame()) < 0) {
2275 return_frame = _session->audible_frame();
2278 if (start_frame >= 0) {
2279 _session->request_roll_at_and_return (start_frame, return_frame);
2284 Editor::play_selection ()
2286 if (selection->time.empty()) {
2290 _session->request_play_range (&selection->time, true);
2294 Editor::get_preroll ()
2296 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2301 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2303 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2306 location -= get_preroll();
2308 //don't try to locate before the beginning of time
2312 //if follow_playhead is on, keep the playhead on the screen
2313 if ( _follow_playhead )
2314 if ( location < leftmost_frame )
2315 location = leftmost_frame;
2317 _session->request_locate( location );
2321 Editor::play_with_preroll ()
2323 if (selection->time.empty()) {
2326 framepos_t preroll = get_preroll();
2328 framepos_t start = 0;
2329 if (selection->time[clicked_selection].start > preroll)
2330 start = selection->time[clicked_selection].start - preroll;
2332 framepos_t end = selection->time[clicked_selection].end + preroll;
2334 AudioRange ar (start, end, 0);
2335 list<AudioRange> lar;
2338 _session->request_play_range (&lar, true);
2343 Editor::play_location (Location& location)
2345 if (location.start() <= location.end()) {
2349 _session->request_bounded_roll (location.start(), location.end());
2353 Editor::loop_location (Location& location)
2355 if (location.start() <= location.end()) {
2361 if ((tll = transport_loop_location()) != 0) {
2362 tll->set (location.start(), location.end());
2364 // enable looping, reposition and start rolling
2365 _session->request_locate (tll->start(), true);
2366 _session->request_play_loop (true);
2371 Editor::do_layer_operation (LayerOperation op)
2373 if (selection->regions.empty ()) {
2377 bool const multiple = selection->regions.size() > 1;
2381 begin_reversible_command (_("raise regions"));
2383 begin_reversible_command (_("raise region"));
2389 begin_reversible_command (_("raise regions to top"));
2391 begin_reversible_command (_("raise region to top"));
2397 begin_reversible_command (_("lower regions"));
2399 begin_reversible_command (_("lower region"));
2405 begin_reversible_command (_("lower regions to bottom"));
2407 begin_reversible_command (_("lower region"));
2412 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2413 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2414 (*i)->clear_owned_changes ();
2417 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2418 boost::shared_ptr<Region> r = (*i)->region ();
2430 r->lower_to_bottom ();
2434 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2435 vector<Command*> cmds;
2437 _session->add_commands (cmds);
2440 commit_reversible_command ();
2444 Editor::raise_region ()
2446 do_layer_operation (Raise);
2450 Editor::raise_region_to_top ()
2452 do_layer_operation (RaiseToTop);
2456 Editor::lower_region ()
2458 do_layer_operation (Lower);
2462 Editor::lower_region_to_bottom ()
2464 do_layer_operation (LowerToBottom);
2467 /** Show the region editor for the selected regions */
2469 Editor::show_region_properties ()
2471 selection->foreach_regionview (&RegionView::show_region_editor);
2474 /** Show the midi list editor for the selected MIDI regions */
2476 Editor::show_midi_list_editor ()
2478 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2482 Editor::rename_region ()
2484 RegionSelection rs = get_regions_from_selection_and_entered ();
2490 ArdourDialog d (*this, _("Rename Region"), true, false);
2492 Label label (_("New name:"));
2495 hbox.set_spacing (6);
2496 hbox.pack_start (label, false, false);
2497 hbox.pack_start (entry, true, true);
2499 d.get_vbox()->set_border_width (12);
2500 d.get_vbox()->pack_start (hbox, false, false);
2502 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2503 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2505 d.set_size_request (300, -1);
2507 entry.set_text (rs.front()->region()->name());
2508 entry.select_region (0, -1);
2510 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2516 int const ret = d.run();
2520 if (ret != RESPONSE_OK) {
2524 std::string str = entry.get_text();
2525 strip_whitespace_edges (str);
2527 rs.front()->region()->set_name (str);
2528 _regions->redisplay ();
2533 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2535 if (_session->is_auditioning()) {
2536 _session->cancel_audition ();
2539 // note: some potential for creativity here, because region doesn't
2540 // have to belong to the playlist that Route is handling
2542 // bool was_soloed = route.soloed();
2544 route.set_solo (true, this);
2546 _session->request_bounded_roll (region->position(), region->position() + region->length());
2548 /* XXX how to unset the solo state ? */
2551 /** Start an audition of the first selected region */
2553 Editor::play_edit_range ()
2555 framepos_t start, end;
2557 if (get_edit_op_range (start, end)) {
2558 _session->request_bounded_roll (start, end);
2563 Editor::play_selected_region ()
2565 framepos_t start = max_framepos;
2568 RegionSelection rs = get_regions_from_selection_and_entered ();
2574 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2575 if ((*i)->region()->position() < start) {
2576 start = (*i)->region()->position();
2578 if ((*i)->region()->last_frame() + 1 > end) {
2579 end = (*i)->region()->last_frame() + 1;
2583 _session->request_bounded_roll (start, end);
2587 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2589 _session->audition_region (region);
2593 Editor::region_from_selection ()
2595 if (clicked_axisview == 0) {
2599 if (selection->time.empty()) {
2603 framepos_t start = selection->time[clicked_selection].start;
2604 framepos_t end = selection->time[clicked_selection].end;
2606 TrackViewList tracks = get_tracks_for_range_action ();
2608 framepos_t selection_cnt = end - start + 1;
2610 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2611 boost::shared_ptr<Region> current;
2612 boost::shared_ptr<Playlist> pl;
2613 framepos_t internal_start;
2616 if ((pl = (*i)->playlist()) == 0) {
2620 if ((current = pl->top_region_at (start)) == 0) {
2624 internal_start = start - current->position();
2625 RegionFactory::region_name (new_name, current->name(), true);
2629 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2630 plist.add (ARDOUR::Properties::length, selection_cnt);
2631 plist.add (ARDOUR::Properties::name, new_name);
2632 plist.add (ARDOUR::Properties::layer, 0);
2634 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2639 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2641 if (selection->time.empty() || selection->tracks.empty()) {
2645 framepos_t start = selection->time[clicked_selection].start;
2646 framepos_t end = selection->time[clicked_selection].end;
2648 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2649 sort_track_selection (ts);
2651 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2652 boost::shared_ptr<Region> current;
2653 boost::shared_ptr<Playlist> playlist;
2654 framepos_t internal_start;
2657 if ((playlist = (*i)->playlist()) == 0) {
2661 if ((current = playlist->top_region_at(start)) == 0) {
2665 internal_start = start - current->position();
2666 RegionFactory::region_name (new_name, current->name(), true);
2670 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2671 plist.add (ARDOUR::Properties::length, end - start + 1);
2672 plist.add (ARDOUR::Properties::name, new_name);
2674 new_regions.push_back (RegionFactory::create (current, plist));
2679 Editor::split_multichannel_region ()
2681 RegionSelection rs = get_regions_from_selection_and_entered ();
2687 vector< boost::shared_ptr<Region> > v;
2689 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2690 (*x)->region()->separate_by_channel (*_session, v);
2695 Editor::new_region_from_selection ()
2697 region_from_selection ();
2698 cancel_selection ();
2702 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2704 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2705 case Evoral::OverlapNone:
2713 * - selected tracks, or if there are none...
2714 * - tracks containing selected regions, or if there are none...
2719 Editor::get_tracks_for_range_action () const
2723 if (selection->tracks.empty()) {
2725 /* use tracks with selected regions */
2727 RegionSelection rs = selection->regions;
2729 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2730 TimeAxisView* tv = &(*i)->get_time_axis_view();
2732 if (!t.contains (tv)) {
2738 /* no regions and no tracks: use all tracks */
2744 t = selection->tracks;
2747 return t.filter_to_unique_playlists();
2751 Editor::separate_regions_between (const TimeSelection& ts)
2753 bool in_command = false;
2754 boost::shared_ptr<Playlist> playlist;
2755 RegionSelection new_selection;
2757 TrackViewList tmptracks = get_tracks_for_range_action ();
2758 sort_track_selection (tmptracks);
2760 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2762 RouteTimeAxisView* rtv;
2764 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2766 if (rtv->is_track()) {
2768 /* no edits to destructive tracks */
2770 if (rtv->track()->destructive()) {
2774 if ((playlist = rtv->playlist()) != 0) {
2776 playlist->clear_changes ();
2778 /* XXX need to consider musical time selections here at some point */
2780 double speed = rtv->track()->speed();
2783 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2785 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2786 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2788 latest_regionviews.clear ();
2790 playlist->partition ((framepos_t)((*t).start * speed),
2791 (framepos_t)((*t).end * speed), false);
2795 if (!latest_regionviews.empty()) {
2797 rtv->view()->foreach_regionview (sigc::bind (
2798 sigc::ptr_fun (add_if_covered),
2799 &(*t), &new_selection));
2802 begin_reversible_command (_("separate"));
2806 /* pick up changes to existing regions */
2808 vector<Command*> cmds;
2809 playlist->rdiff (cmds);
2810 _session->add_commands (cmds);
2812 /* pick up changes to the playlist itself (adds/removes)
2815 _session->add_command(new StatefulDiffCommand (playlist));
2824 // selection->set (new_selection);
2826 commit_reversible_command ();
2830 struct PlaylistState {
2831 boost::shared_ptr<Playlist> playlist;
2835 /** Take tracks from get_tracks_for_range_action and cut any regions
2836 * on those tracks so that the tracks are empty over the time
2840 Editor::separate_region_from_selection ()
2842 /* preferentially use *all* ranges in the time selection if we're in range mode
2843 to allow discontiguous operation, since get_edit_op_range() currently
2844 returns a single range.
2847 if (!selection->time.empty()) {
2849 separate_regions_between (selection->time);
2856 if (get_edit_op_range (start, end)) {
2858 AudioRange ar (start, end, 1);
2862 separate_regions_between (ts);
2868 Editor::separate_region_from_punch ()
2870 Location* loc = _session->locations()->auto_punch_location();
2872 separate_regions_using_location (*loc);
2877 Editor::separate_region_from_loop ()
2879 Location* loc = _session->locations()->auto_loop_location();
2881 separate_regions_using_location (*loc);
2886 Editor::separate_regions_using_location (Location& loc)
2888 if (loc.is_mark()) {
2892 AudioRange ar (loc.start(), loc.end(), 1);
2897 separate_regions_between (ts);
2900 /** Separate regions under the selected region */
2902 Editor::separate_under_selected_regions ()
2904 vector<PlaylistState> playlists;
2908 rs = get_regions_from_selection_and_entered();
2910 if (!_session || rs.empty()) {
2914 begin_reversible_command (_("separate region under"));
2916 list<boost::shared_ptr<Region> > regions_to_remove;
2918 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2919 // we can't just remove the region(s) in this loop because
2920 // this removes them from the RegionSelection, and they thus
2921 // disappear from underneath the iterator, and the ++i above
2922 // SEGVs in a puzzling fashion.
2924 // so, first iterate over the regions to be removed from rs and
2925 // add them to the regions_to_remove list, and then
2926 // iterate over the list to actually remove them.
2928 regions_to_remove.push_back ((*i)->region());
2931 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2933 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2936 // is this check necessary?
2940 vector<PlaylistState>::iterator i;
2942 //only take state if this is a new playlist.
2943 for (i = playlists.begin(); i != playlists.end(); ++i) {
2944 if ((*i).playlist == playlist) {
2949 if (i == playlists.end()) {
2951 PlaylistState before;
2952 before.playlist = playlist;
2953 before.before = &playlist->get_state();
2955 playlist->freeze ();
2956 playlists.push_back(before);
2959 //Partition on the region bounds
2960 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2962 //Re-add region that was just removed due to the partition operation
2963 playlist->add_region( (*rl), (*rl)->first_frame() );
2966 vector<PlaylistState>::iterator pl;
2968 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2969 (*pl).playlist->thaw ();
2970 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2973 commit_reversible_command ();
2977 Editor::crop_region_to_selection ()
2979 if (!selection->time.empty()) {
2981 crop_region_to (selection->time.start(), selection->time.end_frame());
2988 if (get_edit_op_range (start, end)) {
2989 crop_region_to (start, end);
2996 Editor::crop_region_to (framepos_t start, framepos_t end)
2998 vector<boost::shared_ptr<Playlist> > playlists;
2999 boost::shared_ptr<Playlist> playlist;
3002 if (selection->tracks.empty()) {
3003 ts = track_views.filter_to_unique_playlists();
3005 ts = selection->tracks.filter_to_unique_playlists ();
3008 sort_track_selection (ts);
3010 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3012 RouteTimeAxisView* rtv;
3014 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3016 boost::shared_ptr<Track> t = rtv->track();
3018 if (t != 0 && ! t->destructive()) {
3020 if ((playlist = rtv->playlist()) != 0) {
3021 playlists.push_back (playlist);
3027 if (playlists.empty()) {
3031 framepos_t the_start;
3035 begin_reversible_command (_("trim to selection"));
3037 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3039 boost::shared_ptr<Region> region;
3043 if ((region = (*i)->top_region_at(the_start)) == 0) {
3047 /* now adjust lengths to that we do the right thing
3048 if the selection extends beyond the region
3051 the_start = max (the_start, (framepos_t) region->position());
3052 if (max_framepos - the_start < region->length()) {
3053 the_end = the_start + region->length() - 1;
3055 the_end = max_framepos;
3057 the_end = min (end, the_end);
3058 cnt = the_end - the_start + 1;
3060 region->clear_changes ();
3061 region->trim_to (the_start, cnt);
3062 _session->add_command (new StatefulDiffCommand (region));
3065 commit_reversible_command ();
3069 Editor::region_fill_track ()
3071 RegionSelection rs = get_regions_from_selection_and_entered ();
3073 if (!_session || rs.empty()) {
3077 framepos_t const end = _session->current_end_frame ();
3079 begin_reversible_command (Operations::region_fill);
3081 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3083 boost::shared_ptr<Region> region ((*i)->region());
3085 boost::shared_ptr<Playlist> pl = region->playlist();
3087 if (end <= region->last_frame()) {
3091 double times = (double) (end - region->last_frame()) / (double) region->length();
3097 pl->clear_changes ();
3098 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3099 _session->add_command (new StatefulDiffCommand (pl));
3102 commit_reversible_command ();
3106 Editor::region_fill_selection ()
3108 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3112 if (selection->time.empty()) {
3116 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3121 framepos_t start = selection->time[clicked_selection].start;
3122 framepos_t end = selection->time[clicked_selection].end;
3124 boost::shared_ptr<Playlist> playlist;
3126 if (selection->tracks.empty()) {
3130 framepos_t selection_length = end - start;
3131 float times = (float)selection_length / region->length();
3133 begin_reversible_command (Operations::fill_selection);
3135 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3137 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3139 if ((playlist = (*i)->playlist()) == 0) {
3143 playlist->clear_changes ();
3144 playlist->add_region (RegionFactory::create (region, true), start, times);
3145 _session->add_command (new StatefulDiffCommand (playlist));
3148 commit_reversible_command ();
3152 Editor::set_region_sync_position ()
3154 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3158 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3160 bool in_command = false;
3162 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3164 if (!(*r)->region()->covers (where)) {
3168 boost::shared_ptr<Region> region ((*r)->region());
3171 begin_reversible_command (_("set sync point"));
3175 region->clear_changes ();
3176 region->set_sync_position (where);
3177 _session->add_command(new StatefulDiffCommand (region));
3181 commit_reversible_command ();
3185 /** Remove the sync positions of the selection */
3187 Editor::remove_region_sync ()
3189 RegionSelection rs = get_regions_from_selection_and_entered ();
3195 begin_reversible_command (_("remove region sync"));
3197 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3199 (*i)->region()->clear_changes ();
3200 (*i)->region()->clear_sync_position ();
3201 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3204 commit_reversible_command ();
3208 Editor::naturalize_region ()
3210 RegionSelection rs = get_regions_from_selection_and_entered ();
3216 if (rs.size() > 1) {
3217 begin_reversible_command (_("move regions to original position"));
3219 begin_reversible_command (_("move region to original position"));
3222 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3223 (*i)->region()->clear_changes ();
3224 (*i)->region()->move_to_natural_position ();
3225 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3228 commit_reversible_command ();
3232 Editor::align_regions (RegionPoint what)
3234 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3240 begin_reversible_command (_("align selection"));
3242 framepos_t const position = get_preferred_edit_position ();
3244 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3245 align_region_internal ((*i)->region(), what, position);
3248 commit_reversible_command ();
3251 struct RegionSortByTime {
3252 bool operator() (const RegionView* a, const RegionView* b) {
3253 return a->region()->position() < b->region()->position();
3258 Editor::align_regions_relative (RegionPoint point)
3260 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3266 framepos_t const position = get_preferred_edit_position ();
3268 framepos_t distance = 0;
3272 list<RegionView*> sorted;
3273 rs.by_position (sorted);
3275 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3280 if (position > r->position()) {
3281 distance = position - r->position();
3283 distance = r->position() - position;
3289 if (position > r->last_frame()) {
3290 distance = position - r->last_frame();
3291 pos = r->position() + distance;
3293 distance = r->last_frame() - position;
3294 pos = r->position() - distance;
3300 pos = r->adjust_to_sync (position);
3301 if (pos > r->position()) {
3302 distance = pos - r->position();
3304 distance = r->position() - pos;
3310 if (pos == r->position()) {
3314 begin_reversible_command (_("align selection (relative)"));
3316 /* move first one specially */
3318 r->clear_changes ();
3319 r->set_position (pos);
3320 _session->add_command(new StatefulDiffCommand (r));
3322 /* move rest by the same amount */
3326 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3328 boost::shared_ptr<Region> region ((*i)->region());
3330 region->clear_changes ();
3333 region->set_position (region->position() + distance);
3335 region->set_position (region->position() - distance);
3338 _session->add_command(new StatefulDiffCommand (region));
3342 commit_reversible_command ();
3346 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3348 begin_reversible_command (_("align region"));
3349 align_region_internal (region, point, position);
3350 commit_reversible_command ();
3354 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3356 region->clear_changes ();
3360 region->set_position (region->adjust_to_sync (position));
3364 if (position > region->length()) {
3365 region->set_position (position - region->length());
3370 region->set_position (position);
3374 _session->add_command(new StatefulDiffCommand (region));
3378 Editor::trim_region_front ()
3384 Editor::trim_region_back ()
3386 trim_region (false);
3390 Editor::trim_region (bool front)
3392 framepos_t where = get_preferred_edit_position();
3393 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3399 begin_reversible_command (front ? _("trim front") : _("trim back"));
3401 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3402 if (!(*i)->region()->locked()) {
3404 (*i)->region()->clear_changes ();
3407 (*i)->region()->trim_front (where);
3408 maybe_locate_with_edit_preroll ( where );
3410 (*i)->region()->trim_end (where);
3411 maybe_locate_with_edit_preroll ( where );
3414 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3418 commit_reversible_command ();
3421 /** Trim the end of the selected regions to the position of the edit cursor */
3423 Editor::trim_region_to_loop ()
3425 Location* loc = _session->locations()->auto_loop_location();
3429 trim_region_to_location (*loc, _("trim to loop"));
3433 Editor::trim_region_to_punch ()
3435 Location* loc = _session->locations()->auto_punch_location();
3439 trim_region_to_location (*loc, _("trim to punch"));
3443 Editor::trim_region_to_location (const Location& loc, const char* str)
3445 RegionSelection rs = get_regions_from_selection_and_entered ();
3447 begin_reversible_command (str);
3449 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3450 RegionView* rv = (*x);
3452 /* require region to span proposed trim */
3453 switch (rv->region()->coverage (loc.start(), loc.end())) {
3454 case Evoral::OverlapInternal:
3460 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3469 if (tav->track() != 0) {
3470 speed = tav->track()->speed();
3473 start = session_frame_to_track_frame (loc.start(), speed);
3474 end = session_frame_to_track_frame (loc.end(), speed);
3476 rv->region()->clear_changes ();
3477 rv->region()->trim_to (start, (end - start));
3478 _session->add_command(new StatefulDiffCommand (rv->region()));
3481 commit_reversible_command ();
3485 Editor::trim_region_to_previous_region_end ()
3487 return trim_to_region(false);
3491 Editor::trim_region_to_next_region_start ()
3493 return trim_to_region(true);
3497 Editor::trim_to_region(bool forward)
3499 RegionSelection rs = get_regions_from_selection_and_entered ();
3501 begin_reversible_command (_("trim to region"));
3503 boost::shared_ptr<Region> next_region;
3505 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3507 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3513 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3521 if (atav->track() != 0) {
3522 speed = atav->track()->speed();
3526 boost::shared_ptr<Region> region = arv->region();
3527 boost::shared_ptr<Playlist> playlist (region->playlist());
3529 region->clear_changes ();
3533 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3539 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3540 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3544 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3550 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3552 arv->region_changed (ARDOUR::bounds_change);
3555 _session->add_command(new StatefulDiffCommand (region));
3558 commit_reversible_command ();
3562 Editor::unfreeze_route ()
3564 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3568 clicked_routeview->track()->unfreeze ();
3572 Editor::_freeze_thread (void* arg)
3574 return static_cast<Editor*>(arg)->freeze_thread ();
3578 Editor::freeze_thread ()
3580 /* create event pool because we may need to talk to the session */
3581 SessionEvent::create_per_thread_pool ("freeze events", 64);
3582 /* create per-thread buffers for process() tree to use */
3583 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3584 current_interthread_info->done = true;
3589 Editor::freeze_route ()
3595 /* stop transport before we start. this is important */
3597 _session->request_transport_speed (0.0);
3599 /* wait for just a little while, because the above call is asynchronous */
3601 Glib::usleep (250000);
3603 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3607 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3609 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3610 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3612 d.set_title (_("Cannot freeze"));
3617 if (clicked_routeview->track()->has_external_redirects()) {
3618 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"
3619 "Freezing will only process the signal as far as the first send/insert/return."),
3620 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3622 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3623 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3624 d.set_title (_("Freeze Limits"));
3626 int response = d.run ();
3629 case Gtk::RESPONSE_CANCEL:
3636 InterThreadInfo itt;
3637 current_interthread_info = &itt;
3639 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3641 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3643 set_canvas_cursor (_cursors->wait);
3645 while (!itt.done && !itt.cancel) {
3646 gtk_main_iteration ();
3649 current_interthread_info = 0;
3650 set_canvas_cursor (current_canvas_cursor);
3654 Editor::bounce_range_selection (bool replace, bool enable_processing)
3656 if (selection->time.empty()) {
3660 TrackSelection views = selection->tracks;
3662 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3664 if (enable_processing) {
3666 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3668 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3670 _("You can't perform this operation because the processing of the signal "
3671 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3672 "You can do this without processing, which is a different operation.")
3674 d.set_title (_("Cannot bounce"));
3681 framepos_t start = selection->time[clicked_selection].start;
3682 framepos_t end = selection->time[clicked_selection].end;
3683 framepos_t cnt = end - start + 1;
3685 begin_reversible_command (_("bounce range"));
3687 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3689 RouteTimeAxisView* rtv;
3691 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3695 boost::shared_ptr<Playlist> playlist;
3697 if ((playlist = rtv->playlist()) == 0) {
3701 InterThreadInfo itt;
3703 playlist->clear_changes ();
3704 playlist->clear_owned_changes ();
3706 boost::shared_ptr<Region> r;
3708 if (enable_processing) {
3709 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3711 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3719 list<AudioRange> ranges;
3720 ranges.push_back (AudioRange (start, start+cnt, 0));
3721 playlist->cut (ranges); // discard result
3722 playlist->add_region (r, start);
3725 vector<Command*> cmds;
3726 playlist->rdiff (cmds);
3727 _session->add_commands (cmds);
3729 _session->add_command (new StatefulDiffCommand (playlist));
3732 commit_reversible_command ();
3735 /** Delete selected regions, automation points or a time range */
3739 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3740 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3741 bool deleted = false;
3742 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3743 deleted = current_mixer_strip->delete_processors ();
3749 /** Cut selected regions, automation points or a time range */
3756 /** Copy selected regions, automation points or a time range */
3764 /** @return true if a Cut, Copy or Clear is possible */
3766 Editor::can_cut_copy () const
3768 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3775 /** Cut, copy or clear selected regions, automation points or a time range.
3776 * @param op Operation (Delete, Cut, Copy or Clear)
3779 Editor::cut_copy (CutCopyOp op)
3781 /* only cancel selection if cut/copy is successful.*/
3787 opname = _("delete");
3796 opname = _("clear");
3800 /* if we're deleting something, and the mouse is still pressed,
3801 the thing we started a drag for will be gone when we release
3802 the mouse button(s). avoid this. see part 2 at the end of
3806 if (op == Delete || op == Cut || op == Clear) {
3807 if (_drags->active ()) {
3812 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3813 cut_buffer->clear ();
3815 if (entered_marker) {
3817 /* cut/delete op while pointing at a marker */
3820 Location* loc = find_location_from_marker (entered_marker, ignored);
3822 if (_session && loc) {
3823 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3830 if (internal_editing()) {
3832 switch (effective_mouse_mode()) {
3835 begin_reversible_command (opname + ' ' + X_("MIDI"));
3837 commit_reversible_command ();
3846 bool did_edit = false;
3848 if (!selection->points.empty()) {
3849 begin_reversible_command (opname + _(" points"));
3851 cut_copy_points (op);
3852 if (op == Cut || op == Delete) {
3853 selection->clear_points ();
3855 } else if (!selection->regions.empty() || !selection->points.empty()) {
3859 if (selection->regions.empty()) {
3860 thing_name = _("points");
3861 } else if (selection->points.empty()) {
3862 thing_name = _("regions");
3864 thing_name = _("objects");
3867 begin_reversible_command (opname + ' ' + thing_name);
3870 if (!selection->regions.empty()) {
3871 cut_copy_regions (op, selection->regions);
3873 if (op == Cut || op == Delete) {
3874 selection->clear_regions ();
3878 if (!selection->points.empty()) {
3879 cut_copy_points (op);
3881 if (op == Cut || op == Delete) {
3882 selection->clear_points ();
3885 } else if (selection->time.empty()) {
3886 framepos_t start, end;
3887 /* no time selection, see if we can get an edit range
3890 if (get_edit_op_range (start, end)) {
3891 selection->set (start, end);
3893 } else if (!selection->time.empty()) {
3894 begin_reversible_command (opname + _(" range"));
3897 cut_copy_ranges (op);
3899 if (op == Cut || op == Delete) {
3900 selection->clear_time ();
3905 commit_reversible_command ();
3908 if (op == Delete || op == Cut || op == Clear) {
3913 struct AutomationRecord {
3914 AutomationRecord () : state (0) {}
3915 AutomationRecord (XMLNode* s) : state (s) {}
3917 XMLNode* state; ///< state before any operation
3918 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3921 /** Cut, copy or clear selected automation points.
3922 * @param op Operation (Cut, Copy or Clear)
3925 Editor::cut_copy_points (CutCopyOp op)
3927 if (selection->points.empty ()) {
3931 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3932 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3934 /* Keep a record of the AutomationLists that we end up using in this operation */
3935 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3938 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3939 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3940 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3941 if (lists.find (al) == lists.end ()) {
3942 /* We haven't seen this list yet, so make a record for it. This includes
3943 taking a copy of its current state, in case this is needed for undo later.
3945 lists[al] = AutomationRecord (&al->get_state ());
3949 if (op == Cut || op == Copy) {
3950 /* This operation will involve putting things in the cut buffer, so create an empty
3951 ControlList for each of our source lists to put the cut buffer data in.
3953 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3954 i->second.copy = i->first->create (i->first->parameter ());
3957 /* Add all selected points to the relevant copy ControlLists */
3958 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3959 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3960 AutomationList::const_iterator j = (*i)->model ();
3961 lists[al].copy->add ((*j)->when, (*j)->value);
3964 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3965 /* Correct this copy list so that it starts at time 0 */
3966 double const start = i->second.copy->front()->when;
3967 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3968 (*j)->when -= start;
3971 /* And add it to the cut buffer */
3972 cut_buffer->add (i->second.copy);
3976 if (op == Delete || op == Cut) {
3977 /* This operation needs to remove things from the main AutomationList, so do that now */
3979 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3980 i->first->freeze ();
3983 /* Remove each selected point from its AutomationList */
3984 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3985 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3986 al->erase ((*i)->model ());
3989 /* Thaw the lists and add undo records for them */
3990 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3991 boost::shared_ptr<AutomationList> al = i->first;
3993 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3998 /** Cut, copy or clear selected automation points.
3999 * @param op Operation (Cut, Copy or Clear)
4002 Editor::cut_copy_midi (CutCopyOp op)
4004 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4005 MidiRegionView* mrv = *i;
4006 mrv->cut_copy_clear (op);
4012 struct lt_playlist {
4013 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4014 return a.playlist < b.playlist;
4018 struct PlaylistMapping {
4020 boost::shared_ptr<Playlist> pl;
4022 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4025 /** Remove `clicked_regionview' */
4027 Editor::remove_clicked_region ()
4029 if (clicked_routeview == 0 || clicked_regionview == 0) {
4033 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4035 playlist->clear_changes ();
4036 playlist->clear_owned_changes ();
4037 playlist->remove_region (clicked_regionview->region());
4038 if (Config->get_edit_mode() == Ripple)
4039 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4041 /* We might have removed regions, which alters other regions' layering_index,
4042 so we need to do a recursive diff here.
4044 vector<Command*> cmds;
4045 playlist->rdiff (cmds);
4046 _session->add_commands (cmds);
4048 _session->add_command(new StatefulDiffCommand (playlist));
4049 commit_reversible_command ();
4053 /** Remove the selected regions */
4055 Editor::remove_selected_regions ()
4057 RegionSelection rs = get_regions_from_selection_and_entered ();
4059 if (!_session || rs.empty()) {
4063 begin_reversible_command (_("remove region"));
4065 list<boost::shared_ptr<Region> > regions_to_remove;
4067 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4068 // we can't just remove the region(s) in this loop because
4069 // this removes them from the RegionSelection, and they thus
4070 // disappear from underneath the iterator, and the ++i above
4071 // SEGVs in a puzzling fashion.
4073 // so, first iterate over the regions to be removed from rs and
4074 // add them to the regions_to_remove list, and then
4075 // iterate over the list to actually remove them.
4077 regions_to_remove.push_back ((*i)->region());
4080 vector<boost::shared_ptr<Playlist> > playlists;
4082 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4084 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4087 // is this check necessary?
4091 /* get_regions_from_selection_and_entered() guarantees that
4092 the playlists involved are unique, so there is no need
4096 playlists.push_back (playlist);
4098 playlist->clear_changes ();
4099 playlist->clear_owned_changes ();
4100 playlist->freeze ();
4101 playlist->remove_region (*rl);
4102 if (Config->get_edit_mode() == Ripple)
4103 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4107 vector<boost::shared_ptr<Playlist> >::iterator pl;
4109 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4112 /* We might have removed regions, which alters other regions' layering_index,
4113 so we need to do a recursive diff here.
4115 vector<Command*> cmds;
4116 (*pl)->rdiff (cmds);
4117 _session->add_commands (cmds);
4119 _session->add_command(new StatefulDiffCommand (*pl));
4122 commit_reversible_command ();
4125 /** Cut, copy or clear selected regions.
4126 * @param op Operation (Cut, Copy or Clear)
4129 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4131 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4132 a map when we want ordered access to both elements. i think.
4135 vector<PlaylistMapping> pmap;
4137 framepos_t first_position = max_framepos;
4139 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4140 FreezeList freezelist;
4142 /* get ordering correct before we cut/copy */
4144 rs.sort_by_position_and_track ();
4146 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4148 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4150 if (op == Cut || op == Clear || op == Delete) {
4151 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4154 FreezeList::iterator fl;
4156 // only take state if this is a new playlist.
4157 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4163 if (fl == freezelist.end()) {
4164 pl->clear_changes();
4165 pl->clear_owned_changes ();
4167 freezelist.insert (pl);
4172 TimeAxisView* tv = &(*x)->get_time_axis_view();
4173 vector<PlaylistMapping>::iterator z;
4175 for (z = pmap.begin(); z != pmap.end(); ++z) {
4176 if ((*z).tv == tv) {
4181 if (z == pmap.end()) {
4182 pmap.push_back (PlaylistMapping (tv));
4186 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4188 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4191 /* region not yet associated with a playlist (e.g. unfinished
4198 TimeAxisView& tv = (*x)->get_time_axis_view();
4199 boost::shared_ptr<Playlist> npl;
4200 RegionSelection::iterator tmp;
4207 vector<PlaylistMapping>::iterator z;
4209 for (z = pmap.begin(); z != pmap.end(); ++z) {
4210 if ((*z).tv == &tv) {
4215 assert (z != pmap.end());
4218 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4226 boost::shared_ptr<Region> r = (*x)->region();
4227 boost::shared_ptr<Region> _xx;
4233 pl->remove_region (r);
4234 if (Config->get_edit_mode() == Ripple)
4235 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4239 _xx = RegionFactory::create (r);
4240 npl->add_region (_xx, r->position() - first_position);
4241 pl->remove_region (r);
4242 if (Config->get_edit_mode() == Ripple)
4243 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4247 /* copy region before adding, so we're not putting same object into two different playlists */
4248 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4252 pl->remove_region (r);
4253 if (Config->get_edit_mode() == Ripple)
4254 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4263 list<boost::shared_ptr<Playlist> > foo;
4265 /* the pmap is in the same order as the tracks in which selected regions occured */
4267 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4270 foo.push_back ((*i).pl);
4275 cut_buffer->set (foo);
4279 _last_cut_copy_source_track = 0;
4281 _last_cut_copy_source_track = pmap.front().tv;
4285 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4288 /* We might have removed regions, which alters other regions' layering_index,
4289 so we need to do a recursive diff here.
4291 vector<Command*> cmds;
4292 (*pl)->rdiff (cmds);
4293 _session->add_commands (cmds);
4295 _session->add_command (new StatefulDiffCommand (*pl));
4300 Editor::cut_copy_ranges (CutCopyOp op)
4302 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4304 /* Sort the track selection now, so that it if is used, the playlists
4305 selected by the calls below to cut_copy_clear are in the order that
4306 their tracks appear in the editor. This makes things like paste
4307 of ranges work properly.
4310 sort_track_selection (ts);
4313 if (!entered_track) {
4316 ts.push_back (entered_track);
4319 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4320 (*i)->cut_copy_clear (*selection, op);
4325 Editor::paste (float times, bool from_context)
4327 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4329 paste_internal (get_preferred_edit_position (false, from_context), times);
4333 Editor::mouse_paste ()
4338 if (!mouse_frame (where, ignored)) {
4343 paste_internal (where, 1);
4347 Editor::paste_internal (framepos_t position, float times)
4349 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4351 if (internal_editing()) {
4352 if (cut_buffer->midi_notes.empty()) {
4356 if (cut_buffer->empty()) {
4361 if (position == max_framepos) {
4362 position = get_preferred_edit_position();
4363 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4367 TrackViewList::iterator i;
4370 /* get everything in the correct order */
4372 if (_edit_point == Editing::EditAtMouse && entered_track) {
4373 /* With the mouse edit point, paste onto the track under the mouse */
4374 ts.push_back (entered_track);
4375 } else if (!selection->tracks.empty()) {
4376 /* Otherwise, if there are some selected tracks, paste to them */
4377 ts = selection->tracks.filter_to_unique_playlists ();
4378 sort_track_selection (ts);
4379 } else if (_last_cut_copy_source_track) {
4380 /* Otherwise paste to the track that the cut/copy came from;
4381 see discussion in mantis #3333.
4383 ts.push_back (_last_cut_copy_source_track);
4386 if (internal_editing ()) {
4388 /* undo/redo is handled by individual tracks/regions */
4390 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4393 RegionSelection::iterator r;
4394 MidiNoteSelection::iterator cb;
4396 get_regions_at (rs, position, ts);
4398 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4399 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4400 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4402 mrv->paste (position, times, **cb);
4410 /* we do redo (do you do voodoo?) */
4412 begin_reversible_command (Operations::paste);
4414 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4415 (*i)->paste (position, times, *cut_buffer, nth);
4418 commit_reversible_command ();
4423 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4425 boost::shared_ptr<Playlist> playlist;
4426 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4427 RegionSelection foo;
4429 framepos_t const start_frame = regions.start ();
4430 framepos_t const end_frame = regions.end_frame ();
4432 begin_reversible_command (Operations::duplicate_region);
4434 selection->clear_regions ();
4436 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4438 boost::shared_ptr<Region> r ((*i)->region());
4440 TimeAxisView& tv = (*i)->get_time_axis_view();
4441 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4442 latest_regionviews.clear ();
4443 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4445 playlist = (*i)->region()->playlist();
4446 playlist->clear_changes ();
4447 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4448 _session->add_command(new StatefulDiffCommand (playlist));
4452 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4455 commit_reversible_command ();
4458 selection->set (foo);
4463 Editor::duplicate_selection (float times)
4465 if (selection->time.empty() || selection->tracks.empty()) {
4469 boost::shared_ptr<Playlist> playlist;
4470 vector<boost::shared_ptr<Region> > new_regions;
4471 vector<boost::shared_ptr<Region> >::iterator ri;
4473 create_region_from_selection (new_regions);
4475 if (new_regions.empty()) {
4479 begin_reversible_command (_("duplicate selection"));
4481 ri = new_regions.begin();
4483 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4485 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4486 if ((playlist = (*i)->playlist()) == 0) {
4489 playlist->clear_changes ();
4490 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4491 _session->add_command (new StatefulDiffCommand (playlist));
4494 if (ri == new_regions.end()) {
4499 commit_reversible_command ();
4502 /** Reset all selected points to the relevant default value */
4504 Editor::reset_point_selection ()
4506 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4507 ARDOUR::AutomationList::iterator j = (*i)->model ();
4508 (*j)->value = (*i)->line().the_list()->default_value ();
4513 Editor::center_playhead ()
4515 float const page = _visible_canvas_width * samples_per_pixel;
4516 center_screen_internal (playhead_cursor->current_frame (), page);
4520 Editor::center_edit_point ()
4522 float const page = _visible_canvas_width * samples_per_pixel;
4523 center_screen_internal (get_preferred_edit_position(), page);
4526 /** Caller must begin and commit a reversible command */
4528 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4530 playlist->clear_changes ();
4532 _session->add_command (new StatefulDiffCommand (playlist));
4536 Editor::nudge_track (bool use_edit, bool forwards)
4538 boost::shared_ptr<Playlist> playlist;
4539 framepos_t distance;
4540 framepos_t next_distance;
4544 start = get_preferred_edit_position();
4549 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4553 if (selection->tracks.empty()) {
4557 begin_reversible_command (_("nudge track"));
4559 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4561 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4563 if ((playlist = (*i)->playlist()) == 0) {
4567 playlist->clear_changes ();
4568 playlist->clear_owned_changes ();
4570 playlist->nudge_after (start, distance, forwards);
4572 vector<Command*> cmds;
4574 playlist->rdiff (cmds);
4575 _session->add_commands (cmds);
4577 _session->add_command (new StatefulDiffCommand (playlist));
4580 commit_reversible_command ();
4584 Editor::remove_last_capture ()
4586 vector<string> choices;
4593 if (Config->get_verify_remove_last_capture()) {
4594 prompt = _("Do you really want to destroy the last capture?"
4595 "\n(This is destructive and cannot be undone)");
4597 choices.push_back (_("No, do nothing."));
4598 choices.push_back (_("Yes, destroy it."));
4600 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4602 if (prompter.run () == 1) {
4603 _session->remove_last_capture ();
4604 _regions->redisplay ();
4608 _session->remove_last_capture();
4609 _regions->redisplay ();
4614 Editor::normalize_region ()
4620 RegionSelection rs = get_regions_from_selection_and_entered ();
4626 NormalizeDialog dialog (rs.size() > 1);
4628 if (dialog.run () == RESPONSE_CANCEL) {
4632 set_canvas_cursor (_cursors->wait);
4635 /* XXX: should really only count audio regions here */
4636 int const regions = rs.size ();
4638 /* Make a list of the selected audio regions' maximum amplitudes, and also
4639 obtain the maximum amplitude of them all.
4641 list<double> max_amps;
4643 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4644 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4646 dialog.descend (1.0 / regions);
4647 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4650 /* the user cancelled the operation */
4651 set_canvas_cursor (current_canvas_cursor);
4655 max_amps.push_back (a);
4656 max_amp = max (max_amp, a);
4661 begin_reversible_command (_("normalize"));
4663 list<double>::const_iterator a = max_amps.begin ();
4665 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4666 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4671 arv->region()->clear_changes ();
4673 double const amp = dialog.normalize_individually() ? *a : max_amp;
4675 arv->audio_region()->normalize (amp, dialog.target ());
4676 _session->add_command (new StatefulDiffCommand (arv->region()));
4681 commit_reversible_command ();
4682 set_canvas_cursor (current_canvas_cursor);
4687 Editor::reset_region_scale_amplitude ()
4693 RegionSelection rs = get_regions_from_selection_and_entered ();
4699 begin_reversible_command ("reset gain");
4701 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4702 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4705 arv->region()->clear_changes ();
4706 arv->audio_region()->set_scale_amplitude (1.0f);
4707 _session->add_command (new StatefulDiffCommand (arv->region()));
4710 commit_reversible_command ();
4714 Editor::adjust_region_gain (bool up)
4716 RegionSelection rs = get_regions_from_selection_and_entered ();
4718 if (!_session || rs.empty()) {
4722 begin_reversible_command ("adjust region gain");
4724 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4725 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4730 arv->region()->clear_changes ();
4732 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4740 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4741 _session->add_command (new StatefulDiffCommand (arv->region()));
4744 commit_reversible_command ();
4749 Editor::reverse_region ()
4755 Reverse rev (*_session);
4756 apply_filter (rev, _("reverse regions"));
4760 Editor::strip_region_silence ()
4766 RegionSelection rs = get_regions_from_selection_and_entered ();
4772 std::list<RegionView*> audio_only;
4774 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4775 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4777 audio_only.push_back (arv);
4781 StripSilenceDialog d (_session, audio_only);
4782 int const r = d.run ();
4786 if (r == Gtk::RESPONSE_OK) {
4787 ARDOUR::AudioIntervalMap silences;
4788 d.silences (silences);
4789 StripSilence s (*_session, silences, d.fade_length());
4790 apply_filter (s, _("strip silence"), &d);
4795 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4797 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4798 mrv.selection_as_notelist (selected, true);
4800 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4801 v.push_back (selected);
4803 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4804 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4806 return op (mrv.midi_region()->model(), pos_beats, v);
4810 Editor::apply_midi_note_edit_op (MidiOperator& op)
4814 RegionSelection rs = get_regions_from_selection_and_entered ();
4820 begin_reversible_command (op.name ());
4822 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4823 RegionSelection::iterator tmp = r;
4826 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4829 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4832 _session->add_command (cmd);
4839 commit_reversible_command ();
4843 Editor::fork_region ()
4845 RegionSelection rs = get_regions_from_selection_and_entered ();
4851 begin_reversible_command (_("Fork Region(s)"));
4853 set_canvas_cursor (_cursors->wait);
4856 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4857 RegionSelection::iterator tmp = r;
4860 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4864 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4865 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4866 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4868 playlist->clear_changes ();
4869 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4870 _session->add_command(new StatefulDiffCommand (playlist));
4872 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4879 commit_reversible_command ();
4881 set_canvas_cursor (current_canvas_cursor);
4885 Editor::quantize_region ()
4887 int selected_midi_region_cnt = 0;
4893 RegionSelection rs = get_regions_from_selection_and_entered ();
4899 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4900 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4902 selected_midi_region_cnt++;
4906 if (selected_midi_region_cnt == 0) {
4910 QuantizeDialog* qd = new QuantizeDialog (*this);
4913 const int r = qd->run ();
4916 if (r == Gtk::RESPONSE_OK) {
4917 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4918 qd->start_grid_size(), qd->end_grid_size(),
4919 qd->strength(), qd->swing(), qd->threshold());
4921 apply_midi_note_edit_op (quant);
4926 Editor::insert_patch_change (bool from_context)
4928 RegionSelection rs = get_regions_from_selection_and_entered ();
4934 const framepos_t p = get_preferred_edit_position (false, from_context);
4936 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4937 there may be more than one, but the PatchChangeDialog can only offer
4938 one set of patch menus.
4940 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4942 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4943 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4945 if (d.run() == RESPONSE_CANCEL) {
4949 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4950 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4952 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4953 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4960 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4962 RegionSelection rs = get_regions_from_selection_and_entered ();
4968 begin_reversible_command (command);
4970 set_canvas_cursor (_cursors->wait);
4974 int const N = rs.size ();
4976 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4977 RegionSelection::iterator tmp = r;
4980 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4982 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4985 progress->descend (1.0 / N);
4988 if (arv->audio_region()->apply (filter, progress) == 0) {
4990 playlist->clear_changes ();
4991 playlist->clear_owned_changes ();
4993 if (filter.results.empty ()) {
4995 /* no regions returned; remove the old one */
4996 playlist->remove_region (arv->region ());
5000 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5002 /* first region replaces the old one */
5003 playlist->replace_region (arv->region(), *res, (*res)->position());
5007 while (res != filter.results.end()) {
5008 playlist->add_region (*res, (*res)->position());
5014 /* We might have removed regions, which alters other regions' layering_index,
5015 so we need to do a recursive diff here.
5017 vector<Command*> cmds;
5018 playlist->rdiff (cmds);
5019 _session->add_commands (cmds);
5021 _session->add_command(new StatefulDiffCommand (playlist));
5027 progress->ascend ();
5035 commit_reversible_command ();
5038 set_canvas_cursor (current_canvas_cursor);
5042 Editor::external_edit_region ()
5048 Editor::reset_region_gain_envelopes ()
5050 RegionSelection rs = get_regions_from_selection_and_entered ();
5052 if (!_session || rs.empty()) {
5056 _session->begin_reversible_command (_("reset region gain"));
5058 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5059 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5061 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5062 XMLNode& before (alist->get_state());
5064 arv->audio_region()->set_default_envelope ();
5065 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5069 _session->commit_reversible_command ();
5073 Editor::set_region_gain_visibility (RegionView* rv)
5075 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5077 arv->update_envelope_visibility();
5082 Editor::set_gain_envelope_visibility ()
5088 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5089 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5091 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5097 Editor::toggle_gain_envelope_active ()
5099 if (_ignore_region_action) {
5103 RegionSelection rs = get_regions_from_selection_and_entered ();
5105 if (!_session || rs.empty()) {
5109 _session->begin_reversible_command (_("region gain envelope active"));
5111 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5112 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5114 arv->region()->clear_changes ();
5115 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5116 _session->add_command (new StatefulDiffCommand (arv->region()));
5120 _session->commit_reversible_command ();
5124 Editor::toggle_region_lock ()
5126 if (_ignore_region_action) {
5130 RegionSelection rs = get_regions_from_selection_and_entered ();
5132 if (!_session || rs.empty()) {
5136 _session->begin_reversible_command (_("toggle region lock"));
5138 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5139 (*i)->region()->clear_changes ();
5140 (*i)->region()->set_locked (!(*i)->region()->locked());
5141 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5144 _session->commit_reversible_command ();
5148 Editor::toggle_region_video_lock ()
5150 if (_ignore_region_action) {
5154 RegionSelection rs = get_regions_from_selection_and_entered ();
5156 if (!_session || rs.empty()) {
5160 _session->begin_reversible_command (_("Toggle Video Lock"));
5162 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5163 (*i)->region()->clear_changes ();
5164 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5165 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5168 _session->commit_reversible_command ();
5172 Editor::toggle_region_lock_style ()
5174 if (_ignore_region_action) {
5178 RegionSelection rs = get_regions_from_selection_and_entered ();
5180 if (!_session || rs.empty()) {
5184 _session->begin_reversible_command (_("region lock style"));
5186 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5187 (*i)->region()->clear_changes ();
5188 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5189 (*i)->region()->set_position_lock_style (ns);
5190 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5193 _session->commit_reversible_command ();
5197 Editor::toggle_opaque_region ()
5199 if (_ignore_region_action) {
5203 RegionSelection rs = get_regions_from_selection_and_entered ();
5205 if (!_session || rs.empty()) {
5209 _session->begin_reversible_command (_("change region opacity"));
5211 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5212 (*i)->region()->clear_changes ();
5213 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5214 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5217 _session->commit_reversible_command ();
5221 Editor::toggle_record_enable ()
5223 bool new_state = false;
5225 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5226 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5229 if (!rtav->is_track())
5233 new_state = !rtav->track()->record_enabled();
5237 rtav->track()->set_record_enabled (new_state, this);
5242 Editor::toggle_solo ()
5244 bool new_state = false;
5246 boost::shared_ptr<RouteList> rl (new RouteList);
5248 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5249 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5256 new_state = !rtav->route()->soloed ();
5260 rl->push_back (rtav->route());
5263 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5267 Editor::toggle_mute ()
5269 bool new_state = false;
5271 boost::shared_ptr<RouteList> rl (new RouteList);
5273 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5274 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5281 new_state = !rtav->route()->muted();
5285 rl->push_back (rtav->route());
5288 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5292 Editor::toggle_solo_isolate ()
5298 Editor::fade_range ()
5300 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5302 begin_reversible_command (_("fade range"));
5304 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5305 (*i)->fade_range (selection->time);
5308 commit_reversible_command ();
5313 Editor::set_fade_length (bool in)
5315 RegionSelection rs = get_regions_from_selection_and_entered ();
5321 /* we need a region to measure the offset from the start */
5323 RegionView* rv = rs.front ();
5325 framepos_t pos = get_preferred_edit_position();
5329 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5330 /* edit point is outside the relevant region */
5335 if (pos <= rv->region()->position()) {
5339 len = pos - rv->region()->position();
5340 cmd = _("set fade in length");
5342 if (pos >= rv->region()->last_frame()) {
5346 len = rv->region()->last_frame() - pos;
5347 cmd = _("set fade out length");
5350 begin_reversible_command (cmd);
5352 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5353 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5359 boost::shared_ptr<AutomationList> alist;
5361 alist = tmp->audio_region()->fade_in();
5363 alist = tmp->audio_region()->fade_out();
5366 XMLNode &before = alist->get_state();
5369 tmp->audio_region()->set_fade_in_length (len);
5370 tmp->audio_region()->set_fade_in_active (true);
5372 tmp->audio_region()->set_fade_out_length (len);
5373 tmp->audio_region()->set_fade_out_active (true);
5376 XMLNode &after = alist->get_state();
5377 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5380 commit_reversible_command ();
5384 Editor::set_fade_in_shape (FadeShape shape)
5386 RegionSelection rs = get_regions_from_selection_and_entered ();
5392 begin_reversible_command (_("set fade in shape"));
5394 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5395 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5401 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5402 XMLNode &before = alist->get_state();
5404 tmp->audio_region()->set_fade_in_shape (shape);
5406 XMLNode &after = alist->get_state();
5407 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5410 commit_reversible_command ();
5415 Editor::set_fade_out_shape (FadeShape shape)
5417 RegionSelection rs = get_regions_from_selection_and_entered ();
5423 begin_reversible_command (_("set fade out shape"));
5425 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5426 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5432 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5433 XMLNode &before = alist->get_state();
5435 tmp->audio_region()->set_fade_out_shape (shape);
5437 XMLNode &after = alist->get_state();
5438 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5441 commit_reversible_command ();
5445 Editor::set_fade_in_active (bool yn)
5447 RegionSelection rs = get_regions_from_selection_and_entered ();
5453 begin_reversible_command (_("set fade in active"));
5455 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5456 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5463 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5465 ar->clear_changes ();
5466 ar->set_fade_in_active (yn);
5467 _session->add_command (new StatefulDiffCommand (ar));
5470 commit_reversible_command ();
5474 Editor::set_fade_out_active (bool yn)
5476 RegionSelection rs = get_regions_from_selection_and_entered ();
5482 begin_reversible_command (_("set fade out active"));
5484 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5485 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5491 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5493 ar->clear_changes ();
5494 ar->set_fade_out_active (yn);
5495 _session->add_command(new StatefulDiffCommand (ar));
5498 commit_reversible_command ();
5502 Editor::toggle_region_fades (int dir)
5504 if (_ignore_region_action) {
5508 boost::shared_ptr<AudioRegion> ar;
5511 RegionSelection rs = get_regions_from_selection_and_entered ();
5517 RegionSelection::iterator i;
5518 for (i = rs.begin(); i != rs.end(); ++i) {
5519 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5521 yn = ar->fade_out_active ();
5523 yn = ar->fade_in_active ();
5529 if (i == rs.end()) {
5533 /* XXX should this undo-able? */
5535 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5536 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5539 if (dir == 1 || dir == 0) {
5540 ar->set_fade_in_active (!yn);
5543 if (dir == -1 || dir == 0) {
5544 ar->set_fade_out_active (!yn);
5550 /** Update region fade visibility after its configuration has been changed */
5552 Editor::update_region_fade_visibility ()
5554 bool _fade_visibility = _session->config.get_show_region_fades ();
5556 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5557 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5559 if (_fade_visibility) {
5560 v->audio_view()->show_all_fades ();
5562 v->audio_view()->hide_all_fades ();
5569 Editor::set_edit_point ()
5574 if (!mouse_frame (where, ignored)) {
5580 if (selection->markers.empty()) {
5582 mouse_add_new_marker (where);
5587 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5590 loc->move_to (where);
5596 Editor::set_playhead_cursor ()
5598 if (entered_marker) {
5599 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5604 if (!mouse_frame (where, ignored)) {
5611 _session->request_locate (where, _session->transport_rolling());
5615 if ( Config->get_follow_edits() )
5616 cancel_time_selection();
5620 Editor::split_region ()
5622 if ( !selection->time.empty()) {
5623 separate_regions_between (selection->time);
5627 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5629 framepos_t where = get_preferred_edit_position ();
5635 split_regions_at (where, rs);
5638 struct EditorOrderRouteSorter {
5639 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5640 return a->order_key () < b->order_key ();
5645 Editor::select_next_route()
5647 if (selection->tracks.empty()) {
5648 selection->set (track_views.front());
5652 TimeAxisView* current = selection->tracks.front();
5656 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5657 if (*i == current) {
5659 if (i != track_views.end()) {
5662 current = (*(track_views.begin()));
5663 //selection->set (*(track_views.begin()));
5668 rui = dynamic_cast<RouteUI *>(current);
5669 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5671 selection->set(current);
5673 ensure_time_axis_view_is_visible (*current, false);
5677 Editor::select_prev_route()
5679 if (selection->tracks.empty()) {
5680 selection->set (track_views.front());
5684 TimeAxisView* current = selection->tracks.front();
5688 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5689 if (*i == current) {
5691 if (i != track_views.rend()) {
5694 current = *(track_views.rbegin());
5699 rui = dynamic_cast<RouteUI *>(current);
5700 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5702 selection->set (current);
5704 ensure_time_axis_view_is_visible (*current, false);
5708 Editor::set_loop_from_selection (bool play)
5710 if (_session == 0 || selection->time.empty()) {
5714 framepos_t start = selection->time[clicked_selection].start;
5715 framepos_t end = selection->time[clicked_selection].end;
5717 set_loop_range (start, end, _("set loop range from selection"));
5720 _session->request_locate (start, true);
5721 _session->request_play_loop (true);
5726 Editor::set_loop_from_edit_range (bool play)
5728 if (_session == 0) {
5735 if (!get_edit_op_range (start, end)) {
5739 set_loop_range (start, end, _("set loop range from edit range"));
5742 _session->request_locate (start, true);
5743 _session->request_play_loop (true);
5748 Editor::set_loop_from_region (bool play)
5750 framepos_t start = max_framepos;
5753 RegionSelection rs = get_regions_from_selection_and_entered ();
5759 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5760 if ((*i)->region()->position() < start) {
5761 start = (*i)->region()->position();
5763 if ((*i)->region()->last_frame() + 1 > end) {
5764 end = (*i)->region()->last_frame() + 1;
5768 set_loop_range (start, end, _("set loop range from region"));
5771 _session->request_locate (start, true);
5772 _session->request_play_loop (true);
5777 Editor::set_punch_from_selection ()
5779 if (_session == 0 || selection->time.empty()) {
5783 framepos_t start = selection->time[clicked_selection].start;
5784 framepos_t end = selection->time[clicked_selection].end;
5786 set_punch_range (start, end, _("set punch range from selection"));
5790 Editor::set_punch_from_edit_range ()
5792 if (_session == 0) {
5799 if (!get_edit_op_range (start, end)) {
5803 set_punch_range (start, end, _("set punch range from edit range"));
5807 Editor::set_punch_from_region ()
5809 framepos_t start = max_framepos;
5812 RegionSelection rs = get_regions_from_selection_and_entered ();
5818 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5819 if ((*i)->region()->position() < start) {
5820 start = (*i)->region()->position();
5822 if ((*i)->region()->last_frame() + 1 > end) {
5823 end = (*i)->region()->last_frame() + 1;
5827 set_punch_range (start, end, _("set punch range from region"));
5831 Editor::pitch_shift_region ()
5833 RegionSelection rs = get_regions_from_selection_and_entered ();
5835 RegionSelection audio_rs;
5836 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5837 if (dynamic_cast<AudioRegionView*> (*i)) {
5838 audio_rs.push_back (*i);
5842 if (audio_rs.empty()) {
5846 pitch_shift (audio_rs, 1.2);
5850 Editor::transpose_region ()
5852 RegionSelection rs = get_regions_from_selection_and_entered ();
5854 list<MidiRegionView*> midi_region_views;
5855 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5856 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5858 midi_region_views.push_back (mrv);
5863 int const r = d.run ();
5864 if (r != RESPONSE_ACCEPT) {
5868 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5869 (*i)->midi_region()->transpose (d.semitones ());
5874 Editor::set_tempo_from_region ()
5876 RegionSelection rs = get_regions_from_selection_and_entered ();
5878 if (!_session || rs.empty()) {
5882 RegionView* rv = rs.front();
5884 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5888 Editor::use_range_as_bar ()
5890 framepos_t start, end;
5891 if (get_edit_op_range (start, end)) {
5892 define_one_bar (start, end);
5897 Editor::define_one_bar (framepos_t start, framepos_t end)
5899 framepos_t length = end - start;
5901 const Meter& m (_session->tempo_map().meter_at (start));
5903 /* length = 1 bar */
5905 /* now we want frames per beat.
5906 we have frames per bar, and beats per bar, so ...
5909 /* XXXX METER MATH */
5911 double frames_per_beat = length / m.divisions_per_bar();
5913 /* beats per minute = */
5915 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5917 /* now decide whether to:
5919 (a) set global tempo
5920 (b) add a new tempo marker
5924 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5926 bool do_global = false;
5928 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5930 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5931 at the start, or create a new marker
5934 vector<string> options;
5935 options.push_back (_("Cancel"));
5936 options.push_back (_("Add new marker"));
5937 options.push_back (_("Set global tempo"));
5940 _("Define one bar"),
5941 _("Do you want to set the global tempo or add a new tempo marker?"),
5945 c.set_default_response (2);
5961 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5962 if the marker is at the region starter, change it, otherwise add
5967 begin_reversible_command (_("set tempo from region"));
5968 XMLNode& before (_session->tempo_map().get_state());
5971 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5972 } else if (t.frame() == start) {
5973 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5975 Timecode::BBT_Time bbt;
5976 _session->tempo_map().bbt_time (start, bbt);
5977 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5980 XMLNode& after (_session->tempo_map().get_state());
5982 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5983 commit_reversible_command ();
5987 Editor::split_region_at_transients ()
5989 AnalysisFeatureList positions;
5991 RegionSelection rs = get_regions_from_selection_and_entered ();
5993 if (!_session || rs.empty()) {
5997 _session->begin_reversible_command (_("split regions"));
5999 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6001 RegionSelection::iterator tmp;
6006 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6008 if (ar && (ar->get_transients (positions) == 0)) {
6009 split_region_at_points ((*i)->region(), positions, true);
6016 _session->commit_reversible_command ();
6021 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6023 bool use_rhythmic_rodent = false;
6025 boost::shared_ptr<Playlist> pl = r->playlist();
6027 list<boost::shared_ptr<Region> > new_regions;
6033 if (positions.empty()) {
6038 if (positions.size() > 20 && can_ferret) {
6039 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);
6040 MessageDialog msg (msgstr,
6043 Gtk::BUTTONS_OK_CANCEL);
6046 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6047 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6049 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6052 msg.set_title (_("Excessive split?"));
6055 int response = msg.run();
6061 case RESPONSE_APPLY:
6062 use_rhythmic_rodent = true;
6069 if (use_rhythmic_rodent) {
6070 show_rhythm_ferret ();
6074 AnalysisFeatureList::const_iterator x;
6076 pl->clear_changes ();
6077 pl->clear_owned_changes ();
6079 x = positions.begin();
6081 if (x == positions.end()) {
6086 pl->remove_region (r);
6090 while (x != positions.end()) {
6092 /* deal with positons that are out of scope of present region bounds */
6093 if (*x <= 0 || *x > r->length()) {
6098 /* file start = original start + how far we from the initial position ?
6101 framepos_t file_start = r->start() + pos;
6103 /* length = next position - current position
6106 framepos_t len = (*x) - pos;
6108 /* XXX we do we really want to allow even single-sample regions?
6109 shouldn't we have some kind of lower limit on region size?
6118 if (RegionFactory::region_name (new_name, r->name())) {
6122 /* do NOT announce new regions 1 by one, just wait till they are all done */
6126 plist.add (ARDOUR::Properties::start, file_start);
6127 plist.add (ARDOUR::Properties::length, len);
6128 plist.add (ARDOUR::Properties::name, new_name);
6129 plist.add (ARDOUR::Properties::layer, 0);
6131 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6132 /* because we set annouce to false, manually add the new region to the
6135 RegionFactory::map_add (nr);
6137 pl->add_region (nr, r->position() + pos);
6140 new_regions.push_front(nr);
6149 RegionFactory::region_name (new_name, r->name());
6151 /* Add the final region */
6154 plist.add (ARDOUR::Properties::start, r->start() + pos);
6155 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6156 plist.add (ARDOUR::Properties::name, new_name);
6157 plist.add (ARDOUR::Properties::layer, 0);
6159 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6160 /* because we set annouce to false, manually add the new region to the
6163 RegionFactory::map_add (nr);
6164 pl->add_region (nr, r->position() + pos);
6167 new_regions.push_front(nr);
6172 /* We might have removed regions, which alters other regions' layering_index,
6173 so we need to do a recursive diff here.
6175 vector<Command*> cmds;
6177 _session->add_commands (cmds);
6179 _session->add_command (new StatefulDiffCommand (pl));
6183 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6184 set_selected_regionview_from_region_list ((*i), Selection::Add);
6190 Editor::place_transient()
6196 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6202 framepos_t where = get_preferred_edit_position();
6204 _session->begin_reversible_command (_("place transient"));
6206 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6207 framepos_t position = (*r)->region()->position();
6208 (*r)->region()->add_transient(where - position);
6211 _session->commit_reversible_command ();
6215 Editor::remove_transient(ArdourCanvas::Item* item)
6221 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6224 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6225 _arv->remove_transient (*(float*) _line->get_data ("position"));
6229 Editor::snap_regions_to_grid ()
6231 list <boost::shared_ptr<Playlist > > used_playlists;
6233 RegionSelection rs = get_regions_from_selection_and_entered ();
6235 if (!_session || rs.empty()) {
6239 _session->begin_reversible_command (_("snap regions to grid"));
6241 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6243 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6245 if (!pl->frozen()) {
6246 /* we haven't seen this playlist before */
6248 /* remember used playlists so we can thaw them later */
6249 used_playlists.push_back(pl);
6253 framepos_t start_frame = (*r)->region()->first_frame ();
6254 snap_to (start_frame);
6255 (*r)->region()->set_position (start_frame);
6258 while (used_playlists.size() > 0) {
6259 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6261 used_playlists.pop_front();
6264 _session->commit_reversible_command ();
6268 Editor::close_region_gaps ()
6270 list <boost::shared_ptr<Playlist > > used_playlists;
6272 RegionSelection rs = get_regions_from_selection_and_entered ();
6274 if (!_session || rs.empty()) {
6278 Dialog dialog (_("Close Region Gaps"));
6281 table.set_spacings (12);
6282 table.set_border_width (12);
6283 Label* l = manage (left_aligned_label (_("Crossfade length")));
6284 table.attach (*l, 0, 1, 0, 1);
6286 SpinButton spin_crossfade (1, 0);
6287 spin_crossfade.set_range (0, 15);
6288 spin_crossfade.set_increments (1, 1);
6289 spin_crossfade.set_value (5);
6290 table.attach (spin_crossfade, 1, 2, 0, 1);
6292 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6294 l = manage (left_aligned_label (_("Pull-back length")));
6295 table.attach (*l, 0, 1, 1, 2);
6297 SpinButton spin_pullback (1, 0);
6298 spin_pullback.set_range (0, 100);
6299 spin_pullback.set_increments (1, 1);
6300 spin_pullback.set_value(30);
6301 table.attach (spin_pullback, 1, 2, 1, 2);
6303 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6305 dialog.get_vbox()->pack_start (table);
6306 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6307 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6310 if (dialog.run () == RESPONSE_CANCEL) {
6314 framepos_t crossfade_len = spin_crossfade.get_value();
6315 framepos_t pull_back_frames = spin_pullback.get_value();
6317 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6318 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6320 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6322 _session->begin_reversible_command (_("close region gaps"));
6325 boost::shared_ptr<Region> last_region;
6327 rs.sort_by_position_and_track();
6329 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6331 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6333 if (!pl->frozen()) {
6334 /* we haven't seen this playlist before */
6336 /* remember used playlists so we can thaw them later */
6337 used_playlists.push_back(pl);
6341 framepos_t position = (*r)->region()->position();
6343 if (idx == 0 || position < last_region->position()){
6344 last_region = (*r)->region();
6349 (*r)->region()->trim_front( (position - pull_back_frames));
6350 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6352 last_region = (*r)->region();
6357 while (used_playlists.size() > 0) {
6358 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6360 used_playlists.pop_front();
6363 _session->commit_reversible_command ();
6367 Editor::tab_to_transient (bool forward)
6369 AnalysisFeatureList positions;
6371 RegionSelection rs = get_regions_from_selection_and_entered ();
6377 framepos_t pos = _session->audible_frame ();
6379 if (!selection->tracks.empty()) {
6381 /* don't waste time searching for transients in duplicate playlists.
6384 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6386 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6388 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6391 boost::shared_ptr<Track> tr = rtv->track();
6393 boost::shared_ptr<Playlist> pl = tr->playlist ();
6395 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6398 positions.push_back (result);
6411 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6412 (*r)->region()->get_transients (positions);
6416 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6419 AnalysisFeatureList::iterator x;
6421 for (x = positions.begin(); x != positions.end(); ++x) {
6427 if (x != positions.end ()) {
6428 _session->request_locate (*x);
6432 AnalysisFeatureList::reverse_iterator x;
6434 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6440 if (x != positions.rend ()) {
6441 _session->request_locate (*x);
6447 Editor::playhead_forward_to_grid ()
6453 framepos_t pos = playhead_cursor->current_frame ();
6454 if (pos < max_framepos - 1) {
6456 snap_to_internal (pos, 1, false);
6457 _session->request_locate (pos);
6463 Editor::playhead_backward_to_grid ()
6469 framepos_t pos = playhead_cursor->current_frame ();
6472 snap_to_internal (pos, -1, false);
6473 _session->request_locate (pos);
6478 Editor::set_track_height (Height h)
6480 TrackSelection& ts (selection->tracks);
6482 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6483 (*x)->set_height_enum (h);
6488 Editor::toggle_tracks_active ()
6490 TrackSelection& ts (selection->tracks);
6492 bool target = false;
6498 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6499 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6503 target = !rtv->_route->active();
6506 rtv->_route->set_active (target, this);
6512 Editor::remove_tracks ()
6514 TrackSelection& ts (selection->tracks);
6520 vector<string> choices;
6524 const char* trackstr;
6526 vector<boost::shared_ptr<Route> > routes;
6527 bool special_bus = false;
6529 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6530 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6534 if (rtv->is_track()) {
6539 routes.push_back (rtv->_route);
6541 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6546 if (special_bus && !Config->get_allow_special_bus_removal()) {
6547 MessageDialog msg (_("That would be bad news ...."),
6551 msg.set_secondary_text (string_compose (_(
6552 "Removing the master or monitor bus is such a bad idea\n\
6553 that %1 is not going to allow it.\n\
6555 If you really want to do this sort of thing\n\
6556 edit your ardour.rc file to set the\n\
6557 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6564 if (ntracks + nbusses == 0) {
6568 // XXX should be using gettext plural forms, maybe?
6570 trackstr = _("tracks");
6572 trackstr = _("track");
6576 busstr = _("busses");
6583 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6584 "(You may also lose the playlists associated with the %2)\n\n"
6585 "This action cannot be undone, and the session file will be overwritten!"),
6586 ntracks, trackstr, nbusses, busstr);
6588 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6589 "(You may also lose the playlists associated with the %2)\n\n"
6590 "This action cannot be undone, and the session file will be overwritten!"),
6593 } else if (nbusses) {
6594 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6595 "This action cannot be undone, and the session file will be overwritten"),
6599 choices.push_back (_("No, do nothing."));
6600 if (ntracks + nbusses > 1) {
6601 choices.push_back (_("Yes, remove them."));
6603 choices.push_back (_("Yes, remove it."));
6608 title = string_compose (_("Remove %1"), trackstr);
6610 title = string_compose (_("Remove %1"), busstr);
6613 Choice prompter (title, prompt, choices);
6615 if (prompter.run () != 1) {
6620 Session::StateProtector sp (_session);
6621 DisplaySuspender ds;
6622 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6623 _session->remove_route (*x);
6629 Editor::do_insert_time ()
6631 if (selection->tracks.empty()) {
6635 InsertTimeDialog d (*this);
6636 int response = d.run ();
6638 if (response != RESPONSE_OK) {
6642 if (d.distance() == 0) {
6646 InsertTimeOption opt = d.intersected_region_action ();
6649 get_preferred_edit_position(),
6655 d.move_glued_markers(),
6656 d.move_locked_markers(),
6662 Editor::insert_time (
6663 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6664 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6667 bool commit = false;
6669 if (Config->get_edit_mode() == Lock) {
6673 begin_reversible_command (_("insert time"));
6675 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6677 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6681 /* don't operate on any playlist more than once, which could
6682 * happen if "all playlists" is enabled, but there is more
6683 * than 1 track using playlists "from" a given track.
6686 set<boost::shared_ptr<Playlist> > pl;
6688 if (all_playlists) {
6689 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6691 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6692 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6697 if ((*x)->playlist ()) {
6698 pl.insert ((*x)->playlist ());
6702 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6704 (*i)->clear_changes ();
6705 (*i)->clear_owned_changes ();
6707 if (opt == SplitIntersected) {
6711 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6713 vector<Command*> cmds;
6715 _session->add_commands (cmds);
6717 _session->add_command (new StatefulDiffCommand (*i));
6722 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6724 rtav->route ()->shift (pos, frames);
6732 XMLNode& before (_session->locations()->get_state());
6733 Locations::LocationList copy (_session->locations()->list());
6735 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6737 Locations::LocationList::const_iterator tmp;
6739 bool const was_locked = (*i)->locked ();
6740 if (locked_markers_too) {
6744 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6746 if ((*i)->start() >= pos) {
6747 (*i)->set_start ((*i)->start() + frames);
6748 if (!(*i)->is_mark()) {
6749 (*i)->set_end ((*i)->end() + frames);
6762 XMLNode& after (_session->locations()->get_state());
6763 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6768 _session->tempo_map().insert_time (pos, frames);
6772 commit_reversible_command ();
6777 Editor::fit_selected_tracks ()
6779 if (!selection->tracks.empty()) {
6780 fit_tracks (selection->tracks);
6784 /* no selected tracks - use tracks with selected regions */
6786 if (!selection->regions.empty()) {
6787 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6788 tvl.push_back (&(*r)->get_time_axis_view ());
6794 } else if (internal_editing()) {
6795 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6798 if (entered_track) {
6799 tvl.push_back (entered_track);
6808 Editor::fit_tracks (TrackViewList & tracks)
6810 if (tracks.empty()) {
6814 uint32_t child_heights = 0;
6815 int visible_tracks = 0;
6817 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6819 if (!(*t)->marked_for_display()) {
6823 child_heights += (*t)->effective_height() - (*t)->current_height();
6827 /* compute the per-track height from:
6829 total canvas visible height -
6830 height that will be taken by visible children of selected
6831 tracks - height of the ruler/hscroll area
6833 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6834 double first_y_pos = DBL_MAX;
6836 if (h < TimeAxisView::preset_height (HeightSmall)) {
6837 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6838 /* too small to be displayed */
6842 undo_visual_stack.push_back (current_visual_state (true));
6843 no_save_visual = true;
6845 /* build a list of all tracks, including children */
6848 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6850 TimeAxisView::Children c = (*i)->get_child_list ();
6851 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6852 all.push_back (j->get());
6856 bool prev_was_selected = false;
6857 bool is_selected = tracks.contains (all.front());
6858 bool next_is_selected;
6860 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6862 TrackViewList::iterator next;
6867 if (next != all.end()) {
6868 next_is_selected = tracks.contains (*next);
6870 next_is_selected = false;
6873 if ((*t)->marked_for_display ()) {
6875 (*t)->set_height (h);
6876 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6878 if (prev_was_selected && next_is_selected) {
6879 hide_track_in_display (*t);
6884 prev_was_selected = is_selected;
6885 is_selected = next_is_selected;
6889 set the controls_layout height now, because waiting for its size
6890 request signal handler will cause the vertical adjustment setting to fail
6893 controls_layout.property_height () = _full_canvas_height;
6894 vertical_adjustment.set_value (first_y_pos);
6896 redo_visual_stack.push_back (current_visual_state (true));
6898 visible_tracks_selector.set_text (_("Sel"));
6902 Editor::save_visual_state (uint32_t n)
6904 while (visual_states.size() <= n) {
6905 visual_states.push_back (0);
6908 if (visual_states[n] != 0) {
6909 delete visual_states[n];
6912 visual_states[n] = current_visual_state (true);
6917 Editor::goto_visual_state (uint32_t n)
6919 if (visual_states.size() <= n) {
6923 if (visual_states[n] == 0) {
6927 use_visual_state (*visual_states[n]);
6931 Editor::start_visual_state_op (uint32_t n)
6933 save_visual_state (n);
6935 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6937 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6938 pup->set_text (buf);
6943 Editor::cancel_visual_state_op (uint32_t n)
6945 goto_visual_state (n);
6949 Editor::toggle_region_mute ()
6951 if (_ignore_region_action) {
6955 RegionSelection rs = get_regions_from_selection_and_entered ();
6961 if (rs.size() > 1) {
6962 begin_reversible_command (_("mute regions"));
6964 begin_reversible_command (_("mute region"));
6967 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6969 (*i)->region()->playlist()->clear_changes ();
6970 (*i)->region()->set_muted (!(*i)->region()->muted ());
6971 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6975 commit_reversible_command ();
6979 Editor::combine_regions ()
6981 /* foreach track with selected regions, take all selected regions
6982 and join them into a new region containing the subregions (as a
6986 typedef set<RouteTimeAxisView*> RTVS;
6989 if (selection->regions.empty()) {
6993 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6994 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6997 tracks.insert (rtv);
7001 begin_reversible_command (_("combine regions"));
7003 vector<RegionView*> new_selection;
7005 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7008 if ((rv = (*i)->combine_regions ()) != 0) {
7009 new_selection.push_back (rv);
7013 selection->clear_regions ();
7014 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7015 selection->add (*i);
7018 commit_reversible_command ();
7022 Editor::uncombine_regions ()
7024 typedef set<RouteTimeAxisView*> RTVS;
7027 if (selection->regions.empty()) {
7031 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7032 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7035 tracks.insert (rtv);
7039 begin_reversible_command (_("uncombine regions"));
7041 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7042 (*i)->uncombine_regions ();
7045 commit_reversible_command ();
7049 Editor::toggle_midi_input_active (bool flip_others)
7052 boost::shared_ptr<RouteList> rl (new RouteList);
7054 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7055 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7061 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7064 rl->push_back (rtav->route());
7065 onoff = !mt->input_active();
7069 _session->set_exclusive_input_active (rl, onoff, flip_others);
7076 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7078 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7079 lock_dialog->get_vbox()->pack_start (*padlock);
7081 ArdourButton* b = manage (new ArdourButton);
7082 b->set_name ("lock button");
7083 b->set_text (_("Click to unlock"));
7084 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7085 lock_dialog->get_vbox()->pack_start (*b);
7087 lock_dialog->get_vbox()->show_all ();
7088 lock_dialog->set_size_request (200, 200);
7092 /* The global menu bar continues to be accessible to applications
7093 with modal dialogs, which means that we need to desensitize
7094 all items in the menu bar. Since those items are really just
7095 proxies for actions, that means disabling all actions.
7097 ActionManager::disable_all_actions ();
7099 lock_dialog->present ();
7105 lock_dialog->hide ();
7108 ActionManager::pop_action_state ();
7111 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7112 start_lock_event_timing ();
7117 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7119 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7123 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7125 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7126 Gtkmm2ext::UI::instance()->flush_pending ();
7130 Editor::bring_all_sources_into_session ()
7137 ArdourDialog w (_("Moving embedded files into session folder"));
7138 w.get_vbox()->pack_start (msg);
7141 /* flush all pending GUI events because we're about to start copying
7145 Gtkmm2ext::UI::instance()->flush_pending ();
7149 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));