2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <pbd/error.h>
28 #include <pbd/basename.h>
29 #include <pbd/pthread_utils.h>
30 #include <pbd/memento_command.h>
32 #include <gtkmm2ext/utils.h>
33 #include <gtkmm2ext/choice.h>
34 #include <gtkmm2ext/window_title.h>
36 #include <ardour/audioengine.h>
37 #include <ardour/session.h>
38 #include <ardour/audioplaylist.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/utils.h>
42 #include <ardour/location.h>
43 #include <ardour/named_selection.h>
44 #include <ardour/audio_track.h>
45 #include <ardour/audioplaylist.h>
46 #include <ardour/region_factory.h>
47 #include <ardour/playlist_factory.h>
48 #include <ardour/reverse.h>
50 #include "ardour_ui.h"
52 #include "time_axis_view.h"
53 #include "audio_time_axis.h"
54 #include "automation_time_axis.h"
55 #include "streamview.h"
56 #include "audio_region_view.h"
57 #include "rgb_macros.h"
58 #include "selection_templates.h"
59 #include "selection.h"
61 #include "gtk-custom-hruler.h"
62 #include "gui_thread.h"
67 using namespace ARDOUR;
71 using namespace Gtkmm2ext;
72 using namespace Editing;
74 /***********************************************************************
76 ***********************************************************************/
79 Editor::undo (uint32_t n)
87 Editor::redo (uint32_t n)
95 Editor::split_region ()
97 split_region_at (get_preferred_edit_position());
101 Editor::split_region_at (nframes_t where)
103 split_regions_at (where, selection->regions);
107 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
109 begin_reversible_command (_("split"));
111 // if splitting a single region, and snap-to is using
112 // region boundaries, don't pay attention to them
114 if (regions.size() == 1) {
116 case SnapToRegionStart:
117 case SnapToRegionSync:
118 case SnapToRegionEnd:
128 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
130 RegionSelection::iterator tmp;
132 /* XXX this test needs to be more complicated, to make sure we really
133 have something to split.
136 if (!(*a)->region()->covers (where)) {
144 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
146 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
149 _new_regionviews_show_envelope = arv->envelope_visible();
153 XMLNode &before = pl->get_state();
154 pl->split_region ((*a)->region(), where);
155 XMLNode &after = pl->get_state();
156 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
162 commit_reversible_command ();
163 _new_regionviews_show_envelope = false;
167 Editor::remove_clicked_region ()
169 if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
173 boost::shared_ptr<Playlist> playlist = clicked_audio_trackview->playlist();
175 begin_reversible_command (_("remove region"));
176 XMLNode &before = playlist->get_state();
177 playlist->remove_region (clicked_regionview->region());
178 XMLNode &after = playlist->get_state();
179 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
180 commit_reversible_command ();
184 Editor::destroy_clicked_region ()
186 uint32_t selected = selection->regions.size();
188 if (!session || !selected) {
192 vector<string> choices;
195 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
196 It cannot be undone\n\
197 Do you really want to destroy %1 ?"),
199 _("these regions") : _("this region")));
201 choices.push_back (_("No, do nothing."));
204 choices.push_back (_("Yes, destroy them."));
206 choices.push_back (_("Yes, destroy it."));
209 Gtkmm2ext::Choice prompter (prompt, choices);
211 if (prompter.run() == 0) { /* first choice */
216 list<boost::shared_ptr<Region> > r;
218 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
219 r.push_back ((*i)->region());
222 session->destroy_regions (r);
226 boost::shared_ptr<Region>
227 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
230 boost::shared_ptr<Region> region;
233 if (selection->time.start () == selection->time.end_frame ()) {
235 /* no current selection-> is there a selected regionview? */
237 if (selection->regions.empty()) {
243 if (!selection->regions.empty()) {
245 rv = *(selection->regions.begin());
246 (*tv) = &rv->get_time_axis_view();
247 region = rv->region();
249 } else if (!selection->tracks.empty()) {
251 (*tv) = selection->tracks.front();
253 RouteTimeAxisView* rtv;
255 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
256 boost::shared_ptr<Playlist> pl;
258 if ((pl = rtv->playlist()) == 0) {
262 region = pl->top_region_at (start);
270 Editor::extend_selection_to_end_of_region (bool next)
273 boost::shared_ptr<Region> region;
276 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
280 if (region && selection->time.start () == selection->time.end_frame ()) {
281 start = region->position();
283 start = selection->time.start ();
286 /* Try to leave the selection with the same route if possible */
288 if ((tv = selection->time.track) == 0) {
292 begin_reversible_command (_("extend selection"));
293 selection->set (tv, start, region->position() + region->length());
294 commit_reversible_command ();
298 Editor::extend_selection_to_start_of_region (bool previous)
301 boost::shared_ptr<Region> region;
304 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
308 if (region && selection->time.start () == selection->time.end_frame ()) {
309 end = region->position() + region->length();
311 end = selection->time.end_frame ();
314 /* Try to leave the selection with the same route if possible */
316 if ((tv = selection->time.track) == 0) {
320 begin_reversible_command (_("extend selection"));
321 selection->set (tv, region->position(), end);
322 commit_reversible_command ();
327 Editor::nudge_forward (bool next)
330 nframes_t next_distance;
332 if (!session) return;
334 if (!selection->regions.empty()) {
336 begin_reversible_command (_("nudge forward"));
338 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
339 boost::shared_ptr<Region> r ((*i)->region());
341 distance = get_nudge_distance (r->position(), next_distance);
344 distance = next_distance;
347 XMLNode &before = r->playlist()->get_state();
348 r->set_position (r->position() + distance, this);
349 XMLNode &after = r->playlist()->get_state();
350 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
353 commit_reversible_command ();
356 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
357 session->request_locate (playhead_cursor->current_frame + distance);
362 Editor::nudge_backward (bool next)
365 nframes_t next_distance;
367 if (!session) return;
369 if (!selection->regions.empty()) {
371 begin_reversible_command (_("nudge forward"));
373 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
374 boost::shared_ptr<Region> r ((*i)->region());
376 distance = get_nudge_distance (r->position(), next_distance);
379 distance = next_distance;
382 XMLNode &before = r->playlist()->get_state();
384 if (r->position() > distance) {
385 r->set_position (r->position() - distance, this);
387 r->set_position (0, this);
389 XMLNode &after = r->playlist()->get_state();
390 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
393 commit_reversible_command ();
397 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
399 if (playhead_cursor->current_frame > distance) {
400 session->request_locate (playhead_cursor->current_frame - distance);
402 session->goto_start();
408 Editor::nudge_forward_capture_offset ()
412 if (!session) return;
414 if (!selection->regions.empty()) {
416 begin_reversible_command (_("nudge forward"));
418 distance = session->worst_output_latency();
420 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
421 boost::shared_ptr<Region> r ((*i)->region());
423 XMLNode &before = r->playlist()->get_state();
424 r->set_position (r->position() + distance, this);
425 XMLNode &after = r->playlist()->get_state();
426 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
429 commit_reversible_command ();
435 Editor::nudge_backward_capture_offset ()
439 if (!session) return;
441 if (!selection->regions.empty()) {
443 begin_reversible_command (_("nudge forward"));
445 distance = session->worst_output_latency();
447 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
448 boost::shared_ptr<Region> r ((*i)->region());
450 XMLNode &before = r->playlist()->get_state();
452 if (r->position() > distance) {
453 r->set_position (r->position() - distance, this);
455 r->set_position (0, this);
457 XMLNode &after = r->playlist()->get_state();
458 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
461 commit_reversible_command ();
468 Editor::move_to_start ()
470 session->goto_start ();
474 Editor::move_to_end ()
477 session->request_locate (session->current_end_frame());
481 Editor::build_region_boundary_cache ()
484 vector<RegionPoint> interesting_points;
485 boost::shared_ptr<Region> r;
486 TrackViewList tracks;
489 region_boundary_cache.clear ();
496 case SnapToRegionStart:
497 interesting_points.push_back (Start);
499 case SnapToRegionEnd:
500 interesting_points.push_back (End);
502 case SnapToRegionSync:
503 interesting_points.push_back (SyncPoint);
505 case SnapToRegionBoundary:
506 interesting_points.push_back (Start);
507 interesting_points.push_back (End);
510 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
515 TimeAxisView *ontrack = 0;
518 if (!selection->tracks.empty()) {
519 tlist = selection->tracks;
524 while (pos < session->current_end_frame() && !at_end) {
527 nframes_t lpos = max_frames;
529 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
531 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
532 if (*p == interesting_points.back()) {
535 /* move to next point type */
541 rpos = r->first_frame();
544 rpos = r->last_frame();
547 rpos = r->adjust_to_sync (r->first_frame());
554 AudioTimeAxisView *atav;
556 if (ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
557 if (atav->get_diskstream() != 0) {
558 speed = atav->get_diskstream()->speed();
562 rpos = track_frame_to_session_frame (rpos, speed);
568 /* prevent duplicates, but we don't use set<> because we want to be able
572 vector<nframes_t>::iterator ri;
574 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
580 if (ri == region_boundary_cache.end()) {
581 region_boundary_cache.push_back (rpos);
588 /* finally sort to be sure that the order is correct */
590 sort (region_boundary_cache.begin(), region_boundary_cache.end());
593 boost::shared_ptr<Region>
594 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
596 TrackViewList::iterator i;
597 nframes_t closest = max_frames;
598 boost::shared_ptr<Region> ret;
602 nframes_t track_frame;
603 AudioTimeAxisView *atav;
605 for (i = tracks.begin(); i != tracks.end(); ++i) {
608 boost::shared_ptr<Region> r;
611 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
612 if (atav->get_diskstream()!=0)
613 track_speed = atav->get_diskstream()->speed();
616 track_frame = session_frame_to_track_frame(frame, track_speed);
618 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
624 rpos = r->first_frame ();
628 rpos = r->last_frame ();
632 rpos = r->adjust_to_sync (r->first_frame());
635 // rpos is a "track frame", converting it to "session frame"
636 rpos = track_frame_to_session_frame(rpos, track_speed);
639 distance = rpos - frame;
641 distance = frame - rpos;
644 if (distance < closest) {
656 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
658 boost::shared_ptr<Region> r;
659 nframes_t pos = cursor->current_frame;
665 TimeAxisView *ontrack = 0;
667 // so we don't find the current region again..
671 if (!selection->tracks.empty()) {
673 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
675 } else if (clicked_trackview) {
678 t.push_back (clicked_trackview);
680 r = find_next_region (pos, point, dir, t, &ontrack);
684 r = find_next_region (pos, point, dir, track_views, &ontrack);
693 pos = r->first_frame ();
697 pos = r->last_frame ();
701 pos = r->adjust_to_sync (r->first_frame());
706 AudioTimeAxisView *atav;
708 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
709 if (atav->get_diskstream() != 0) {
710 speed = atav->get_diskstream()->speed();
714 pos = track_frame_to_session_frame(pos, speed);
716 if (cursor == playhead_cursor) {
717 session->request_locate (pos);
719 cursor->set_position (pos);
724 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
726 cursor_to_region_point (cursor, point, 1);
730 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
732 cursor_to_region_point (cursor, point, -1);
736 Editor::cursor_to_selection_start (Cursor *cursor)
739 switch (mouse_mode) {
741 if (!selection->regions.empty()) {
742 pos = selection->regions.start();
747 if (!selection->time.empty()) {
748 pos = selection->time.start ();
756 if (cursor == playhead_cursor) {
757 session->request_locate (pos);
759 cursor->set_position (pos);
764 Editor::cursor_to_selection_end (Cursor *cursor)
768 switch (mouse_mode) {
770 if (!selection->regions.empty()) {
771 pos = selection->regions.end_frame();
776 if (!selection->time.empty()) {
777 pos = selection->time.end_frame ();
785 if (cursor == playhead_cursor) {
786 session->request_locate (pos);
788 cursor->set_position (pos);
793 Editor::edit_point_to_region_point (RegionPoint point, int32_t dir)
795 boost::shared_ptr<Region> r;
800 if (!session || _edit_point != EditAtSelectedMarker || selection->markers.empty()) {
804 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
808 TimeAxisView *ontrack = 0;
812 // so we don't find the current region again..
816 if (!selection->tracks.empty()) {
818 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
820 } else if (clicked_trackview) {
823 t.push_back (clicked_trackview);
825 r = find_next_region (pos, point, dir, t, &ontrack);
829 r = find_next_region (pos, point, dir, track_views, &ontrack);
838 pos = r->first_frame ();
842 pos = r->last_frame ();
846 pos = r->adjust_to_sync (r->first_frame());
851 AudioTimeAxisView *atav;
853 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
854 if (atav->get_diskstream() != 0) {
855 speed = atav->get_diskstream()->speed();
859 pos = track_frame_to_session_frame(pos, speed);
865 Editor::edit_point_to_next_region_point (RegionPoint point)
867 edit_point_to_region_point (point, 1);
871 Editor::edit_point_to_previous_region_point (RegionPoint point)
873 edit_point_to_region_point (point, -1);
877 Editor::edit_point_to_selection_start ()
883 if (!session || _edit_point != EditAtSelectedMarker || selection->markers.empty()) {
887 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
891 switch (mouse_mode) {
893 if (!selection->regions.empty()) {
894 pos = selection->regions.start();
899 if (!selection->time.empty()) {
900 pos = selection->time.start ();
912 Editor::edit_point_to_selection_end ()
918 if (!session || _edit_point != EditAtSelectedMarker || selection->markers.empty()) {
922 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
926 switch (mouse_mode) {
928 if (!selection->regions.empty()) {
929 pos = selection->regions.end_frame();
934 if (!selection->time.empty()) {
935 pos = selection->time.end_frame ();
947 Editor::scroll_playhead (bool forward)
949 nframes_t pos = playhead_cursor->current_frame;
950 nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
953 if (pos == max_frames) {
957 if (pos < max_frames - delta) {
976 session->request_locate (pos);
980 Editor::playhead_backward ()
987 if (get_prefix (prefix, was_floating)) {
991 cnt = (nframes_t) floor (prefix * session->frame_rate ());
993 cnt = (nframes_t) prefix;
997 pos = playhead_cursor->current_frame;
999 if ((nframes_t) pos < cnt) {
1005 /* XXX this is completely insane. with the current buffering
1006 design, we'll force a complete track buffer flush and
1007 reload, just to move 1 sample !!!
1010 session->request_locate (pos);
1014 Editor::playhead_forward ()
1021 if (get_prefix (prefix, was_floating)) {
1025 cnt = (nframes_t) floor (prefix * session->frame_rate ());
1027 cnt = (nframes_t) floor (prefix);
1031 pos = playhead_cursor->current_frame;
1033 /* XXX this is completely insane. with the current buffering
1034 design, we'll force a complete track buffer flush and
1035 reload, just to move 1 sample !!!
1038 session->request_locate (pos+cnt);
1042 Editor::cursor_align (bool playhead_to_edit)
1044 if (playhead_to_edit) {
1046 session->request_locate (get_preferred_edit_position());
1049 if (_edit_point == EditAtSelectedMarker) {
1051 /* move selected markers to playhead */
1053 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1056 Location* loc = find_location_from_marker (*i, ignored);
1058 if (loc->is_mark()) {
1059 loc->set_start (playhead_cursor->current_frame);
1061 loc->set (playhead_cursor->current_frame,
1062 playhead_cursor->current_frame + loc->length());
1070 Editor::edit_cursor_backward ()
1077 if (get_prefix (prefix, was_floating)) {
1081 cnt = (nframes_t) floor (prefix * session->frame_rate ());
1083 cnt = (nframes_t) prefix;
1087 if ((pos = get_preferred_edit_position()) < 0) {
1097 // EDIT CURSOR edit_cursor->set_position (pos);
1101 Editor::edit_cursor_forward ()
1108 if (get_prefix (prefix, was_floating)) {
1112 cnt = (nframes_t) floor (prefix * session->frame_rate ());
1114 cnt = (nframes_t) floor (prefix);
1118 // pos = edit_cursor->current_frame;
1119 // EDIT CURSOR edit_cursor->set_position (pos+cnt);
1123 Editor::goto_frame ()
1129 if (get_prefix (prefix, was_floating)) {
1134 frame = (nframes_t) floor (prefix * session->frame_rate());
1136 frame = (nframes_t) floor (prefix);
1139 session->request_locate (frame);
1143 Editor::scroll_backward (float pages)
1146 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1151 if (get_prefix (prefix, was_floating)) {
1152 cnt = (nframes_t) floor (pages * one_page);
1155 cnt = (nframes_t) floor (prefix * session->frame_rate());
1157 cnt = (nframes_t) floor (prefix * one_page);
1161 if (leftmost_frame < cnt) {
1164 frame = leftmost_frame - cnt;
1167 reset_x_origin (frame);
1171 Editor::scroll_forward (float pages)
1174 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1179 if (get_prefix (prefix, was_floating)) {
1180 cnt = (nframes_t) floor (pages * one_page);
1183 cnt = (nframes_t) floor (prefix * session->frame_rate());
1185 cnt = (nframes_t) floor (prefix * one_page);
1189 if (max_frames - cnt < leftmost_frame) {
1190 frame = max_frames - cnt;
1192 frame = leftmost_frame + cnt;
1195 reset_x_origin (frame);
1199 Editor::scroll_tracks_down ()
1205 if (get_prefix (prefix, was_floating)) {
1208 cnt = (int) floor (prefix);
1211 double vert_value = vertical_adjustment.get_value() + (cnt *
1212 vertical_adjustment.get_page_size());
1213 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1214 vert_value = vertical_adjustment.get_upper() - canvas_height;
1216 vertical_adjustment.set_value (vert_value);
1220 Editor::scroll_tracks_up ()
1226 if (get_prefix (prefix, was_floating)) {
1229 cnt = (int) floor (prefix);
1232 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1236 Editor::scroll_tracks_down_line ()
1239 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1240 double vert_value = adj->get_value() + 20;
1242 if (vert_value>adj->get_upper() - canvas_height) {
1243 vert_value = adj->get_upper() - canvas_height;
1245 adj->set_value (vert_value);
1249 Editor::scroll_tracks_up_line ()
1251 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1252 adj->set_value (adj->get_value() - 20);
1258 Editor::temporal_zoom_step (bool coarser)
1260 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1264 nfpu = frames_per_unit;
1269 nfpu = max(1.0,(nfpu/1.61803399));
1272 temporal_zoom (nfpu);
1276 Editor::temporal_zoom (gdouble fpu)
1278 if (!session) return;
1280 nframes64_t current_page = current_page_frames();
1281 nframes64_t current_leftmost = leftmost_frame;
1282 nframes64_t current_rightmost;
1283 nframes64_t current_center;
1284 nframes64_t new_page;
1285 nframes64_t leftmost_after_zoom = 0;
1287 bool in_track_canvas;
1292 new_page = (nframes_t) floor (canvas_width * nfpu);
1294 switch (zoom_focus) {
1296 leftmost_after_zoom = current_leftmost;
1299 case ZoomFocusRight:
1300 current_rightmost = leftmost_frame + current_page;
1301 if (current_rightmost > new_page) {
1302 leftmost_after_zoom = current_rightmost - new_page;
1304 leftmost_after_zoom = 0;
1308 case ZoomFocusCenter:
1309 current_center = current_leftmost + (current_page/2);
1310 if (current_center > (new_page/2)) {
1311 leftmost_after_zoom = current_center - (new_page / 2);
1313 leftmost_after_zoom = 0;
1317 case ZoomFocusPlayhead:
1318 /* try to keep the playhead in the center */
1319 if (playhead_cursor->current_frame > new_page/2) {
1320 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1322 leftmost_after_zoom = 0;
1326 case ZoomFocusMouse:
1327 /* try to keep the mouse over the same point in the display */
1329 if (!mouse_frame (where, in_track_canvas)) {
1330 /* use playhead instead */
1331 where = playhead_cursor->current_frame;
1333 if (where > new_page/2) {
1334 leftmost_after_zoom = where - (new_page/2);
1336 leftmost_after_zoom = 0;
1341 double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where);
1344 leftmost_after_zoom = 0;
1345 } else if (l > max_frames) {
1346 leftmost_after_zoom = max_frames - new_page;
1348 leftmost_after_zoom = (nframes64_t) l;
1355 /* try to keep the edit point in the center */
1356 if (get_preferred_edit_position() > new_page/2) {
1357 leftmost_after_zoom = get_preferred_edit_position() - (new_page/2);
1359 leftmost_after_zoom = 0;
1365 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1367 // begin_reversible_command (_("zoom"));
1368 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1369 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1370 // commit_reversible_command ();
1372 // cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl;
1374 reposition_and_zoom (leftmost_after_zoom, nfpu);
1378 Editor::temporal_zoom_selection ()
1380 if (!selection) return;
1382 if (selection->time.empty()) {
1386 nframes_t start = selection->time[clicked_selection].start;
1387 nframes_t end = selection->time[clicked_selection].end;
1389 temporal_zoom_by_frame (start, end, "zoom to selection");
1393 Editor::temporal_zoom_session ()
1395 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1398 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1403 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1405 if (!session) return;
1407 if ((start == 0 && end == 0) || end < start) {
1411 nframes_t range = end - start;
1413 double new_fpu = (double)range / (double)canvas_width;
1416 // while (p2 < new_fpu) {
1421 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1422 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1423 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1425 if (new_leftmost > middle) new_leftmost = 0;
1427 // begin_reversible_command (op);
1428 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1429 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1430 // commit_reversible_command ();
1432 reposition_and_zoom (new_leftmost, new_fpu);
1436 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1438 if (!session) return;
1440 double range_before = frame - leftmost_frame;
1443 new_fpu = frames_per_unit;
1446 new_fpu *= 1.61803399;
1447 range_before *= 1.61803399;
1449 new_fpu = max(1.0,(new_fpu/1.61803399));
1450 range_before /= 1.61803399;
1453 if (new_fpu == frames_per_unit) return;
1455 nframes_t new_leftmost = frame - (nframes_t)range_before;
1457 if (new_leftmost > frame) new_leftmost = 0;
1459 // begin_reversible_command (_("zoom to frame"));
1460 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1461 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1462 // commit_reversible_command ();
1464 reposition_and_zoom (new_leftmost, new_fpu);
1468 Editor::add_location_from_selection ()
1472 if (selection->time.empty()) {
1476 if (session == 0 || clicked_trackview == 0) {
1480 nframes_t start = selection->time[clicked_selection].start;
1481 nframes_t end = selection->time[clicked_selection].end;
1483 session->locations()->next_available_name(rangename,"selection");
1484 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1486 session->begin_reversible_command (_("add marker"));
1487 XMLNode &before = session->locations()->get_state();
1488 session->locations()->add (location, true);
1489 XMLNode &after = session->locations()->get_state();
1490 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1491 session->commit_reversible_command ();
1495 Editor::add_location_from_playhead_cursor ()
1499 nframes_t where = session->audible_frame();
1501 session->locations()->next_available_name(markername,"mark");
1502 Location *location = new Location (where, where, markername, Location::IsMark);
1503 session->begin_reversible_command (_("add marker"));
1504 XMLNode &before = session->locations()->get_state();
1505 session->locations()->add (location, true);
1506 XMLNode &after = session->locations()->get_state();
1507 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1508 session->commit_reversible_command ();
1512 Editor::add_location_from_audio_region ()
1514 if (selection->regions.empty()) {
1518 RegionView* rv = *(selection->regions.begin());
1519 boost::shared_ptr<Region> region = rv->region();
1521 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1522 session->begin_reversible_command (_("add marker"));
1523 XMLNode &before = session->locations()->get_state();
1524 session->locations()->add (location, true);
1525 XMLNode &after = session->locations()->get_state();
1526 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1527 session->commit_reversible_command ();
1531 Editor::amplitude_zoom_step (bool in)
1545 #ifdef FIX_FOR_CANVAS
1546 /* XXX DO SOMETHING */
1555 Editor::delete_sample_forward ()
1560 Editor::delete_sample_backward ()
1565 Editor::delete_screen ()
1572 Editor::search_backwards ()
1578 Editor::search_forwards ()
1586 Editor::jump_forward_to_mark ()
1592 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1595 session->request_locate (location->start(), session->transport_rolling());
1597 session->request_locate (session->current_end_frame());
1602 Editor::jump_backward_to_mark ()
1608 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1611 session->request_locate (location->start(), session->transport_rolling());
1613 session->goto_start ();
1625 if (get_prefix (prefix, was_floating)) {
1626 pos = session->audible_frame ();
1629 pos = (nframes_t) floor (prefix * session->frame_rate ());
1631 pos = (nframes_t) floor (prefix);
1635 session->locations()->next_available_name(markername,"mark");
1636 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1640 Editor::clear_markers ()
1643 session->begin_reversible_command (_("clear markers"));
1644 XMLNode &before = session->locations()->get_state();
1645 session->locations()->clear_markers ();
1646 XMLNode &after = session->locations()->get_state();
1647 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1648 session->commit_reversible_command ();
1653 Editor::clear_ranges ()
1656 session->begin_reversible_command (_("clear ranges"));
1657 XMLNode &before = session->locations()->get_state();
1659 Location * looploc = session->locations()->auto_loop_location();
1660 Location * punchloc = session->locations()->auto_punch_location();
1662 session->locations()->clear_ranges ();
1664 if (looploc) session->locations()->add (looploc);
1665 if (punchloc) session->locations()->add (punchloc);
1667 XMLNode &after = session->locations()->get_state();
1668 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1669 session->commit_reversible_command ();
1674 Editor::clear_locations ()
1676 session->begin_reversible_command (_("clear locations"));
1677 XMLNode &before = session->locations()->get_state();
1678 session->locations()->clear ();
1679 XMLNode &after = session->locations()->get_state();
1680 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1681 session->commit_reversible_command ();
1682 session->locations()->clear ();
1686 Editor::unhide_markers ()
1688 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1689 Location *l = (*i).first;
1690 if (l->is_hidden() && l->is_mark()) {
1691 l->set_hidden(false, this);
1697 Editor::unhide_ranges ()
1699 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1700 Location *l = (*i).first;
1701 if (l->is_hidden() && l->is_range_marker()) {
1702 l->set_hidden(false, this);
1707 /* INSERT/REPLACE */
1710 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1716 AudioTimeAxisView *atv = 0;
1717 boost::shared_ptr<Playlist> playlist;
1719 track_canvas.window_to_world (x, y, wx, wy);
1720 wx += horizontal_adjustment.get_value();
1721 wy += vertical_adjustment.get_value();
1724 event.type = GDK_BUTTON_RELEASE;
1725 event.button.x = wx;
1726 event.button.y = wy;
1728 where = event_frame (&event, &cx, &cy);
1730 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1731 /* clearly outside canvas area */
1735 if ((tv = trackview_by_y_position (cy)) == 0) {
1739 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1743 if ((playlist = atv->playlist()) == 0) {
1749 begin_reversible_command (_("insert dragged region"));
1750 XMLNode &before = playlist->get_state();
1751 playlist->add_region (RegionFactory::create (region), where, 1.0);
1752 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1753 commit_reversible_command ();
1757 Editor::insert_region_list_selection (float times)
1759 RouteTimeAxisView *tv = 0;
1760 boost::shared_ptr<Playlist> playlist;
1762 if (clicked_audio_trackview != 0) {
1763 tv = clicked_audio_trackview;
1764 } else if (!selection->tracks.empty()) {
1765 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1772 if ((playlist = tv->playlist()) == 0) {
1776 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1778 if (selected->count_selected_rows() != 1) {
1782 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1784 /* only one row selected, so rows.begin() is it */
1788 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1790 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1792 begin_reversible_command (_("insert region"));
1793 XMLNode &before = playlist->get_state();
1794 playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
1795 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1796 commit_reversible_command ();
1800 /* BUILT-IN EFFECTS */
1803 Editor::reverse_selection ()
1808 /* GAIN ENVELOPE EDITING */
1811 Editor::edit_envelope ()
1818 Editor::transition_to_rolling (bool fwd)
1824 switch (Config->get_slave_source()) {
1829 /* transport controlled by the master */
1833 if (session->is_auditioning()) {
1834 session->cancel_audition ();
1838 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1842 Editor::toggle_playback (bool with_abort)
1848 switch (Config->get_slave_source()) {
1853 /* transport controlled by the master */
1857 if (session->is_auditioning()) {
1858 session->cancel_audition ();
1862 if (session->transport_rolling()) {
1863 session->request_stop (with_abort);
1864 if (session->get_play_loop()) {
1865 session->request_play_loop (false);
1868 session->request_transport_speed (1.0f);
1873 Editor::play_from_start ()
1875 session->request_locate (session->current_start_frame(), true);
1879 Editor::play_from_edit_point ()
1881 session->request_locate (get_preferred_edit_position(), true);
1885 Editor::play_selection ()
1887 if (selection->time.empty()) {
1891 session->request_play_range (true);
1895 Editor::play_selected_region ()
1897 if (!selection->regions.empty()) {
1898 RegionView *rv = *(selection->regions.begin());
1900 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1905 Editor::loop_selected_region ()
1907 if (!selection->regions.empty()) {
1908 RegionView *rv = *(selection->regions.begin());
1911 if ((tll = transport_loop_location()) != 0) {
1913 tll->set (rv->region()->position(), rv->region()->last_frame());
1915 // enable looping, reposition and start rolling
1917 session->request_play_loop (true);
1918 session->request_locate (tll->start(), false);
1919 session->request_transport_speed (1.0f);
1925 Editor::play_location (Location& location)
1927 if (location.start() <= location.end()) {
1931 session->request_bounded_roll (location.start(), location.end());
1935 Editor::loop_location (Location& location)
1937 if (location.start() <= location.end()) {
1943 if ((tll = transport_loop_location()) != 0) {
1944 tll->set (location.start(), location.end());
1946 // enable looping, reposition and start rolling
1947 session->request_play_loop (true);
1948 session->request_locate (tll->start(), true);
1953 Editor::raise_region ()
1955 selection->foreach_region (&Region::raise);
1959 Editor::raise_region_to_top ()
1961 selection->foreach_region (&Region::raise_to_top);
1965 Editor::lower_region ()
1967 selection->foreach_region (&Region::lower);
1971 Editor::lower_region_to_bottom ()
1973 selection->foreach_region (&Region::lower_to_bottom);
1977 Editor::edit_region ()
1979 if (clicked_regionview == 0) {
1983 clicked_regionview->show_region_editor ();
1987 Editor::rename_region ()
1991 Button ok_button (_("OK"));
1992 Button cancel_button (_("Cancel"));
1994 if (selection->regions.empty()) {
1998 WindowTitle title(Glib::get_application_name());
1999 title += _("Rename Region");
2001 dialog.set_title (title.get_string());
2002 dialog.set_name ("RegionRenameWindow");
2003 dialog.set_size_request (300, -1);
2004 dialog.set_position (Gtk::WIN_POS_MOUSE);
2005 dialog.set_modal (true);
2007 dialog.get_vbox()->set_border_width (10);
2008 dialog.get_vbox()->pack_start (entry);
2009 dialog.get_action_area()->pack_start (ok_button);
2010 dialog.get_action_area()->pack_start (cancel_button);
2012 entry.set_name ("RegionNameDisplay");
2013 ok_button.set_name ("EditorGTKButton");
2014 cancel_button.set_name ("EditorGTKButton");
2016 region_renamed = false;
2018 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2019 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2020 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2027 if (region_renamed) {
2028 (*selection->regions.begin())->region()->set_name (entry.get_text());
2029 redisplay_regions ();
2034 Editor::rename_region_finished (bool status)
2037 region_renamed = status;
2042 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2044 if (session->is_auditioning()) {
2045 session->cancel_audition ();
2048 // note: some potential for creativity here, because region doesn't
2049 // have to belong to the playlist that Route is handling
2051 // bool was_soloed = route.soloed();
2053 route.set_solo (true, this);
2055 session->request_bounded_roll (region->position(), region->position() + region->length());
2057 /* XXX how to unset the solo state ? */
2061 Editor::audition_selected_region ()
2063 if (!selection->regions.empty()) {
2064 RegionView* rv = *(selection->regions.begin());
2065 session->audition_region (rv->region());
2070 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2072 session->audition_region (region);
2076 Editor::build_interthread_progress_window ()
2078 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2080 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2082 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2083 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2085 // GTK2FIX: this button needs a modifiable label
2087 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2088 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2090 interthread_cancel_button.add (interthread_cancel_label);
2092 interthread_progress_window->set_default_size (200, 100);
2096 Editor::interthread_cancel_clicked ()
2098 if (current_interthread_info) {
2099 current_interthread_info->cancel = true;
2104 Editor::region_from_selection ()
2106 if (clicked_trackview == 0) {
2110 if (selection->time.empty()) {
2114 nframes_t start = selection->time[clicked_selection].start;
2115 nframes_t end = selection->time[clicked_selection].end;
2117 nframes_t selection_cnt = end - start + 1;
2119 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2120 boost::shared_ptr<AudioRegion> current;
2121 boost::shared_ptr<Region> current_r;
2122 boost::shared_ptr<Playlist> pl;
2124 nframes_t internal_start;
2127 if ((pl = (*i)->playlist()) == 0) {
2131 if ((current_r = pl->top_region_at (start)) == 0) {
2135 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2136 // FIXME: audio only
2138 internal_start = start - current->position();
2139 session->region_name (new_name, current->name(), true);
2140 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2146 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2148 if (selection->time.empty() || selection->tracks.empty()) {
2152 nframes_t start = selection->time[clicked_selection].start;
2153 nframes_t end = selection->time[clicked_selection].end;
2155 sort_track_selection ();
2157 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2159 boost::shared_ptr<AudioRegion> current;
2160 boost::shared_ptr<Region> current_r;
2161 boost::shared_ptr<Playlist> playlist;
2162 nframes_t internal_start;
2165 if ((playlist = (*i)->playlist()) == 0) {
2169 if ((current_r = playlist->top_region_at(start)) == 0) {
2173 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2177 internal_start = start - current->position();
2178 session->region_name (new_name, current->name(), true);
2180 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2185 Editor::split_multichannel_region ()
2187 if (selection->regions.empty()) {
2191 vector<boost::shared_ptr<AudioRegion> > v;
2193 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2195 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
2197 if (!arv || arv->audio_region()->n_channels() < 2) {
2201 (arv)->audio_region()->separate_by_channel (*session, v);
2206 Editor::new_region_from_selection ()
2208 region_from_selection ();
2209 cancel_selection ();
2213 Editor::separate_region_from_selection ()
2215 bool doing_undo = false;
2217 if (selection->time.empty()) {
2221 boost::shared_ptr<Playlist> playlist;
2223 sort_track_selection ();
2225 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2227 AudioTimeAxisView* atv;
2229 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2231 if (atv->is_audio_track()) {
2233 /* no edits to destructive tracks */
2235 if (atv->audio_track()->audio_diskstream()->destructive()) {
2239 if ((playlist = atv->playlist()) != 0) {
2241 begin_reversible_command (_("separate"));
2246 before = &(playlist->get_state());
2248 /* XXX need to consider musical time selections here at some point */
2250 double speed = atv->get_diskstream()->speed();
2252 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2253 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2257 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2263 if (doing_undo) commit_reversible_command ();
2267 Editor::separate_regions_using_location (Location& loc)
2269 bool doing_undo = false;
2271 if (loc.is_mark()) {
2275 boost::shared_ptr<Playlist> playlist;
2277 /* XXX i'm unsure as to whether this should operate on selected tracks only
2278 or the entire enchillada. uncomment the below line to correct the behaviour
2279 (currently set for all tracks)
2282 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2283 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2285 AudioTimeAxisView* atv;
2287 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2289 if (atv->is_audio_track()) {
2291 /* no edits to destructive tracks */
2293 if (atv->audio_track()->audio_diskstream()->destructive()) {
2297 if ((playlist = atv->playlist()) != 0) {
2300 begin_reversible_command (_("separate"));
2304 before = &(playlist->get_state());
2307 /* XXX need to consider musical time selections here at some point */
2309 double speed = atv->get_diskstream()->speed();
2312 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2314 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2320 if (doing_undo) commit_reversible_command ();
2324 Editor::crop_region_to_selection ()
2326 if (selection->time.empty() || selection->tracks.empty()) {
2330 vector<boost::shared_ptr<Playlist> > playlists;
2331 boost::shared_ptr<Playlist> playlist;
2333 sort_track_selection ();
2335 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2337 AudioTimeAxisView* atv;
2339 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2341 if (atv->is_audio_track()) {
2343 /* no edits to destructive tracks */
2345 if (atv->audio_track()->audio_diskstream()->destructive()) {
2349 if ((playlist = atv->playlist()) != 0) {
2350 playlists.push_back (playlist);
2356 if (playlists.empty()) {
2364 begin_reversible_command (_("trim to selection"));
2366 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2368 boost::shared_ptr<Region> region;
2370 start = selection->time.start();
2372 if ((region = (*i)->top_region_at(start)) == 0) {
2376 /* now adjust lengths to that we do the right thing
2377 if the selection extends beyond the region
2380 start = max (start, region->position());
2381 if (max_frames - start < region->length()) {
2382 end = start + region->length() - 1;
2386 end = min (selection->time.end_frame(), end);
2387 cnt = end - start + 1;
2389 XMLNode &before = (*i)->get_state();
2390 region->trim_to (start, cnt, this);
2391 XMLNode &after = (*i)->get_state();
2392 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2395 commit_reversible_command ();
2399 Editor::region_fill_track ()
2403 if (!session || selection->regions.empty()) {
2407 end = session->current_end_frame ();
2409 begin_reversible_command (_("region fill"));
2411 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2413 boost::shared_ptr<Region> region ((*i)->region());
2416 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2420 boost::shared_ptr<Playlist> pl = region->playlist();
2422 if (end <= region->last_frame()) {
2426 double times = (double) (end - region->last_frame()) / (double) region->length();
2432 XMLNode &before = pl->get_state();
2433 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2434 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2437 commit_reversible_command ();
2441 Editor::region_fill_selection ()
2443 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2447 if (selection->time.empty()) {
2452 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2454 if (selected->count_selected_rows() != 1) {
2458 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2459 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2461 nframes_t start = selection->time[clicked_selection].start;
2462 nframes_t end = selection->time[clicked_selection].end;
2464 boost::shared_ptr<Playlist> playlist;
2466 if (selection->tracks.empty()) {
2470 nframes_t selection_length = end - start;
2471 float times = (float)selection_length / region->length();
2473 begin_reversible_command (_("fill selection"));
2475 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2477 if ((playlist = (*i)->playlist()) == 0) {
2481 XMLNode &before = playlist->get_state();
2482 playlist->add_region (RegionFactory::create (region), start, times);
2483 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2486 commit_reversible_command ();
2490 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2493 if (!region->covers (position)) {
2494 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2497 begin_reversible_command (_("set region sync position"));
2498 XMLNode &before = region->playlist()->get_state();
2499 region->set_sync_position (position);
2500 XMLNode &after = region->playlist()->get_state();
2501 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2502 commit_reversible_command ();
2506 Editor::set_region_sync_from_edit_point ()
2508 if (clicked_regionview == 0) {
2512 if (!clicked_regionview->region()->covers (get_preferred_edit_position())) {
2513 error << _("Place the edit point at the desired sync point") << endmsg;
2517 boost::shared_ptr<Region> region (clicked_regionview->region());
2518 begin_reversible_command (_("set sync from edit point"));
2519 XMLNode &before = region->playlist()->get_state();
2520 region->set_sync_position (get_preferred_edit_position());
2521 XMLNode &after = region->playlist()->get_state();
2522 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2523 commit_reversible_command ();
2527 Editor::remove_region_sync ()
2529 if (clicked_regionview) {
2530 boost::shared_ptr<Region> region (clicked_regionview->region());
2531 begin_reversible_command (_("remove sync"));
2532 XMLNode &before = region->playlist()->get_state();
2533 region->clear_sync_position ();
2534 XMLNode &after = region->playlist()->get_state();
2535 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2536 commit_reversible_command ();
2541 Editor::naturalize ()
2543 if (selection->regions.empty()) {
2546 begin_reversible_command (_("naturalize"));
2547 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2548 XMLNode &before = (*i)->region()->get_state();
2549 (*i)->region()->move_to_natural_position (this);
2550 XMLNode &after = (*i)->region()->get_state();
2551 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2553 commit_reversible_command ();
2557 Editor::align (RegionPoint what)
2559 align_selection (what, get_preferred_edit_position(), selection->regions);
2563 Editor::align_relative (RegionPoint what)
2565 align_selection_relative (what, get_preferred_edit_position(), selection->regions);
2568 struct RegionSortByTime {
2569 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2570 return a->region()->position() < b->region()->position();
2575 Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
2585 list<RegionView*> sorted;
2586 rs.by_position (sorted);
2587 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2591 pos = r->first_frame ();
2595 pos = r->last_frame();
2599 pos = r->adjust_to_sync (r->first_frame());
2603 if (pos > position) {
2604 distance = pos - position;
2607 distance = position - pos;
2611 begin_reversible_command (_("align selection (relative)"));
2613 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2615 boost::shared_ptr<Region> region ((*i)->region());
2617 XMLNode &before = region->playlist()->get_state();
2620 region->set_position (region->position() + distance, this);
2622 region->set_position (region->position() - distance, this);
2625 XMLNode &after = region->playlist()->get_state();
2626 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2630 commit_reversible_command ();
2634 Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
2640 begin_reversible_command (_("align selection"));
2642 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2643 align_region_internal ((*i)->region(), point, position);
2646 commit_reversible_command ();
2650 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2652 begin_reversible_command (_("align region"));
2653 align_region_internal (region, point, position);
2654 commit_reversible_command ();
2658 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2660 XMLNode &before = region->playlist()->get_state();
2664 region->set_position (region->adjust_to_sync (position), this);
2668 if (position > region->length()) {
2669 region->set_position (position - region->length(), this);
2674 region->set_position (position, this);
2678 XMLNode &after = region->playlist()->get_state();
2679 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2683 Editor::trim_region_to_edit_point ()
2685 if (clicked_regionview == 0) {
2689 boost::shared_ptr<Region> region (clicked_regionview->region());
2692 AudioTimeAxisView *atav;
2694 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2695 if (atav->get_diskstream() != 0) {
2696 speed = atav->get_diskstream()->speed();
2700 begin_reversible_command (_("trim to edit"));
2701 XMLNode &before = region->playlist()->get_state();
2702 region->trim_end( session_frame_to_track_frame(get_preferred_edit_position(), speed), this);
2703 XMLNode &after = region->playlist()->get_state();
2704 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2705 commit_reversible_command ();
2709 Editor::trim_region_from_edit_point ()
2711 if (clicked_regionview == 0) {
2715 boost::shared_ptr<Region> region (clicked_regionview->region());
2718 AudioTimeAxisView *atav;
2720 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2721 if (atav->get_diskstream() != 0) {
2722 speed = atav->get_diskstream()->speed();
2726 begin_reversible_command (_("trim to edit"));
2727 XMLNode &before = region->playlist()->get_state();
2728 region->trim_front ( session_frame_to_track_frame(get_preferred_edit_position(), speed), this);
2729 XMLNode &after = region->playlist()->get_state();
2730 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2731 commit_reversible_command ();
2735 Editor::unfreeze_route ()
2737 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2741 clicked_audio_trackview->audio_track()->unfreeze ();
2745 Editor::_freeze_thread (void* arg)
2747 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2748 return static_cast<Editor*>(arg)->freeze_thread ();
2752 Editor::freeze_thread ()
2754 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2759 Editor::freeze_progress_timeout (void *arg)
2761 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2762 return !(current_interthread_info->done || current_interthread_info->cancel);
2766 Editor::freeze_route ()
2768 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2772 InterThreadInfo itt;
2774 if (interthread_progress_window == 0) {
2775 build_interthread_progress_window ();
2778 WindowTitle title(Glib::get_application_name());
2779 title += _("Freeze");
2780 interthread_progress_window->set_title (title.get_string());
2781 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2782 interthread_progress_window->show_all ();
2783 interthread_progress_bar.set_fraction (0.0f);
2784 interthread_progress_label.set_text ("");
2785 interthread_cancel_label.set_text (_("Cancel Freeze"));
2786 current_interthread_info = &itt;
2788 interthread_progress_connection =
2789 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2793 itt.progress = 0.0f;
2795 pthread_attr_t attr;
2796 pthread_attr_init(&attr);
2797 pthread_attr_setstacksize(&attr, 500000);
2799 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2801 pthread_attr_destroy(&attr);
2803 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2805 while (!itt.done && !itt.cancel) {
2806 gtk_main_iteration ();
2809 interthread_progress_connection.disconnect ();
2810 interthread_progress_window->hide_all ();
2811 current_interthread_info = 0;
2812 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2816 Editor::bounce_range_selection ()
2818 if (selection->time.empty()) {
2822 TrackSelection views = selection->tracks;
2824 nframes_t start = selection->time[clicked_selection].start;
2825 nframes_t end = selection->time[clicked_selection].end;
2826 nframes_t cnt = end - start + 1;
2828 begin_reversible_command (_("bounce range"));
2830 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2832 AudioTimeAxisView* atv;
2834 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2838 boost::shared_ptr<Playlist> playlist;
2840 if ((playlist = atv->playlist()) == 0) {
2844 InterThreadInfo itt;
2848 itt.progress = false;
2850 XMLNode &before = playlist->get_state();
2851 atv->audio_track()->bounce_range (start, cnt, itt);
2852 XMLNode &after = playlist->get_state();
2853 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2856 commit_reversible_command ();
2872 Editor::cut_copy (CutCopyOp op)
2874 /* only cancel selection if cut/copy is successful.*/
2886 opname = _("clear");
2890 cut_buffer->clear ();
2892 switch (current_mouse_mode()) {
2894 if (!selection->regions.empty() || !selection->points.empty()) {
2896 begin_reversible_command (opname + _(" objects"));
2898 if (!selection->regions.empty()) {
2900 cut_copy_regions (op);
2903 selection->clear_regions ();
2907 if (!selection->points.empty()) {
2908 cut_copy_points (op);
2911 selection->clear_points ();
2915 commit_reversible_command ();
2920 if (!selection->time.empty()) {
2922 begin_reversible_command (opname + _(" range"));
2923 cut_copy_ranges (op);
2924 commit_reversible_command ();
2927 selection->clear_time ();
2939 Editor::cut_copy_points (CutCopyOp op)
2941 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2943 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2946 atv->cut_copy_clear_objects (selection->points, op);
2951 struct PlaylistState {
2952 boost::shared_ptr<Playlist> playlist;
2956 struct lt_playlist {
2957 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2958 return a.playlist < b.playlist;
2962 struct PlaylistMapping {
2964 boost::shared_ptr<AudioPlaylist> pl;
2966 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2970 Editor::cut_copy_regions (CutCopyOp op)
2972 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2973 a map when we want ordered access to both elements. i think.
2976 vector<PlaylistMapping> pmap;
2978 nframes_t first_position = max_frames;
2980 set<PlaylistState, lt_playlist> freezelist;
2981 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2983 /* get ordering correct before we cut/copy */
2985 selection->regions.sort_by_position_and_track ();
2987 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2989 first_position = min ((*x)->region()->position(), first_position);
2991 if (op == Cut || op == Clear) {
2992 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2996 PlaylistState before;
2997 before.playlist = pl;
2998 before.before = &pl->get_state();
3000 insert_result = freezelist.insert (before);
3002 if (insert_result.second) {
3008 TimeAxisView* tv = &(*x)->get_trackview();
3009 vector<PlaylistMapping>::iterator z;
3011 for (z = pmap.begin(); z != pmap.end(); ++z) {
3012 if ((*z).tv == tv) {
3017 if (z == pmap.end()) {
3018 pmap.push_back (PlaylistMapping (tv));
3022 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3024 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3027 /* impossible, but this handles it for the future */
3031 TimeAxisView& tv = (*x)->get_trackview();
3032 boost::shared_ptr<AudioPlaylist> npl;
3033 RegionSelection::iterator tmp;
3038 vector<PlaylistMapping>::iterator z;
3040 for (z = pmap.begin(); z != pmap.end(); ++z) {
3041 if ((*z).tv == &tv) {
3046 assert (z != pmap.end());
3049 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3056 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3057 boost::shared_ptr<Region> _xx;
3063 _xx = RegionFactory::create ((*x)->region());
3064 npl->add_region (_xx, (*x)->region()->position() - first_position);
3065 pl->remove_region (((*x)->region()));
3071 /* copy region before adding, so we're not putting same object into two different playlists */
3072 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
3076 pl->remove_region (((*x)->region()));
3083 list<boost::shared_ptr<Playlist> > foo;
3085 /* the pmap is in the same order as the tracks in which selected regions occured */
3087 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3089 foo.push_back ((*i).pl);
3094 cut_buffer->set (foo);
3097 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3098 (*pl).playlist->thaw ();
3099 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3104 Editor::cut_copy_ranges (CutCopyOp op)
3106 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3107 (*i)->cut_copy_clear (*selection, op);
3112 Editor::paste (float times)
3114 paste_internal (get_preferred_edit_position(), times);
3118 Editor::mouse_paste ()
3123 if (!mouse_frame (where, ignored)) {
3128 paste_internal (where, 1);
3132 Editor::paste_internal (nframes_t position, float times)
3134 bool commit = false;
3136 if (cut_buffer->empty() || selection->tracks.empty()) {
3140 if (position == max_frames) {
3141 position = get_preferred_edit_position();
3144 begin_reversible_command (_("paste"));
3146 TrackSelection::iterator i;
3149 /* get everything in the correct order */
3151 sort_track_selection ();
3153 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3155 /* undo/redo is handled by individual tracks */
3157 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3163 commit_reversible_command ();
3168 Editor::paste_named_selection (float times)
3170 TrackSelection::iterator t;
3172 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3174 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3178 TreeModel::iterator i = selected->get_selected();
3179 NamedSelection* ns = (*i)[named_selection_columns.selection];
3181 list<boost::shared_ptr<Playlist> >::iterator chunk;
3182 list<boost::shared_ptr<Playlist> >::iterator tmp;
3184 chunk = ns->playlists.begin();
3186 begin_reversible_command (_("paste chunk"));
3188 sort_track_selection ();
3190 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3192 AudioTimeAxisView* atv;
3193 boost::shared_ptr<Playlist> pl;
3194 boost::shared_ptr<AudioPlaylist> apl;
3196 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3200 if ((pl = atv->playlist()) == 0) {
3204 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3211 XMLNode &before = apl->get_state();
3212 apl->paste (*chunk, get_preferred_edit_position(), times);
3213 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3215 if (tmp != ns->playlists.end()) {
3220 commit_reversible_command();
3224 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3226 boost::shared_ptr<Playlist> playlist;
3227 RegionSelection sel = regions; // clear (below) will clear the argument list
3229 begin_reversible_command (_("duplicate region"));
3231 selection->clear_regions ();
3233 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3235 boost::shared_ptr<Region> r ((*i)->region());
3237 TimeAxisView& tv = (*i)->get_time_axis_view();
3238 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3239 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3241 playlist = (*i)->region()->playlist();
3242 XMLNode &before = playlist->get_state();
3243 playlist->duplicate (r, r->last_frame() + 1, times);
3244 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3248 if (latest_regionview) {
3249 selection->add (latest_regionview);
3254 commit_reversible_command ();
3258 Editor::duplicate_selection (float times)
3260 if (selection->time.empty() || selection->tracks.empty()) {
3264 boost::shared_ptr<Playlist> playlist;
3265 vector<boost::shared_ptr<AudioRegion> > new_regions;
3266 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3268 create_region_from_selection (new_regions);
3270 if (new_regions.empty()) {
3274 begin_reversible_command (_("duplicate selection"));
3276 ri = new_regions.begin();
3278 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3279 if ((playlist = (*i)->playlist()) == 0) {
3282 XMLNode &before = playlist->get_state();
3283 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3284 XMLNode &after = playlist->get_state();
3285 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3288 if (ri == new_regions.end()) {
3293 commit_reversible_command ();
3297 Editor::reset_point_selection ()
3299 /* reset all selected points to the relevant default value */
3301 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3303 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3306 atv->reset_objects (selection->points);
3312 Editor::center_playhead ()
3314 float page = canvas_width * frames_per_unit;
3315 center_screen_internal (playhead_cursor->current_frame, page);
3319 Editor::center_edit_point ()
3321 float page = canvas_width * frames_per_unit;
3322 center_screen_internal (get_preferred_edit_position(), page);
3326 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3328 begin_reversible_command (_("clear playlist"));
3329 XMLNode &before = playlist->get_state();
3331 XMLNode &after = playlist->get_state();
3332 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3333 commit_reversible_command ();
3337 Editor::nudge_track (bool use_edit, bool forwards)
3339 boost::shared_ptr<Playlist> playlist;
3341 nframes_t next_distance;
3345 start = get_preferred_edit_position();
3350 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3354 if (selection->tracks.empty()) {
3358 begin_reversible_command (_("nudge track"));
3360 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3362 if ((playlist = (*i)->playlist()) == 0) {
3366 XMLNode &before = playlist->get_state();
3367 playlist->nudge_after (start, distance, forwards);
3368 XMLNode &after = playlist->get_state();
3369 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3372 commit_reversible_command ();
3376 Editor::remove_last_capture ()
3378 vector<string> choices;
3385 if (Config->get_verify_remove_last_capture()) {
3386 prompt = _("Do you really want to destroy the last capture?"
3387 "\n(This is destructive and cannot be undone)");
3389 choices.push_back (_("No, do nothing."));
3390 choices.push_back (_("Yes, destroy it."));
3392 Gtkmm2ext::Choice prompter (prompt, choices);
3394 if (prompter.run () == 1) {
3395 session->remove_last_capture ();
3399 session->remove_last_capture();
3404 Editor::normalize_region ()
3410 if (selection->regions.empty()) {
3414 begin_reversible_command (_("normalize"));
3416 track_canvas.get_window()->set_cursor (*wait_cursor);
3419 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3420 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3423 XMLNode &before = arv->region()->get_state();
3424 arv->audio_region()->normalize_to (0.0f);
3425 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3428 commit_reversible_command ();
3429 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3434 Editor::denormalize_region ()
3440 if (selection->regions.empty()) {
3444 begin_reversible_command ("denormalize");
3446 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3447 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3450 XMLNode &before = arv->region()->get_state();
3451 arv->audio_region()->set_scale_amplitude (1.0f);
3452 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3455 commit_reversible_command ();
3460 Editor::reverse_region ()
3466 Reverse rev (*session);
3467 apply_filter (rev, _("reverse regions"));
3471 Editor::apply_filter (AudioFilter& filter, string command)
3473 if (selection->regions.empty()) {
3477 begin_reversible_command (command);
3479 track_canvas.get_window()->set_cursor (*wait_cursor);
3482 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3483 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3487 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3489 RegionSelection::iterator tmp;
3494 if (arv->audio_region()->apply (filter) == 0) {
3496 XMLNode &before = playlist->get_state();
3497 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3498 XMLNode &after = playlist->get_state();
3499 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3507 commit_reversible_command ();
3508 selection->regions.clear ();
3511 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3515 Editor::region_selection_op (void (Region::*pmf)(void))
3517 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3518 Region* region = (*i)->region().get();
3525 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3527 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3528 Region* region = (*i)->region().get();
3529 (region->*pmf)(arg);
3534 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3536 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3537 Region* region = (*i)->region().get();
3543 Editor::external_edit_region ()
3545 if (!clicked_regionview) {
3553 Editor::brush (nframes_t pos)
3555 RegionSelection sel;
3558 if (selection->regions.empty()) {
3559 /* XXX get selection from region list */
3561 sel = selection->regions;
3568 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3569 mouse_brush_insert_region ((*i), pos);
3574 Editor::reset_region_gain_envelopes ()
3576 if (!session || selection->regions.empty()) {
3580 session->begin_reversible_command (_("reset region gain"));
3582 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3583 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3585 AutomationList& alist (arv->audio_region()->envelope());
3586 XMLNode& before (alist.get_state());
3588 arv->audio_region()->set_default_envelope ();
3589 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3593 session->commit_reversible_command ();
3597 Editor::toggle_gain_envelope_visibility ()
3599 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3600 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3602 bool x = region_envelope_visible_item->get_active();
3603 if (x != arv->envelope_visible()) {
3604 arv->set_envelope_visible (x);
3611 Editor::toggle_gain_envelope_active ()
3613 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3614 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3616 bool x = region_envelope_active_item->get_active();
3617 if (x != arv->audio_region()->envelope_active()) {
3618 arv->audio_region()->set_envelope_active (x);
3625 Editor::toggle_region_lock ()
3627 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3628 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3630 bool x = region_lock_item->get_active();
3631 if (x != arv->audio_region()->locked()) {
3632 arv->audio_region()->set_locked (x);
3639 Editor::toggle_region_mute ()
3641 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3642 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3644 bool x = region_mute_item->get_active();
3645 if (x != arv->audio_region()->muted()) {
3646 arv->audio_region()->set_muted (x);
3653 Editor::toggle_region_opaque ()
3655 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3656 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3658 bool x = region_opaque_item->get_active();
3659 if (x != arv->audio_region()->opaque()) {
3660 arv->audio_region()->set_opaque (x);
3667 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3669 begin_reversible_command (_("set fade in shape"));
3671 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3672 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3678 AutomationList& alist = tmp->audio_region()->fade_in();
3679 XMLNode &before = alist.get_state();
3681 tmp->audio_region()->set_fade_in_shape (shape);
3683 XMLNode &after = alist.get_state();
3684 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3687 commit_reversible_command ();
3691 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3693 begin_reversible_command (_("set fade out shape"));
3695 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3696 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3702 AutomationList& alist = tmp->audio_region()->fade_out();
3703 XMLNode &before = alist.get_state();
3705 tmp->audio_region()->set_fade_out_shape (shape);
3707 XMLNode &after = alist.get_state();
3708 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3711 commit_reversible_command ();
3715 Editor::set_fade_in_active (bool yn)
3717 begin_reversible_command (_("set fade in active"));
3719 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3720 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3727 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3729 XMLNode &before = ar->get_state();
3731 ar->set_fade_in_active (yn);
3733 XMLNode &after = ar->get_state();
3734 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3739 Editor::set_fade_out_active (bool yn)
3741 begin_reversible_command (_("set fade out active"));
3743 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3744 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3750 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3752 XMLNode &before = ar->get_state();
3754 ar->set_fade_out_active (yn);
3756 XMLNode &after = ar->get_state();
3757 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3762 /** Update crossfade visibility after its configuration has been changed */
3764 Editor::update_xfade_visibility ()
3766 _xfade_visibility = Config->get_xfades_visible ();
3768 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3769 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3771 if (_xfade_visibility) {
3772 v->show_all_xfades ();
3774 v->hide_all_xfades ();