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::playhead_backward ()
767 if (get_prefix (prefix, was_floating)) {
771 cnt = (nframes_t) floor (prefix * session->frame_rate ());
773 cnt = (nframes_t) prefix;
777 pos = playhead_cursor->current_frame;
779 if ((nframes_t) pos < cnt) {
785 /* XXX this is completely insane. with the current buffering
786 design, we'll force a complete track buffer flush and
787 reload, just to move 1 sample !!!
790 session->request_locate (pos);
794 Editor::playhead_forward ()
801 if (get_prefix (prefix, was_floating)) {
805 cnt = (nframes_t) floor (prefix * session->frame_rate ());
807 cnt = (nframes_t) floor (prefix);
811 pos = playhead_cursor->current_frame;
813 /* XXX this is completely insane. with the current buffering
814 design, we'll force a complete track buffer flush and
815 reload, just to move 1 sample !!!
818 session->request_locate (pos+cnt);
822 Editor::cursor_align (bool playhead_to_edit)
824 if (playhead_to_edit) {
826 session->request_locate (edit_cursor->current_frame);
829 edit_cursor->set_position (playhead_cursor->current_frame);
834 Editor::edit_cursor_backward ()
841 if (get_prefix (prefix, was_floating)) {
845 cnt = (nframes_t) floor (prefix * session->frame_rate ());
847 cnt = (nframes_t) prefix;
851 pos = edit_cursor->current_frame;
853 if ((nframes_t) pos < cnt) {
859 edit_cursor->set_position (pos);
863 Editor::edit_cursor_forward ()
870 if (get_prefix (prefix, was_floating)) {
874 cnt = (nframes_t) floor (prefix * session->frame_rate ());
876 cnt = (nframes_t) floor (prefix);
880 pos = edit_cursor->current_frame;
881 edit_cursor->set_position (pos+cnt);
885 Editor::goto_frame ()
891 if (get_prefix (prefix, was_floating)) {
896 frame = (nframes_t) floor (prefix * session->frame_rate());
898 frame = (nframes_t) floor (prefix);
901 session->request_locate (frame);
905 Editor::scroll_backward (float pages)
908 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
913 if (get_prefix (prefix, was_floating)) {
914 cnt = (nframes_t) floor (pages * one_page);
917 cnt = (nframes_t) floor (prefix * session->frame_rate());
919 cnt = (nframes_t) floor (prefix * one_page);
923 if (leftmost_frame < cnt) {
926 frame = leftmost_frame - cnt;
929 reposition_x_origin (frame);
933 Editor::scroll_forward (float pages)
936 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
941 if (get_prefix (prefix, was_floating)) {
942 cnt = (nframes_t) floor (pages * one_page);
945 cnt = (nframes_t) floor (prefix * session->frame_rate());
947 cnt = (nframes_t) floor (prefix * one_page);
951 if (max_frames - cnt < leftmost_frame) {
952 frame = max_frames - cnt;
954 frame = leftmost_frame + cnt;
957 reposition_x_origin (frame);
961 Editor::scroll_tracks_down ()
967 if (get_prefix (prefix, was_floating)) {
970 cnt = (int) floor (prefix);
973 double vert_value = vertical_adjustment.get_value() + (cnt *
974 vertical_adjustment.get_page_size());
975 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
976 vert_value = vertical_adjustment.get_upper() - canvas_height;
978 vertical_adjustment.set_value (vert_value);
982 Editor::scroll_tracks_up ()
988 if (get_prefix (prefix, was_floating)) {
991 cnt = (int) floor (prefix);
994 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
998 Editor::scroll_tracks_down_line ()
1001 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1002 double vert_value = adj->get_value() + 20;
1004 if (vert_value>adj->get_upper() - canvas_height) {
1005 vert_value = adj->get_upper() - canvas_height;
1007 adj->set_value (vert_value);
1011 Editor::scroll_tracks_up_line ()
1013 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1014 adj->set_value (adj->get_value() - 20);
1020 Editor::temporal_zoom_step (bool coarser)
1022 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1026 nfpu = frames_per_unit;
1031 nfpu = max(1.0,(nfpu/1.61803399));
1034 temporal_zoom (nfpu);
1038 Editor::temporal_zoom (gdouble fpu)
1040 if (!session) return;
1042 nframes_t current_page = current_page_frames();
1043 nframes_t current_leftmost = leftmost_frame;
1044 nframes_t current_rightmost;
1045 nframes_t current_center;
1047 nframes_t leftmost_after_zoom = 0;
1052 new_page = (nframes_t) floor (canvas_width * nfpu);
1054 switch (zoom_focus) {
1056 leftmost_after_zoom = current_leftmost;
1059 case ZoomFocusRight:
1060 current_rightmost = leftmost_frame + current_page;
1061 if (current_rightmost > new_page) {
1062 leftmost_after_zoom = current_rightmost - new_page;
1064 leftmost_after_zoom = 0;
1068 case ZoomFocusCenter:
1069 current_center = current_leftmost + (current_page/2);
1070 if (current_center > (new_page/2)) {
1071 leftmost_after_zoom = current_center - (new_page / 2);
1073 leftmost_after_zoom = 0;
1077 case ZoomFocusPlayhead:
1078 /* try to keep the playhead in the center */
1079 if (playhead_cursor->current_frame > new_page/2) {
1080 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1082 leftmost_after_zoom = 0;
1087 /* try to keep the edit cursor in the center */
1088 if (edit_cursor->current_frame > new_page/2) {
1089 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1091 leftmost_after_zoom = 0;
1097 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1099 // begin_reversible_command (_("zoom"));
1100 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1101 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1102 // commit_reversible_command ();
1104 reposition_and_zoom (leftmost_after_zoom, nfpu);
1108 Editor::temporal_zoom_selection ()
1110 if (!selection) return;
1112 if (selection->time.empty()) {
1116 nframes_t start = selection->time[clicked_selection].start;
1117 nframes_t end = selection->time[clicked_selection].end;
1119 temporal_zoom_by_frame (start, end, "zoom to selection");
1123 Editor::temporal_zoom_session ()
1125 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1128 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1133 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1135 if (!session) return;
1137 if ((start == 0 && end == 0) || end < start) {
1141 nframes_t range = end - start;
1143 double new_fpu = (double)range / (double)canvas_width;
1146 // while (p2 < new_fpu) {
1151 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1152 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1153 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1155 if (new_leftmost > middle) new_leftmost = 0;
1157 // begin_reversible_command (op);
1158 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1159 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1160 // commit_reversible_command ();
1162 reposition_and_zoom (new_leftmost, new_fpu);
1166 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1168 if (!session) return;
1170 double range_before = frame - leftmost_frame;
1173 new_fpu = frames_per_unit;
1176 new_fpu *= 1.61803399;
1177 range_before *= 1.61803399;
1179 new_fpu = max(1.0,(new_fpu/1.61803399));
1180 range_before /= 1.61803399;
1183 if (new_fpu == frames_per_unit) return;
1185 nframes_t new_leftmost = frame - (nframes_t)range_before;
1187 if (new_leftmost > frame) new_leftmost = 0;
1189 // begin_reversible_command (_("zoom to frame"));
1190 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1191 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1192 // commit_reversible_command ();
1194 reposition_and_zoom (new_leftmost, new_fpu);
1198 Editor::add_location_from_selection ()
1202 if (selection->time.empty()) {
1206 if (session == 0 || clicked_trackview == 0) {
1210 nframes_t start = selection->time[clicked_selection].start;
1211 nframes_t end = selection->time[clicked_selection].end;
1213 session->locations()->next_available_name(rangename,"selection");
1214 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1216 session->begin_reversible_command (_("add marker"));
1217 XMLNode &before = session->locations()->get_state();
1218 session->locations()->add (location, true);
1219 XMLNode &after = session->locations()->get_state();
1220 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1221 session->commit_reversible_command ();
1225 Editor::add_location_from_playhead_cursor ()
1229 nframes_t where = session->audible_frame();
1231 session->locations()->next_available_name(markername,"mark");
1232 Location *location = new Location (where, where, markername, Location::IsMark);
1233 session->begin_reversible_command (_("add marker"));
1234 XMLNode &before = session->locations()->get_state();
1235 session->locations()->add (location, true);
1236 XMLNode &after = session->locations()->get_state();
1237 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1238 session->commit_reversible_command ();
1242 Editor::add_location_from_audio_region ()
1244 if (selection->regions.empty()) {
1248 RegionView* rv = *(selection->regions.begin());
1249 boost::shared_ptr<Region> region = rv->region();
1251 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1252 session->begin_reversible_command (_("add marker"));
1253 XMLNode &before = session->locations()->get_state();
1254 session->locations()->add (location, true);
1255 XMLNode &after = session->locations()->get_state();
1256 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1257 session->commit_reversible_command ();
1261 Editor::select_all_in_track (Selection::Operation op)
1263 list<Selectable *> touched;
1265 if (!clicked_trackview) {
1269 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1272 case Selection::Toggle:
1273 selection->add (touched);
1275 case Selection::Set:
1276 selection->set (touched);
1278 case Selection::Extend:
1279 /* not defined yet */
1281 case Selection::Add:
1282 selection->add (touched);
1288 Editor::select_all (Selection::Operation op)
1290 list<Selectable *> touched;
1292 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1293 if ((*iter)->hidden()) {
1296 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1298 begin_reversible_command (_("select all"));
1300 case Selection::Add:
1301 case Selection::Toggle:
1302 selection->add (touched);
1304 case Selection::Set:
1305 selection->set (touched);
1307 case Selection::Extend:
1308 /* not defined yet */
1311 commit_reversible_command ();
1315 Editor::invert_selection_in_track ()
1317 list<Selectable *> touched;
1319 if (!clicked_trackview) {
1323 clicked_trackview->get_inverted_selectables (*selection, touched);
1324 selection->set (touched);
1328 Editor::invert_selection ()
1330 list<Selectable *> touched;
1332 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1333 if ((*iter)->hidden()) {
1336 (*iter)->get_inverted_selectables (*selection, touched);
1339 selection->set (touched);
1343 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, Selection::Operation op)
1345 list<Selectable *> touched;
1347 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1348 if ((*iter)->hidden()) {
1351 (*iter)->get_selectables (start, end, top, bot, touched);
1354 cerr << "select all within found " << touched.size() << endl;
1356 begin_reversible_command (_("select all within"));
1358 case Selection::Add:
1359 case Selection::Toggle:
1361 selection->add (touched);
1363 case Selection::Set:
1365 selection->set (touched);
1367 case Selection::Extend:
1369 /* not defined yet */
1373 cerr << "selection now has " << selection->points.size() << endl;
1375 commit_reversible_command ();
1376 return !touched.empty();
1380 Editor::set_selection_from_audio_region ()
1382 if (selection->regions.empty()) {
1386 RegionView* rv = *(selection->regions.begin());
1387 boost::shared_ptr<Region> region = rv->region();
1389 begin_reversible_command (_("set selection from region"));
1390 selection->set (0, region->position(), region->last_frame());
1391 commit_reversible_command ();
1393 set_mouse_mode (Editing::MouseRange, false);
1397 Editor::set_selection_from_punch()
1401 if ((location = session->locations()->auto_punch_location()) == 0) {
1405 set_selection_from_range (*location);
1409 Editor::set_selection_from_loop()
1413 if ((location = session->locations()->auto_loop_location()) == 0) {
1416 set_selection_from_range (*location);
1420 Editor::set_selection_from_range (Location& loc)
1422 begin_reversible_command (_("set selection from range"));
1423 selection->set (0, loc.start(), loc.end());
1424 commit_reversible_command ();
1426 set_mouse_mode (Editing::MouseRange, false);
1430 Editor::select_all_selectables_using_time_selection ()
1432 list<Selectable *> touched;
1434 if (selection->time.empty()) {
1438 nframes_t start = selection->time[clicked_selection].start;
1439 nframes_t end = selection->time[clicked_selection].end;
1441 if (end - start < 1) {
1445 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1446 if ((*iter)->hidden()) {
1449 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1452 begin_reversible_command (_("select all from range"));
1453 selection->set (touched);
1454 commit_reversible_command ();
1459 Editor::select_all_selectables_using_punch()
1461 Location* location = session->locations()->auto_punch_location();
1462 list<Selectable *> touched;
1464 if (location == 0 || (location->end() - location->start() <= 1)) {
1468 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1469 if ((*iter)->hidden()) {
1472 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1474 begin_reversible_command (_("select all from punch"));
1475 selection->set (touched);
1476 commit_reversible_command ();
1481 Editor::select_all_selectables_using_loop()
1483 Location* location = session->locations()->auto_loop_location();
1484 list<Selectable *> touched;
1486 if (location == 0 || (location->end() - location->start() <= 1)) {
1490 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1491 if ((*iter)->hidden()) {
1494 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1496 begin_reversible_command (_("select all from loop"));
1497 selection->set (touched);
1498 commit_reversible_command ();
1503 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1507 list<Selectable *> touched;
1510 begin_reversible_command (_("select all after cursor"));
1511 start = cursor->current_frame ;
1512 end = session->current_end_frame();
1514 if (cursor->current_frame > 0) {
1515 begin_reversible_command (_("select all before cursor"));
1517 end = cursor->current_frame - 1;
1523 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1524 if ((*iter)->hidden()) {
1527 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1529 selection->set (touched);
1530 commit_reversible_command ();
1534 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1538 list<Selectable *> touched;
1539 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1541 if (cursor->current_frame == other_cursor->current_frame) {
1545 begin_reversible_command (_("select all between cursors"));
1546 if (other_cursor_is_first) {
1547 start = other_cursor->current_frame;
1548 end = cursor->current_frame - 1;
1551 start = cursor->current_frame;
1552 end = other_cursor->current_frame - 1;
1555 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1556 if ((*iter)->hidden()) {
1559 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1561 selection->set (touched);
1562 commit_reversible_command ();
1566 Editor::amplitude_zoom_step (bool in)
1580 #ifdef FIX_FOR_CANVAS
1581 /* XXX DO SOMETHING */
1590 Editor::delete_sample_forward ()
1595 Editor::delete_sample_backward ()
1600 Editor::delete_screen ()
1607 Editor::search_backwards ()
1613 Editor::search_forwards ()
1621 Editor::jump_forward_to_mark ()
1627 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1630 session->request_locate (location->start(), session->transport_rolling());
1632 session->request_locate (session->current_end_frame());
1637 Editor::jump_backward_to_mark ()
1643 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1646 session->request_locate (location->start(), session->transport_rolling());
1648 session->goto_start ();
1660 if (get_prefix (prefix, was_floating)) {
1661 pos = session->audible_frame ();
1664 pos = (nframes_t) floor (prefix * session->frame_rate ());
1666 pos = (nframes_t) floor (prefix);
1670 session->locations()->next_available_name(markername,"mark");
1671 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1675 Editor::clear_markers ()
1678 session->begin_reversible_command (_("clear markers"));
1679 XMLNode &before = session->locations()->get_state();
1680 session->locations()->clear_markers ();
1681 XMLNode &after = session->locations()->get_state();
1682 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1683 session->commit_reversible_command ();
1688 Editor::clear_ranges ()
1691 session->begin_reversible_command (_("clear ranges"));
1692 XMLNode &before = session->locations()->get_state();
1694 Location * looploc = session->locations()->auto_loop_location();
1695 Location * punchloc = session->locations()->auto_punch_location();
1697 session->locations()->clear_ranges ();
1699 if (looploc) session->locations()->add (looploc);
1700 if (punchloc) session->locations()->add (punchloc);
1702 XMLNode &after = session->locations()->get_state();
1703 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1704 session->commit_reversible_command ();
1709 Editor::clear_locations ()
1711 session->begin_reversible_command (_("clear locations"));
1712 XMLNode &before = session->locations()->get_state();
1713 session->locations()->clear ();
1714 XMLNode &after = session->locations()->get_state();
1715 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1716 session->commit_reversible_command ();
1717 session->locations()->clear ();
1721 Editor::unhide_markers ()
1723 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1724 Location *l = (*i).first;
1725 if (l->is_hidden() && l->is_mark()) {
1726 l->set_hidden(false, this);
1732 Editor::unhide_ranges ()
1734 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1735 Location *l = (*i).first;
1736 if (l->is_hidden() && l->is_range_marker()) {
1737 l->set_hidden(false, this);
1742 /* INSERT/REPLACE */
1745 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1751 AudioTimeAxisView *atv = 0;
1752 boost::shared_ptr<Playlist> playlist;
1754 track_canvas.window_to_world (x, y, wx, wy);
1755 wx += horizontal_adjustment.get_value();
1756 wy += vertical_adjustment.get_value();
1759 event.type = GDK_BUTTON_RELEASE;
1760 event.button.x = wx;
1761 event.button.y = wy;
1763 where = event_frame (&event, &cx, &cy);
1765 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1766 /* clearly outside canvas area */
1770 if ((tv = trackview_by_y_position (cy)) == 0) {
1774 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1778 if ((playlist = atv->playlist()) == 0) {
1782 cerr << "drop target playlist, UC = " << playlist.use_count() << endl;
1786 begin_reversible_command (_("insert dragged region"));
1787 XMLNode &before = playlist->get_state();
1788 cerr << "pre add target playlist, UC = " << playlist.use_count() << endl;
1789 playlist->add_region (RegionFactory::create (region), where, 1.0);
1790 cerr << "post add target playlist, UC = " << playlist.use_count() << endl;
1791 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1792 commit_reversible_command ();
1794 cerr << "post drop target playlist, UC = " << playlist.use_count() << endl;
1798 Editor::insert_region_list_selection (float times)
1800 RouteTimeAxisView *tv = 0;
1801 boost::shared_ptr<Playlist> playlist;
1803 if (clicked_audio_trackview != 0) {
1804 tv = clicked_audio_trackview;
1805 } else if (!selection->tracks.empty()) {
1806 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1813 if ((playlist = tv->playlist()) == 0) {
1817 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1819 if (selected->count_selected_rows() != 1) {
1823 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1825 /* only one row selected, so rows.begin() is it */
1829 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1831 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1833 begin_reversible_command (_("insert region"));
1834 XMLNode &before = playlist->get_state();
1835 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1836 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1837 commit_reversible_command ();
1841 /* BUILT-IN EFFECTS */
1844 Editor::reverse_selection ()
1849 /* GAIN ENVELOPE EDITING */
1852 Editor::edit_envelope ()
1859 Editor::toggle_playback (bool with_abort)
1865 switch (Config->get_slave_source()) {
1870 /* transport controlled by the master */
1874 if (session->is_auditioning()) {
1875 session->cancel_audition ();
1879 if (session->transport_rolling()) {
1880 session->request_stop (with_abort);
1881 if (session->get_play_loop()) {
1882 session->request_play_loop (false);
1885 session->request_transport_speed (1.0f);
1890 Editor::play_from_start ()
1892 session->request_locate (session->current_start_frame(), true);
1896 Editor::play_from_edit_cursor ()
1898 session->request_locate (edit_cursor->current_frame, true);
1902 Editor::play_selection ()
1904 if (selection->time.empty()) {
1908 session->request_play_range (true);
1912 Editor::play_selected_region ()
1914 if (!selection->regions.empty()) {
1915 RegionView *rv = *(selection->regions.begin());
1917 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1922 Editor::loop_selected_region ()
1924 if (!selection->regions.empty()) {
1925 RegionView *rv = *(selection->regions.begin());
1928 if ((tll = transport_loop_location()) != 0) {
1930 tll->set (rv->region()->position(), rv->region()->last_frame());
1932 // enable looping, reposition and start rolling
1934 session->request_play_loop (true);
1935 session->request_locate (tll->start(), false);
1936 session->request_transport_speed (1.0f);
1942 Editor::play_location (Location& location)
1944 if (location.start() <= location.end()) {
1948 session->request_bounded_roll (location.start(), location.end());
1952 Editor::loop_location (Location& location)
1954 if (location.start() <= location.end()) {
1960 if ((tll = transport_loop_location()) != 0) {
1961 tll->set (location.start(), location.end());
1963 // enable looping, reposition and start rolling
1964 session->request_play_loop (true);
1965 session->request_locate (tll->start(), true);
1970 Editor::raise_region ()
1972 selection->foreach_region (&Region::raise);
1976 Editor::raise_region_to_top ()
1978 selection->foreach_region (&Region::raise_to_top);
1982 Editor::lower_region ()
1984 selection->foreach_region (&Region::lower);
1988 Editor::lower_region_to_bottom ()
1990 selection->foreach_region (&Region::lower_to_bottom);
1994 Editor::edit_region ()
1996 if (clicked_regionview == 0) {
2000 clicked_regionview->show_region_editor ();
2004 Editor::rename_region ()
2008 Button ok_button (_("OK"));
2009 Button cancel_button (_("Cancel"));
2011 if (selection->regions.empty()) {
2015 dialog.set_title (_("ardour: rename region"));
2016 dialog.set_name ("RegionRenameWindow");
2017 dialog.set_size_request (300, -1);
2018 dialog.set_position (Gtk::WIN_POS_MOUSE);
2019 dialog.set_modal (true);
2021 dialog.get_vbox()->set_border_width (10);
2022 dialog.get_vbox()->pack_start (entry);
2023 dialog.get_action_area()->pack_start (ok_button);
2024 dialog.get_action_area()->pack_start (cancel_button);
2026 entry.set_name ("RegionNameDisplay");
2027 ok_button.set_name ("EditorGTKButton");
2028 cancel_button.set_name ("EditorGTKButton");
2030 region_renamed = false;
2032 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2033 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2034 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2041 if (region_renamed) {
2042 (*selection->regions.begin())->region()->set_name (entry.get_text());
2043 redisplay_regions ();
2048 Editor::rename_region_finished (bool status)
2051 region_renamed = status;
2056 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2058 if (session->is_auditioning()) {
2059 session->cancel_audition ();
2062 // note: some potential for creativity here, because region doesn't
2063 // have to belong to the playlist that Route is handling
2065 // bool was_soloed = route.soloed();
2067 route.set_solo (true, this);
2069 session->request_bounded_roll (region->position(), region->position() + region->length());
2071 /* XXX how to unset the solo state ? */
2075 Editor::audition_selected_region ()
2077 if (!selection->regions.empty()) {
2078 RegionView* rv = *(selection->regions.begin());
2079 session->audition_region (rv->region());
2084 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2086 session->audition_region (region);
2090 Editor::build_interthread_progress_window ()
2092 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2094 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2096 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2097 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2099 // GTK2FIX: this button needs a modifiable label
2101 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2102 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2104 interthread_cancel_button.add (interthread_cancel_label);
2106 interthread_progress_window->set_default_size (200, 100);
2110 Editor::interthread_cancel_clicked ()
2112 if (current_interthread_info) {
2113 current_interthread_info->cancel = true;
2118 Editor::region_from_selection ()
2120 if (clicked_trackview == 0) {
2124 if (selection->time.empty()) {
2128 nframes_t start = selection->time[clicked_selection].start;
2129 nframes_t end = selection->time[clicked_selection].end;
2131 nframes_t selection_cnt = end - start + 1;
2133 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2134 boost::shared_ptr<AudioRegion> current;
2135 boost::shared_ptr<Region> current_r;
2136 boost::shared_ptr<Playlist> pl;
2138 nframes_t internal_start;
2141 if ((pl = (*i)->playlist()) == 0) {
2145 if ((current_r = pl->top_region_at (start)) == 0) {
2149 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2150 // FIXME: audio only
2152 internal_start = start - current->position();
2153 session->region_name (new_name, current->name(), true);
2154 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2160 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2162 if (selection->time.empty() || selection->tracks.empty()) {
2166 nframes_t start = selection->time[clicked_selection].start;
2167 nframes_t end = selection->time[clicked_selection].end;
2169 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2171 boost::shared_ptr<AudioRegion> current;
2172 boost::shared_ptr<Region> current_r;
2173 boost::shared_ptr<Playlist> playlist;
2174 nframes_t internal_start;
2177 if ((playlist = (*i)->playlist()) == 0) {
2181 if ((current_r = playlist->top_region_at(start)) == 0) {
2185 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2189 internal_start = start - current->position();
2190 session->region_name (new_name, current->name(), true);
2192 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2197 Editor::split_multichannel_region ()
2199 vector<AudioRegion*> v;
2201 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2203 if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2207 clicked_arv->audio_region()->separate_by_channel (*session, v);
2209 /* nothing else to do, really */
2213 Editor::new_region_from_selection ()
2215 region_from_selection ();
2216 cancel_selection ();
2220 Editor::separate_region_from_selection ()
2222 bool doing_undo = false;
2224 if (selection->time.empty()) {
2228 boost::shared_ptr<Playlist> playlist;
2230 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2232 AudioTimeAxisView* atv;
2234 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2236 if (atv->is_audio_track()) {
2238 if ((playlist = atv->playlist()) != 0) {
2240 begin_reversible_command (_("separate"));
2245 before = &(playlist->get_state());
2247 /* XXX need to consider musical time selections here at some point */
2249 double speed = atv->get_diskstream()->speed();
2251 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2252 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2256 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2262 if (doing_undo) commit_reversible_command ();
2266 Editor::separate_regions_using_location (Location& loc)
2268 bool doing_undo = false;
2270 if (loc.is_mark()) {
2274 boost::shared_ptr<Playlist> playlist;
2276 /* XXX i'm unsure as to whether this should operate on selected tracks only
2277 or the entire enchillada. uncomment the below line to correct the behaviour
2278 (currently set for all tracks)
2281 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2282 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2284 AudioTimeAxisView* atv;
2286 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2288 if (atv->is_audio_track()) {
2290 if ((playlist = atv->playlist()) != 0) {
2293 begin_reversible_command (_("separate"));
2297 before = &(playlist->get_state());
2300 /* XXX need to consider musical time selections here at some point */
2302 double speed = atv->get_diskstream()->speed();
2305 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2307 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2313 if (doing_undo) commit_reversible_command ();
2317 Editor::crop_region_to_selection ()
2319 if (selection->time.empty()) {
2323 vector<boost::shared_ptr<Playlist> > playlists;
2324 boost::shared_ptr<Playlist> playlist;
2326 if (clicked_trackview != 0) {
2328 if ((playlist = clicked_trackview->playlist()) == 0) {
2332 playlists.push_back (playlist);
2336 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2338 AudioTimeAxisView* atv;
2340 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2342 if (atv->is_audio_track()) {
2344 if ((playlist = atv->playlist()) != 0) {
2345 playlists.push_back (playlist);
2352 if (!playlists.empty()) {
2358 begin_reversible_command (_("trim to selection"));
2360 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2362 boost::shared_ptr<Region> region;
2364 start = selection->time.start();
2366 if ((region = (*i)->top_region_at(start)) == 0) {
2370 /* now adjust lengths to that we do the right thing
2371 if the selection extends beyond the region
2374 start = max (start, region->position());
2375 end = min (selection->time.end_frame(), start + region->length() - 1);
2376 cnt = end - start + 1;
2378 XMLNode &before = (*i)->get_state();
2379 region->trim_to (start, cnt, this);
2380 XMLNode &after = (*i)->get_state();
2381 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2384 commit_reversible_command ();
2389 Editor::region_fill_track ()
2393 if (!session || selection->regions.empty()) {
2397 end = session->current_end_frame ();
2399 begin_reversible_command (_("region fill"));
2401 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2403 boost::shared_ptr<Region> region ((*i)->region());
2406 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2410 boost::shared_ptr<Playlist> pl = region->playlist();
2412 if (end <= region->last_frame()) {
2416 double times = (double) (end - region->last_frame()) / (double) region->length();
2422 XMLNode &before = pl->get_state();
2423 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2424 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2427 commit_reversible_command ();
2431 Editor::region_fill_selection ()
2433 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2437 if (selection->time.empty()) {
2442 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2444 if (selected->count_selected_rows() != 1) {
2448 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2449 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2451 nframes_t start = selection->time[clicked_selection].start;
2452 nframes_t end = selection->time[clicked_selection].end;
2454 boost::shared_ptr<Playlist> playlist;
2456 if (selection->tracks.empty()) {
2460 nframes_t selection_length = end - start;
2461 float times = (float)selection_length / region->length();
2463 begin_reversible_command (_("fill selection"));
2465 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2467 if ((playlist = (*i)->playlist()) == 0) {
2471 XMLNode &before = playlist->get_state();
2472 playlist->add_region (RegionFactory::create (region), start, times);
2473 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2476 commit_reversible_command ();
2480 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2483 if (!region->covers (position)) {
2484 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2487 begin_reversible_command (_("set region sync position"));
2488 XMLNode &before = region->playlist()->get_state();
2489 region->set_sync_position (position);
2490 XMLNode &after = region->playlist()->get_state();
2491 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2492 commit_reversible_command ();
2496 Editor::set_region_sync_from_edit_cursor ()
2498 if (clicked_regionview == 0) {
2502 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2503 error << _("Place the edit cursor at the desired sync point") << endmsg;
2507 boost::shared_ptr<Region> region (clicked_regionview->region());
2508 begin_reversible_command (_("set sync from edit cursor"));
2509 XMLNode &before = region->playlist()->get_state();
2510 region->set_sync_position (edit_cursor->current_frame);
2511 XMLNode &after = region->playlist()->get_state();
2512 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2513 commit_reversible_command ();
2517 Editor::remove_region_sync ()
2519 if (clicked_regionview) {
2520 boost::shared_ptr<Region> region (clicked_regionview->region());
2521 begin_reversible_command (_("remove sync"));
2522 XMLNode &before = region->playlist()->get_state();
2523 region->clear_sync_position ();
2524 XMLNode &after = region->playlist()->get_state();
2525 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2526 commit_reversible_command ();
2531 Editor::naturalize ()
2533 if (selection->regions.empty()) {
2536 begin_reversible_command (_("naturalize"));
2537 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2538 XMLNode &before = (*i)->region()->get_state();
2539 (*i)->region()->move_to_natural_position (this);
2540 XMLNode &after = (*i)->region()->get_state();
2541 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2543 commit_reversible_command ();
2547 Editor::align (RegionPoint what)
2549 align_selection (what, edit_cursor->current_frame);
2553 Editor::align_relative (RegionPoint what)
2555 align_selection_relative (what, edit_cursor->current_frame);
2558 struct RegionSortByTime {
2559 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2560 return a->region()->position() < b->region()->position();
2565 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2567 if (selection->regions.empty()) {
2575 list<RegionView*> sorted;
2576 selection->regions.by_position (sorted);
2577 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2581 pos = r->first_frame ();
2585 pos = r->last_frame();
2589 pos = r->adjust_to_sync (r->first_frame());
2593 if (pos > position) {
2594 distance = pos - position;
2597 distance = position - pos;
2601 begin_reversible_command (_("align selection (relative)"));
2603 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2605 boost::shared_ptr<Region> region ((*i)->region());
2607 XMLNode &before = region->playlist()->get_state();
2610 region->set_position (region->position() + distance, this);
2612 region->set_position (region->position() - distance, this);
2615 XMLNode &after = region->playlist()->get_state();
2616 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2620 commit_reversible_command ();
2624 Editor::align_selection (RegionPoint point, nframes_t position)
2626 if (selection->regions.empty()) {
2630 begin_reversible_command (_("align selection"));
2632 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2633 align_region_internal ((*i)->region(), point, position);
2636 commit_reversible_command ();
2640 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2642 begin_reversible_command (_("align region"));
2643 align_region_internal (region, point, position);
2644 commit_reversible_command ();
2648 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2650 XMLNode &before = region->playlist()->get_state();
2654 region->set_position (region->adjust_to_sync (position), this);
2658 if (position > region->length()) {
2659 region->set_position (position - region->length(), this);
2664 region->set_position (position, this);
2668 XMLNode &after = region->playlist()->get_state();
2669 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2673 Editor::trim_region_to_edit_cursor ()
2675 if (clicked_regionview == 0) {
2679 boost::shared_ptr<Region> region (clicked_regionview->region());
2682 AudioTimeAxisView *atav;
2684 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2685 if (atav->get_diskstream() != 0) {
2686 speed = atav->get_diskstream()->speed();
2690 begin_reversible_command (_("trim to edit"));
2691 XMLNode &before = region->playlist()->get_state();
2692 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2693 XMLNode &after = region->playlist()->get_state();
2694 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2695 commit_reversible_command ();
2699 Editor::trim_region_from_edit_cursor ()
2701 if (clicked_regionview == 0) {
2705 boost::shared_ptr<Region> region (clicked_regionview->region());
2708 AudioTimeAxisView *atav;
2710 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2711 if (atav->get_diskstream() != 0) {
2712 speed = atav->get_diskstream()->speed();
2716 begin_reversible_command (_("trim to edit"));
2717 XMLNode &before = region->playlist()->get_state();
2718 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2719 XMLNode &after = region->playlist()->get_state();
2720 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2721 commit_reversible_command ();
2725 Editor::unfreeze_route ()
2727 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2731 clicked_audio_trackview->audio_track()->unfreeze ();
2735 Editor::_freeze_thread (void* arg)
2737 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2738 return static_cast<Editor*>(arg)->freeze_thread ();
2742 Editor::freeze_thread ()
2744 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2749 Editor::freeze_progress_timeout (void *arg)
2751 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2752 return !(current_interthread_info->done || current_interthread_info->cancel);
2756 Editor::freeze_route ()
2758 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2762 InterThreadInfo itt;
2764 if (interthread_progress_window == 0) {
2765 build_interthread_progress_window ();
2768 interthread_progress_window->set_title (_("ardour: freeze"));
2769 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2770 interthread_progress_window->show_all ();
2771 interthread_progress_bar.set_fraction (0.0f);
2772 interthread_progress_label.set_text ("");
2773 interthread_cancel_label.set_text (_("Cancel Freeze"));
2774 current_interthread_info = &itt;
2776 interthread_progress_connection =
2777 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2781 itt.progress = 0.0f;
2783 pthread_attr_t attr;
2784 pthread_attr_init(&attr);
2785 pthread_attr_setstacksize(&attr, 500000);
2787 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2789 pthread_attr_destroy(&attr);
2791 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2793 while (!itt.done && !itt.cancel) {
2794 gtk_main_iteration ();
2797 interthread_progress_connection.disconnect ();
2798 interthread_progress_window->hide_all ();
2799 current_interthread_info = 0;
2800 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2804 Editor::bounce_range_selection ()
2806 if (selection->time.empty()) {
2810 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2812 nframes_t start = selection->time[clicked_selection].start;
2813 nframes_t end = selection->time[clicked_selection].end;
2814 nframes_t cnt = end - start + 1;
2816 begin_reversible_command (_("bounce range"));
2818 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2820 AudioTimeAxisView* atv;
2822 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2826 boost::shared_ptr<Playlist> playlist;
2828 if ((playlist = atv->playlist()) == 0) {
2832 InterThreadInfo itt;
2836 itt.progress = false;
2838 XMLNode &before = playlist->get_state();
2839 atv->audio_track()->bounce_range (start, cnt, itt);
2840 XMLNode &after = playlist->get_state();
2841 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2844 commit_reversible_command ();
2862 Editor::cut_copy (CutCopyOp op)
2864 /* only cancel selection if cut/copy is successful.*/
2876 opname = _("clear");
2880 cut_buffer->clear ();
2882 switch (current_mouse_mode()) {
2884 if (!selection->regions.empty() || !selection->points.empty()) {
2886 begin_reversible_command (opname + _(" objects"));
2888 if (!selection->regions.empty()) {
2890 cut_copy_regions (op);
2893 selection->clear_regions ();
2897 if (!selection->points.empty()) {
2898 cut_copy_points (op);
2901 selection->clear_points ();
2905 commit_reversible_command ();
2910 if (!selection->time.empty()) {
2912 begin_reversible_command (opname + _(" range"));
2913 cut_copy_ranges (op);
2914 commit_reversible_command ();
2917 selection->clear_time ();
2929 Editor::cut_copy_points (CutCopyOp op)
2931 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2933 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2936 atv->cut_copy_clear_objects (selection->points, op);
2941 struct PlaylistState {
2942 boost::shared_ptr<Playlist> playlist;
2946 struct lt_playlist {
2947 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2948 return a.playlist < b.playlist;
2953 Editor::cut_copy_regions (CutCopyOp op)
2955 typedef std::map<boost::shared_ptr<AudioPlaylist>,boost::shared_ptr<AudioPlaylist> > PlaylistMapping;
2956 PlaylistMapping pmap;
2957 nframes_t first_position = max_frames;
2959 set<PlaylistState, lt_playlist> freezelist;
2960 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2962 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2963 first_position = min ((*x)->region()->position(), first_position);
2965 if (op == Cut || op == Clear) {
2966 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2970 PlaylistState before;
2971 before.playlist = pl;
2972 before.before = &pl->get_state();
2974 insert_result = freezelist.insert (before);
2976 if (insert_result.second) {
2983 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2985 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2986 boost::shared_ptr<AudioPlaylist> npl;
2987 RegionSelection::iterator tmp;
2994 PlaylistMapping::iterator pi = pmap.find (pl);
2996 if (pi == pmap.end()) {
2997 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3005 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3010 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3011 pl->remove_region (((*x)->region()));
3017 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3021 pl->remove_region (((*x)->region()));
3029 list<boost::shared_ptr<Playlist> > foo;
3031 for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3032 foo.push_back (i->second);
3036 cut_buffer->set (foo);
3039 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3040 (*pl).playlist->thaw ();
3041 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3046 Editor::cut_copy_ranges (CutCopyOp op)
3048 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3049 (*i)->cut_copy_clear (*selection, op);
3054 Editor::paste (float times)
3056 paste_internal (edit_cursor->current_frame, times);
3060 Editor::mouse_paste ()
3065 track_canvas.get_pointer (x, y);
3066 track_canvas.window_to_world (x, y, wx, wy);
3067 wx += horizontal_adjustment.get_value();
3068 wy += vertical_adjustment.get_value();
3071 event.type = GDK_BUTTON_RELEASE;
3072 event.button.x = wx;
3073 event.button.y = wy;
3075 nframes_t where = event_frame (&event, 0, 0);
3077 paste_internal (where, 1);
3081 Editor::paste_internal (nframes_t position, float times)
3083 bool commit = false;
3085 if (cut_buffer->empty() || selection->tracks.empty()) {
3089 if (position == max_frames) {
3090 position = edit_cursor->current_frame;
3093 begin_reversible_command (_("paste"));
3095 TrackSelection::iterator i;
3098 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3100 /* undo/redo is handled by individual tracks */
3102 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3108 commit_reversible_command ();
3113 Editor::paste_named_selection (float times)
3115 TrackSelection::iterator t;
3117 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3119 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3123 TreeModel::iterator i = selected->get_selected();
3124 NamedSelection* ns = (*i)[named_selection_columns.selection];
3126 list<boost::shared_ptr<Playlist> >::iterator chunk;
3127 list<boost::shared_ptr<Playlist> >::iterator tmp;
3129 chunk = ns->playlists.begin();
3131 begin_reversible_command (_("paste chunk"));
3133 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3135 AudioTimeAxisView* atv;
3136 boost::shared_ptr<Playlist> pl;
3137 boost::shared_ptr<AudioPlaylist> apl;
3139 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3143 if ((pl = atv->playlist()) == 0) {
3147 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3154 XMLNode &before = apl->get_state();
3155 apl->paste (*chunk, edit_cursor->current_frame, times);
3156 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3158 if (tmp != ns->playlists.end()) {
3163 commit_reversible_command();
3167 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3169 boost::shared_ptr<Playlist> playlist;
3170 RegionSelection sel = regions; // clear (below) will clear the argument list
3172 begin_reversible_command (_("duplicate region"));
3174 selection->clear_regions ();
3176 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3178 boost::shared_ptr<Region> r ((*i)->region());
3180 TimeAxisView& tv = (*i)->get_time_axis_view();
3181 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3182 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3184 playlist = (*i)->region()->playlist();
3185 XMLNode &before = playlist->get_state();
3186 playlist->duplicate (r, r->last_frame(), times);
3187 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3191 if (latest_regionview) {
3192 selection->add (latest_regionview);
3197 commit_reversible_command ();
3201 Editor::duplicate_selection (float times)
3203 if (selection->time.empty() || selection->tracks.empty()) {
3207 boost::shared_ptr<Playlist> playlist;
3208 vector<boost::shared_ptr<AudioRegion> > new_regions;
3209 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3211 create_region_from_selection (new_regions);
3213 if (new_regions.empty()) {
3217 begin_reversible_command (_("duplicate selection"));
3219 ri = new_regions.begin();
3221 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3222 if ((playlist = (*i)->playlist()) == 0) {
3225 XMLNode &before = playlist->get_state();
3226 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3227 XMLNode &after = playlist->get_state();
3228 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3231 if (ri == new_regions.end()) {
3236 commit_reversible_command ();
3240 Editor::reset_point_selection ()
3242 /* reset all selected points to the relevant default value */
3244 cerr << "point selection has " << selection->points.size() << " entries\n";
3246 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3248 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3251 atv->reset_objects (selection->points);
3257 Editor::center_playhead ()
3259 float page = canvas_width * frames_per_unit;
3261 center_screen_internal (playhead_cursor->current_frame, page);
3265 Editor::center_edit_cursor ()
3267 float page = canvas_width * frames_per_unit;
3269 center_screen_internal (edit_cursor->current_frame, page);
3273 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3275 begin_reversible_command (_("clear playlist"));
3276 XMLNode &before = playlist->get_state();
3278 XMLNode &after = playlist->get_state();
3279 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3280 commit_reversible_command ();
3284 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3286 boost::shared_ptr<Playlist> playlist;
3288 nframes_t next_distance;
3291 if (use_edit_cursor) {
3292 start = edit_cursor->current_frame;
3297 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3301 if (selection->tracks.empty()) {
3305 begin_reversible_command (_("nudge track"));
3307 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3309 if ((playlist = (*i)->playlist()) == 0) {
3313 XMLNode &before = playlist->get_state();
3314 playlist->nudge_after (start, distance, forwards);
3315 XMLNode &after = playlist->get_state();
3316 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3319 commit_reversible_command ();
3323 Editor::remove_last_capture ()
3325 vector<string> choices;
3332 if (Config->get_verify_remove_last_capture()) {
3333 prompt = _("Do you really want to destroy the last capture?"
3334 "\n(This is destructive and cannot be undone)");
3336 choices.push_back (_("No, do nothing."));
3337 choices.push_back (_("Yes, destroy it."));
3339 Gtkmm2ext::Choice prompter (prompt, choices);
3341 if (prompter.run () == 1) {
3342 session->remove_last_capture ();
3346 session->remove_last_capture();
3351 Editor::normalize_region ()
3357 if (selection->regions.empty()) {
3361 begin_reversible_command (_("normalize"));
3363 track_canvas.get_window()->set_cursor (*wait_cursor);
3366 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3367 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3370 XMLNode &before = arv->region()->get_state();
3371 arv->audio_region()->normalize_to (0.0f);
3372 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3375 commit_reversible_command ();
3376 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3381 Editor::denormalize_region ()
3387 if (selection->regions.empty()) {
3391 begin_reversible_command ("denormalize");
3393 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3394 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3397 XMLNode &before = arv->region()->get_state();
3398 arv->audio_region()->set_scale_amplitude (1.0f);
3399 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3402 commit_reversible_command ();
3407 Editor::reverse_region ()
3413 Reverse rev (*session);
3414 apply_filter (rev, _("reverse regions"));
3418 Editor::apply_filter (AudioFilter& filter, string command)
3420 if (selection->regions.empty()) {
3424 begin_reversible_command (command);
3426 track_canvas.get_window()->set_cursor (*wait_cursor);
3429 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3430 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3434 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3436 RegionSelection::iterator tmp;
3441 if (arv->audio_region()->apply (filter) == 0) {
3443 XMLNode &before = playlist->get_state();
3444 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3445 XMLNode &after = playlist->get_state();
3446 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3454 commit_reversible_command ();
3455 selection->regions.clear ();
3458 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3462 Editor::region_selection_op (void (Region::*pmf)(void))
3464 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3465 Region* region = (*i)->region().get();
3472 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3474 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3475 Region* region = (*i)->region().get();
3476 (region->*pmf)(arg);
3481 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3483 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3484 Region* region = (*i)->region().get();
3490 Editor::external_edit_region ()
3492 if (!clicked_regionview) {
3500 Editor::brush (nframes_t pos)
3502 RegionSelection sel;
3505 if (selection->regions.empty()) {
3506 /* XXX get selection from region list */
3508 sel = selection->regions;
3515 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3516 mouse_brush_insert_region ((*i), pos);
3521 Editor::reset_region_gain_envelopes ()
3523 if (!session || selection->regions.empty()) {
3527 session->begin_reversible_command (_("reset region gain"));
3529 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3530 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3532 AutomationList& alist (arv->audio_region()->envelope());
3533 XMLNode& before (alist.get_state());
3535 arv->audio_region()->set_default_envelope ();
3536 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3540 session->commit_reversible_command ();
3544 Editor::toggle_gain_envelope_visibility ()
3546 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3547 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3549 bool x = region_envelope_visible_item->get_active();
3550 if (x != arv->envelope_visible()) {
3551 arv->set_envelope_visible (x);
3558 Editor::toggle_gain_envelope_active ()
3560 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3561 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3563 bool x = region_envelope_active_item->get_active();
3564 if (x != arv->audio_region()->envelope_active()) {
3565 arv->audio_region()->set_envelope_active (x);
3572 Editor::toggle_region_lock ()
3574 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3575 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3577 bool x = region_lock_item->get_active();
3578 if (x != arv->audio_region()->locked()) {
3579 arv->audio_region()->set_locked (x);
3586 Editor::toggle_region_mute ()
3588 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3589 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3591 bool x = region_mute_item->get_active();
3592 if (x != arv->audio_region()->muted()) {
3593 arv->audio_region()->set_muted (x);
3600 Editor::toggle_region_opaque ()
3602 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3603 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3605 bool x = region_opaque_item->get_active();
3606 if (x != arv->audio_region()->opaque()) {
3607 arv->audio_region()->set_opaque (x);