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.
27 #include <pbd/error.h>
28 #include <pbd/basename.h>
29 #include <pbd/pthread_utils.h>
30 #include <pbd/memento_command.h>
32 #include <gtkmm2ext/utils.h>
33 #include <gtkmm2ext/choice.h>
34 #include <gtkmm2ext/window_title.h>
36 #include <ardour/audioengine.h>
37 #include <ardour/session.h>
38 #include <ardour/audioplaylist.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/utils.h>
42 #include <ardour/location.h>
43 #include <ardour/named_selection.h>
44 #include <ardour/audio_track.h>
45 #include <ardour/audioplaylist.h>
46 #include <ardour/region_factory.h>
47 #include <ardour/playlist_factory.h>
48 #include <ardour/reverse.h>
50 #include "ardour_ui.h"
52 #include "time_axis_view.h"
53 #include "audio_time_axis.h"
54 #include "automation_time_axis.h"
55 #include "streamview.h"
56 #include "audio_region_view.h"
57 #include "rgb_macros.h"
58 #include "selection_templates.h"
59 #include "selection.h"
61 #include "gtk-custom-hruler.h"
62 #include "gui_thread.h"
67 using namespace ARDOUR;
71 using namespace Gtkmm2ext;
72 using namespace Editing;
74 /***********************************************************************
76 ***********************************************************************/
79 Editor::undo (uint32_t n)
87 Editor::redo (uint32_t n)
95 Editor::ensure_cursor (nframes_t *pos)
97 *pos = edit_cursor->current_frame;
102 Editor::split_region ()
104 split_region_at (edit_cursor->current_frame);
108 Editor::split_region_at (nframes_t where)
110 split_regions_at (where, selection->regions);
114 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
116 begin_reversible_command (_("split"));
118 // if splitting a single region, and snap-to is using
119 // region boundaries, don't pay attention to them
121 if (regions.size() == 1) {
123 case SnapToRegionStart:
124 case SnapToRegionSync:
125 case SnapToRegionEnd:
135 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
137 RegionSelection::iterator tmp;
142 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
144 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
146 _new_regionviews_show_envelope = arv->envelope_visible();
149 XMLNode &before = pl->get_state();
150 pl->split_region ((*a)->region(), where);
151 XMLNode &after = pl->get_state();
152 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
158 commit_reversible_command ();
159 _new_regionviews_show_envelope = false;
163 Editor::remove_clicked_region ()
165 if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
169 boost::shared_ptr<Playlist> playlist = clicked_audio_trackview->playlist();
171 begin_reversible_command (_("remove region"));
172 XMLNode &before = playlist->get_state();
173 playlist->remove_region (clicked_regionview->region());
174 XMLNode &after = playlist->get_state();
175 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
176 commit_reversible_command ();
180 Editor::destroy_clicked_region ()
182 uint32_t selected = selection->regions.size();
184 if (!session || !selected) {
188 vector<string> choices;
191 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
192 It cannot be undone\n\
193 Do you really want to destroy %1 ?"),
195 _("these regions") : _("this region")));
197 choices.push_back (_("No, do nothing."));
200 choices.push_back (_("Yes, destroy them."));
202 choices.push_back (_("Yes, destroy it."));
205 Gtkmm2ext::Choice prompter (prompt, choices);
207 if (prompter.run() == 0) { /* first choice */
212 list<boost::shared_ptr<Region> > r;
214 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
215 r.push_back ((*i)->region());
218 session->destroy_regions (r);
222 boost::shared_ptr<Region>
223 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
226 boost::shared_ptr<Region> region;
229 if (selection->time.start () == selection->time.end_frame ()) {
231 /* no current selection-> is there a selected regionview? */
233 if (selection->regions.empty()) {
239 if (!selection->regions.empty()) {
241 rv = *(selection->regions.begin());
242 (*tv) = &rv->get_time_axis_view();
243 region = rv->region();
245 } else if (!selection->tracks.empty()) {
247 (*tv) = selection->tracks.front();
249 RouteTimeAxisView* rtv;
251 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
252 boost::shared_ptr<Playlist> pl;
254 if ((pl = rtv->playlist()) == 0) {
258 region = pl->top_region_at (start);
266 Editor::extend_selection_to_end_of_region (bool next)
269 boost::shared_ptr<Region> region;
272 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
276 if (region && selection->time.start () == selection->time.end_frame ()) {
277 start = region->position();
279 start = selection->time.start ();
282 /* Try to leave the selection with the same route if possible */
284 if ((tv = selection->time.track) == 0) {
288 begin_reversible_command (_("extend selection"));
289 selection->set (tv, start, region->position() + region->length());
290 commit_reversible_command ();
294 Editor::extend_selection_to_start_of_region (bool previous)
297 boost::shared_ptr<Region> region;
300 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
304 if (region && selection->time.start () == selection->time.end_frame ()) {
305 end = region->position() + region->length();
307 end = selection->time.end_frame ();
310 /* Try to leave the selection with the same route if possible */
312 if ((tv = selection->time.track) == 0) {
316 begin_reversible_command (_("extend selection"));
317 selection->set (tv, region->position(), end);
318 commit_reversible_command ();
323 Editor::nudge_forward (bool next)
326 nframes_t next_distance;
328 if (!session) return;
330 if (!selection->regions.empty()) {
332 begin_reversible_command (_("nudge forward"));
334 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
335 boost::shared_ptr<Region> r ((*i)->region());
337 distance = get_nudge_distance (r->position(), next_distance);
340 distance = next_distance;
343 XMLNode &before = r->playlist()->get_state();
344 r->set_position (r->position() + distance, this);
345 XMLNode &after = r->playlist()->get_state();
346 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
349 commit_reversible_command ();
352 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
353 session->request_locate (playhead_cursor->current_frame + distance);
358 Editor::nudge_backward (bool next)
361 nframes_t next_distance;
363 if (!session) return;
365 if (!selection->regions.empty()) {
367 begin_reversible_command (_("nudge forward"));
369 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
370 boost::shared_ptr<Region> r ((*i)->region());
372 distance = get_nudge_distance (r->position(), next_distance);
375 distance = next_distance;
378 XMLNode &before = r->playlist()->get_state();
380 if (r->position() > distance) {
381 r->set_position (r->position() - distance, this);
383 r->set_position (0, this);
385 XMLNode &after = r->playlist()->get_state();
386 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
389 commit_reversible_command ();
393 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
395 if (playhead_cursor->current_frame > distance) {
396 session->request_locate (playhead_cursor->current_frame - distance);
398 session->goto_start();
404 Editor::nudge_forward_capture_offset ()
408 if (!session) return;
410 if (!selection->regions.empty()) {
412 begin_reversible_command (_("nudge forward"));
414 distance = session->worst_output_latency();
416 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
417 boost::shared_ptr<Region> r ((*i)->region());
419 XMLNode &before = r->playlist()->get_state();
420 r->set_position (r->position() + distance, this);
421 XMLNode &after = r->playlist()->get_state();
422 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
425 commit_reversible_command ();
431 Editor::nudge_backward_capture_offset ()
435 if (!session) return;
437 if (!selection->regions.empty()) {
439 begin_reversible_command (_("nudge forward"));
441 distance = session->worst_output_latency();
443 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
444 boost::shared_ptr<Region> r ((*i)->region());
446 XMLNode &before = r->playlist()->get_state();
448 if (r->position() > distance) {
449 r->set_position (r->position() - distance, this);
451 r->set_position (0, this);
453 XMLNode &after = r->playlist()->get_state();
454 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
457 commit_reversible_command ();
464 Editor::move_to_start ()
466 session->goto_start ();
470 Editor::move_to_end ()
473 session->request_locate (session->current_end_frame());
477 Editor::build_region_boundary_cache ()
480 vector<RegionPoint> interesting_points;
481 boost::shared_ptr<Region> r;
482 TrackViewList tracks;
485 region_boundary_cache.clear ();
492 case SnapToRegionStart:
493 interesting_points.push_back (Start);
495 case SnapToRegionEnd:
496 interesting_points.push_back (End);
498 case SnapToRegionSync:
499 interesting_points.push_back (SyncPoint);
501 case SnapToRegionBoundary:
502 interesting_points.push_back (Start);
503 interesting_points.push_back (End);
506 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
511 TimeAxisView *ontrack = 0;
514 if (!selection->tracks.empty()) {
515 tlist = selection->tracks;
520 while (pos < session->current_end_frame() && !at_end) {
523 nframes_t lpos = max_frames;
525 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
527 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
528 if (*p == interesting_points.back()) {
531 /* move to next point type */
537 rpos = r->first_frame();
540 rpos = r->last_frame();
543 rpos = r->adjust_to_sync (r->first_frame());
550 AudioTimeAxisView *atav;
552 if (ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
553 if (atav->get_diskstream() != 0) {
554 speed = atav->get_diskstream()->speed();
558 rpos = track_frame_to_session_frame (rpos, speed);
564 /* prevent duplicates, but we don't use set<> because we want to be able
568 vector<nframes_t>::iterator ri;
570 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
576 if (ri == region_boundary_cache.end()) {
577 region_boundary_cache.push_back (rpos);
584 /* finally sort to be sure that the order is correct */
586 sort (region_boundary_cache.begin(), region_boundary_cache.end());
589 boost::shared_ptr<Region>
590 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
592 TrackViewList::iterator i;
593 nframes_t closest = max_frames;
594 boost::shared_ptr<Region> ret;
598 nframes_t track_frame;
599 AudioTimeAxisView *atav;
601 for (i = tracks.begin(); i != tracks.end(); ++i) {
604 boost::shared_ptr<Region> r;
607 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
608 if (atav->get_diskstream()!=0)
609 track_speed = atav->get_diskstream()->speed();
612 track_frame = session_frame_to_track_frame(frame, track_speed);
614 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
620 rpos = r->first_frame ();
624 rpos = r->last_frame ();
628 rpos = r->adjust_to_sync (r->first_frame());
631 // rpos is a "track frame", converting it to "session frame"
632 rpos = track_frame_to_session_frame(rpos, track_speed);
635 distance = rpos - frame;
637 distance = frame - rpos;
640 if (distance < closest) {
652 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
654 boost::shared_ptr<Region> r;
655 nframes_t pos = cursor->current_frame;
661 TimeAxisView *ontrack = 0;
663 // so we don't find the current region again..
667 if (!selection->tracks.empty()) {
669 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
671 } else if (clicked_trackview) {
674 t.push_back (clicked_trackview);
676 r = find_next_region (pos, point, dir, t, &ontrack);
680 r = find_next_region (pos, point, dir, track_views, &ontrack);
689 pos = r->first_frame ();
693 pos = r->last_frame ();
697 pos = r->adjust_to_sync (r->first_frame());
702 AudioTimeAxisView *atav;
704 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
705 if (atav->get_diskstream() != 0) {
706 speed = atav->get_diskstream()->speed();
710 pos = track_frame_to_session_frame(pos, speed);
712 if (cursor == playhead_cursor) {
713 session->request_locate (pos);
715 cursor->set_position (pos);
720 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
722 cursor_to_region_point (cursor, point, 1);
726 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
728 cursor_to_region_point (cursor, point, -1);
732 Editor::cursor_to_selection_start (Cursor *cursor)
735 switch (mouse_mode) {
737 if (!selection->regions.empty()) {
738 pos = selection->regions.start();
743 if (!selection->time.empty()) {
744 pos = selection->time.start ();
752 if (cursor == playhead_cursor) {
753 session->request_locate (pos);
755 cursor->set_position (pos);
760 Editor::cursor_to_selection_end (Cursor *cursor)
764 switch (mouse_mode) {
766 if (!selection->regions.empty()) {
767 pos = selection->regions.end_frame();
772 if (!selection->time.empty()) {
773 pos = selection->time.end_frame ();
781 if (cursor == playhead_cursor) {
782 session->request_locate (pos);
784 cursor->set_position (pos);
789 Editor::scroll_playhead (bool forward)
791 nframes_t pos = playhead_cursor->current_frame;
792 nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
795 if (pos == max_frames) {
799 if (pos < max_frames - delta) {
818 session->request_locate (pos);
822 Editor::playhead_backward ()
829 if (get_prefix (prefix, was_floating)) {
833 cnt = (nframes_t) floor (prefix * session->frame_rate ());
835 cnt = (nframes_t) prefix;
839 pos = playhead_cursor->current_frame;
841 if ((nframes_t) pos < cnt) {
847 /* XXX this is completely insane. with the current buffering
848 design, we'll force a complete track buffer flush and
849 reload, just to move 1 sample !!!
852 session->request_locate (pos);
856 Editor::playhead_forward ()
863 if (get_prefix (prefix, was_floating)) {
867 cnt = (nframes_t) floor (prefix * session->frame_rate ());
869 cnt = (nframes_t) floor (prefix);
873 pos = playhead_cursor->current_frame;
875 /* XXX this is completely insane. with the current buffering
876 design, we'll force a complete track buffer flush and
877 reload, just to move 1 sample !!!
880 session->request_locate (pos+cnt);
884 Editor::cursor_align (bool playhead_to_edit)
886 if (playhead_to_edit) {
888 session->request_locate (edit_cursor->current_frame);
891 edit_cursor->set_position (playhead_cursor->current_frame);
896 Editor::edit_cursor_backward ()
903 if (get_prefix (prefix, was_floating)) {
907 cnt = (nframes_t) floor (prefix * session->frame_rate ());
909 cnt = (nframes_t) prefix;
913 pos = edit_cursor->current_frame;
915 if ((nframes_t) pos < cnt) {
921 edit_cursor->set_position (pos);
925 Editor::edit_cursor_forward ()
932 if (get_prefix (prefix, was_floating)) {
936 cnt = (nframes_t) floor (prefix * session->frame_rate ());
938 cnt = (nframes_t) floor (prefix);
942 pos = edit_cursor->current_frame;
943 edit_cursor->set_position (pos+cnt);
947 Editor::goto_frame ()
953 if (get_prefix (prefix, was_floating)) {
958 frame = (nframes_t) floor (prefix * session->frame_rate());
960 frame = (nframes_t) floor (prefix);
963 session->request_locate (frame);
967 Editor::scroll_backward (float pages)
970 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
975 if (get_prefix (prefix, was_floating)) {
976 cnt = (nframes_t) floor (pages * one_page);
979 cnt = (nframes_t) floor (prefix * session->frame_rate());
981 cnt = (nframes_t) floor (prefix * one_page);
985 if (leftmost_frame < cnt) {
988 frame = leftmost_frame - cnt;
991 reset_x_origin (frame);
995 Editor::scroll_forward (float pages)
998 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1003 if (get_prefix (prefix, was_floating)) {
1004 cnt = (nframes_t) floor (pages * one_page);
1007 cnt = (nframes_t) floor (prefix * session->frame_rate());
1009 cnt = (nframes_t) floor (prefix * one_page);
1013 if (max_frames - cnt < leftmost_frame) {
1014 frame = max_frames - cnt;
1016 frame = leftmost_frame + cnt;
1019 reset_x_origin (frame);
1023 Editor::scroll_tracks_down ()
1029 if (get_prefix (prefix, was_floating)) {
1032 cnt = (int) floor (prefix);
1035 double vert_value = vertical_adjustment.get_value() + (cnt *
1036 vertical_adjustment.get_page_size());
1037 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1038 vert_value = vertical_adjustment.get_upper() - canvas_height;
1040 vertical_adjustment.set_value (vert_value);
1044 Editor::scroll_tracks_up ()
1050 if (get_prefix (prefix, was_floating)) {
1053 cnt = (int) floor (prefix);
1056 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1060 Editor::scroll_tracks_down_line ()
1063 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1064 double vert_value = adj->get_value() + 20;
1066 if (vert_value>adj->get_upper() - canvas_height) {
1067 vert_value = adj->get_upper() - canvas_height;
1069 adj->set_value (vert_value);
1073 Editor::scroll_tracks_up_line ()
1075 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1076 adj->set_value (adj->get_value() - 20);
1082 Editor::temporal_zoom_step (bool coarser)
1084 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1088 nfpu = frames_per_unit;
1093 nfpu = max(1.0,(nfpu/1.61803399));
1096 temporal_zoom (nfpu);
1100 Editor::temporal_zoom (gdouble fpu)
1102 if (!session) return;
1104 nframes_t current_page = current_page_frames();
1105 nframes_t current_leftmost = leftmost_frame;
1106 nframes_t current_rightmost;
1107 nframes_t current_center;
1109 nframes_t leftmost_after_zoom = 0;
1114 new_page = (nframes_t) floor (canvas_width * nfpu);
1116 switch (zoom_focus) {
1118 leftmost_after_zoom = current_leftmost;
1121 case ZoomFocusRight:
1122 current_rightmost = leftmost_frame + current_page;
1123 if (current_rightmost > new_page) {
1124 leftmost_after_zoom = current_rightmost - new_page;
1126 leftmost_after_zoom = 0;
1130 case ZoomFocusCenter:
1131 current_center = current_leftmost + (current_page/2);
1132 if (current_center > (new_page/2)) {
1133 leftmost_after_zoom = current_center - (new_page / 2);
1135 leftmost_after_zoom = 0;
1139 case ZoomFocusPlayhead:
1140 /* try to keep the playhead in the center */
1141 if (playhead_cursor->current_frame > new_page/2) {
1142 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1144 leftmost_after_zoom = 0;
1149 /* try to keep the edit cursor in the center */
1150 if (edit_cursor->current_frame > new_page/2) {
1151 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1153 leftmost_after_zoom = 0;
1159 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1161 // begin_reversible_command (_("zoom"));
1162 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1163 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1164 // commit_reversible_command ();
1166 reposition_and_zoom (leftmost_after_zoom, nfpu);
1170 Editor::temporal_zoom_selection ()
1172 if (!selection) return;
1174 if (selection->time.empty()) {
1178 nframes_t start = selection->time[clicked_selection].start;
1179 nframes_t end = selection->time[clicked_selection].end;
1181 temporal_zoom_by_frame (start, end, "zoom to selection");
1185 Editor::temporal_zoom_session ()
1187 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1190 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1195 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1197 if (!session) return;
1199 if ((start == 0 && end == 0) || end < start) {
1203 nframes_t range = end - start;
1205 double new_fpu = (double)range / (double)canvas_width;
1208 // while (p2 < new_fpu) {
1213 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1214 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1215 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1217 if (new_leftmost > middle) new_leftmost = 0;
1219 // begin_reversible_command (op);
1220 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1221 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1222 // commit_reversible_command ();
1224 reposition_and_zoom (new_leftmost, new_fpu);
1228 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1230 if (!session) return;
1232 double range_before = frame - leftmost_frame;
1235 new_fpu = frames_per_unit;
1238 new_fpu *= 1.61803399;
1239 range_before *= 1.61803399;
1241 new_fpu = max(1.0,(new_fpu/1.61803399));
1242 range_before /= 1.61803399;
1245 if (new_fpu == frames_per_unit) return;
1247 nframes_t new_leftmost = frame - (nframes_t)range_before;
1249 if (new_leftmost > frame) new_leftmost = 0;
1251 // begin_reversible_command (_("zoom to frame"));
1252 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1253 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1254 // commit_reversible_command ();
1256 reposition_and_zoom (new_leftmost, new_fpu);
1260 Editor::add_location_from_selection ()
1264 if (selection->time.empty()) {
1268 if (session == 0 || clicked_trackview == 0) {
1272 nframes_t start = selection->time[clicked_selection].start;
1273 nframes_t end = selection->time[clicked_selection].end;
1275 session->locations()->next_available_name(rangename,"selection");
1276 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1278 session->begin_reversible_command (_("add marker"));
1279 XMLNode &before = session->locations()->get_state();
1280 session->locations()->add (location, true);
1281 XMLNode &after = session->locations()->get_state();
1282 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1283 session->commit_reversible_command ();
1287 Editor::add_location_from_playhead_cursor ()
1291 nframes_t where = session->audible_frame();
1293 session->locations()->next_available_name(markername,"mark");
1294 Location *location = new Location (where, where, markername, Location::IsMark);
1295 session->begin_reversible_command (_("add marker"));
1296 XMLNode &before = session->locations()->get_state();
1297 session->locations()->add (location, true);
1298 XMLNode &after = session->locations()->get_state();
1299 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1300 session->commit_reversible_command ();
1304 Editor::add_location_from_audio_region ()
1306 if (selection->regions.empty()) {
1310 RegionView* rv = *(selection->regions.begin());
1311 boost::shared_ptr<Region> region = rv->region();
1313 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1314 session->begin_reversible_command (_("add marker"));
1315 XMLNode &before = session->locations()->get_state();
1316 session->locations()->add (location, true);
1317 XMLNode &after = session->locations()->get_state();
1318 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1319 session->commit_reversible_command ();
1323 Editor::amplitude_zoom_step (bool in)
1337 #ifdef FIX_FOR_CANVAS
1338 /* XXX DO SOMETHING */
1347 Editor::delete_sample_forward ()
1352 Editor::delete_sample_backward ()
1357 Editor::delete_screen ()
1364 Editor::search_backwards ()
1370 Editor::search_forwards ()
1378 Editor::jump_forward_to_mark ()
1384 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1387 session->request_locate (location->start(), session->transport_rolling());
1389 session->request_locate (session->current_end_frame());
1394 Editor::jump_backward_to_mark ()
1400 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1403 session->request_locate (location->start(), session->transport_rolling());
1405 session->goto_start ();
1417 if (get_prefix (prefix, was_floating)) {
1418 pos = session->audible_frame ();
1421 pos = (nframes_t) floor (prefix * session->frame_rate ());
1423 pos = (nframes_t) floor (prefix);
1427 session->locations()->next_available_name(markername,"mark");
1428 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1432 Editor::clear_markers ()
1435 session->begin_reversible_command (_("clear markers"));
1436 XMLNode &before = session->locations()->get_state();
1437 session->locations()->clear_markers ();
1438 XMLNode &after = session->locations()->get_state();
1439 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1440 session->commit_reversible_command ();
1445 Editor::clear_ranges ()
1448 session->begin_reversible_command (_("clear ranges"));
1449 XMLNode &before = session->locations()->get_state();
1451 Location * looploc = session->locations()->auto_loop_location();
1452 Location * punchloc = session->locations()->auto_punch_location();
1454 session->locations()->clear_ranges ();
1456 if (looploc) session->locations()->add (looploc);
1457 if (punchloc) session->locations()->add (punchloc);
1459 XMLNode &after = session->locations()->get_state();
1460 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1461 session->commit_reversible_command ();
1466 Editor::clear_locations ()
1468 session->begin_reversible_command (_("clear locations"));
1469 XMLNode &before = session->locations()->get_state();
1470 session->locations()->clear ();
1471 XMLNode &after = session->locations()->get_state();
1472 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1473 session->commit_reversible_command ();
1474 session->locations()->clear ();
1478 Editor::unhide_markers ()
1480 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1481 Location *l = (*i).first;
1482 if (l->is_hidden() && l->is_mark()) {
1483 l->set_hidden(false, this);
1489 Editor::unhide_ranges ()
1491 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1492 Location *l = (*i).first;
1493 if (l->is_hidden() && l->is_range_marker()) {
1494 l->set_hidden(false, this);
1499 /* INSERT/REPLACE */
1502 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1508 AudioTimeAxisView *atv = 0;
1509 boost::shared_ptr<Playlist> playlist;
1511 track_canvas.window_to_world (x, y, wx, wy);
1512 wx += horizontal_adjustment.get_value();
1513 wy += vertical_adjustment.get_value();
1516 event.type = GDK_BUTTON_RELEASE;
1517 event.button.x = wx;
1518 event.button.y = wy;
1520 where = event_frame (&event, &cx, &cy);
1522 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1523 /* clearly outside canvas area */
1527 if ((tv = trackview_by_y_position (cy)) == 0) {
1531 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1535 if ((playlist = atv->playlist()) == 0) {
1541 begin_reversible_command (_("insert dragged region"));
1542 XMLNode &before = playlist->get_state();
1543 playlist->add_region (RegionFactory::create (region), where, 1.0);
1544 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1545 commit_reversible_command ();
1549 Editor::insert_region_list_selection (float times)
1551 RouteTimeAxisView *tv = 0;
1552 boost::shared_ptr<Playlist> playlist;
1554 if (clicked_audio_trackview != 0) {
1555 tv = clicked_audio_trackview;
1556 } else if (!selection->tracks.empty()) {
1557 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1564 if ((playlist = tv->playlist()) == 0) {
1568 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1570 if (selected->count_selected_rows() != 1) {
1574 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1576 /* only one row selected, so rows.begin() is it */
1580 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1582 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1584 begin_reversible_command (_("insert region"));
1585 XMLNode &before = playlist->get_state();
1586 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1587 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1588 commit_reversible_command ();
1592 /* BUILT-IN EFFECTS */
1595 Editor::reverse_selection ()
1600 /* GAIN ENVELOPE EDITING */
1603 Editor::edit_envelope ()
1610 Editor::transition_to_rolling (bool fwd)
1616 switch (Config->get_slave_source()) {
1621 /* transport controlled by the master */
1625 if (session->is_auditioning()) {
1626 session->cancel_audition ();
1630 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1634 Editor::toggle_playback (bool with_abort)
1640 switch (Config->get_slave_source()) {
1645 /* transport controlled by the master */
1649 if (session->is_auditioning()) {
1650 session->cancel_audition ();
1654 if (session->transport_rolling()) {
1655 session->request_stop (with_abort);
1656 if (session->get_play_loop()) {
1657 session->request_play_loop (false);
1660 session->request_transport_speed (1.0f);
1665 Editor::play_from_start ()
1667 session->request_locate (session->current_start_frame(), true);
1671 Editor::play_from_edit_cursor ()
1673 session->request_locate (edit_cursor->current_frame, true);
1677 Editor::play_selection ()
1679 if (selection->time.empty()) {
1683 session->request_play_range (true);
1687 Editor::play_selected_region ()
1689 if (!selection->regions.empty()) {
1690 RegionView *rv = *(selection->regions.begin());
1692 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1697 Editor::loop_selected_region ()
1699 if (!selection->regions.empty()) {
1700 RegionView *rv = *(selection->regions.begin());
1703 if ((tll = transport_loop_location()) != 0) {
1705 tll->set (rv->region()->position(), rv->region()->last_frame());
1707 // enable looping, reposition and start rolling
1709 session->request_play_loop (true);
1710 session->request_locate (tll->start(), false);
1711 session->request_transport_speed (1.0f);
1717 Editor::play_location (Location& location)
1719 if (location.start() <= location.end()) {
1723 session->request_bounded_roll (location.start(), location.end());
1727 Editor::loop_location (Location& location)
1729 if (location.start() <= location.end()) {
1735 if ((tll = transport_loop_location()) != 0) {
1736 tll->set (location.start(), location.end());
1738 // enable looping, reposition and start rolling
1739 session->request_play_loop (true);
1740 session->request_locate (tll->start(), true);
1745 Editor::raise_region ()
1747 selection->foreach_region (&Region::raise);
1751 Editor::raise_region_to_top ()
1753 selection->foreach_region (&Region::raise_to_top);
1757 Editor::lower_region ()
1759 selection->foreach_region (&Region::lower);
1763 Editor::lower_region_to_bottom ()
1765 selection->foreach_region (&Region::lower_to_bottom);
1769 Editor::edit_region ()
1771 if (clicked_regionview == 0) {
1775 clicked_regionview->show_region_editor ();
1779 Editor::rename_region ()
1783 Button ok_button (_("OK"));
1784 Button cancel_button (_("Cancel"));
1786 if (selection->regions.empty()) {
1790 WindowTitle title(Glib::get_application_name());
1791 title += _("Rename Region");
1793 dialog.set_title (title.get_string());
1794 dialog.set_name ("RegionRenameWindow");
1795 dialog.set_size_request (300, -1);
1796 dialog.set_position (Gtk::WIN_POS_MOUSE);
1797 dialog.set_modal (true);
1799 dialog.get_vbox()->set_border_width (10);
1800 dialog.get_vbox()->pack_start (entry);
1801 dialog.get_action_area()->pack_start (ok_button);
1802 dialog.get_action_area()->pack_start (cancel_button);
1804 entry.set_name ("RegionNameDisplay");
1805 ok_button.set_name ("EditorGTKButton");
1806 cancel_button.set_name ("EditorGTKButton");
1808 region_renamed = false;
1810 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1811 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1812 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1819 if (region_renamed) {
1820 (*selection->regions.begin())->region()->set_name (entry.get_text());
1821 redisplay_regions ();
1826 Editor::rename_region_finished (bool status)
1829 region_renamed = status;
1834 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
1836 if (session->is_auditioning()) {
1837 session->cancel_audition ();
1840 // note: some potential for creativity here, because region doesn't
1841 // have to belong to the playlist that Route is handling
1843 // bool was_soloed = route.soloed();
1845 route.set_solo (true, this);
1847 session->request_bounded_roll (region->position(), region->position() + region->length());
1849 /* XXX how to unset the solo state ? */
1853 Editor::audition_selected_region ()
1855 if (!selection->regions.empty()) {
1856 RegionView* rv = *(selection->regions.begin());
1857 session->audition_region (rv->region());
1862 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
1864 session->audition_region (region);
1868 Editor::build_interthread_progress_window ()
1870 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
1872 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1874 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
1875 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
1877 // GTK2FIX: this button needs a modifiable label
1879 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1880 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1882 interthread_cancel_button.add (interthread_cancel_label);
1884 interthread_progress_window->set_default_size (200, 100);
1888 Editor::interthread_cancel_clicked ()
1890 if (current_interthread_info) {
1891 current_interthread_info->cancel = true;
1896 Editor::region_from_selection ()
1898 if (clicked_trackview == 0) {
1902 if (selection->time.empty()) {
1906 nframes_t start = selection->time[clicked_selection].start;
1907 nframes_t end = selection->time[clicked_selection].end;
1909 nframes_t selection_cnt = end - start + 1;
1911 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1912 boost::shared_ptr<AudioRegion> current;
1913 boost::shared_ptr<Region> current_r;
1914 boost::shared_ptr<Playlist> pl;
1916 nframes_t internal_start;
1919 if ((pl = (*i)->playlist()) == 0) {
1923 if ((current_r = pl->top_region_at (start)) == 0) {
1927 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
1928 // FIXME: audio only
1930 internal_start = start - current->position();
1931 session->region_name (new_name, current->name(), true);
1932 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
1938 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
1940 if (selection->time.empty() || selection->tracks.empty()) {
1944 nframes_t start = selection->time[clicked_selection].start;
1945 nframes_t end = selection->time[clicked_selection].end;
1947 sort_track_selection ();
1949 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1951 boost::shared_ptr<AudioRegion> current;
1952 boost::shared_ptr<Region> current_r;
1953 boost::shared_ptr<Playlist> playlist;
1954 nframes_t internal_start;
1957 if ((playlist = (*i)->playlist()) == 0) {
1961 if ((current_r = playlist->top_region_at(start)) == 0) {
1965 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
1969 internal_start = start - current->position();
1970 session->region_name (new_name, current->name(), true);
1972 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
1977 Editor::split_multichannel_region ()
1979 if (selection->regions.empty()) {
1983 vector<boost::shared_ptr<AudioRegion> > v;
1985 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
1987 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
1989 if (!arv || arv->audio_region()->n_channels() < 2) {
1993 (arv)->audio_region()->separate_by_channel (*session, v);
1998 Editor::new_region_from_selection ()
2000 region_from_selection ();
2001 cancel_selection ();
2005 Editor::separate_region_from_selection ()
2007 bool doing_undo = false;
2009 if (selection->time.empty()) {
2013 boost::shared_ptr<Playlist> playlist;
2015 sort_track_selection ();
2017 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2019 AudioTimeAxisView* atv;
2021 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2023 if (atv->is_audio_track()) {
2025 /* no edits to destructive tracks */
2027 if (atv->audio_track()->audio_diskstream()->destructive()) {
2031 if ((playlist = atv->playlist()) != 0) {
2033 begin_reversible_command (_("separate"));
2038 before = &(playlist->get_state());
2040 /* XXX need to consider musical time selections here at some point */
2042 double speed = atv->get_diskstream()->speed();
2044 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2045 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2049 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2055 if (doing_undo) commit_reversible_command ();
2059 Editor::separate_regions_using_location (Location& loc)
2061 bool doing_undo = false;
2063 if (loc.is_mark()) {
2067 boost::shared_ptr<Playlist> playlist;
2069 /* XXX i'm unsure as to whether this should operate on selected tracks only
2070 or the entire enchillada. uncomment the below line to correct the behaviour
2071 (currently set for all tracks)
2074 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2075 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2077 AudioTimeAxisView* atv;
2079 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2081 if (atv->is_audio_track()) {
2083 /* no edits to destructive tracks */
2085 if (atv->audio_track()->audio_diskstream()->destructive()) {
2089 if ((playlist = atv->playlist()) != 0) {
2092 begin_reversible_command (_("separate"));
2096 before = &(playlist->get_state());
2099 /* XXX need to consider musical time selections here at some point */
2101 double speed = atv->get_diskstream()->speed();
2104 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2106 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2112 if (doing_undo) commit_reversible_command ();
2116 Editor::crop_region_to_selection ()
2118 if (selection->time.empty() || selection->tracks.empty()) {
2122 vector<boost::shared_ptr<Playlist> > playlists;
2123 boost::shared_ptr<Playlist> playlist;
2125 sort_track_selection ();
2127 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2129 AudioTimeAxisView* atv;
2131 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2133 if (atv->is_audio_track()) {
2135 /* no edits to destructive tracks */
2137 if (atv->audio_track()->audio_diskstream()->destructive()) {
2141 if ((playlist = atv->playlist()) != 0) {
2142 playlists.push_back (playlist);
2148 if (playlists.empty()) {
2156 begin_reversible_command (_("trim to selection"));
2158 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2160 boost::shared_ptr<Region> region;
2162 start = selection->time.start();
2164 if ((region = (*i)->top_region_at(start)) == 0) {
2168 /* now adjust lengths to that we do the right thing
2169 if the selection extends beyond the region
2172 start = max (start, region->position());
2173 if (max_frames - start < region->length()) {
2174 end = start + region->length() - 1;
2178 end = min (selection->time.end_frame(), end);
2179 cnt = end - start + 1;
2181 XMLNode &before = (*i)->get_state();
2182 region->trim_to (start, cnt, this);
2183 XMLNode &after = (*i)->get_state();
2184 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2187 commit_reversible_command ();
2191 Editor::region_fill_track ()
2195 if (!session || selection->regions.empty()) {
2199 end = session->current_end_frame ();
2201 begin_reversible_command (_("region fill"));
2203 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2205 boost::shared_ptr<Region> region ((*i)->region());
2208 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2212 boost::shared_ptr<Playlist> pl = region->playlist();
2214 if (end <= region->last_frame()) {
2218 double times = (double) (end - region->last_frame()) / (double) region->length();
2224 XMLNode &before = pl->get_state();
2225 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2226 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2229 commit_reversible_command ();
2233 Editor::region_fill_selection ()
2235 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2239 if (selection->time.empty()) {
2244 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2246 if (selected->count_selected_rows() != 1) {
2250 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2251 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2253 nframes_t start = selection->time[clicked_selection].start;
2254 nframes_t end = selection->time[clicked_selection].end;
2256 boost::shared_ptr<Playlist> playlist;
2258 if (selection->tracks.empty()) {
2262 nframes_t selection_length = end - start;
2263 float times = (float)selection_length / region->length();
2265 begin_reversible_command (_("fill selection"));
2267 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2269 if ((playlist = (*i)->playlist()) == 0) {
2273 XMLNode &before = playlist->get_state();
2274 playlist->add_region (RegionFactory::create (region), start, times);
2275 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2278 commit_reversible_command ();
2282 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2285 if (!region->covers (position)) {
2286 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2289 begin_reversible_command (_("set region sync position"));
2290 XMLNode &before = region->playlist()->get_state();
2291 region->set_sync_position (position);
2292 XMLNode &after = region->playlist()->get_state();
2293 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2294 commit_reversible_command ();
2298 Editor::set_region_sync_from_edit_cursor ()
2300 if (clicked_regionview == 0) {
2304 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2305 error << _("Place the edit cursor at the desired sync point") << endmsg;
2309 boost::shared_ptr<Region> region (clicked_regionview->region());
2310 begin_reversible_command (_("set sync from edit cursor"));
2311 XMLNode &before = region->playlist()->get_state();
2312 region->set_sync_position (edit_cursor->current_frame);
2313 XMLNode &after = region->playlist()->get_state();
2314 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2315 commit_reversible_command ();
2319 Editor::remove_region_sync ()
2321 if (clicked_regionview) {
2322 boost::shared_ptr<Region> region (clicked_regionview->region());
2323 begin_reversible_command (_("remove sync"));
2324 XMLNode &before = region->playlist()->get_state();
2325 region->clear_sync_position ();
2326 XMLNode &after = region->playlist()->get_state();
2327 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2328 commit_reversible_command ();
2333 Editor::naturalize ()
2335 if (selection->regions.empty()) {
2338 begin_reversible_command (_("naturalize"));
2339 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2340 XMLNode &before = (*i)->region()->get_state();
2341 (*i)->region()->move_to_natural_position (this);
2342 XMLNode &after = (*i)->region()->get_state();
2343 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2345 commit_reversible_command ();
2349 Editor::align (RegionPoint what)
2351 align_selection (what, edit_cursor->current_frame);
2355 Editor::align_relative (RegionPoint what)
2357 align_selection_relative (what, edit_cursor->current_frame);
2360 struct RegionSortByTime {
2361 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2362 return a->region()->position() < b->region()->position();
2367 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2369 if (selection->regions.empty()) {
2377 list<RegionView*> sorted;
2378 selection->regions.by_position (sorted);
2379 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2383 pos = r->first_frame ();
2387 pos = r->last_frame();
2391 pos = r->adjust_to_sync (r->first_frame());
2395 if (pos > position) {
2396 distance = pos - position;
2399 distance = position - pos;
2403 begin_reversible_command (_("align selection (relative)"));
2405 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2407 boost::shared_ptr<Region> region ((*i)->region());
2409 XMLNode &before = region->playlist()->get_state();
2412 region->set_position (region->position() + distance, this);
2414 region->set_position (region->position() - distance, this);
2417 XMLNode &after = region->playlist()->get_state();
2418 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2422 commit_reversible_command ();
2426 Editor::align_selection (RegionPoint point, nframes_t position)
2428 if (selection->regions.empty()) {
2432 begin_reversible_command (_("align selection"));
2434 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2435 align_region_internal ((*i)->region(), point, position);
2438 commit_reversible_command ();
2442 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2444 begin_reversible_command (_("align region"));
2445 align_region_internal (region, point, position);
2446 commit_reversible_command ();
2450 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2452 XMLNode &before = region->playlist()->get_state();
2456 region->set_position (region->adjust_to_sync (position), this);
2460 if (position > region->length()) {
2461 region->set_position (position - region->length(), this);
2466 region->set_position (position, this);
2470 XMLNode &after = region->playlist()->get_state();
2471 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2475 Editor::trim_region_to_edit_cursor ()
2477 if (clicked_regionview == 0) {
2481 boost::shared_ptr<Region> region (clicked_regionview->region());
2484 AudioTimeAxisView *atav;
2486 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2487 if (atav->get_diskstream() != 0) {
2488 speed = atav->get_diskstream()->speed();
2492 begin_reversible_command (_("trim to edit"));
2493 XMLNode &before = region->playlist()->get_state();
2494 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2495 XMLNode &after = region->playlist()->get_state();
2496 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2497 commit_reversible_command ();
2501 Editor::trim_region_from_edit_cursor ()
2503 if (clicked_regionview == 0) {
2507 boost::shared_ptr<Region> region (clicked_regionview->region());
2510 AudioTimeAxisView *atav;
2512 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2513 if (atav->get_diskstream() != 0) {
2514 speed = atav->get_diskstream()->speed();
2518 begin_reversible_command (_("trim to edit"));
2519 XMLNode &before = region->playlist()->get_state();
2520 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2521 XMLNode &after = region->playlist()->get_state();
2522 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2523 commit_reversible_command ();
2527 Editor::unfreeze_route ()
2529 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2533 clicked_audio_trackview->audio_track()->unfreeze ();
2537 Editor::_freeze_thread (void* arg)
2539 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2540 return static_cast<Editor*>(arg)->freeze_thread ();
2544 Editor::freeze_thread ()
2546 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2551 Editor::freeze_progress_timeout (void *arg)
2553 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2554 return !(current_interthread_info->done || current_interthread_info->cancel);
2558 Editor::freeze_route ()
2560 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2564 InterThreadInfo itt;
2566 if (interthread_progress_window == 0) {
2567 build_interthread_progress_window ();
2570 WindowTitle title(Glib::get_application_name());
2571 title += _("Freeze");
2572 interthread_progress_window->set_title (title.get_string());
2573 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2574 interthread_progress_window->show_all ();
2575 interthread_progress_bar.set_fraction (0.0f);
2576 interthread_progress_label.set_text ("");
2577 interthread_cancel_label.set_text (_("Cancel Freeze"));
2578 current_interthread_info = &itt;
2580 interthread_progress_connection =
2581 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2585 itt.progress = 0.0f;
2587 pthread_attr_t attr;
2588 pthread_attr_init(&attr);
2589 pthread_attr_setstacksize(&attr, 500000);
2591 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2593 pthread_attr_destroy(&attr);
2595 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2597 while (!itt.done && !itt.cancel) {
2598 gtk_main_iteration ();
2601 interthread_progress_connection.disconnect ();
2602 interthread_progress_window->hide_all ();
2603 current_interthread_info = 0;
2604 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2608 Editor::bounce_range_selection ()
2610 if (selection->time.empty()) {
2614 TrackSelection views = selection->tracks;
2616 nframes_t start = selection->time[clicked_selection].start;
2617 nframes_t end = selection->time[clicked_selection].end;
2618 nframes_t cnt = end - start + 1;
2620 begin_reversible_command (_("bounce range"));
2622 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2624 AudioTimeAxisView* atv;
2626 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2630 boost::shared_ptr<Playlist> playlist;
2632 if ((playlist = atv->playlist()) == 0) {
2636 InterThreadInfo itt;
2640 itt.progress = false;
2642 XMLNode &before = playlist->get_state();
2643 atv->audio_track()->bounce_range (start, cnt, itt);
2644 XMLNode &after = playlist->get_state();
2645 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2648 commit_reversible_command ();
2664 Editor::cut_copy (CutCopyOp op)
2666 /* only cancel selection if cut/copy is successful.*/
2678 opname = _("clear");
2682 cut_buffer->clear ();
2684 switch (current_mouse_mode()) {
2686 if (!selection->regions.empty() || !selection->points.empty()) {
2688 begin_reversible_command (opname + _(" objects"));
2690 if (!selection->regions.empty()) {
2692 cut_copy_regions (op);
2695 selection->clear_regions ();
2699 if (!selection->points.empty()) {
2700 cut_copy_points (op);
2703 selection->clear_points ();
2707 commit_reversible_command ();
2712 if (!selection->time.empty()) {
2714 begin_reversible_command (opname + _(" range"));
2715 cut_copy_ranges (op);
2716 commit_reversible_command ();
2719 selection->clear_time ();
2731 Editor::cut_copy_points (CutCopyOp op)
2733 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2735 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2738 atv->cut_copy_clear_objects (selection->points, op);
2743 struct PlaylistState {
2744 boost::shared_ptr<Playlist> playlist;
2748 struct lt_playlist {
2749 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2750 return a.playlist < b.playlist;
2754 struct PlaylistMapping {
2756 boost::shared_ptr<AudioPlaylist> pl;
2758 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2762 Editor::cut_copy_regions (CutCopyOp op)
2764 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2765 a map when we want ordered access to both elements. i think.
2768 vector<PlaylistMapping> pmap;
2770 nframes_t first_position = max_frames;
2772 set<PlaylistState, lt_playlist> freezelist;
2773 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2775 /* get ordering correct before we cut/copy */
2777 selection->regions.sort_by_position_and_track ();
2779 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2781 first_position = min ((*x)->region()->position(), first_position);
2783 if (op == Cut || op == Clear) {
2784 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2788 PlaylistState before;
2789 before.playlist = pl;
2790 before.before = &pl->get_state();
2792 insert_result = freezelist.insert (before);
2794 if (insert_result.second) {
2800 TimeAxisView* tv = &(*x)->get_trackview();
2801 vector<PlaylistMapping>::iterator z;
2803 for (z = pmap.begin(); z != pmap.end(); ++z) {
2804 if ((*z).tv == tv) {
2809 if (z == pmap.end()) {
2810 pmap.push_back (PlaylistMapping (tv));
2814 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2816 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2819 /* impossible, but this handles it for the future */
2823 TimeAxisView& tv = (*x)->get_trackview();
2824 boost::shared_ptr<AudioPlaylist> npl;
2825 RegionSelection::iterator tmp;
2830 vector<PlaylistMapping>::iterator z;
2832 for (z = pmap.begin(); z != pmap.end(); ++z) {
2833 if ((*z).tv == &tv) {
2838 assert (z != pmap.end());
2841 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
2848 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
2849 boost::shared_ptr<Region> _xx;
2855 _xx = RegionFactory::create ((*x)->region());
2856 npl->add_region (_xx, (*x)->region()->position() - first_position);
2857 pl->remove_region (((*x)->region()));
2863 /* copy region before adding, so we're not putting same object into two different playlists */
2864 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
2868 pl->remove_region (((*x)->region()));
2875 list<boost::shared_ptr<Playlist> > foo;
2877 /* the pmap is in the same order as the tracks in which selected regions occured */
2879 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2881 foo.push_back ((*i).pl);
2886 cut_buffer->set (foo);
2889 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2890 (*pl).playlist->thaw ();
2891 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2896 Editor::cut_copy_ranges (CutCopyOp op)
2898 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2899 (*i)->cut_copy_clear (*selection, op);
2904 Editor::paste (float times)
2906 paste_internal (edit_cursor->current_frame, times);
2910 Editor::mouse_paste ()
2915 track_canvas.get_pointer (x, y);
2916 track_canvas.window_to_world (x, y, wx, wy);
2917 wx += horizontal_adjustment.get_value();
2918 wy += vertical_adjustment.get_value();
2921 event.type = GDK_BUTTON_RELEASE;
2922 event.button.x = wx;
2923 event.button.y = wy;
2925 nframes_t where = event_frame (&event, 0, 0);
2927 paste_internal (where, 1);
2931 Editor::paste_internal (nframes_t position, float times)
2933 bool commit = false;
2935 if (cut_buffer->empty() || selection->tracks.empty()) {
2939 if (position == max_frames) {
2940 position = edit_cursor->current_frame;
2943 begin_reversible_command (_("paste"));
2945 TrackSelection::iterator i;
2948 /* get everything in the correct order */
2950 sort_track_selection ();
2952 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
2954 /* undo/redo is handled by individual tracks */
2956 if ((*i)->paste (position, times, *cut_buffer, nth)) {
2962 commit_reversible_command ();
2967 Editor::paste_named_selection (float times)
2969 TrackSelection::iterator t;
2971 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
2973 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
2977 TreeModel::iterator i = selected->get_selected();
2978 NamedSelection* ns = (*i)[named_selection_columns.selection];
2980 list<boost::shared_ptr<Playlist> >::iterator chunk;
2981 list<boost::shared_ptr<Playlist> >::iterator tmp;
2983 chunk = ns->playlists.begin();
2985 begin_reversible_command (_("paste chunk"));
2987 sort_track_selection ();
2989 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
2991 AudioTimeAxisView* atv;
2992 boost::shared_ptr<Playlist> pl;
2993 boost::shared_ptr<AudioPlaylist> apl;
2995 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
2999 if ((pl = atv->playlist()) == 0) {
3003 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3010 XMLNode &before = apl->get_state();
3011 apl->paste (*chunk, edit_cursor->current_frame, times);
3012 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3014 if (tmp != ns->playlists.end()) {
3019 commit_reversible_command();
3023 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3025 boost::shared_ptr<Playlist> playlist;
3026 RegionSelection sel = regions; // clear (below) will clear the argument list
3028 begin_reversible_command (_("duplicate region"));
3030 selection->clear_regions ();
3032 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3034 boost::shared_ptr<Region> r ((*i)->region());
3036 TimeAxisView& tv = (*i)->get_time_axis_view();
3037 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3038 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3040 playlist = (*i)->region()->playlist();
3041 XMLNode &before = playlist->get_state();
3042 playlist->duplicate (r, r->last_frame() + 1, times);
3043 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3047 if (latest_regionview) {
3048 selection->add (latest_regionview);
3053 commit_reversible_command ();
3057 Editor::duplicate_selection (float times)
3059 if (selection->time.empty() || selection->tracks.empty()) {
3063 boost::shared_ptr<Playlist> playlist;
3064 vector<boost::shared_ptr<AudioRegion> > new_regions;
3065 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3067 create_region_from_selection (new_regions);
3069 if (new_regions.empty()) {
3073 begin_reversible_command (_("duplicate selection"));
3075 ri = new_regions.begin();
3077 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3078 if ((playlist = (*i)->playlist()) == 0) {
3081 XMLNode &before = playlist->get_state();
3082 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3083 XMLNode &after = playlist->get_state();
3084 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3087 if (ri == new_regions.end()) {
3092 commit_reversible_command ();
3096 Editor::reset_point_selection ()
3098 /* reset all selected points to the relevant default value */
3100 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3102 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3105 atv->reset_objects (selection->points);
3111 Editor::center_playhead ()
3113 float page = canvas_width * frames_per_unit;
3115 center_screen_internal (playhead_cursor->current_frame, page);
3119 Editor::center_edit_cursor ()
3121 float page = canvas_width * frames_per_unit;
3123 center_screen_internal (edit_cursor->current_frame, page);
3127 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3129 begin_reversible_command (_("clear playlist"));
3130 XMLNode &before = playlist->get_state();
3132 XMLNode &after = playlist->get_state();
3133 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3134 commit_reversible_command ();
3138 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3140 boost::shared_ptr<Playlist> playlist;
3142 nframes_t next_distance;
3145 if (use_edit_cursor) {
3146 start = edit_cursor->current_frame;
3151 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3155 if (selection->tracks.empty()) {
3159 begin_reversible_command (_("nudge track"));
3161 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3163 if ((playlist = (*i)->playlist()) == 0) {
3167 XMLNode &before = playlist->get_state();
3168 playlist->nudge_after (start, distance, forwards);
3169 XMLNode &after = playlist->get_state();
3170 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3173 commit_reversible_command ();
3177 Editor::remove_last_capture ()
3179 vector<string> choices;
3186 if (Config->get_verify_remove_last_capture()) {
3187 prompt = _("Do you really want to destroy the last capture?"
3188 "\n(This is destructive and cannot be undone)");
3190 choices.push_back (_("No, do nothing."));
3191 choices.push_back (_("Yes, destroy it."));
3193 Gtkmm2ext::Choice prompter (prompt, choices);
3195 if (prompter.run () == 1) {
3196 session->remove_last_capture ();
3200 session->remove_last_capture();
3205 Editor::normalize_region ()
3211 if (selection->regions.empty()) {
3215 begin_reversible_command (_("normalize"));
3217 track_canvas.get_window()->set_cursor (*wait_cursor);
3220 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3221 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3224 XMLNode &before = arv->region()->get_state();
3225 arv->audio_region()->normalize_to (0.0f);
3226 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3229 commit_reversible_command ();
3230 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3235 Editor::denormalize_region ()
3241 if (selection->regions.empty()) {
3245 begin_reversible_command ("denormalize");
3247 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3248 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3251 XMLNode &before = arv->region()->get_state();
3252 arv->audio_region()->set_scale_amplitude (1.0f);
3253 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3256 commit_reversible_command ();
3261 Editor::reverse_region ()
3267 Reverse rev (*session);
3268 apply_filter (rev, _("reverse regions"));
3272 Editor::apply_filter (AudioFilter& filter, string command)
3274 if (selection->regions.empty()) {
3278 begin_reversible_command (command);
3280 track_canvas.get_window()->set_cursor (*wait_cursor);
3283 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3284 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3288 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3290 RegionSelection::iterator tmp;
3295 if (arv->audio_region()->apply (filter) == 0) {
3297 XMLNode &before = playlist->get_state();
3298 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3299 XMLNode &after = playlist->get_state();
3300 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3308 commit_reversible_command ();
3309 selection->regions.clear ();
3312 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3316 Editor::region_selection_op (void (Region::*pmf)(void))
3318 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3319 Region* region = (*i)->region().get();
3326 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3328 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3329 Region* region = (*i)->region().get();
3330 (region->*pmf)(arg);
3335 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3337 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3338 Region* region = (*i)->region().get();
3344 Editor::external_edit_region ()
3346 if (!clicked_regionview) {
3354 Editor::brush (nframes_t pos)
3356 RegionSelection sel;
3359 if (selection->regions.empty()) {
3360 /* XXX get selection from region list */
3362 sel = selection->regions;
3369 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3370 mouse_brush_insert_region ((*i), pos);
3375 Editor::reset_region_gain_envelopes ()
3377 if (!session || selection->regions.empty()) {
3381 session->begin_reversible_command (_("reset region gain"));
3383 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3384 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3386 AutomationList& alist (arv->audio_region()->envelope());
3387 XMLNode& before (alist.get_state());
3389 arv->audio_region()->set_default_envelope ();
3390 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3394 session->commit_reversible_command ();
3398 Editor::toggle_gain_envelope_visibility ()
3400 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3401 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3403 bool x = region_envelope_visible_item->get_active();
3404 if (x != arv->envelope_visible()) {
3405 arv->set_envelope_visible (x);
3412 Editor::toggle_gain_envelope_active ()
3414 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3415 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3417 bool x = region_envelope_active_item->get_active();
3418 if (x != arv->audio_region()->envelope_active()) {
3419 arv->audio_region()->set_envelope_active (x);
3426 Editor::toggle_region_lock ()
3428 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3429 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3431 bool x = region_lock_item->get_active();
3432 if (x != arv->audio_region()->locked()) {
3433 arv->audio_region()->set_locked (x);
3440 Editor::toggle_region_mute ()
3442 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3443 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3445 bool x = region_mute_item->get_active();
3446 if (x != arv->audio_region()->muted()) {
3447 arv->audio_region()->set_muted (x);
3454 Editor::toggle_region_opaque ()
3456 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3457 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3459 bool x = region_opaque_item->get_active();
3460 if (x != arv->audio_region()->opaque()) {
3461 arv->audio_region()->set_opaque (x);
3468 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3470 begin_reversible_command (_("set fade in shape"));
3472 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3473 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3479 AutomationList& alist = tmp->audio_region()->fade_in();
3480 XMLNode &before = alist.get_state();
3482 tmp->audio_region()->set_fade_in_shape (shape);
3484 XMLNode &after = alist.get_state();
3485 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3488 commit_reversible_command ();
3492 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3494 begin_reversible_command (_("set fade out shape"));
3496 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3497 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3503 AutomationList& alist = tmp->audio_region()->fade_out();
3504 XMLNode &before = alist.get_state();
3506 tmp->audio_region()->set_fade_out_shape (shape);
3508 XMLNode &after = alist.get_state();
3509 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3512 commit_reversible_command ();
3516 Editor::set_fade_in_active (bool yn)
3518 begin_reversible_command (_("set fade in active"));
3520 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3521 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3528 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3530 XMLNode &before = ar->get_state();
3532 ar->set_fade_in_active (yn);
3534 XMLNode &after = ar->get_state();
3535 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3540 Editor::set_fade_out_active (bool yn)
3542 begin_reversible_command (_("set fade out active"));
3544 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3545 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3551 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3553 XMLNode &before = ar->get_state();
3555 ar->set_fade_out_active (yn);
3557 XMLNode &after = ar->get_state();
3558 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3563 /** Update crossfade visibility after its configuration has been changed */
3565 Editor::update_xfade_visibility ()
3567 _xfade_visibility = Config->get_xfades_visible ();
3569 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3570 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3572 if (_xfade_visibility) {
3573 v->show_all_xfades ();
3575 v->hide_all_xfades ();