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