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/reverse.h>
49 #include "ardour_ui.h"
51 #include "time_axis_view.h"
52 #include "audio_time_axis.h"
53 #include "automation_time_axis.h"
54 #include "streamview.h"
55 #include "audio_region_view.h"
56 #include "rgb_macros.h"
57 #include "selection_templates.h"
58 #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 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_routeview == 0 || clicked_regionview == 0) {
152 Playlist* playlist = clicked_routeview->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 int32_t selected = selection->regions.size();
167 if (!session || clicked_regionview == 0 && selected == 0) {
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);
203 } else if (clicked_regionview) {
204 session->destroy_region (clicked_regionview->region());
208 boost::shared_ptr<Region>
209 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
212 boost::shared_ptr<Region> region;
215 if (selection->time.start () == selection->time.end_frame ()) {
217 /* no current selection-> is there a selected regionview? */
219 if (selection->regions.empty()) {
225 if (!selection->regions.empty()) {
227 rv = *(selection->regions.begin());
228 (*tv) = &rv->get_time_axis_view();
229 region = rv->region();
231 } else if (!selection->tracks.empty()) {
233 (*tv) = selection->tracks.front();
235 RouteTimeAxisView* rtv;
237 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
240 if ((pl = rtv->playlist()) == 0) {
244 region = pl->top_region_at (start);
252 Editor::extend_selection_to_end_of_region (bool next)
255 boost::shared_ptr<Region> region;
258 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
262 if (region && selection->time.start () == selection->time.end_frame ()) {
263 start = region->position();
265 start = selection->time.start ();
268 /* Try to leave the selection with the same route if possible */
270 if ((tv = selection->time.track) == 0) {
274 begin_reversible_command (_("extend selection"));
275 selection->set (tv, start, region->position() + region->length());
276 commit_reversible_command ();
280 Editor::extend_selection_to_start_of_region (bool previous)
283 boost::shared_ptr<Region> region;
286 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
290 if (region && selection->time.start () == selection->time.end_frame ()) {
291 end = region->position() + region->length();
293 end = selection->time.end_frame ();
296 /* Try to leave the selection with the same route if possible */
298 if ((tv = selection->time.track) == 0) {
302 begin_reversible_command (_("extend selection"));
303 selection->set (tv, region->position(), end);
304 commit_reversible_command ();
309 Editor::nudge_forward (bool next)
312 nframes_t next_distance;
314 if (!session) return;
316 if (!selection->regions.empty()) {
318 begin_reversible_command (_("nudge forward"));
320 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
321 boost::shared_ptr<Region> r ((*i)->region());
323 distance = get_nudge_distance (r->position(), next_distance);
326 distance = next_distance;
329 XMLNode &before = r->playlist()->get_state();
330 r->set_position (r->position() + distance, this);
331 XMLNode &after = r->playlist()->get_state();
332 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
335 commit_reversible_command ();
338 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
339 session->request_locate (playhead_cursor->current_frame + distance);
344 Editor::nudge_backward (bool next)
347 nframes_t next_distance;
349 if (!session) return;
351 if (!selection->regions.empty()) {
353 begin_reversible_command (_("nudge forward"));
355 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
356 boost::shared_ptr<Region> r ((*i)->region());
358 distance = get_nudge_distance (r->position(), next_distance);
361 distance = next_distance;
364 XMLNode &before = r->playlist()->get_state();
366 if (r->position() > distance) {
367 r->set_position (r->position() - distance, this);
369 r->set_position (0, this);
371 XMLNode &after = r->playlist()->get_state();
372 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
375 commit_reversible_command ();
379 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
381 if (playhead_cursor->current_frame > distance) {
382 session->request_locate (playhead_cursor->current_frame - distance);
384 session->goto_start();
390 Editor::nudge_forward_capture_offset ()
394 if (!session) return;
396 if (!selection->regions.empty()) {
398 begin_reversible_command (_("nudge forward"));
400 distance = session->worst_output_latency();
402 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
403 boost::shared_ptr<Region> r ((*i)->region());
405 XMLNode &before = r->playlist()->get_state();
406 r->set_position (r->position() + distance, this);
407 XMLNode &after = r->playlist()->get_state();
408 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
411 commit_reversible_command ();
417 Editor::nudge_backward_capture_offset ()
421 if (!session) return;
423 if (!selection->regions.empty()) {
425 begin_reversible_command (_("nudge forward"));
427 distance = session->worst_output_latency();
429 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
430 boost::shared_ptr<Region> r ((*i)->region());
432 XMLNode &before = r->playlist()->get_state();
434 if (r->position() > distance) {
435 r->set_position (r->position() - distance, this);
437 r->set_position (0, this);
439 XMLNode &after = r->playlist()->get_state();
440 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
443 commit_reversible_command ();
450 Editor::move_to_start ()
452 session->goto_start ();
456 Editor::move_to_end ()
459 session->request_locate (session->current_end_frame());
463 Editor::build_region_boundary_cache ()
467 boost::shared_ptr<Region> r;
468 TrackViewList tracks;
470 region_boundary_cache.clear ();
477 case SnapToRegionStart:
480 case SnapToRegionEnd:
483 case SnapToRegionSync:
486 case SnapToRegionBoundary:
490 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
495 TimeAxisView *ontrack = 0;
497 while (pos < session->current_end_frame()) {
499 if (!selection->tracks.empty()) {
501 if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
505 } else if (clicked_axisview) {
508 t.push_back (clicked_axisview);
510 if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
516 if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
524 case SnapToRegionStart:
525 rpos = r->first_frame();
527 case SnapToRegionEnd:
528 rpos = r->last_frame();
530 case SnapToRegionSync:
531 rpos = r->adjust_to_sync (r->first_frame());
534 case SnapToRegionBoundary:
535 rpos = r->last_frame();
542 AudioTimeAxisView *atav;
544 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
545 if (atav->get_diskstream() != 0) {
546 speed = atav->get_diskstream()->speed();
550 rpos = track_frame_to_session_frame(rpos, speed);
552 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
553 if (snap_type == SnapToRegionBoundary) {
554 region_boundary_cache.push_back (r->first_frame());
556 region_boundary_cache.push_back (rpos);
563 boost::shared_ptr<Region>
564 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
566 TrackViewList::iterator i;
567 nframes_t closest = max_frames;
568 boost::shared_ptr<Region> ret;
572 nframes_t track_frame;
573 AudioTimeAxisView *atav;
575 for (i = tracks.begin(); i != tracks.end(); ++i) {
578 boost::shared_ptr<Region> r;
581 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
582 if (atav->get_diskstream()!=0)
583 track_speed = atav->get_diskstream()->speed();
586 track_frame = session_frame_to_track_frame(frame, track_speed);
588 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
594 rpos = r->first_frame ();
598 rpos = r->last_frame ();
602 rpos = r->adjust_to_sync (r->first_frame());
605 // rpos is a "track frame", converting it to "session frame"
606 rpos = track_frame_to_session_frame(rpos, track_speed);
609 distance = rpos - frame;
611 distance = frame - rpos;
614 if (distance < closest) {
626 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
628 boost::shared_ptr<Region> r;
629 nframes_t pos = cursor->current_frame;
635 TimeAxisView *ontrack = 0;
637 // so we don't find the current region again..
641 if (!selection->tracks.empty()) {
643 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
645 } else if (clicked_axisview) {
648 t.push_back (clicked_axisview);
650 r = find_next_region (pos, point, dir, t, &ontrack);
654 r = find_next_region (pos, point, dir, track_views, &ontrack);
663 pos = r->first_frame ();
667 pos = r->last_frame ();
671 pos = r->adjust_to_sync (r->first_frame());
676 AudioTimeAxisView *atav;
678 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
679 if (atav->get_diskstream() != 0) {
680 speed = atav->get_diskstream()->speed();
684 pos = track_frame_to_session_frame(pos, speed);
686 if (cursor == playhead_cursor) {
687 session->request_locate (pos);
689 cursor->set_position (pos);
694 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
696 cursor_to_region_point (cursor, point, 1);
700 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
702 cursor_to_region_point (cursor, point, -1);
706 Editor::cursor_to_selection_start (Cursor *cursor)
709 switch (mouse_mode) {
711 if (!selection->regions.empty()) {
712 pos = selection->regions.start();
717 if (!selection->time.empty()) {
718 pos = selection->time.start ();
726 if (cursor == playhead_cursor) {
727 session->request_locate (pos);
729 cursor->set_position (pos);
734 Editor::cursor_to_selection_end (Cursor *cursor)
738 switch (mouse_mode) {
740 if (!selection->regions.empty()) {
741 pos = selection->regions.end_frame();
746 if (!selection->time.empty()) {
747 pos = selection->time.end_frame ();
755 if (cursor == playhead_cursor) {
756 session->request_locate (pos);
758 cursor->set_position (pos);
763 Editor::playhead_backward ()
770 if (get_prefix (prefix, was_floating)) {
774 cnt = (nframes_t) floor (prefix * session->frame_rate ());
776 cnt = (nframes_t) prefix;
780 pos = playhead_cursor->current_frame;
782 if ((nframes_t) pos < cnt) {
788 /* XXX this is completely insane. with the current buffering
789 design, we'll force a complete track buffer flush and
790 reload, just to move 1 sample !!!
793 session->request_locate (pos);
797 Editor::playhead_forward ()
804 if (get_prefix (prefix, was_floating)) {
808 cnt = (nframes_t) floor (prefix * session->frame_rate ());
810 cnt = (nframes_t) floor (prefix);
814 pos = playhead_cursor->current_frame;
816 /* XXX this is completely insane. with the current buffering
817 design, we'll force a complete track buffer flush and
818 reload, just to move 1 sample !!!
821 session->request_locate (pos+cnt);
825 Editor::cursor_align (bool playhead_to_edit)
827 if (playhead_to_edit) {
829 session->request_locate (edit_cursor->current_frame);
832 edit_cursor->set_position (playhead_cursor->current_frame);
837 Editor::edit_cursor_backward ()
844 if (get_prefix (prefix, was_floating)) {
848 cnt = (nframes_t) floor (prefix * session->frame_rate ());
850 cnt = (nframes_t) prefix;
854 pos = edit_cursor->current_frame;
856 if ((nframes_t) pos < cnt) {
862 edit_cursor->set_position (pos);
866 Editor::edit_cursor_forward ()
873 if (get_prefix (prefix, was_floating)) {
877 cnt = (nframes_t) floor (prefix * session->frame_rate ());
879 cnt = (nframes_t) floor (prefix);
883 pos = edit_cursor->current_frame;
884 edit_cursor->set_position (pos+cnt);
888 Editor::goto_frame ()
894 if (get_prefix (prefix, was_floating)) {
899 frame = (nframes_t) floor (prefix * session->frame_rate());
901 frame = (nframes_t) floor (prefix);
904 session->request_locate (frame);
908 Editor::scroll_backward (float pages)
911 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
916 if (get_prefix (prefix, was_floating)) {
917 cnt = (nframes_t) floor (pages * one_page);
920 cnt = (nframes_t) floor (prefix * session->frame_rate());
922 cnt = (nframes_t) floor (prefix * one_page);
926 if (leftmost_frame < cnt) {
929 frame = leftmost_frame - cnt;
932 reposition_x_origin (frame);
936 Editor::scroll_forward (float pages)
939 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
944 if (get_prefix (prefix, was_floating)) {
945 cnt = (nframes_t) floor (pages * one_page);
948 cnt = (nframes_t) floor (prefix * session->frame_rate());
950 cnt = (nframes_t) floor (prefix * one_page);
954 if (max_frames - cnt < leftmost_frame) {
955 frame = max_frames - cnt;
957 frame = leftmost_frame + cnt;
960 reposition_x_origin (frame);
964 Editor::scroll_tracks_down ()
970 if (get_prefix (prefix, was_floating)) {
973 cnt = (int) floor (prefix);
976 double vert_value = vertical_adjustment.get_value() + (cnt *
977 vertical_adjustment.get_page_size());
978 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
979 vert_value = vertical_adjustment.get_upper() - canvas_height;
981 vertical_adjustment.set_value (vert_value);
985 Editor::scroll_tracks_up ()
991 if (get_prefix (prefix, was_floating)) {
994 cnt = (int) floor (prefix);
997 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1001 Editor::scroll_tracks_down_line ()
1004 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1005 double vert_value = adj->get_value() + 20;
1007 if (vert_value>adj->get_upper() - canvas_height) {
1008 vert_value = adj->get_upper() - canvas_height;
1010 adj->set_value (vert_value);
1014 Editor::scroll_tracks_up_line ()
1016 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1017 adj->set_value (adj->get_value() - 20);
1023 Editor::temporal_zoom_step (bool coarser)
1025 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1029 nfpu = frames_per_unit;
1034 nfpu = max(1.0,(nfpu/1.61803399));
1037 temporal_zoom (nfpu);
1041 Editor::temporal_zoom (gdouble fpu)
1043 if (!session) return;
1045 nframes_t current_page = current_page_frames();
1046 nframes_t current_leftmost = leftmost_frame;
1047 nframes_t current_rightmost;
1048 nframes_t current_center;
1050 nframes_t leftmost_after_zoom = 0;
1055 new_page = (nframes_t) floor (canvas_width * nfpu);
1057 switch (zoom_focus) {
1059 leftmost_after_zoom = current_leftmost;
1062 case ZoomFocusRight:
1063 current_rightmost = leftmost_frame + current_page;
1064 if (current_rightmost > new_page) {
1065 leftmost_after_zoom = current_rightmost - new_page;
1067 leftmost_after_zoom = 0;
1071 case ZoomFocusCenter:
1072 current_center = current_leftmost + (current_page/2);
1073 if (current_center > (new_page/2)) {
1074 leftmost_after_zoom = current_center - (new_page / 2);
1076 leftmost_after_zoom = 0;
1080 case ZoomFocusPlayhead:
1081 /* try to keep the playhead in the center */
1082 if (playhead_cursor->current_frame > new_page/2) {
1083 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1085 leftmost_after_zoom = 0;
1090 /* try to keep the edit cursor in the center */
1091 if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
1092 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1094 leftmost_after_zoom = 0;
1100 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1102 // begin_reversible_command (_("zoom"));
1103 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1104 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1105 // commit_reversible_command ();
1107 reposition_and_zoom (leftmost_after_zoom, nfpu);
1111 Editor::temporal_zoom_selection ()
1113 if (!selection) return;
1115 if (selection->time.empty()) {
1119 nframes_t start = selection->time[clicked_selection].start;
1120 nframes_t end = selection->time[clicked_selection].end;
1122 temporal_zoom_by_frame (start, end, "zoom to selection");
1126 Editor::temporal_zoom_session ()
1128 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1131 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1136 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1138 if (!session) return;
1140 if ((start == 0 && end == 0) || end < start) {
1144 nframes_t range = end - start;
1146 double new_fpu = (double)range / (double)canvas_width;
1149 // while (p2 < new_fpu) {
1154 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1155 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1156 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1158 if (new_leftmost > middle) new_leftmost = 0;
1160 // begin_reversible_command (op);
1161 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1162 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1163 // commit_reversible_command ();
1165 reposition_and_zoom (new_leftmost, new_fpu);
1169 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1171 if (!session) return;
1173 double range_before = frame - leftmost_frame;
1176 new_fpu = frames_per_unit;
1179 new_fpu *= 1.61803399;
1180 range_before *= 1.61803399;
1182 new_fpu = max(1.0,(new_fpu/1.61803399));
1183 range_before /= 1.61803399;
1186 if (new_fpu == frames_per_unit) return;
1188 nframes_t new_leftmost = frame - (nframes_t)range_before;
1190 if (new_leftmost > frame) new_leftmost = 0;
1192 // begin_reversible_command (_("zoom to frame"));
1193 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1194 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1195 // commit_reversible_command ();
1197 reposition_and_zoom (new_leftmost, new_fpu);
1201 Editor::add_location_from_selection ()
1203 if (selection->time.empty()) {
1207 if (session == 0 || clicked_axisview == 0) {
1211 nframes_t start = selection->time[clicked_selection].start;
1212 nframes_t end = selection->time[clicked_selection].end;
1214 Location *location = new Location (start, end, "selection");
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 ()
1227 nframes_t where = session->audible_frame();
1229 Location *location = new Location (where, where, "mark", Location::IsMark);
1230 session->begin_reversible_command (_("add marker"));
1231 XMLNode &before = session->locations()->get_state();
1232 session->locations()->add (location, true);
1233 XMLNode &after = session->locations()->get_state();
1234 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1235 session->commit_reversible_command ();
1239 Editor::add_location_from_audio_region ()
1241 if (selection->regions.empty()) {
1245 RegionView* rv = *(selection->regions.begin());
1246 boost::shared_ptr<Region> region = rv->region();
1248 Location *location = new Location (region->position(), region->last_frame(), region->name());
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::select_all_in_track (Selection::Operation op)
1260 list<Selectable *> touched;
1262 if (!clicked_axisview) {
1266 clicked_axisview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1269 case Selection::Toggle:
1270 selection->add (touched);
1272 case Selection::Set:
1273 selection->set (touched);
1275 case Selection::Extend:
1276 /* not defined yet */
1282 Editor::select_all (Selection::Operation op)
1284 list<Selectable *> touched;
1286 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1287 if ((*iter)->hidden()) {
1290 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1292 begin_reversible_command (_("select all"));
1294 case Selection::Toggle:
1295 selection->add (touched);
1297 case Selection::Set:
1298 selection->set (touched);
1300 case Selection::Extend:
1301 /* not defined yet */
1304 commit_reversible_command ();
1308 Editor::invert_selection_in_track ()
1310 list<Selectable *> touched;
1312 if (!clicked_axisview) {
1316 clicked_axisview->get_inverted_selectables (*selection, touched);
1317 selection->set (touched);
1321 Editor::invert_selection ()
1323 list<Selectable *> touched;
1325 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1326 if ((*iter)->hidden()) {
1329 (*iter)->get_inverted_selectables (*selection, touched);
1332 selection->set (touched);
1336 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, Selection::Operation op)
1338 list<Selectable *> touched;
1340 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1341 if ((*iter)->hidden()) {
1344 (*iter)->get_selectables (start, end, top, bot, touched);
1347 cerr << "select all within found " << touched.size() << endl;
1349 begin_reversible_command (_("select all within"));
1351 case Selection::Toggle:
1353 selection->add (touched);
1355 case Selection::Set:
1357 selection->set (touched);
1359 case Selection::Extend:
1361 /* not defined yet */
1365 cerr << "selection now has " << selection->points.size() << endl;
1367 commit_reversible_command ();
1368 return !touched.empty();
1372 Editor::set_selection_from_audio_region ()
1374 if (selection->regions.empty()) {
1378 RegionView* rv = *(selection->regions.begin());
1379 boost::shared_ptr<Region> region = rv->region();
1381 begin_reversible_command (_("set selection from region"));
1382 selection->set (0, region->position(), region->last_frame());
1383 commit_reversible_command ();
1385 set_mouse_mode (Editing::MouseRange, false);
1389 Editor::set_selection_from_punch()
1393 if ((location = session->locations()->auto_punch_location()) == 0) {
1397 set_selection_from_range (*location);
1401 Editor::set_selection_from_loop()
1405 if ((location = session->locations()->auto_loop_location()) == 0) {
1408 set_selection_from_range (*location);
1412 Editor::set_selection_from_range (Location& loc)
1414 begin_reversible_command (_("set selection from range"));
1415 selection->set (0, loc.start(), loc.end());
1416 commit_reversible_command ();
1418 set_mouse_mode (Editing::MouseRange, false);
1422 Editor::select_all_selectables_using_time_selection ()
1424 list<Selectable *> touched;
1426 if (selection->time.empty()) {
1430 nframes_t start = selection->time[clicked_selection].start;
1431 nframes_t end = selection->time[clicked_selection].end;
1433 if (end - start < 1) {
1437 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1438 if ((*iter)->hidden()) {
1441 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1444 begin_reversible_command (_("select all from range"));
1445 selection->set (touched);
1446 commit_reversible_command ();
1451 Editor::select_all_selectables_using_punch()
1453 Location* location = session->locations()->auto_punch_location();
1454 list<Selectable *> touched;
1456 if (location == 0 || (location->end() - location->start() <= 1)) {
1460 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1461 if ((*iter)->hidden()) {
1464 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1466 begin_reversible_command (_("select all from punch"));
1467 selection->set (touched);
1468 commit_reversible_command ();
1473 Editor::select_all_selectables_using_loop()
1475 Location* location = session->locations()->auto_loop_location();
1476 list<Selectable *> touched;
1478 if (location == 0 || (location->end() - location->start() <= 1)) {
1482 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1483 if ((*iter)->hidden()) {
1486 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1488 begin_reversible_command (_("select all from loop"));
1489 selection->set (touched);
1490 commit_reversible_command ();
1495 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1499 list<Selectable *> touched;
1502 begin_reversible_command (_("select all after cursor"));
1503 start = cursor->current_frame ;
1504 end = session->current_end_frame();
1506 if (cursor->current_frame > 0) {
1507 begin_reversible_command (_("select all before cursor"));
1509 end = cursor->current_frame - 1;
1515 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1516 if ((*iter)->hidden()) {
1519 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1521 selection->set (touched);
1522 commit_reversible_command ();
1526 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1530 list<Selectable *> touched;
1531 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1533 if (cursor->current_frame == other_cursor->current_frame) {
1537 begin_reversible_command (_("select all between cursors"));
1538 if (other_cursor_is_first) {
1539 start = other_cursor->current_frame;
1540 end = cursor->current_frame - 1;
1543 start = cursor->current_frame;
1544 end = other_cursor->current_frame - 1;
1547 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1548 if ((*iter)->hidden()) {
1551 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1553 selection->set (touched);
1554 commit_reversible_command ();
1558 Editor::amplitude_zoom_step (bool in)
1572 #ifdef FIX_FOR_CANVAS
1573 /* XXX DO SOMETHING */
1582 Editor::delete_sample_forward ()
1587 Editor::delete_sample_backward ()
1592 Editor::delete_screen ()
1599 Editor::search_backwards ()
1605 Editor::search_forwards ()
1613 Editor::jump_forward_to_mark ()
1619 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1622 session->request_locate (location->start(), session->transport_rolling());
1624 session->request_locate (session->current_end_frame());
1629 Editor::jump_backward_to_mark ()
1635 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1638 session->request_locate (location->start(), session->transport_rolling());
1640 session->goto_start ();
1651 if (get_prefix (prefix, was_floating)) {
1652 pos = session->audible_frame ();
1655 pos = (nframes_t) floor (prefix * session->frame_rate ());
1657 pos = (nframes_t) floor (prefix);
1661 session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1665 Editor::clear_markers ()
1668 session->begin_reversible_command (_("clear markers"));
1669 XMLNode &before = session->locations()->get_state();
1670 session->locations()->clear_markers ();
1671 XMLNode &after = session->locations()->get_state();
1672 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1673 session->commit_reversible_command ();
1678 Editor::clear_ranges ()
1681 session->begin_reversible_command (_("clear ranges"));
1682 XMLNode &before = session->locations()->get_state();
1684 Location * looploc = session->locations()->auto_loop_location();
1685 Location * punchloc = session->locations()->auto_punch_location();
1687 session->locations()->clear_ranges ();
1689 if (looploc) session->locations()->add (looploc);
1690 if (punchloc) session->locations()->add (punchloc);
1692 XMLNode &after = session->locations()->get_state();
1693 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1694 session->commit_reversible_command ();
1699 Editor::clear_locations ()
1701 session->begin_reversible_command (_("clear locations"));
1702 XMLNode &before = session->locations()->get_state();
1703 session->locations()->clear ();
1704 XMLNode &after = session->locations()->get_state();
1705 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1706 session->commit_reversible_command ();
1707 session->locations()->clear ();
1710 /* INSERT/REPLACE */
1713 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1719 AudioTimeAxisView *atv = 0;
1722 track_canvas.window_to_world (x, y, wx, wy);
1723 wx += horizontal_adjustment.get_value();
1724 wy += vertical_adjustment.get_value();
1727 event.type = GDK_BUTTON_RELEASE;
1728 event.button.x = wx;
1729 event.button.y = wy;
1731 where = event_frame (&event, &cx, &cy);
1733 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1734 /* clearly outside canvas area */
1738 if ((tv = trackview_by_y_position (cy)) == 0) {
1742 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1746 if ((playlist = atv->playlist()) == 0) {
1752 begin_reversible_command (_("insert dragged region"));
1753 XMLNode &before = playlist->get_state();
1754 playlist->add_region (RegionFactory::create (region), where, 1.0);
1755 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1756 commit_reversible_command ();
1760 Editor::insert_region_list_selection (float times)
1762 RouteTimeAxisView *tv = 0;
1765 if (clicked_routeview != 0) {
1766 tv = clicked_routeview;
1767 } else if (!selection->tracks.empty()) {
1768 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1775 if ((playlist = tv->playlist()) == 0) {
1779 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1781 if (selected->count_selected_rows() != 1) {
1785 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1787 /* only one row selected, so rows.begin() is it */
1791 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1793 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1795 begin_reversible_command (_("insert region"));
1796 XMLNode &before = playlist->get_state();
1797 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1798 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1799 commit_reversible_command ();
1803 /* BUILT-IN EFFECTS */
1806 Editor::reverse_selection ()
1811 /* GAIN ENVELOPE EDITING */
1814 Editor::edit_envelope ()
1821 Editor::toggle_playback (bool with_abort)
1827 switch (Config->get_slave_source()) {
1832 /* transport controlled by the master */
1836 if (session->is_auditioning()) {
1837 session->cancel_audition ();
1841 if (session->transport_rolling()) {
1842 session->request_stop (with_abort);
1843 if (Config->get_auto_loop()) {
1844 session->request_play_loop (false);
1847 session->request_transport_speed (1.0f);
1852 Editor::play_from_start ()
1854 session->request_locate (session->current_start_frame(), true);
1858 Editor::play_selection ()
1860 if (selection->time.empty()) {
1864 session->request_play_range (true);
1868 Editor::play_selected_region ()
1870 if (!selection->regions.empty()) {
1871 RegionView *rv = *(selection->regions.begin());
1873 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1878 Editor::loop_selected_region ()
1880 if (!selection->regions.empty()) {
1881 RegionView *rv = *(selection->regions.begin());
1884 if ((tll = transport_loop_location()) != 0) {
1886 tll->set (rv->region()->position(), rv->region()->last_frame());
1888 // enable looping, reposition and start rolling
1890 session->request_play_loop (true);
1891 session->request_locate (tll->start(), false);
1892 session->request_transport_speed (1.0f);
1898 Editor::play_location (Location& location)
1900 if (location.start() <= location.end()) {
1904 session->request_bounded_roll (location.start(), location.end());
1908 Editor::loop_location (Location& location)
1910 if (location.start() <= location.end()) {
1916 if ((tll = transport_loop_location()) != 0) {
1917 tll->set (location.start(), location.end());
1919 // enable looping, reposition and start rolling
1920 session->request_play_loop (true);
1921 session->request_locate (tll->start(), true);
1926 Editor::toggle_region_mute ()
1928 if (clicked_regionview) {
1929 clicked_regionview->region()->set_muted (!clicked_regionview->region()->muted());
1930 } else if (!selection->regions.empty()) {
1931 bool yn = ! (*selection->regions.begin())->region()->muted();
1932 selection->foreach_region (&Region::set_muted, yn);
1937 Editor::toggle_region_opaque ()
1939 if (clicked_regionview) {
1940 clicked_regionview->region()->set_opaque (!clicked_regionview->region()->opaque());
1941 } else if (!selection->regions.empty()) {
1942 bool yn = ! (*selection->regions.begin())->region()->opaque();
1943 selection->foreach_region (&Region::set_opaque, yn);
1948 Editor::raise_region ()
1950 selection->foreach_region (&Region::raise);
1954 Editor::raise_region_to_top ()
1956 selection->foreach_region (&Region::raise_to_top);
1960 Editor::lower_region ()
1962 selection->foreach_region (&Region::lower);
1966 Editor::lower_region_to_bottom ()
1968 selection->foreach_region (&Region::lower_to_bottom);
1972 Editor::edit_region ()
1974 if (clicked_regionview == 0) {
1978 clicked_regionview->show_region_editor ();
1982 Editor::rename_region ()
1986 Button ok_button (_("OK"));
1987 Button cancel_button (_("Cancel"));
1989 if (selection->regions.empty()) {
1993 dialog.set_title (_("ardour: rename region"));
1994 dialog.set_name ("RegionRenameWindow");
1995 dialog.set_size_request (300, -1);
1996 dialog.set_position (Gtk::WIN_POS_MOUSE);
1997 dialog.set_modal (true);
1999 dialog.get_vbox()->set_border_width (10);
2000 dialog.get_vbox()->pack_start (entry);
2001 dialog.get_action_area()->pack_start (ok_button);
2002 dialog.get_action_area()->pack_start (cancel_button);
2004 entry.set_name ("RegionNameDisplay");
2005 ok_button.set_name ("EditorGTKButton");
2006 cancel_button.set_name ("EditorGTKButton");
2008 region_renamed = false;
2010 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2011 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2012 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2019 if (region_renamed) {
2020 (*selection->regions.begin())->region()->set_name (entry.get_text());
2021 redisplay_regions ();
2026 Editor::rename_region_finished (bool status)
2029 region_renamed = status;
2034 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2036 if (session->is_auditioning()) {
2037 session->cancel_audition ();
2040 // note: some potential for creativity here, because region doesn't
2041 // have to belong to the playlist that Route is handling
2043 // bool was_soloed = route.soloed();
2045 route.set_solo (true, this);
2047 session->request_bounded_roll (region->position(), region->position() + region->length());
2049 /* XXX how to unset the solo state ? */
2053 Editor::audition_selected_region ()
2055 if (!selection->regions.empty()) {
2056 RegionView* rv = *(selection->regions.begin());
2057 session->audition_region (rv->region());
2062 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2064 session->audition_region (region);
2068 Editor::build_interthread_progress_window ()
2070 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2072 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2074 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2075 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2077 // GTK2FIX: this button needs a modifiable label
2079 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2080 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2082 interthread_cancel_button.add (interthread_cancel_label);
2084 interthread_progress_window->set_default_size (200, 100);
2088 Editor::interthread_cancel_clicked ()
2090 if (current_interthread_info) {
2091 current_interthread_info->cancel = true;
2096 Editor::region_from_selection ()
2098 if (clicked_axisview == 0) {
2102 if (selection->time.empty()) {
2106 nframes_t start = selection->time[clicked_selection].start;
2107 nframes_t end = selection->time[clicked_selection].end;
2109 nframes_t selection_cnt = end - start + 1;
2111 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2112 boost::shared_ptr<AudioRegion> current;
2113 boost::shared_ptr<Region> current_r;
2116 nframes_t internal_start;
2119 if ((pl = (*i)->playlist()) == 0) {
2123 if ((current_r = pl->top_region_at (start)) == 0) {
2127 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2128 assert(current); // FIXME
2130 internal_start = start - current->position();
2131 session->region_name (new_name, current->name(), true);
2132 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2138 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2140 if (selection->time.empty() || selection->tracks.empty()) {
2144 nframes_t start = selection->time[clicked_selection].start;
2145 nframes_t end = selection->time[clicked_selection].end;
2147 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2149 boost::shared_ptr<AudioRegion> current;
2150 boost::shared_ptr<Region> current_r;
2152 nframes_t internal_start;
2155 if ((playlist = (*i)->playlist()) == 0) {
2159 if ((current_r = playlist->top_region_at(start)) == 0) {
2163 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2167 internal_start = start - current->position();
2168 session->region_name (new_name, current->name(), true);
2170 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2175 Editor::split_multichannel_region ()
2177 vector<AudioRegion*> v;
2179 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2181 if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2185 clicked_arv->audio_region()->separate_by_channel (*session, v);
2187 /* nothing else to do, really */
2191 Editor::new_region_from_selection ()
2193 region_from_selection ();
2194 cancel_selection ();
2198 Editor::separate_region_from_selection ()
2202 bool doing_undo = false;
2204 if (selection->time.empty()) {
2210 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2212 AudioTimeAxisView* atv;
2214 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2216 if (atv->is_audio_track()) {
2218 if ((playlist = atv->playlist()) != 0) {
2220 begin_reversible_command (_("separate"));
2225 before = &(playlist->get_state());
2227 /* XXX need to consider musical time selections here at some point */
2229 double speed = atv->get_diskstream()->speed();
2231 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2232 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2236 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2242 if (doing_undo) commit_reversible_command ();
2246 Editor::separate_regions_using_location (Location& loc)
2250 bool doing_undo = false;
2252 if (loc.is_mark()) {
2258 /* XXX i'm unsure as to whether this should operate on selected tracks only
2259 or the entire enchillada. uncomment the below line to correct the behaviour
2260 (currently set for all tracks)
2263 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2264 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2266 AudioTimeAxisView* atv;
2268 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2270 if (atv->is_audio_track()) {
2272 if ((playlist = atv->playlist()) != 0) {
2275 begin_reversible_command (_("separate"));
2279 before = &(playlist->get_state());
2282 /* XXX need to consider musical time selections here at some point */
2284 double speed = atv->get_diskstream()->speed();
2287 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2289 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2295 if (doing_undo) commit_reversible_command ();
2299 Editor::crop_region_to_selection ()
2301 if (selection->time.empty()) {
2305 vector<Playlist*> playlists;
2308 if (clicked_axisview != 0) {
2310 if ((playlist = clicked_axisview->playlist()) == 0) {
2314 playlists.push_back (playlist);
2318 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2320 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i);
2322 if (rtv && rtv->is_track()) {
2324 if ((playlist = rtv->playlist()) != 0) {
2325 playlists.push_back (playlist);
2331 if (!playlists.empty()) {
2337 begin_reversible_command (_("trim to selection"));
2339 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2341 boost::shared_ptr<Region> region;
2343 start = selection->time.start();
2345 if ((region = (*i)->top_region_at(start)) == 0) {
2349 /* now adjust lengths to that we do the right thing
2350 if the selection extends beyond the region
2353 start = max (start, region->position());
2354 end = min (selection->time.end_frame(), start + region->length() - 1);
2355 cnt = end - start + 1;
2357 XMLNode &before = (*i)->get_state();
2358 region->trim_to (start, cnt, this);
2359 XMLNode &after = (*i)->get_state();
2360 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2363 commit_reversible_command ();
2368 Editor::region_fill_track ()
2372 if (!session || selection->regions.empty()) {
2376 end = session->current_end_frame ();
2378 begin_reversible_command (_("region fill"));
2380 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2382 boost::shared_ptr<Region> region ((*i)->region());
2385 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2388 Playlist* pl = region->playlist();
2390 if (end <= region->last_frame()) {
2394 double times = (double) (end - region->last_frame()) / (double) region->length();
2400 XMLNode &before = pl->get_state();
2401 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2402 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2405 commit_reversible_command ();
2409 Editor::region_fill_selection ()
2411 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2415 if (selection->time.empty()) {
2420 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2422 if (selected->count_selected_rows() != 1) {
2426 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2427 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2429 nframes_t start = selection->time[clicked_selection].start;
2430 nframes_t end = selection->time[clicked_selection].end;
2434 if (selection->tracks.empty()) {
2438 nframes_t selection_length = end - start;
2439 float times = (float)selection_length / region->length();
2441 begin_reversible_command (_("fill selection"));
2443 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2445 if ((playlist = (*i)->playlist()) == 0) {
2449 XMLNode &before = playlist->get_state();
2450 playlist->add_region (RegionFactory::create (region), start, times);
2451 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2454 commit_reversible_command ();
2458 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2461 if (!region->covers (position)) {
2462 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2465 begin_reversible_command (_("set region sync position"));
2466 XMLNode &before = region->playlist()->get_state();
2467 region->set_sync_position (position);
2468 XMLNode &after = region->playlist()->get_state();
2469 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2470 commit_reversible_command ();
2474 Editor::set_region_sync_from_edit_cursor ()
2476 if (clicked_regionview == 0) {
2480 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2481 error << _("Place the edit cursor at the desired sync point") << endmsg;
2485 boost::shared_ptr<Region> region (clicked_regionview->region());
2486 begin_reversible_command (_("set sync from edit cursor"));
2487 XMLNode &before = region->playlist()->get_state();
2488 region->set_sync_position (edit_cursor->current_frame);
2489 XMLNode &after = region->playlist()->get_state();
2490 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2491 commit_reversible_command ();
2495 Editor::remove_region_sync ()
2497 if (clicked_regionview) {
2498 boost::shared_ptr<Region> region (clicked_regionview->region());
2499 begin_reversible_command (_("remove sync"));
2500 XMLNode &before = region->playlist()->get_state();
2501 region->clear_sync_position ();
2502 XMLNode &after = region->playlist()->get_state();
2503 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2504 commit_reversible_command ();
2509 Editor::naturalize ()
2511 if (selection->regions.empty()) {
2514 begin_reversible_command (_("naturalize"));
2515 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2516 XMLNode &before = (*i)->region()->get_state();
2517 (*i)->region()->move_to_natural_position (this);
2518 XMLNode &after = (*i)->region()->get_state();
2519 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2521 commit_reversible_command ();
2525 Editor::align (RegionPoint what)
2527 align_selection (what, edit_cursor->current_frame);
2531 Editor::align_relative (RegionPoint what)
2533 align_selection_relative (what, edit_cursor->current_frame);
2536 struct RegionSortByTime {
2537 bool operator() (const RegionView* a, const RegionView* b) {
2538 return a->region()->position() < b->region()->position();
2543 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2545 if (selection->regions.empty()) {
2553 list<RegionView*> sorted;
2554 selection->regions.by_position (sorted);
2555 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2559 pos = r->first_frame ();
2563 pos = r->last_frame();
2567 pos = r->adjust_to_sync (r->first_frame());
2571 if (pos > position) {
2572 distance = pos - position;
2575 distance = position - pos;
2579 begin_reversible_command (_("align selection (relative)"));
2581 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2583 boost::shared_ptr<Region> region ((*i)->region());
2585 XMLNode &before = region->playlist()->get_state();
2588 region->set_position (region->position() + distance, this);
2590 region->set_position (region->position() - distance, this);
2593 XMLNode &after = region->playlist()->get_state();
2594 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2598 commit_reversible_command ();
2602 Editor::align_selection (RegionPoint point, nframes_t position)
2604 if (selection->regions.empty()) {
2608 begin_reversible_command (_("align selection"));
2610 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2611 align_region_internal ((*i)->region(), point, position);
2614 commit_reversible_command ();
2618 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2620 begin_reversible_command (_("align region"));
2621 align_region_internal (region, point, position);
2622 commit_reversible_command ();
2626 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2628 XMLNode &before = region->playlist()->get_state();
2632 region->set_position (region->adjust_to_sync (position), this);
2636 if (position > region->length()) {
2637 region->set_position (position - region->length(), this);
2642 region->set_position (position, this);
2646 XMLNode &after = region->playlist()->get_state();
2647 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2651 Editor::trim_region_to_edit_cursor ()
2653 if (clicked_regionview == 0) {
2657 boost::shared_ptr<Region> region (clicked_regionview->region());
2660 AudioTimeAxisView *atav;
2662 if ( clicked_axisview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_axisview)) != 0 ) {
2663 if (atav->get_diskstream() != 0) {
2664 speed = atav->get_diskstream()->speed();
2668 begin_reversible_command (_("trim to edit"));
2669 XMLNode &before = region->playlist()->get_state();
2670 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2671 XMLNode &after = region->playlist()->get_state();
2672 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2673 commit_reversible_command ();
2677 Editor::trim_region_from_edit_cursor ()
2679 if (clicked_regionview == 0) {
2683 boost::shared_ptr<Region> region (clicked_regionview->region());
2686 AudioTimeAxisView *atav;
2688 if ( clicked_axisview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_axisview)) != 0 ) {
2689 if (atav->get_diskstream() != 0) {
2690 speed = atav->get_diskstream()->speed();
2694 begin_reversible_command (_("trim to edit"));
2695 XMLNode &before = region->playlist()->get_state();
2696 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2697 XMLNode &after = region->playlist()->get_state();
2698 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2699 commit_reversible_command ();
2703 Editor::unfreeze_route ()
2705 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2709 clicked_routeview->track()->unfreeze ();
2713 Editor::_freeze_thread (void* arg)
2715 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2716 return static_cast<Editor*>(arg)->freeze_thread ();
2720 Editor::freeze_thread ()
2722 clicked_routeview->audio_track()->freeze (*current_interthread_info);
2727 Editor::freeze_progress_timeout (void *arg)
2729 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2730 return !(current_interthread_info->done || current_interthread_info->cancel);
2734 Editor::freeze_route ()
2736 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2740 InterThreadInfo itt;
2742 if (interthread_progress_window == 0) {
2743 build_interthread_progress_window ();
2746 interthread_progress_window->set_title (_("ardour: freeze"));
2747 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2748 interthread_progress_window->show_all ();
2749 interthread_progress_bar.set_fraction (0.0f);
2750 interthread_progress_label.set_text ("");
2751 interthread_cancel_label.set_text (_("Cancel Freeze"));
2752 current_interthread_info = &itt;
2754 interthread_progress_connection =
2755 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2759 itt.progress = 0.0f;
2761 pthread_create (&itt.thread, 0, _freeze_thread, this);
2763 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2765 while (!itt.done && !itt.cancel) {
2766 gtk_main_iteration ();
2769 interthread_progress_connection.disconnect ();
2770 interthread_progress_window->hide_all ();
2771 current_interthread_info = 0;
2772 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2776 Editor::bounce_range_selection ()
2778 if (selection->time.empty()) {
2782 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2784 nframes_t start = selection->time[clicked_selection].start;
2785 nframes_t end = selection->time[clicked_selection].end;
2786 nframes_t cnt = end - start + 1;
2788 begin_reversible_command (_("bounce range"));
2790 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2792 AudioTimeAxisView* atv;
2794 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2800 if ((playlist = atv->playlist()) == 0) {
2804 InterThreadInfo itt;
2808 itt.progress = false;
2810 XMLNode &before = playlist->get_state();
2811 atv->audio_track()->bounce_range (start, cnt, itt);
2812 XMLNode &after = playlist->get_state();
2813 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2816 commit_reversible_command ();
2834 Editor::cut_copy (CutCopyOp op)
2836 /* only cancel selection if cut/copy is successful.*/
2848 opname = _("clear");
2852 cut_buffer->clear ();
2854 switch (current_mouse_mode()) {
2856 if (!selection->regions.empty() || !selection->points.empty()) {
2858 begin_reversible_command (opname + _(" objects"));
2860 if (!selection->regions.empty()) {
2862 cut_copy_regions (op);
2865 selection->clear_regions ();
2869 if (!selection->points.empty()) {
2870 cut_copy_points (op);
2873 selection->clear_points ();
2877 commit_reversible_command ();
2882 if (!selection->time.empty()) {
2884 begin_reversible_command (opname + _(" range"));
2885 cut_copy_ranges (op);
2886 commit_reversible_command ();
2889 selection->clear_time ();
2901 Editor::cut_copy_points (CutCopyOp op)
2903 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2905 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2908 atv->cut_copy_clear_objects (selection->points, op);
2914 Editor::cut_copy_regions (CutCopyOp op)
2916 typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
2917 PlaylistMapping pmap;
2918 nframes_t first_position = max_frames;
2919 set<Playlist*> freezelist;
2920 pair<set<Playlist*>::iterator,bool> insert_result;
2922 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2923 first_position = min ((*x)->region()->position(), first_position);
2925 if (op == Cut || op == Clear) {
2926 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
2928 insert_result = freezelist.insert (pl);
2929 if (insert_result.second) {
2931 session->add_command (new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
2937 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2939 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
2941 RegionSelection::iterator tmp;
2948 PlaylistMapping::iterator pi = pmap.find (pl);
2950 if (pi == pmap.end()) {
2951 npl = new AudioPlaylist (*session, "cutlist", true);
2959 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
2964 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
2965 pl->remove_region (((*x)->region()));
2971 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
2975 pl->remove_region (((*x)->region()));
2983 list<Playlist*> foo;
2985 for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
2986 foo.push_back (i->second);
2990 cut_buffer->set (foo);
2993 for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
2995 session->add_command (new MementoCommand<Playlist>(*(*pl), 0, &(*pl)->get_state()));
3000 Editor::cut_copy_ranges (CutCopyOp op)
3002 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3003 (*i)->cut_copy_clear (*selection, op);
3008 Editor::paste (float times)
3010 paste_internal (edit_cursor->current_frame, times);
3014 Editor::mouse_paste ()
3019 track_canvas.get_pointer (x, y);
3020 track_canvas.window_to_world (x, y, wx, wy);
3021 wx += horizontal_adjustment.get_value();
3022 wy += vertical_adjustment.get_value();
3025 event.type = GDK_BUTTON_RELEASE;
3026 event.button.x = wx;
3027 event.button.y = wy;
3029 nframes_t where = event_frame (&event, 0, 0);
3031 paste_internal (where, 1);
3035 Editor::paste_internal (nframes_t position, float times)
3037 bool commit = false;
3039 if (cut_buffer->empty() || selection->tracks.empty()) {
3043 if (position == max_frames) {
3044 position = edit_cursor->current_frame;
3047 begin_reversible_command (_("paste"));
3049 TrackSelection::iterator i;
3052 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3054 /* undo/redo is handled by individual tracks */
3056 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3062 commit_reversible_command ();
3067 Editor::paste_named_selection (float times)
3069 TrackSelection::iterator t;
3071 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3073 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3077 TreeModel::iterator i = selected->get_selected();
3078 NamedSelection* ns = (*i)[named_selection_columns.selection];
3080 list<Playlist*>::iterator chunk;
3081 list<Playlist*>::iterator tmp;
3083 chunk = ns->playlists.begin();
3085 begin_reversible_command (_("paste chunk"));
3087 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3089 AudioTimeAxisView* atv;
3093 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3097 if ((pl = atv->playlist()) == 0) {
3101 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3108 XMLNode &before = apl->get_state();
3109 apl->paste (**chunk, edit_cursor->current_frame, times);
3110 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3112 if (tmp != ns->playlists.end()) {
3117 commit_reversible_command();
3121 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3124 RegionSelection sel = regions; // clear (below) will clear the argument list
3126 begin_reversible_command (_("duplicate region"));
3128 selection->clear_regions ();
3130 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3132 boost::shared_ptr<Region> r ((*i)->region());
3134 TimeAxisView& tv = (*i)->get_time_axis_view();
3135 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3136 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3138 playlist = (*i)->region()->playlist();
3139 XMLNode &before = playlist->get_state();
3140 playlist->duplicate (r, r->last_frame(), times);
3141 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3145 if (latest_regionview) {
3146 selection->add (latest_regionview);
3151 commit_reversible_command ();
3155 Editor::duplicate_selection (float times)
3157 if (selection->time.empty() || selection->tracks.empty()) {
3162 vector<boost::shared_ptr<AudioRegion> > new_regions;
3163 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3165 create_region_from_selection (new_regions);
3167 if (new_regions.empty()) {
3171 begin_reversible_command (_("duplicate selection"));
3173 ri = new_regions.begin();
3175 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3176 if ((playlist = (*i)->playlist()) == 0) {
3179 XMLNode &before = playlist->get_state();
3180 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3181 XMLNode &after = playlist->get_state();
3182 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3185 if (ri == new_regions.end()) {
3190 commit_reversible_command ();
3194 Editor::reset_point_selection ()
3196 /* reset all selected points to the relevant default value */
3198 cerr << "point selection has " << selection->points.size() << " entries\n";
3200 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3202 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3205 atv->reset_objects (selection->points);
3211 Editor::center_playhead ()
3213 float page = canvas_width * frames_per_unit;
3215 center_screen_internal (playhead_cursor->current_frame, page);
3219 Editor::center_edit_cursor ()
3221 float page = canvas_width * frames_per_unit;
3223 center_screen_internal (edit_cursor->current_frame, page);
3227 Editor::clear_playlist (Playlist& playlist)
3229 begin_reversible_command (_("clear playlist"));
3230 XMLNode &before = playlist.get_state();
3232 XMLNode &after = playlist.get_state();
3233 session->add_command (new MementoCommand<Playlist>(playlist, &before, &after));
3234 commit_reversible_command ();
3238 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3242 nframes_t next_distance;
3245 if (use_edit_cursor) {
3246 start = edit_cursor->current_frame;
3251 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3255 if (selection->tracks.empty()) {
3259 begin_reversible_command (_("nudge track"));
3261 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3263 if ((playlist = (*i)->playlist()) == 0) {
3267 XMLNode &before = playlist->get_state();
3268 playlist->nudge_after (start, distance, forwards);
3269 XMLNode &after = playlist->get_state();
3270 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3273 commit_reversible_command ();
3277 Editor::remove_last_capture ()
3279 vector<string> choices;
3286 if (Config->get_verify_remove_last_capture()) {
3287 prompt = _("Do you really want to destroy the last capture?"
3288 "\n(This is destructive and cannot be undone)");
3290 choices.push_back (_("No, do nothing."));
3291 choices.push_back (_("Yes, destroy it."));
3293 Gtkmm2ext::Choice prompter (prompt, choices);
3295 if (prompter.run () == 1) {
3296 session->remove_last_capture ();
3300 session->remove_last_capture();
3305 Editor::normalize_region ()
3311 if (selection->regions.empty()) {
3315 begin_reversible_command (_("normalize"));
3317 track_canvas.get_window()->set_cursor (*wait_cursor);
3320 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3321 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3324 XMLNode &before = arv->region()->get_state();
3325 arv->audio_region()->normalize_to (0.0f);
3326 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3329 commit_reversible_command ();
3330 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3335 Editor::denormalize_region ()
3341 if (selection->regions.empty()) {
3345 begin_reversible_command ("denormalize");
3347 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3348 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3351 XMLNode &before = arv->region()->get_state();
3352 arv->audio_region()->set_scale_amplitude (1.0f);
3353 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3356 commit_reversible_command ();
3361 Editor::reverse_region ()
3367 Reverse rev (*session);
3368 apply_filter (rev, _("reverse regions"));
3372 Editor::apply_filter (AudioFilter& filter, string command)
3374 if (selection->regions.empty()) {
3378 begin_reversible_command (command);
3380 track_canvas.get_window()->set_cursor (*wait_cursor);
3383 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3384 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3388 Playlist* playlist = arv->region()->playlist();
3390 RegionSelection::iterator tmp;
3395 if (arv->audio_region()->apply (filter) == 0) {
3397 XMLNode &before = playlist->get_state();
3398 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3399 XMLNode &after = playlist->get_state();
3400 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3408 commit_reversible_command ();
3409 selection->regions.clear ();
3412 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3416 Editor::region_selection_op (void (Region::*pmf)(void))
3418 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3419 Region* region = (*i)->region().get();
3426 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3428 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3429 Region* region = (*i)->region().get();
3430 (region->*pmf)(arg);
3435 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3437 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3438 Region* region = (*i)->region().get();
3444 Editor::external_edit_region ()
3446 if (!clicked_regionview) {
3454 Editor::brush (nframes_t pos)
3456 RegionSelection sel;
3459 if (selection->regions.empty()) {
3460 /* XXX get selection from region list */
3462 sel = selection->regions;
3469 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3470 mouse_brush_insert_region ((*i), pos);
3475 Editor::toggle_gain_envelope_visibility ()
3477 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3478 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3480 arv->set_envelope_visible (!arv->envelope_visible());
3485 Editor::toggle_gain_envelope_active ()
3487 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3488 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3490 arv->audio_region()->set_envelope_active (true);