2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
29 #include <pbd/error.h>
30 #include <pbd/basename.h>
31 #include <pbd/pthread_utils.h>
32 #include <pbd/memento_command.h>
34 #include <gtkmm2ext/utils.h>
35 #include <gtkmm2ext/choice.h>
36 #include <gtkmm2ext/window_title.h>
38 #include <ardour/audioengine.h>
39 #include <ardour/session.h>
40 #include <ardour/audioplaylist.h>
41 #include <ardour/audioregion.h>
42 #include <ardour/audio_diskstream.h>
43 #include <ardour/utils.h>
44 #include <ardour/location.h>
45 #include <ardour/named_selection.h>
46 #include <ardour/audio_track.h>
47 #include <ardour/audioplaylist.h>
48 #include <ardour/region_factory.h>
49 #include <ardour/playlist_factory.h>
50 #include <ardour/reverse.h>
51 #include <ardour/quantize.h>
53 #include "ardour_ui.h"
55 #include "time_axis_view.h"
56 #include "audio_time_axis.h"
57 #include "automation_time_axis.h"
58 #include "streamview.h"
59 #include "audio_region_view.h"
60 #include "midi_region_view.h"
61 #include "rgb_macros.h"
62 #include "selection_templates.h"
63 #include "selection.h"
65 #include "gtk-custom-hruler.h"
66 #include "gui_thread.h"
71 using namespace ARDOUR;
75 using namespace Gtkmm2ext;
76 using namespace Editing;
78 /***********************************************************************
80 ***********************************************************************/
83 Editor::undo (uint32_t n)
91 Editor::redo (uint32_t n)
99 Editor::ensure_cursor (nframes_t *pos)
101 *pos = edit_cursor->current_frame;
106 Editor::split_region ()
108 split_region_at (edit_cursor->current_frame);
112 Editor::split_region_at (nframes_t where)
114 split_regions_at (where, selection->regions);
118 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
120 begin_reversible_command (_("split"));
123 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
125 RegionSelection::iterator tmp;
130 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
132 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
134 _new_regionviews_show_envelope = arv->envelope_visible();
137 XMLNode &before = pl->get_state();
138 pl->split_region ((*a)->region(), where);
139 XMLNode &after = pl->get_state();
140 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
146 commit_reversible_command ();
147 _new_regionviews_show_envelope = false;
151 /** Remove `clicked_regionview' */
153 Editor::remove_clicked_region ()
155 if (clicked_routeview == 0 || clicked_regionview == 0) {
159 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
161 begin_reversible_command (_("remove region"));
162 XMLNode &before = playlist->get_state();
163 playlist->remove_region (clicked_regionview->region());
164 XMLNode &after = playlist->get_state();
165 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
166 commit_reversible_command ();
170 /** Remove the selected regions */
172 Editor::remove_selected_regions ()
174 if (selection->regions.empty()) {
178 /* XXX: should be called remove regions if we're removing more than one */
179 begin_reversible_command (_("remove region"));
181 while (!selection->regions.empty()) {
182 boost::shared_ptr<Region> region = selection->regions.front()->region ();
183 boost::shared_ptr<Playlist> playlist = region->playlist ();
185 XMLNode &before = playlist->get_state();
186 playlist->remove_region (region);
187 XMLNode &after = playlist->get_state();
188 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
191 commit_reversible_command ();
194 boost::shared_ptr<Region>
195 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
198 boost::shared_ptr<Region> region;
201 if (selection->time.start () == selection->time.end_frame ()) {
203 /* no current selection-> is there a selected regionview? */
205 if (selection->regions.empty()) {
211 if (!selection->regions.empty()) {
213 rv = *(selection->regions.begin());
214 (*tv) = &rv->get_time_axis_view();
215 region = rv->region();
217 } else if (!selection->tracks.empty()) {
219 (*tv) = selection->tracks.front();
221 RouteTimeAxisView* rtv;
223 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
224 boost::shared_ptr<Playlist> pl;
226 if ((pl = rtv->playlist()) == 0) {
230 region = pl->top_region_at (start);
238 Editor::extend_selection_to_end_of_region (bool next)
241 boost::shared_ptr<Region> region;
244 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
248 if (region && selection->time.start () == selection->time.end_frame ()) {
249 start = region->position();
251 start = selection->time.start ();
254 /* Try to leave the selection with the same route if possible */
256 if ((tv = selection->time.track) == 0) {
260 begin_reversible_command (_("extend selection"));
261 selection->set (tv, start, region->position() + region->length());
262 commit_reversible_command ();
266 Editor::extend_selection_to_start_of_region (bool previous)
269 boost::shared_ptr<Region> region;
272 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
276 if (region && selection->time.start () == selection->time.end_frame ()) {
277 end = region->position() + region->length();
279 end = selection->time.end_frame ();
282 /* Try to leave the selection with the same route if possible */
284 if ((tv = selection->time.track) == 0) {
288 begin_reversible_command (_("extend selection"));
289 selection->set (tv, region->position(), end);
290 commit_reversible_command ();
295 Editor::nudge_forward (bool next)
298 nframes_t next_distance;
300 if (!session) return;
302 if (!selection->regions.empty()) {
304 begin_reversible_command (_("nudge forward"));
306 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
307 boost::shared_ptr<Region> r ((*i)->region());
309 distance = get_nudge_distance (r->position(), next_distance);
312 distance = next_distance;
315 XMLNode &before = r->playlist()->get_state();
316 r->set_position (r->position() + distance, this);
317 XMLNode &after = r->playlist()->get_state();
318 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
321 commit_reversible_command ();
324 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
325 session->request_locate (playhead_cursor->current_frame + distance);
330 Editor::nudge_backward (bool next)
333 nframes_t next_distance;
335 if (!session) return;
337 if (!selection->regions.empty()) {
339 begin_reversible_command (_("nudge forward"));
341 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
342 boost::shared_ptr<Region> r ((*i)->region());
344 distance = get_nudge_distance (r->position(), next_distance);
347 distance = next_distance;
350 XMLNode &before = r->playlist()->get_state();
352 if (r->position() > distance) {
353 r->set_position (r->position() - distance, this);
355 r->set_position (0, this);
357 XMLNode &after = r->playlist()->get_state();
358 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
361 commit_reversible_command ();
365 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
367 if (playhead_cursor->current_frame > distance) {
368 session->request_locate (playhead_cursor->current_frame - distance);
370 session->goto_start();
376 Editor::nudge_forward_capture_offset ()
380 if (!session) return;
382 if (!selection->regions.empty()) {
384 begin_reversible_command (_("nudge forward"));
386 distance = session->worst_output_latency();
388 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
389 boost::shared_ptr<Region> r ((*i)->region());
391 XMLNode &before = r->playlist()->get_state();
392 r->set_position (r->position() + distance, this);
393 XMLNode &after = r->playlist()->get_state();
394 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
397 commit_reversible_command ();
403 Editor::nudge_backward_capture_offset ()
407 if (!session) return;
409 if (!selection->regions.empty()) {
411 begin_reversible_command (_("nudge forward"));
413 distance = session->worst_output_latency();
415 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
416 boost::shared_ptr<Region> r ((*i)->region());
418 XMLNode &before = r->playlist()->get_state();
420 if (r->position() > distance) {
421 r->set_position (r->position() - distance, this);
423 r->set_position (0, this);
425 XMLNode &after = r->playlist()->get_state();
426 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
429 commit_reversible_command ();
436 Editor::move_to_start ()
438 session->goto_start ();
442 Editor::move_to_end ()
445 session->request_locate (session->current_end_frame());
449 Editor::build_region_boundary_cache ()
452 vector<RegionPoint> interesting_points;
453 boost::shared_ptr<Region> r;
454 TrackViewList tracks;
457 region_boundary_cache.clear ();
464 case SnapToRegionStart:
465 interesting_points.push_back (Start);
467 case SnapToRegionEnd:
468 interesting_points.push_back (End);
470 case SnapToRegionSync:
471 interesting_points.push_back (SyncPoint);
473 case SnapToRegionBoundary:
474 interesting_points.push_back (Start);
475 interesting_points.push_back (End);
478 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
483 TimeAxisView *ontrack = 0;
486 if (!selection->tracks.empty()) {
487 tlist = selection->tracks;
492 while (pos < session->current_end_frame() && !at_end) {
495 nframes_t lpos = max_frames;
497 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
499 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
501 /* move to next point type */
508 rpos = r->first_frame();
511 rpos = r->last_frame();
514 rpos = r->adjust_to_sync (r->first_frame());
521 RouteTimeAxisView *rtav;
523 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
524 if (rtav->get_diskstream() != 0) {
525 speed = rtav->get_diskstream()->speed();
529 rpos = track_frame_to_session_frame (rpos, speed);
535 /* prevent duplicates, but we don't use set<> because we want to be able
539 vector<nframes_t>::iterator ri;
541 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
547 if (ri == region_boundary_cache.end()) {
548 region_boundary_cache.push_back (rpos);
555 /* finally sort to be sure that the order is correct */
557 sort (region_boundary_cache.begin(), region_boundary_cache.end());
560 boost::shared_ptr<Region>
561 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
563 TrackViewList::iterator i;
564 nframes_t closest = max_frames;
565 boost::shared_ptr<Region> ret;
569 nframes_t track_frame;
570 RouteTimeAxisView *rtav;
572 for (i = tracks.begin(); i != tracks.end(); ++i) {
575 boost::shared_ptr<Region> r;
578 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
579 if (rtav->get_diskstream()!=0)
580 track_speed = rtav->get_diskstream()->speed();
583 track_frame = session_frame_to_track_frame(frame, track_speed);
585 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
591 rpos = r->first_frame ();
595 rpos = r->last_frame ();
599 rpos = r->adjust_to_sync (r->first_frame());
602 // rpos is a "track frame", converting it to "session frame"
603 rpos = track_frame_to_session_frame(rpos, track_speed);
606 distance = rpos - frame;
608 distance = frame - rpos;
611 if (distance < closest) {
623 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
625 boost::shared_ptr<Region> r;
626 nframes_t pos = cursor->current_frame;
632 TimeAxisView *ontrack = 0;
634 // so we don't find the current region again..
638 if (!selection->tracks.empty()) {
640 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
642 } else if (clicked_axisview) {
645 t.push_back (clicked_axisview);
647 r = find_next_region (pos, point, dir, t, &ontrack);
651 r = find_next_region (pos, point, dir, track_views, &ontrack);
660 pos = r->first_frame ();
664 pos = r->last_frame ();
668 pos = r->adjust_to_sync (r->first_frame());
673 RouteTimeAxisView *rtav;
675 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
676 if (rtav->get_diskstream() != 0) {
677 speed = rtav->get_diskstream()->speed();
681 pos = track_frame_to_session_frame(pos, speed);
683 if (cursor == playhead_cursor) {
684 session->request_locate (pos);
686 cursor->set_position (pos);
691 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
693 cursor_to_region_point (cursor, point, 1);
697 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
699 cursor_to_region_point (cursor, point, -1);
703 Editor::cursor_to_selection_start (Cursor *cursor)
706 switch (mouse_mode) {
708 if (!selection->regions.empty()) {
709 pos = selection->regions.start();
714 if (!selection->time.empty()) {
715 pos = selection->time.start ();
723 if (cursor == playhead_cursor) {
724 session->request_locate (pos);
726 cursor->set_position (pos);
731 Editor::cursor_to_selection_end (Cursor *cursor)
735 switch (mouse_mode) {
737 if (!selection->regions.empty()) {
738 pos = selection->regions.end_frame();
743 if (!selection->time.empty()) {
744 pos = selection->time.end_frame ();
752 if (cursor == playhead_cursor) {
753 session->request_locate (pos);
755 cursor->set_position (pos);
760 Editor::scroll_playhead (bool forward)
762 nframes_t pos = playhead_cursor->current_frame;
763 nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
766 if (pos == max_frames) {
770 if (pos < max_frames - delta) {
789 session->request_locate (pos);
793 Editor::playhead_backward ()
800 if (get_prefix (prefix, was_floating)) {
804 cnt = (nframes_t) floor (prefix * session->frame_rate ());
806 cnt = (nframes_t) prefix;
810 pos = playhead_cursor->current_frame;
812 if ((nframes_t) pos < cnt) {
818 /* XXX this is completely insane. with the current buffering
819 design, we'll force a complete track buffer flush and
820 reload, just to move 1 sample !!!
823 session->request_locate (pos);
827 Editor::playhead_forward ()
834 if (get_prefix (prefix, was_floating)) {
838 cnt = (nframes_t) floor (prefix * session->frame_rate ());
840 cnt = (nframes_t) floor (prefix);
844 pos = playhead_cursor->current_frame;
846 /* XXX this is completely insane. with the current buffering
847 design, we'll force a complete track buffer flush and
848 reload, just to move 1 sample !!!
851 session->request_locate (pos+cnt);
855 Editor::cursor_align (bool playhead_to_edit)
857 if (playhead_to_edit) {
859 session->request_locate (edit_cursor->current_frame);
862 edit_cursor->set_position (playhead_cursor->current_frame);
867 Editor::edit_cursor_backward ()
874 if (get_prefix (prefix, was_floating)) {
878 cnt = (nframes_t) floor (prefix * session->frame_rate ());
880 cnt = (nframes_t) prefix;
884 pos = edit_cursor->current_frame;
886 if ((nframes_t) pos < cnt) {
892 edit_cursor->set_position (pos);
896 Editor::edit_cursor_forward ()
903 if (get_prefix (prefix, was_floating)) {
907 cnt = (nframes_t) floor (prefix * session->frame_rate ());
909 cnt = (nframes_t) floor (prefix);
913 pos = edit_cursor->current_frame;
914 edit_cursor->set_position (pos+cnt);
918 Editor::goto_frame ()
924 if (get_prefix (prefix, was_floating)) {
929 frame = (nframes_t) floor (prefix * session->frame_rate());
931 frame = (nframes_t) floor (prefix);
934 session->request_locate (frame);
938 Editor::scroll_backward (float pages)
941 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
946 if (get_prefix (prefix, was_floating)) {
947 cnt = (nframes_t) floor (pages * one_page);
950 cnt = (nframes_t) floor (prefix * session->frame_rate());
952 cnt = (nframes_t) floor (prefix * one_page);
956 if (leftmost_frame < cnt) {
959 frame = leftmost_frame - cnt;
962 reset_x_origin (frame);
966 Editor::scroll_forward (float pages)
969 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
974 if (get_prefix (prefix, was_floating)) {
975 cnt = (nframes_t) floor (pages * one_page);
978 cnt = (nframes_t) floor (prefix * session->frame_rate());
980 cnt = (nframes_t) floor (prefix * one_page);
984 if (max_frames - cnt < leftmost_frame) {
985 frame = max_frames - cnt;
987 frame = leftmost_frame + cnt;
990 reset_x_origin (frame);
994 Editor::scroll_tracks_down ()
1000 if (get_prefix (prefix, was_floating)) {
1003 cnt = (int) floor (prefix);
1006 double vert_value = vertical_adjustment.get_value() + (cnt *
1007 vertical_adjustment.get_page_size());
1008 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1009 vert_value = vertical_adjustment.get_upper() - canvas_height;
1011 vertical_adjustment.set_value (vert_value);
1015 Editor::scroll_tracks_up ()
1021 if (get_prefix (prefix, was_floating)) {
1024 cnt = (int) floor (prefix);
1027 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1031 Editor::scroll_tracks_down_line ()
1034 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1035 double vert_value = adj->get_value() + 20;
1037 if (vert_value>adj->get_upper() - canvas_height) {
1038 vert_value = adj->get_upper() - canvas_height;
1040 adj->set_value (vert_value);
1044 Editor::scroll_tracks_up_line ()
1046 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1047 adj->set_value (adj->get_value() - 20);
1053 Editor::temporal_zoom_step (bool coarser)
1055 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1059 nfpu = frames_per_unit;
1064 nfpu = max(1.0,(nfpu/1.61803399));
1067 temporal_zoom (nfpu);
1071 Editor::temporal_zoom (gdouble fpu)
1073 if (!session) return;
1075 nframes_t current_page = current_page_frames();
1076 nframes_t current_leftmost = leftmost_frame;
1077 nframes_t current_rightmost;
1078 nframes_t current_center;
1080 nframes_t leftmost_after_zoom = 0;
1085 new_page = (nframes_t) floor (canvas_width * nfpu);
1087 switch (zoom_focus) {
1089 leftmost_after_zoom = current_leftmost;
1092 case ZoomFocusRight:
1093 current_rightmost = leftmost_frame + current_page;
1094 if (current_rightmost > new_page) {
1095 leftmost_after_zoom = current_rightmost - new_page;
1097 leftmost_after_zoom = 0;
1101 case ZoomFocusCenter:
1102 current_center = current_leftmost + (current_page/2);
1103 if (current_center > (new_page/2)) {
1104 leftmost_after_zoom = current_center - (new_page / 2);
1106 leftmost_after_zoom = 0;
1110 case ZoomFocusPlayhead:
1111 /* try to keep the playhead in the center */
1112 if (playhead_cursor->current_frame > new_page/2) {
1113 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1115 leftmost_after_zoom = 0;
1120 /* try to keep the edit cursor in the center */
1121 if (edit_cursor->current_frame > new_page/2) {
1122 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1124 leftmost_after_zoom = 0;
1130 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1132 // begin_reversible_command (_("zoom"));
1133 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1134 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1135 // commit_reversible_command ();
1137 reposition_and_zoom (leftmost_after_zoom, nfpu);
1141 Editor::temporal_zoom_selection ()
1143 if (!selection) return;
1145 if (selection->time.empty()) {
1149 nframes_t start = selection->time[clicked_selection].start;
1150 nframes_t end = selection->time[clicked_selection].end;
1152 temporal_zoom_by_frame (start, end, "zoom to selection");
1156 Editor::temporal_zoom_session ()
1158 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1161 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1166 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1168 if (!session) return;
1170 if ((start == 0 && end == 0) || end < start) {
1174 nframes_t range = end - start;
1176 double new_fpu = (double)range / (double)canvas_width;
1179 // while (p2 < new_fpu) {
1184 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1185 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1186 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1188 if (new_leftmost > middle) new_leftmost = 0;
1190 // begin_reversible_command (op);
1191 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1192 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1193 // commit_reversible_command ();
1195 reposition_and_zoom (new_leftmost, new_fpu);
1199 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1201 if (!session) return;
1203 double range_before = frame - leftmost_frame;
1206 new_fpu = frames_per_unit;
1209 new_fpu *= 1.61803399;
1210 range_before *= 1.61803399;
1212 new_fpu = max(1.0,(new_fpu/1.61803399));
1213 range_before /= 1.61803399;
1216 if (new_fpu == frames_per_unit) return;
1218 nframes_t new_leftmost = frame - (nframes_t)range_before;
1220 if (new_leftmost > frame) new_leftmost = 0;
1222 // begin_reversible_command (_("zoom to frame"));
1223 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1224 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1225 // commit_reversible_command ();
1227 reposition_and_zoom (new_leftmost, new_fpu);
1231 Editor::add_location_from_selection ()
1235 if (selection->time.empty()) {
1239 if (session == 0 || clicked_axisview == 0) {
1243 nframes_t start = selection->time[clicked_selection].start;
1244 nframes_t end = selection->time[clicked_selection].end;
1246 session->locations()->next_available_name(rangename,"selection");
1247 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1249 session->begin_reversible_command (_("add marker"));
1250 XMLNode &before = session->locations()->get_state();
1251 session->locations()->add (location, true);
1252 XMLNode &after = session->locations()->get_state();
1253 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1254 session->commit_reversible_command ();
1258 Editor::add_location_from_playhead_cursor ()
1262 nframes_t where = session->audible_frame();
1264 session->locations()->next_available_name(markername,"mark");
1265 Location *location = new Location (where, where, markername, Location::IsMark);
1266 session->begin_reversible_command (_("add marker"));
1267 XMLNode &before = session->locations()->get_state();
1268 session->locations()->add (location, true);
1269 XMLNode &after = session->locations()->get_state();
1270 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1271 session->commit_reversible_command ();
1275 Editor::add_location_from_audio_region ()
1277 if (selection->regions.empty()) {
1281 RegionView* rv = *(selection->regions.begin());
1282 boost::shared_ptr<Region> region = rv->region();
1284 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1285 session->begin_reversible_command (_("add marker"));
1286 XMLNode &before = session->locations()->get_state();
1287 session->locations()->add (location, true);
1288 XMLNode &after = session->locations()->get_state();
1289 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1290 session->commit_reversible_command ();
1294 Editor::amplitude_zoom_step (bool in)
1308 #ifdef FIX_FOR_CANVAS
1309 /* XXX DO SOMETHING */
1318 Editor::delete_sample_forward ()
1323 Editor::delete_sample_backward ()
1328 Editor::delete_screen ()
1335 Editor::search_backwards ()
1341 Editor::search_forwards ()
1349 Editor::jump_forward_to_mark ()
1355 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1358 session->request_locate (location->start(), session->transport_rolling());
1360 session->request_locate (session->current_end_frame());
1365 Editor::jump_backward_to_mark ()
1371 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1374 session->request_locate (location->start(), session->transport_rolling());
1376 session->goto_start ();
1388 if (get_prefix (prefix, was_floating)) {
1389 pos = session->audible_frame ();
1392 pos = (nframes_t) floor (prefix * session->frame_rate ());
1394 pos = (nframes_t) floor (prefix);
1398 session->locations()->next_available_name(markername,"mark");
1399 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1403 Editor::clear_markers ()
1406 session->begin_reversible_command (_("clear markers"));
1407 XMLNode &before = session->locations()->get_state();
1408 session->locations()->clear_markers ();
1409 XMLNode &after = session->locations()->get_state();
1410 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1411 session->commit_reversible_command ();
1416 Editor::clear_ranges ()
1419 session->begin_reversible_command (_("clear ranges"));
1420 XMLNode &before = session->locations()->get_state();
1422 Location * looploc = session->locations()->auto_loop_location();
1423 Location * punchloc = session->locations()->auto_punch_location();
1425 session->locations()->clear_ranges ();
1427 if (looploc) session->locations()->add (looploc);
1428 if (punchloc) session->locations()->add (punchloc);
1430 XMLNode &after = session->locations()->get_state();
1431 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1432 session->commit_reversible_command ();
1437 Editor::clear_locations ()
1439 session->begin_reversible_command (_("clear locations"));
1440 XMLNode &before = session->locations()->get_state();
1441 session->locations()->clear ();
1442 XMLNode &after = session->locations()->get_state();
1443 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1444 session->commit_reversible_command ();
1445 session->locations()->clear ();
1449 Editor::unhide_markers ()
1451 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1452 Location *l = (*i).first;
1453 if (l->is_hidden() && l->is_mark()) {
1454 l->set_hidden(false, this);
1460 Editor::unhide_ranges ()
1462 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1463 Location *l = (*i).first;
1464 if (l->is_hidden() && l->is_range_marker()) {
1465 l->set_hidden(false, this);
1470 /* INSERT/REPLACE */
1473 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1479 RouteTimeAxisView *rtv = 0;
1480 boost::shared_ptr<Playlist> playlist;
1482 track_canvas.window_to_world (x, y, wx, wy);
1483 wx += horizontal_adjustment.get_value();
1484 wy += vertical_adjustment.get_value();
1487 event.type = GDK_BUTTON_RELEASE;
1488 event.button.x = wx;
1489 event.button.y = wy;
1491 where = event_frame (&event, &cx, &cy);
1493 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1494 /* clearly outside canvas area */
1498 if ((tv = trackview_by_y_position (cy)) == 0) {
1502 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) == 0) {
1506 if ((playlist = rtv->playlist()) == 0) {
1512 begin_reversible_command (_("insert dragged region"));
1513 XMLNode &before = playlist->get_state();
1514 playlist->add_region (RegionFactory::create (region), where, 1.0);
1515 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1516 commit_reversible_command ();
1520 Editor::insert_region_list_selection (float times)
1522 RouteTimeAxisView *tv = 0;
1523 boost::shared_ptr<Playlist> playlist;
1525 if (selection->tracks.empty()) {
1529 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1533 if ((playlist = tv->playlist()) == 0) {
1537 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1539 if (selected->count_selected_rows() != 1) {
1543 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1545 /* only one row selected, so rows.begin() is it */
1549 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1551 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1553 begin_reversible_command (_("insert region"));
1554 XMLNode &before = playlist->get_state();
1555 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1556 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1557 commit_reversible_command ();
1561 /* BUILT-IN EFFECTS */
1564 Editor::reverse_selection ()
1569 /* GAIN ENVELOPE EDITING */
1572 Editor::edit_envelope ()
1579 Editor::transition_to_rolling (bool fwd)
1585 switch (Config->get_slave_source()) {
1590 /* transport controlled by the master */
1594 if (session->is_auditioning()) {
1595 session->cancel_audition ();
1599 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1603 Editor::toggle_playback (bool with_abort)
1609 switch (Config->get_slave_source()) {
1614 /* transport controlled by the master */
1618 if (session->is_auditioning()) {
1619 session->cancel_audition ();
1623 if (session->transport_rolling()) {
1624 session->request_stop (with_abort);
1625 if (session->get_play_loop()) {
1626 session->request_play_loop (false);
1629 session->request_transport_speed (1.0f);
1634 Editor::play_from_start ()
1636 session->request_locate (session->current_start_frame(), true);
1640 Editor::play_from_edit_cursor ()
1642 session->request_locate (edit_cursor->current_frame, true);
1646 Editor::play_selection ()
1648 if (selection->time.empty()) {
1652 session->request_play_range (true);
1656 Editor::play_selected_region ()
1658 if (!selection->regions.empty()) {
1659 RegionView *rv = *(selection->regions.begin());
1661 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1666 Editor::loop_selected_region ()
1668 if (!selection->regions.empty()) {
1669 RegionView *rv = *(selection->regions.begin());
1672 if ((tll = transport_loop_location()) != 0) {
1674 tll->set (rv->region()->position(), rv->region()->last_frame());
1676 // enable looping, reposition and start rolling
1678 session->request_play_loop (true);
1679 session->request_locate (tll->start(), false);
1680 session->request_transport_speed (1.0f);
1686 Editor::play_location (Location& location)
1688 if (location.start() <= location.end()) {
1692 session->request_bounded_roll (location.start(), location.end());
1696 Editor::loop_location (Location& location)
1698 if (location.start() <= location.end()) {
1704 if ((tll = transport_loop_location()) != 0) {
1705 tll->set (location.start(), location.end());
1707 // enable looping, reposition and start rolling
1708 session->request_play_loop (true);
1709 session->request_locate (tll->start(), true);
1714 Editor::raise_region_to_top ()
1716 selection->foreach_region (&Region::raise_to_top);
1720 Editor::lower_region_to_bottom ()
1722 selection->foreach_region (&Region::lower_to_bottom);
1725 /** Show the region editor for the selected regions */
1727 Editor::edit_region ()
1729 selection->foreach_regionview (&RegionView::show_region_editor);
1733 Editor::rename_region ()
1737 Button ok_button (_("OK"));
1738 Button cancel_button (_("Cancel"));
1740 if (selection->regions.empty()) {
1744 WindowTitle title(Glib::get_application_name());
1745 title += _("Rename Region");
1747 dialog.set_title (title.get_string());
1748 dialog.set_name ("RegionRenameWindow");
1749 dialog.set_size_request (300, -1);
1750 dialog.set_position (Gtk::WIN_POS_MOUSE);
1751 dialog.set_modal (true);
1753 dialog.get_vbox()->set_border_width (10);
1754 dialog.get_vbox()->pack_start (entry);
1755 dialog.get_action_area()->pack_start (ok_button);
1756 dialog.get_action_area()->pack_start (cancel_button);
1758 entry.set_name ("RegionNameDisplay");
1759 ok_button.set_name ("EditorGTKButton");
1760 cancel_button.set_name ("EditorGTKButton");
1762 region_renamed = false;
1764 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1765 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1766 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1773 if (region_renamed) {
1774 (*selection->regions.begin())->region()->set_name (entry.get_text());
1775 redisplay_regions ();
1780 Editor::rename_region_finished (bool status)
1783 region_renamed = status;
1788 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
1790 if (session->is_auditioning()) {
1791 session->cancel_audition ();
1794 // note: some potential for creativity here, because region doesn't
1795 // have to belong to the playlist that Route is handling
1797 // bool was_soloed = route.soloed();
1799 route.set_solo (true, this);
1801 session->request_bounded_roll (region->position(), region->position() + region->length());
1803 /* XXX how to unset the solo state ? */
1806 /** Start an audition of the first selected region */
1808 Editor::audition_selected_region ()
1810 if (!selection->regions.empty()) {
1811 RegionView* rv = *(selection->regions.begin());
1812 session->audition_region (rv->region());
1817 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
1819 session->audition_region (region);
1823 Editor::build_interthread_progress_window ()
1825 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
1827 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1829 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
1830 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
1832 // GTK2FIX: this button needs a modifiable label
1834 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1835 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1837 interthread_cancel_button.add (interthread_cancel_label);
1839 interthread_progress_window->set_default_size (200, 100);
1843 Editor::interthread_cancel_clicked ()
1845 if (current_interthread_info) {
1846 current_interthread_info->cancel = true;
1851 Editor::region_from_selection ()
1853 if (clicked_axisview == 0) {
1857 if (selection->time.empty()) {
1861 nframes_t start = selection->time[clicked_selection].start;
1862 nframes_t end = selection->time[clicked_selection].end;
1864 nframes_t selection_cnt = end - start + 1;
1866 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1867 boost::shared_ptr<AudioRegion> current;
1868 boost::shared_ptr<Region> current_r;
1869 boost::shared_ptr<Playlist> pl;
1871 nframes_t internal_start;
1874 if ((pl = (*i)->playlist()) == 0) {
1878 if ((current_r = pl->top_region_at (start)) == 0) {
1882 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
1883 assert(current); // FIXME
1885 internal_start = start - current->position();
1886 session->region_name (new_name, current->name(), true);
1887 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
1893 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
1895 if (selection->time.empty() || selection->tracks.empty()) {
1899 nframes_t start = selection->time[clicked_selection].start;
1900 nframes_t end = selection->time[clicked_selection].end;
1902 sort_track_selection ();
1904 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1906 boost::shared_ptr<AudioRegion> current;
1907 boost::shared_ptr<Region> current_r;
1908 boost::shared_ptr<Playlist> playlist;
1909 nframes_t internal_start;
1912 if ((playlist = (*i)->playlist()) == 0) {
1916 if ((current_r = playlist->top_region_at(start)) == 0) {
1920 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
1924 internal_start = start - current->position();
1925 session->region_name (new_name, current->name(), true);
1927 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
1932 Editor::split_multichannel_region ()
1934 if (selection->regions.empty()) {
1938 vector<boost::shared_ptr<AudioRegion> > v;
1940 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
1942 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
1944 if (!arv || arv->audio_region()->n_channels() < 2) {
1948 (arv)->audio_region()->separate_by_channel (*session, v);
1953 Editor::new_region_from_selection ()
1955 region_from_selection ();
1956 cancel_selection ();
1960 Editor::separate_region_from_selection ()
1964 bool doing_undo = false;
1966 if (selection->time.empty()) {
1970 boost::shared_ptr<Playlist> playlist;
1972 sort_track_selection ();
1974 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1976 RouteTimeAxisView* rtv;
1978 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
1980 boost::shared_ptr<Track> t = rtv->track();
1982 if (t != 0 && ! t->diskstream()->destructive()) {
1984 if ((playlist = rtv->playlist()) != 0) {
1986 begin_reversible_command (_("separate"));
1992 before = &(playlist->get_state());
1994 /* XXX need to consider musical time selections here at some point */
1996 double speed = t->diskstream()->speed();
1998 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
1999 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2003 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2009 if (doing_undo) commit_reversible_command ();
2013 Editor::separate_regions_using_location (Location& loc)
2017 bool doing_undo = false;
2019 if (loc.is_mark()) {
2023 boost::shared_ptr<Playlist> playlist;
2025 /* XXX i'm unsure as to whether this should operate on selected tracks only
2026 or the entire enchillada. uncomment the below line to correct the behaviour
2027 (currently set for all tracks)
2030 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2031 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2033 RouteTimeAxisView* rtv;
2035 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2037 boost::shared_ptr<Track> t = rtv->track();
2039 if (t != 0 && ! t->diskstream()->destructive()) {
2041 if ((playlist = rtv->playlist()) != 0) {
2045 begin_reversible_command (_("separate"));
2049 before = &(playlist->get_state());
2052 /* XXX need to consider musical time selections here at some point */
2054 double speed = rtv->get_diskstream()->speed();
2057 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2059 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2065 if (doing_undo) commit_reversible_command ();
2069 Editor::crop_region_to_selection ()
2071 if (selection->time.empty() || selection->tracks.empty()) {
2075 vector<boost::shared_ptr<Playlist> > playlists;
2076 boost::shared_ptr<Playlist> playlist;
2078 sort_track_selection ();
2080 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2082 RouteTimeAxisView* rtv;
2084 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2086 boost::shared_ptr<Track> t = rtv->track();
2088 if (t != 0 && ! t->diskstream()->destructive()) {
2090 if ((playlist = rtv->playlist()) != 0) {
2091 playlists.push_back (playlist);
2097 if (playlists.empty()) {
2105 begin_reversible_command (_("trim to selection"));
2107 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2109 boost::shared_ptr<Region> region;
2111 start = selection->time.start();
2113 if ((region = (*i)->top_region_at(start)) == 0) {
2117 /* now adjust lengths to that we do the right thing
2118 if the selection extends beyond the region
2121 start = max (start, region->position());
2122 if (max_frames - start < region->length()) {
2123 end = start + region->length() - 1;
2127 end = min (selection->time.end_frame(), end);
2128 cnt = end - start + 1;
2130 XMLNode &before = (*i)->get_state();
2131 region->trim_to (start, cnt, this);
2132 XMLNode &after = (*i)->get_state();
2133 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2136 commit_reversible_command ();
2140 Editor::region_fill_track ()
2144 if (!session || selection->regions.empty()) {
2148 end = session->current_end_frame ();
2150 begin_reversible_command (_("region fill"));
2152 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2154 boost::shared_ptr<Region> region ((*i)->region());
2157 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2160 boost::shared_ptr<Playlist> pl = region->playlist();
2162 if (end <= region->last_frame()) {
2166 double times = (double) (end - region->last_frame()) / (double) region->length();
2172 XMLNode &before = pl->get_state();
2173 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2174 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2177 commit_reversible_command ();
2181 Editor::region_fill_selection ()
2183 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2187 if (selection->time.empty()) {
2192 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2194 if (selected->count_selected_rows() != 1) {
2198 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2199 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2201 nframes_t start = selection->time[clicked_selection].start;
2202 nframes_t end = selection->time[clicked_selection].end;
2204 boost::shared_ptr<Playlist> playlist;
2206 if (selection->tracks.empty()) {
2210 nframes_t selection_length = end - start;
2211 float times = (float)selection_length / region->length();
2213 begin_reversible_command (_("fill selection"));
2215 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2217 if ((playlist = (*i)->playlist()) == 0) {
2221 XMLNode &before = playlist->get_state();
2222 playlist->add_region (RegionFactory::create (region), start, times);
2223 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2226 commit_reversible_command ();
2230 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2233 if (!region->covers (position)) {
2234 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2237 begin_reversible_command (_("set region sync position"));
2238 XMLNode &before = region->playlist()->get_state();
2239 region->set_sync_position (position);
2240 XMLNode &after = region->playlist()->get_state();
2241 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2242 commit_reversible_command ();
2245 /** Set the sync position of the selection using the position of the edit cursor */
2247 Editor::set_region_sync_from_edit_cursor ()
2249 /* Check that at the edit cursor is in at least one of the selected regions */
2250 RegionSelection::const_iterator i = selection->regions.begin();
2251 while (i != selection->regions.end() && !(*i)->region()->covers (edit_cursor->current_frame)) {
2255 /* Give the user a hint if not */
2256 if (i == selection->regions.end()) {
2257 error << _("Place the edit cursor at the desired sync point") << endmsg;
2261 begin_reversible_command (_("set sync from edit cursor"));
2263 for (RegionSelection::iterator j = selection->regions.begin(); j != selection->regions.end(); ++j) {
2264 boost::shared_ptr<Region> r = (*j)->region();
2265 XMLNode &before = r->playlist()->get_state();
2266 r->set_sync_position (edit_cursor->current_frame);
2267 XMLNode &after = r->playlist()->get_state();
2268 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
2271 commit_reversible_command ();
2274 /** Remove the sync positions of the selection */
2276 Editor::remove_region_sync ()
2278 begin_reversible_command (_("remove sync"));
2280 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2281 boost::shared_ptr<Region> r = (*i)->region();
2282 XMLNode &before = r->playlist()->get_state();
2283 r->clear_sync_position ();
2284 XMLNode &after = r->playlist()->get_state();
2285 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
2288 commit_reversible_command ();
2292 Editor::naturalize ()
2294 if (selection->regions.empty()) {
2297 begin_reversible_command (_("naturalize"));
2298 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2299 XMLNode &before = (*i)->region()->get_state();
2300 (*i)->region()->move_to_natural_position (this);
2301 XMLNode &after = (*i)->region()->get_state();
2302 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2304 commit_reversible_command ();
2308 Editor::align (RegionPoint what)
2310 align_selection (what, edit_cursor->current_frame);
2314 Editor::align_relative (RegionPoint what)
2316 align_selection_relative (what, edit_cursor->current_frame);
2319 struct RegionSortByTime {
2320 bool operator() (const RegionView* a, const RegionView* b) {
2321 return a->region()->position() < b->region()->position();
2326 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2328 if (selection->regions.empty()) {
2336 list<RegionView*> sorted;
2337 selection->regions.by_position (sorted);
2338 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2342 pos = r->first_frame ();
2346 pos = r->last_frame();
2350 pos = r->adjust_to_sync (r->first_frame());
2354 if (pos > position) {
2355 distance = pos - position;
2358 distance = position - pos;
2362 begin_reversible_command (_("align selection (relative)"));
2364 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2366 boost::shared_ptr<Region> region ((*i)->region());
2368 XMLNode &before = region->playlist()->get_state();
2371 region->set_position (region->position() + distance, this);
2373 region->set_position (region->position() - distance, this);
2376 XMLNode &after = region->playlist()->get_state();
2377 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2381 commit_reversible_command ();
2385 Editor::align_selection (RegionPoint point, nframes_t position)
2387 if (selection->regions.empty()) {
2391 begin_reversible_command (_("align selection"));
2393 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2394 align_region_internal ((*i)->region(), point, position);
2397 commit_reversible_command ();
2401 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2403 begin_reversible_command (_("align region"));
2404 align_region_internal (region, point, position);
2405 commit_reversible_command ();
2409 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2411 XMLNode &before = region->playlist()->get_state();
2415 region->set_position (region->adjust_to_sync (position), this);
2419 if (position > region->length()) {
2420 region->set_position (position - region->length(), this);
2425 region->set_position (position, this);
2429 XMLNode &after = region->playlist()->get_state();
2430 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2433 /** Trim the end of the selected regions to the position of the edit cursor */
2435 Editor::trim_region_to_edit_cursor ()
2437 if (selection->regions.empty()) {
2441 begin_reversible_command (_("trim to edit"));
2443 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2444 boost::shared_ptr<Region> region ((*i)->region());
2447 RouteTimeAxisView *rtav;
2449 /* XXX I don't think clicked_axisview should be used here! */
2450 if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
2451 if (rtav->get_diskstream() != 0) {
2452 speed = rtav->get_diskstream()->speed();
2456 XMLNode &before = region->playlist()->get_state();
2457 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2458 XMLNode &after = region->playlist()->get_state();
2459 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2462 commit_reversible_command ();
2465 /** Trim the start of the selected regions to the position of the edit cursor */
2467 Editor::trim_region_from_edit_cursor ()
2469 if (selection->regions.empty()) {
2473 begin_reversible_command (_("trim to edit"));
2475 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2476 boost::shared_ptr<Region> region ((*i)->region());
2479 RouteTimeAxisView *rtav;
2481 /* XXX: not sure about clicked_axisview here */
2482 if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
2483 if (rtav->get_diskstream() != 0) {
2484 speed = rtav->get_diskstream()->speed();
2488 XMLNode &before = region->playlist()->get_state();
2489 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2490 XMLNode &after = region->playlist()->get_state();
2491 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2494 commit_reversible_command ();
2497 /** Unfreeze selected routes */
2499 Editor::unfreeze_routes ()
2501 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2502 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*i);
2503 if (atv && atv->is_audio_track()) {
2504 atv->audio_track()->unfreeze ();
2510 Editor::_freeze_thread (void* arg)
2512 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2513 return static_cast<Editor*>(arg)->freeze_thread ();
2517 Editor::freeze_thread ()
2519 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2520 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*i);
2521 if (atv && atv->is_audio_track()) {
2522 atv->audio_track()->freeze (*current_interthread_info);
2526 current_interthread_info->done = true;
2532 Editor::freeze_progress_timeout (void *arg)
2534 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2535 return !(current_interthread_info->done || current_interthread_info->cancel);
2538 /** Freeze selected routes */
2540 Editor::freeze_routes ()
2542 InterThreadInfo itt;
2544 if (interthread_progress_window == 0) {
2545 build_interthread_progress_window ();
2548 WindowTitle title(Glib::get_application_name());
2549 title += _("Freeze");
2550 interthread_progress_window->set_title (title.get_string());
2551 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2552 interthread_progress_window->show_all ();
2553 interthread_progress_bar.set_fraction (0.0f);
2554 interthread_progress_label.set_text ("");
2555 interthread_cancel_label.set_text (_("Cancel Freeze"));
2556 current_interthread_info = &itt;
2558 interthread_progress_connection =
2559 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2563 itt.progress = 0.0f;
2565 pthread_attr_t attr;
2566 pthread_attr_init(&attr);
2567 pthread_attr_setstacksize(&attr, 500000);
2569 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2571 pthread_attr_destroy(&attr);
2573 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2575 while (!itt.done && !itt.cancel) {
2576 gtk_main_iteration ();
2579 interthread_progress_connection.disconnect ();
2580 interthread_progress_window->hide_all ();
2581 current_interthread_info = 0;
2582 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2586 Editor::bounce_range_selection ()
2588 if (selection->time.empty()) {
2592 TrackSelection views = selection->tracks;
2594 nframes_t start = selection->time[clicked_selection].start;
2595 nframes_t end = selection->time[clicked_selection].end;
2596 nframes_t cnt = end - start + 1;
2598 begin_reversible_command (_("bounce range"));
2600 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2602 RouteTimeAxisView* rtv;
2604 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
2608 boost::shared_ptr<Playlist> playlist;
2610 if ((playlist = rtv->playlist()) == 0) {
2614 InterThreadInfo itt;
2618 itt.progress = false;
2620 XMLNode &before = playlist->get_state();
2621 rtv->track()->bounce_range (start, cnt, itt);
2622 XMLNode &after = playlist->get_state();
2623 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2626 commit_reversible_command ();
2629 /** Cut selected regions, automation points or a time range */
2636 /** Copy selected regions, automation points or a time range */
2644 /** @return true if a Cut, Copy or Clear is possible */
2646 Editor::can_cut_copy () const
2648 switch (current_mouse_mode()) {
2651 if (!selection->regions.empty() || !selection->points.empty()) {
2657 if (!selection->time.empty()) {
2670 /** Cut, copy or clear selected regions, automation points or a time range.
2671 * @param op Operation (Cut, Copy or Clear)
2674 Editor::cut_copy (CutCopyOp op)
2676 /* only cancel selection if cut/copy is successful.*/
2688 opname = _("clear");
2692 cut_buffer->clear ();
2694 switch (current_mouse_mode()) {
2696 if (!selection->regions.empty() || !selection->points.empty()) {
2698 begin_reversible_command (opname + _(" objects"));
2700 if (!selection->regions.empty()) {
2702 cut_copy_regions (op);
2705 selection->clear_regions ();
2709 if (!selection->points.empty()) {
2710 cut_copy_points (op);
2713 selection->clear_points ();
2717 commit_reversible_command ();
2722 if (!selection->time.empty()) {
2724 begin_reversible_command (opname + _(" range"));
2725 cut_copy_ranges (op);
2726 commit_reversible_command ();
2729 selection->clear_time ();
2740 /** Cut, copy or clear selected automation points.
2741 * @param op Operation (Cut, Copy or Clear)
2744 Editor::cut_copy_points (CutCopyOp op)
2746 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2748 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2751 atv->cut_copy_clear_objects (selection->points, op);
2756 struct PlaylistState {
2757 boost::shared_ptr<Playlist> playlist;
2761 struct lt_playlist {
2762 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2763 return a.playlist < b.playlist;
2767 struct PlaylistMapping {
2769 boost::shared_ptr<Playlist> pl;
2771 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2775 /** Cut, copy or clear selected regions.
2776 * @param op Operation (Cut, Copy or Clear)
2779 Editor::cut_copy_regions (CutCopyOp op)
2781 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2782 a map when we want ordered access to both elements. i think.
2785 vector<PlaylistMapping> pmap;
2787 nframes_t first_position = max_frames;
2789 set<PlaylistState, lt_playlist> freezelist;
2790 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2792 /* get ordering correct before we cut/copy */
2794 selection->regions.sort_by_position_and_track ();
2796 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2798 first_position = min ((*x)->region()->position(), first_position);
2800 if (op == Cut || op == Clear) {
2801 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
2805 PlaylistState before;
2806 before.playlist = pl;
2807 before.before = &pl->get_state();
2809 insert_result = freezelist.insert (before);
2811 if (insert_result.second) {
2817 TimeAxisView* tv = &(*x)->get_trackview();
2818 vector<PlaylistMapping>::iterator z;
2820 for (z = pmap.begin(); z != pmap.end(); ++z) {
2821 if ((*z).tv == tv) {
2826 if (z == pmap.end()) {
2827 pmap.push_back (PlaylistMapping (tv));
2831 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2833 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
2836 /* impossible, but this handles it for the future */
2840 TimeAxisView& tv = (*x)->get_trackview();
2841 boost::shared_ptr<Playlist> npl;
2842 RegionSelection::iterator tmp;
2847 vector<PlaylistMapping>::iterator z;
2849 for (z = pmap.begin(); z != pmap.end(); ++z) {
2850 if ((*z).tv == &tv) {
2855 assert (z != pmap.end());
2858 npl = PlaylistFactory::create (pl->data_type(), *session, "cutlist", true);
2865 boost::shared_ptr<Region> r = (*x)->region();
2866 boost::shared_ptr<Region> _xx;
2872 _xx = RegionFactory::create (r);
2873 npl->add_region (_xx, r->position() - first_position);
2874 pl->remove_region (r);
2878 /* copy region before adding, so we're not putting same object into two different playlists */
2879 npl->add_region (RegionFactory::create (r), r->position() - first_position);
2883 pl->remove_region (r);
2890 list<boost::shared_ptr<Playlist> > foo;
2892 /* the pmap is in the same order as the tracks in which selected regions occured */
2894 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2896 foo.push_back ((*i).pl);
2901 cut_buffer->set (foo);
2904 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2905 (*pl).playlist->thaw ();
2906 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2911 Editor::cut_copy_ranges (CutCopyOp op)
2913 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2914 (*i)->cut_copy_clear (*selection, op);
2919 Editor::paste (float times)
2921 paste_internal (edit_cursor->current_frame, times);
2925 Editor::mouse_paste ()
2930 track_canvas.get_pointer (x, y);
2931 track_canvas.window_to_world (x, y, wx, wy);
2932 wx += horizontal_adjustment.get_value();
2933 wy += vertical_adjustment.get_value();
2936 event.type = GDK_BUTTON_RELEASE;
2937 event.button.x = wx;
2938 event.button.y = wy;
2940 nframes_t where = event_frame (&event, 0, 0);
2942 paste_internal (where, 1);
2946 Editor::paste_internal (nframes_t position, float times)
2948 bool commit = false;
2950 if (cut_buffer->empty() || selection->tracks.empty()) {
2954 if (position == max_frames) {
2955 position = edit_cursor->current_frame;
2958 begin_reversible_command (_("paste"));
2960 TrackSelection::iterator i;
2963 /* get everything in the correct order */
2965 sort_track_selection ();
2967 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
2969 /* undo/redo is handled by individual tracks */
2971 if ((*i)->paste (position, times, *cut_buffer, nth)) {
2977 commit_reversible_command ();
2982 Editor::paste_named_selection (float times)
2984 TrackSelection::iterator t;
2986 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
2988 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
2992 TreeModel::iterator i = selected->get_selected();
2993 NamedSelection* ns = (*i)[named_selection_columns.selection];
2995 list<boost::shared_ptr<Playlist> >::iterator chunk;
2996 list<boost::shared_ptr<Playlist> >::iterator tmp;
2998 chunk = ns->playlists.begin();
3000 begin_reversible_command (_("paste chunk"));
3002 sort_track_selection ();
3004 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3006 RouteTimeAxisView* rtv;
3007 boost::shared_ptr<Playlist> pl;
3008 boost::shared_ptr<AudioPlaylist> apl;
3010 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*t)) == 0) {
3014 if ((pl = rtv->playlist()) == 0) {
3018 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3025 XMLNode &before = apl->get_state();
3026 apl->paste (*chunk, edit_cursor->current_frame, times);
3027 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3029 if (tmp != ns->playlists.end()) {
3034 commit_reversible_command();
3038 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3040 boost::shared_ptr<Playlist> playlist;
3041 RegionSelection sel = regions; // clear (below) will clear the argument list
3043 begin_reversible_command (_("duplicate region"));
3045 selection->clear_regions ();
3047 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3049 boost::shared_ptr<Region> r ((*i)->region());
3051 TimeAxisView& tv = (*i)->get_time_axis_view();
3052 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3053 sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3055 playlist = (*i)->region()->playlist();
3056 XMLNode &before = playlist->get_state();
3057 playlist->duplicate (r, r->last_frame(), times);
3058 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3062 if (latest_regionview) {
3063 selection->add (latest_regionview);
3068 commit_reversible_command ();
3072 Editor::duplicate_selection (float times)
3074 if (selection->time.empty() || selection->tracks.empty()) {
3078 boost::shared_ptr<Playlist> playlist;
3079 vector<boost::shared_ptr<AudioRegion> > new_regions;
3080 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3082 create_region_from_selection (new_regions);
3084 if (new_regions.empty()) {
3088 begin_reversible_command (_("duplicate selection"));
3090 ri = new_regions.begin();
3092 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3093 if ((playlist = (*i)->playlist()) == 0) {
3096 XMLNode &before = playlist->get_state();
3097 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3098 XMLNode &after = playlist->get_state();
3099 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3102 if (ri == new_regions.end()) {
3107 commit_reversible_command ();
3111 Editor::reset_point_selection ()
3113 /* reset all selected points to the relevant default value */
3115 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3117 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3120 atv->reset_objects (selection->points);
3126 Editor::center_playhead ()
3128 float page = canvas_width * frames_per_unit;
3130 center_screen_internal (playhead_cursor->current_frame, page);
3134 Editor::center_edit_cursor ()
3136 float page = canvas_width * frames_per_unit;
3138 center_screen_internal (edit_cursor->current_frame, page);
3142 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3144 begin_reversible_command (_("clear playlist"));
3145 XMLNode &before = playlist->get_state();
3147 XMLNode &after = playlist->get_state();
3148 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3149 commit_reversible_command ();
3153 Editor::nudge_selected_tracks (bool use_edit_cursor, bool forwards)
3155 boost::shared_ptr<Playlist> playlist;
3157 nframes_t next_distance;
3160 if (use_edit_cursor) {
3161 start = edit_cursor->current_frame;
3166 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3170 if (selection->tracks.empty()) {
3174 begin_reversible_command (_("nudge track"));
3176 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3178 if ((playlist = (*i)->playlist()) == 0) {
3182 XMLNode &before = playlist->get_state();
3183 playlist->nudge_after (start, distance, forwards);
3184 XMLNode &after = playlist->get_state();
3185 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3188 commit_reversible_command ();
3192 Editor::remove_last_capture ()
3194 vector<string> choices;
3201 if (Config->get_verify_remove_last_capture()) {
3202 prompt = _("Do you really want to destroy the last capture?"
3203 "\n(This is destructive and cannot be undone)");
3205 choices.push_back (_("No, do nothing."));
3206 choices.push_back (_("Yes, destroy it."));
3208 Gtkmm2ext::Choice prompter (prompt, choices);
3210 if (prompter.run () == 1) {
3211 session->remove_last_capture ();
3215 session->remove_last_capture();
3220 Editor::normalize_regions ()
3226 if (selection->regions.empty()) {
3230 begin_reversible_command (_("normalize"));
3232 track_canvas.get_window()->set_cursor (*wait_cursor);
3235 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3236 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3239 XMLNode &before = arv->region()->get_state();
3240 arv->audio_region()->normalize_to (0.0f);
3241 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3244 commit_reversible_command ();
3245 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3250 Editor::denormalize_regions ()
3256 if (selection->regions.empty()) {
3260 begin_reversible_command ("denormalize");
3262 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3263 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3266 XMLNode &before = arv->region()->get_state();
3267 arv->audio_region()->set_scale_amplitude (1.0f);
3268 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3271 commit_reversible_command ();
3276 Editor::reverse_regions ()
3282 Reverse rev (*session);
3283 apply_filter (rev, _("reverse regions"));
3288 Editor::quantize_regions ()
3294 // FIXME: varying meter?
3295 Quantize quant (*session, snap_length_beats(0));
3296 apply_filter (quant, _("quantize regions"));
3300 Editor::apply_filter (Filter& filter, string command)
3302 if (selection->regions.empty()) {
3306 begin_reversible_command (command);
3308 track_canvas.get_window()->set_cursor (*wait_cursor);
3312 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3313 RegionSelection::iterator tmp = r;
3316 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
3318 if (mrv->midi_region()->apply(filter) == 0) {
3319 mrv->redisplay_model();
3323 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3325 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3327 if (arv->audio_region()->apply (filter) == 0) {
3329 XMLNode &before = playlist->get_state();
3330 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3331 XMLNode &after = playlist->get_state();
3332 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3341 commit_reversible_command ();
3342 selection->regions.clear ();
3345 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3349 Editor::region_selection_op (void (Region::*pmf)(void))
3351 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3352 Region* region = (*i)->region().get();
3359 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3361 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3362 Region* region = (*i)->region().get();
3363 (region->*pmf)(arg);
3368 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3370 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3371 Region* region = (*i)->region().get();
3377 Editor::external_edit_region ()
3383 Editor::brush (nframes_t pos)
3385 RegionSelection sel;
3388 if (selection->regions.empty()) {
3389 /* XXX get selection from region list */
3391 sel = selection->regions;
3398 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3399 mouse_brush_insert_region ((*i), pos);
3404 Editor::reset_region_gain_envelopes ()
3406 if (!session || selection->regions.empty()) {
3410 session->begin_reversible_command (_("reset region gain"));
3412 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3413 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3415 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
3416 XMLNode& before (alist->get_state());
3418 arv->audio_region()->set_default_envelope ();
3419 session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
3423 session->commit_reversible_command ();
3426 /** Set whether or not gain envelopes are visible for the selected regions.
3427 * @param yn true to make visible, false to make invisible.
3430 Editor::set_gain_envelope_visibility (bool yn)
3432 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3433 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3435 if (arv->envelope_visible() != yn) {
3436 arv->set_envelope_visible (yn);
3442 /** Set whether or not gain envelopes are active for the selected regions.
3443 * @param yn true to make active, false to make inactive.
3446 Editor::set_gain_envelope_active (bool yn)
3448 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3449 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3451 if (arv->audio_region()->envelope_active() != yn) {
3452 arv->audio_region()->set_envelope_active (yn);
3458 /** Set the locked state of all selected regions to a particular value.
3459 * @param yn true to make locked, false to make unlocked.
3462 Editor::set_region_lock (bool yn)
3464 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3465 (*i)->region()->set_locked (yn);
3469 /** Set the position-locked state of all selected regions to a particular value.
3470 * @param yn true to make locked, false to make unlocked.
3473 Editor::set_region_position_lock (bool yn)
3475 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3476 (*i)->region()->set_position_locked (yn);
3481 Editor::set_region_mute (bool yn)
3483 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3484 (*i)->region()->set_muted (yn);
3489 Editor::set_region_opaque (bool yn)
3491 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3492 (*i)->region()->set_opaque (yn);
3497 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3499 begin_reversible_command (_("set fade in shape"));
3501 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3502 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3508 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
3509 XMLNode &before = alist->get_state();
3511 tmp->audio_region()->set_fade_in_shape (shape);
3513 XMLNode &after = alist->get_state();
3514 session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
3517 commit_reversible_command ();
3521 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3523 begin_reversible_command (_("set fade out shape"));
3525 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3526 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3532 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
3533 XMLNode &before = alist->get_state();
3535 tmp->audio_region()->set_fade_out_shape (shape);
3537 XMLNode &after = alist->get_state();
3538 session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
3541 commit_reversible_command ();
3545 Editor::set_fade_in_active (bool yn)
3547 begin_reversible_command (_("set fade in active"));
3549 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3550 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3557 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3559 XMLNode &before = ar->get_state();
3561 ar->set_fade_in_active (yn);
3563 XMLNode &after = ar->get_state();
3564 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3569 Editor::set_fade_out_active (bool yn)
3571 begin_reversible_command (_("set fade out active"));
3573 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3574 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3580 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3582 XMLNode &before = ar->get_state();
3584 ar->set_fade_out_active (yn);
3586 XMLNode &after = ar->get_state();
3587 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3592 /** Update crossfade visibility after its configuration has been changed */
3594 Editor::update_xfade_visibility ()
3596 _xfade_visibility = Config->get_xfades_visible ();
3598 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3599 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3601 if (_xfade_visibility) {
3602 v->show_all_xfades ();
3604 v->hide_all_xfades ();