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.
28 #include <pbd/error.h>
29 #include <pbd/basename.h>
30 #include <pbd/pthread_utils.h>
31 #include <pbd/memento_command.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/choice.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 Editing;
73 /***********************************************************************
75 ***********************************************************************/
78 Editor::undo (uint32_t n)
86 Editor::redo (uint32_t n)
94 Editor::ensure_cursor (nframes_t *pos)
96 *pos = edit_cursor->current_frame;
101 Editor::split_region ()
103 split_region_at (edit_cursor->current_frame);
107 Editor::split_region_at (nframes_t where)
109 split_regions_at (where, selection->regions);
113 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
115 begin_reversible_command (_("split"));
118 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
120 RegionSelection::iterator tmp;
125 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
127 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
129 _new_regionviews_show_envelope = arv->envelope_visible();
132 XMLNode &before = pl->get_state();
133 pl->split_region ((*a)->region(), where);
134 XMLNode &after = pl->get_state();
135 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
141 commit_reversible_command ();
142 _new_regionviews_show_envelope = false;
146 Editor::remove_clicked_region ()
148 if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
152 boost::shared_ptr<Playlist> playlist = clicked_audio_trackview->playlist();
154 begin_reversible_command (_("remove region"));
155 XMLNode &before = playlist->get_state();
156 playlist->remove_region (clicked_regionview->region());
157 XMLNode &after = playlist->get_state();
158 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
159 commit_reversible_command ();
163 Editor::destroy_clicked_region ()
165 uint32_t selected = selection->regions.size();
167 if (!session || !selected) {
171 vector<string> choices;
174 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
175 It cannot be undone\n\
176 Do you really want to destroy %1 ?"),
178 _("these regions") : _("this region")));
180 choices.push_back (_("No, do nothing."));
183 choices.push_back (_("Yes, destroy them."));
185 choices.push_back (_("Yes, destroy it."));
188 Gtkmm2ext::Choice prompter (prompt, choices);
190 if (prompter.run() == 0) { /* first choice */
195 list<boost::shared_ptr<Region> > r;
197 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
198 r.push_back ((*i)->region());
201 session->destroy_regions (r);
205 boost::shared_ptr<Region>
206 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
209 boost::shared_ptr<Region> region;
212 if (selection->time.start () == selection->time.end_frame ()) {
214 /* no current selection-> is there a selected regionview? */
216 if (selection->regions.empty()) {
222 if (!selection->regions.empty()) {
224 rv = *(selection->regions.begin());
225 (*tv) = &rv->get_time_axis_view();
226 region = rv->region();
228 } else if (!selection->tracks.empty()) {
230 (*tv) = selection->tracks.front();
232 RouteTimeAxisView* rtv;
234 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
235 boost::shared_ptr<Playlist> pl;
237 if ((pl = rtv->playlist()) == 0) {
241 region = pl->top_region_at (start);
249 Editor::extend_selection_to_end_of_region (bool next)
252 boost::shared_ptr<Region> region;
255 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
259 if (region && selection->time.start () == selection->time.end_frame ()) {
260 start = region->position();
262 start = selection->time.start ();
265 /* Try to leave the selection with the same route if possible */
267 if ((tv = selection->time.track) == 0) {
271 begin_reversible_command (_("extend selection"));
272 selection->set (tv, start, region->position() + region->length());
273 commit_reversible_command ();
277 Editor::extend_selection_to_start_of_region (bool previous)
280 boost::shared_ptr<Region> region;
283 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
287 if (region && selection->time.start () == selection->time.end_frame ()) {
288 end = region->position() + region->length();
290 end = selection->time.end_frame ();
293 /* Try to leave the selection with the same route if possible */
295 if ((tv = selection->time.track) == 0) {
299 begin_reversible_command (_("extend selection"));
300 selection->set (tv, region->position(), end);
301 commit_reversible_command ();
306 Editor::nudge_forward (bool next)
309 nframes_t next_distance;
311 if (!session) return;
313 if (!selection->regions.empty()) {
315 begin_reversible_command (_("nudge forward"));
317 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
318 boost::shared_ptr<Region> r ((*i)->region());
320 distance = get_nudge_distance (r->position(), next_distance);
323 distance = next_distance;
326 XMLNode &before = r->playlist()->get_state();
327 r->set_position (r->position() + distance, this);
328 XMLNode &after = r->playlist()->get_state();
329 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
332 commit_reversible_command ();
335 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
336 session->request_locate (playhead_cursor->current_frame + distance);
341 Editor::nudge_backward (bool next)
344 nframes_t next_distance;
346 if (!session) return;
348 if (!selection->regions.empty()) {
350 begin_reversible_command (_("nudge forward"));
352 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
353 boost::shared_ptr<Region> r ((*i)->region());
355 distance = get_nudge_distance (r->position(), next_distance);
358 distance = next_distance;
361 XMLNode &before = r->playlist()->get_state();
363 if (r->position() > distance) {
364 r->set_position (r->position() - distance, this);
366 r->set_position (0, this);
368 XMLNode &after = r->playlist()->get_state();
369 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
372 commit_reversible_command ();
376 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
378 if (playhead_cursor->current_frame > distance) {
379 session->request_locate (playhead_cursor->current_frame - distance);
381 session->goto_start();
387 Editor::nudge_forward_capture_offset ()
391 if (!session) return;
393 if (!selection->regions.empty()) {
395 begin_reversible_command (_("nudge forward"));
397 distance = session->worst_output_latency();
399 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
400 boost::shared_ptr<Region> r ((*i)->region());
402 XMLNode &before = r->playlist()->get_state();
403 r->set_position (r->position() + distance, this);
404 XMLNode &after = r->playlist()->get_state();
405 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
408 commit_reversible_command ();
414 Editor::nudge_backward_capture_offset ()
418 if (!session) return;
420 if (!selection->regions.empty()) {
422 begin_reversible_command (_("nudge forward"));
424 distance = session->worst_output_latency();
426 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
427 boost::shared_ptr<Region> r ((*i)->region());
429 XMLNode &before = r->playlist()->get_state();
431 if (r->position() > distance) {
432 r->set_position (r->position() - distance, this);
434 r->set_position (0, this);
436 XMLNode &after = r->playlist()->get_state();
437 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
440 commit_reversible_command ();
447 Editor::move_to_start ()
449 session->goto_start ();
453 Editor::move_to_end ()
456 session->request_locate (session->current_end_frame());
460 Editor::build_region_boundary_cache ()
464 boost::shared_ptr<Region> r;
465 TrackViewList tracks;
467 region_boundary_cache.clear ();
474 case SnapToRegionStart:
477 case SnapToRegionEnd:
480 case SnapToRegionSync:
483 case SnapToRegionBoundary:
487 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
492 TimeAxisView *ontrack = 0;
494 while (pos < session->current_end_frame()) {
496 if (!selection->tracks.empty()) {
498 if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
502 } else if (clicked_trackview) {
505 t.push_back (clicked_trackview);
507 if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
513 if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
521 case SnapToRegionStart:
522 rpos = r->first_frame();
524 case SnapToRegionEnd:
525 rpos = r->last_frame();
527 case SnapToRegionSync:
528 rpos = r->adjust_to_sync (r->first_frame());
531 case SnapToRegionBoundary:
532 rpos = r->last_frame();
539 AudioTimeAxisView *atav;
541 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
542 if (atav->get_diskstream() != 0) {
543 speed = atav->get_diskstream()->speed();
547 rpos = track_frame_to_session_frame(rpos, speed);
549 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
550 if (snap_type == SnapToRegionBoundary) {
551 region_boundary_cache.push_back (r->first_frame());
553 region_boundary_cache.push_back (rpos);
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 AudioTimeAxisView *atav;
572 for (i = tracks.begin(); i != tracks.end(); ++i) {
575 boost::shared_ptr<Region> r;
578 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
579 if (atav->get_diskstream()!=0)
580 track_speed = atav->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_trackview) {
645 t.push_back (clicked_trackview);
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 AudioTimeAxisView *atav;
675 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
676 if (atav->get_diskstream() != 0) {
677 speed = atav->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_trackview == 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::select_all_in_track (Selection::Operation op)
1296 list<Selectable *> touched;
1298 if (!clicked_trackview) {
1302 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1305 case Selection::Toggle:
1306 selection->add (touched);
1308 case Selection::Set:
1309 selection->set (touched);
1311 case Selection::Extend:
1312 /* meaningless, because we're selecting everything */
1314 case Selection::Add:
1315 selection->add (touched);
1321 Editor::select_all (Selection::Operation op)
1323 list<Selectable *> touched;
1325 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1326 if ((*iter)->hidden()) {
1329 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1331 begin_reversible_command (_("select all"));
1333 case Selection::Add:
1334 selection->add (touched);
1336 case Selection::Toggle:
1337 selection->add (touched);
1339 case Selection::Set:
1340 selection->set (touched);
1342 case Selection::Extend:
1343 /* meaningless, because we're selecting everything */
1346 commit_reversible_command ();
1350 Editor::invert_selection_in_track ()
1352 list<Selectable *> touched;
1354 if (!clicked_trackview) {
1358 clicked_trackview->get_inverted_selectables (*selection, touched);
1359 selection->set (touched);
1363 Editor::invert_selection ()
1365 list<Selectable *> touched;
1367 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1368 if ((*iter)->hidden()) {
1371 (*iter)->get_inverted_selectables (*selection, touched);
1374 selection->set (touched);
1378 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, Selection::Operation op)
1380 list<Selectable*> touched;
1381 list<Selectable*>::size_type n = 0;
1382 TrackViewList touched_tracks;
1384 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1385 if ((*iter)->hidden()) {
1391 (*iter)->get_selectables (start, end, top, bot, touched);
1393 if (n != touched.size()) {
1394 touched_tracks.push_back (*iter);
1398 if (!touched_tracks.empty()) {
1400 case Selection::Add:
1401 selection->add (touched_tracks);
1403 case Selection::Toggle:
1404 selection->toggle (touched_tracks);
1406 case Selection::Set:
1407 selection->set (touched_tracks);
1409 case Selection::Extend:
1410 /* not defined yet */
1415 begin_reversible_command (_("select all within"));
1417 case Selection::Add:
1418 selection->add (touched);
1420 case Selection::Toggle:
1421 selection->toggle (touched);
1423 case Selection::Set:
1424 selection->set (touched);
1426 case Selection::Extend:
1427 /* not defined yet */
1431 commit_reversible_command ();
1432 return !touched.empty();
1436 Editor::set_selection_from_audio_region ()
1438 if (selection->regions.empty()) {
1442 RegionView* rv = *(selection->regions.begin());
1443 boost::shared_ptr<Region> region = rv->region();
1445 begin_reversible_command (_("set selection from region"));
1446 selection->set (0, region->position(), region->last_frame());
1447 commit_reversible_command ();
1449 set_mouse_mode (Editing::MouseRange, false);
1453 Editor::set_selection_from_punch()
1457 if ((location = session->locations()->auto_punch_location()) == 0) {
1461 set_selection_from_range (*location);
1465 Editor::set_selection_from_loop()
1469 if ((location = session->locations()->auto_loop_location()) == 0) {
1472 set_selection_from_range (*location);
1476 Editor::set_selection_from_range (Location& loc)
1478 begin_reversible_command (_("set selection from range"));
1479 selection->set (0, loc.start(), loc.end());
1480 commit_reversible_command ();
1482 set_mouse_mode (Editing::MouseRange, false);
1486 Editor::select_all_selectables_using_time_selection ()
1488 list<Selectable *> touched;
1490 if (selection->time.empty()) {
1494 nframes_t start = selection->time[clicked_selection].start;
1495 nframes_t end = selection->time[clicked_selection].end;
1497 if (end - start < 1) {
1501 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1502 if ((*iter)->hidden()) {
1505 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1508 begin_reversible_command (_("select all from range"));
1509 selection->set (touched);
1510 commit_reversible_command ();
1515 Editor::select_all_selectables_using_punch()
1517 Location* location = session->locations()->auto_punch_location();
1518 list<Selectable *> touched;
1520 if (location == 0 || (location->end() - location->start() <= 1)) {
1524 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1525 if ((*iter)->hidden()) {
1528 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1530 begin_reversible_command (_("select all from punch"));
1531 selection->set (touched);
1532 commit_reversible_command ();
1537 Editor::select_all_selectables_using_loop()
1539 Location* location = session->locations()->auto_loop_location();
1540 list<Selectable *> touched;
1542 if (location == 0 || (location->end() - location->start() <= 1)) {
1546 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1547 if ((*iter)->hidden()) {
1550 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1552 begin_reversible_command (_("select all from loop"));
1553 selection->set (touched);
1554 commit_reversible_command ();
1559 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1563 list<Selectable *> touched;
1566 begin_reversible_command (_("select all after cursor"));
1567 start = cursor->current_frame ;
1568 end = session->current_end_frame();
1570 if (cursor->current_frame > 0) {
1571 begin_reversible_command (_("select all before cursor"));
1573 end = cursor->current_frame - 1;
1579 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1580 if ((*iter)->hidden()) {
1583 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1585 selection->set (touched);
1586 commit_reversible_command ();
1590 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1594 list<Selectable *> touched;
1595 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1597 if (cursor->current_frame == other_cursor->current_frame) {
1601 begin_reversible_command (_("select all between cursors"));
1602 if (other_cursor_is_first) {
1603 start = other_cursor->current_frame;
1604 end = cursor->current_frame - 1;
1607 start = cursor->current_frame;
1608 end = other_cursor->current_frame - 1;
1611 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1612 if ((*iter)->hidden()) {
1615 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1617 selection->set (touched);
1618 commit_reversible_command ();
1622 Editor::amplitude_zoom_step (bool in)
1636 #ifdef FIX_FOR_CANVAS
1637 /* XXX DO SOMETHING */
1646 Editor::delete_sample_forward ()
1651 Editor::delete_sample_backward ()
1656 Editor::delete_screen ()
1663 Editor::search_backwards ()
1669 Editor::search_forwards ()
1677 Editor::jump_forward_to_mark ()
1683 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1686 session->request_locate (location->start(), session->transport_rolling());
1688 session->request_locate (session->current_end_frame());
1693 Editor::jump_backward_to_mark ()
1699 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1702 session->request_locate (location->start(), session->transport_rolling());
1704 session->goto_start ();
1716 if (get_prefix (prefix, was_floating)) {
1717 pos = session->audible_frame ();
1720 pos = (nframes_t) floor (prefix * session->frame_rate ());
1722 pos = (nframes_t) floor (prefix);
1726 session->locations()->next_available_name(markername,"mark");
1727 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1731 Editor::clear_markers ()
1734 session->begin_reversible_command (_("clear markers"));
1735 XMLNode &before = session->locations()->get_state();
1736 session->locations()->clear_markers ();
1737 XMLNode &after = session->locations()->get_state();
1738 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1739 session->commit_reversible_command ();
1744 Editor::clear_ranges ()
1747 session->begin_reversible_command (_("clear ranges"));
1748 XMLNode &before = session->locations()->get_state();
1750 Location * looploc = session->locations()->auto_loop_location();
1751 Location * punchloc = session->locations()->auto_punch_location();
1753 session->locations()->clear_ranges ();
1755 if (looploc) session->locations()->add (looploc);
1756 if (punchloc) session->locations()->add (punchloc);
1758 XMLNode &after = session->locations()->get_state();
1759 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1760 session->commit_reversible_command ();
1765 Editor::clear_locations ()
1767 session->begin_reversible_command (_("clear locations"));
1768 XMLNode &before = session->locations()->get_state();
1769 session->locations()->clear ();
1770 XMLNode &after = session->locations()->get_state();
1771 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1772 session->commit_reversible_command ();
1773 session->locations()->clear ();
1777 Editor::unhide_markers ()
1779 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1780 Location *l = (*i).first;
1781 if (l->is_hidden() && l->is_mark()) {
1782 l->set_hidden(false, this);
1788 Editor::unhide_ranges ()
1790 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1791 Location *l = (*i).first;
1792 if (l->is_hidden() && l->is_range_marker()) {
1793 l->set_hidden(false, this);
1798 /* INSERT/REPLACE */
1801 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1807 AudioTimeAxisView *atv = 0;
1808 boost::shared_ptr<Playlist> playlist;
1810 track_canvas.window_to_world (x, y, wx, wy);
1811 wx += horizontal_adjustment.get_value();
1812 wy += vertical_adjustment.get_value();
1815 event.type = GDK_BUTTON_RELEASE;
1816 event.button.x = wx;
1817 event.button.y = wy;
1819 where = event_frame (&event, &cx, &cy);
1821 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1822 /* clearly outside canvas area */
1826 if ((tv = trackview_by_y_position (cy)) == 0) {
1830 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1834 if ((playlist = atv->playlist()) == 0) {
1838 cerr << "drop target playlist, UC = " << playlist.use_count() << endl;
1842 begin_reversible_command (_("insert dragged region"));
1843 XMLNode &before = playlist->get_state();
1844 cerr << "pre add target playlist, UC = " << playlist.use_count() << endl;
1845 playlist->add_region (RegionFactory::create (region), where, 1.0);
1846 cerr << "post add target playlist, UC = " << playlist.use_count() << endl;
1847 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1848 commit_reversible_command ();
1850 cerr << "post drop target playlist, UC = " << playlist.use_count() << endl;
1854 Editor::insert_region_list_selection (float times)
1856 RouteTimeAxisView *tv = 0;
1857 boost::shared_ptr<Playlist> playlist;
1859 if (clicked_audio_trackview != 0) {
1860 tv = clicked_audio_trackview;
1861 } else if (!selection->tracks.empty()) {
1862 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1869 if ((playlist = tv->playlist()) == 0) {
1873 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1875 if (selected->count_selected_rows() != 1) {
1879 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1881 /* only one row selected, so rows.begin() is it */
1885 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1887 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1889 begin_reversible_command (_("insert region"));
1890 XMLNode &before = playlist->get_state();
1891 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1892 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1893 commit_reversible_command ();
1897 /* BUILT-IN EFFECTS */
1900 Editor::reverse_selection ()
1905 /* GAIN ENVELOPE EDITING */
1908 Editor::edit_envelope ()
1915 Editor::toggle_playback (bool with_abort)
1921 switch (Config->get_slave_source()) {
1926 /* transport controlled by the master */
1930 if (session->is_auditioning()) {
1931 session->cancel_audition ();
1935 if (session->transport_rolling()) {
1936 session->request_stop (with_abort);
1937 if (session->get_play_loop()) {
1938 session->request_play_loop (false);
1941 session->request_transport_speed (1.0f);
1946 Editor::play_from_start ()
1948 session->request_locate (session->current_start_frame(), true);
1952 Editor::play_from_edit_cursor ()
1954 session->request_locate (edit_cursor->current_frame, true);
1958 Editor::play_selection ()
1960 if (selection->time.empty()) {
1964 session->request_play_range (true);
1968 Editor::play_selected_region ()
1970 if (!selection->regions.empty()) {
1971 RegionView *rv = *(selection->regions.begin());
1973 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1978 Editor::loop_selected_region ()
1980 if (!selection->regions.empty()) {
1981 RegionView *rv = *(selection->regions.begin());
1984 if ((tll = transport_loop_location()) != 0) {
1986 tll->set (rv->region()->position(), rv->region()->last_frame());
1988 // enable looping, reposition and start rolling
1990 session->request_play_loop (true);
1991 session->request_locate (tll->start(), false);
1992 session->request_transport_speed (1.0f);
1998 Editor::play_location (Location& location)
2000 if (location.start() <= location.end()) {
2004 session->request_bounded_roll (location.start(), location.end());
2008 Editor::loop_location (Location& location)
2010 if (location.start() <= location.end()) {
2016 if ((tll = transport_loop_location()) != 0) {
2017 tll->set (location.start(), location.end());
2019 // enable looping, reposition and start rolling
2020 session->request_play_loop (true);
2021 session->request_locate (tll->start(), true);
2026 Editor::raise_region ()
2028 selection->foreach_region (&Region::raise);
2032 Editor::raise_region_to_top ()
2034 selection->foreach_region (&Region::raise_to_top);
2038 Editor::lower_region ()
2040 selection->foreach_region (&Region::lower);
2044 Editor::lower_region_to_bottom ()
2046 selection->foreach_region (&Region::lower_to_bottom);
2050 Editor::edit_region ()
2052 if (clicked_regionview == 0) {
2056 clicked_regionview->show_region_editor ();
2060 Editor::rename_region ()
2064 Button ok_button (_("OK"));
2065 Button cancel_button (_("Cancel"));
2067 if (selection->regions.empty()) {
2071 dialog.set_title (_("ardour: rename region"));
2072 dialog.set_name ("RegionRenameWindow");
2073 dialog.set_size_request (300, -1);
2074 dialog.set_position (Gtk::WIN_POS_MOUSE);
2075 dialog.set_modal (true);
2077 dialog.get_vbox()->set_border_width (10);
2078 dialog.get_vbox()->pack_start (entry);
2079 dialog.get_action_area()->pack_start (ok_button);
2080 dialog.get_action_area()->pack_start (cancel_button);
2082 entry.set_name ("RegionNameDisplay");
2083 ok_button.set_name ("EditorGTKButton");
2084 cancel_button.set_name ("EditorGTKButton");
2086 region_renamed = false;
2088 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2089 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2090 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2097 if (region_renamed) {
2098 (*selection->regions.begin())->region()->set_name (entry.get_text());
2099 redisplay_regions ();
2104 Editor::rename_region_finished (bool status)
2107 region_renamed = status;
2112 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2114 if (session->is_auditioning()) {
2115 session->cancel_audition ();
2118 // note: some potential for creativity here, because region doesn't
2119 // have to belong to the playlist that Route is handling
2121 // bool was_soloed = route.soloed();
2123 route.set_solo (true, this);
2125 session->request_bounded_roll (region->position(), region->position() + region->length());
2127 /* XXX how to unset the solo state ? */
2131 Editor::audition_selected_region ()
2133 if (!selection->regions.empty()) {
2134 RegionView* rv = *(selection->regions.begin());
2135 session->audition_region (rv->region());
2140 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2142 session->audition_region (region);
2146 Editor::build_interthread_progress_window ()
2148 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2150 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2152 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2153 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2155 // GTK2FIX: this button needs a modifiable label
2157 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2158 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2160 interthread_cancel_button.add (interthread_cancel_label);
2162 interthread_progress_window->set_default_size (200, 100);
2166 Editor::interthread_cancel_clicked ()
2168 if (current_interthread_info) {
2169 current_interthread_info->cancel = true;
2174 Editor::region_from_selection ()
2176 if (clicked_trackview == 0) {
2180 if (selection->time.empty()) {
2184 nframes_t start = selection->time[clicked_selection].start;
2185 nframes_t end = selection->time[clicked_selection].end;
2187 nframes_t selection_cnt = end - start + 1;
2189 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2190 boost::shared_ptr<AudioRegion> current;
2191 boost::shared_ptr<Region> current_r;
2192 boost::shared_ptr<Playlist> pl;
2194 nframes_t internal_start;
2197 if ((pl = (*i)->playlist()) == 0) {
2201 if ((current_r = pl->top_region_at (start)) == 0) {
2205 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2206 // FIXME: audio only
2208 internal_start = start - current->position();
2209 session->region_name (new_name, current->name(), true);
2210 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2216 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2218 if (selection->time.empty() || selection->tracks.empty()) {
2222 nframes_t start = selection->time[clicked_selection].start;
2223 nframes_t end = selection->time[clicked_selection].end;
2225 sort_track_selection ();
2227 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2229 boost::shared_ptr<AudioRegion> current;
2230 boost::shared_ptr<Region> current_r;
2231 boost::shared_ptr<Playlist> playlist;
2232 nframes_t internal_start;
2235 if ((playlist = (*i)->playlist()) == 0) {
2239 if ((current_r = playlist->top_region_at(start)) == 0) {
2243 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2247 internal_start = start - current->position();
2248 session->region_name (new_name, current->name(), true);
2250 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2255 Editor::split_multichannel_region ()
2257 vector<AudioRegion*> v;
2259 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2261 if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2265 clicked_arv->audio_region()->separate_by_channel (*session, v);
2267 /* nothing else to do, really */
2271 Editor::new_region_from_selection ()
2273 region_from_selection ();
2274 cancel_selection ();
2278 Editor::separate_region_from_selection ()
2280 bool doing_undo = false;
2282 if (selection->time.empty()) {
2286 boost::shared_ptr<Playlist> playlist;
2288 sort_track_selection ();
2290 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2292 AudioTimeAxisView* atv;
2294 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2296 if (atv->is_audio_track()) {
2298 if ((playlist = atv->playlist()) != 0) {
2300 begin_reversible_command (_("separate"));
2305 before = &(playlist->get_state());
2307 /* XXX need to consider musical time selections here at some point */
2309 double speed = atv->get_diskstream()->speed();
2311 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2312 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2316 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2322 if (doing_undo) commit_reversible_command ();
2326 Editor::separate_regions_using_location (Location& loc)
2328 bool doing_undo = false;
2330 if (loc.is_mark()) {
2334 boost::shared_ptr<Playlist> playlist;
2336 /* XXX i'm unsure as to whether this should operate on selected tracks only
2337 or the entire enchillada. uncomment the below line to correct the behaviour
2338 (currently set for all tracks)
2341 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2342 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2344 AudioTimeAxisView* atv;
2346 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2348 if (atv->is_audio_track()) {
2350 if ((playlist = atv->playlist()) != 0) {
2353 begin_reversible_command (_("separate"));
2357 before = &(playlist->get_state());
2360 /* XXX need to consider musical time selections here at some point */
2362 double speed = atv->get_diskstream()->speed();
2365 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2367 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2373 if (doing_undo) commit_reversible_command ();
2377 Editor::crop_region_to_selection ()
2379 if (selection->time.empty()) {
2383 vector<boost::shared_ptr<Playlist> > playlists;
2384 boost::shared_ptr<Playlist> playlist;
2386 if (clicked_trackview != 0) {
2388 if ((playlist = clicked_trackview->playlist()) == 0) {
2392 playlists.push_back (playlist);
2396 sort_track_selection ();
2398 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2400 AudioTimeAxisView* atv;
2402 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2404 if (atv->is_audio_track()) {
2406 if ((playlist = atv->playlist()) != 0) {
2407 playlists.push_back (playlist);
2414 if (!playlists.empty()) {
2420 begin_reversible_command (_("trim to selection"));
2422 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2424 boost::shared_ptr<Region> region;
2426 start = selection->time.start();
2428 if ((region = (*i)->top_region_at(start)) == 0) {
2432 /* now adjust lengths to that we do the right thing
2433 if the selection extends beyond the region
2436 start = max (start, region->position());
2437 end = min (selection->time.end_frame(), start + region->length() - 1);
2438 cnt = end - start + 1;
2440 XMLNode &before = (*i)->get_state();
2441 region->trim_to (start, cnt, this);
2442 XMLNode &after = (*i)->get_state();
2443 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2446 commit_reversible_command ();
2451 Editor::region_fill_track ()
2455 if (!session || selection->regions.empty()) {
2459 end = session->current_end_frame ();
2461 begin_reversible_command (_("region fill"));
2463 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2465 boost::shared_ptr<Region> region ((*i)->region());
2468 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2472 boost::shared_ptr<Playlist> pl = region->playlist();
2474 if (end <= region->last_frame()) {
2478 double times = (double) (end - region->last_frame()) / (double) region->length();
2484 XMLNode &before = pl->get_state();
2485 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2486 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2489 commit_reversible_command ();
2493 Editor::region_fill_selection ()
2495 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2499 if (selection->time.empty()) {
2504 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2506 if (selected->count_selected_rows() != 1) {
2510 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2511 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2513 nframes_t start = selection->time[clicked_selection].start;
2514 nframes_t end = selection->time[clicked_selection].end;
2516 boost::shared_ptr<Playlist> playlist;
2518 if (selection->tracks.empty()) {
2522 nframes_t selection_length = end - start;
2523 float times = (float)selection_length / region->length();
2525 begin_reversible_command (_("fill selection"));
2527 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2529 if ((playlist = (*i)->playlist()) == 0) {
2533 XMLNode &before = playlist->get_state();
2534 playlist->add_region (RegionFactory::create (region), start, times);
2535 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2538 commit_reversible_command ();
2542 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2545 if (!region->covers (position)) {
2546 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2549 begin_reversible_command (_("set region sync position"));
2550 XMLNode &before = region->playlist()->get_state();
2551 region->set_sync_position (position);
2552 XMLNode &after = region->playlist()->get_state();
2553 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2554 commit_reversible_command ();
2558 Editor::set_region_sync_from_edit_cursor ()
2560 if (clicked_regionview == 0) {
2564 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2565 error << _("Place the edit cursor at the desired sync point") << endmsg;
2569 boost::shared_ptr<Region> region (clicked_regionview->region());
2570 begin_reversible_command (_("set sync from edit cursor"));
2571 XMLNode &before = region->playlist()->get_state();
2572 region->set_sync_position (edit_cursor->current_frame);
2573 XMLNode &after = region->playlist()->get_state();
2574 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2575 commit_reversible_command ();
2579 Editor::remove_region_sync ()
2581 if (clicked_regionview) {
2582 boost::shared_ptr<Region> region (clicked_regionview->region());
2583 begin_reversible_command (_("remove sync"));
2584 XMLNode &before = region->playlist()->get_state();
2585 region->clear_sync_position ();
2586 XMLNode &after = region->playlist()->get_state();
2587 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2588 commit_reversible_command ();
2593 Editor::naturalize ()
2595 if (selection->regions.empty()) {
2598 begin_reversible_command (_("naturalize"));
2599 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2600 XMLNode &before = (*i)->region()->get_state();
2601 (*i)->region()->move_to_natural_position (this);
2602 XMLNode &after = (*i)->region()->get_state();
2603 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2605 commit_reversible_command ();
2609 Editor::align (RegionPoint what)
2611 align_selection (what, edit_cursor->current_frame);
2615 Editor::align_relative (RegionPoint what)
2617 align_selection_relative (what, edit_cursor->current_frame);
2620 struct RegionSortByTime {
2621 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2622 return a->region()->position() < b->region()->position();
2627 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2629 if (selection->regions.empty()) {
2637 list<RegionView*> sorted;
2638 selection->regions.by_position (sorted);
2639 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2643 pos = r->first_frame ();
2647 pos = r->last_frame();
2651 pos = r->adjust_to_sync (r->first_frame());
2655 if (pos > position) {
2656 distance = pos - position;
2659 distance = position - pos;
2663 begin_reversible_command (_("align selection (relative)"));
2665 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2667 boost::shared_ptr<Region> region ((*i)->region());
2669 XMLNode &before = region->playlist()->get_state();
2672 region->set_position (region->position() + distance, this);
2674 region->set_position (region->position() - distance, this);
2677 XMLNode &after = region->playlist()->get_state();
2678 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2682 commit_reversible_command ();
2686 Editor::align_selection (RegionPoint point, nframes_t position)
2688 if (selection->regions.empty()) {
2692 begin_reversible_command (_("align selection"));
2694 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2695 align_region_internal ((*i)->region(), point, position);
2698 commit_reversible_command ();
2702 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2704 begin_reversible_command (_("align region"));
2705 align_region_internal (region, point, position);
2706 commit_reversible_command ();
2710 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2712 XMLNode &before = region->playlist()->get_state();
2716 region->set_position (region->adjust_to_sync (position), this);
2720 if (position > region->length()) {
2721 region->set_position (position - region->length(), this);
2726 region->set_position (position, this);
2730 XMLNode &after = region->playlist()->get_state();
2731 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2735 Editor::trim_region_to_edit_cursor ()
2737 if (clicked_regionview == 0) {
2741 boost::shared_ptr<Region> region (clicked_regionview->region());
2744 AudioTimeAxisView *atav;
2746 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2747 if (atav->get_diskstream() != 0) {
2748 speed = atav->get_diskstream()->speed();
2752 begin_reversible_command (_("trim to edit"));
2753 XMLNode &before = region->playlist()->get_state();
2754 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2755 XMLNode &after = region->playlist()->get_state();
2756 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2757 commit_reversible_command ();
2761 Editor::trim_region_from_edit_cursor ()
2763 if (clicked_regionview == 0) {
2767 boost::shared_ptr<Region> region (clicked_regionview->region());
2770 AudioTimeAxisView *atav;
2772 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2773 if (atav->get_diskstream() != 0) {
2774 speed = atav->get_diskstream()->speed();
2778 begin_reversible_command (_("trim to edit"));
2779 XMLNode &before = region->playlist()->get_state();
2780 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2781 XMLNode &after = region->playlist()->get_state();
2782 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2783 commit_reversible_command ();
2787 Editor::unfreeze_route ()
2789 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2793 clicked_audio_trackview->audio_track()->unfreeze ();
2797 Editor::_freeze_thread (void* arg)
2799 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2800 return static_cast<Editor*>(arg)->freeze_thread ();
2804 Editor::freeze_thread ()
2806 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2811 Editor::freeze_progress_timeout (void *arg)
2813 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2814 return !(current_interthread_info->done || current_interthread_info->cancel);
2818 Editor::freeze_route ()
2820 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2824 InterThreadInfo itt;
2826 if (interthread_progress_window == 0) {
2827 build_interthread_progress_window ();
2830 interthread_progress_window->set_title (_("ardour: freeze"));
2831 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2832 interthread_progress_window->show_all ();
2833 interthread_progress_bar.set_fraction (0.0f);
2834 interthread_progress_label.set_text ("");
2835 interthread_cancel_label.set_text (_("Cancel Freeze"));
2836 current_interthread_info = &itt;
2838 interthread_progress_connection =
2839 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2843 itt.progress = 0.0f;
2845 pthread_attr_t attr;
2846 pthread_attr_init(&attr);
2847 pthread_attr_setstacksize(&attr, 500000);
2849 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2851 pthread_attr_destroy(&attr);
2853 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2855 while (!itt.done && !itt.cancel) {
2856 gtk_main_iteration ();
2859 interthread_progress_connection.disconnect ();
2860 interthread_progress_window->hide_all ();
2861 current_interthread_info = 0;
2862 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2866 Editor::bounce_range_selection ()
2868 if (selection->time.empty()) {
2872 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2874 nframes_t start = selection->time[clicked_selection].start;
2875 nframes_t end = selection->time[clicked_selection].end;
2876 nframes_t cnt = end - start + 1;
2878 begin_reversible_command (_("bounce range"));
2880 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2882 AudioTimeAxisView* atv;
2884 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2888 boost::shared_ptr<Playlist> playlist;
2890 if ((playlist = atv->playlist()) == 0) {
2894 InterThreadInfo itt;
2898 itt.progress = false;
2900 XMLNode &before = playlist->get_state();
2901 atv->audio_track()->bounce_range (start, cnt, itt);
2902 XMLNode &after = playlist->get_state();
2903 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2906 commit_reversible_command ();
2924 Editor::cut_copy (CutCopyOp op)
2926 /* only cancel selection if cut/copy is successful.*/
2938 opname = _("clear");
2942 cut_buffer->clear ();
2944 switch (current_mouse_mode()) {
2946 if (!selection->regions.empty() || !selection->points.empty()) {
2948 begin_reversible_command (opname + _(" objects"));
2950 if (!selection->regions.empty()) {
2952 cut_copy_regions (op);
2955 selection->clear_regions ();
2959 if (!selection->points.empty()) {
2960 cut_copy_points (op);
2963 selection->clear_points ();
2967 commit_reversible_command ();
2972 if (!selection->time.empty()) {
2974 begin_reversible_command (opname + _(" range"));
2975 cut_copy_ranges (op);
2976 commit_reversible_command ();
2979 selection->clear_time ();
2991 Editor::cut_copy_points (CutCopyOp op)
2993 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2995 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2998 atv->cut_copy_clear_objects (selection->points, op);
3003 struct PlaylistState {
3004 boost::shared_ptr<Playlist> playlist;
3008 struct lt_playlist {
3009 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3010 return a.playlist < b.playlist;
3014 struct PlaylistMapping {
3016 boost::shared_ptr<AudioPlaylist> pl;
3018 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3022 Editor::cut_copy_regions (CutCopyOp op)
3024 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3025 a map when we want ordered access to both elements. i think.
3028 vector<PlaylistMapping> pmap;
3030 nframes_t first_position = max_frames;
3032 set<PlaylistState, lt_playlist> freezelist;
3033 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
3035 /* get ordering correct before we cut/copy */
3037 selection->regions.sort_by_position_and_track ();
3039 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3041 first_position = min ((*x)->region()->position(), first_position);
3043 if (op == Cut || op == Clear) {
3044 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3048 PlaylistState before;
3049 before.playlist = pl;
3050 before.before = &pl->get_state();
3052 insert_result = freezelist.insert (before);
3054 if (insert_result.second) {
3060 TimeAxisView* tv = &(*x)->get_trackview();
3061 vector<PlaylistMapping>::iterator z;
3063 for (z = pmap.begin(); z != pmap.end(); ++z) {
3064 if ((*z).tv == tv) {
3069 if (z == pmap.end()) {
3070 pmap.push_back (PlaylistMapping (tv));
3074 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3076 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3079 /* impossible, but this handles it for the future */
3083 TimeAxisView& tv = (*x)->get_trackview();
3084 boost::shared_ptr<AudioPlaylist> npl;
3085 RegionSelection::iterator tmp;
3090 vector<PlaylistMapping>::iterator z;
3092 for (z = pmap.begin(); z != pmap.end(); ++z) {
3093 if ((*z).tv == &tv) {
3098 assert (z != pmap.end());
3101 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3108 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3114 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3115 pl->remove_region (((*x)->region()));
3121 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3125 pl->remove_region (((*x)->region()));
3132 list<boost::shared_ptr<Playlist> > foo;
3134 /* the pmap is in the same order as the tracks in which selected regions occured */
3136 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3138 foo.push_back ((*i).pl);
3142 cut_buffer->set (foo);
3145 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3146 (*pl).playlist->thaw ();
3147 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3152 Editor::cut_copy_ranges (CutCopyOp op)
3154 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3155 (*i)->cut_copy_clear (*selection, op);
3160 Editor::paste (float times)
3162 paste_internal (edit_cursor->current_frame, times);
3166 Editor::mouse_paste ()
3171 track_canvas.get_pointer (x, y);
3172 track_canvas.window_to_world (x, y, wx, wy);
3173 wx += horizontal_adjustment.get_value();
3174 wy += vertical_adjustment.get_value();
3177 event.type = GDK_BUTTON_RELEASE;
3178 event.button.x = wx;
3179 event.button.y = wy;
3181 nframes_t where = event_frame (&event, 0, 0);
3183 paste_internal (where, 1);
3187 Editor::paste_internal (nframes_t position, float times)
3189 bool commit = false;
3191 if (cut_buffer->empty() || selection->tracks.empty()) {
3195 if (position == max_frames) {
3196 position = edit_cursor->current_frame;
3199 begin_reversible_command (_("paste"));
3201 TrackSelection::iterator i;
3204 /* get everything in the correct order */
3206 sort_track_selection ();
3208 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3210 /* undo/redo is handled by individual tracks */
3212 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3218 commit_reversible_command ();
3223 Editor::paste_named_selection (float times)
3225 TrackSelection::iterator t;
3227 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3229 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3233 TreeModel::iterator i = selected->get_selected();
3234 NamedSelection* ns = (*i)[named_selection_columns.selection];
3236 list<boost::shared_ptr<Playlist> >::iterator chunk;
3237 list<boost::shared_ptr<Playlist> >::iterator tmp;
3239 chunk = ns->playlists.begin();
3241 begin_reversible_command (_("paste chunk"));
3243 sort_track_selection ();
3245 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3247 AudioTimeAxisView* atv;
3248 boost::shared_ptr<Playlist> pl;
3249 boost::shared_ptr<AudioPlaylist> apl;
3251 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3255 if ((pl = atv->playlist()) == 0) {
3259 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3266 XMLNode &before = apl->get_state();
3267 apl->paste (*chunk, edit_cursor->current_frame, times);
3268 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3270 if (tmp != ns->playlists.end()) {
3275 commit_reversible_command();
3279 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3281 boost::shared_ptr<Playlist> playlist;
3282 RegionSelection sel = regions; // clear (below) will clear the argument list
3284 begin_reversible_command (_("duplicate region"));
3286 selection->clear_regions ();
3288 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3290 boost::shared_ptr<Region> r ((*i)->region());
3292 TimeAxisView& tv = (*i)->get_time_axis_view();
3293 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3294 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3296 playlist = (*i)->region()->playlist();
3297 XMLNode &before = playlist->get_state();
3298 playlist->duplicate (r, r->last_frame(), times);
3299 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3303 if (latest_regionview) {
3304 selection->add (latest_regionview);
3309 commit_reversible_command ();
3313 Editor::duplicate_selection (float times)
3315 if (selection->time.empty() || selection->tracks.empty()) {
3319 boost::shared_ptr<Playlist> playlist;
3320 vector<boost::shared_ptr<AudioRegion> > new_regions;
3321 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3323 create_region_from_selection (new_regions);
3325 if (new_regions.empty()) {
3329 begin_reversible_command (_("duplicate selection"));
3331 ri = new_regions.begin();
3333 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3334 if ((playlist = (*i)->playlist()) == 0) {
3337 XMLNode &before = playlist->get_state();
3338 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3339 XMLNode &after = playlist->get_state();
3340 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3343 if (ri == new_regions.end()) {
3348 commit_reversible_command ();
3352 Editor::reset_point_selection ()
3354 /* reset all selected points to the relevant default value */
3356 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3358 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3361 atv->reset_objects (selection->points);
3367 Editor::center_playhead ()
3369 float page = canvas_width * frames_per_unit;
3371 center_screen_internal (playhead_cursor->current_frame, page);
3375 Editor::center_edit_cursor ()
3377 float page = canvas_width * frames_per_unit;
3379 center_screen_internal (edit_cursor->current_frame, page);
3383 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3385 begin_reversible_command (_("clear playlist"));
3386 XMLNode &before = playlist->get_state();
3388 XMLNode &after = playlist->get_state();
3389 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3390 commit_reversible_command ();
3394 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3396 boost::shared_ptr<Playlist> playlist;
3398 nframes_t next_distance;
3401 if (use_edit_cursor) {
3402 start = edit_cursor->current_frame;
3407 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3411 if (selection->tracks.empty()) {
3415 begin_reversible_command (_("nudge track"));
3417 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3419 if ((playlist = (*i)->playlist()) == 0) {
3423 XMLNode &before = playlist->get_state();
3424 playlist->nudge_after (start, distance, forwards);
3425 XMLNode &after = playlist->get_state();
3426 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3429 commit_reversible_command ();
3433 Editor::remove_last_capture ()
3435 vector<string> choices;
3442 if (Config->get_verify_remove_last_capture()) {
3443 prompt = _("Do you really want to destroy the last capture?"
3444 "\n(This is destructive and cannot be undone)");
3446 choices.push_back (_("No, do nothing."));
3447 choices.push_back (_("Yes, destroy it."));
3449 Gtkmm2ext::Choice prompter (prompt, choices);
3451 if (prompter.run () == 1) {
3452 session->remove_last_capture ();
3456 session->remove_last_capture();
3461 Editor::normalize_region ()
3467 if (selection->regions.empty()) {
3471 begin_reversible_command (_("normalize"));
3473 track_canvas.get_window()->set_cursor (*wait_cursor);
3476 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3477 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3480 XMLNode &before = arv->region()->get_state();
3481 arv->audio_region()->normalize_to (0.0f);
3482 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3485 commit_reversible_command ();
3486 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3491 Editor::denormalize_region ()
3497 if (selection->regions.empty()) {
3501 begin_reversible_command ("denormalize");
3503 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3504 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3507 XMLNode &before = arv->region()->get_state();
3508 arv->audio_region()->set_scale_amplitude (1.0f);
3509 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3512 commit_reversible_command ();
3517 Editor::reverse_region ()
3523 Reverse rev (*session);
3524 apply_filter (rev, _("reverse regions"));
3528 Editor::apply_filter (AudioFilter& filter, string command)
3530 if (selection->regions.empty()) {
3534 begin_reversible_command (command);
3536 track_canvas.get_window()->set_cursor (*wait_cursor);
3539 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3540 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3544 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3546 RegionSelection::iterator tmp;
3551 if (arv->audio_region()->apply (filter) == 0) {
3553 XMLNode &before = playlist->get_state();
3554 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3555 XMLNode &after = playlist->get_state();
3556 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3564 commit_reversible_command ();
3565 selection->regions.clear ();
3568 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3572 Editor::region_selection_op (void (Region::*pmf)(void))
3574 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3575 Region* region = (*i)->region().get();
3582 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3584 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3585 Region* region = (*i)->region().get();
3586 (region->*pmf)(arg);
3591 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3593 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3594 Region* region = (*i)->region().get();
3600 Editor::external_edit_region ()
3602 if (!clicked_regionview) {
3610 Editor::brush (nframes_t pos)
3612 RegionSelection sel;
3615 if (selection->regions.empty()) {
3616 /* XXX get selection from region list */
3618 sel = selection->regions;
3625 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3626 mouse_brush_insert_region ((*i), pos);
3631 Editor::reset_region_gain_envelopes ()
3633 if (!session || selection->regions.empty()) {
3637 session->begin_reversible_command (_("reset region gain"));
3639 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3640 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3642 AutomationList& alist (arv->audio_region()->envelope());
3643 XMLNode& before (alist.get_state());
3645 arv->audio_region()->set_default_envelope ();
3646 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3650 session->commit_reversible_command ();
3654 Editor::toggle_gain_envelope_visibility ()
3656 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3657 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3659 bool x = region_envelope_visible_item->get_active();
3660 if (x != arv->envelope_visible()) {
3661 arv->set_envelope_visible (x);
3668 Editor::toggle_gain_envelope_active ()
3670 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3671 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3673 bool x = region_envelope_active_item->get_active();
3674 if (x != arv->audio_region()->envelope_active()) {
3675 arv->audio_region()->set_envelope_active (x);
3682 Editor::toggle_region_lock ()
3684 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3685 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3687 bool x = region_lock_item->get_active();
3688 if (x != arv->audio_region()->locked()) {
3689 arv->audio_region()->set_locked (x);
3696 Editor::toggle_region_mute ()
3698 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3699 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3701 bool x = region_mute_item->get_active();
3702 if (x != arv->audio_region()->muted()) {
3703 arv->audio_region()->set_muted (x);
3710 Editor::toggle_region_opaque ()
3712 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3713 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3715 bool x = region_opaque_item->get_active();
3716 if (x != arv->audio_region()->opaque()) {
3717 arv->audio_region()->set_opaque (x);
3724 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3726 begin_reversible_command (_("set fade in shape"));
3728 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3729 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3735 AutomationList& alist = tmp->audio_region()->fade_in();
3736 XMLNode &before = alist.get_state();
3738 tmp->audio_region()->set_fade_in_shape (shape);
3740 XMLNode &after = alist.get_state();
3741 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3744 commit_reversible_command ();
3748 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3750 begin_reversible_command (_("set fade out shape"));
3752 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3753 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3759 AutomationList& alist = tmp->audio_region()->fade_out();
3760 XMLNode &before = alist.get_state();
3762 tmp->audio_region()->set_fade_out_shape (shape);
3764 XMLNode &after = alist.get_state();
3765 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3768 commit_reversible_command ();
3772 Editor::set_fade_in_active (bool yn)
3774 begin_reversible_command (_("set fade in active"));
3776 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3777 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3784 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3786 XMLNode &before = ar->get_state();
3788 ar->set_fade_in_active (yn);
3790 XMLNode &after = ar->get_state();
3791 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3796 Editor::set_fade_out_active (bool yn)
3798 begin_reversible_command (_("set fade out active"));
3800 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3801 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3807 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3809 XMLNode &before = ar->get_state();
3811 ar->set_fade_out_active (yn);
3813 XMLNode &after = ar->get_state();
3814 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));