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 ((*x)->region());
2832 npl->add_region (_xx, (*x)->region()->position() - first_position);
2833 pl->remove_region (((*x)->region()));
2839 /* copy region before adding, so we're not putting same object into two different playlists */
2840 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
2844 pl->remove_region (r);
2851 list<boost::shared_ptr<Playlist> > foo;
2853 /* the pmap is in the same order as the tracks in which selected regions occured */
2855 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2857 foo.push_back ((*i).pl);
2862 cut_buffer->set (foo);
2865 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2866 (*pl).playlist->thaw ();
2867 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2872 Editor::cut_copy_ranges (CutCopyOp op)
2874 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2875 (*i)->cut_copy_clear (*selection, op);
2880 Editor::paste (float times)
2882 paste_internal (edit_cursor->current_frame, times);
2886 Editor::mouse_paste ()
2891 track_canvas.get_pointer (x, y);
2892 track_canvas.window_to_world (x, y, wx, wy);
2893 wx += horizontal_adjustment.get_value();
2894 wy += vertical_adjustment.get_value();
2897 event.type = GDK_BUTTON_RELEASE;
2898 event.button.x = wx;
2899 event.button.y = wy;
2901 nframes_t where = event_frame (&event, 0, 0);
2903 paste_internal (where, 1);
2907 Editor::paste_internal (nframes_t position, float times)
2909 bool commit = false;
2911 if (cut_buffer->empty() || selection->tracks.empty()) {
2915 if (position == max_frames) {
2916 position = edit_cursor->current_frame;
2919 begin_reversible_command (_("paste"));
2921 TrackSelection::iterator i;
2924 /* get everything in the correct order */
2926 sort_track_selection ();
2928 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
2930 /* undo/redo is handled by individual tracks */
2932 if ((*i)->paste (position, times, *cut_buffer, nth)) {
2938 commit_reversible_command ();
2943 Editor::paste_named_selection (float times)
2945 TrackSelection::iterator t;
2947 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
2949 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
2953 TreeModel::iterator i = selected->get_selected();
2954 NamedSelection* ns = (*i)[named_selection_columns.selection];
2956 list<boost::shared_ptr<Playlist> >::iterator chunk;
2957 list<boost::shared_ptr<Playlist> >::iterator tmp;
2959 chunk = ns->playlists.begin();
2961 begin_reversible_command (_("paste chunk"));
2963 sort_track_selection ();
2965 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
2967 RouteTimeAxisView* rtv;
2968 boost::shared_ptr<Playlist> pl;
2969 boost::shared_ptr<AudioPlaylist> apl;
2971 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*t)) == 0) {
2975 if ((pl = rtv->playlist()) == 0) {
2979 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
2986 XMLNode &before = apl->get_state();
2987 apl->paste (*chunk, edit_cursor->current_frame, times);
2988 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
2990 if (tmp != ns->playlists.end()) {
2995 commit_reversible_command();
2999 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3001 boost::shared_ptr<Playlist> playlist;
3002 RegionSelection sel = regions; // clear (below) will clear the argument list
3004 begin_reversible_command (_("duplicate region"));
3006 selection->clear_regions ();
3008 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3010 boost::shared_ptr<Region> r ((*i)->region());
3012 TimeAxisView& tv = (*i)->get_time_axis_view();
3013 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3014 sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3016 playlist = (*i)->region()->playlist();
3017 XMLNode &before = playlist->get_state();
3018 playlist->duplicate (r, r->last_frame(), times);
3019 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3023 if (latest_regionview) {
3024 selection->add (latest_regionview);
3029 commit_reversible_command ();
3033 Editor::duplicate_selection (float times)
3035 if (selection->time.empty() || selection->tracks.empty()) {
3039 boost::shared_ptr<Playlist> playlist;
3040 vector<boost::shared_ptr<AudioRegion> > new_regions;
3041 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3043 create_region_from_selection (new_regions);
3045 if (new_regions.empty()) {
3049 begin_reversible_command (_("duplicate selection"));
3051 ri = new_regions.begin();
3053 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3054 if ((playlist = (*i)->playlist()) == 0) {
3057 XMLNode &before = playlist->get_state();
3058 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3059 XMLNode &after = playlist->get_state();
3060 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3063 if (ri == new_regions.end()) {
3068 commit_reversible_command ();
3072 Editor::reset_point_selection ()
3074 /* reset all selected points to the relevant default value */
3076 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3078 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3081 atv->reset_objects (selection->points);
3087 Editor::center_playhead ()
3089 float page = canvas_width * frames_per_unit;
3091 center_screen_internal (playhead_cursor->current_frame, page);
3095 Editor::center_edit_cursor ()
3097 float page = canvas_width * frames_per_unit;
3099 center_screen_internal (edit_cursor->current_frame, page);
3103 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3105 begin_reversible_command (_("clear playlist"));
3106 XMLNode &before = playlist->get_state();
3108 XMLNode &after = playlist->get_state();
3109 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3110 commit_reversible_command ();
3114 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3116 boost::shared_ptr<Playlist> playlist;
3118 nframes_t next_distance;
3121 if (use_edit_cursor) {
3122 start = edit_cursor->current_frame;
3127 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3131 if (selection->tracks.empty()) {
3135 begin_reversible_command (_("nudge track"));
3137 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3139 if ((playlist = (*i)->playlist()) == 0) {
3143 XMLNode &before = playlist->get_state();
3144 playlist->nudge_after (start, distance, forwards);
3145 XMLNode &after = playlist->get_state();
3146 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3149 commit_reversible_command ();
3153 Editor::remove_last_capture ()
3155 vector<string> choices;
3162 if (Config->get_verify_remove_last_capture()) {
3163 prompt = _("Do you really want to destroy the last capture?"
3164 "\n(This is destructive and cannot be undone)");
3166 choices.push_back (_("No, do nothing."));
3167 choices.push_back (_("Yes, destroy it."));
3169 Gtkmm2ext::Choice prompter (prompt, choices);
3171 if (prompter.run () == 1) {
3172 session->remove_last_capture ();
3176 session->remove_last_capture();
3181 Editor::normalize_region ()
3187 if (selection->regions.empty()) {
3191 begin_reversible_command (_("normalize"));
3193 track_canvas.get_window()->set_cursor (*wait_cursor);
3196 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3197 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3200 XMLNode &before = arv->region()->get_state();
3201 arv->audio_region()->normalize_to (0.0f);
3202 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3205 commit_reversible_command ();
3206 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3211 Editor::denormalize_region ()
3217 if (selection->regions.empty()) {
3221 begin_reversible_command ("denormalize");
3223 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3224 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3227 XMLNode &before = arv->region()->get_state();
3228 arv->audio_region()->set_scale_amplitude (1.0f);
3229 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3232 commit_reversible_command ();
3237 Editor::reverse_region ()
3243 Reverse rev (*session);
3244 apply_filter (rev, _("reverse regions"));
3248 Editor::apply_filter (AudioFilter& filter, string command)
3250 if (selection->regions.empty()) {
3254 begin_reversible_command (command);
3256 track_canvas.get_window()->set_cursor (*wait_cursor);
3259 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3260 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3264 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3266 RegionSelection::iterator tmp;
3271 if (arv->audio_region()->apply (filter) == 0) {
3273 XMLNode &before = playlist->get_state();
3274 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3275 XMLNode &after = playlist->get_state();
3276 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3284 commit_reversible_command ();
3285 selection->regions.clear ();
3288 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3292 Editor::region_selection_op (void (Region::*pmf)(void))
3294 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3295 Region* region = (*i)->region().get();
3302 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3304 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3305 Region* region = (*i)->region().get();
3306 (region->*pmf)(arg);
3311 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3313 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3314 Region* region = (*i)->region().get();
3320 Editor::external_edit_region ()
3322 if (!clicked_regionview) {
3330 Editor::brush (nframes_t pos)
3332 RegionSelection sel;
3335 if (selection->regions.empty()) {
3336 /* XXX get selection from region list */
3338 sel = selection->regions;
3345 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3346 mouse_brush_insert_region ((*i), pos);
3351 Editor::reset_region_gain_envelopes ()
3353 if (!session || selection->regions.empty()) {
3357 session->begin_reversible_command (_("reset region gain"));
3359 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3360 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3362 AutomationList& alist (arv->audio_region()->envelope());
3363 XMLNode& before (alist.get_state());
3365 arv->audio_region()->set_default_envelope ();
3366 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3370 session->commit_reversible_command ();
3374 Editor::toggle_gain_envelope_visibility ()
3376 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3377 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3379 bool x = region_envelope_visible_item->get_active();
3380 if (x != arv->envelope_visible()) {
3381 arv->set_envelope_visible (x);
3388 Editor::toggle_gain_envelope_active ()
3390 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3391 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3393 bool x = region_envelope_active_item->get_active();
3394 if (x != arv->audio_region()->envelope_active()) {
3395 arv->audio_region()->set_envelope_active (x);
3402 Editor::toggle_region_lock ()
3404 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3405 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3407 bool x = region_lock_item->get_active();
3408 if (x != arv->audio_region()->locked()) {
3409 arv->audio_region()->set_locked (x);
3416 Editor::toggle_region_mute ()
3418 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3419 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3421 bool x = region_mute_item->get_active();
3422 if (x != arv->audio_region()->muted()) {
3423 arv->audio_region()->set_muted (x);
3430 Editor::toggle_region_opaque ()
3432 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3433 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3435 bool x = region_opaque_item->get_active();
3436 if (x != arv->audio_region()->opaque()) {
3437 arv->audio_region()->set_opaque (x);
3444 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3446 begin_reversible_command (_("set fade in shape"));
3448 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3449 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3455 AutomationList& alist = tmp->audio_region()->fade_in();
3456 XMLNode &before = alist.get_state();
3458 tmp->audio_region()->set_fade_in_shape (shape);
3460 XMLNode &after = alist.get_state();
3461 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3464 commit_reversible_command ();
3468 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3470 begin_reversible_command (_("set fade out shape"));
3472 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3473 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3479 AutomationList& alist = tmp->audio_region()->fade_out();
3480 XMLNode &before = alist.get_state();
3482 tmp->audio_region()->set_fade_out_shape (shape);
3484 XMLNode &after = alist.get_state();
3485 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3488 commit_reversible_command ();
3492 Editor::set_fade_in_active (bool yn)
3494 begin_reversible_command (_("set fade in active"));
3496 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3497 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3504 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3506 XMLNode &before = ar->get_state();
3508 ar->set_fade_in_active (yn);
3510 XMLNode &after = ar->get_state();
3511 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3516 Editor::set_fade_out_active (bool yn)
3518 begin_reversible_command (_("set fade out active"));
3520 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3521 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3527 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3529 XMLNode &before = ar->get_state();
3531 ar->set_fade_out_active (yn);
3533 XMLNode &after = ar->get_state();
3534 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));