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 */
29 #include <pbd/error.h>
30 #include <pbd/basename.h>
31 #include <pbd/pthread_utils.h>
32 #include <pbd/memento_command.h>
34 #include <gtkmm2ext/utils.h>
35 #include <gtkmm2ext/choice.h>
36 #include <gtkmm2ext/window_title.h>
38 #include <ardour/audioengine.h>
39 #include <ardour/session.h>
40 #include <ardour/audioplaylist.h>
41 #include <ardour/audioregion.h>
42 #include <ardour/audio_diskstream.h>
43 #include <ardour/utils.h>
44 #include <ardour/location.h>
45 #include <ardour/named_selection.h>
46 #include <ardour/audio_track.h>
47 #include <ardour/audioplaylist.h>
48 #include <ardour/region_factory.h>
49 #include <ardour/playlist_factory.h>
50 #include <ardour/reverse.h>
52 #include "ardour_ui.h"
54 #include "time_axis_view.h"
55 #include "audio_time_axis.h"
56 #include "automation_time_axis.h"
57 #include "streamview.h"
58 #include "audio_region_view.h"
59 #include "rgb_macros.h"
60 #include "selection_templates.h"
61 #include "selection.h"
63 #include "gtk-custom-hruler.h"
64 #include "gui_thread.h"
69 using namespace ARDOUR;
73 using namespace Gtkmm2ext;
74 using namespace Editing;
76 /***********************************************************************
78 ***********************************************************************/
81 Editor::undo (uint32_t n)
89 Editor::redo (uint32_t n)
97 Editor::ensure_cursor (nframes_t *pos)
99 *pos = edit_cursor->current_frame;
104 Editor::split_region ()
106 split_region_at (edit_cursor->current_frame);
110 Editor::split_region_at (nframes_t where)
112 split_regions_at (where, selection->regions);
116 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
118 begin_reversible_command (_("split"));
121 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
123 RegionSelection::iterator tmp;
128 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
130 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
132 _new_regionviews_show_envelope = arv->envelope_visible();
135 XMLNode &before = pl->get_state();
136 pl->split_region ((*a)->region(), where);
137 XMLNode &after = pl->get_state();
138 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
144 commit_reversible_command ();
145 _new_regionviews_show_envelope = false;
149 /** Remove `clicked_regionview' */
151 Editor::remove_clicked_region ()
153 if (clicked_routeview == 0 || clicked_regionview == 0) {
157 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
159 begin_reversible_command (_("remove region"));
160 XMLNode &before = playlist->get_state();
161 playlist->remove_region (clicked_regionview->region());
162 XMLNode &after = playlist->get_state();
163 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
164 commit_reversible_command ();
168 /** Remove the selected regions */
170 Editor::remove_selected_regions ()
172 if (selection->regions.empty()) {
176 /* XXX: should be called remove regions if we're removing more than one */
177 begin_reversible_command (_("remove region"));
179 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
180 boost::shared_ptr<Region> region = (*i)->region ();
181 boost::shared_ptr<Playlist> playlist = region->playlist ();
183 XMLNode &before = playlist->get_state();
184 playlist->remove_region (region);
185 XMLNode &after = playlist->get_state();
186 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
189 commit_reversible_command ();
192 boost::shared_ptr<Region>
193 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
196 boost::shared_ptr<Region> region;
199 if (selection->time.start () == selection->time.end_frame ()) {
201 /* no current selection-> is there a selected regionview? */
203 if (selection->regions.empty()) {
209 if (!selection->regions.empty()) {
211 rv = *(selection->regions.begin());
212 (*tv) = &rv->get_time_axis_view();
213 region = rv->region();
215 } else if (!selection->tracks.empty()) {
217 (*tv) = selection->tracks.front();
219 RouteTimeAxisView* rtv;
221 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
222 boost::shared_ptr<Playlist> pl;
224 if ((pl = rtv->playlist()) == 0) {
228 region = pl->top_region_at (start);
236 Editor::extend_selection_to_end_of_region (bool next)
239 boost::shared_ptr<Region> region;
242 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
246 if (region && selection->time.start () == selection->time.end_frame ()) {
247 start = region->position();
249 start = selection->time.start ();
252 /* Try to leave the selection with the same route if possible */
254 if ((tv = selection->time.track) == 0) {
258 begin_reversible_command (_("extend selection"));
259 selection->set (tv, start, region->position() + region->length());
260 commit_reversible_command ();
264 Editor::extend_selection_to_start_of_region (bool previous)
267 boost::shared_ptr<Region> region;
270 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
274 if (region && selection->time.start () == selection->time.end_frame ()) {
275 end = region->position() + region->length();
277 end = selection->time.end_frame ();
280 /* Try to leave the selection with the same route if possible */
282 if ((tv = selection->time.track) == 0) {
286 begin_reversible_command (_("extend selection"));
287 selection->set (tv, region->position(), end);
288 commit_reversible_command ();
293 Editor::nudge_forward (bool next)
296 nframes_t next_distance;
298 if (!session) return;
300 if (!selection->regions.empty()) {
302 begin_reversible_command (_("nudge forward"));
304 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
305 boost::shared_ptr<Region> r ((*i)->region());
307 distance = get_nudge_distance (r->position(), next_distance);
310 distance = next_distance;
313 XMLNode &before = r->playlist()->get_state();
314 r->set_position (r->position() + distance, this);
315 XMLNode &after = r->playlist()->get_state();
316 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
319 commit_reversible_command ();
322 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
323 session->request_locate (playhead_cursor->current_frame + distance);
328 Editor::nudge_backward (bool next)
331 nframes_t next_distance;
333 if (!session) return;
335 if (!selection->regions.empty()) {
337 begin_reversible_command (_("nudge forward"));
339 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
340 boost::shared_ptr<Region> r ((*i)->region());
342 distance = get_nudge_distance (r->position(), next_distance);
345 distance = next_distance;
348 XMLNode &before = r->playlist()->get_state();
350 if (r->position() > distance) {
351 r->set_position (r->position() - distance, this);
353 r->set_position (0, this);
355 XMLNode &after = r->playlist()->get_state();
356 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
359 commit_reversible_command ();
363 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
365 if (playhead_cursor->current_frame > distance) {
366 session->request_locate (playhead_cursor->current_frame - distance);
368 session->goto_start();
374 Editor::nudge_forward_capture_offset ()
378 if (!session) return;
380 if (!selection->regions.empty()) {
382 begin_reversible_command (_("nudge forward"));
384 distance = session->worst_output_latency();
386 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
387 boost::shared_ptr<Region> r ((*i)->region());
389 XMLNode &before = r->playlist()->get_state();
390 r->set_position (r->position() + distance, this);
391 XMLNode &after = r->playlist()->get_state();
392 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
395 commit_reversible_command ();
401 Editor::nudge_backward_capture_offset ()
405 if (!session) return;
407 if (!selection->regions.empty()) {
409 begin_reversible_command (_("nudge forward"));
411 distance = session->worst_output_latency();
413 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
414 boost::shared_ptr<Region> r ((*i)->region());
416 XMLNode &before = r->playlist()->get_state();
418 if (r->position() > distance) {
419 r->set_position (r->position() - distance, this);
421 r->set_position (0, this);
423 XMLNode &after = r->playlist()->get_state();
424 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
427 commit_reversible_command ();
434 Editor::move_to_start ()
436 session->goto_start ();
440 Editor::move_to_end ()
443 session->request_locate (session->current_end_frame());
447 Editor::build_region_boundary_cache ()
450 vector<RegionPoint> interesting_points;
451 boost::shared_ptr<Region> r;
452 TrackViewList tracks;
455 region_boundary_cache.clear ();
462 case SnapToRegionStart:
463 interesting_points.push_back (Start);
465 case SnapToRegionEnd:
466 interesting_points.push_back (End);
468 case SnapToRegionSync:
469 interesting_points.push_back (SyncPoint);
471 case SnapToRegionBoundary:
472 interesting_points.push_back (Start);
473 interesting_points.push_back (End);
476 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
481 TimeAxisView *ontrack = 0;
484 if (!selection->tracks.empty()) {
485 tlist = selection->tracks;
490 while (pos < session->current_end_frame() && !at_end) {
493 nframes_t lpos = max_frames;
495 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
497 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
499 /* move to next point type */
506 rpos = r->first_frame();
509 rpos = r->last_frame();
512 rpos = r->adjust_to_sync (r->first_frame());
519 RouteTimeAxisView *rtav;
521 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
522 if (rtav->get_diskstream() != 0) {
523 speed = rtav->get_diskstream()->speed();
527 rpos = track_frame_to_session_frame (rpos, speed);
533 /* prevent duplicates, but we don't use set<> because we want to be able
537 vector<nframes_t>::iterator ri;
539 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
545 if (ri == region_boundary_cache.end()) {
546 region_boundary_cache.push_back (rpos);
553 /* finally sort to be sure that the order is correct */
555 sort (region_boundary_cache.begin(), region_boundary_cache.end());
558 boost::shared_ptr<Region>
559 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
561 TrackViewList::iterator i;
562 nframes_t closest = max_frames;
563 boost::shared_ptr<Region> ret;
567 nframes_t track_frame;
568 RouteTimeAxisView *rtav;
570 for (i = tracks.begin(); i != tracks.end(); ++i) {
573 boost::shared_ptr<Region> r;
576 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
577 if (rtav->get_diskstream()!=0)
578 track_speed = rtav->get_diskstream()->speed();
581 track_frame = session_frame_to_track_frame(frame, track_speed);
583 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
589 rpos = r->first_frame ();
593 rpos = r->last_frame ();
597 rpos = r->adjust_to_sync (r->first_frame());
600 // rpos is a "track frame", converting it to "session frame"
601 rpos = track_frame_to_session_frame(rpos, track_speed);
604 distance = rpos - frame;
606 distance = frame - rpos;
609 if (distance < closest) {
621 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
623 boost::shared_ptr<Region> r;
624 nframes_t pos = cursor->current_frame;
630 TimeAxisView *ontrack = 0;
632 // so we don't find the current region again..
636 if (!selection->tracks.empty()) {
638 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
640 } else if (clicked_axisview) {
643 t.push_back (clicked_axisview);
645 r = find_next_region (pos, point, dir, t, &ontrack);
649 r = find_next_region (pos, point, dir, track_views, &ontrack);
658 pos = r->first_frame ();
662 pos = r->last_frame ();
666 pos = r->adjust_to_sync (r->first_frame());
671 RouteTimeAxisView *rtav;
673 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
674 if (rtav->get_diskstream() != 0) {
675 speed = rtav->get_diskstream()->speed();
679 pos = track_frame_to_session_frame(pos, speed);
681 if (cursor == playhead_cursor) {
682 session->request_locate (pos);
684 cursor->set_position (pos);
689 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
691 cursor_to_region_point (cursor, point, 1);
695 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
697 cursor_to_region_point (cursor, point, -1);
701 Editor::cursor_to_selection_start (Cursor *cursor)
704 switch (mouse_mode) {
706 if (!selection->regions.empty()) {
707 pos = selection->regions.start();
712 if (!selection->time.empty()) {
713 pos = selection->time.start ();
721 if (cursor == playhead_cursor) {
722 session->request_locate (pos);
724 cursor->set_position (pos);
729 Editor::cursor_to_selection_end (Cursor *cursor)
733 switch (mouse_mode) {
735 if (!selection->regions.empty()) {
736 pos = selection->regions.end_frame();
741 if (!selection->time.empty()) {
742 pos = selection->time.end_frame ();
750 if (cursor == playhead_cursor) {
751 session->request_locate (pos);
753 cursor->set_position (pos);
758 Editor::scroll_playhead (bool forward)
760 nframes_t pos = playhead_cursor->current_frame;
761 nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
764 if (pos == max_frames) {
768 if (pos < max_frames - delta) {
787 session->request_locate (pos);
791 Editor::playhead_backward ()
798 if (get_prefix (prefix, was_floating)) {
802 cnt = (nframes_t) floor (prefix * session->frame_rate ());
804 cnt = (nframes_t) prefix;
808 pos = playhead_cursor->current_frame;
810 if ((nframes_t) pos < cnt) {
816 /* XXX this is completely insane. with the current buffering
817 design, we'll force a complete track buffer flush and
818 reload, just to move 1 sample !!!
821 session->request_locate (pos);
825 Editor::playhead_forward ()
832 if (get_prefix (prefix, was_floating)) {
836 cnt = (nframes_t) floor (prefix * session->frame_rate ());
838 cnt = (nframes_t) floor (prefix);
842 pos = playhead_cursor->current_frame;
844 /* XXX this is completely insane. with the current buffering
845 design, we'll force a complete track buffer flush and
846 reload, just to move 1 sample !!!
849 session->request_locate (pos+cnt);
853 Editor::cursor_align (bool playhead_to_edit)
855 if (playhead_to_edit) {
857 session->request_locate (edit_cursor->current_frame);
860 edit_cursor->set_position (playhead_cursor->current_frame);
865 Editor::edit_cursor_backward ()
872 if (get_prefix (prefix, was_floating)) {
876 cnt = (nframes_t) floor (prefix * session->frame_rate ());
878 cnt = (nframes_t) prefix;
882 pos = edit_cursor->current_frame;
884 if ((nframes_t) pos < cnt) {
890 edit_cursor->set_position (pos);
894 Editor::edit_cursor_forward ()
901 if (get_prefix (prefix, was_floating)) {
905 cnt = (nframes_t) floor (prefix * session->frame_rate ());
907 cnt = (nframes_t) floor (prefix);
911 pos = edit_cursor->current_frame;
912 edit_cursor->set_position (pos+cnt);
916 Editor::goto_frame ()
922 if (get_prefix (prefix, was_floating)) {
927 frame = (nframes_t) floor (prefix * session->frame_rate());
929 frame = (nframes_t) floor (prefix);
932 session->request_locate (frame);
936 Editor::scroll_backward (float pages)
939 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
944 if (get_prefix (prefix, was_floating)) {
945 cnt = (nframes_t) floor (pages * one_page);
948 cnt = (nframes_t) floor (prefix * session->frame_rate());
950 cnt = (nframes_t) floor (prefix * one_page);
954 if (leftmost_frame < cnt) {
957 frame = leftmost_frame - cnt;
960 reset_x_origin (frame);
964 Editor::scroll_forward (float pages)
967 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
972 if (get_prefix (prefix, was_floating)) {
973 cnt = (nframes_t) floor (pages * one_page);
976 cnt = (nframes_t) floor (prefix * session->frame_rate());
978 cnt = (nframes_t) floor (prefix * one_page);
982 if (max_frames - cnt < leftmost_frame) {
983 frame = max_frames - cnt;
985 frame = leftmost_frame + cnt;
988 reset_x_origin (frame);
992 Editor::scroll_tracks_down ()
998 if (get_prefix (prefix, was_floating)) {
1001 cnt = (int) floor (prefix);
1004 double vert_value = vertical_adjustment.get_value() + (cnt *
1005 vertical_adjustment.get_page_size());
1006 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1007 vert_value = vertical_adjustment.get_upper() - canvas_height;
1009 vertical_adjustment.set_value (vert_value);
1013 Editor::scroll_tracks_up ()
1019 if (get_prefix (prefix, was_floating)) {
1022 cnt = (int) floor (prefix);
1025 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1029 Editor::scroll_tracks_down_line ()
1032 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1033 double vert_value = adj->get_value() + 20;
1035 if (vert_value>adj->get_upper() - canvas_height) {
1036 vert_value = adj->get_upper() - canvas_height;
1038 adj->set_value (vert_value);
1042 Editor::scroll_tracks_up_line ()
1044 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1045 adj->set_value (adj->get_value() - 20);
1051 Editor::temporal_zoom_step (bool coarser)
1053 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1057 nfpu = frames_per_unit;
1062 nfpu = max(1.0,(nfpu/1.61803399));
1065 temporal_zoom (nfpu);
1069 Editor::temporal_zoom (gdouble fpu)
1071 if (!session) return;
1073 nframes_t current_page = current_page_frames();
1074 nframes_t current_leftmost = leftmost_frame;
1075 nframes_t current_rightmost;
1076 nframes_t current_center;
1078 nframes_t leftmost_after_zoom = 0;
1083 new_page = (nframes_t) floor (canvas_width * nfpu);
1085 switch (zoom_focus) {
1087 leftmost_after_zoom = current_leftmost;
1090 case ZoomFocusRight:
1091 current_rightmost = leftmost_frame + current_page;
1092 if (current_rightmost > new_page) {
1093 leftmost_after_zoom = current_rightmost - new_page;
1095 leftmost_after_zoom = 0;
1099 case ZoomFocusCenter:
1100 current_center = current_leftmost + (current_page/2);
1101 if (current_center > (new_page/2)) {
1102 leftmost_after_zoom = current_center - (new_page / 2);
1104 leftmost_after_zoom = 0;
1108 case ZoomFocusPlayhead:
1109 /* try to keep the playhead in the center */
1110 if (playhead_cursor->current_frame > new_page/2) {
1111 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1113 leftmost_after_zoom = 0;
1118 /* try to keep the edit cursor in the center */
1119 if (edit_cursor->current_frame > new_page/2) {
1120 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1122 leftmost_after_zoom = 0;
1128 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1130 // begin_reversible_command (_("zoom"));
1131 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1132 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1133 // commit_reversible_command ();
1135 reposition_and_zoom (leftmost_after_zoom, nfpu);
1139 Editor::temporal_zoom_selection ()
1141 if (!selection) return;
1143 if (selection->time.empty()) {
1147 nframes_t start = selection->time[clicked_selection].start;
1148 nframes_t end = selection->time[clicked_selection].end;
1150 temporal_zoom_by_frame (start, end, "zoom to selection");
1154 Editor::temporal_zoom_session ()
1156 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1159 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1164 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1166 if (!session) return;
1168 if ((start == 0 && end == 0) || end < start) {
1172 nframes_t range = end - start;
1174 double new_fpu = (double)range / (double)canvas_width;
1177 // while (p2 < new_fpu) {
1182 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1183 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1184 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1186 if (new_leftmost > middle) new_leftmost = 0;
1188 // begin_reversible_command (op);
1189 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1190 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1191 // commit_reversible_command ();
1193 reposition_and_zoom (new_leftmost, new_fpu);
1197 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1199 if (!session) return;
1201 double range_before = frame - leftmost_frame;
1204 new_fpu = frames_per_unit;
1207 new_fpu *= 1.61803399;
1208 range_before *= 1.61803399;
1210 new_fpu = max(1.0,(new_fpu/1.61803399));
1211 range_before /= 1.61803399;
1214 if (new_fpu == frames_per_unit) return;
1216 nframes_t new_leftmost = frame - (nframes_t)range_before;
1218 if (new_leftmost > frame) new_leftmost = 0;
1220 // begin_reversible_command (_("zoom to frame"));
1221 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1222 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1223 // commit_reversible_command ();
1225 reposition_and_zoom (new_leftmost, new_fpu);
1229 Editor::add_location_from_selection ()
1233 if (selection->time.empty()) {
1237 if (session == 0 || clicked_axisview == 0) {
1241 nframes_t start = selection->time[clicked_selection].start;
1242 nframes_t end = selection->time[clicked_selection].end;
1244 session->locations()->next_available_name(rangename,"selection");
1245 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1247 session->begin_reversible_command (_("add marker"));
1248 XMLNode &before = session->locations()->get_state();
1249 session->locations()->add (location, true);
1250 XMLNode &after = session->locations()->get_state();
1251 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1252 session->commit_reversible_command ();
1256 Editor::add_location_from_playhead_cursor ()
1260 nframes_t where = session->audible_frame();
1262 session->locations()->next_available_name(markername,"mark");
1263 Location *location = new Location (where, where, markername, Location::IsMark);
1264 session->begin_reversible_command (_("add marker"));
1265 XMLNode &before = session->locations()->get_state();
1266 session->locations()->add (location, true);
1267 XMLNode &after = session->locations()->get_state();
1268 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1269 session->commit_reversible_command ();
1273 Editor::add_location_from_audio_region ()
1275 if (selection->regions.empty()) {
1279 RegionView* rv = *(selection->regions.begin());
1280 boost::shared_ptr<Region> region = rv->region();
1282 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1283 session->begin_reversible_command (_("add marker"));
1284 XMLNode &before = session->locations()->get_state();
1285 session->locations()->add (location, true);
1286 XMLNode &after = session->locations()->get_state();
1287 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1288 session->commit_reversible_command ();
1292 Editor::amplitude_zoom_step (bool in)
1306 #ifdef FIX_FOR_CANVAS
1307 /* XXX DO SOMETHING */
1316 Editor::delete_sample_forward ()
1321 Editor::delete_sample_backward ()
1326 Editor::delete_screen ()
1333 Editor::search_backwards ()
1339 Editor::search_forwards ()
1347 Editor::jump_forward_to_mark ()
1353 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1356 session->request_locate (location->start(), session->transport_rolling());
1358 session->request_locate (session->current_end_frame());
1363 Editor::jump_backward_to_mark ()
1369 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1372 session->request_locate (location->start(), session->transport_rolling());
1374 session->goto_start ();
1386 if (get_prefix (prefix, was_floating)) {
1387 pos = session->audible_frame ();
1390 pos = (nframes_t) floor (prefix * session->frame_rate ());
1392 pos = (nframes_t) floor (prefix);
1396 session->locations()->next_available_name(markername,"mark");
1397 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1401 Editor::clear_markers ()
1404 session->begin_reversible_command (_("clear markers"));
1405 XMLNode &before = session->locations()->get_state();
1406 session->locations()->clear_markers ();
1407 XMLNode &after = session->locations()->get_state();
1408 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1409 session->commit_reversible_command ();
1414 Editor::clear_ranges ()
1417 session->begin_reversible_command (_("clear ranges"));
1418 XMLNode &before = session->locations()->get_state();
1420 Location * looploc = session->locations()->auto_loop_location();
1421 Location * punchloc = session->locations()->auto_punch_location();
1423 session->locations()->clear_ranges ();
1425 if (looploc) session->locations()->add (looploc);
1426 if (punchloc) session->locations()->add (punchloc);
1428 XMLNode &after = session->locations()->get_state();
1429 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1430 session->commit_reversible_command ();
1435 Editor::clear_locations ()
1437 session->begin_reversible_command (_("clear locations"));
1438 XMLNode &before = session->locations()->get_state();
1439 session->locations()->clear ();
1440 XMLNode &after = session->locations()->get_state();
1441 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1442 session->commit_reversible_command ();
1443 session->locations()->clear ();
1447 Editor::unhide_markers ()
1449 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1450 Location *l = (*i).first;
1451 if (l->is_hidden() && l->is_mark()) {
1452 l->set_hidden(false, this);
1458 Editor::unhide_ranges ()
1460 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1461 Location *l = (*i).first;
1462 if (l->is_hidden() && l->is_range_marker()) {
1463 l->set_hidden(false, this);
1468 /* INSERT/REPLACE */
1471 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1477 RouteTimeAxisView *rtv = 0;
1478 boost::shared_ptr<Playlist> playlist;
1480 track_canvas.window_to_world (x, y, wx, wy);
1481 wx += horizontal_adjustment.get_value();
1482 wy += vertical_adjustment.get_value();
1485 event.type = GDK_BUTTON_RELEASE;
1486 event.button.x = wx;
1487 event.button.y = wy;
1489 where = event_frame (&event, &cx, &cy);
1491 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1492 /* clearly outside canvas area */
1496 if ((tv = trackview_by_y_position (cy)) == 0) {
1500 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) == 0) {
1504 if ((playlist = rtv->playlist()) == 0) {
1510 begin_reversible_command (_("insert dragged region"));
1511 XMLNode &before = playlist->get_state();
1512 playlist->add_region (RegionFactory::create (region), where, 1.0);
1513 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1514 commit_reversible_command ();
1518 Editor::insert_region_list_selection (float times)
1520 RouteTimeAxisView *tv = 0;
1521 boost::shared_ptr<Playlist> playlist;
1523 if (selection->tracks.empty()) {
1527 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1531 if ((playlist = tv->playlist()) == 0) {
1535 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1537 if (selected->count_selected_rows() != 1) {
1541 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1543 /* only one row selected, so rows.begin() is it */
1547 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1549 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1551 begin_reversible_command (_("insert region"));
1552 XMLNode &before = playlist->get_state();
1553 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1554 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1555 commit_reversible_command ();
1559 /* BUILT-IN EFFECTS */
1562 Editor::reverse_selection ()
1567 /* GAIN ENVELOPE EDITING */
1570 Editor::edit_envelope ()
1577 Editor::transition_to_rolling (bool fwd)
1583 switch (Config->get_slave_source()) {
1588 /* transport controlled by the master */
1592 if (session->is_auditioning()) {
1593 session->cancel_audition ();
1597 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1601 Editor::toggle_playback (bool with_abort)
1607 switch (Config->get_slave_source()) {
1612 /* transport controlled by the master */
1616 if (session->is_auditioning()) {
1617 session->cancel_audition ();
1621 if (session->transport_rolling()) {
1622 session->request_stop (with_abort);
1623 if (session->get_play_loop()) {
1624 session->request_play_loop (false);
1627 session->request_transport_speed (1.0f);
1632 Editor::play_from_start ()
1634 session->request_locate (session->current_start_frame(), true);
1638 Editor::play_from_edit_cursor ()
1640 session->request_locate (edit_cursor->current_frame, true);
1644 Editor::play_selection ()
1646 if (selection->time.empty()) {
1650 session->request_play_range (true);
1654 Editor::play_selected_region ()
1656 if (!selection->regions.empty()) {
1657 RegionView *rv = *(selection->regions.begin());
1659 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1664 Editor::loop_selected_region ()
1666 if (!selection->regions.empty()) {
1667 RegionView *rv = *(selection->regions.begin());
1670 if ((tll = transport_loop_location()) != 0) {
1672 tll->set (rv->region()->position(), rv->region()->last_frame());
1674 // enable looping, reposition and start rolling
1676 session->request_play_loop (true);
1677 session->request_locate (tll->start(), false);
1678 session->request_transport_speed (1.0f);
1684 Editor::play_location (Location& location)
1686 if (location.start() <= location.end()) {
1690 session->request_bounded_roll (location.start(), location.end());
1694 Editor::loop_location (Location& location)
1696 if (location.start() <= location.end()) {
1702 if ((tll = transport_loop_location()) != 0) {
1703 tll->set (location.start(), location.end());
1705 // enable looping, reposition and start rolling
1706 session->request_play_loop (true);
1707 session->request_locate (tll->start(), true);
1712 Editor::raise_region_to_top ()
1714 selection->foreach_region (&Region::raise_to_top);
1718 Editor::lower_region_to_bottom ()
1720 selection->foreach_region (&Region::lower_to_bottom);
1723 /** Show the region editor for the selected regions */
1725 Editor::edit_region ()
1727 selection->foreach_regionview (&RegionView::show_region_editor);
1731 Editor::rename_region ()
1735 Button ok_button (_("OK"));
1736 Button cancel_button (_("Cancel"));
1738 if (selection->regions.empty()) {
1742 WindowTitle title(Glib::get_application_name());
1743 title += _("Rename Region");
1745 dialog.set_title (title.get_string());
1746 dialog.set_name ("RegionRenameWindow");
1747 dialog.set_size_request (300, -1);
1748 dialog.set_position (Gtk::WIN_POS_MOUSE);
1749 dialog.set_modal (true);
1751 dialog.get_vbox()->set_border_width (10);
1752 dialog.get_vbox()->pack_start (entry);
1753 dialog.get_action_area()->pack_start (ok_button);
1754 dialog.get_action_area()->pack_start (cancel_button);
1756 entry.set_name ("RegionNameDisplay");
1757 ok_button.set_name ("EditorGTKButton");
1758 cancel_button.set_name ("EditorGTKButton");
1760 region_renamed = false;
1762 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1763 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1764 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1771 if (region_renamed) {
1772 (*selection->regions.begin())->region()->set_name (entry.get_text());
1773 redisplay_regions ();
1778 Editor::rename_region_finished (bool status)
1781 region_renamed = status;
1786 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
1788 if (session->is_auditioning()) {
1789 session->cancel_audition ();
1792 // note: some potential for creativity here, because region doesn't
1793 // have to belong to the playlist that Route is handling
1795 // bool was_soloed = route.soloed();
1797 route.set_solo (true, this);
1799 session->request_bounded_roll (region->position(), region->position() + region->length());
1801 /* XXX how to unset the solo state ? */
1804 /** Start an audition of the first selected region */
1806 Editor::audition_selected_region ()
1808 if (!selection->regions.empty()) {
1809 RegionView* rv = *(selection->regions.begin());
1810 session->audition_region (rv->region());
1815 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
1817 session->audition_region (region);
1821 Editor::build_interthread_progress_window ()
1823 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
1825 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1827 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
1828 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
1830 // GTK2FIX: this button needs a modifiable label
1832 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1833 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1835 interthread_cancel_button.add (interthread_cancel_label);
1837 interthread_progress_window->set_default_size (200, 100);
1841 Editor::interthread_cancel_clicked ()
1843 if (current_interthread_info) {
1844 current_interthread_info->cancel = true;
1849 Editor::region_from_selection ()
1851 if (clicked_axisview == 0) {
1855 if (selection->time.empty()) {
1859 nframes_t start = selection->time[clicked_selection].start;
1860 nframes_t end = selection->time[clicked_selection].end;
1862 nframes_t selection_cnt = end - start + 1;
1864 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1865 boost::shared_ptr<AudioRegion> current;
1866 boost::shared_ptr<Region> current_r;
1867 boost::shared_ptr<Playlist> pl;
1869 nframes_t internal_start;
1872 if ((pl = (*i)->playlist()) == 0) {
1876 if ((current_r = pl->top_region_at (start)) == 0) {
1880 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
1881 assert(current); // FIXME
1883 internal_start = start - current->position();
1884 session->region_name (new_name, current->name(), true);
1885 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
1891 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
1893 if (selection->time.empty() || selection->tracks.empty()) {
1897 nframes_t start = selection->time[clicked_selection].start;
1898 nframes_t end = selection->time[clicked_selection].end;
1900 sort_track_selection ();
1902 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1904 boost::shared_ptr<AudioRegion> current;
1905 boost::shared_ptr<Region> current_r;
1906 boost::shared_ptr<Playlist> playlist;
1907 nframes_t internal_start;
1910 if ((playlist = (*i)->playlist()) == 0) {
1914 if ((current_r = playlist->top_region_at(start)) == 0) {
1918 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
1922 internal_start = start - current->position();
1923 session->region_name (new_name, current->name(), true);
1925 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
1930 Editor::split_multichannel_region ()
1932 if (selection->regions.empty()) {
1936 vector<boost::shared_ptr<AudioRegion> > v;
1938 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
1940 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
1942 if (!arv || arv->audio_region()->n_channels() < 2) {
1946 (arv)->audio_region()->separate_by_channel (*session, v);
1951 Editor::new_region_from_selection ()
1953 region_from_selection ();
1954 cancel_selection ();
1958 Editor::separate_region_from_selection ()
1962 bool doing_undo = false;
1964 if (selection->time.empty()) {
1968 boost::shared_ptr<Playlist> playlist;
1970 sort_track_selection ();
1972 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1974 RouteTimeAxisView* rtv;
1976 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
1978 boost::shared_ptr<Track> t = rtv->track();
1980 if (t != 0 && ! t->diskstream()->destructive()) {
1982 if ((playlist = rtv->playlist()) != 0) {
1984 begin_reversible_command (_("separate"));
1990 before = &(playlist->get_state());
1992 /* XXX need to consider musical time selections here at some point */
1994 double speed = t->diskstream()->speed();
1996 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
1997 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2001 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2007 if (doing_undo) commit_reversible_command ();
2011 Editor::separate_regions_using_location (Location& loc)
2015 bool doing_undo = false;
2017 if (loc.is_mark()) {
2021 boost::shared_ptr<Playlist> playlist;
2023 /* XXX i'm unsure as to whether this should operate on selected tracks only
2024 or the entire enchillada. uncomment the below line to correct the behaviour
2025 (currently set for all tracks)
2028 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2029 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2031 RouteTimeAxisView* rtv;
2033 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2035 boost::shared_ptr<Track> t = rtv->track();
2037 if (t != 0 && ! t->diskstream()->destructive()) {
2039 if ((playlist = rtv->playlist()) != 0) {
2043 begin_reversible_command (_("separate"));
2047 before = &(playlist->get_state());
2050 /* XXX need to consider musical time selections here at some point */
2052 double speed = rtv->get_diskstream()->speed();
2055 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2057 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2063 if (doing_undo) commit_reversible_command ();
2067 Editor::crop_region_to_selection ()
2069 if (selection->time.empty() || selection->tracks.empty()) {
2073 vector<boost::shared_ptr<Playlist> > playlists;
2074 boost::shared_ptr<Playlist> playlist;
2076 sort_track_selection ();
2078 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2080 RouteTimeAxisView* rtv;
2082 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2084 boost::shared_ptr<Track> t = rtv->track();
2086 if (t != 0 && ! t->diskstream()->destructive()) {
2088 if ((playlist = rtv->playlist()) != 0) {
2089 playlists.push_back (playlist);
2095 if (playlists.empty()) {
2103 begin_reversible_command (_("trim to selection"));
2105 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2107 boost::shared_ptr<Region> region;
2109 start = selection->time.start();
2111 if ((region = (*i)->top_region_at(start)) == 0) {
2115 /* now adjust lengths to that we do the right thing
2116 if the selection extends beyond the region
2119 start = max (start, region->position());
2120 if (max_frames - start < region->length()) {
2121 end = start + region->length() - 1;
2125 end = min (selection->time.end_frame(), end);
2126 cnt = end - start + 1;
2128 XMLNode &before = (*i)->get_state();
2129 region->trim_to (start, cnt, this);
2130 XMLNode &after = (*i)->get_state();
2131 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2134 commit_reversible_command ();
2138 Editor::region_fill_track ()
2142 if (!session || selection->regions.empty()) {
2146 end = session->current_end_frame ();
2148 begin_reversible_command (_("region fill"));
2150 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2152 boost::shared_ptr<Region> region ((*i)->region());
2155 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2158 boost::shared_ptr<Playlist> pl = region->playlist();
2160 if (end <= region->last_frame()) {
2164 double times = (double) (end - region->last_frame()) / (double) region->length();
2170 XMLNode &before = pl->get_state();
2171 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2172 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2175 commit_reversible_command ();
2179 Editor::region_fill_selection ()
2181 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2185 if (selection->time.empty()) {
2190 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2192 if (selected->count_selected_rows() != 1) {
2196 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2197 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2199 nframes_t start = selection->time[clicked_selection].start;
2200 nframes_t end = selection->time[clicked_selection].end;
2202 boost::shared_ptr<Playlist> playlist;
2204 if (selection->tracks.empty()) {
2208 nframes_t selection_length = end - start;
2209 float times = (float)selection_length / region->length();
2211 begin_reversible_command (_("fill selection"));
2213 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2215 if ((playlist = (*i)->playlist()) == 0) {
2219 XMLNode &before = playlist->get_state();
2220 playlist->add_region (RegionFactory::create (region), start, times);
2221 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2224 commit_reversible_command ();
2228 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2231 if (!region->covers (position)) {
2232 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2235 begin_reversible_command (_("set region sync position"));
2236 XMLNode &before = region->playlist()->get_state();
2237 region->set_sync_position (position);
2238 XMLNode &after = region->playlist()->get_state();
2239 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2240 commit_reversible_command ();
2243 /** Set the sync position of the selection using the position of the edit cursor */
2245 Editor::set_region_sync_from_edit_cursor ()
2247 /* Check that at the edit cursor is in at least one of the selected regions */
2248 RegionSelection::const_iterator i = selection->regions.begin();
2249 while (i != selection->regions.end() && !(*i)->region()->covers (edit_cursor->current_frame)) {
2253 /* Give the user a hint if not */
2254 if (i == selection->regions.end()) {
2255 error << _("Place the edit cursor at the desired sync point") << endmsg;
2259 begin_reversible_command (_("set sync from edit cursor"));
2261 for (RegionSelection::iterator j = selection->regions.begin(); j != selection->regions.end(); ++j) {
2262 boost::shared_ptr<Region> r = (*j)->region();
2263 XMLNode &before = r->playlist()->get_state();
2264 r->set_sync_position (edit_cursor->current_frame);
2265 XMLNode &after = r->playlist()->get_state();
2266 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
2269 commit_reversible_command ();
2272 /** Remove the sync positions of the selection */
2274 Editor::remove_region_sync ()
2276 begin_reversible_command (_("remove sync"));
2278 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2279 boost::shared_ptr<Region> r = (*i)->region();
2280 XMLNode &before = r->playlist()->get_state();
2281 r->clear_sync_position ();
2282 XMLNode &after = r->playlist()->get_state();
2283 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
2286 commit_reversible_command ();
2290 Editor::naturalize ()
2292 if (selection->regions.empty()) {
2295 begin_reversible_command (_("naturalize"));
2296 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2297 XMLNode &before = (*i)->region()->get_state();
2298 (*i)->region()->move_to_natural_position (this);
2299 XMLNode &after = (*i)->region()->get_state();
2300 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2302 commit_reversible_command ();
2306 Editor::align (RegionPoint what)
2308 align_selection (what, edit_cursor->current_frame);
2312 Editor::align_relative (RegionPoint what)
2314 align_selection_relative (what, edit_cursor->current_frame);
2317 struct RegionSortByTime {
2318 bool operator() (const RegionView* a, const RegionView* b) {
2319 return a->region()->position() < b->region()->position();
2324 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2326 if (selection->regions.empty()) {
2334 list<RegionView*> sorted;
2335 selection->regions.by_position (sorted);
2336 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2340 pos = r->first_frame ();
2344 pos = r->last_frame();
2348 pos = r->adjust_to_sync (r->first_frame());
2352 if (pos > position) {
2353 distance = pos - position;
2356 distance = position - pos;
2360 begin_reversible_command (_("align selection (relative)"));
2362 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2364 boost::shared_ptr<Region> region ((*i)->region());
2366 XMLNode &before = region->playlist()->get_state();
2369 region->set_position (region->position() + distance, this);
2371 region->set_position (region->position() - distance, this);
2374 XMLNode &after = region->playlist()->get_state();
2375 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2379 commit_reversible_command ();
2383 Editor::align_selection (RegionPoint point, nframes_t position)
2385 if (selection->regions.empty()) {
2389 begin_reversible_command (_("align selection"));
2391 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2392 align_region_internal ((*i)->region(), point, position);
2395 commit_reversible_command ();
2399 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2401 begin_reversible_command (_("align region"));
2402 align_region_internal (region, point, position);
2403 commit_reversible_command ();
2407 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2409 XMLNode &before = region->playlist()->get_state();
2413 region->set_position (region->adjust_to_sync (position), this);
2417 if (position > region->length()) {
2418 region->set_position (position - region->length(), this);
2423 region->set_position (position, this);
2427 XMLNode &after = region->playlist()->get_state();
2428 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2431 /** Trim the end of the selected regions to the position of the edit cursor */
2433 Editor::trim_region_to_edit_cursor ()
2435 if (selection->regions.empty()) {
2439 begin_reversible_command (_("trim to edit"));
2441 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2442 boost::shared_ptr<Region> region ((*i)->region());
2445 RouteTimeAxisView *rtav;
2447 /* XXX I don't think clicked_axisview should be used here! */
2448 if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
2449 if (rtav->get_diskstream() != 0) {
2450 speed = rtav->get_diskstream()->speed();
2454 XMLNode &before = region->playlist()->get_state();
2455 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2456 XMLNode &after = region->playlist()->get_state();
2457 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2460 commit_reversible_command ();
2463 /** Trim the start of the selected regions to the position of the edit cursor */
2465 Editor::trim_region_from_edit_cursor ()
2467 if (selection->regions.empty()) {
2471 begin_reversible_command (_("trim to edit"));
2473 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2474 boost::shared_ptr<Region> region ((*i)->region());
2477 RouteTimeAxisView *rtav;
2479 /* XXX: not sure about clicked_axisview here */
2480 if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
2481 if (rtav->get_diskstream() != 0) {
2482 speed = rtav->get_diskstream()->speed();
2486 XMLNode &before = region->playlist()->get_state();
2487 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2488 XMLNode &after = region->playlist()->get_state();
2489 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2492 commit_reversible_command ();
2495 /** Unfreeze selected routes */
2497 Editor::unfreeze_routes ()
2499 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2500 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*i);
2501 if (atv && atv->is_audio_track()) {
2502 atv->audio_track()->unfreeze ();
2508 Editor::_freeze_thread (void* arg)
2510 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2511 return static_cast<Editor*>(arg)->freeze_thread ();
2515 Editor::freeze_thread ()
2517 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2518 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*i);
2519 if (atv && atv->is_audio_track()) {
2520 atv->audio_track()->freeze (*current_interthread_info);
2524 current_interthread_info->done = true;
2530 Editor::freeze_progress_timeout (void *arg)
2532 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2533 return !(current_interthread_info->done || current_interthread_info->cancel);
2536 /** Freeze selected routes */
2538 Editor::freeze_routes ()
2540 InterThreadInfo itt;
2542 if (interthread_progress_window == 0) {
2543 build_interthread_progress_window ();
2546 WindowTitle title(Glib::get_application_name());
2547 title += _("Freeze");
2548 interthread_progress_window->set_title (title.get_string());
2549 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2550 interthread_progress_window->show_all ();
2551 interthread_progress_bar.set_fraction (0.0f);
2552 interthread_progress_label.set_text ("");
2553 interthread_cancel_label.set_text (_("Cancel Freeze"));
2554 current_interthread_info = &itt;
2556 interthread_progress_connection =
2557 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2561 itt.progress = 0.0f;
2563 pthread_attr_t attr;
2564 pthread_attr_init(&attr);
2565 pthread_attr_setstacksize(&attr, 500000);
2567 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2569 pthread_attr_destroy(&attr);
2571 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2573 while (!itt.done && !itt.cancel) {
2574 gtk_main_iteration ();
2577 interthread_progress_connection.disconnect ();
2578 interthread_progress_window->hide_all ();
2579 current_interthread_info = 0;
2580 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2584 Editor::bounce_range_selection ()
2586 if (selection->time.empty()) {
2590 TrackSelection views = selection->tracks;
2592 nframes_t start = selection->time[clicked_selection].start;
2593 nframes_t end = selection->time[clicked_selection].end;
2594 nframes_t cnt = end - start + 1;
2596 begin_reversible_command (_("bounce range"));
2598 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2600 RouteTimeAxisView* rtv;
2602 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
2606 boost::shared_ptr<Playlist> playlist;
2608 if ((playlist = rtv->playlist()) == 0) {
2612 InterThreadInfo itt;
2616 itt.progress = false;
2618 XMLNode &before = playlist->get_state();
2619 rtv->track()->bounce_range (start, cnt, itt);
2620 XMLNode &after = playlist->get_state();
2621 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2624 commit_reversible_command ();
2627 /** Cut selected regions, automation points or a time range */
2634 /** Copy selected regions, automation points or a time range */
2642 /** @return true if a Cut, Copy or Clear is possible */
2644 Editor::can_cut_copy () const
2646 switch (current_mouse_mode()) {
2649 if (!selection->regions.empty() || !selection->points.empty()) {
2655 if (!selection->time.empty()) {
2668 /** Cut, copy or clear selected regions, automation points or a time range.
2669 * @param op Operation (Cut, Copy or Clear)
2672 Editor::cut_copy (CutCopyOp op)
2674 /* only cancel selection if cut/copy is successful.*/
2686 opname = _("clear");
2690 cut_buffer->clear ();
2692 switch (current_mouse_mode()) {
2694 if (!selection->regions.empty() || !selection->points.empty()) {
2696 begin_reversible_command (opname + _(" objects"));
2698 if (!selection->regions.empty()) {
2700 cut_copy_regions (op);
2703 selection->clear_regions ();
2707 if (!selection->points.empty()) {
2708 cut_copy_points (op);
2711 selection->clear_points ();
2715 commit_reversible_command ();
2720 if (!selection->time.empty()) {
2722 begin_reversible_command (opname + _(" range"));
2723 cut_copy_ranges (op);
2724 commit_reversible_command ();
2727 selection->clear_time ();
2738 /** Cut, copy or clear selected automation points.
2739 * @param op Operation (Cut, Copy or Clear)
2742 Editor::cut_copy_points (CutCopyOp op)
2744 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2746 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2749 atv->cut_copy_clear_objects (selection->points, op);
2754 struct PlaylistState {
2755 boost::shared_ptr<Playlist> playlist;
2759 struct lt_playlist {
2760 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2761 return a.playlist < b.playlist;
2765 struct PlaylistMapping {
2767 boost::shared_ptr<Playlist> pl;
2769 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2773 /** Cut, copy or clear selected regions.
2774 * @param op Operation (Cut, Copy or Clear)
2777 Editor::cut_copy_regions (CutCopyOp op)
2779 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2780 a map when we want ordered access to both elements. i think.
2783 vector<PlaylistMapping> pmap;
2785 nframes_t first_position = max_frames;
2787 set<PlaylistState, lt_playlist> freezelist;
2788 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2790 /* get ordering correct before we cut/copy */
2792 selection->regions.sort_by_position_and_track ();
2794 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2796 first_position = min ((*x)->region()->position(), first_position);
2798 if (op == Cut || op == Clear) {
2799 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
2803 PlaylistState before;
2804 before.playlist = pl;
2805 before.before = &pl->get_state();
2807 insert_result = freezelist.insert (before);
2809 if (insert_result.second) {
2815 TimeAxisView* tv = &(*x)->get_trackview();
2816 vector<PlaylistMapping>::iterator z;
2818 for (z = pmap.begin(); z != pmap.end(); ++z) {
2819 if ((*z).tv == tv) {
2824 if (z == pmap.end()) {
2825 pmap.push_back (PlaylistMapping (tv));
2829 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2831 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
2834 /* impossible, but this handles it for the future */
2838 TimeAxisView& tv = (*x)->get_trackview();
2839 boost::shared_ptr<Playlist> npl;
2840 RegionSelection::iterator tmp;
2845 vector<PlaylistMapping>::iterator z;
2847 for (z = pmap.begin(); z != pmap.end(); ++z) {
2848 if ((*z).tv == &tv) {
2853 assert (z != pmap.end());
2856 npl = PlaylistFactory::create (pl->data_type(), *session, "cutlist", true);
2863 boost::shared_ptr<Region> r = (*x)->region();
2864 boost::shared_ptr<Region> _xx;
2870 _xx = RegionFactory::create (r);
2871 npl->add_region (_xx, r->position() - first_position);
2872 pl->remove_region (r);
2876 /* copy region before adding, so we're not putting same object into two different playlists */
2877 npl->add_region (RegionFactory::create (r), r->position() - first_position);
2881 pl->remove_region (r);
2888 list<boost::shared_ptr<Playlist> > foo;
2890 /* the pmap is in the same order as the tracks in which selected regions occured */
2892 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2894 foo.push_back ((*i).pl);
2899 cut_buffer->set (foo);
2902 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2903 (*pl).playlist->thaw ();
2904 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2909 Editor::cut_copy_ranges (CutCopyOp op)
2911 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2912 (*i)->cut_copy_clear (*selection, op);
2917 Editor::paste (float times)
2919 paste_internal (edit_cursor->current_frame, times);
2923 Editor::mouse_paste ()
2928 track_canvas.get_pointer (x, y);
2929 track_canvas.window_to_world (x, y, wx, wy);
2930 wx += horizontal_adjustment.get_value();
2931 wy += vertical_adjustment.get_value();
2934 event.type = GDK_BUTTON_RELEASE;
2935 event.button.x = wx;
2936 event.button.y = wy;
2938 nframes_t where = event_frame (&event, 0, 0);
2940 paste_internal (where, 1);
2944 Editor::paste_internal (nframes_t position, float times)
2946 bool commit = false;
2948 if (cut_buffer->empty() || selection->tracks.empty()) {
2952 if (position == max_frames) {
2953 position = edit_cursor->current_frame;
2956 begin_reversible_command (_("paste"));
2958 TrackSelection::iterator i;
2961 /* get everything in the correct order */
2963 sort_track_selection ();
2965 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
2967 /* undo/redo is handled by individual tracks */
2969 if ((*i)->paste (position, times, *cut_buffer, nth)) {
2975 commit_reversible_command ();
2980 Editor::paste_named_selection (float times)
2982 TrackSelection::iterator t;
2984 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
2986 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
2990 TreeModel::iterator i = selected->get_selected();
2991 NamedSelection* ns = (*i)[named_selection_columns.selection];
2993 list<boost::shared_ptr<Playlist> >::iterator chunk;
2994 list<boost::shared_ptr<Playlist> >::iterator tmp;
2996 chunk = ns->playlists.begin();
2998 begin_reversible_command (_("paste chunk"));
3000 sort_track_selection ();
3002 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3004 RouteTimeAxisView* rtv;
3005 boost::shared_ptr<Playlist> pl;
3006 boost::shared_ptr<AudioPlaylist> apl;
3008 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*t)) == 0) {
3012 if ((pl = rtv->playlist()) == 0) {
3016 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3023 XMLNode &before = apl->get_state();
3024 apl->paste (*chunk, edit_cursor->current_frame, times);
3025 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3027 if (tmp != ns->playlists.end()) {
3032 commit_reversible_command();
3036 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3038 boost::shared_ptr<Playlist> playlist;
3039 RegionSelection sel = regions; // clear (below) will clear the argument list
3041 begin_reversible_command (_("duplicate region"));
3043 selection->clear_regions ();
3045 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3047 boost::shared_ptr<Region> r ((*i)->region());
3049 TimeAxisView& tv = (*i)->get_time_axis_view();
3050 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3051 sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3053 playlist = (*i)->region()->playlist();
3054 XMLNode &before = playlist->get_state();
3055 playlist->duplicate (r, r->last_frame(), times);
3056 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3060 if (latest_regionview) {
3061 selection->add (latest_regionview);
3066 commit_reversible_command ();
3070 Editor::duplicate_selection (float times)
3072 if (selection->time.empty() || selection->tracks.empty()) {
3076 boost::shared_ptr<Playlist> playlist;
3077 vector<boost::shared_ptr<AudioRegion> > new_regions;
3078 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3080 create_region_from_selection (new_regions);
3082 if (new_regions.empty()) {
3086 begin_reversible_command (_("duplicate selection"));
3088 ri = new_regions.begin();
3090 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3091 if ((playlist = (*i)->playlist()) == 0) {
3094 XMLNode &before = playlist->get_state();
3095 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3096 XMLNode &after = playlist->get_state();
3097 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3100 if (ri == new_regions.end()) {
3105 commit_reversible_command ();
3109 Editor::reset_point_selection ()
3111 /* reset all selected points to the relevant default value */
3113 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3115 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3118 atv->reset_objects (selection->points);
3124 Editor::center_playhead ()
3126 float page = canvas_width * frames_per_unit;
3128 center_screen_internal (playhead_cursor->current_frame, page);
3132 Editor::center_edit_cursor ()
3134 float page = canvas_width * frames_per_unit;
3136 center_screen_internal (edit_cursor->current_frame, page);
3140 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3142 begin_reversible_command (_("clear playlist"));
3143 XMLNode &before = playlist->get_state();
3145 XMLNode &after = playlist->get_state();
3146 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3147 commit_reversible_command ();
3151 Editor::nudge_selected_tracks (bool use_edit_cursor, bool forwards)
3153 boost::shared_ptr<Playlist> playlist;
3155 nframes_t next_distance;
3158 if (use_edit_cursor) {
3159 start = edit_cursor->current_frame;
3164 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3168 if (selection->tracks.empty()) {
3172 begin_reversible_command (_("nudge track"));
3174 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3176 if ((playlist = (*i)->playlist()) == 0) {
3180 XMLNode &before = playlist->get_state();
3181 playlist->nudge_after (start, distance, forwards);
3182 XMLNode &after = playlist->get_state();
3183 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3186 commit_reversible_command ();
3190 Editor::remove_last_capture ()
3192 vector<string> choices;
3199 if (Config->get_verify_remove_last_capture()) {
3200 prompt = _("Do you really want to destroy the last capture?"
3201 "\n(This is destructive and cannot be undone)");
3203 choices.push_back (_("No, do nothing."));
3204 choices.push_back (_("Yes, destroy it."));
3206 Gtkmm2ext::Choice prompter (prompt, choices);
3208 if (prompter.run () == 1) {
3209 session->remove_last_capture ();
3213 session->remove_last_capture();
3218 Editor::normalize_regions ()
3224 if (selection->regions.empty()) {
3228 begin_reversible_command (_("normalize"));
3230 track_canvas.get_window()->set_cursor (*wait_cursor);
3233 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3234 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3237 XMLNode &before = arv->region()->get_state();
3238 arv->audio_region()->normalize_to (0.0f);
3239 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3242 commit_reversible_command ();
3243 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3248 Editor::denormalize_regions ()
3254 if (selection->regions.empty()) {
3258 begin_reversible_command ("denormalize");
3260 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3261 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3264 XMLNode &before = arv->region()->get_state();
3265 arv->audio_region()->set_scale_amplitude (1.0f);
3266 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3269 commit_reversible_command ();
3274 Editor::reverse_regions ()
3280 Reverse rev (*session);
3281 apply_filter (rev, _("reverse regions"));
3285 Editor::apply_filter (AudioFilter& filter, string command)
3287 if (selection->regions.empty()) {
3291 begin_reversible_command (command);
3293 track_canvas.get_window()->set_cursor (*wait_cursor);
3296 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3297 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3301 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3303 RegionSelection::iterator tmp;
3308 if (arv->audio_region()->apply (filter) == 0) {
3310 XMLNode &before = playlist->get_state();
3311 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3312 XMLNode &after = playlist->get_state();
3313 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3321 commit_reversible_command ();
3322 selection->regions.clear ();
3325 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3329 Editor::region_selection_op (void (Region::*pmf)(void))
3331 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3332 Region* region = (*i)->region().get();
3339 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3341 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3342 Region* region = (*i)->region().get();
3343 (region->*pmf)(arg);
3348 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3350 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3351 Region* region = (*i)->region().get();
3357 Editor::external_edit_region ()
3363 Editor::brush (nframes_t pos)
3365 RegionSelection sel;
3368 if (selection->regions.empty()) {
3369 /* XXX get selection from region list */
3371 sel = selection->regions;
3378 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3379 mouse_brush_insert_region ((*i), pos);
3384 Editor::reset_region_gain_envelopes ()
3386 if (!session || selection->regions.empty()) {
3390 session->begin_reversible_command (_("reset region gain"));
3392 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3393 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3395 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
3396 XMLNode& before (alist->get_state());
3398 arv->audio_region()->set_default_envelope ();
3399 session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
3403 session->commit_reversible_command ();
3406 /** Set whether or not gain envelopes are visible for the selected regions.
3407 * @param yn true to make visible, false to make invisible.
3410 Editor::set_gain_envelope_visibility (bool yn)
3412 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3413 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3415 if (arv->envelope_visible() != yn) {
3416 arv->set_envelope_visible (yn);
3422 /** Set whether or not gain envelopes are active for the selected regions.
3423 * @param yn true to make active, false to make inactive.
3426 Editor::set_gain_envelope_active (bool yn)
3428 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3429 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3431 if (arv->audio_region()->envelope_active() != yn) {
3432 arv->audio_region()->set_envelope_active (yn);
3438 /** Set the locked state of all selected regions to a particular value.
3439 * @param yn true to make locked, false to make unlocked.
3442 Editor::set_region_lock (bool yn)
3444 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3445 (*i)->region()->set_locked (yn);
3449 /** Set the position-locked state of all selected regions to a particular value.
3450 * @param yn true to make locked, false to make unlocked.
3453 Editor::set_region_position_lock (bool yn)
3455 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3456 (*i)->region()->set_position_locked (yn);
3461 Editor::set_region_mute (bool yn)
3463 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3464 (*i)->region()->set_muted (yn);
3469 Editor::set_region_opaque (bool yn)
3471 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3472 (*i)->region()->set_opaque (yn);
3477 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3479 begin_reversible_command (_("set fade in shape"));
3481 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3482 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3488 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
3489 XMLNode &before = alist->get_state();
3491 tmp->audio_region()->set_fade_in_shape (shape);
3493 XMLNode &after = alist->get_state();
3494 session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
3497 commit_reversible_command ();
3501 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3503 begin_reversible_command (_("set fade out shape"));
3505 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3506 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3512 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
3513 XMLNode &before = alist->get_state();
3515 tmp->audio_region()->set_fade_out_shape (shape);
3517 XMLNode &after = alist->get_state();
3518 session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
3521 commit_reversible_command ();
3525 Editor::set_fade_in_active (bool yn)
3527 begin_reversible_command (_("set fade in active"));
3529 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3530 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3537 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3539 XMLNode &before = ar->get_state();
3541 ar->set_fade_in_active (yn);
3543 XMLNode &after = ar->get_state();
3544 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3549 Editor::set_fade_out_active (bool yn)
3551 begin_reversible_command (_("set fade out active"));
3553 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3554 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3560 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3562 XMLNode &before = ar->get_state();
3564 ar->set_fade_out_active (yn);
3566 XMLNode &after = ar->get_state();
3567 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3572 /** Update crossfade visibility after its configuration has been changed */
3574 Editor::update_xfade_visibility ()
3576 _xfade_visibility = Config->get_xfades_visible ();
3578 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3579 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3581 if (_xfade_visibility) {
3582 v->show_all_xfades ();
3584 v->hide_all_xfades ();