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)
1048 if (playhead_to_edit) {
1050 if (selection->markers.empty()) {
1054 session->request_locate (selection->markers.front()->position(), session->transport_rolling());
1058 /* move selected markers to playhead */
1060 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1063 Location* loc = find_location_from_marker (*i, ignored);
1065 if (loc->is_mark()) {
1066 loc->set_start (playhead_cursor->current_frame);
1068 loc->set (playhead_cursor->current_frame,
1069 playhead_cursor->current_frame + loc->length());
1076 Editor::edit_cursor_backward ()
1083 if (get_prefix (prefix, was_floating)) {
1087 cnt = (nframes_t) floor (prefix * session->frame_rate ());
1089 cnt = (nframes_t) prefix;
1093 if ((pos = get_preferred_edit_position()) < 0) {
1103 // EDIT CURSOR edit_cursor->set_position (pos);
1107 Editor::edit_cursor_forward ()
1114 if (get_prefix (prefix, was_floating)) {
1118 cnt = (nframes_t) floor (prefix * session->frame_rate ());
1120 cnt = (nframes_t) floor (prefix);
1124 // pos = edit_cursor->current_frame;
1125 // EDIT CURSOR edit_cursor->set_position (pos+cnt);
1129 Editor::goto_frame ()
1135 if (get_prefix (prefix, was_floating)) {
1140 frame = (nframes_t) floor (prefix * session->frame_rate());
1142 frame = (nframes_t) floor (prefix);
1145 session->request_locate (frame);
1149 Editor::scroll_backward (float pages)
1152 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1157 if (get_prefix (prefix, was_floating)) {
1158 cnt = (nframes_t) floor (pages * one_page);
1161 cnt = (nframes_t) floor (prefix * session->frame_rate());
1163 cnt = (nframes_t) floor (prefix * one_page);
1167 if (leftmost_frame < cnt) {
1170 frame = leftmost_frame - cnt;
1173 reset_x_origin (frame);
1177 Editor::scroll_forward (float pages)
1180 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1185 if (get_prefix (prefix, was_floating)) {
1186 cnt = (nframes_t) floor (pages * one_page);
1189 cnt = (nframes_t) floor (prefix * session->frame_rate());
1191 cnt = (nframes_t) floor (prefix * one_page);
1195 if (max_frames - cnt < leftmost_frame) {
1196 frame = max_frames - cnt;
1198 frame = leftmost_frame + cnt;
1201 reset_x_origin (frame);
1205 Editor::scroll_tracks_down ()
1211 if (get_prefix (prefix, was_floating)) {
1214 cnt = (int) floor (prefix);
1217 double vert_value = vertical_adjustment.get_value() + (cnt *
1218 vertical_adjustment.get_page_size());
1219 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1220 vert_value = vertical_adjustment.get_upper() - canvas_height;
1222 vertical_adjustment.set_value (vert_value);
1226 Editor::scroll_tracks_up ()
1232 if (get_prefix (prefix, was_floating)) {
1235 cnt = (int) floor (prefix);
1238 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1242 Editor::scroll_tracks_down_line ()
1245 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1246 double vert_value = adj->get_value() + 20;
1248 if (vert_value>adj->get_upper() - canvas_height) {
1249 vert_value = adj->get_upper() - canvas_height;
1251 adj->set_value (vert_value);
1255 Editor::scroll_tracks_up_line ()
1257 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1258 adj->set_value (adj->get_value() - 20);
1264 Editor::temporal_zoom_step (bool coarser)
1266 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1270 nfpu = frames_per_unit;
1275 nfpu = max(1.0,(nfpu/1.61803399));
1278 temporal_zoom (nfpu);
1282 Editor::temporal_zoom (gdouble fpu)
1284 if (!session) return;
1286 nframes64_t current_page = current_page_frames();
1287 nframes64_t current_leftmost = leftmost_frame;
1288 nframes64_t current_rightmost;
1289 nframes64_t current_center;
1290 nframes64_t new_page;
1291 nframes64_t leftmost_after_zoom = 0;
1293 bool in_track_canvas;
1298 new_page = (nframes_t) floor (canvas_width * nfpu);
1300 switch (zoom_focus) {
1302 leftmost_after_zoom = current_leftmost;
1305 case ZoomFocusRight:
1306 current_rightmost = leftmost_frame + current_page;
1307 if (current_rightmost > new_page) {
1308 leftmost_after_zoom = current_rightmost - new_page;
1310 leftmost_after_zoom = 0;
1314 case ZoomFocusCenter:
1315 current_center = current_leftmost + (current_page/2);
1316 if (current_center > (new_page/2)) {
1317 leftmost_after_zoom = current_center - (new_page / 2);
1319 leftmost_after_zoom = 0;
1323 case ZoomFocusPlayhead:
1324 /* try to keep the playhead in the center */
1325 if (playhead_cursor->current_frame > new_page/2) {
1326 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1328 leftmost_after_zoom = 0;
1332 case ZoomFocusMouse:
1333 /* try to keep the mouse over the same point in the display */
1335 if (!mouse_frame (where, in_track_canvas)) {
1336 /* use playhead instead */
1337 where = playhead_cursor->current_frame;
1339 if (where > new_page/2) {
1340 leftmost_after_zoom = where - (new_page/2);
1342 leftmost_after_zoom = 0;
1347 double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where);
1350 leftmost_after_zoom = 0;
1351 } else if (l > max_frames) {
1352 leftmost_after_zoom = max_frames - new_page;
1354 leftmost_after_zoom = (nframes64_t) l;
1361 /* try to keep the edit point in the center */
1362 if (get_preferred_edit_position() > new_page/2) {
1363 leftmost_after_zoom = get_preferred_edit_position() - (new_page/2);
1365 leftmost_after_zoom = 0;
1371 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1373 // begin_reversible_command (_("zoom"));
1374 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1375 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1376 // commit_reversible_command ();
1378 // cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl;
1380 reposition_and_zoom (leftmost_after_zoom, nfpu);
1384 Editor::temporal_zoom_selection ()
1386 if (!selection) return;
1388 if (selection->time.empty()) {
1392 nframes_t start = selection->time[clicked_selection].start;
1393 nframes_t end = selection->time[clicked_selection].end;
1395 temporal_zoom_by_frame (start, end, "zoom to selection");
1399 Editor::temporal_zoom_session ()
1401 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1404 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1409 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1411 if (!session) return;
1413 if ((start == 0 && end == 0) || end < start) {
1417 nframes_t range = end - start;
1419 double new_fpu = (double)range / (double)canvas_width;
1422 // while (p2 < new_fpu) {
1427 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1428 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1429 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1431 if (new_leftmost > middle) new_leftmost = 0;
1433 // begin_reversible_command (op);
1434 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1435 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1436 // commit_reversible_command ();
1438 reposition_and_zoom (new_leftmost, new_fpu);
1442 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1444 if (!session) return;
1446 double range_before = frame - leftmost_frame;
1449 new_fpu = frames_per_unit;
1452 new_fpu *= 1.61803399;
1453 range_before *= 1.61803399;
1455 new_fpu = max(1.0,(new_fpu/1.61803399));
1456 range_before /= 1.61803399;
1459 if (new_fpu == frames_per_unit) return;
1461 nframes_t new_leftmost = frame - (nframes_t)range_before;
1463 if (new_leftmost > frame) new_leftmost = 0;
1465 // begin_reversible_command (_("zoom to frame"));
1466 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1467 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1468 // commit_reversible_command ();
1470 reposition_and_zoom (new_leftmost, new_fpu);
1474 Editor::add_location_from_selection ()
1478 if (selection->time.empty()) {
1482 if (session == 0 || clicked_trackview == 0) {
1486 nframes_t start = selection->time[clicked_selection].start;
1487 nframes_t end = selection->time[clicked_selection].end;
1489 session->locations()->next_available_name(rangename,"selection");
1490 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1492 session->begin_reversible_command (_("add marker"));
1493 XMLNode &before = session->locations()->get_state();
1494 session->locations()->add (location, true);
1495 XMLNode &after = session->locations()->get_state();
1496 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1497 session->commit_reversible_command ();
1501 Editor::add_location_from_playhead_cursor ()
1505 nframes_t where = session->audible_frame();
1507 session->locations()->next_available_name(markername,"mark");
1508 Location *location = new Location (where, where, markername, Location::IsMark);
1509 session->begin_reversible_command (_("add marker"));
1510 XMLNode &before = session->locations()->get_state();
1511 session->locations()->add (location, true);
1512 XMLNode &after = session->locations()->get_state();
1513 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1514 session->commit_reversible_command ();
1518 Editor::add_location_from_audio_region ()
1520 if (selection->regions.empty()) {
1524 RegionView* rv = *(selection->regions.begin());
1525 boost::shared_ptr<Region> region = rv->region();
1527 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1528 session->begin_reversible_command (_("add marker"));
1529 XMLNode &before = session->locations()->get_state();
1530 session->locations()->add (location, true);
1531 XMLNode &after = session->locations()->get_state();
1532 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1533 session->commit_reversible_command ();
1537 Editor::amplitude_zoom_step (bool in)
1551 #ifdef FIX_FOR_CANVAS
1552 /* XXX DO SOMETHING */
1561 Editor::delete_sample_forward ()
1566 Editor::delete_sample_backward ()
1571 Editor::delete_screen ()
1578 Editor::search_backwards ()
1584 Editor::search_forwards ()
1592 Editor::jump_forward_to_mark ()
1598 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1601 session->request_locate (location->start(), session->transport_rolling());
1603 session->request_locate (session->current_end_frame());
1608 Editor::jump_backward_to_mark ()
1614 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1617 session->request_locate (location->start(), session->transport_rolling());
1619 session->goto_start ();
1631 if (get_prefix (prefix, was_floating)) {
1632 pos = session->audible_frame ();
1635 pos = (nframes_t) floor (prefix * session->frame_rate ());
1637 pos = (nframes_t) floor (prefix);
1641 session->locations()->next_available_name(markername,"mark");
1642 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1646 Editor::clear_markers ()
1649 session->begin_reversible_command (_("clear markers"));
1650 XMLNode &before = session->locations()->get_state();
1651 session->locations()->clear_markers ();
1652 XMLNode &after = session->locations()->get_state();
1653 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1654 session->commit_reversible_command ();
1659 Editor::clear_ranges ()
1662 session->begin_reversible_command (_("clear ranges"));
1663 XMLNode &before = session->locations()->get_state();
1665 Location * looploc = session->locations()->auto_loop_location();
1666 Location * punchloc = session->locations()->auto_punch_location();
1668 session->locations()->clear_ranges ();
1670 if (looploc) session->locations()->add (looploc);
1671 if (punchloc) session->locations()->add (punchloc);
1673 XMLNode &after = session->locations()->get_state();
1674 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1675 session->commit_reversible_command ();
1680 Editor::clear_locations ()
1682 session->begin_reversible_command (_("clear locations"));
1683 XMLNode &before = session->locations()->get_state();
1684 session->locations()->clear ();
1685 XMLNode &after = session->locations()->get_state();
1686 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1687 session->commit_reversible_command ();
1688 session->locations()->clear ();
1692 Editor::unhide_markers ()
1694 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1695 Location *l = (*i).first;
1696 if (l->is_hidden() && l->is_mark()) {
1697 l->set_hidden(false, this);
1703 Editor::unhide_ranges ()
1705 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1706 Location *l = (*i).first;
1707 if (l->is_hidden() && l->is_range_marker()) {
1708 l->set_hidden(false, this);
1713 /* INSERT/REPLACE */
1716 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1722 AudioTimeAxisView *atv = 0;
1723 boost::shared_ptr<Playlist> playlist;
1725 track_canvas.window_to_world (x, y, wx, wy);
1726 wx += horizontal_adjustment.get_value();
1727 wy += vertical_adjustment.get_value();
1730 event.type = GDK_BUTTON_RELEASE;
1731 event.button.x = wx;
1732 event.button.y = wy;
1734 where = event_frame (&event, &cx, &cy);
1736 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1737 /* clearly outside canvas area */
1741 if ((tv = trackview_by_y_position (cy)) == 0) {
1745 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1749 if ((playlist = atv->playlist()) == 0) {
1755 begin_reversible_command (_("insert dragged region"));
1756 XMLNode &before = playlist->get_state();
1757 playlist->add_region (RegionFactory::create (region), where, 1.0);
1758 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1759 commit_reversible_command ();
1763 Editor::insert_region_list_selection (float times)
1765 RouteTimeAxisView *tv = 0;
1766 boost::shared_ptr<Playlist> playlist;
1768 if (clicked_audio_trackview != 0) {
1769 tv = clicked_audio_trackview;
1770 } else if (!selection->tracks.empty()) {
1771 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1778 if ((playlist = tv->playlist()) == 0) {
1782 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1784 if (selected->count_selected_rows() != 1) {
1788 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1790 /* only one row selected, so rows.begin() is it */
1794 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1796 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1798 begin_reversible_command (_("insert region"));
1799 XMLNode &before = playlist->get_state();
1800 playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
1801 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1802 commit_reversible_command ();
1806 /* BUILT-IN EFFECTS */
1809 Editor::reverse_selection ()
1814 /* GAIN ENVELOPE EDITING */
1817 Editor::edit_envelope ()
1824 Editor::transition_to_rolling (bool fwd)
1830 switch (Config->get_slave_source()) {
1835 /* transport controlled by the master */
1839 if (session->is_auditioning()) {
1840 session->cancel_audition ();
1844 session->request_transport_speed (fwd ? 1.0f : -1.0f);
1848 Editor::toggle_playback (bool with_abort)
1854 switch (Config->get_slave_source()) {
1859 /* transport controlled by the master */
1863 if (session->is_auditioning()) {
1864 session->cancel_audition ();
1868 if (session->transport_rolling()) {
1869 session->request_stop (with_abort);
1870 if (session->get_play_loop()) {
1871 session->request_play_loop (false);
1874 session->request_transport_speed (1.0f);
1879 Editor::play_from_start ()
1881 session->request_locate (session->current_start_frame(), true);
1885 Editor::play_from_edit_point ()
1887 session->request_locate (get_preferred_edit_position(), true);
1891 Editor::play_selection ()
1893 if (selection->time.empty()) {
1897 session->request_play_range (true);
1901 Editor::play_selected_region ()
1903 if (!selection->regions.empty()) {
1904 RegionView *rv = *(selection->regions.begin());
1906 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1911 Editor::loop_selected_region ()
1913 if (!selection->regions.empty()) {
1914 RegionView *rv = *(selection->regions.begin());
1917 if ((tll = transport_loop_location()) != 0) {
1919 tll->set (rv->region()->position(), rv->region()->last_frame());
1921 // enable looping, reposition and start rolling
1923 session->request_play_loop (true);
1924 session->request_locate (tll->start(), false);
1925 session->request_transport_speed (1.0f);
1931 Editor::play_location (Location& location)
1933 if (location.start() <= location.end()) {
1937 session->request_bounded_roll (location.start(), location.end());
1941 Editor::loop_location (Location& location)
1943 if (location.start() <= location.end()) {
1949 if ((tll = transport_loop_location()) != 0) {
1950 tll->set (location.start(), location.end());
1952 // enable looping, reposition and start rolling
1953 session->request_play_loop (true);
1954 session->request_locate (tll->start(), true);
1959 Editor::raise_region ()
1961 selection->foreach_region (&Region::raise);
1965 Editor::raise_region_to_top ()
1967 selection->foreach_region (&Region::raise_to_top);
1971 Editor::lower_region ()
1973 selection->foreach_region (&Region::lower);
1977 Editor::lower_region_to_bottom ()
1979 selection->foreach_region (&Region::lower_to_bottom);
1983 Editor::edit_region ()
1985 if (clicked_regionview == 0) {
1989 clicked_regionview->show_region_editor ();
1993 Editor::rename_region ()
1997 Button ok_button (_("OK"));
1998 Button cancel_button (_("Cancel"));
2000 if (selection->regions.empty()) {
2004 WindowTitle title(Glib::get_application_name());
2005 title += _("Rename Region");
2007 dialog.set_title (title.get_string());
2008 dialog.set_name ("RegionRenameWindow");
2009 dialog.set_size_request (300, -1);
2010 dialog.set_position (Gtk::WIN_POS_MOUSE);
2011 dialog.set_modal (true);
2013 dialog.get_vbox()->set_border_width (10);
2014 dialog.get_vbox()->pack_start (entry);
2015 dialog.get_action_area()->pack_start (ok_button);
2016 dialog.get_action_area()->pack_start (cancel_button);
2018 entry.set_name ("RegionNameDisplay");
2019 ok_button.set_name ("EditorGTKButton");
2020 cancel_button.set_name ("EditorGTKButton");
2022 region_renamed = false;
2024 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2025 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2026 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2033 if (region_renamed) {
2034 (*selection->regions.begin())->region()->set_name (entry.get_text());
2035 redisplay_regions ();
2040 Editor::rename_region_finished (bool status)
2043 region_renamed = status;
2048 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2050 if (session->is_auditioning()) {
2051 session->cancel_audition ();
2054 // note: some potential for creativity here, because region doesn't
2055 // have to belong to the playlist that Route is handling
2057 // bool was_soloed = route.soloed();
2059 route.set_solo (true, this);
2061 session->request_bounded_roll (region->position(), region->position() + region->length());
2063 /* XXX how to unset the solo state ? */
2067 Editor::audition_selected_region ()
2069 if (!selection->regions.empty()) {
2070 RegionView* rv = *(selection->regions.begin());
2071 session->audition_region (rv->region());
2076 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2078 session->audition_region (region);
2082 Editor::build_interthread_progress_window ()
2084 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2086 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2088 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2089 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2091 // GTK2FIX: this button needs a modifiable label
2093 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2094 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2096 interthread_cancel_button.add (interthread_cancel_label);
2098 interthread_progress_window->set_default_size (200, 100);
2102 Editor::interthread_cancel_clicked ()
2104 if (current_interthread_info) {
2105 current_interthread_info->cancel = true;
2110 Editor::region_from_selection ()
2112 if (clicked_trackview == 0) {
2116 if (selection->time.empty()) {
2120 nframes_t start = selection->time[clicked_selection].start;
2121 nframes_t end = selection->time[clicked_selection].end;
2123 nframes_t selection_cnt = end - start + 1;
2125 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2126 boost::shared_ptr<AudioRegion> current;
2127 boost::shared_ptr<Region> current_r;
2128 boost::shared_ptr<Playlist> pl;
2130 nframes_t internal_start;
2133 if ((pl = (*i)->playlist()) == 0) {
2137 if ((current_r = pl->top_region_at (start)) == 0) {
2141 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2142 // FIXME: audio only
2144 internal_start = start - current->position();
2145 session->region_name (new_name, current->name(), true);
2146 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2152 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2154 if (selection->time.empty() || selection->tracks.empty()) {
2158 nframes_t start = selection->time[clicked_selection].start;
2159 nframes_t end = selection->time[clicked_selection].end;
2161 sort_track_selection ();
2163 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2165 boost::shared_ptr<AudioRegion> current;
2166 boost::shared_ptr<Region> current_r;
2167 boost::shared_ptr<Playlist> playlist;
2168 nframes_t internal_start;
2171 if ((playlist = (*i)->playlist()) == 0) {
2175 if ((current_r = playlist->top_region_at(start)) == 0) {
2179 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2183 internal_start = start - current->position();
2184 session->region_name (new_name, current->name(), true);
2186 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2191 Editor::split_multichannel_region ()
2193 if (selection->regions.empty()) {
2197 vector<boost::shared_ptr<AudioRegion> > v;
2199 for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2201 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
2203 if (!arv || arv->audio_region()->n_channels() < 2) {
2207 (arv)->audio_region()->separate_by_channel (*session, v);
2212 Editor::new_region_from_selection ()
2214 region_from_selection ();
2215 cancel_selection ();
2219 Editor::separate_region_from_selection ()
2221 bool doing_undo = false;
2223 if (selection->time.empty()) {
2227 boost::shared_ptr<Playlist> playlist;
2229 sort_track_selection ();
2231 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2233 AudioTimeAxisView* atv;
2235 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2237 if (atv->is_audio_track()) {
2239 /* no edits to destructive tracks */
2241 if (atv->audio_track()->audio_diskstream()->destructive()) {
2245 if ((playlist = atv->playlist()) != 0) {
2247 begin_reversible_command (_("separate"));
2252 before = &(playlist->get_state());
2254 /* XXX need to consider musical time selections here at some point */
2256 double speed = atv->get_diskstream()->speed();
2258 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2259 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2263 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2269 if (doing_undo) commit_reversible_command ();
2273 Editor::separate_regions_using_location (Location& loc)
2275 bool doing_undo = false;
2277 if (loc.is_mark()) {
2281 boost::shared_ptr<Playlist> playlist;
2283 /* XXX i'm unsure as to whether this should operate on selected tracks only
2284 or the entire enchillada. uncomment the below line to correct the behaviour
2285 (currently set for all tracks)
2288 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2289 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2291 AudioTimeAxisView* atv;
2293 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2295 if (atv->is_audio_track()) {
2297 /* no edits to destructive tracks */
2299 if (atv->audio_track()->audio_diskstream()->destructive()) {
2303 if ((playlist = atv->playlist()) != 0) {
2306 begin_reversible_command (_("separate"));
2310 before = &(playlist->get_state());
2313 /* XXX need to consider musical time selections here at some point */
2315 double speed = atv->get_diskstream()->speed();
2318 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2320 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2326 if (doing_undo) commit_reversible_command ();
2330 Editor::crop_region_to_selection ()
2332 if (!selection->time.empty()) {
2334 crop_region_to (selection->time.start(), selection->time.end_frame());
2336 } else if (_edit_point != EditAtPlayhead) {
2341 if (get_edit_op_range (start, end)) {
2342 crop_region_to (start, end);
2349 Editor::crop_region_to (nframes_t start, nframes_t end)
2351 vector<boost::shared_ptr<Playlist> > playlists;
2352 boost::shared_ptr<Playlist> playlist;
2355 if (selection->tracks.empty()) {
2358 sort_track_selection ();
2359 ts = &selection->tracks;
2362 for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
2364 AudioTimeAxisView* atv;
2366 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2368 if (atv->is_audio_track()) {
2370 /* no edits to destructive tracks */
2372 if (atv->audio_track()->audio_diskstream()->destructive()) {
2376 if ((playlist = atv->playlist()) != 0) {
2377 playlists.push_back (playlist);
2383 if (playlists.empty()) {
2387 nframes_t the_start;
2391 begin_reversible_command (_("trim to selection"));
2393 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2395 boost::shared_ptr<Region> region;
2399 if ((region = (*i)->top_region_at(the_start)) == 0) {
2403 /* now adjust lengths to that we do the right thing
2404 if the selection extends beyond the region
2407 the_start = max (the_start, region->position());
2408 if (max_frames - the_start < region->length()) {
2409 the_end = the_start + region->length() - 1;
2411 the_end = max_frames;
2413 the_end = min (end, the_end);
2414 cnt = the_end - the_start + 1;
2416 XMLNode &before = (*i)->get_state();
2417 region->trim_to (the_start, cnt, this);
2418 XMLNode &after = (*i)->get_state();
2419 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2422 commit_reversible_command ();
2426 Editor::region_fill_track ()
2430 if (!session || selection->regions.empty()) {
2434 end = session->current_end_frame ();
2436 begin_reversible_command (_("region fill"));
2438 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2440 boost::shared_ptr<Region> region ((*i)->region());
2443 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2447 boost::shared_ptr<Playlist> pl = region->playlist();
2449 if (end <= region->last_frame()) {
2453 double times = (double) (end - region->last_frame()) / (double) region->length();
2459 XMLNode &before = pl->get_state();
2460 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2461 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2464 commit_reversible_command ();
2468 Editor::region_fill_selection ()
2470 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2474 if (selection->time.empty()) {
2479 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2481 if (selected->count_selected_rows() != 1) {
2485 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2486 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2488 nframes_t start = selection->time[clicked_selection].start;
2489 nframes_t end = selection->time[clicked_selection].end;
2491 boost::shared_ptr<Playlist> playlist;
2493 if (selection->tracks.empty()) {
2497 nframes_t selection_length = end - start;
2498 float times = (float)selection_length / region->length();
2500 begin_reversible_command (_("fill selection"));
2502 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2504 if ((playlist = (*i)->playlist()) == 0) {
2508 XMLNode &before = playlist->get_state();
2509 playlist->add_region (RegionFactory::create (region), start, times);
2510 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2513 commit_reversible_command ();
2517 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2520 if (!region->covers (position)) {
2521 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2524 begin_reversible_command (_("set region sync position"));
2525 XMLNode &before = region->playlist()->get_state();
2526 region->set_sync_position (position);
2527 XMLNode &after = region->playlist()->get_state();
2528 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2529 commit_reversible_command ();
2533 Editor::set_region_sync_from_edit_point ()
2535 if (clicked_regionview == 0) {
2539 if (!clicked_regionview->region()->covers (get_preferred_edit_position())) {
2540 error << _("Place the edit point at the desired sync point") << endmsg;
2544 boost::shared_ptr<Region> region (clicked_regionview->region());
2545 begin_reversible_command (_("set sync from edit point"));
2546 XMLNode &before = region->playlist()->get_state();
2547 region->set_sync_position (get_preferred_edit_position());
2548 XMLNode &after = region->playlist()->get_state();
2549 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2550 commit_reversible_command ();
2554 Editor::remove_region_sync ()
2556 if (clicked_regionview) {
2557 boost::shared_ptr<Region> region (clicked_regionview->region());
2558 begin_reversible_command (_("remove sync"));
2559 XMLNode &before = region->playlist()->get_state();
2560 region->clear_sync_position ();
2561 XMLNode &after = region->playlist()->get_state();
2562 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2563 commit_reversible_command ();
2568 Editor::naturalize ()
2570 if (selection->regions.empty()) {
2573 begin_reversible_command (_("naturalize"));
2574 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2575 XMLNode &before = (*i)->region()->get_state();
2576 (*i)->region()->move_to_natural_position (this);
2577 XMLNode &after = (*i)->region()->get_state();
2578 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2580 commit_reversible_command ();
2584 Editor::align (RegionPoint what)
2586 nframes64_t where = get_preferred_edit_position();
2588 if (!selection->regions.empty()) {
2589 align_selection (what, where, selection->regions);
2593 rs = get_regions_at (where, selection->tracks);
2594 align_selection (what, where, rs);
2599 Editor::align_relative (RegionPoint what)
2601 nframes64_t where = get_preferred_edit_position();
2603 if (!selection->regions.empty()) {
2604 align_selection_relative (what, where, selection->regions);
2608 rs = get_regions_at (where, selection->tracks);
2609 align_selection_relative (what, where, rs);
2613 struct RegionSortByTime {
2614 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2615 return a->region()->position() < b->region()->position();
2620 Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
2630 list<RegionView*> sorted;
2631 rs.by_position (sorted);
2632 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2636 pos = r->first_frame ();
2640 pos = r->last_frame();
2644 pos = r->adjust_to_sync (r->first_frame());
2648 if (pos > position) {
2649 distance = pos - position;
2652 distance = position - pos;
2656 begin_reversible_command (_("align selection (relative)"));
2658 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2660 boost::shared_ptr<Region> region ((*i)->region());
2662 XMLNode &before = region->playlist()->get_state();
2665 region->set_position (region->position() + distance, this);
2667 region->set_position (region->position() - distance, this);
2670 XMLNode &after = region->playlist()->get_state();
2671 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2675 commit_reversible_command ();
2679 Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
2685 begin_reversible_command (_("align selection"));
2687 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2688 align_region_internal ((*i)->region(), point, position);
2691 commit_reversible_command ();
2695 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2697 begin_reversible_command (_("align region"));
2698 align_region_internal (region, point, position);
2699 commit_reversible_command ();
2703 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2705 XMLNode &before = region->playlist()->get_state();
2709 region->set_position (region->adjust_to_sync (position), this);
2713 if (position > region->length()) {
2714 region->set_position (position - region->length(), this);
2719 region->set_position (position, this);
2723 XMLNode &after = region->playlist()->get_state();
2724 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2728 Editor::trim_region_to_loop ()
2730 Location* loc = session->locations()->auto_loop_location();
2734 trim_region_to_location (*loc, _("trim to loop"));
2738 Editor::trim_region_to_punch ()
2740 Location* loc = session->locations()->auto_punch_location();
2744 trim_region_to_location (*loc, _("trim to punch"));
2748 Editor::trim_region_to_location (const Location& loc, const char* str)
2750 RegionSelection& rs (get_regions_for_action ());
2752 begin_reversible_command (str);
2754 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2755 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2761 /* require region to span proposed trim */
2763 switch (arv->region()->coverage (loc.start(), loc.end())) {
2764 case OverlapInternal:
2770 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2780 if (atav->get_diskstream() != 0) {
2781 speed = atav->get_diskstream()->speed();
2784 start = session_frame_to_track_frame (loc.start(), speed);
2785 end = session_frame_to_track_frame (loc.end(), speed);
2787 XMLNode &before = arv->region()->playlist()->get_state();
2788 arv->region()->trim_to (start, (end - start), this);
2789 XMLNode &after = arv->region()->playlist()->get_state();
2790 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2793 commit_reversible_command ();
2797 Editor::trim_region_to_edit_point ()
2799 RegionSelection& rs (get_regions_for_action ());
2800 nframes64_t where = get_preferred_edit_position();
2802 begin_reversible_command (_("trim region start to edit point"));
2804 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2805 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2811 /* require region to cover trim */
2813 if (!arv->region()->covers (where)) {
2817 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2825 if (atav->get_diskstream() != 0) {
2826 speed = atav->get_diskstream()->speed();
2829 XMLNode &before = arv->region()->playlist()->get_state();
2830 arv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
2831 XMLNode &after = arv->region()->playlist()->get_state();
2832 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2835 commit_reversible_command ();
2839 Editor::trim_region_from_edit_point ()
2841 RegionSelection& rs (get_regions_for_action ());
2842 nframes64_t where = get_preferred_edit_position();
2844 begin_reversible_command (_("trim region end to edit point"));
2846 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2847 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2853 /* require region to cover trim */
2855 if (!arv->region()->covers (where)) {
2859 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2867 if (atav->get_diskstream() != 0) {
2868 speed = atav->get_diskstream()->speed();
2871 XMLNode &before = arv->region()->playlist()->get_state();
2872 arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
2873 XMLNode &after = arv->region()->playlist()->get_state();
2874 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2877 commit_reversible_command ();
2881 Editor::unfreeze_route ()
2883 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2887 clicked_audio_trackview->audio_track()->unfreeze ();
2891 Editor::_freeze_thread (void* arg)
2893 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2894 return static_cast<Editor*>(arg)->freeze_thread ();
2898 Editor::freeze_thread ()
2900 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2905 Editor::freeze_progress_timeout (void *arg)
2907 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2908 return !(current_interthread_info->done || current_interthread_info->cancel);
2912 Editor::freeze_route ()
2914 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2918 InterThreadInfo itt;
2920 if (interthread_progress_window == 0) {
2921 build_interthread_progress_window ();
2924 WindowTitle title(Glib::get_application_name());
2925 title += _("Freeze");
2926 interthread_progress_window->set_title (title.get_string());
2927 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2928 interthread_progress_window->show_all ();
2929 interthread_progress_bar.set_fraction (0.0f);
2930 interthread_progress_label.set_text ("");
2931 interthread_cancel_label.set_text (_("Cancel Freeze"));
2932 current_interthread_info = &itt;
2934 interthread_progress_connection =
2935 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2939 itt.progress = 0.0f;
2941 pthread_attr_t attr;
2942 pthread_attr_init(&attr);
2943 pthread_attr_setstacksize(&attr, 500000);
2945 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2947 pthread_attr_destroy(&attr);
2949 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2951 while (!itt.done && !itt.cancel) {
2952 gtk_main_iteration ();
2955 interthread_progress_connection.disconnect ();
2956 interthread_progress_window->hide_all ();
2957 current_interthread_info = 0;
2958 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2962 Editor::bounce_range_selection ()
2964 if (selection->time.empty()) {
2968 TrackSelection views = selection->tracks;
2970 nframes_t start = selection->time[clicked_selection].start;
2971 nframes_t end = selection->time[clicked_selection].end;
2972 nframes_t cnt = end - start + 1;
2974 begin_reversible_command (_("bounce range"));
2976 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2978 AudioTimeAxisView* atv;
2980 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2984 boost::shared_ptr<Playlist> playlist;
2986 if ((playlist = atv->playlist()) == 0) {
2990 InterThreadInfo itt;
2994 itt.progress = false;
2996 XMLNode &before = playlist->get_state();
2997 atv->audio_track()->bounce_range (start, cnt, itt);
2998 XMLNode &after = playlist->get_state();
2999 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
3002 commit_reversible_command ();
3018 Editor::cut_copy (CutCopyOp op)
3020 /* only cancel selection if cut/copy is successful.*/
3032 opname = _("clear");
3036 cut_buffer->clear ();
3038 if (entered_marker) {
3040 /* cut/delete op while pointing at a marker */
3043 Location* loc = find_location_from_marker (entered_marker, ignored);
3045 if (session && loc) {
3046 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
3052 switch (current_mouse_mode()) {
3054 if (!selection->regions.empty() || !selection->points.empty()) {
3056 begin_reversible_command (opname + _(" objects"));
3058 if (!selection->regions.empty()) {
3060 cut_copy_regions (op);
3063 selection->clear_regions ();
3067 if (!selection->points.empty()) {
3068 cut_copy_points (op);
3071 selection->clear_points ();
3075 commit_reversible_command ();
3076 break; // terminate case statement here
3078 if (!selection->time.empty()) {
3079 /* don't cause suprises */
3082 // fall thru if there was nothing selected
3085 if (selection->time.empty()) {
3086 nframes64_t start, end;
3087 if (!get_edit_op_range (start, end)) {
3090 selection->set (0, start, end);
3093 begin_reversible_command (opname + _(" range"));
3094 cut_copy_ranges (op);
3095 commit_reversible_command ();
3098 selection->clear_time ();
3109 Editor::cut_copy_points (CutCopyOp op)
3111 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3113 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3116 atv->cut_copy_clear_objects (selection->points, op);
3121 struct PlaylistState {
3122 boost::shared_ptr<Playlist> playlist;
3126 struct lt_playlist {
3127 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3128 return a.playlist < b.playlist;
3132 struct PlaylistMapping {
3134 boost::shared_ptr<AudioPlaylist> pl;
3136 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3140 Editor::cut_copy_regions (CutCopyOp op)
3142 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3143 a map when we want ordered access to both elements. i think.
3146 vector<PlaylistMapping> pmap;
3148 nframes_t first_position = max_frames;
3150 set<PlaylistState, lt_playlist> freezelist;
3151 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
3153 /* get ordering correct before we cut/copy */
3155 selection->regions.sort_by_position_and_track ();
3157 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3159 first_position = min ((*x)->region()->position(), first_position);
3161 if (op == Cut || op == Clear) {
3162 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3166 PlaylistState before;
3167 before.playlist = pl;
3168 before.before = &pl->get_state();
3170 insert_result = freezelist.insert (before);
3172 if (insert_result.second) {
3178 TimeAxisView* tv = &(*x)->get_trackview();
3179 vector<PlaylistMapping>::iterator z;
3181 for (z = pmap.begin(); z != pmap.end(); ++z) {
3182 if ((*z).tv == tv) {
3187 if (z == pmap.end()) {
3188 pmap.push_back (PlaylistMapping (tv));
3192 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3194 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3197 /* impossible, but this handles it for the future */
3201 TimeAxisView& tv = (*x)->get_trackview();
3202 boost::shared_ptr<AudioPlaylist> npl;
3203 RegionSelection::iterator tmp;
3208 vector<PlaylistMapping>::iterator z;
3210 for (z = pmap.begin(); z != pmap.end(); ++z) {
3211 if ((*z).tv == &tv) {
3216 assert (z != pmap.end());
3219 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3226 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3227 boost::shared_ptr<Region> _xx;
3233 _xx = RegionFactory::create ((*x)->region());
3234 npl->add_region (_xx, (*x)->region()->position() - first_position);
3235 pl->remove_region (((*x)->region()));
3241 /* copy region before adding, so we're not putting same object into two different playlists */
3242 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
3246 pl->remove_region (((*x)->region()));
3253 list<boost::shared_ptr<Playlist> > foo;
3255 /* the pmap is in the same order as the tracks in which selected regions occured */
3257 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3259 foo.push_back ((*i).pl);
3264 cut_buffer->set (foo);
3267 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3268 (*pl).playlist->thaw ();
3269 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3274 Editor::cut_copy_ranges (CutCopyOp op)
3278 if (selection->tracks.empty()) {
3281 ts = &selection->tracks;
3284 for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3285 (*i)->cut_copy_clear (*selection, op);
3290 Editor::paste (float times)
3292 paste_internal (get_preferred_edit_position(), times);
3296 Editor::mouse_paste ()
3301 if (!mouse_frame (where, ignored)) {
3306 paste_internal (where, 1);
3310 Editor::paste_internal (nframes_t position, float times)
3312 bool commit = false;
3314 if (cut_buffer->empty() || selection->tracks.empty()) {
3318 if (position == max_frames) {
3319 position = get_preferred_edit_position();
3322 begin_reversible_command (_("paste"));
3324 TrackSelection::iterator i;
3327 /* get everything in the correct order */
3329 sort_track_selection ();
3331 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3333 /* undo/redo is handled by individual tracks */
3335 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3341 commit_reversible_command ();
3346 Editor::paste_named_selection (float times)
3348 TrackSelection::iterator t;
3350 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3352 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3356 TreeModel::iterator i = selected->get_selected();
3357 NamedSelection* ns = (*i)[named_selection_columns.selection];
3359 list<boost::shared_ptr<Playlist> >::iterator chunk;
3360 list<boost::shared_ptr<Playlist> >::iterator tmp;
3362 chunk = ns->playlists.begin();
3364 begin_reversible_command (_("paste chunk"));
3366 sort_track_selection ();
3368 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3370 AudioTimeAxisView* atv;
3371 boost::shared_ptr<Playlist> pl;
3372 boost::shared_ptr<AudioPlaylist> apl;
3374 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3378 if ((pl = atv->playlist()) == 0) {
3382 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3389 XMLNode &before = apl->get_state();
3390 apl->paste (*chunk, get_preferred_edit_position(), times);
3391 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3393 if (tmp != ns->playlists.end()) {
3398 commit_reversible_command();
3402 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3404 boost::shared_ptr<Playlist> playlist;
3405 RegionSelection sel = regions; // clear (below) will clear the argument list
3407 begin_reversible_command (_("duplicate region"));
3409 selection->clear_regions ();
3411 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3413 boost::shared_ptr<Region> r ((*i)->region());
3415 TimeAxisView& tv = (*i)->get_time_axis_view();
3416 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3417 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3419 playlist = (*i)->region()->playlist();
3420 XMLNode &before = playlist->get_state();
3421 playlist->duplicate (r, r->last_frame() + 1, times);
3422 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3426 if (latest_regionview) {
3427 selection->add (latest_regionview);
3432 commit_reversible_command ();
3436 Editor::duplicate_selection (float times)
3438 if (selection->time.empty() || selection->tracks.empty()) {
3442 boost::shared_ptr<Playlist> playlist;
3443 vector<boost::shared_ptr<AudioRegion> > new_regions;
3444 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3446 create_region_from_selection (new_regions);
3448 if (new_regions.empty()) {
3452 begin_reversible_command (_("duplicate selection"));
3454 ri = new_regions.begin();
3456 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3457 if ((playlist = (*i)->playlist()) == 0) {
3460 XMLNode &before = playlist->get_state();
3461 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3462 XMLNode &after = playlist->get_state();
3463 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3466 if (ri == new_regions.end()) {
3471 commit_reversible_command ();
3475 Editor::reset_point_selection ()
3477 /* reset all selected points to the relevant default value */
3479 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3481 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3484 atv->reset_objects (selection->points);
3490 Editor::center_playhead ()
3492 float page = canvas_width * frames_per_unit;
3493 center_screen_internal (playhead_cursor->current_frame, page);
3497 Editor::center_edit_point ()
3499 float page = canvas_width * frames_per_unit;
3500 center_screen_internal (get_preferred_edit_position(), page);
3504 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3506 begin_reversible_command (_("clear playlist"));
3507 XMLNode &before = playlist->get_state();
3509 XMLNode &after = playlist->get_state();
3510 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3511 commit_reversible_command ();
3515 Editor::nudge_track (bool use_edit, bool forwards)
3517 boost::shared_ptr<Playlist> playlist;
3519 nframes_t next_distance;
3523 start = get_preferred_edit_position();
3528 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3532 if (selection->tracks.empty()) {
3536 begin_reversible_command (_("nudge track"));
3538 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3540 if ((playlist = (*i)->playlist()) == 0) {
3544 XMLNode &before = playlist->get_state();
3545 playlist->nudge_after (start, distance, forwards);
3546 XMLNode &after = playlist->get_state();
3547 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3550 commit_reversible_command ();
3554 Editor::remove_last_capture ()
3556 vector<string> choices;
3563 if (Config->get_verify_remove_last_capture()) {
3564 prompt = _("Do you really want to destroy the last capture?"
3565 "\n(This is destructive and cannot be undone)");
3567 choices.push_back (_("No, do nothing."));
3568 choices.push_back (_("Yes, destroy it."));
3570 Gtkmm2ext::Choice prompter (prompt, choices);
3572 if (prompter.run () == 1) {
3573 session->remove_last_capture ();
3577 session->remove_last_capture();
3582 Editor::normalize_region ()
3588 if (selection->regions.empty()) {
3592 begin_reversible_command (_("normalize"));
3594 track_canvas.get_window()->set_cursor (*wait_cursor);
3597 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3598 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3601 XMLNode &before = arv->region()->get_state();
3602 arv->audio_region()->normalize_to (0.0f);
3603 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3606 commit_reversible_command ();
3607 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3612 Editor::denormalize_region ()
3618 if (selection->regions.empty()) {
3622 begin_reversible_command ("denormalize");
3624 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3625 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3628 XMLNode &before = arv->region()->get_state();
3629 arv->audio_region()->set_scale_amplitude (1.0f);
3630 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3633 commit_reversible_command ();
3638 Editor::reverse_region ()
3644 Reverse rev (*session);
3645 apply_filter (rev, _("reverse regions"));
3649 Editor::apply_filter (AudioFilter& filter, string command)
3651 if (selection->regions.empty()) {
3655 begin_reversible_command (command);
3657 track_canvas.get_window()->set_cursor (*wait_cursor);
3660 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3661 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3665 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3667 RegionSelection::iterator tmp;
3672 if (arv->audio_region()->apply (filter) == 0) {
3674 XMLNode &before = playlist->get_state();
3675 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3676 XMLNode &after = playlist->get_state();
3677 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3685 commit_reversible_command ();
3686 selection->regions.clear ();
3689 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3693 Editor::region_selection_op (void (Region::*pmf)(void))
3695 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3696 Region* region = (*i)->region().get();
3703 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3705 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3706 Region* region = (*i)->region().get();
3707 (region->*pmf)(arg);
3712 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3714 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3715 Region* region = (*i)->region().get();
3721 Editor::external_edit_region ()
3723 if (!clicked_regionview) {
3731 Editor::brush (nframes_t pos)
3733 RegionSelection sel;
3736 if (selection->regions.empty()) {
3737 /* XXX get selection from region list */
3739 sel = selection->regions;
3746 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3747 mouse_brush_insert_region ((*i), pos);
3752 Editor::reset_region_gain_envelopes ()
3754 if (!session || selection->regions.empty()) {
3758 session->begin_reversible_command (_("reset region gain"));
3760 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3761 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3763 AutomationList& alist (arv->audio_region()->envelope());
3764 XMLNode& before (alist.get_state());
3766 arv->audio_region()->set_default_envelope ();
3767 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3771 session->commit_reversible_command ();
3775 Editor::toggle_gain_envelope_visibility ()
3777 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3778 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3780 bool x = region_envelope_visible_item->get_active();
3781 if (x != arv->envelope_visible()) {
3782 arv->set_envelope_visible (x);
3789 Editor::toggle_gain_envelope_active ()
3791 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3792 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3794 bool x = region_envelope_active_item->get_active();
3795 if (x != arv->audio_region()->envelope_active()) {
3796 arv->audio_region()->set_envelope_active (x);
3803 Editor::toggle_region_lock ()
3805 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3806 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3808 bool x = region_lock_item->get_active();
3809 if (x != arv->audio_region()->locked()) {
3810 arv->audio_region()->set_locked (x);
3817 Editor::toggle_region_mute ()
3819 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3820 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3822 bool x = region_mute_item->get_active();
3823 if (x != arv->audio_region()->muted()) {
3824 arv->audio_region()->set_muted (x);
3831 Editor::toggle_region_opaque ()
3833 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3834 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3836 bool x = region_opaque_item->get_active();
3837 if (x != arv->audio_region()->opaque()) {
3838 arv->audio_region()->set_opaque (x);
3845 Editor::set_fade_length (bool in)
3847 /* we need a region to measure the offset from the start */
3851 if (entered_regionview) {
3852 rv = entered_regionview;
3853 } else if (!selection->regions.empty()) {
3854 rv = selection->regions.front();
3859 nframes64_t pos = get_preferred_edit_position();
3864 if (pos <= rv->region()->start()) {
3868 len = pos - rv->region()->start();
3869 cmd = _("set fade in length");
3871 if (pos >= rv->region()->last_frame()) {
3875 len = rv->region()->last_frame() - pos;
3876 cmd = _("set fade out length");
3879 begin_reversible_command (cmd);
3881 cerr << "start " << cmd << " with len = " << len << endl;
3883 RegionSelection& rs (get_regions_for_action());
3885 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3886 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3892 AutomationList& alist = tmp->audio_region()->fade_in();
3893 XMLNode &before = alist.get_state();
3896 tmp->audio_region()->set_fade_in_length (len);
3898 tmp->audio_region()->set_fade_out_length (len);
3901 XMLNode &after = alist.get_state();
3902 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3905 commit_reversible_command ();
3909 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3911 begin_reversible_command (_("set fade in shape"));
3913 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3914 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3920 AutomationList& alist = tmp->audio_region()->fade_in();
3921 XMLNode &before = alist.get_state();
3923 tmp->audio_region()->set_fade_in_shape (shape);
3925 XMLNode &after = alist.get_state();
3926 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3929 commit_reversible_command ();
3933 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3935 begin_reversible_command (_("set fade out shape"));
3937 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3938 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3944 AutomationList& alist = tmp->audio_region()->fade_out();
3945 XMLNode &before = alist.get_state();
3947 tmp->audio_region()->set_fade_out_shape (shape);
3949 XMLNode &after = alist.get_state();
3950 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3953 commit_reversible_command ();
3957 Editor::set_fade_in_active (bool yn)
3959 begin_reversible_command (_("set fade in active"));
3961 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3962 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3969 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3971 XMLNode &before = ar->get_state();
3973 ar->set_fade_in_active (yn);
3975 XMLNode &after = ar->get_state();
3976 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3981 Editor::set_fade_out_active (bool yn)
3983 begin_reversible_command (_("set fade out active"));
3985 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3986 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3992 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3994 XMLNode &before = ar->get_state();
3996 ar->set_fade_out_active (yn);
3998 XMLNode &after = ar->get_state();
3999 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4004 /** Update crossfade visibility after its configuration has been changed */
4006 Editor::update_xfade_visibility ()
4008 _xfade_visibility = Config->get_xfades_visible ();
4010 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4011 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4013 if (_xfade_visibility) {
4014 v->show_all_xfades ();
4016 v->hide_all_xfades ();
4023 Editor::set_edit_point ()
4028 if (!mouse_frame (where, ignored)) {
4034 if (selection->markers.empty()) {
4036 mouse_add_new_marker (where);
4041 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
4044 loc->move_to (where);
4050 Editor::set_playhead_cursor ()
4052 if (entered_marker) {
4053 session->request_locate (entered_marker->position(), session->transport_rolling());
4058 if (!mouse_frame (where, ignored)) {
4065 session->request_locate (where, session->transport_rolling());
4073 nframes64_t where = get_preferred_edit_position();
4075 if (!selection->regions.empty()) {
4077 split_regions_at (where, selection->regions);
4082 rs = get_regions_at (where, selection->tracks);
4083 split_regions_at (where, rs);