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 nframes64_t current_page = current_page_frames();
1105 nframes64_t current_leftmost = leftmost_frame;
1106 nframes64_t current_rightmost;
1107 nframes64_t current_center;
1108 nframes64_t new_page;
1109 nframes64_t leftmost_after_zoom = 0;
1111 bool in_track_canvas;
1116 new_page = (nframes_t) floor (canvas_width * nfpu);
1118 switch (zoom_focus) {
1120 leftmost_after_zoom = current_leftmost;
1123 case ZoomFocusRight:
1124 current_rightmost = leftmost_frame + current_page;
1125 if (current_rightmost > new_page) {
1126 leftmost_after_zoom = current_rightmost - new_page;
1128 leftmost_after_zoom = 0;
1132 case ZoomFocusCenter:
1133 current_center = current_leftmost + (current_page/2);
1134 if (current_center > (new_page/2)) {
1135 leftmost_after_zoom = current_center - (new_page / 2);
1137 leftmost_after_zoom = 0;
1141 case ZoomFocusPlayhead:
1142 /* try to keep the playhead in the center */
1143 if (playhead_cursor->current_frame > new_page/2) {
1144 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1146 leftmost_after_zoom = 0;
1150 case ZoomFocusMouse:
1151 /* try to keep the mouse over the same point in the display */
1153 if (!mouse_frame (where, in_track_canvas)) {
1154 /* use playhead instead */
1155 where = playhead_cursor->current_frame;
1157 if (where > new_page/2) {
1158 leftmost_after_zoom = where - (new_page/2);
1160 leftmost_after_zoom = 0;
1165 double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where);
1168 leftmost_after_zoom = 0;
1169 } else if (l > max_frames) {
1170 leftmost_after_zoom = max_frames - new_page;
1172 leftmost_after_zoom = (nframes64_t) l;
1179 /* try to keep the edit cursor in the center */
1180 if (edit_cursor->current_frame > new_page/2) {
1181 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1183 leftmost_after_zoom = 0;
1189 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1191 // begin_reversible_command (_("zoom"));
1192 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1193 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1194 // commit_reversible_command ();
1196 cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl;
1198 reposition_and_zoom (leftmost_after_zoom, nfpu);
1202 Editor::temporal_zoom_selection ()
1204 if (!selection) return;
1206 if (selection->time.empty()) {
1210 nframes_t start = selection->time[clicked_selection].start;
1211 nframes_t end = selection->time[clicked_selection].end;
1213 temporal_zoom_by_frame (start, end, "zoom to selection");
1217 Editor::temporal_zoom_session ()
1219 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1222 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1227 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1229 if (!session) return;
1231 if ((start == 0 && end == 0) || end < start) {
1235 nframes_t range = end - start;
1237 double new_fpu = (double)range / (double)canvas_width;
1240 // while (p2 < new_fpu) {
1245 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1246 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1247 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1249 if (new_leftmost > middle) new_leftmost = 0;
1251 // begin_reversible_command (op);
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::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1262 if (!session) return;
1264 double range_before = frame - leftmost_frame;
1267 new_fpu = frames_per_unit;
1270 new_fpu *= 1.61803399;
1271 range_before *= 1.61803399;
1273 new_fpu = max(1.0,(new_fpu/1.61803399));
1274 range_before /= 1.61803399;
1277 if (new_fpu == frames_per_unit) return;
1279 nframes_t new_leftmost = frame - (nframes_t)range_before;
1281 if (new_leftmost > frame) new_leftmost = 0;
1283 // begin_reversible_command (_("zoom to frame"));
1284 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1285 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1286 // commit_reversible_command ();
1288 reposition_and_zoom (new_leftmost, new_fpu);
1292 Editor::add_location_from_selection ()
1296 if (selection->time.empty()) {
1300 if (session == 0 || clicked_trackview == 0) {
1304 nframes_t start = selection->time[clicked_selection].start;
1305 nframes_t end = selection->time[clicked_selection].end;
1307 session->locations()->next_available_name(rangename,"selection");
1308 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1310 session->begin_reversible_command (_("add marker"));
1311 XMLNode &before = session->locations()->get_state();
1312 session->locations()->add (location, true);
1313 XMLNode &after = session->locations()->get_state();
1314 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1315 session->commit_reversible_command ();
1319 Editor::add_location_from_playhead_cursor ()
1323 nframes_t where = session->audible_frame();
1325 session->locations()->next_available_name(markername,"mark");
1326 Location *location = new Location (where, where, markername, Location::IsMark);
1327 session->begin_reversible_command (_("add marker"));
1328 XMLNode &before = session->locations()->get_state();
1329 session->locations()->add (location, true);
1330 XMLNode &after = session->locations()->get_state();
1331 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1332 session->commit_reversible_command ();
1336 Editor::add_location_from_audio_region ()
1338 if (selection->regions.empty()) {
1342 RegionView* rv = *(selection->regions.begin());
1343 boost::shared_ptr<Region> region = rv->region();
1345 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1346 session->begin_reversible_command (_("add marker"));
1347 XMLNode &before = session->locations()->get_state();
1348 session->locations()->add (location, true);
1349 XMLNode &after = session->locations()->get_state();
1350 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1351 session->commit_reversible_command ();
1355 Editor::amplitude_zoom_step (bool in)
1369 #ifdef FIX_FOR_CANVAS
1370 /* XXX DO SOMETHING */
1379 Editor::delete_sample_forward ()
1384 Editor::delete_sample_backward ()
1389 Editor::delete_screen ()
1396 Editor::search_backwards ()
1402 Editor::search_forwards ()
1410 Editor::jump_forward_to_mark ()
1416 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1419 session->request_locate (location->start(), session->transport_rolling());
1421 session->request_locate (session->current_end_frame());
1426 Editor::jump_backward_to_mark ()
1432 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1435 session->request_locate (location->start(), session->transport_rolling());
1437 session->goto_start ();
1449 if (get_prefix (prefix, was_floating)) {
1450 pos = session->audible_frame ();
1453 pos = (nframes_t) floor (prefix * session->frame_rate ());
1455 pos = (nframes_t) floor (prefix);
1459 session->locations()->next_available_name(markername,"mark");
1460 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1464 Editor::clear_markers ()
1467 session->begin_reversible_command (_("clear markers"));
1468 XMLNode &before = session->locations()->get_state();
1469 session->locations()->clear_markers ();
1470 XMLNode &after = session->locations()->get_state();
1471 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1472 session->commit_reversible_command ();
1477 Editor::clear_ranges ()
1480 session->begin_reversible_command (_("clear ranges"));
1481 XMLNode &before = session->locations()->get_state();
1483 Location * looploc = session->locations()->auto_loop_location();
1484 Location * punchloc = session->locations()->auto_punch_location();
1486 session->locations()->clear_ranges ();
1488 if (looploc) session->locations()->add (looploc);
1489 if (punchloc) session->locations()->add (punchloc);
1491 XMLNode &after = session->locations()->get_state();
1492 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1493 session->commit_reversible_command ();
1498 Editor::clear_locations ()
1500 session->begin_reversible_command (_("clear locations"));
1501 XMLNode &before = session->locations()->get_state();
1502 session->locations()->clear ();
1503 XMLNode &after = session->locations()->get_state();
1504 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1505 session->commit_reversible_command ();
1506 session->locations()->clear ();
1510 Editor::unhide_markers ()
1512 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1513 Location *l = (*i).first;
1514 if (l->is_hidden() && l->is_mark()) {
1515 l->set_hidden(false, this);
1521 Editor::unhide_ranges ()
1523 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1524 Location *l = (*i).first;
1525 if (l->is_hidden() && l->is_range_marker()) {
1526 l->set_hidden(false, this);
1531 /* INSERT/REPLACE */
1534 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1540 AudioTimeAxisView *atv = 0;
1541 boost::shared_ptr<Playlist> playlist;
1543 track_canvas.window_to_world (x, y, wx, wy);
1544 wx += horizontal_adjustment.get_value();
1545 wy += vertical_adjustment.get_value();
1548 event.type = GDK_BUTTON_RELEASE;
1549 event.button.x = wx;
1550 event.button.y = wy;
1552 where = event_frame (&event, &cx, &cy);
1554 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1555 /* clearly outside canvas area */
1559 if ((tv = trackview_by_y_position (cy)) == 0) {
1563 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1567 if ((playlist = atv->playlist()) == 0) {
1573 begin_reversible_command (_("insert dragged region"));
1574 XMLNode &before = playlist->get_state();
1575 playlist->add_region (RegionFactory::create (region), where, 1.0);
1576 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1577 commit_reversible_command ();
1581 Editor::insert_region_list_selection (float times)
1583 RouteTimeAxisView *tv = 0;
1584 boost::shared_ptr<Playlist> playlist;
1586 if (clicked_audio_trackview != 0) {
1587 tv = clicked_audio_trackview;
1588 } else if (!selection->tracks.empty()) {
1589 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1596 if ((playlist = tv->playlist()) == 0) {
1600 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1602 if (selected->count_selected_rows() != 1) {
1606 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1608 /* only one row selected, so rows.begin() is it */
1612 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1614 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1616 begin_reversible_command (_("insert region"));
1617 XMLNode &before = playlist->get_state();
1618 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1619 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1620 commit_reversible_command ();
1624 /* BUILT-IN EFFECTS */
1627 Editor::reverse_selection ()
1632 /* GAIN ENVELOPE EDITING */
1635 Editor::edit_envelope ()
1642 Editor::transition_to_rolling (bool fwd)
1648 switch (Config->get_slave_source()) {
1653 /* transport controlled by the master */
1657 if (session->is_auditioning()) {
1658 session->cancel_audition ();
1662 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1666 Editor::toggle_playback (bool with_abort)
1672 switch (Config->get_slave_source()) {
1677 /* transport controlled by the master */
1681 if (session->is_auditioning()) {
1682 session->cancel_audition ();
1686 if (session->transport_rolling()) {
1687 session->request_stop (with_abort);
1688 if (session->get_play_loop()) {
1689 session->request_play_loop (false);
1692 session->request_transport_speed (1.0f);
1697 Editor::play_from_start ()
1699 session->request_locate (session->current_start_frame(), true);
1703 Editor::play_from_edit_cursor ()
1705 session->request_locate (edit_cursor->current_frame, true);
1709 Editor::play_selection ()
1711 if (selection->time.empty()) {
1715 session->request_play_range (true);
1719 Editor::play_selected_region ()
1721 if (!selection->regions.empty()) {
1722 RegionView *rv = *(selection->regions.begin());
1724 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1729 Editor::loop_selected_region ()
1731 if (!selection->regions.empty()) {
1732 RegionView *rv = *(selection->regions.begin());
1735 if ((tll = transport_loop_location()) != 0) {
1737 tll->set (rv->region()->position(), rv->region()->last_frame());
1739 // enable looping, reposition and start rolling
1741 session->request_play_loop (true);
1742 session->request_locate (tll->start(), false);
1743 session->request_transport_speed (1.0f);
1749 Editor::play_location (Location& location)
1751 if (location.start() <= location.end()) {
1755 session->request_bounded_roll (location.start(), location.end());
1759 Editor::loop_location (Location& location)
1761 if (location.start() <= location.end()) {
1767 if ((tll = transport_loop_location()) != 0) {
1768 tll->set (location.start(), location.end());
1770 // enable looping, reposition and start rolling
1771 session->request_play_loop (true);
1772 session->request_locate (tll->start(), true);
1777 Editor::raise_region ()
1779 selection->foreach_region (&Region::raise);
1783 Editor::raise_region_to_top ()
1785 selection->foreach_region (&Region::raise_to_top);
1789 Editor::lower_region ()
1791 selection->foreach_region (&Region::lower);
1795 Editor::lower_region_to_bottom ()
1797 selection->foreach_region (&Region::lower_to_bottom);
1801 Editor::edit_region ()
1803 if (clicked_regionview == 0) {
1807 clicked_regionview->show_region_editor ();
1811 Editor::rename_region ()
1815 Button ok_button (_("OK"));
1816 Button cancel_button (_("Cancel"));
1818 if (selection->regions.empty()) {
1822 WindowTitle title(Glib::get_application_name());
1823 title += _("Rename Region");
1825 dialog.set_title (title.get_string());
1826 dialog.set_name ("RegionRenameWindow");
1827 dialog.set_size_request (300, -1);
1828 dialog.set_position (Gtk::WIN_POS_MOUSE);
1829 dialog.set_modal (true);
1831 dialog.get_vbox()->set_border_width (10);
1832 dialog.get_vbox()->pack_start (entry);
1833 dialog.get_action_area()->pack_start (ok_button);
1834 dialog.get_action_area()->pack_start (cancel_button);
1836 entry.set_name ("RegionNameDisplay");
1837 ok_button.set_name ("EditorGTKButton");
1838 cancel_button.set_name ("EditorGTKButton");
1840 region_renamed = false;
1842 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1843 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1844 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1851 if (region_renamed) {
1852 (*selection->regions.begin())->region()->set_name (entry.get_text());
1853 redisplay_regions ();
1858 Editor::rename_region_finished (bool status)
1861 region_renamed = status;
1866 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
1868 if (session->is_auditioning()) {
1869 session->cancel_audition ();
1872 // note: some potential for creativity here, because region doesn't
1873 // have to belong to the playlist that Route is handling
1875 // bool was_soloed = route.soloed();
1877 route.set_solo (true, this);
1879 session->request_bounded_roll (region->position(), region->position() + region->length());
1881 /* XXX how to unset the solo state ? */
1885 Editor::audition_selected_region ()
1887 if (!selection->regions.empty()) {
1888 RegionView* rv = *(selection->regions.begin());
1889 session->audition_region (rv->region());
1894 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
1896 session->audition_region (region);
1900 Editor::build_interthread_progress_window ()
1902 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
1904 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1906 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
1907 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
1909 // GTK2FIX: this button needs a modifiable label
1911 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1912 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1914 interthread_cancel_button.add (interthread_cancel_label);
1916 interthread_progress_window->set_default_size (200, 100);
1920 Editor::interthread_cancel_clicked ()
1922 if (current_interthread_info) {
1923 current_interthread_info->cancel = true;
1928 Editor::region_from_selection ()
1930 if (clicked_trackview == 0) {
1934 if (selection->time.empty()) {
1938 nframes_t start = selection->time[clicked_selection].start;
1939 nframes_t end = selection->time[clicked_selection].end;
1941 nframes_t selection_cnt = end - start + 1;
1943 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1944 boost::shared_ptr<AudioRegion> current;
1945 boost::shared_ptr<Region> current_r;
1946 boost::shared_ptr<Playlist> pl;
1948 nframes_t internal_start;
1951 if ((pl = (*i)->playlist()) == 0) {
1955 if ((current_r = pl->top_region_at (start)) == 0) {
1959 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
1960 // FIXME: audio only
1962 internal_start = start - current->position();
1963 session->region_name (new_name, current->name(), true);
1964 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
1970 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
1972 if (selection->time.empty() || selection->tracks.empty()) {
1976 nframes_t start = selection->time[clicked_selection].start;
1977 nframes_t end = selection->time[clicked_selection].end;
1979 sort_track_selection ();
1981 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1983 boost::shared_ptr<AudioRegion> current;
1984 boost::shared_ptr<Region> current_r;
1985 boost::shared_ptr<Playlist> playlist;
1986 nframes_t internal_start;
1989 if ((playlist = (*i)->playlist()) == 0) {
1993 if ((current_r = playlist->top_region_at(start)) == 0) {
1997 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2001 internal_start = start - current->position();
2002 session->region_name (new_name, current->name(), true);
2004 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2009 Editor::split_multichannel_region ()
2011 if (selection->regions.empty()) {
2015 vector<boost::shared_ptr<AudioRegion> > v;
2017 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2019 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
2021 if (!arv || arv->audio_region()->n_channels() < 2) {
2025 (arv)->audio_region()->separate_by_channel (*session, v);
2030 Editor::new_region_from_selection ()
2032 region_from_selection ();
2033 cancel_selection ();
2037 Editor::separate_region_from_selection ()
2039 bool doing_undo = false;
2041 if (selection->time.empty()) {
2045 boost::shared_ptr<Playlist> playlist;
2047 sort_track_selection ();
2049 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2051 AudioTimeAxisView* atv;
2053 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2055 if (atv->is_audio_track()) {
2057 /* no edits to destructive tracks */
2059 if (atv->audio_track()->audio_diskstream()->destructive()) {
2063 if ((playlist = atv->playlist()) != 0) {
2065 begin_reversible_command (_("separate"));
2070 before = &(playlist->get_state());
2072 /* XXX need to consider musical time selections here at some point */
2074 double speed = atv->get_diskstream()->speed();
2076 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2077 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2081 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2087 if (doing_undo) commit_reversible_command ();
2091 Editor::separate_regions_using_location (Location& loc)
2093 bool doing_undo = false;
2095 if (loc.is_mark()) {
2099 boost::shared_ptr<Playlist> playlist;
2101 /* XXX i'm unsure as to whether this should operate on selected tracks only
2102 or the entire enchillada. uncomment the below line to correct the behaviour
2103 (currently set for all tracks)
2106 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2107 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2109 AudioTimeAxisView* atv;
2111 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2113 if (atv->is_audio_track()) {
2115 /* no edits to destructive tracks */
2117 if (atv->audio_track()->audio_diskstream()->destructive()) {
2121 if ((playlist = atv->playlist()) != 0) {
2124 begin_reversible_command (_("separate"));
2128 before = &(playlist->get_state());
2131 /* XXX need to consider musical time selections here at some point */
2133 double speed = atv->get_diskstream()->speed();
2136 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2138 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2144 if (doing_undo) commit_reversible_command ();
2148 Editor::crop_region_to_selection ()
2150 if (selection->time.empty() || selection->tracks.empty()) {
2154 vector<boost::shared_ptr<Playlist> > playlists;
2155 boost::shared_ptr<Playlist> playlist;
2157 sort_track_selection ();
2159 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2161 AudioTimeAxisView* atv;
2163 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2165 if (atv->is_audio_track()) {
2167 /* no edits to destructive tracks */
2169 if (atv->audio_track()->audio_diskstream()->destructive()) {
2173 if ((playlist = atv->playlist()) != 0) {
2174 playlists.push_back (playlist);
2180 if (playlists.empty()) {
2188 begin_reversible_command (_("trim to selection"));
2190 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2192 boost::shared_ptr<Region> region;
2194 start = selection->time.start();
2196 if ((region = (*i)->top_region_at(start)) == 0) {
2200 /* now adjust lengths to that we do the right thing
2201 if the selection extends beyond the region
2204 start = max (start, region->position());
2205 if (max_frames - start < region->length()) {
2206 end = start + region->length() - 1;
2210 end = min (selection->time.end_frame(), end);
2211 cnt = end - start + 1;
2213 XMLNode &before = (*i)->get_state();
2214 region->trim_to (start, cnt, this);
2215 XMLNode &after = (*i)->get_state();
2216 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2219 commit_reversible_command ();
2223 Editor::region_fill_track ()
2227 if (!session || selection->regions.empty()) {
2231 end = session->current_end_frame ();
2233 begin_reversible_command (_("region fill"));
2235 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2237 boost::shared_ptr<Region> region ((*i)->region());
2240 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2244 boost::shared_ptr<Playlist> pl = region->playlist();
2246 if (end <= region->last_frame()) {
2250 double times = (double) (end - region->last_frame()) / (double) region->length();
2256 XMLNode &before = pl->get_state();
2257 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2258 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2261 commit_reversible_command ();
2265 Editor::region_fill_selection ()
2267 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2271 if (selection->time.empty()) {
2276 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2278 if (selected->count_selected_rows() != 1) {
2282 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2283 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2285 nframes_t start = selection->time[clicked_selection].start;
2286 nframes_t end = selection->time[clicked_selection].end;
2288 boost::shared_ptr<Playlist> playlist;
2290 if (selection->tracks.empty()) {
2294 nframes_t selection_length = end - start;
2295 float times = (float)selection_length / region->length();
2297 begin_reversible_command (_("fill selection"));
2299 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2301 if ((playlist = (*i)->playlist()) == 0) {
2305 XMLNode &before = playlist->get_state();
2306 playlist->add_region (RegionFactory::create (region), start, times);
2307 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2310 commit_reversible_command ();
2314 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2317 if (!region->covers (position)) {
2318 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2321 begin_reversible_command (_("set region sync position"));
2322 XMLNode &before = region->playlist()->get_state();
2323 region->set_sync_position (position);
2324 XMLNode &after = region->playlist()->get_state();
2325 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2326 commit_reversible_command ();
2330 Editor::set_region_sync_from_edit_cursor ()
2332 if (clicked_regionview == 0) {
2336 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2337 error << _("Place the edit cursor at the desired sync point") << endmsg;
2341 boost::shared_ptr<Region> region (clicked_regionview->region());
2342 begin_reversible_command (_("set sync from edit cursor"));
2343 XMLNode &before = region->playlist()->get_state();
2344 region->set_sync_position (edit_cursor->current_frame);
2345 XMLNode &after = region->playlist()->get_state();
2346 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2347 commit_reversible_command ();
2351 Editor::remove_region_sync ()
2353 if (clicked_regionview) {
2354 boost::shared_ptr<Region> region (clicked_regionview->region());
2355 begin_reversible_command (_("remove sync"));
2356 XMLNode &before = region->playlist()->get_state();
2357 region->clear_sync_position ();
2358 XMLNode &after = region->playlist()->get_state();
2359 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2360 commit_reversible_command ();
2365 Editor::naturalize ()
2367 if (selection->regions.empty()) {
2370 begin_reversible_command (_("naturalize"));
2371 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2372 XMLNode &before = (*i)->region()->get_state();
2373 (*i)->region()->move_to_natural_position (this);
2374 XMLNode &after = (*i)->region()->get_state();
2375 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2377 commit_reversible_command ();
2381 Editor::align (RegionPoint what)
2383 align_selection (what, edit_cursor->current_frame);
2387 Editor::align_relative (RegionPoint what)
2389 align_selection_relative (what, edit_cursor->current_frame);
2392 struct RegionSortByTime {
2393 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2394 return a->region()->position() < b->region()->position();
2399 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2401 if (selection->regions.empty()) {
2409 list<RegionView*> sorted;
2410 selection->regions.by_position (sorted);
2411 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2415 pos = r->first_frame ();
2419 pos = r->last_frame();
2423 pos = r->adjust_to_sync (r->first_frame());
2427 if (pos > position) {
2428 distance = pos - position;
2431 distance = position - pos;
2435 begin_reversible_command (_("align selection (relative)"));
2437 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2439 boost::shared_ptr<Region> region ((*i)->region());
2441 XMLNode &before = region->playlist()->get_state();
2444 region->set_position (region->position() + distance, this);
2446 region->set_position (region->position() - distance, this);
2449 XMLNode &after = region->playlist()->get_state();
2450 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2454 commit_reversible_command ();
2458 Editor::align_selection (RegionPoint point, nframes_t position)
2460 if (selection->regions.empty()) {
2464 begin_reversible_command (_("align selection"));
2466 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2467 align_region_internal ((*i)->region(), point, position);
2470 commit_reversible_command ();
2474 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2476 begin_reversible_command (_("align region"));
2477 align_region_internal (region, point, position);
2478 commit_reversible_command ();
2482 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2484 XMLNode &before = region->playlist()->get_state();
2488 region->set_position (region->adjust_to_sync (position), this);
2492 if (position > region->length()) {
2493 region->set_position (position - region->length(), this);
2498 region->set_position (position, this);
2502 XMLNode &after = region->playlist()->get_state();
2503 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2507 Editor::trim_region_to_edit_cursor ()
2509 if (clicked_regionview == 0) {
2513 boost::shared_ptr<Region> region (clicked_regionview->region());
2516 AudioTimeAxisView *atav;
2518 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2519 if (atav->get_diskstream() != 0) {
2520 speed = atav->get_diskstream()->speed();
2524 begin_reversible_command (_("trim to edit"));
2525 XMLNode &before = region->playlist()->get_state();
2526 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2527 XMLNode &after = region->playlist()->get_state();
2528 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2529 commit_reversible_command ();
2533 Editor::trim_region_from_edit_cursor ()
2535 if (clicked_regionview == 0) {
2539 boost::shared_ptr<Region> region (clicked_regionview->region());
2542 AudioTimeAxisView *atav;
2544 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2545 if (atav->get_diskstream() != 0) {
2546 speed = atav->get_diskstream()->speed();
2550 begin_reversible_command (_("trim to edit"));
2551 XMLNode &before = region->playlist()->get_state();
2552 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2553 XMLNode &after = region->playlist()->get_state();
2554 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2555 commit_reversible_command ();
2559 Editor::unfreeze_route ()
2561 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2565 clicked_audio_trackview->audio_track()->unfreeze ();
2569 Editor::_freeze_thread (void* arg)
2571 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2572 return static_cast<Editor*>(arg)->freeze_thread ();
2576 Editor::freeze_thread ()
2578 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2583 Editor::freeze_progress_timeout (void *arg)
2585 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2586 return !(current_interthread_info->done || current_interthread_info->cancel);
2590 Editor::freeze_route ()
2592 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2596 InterThreadInfo itt;
2598 if (interthread_progress_window == 0) {
2599 build_interthread_progress_window ();
2602 WindowTitle title(Glib::get_application_name());
2603 title += _("Freeze");
2604 interthread_progress_window->set_title (title.get_string());
2605 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2606 interthread_progress_window->show_all ();
2607 interthread_progress_bar.set_fraction (0.0f);
2608 interthread_progress_label.set_text ("");
2609 interthread_cancel_label.set_text (_("Cancel Freeze"));
2610 current_interthread_info = &itt;
2612 interthread_progress_connection =
2613 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2617 itt.progress = 0.0f;
2619 pthread_attr_t attr;
2620 pthread_attr_init(&attr);
2621 pthread_attr_setstacksize(&attr, 500000);
2623 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2625 pthread_attr_destroy(&attr);
2627 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2629 while (!itt.done && !itt.cancel) {
2630 gtk_main_iteration ();
2633 interthread_progress_connection.disconnect ();
2634 interthread_progress_window->hide_all ();
2635 current_interthread_info = 0;
2636 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2640 Editor::bounce_range_selection ()
2642 if (selection->time.empty()) {
2646 TrackSelection views = selection->tracks;
2648 nframes_t start = selection->time[clicked_selection].start;
2649 nframes_t end = selection->time[clicked_selection].end;
2650 nframes_t cnt = end - start + 1;
2652 begin_reversible_command (_("bounce range"));
2654 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2656 AudioTimeAxisView* atv;
2658 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2662 boost::shared_ptr<Playlist> playlist;
2664 if ((playlist = atv->playlist()) == 0) {
2668 InterThreadInfo itt;
2672 itt.progress = false;
2674 XMLNode &before = playlist->get_state();
2675 atv->audio_track()->bounce_range (start, cnt, itt);
2676 XMLNode &after = playlist->get_state();
2677 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2680 commit_reversible_command ();
2696 Editor::cut_copy (CutCopyOp op)
2698 /* only cancel selection if cut/copy is successful.*/
2710 opname = _("clear");
2714 cut_buffer->clear ();
2716 switch (current_mouse_mode()) {
2718 if (!selection->regions.empty() || !selection->points.empty()) {
2720 begin_reversible_command (opname + _(" objects"));
2722 if (!selection->regions.empty()) {
2724 cut_copy_regions (op);
2727 selection->clear_regions ();
2731 if (!selection->points.empty()) {
2732 cut_copy_points (op);
2735 selection->clear_points ();
2739 commit_reversible_command ();
2744 if (!selection->time.empty()) {
2746 begin_reversible_command (opname + _(" range"));
2747 cut_copy_ranges (op);
2748 commit_reversible_command ();
2751 selection->clear_time ();
2763 Editor::cut_copy_points (CutCopyOp op)
2765 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2767 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2770 atv->cut_copy_clear_objects (selection->points, op);
2775 struct PlaylistState {
2776 boost::shared_ptr<Playlist> playlist;
2780 struct lt_playlist {
2781 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2782 return a.playlist < b.playlist;
2786 struct PlaylistMapping {
2788 boost::shared_ptr<AudioPlaylist> pl;
2790 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2794 Editor::cut_copy_regions (CutCopyOp op)
2796 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2797 a map when we want ordered access to both elements. i think.
2800 vector<PlaylistMapping> pmap;
2802 nframes_t first_position = max_frames;
2804 set<PlaylistState, lt_playlist> freezelist;
2805 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2807 /* get ordering correct before we cut/copy */
2809 selection->regions.sort_by_position_and_track ();
2811 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2813 first_position = min ((*x)->region()->position(), first_position);
2815 if (op == Cut || op == Clear) {
2816 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2820 PlaylistState before;
2821 before.playlist = pl;
2822 before.before = &pl->get_state();
2824 insert_result = freezelist.insert (before);
2826 if (insert_result.second) {
2832 TimeAxisView* tv = &(*x)->get_trackview();
2833 vector<PlaylistMapping>::iterator z;
2835 for (z = pmap.begin(); z != pmap.end(); ++z) {
2836 if ((*z).tv == tv) {
2841 if (z == pmap.end()) {
2842 pmap.push_back (PlaylistMapping (tv));
2846 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2848 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2851 /* impossible, but this handles it for the future */
2855 TimeAxisView& tv = (*x)->get_trackview();
2856 boost::shared_ptr<AudioPlaylist> npl;
2857 RegionSelection::iterator tmp;
2862 vector<PlaylistMapping>::iterator z;
2864 for (z = pmap.begin(); z != pmap.end(); ++z) {
2865 if ((*z).tv == &tv) {
2870 assert (z != pmap.end());
2873 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
2880 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
2881 boost::shared_ptr<Region> _xx;
2887 _xx = RegionFactory::create ((*x)->region());
2888 npl->add_region (_xx, (*x)->region()->position() - first_position);
2889 pl->remove_region (((*x)->region()));
2895 /* copy region before adding, so we're not putting same object into two different playlists */
2896 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
2900 pl->remove_region (((*x)->region()));
2907 list<boost::shared_ptr<Playlist> > foo;
2909 /* the pmap is in the same order as the tracks in which selected regions occured */
2911 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2913 foo.push_back ((*i).pl);
2918 cut_buffer->set (foo);
2921 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2922 (*pl).playlist->thaw ();
2923 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2928 Editor::cut_copy_ranges (CutCopyOp op)
2930 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2931 (*i)->cut_copy_clear (*selection, op);
2936 Editor::paste (float times)
2938 paste_internal (edit_cursor->current_frame, times);
2942 Editor::mouse_paste ()
2947 if (!mouse_frame (where, ignored)) {
2952 paste_internal (where, 1);
2956 Editor::paste_internal (nframes_t position, float times)
2958 bool commit = false;
2960 if (cut_buffer->empty() || selection->tracks.empty()) {
2964 if (position == max_frames) {
2965 position = edit_cursor->current_frame;
2968 begin_reversible_command (_("paste"));
2970 TrackSelection::iterator i;
2973 /* get everything in the correct order */
2975 sort_track_selection ();
2977 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
2979 /* undo/redo is handled by individual tracks */
2981 if ((*i)->paste (position, times, *cut_buffer, nth)) {
2987 commit_reversible_command ();
2992 Editor::paste_named_selection (float times)
2994 TrackSelection::iterator t;
2996 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
2998 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3002 TreeModel::iterator i = selected->get_selected();
3003 NamedSelection* ns = (*i)[named_selection_columns.selection];
3005 list<boost::shared_ptr<Playlist> >::iterator chunk;
3006 list<boost::shared_ptr<Playlist> >::iterator tmp;
3008 chunk = ns->playlists.begin();
3010 begin_reversible_command (_("paste chunk"));
3012 sort_track_selection ();
3014 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3016 AudioTimeAxisView* atv;
3017 boost::shared_ptr<Playlist> pl;
3018 boost::shared_ptr<AudioPlaylist> apl;
3020 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3024 if ((pl = atv->playlist()) == 0) {
3028 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3035 XMLNode &before = apl->get_state();
3036 apl->paste (*chunk, edit_cursor->current_frame, times);
3037 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3039 if (tmp != ns->playlists.end()) {
3044 commit_reversible_command();
3048 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3050 boost::shared_ptr<Playlist> playlist;
3051 RegionSelection sel = regions; // clear (below) will clear the argument list
3053 begin_reversible_command (_("duplicate region"));
3055 selection->clear_regions ();
3057 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3059 boost::shared_ptr<Region> r ((*i)->region());
3061 TimeAxisView& tv = (*i)->get_time_axis_view();
3062 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3063 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3065 playlist = (*i)->region()->playlist();
3066 XMLNode &before = playlist->get_state();
3067 playlist->duplicate (r, r->last_frame() + 1, times);
3068 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3072 if (latest_regionview) {
3073 selection->add (latest_regionview);
3078 commit_reversible_command ();
3082 Editor::duplicate_selection (float times)
3084 if (selection->time.empty() || selection->tracks.empty()) {
3088 boost::shared_ptr<Playlist> playlist;
3089 vector<boost::shared_ptr<AudioRegion> > new_regions;
3090 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3092 create_region_from_selection (new_regions);
3094 if (new_regions.empty()) {
3098 begin_reversible_command (_("duplicate selection"));
3100 ri = new_regions.begin();
3102 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3103 if ((playlist = (*i)->playlist()) == 0) {
3106 XMLNode &before = playlist->get_state();
3107 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3108 XMLNode &after = playlist->get_state();
3109 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3112 if (ri == new_regions.end()) {
3117 commit_reversible_command ();
3121 Editor::reset_point_selection ()
3123 /* reset all selected points to the relevant default value */
3125 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3127 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3130 atv->reset_objects (selection->points);
3136 Editor::center_playhead ()
3138 float page = canvas_width * frames_per_unit;
3140 center_screen_internal (playhead_cursor->current_frame, page);
3144 Editor::center_edit_cursor ()
3146 float page = canvas_width * frames_per_unit;
3148 center_screen_internal (edit_cursor->current_frame, page);
3152 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3154 begin_reversible_command (_("clear playlist"));
3155 XMLNode &before = playlist->get_state();
3157 XMLNode &after = playlist->get_state();
3158 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3159 commit_reversible_command ();
3163 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3165 boost::shared_ptr<Playlist> playlist;
3167 nframes_t next_distance;
3170 if (use_edit_cursor) {
3171 start = edit_cursor->current_frame;
3176 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3180 if (selection->tracks.empty()) {
3184 begin_reversible_command (_("nudge track"));
3186 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3188 if ((playlist = (*i)->playlist()) == 0) {
3192 XMLNode &before = playlist->get_state();
3193 playlist->nudge_after (start, distance, forwards);
3194 XMLNode &after = playlist->get_state();
3195 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3198 commit_reversible_command ();
3202 Editor::remove_last_capture ()
3204 vector<string> choices;
3211 if (Config->get_verify_remove_last_capture()) {
3212 prompt = _("Do you really want to destroy the last capture?"
3213 "\n(This is destructive and cannot be undone)");
3215 choices.push_back (_("No, do nothing."));
3216 choices.push_back (_("Yes, destroy it."));
3218 Gtkmm2ext::Choice prompter (prompt, choices);
3220 if (prompter.run () == 1) {
3221 session->remove_last_capture ();
3225 session->remove_last_capture();
3230 Editor::normalize_region ()
3236 if (selection->regions.empty()) {
3240 begin_reversible_command (_("normalize"));
3242 track_canvas.get_window()->set_cursor (*wait_cursor);
3245 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3246 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3249 XMLNode &before = arv->region()->get_state();
3250 arv->audio_region()->normalize_to (0.0f);
3251 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3254 commit_reversible_command ();
3255 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3260 Editor::denormalize_region ()
3266 if (selection->regions.empty()) {
3270 begin_reversible_command ("denormalize");
3272 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3273 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3276 XMLNode &before = arv->region()->get_state();
3277 arv->audio_region()->set_scale_amplitude (1.0f);
3278 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3281 commit_reversible_command ();
3286 Editor::reverse_region ()
3292 Reverse rev (*session);
3293 apply_filter (rev, _("reverse regions"));
3297 Editor::apply_filter (AudioFilter& filter, string command)
3299 if (selection->regions.empty()) {
3303 begin_reversible_command (command);
3305 track_canvas.get_window()->set_cursor (*wait_cursor);
3308 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3309 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3313 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3315 RegionSelection::iterator tmp;
3320 if (arv->audio_region()->apply (filter) == 0) {
3322 XMLNode &before = playlist->get_state();
3323 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3324 XMLNode &after = playlist->get_state();
3325 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3333 commit_reversible_command ();
3334 selection->regions.clear ();
3337 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3341 Editor::region_selection_op (void (Region::*pmf)(void))
3343 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3344 Region* region = (*i)->region().get();
3351 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3353 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3354 Region* region = (*i)->region().get();
3355 (region->*pmf)(arg);
3360 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3362 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3363 Region* region = (*i)->region().get();
3369 Editor::external_edit_region ()
3371 if (!clicked_regionview) {
3379 Editor::brush (nframes_t pos)
3381 RegionSelection sel;
3384 if (selection->regions.empty()) {
3385 /* XXX get selection from region list */
3387 sel = selection->regions;
3394 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3395 mouse_brush_insert_region ((*i), pos);
3400 Editor::reset_region_gain_envelopes ()
3402 if (!session || selection->regions.empty()) {
3406 session->begin_reversible_command (_("reset region gain"));
3408 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3409 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3411 AutomationList& alist (arv->audio_region()->envelope());
3412 XMLNode& before (alist.get_state());
3414 arv->audio_region()->set_default_envelope ();
3415 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3419 session->commit_reversible_command ();
3423 Editor::toggle_gain_envelope_visibility ()
3425 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3426 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3428 bool x = region_envelope_visible_item->get_active();
3429 if (x != arv->envelope_visible()) {
3430 arv->set_envelope_visible (x);
3437 Editor::toggle_gain_envelope_active ()
3439 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3440 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3442 bool x = region_envelope_active_item->get_active();
3443 if (x != arv->audio_region()->envelope_active()) {
3444 arv->audio_region()->set_envelope_active (x);
3451 Editor::toggle_region_lock ()
3453 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3454 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3456 bool x = region_lock_item->get_active();
3457 if (x != arv->audio_region()->locked()) {
3458 arv->audio_region()->set_locked (x);
3465 Editor::toggle_region_mute ()
3467 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3468 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3470 bool x = region_mute_item->get_active();
3471 if (x != arv->audio_region()->muted()) {
3472 arv->audio_region()->set_muted (x);
3479 Editor::toggle_region_opaque ()
3481 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3482 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3484 bool x = region_opaque_item->get_active();
3485 if (x != arv->audio_region()->opaque()) {
3486 arv->audio_region()->set_opaque (x);
3493 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3495 begin_reversible_command (_("set fade in shape"));
3497 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3498 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3504 AutomationList& alist = tmp->audio_region()->fade_in();
3505 XMLNode &before = alist.get_state();
3507 tmp->audio_region()->set_fade_in_shape (shape);
3509 XMLNode &after = alist.get_state();
3510 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3513 commit_reversible_command ();
3517 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3519 begin_reversible_command (_("set fade out shape"));
3521 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3522 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3528 AutomationList& alist = tmp->audio_region()->fade_out();
3529 XMLNode &before = alist.get_state();
3531 tmp->audio_region()->set_fade_out_shape (shape);
3533 XMLNode &after = alist.get_state();
3534 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3537 commit_reversible_command ();
3541 Editor::set_fade_in_active (bool yn)
3543 begin_reversible_command (_("set fade in active"));
3545 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3546 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3553 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3555 XMLNode &before = ar->get_state();
3557 ar->set_fade_in_active (yn);
3559 XMLNode &after = ar->get_state();
3560 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3565 Editor::set_fade_out_active (bool yn)
3567 begin_reversible_command (_("set fade out active"));
3569 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3570 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3576 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3578 XMLNode &before = ar->get_state();
3580 ar->set_fade_out_active (yn);
3582 XMLNode &after = ar->get_state();
3583 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3588 /** Update crossfade visibility after its configuration has been changed */
3590 Editor::update_xfade_visibility ()
3592 _xfade_visibility = Config->get_xfades_visible ();
3594 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3595 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3597 if (_xfade_visibility) {
3598 v->show_all_xfades ();
3600 v->hide_all_xfades ();