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()) {
2328 crop_region_to (selection->time.start(), selection->time.end_frame());
2330 } else if (_edit_point != EditAtPlayhead) {
2335 if (get_edit_op_range (start, end)) {
2336 crop_region_to (start, end);
2343 Editor::crop_region_to (nframes_t start, nframes_t end)
2345 vector<boost::shared_ptr<Playlist> > playlists;
2346 boost::shared_ptr<Playlist> playlist;
2349 if (selection->tracks.empty()) {
2352 sort_track_selection ();
2353 ts = &selection->tracks;
2356 for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
2358 AudioTimeAxisView* atv;
2360 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2362 if (atv->is_audio_track()) {
2364 /* no edits to destructive tracks */
2366 if (atv->audio_track()->audio_diskstream()->destructive()) {
2370 if ((playlist = atv->playlist()) != 0) {
2371 playlists.push_back (playlist);
2377 if (playlists.empty()) {
2381 nframes_t the_start;
2385 begin_reversible_command (_("trim to selection"));
2387 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2389 boost::shared_ptr<Region> region;
2393 if ((region = (*i)->top_region_at(the_start)) == 0) {
2397 /* now adjust lengths to that we do the right thing
2398 if the selection extends beyond the region
2401 the_start = max (the_start, region->position());
2402 if (max_frames - the_start < region->length()) {
2403 the_end = the_start + region->length() - 1;
2405 the_end = max_frames;
2407 the_end = min (end, the_end);
2408 cnt = the_end - the_start + 1;
2410 XMLNode &before = (*i)->get_state();
2411 region->trim_to (the_start, cnt, this);
2412 XMLNode &after = (*i)->get_state();
2413 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2416 commit_reversible_command ();
2420 Editor::region_fill_track ()
2424 if (!session || selection->regions.empty()) {
2428 end = session->current_end_frame ();
2430 begin_reversible_command (_("region fill"));
2432 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2434 boost::shared_ptr<Region> region ((*i)->region());
2437 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2441 boost::shared_ptr<Playlist> pl = region->playlist();
2443 if (end <= region->last_frame()) {
2447 double times = (double) (end - region->last_frame()) / (double) region->length();
2453 XMLNode &before = pl->get_state();
2454 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2455 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2458 commit_reversible_command ();
2462 Editor::region_fill_selection ()
2464 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2468 if (selection->time.empty()) {
2473 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2475 if (selected->count_selected_rows() != 1) {
2479 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2480 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2482 nframes_t start = selection->time[clicked_selection].start;
2483 nframes_t end = selection->time[clicked_selection].end;
2485 boost::shared_ptr<Playlist> playlist;
2487 if (selection->tracks.empty()) {
2491 nframes_t selection_length = end - start;
2492 float times = (float)selection_length / region->length();
2494 begin_reversible_command (_("fill selection"));
2496 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2498 if ((playlist = (*i)->playlist()) == 0) {
2502 XMLNode &before = playlist->get_state();
2503 playlist->add_region (RegionFactory::create (region), start, times);
2504 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2507 commit_reversible_command ();
2511 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2514 if (!region->covers (position)) {
2515 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2518 begin_reversible_command (_("set region sync position"));
2519 XMLNode &before = region->playlist()->get_state();
2520 region->set_sync_position (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::set_region_sync_from_edit_point ()
2529 if (clicked_regionview == 0) {
2533 if (!clicked_regionview->region()->covers (get_preferred_edit_position())) {
2534 error << _("Place the edit point at the desired sync point") << endmsg;
2538 boost::shared_ptr<Region> region (clicked_regionview->region());
2539 begin_reversible_command (_("set sync from edit point"));
2540 XMLNode &before = region->playlist()->get_state();
2541 region->set_sync_position (get_preferred_edit_position());
2542 XMLNode &after = region->playlist()->get_state();
2543 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2544 commit_reversible_command ();
2548 Editor::remove_region_sync ()
2550 if (clicked_regionview) {
2551 boost::shared_ptr<Region> region (clicked_regionview->region());
2552 begin_reversible_command (_("remove sync"));
2553 XMLNode &before = region->playlist()->get_state();
2554 region->clear_sync_position ();
2555 XMLNode &after = region->playlist()->get_state();
2556 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2557 commit_reversible_command ();
2562 Editor::naturalize ()
2564 if (selection->regions.empty()) {
2567 begin_reversible_command (_("naturalize"));
2568 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2569 XMLNode &before = (*i)->region()->get_state();
2570 (*i)->region()->move_to_natural_position (this);
2571 XMLNode &after = (*i)->region()->get_state();
2572 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2574 commit_reversible_command ();
2578 Editor::align (RegionPoint what)
2580 align_selection (what, get_preferred_edit_position(), selection->regions);
2584 Editor::align_relative (RegionPoint what)
2586 align_selection_relative (what, get_preferred_edit_position(), selection->regions);
2589 struct RegionSortByTime {
2590 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2591 return a->region()->position() < b->region()->position();
2596 Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
2606 list<RegionView*> sorted;
2607 rs.by_position (sorted);
2608 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2612 pos = r->first_frame ();
2616 pos = r->last_frame();
2620 pos = r->adjust_to_sync (r->first_frame());
2624 if (pos > position) {
2625 distance = pos - position;
2628 distance = position - pos;
2632 begin_reversible_command (_("align selection (relative)"));
2634 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2636 boost::shared_ptr<Region> region ((*i)->region());
2638 XMLNode &before = region->playlist()->get_state();
2641 region->set_position (region->position() + distance, this);
2643 region->set_position (region->position() - distance, this);
2646 XMLNode &after = region->playlist()->get_state();
2647 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2651 commit_reversible_command ();
2655 Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
2661 begin_reversible_command (_("align selection"));
2663 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2664 align_region_internal ((*i)->region(), point, position);
2667 commit_reversible_command ();
2671 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2673 begin_reversible_command (_("align region"));
2674 align_region_internal (region, point, position);
2675 commit_reversible_command ();
2679 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2681 XMLNode &before = region->playlist()->get_state();
2685 region->set_position (region->adjust_to_sync (position), this);
2689 if (position > region->length()) {
2690 region->set_position (position - region->length(), this);
2695 region->set_position (position, this);
2699 XMLNode &after = region->playlist()->get_state();
2700 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2704 Editor::trim_region_to_edit_point ()
2706 if (clicked_regionview == 0) {
2710 boost::shared_ptr<Region> region (clicked_regionview->region());
2713 AudioTimeAxisView *atav;
2715 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2716 if (atav->get_diskstream() != 0) {
2717 speed = atav->get_diskstream()->speed();
2721 begin_reversible_command (_("trim to edit"));
2722 XMLNode &before = region->playlist()->get_state();
2723 region->trim_end( session_frame_to_track_frame(get_preferred_edit_position(), speed), this);
2724 XMLNode &after = region->playlist()->get_state();
2725 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2726 commit_reversible_command ();
2730 Editor::trim_region_from_edit_point ()
2732 if (clicked_regionview == 0) {
2736 boost::shared_ptr<Region> region (clicked_regionview->region());
2739 AudioTimeAxisView *atav;
2741 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2742 if (atav->get_diskstream() != 0) {
2743 speed = atav->get_diskstream()->speed();
2747 begin_reversible_command (_("trim to edit"));
2748 XMLNode &before = region->playlist()->get_state();
2749 region->trim_front ( session_frame_to_track_frame(get_preferred_edit_position(), speed), this);
2750 XMLNode &after = region->playlist()->get_state();
2751 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2752 commit_reversible_command ();
2756 Editor::unfreeze_route ()
2758 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2762 clicked_audio_trackview->audio_track()->unfreeze ();
2766 Editor::_freeze_thread (void* arg)
2768 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2769 return static_cast<Editor*>(arg)->freeze_thread ();
2773 Editor::freeze_thread ()
2775 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2780 Editor::freeze_progress_timeout (void *arg)
2782 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2783 return !(current_interthread_info->done || current_interthread_info->cancel);
2787 Editor::freeze_route ()
2789 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2793 InterThreadInfo itt;
2795 if (interthread_progress_window == 0) {
2796 build_interthread_progress_window ();
2799 WindowTitle title(Glib::get_application_name());
2800 title += _("Freeze");
2801 interthread_progress_window->set_title (title.get_string());
2802 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2803 interthread_progress_window->show_all ();
2804 interthread_progress_bar.set_fraction (0.0f);
2805 interthread_progress_label.set_text ("");
2806 interthread_cancel_label.set_text (_("Cancel Freeze"));
2807 current_interthread_info = &itt;
2809 interthread_progress_connection =
2810 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2814 itt.progress = 0.0f;
2816 pthread_attr_t attr;
2817 pthread_attr_init(&attr);
2818 pthread_attr_setstacksize(&attr, 500000);
2820 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2822 pthread_attr_destroy(&attr);
2824 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2826 while (!itt.done && !itt.cancel) {
2827 gtk_main_iteration ();
2830 interthread_progress_connection.disconnect ();
2831 interthread_progress_window->hide_all ();
2832 current_interthread_info = 0;
2833 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2837 Editor::bounce_range_selection ()
2839 if (selection->time.empty()) {
2843 TrackSelection views = selection->tracks;
2845 nframes_t start = selection->time[clicked_selection].start;
2846 nframes_t end = selection->time[clicked_selection].end;
2847 nframes_t cnt = end - start + 1;
2849 begin_reversible_command (_("bounce range"));
2851 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
2853 AudioTimeAxisView* atv;
2855 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2859 boost::shared_ptr<Playlist> playlist;
2861 if ((playlist = atv->playlist()) == 0) {
2865 InterThreadInfo itt;
2869 itt.progress = false;
2871 XMLNode &before = playlist->get_state();
2872 atv->audio_track()->bounce_range (start, cnt, itt);
2873 XMLNode &after = playlist->get_state();
2874 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2877 commit_reversible_command ();
2893 Editor::cut_copy (CutCopyOp op)
2895 /* only cancel selection if cut/copy is successful.*/
2907 opname = _("clear");
2911 cut_buffer->clear ();
2913 if (entered_marker) {
2915 /* cut/delete op while pointing at a marker */
2918 Location* loc = find_location_from_marker (entered_marker, ignored);
2920 if (session && loc) {
2921 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
2927 switch (current_mouse_mode()) {
2929 if (!selection->regions.empty() || !selection->points.empty()) {
2931 begin_reversible_command (opname + _(" objects"));
2933 if (!selection->regions.empty()) {
2935 cut_copy_regions (op);
2938 selection->clear_regions ();
2942 if (!selection->points.empty()) {
2943 cut_copy_points (op);
2946 selection->clear_points ();
2950 commit_reversible_command ();
2951 break; // terminate case statement here
2953 if (!selection->time.empty()) {
2954 /* don't cause suprises */
2957 // fall thru if there was nothing selected
2960 if (selection->time.empty()) {
2961 nframes64_t start, end;
2962 if (!get_edit_op_range (start, end)) {
2965 selection->set (0, start, end);
2968 begin_reversible_command (opname + _(" range"));
2969 cut_copy_ranges (op);
2970 commit_reversible_command ();
2973 selection->clear_time ();
2984 Editor::cut_copy_points (CutCopyOp op)
2986 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2988 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2991 atv->cut_copy_clear_objects (selection->points, op);
2996 struct PlaylistState {
2997 boost::shared_ptr<Playlist> playlist;
3001 struct lt_playlist {
3002 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3003 return a.playlist < b.playlist;
3007 struct PlaylistMapping {
3009 boost::shared_ptr<AudioPlaylist> pl;
3011 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3015 Editor::cut_copy_regions (CutCopyOp op)
3017 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3018 a map when we want ordered access to both elements. i think.
3021 vector<PlaylistMapping> pmap;
3023 nframes_t first_position = max_frames;
3025 set<PlaylistState, lt_playlist> freezelist;
3026 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
3028 /* get ordering correct before we cut/copy */
3030 selection->regions.sort_by_position_and_track ();
3032 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3034 first_position = min ((*x)->region()->position(), first_position);
3036 if (op == Cut || op == Clear) {
3037 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3041 PlaylistState before;
3042 before.playlist = pl;
3043 before.before = &pl->get_state();
3045 insert_result = freezelist.insert (before);
3047 if (insert_result.second) {
3053 TimeAxisView* tv = &(*x)->get_trackview();
3054 vector<PlaylistMapping>::iterator z;
3056 for (z = pmap.begin(); z != pmap.end(); ++z) {
3057 if ((*z).tv == tv) {
3062 if (z == pmap.end()) {
3063 pmap.push_back (PlaylistMapping (tv));
3067 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3069 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3072 /* impossible, but this handles it for the future */
3076 TimeAxisView& tv = (*x)->get_trackview();
3077 boost::shared_ptr<AudioPlaylist> npl;
3078 RegionSelection::iterator tmp;
3083 vector<PlaylistMapping>::iterator z;
3085 for (z = pmap.begin(); z != pmap.end(); ++z) {
3086 if ((*z).tv == &tv) {
3091 assert (z != pmap.end());
3094 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3101 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3102 boost::shared_ptr<Region> _xx;
3108 _xx = RegionFactory::create ((*x)->region());
3109 npl->add_region (_xx, (*x)->region()->position() - first_position);
3110 pl->remove_region (((*x)->region()));
3116 /* copy region before adding, so we're not putting same object into two different playlists */
3117 npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
3121 pl->remove_region (((*x)->region()));
3128 list<boost::shared_ptr<Playlist> > foo;
3130 /* the pmap is in the same order as the tracks in which selected regions occured */
3132 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3134 foo.push_back ((*i).pl);
3139 cut_buffer->set (foo);
3142 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3143 (*pl).playlist->thaw ();
3144 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3149 Editor::cut_copy_ranges (CutCopyOp op)
3153 if (selection->tracks.empty()) {
3156 ts = &selection->tracks;
3159 for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3160 (*i)->cut_copy_clear (*selection, op);
3165 Editor::paste (float times)
3167 paste_internal (get_preferred_edit_position(), times);
3171 Editor::mouse_paste ()
3176 if (!mouse_frame (where, ignored)) {
3181 paste_internal (where, 1);
3185 Editor::paste_internal (nframes_t position, float times)
3187 bool commit = false;
3189 if (cut_buffer->empty() || selection->tracks.empty()) {
3193 if (position == max_frames) {
3194 position = get_preferred_edit_position();
3197 begin_reversible_command (_("paste"));
3199 TrackSelection::iterator i;
3202 /* get everything in the correct order */
3204 sort_track_selection ();
3206 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3208 /* undo/redo is handled by individual tracks */
3210 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3216 commit_reversible_command ();
3221 Editor::paste_named_selection (float times)
3223 TrackSelection::iterator t;
3225 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3227 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3231 TreeModel::iterator i = selected->get_selected();
3232 NamedSelection* ns = (*i)[named_selection_columns.selection];
3234 list<boost::shared_ptr<Playlist> >::iterator chunk;
3235 list<boost::shared_ptr<Playlist> >::iterator tmp;
3237 chunk = ns->playlists.begin();
3239 begin_reversible_command (_("paste chunk"));
3241 sort_track_selection ();
3243 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3245 AudioTimeAxisView* atv;
3246 boost::shared_ptr<Playlist> pl;
3247 boost::shared_ptr<AudioPlaylist> apl;
3249 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3253 if ((pl = atv->playlist()) == 0) {
3257 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3264 XMLNode &before = apl->get_state();
3265 apl->paste (*chunk, get_preferred_edit_position(), times);
3266 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3268 if (tmp != ns->playlists.end()) {
3273 commit_reversible_command();
3277 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3279 boost::shared_ptr<Playlist> playlist;
3280 RegionSelection sel = regions; // clear (below) will clear the argument list
3282 begin_reversible_command (_("duplicate region"));
3284 selection->clear_regions ();
3286 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3288 boost::shared_ptr<Region> r ((*i)->region());
3290 TimeAxisView& tv = (*i)->get_time_axis_view();
3291 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3292 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3294 playlist = (*i)->region()->playlist();
3295 XMLNode &before = playlist->get_state();
3296 playlist->duplicate (r, r->last_frame() + 1, times);
3297 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3301 if (latest_regionview) {
3302 selection->add (latest_regionview);
3307 commit_reversible_command ();
3311 Editor::duplicate_selection (float times)
3313 if (selection->time.empty() || selection->tracks.empty()) {
3317 boost::shared_ptr<Playlist> playlist;
3318 vector<boost::shared_ptr<AudioRegion> > new_regions;
3319 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3321 create_region_from_selection (new_regions);
3323 if (new_regions.empty()) {
3327 begin_reversible_command (_("duplicate selection"));
3329 ri = new_regions.begin();
3331 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3332 if ((playlist = (*i)->playlist()) == 0) {
3335 XMLNode &before = playlist->get_state();
3336 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3337 XMLNode &after = playlist->get_state();
3338 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3341 if (ri == new_regions.end()) {
3346 commit_reversible_command ();
3350 Editor::reset_point_selection ()
3352 /* reset all selected points to the relevant default value */
3354 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3356 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3359 atv->reset_objects (selection->points);
3365 Editor::center_playhead ()
3367 float page = canvas_width * frames_per_unit;
3368 center_screen_internal (playhead_cursor->current_frame, page);
3372 Editor::center_edit_point ()
3374 float page = canvas_width * frames_per_unit;
3375 center_screen_internal (get_preferred_edit_position(), page);
3379 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3381 begin_reversible_command (_("clear playlist"));
3382 XMLNode &before = playlist->get_state();
3384 XMLNode &after = playlist->get_state();
3385 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3386 commit_reversible_command ();
3390 Editor::nudge_track (bool use_edit, bool forwards)
3392 boost::shared_ptr<Playlist> playlist;
3394 nframes_t next_distance;
3398 start = get_preferred_edit_position();
3403 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3407 if (selection->tracks.empty()) {
3411 begin_reversible_command (_("nudge track"));
3413 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3415 if ((playlist = (*i)->playlist()) == 0) {
3419 XMLNode &before = playlist->get_state();
3420 playlist->nudge_after (start, distance, forwards);
3421 XMLNode &after = playlist->get_state();
3422 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3425 commit_reversible_command ();
3429 Editor::remove_last_capture ()
3431 vector<string> choices;
3438 if (Config->get_verify_remove_last_capture()) {
3439 prompt = _("Do you really want to destroy the last capture?"
3440 "\n(This is destructive and cannot be undone)");
3442 choices.push_back (_("No, do nothing."));
3443 choices.push_back (_("Yes, destroy it."));
3445 Gtkmm2ext::Choice prompter (prompt, choices);
3447 if (prompter.run () == 1) {
3448 session->remove_last_capture ();
3452 session->remove_last_capture();
3457 Editor::normalize_region ()
3463 if (selection->regions.empty()) {
3467 begin_reversible_command (_("normalize"));
3469 track_canvas.get_window()->set_cursor (*wait_cursor);
3472 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3473 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3476 XMLNode &before = arv->region()->get_state();
3477 arv->audio_region()->normalize_to (0.0f);
3478 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3481 commit_reversible_command ();
3482 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3487 Editor::denormalize_region ()
3493 if (selection->regions.empty()) {
3497 begin_reversible_command ("denormalize");
3499 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3500 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3503 XMLNode &before = arv->region()->get_state();
3504 arv->audio_region()->set_scale_amplitude (1.0f);
3505 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3508 commit_reversible_command ();
3513 Editor::reverse_region ()
3519 Reverse rev (*session);
3520 apply_filter (rev, _("reverse regions"));
3524 Editor::apply_filter (AudioFilter& filter, string command)
3526 if (selection->regions.empty()) {
3530 begin_reversible_command (command);
3532 track_canvas.get_window()->set_cursor (*wait_cursor);
3535 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3536 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3540 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3542 RegionSelection::iterator tmp;
3547 if (arv->audio_region()->apply (filter) == 0) {
3549 XMLNode &before = playlist->get_state();
3550 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3551 XMLNode &after = playlist->get_state();
3552 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3560 commit_reversible_command ();
3561 selection->regions.clear ();
3564 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3568 Editor::region_selection_op (void (Region::*pmf)(void))
3570 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3571 Region* region = (*i)->region().get();
3578 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3580 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3581 Region* region = (*i)->region().get();
3582 (region->*pmf)(arg);
3587 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3589 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3590 Region* region = (*i)->region().get();
3596 Editor::external_edit_region ()
3598 if (!clicked_regionview) {
3606 Editor::brush (nframes_t pos)
3608 RegionSelection sel;
3611 if (selection->regions.empty()) {
3612 /* XXX get selection from region list */
3614 sel = selection->regions;
3621 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3622 mouse_brush_insert_region ((*i), pos);
3627 Editor::reset_region_gain_envelopes ()
3629 if (!session || selection->regions.empty()) {
3633 session->begin_reversible_command (_("reset region gain"));
3635 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3636 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3638 AutomationList& alist (arv->audio_region()->envelope());
3639 XMLNode& before (alist.get_state());
3641 arv->audio_region()->set_default_envelope ();
3642 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3646 session->commit_reversible_command ();
3650 Editor::toggle_gain_envelope_visibility ()
3652 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3653 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3655 bool x = region_envelope_visible_item->get_active();
3656 if (x != arv->envelope_visible()) {
3657 arv->set_envelope_visible (x);
3664 Editor::toggle_gain_envelope_active ()
3666 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3667 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3669 bool x = region_envelope_active_item->get_active();
3670 if (x != arv->audio_region()->envelope_active()) {
3671 arv->audio_region()->set_envelope_active (x);
3678 Editor::toggle_region_lock ()
3680 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3681 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3683 bool x = region_lock_item->get_active();
3684 if (x != arv->audio_region()->locked()) {
3685 arv->audio_region()->set_locked (x);
3692 Editor::toggle_region_mute ()
3694 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3695 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3697 bool x = region_mute_item->get_active();
3698 if (x != arv->audio_region()->muted()) {
3699 arv->audio_region()->set_muted (x);
3706 Editor::toggle_region_opaque ()
3708 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3709 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3711 bool x = region_opaque_item->get_active();
3712 if (x != arv->audio_region()->opaque()) {
3713 arv->audio_region()->set_opaque (x);
3720 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
3722 begin_reversible_command (_("set fade in shape"));
3724 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3725 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3731 AutomationList& alist = tmp->audio_region()->fade_in();
3732 XMLNode &before = alist.get_state();
3734 tmp->audio_region()->set_fade_in_shape (shape);
3736 XMLNode &after = alist.get_state();
3737 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3740 commit_reversible_command ();
3744 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
3746 begin_reversible_command (_("set fade out shape"));
3748 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3749 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3755 AutomationList& alist = tmp->audio_region()->fade_out();
3756 XMLNode &before = alist.get_state();
3758 tmp->audio_region()->set_fade_out_shape (shape);
3760 XMLNode &after = alist.get_state();
3761 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
3764 commit_reversible_command ();
3768 Editor::set_fade_in_active (bool yn)
3770 begin_reversible_command (_("set fade in active"));
3772 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3773 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3780 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3782 XMLNode &before = ar->get_state();
3784 ar->set_fade_in_active (yn);
3786 XMLNode &after = ar->get_state();
3787 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3792 Editor::set_fade_out_active (bool yn)
3794 begin_reversible_command (_("set fade out active"));
3796 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3797 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
3803 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
3805 XMLNode &before = ar->get_state();
3807 ar->set_fade_out_active (yn);
3809 XMLNode &after = ar->get_state();
3810 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
3815 /** Update crossfade visibility after its configuration has been changed */
3817 Editor::update_xfade_visibility ()
3819 _xfade_visibility = Config->get_xfades_visible ();
3821 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3822 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
3824 if (_xfade_visibility) {
3825 v->show_all_xfades ();
3827 v->hide_all_xfades ();