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"));
119 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
121 RegionSelection::iterator tmp;
126 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
128 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
130 _new_regionviews_show_envelope = arv->envelope_visible();
133 XMLNode &before = pl->get_state();
134 pl->split_region ((*a)->region(), where);
135 XMLNode &after = pl->get_state();
136 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
142 commit_reversible_command ();
143 _new_regionviews_show_envelope = false;
147 Editor::remove_clicked_region ()
149 if (clicked_routeview == 0 || clicked_regionview == 0) {
153 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
155 begin_reversible_command (_("remove region"));
156 XMLNode &before = playlist->get_state();
157 playlist->remove_region (clicked_regionview->region());
158 XMLNode &after = playlist->get_state();
159 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
160 commit_reversible_command ();
164 Editor::destroy_clicked_region ()
166 uint32_t selected = selection->regions.size();
168 if (!session || !selected) {
172 vector<string> choices;
175 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
176 It cannot be undone\n\
177 Do you really want to destroy %1 ?"),
179 _("these regions") : _("this region")));
181 choices.push_back (_("No, do nothing."));
184 choices.push_back (_("Yes, destroy them."));
186 choices.push_back (_("Yes, destroy it."));
189 Gtkmm2ext::Choice prompter (prompt, choices);
191 if (prompter.run() == 0) { /* first choice */
196 list<boost::shared_ptr<Region> > r;
198 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
199 r.push_back ((*i)->region());
202 session->destroy_regions (r);
206 boost::shared_ptr<Region>
207 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
210 boost::shared_ptr<Region> region;
213 if (selection->time.start () == selection->time.end_frame ()) {
215 /* no current selection-> is there a selected regionview? */
217 if (selection->regions.empty()) {
223 if (!selection->regions.empty()) {
225 rv = *(selection->regions.begin());
226 (*tv) = &rv->get_time_axis_view();
227 region = rv->region();
229 } else if (!selection->tracks.empty()) {
231 (*tv) = selection->tracks.front();
233 RouteTimeAxisView* rtv;
235 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
236 boost::shared_ptr<Playlist> pl;
238 if ((pl = rtv->playlist()) == 0) {
242 region = pl->top_region_at (start);
250 Editor::extend_selection_to_end_of_region (bool next)
253 boost::shared_ptr<Region> region;
256 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
260 if (region && selection->time.start () == selection->time.end_frame ()) {
261 start = region->position();
263 start = selection->time.start ();
266 /* Try to leave the selection with the same route if possible */
268 if ((tv = selection->time.track) == 0) {
272 begin_reversible_command (_("extend selection"));
273 selection->set (tv, start, region->position() + region->length());
274 commit_reversible_command ();
278 Editor::extend_selection_to_start_of_region (bool previous)
281 boost::shared_ptr<Region> region;
284 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
288 if (region && selection->time.start () == selection->time.end_frame ()) {
289 end = region->position() + region->length();
291 end = selection->time.end_frame ();
294 /* Try to leave the selection with the same route if possible */
296 if ((tv = selection->time.track) == 0) {
300 begin_reversible_command (_("extend selection"));
301 selection->set (tv, region->position(), end);
302 commit_reversible_command ();
307 Editor::nudge_forward (bool next)
310 nframes_t next_distance;
312 if (!session) return;
314 if (!selection->regions.empty()) {
316 begin_reversible_command (_("nudge forward"));
318 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
319 boost::shared_ptr<Region> r ((*i)->region());
321 distance = get_nudge_distance (r->position(), next_distance);
324 distance = next_distance;
327 XMLNode &before = r->playlist()->get_state();
328 r->set_position (r->position() + distance, this);
329 XMLNode &after = r->playlist()->get_state();
330 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
333 commit_reversible_command ();
336 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
337 session->request_locate (playhead_cursor->current_frame + distance);
342 Editor::nudge_backward (bool next)
345 nframes_t next_distance;
347 if (!session) return;
349 if (!selection->regions.empty()) {
351 begin_reversible_command (_("nudge forward"));
353 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
354 boost::shared_ptr<Region> r ((*i)->region());
356 distance = get_nudge_distance (r->position(), next_distance);
359 distance = next_distance;
362 XMLNode &before = r->playlist()->get_state();
364 if (r->position() > distance) {
365 r->set_position (r->position() - distance, this);
367 r->set_position (0, this);
369 XMLNode &after = r->playlist()->get_state();
370 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
373 commit_reversible_command ();
377 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
379 if (playhead_cursor->current_frame > distance) {
380 session->request_locate (playhead_cursor->current_frame - distance);
382 session->goto_start();
388 Editor::nudge_forward_capture_offset ()
392 if (!session) return;
394 if (!selection->regions.empty()) {
396 begin_reversible_command (_("nudge forward"));
398 distance = session->worst_output_latency();
400 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
401 boost::shared_ptr<Region> r ((*i)->region());
403 XMLNode &before = r->playlist()->get_state();
404 r->set_position (r->position() + distance, this);
405 XMLNode &after = r->playlist()->get_state();
406 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
409 commit_reversible_command ();
415 Editor::nudge_backward_capture_offset ()
419 if (!session) return;
421 if (!selection->regions.empty()) {
423 begin_reversible_command (_("nudge forward"));
425 distance = session->worst_output_latency();
427 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
428 boost::shared_ptr<Region> r ((*i)->region());
430 XMLNode &before = r->playlist()->get_state();
432 if (r->position() > distance) {
433 r->set_position (r->position() - distance, this);
435 r->set_position (0, this);
437 XMLNode &after = r->playlist()->get_state();
438 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
441 commit_reversible_command ();
448 Editor::move_to_start ()
450 session->goto_start ();
454 Editor::move_to_end ()
457 session->request_locate (session->current_end_frame());
461 Editor::build_region_boundary_cache ()
464 vector<RegionPoint> interesting_points;
465 boost::shared_ptr<Region> r;
466 TrackViewList tracks;
469 region_boundary_cache.clear ();
476 case SnapToRegionStart:
477 interesting_points.push_back (Start);
479 case SnapToRegionEnd:
480 interesting_points.push_back (End);
482 case SnapToRegionSync:
483 interesting_points.push_back (SyncPoint);
485 case SnapToRegionBoundary:
486 interesting_points.push_back (Start);
487 interesting_points.push_back (End);
490 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
495 TimeAxisView *ontrack = 0;
498 if (!selection->tracks.empty()) {
499 tlist = selection->tracks;
504 while (pos < session->current_end_frame() && !at_end) {
507 nframes_t lpos = max_frames;
509 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
511 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
513 /* move to next point type */
520 rpos = r->first_frame();
523 rpos = r->last_frame();
526 rpos = r->adjust_to_sync (r->first_frame());
533 RouteTimeAxisView *rtav;
535 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
536 if (rtav->get_diskstream() != 0) {
537 speed = rtav->get_diskstream()->speed();
541 rpos = track_frame_to_session_frame (rpos, speed);
547 /* prevent duplicates, but we don't use set<> because we want to be able
551 vector<nframes_t>::iterator ri;
553 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
559 if (ri == region_boundary_cache.end()) {
560 region_boundary_cache.push_back (rpos);
567 /* finally sort to be sure that the order is correct */
569 sort (region_boundary_cache.begin(), region_boundary_cache.end());
572 boost::shared_ptr<Region>
573 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
575 TrackViewList::iterator i;
576 nframes_t closest = max_frames;
577 boost::shared_ptr<Region> ret;
581 nframes_t track_frame;
582 RouteTimeAxisView *rtav;
584 for (i = tracks.begin(); i != tracks.end(); ++i) {
587 boost::shared_ptr<Region> r;
590 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
591 if (rtav->get_diskstream()!=0)
592 track_speed = rtav->get_diskstream()->speed();
595 track_frame = session_frame_to_track_frame(frame, track_speed);
597 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
603 rpos = r->first_frame ();
607 rpos = r->last_frame ();
611 rpos = r->adjust_to_sync (r->first_frame());
614 // rpos is a "track frame", converting it to "session frame"
615 rpos = track_frame_to_session_frame(rpos, track_speed);
618 distance = rpos - frame;
620 distance = frame - rpos;
623 if (distance < closest) {
635 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
637 boost::shared_ptr<Region> r;
638 nframes_t pos = cursor->current_frame;
644 TimeAxisView *ontrack = 0;
646 // so we don't find the current region again..
650 if (!selection->tracks.empty()) {
652 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
654 } else if (clicked_axisview) {
657 t.push_back (clicked_axisview);
659 r = find_next_region (pos, point, dir, t, &ontrack);
663 r = find_next_region (pos, point, dir, track_views, &ontrack);
672 pos = r->first_frame ();
676 pos = r->last_frame ();
680 pos = r->adjust_to_sync (r->first_frame());
685 RouteTimeAxisView *rtav;
687 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
688 if (rtav->get_diskstream() != 0) {
689 speed = rtav->get_diskstream()->speed();
693 pos = track_frame_to_session_frame(pos, speed);
695 if (cursor == playhead_cursor) {
696 session->request_locate (pos);
698 cursor->set_position (pos);
703 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
705 cursor_to_region_point (cursor, point, 1);
709 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
711 cursor_to_region_point (cursor, point, -1);
715 Editor::cursor_to_selection_start (Cursor *cursor)
718 switch (mouse_mode) {
720 if (!selection->regions.empty()) {
721 pos = selection->regions.start();
726 if (!selection->time.empty()) {
727 pos = selection->time.start ();
735 if (cursor == playhead_cursor) {
736 session->request_locate (pos);
738 cursor->set_position (pos);
743 Editor::cursor_to_selection_end (Cursor *cursor)
747 switch (mouse_mode) {
749 if (!selection->regions.empty()) {
750 pos = selection->regions.end_frame();
755 if (!selection->time.empty()) {
756 pos = selection->time.end_frame ();
764 if (cursor == playhead_cursor) {
765 session->request_locate (pos);
767 cursor->set_position (pos);
772 Editor::scroll_playhead (bool forward)
774 nframes_t pos = playhead_cursor->current_frame;
775 nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
778 if (pos == max_frames) {
782 if (pos < max_frames - delta) {
801 session->request_locate (pos);
805 Editor::playhead_backward ()
812 if (get_prefix (prefix, was_floating)) {
816 cnt = (nframes_t) floor (prefix * session->frame_rate ());
818 cnt = (nframes_t) prefix;
822 pos = playhead_cursor->current_frame;
824 if ((nframes_t) pos < cnt) {
830 /* XXX this is completely insane. with the current buffering
831 design, we'll force a complete track buffer flush and
832 reload, just to move 1 sample !!!
835 session->request_locate (pos);
839 Editor::playhead_forward ()
846 if (get_prefix (prefix, was_floating)) {
850 cnt = (nframes_t) floor (prefix * session->frame_rate ());
852 cnt = (nframes_t) floor (prefix);
856 pos = playhead_cursor->current_frame;
858 /* XXX this is completely insane. with the current buffering
859 design, we'll force a complete track buffer flush and
860 reload, just to move 1 sample !!!
863 session->request_locate (pos+cnt);
867 Editor::cursor_align (bool playhead_to_edit)
869 if (playhead_to_edit) {
871 session->request_locate (edit_cursor->current_frame);
874 edit_cursor->set_position (playhead_cursor->current_frame);
879 Editor::edit_cursor_backward ()
886 if (get_prefix (prefix, was_floating)) {
890 cnt = (nframes_t) floor (prefix * session->frame_rate ());
892 cnt = (nframes_t) prefix;
896 pos = edit_cursor->current_frame;
898 if ((nframes_t) pos < cnt) {
904 edit_cursor->set_position (pos);
908 Editor::edit_cursor_forward ()
915 if (get_prefix (prefix, was_floating)) {
919 cnt = (nframes_t) floor (prefix * session->frame_rate ());
921 cnt = (nframes_t) floor (prefix);
925 pos = edit_cursor->current_frame;
926 edit_cursor->set_position (pos+cnt);
930 Editor::goto_frame ()
936 if (get_prefix (prefix, was_floating)) {
941 frame = (nframes_t) floor (prefix * session->frame_rate());
943 frame = (nframes_t) floor (prefix);
946 session->request_locate (frame);
950 Editor::scroll_backward (float pages)
953 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
958 if (get_prefix (prefix, was_floating)) {
959 cnt = (nframes_t) floor (pages * one_page);
962 cnt = (nframes_t) floor (prefix * session->frame_rate());
964 cnt = (nframes_t) floor (prefix * one_page);
968 if (leftmost_frame < cnt) {
971 frame = leftmost_frame - cnt;
974 reset_x_origin (frame);
978 Editor::scroll_forward (float pages)
981 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
986 if (get_prefix (prefix, was_floating)) {
987 cnt = (nframes_t) floor (pages * one_page);
990 cnt = (nframes_t) floor (prefix * session->frame_rate());
992 cnt = (nframes_t) floor (prefix * one_page);
996 if (max_frames - cnt < leftmost_frame) {
997 frame = max_frames - cnt;
999 frame = leftmost_frame + cnt;
1002 reset_x_origin (frame);
1006 Editor::scroll_tracks_down ()
1012 if (get_prefix (prefix, was_floating)) {
1015 cnt = (int) floor (prefix);
1018 double vert_value = vertical_adjustment.get_value() + (cnt *
1019 vertical_adjustment.get_page_size());
1020 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1021 vert_value = vertical_adjustment.get_upper() - canvas_height;
1023 vertical_adjustment.set_value (vert_value);
1027 Editor::scroll_tracks_up ()
1033 if (get_prefix (prefix, was_floating)) {
1036 cnt = (int) floor (prefix);
1039 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1043 Editor::scroll_tracks_down_line ()
1046 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1047 double vert_value = adj->get_value() + 20;
1049 if (vert_value>adj->get_upper() - canvas_height) {
1050 vert_value = adj->get_upper() - canvas_height;
1052 adj->set_value (vert_value);
1056 Editor::scroll_tracks_up_line ()
1058 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1059 adj->set_value (adj->get_value() - 20);
1065 Editor::temporal_zoom_step (bool coarser)
1067 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1071 nfpu = frames_per_unit;
1076 nfpu = max(1.0,(nfpu/1.61803399));
1079 temporal_zoom (nfpu);
1083 Editor::temporal_zoom (gdouble fpu)
1085 if (!session) return;
1087 nframes_t current_page = current_page_frames();
1088 nframes_t current_leftmost = leftmost_frame;
1089 nframes_t current_rightmost;
1090 nframes_t current_center;
1092 nframes_t leftmost_after_zoom = 0;
1097 new_page = (nframes_t) floor (canvas_width * nfpu);
1099 switch (zoom_focus) {
1101 leftmost_after_zoom = current_leftmost;
1104 case ZoomFocusRight:
1105 current_rightmost = leftmost_frame + current_page;
1106 if (current_rightmost > new_page) {
1107 leftmost_after_zoom = current_rightmost - new_page;
1109 leftmost_after_zoom = 0;
1113 case ZoomFocusCenter:
1114 current_center = current_leftmost + (current_page/2);
1115 if (current_center > (new_page/2)) {
1116 leftmost_after_zoom = current_center - (new_page / 2);
1118 leftmost_after_zoom = 0;
1122 case ZoomFocusPlayhead:
1123 /* try to keep the playhead in the center */
1124 if (playhead_cursor->current_frame > new_page/2) {
1125 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1127 leftmost_after_zoom = 0;
1132 /* try to keep the edit cursor in the center */
1133 if (edit_cursor->current_frame > new_page/2) {
1134 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1136 leftmost_after_zoom = 0;
1142 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1144 // begin_reversible_command (_("zoom"));
1145 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1146 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1147 // commit_reversible_command ();
1149 reposition_and_zoom (leftmost_after_zoom, nfpu);
1153 Editor::temporal_zoom_selection ()
1155 if (!selection) return;
1157 if (selection->time.empty()) {
1161 nframes_t start = selection->time[clicked_selection].start;
1162 nframes_t end = selection->time[clicked_selection].end;
1164 temporal_zoom_by_frame (start, end, "zoom to selection");
1168 Editor::temporal_zoom_session ()
1170 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1173 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1178 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1180 if (!session) return;
1182 if ((start == 0 && end == 0) || end < start) {
1186 nframes_t range = end - start;
1188 double new_fpu = (double)range / (double)canvas_width;
1191 // while (p2 < new_fpu) {
1196 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1197 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1198 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1200 if (new_leftmost > middle) new_leftmost = 0;
1202 // begin_reversible_command (op);
1203 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1204 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1205 // commit_reversible_command ();
1207 reposition_and_zoom (new_leftmost, new_fpu);
1211 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1213 if (!session) return;
1215 double range_before = frame - leftmost_frame;
1218 new_fpu = frames_per_unit;
1221 new_fpu *= 1.61803399;
1222 range_before *= 1.61803399;
1224 new_fpu = max(1.0,(new_fpu/1.61803399));
1225 range_before /= 1.61803399;
1228 if (new_fpu == frames_per_unit) return;
1230 nframes_t new_leftmost = frame - (nframes_t)range_before;
1232 if (new_leftmost > frame) new_leftmost = 0;
1234 // begin_reversible_command (_("zoom to frame"));
1235 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1236 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1237 // commit_reversible_command ();
1239 reposition_and_zoom (new_leftmost, new_fpu);
1243 Editor::add_location_from_selection ()
1247 if (selection->time.empty()) {
1251 if (session == 0 || clicked_axisview == 0) {
1255 nframes_t start = selection->time[clicked_selection].start;
1256 nframes_t end = selection->time[clicked_selection].end;
1258 session->locations()->next_available_name(rangename,"selection");
1259 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1261 session->begin_reversible_command (_("add marker"));
1262 XMLNode &before = session->locations()->get_state();
1263 session->locations()->add (location, true);
1264 XMLNode &after = session->locations()->get_state();
1265 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1266 session->commit_reversible_command ();
1270 Editor::add_location_from_playhead_cursor ()
1274 nframes_t where = session->audible_frame();
1276 session->locations()->next_available_name(markername,"mark");
1277 Location *location = new Location (where, where, markername, Location::IsMark);
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_audio_region ()
1289 if (selection->regions.empty()) {
1293 RegionView* rv = *(selection->regions.begin());
1294 boost::shared_ptr<Region> region = rv->region();
1296 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1297 session->begin_reversible_command (_("add marker"));
1298 XMLNode &before = session->locations()->get_state();
1299 session->locations()->add (location, true);
1300 XMLNode &after = session->locations()->get_state();
1301 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1302 session->commit_reversible_command ();
1306 Editor::amplitude_zoom_step (bool in)
1320 #ifdef FIX_FOR_CANVAS
1321 /* XXX DO SOMETHING */
1330 Editor::delete_sample_forward ()
1335 Editor::delete_sample_backward ()
1340 Editor::delete_screen ()
1347 Editor::search_backwards ()
1353 Editor::search_forwards ()
1361 Editor::jump_forward_to_mark ()
1367 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1370 session->request_locate (location->start(), session->transport_rolling());
1372 session->request_locate (session->current_end_frame());
1377 Editor::jump_backward_to_mark ()
1383 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1386 session->request_locate (location->start(), session->transport_rolling());
1388 session->goto_start ();
1400 if (get_prefix (prefix, was_floating)) {
1401 pos = session->audible_frame ();
1404 pos = (nframes_t) floor (prefix * session->frame_rate ());
1406 pos = (nframes_t) floor (prefix);
1410 session->locations()->next_available_name(markername,"mark");
1411 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1415 Editor::clear_markers ()
1418 session->begin_reversible_command (_("clear markers"));
1419 XMLNode &before = session->locations()->get_state();
1420 session->locations()->clear_markers ();
1421 XMLNode &after = session->locations()->get_state();
1422 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1423 session->commit_reversible_command ();
1428 Editor::clear_ranges ()
1431 session->begin_reversible_command (_("clear ranges"));
1432 XMLNode &before = session->locations()->get_state();
1434 Location * looploc = session->locations()->auto_loop_location();
1435 Location * punchloc = session->locations()->auto_punch_location();
1437 session->locations()->clear_ranges ();
1439 if (looploc) session->locations()->add (looploc);
1440 if (punchloc) session->locations()->add (punchloc);
1442 XMLNode &after = session->locations()->get_state();
1443 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1444 session->commit_reversible_command ();
1449 Editor::clear_locations ()
1451 session->begin_reversible_command (_("clear locations"));
1452 XMLNode &before = session->locations()->get_state();
1453 session->locations()->clear ();
1454 XMLNode &after = session->locations()->get_state();
1455 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1456 session->commit_reversible_command ();
1457 session->locations()->clear ();
1461 Editor::unhide_markers ()
1463 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1464 Location *l = (*i).first;
1465 if (l->is_hidden() && l->is_mark()) {
1466 l->set_hidden(false, this);
1472 Editor::unhide_ranges ()
1474 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1475 Location *l = (*i).first;
1476 if (l->is_hidden() && l->is_range_marker()) {
1477 l->set_hidden(false, this);
1482 /* INSERT/REPLACE */
1485 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1491 RouteTimeAxisView *rtv = 0;
1492 boost::shared_ptr<Playlist> playlist;
1494 track_canvas.window_to_world (x, y, wx, wy);
1495 wx += horizontal_adjustment.get_value();
1496 wy += vertical_adjustment.get_value();
1499 event.type = GDK_BUTTON_RELEASE;
1500 event.button.x = wx;
1501 event.button.y = wy;
1503 where = event_frame (&event, &cx, &cy);
1505 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1506 /* clearly outside canvas area */
1510 if ((tv = trackview_by_y_position (cy)) == 0) {
1514 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) == 0) {
1518 if ((playlist = rtv->playlist()) == 0) {
1524 begin_reversible_command (_("insert dragged region"));
1525 XMLNode &before = playlist->get_state();
1526 playlist->add_region (RegionFactory::create (region), where, 1.0);
1527 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1528 commit_reversible_command ();
1532 Editor::insert_region_list_selection (float times)
1534 RouteTimeAxisView *tv = 0;
1535 boost::shared_ptr<Playlist> playlist;
1537 if (clicked_routeview != 0) {
1538 tv = clicked_routeview;
1539 } else if (!selection->tracks.empty()) {
1540 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1547 if ((playlist = tv->playlist()) == 0) {
1551 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1553 if (selected->count_selected_rows() != 1) {
1557 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1559 /* only one row selected, so rows.begin() is it */
1563 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1565 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1567 begin_reversible_command (_("insert region"));
1568 XMLNode &before = playlist->get_state();
1569 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1570 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1571 commit_reversible_command ();
1575 /* BUILT-IN EFFECTS */
1578 Editor::reverse_selection ()
1583 /* GAIN ENVELOPE EDITING */
1586 Editor::edit_envelope ()
1593 Editor::transition_to_rolling (bool fwd)
1599 switch (Config->get_slave_source()) {
1604 /* transport controlled by the master */
1608 if (session->is_auditioning()) {
1609 session->cancel_audition ();
1613 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1617 Editor::toggle_playback (bool with_abort)
1623 switch (Config->get_slave_source()) {
1628 /* transport controlled by the master */
1632 if (session->is_auditioning()) {
1633 session->cancel_audition ();
1637 if (session->transport_rolling()) {
1638 session->request_stop (with_abort);
1639 if (session->get_play_loop()) {
1640 session->request_play_loop (false);
1643 session->request_transport_speed (1.0f);
1648 Editor::play_from_start ()
1650 session->request_locate (session->current_start_frame(), true);
1654 Editor::play_from_edit_cursor ()
1656 session->request_locate (edit_cursor->current_frame, true);
1660 Editor::play_selection ()
1662 if (selection->time.empty()) {
1666 session->request_play_range (true);
1670 Editor::play_selected_region ()
1672 if (!selection->regions.empty()) {
1673 RegionView *rv = *(selection->regions.begin());
1675 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1680 Editor::loop_selected_region ()
1682 if (!selection->regions.empty()) {
1683 RegionView *rv = *(selection->regions.begin());
1686 if ((tll = transport_loop_location()) != 0) {
1688 tll->set (rv->region()->position(), rv->region()->last_frame());
1690 // enable looping, reposition and start rolling
1692 session->request_play_loop (true);
1693 session->request_locate (tll->start(), false);
1694 session->request_transport_speed (1.0f);
1700 Editor::play_location (Location& location)
1702 if (location.start() <= location.end()) {
1706 session->request_bounded_roll (location.start(), location.end());
1710 Editor::loop_location (Location& location)
1712 if (location.start() <= location.end()) {
1718 if ((tll = transport_loop_location()) != 0) {
1719 tll->set (location.start(), location.end());
1721 // enable looping, reposition and start rolling
1722 session->request_play_loop (true);
1723 session->request_locate (tll->start(), true);
1728 Editor::raise_region ()
1730 selection->foreach_region (&Region::raise);
1734 Editor::raise_region_to_top ()
1736 selection->foreach_region (&Region::raise_to_top);
1740 Editor::lower_region ()
1742 selection->foreach_region (&Region::lower);
1746 Editor::lower_region_to_bottom ()
1748 selection->foreach_region (&Region::lower_to_bottom);
1752 Editor::edit_region ()
1754 if (clicked_regionview == 0) {
1758 clicked_regionview->show_region_editor ();
1762 Editor::rename_region ()
1766 Button ok_button (_("OK"));
1767 Button cancel_button (_("Cancel"));
1769 if (selection->regions.empty()) {
1773 WindowTitle title(Glib::get_application_name());
1774 title += _("Rename Region");
1776 dialog.set_title (title.get_string());
1777 dialog.set_name ("RegionRenameWindow");
1778 dialog.set_size_request (300, -1);
1779 dialog.set_position (Gtk::WIN_POS_MOUSE);
1780 dialog.set_modal (true);
1782 dialog.get_vbox()->set_border_width (10);
1783 dialog.get_vbox()->pack_start (entry);
1784 dialog.get_action_area()->pack_start (ok_button);
1785 dialog.get_action_area()->pack_start (cancel_button);
1787 entry.set_name ("RegionNameDisplay");
1788 ok_button.set_name ("EditorGTKButton");
1789 cancel_button.set_name ("EditorGTKButton");
1791 region_renamed = false;
1793 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1794 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1795 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1802 if (region_renamed) {
1803 (*selection->regions.begin())->region()->set_name (entry.get_text());
1804 redisplay_regions ();
1809 Editor::rename_region_finished (bool status)
1812 region_renamed = status;
1817 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
1819 if (session->is_auditioning()) {
1820 session->cancel_audition ();
1823 // note: some potential for creativity here, because region doesn't
1824 // have to belong to the playlist that Route is handling
1826 // bool was_soloed = route.soloed();
1828 route.set_solo (true, this);
1830 session->request_bounded_roll (region->position(), region->position() + region->length());
1832 /* XXX how to unset the solo state ? */
1836 Editor::audition_selected_region ()
1838 if (!selection->regions.empty()) {
1839 RegionView* rv = *(selection->regions.begin());
1840 session->audition_region (rv->region());
1845 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
1847 session->audition_region (region);
1851 Editor::build_interthread_progress_window ()
1853 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
1855 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1857 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
1858 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
1860 // GTK2FIX: this button needs a modifiable label
1862 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1863 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1865 interthread_cancel_button.add (interthread_cancel_label);
1867 interthread_progress_window->set_default_size (200, 100);
1871 Editor::interthread_cancel_clicked ()
1873 if (current_interthread_info) {
1874 current_interthread_info->cancel = true;
1879 Editor::region_from_selection ()
1881 if (clicked_axisview == 0) {
1885 if (selection->time.empty()) {
1889 nframes_t start = selection->time[clicked_selection].start;
1890 nframes_t end = selection->time[clicked_selection].end;
1892 nframes_t selection_cnt = end - start + 1;
1894 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1895 boost::shared_ptr<AudioRegion> current;
1896 boost::shared_ptr<Region> current_r;
1897 boost::shared_ptr<Playlist> pl;
1899 nframes_t internal_start;
1902 if ((pl = (*i)->playlist()) == 0) {
1906 if ((current_r = pl->top_region_at (start)) == 0) {
1910 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
1911 assert(current); // FIXME
1913 internal_start = start - current->position();
1914 session->region_name (new_name, current->name(), true);
1915 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
1921 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
1923 if (selection->time.empty() || selection->tracks.empty()) {
1927 nframes_t start = selection->time[clicked_selection].start;
1928 nframes_t end = selection->time[clicked_selection].end;
1930 sort_track_selection ();
1932 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1934 boost::shared_ptr<AudioRegion> current;
1935 boost::shared_ptr<Region> current_r;
1936 boost::shared_ptr<Playlist> playlist;
1937 nframes_t internal_start;
1940 if ((playlist = (*i)->playlist()) == 0) {
1944 if ((current_r = playlist->top_region_at(start)) == 0) {
1948 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
1952 internal_start = start - current->position();
1953 session->region_name (new_name, current->name(), true);
1955 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
1960 Editor::split_multichannel_region ()
1962 if (selection->regions.empty()) {
1966 vector<boost::shared_ptr<AudioRegion> > v;
1968 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
1970 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
1972 if (!arv || arv->audio_region()->n_channels() < 2) {
1976 (arv)->audio_region()->separate_by_channel (*session, v);
1981 Editor::new_region_from_selection ()
1983 region_from_selection ();
1984 cancel_selection ();
1988 Editor::separate_region_from_selection ()
1992 bool doing_undo = false;
1994 if (selection->time.empty()) {
1998 boost::shared_ptr<Playlist> playlist;
2000 sort_track_selection ();
2002 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2004 RouteTimeAxisView* rtv;
2006 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2008 Track* t = dynamic_cast<Track*>(rtv->track());
2010 if (t != 0 && ! t->diskstream()->destructive()) {
2012 if ((playlist = rtv->playlist()) != 0) {
2014 begin_reversible_command (_("separate"));
2020 before = &(playlist->get_state());
2022 /* XXX need to consider musical time selections here at some point */
2024 double speed = t->diskstream()->speed();
2026 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2027 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2031 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2037 if (doing_undo) commit_reversible_command ();
2041 Editor::separate_regions_using_location (Location& loc)
2045 bool doing_undo = false;
2047 if (loc.is_mark()) {
2051 boost::shared_ptr<Playlist> playlist;
2053 /* XXX i'm unsure as to whether this should operate on selected tracks only
2054 or the entire enchillada. uncomment the below line to correct the behaviour
2055 (currently set for all tracks)
2058 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2059 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2061 RouteTimeAxisView* rtv;
2063 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2065 Track* t = dynamic_cast<Track*>(rtv->track());
2067 if (t != 0 && ! t->diskstream()->destructive()) {
2069 if ((playlist = rtv->playlist()) != 0) {
2073 begin_reversible_command (_("separate"));
2077 before = &(playlist->get_state());
2080 /* XXX need to consider musical time selections here at some point */
2082 double speed = rtv->get_diskstream()->speed();
2085 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2087 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2093 if (doing_undo) commit_reversible_command ();
2097 Editor::crop_region_to_selection ()
2099 if (selection->time.empty() || selection->tracks.empty()) {
2103 vector<boost::shared_ptr<Playlist> > playlists;
2104 boost::shared_ptr<Playlist> playlist;
2106 sort_track_selection ();
2108 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2110 RouteTimeAxisView* rtv;
2112 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2114 Track* t = dynamic_cast<Track*>(rtv->track());
2116 if (t != 0 && ! t->diskstream()->destructive()) {
2118 if ((playlist = rtv->playlist()) != 0) {
2119 playlists.push_back (playlist);
2125 if (playlists.empty()) {
2133 begin_reversible_command (_("trim to selection"));
2135 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2137 boost::shared_ptr<Region> region;
2139 start = selection->time.start();
2141 if ((region = (*i)->top_region_at(start)) == 0) {
2145 /* now adjust lengths to that we do the right thing
2146 if the selection extends beyond the region
2149 start = max (start, region->position());
2150 if (max_frames - start < region->length()) {
2151 end = start + region->length() - 1;
2155 end = min (selection->time.end_frame(), end);
2156 cnt = end - start + 1;
2158 XMLNode &before = (*i)->get_state();
2159 region->trim_to (start, cnt, this);
2160 XMLNode &after = (*i)->get_state();
2161 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2164 commit_reversible_command ();
2168 Editor::region_fill_track ()
2172 if (!session || selection->regions.empty()) {
2176 end = session->current_end_frame ();
2178 begin_reversible_command (_("region fill"));
2180 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2182 boost::shared_ptr<Region> region ((*i)->region());
2185 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2188 boost::shared_ptr<Playlist> pl = region->playlist();
2190 if (end <= region->last_frame()) {
2194 double times = (double) (end - region->last_frame()) / (double) region->length();
2200 XMLNode &before = pl->get_state();
2201 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2202 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2205 commit_reversible_command ();
2209 Editor::region_fill_selection ()
2211 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2215 if (selection->time.empty()) {
2220 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2222 if (selected->count_selected_rows() != 1) {
2226 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2227 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2229 nframes_t start = selection->time[clicked_selection].start;
2230 nframes_t end = selection->time[clicked_selection].end;
2232 boost::shared_ptr<Playlist> playlist;
2234 if (selection->tracks.empty()) {
2238 nframes_t selection_length = end - start;
2239 float times = (float)selection_length / region->length();
2241 begin_reversible_command (_("fill selection"));
2243 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2245 if ((playlist = (*i)->playlist()) == 0) {
2249 XMLNode &before = playlist->get_state();
2250 playlist->add_region (RegionFactory::create (region), start, times);
2251 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2254 commit_reversible_command ();
2258 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2261 if (!region->covers (position)) {
2262 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2265 begin_reversible_command (_("set region sync position"));
2266 XMLNode &before = region->playlist()->get_state();
2267 region->set_sync_position (position);
2268 XMLNode &after = region->playlist()->get_state();
2269 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2270 commit_reversible_command ();
2274 Editor::set_region_sync_from_edit_cursor ()
2276 if (clicked_regionview == 0) {
2280 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2281 error << _("Place the edit cursor at the desired sync point") << endmsg;
2285 boost::shared_ptr<Region> region (clicked_regionview->region());
2286 begin_reversible_command (_("set sync from edit cursor"));
2287 XMLNode &before = region->playlist()->get_state();
2288 region->set_sync_position (edit_cursor->current_frame);
2289 XMLNode &after = region->playlist()->get_state();
2290 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2291 commit_reversible_command ();
2295 Editor::remove_region_sync ()
2297 if (clicked_regionview) {
2298 boost::shared_ptr<Region> region (clicked_regionview->region());
2299 begin_reversible_command (_("remove sync"));
2300 XMLNode &before = region->playlist()->get_state();
2301 region->clear_sync_position ();
2302 XMLNode &after = region->playlist()->get_state();
2303 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2304 commit_reversible_command ();
2309 Editor::naturalize ()
2311 if (selection->regions.empty()) {
2314 begin_reversible_command (_("naturalize"));
2315 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2316 XMLNode &before = (*i)->region()->get_state();
2317 (*i)->region()->move_to_natural_position (this);
2318 XMLNode &after = (*i)->region()->get_state();
2319 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2321 commit_reversible_command ();
2325 Editor::align (RegionPoint what)
2327 align_selection (what, edit_cursor->current_frame);
2331 Editor::align_relative (RegionPoint what)
2333 align_selection_relative (what, edit_cursor->current_frame);
2336 struct RegionSortByTime {
2337 bool operator() (const RegionView* a, const RegionView* b) {
2338 return a->region()->position() < b->region()->position();
2343 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2345 if (selection->regions.empty()) {
2353 list<RegionView*> sorted;
2354 selection->regions.by_position (sorted);
2355 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2359 pos = r->first_frame ();
2363 pos = r->last_frame();
2367 pos = r->adjust_to_sync (r->first_frame());
2371 if (pos > position) {
2372 distance = pos - position;
2375 distance = position - pos;
2379 begin_reversible_command (_("align selection (relative)"));
2381 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2383 boost::shared_ptr<Region> region ((*i)->region());
2385 XMLNode &before = region->playlist()->get_state();
2388 region->set_position (region->position() + distance, this);
2390 region->set_position (region->position() - distance, this);
2393 XMLNode &after = region->playlist()->get_state();
2394 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2398 commit_reversible_command ();
2402 Editor::align_selection (RegionPoint point, nframes_t position)
2404 if (selection->regions.empty()) {
2408 begin_reversible_command (_("align selection"));
2410 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2411 align_region_internal ((*i)->region(), point, position);
2414 commit_reversible_command ();
2418 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2420 begin_reversible_command (_("align region"));
2421 align_region_internal (region, point, position);
2422 commit_reversible_command ();
2426 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2428 XMLNode &before = region->playlist()->get_state();
2432 region->set_position (region->adjust_to_sync (position), this);
2436 if (position > region->length()) {
2437 region->set_position (position - region->length(), this);
2442 region->set_position (position, this);
2446 XMLNode &after = region->playlist()->get_state();
2447 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2451 Editor::trim_region_to_edit_cursor ()
2453 if (clicked_regionview == 0) {
2457 boost::shared_ptr<Region> region (clicked_regionview->region());
2460 RouteTimeAxisView *rtav;
2462 if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
2463 if (rtav->get_diskstream() != 0) {
2464 speed = rtav->get_diskstream()->speed();
2468 begin_reversible_command (_("trim to edit"));
2469 XMLNode &before = region->playlist()->get_state();
2470 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2471 XMLNode &after = region->playlist()->get_state();
2472 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2473 commit_reversible_command ();
2477 Editor::trim_region_from_edit_cursor ()
2479 if (clicked_regionview == 0) {
2483 boost::shared_ptr<Region> region (clicked_regionview->region());
2486 RouteTimeAxisView *rtav;
2488 if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
2489 if (rtav->get_diskstream() != 0) {
2490 speed = rtav->get_diskstream()->speed();
2494 begin_reversible_command (_("trim to edit"));
2495 XMLNode &before = region->playlist()->get_state();
2496 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2497 XMLNode &after = region->playlist()->get_state();
2498 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2499 commit_reversible_command ();
2503 Editor::unfreeze_route ()
2505 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2509 clicked_routeview->track()->unfreeze ();
2513 Editor::_freeze_thread (void* arg)
2515 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2516 return static_cast<Editor*>(arg)->freeze_thread ();
2520 Editor::freeze_thread ()
2522 clicked_routeview->audio_track()->freeze (*current_interthread_info);
2527 Editor::freeze_progress_timeout (void *arg)
2529 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2530 return !(current_interthread_info->done || current_interthread_info->cancel);
2534 Editor::freeze_route ()
2536 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2540 InterThreadInfo itt;
2542 if (interthread_progress_window == 0) {
2543 build_interthread_progress_window ();
2546 WindowTitle title(Glib::get_application_name());
2547 title += _("Freeze");
2548 interthread_progress_window->set_title (title.get_string());
2549 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2550 interthread_progress_window->show_all ();
2551 interthread_progress_bar.set_fraction (0.0f);
2552 interthread_progress_label.set_text ("");
2553 interthread_cancel_label.set_text (_("Cancel Freeze"));
2554 current_interthread_info = &itt;
2556 interthread_progress_connection =
2557 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2561 itt.progress = 0.0f;
2563 pthread_attr_t attr;
2564 pthread_attr_init(&attr);
2565 pthread_attr_setstacksize(&attr, 500000);
2567 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2569 pthread_attr_destroy(&attr);
2571 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2573 while (!itt.done && !itt.cancel) {
2574 gtk_main_iteration ();
2577 interthread_progress_connection.disconnect ();
2578 interthread_progress_window->hide_all ();
2579 current_interthread_info = 0;
2580 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2584 Editor::bounce_range_selection ()
2586 if (selection->time.empty()) {
2590 TrackSelection views = selection->tracks;
2592 nframes_t start = selection->time[clicked_selection].start;
2593 nframes_t end = selection->time[clicked_selection].end;
2594 nframes_t cnt = end - start + 1;
2596 begin_reversible_command (_("bounce range"));
2598 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2600 RouteTimeAxisView* rtv;
2602 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
2606 boost::shared_ptr<Playlist> playlist;
2608 if ((playlist = rtv->playlist()) == 0) {
2612 InterThreadInfo itt;
2616 itt.progress = false;
2618 XMLNode &before = playlist->get_state();
2619 rtv->track()->bounce_range (start, cnt, itt);
2620 XMLNode &after = playlist->get_state();
2621 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2624 commit_reversible_command ();
2640 Editor::cut_copy (CutCopyOp op)
2642 /* only cancel selection if cut/copy is successful.*/
2654 opname = _("clear");
2658 cut_buffer->clear ();
2660 switch (current_mouse_mode()) {
2662 if (!selection->regions.empty() || !selection->points.empty()) {
2664 begin_reversible_command (opname + _(" objects"));
2666 if (!selection->regions.empty()) {
2668 cut_copy_regions (op);
2671 selection->clear_regions ();
2675 if (!selection->points.empty()) {
2676 cut_copy_points (op);
2679 selection->clear_points ();
2683 commit_reversible_command ();
2688 if (!selection->time.empty()) {
2690 begin_reversible_command (opname + _(" range"));
2691 cut_copy_ranges (op);
2692 commit_reversible_command ();
2695 selection->clear_time ();
2707 Editor::cut_copy_points (CutCopyOp op)
2709 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2711 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2714 atv->cut_copy_clear_objects (selection->points, op);
2719 struct PlaylistState {
2720 boost::shared_ptr<Playlist> playlist;
2724 struct lt_playlist {
2725 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2726 return a.playlist < b.playlist;
2730 struct PlaylistMapping {
2732 boost::shared_ptr<Playlist> pl;
2734 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2738 Editor::cut_copy_regions (CutCopyOp op)
2740 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2741 a map when we want ordered access to both elements. i think.
2744 vector<PlaylistMapping> pmap;
2746 nframes_t first_position = max_frames;
2748 set<PlaylistState, lt_playlist> freezelist;
2749 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2751 /* get ordering correct before we cut/copy */
2753 selection->regions.sort_by_position_and_track ();
2755 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2757 first_position = min ((*x)->region()->position(), first_position);
2759 if (op == Cut || op == Clear) {
2760 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
2764 PlaylistState before;
2765 before.playlist = pl;
2766 before.before = &pl->get_state();
2768 insert_result = freezelist.insert (before);
2770 if (insert_result.second) {
2776 TimeAxisView* tv = &(*x)->get_trackview();
2777 vector<PlaylistMapping>::iterator z;
2779 for (z = pmap.begin(); z != pmap.end(); ++z) {
2780 if ((*z).tv == tv) {
2785 if (z == pmap.end()) {
2786 pmap.push_back (PlaylistMapping (tv));
2790 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2792 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
2795 /* impossible, but this handles it for the future */
2799 TimeAxisView& tv = (*x)->get_trackview();
2800 boost::shared_ptr<Playlist> npl;
2801 RegionSelection::iterator tmp;
2806 vector<PlaylistMapping>::iterator z;
2808 for (z = pmap.begin(); z != pmap.end(); ++z) {
2809 if ((*z).tv == &tv) {
2814 assert (z != pmap.end());
2817 npl = PlaylistFactory::create (pl->data_type(), *session, "cutlist", true);
2824 boost::shared_ptr<Region> r = (*x)->region();
2825 boost::shared_ptr<Region> _xx;
2831 _xx = RegionFactory::create (r);
2832 npl->add_region (_xx, r->position() - first_position);
2833 pl->remove_region (r);
2837 /* copy region before adding, so we're not putting same object into two different playlists */
2838 npl->add_region (RegionFactory::create (r), r->position() - first_position);
2842 pl->remove_region (r);
2849 list<boost::shared_ptr<Playlist> > foo;
2851 /* the pmap is in the same order as the tracks in which selected regions occured */
2853 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2855 foo.push_back ((*i).pl);
2860 cut_buffer->set (foo);
2863 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2864 (*pl).playlist->thaw ();
2865 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2870 Editor::cut_copy_ranges (CutCopyOp op)
2872 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2873 (*i)->cut_copy_clear (*selection, op);
2878 Editor::paste (float times)
2880 paste_internal (edit_cursor->current_frame, times);
2884 Editor::mouse_paste ()
2889 track_canvas.get_pointer (x, y);
2890 track_canvas.window_to_world (x, y, wx, wy);
2891 wx += horizontal_adjustment.get_value();
2892 wy += vertical_adjustment.get_value();
2895 event.type = GDK_BUTTON_RELEASE;
2896 event.button.x = wx;
2897 event.button.y = wy;
2899 nframes_t where = event_frame (&event, 0, 0);
2901 paste_internal (where, 1);
2905 Editor::paste_internal (nframes_t position, float times)
2907 bool commit = false;
2909 if (cut_buffer->empty() || selection->tracks.empty()) {
2913 if (position == max_frames) {
2914 position = edit_cursor->current_frame;
2917 begin_reversible_command (_("paste"));
2919 TrackSelection::iterator i;
2922 /* get everything in the correct order */
2924 sort_track_selection ();
2926 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
2928 /* undo/redo is handled by individual tracks */
2930 if ((*i)->paste (position, times, *cut_buffer, nth)) {
2936 commit_reversible_command ();
2941 Editor::paste_named_selection (float times)
2943 TrackSelection::iterator t;
2945 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
2947 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
2951 TreeModel::iterator i = selected->get_selected();
2952 NamedSelection* ns = (*i)[named_selection_columns.selection];
2954 list<boost::shared_ptr<Playlist> >::iterator chunk;
2955 list<boost::shared_ptr<Playlist> >::iterator tmp;
2957 chunk = ns->playlists.begin();
2959 begin_reversible_command (_("paste chunk"));
2961 sort_track_selection ();
2963 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
2965 RouteTimeAxisView* rtv;
2966 boost::shared_ptr<Playlist> pl;
2967 boost::shared_ptr<AudioPlaylist> apl;
2969 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*t)) == 0) {
2973 if ((pl = rtv->playlist()) == 0) {
2977 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
2984 XMLNode &before = apl->get_state();
2985 apl->paste (*chunk, edit_cursor->current_frame, times);
2986 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
2988 if (tmp != ns->playlists.end()) {
2993 commit_reversible_command();
2997 Editor::duplicate_some_regions (RegionSelection& regions, float times)
2999 boost::shared_ptr<Playlist> playlist;
3000 RegionSelection sel = regions; // clear (below) will clear the argument list
3002 begin_reversible_command (_("duplicate region"));
3004 selection->clear_regions ();
3006 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3008 boost::shared_ptr<Region> r ((*i)->region());
3010 TimeAxisView& tv = (*i)->get_time_axis_view();
3011 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3012 sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3014 playlist = (*i)->region()->playlist();
3015 XMLNode &before = playlist->get_state();
3016 playlist->duplicate (r, r->last_frame(), times);
3017 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3021 if (latest_regionview) {
3022 selection->add (latest_regionview);
3027 commit_reversible_command ();
3031 Editor::duplicate_selection (float times)
3033 if (selection->time.empty() || selection->tracks.empty()) {
3037 boost::shared_ptr<Playlist> playlist;
3038 vector<boost::shared_ptr<AudioRegion> > new_regions;
3039 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3041 create_region_from_selection (new_regions);
3043 if (new_regions.empty()) {
3047 begin_reversible_command (_("duplicate selection"));
3049 ri = new_regions.begin();
3051 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3052 if ((playlist = (*i)->playlist()) == 0) {
3055 XMLNode &before = playlist->get_state();
3056 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3057 XMLNode &after = playlist->get_state();
3058 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3061 if (ri == new_regions.end()) {
3066 commit_reversible_command ();
3070 Editor::reset_point_selection ()
3072 /* reset all selected points to the relevant default value */
3074 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3076 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3079 atv->reset_objects (selection->points);
3085 Editor::center_playhead ()
3087 float page = canvas_width * frames_per_unit;
3089 center_screen_internal (playhead_cursor->current_frame, page);
3093 Editor::center_edit_cursor ()
3095 float page = canvas_width * frames_per_unit;
3097 center_screen_internal (edit_cursor->current_frame, page);
3101 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3103 begin_reversible_command (_("clear playlist"));
3104 XMLNode &before = playlist->get_state();
3106 XMLNode &after = playlist->get_state();
3107 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3108 commit_reversible_command ();
3112 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3114 boost::shared_ptr<Playlist> playlist;
3116 nframes_t next_distance;
3119 if (use_edit_cursor) {
3120 start = edit_cursor->current_frame;
3125 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3129 if (selection->tracks.empty()) {
3133 begin_reversible_command (_("nudge track"));
3135 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3137 if ((playlist = (*i)->playlist()) == 0) {
3141 XMLNode &before = playlist->get_state();
3142 playlist->nudge_after (start, distance, forwards);
3143 XMLNode &after = playlist->get_state();
3144 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3147 commit_reversible_command ();
3151 Editor::remove_last_capture ()
3153 vector<string> choices;
3160 if (Config->get_verify_remove_last_capture()) {
3161 prompt = _("Do you really want to destroy the last capture?"
3162 "\n(This is destructive and cannot be undone)");
3164 choices.push_back (_("No, do nothing."));
3165 choices.push_back (_("Yes, destroy it."));
3167 Gtkmm2ext::Choice prompter (prompt, choices);
3169 if (prompter.run () == 1) {
3170 session->remove_last_capture ();
3174 session->remove_last_capture();
3179 Editor::normalize_region ()
3185 if (selection->regions.empty()) {
3189 begin_reversible_command (_("normalize"));
3191 track_canvas.get_window()->set_cursor (*wait_cursor);
3194 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3195 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3198 XMLNode &before = arv->region()->get_state();
3199 arv->audio_region()->normalize_to (0.0f);
3200 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3203 commit_reversible_command ();
3204 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3209 Editor::denormalize_region ()
3215 if (selection->regions.empty()) {
3219 begin_reversible_command ("denormalize");
3221 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3222 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3225 XMLNode &before = arv->region()->get_state();
3226 arv->audio_region()->set_scale_amplitude (1.0f);
3227 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3230 commit_reversible_command ();
3235 Editor::reverse_region ()
3241 Reverse rev (*session);
3242 apply_filter (rev, _("reverse regions"));
3246 Editor::apply_filter (AudioFilter& filter, string command)
3248 if (selection->regions.empty()) {
3252 begin_reversible_command (command);
3254 track_canvas.get_window()->set_cursor (*wait_cursor);
3257 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3258 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3262 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3264 RegionSelection::iterator tmp;
3269 if (arv->audio_region()->apply (filter) == 0) {
3271 XMLNode &before = playlist->get_state();
3272 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3273 XMLNode &after = playlist->get_state();
3274 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3282 commit_reversible_command ();
3283 selection->regions.clear ();
3286 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3290 Editor::region_selection_op (void (Region::*pmf)(void))
3292 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3293 Region* region = (*i)->region().get();
3300 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3302 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3303 Region* region = (*i)->region().get();
3304 (region->*pmf)(arg);
3309 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3311 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3312 Region* region = (*i)->region().get();
3318 Editor::external_edit_region ()
3320 if (!clicked_regionview) {
3328 Editor::brush (nframes_t pos)
3330 RegionSelection sel;
3333 if (selection->regions.empty()) {
3334 /* XXX get selection from region list */
3336 sel = selection->regions;
3343 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3344 mouse_brush_insert_region ((*i), pos);
3349 Editor::reset_region_gain_envelopes ()
3351 if (!session || selection->regions.empty()) {
3355 session->begin_reversible_command (_("reset region gain"));
3357 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3358 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3360 AutomationList& alist (arv->audio_region()->envelope());
3361 XMLNode& before (alist.get_state());
3363 arv->audio_region()->set_default_envelope ();
3364 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3368 session->commit_reversible_command ();
3372 Editor::toggle_gain_envelope_visibility ()
3374 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3375 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3377 bool x = region_envelope_visible_item->get_active();
3378 if (x != arv->envelope_visible()) {
3379 arv->set_envelope_visible (x);
3386 Editor::toggle_gain_envelope_active ()
3388 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3389 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3391 bool x = region_envelope_active_item->get_active();
3392 if (x != arv->audio_region()->envelope_active()) {
3393 arv->audio_region()->set_envelope_active (x);
3400 Editor::toggle_region_lock ()
3402 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3403 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3405 bool x = region_lock_item->get_active();
3406 if (x != arv->audio_region()->locked()) {
3407 arv->audio_region()->set_locked (x);
3414 Editor::toggle_region_mute ()
3416 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3417 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3419 bool x = region_mute_item->get_active();
3420 if (x != arv->audio_region()->muted()) {
3421 arv->audio_region()->set_muted (x);
3428 Editor::toggle_region_opaque ()
3430 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3431 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3433 bool x = region_opaque_item->get_active();
3434 if (x != arv->audio_region()->opaque()) {
3435 arv->audio_region()->set_opaque (x);
3442 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3444 begin_reversible_command (_("set fade in shape"));
3446 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3447 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3453 AutomationList& alist = tmp->audio_region()->fade_in();
3454 XMLNode &before = alist.get_state();
3456 tmp->audio_region()->set_fade_in_shape (shape);
3458 XMLNode &after = alist.get_state();
3459 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3462 commit_reversible_command ();
3466 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3468 begin_reversible_command (_("set fade out shape"));
3470 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3471 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3477 AutomationList& alist = tmp->audio_region()->fade_out();
3478 XMLNode &before = alist.get_state();
3480 tmp->audio_region()->set_fade_out_shape (shape);
3482 XMLNode &after = alist.get_state();
3483 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3486 commit_reversible_command ();
3490 Editor::set_fade_in_active (bool yn)
3492 begin_reversible_command (_("set fade in active"));
3494 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3495 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3502 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3504 XMLNode &before = ar->get_state();
3506 ar->set_fade_in_active (yn);
3508 XMLNode &after = ar->get_state();
3509 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3514 Editor::set_fade_out_active (bool yn)
3516 begin_reversible_command (_("set fade out active"));
3518 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3519 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3525 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3527 XMLNode &before = ar->get_state();
3529 ar->set_fade_out_active (yn);
3531 XMLNode &after = ar->get_state();
3532 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3537 /** Update crossfade visibility after its configuration has been changed */
3539 Editor::update_xfade_visibility ()
3541 _xfade_visibility = Config->get_xfades_visible ();
3543 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3544 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3546 if (_xfade_visibility) {
3547 v->show_all_xfades ();
3549 v->hide_all_xfades ();