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 || 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 || 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 || 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_regions_between (const TimeSelection& ts)
2221 bool doing_undo = false;
2222 boost::shared_ptr<Playlist> playlist;
2223 RegionSelection new_selection;
2225 sort_track_selection ();
2227 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2229 AudioTimeAxisView* atv;
2231 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2233 if (atv->is_audio_track()) {
2235 /* no edits to destructive tracks */
2237 if (atv->audio_track()->audio_diskstream()->destructive()) {
2241 if ((playlist = atv->playlist()) != 0) {
2244 begin_reversible_command (_("separate"));
2251 before = &(playlist->get_state());
2254 /* XXX need to consider musical time selections here at some point */
2256 double speed = atv->get_diskstream()->speed();
2258 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2259 latest_regionviews.clear ();
2261 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2262 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2267 if (!latest_regionviews.empty()) {
2269 /* here is a trick: partitioning will generally create 1 or 2 new regions.
2270 if the region spanned the selection, the first new one will be the middle
2271 of the original. if the region overlapped one end of the selection,
2272 the first (and only) new one will be the area corresponding to the
2275 we want to select this region and return to mouse object mode ...
2278 new_selection.push_back (latest_regionviews.front());
2281 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2284 cerr << " no new rv's for " << playlist->name() << endl;
2291 selection->set (new_selection);
2292 set_mouse_mode (MouseObject);
2295 commit_reversible_command ();
2300 Editor::separate_region_from_selection ()
2302 /* preferentially use *all* ranges in the time selection if we're in range mode
2303 to allow discontiguous operation, since get_edit_op_range() currently
2304 returns a single range.
2306 if (mouse_mode == MouseRange && !selection->time.empty()) {
2308 separate_regions_between (selection->time);
2315 if (get_edit_op_range (start, end)) {
2317 AudioRange ar (start, end, 1);
2321 /* force track selection */
2323 ensure_entered_selected ();
2325 separate_regions_between (ts);
2331 Editor::separate_regions_using_location (Location& loc)
2333 if (loc.is_mark()) {
2337 AudioRange ar (loc.start(), loc.end(), 1);
2342 separate_regions_between (ts);
2346 Editor::crop_region_to_selection ()
2348 ensure_entered_selected ();
2350 if (!selection->time.empty()) {
2352 crop_region_to (selection->time.start(), selection->time.end_frame());
2354 } else if (_edit_point != EditAtPlayhead) {
2359 if (get_edit_op_range (start, end)) {
2360 crop_region_to (start, end);
2367 Editor::crop_region_to (nframes_t start, nframes_t end)
2369 vector<boost::shared_ptr<Playlist> > playlists;
2370 boost::shared_ptr<Playlist> playlist;
2373 ensure_entered_selected ();
2375 if (selection->tracks.empty()) {
2378 sort_track_selection ();
2379 ts = &selection->tracks;
2382 for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
2384 AudioTimeAxisView* atv;
2386 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2388 if (atv->is_audio_track()) {
2390 /* no edits to destructive tracks */
2392 if (atv->audio_track()->audio_diskstream()->destructive()) {
2396 if ((playlist = atv->playlist()) != 0) {
2397 playlists.push_back (playlist);
2403 if (playlists.empty()) {
2407 nframes_t the_start;
2411 begin_reversible_command (_("trim to selection"));
2413 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 boost::shared_ptr<Region> region;
2419 if ((region = (*i)->top_region_at(the_start)) == 0) {
2423 /* now adjust lengths to that we do the right thing
2424 if the selection extends beyond the region
2427 the_start = max (the_start, region->position());
2428 if (max_frames - the_start < region->length()) {
2429 the_end = the_start + region->length() - 1;
2431 the_end = max_frames;
2433 the_end = min (end, the_end);
2434 cnt = the_end - the_start + 1;
2436 XMLNode &before = (*i)->get_state();
2437 region->trim_to (the_start, cnt, this);
2438 XMLNode &after = (*i)->get_state();
2439 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2442 commit_reversible_command ();
2446 Editor::region_fill_track ()
2450 if (!session || selection->regions.empty()) {
2454 end = session->current_end_frame ();
2456 begin_reversible_command (_("region fill"));
2458 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2460 boost::shared_ptr<Region> region ((*i)->region());
2463 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2467 boost::shared_ptr<Playlist> pl = region->playlist();
2469 if (end <= region->last_frame()) {
2473 double times = (double) (end - region->last_frame()) / (double) region->length();
2479 XMLNode &before = pl->get_state();
2480 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2481 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2484 commit_reversible_command ();
2488 Editor::region_fill_selection ()
2490 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2494 if (selection->time.empty()) {
2499 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2501 if (selected->count_selected_rows() != 1) {
2505 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2506 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2508 nframes_t start = selection->time[clicked_selection].start;
2509 nframes_t end = selection->time[clicked_selection].end;
2511 boost::shared_ptr<Playlist> playlist;
2513 if (selection->tracks.empty()) {
2517 nframes_t selection_length = end - start;
2518 float times = (float)selection_length / region->length();
2520 begin_reversible_command (_("fill selection"));
2522 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2524 if ((playlist = (*i)->playlist()) == 0) {
2528 XMLNode &before = playlist->get_state();
2529 playlist->add_region (RegionFactory::create (region), start, times);
2530 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2533 commit_reversible_command ();
2537 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2540 if (!region->covers (position)) {
2541 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2544 begin_reversible_command (_("set region sync position"));
2545 XMLNode &before = region->playlist()->get_state();
2546 region->set_sync_position (position);
2547 XMLNode &after = region->playlist()->get_state();
2548 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2549 commit_reversible_command ();
2553 Editor::set_region_sync_from_edit_point ()
2555 if (clicked_regionview == 0) {
2559 if (!clicked_regionview->region()->covers (get_preferred_edit_position())) {
2560 error << _("Place the edit point at the desired sync point") << endmsg;
2564 boost::shared_ptr<Region> region (clicked_regionview->region());
2565 begin_reversible_command (_("set sync from edit point"));
2566 XMLNode &before = region->playlist()->get_state();
2567 region->set_sync_position (get_preferred_edit_position());
2568 XMLNode &after = region->playlist()->get_state();
2569 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2570 commit_reversible_command ();
2574 Editor::remove_region_sync ()
2576 if (clicked_regionview) {
2577 boost::shared_ptr<Region> region (clicked_regionview->region());
2578 begin_reversible_command (_("remove sync"));
2579 XMLNode &before = region->playlist()->get_state();
2580 region->clear_sync_position ();
2581 XMLNode &after = region->playlist()->get_state();
2582 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2583 commit_reversible_command ();
2588 Editor::naturalize ()
2590 if (selection->regions.empty()) {
2593 begin_reversible_command (_("naturalize"));
2594 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2595 XMLNode &before = (*i)->region()->get_state();
2596 (*i)->region()->move_to_natural_position (this);
2597 XMLNode &after = (*i)->region()->get_state();
2598 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2600 commit_reversible_command ();
2604 Editor::align (RegionPoint what)
2606 ensure_entered_selected ();
2608 nframes64_t where = get_preferred_edit_position();
2610 if (!selection->regions.empty()) {
2611 align_selection (what, where, selection->regions);
2615 rs = get_regions_at (where, selection->tracks);
2616 align_selection (what, where, rs);
2621 Editor::align_relative (RegionPoint what)
2623 nframes64_t where = get_preferred_edit_position();
2625 if (!selection->regions.empty()) {
2626 align_selection_relative (what, where, selection->regions);
2630 rs = get_regions_at (where, selection->tracks);
2631 align_selection_relative (what, where, rs);
2635 struct RegionSortByTime {
2636 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2637 return a->region()->position() < b->region()->position();
2642 Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
2652 list<RegionView*> sorted;
2653 rs.by_position (sorted);
2654 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2658 pos = r->first_frame ();
2662 pos = r->last_frame();
2666 pos = r->adjust_to_sync (r->first_frame());
2670 if (pos > position) {
2671 distance = pos - position;
2674 distance = position - pos;
2678 begin_reversible_command (_("align selection (relative)"));
2680 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2682 boost::shared_ptr<Region> region ((*i)->region());
2684 XMLNode &before = region->playlist()->get_state();
2687 region->set_position (region->position() + distance, this);
2689 region->set_position (region->position() - distance, this);
2692 XMLNode &after = region->playlist()->get_state();
2693 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2697 commit_reversible_command ();
2701 Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
2707 begin_reversible_command (_("align selection"));
2709 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2710 align_region_internal ((*i)->region(), point, position);
2713 commit_reversible_command ();
2717 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2719 begin_reversible_command (_("align region"));
2720 align_region_internal (region, point, position);
2721 commit_reversible_command ();
2725 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2727 XMLNode &before = region->playlist()->get_state();
2731 region->set_position (region->adjust_to_sync (position), this);
2735 if (position > region->length()) {
2736 region->set_position (position - region->length(), this);
2741 region->set_position (position, this);
2745 XMLNode &after = region->playlist()->get_state();
2746 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2750 Editor::trim_region_to_loop ()
2752 Location* loc = session->locations()->auto_loop_location();
2756 trim_region_to_location (*loc, _("trim to loop"));
2760 Editor::trim_region_to_punch ()
2762 Location* loc = session->locations()->auto_punch_location();
2766 trim_region_to_location (*loc, _("trim to punch"));
2770 Editor::trim_region_to_location (const Location& loc, const char* str)
2772 ensure_entered_selected ();
2774 RegionSelection& rs (get_regions_for_action ());
2776 begin_reversible_command (str);
2778 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2779 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2785 /* require region to span proposed trim */
2787 switch (arv->region()->coverage (loc.start(), loc.end())) {
2788 case OverlapInternal:
2794 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2804 if (atav->get_diskstream() != 0) {
2805 speed = atav->get_diskstream()->speed();
2808 start = session_frame_to_track_frame (loc.start(), speed);
2809 end = session_frame_to_track_frame (loc.end(), speed);
2811 XMLNode &before = arv->region()->playlist()->get_state();
2812 arv->region()->trim_to (start, (end - start), this);
2813 XMLNode &after = arv->region()->playlist()->get_state();
2814 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2817 commit_reversible_command ();
2821 Editor::trim_region_to_edit_point ()
2823 RegionSelection& rs (get_regions_for_action ());
2824 nframes64_t where = get_preferred_edit_position();
2826 begin_reversible_command (_("trim region start to edit point"));
2828 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2829 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2835 /* require region to cover trim */
2837 if (!arv->region()->covers (where)) {
2841 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2849 if (atav->get_diskstream() != 0) {
2850 speed = atav->get_diskstream()->speed();
2853 XMLNode &before = arv->region()->playlist()->get_state();
2854 arv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
2855 XMLNode &after = arv->region()->playlist()->get_state();
2856 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2859 commit_reversible_command ();
2863 Editor::trim_region_from_edit_point ()
2865 RegionSelection& rs (get_regions_for_action ());
2866 nframes64_t where = get_preferred_edit_position();
2868 begin_reversible_command (_("trim region end to edit point"));
2870 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2871 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2877 /* require region to cover trim */
2879 if (!arv->region()->covers (where)) {
2883 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2891 if (atav->get_diskstream() != 0) {
2892 speed = atav->get_diskstream()->speed();
2895 XMLNode &before = arv->region()->playlist()->get_state();
2896 arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
2897 XMLNode &after = arv->region()->playlist()->get_state();
2898 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2901 commit_reversible_command ();
2905 Editor::unfreeze_route ()
2907 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2911 clicked_audio_trackview->audio_track()->unfreeze ();
2915 Editor::_freeze_thread (void* arg)
2917 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2918 return static_cast<Editor*>(arg)->freeze_thread ();
2922 Editor::freeze_thread ()
2924 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2929 Editor::freeze_progress_timeout (void *arg)
2931 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2932 return !(current_interthread_info->done || current_interthread_info->cancel);
2936 Editor::freeze_route ()
2938 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2942 InterThreadInfo itt;
2944 if (interthread_progress_window == 0) {
2945 build_interthread_progress_window ();
2948 WindowTitle title(Glib::get_application_name());
2949 title += _("Freeze");
2950 interthread_progress_window->set_title (title.get_string());
2951 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2952 interthread_progress_window->show_all ();
2953 interthread_progress_bar.set_fraction (0.0f);
2954 interthread_progress_label.set_text ("");
2955 interthread_cancel_label.set_text (_("Cancel Freeze"));
2956 current_interthread_info = &itt;
2958 interthread_progress_connection =
2959 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2963 itt.progress = 0.0f;
2965 pthread_attr_t attr;
2966 pthread_attr_init(&attr);
2967 pthread_attr_setstacksize(&attr, 500000);
2969 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2971 pthread_attr_destroy(&attr);
2973 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2975 while (!itt.done && !itt.cancel) {
2976 gtk_main_iteration ();
2979 interthread_progress_connection.disconnect ();
2980 interthread_progress_window->hide_all ();
2981 current_interthread_info = 0;
2982 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2986 Editor::bounce_range_selection ()
2988 if (selection->time.empty()) {
2992 TrackSelection views = selection->tracks;
2994 nframes_t start = selection->time[clicked_selection].start;
2995 nframes_t end = selection->time[clicked_selection].end;
2996 nframes_t cnt = end - start + 1;
2998 begin_reversible_command (_("bounce range"));
3000 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3002 AudioTimeAxisView* atv;
3004 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
3008 boost::shared_ptr<Playlist> playlist;
3010 if ((playlist = atv->playlist()) == 0) {
3014 InterThreadInfo itt;
3018 itt.progress = false;
3020 XMLNode &before = playlist->get_state();
3021 atv->audio_track()->bounce_range (start, cnt, itt);
3022 XMLNode &after = playlist->get_state();
3023 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
3026 commit_reversible_command ();
3042 Editor::cut_copy (CutCopyOp op)
3044 /* only cancel selection if cut/copy is successful.*/
3056 opname = _("clear");
3060 cut_buffer->clear ();
3062 if (entered_marker) {
3064 /* cut/delete op while pointing at a marker */
3067 Location* loc = find_location_from_marker (entered_marker, ignored);
3069 if (session && loc) {
3070 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
3076 switch (current_mouse_mode()) {
3078 if (!selection->regions.empty() || !selection->points.empty()) {
3080 begin_reversible_command (opname + _(" objects"));
3082 if (!selection->regions.empty()) {
3084 cut_copy_regions (op);
3087 selection->clear_regions ();
3091 if (!selection->points.empty()) {
3092 cut_copy_points (op);
3095 selection->clear_points ();
3099 commit_reversible_command ();
3100 break; // terminate case statement here
3102 if (!selection->time.empty()) {
3103 /* don't cause suprises */
3106 // fall thru if there was nothing selected
3109 if (selection->time.empty()) {
3110 nframes64_t start, end;
3111 if (!get_edit_op_range (start, end)) {
3114 selection->set (0, start, end);
3117 begin_reversible_command (opname + _(" range"));
3118 cut_copy_ranges (op);
3119 commit_reversible_command ();
3122 selection->clear_time ();
3133 Editor::cut_copy_points (CutCopyOp op)
3135 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3137 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3140 atv->cut_copy_clear_objects (selection->points, op);
3145 struct PlaylistState {
3146 boost::shared_ptr<Playlist> playlist;
3150 struct lt_playlist {
3151 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3152 return a.playlist < b.playlist;
3156 struct PlaylistMapping {
3158 boost::shared_ptr<AudioPlaylist> pl;
3160 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3164 Editor::cut_copy_regions (CutCopyOp op)
3166 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3167 a map when we want ordered access to both elements. i think.
3170 vector<PlaylistMapping> pmap;
3172 nframes_t first_position = max_frames;
3174 set<PlaylistState, lt_playlist> freezelist;
3175 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
3177 /* get ordering correct before we cut/copy */
3179 selection->regions.sort_by_position_and_track ();
3181 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3183 first_position = min ((*x)->region()->position(), first_position);
3185 if (op == Cut || op == Clear) {
3186 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3190 PlaylistState before;
3191 before.playlist = pl;
3192 before.before = &pl->get_state();
3194 insert_result = freezelist.insert (before);
3196 if (insert_result.second) {
3202 TimeAxisView* tv = &(*x)->get_trackview();
3203 vector<PlaylistMapping>::iterator z;
3205 for (z = pmap.begin(); z != pmap.end(); ++z) {
3206 if ((*z).tv == tv) {
3211 if (z == pmap.end()) {
3212 pmap.push_back (PlaylistMapping (tv));
3216 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3218 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3221 /* impossible, but this handles it for the future */
3225 TimeAxisView& tv = (*x)->get_trackview();
3226 boost::shared_ptr<AudioPlaylist> npl;
3227 RegionSelection::iterator tmp;
3232 vector<PlaylistMapping>::iterator z;
3234 for (z = pmap.begin(); z != pmap.end(); ++z) {
3235 if ((*z).tv == &tv) {
3240 assert (z != pmap.end());
3243 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3250 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3251 boost::shared_ptr<Region> _xx;
3257 _xx = RegionFactory::create ((*x)->region());
3258 npl->add_region (_xx, (*x)->region()->position() - first_position);
3259 pl->remove_region (((*x)->region()));
3265 /* copy region before adding, so we're not putting same object into two different playlists */
3266 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
3270 pl->remove_region (((*x)->region()));
3277 list<boost::shared_ptr<Playlist> > foo;
3279 /* the pmap is in the same order as the tracks in which selected regions occured */
3281 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3283 foo.push_back ((*i).pl);
3288 cut_buffer->set (foo);
3291 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3292 (*pl).playlist->thaw ();
3293 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3298 Editor::cut_copy_ranges (CutCopyOp op)
3302 if (selection->tracks.empty()) {
3305 ts = &selection->tracks;
3308 for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3309 (*i)->cut_copy_clear (*selection, op);
3314 Editor::paste (float times)
3316 paste_internal (get_preferred_edit_position(), times);
3320 Editor::mouse_paste ()
3325 if (!mouse_frame (where, ignored)) {
3330 paste_internal (where, 1);
3334 Editor::paste_internal (nframes_t position, float times)
3336 bool commit = false;
3338 if (cut_buffer->empty() || selection->tracks.empty()) {
3342 if (position == max_frames) {
3343 position = get_preferred_edit_position();
3346 begin_reversible_command (_("paste"));
3348 TrackSelection::iterator i;
3351 /* get everything in the correct order */
3353 sort_track_selection ();
3355 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3357 /* undo/redo is handled by individual tracks */
3359 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3365 commit_reversible_command ();
3370 Editor::paste_named_selection (float times)
3372 TrackSelection::iterator t;
3374 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3376 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3380 TreeModel::iterator i = selected->get_selected();
3381 NamedSelection* ns = (*i)[named_selection_columns.selection];
3383 list<boost::shared_ptr<Playlist> >::iterator chunk;
3384 list<boost::shared_ptr<Playlist> >::iterator tmp;
3386 chunk = ns->playlists.begin();
3388 begin_reversible_command (_("paste chunk"));
3390 sort_track_selection ();
3392 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3394 AudioTimeAxisView* atv;
3395 boost::shared_ptr<Playlist> pl;
3396 boost::shared_ptr<AudioPlaylist> apl;
3398 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3402 if ((pl = atv->playlist()) == 0) {
3406 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3413 XMLNode &before = apl->get_state();
3414 apl->paste (*chunk, get_preferred_edit_position(), times);
3415 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3417 if (tmp != ns->playlists.end()) {
3422 commit_reversible_command();
3426 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3428 boost::shared_ptr<Playlist> playlist;
3429 RegionSelection sel = regions; // clear (below) will clear the argument list
3431 begin_reversible_command (_("duplicate region"));
3433 selection->clear_regions ();
3435 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3437 boost::shared_ptr<Region> r ((*i)->region());
3439 TimeAxisView& tv = (*i)->get_time_axis_view();
3440 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3441 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3443 playlist = (*i)->region()->playlist();
3444 XMLNode &before = playlist->get_state();
3445 playlist->duplicate (r, r->last_frame() + 1, times);
3446 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3450 if (!latest_regionviews.empty()) {
3451 selection->add (latest_regionviews);
3456 commit_reversible_command ();
3460 Editor::duplicate_selection (float times)
3462 if (selection->time.empty() || selection->tracks.empty()) {
3466 boost::shared_ptr<Playlist> playlist;
3467 vector<boost::shared_ptr<AudioRegion> > new_regions;
3468 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3470 create_region_from_selection (new_regions);
3472 if (new_regions.empty()) {
3476 begin_reversible_command (_("duplicate selection"));
3478 ri = new_regions.begin();
3480 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3481 if ((playlist = (*i)->playlist()) == 0) {
3484 XMLNode &before = playlist->get_state();
3485 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3486 XMLNode &after = playlist->get_state();
3487 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3490 if (ri == new_regions.end()) {
3495 commit_reversible_command ();
3499 Editor::reset_point_selection ()
3501 /* reset all selected points to the relevant default value */
3503 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3505 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3508 atv->reset_objects (selection->points);
3514 Editor::center_playhead ()
3516 float page = canvas_width * frames_per_unit;
3517 center_screen_internal (playhead_cursor->current_frame, page);
3521 Editor::center_edit_point ()
3523 float page = canvas_width * frames_per_unit;
3524 center_screen_internal (get_preferred_edit_position(), page);
3528 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3530 begin_reversible_command (_("clear playlist"));
3531 XMLNode &before = playlist->get_state();
3533 XMLNode &after = playlist->get_state();
3534 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3535 commit_reversible_command ();
3539 Editor::nudge_track (bool use_edit, bool forwards)
3541 boost::shared_ptr<Playlist> playlist;
3543 nframes_t next_distance;
3547 start = get_preferred_edit_position();
3552 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3556 if (selection->tracks.empty()) {
3560 begin_reversible_command (_("nudge track"));
3562 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3564 if ((playlist = (*i)->playlist()) == 0) {
3568 XMLNode &before = playlist->get_state();
3569 playlist->nudge_after (start, distance, forwards);
3570 XMLNode &after = playlist->get_state();
3571 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3574 commit_reversible_command ();
3578 Editor::remove_last_capture ()
3580 vector<string> choices;
3587 if (Config->get_verify_remove_last_capture()) {
3588 prompt = _("Do you really want to destroy the last capture?"
3589 "\n(This is destructive and cannot be undone)");
3591 choices.push_back (_("No, do nothing."));
3592 choices.push_back (_("Yes, destroy it."));
3594 Gtkmm2ext::Choice prompter (prompt, choices);
3596 if (prompter.run () == 1) {
3597 session->remove_last_capture ();
3601 session->remove_last_capture();
3606 Editor::normalize_region ()
3612 if (selection->regions.empty()) {
3616 begin_reversible_command (_("normalize"));
3618 track_canvas.get_window()->set_cursor (*wait_cursor);
3621 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3622 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3625 XMLNode &before = arv->region()->get_state();
3626 arv->audio_region()->normalize_to (0.0f);
3627 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3630 commit_reversible_command ();
3631 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3636 Editor::denormalize_region ()
3642 if (selection->regions.empty()) {
3646 begin_reversible_command ("denormalize");
3648 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3649 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3652 XMLNode &before = arv->region()->get_state();
3653 arv->audio_region()->set_scale_amplitude (1.0f);
3654 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3657 commit_reversible_command ();
3662 Editor::reverse_region ()
3668 Reverse rev (*session);
3669 apply_filter (rev, _("reverse regions"));
3673 Editor::apply_filter (AudioFilter& filter, string command)
3675 if (selection->regions.empty()) {
3679 begin_reversible_command (command);
3681 track_canvas.get_window()->set_cursor (*wait_cursor);
3684 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3685 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3689 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3691 RegionSelection::iterator tmp;
3696 if (arv->audio_region()->apply (filter) == 0) {
3698 XMLNode &before = playlist->get_state();
3699 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3700 XMLNode &after = playlist->get_state();
3701 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3709 commit_reversible_command ();
3710 selection->regions.clear ();
3713 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3717 Editor::region_selection_op (void (Region::*pmf)(void))
3719 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3720 Region* region = (*i)->region().get();
3727 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3729 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3730 Region* region = (*i)->region().get();
3731 (region->*pmf)(arg);
3736 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3738 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3739 Region* region = (*i)->region().get();
3745 Editor::external_edit_region ()
3747 if (!clicked_regionview) {
3755 Editor::brush (nframes_t pos)
3757 RegionSelection sel;
3760 if (selection->regions.empty()) {
3761 /* XXX get selection from region list */
3763 sel = selection->regions;
3770 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3771 mouse_brush_insert_region ((*i), pos);
3776 Editor::reset_region_gain_envelopes ()
3778 if (!session || selection->regions.empty()) {
3782 session->begin_reversible_command (_("reset region gain"));
3784 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3785 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3787 AutomationList& alist (arv->audio_region()->envelope());
3788 XMLNode& before (alist.get_state());
3790 arv->audio_region()->set_default_envelope ();
3791 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3795 session->commit_reversible_command ();
3799 Editor::toggle_gain_envelope_visibility ()
3801 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3802 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3804 bool x = region_envelope_visible_item->get_active();
3805 if (x != arv->envelope_visible()) {
3806 arv->set_envelope_visible (x);
3813 Editor::toggle_gain_envelope_active ()
3815 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3816 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3818 bool x = region_envelope_active_item->get_active();
3819 if (x != arv->audio_region()->envelope_active()) {
3820 arv->audio_region()->set_envelope_active (x);
3827 Editor::toggle_region_lock ()
3829 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3830 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3832 bool x = region_lock_item->get_active();
3833 if (x != arv->audio_region()->locked()) {
3834 arv->audio_region()->set_locked (x);
3841 Editor::toggle_region_mute ()
3843 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3844 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3846 bool x = region_mute_item->get_active();
3847 if (x != arv->audio_region()->muted()) {
3848 arv->audio_region()->set_muted (x);
3855 Editor::toggle_region_opaque ()
3857 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3858 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3860 bool x = region_opaque_item->get_active();
3861 if (x != arv->audio_region()->opaque()) {
3862 arv->audio_region()->set_opaque (x);
3869 Editor::set_fade_length (bool in)
3871 ensure_entered_selected ();
3873 /* we need a region to measure the offset from the start */
3877 if (entered_regionview) {
3878 rv = entered_regionview;
3879 } else if (!selection->regions.empty()) {
3880 rv = selection->regions.front();
3885 nframes64_t pos = get_preferred_edit_position();
3890 if (pos <= rv->region()->position()) {
3894 len = pos - rv->region()->position();
3895 cmd = _("set fade in length");
3897 if (pos >= rv->region()->last_frame()) {
3901 len = rv->region()->last_frame() - pos;
3902 cmd = _("set fade out length");
3905 begin_reversible_command (cmd);
3907 RegionSelection& rs (get_regions_for_action());
3909 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3910 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3916 AutomationList& alist = tmp->audio_region()->fade_in();
3917 XMLNode &before = alist.get_state();
3920 tmp->audio_region()->set_fade_in_length (len);
3922 tmp->audio_region()->set_fade_out_length (len);
3925 XMLNode &after = alist.get_state();
3926 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3929 commit_reversible_command ();
3933 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3935 begin_reversible_command (_("set fade in 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_in();
3945 XMLNode &before = alist.get_state();
3947 tmp->audio_region()->set_fade_in_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_out_shape (AudioRegion::FadeShape shape)
3959 begin_reversible_command (_("set fade out shape"));
3961 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3962 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3968 AutomationList& alist = tmp->audio_region()->fade_out();
3969 XMLNode &before = alist.get_state();
3971 tmp->audio_region()->set_fade_out_shape (shape);
3973 XMLNode &after = alist.get_state();
3974 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3977 commit_reversible_command ();
3981 Editor::set_fade_in_active (bool yn)
3983 begin_reversible_command (_("set fade in active"));
3985 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3986 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3993 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3995 XMLNode &before = ar->get_state();
3997 ar->set_fade_in_active (yn);
3999 XMLNode &after = ar->get_state();
4000 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4005 Editor::set_fade_out_active (bool yn)
4007 begin_reversible_command (_("set fade out active"));
4009 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
4010 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4016 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4018 XMLNode &before = ar->get_state();
4020 ar->set_fade_out_active (yn);
4022 XMLNode &after = ar->get_state();
4023 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4028 /** Update crossfade visibility after its configuration has been changed */
4030 Editor::update_xfade_visibility ()
4032 _xfade_visibility = Config->get_xfades_visible ();
4034 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4035 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4037 if (_xfade_visibility) {
4038 v->show_all_xfades ();
4040 v->hide_all_xfades ();
4047 Editor::set_edit_point ()
4052 if (!mouse_frame (where, ignored)) {
4058 if (selection->markers.empty()) {
4060 mouse_add_new_marker (where);
4065 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
4068 loc->move_to (where);
4074 Editor::set_playhead_cursor ()
4076 if (entered_marker) {
4077 session->request_locate (entered_marker->position(), session->transport_rolling());
4082 if (!mouse_frame (where, ignored)) {
4089 session->request_locate (where, session->transport_rolling());
4097 ensure_entered_selected ();
4099 nframes64_t where = get_preferred_edit_position();
4101 if (!selection->regions.empty()) {
4103 split_regions_at (where, selection->regions);
4108 rs = get_regions_at (where, selection->tracks);
4109 split_regions_at (where, rs);
4114 Editor::ensure_entered_selected ()
4116 if (entered_regionview) {
4117 if (find (selection->regions.begin(), selection->regions.end(), entered_regionview) == selection->regions.end()) {
4119 /* do NOT clear any existing track selection when we do this */
4121 selection->set (entered_regionview, false);