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.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/stateful_diff_command.h"
37 #include <gtkmm2ext/utils.h>
38 #include <gtkmm2ext/choice.h>
39 #include <gtkmm2ext/popup.h>
41 #include "ardour/audioengine.h"
42 #include "ardour/session.h"
43 #include "ardour/audioplaylist.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/audio_diskstream.h"
46 #include "ardour/utils.h"
47 #include "ardour/location.h"
48 #include "ardour/audio_track.h"
49 #include "ardour/audioplaylist.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/transient_detector.h"
54 #include "ardour/dB.h"
55 #include "ardour/quantize.h"
56 #include "ardour/strip_silence.h"
57 #include "ardour/route_group.h"
59 #include "ardour_ui.h"
61 #include "time_axis_view.h"
62 #include "route_time_axis.h"
63 #include "audio_time_axis.h"
64 #include "automation_time_axis.h"
65 #include "streamview.h"
66 #include "audio_streamview.h"
67 #include "audio_region_view.h"
68 #include "midi_region_view.h"
69 #include "rgb_macros.h"
70 #include "selection_templates.h"
71 #include "selection.h"
73 #include "gtk-custom-hruler.h"
74 #include "gui_thread.h"
77 #include "editor_drag.h"
78 #include "strip_silence_dialog.h"
79 #include "editor_routes.h"
80 #include "editor_regions.h"
81 #include "quantize_dialog.h"
82 #include "interthread_progress_window.h"
87 using namespace ARDOUR
;
90 using namespace Gtkmm2ext
;
91 using namespace Editing
;
92 using Gtkmm2ext::Keyboard
;
94 /***********************************************************************
96 ***********************************************************************/
99 Editor::undo (uint32_t n
)
107 Editor::redo (uint32_t n
)
115 Editor::split_regions_at (nframes64_t where
, RegionSelection
& regions
)
117 list
<boost::shared_ptr
<Playlist
> > used_playlists
;
119 if (regions
.empty()) {
123 begin_reversible_command (_("split"));
125 // if splitting a single region, and snap-to is using
126 // region boundaries, don't pay attention to them
128 if (regions
.size() == 1) {
129 switch (_snap_type
) {
130 case SnapToRegionStart
:
131 case SnapToRegionSync
:
132 case SnapToRegionEnd
:
141 for (RegionSelection::iterator a
= regions
.begin(); a
!= regions
.end(); ) {
143 RegionSelection::iterator tmp
;
145 /* XXX this test needs to be more complicated, to make sure we really
146 have something to split.
149 if (!(*a
)->region()->covers (where
)) {
157 boost::shared_ptr
<Playlist
> pl
= (*a
)->region()->playlist();
160 cerr
<< "region " << (*a
)->region()->name() << " has no playlist!\n";
166 /* we haven't seen this playlist before */
168 /* remember used playlists so we can thaw them later */
169 used_playlists
.push_back(pl
);
174 pl
->clear_history ();
175 pl
->split_region ((*a
)->region(), where
);
176 _session
->add_command (new StatefulDiffCommand (pl
));
182 while (used_playlists
.size() > 0) {
183 list
<boost::shared_ptr
<Playlist
> >::iterator i
= used_playlists
.begin();
185 used_playlists
.pop_front();
188 commit_reversible_command ();
191 boost::shared_ptr
<Region
>
192 Editor::select_region_for_operation (int /*dir*/, TimeAxisView
**tv
)
195 boost::shared_ptr
<Region
> region
;
196 nframes64_t start
= 0;
198 if (selection
->time
.start () == selection
->time
.end_frame ()) {
200 /* no current selection-> is there a selected regionview? */
202 if (selection
->regions
.empty()) {
208 if (!selection
->regions
.empty()) {
210 rv
= *(selection
->regions
.begin());
211 (*tv
) = &rv
->get_time_axis_view();
212 region
= rv
->region();
214 } else if (!selection
->tracks
.empty()) {
216 (*tv
) = selection
->tracks
.front();
218 RouteTimeAxisView
* rtv
;
220 if ((rtv
= dynamic_cast<RouteTimeAxisView
*> (*tv
)) != 0) {
221 boost::shared_ptr
<Playlist
> pl
;
223 if ((pl
= rtv
->playlist()) == 0) {
227 region
= pl
->top_region_at (start
);
235 Editor::extend_selection_to_end_of_region (bool next
)
238 boost::shared_ptr
<Region
> region
;
241 if ((region
= select_region_for_operation (next
? 1 : 0, &tv
)) == 0) {
245 if (region
&& selection
->time
.start () == selection
->time
.end_frame ()) {
246 start
= region
->position();
248 start
= selection
->time
.start ();
251 begin_reversible_command (_("extend selection"));
252 selection
->set (start
, region
->position() + region
->length());
253 commit_reversible_command ();
257 Editor::extend_selection_to_start_of_region (bool previous
)
260 boost::shared_ptr
<Region
> region
;
263 if ((region
= select_region_for_operation (previous
? -1 : 0, &tv
)) == 0) {
267 if (region
&& selection
->time
.start () == selection
->time
.end_frame ()) {
268 end
= region
->position() + region
->length();
270 end
= selection
->time
.end_frame ();
273 /* Try to leave the selection with the same route if possible */
275 begin_reversible_command (_("extend selection"));
276 selection
->set (region
->position(), end
);
277 commit_reversible_command ();
281 Editor::nudge_forward_release (GdkEventButton
* ev
)
283 if (ev
->state
& Keyboard::PrimaryModifier
) {
284 nudge_forward (false, true);
286 nudge_forward (false, false);
292 Editor::nudge_backward_release (GdkEventButton
* ev
)
294 if (ev
->state
& Keyboard::PrimaryModifier
) {
295 nudge_backward (false, true);
297 nudge_backward (false, false);
304 Editor::nudge_forward (bool next
, bool force_playhead
)
306 nframes64_t distance
;
307 nframes64_t next_distance
;
310 get_regions_for_action (rs
);
312 if (!_session
) return;
314 if (!force_playhead
&& !rs
.empty()) {
316 begin_reversible_command (_("nudge regions forward"));
318 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
319 boost::shared_ptr
<Region
> r ((*i
)->region());
321 distance
= get_nudge_distance (r
->position(), next_distance
);
324 distance
= next_distance
;
328 r
->set_position (r
->position() + distance
, this);
329 _session
->add_command (new StatefulDiffCommand (r
));
332 commit_reversible_command ();
335 } else if (!force_playhead
&& !selection
->markers
.empty()) {
339 begin_reversible_command (_("nudge location forward"));
341 for (MarkerSelection::iterator i
= selection
->markers
.begin(); i
!= selection
->markers
.end(); ++i
) {
343 Location
* loc
= find_location_from_marker ((*i
), is_start
);
347 XMLNode
& before (loc
->get_state());
350 distance
= get_nudge_distance (loc
->start(), next_distance
);
352 distance
= next_distance
;
354 if (max_frames
- distance
> loc
->start() + loc
->length()) {
355 loc
->set_start (loc
->start() + distance
);
357 loc
->set_start (max_frames
- loc
->length());
360 distance
= get_nudge_distance (loc
->end(), next_distance
);
362 distance
= next_distance
;
364 if (max_frames
- distance
> loc
->end()) {
365 loc
->set_end (loc
->end() + distance
);
367 loc
->set_end (max_frames
);
370 XMLNode
& after (loc
->get_state());
371 _session
->add_command (new MementoCommand
<Location
>(*loc
, &before
, &after
));
375 commit_reversible_command ();
378 distance
= get_nudge_distance (playhead_cursor
->current_frame
, next_distance
);
379 _session
->request_locate (playhead_cursor
->current_frame
+ distance
);
384 Editor::nudge_backward (bool next
, bool force_playhead
)
386 nframes64_t distance
;
387 nframes64_t next_distance
;
390 get_regions_for_action (rs
);
392 if (!_session
) return;
394 if (!force_playhead
&& !rs
.empty()) {
396 begin_reversible_command (_("nudge regions backward"));
398 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
399 boost::shared_ptr
<Region
> r ((*i
)->region());
401 distance
= get_nudge_distance (r
->position(), next_distance
);
404 distance
= next_distance
;
409 if (r
->position() > distance
) {
410 r
->set_position (r
->position() - distance
, this);
412 r
->set_position (0, this);
414 _session
->add_command (new StatefulDiffCommand (r
));
417 commit_reversible_command ();
419 } else if (!force_playhead
&& !selection
->markers
.empty()) {
423 begin_reversible_command (_("nudge location forward"));
425 for (MarkerSelection::iterator i
= selection
->markers
.begin(); i
!= selection
->markers
.end(); ++i
) {
427 Location
* loc
= find_location_from_marker ((*i
), is_start
);
431 XMLNode
& before (loc
->get_state());
434 distance
= get_nudge_distance (loc
->start(), next_distance
);
436 distance
= next_distance
;
438 if (distance
< loc
->start()) {
439 loc
->set_start (loc
->start() - distance
);
444 distance
= get_nudge_distance (loc
->end(), next_distance
);
447 distance
= next_distance
;
450 if (distance
< loc
->end() - loc
->length()) {
451 loc
->set_end (loc
->end() - distance
);
453 loc
->set_end (loc
->length());
457 XMLNode
& after (loc
->get_state());
458 _session
->add_command (new MementoCommand
<Location
>(*loc
, &before
, &after
));
462 commit_reversible_command ();
466 distance
= get_nudge_distance (playhead_cursor
->current_frame
, next_distance
);
468 if (playhead_cursor
->current_frame
> distance
) {
469 _session
->request_locate (playhead_cursor
->current_frame
- distance
);
471 _session
->goto_start();
477 Editor::nudge_forward_capture_offset ()
479 nframes64_t distance
;
482 get_regions_for_action (rs
);
484 if (!_session
) return;
488 begin_reversible_command (_("nudge forward"));
490 distance
= _session
->worst_output_latency();
492 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
493 boost::shared_ptr
<Region
> r ((*i
)->region());
496 r
->set_position (r
->position() + distance
, this);
497 _session
->add_command(new StatefulDiffCommand (r
));
500 commit_reversible_command ();
506 Editor::nudge_backward_capture_offset ()
508 nframes64_t distance
;
511 get_regions_for_action (rs
);
513 if (!_session
) return;
517 begin_reversible_command (_("nudge forward"));
519 distance
= _session
->worst_output_latency();
521 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
522 boost::shared_ptr
<Region
> r ((*i
)->region());
526 if (r
->position() > distance
) {
527 r
->set_position (r
->position() - distance
, this);
529 r
->set_position (0, this);
531 _session
->add_command(new StatefulDiffCommand (r
));
534 commit_reversible_command ();
541 Editor::move_to_start ()
543 _session
->goto_start ();
547 Editor::move_to_end ()
550 _session
->request_locate (_session
->current_end_frame());
554 Editor::build_region_boundary_cache ()
557 vector
<RegionPoint
> interesting_points
;
558 boost::shared_ptr
<Region
> r
;
559 TrackViewList tracks
;
562 region_boundary_cache
.clear ();
568 switch (_snap_type
) {
569 case SnapToRegionStart
:
570 interesting_points
.push_back (Start
);
572 case SnapToRegionEnd
:
573 interesting_points
.push_back (End
);
575 case SnapToRegionSync
:
576 interesting_points
.push_back (SyncPoint
);
578 case SnapToRegionBoundary
:
579 interesting_points
.push_back (Start
);
580 interesting_points
.push_back (End
);
583 fatal
<< string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type
) << endmsg
;
588 TimeAxisView
*ontrack
= 0;
591 if (!selection
->tracks
.empty()) {
592 tlist
= selection
->tracks
;
597 while (pos
< _session
->current_end_frame() && !at_end
) {
600 nframes64_t lpos
= max_frames
;
602 for (vector
<RegionPoint
>::iterator p
= interesting_points
.begin(); p
!= interesting_points
.end(); ++p
) {
604 if ((r
= find_next_region (pos
, *p
, 1, tlist
, &ontrack
)) == 0) {
605 if (*p
== interesting_points
.back()) {
608 /* move to next point type */
614 rpos
= r
->first_frame();
618 rpos
= r
->last_frame();
622 rpos
= r
->sync_position ();
623 //r->adjust_to_sync (r->first_frame());
631 RouteTimeAxisView
*rtav
;
633 if (ontrack
!= 0 && (rtav
= dynamic_cast<RouteTimeAxisView
*>(ontrack
)) != 0 ) {
634 if (rtav
->track() != 0) {
635 speed
= rtav
->track()->speed();
639 rpos
= track_frame_to_session_frame (rpos
, speed
);
645 /* prevent duplicates, but we don't use set<> because we want to be able
649 vector
<nframes64_t
>::iterator ri
;
651 for (ri
= region_boundary_cache
.begin(); ri
!= region_boundary_cache
.end(); ++ri
) {
657 if (ri
== region_boundary_cache
.end()) {
658 region_boundary_cache
.push_back (rpos
);
665 /* finally sort to be sure that the order is correct */
667 sort (region_boundary_cache
.begin(), region_boundary_cache
.end());
670 boost::shared_ptr
<Region
>
671 Editor::find_next_region (nframes64_t frame
, RegionPoint point
, int32_t dir
, TrackViewList
& tracks
, TimeAxisView
**ontrack
)
673 TrackViewList::iterator i
;
674 nframes64_t closest
= max_frames
;
675 boost::shared_ptr
<Region
> ret
;
676 nframes64_t rpos
= 0;
679 nframes64_t track_frame
;
680 RouteTimeAxisView
*rtav
;
682 for (i
= tracks
.begin(); i
!= tracks
.end(); ++i
) {
684 nframes64_t distance
;
685 boost::shared_ptr
<Region
> r
;
688 if ( (rtav
= dynamic_cast<RouteTimeAxisView
*>(*i
)) != 0 ) {
689 if (rtav
->track()!=0)
690 track_speed
= rtav
->track()->speed();
693 track_frame
= session_frame_to_track_frame(frame
, track_speed
);
695 if ((r
= (*i
)->find_next_region (track_frame
, point
, dir
)) == 0) {
701 rpos
= r
->first_frame ();
705 rpos
= r
->last_frame ();
709 rpos
= r
->sync_position ();
710 // r->adjust_to_sync (r->first_frame());
714 // rpos is a "track frame", converting it to "_session frame"
715 rpos
= track_frame_to_session_frame(rpos
, track_speed
);
718 distance
= rpos
- frame
;
720 distance
= frame
- rpos
;
723 if (distance
< closest
) {
735 Editor::find_next_region_boundary (nframes64_t pos
, int32_t dir
, const TrackViewList
& tracks
)
737 nframes64_t distance
= max_frames
;
738 nframes64_t current_nearest
= -1;
741 for (TrackViewList::const_iterator i
= tracks
.begin(); i
!= tracks
.end(); ++i
) {
742 nframes64_t contender
;
745 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (*i
);
751 if ((contender
= rtv
->find_next_region_boundary (pos
, dir
)) < 0) {
755 d
= ::llabs (pos
- contender
);
758 current_nearest
= contender
;
763 return current_nearest
;
767 Editor::get_region_boundary (nframes64_t pos
, int32_t dir
, bool with_selection
, bool only_onscreen
)
772 if (with_selection
&& Config
->get_region_boundaries_from_selected_tracks()) {
774 if (!selection
->tracks
.empty()) {
776 target
= find_next_region_boundary (pos
, dir
, selection
->tracks
);
780 if (only_onscreen
|| Config
->get_region_boundaries_from_onscreen_tracks()) {
781 get_onscreen_tracks (tvl
);
782 target
= find_next_region_boundary (pos
, dir
, tvl
);
784 target
= find_next_region_boundary (pos
, dir
, track_views
);
790 if (only_onscreen
|| Config
->get_region_boundaries_from_onscreen_tracks()) {
791 get_onscreen_tracks (tvl
);
792 target
= find_next_region_boundary (pos
, dir
, tvl
);
794 target
= find_next_region_boundary (pos
, dir
, track_views
);
802 Editor::cursor_to_region_boundary (bool with_selection
, int32_t dir
)
804 nframes64_t pos
= playhead_cursor
->current_frame
;
811 // so we don't find the current region again..
812 if (dir
> 0 || pos
> 0) {
816 if ((target
= get_region_boundary (pos
, dir
, with_selection
, false)) < 0) {
820 _session
->request_locate (target
);
824 Editor::cursor_to_next_region_boundary (bool with_selection
)
826 cursor_to_region_boundary (with_selection
, 1);
830 Editor::cursor_to_previous_region_boundary (bool with_selection
)
832 cursor_to_region_boundary (with_selection
, -1);
836 Editor::cursor_to_region_point (EditorCursor
* cursor
, RegionPoint point
, int32_t dir
)
838 boost::shared_ptr
<Region
> r
;
839 nframes64_t pos
= cursor
->current_frame
;
845 TimeAxisView
*ontrack
= 0;
847 // so we don't find the current region again..
851 if (!selection
->tracks
.empty()) {
853 r
= find_next_region (pos
, point
, dir
, selection
->tracks
, &ontrack
);
855 } else if (clicked_axisview
) {
858 t
.push_back (clicked_axisview
);
860 r
= find_next_region (pos
, point
, dir
, t
, &ontrack
);
864 r
= find_next_region (pos
, point
, dir
, track_views
, &ontrack
);
873 pos
= r
->first_frame ();
877 pos
= r
->last_frame ();
881 pos
= r
->sync_position ();
882 // r->adjust_to_sync (r->first_frame());
887 RouteTimeAxisView
*rtav
;
889 if ( ontrack
!= 0 && (rtav
= dynamic_cast<RouteTimeAxisView
*>(ontrack
)) != 0 ) {
890 if (rtav
->track() != 0) {
891 speed
= rtav
->track()->speed();
895 pos
= track_frame_to_session_frame(pos
, speed
);
897 if (cursor
== playhead_cursor
) {
898 _session
->request_locate (pos
);
900 cursor
->set_position (pos
);
905 Editor::cursor_to_next_region_point (EditorCursor
* cursor
, RegionPoint point
)
907 cursor_to_region_point (cursor
, point
, 1);
911 Editor::cursor_to_previous_region_point (EditorCursor
* cursor
, RegionPoint point
)
913 cursor_to_region_point (cursor
, point
, -1);
917 Editor::cursor_to_selection_start (EditorCursor
*cursor
)
922 get_regions_for_action (rs
);
924 switch (mouse_mode
) {
932 if (!selection
->time
.empty()) {
933 pos
= selection
->time
.start ();
941 if (cursor
== playhead_cursor
) {
942 _session
->request_locate (pos
);
944 cursor
->set_position (pos
);
949 Editor::cursor_to_selection_end (EditorCursor
*cursor
)
954 get_regions_for_action (rs
);
956 switch (mouse_mode
) {
959 pos
= rs
.end_frame();
964 if (!selection
->time
.empty()) {
965 pos
= selection
->time
.end_frame ();
973 if (cursor
== playhead_cursor
) {
974 _session
->request_locate (pos
);
976 cursor
->set_position (pos
);
981 Editor::selected_marker_to_region_boundary (bool with_selection
, int32_t dir
)
991 if (selection
->markers
.empty()) {
995 if (!mouse_frame (mouse
, ignored
)) {
999 add_location_mark (mouse
);
1002 if ((loc
= find_location_from_marker (selection
->markers
.front(), ignored
)) == 0) {
1006 nframes64_t pos
= loc
->start();
1008 // so we don't find the current region again..
1009 if (dir
> 0 || pos
> 0) {
1013 if ((target
= get_region_boundary (pos
, dir
, with_selection
, false)) < 0) {
1017 loc
->move_to (target
);
1021 Editor::selected_marker_to_next_region_boundary (bool with_selection
)
1023 selected_marker_to_region_boundary (with_selection
, 1);
1027 Editor::selected_marker_to_previous_region_boundary (bool with_selection
)
1029 selected_marker_to_region_boundary (with_selection
, -1);
1033 Editor::selected_marker_to_region_point (RegionPoint point
, int32_t dir
)
1035 boost::shared_ptr
<Region
> r
;
1040 if (!_session
|| selection
->markers
.empty()) {
1044 if ((loc
= find_location_from_marker (selection
->markers
.front(), ignored
)) == 0) {
1048 TimeAxisView
*ontrack
= 0;
1052 // so we don't find the current region again..
1056 if (!selection
->tracks
.empty()) {
1058 r
= find_next_region (pos
, point
, dir
, selection
->tracks
, &ontrack
);
1062 r
= find_next_region (pos
, point
, dir
, track_views
, &ontrack
);
1071 pos
= r
->first_frame ();
1075 pos
= r
->last_frame ();
1079 pos
= r
->adjust_to_sync (r
->first_frame());
1084 RouteTimeAxisView
*rtav
;
1086 if (ontrack
!= 0 && (rtav
= dynamic_cast<RouteTimeAxisView
*>(ontrack
)) != 0) {
1087 if (rtav
->track() != 0) {
1088 speed
= rtav
->track()->speed();
1092 pos
= track_frame_to_session_frame(pos
, speed
);
1098 Editor::selected_marker_to_next_region_point (RegionPoint point
)
1100 selected_marker_to_region_point (point
, 1);
1104 Editor::selected_marker_to_previous_region_point (RegionPoint point
)
1106 selected_marker_to_region_point (point
, -1);
1110 Editor::selected_marker_to_selection_start ()
1112 nframes64_t pos
= 0;
1116 if (!_session
|| selection
->markers
.empty()) {
1120 if ((loc
= find_location_from_marker (selection
->markers
.front(), ignored
)) == 0) {
1126 get_regions_for_action (rs
);
1128 switch (mouse_mode
) {
1136 if (!selection
->time
.empty()) {
1137 pos
= selection
->time
.start ();
1149 Editor::selected_marker_to_selection_end ()
1151 nframes64_t pos
= 0;
1155 if (!_session
|| selection
->markers
.empty()) {
1159 if ((loc
= find_location_from_marker (selection
->markers
.front(), ignored
)) == 0) {
1165 get_regions_for_action (rs
);
1167 switch (mouse_mode
) {
1170 pos
= rs
.end_frame();
1175 if (!selection
->time
.empty()) {
1176 pos
= selection
->time
.end_frame ();
1188 Editor::scroll_playhead (bool forward
)
1190 nframes64_t pos
= playhead_cursor
->current_frame
;
1191 nframes64_t delta
= (nframes64_t
) floor (current_page_frames() / 0.8);
1194 if (pos
== max_frames
) {
1198 if (pos
< max_frames
- delta
) {
1217 _session
->request_locate (pos
);
1221 Editor::playhead_backward ()
1228 if (get_prefix (prefix
, was_floating
)) {
1232 cnt
= (nframes64_t
) floor (prefix
* _session
->frame_rate ());
1234 cnt
= (nframes64_t
) prefix
;
1238 pos
= playhead_cursor
->current_frame
;
1240 if ((nframes64_t
) pos
< cnt
) {
1246 /* XXX this is completely insane. with the current buffering
1247 design, we'll force a complete track buffer flush and
1248 reload, just to move 1 sample !!!
1251 _session
->request_locate (pos
);
1255 Editor::playhead_forward ()
1262 if (get_prefix (prefix
, was_floating
)) {
1266 cnt
= (nframes64_t
) floor (prefix
* _session
->frame_rate ());
1268 cnt
= (nframes64_t
) floor (prefix
);
1272 pos
= playhead_cursor
->current_frame
;
1274 /* XXX this is completely insane. with the current buffering
1275 design, we'll force a complete track buffer flush and
1276 reload, just to move 1 sample !!!
1279 _session
->request_locate (pos
+cnt
);
1283 Editor::cursor_align (bool playhead_to_edit
)
1289 if (playhead_to_edit
) {
1291 if (selection
->markers
.empty()) {
1295 _session
->request_locate (selection
->markers
.front()->position(), _session
->transport_rolling());
1298 /* move selected markers to playhead */
1300 for (MarkerSelection::iterator i
= selection
->markers
.begin(); i
!= selection
->markers
.end(); ++i
) {
1303 Location
* loc
= find_location_from_marker (*i
, ignored
);
1305 if (loc
->is_mark()) {
1306 loc
->set_start (playhead_cursor
->current_frame
);
1308 loc
->set (playhead_cursor
->current_frame
,
1309 playhead_cursor
->current_frame
+ loc
->length());
1316 Editor::edit_cursor_backward ()
1323 if (get_prefix (prefix
, was_floating
)) {
1327 cnt
= (nframes64_t
) floor (prefix
* _session
->frame_rate ());
1329 cnt
= (nframes64_t
) prefix
;
1333 if ((pos
= get_preferred_edit_position()) < 0) {
1343 // EDIT CURSOR edit_cursor->set_position (pos);
1347 Editor::edit_cursor_forward ()
1354 if (get_prefix (prefix
, was_floating
)) {
1358 cnt
= (nframes64_t
) floor (prefix
* _session
->frame_rate ());
1360 cnt
= (nframes64_t
) floor (prefix
);
1364 // pos = edit_cursor->current_frame;
1365 // EDIT CURSOR edit_cursor->set_position (pos+cnt);
1369 Editor::goto_frame ()
1375 if (get_prefix (prefix
, was_floating
)) {
1380 frame
= (nframes64_t
) floor (prefix
* _session
->frame_rate());
1382 frame
= (nframes64_t
) floor (prefix
);
1385 _session
->request_locate (frame
);
1389 Editor::scroll_backward (float pages
)
1392 nframes64_t one_page
= (nframes64_t
) rint (_canvas_width
* frames_per_unit
);
1397 if (get_prefix (prefix
, was_floating
)) {
1398 cnt
= (nframes64_t
) floor (pages
* one_page
);
1401 cnt
= (nframes64_t
) floor (prefix
* _session
->frame_rate());
1403 cnt
= (nframes64_t
) floor (prefix
* one_page
);
1407 if (leftmost_frame
< cnt
) {
1410 frame
= leftmost_frame
- cnt
;
1413 reset_x_origin (frame
);
1417 Editor::scroll_forward (float pages
)
1420 nframes64_t one_page
= (nframes64_t
) rint (_canvas_width
* frames_per_unit
);
1425 if (get_prefix (prefix
, was_floating
)) {
1426 cnt
= (nframes64_t
) floor (pages
* one_page
);
1429 cnt
= (nframes64_t
) floor (prefix
* _session
->frame_rate());
1431 cnt
= (nframes64_t
) floor (prefix
* one_page
);
1435 if (max_frames
- cnt
< leftmost_frame
) {
1436 frame
= max_frames
- cnt
;
1438 frame
= leftmost_frame
+ cnt
;
1441 reset_x_origin (frame
);
1445 Editor::scroll_tracks_down ()
1451 if (get_prefix (prefix
, was_floating
)) {
1454 cnt
= (int) floor (prefix
);
1457 double vert_value
= vertical_adjustment
.get_value() + (cnt
*
1458 vertical_adjustment
.get_page_size());
1459 if (vert_value
> vertical_adjustment
.get_upper() - _canvas_height
) {
1460 vert_value
= vertical_adjustment
.get_upper() - _canvas_height
;
1462 vertical_adjustment
.set_value (vert_value
);
1466 Editor::scroll_tracks_up ()
1472 if (get_prefix (prefix
, was_floating
)) {
1475 cnt
= (int) floor (prefix
);
1478 vertical_adjustment
.set_value (vertical_adjustment
.get_value() - (cnt
* vertical_adjustment
.get_page_size()));
1482 Editor::scroll_tracks_down_line ()
1484 double vert_value
= vertical_adjustment
.get_value() + 60;
1486 if (vert_value
> vertical_adjustment
.get_upper() - _canvas_height
) {
1487 vert_value
= vertical_adjustment
.get_upper() - _canvas_height
;
1490 vertical_adjustment
.set_value (vert_value
);
1494 Editor::scroll_tracks_up_line ()
1496 reset_y_origin (vertical_adjustment
.get_value() - 60);
1502 Editor::tav_zoom_step (bool coarser
)
1504 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step
, coarser
)
1506 _routes
->suspend_redisplay ();
1508 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
1509 TimeAxisView
*tv
= (static_cast<TimeAxisView
*>(*i
));
1510 tv
->step_height (coarser
);
1513 _routes
->resume_redisplay ();
1517 Editor::temporal_zoom_step (bool coarser
)
1519 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step
, coarser
)
1523 nfpu
= frames_per_unit
;
1528 nfpu
= max(1.0,(nfpu
/1.61803399));
1531 temporal_zoom (nfpu
);
1535 Editor::temporal_zoom (gdouble fpu
)
1537 if (!_session
) return;
1539 nframes64_t current_page
= current_page_frames();
1540 nframes64_t current_leftmost
= leftmost_frame
;
1541 nframes64_t current_rightmost
;
1542 nframes64_t current_center
;
1543 nframes64_t new_page_size
;
1544 nframes64_t half_page_size
;
1545 nframes64_t leftmost_after_zoom
= 0;
1547 bool in_track_canvas
;
1551 /* XXX this limit is also in ::set_frames_per_unit() */
1553 if (frames_per_unit
<= 1.0 && fpu
<= frames_per_unit
) {
1559 new_page_size
= (nframes64_t
) floor (_canvas_width
* nfpu
);
1560 half_page_size
= new_page_size
/ 2;
1562 switch (zoom_focus
) {
1564 leftmost_after_zoom
= current_leftmost
;
1567 case ZoomFocusRight
:
1568 current_rightmost
= leftmost_frame
+ current_page
;
1569 if (current_rightmost
< new_page_size
) {
1570 leftmost_after_zoom
= 0;
1572 leftmost_after_zoom
= current_rightmost
- new_page_size
;
1576 case ZoomFocusCenter
:
1577 current_center
= current_leftmost
+ (current_page
/2);
1578 if (current_center
< half_page_size
) {
1579 leftmost_after_zoom
= 0;
1581 leftmost_after_zoom
= current_center
- half_page_size
;
1585 case ZoomFocusPlayhead
:
1586 /* centre playhead */
1587 l
= playhead_cursor
->current_frame
- (new_page_size
* 0.5);
1590 leftmost_after_zoom
= 0;
1591 } else if (l
> max_frames
) {
1592 leftmost_after_zoom
= max_frames
- new_page_size
;
1594 leftmost_after_zoom
= (nframes64_t
) l
;
1598 case ZoomFocusMouse
:
1599 /* try to keep the mouse over the same point in the display */
1601 if (!mouse_frame (where
, in_track_canvas
)) {
1602 /* use playhead instead */
1603 where
= playhead_cursor
->current_frame
;
1605 if (where
< half_page_size
) {
1606 leftmost_after_zoom
= 0;
1608 leftmost_after_zoom
= where
- half_page_size
;
1613 l
= - ((new_page_size
* ((where
- current_leftmost
)/(double)current_page
)) - where
);
1616 leftmost_after_zoom
= 0;
1617 } else if (l
> max_frames
) {
1618 leftmost_after_zoom
= max_frames
- new_page_size
;
1620 leftmost_after_zoom
= (nframes64_t
) l
;
1627 /* try to keep the edit point in the same place */
1628 where
= get_preferred_edit_position ();
1632 double l
= - ((new_page_size
* ((where
- current_leftmost
)/(double)current_page
)) - where
);
1635 leftmost_after_zoom
= 0;
1636 } else if (l
> max_frames
) {
1637 leftmost_after_zoom
= max_frames
- new_page_size
;
1639 leftmost_after_zoom
= (nframes64_t
) l
;
1643 /* edit point not defined */
1650 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1652 reposition_and_zoom (leftmost_after_zoom
, nfpu
);
1656 Editor::temporal_zoom_region (bool both_axes
)
1659 nframes64_t start
= max_frames
;
1660 nframes64_t end
= 0;
1662 set
<TimeAxisView
*> tracks
;
1664 get_regions_for_action (rs
);
1670 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
1672 if ((*i
)->region()->position() < start
) {
1673 start
= (*i
)->region()->position();
1676 if ((*i
)->region()->last_frame() + 1 > end
) {
1677 end
= (*i
)->region()->last_frame() + 1;
1680 tracks
.insert (&((*i
)->get_time_axis_view()));
1683 /* now comes an "interesting" hack ... make sure we leave a little space
1684 at each end of the editor so that the zoom doesn't fit the region
1685 precisely to the screen.
1688 GdkScreen
* screen
= gdk_screen_get_default ();
1689 gint pixwidth
= gdk_screen_get_width (screen
);
1690 gint mmwidth
= gdk_screen_get_width_mm (screen
);
1691 double pix_per_mm
= (double) pixwidth
/ (double) mmwidth
;
1692 double one_centimeter_in_pixels
= pix_per_mm
* 10.0;
1694 if ((start
== 0 && end
== 0) || end
< start
) {
1698 nframes64_t range
= end
- start
;
1699 double new_fpu
= (double)range
/ (double)_canvas_width
;
1700 nframes64_t extra_samples
= (nframes64_t
) floor (one_centimeter_in_pixels
* new_fpu
);
1702 if (start
> extra_samples
) {
1703 start
-= extra_samples
;
1708 if (max_frames
- extra_samples
> end
) {
1709 end
+= extra_samples
;
1715 /* save visual state with track states included, and prevent
1716 set_frames_per_unit() from doing it again.
1718 undo_visual_stack
.push_back (current_visual_state(true));
1719 no_save_visual
= true;
1722 temporal_zoom_by_frame (start
, end
, "zoom to region");
1725 uint32_t per_track_height
= (uint32_t) floor ((_canvas_height
- canvas_timebars_vsize
- 10.0) / tracks
.size());
1727 /* set visible track heights appropriately */
1729 for (set
<TimeAxisView
*>::iterator t
= tracks
.begin(); t
!= tracks
.end(); ++t
) {
1730 (*t
)->set_height (per_track_height
);
1733 /* hide irrelevant tracks */
1735 _routes
->suspend_redisplay ();
1737 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
1738 if (find (tracks
.begin(), tracks
.end(), (*i
)) == tracks
.end()) {
1739 hide_track_in_display (*i
, true);
1743 _routes
->resume_redisplay ();
1745 vertical_adjustment
.set_value (0.0);
1746 no_save_visual
= false;
1749 redo_visual_stack
.push_back (current_visual_state());
1753 Editor::zoom_to_region (bool both_axes
)
1755 temporal_zoom_region (both_axes
);
1759 Editor::temporal_zoom_selection ()
1761 if (!selection
) return;
1763 if (selection
->time
.empty()) {
1767 nframes64_t start
= selection
->time
[clicked_selection
].start
;
1768 nframes64_t end
= selection
->time
[clicked_selection
].end
;
1770 temporal_zoom_by_frame (start
, end
, "zoom to selection");
1774 Editor::temporal_zoom_session ()
1776 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session
)
1779 nframes_t
const l
= _session
->current_end_frame() - _session
->current_start_frame();
1780 double s
= _session
->current_start_frame() - l
* 0.01;
1784 nframes_t
const e
= _session
->current_end_frame() + l
* 0.01;
1785 temporal_zoom_by_frame (nframes_t (s
), e
, "zoom to _session");
1790 Editor::temporal_zoom_by_frame (nframes64_t start
, nframes64_t end
, const string
& /*op*/)
1792 if (!_session
) return;
1794 if ((start
== 0 && end
== 0) || end
< start
) {
1798 nframes64_t range
= end
- start
;
1800 double new_fpu
= (double)range
/ (double)_canvas_width
;
1802 nframes64_t new_page
= (nframes64_t
) floor (_canvas_width
* new_fpu
);
1803 nframes64_t middle
= (nframes64_t
) floor( (double)start
+ ((double)range
/ 2.0f
));
1804 nframes64_t new_leftmost
= (nframes64_t
) floor( (double)middle
- ((double)new_page
/2.0f
));
1806 if (new_leftmost
> middle
) {
1810 reposition_and_zoom (new_leftmost
, new_fpu
);
1814 Editor::temporal_zoom_to_frame (bool coarser
, nframes64_t frame
)
1819 double range_before
= frame
- leftmost_frame
;
1822 new_fpu
= frames_per_unit
;
1825 new_fpu
*= 1.61803399;
1826 range_before
*= 1.61803399;
1828 new_fpu
= max(1.0,(new_fpu
/1.61803399));
1829 range_before
/= 1.61803399;
1832 if (new_fpu
== frames_per_unit
) {
1836 nframes64_t new_leftmost
= frame
- (nframes64_t
)range_before
;
1838 if (new_leftmost
> frame
) {
1841 // begin_reversible_command (_("zoom to frame"));
1842 // _session->add_undo (sigc::bind (sigc::mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1843 // _session->add_redo (sigc::bind (sigc::mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1844 // commit_reversible_command ();
1846 reposition_and_zoom (new_leftmost
, new_fpu
);
1851 Editor::choose_new_marker_name(string
&name
) {
1853 if (!Config
->get_name_new_markers()) {
1854 /* don't prompt user for a new name */
1858 ArdourPrompter
dialog (true);
1860 dialog
.set_prompt (_("New Name:"));
1862 dialog
.set_title (_("New Location Marker"));
1864 dialog
.set_name ("MarkNameWindow");
1865 dialog
.set_size_request (250, -1);
1866 dialog
.set_position (Gtk::WIN_POS_MOUSE
);
1868 dialog
.add_button (Stock::OK
, RESPONSE_ACCEPT
);
1869 dialog
.set_initial_text (name
);
1873 switch (dialog
.run ()) {
1874 case RESPONSE_ACCEPT
:
1880 dialog
.get_result(name
);
1887 Editor::add_location_from_selection ()
1891 if (selection
->time
.empty()) {
1895 if (_session
== 0 || clicked_axisview
== 0) {
1899 nframes64_t start
= selection
->time
[clicked_selection
].start
;
1900 nframes64_t end
= selection
->time
[clicked_selection
].end
;
1902 _session
->locations()->next_available_name(rangename
,"selection");
1903 Location
*location
= new Location (start
, end
, rangename
, Location::IsRangeMarker
);
1905 _session
->begin_reversible_command (_("add marker"));
1906 XMLNode
&before
= _session
->locations()->get_state();
1907 _session
->locations()->add (location
, true);
1908 XMLNode
&after
= _session
->locations()->get_state();
1909 _session
->add_command(new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
1910 _session
->commit_reversible_command ();
1914 Editor::add_location_mark (nframes64_t where
)
1918 select_new_marker
= true;
1920 _session
->locations()->next_available_name(markername
,"mark");
1921 if (!choose_new_marker_name(markername
)) {
1924 Location
*location
= new Location (where
, where
, markername
, Location::IsMark
);
1925 _session
->begin_reversible_command (_("add marker"));
1926 XMLNode
&before
= _session
->locations()->get_state();
1927 _session
->locations()->add (location
, true);
1928 XMLNode
&after
= _session
->locations()->get_state();
1929 _session
->add_command(new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
1930 _session
->commit_reversible_command ();
1934 Editor::add_location_from_playhead_cursor ()
1936 add_location_mark (_session
->audible_frame());
1940 Editor::add_locations_from_audio_region ()
1944 get_regions_for_action (rs
);
1950 _session
->begin_reversible_command (rs
.size () > 1 ? _("add markers") : _("add marker"));
1951 XMLNode
&before
= _session
->locations()->get_state();
1953 cerr
<< "Add locations\n";
1955 for (RegionSelection::iterator i
= rs
.begin (); i
!= rs
.end (); ++i
) {
1957 boost::shared_ptr
<Region
> region
= (*i
)->region ();
1959 Location
*location
= new Location (region
->position(), region
->last_frame(), region
->name(), Location::IsRangeMarker
);
1961 _session
->locations()->add (location
, true);
1964 XMLNode
&after
= _session
->locations()->get_state();
1965 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
1966 _session
->commit_reversible_command ();
1970 Editor::add_location_from_audio_region ()
1974 get_regions_for_action (rs
);
1980 _session
->begin_reversible_command (_("add marker"));
1981 XMLNode
&before
= _session
->locations()->get_state();
1985 if (rs
.size() > 1) { // more than one region selected
1986 _session
->locations()->next_available_name(markername
, "regions");
1988 RegionView
* rv
= *(rs
.begin());
1989 boost::shared_ptr
<Region
> region
= rv
->region();
1990 markername
= region
->name();
1993 if (!choose_new_marker_name(markername
)) {
1997 cerr
<< "Add location\n";
1999 // single range spanning all selected
2000 Location
*location
= new Location (rs
.start(), rs
.end_frame(), markername
, Location::IsRangeMarker
);
2001 _session
->locations()->add (location
, true);
2003 XMLNode
&after
= _session
->locations()->get_state();
2004 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
2005 _session
->commit_reversible_command ();
2009 Editor::amplitude_zoom_step (bool in
)
2023 #ifdef FIX_FOR_CANVAS
2024 /* XXX DO SOMETHING */
2033 Editor::delete_sample_forward ()
2038 Editor::delete_sample_backward ()
2043 Editor::delete_screen ()
2050 Editor::search_backwards ()
2056 Editor::search_forwards ()
2064 Editor::jump_forward_to_mark ()
2070 Location
*location
= _session
->locations()->first_location_after (playhead_cursor
->current_frame
);
2073 _session
->request_locate (location
->start(), _session
->transport_rolling());
2075 _session
->request_locate (_session
->current_end_frame());
2080 Editor::jump_backward_to_mark ()
2086 Location
*location
= _session
->locations()->first_location_before (playhead_cursor
->current_frame
);
2089 _session
->request_locate (location
->start(), _session
->transport_rolling());
2091 _session
->goto_start ();
2103 if (get_prefix (prefix
, was_floating
)) {
2104 pos
= _session
->audible_frame ();
2107 pos
= (nframes64_t
) floor (prefix
* _session
->frame_rate ());
2109 pos
= (nframes64_t
) floor (prefix
);
2113 _session
->locations()->next_available_name(markername
,"mark");
2114 if (!choose_new_marker_name(markername
)) {
2117 _session
->locations()->add (new Location (pos
, 0, markername
, Location::IsMark
), true);
2121 Editor::clear_markers ()
2124 _session
->begin_reversible_command (_("clear markers"));
2125 XMLNode
&before
= _session
->locations()->get_state();
2126 _session
->locations()->clear_markers ();
2127 XMLNode
&after
= _session
->locations()->get_state();
2128 _session
->add_command(new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
2129 _session
->commit_reversible_command ();
2134 Editor::clear_ranges ()
2137 _session
->begin_reversible_command (_("clear ranges"));
2138 XMLNode
&before
= _session
->locations()->get_state();
2140 Location
* looploc
= _session
->locations()->auto_loop_location();
2141 Location
* punchloc
= _session
->locations()->auto_punch_location();
2143 _session
->locations()->clear_ranges ();
2145 if (looploc
) _session
->locations()->add (looploc
);
2146 if (punchloc
) _session
->locations()->add (punchloc
);
2148 XMLNode
&after
= _session
->locations()->get_state();
2149 _session
->add_command(new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
2150 _session
->commit_reversible_command ();
2155 Editor::clear_locations ()
2157 _session
->begin_reversible_command (_("clear locations"));
2158 XMLNode
&before
= _session
->locations()->get_state();
2159 _session
->locations()->clear ();
2160 XMLNode
&after
= _session
->locations()->get_state();
2161 _session
->add_command(new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
2162 _session
->commit_reversible_command ();
2163 _session
->locations()->clear ();
2167 Editor::unhide_markers ()
2169 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
2170 Location
*l
= (*i
).first
;
2171 if (l
->is_hidden() && l
->is_mark()) {
2172 l
->set_hidden(false, this);
2178 Editor::unhide_ranges ()
2180 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
2181 Location
*l
= (*i
).first
;
2182 if (l
->is_hidden() && l
->is_range_marker()) {
2183 l
->set_hidden(false, this);
2188 /* INSERT/REPLACE */
2191 Editor::insert_region_list_drag (boost::shared_ptr
<Region
> region
, int x
, int y
)
2196 RouteTimeAxisView
*rtv
= 0;
2197 boost::shared_ptr
<Playlist
> playlist
;
2199 track_canvas
->window_to_world (x
, y
, wx
, wy
);
2202 event
.type
= GDK_BUTTON_RELEASE
;
2203 event
.button
.x
= wx
;
2204 event
.button
.y
= wy
;
2206 where
= event_frame (&event
, &cx
, &cy
);
2208 if (where
< leftmost_frame
|| where
> leftmost_frame
+ current_page_frames()) {
2209 /* clearly outside canvas area */
2213 std::pair
<TimeAxisView
*, int> tv
= trackview_by_y_position (cy
);
2214 if (tv
.first
== 0) {
2218 if ((rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
.first
)) == 0) {
2222 if ((playlist
= rtv
->playlist()) == 0) {
2228 begin_reversible_command (_("insert dragged region"));
2229 playlist
->clear_history ();
2230 playlist
->add_region (RegionFactory::create (region
), where
, 1.0);
2231 _session
->add_command(new StatefulDiffCommand (playlist
));
2232 commit_reversible_command ();
2236 Editor::insert_route_list_drag (boost::shared_ptr
<Route
> route
, int x
, int y
)
2241 RouteTimeAxisView
*dest_rtv
= 0;
2242 RouteTimeAxisView
*source_rtv
= 0;
2244 track_canvas
->window_to_world (x
, y
, wx
, wy
);
2245 wx
+= horizontal_position ();
2246 wy
+= vertical_adjustment
.get_value();
2249 event
.type
= GDK_BUTTON_RELEASE
;
2250 event
.button
.x
= wx
;
2251 event
.button
.y
= wy
;
2253 where
= event_frame (&event
, &cx
, &cy
);
2255 std::pair
<TimeAxisView
*, int> const tv
= trackview_by_y_position (cy
);
2256 if (tv
.first
== 0) {
2260 if ((dest_rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
.first
)) == 0) {
2264 /* use this drag source to add underlay to a track. But we really don't care
2265 about the Route, only the view of the route, so find it first */
2266 for(TrackViewList::iterator it
= track_views
.begin(); it
!= track_views
.end(); ++it
) {
2267 if((source_rtv
= dynamic_cast<RouteTimeAxisView
*>(*it
)) == 0) {
2271 if(source_rtv
->route() == route
&& source_rtv
!= dest_rtv
) {
2272 dest_rtv
->add_underlay(source_rtv
->view());
2279 Editor::insert_region_list_selection (float times
)
2281 RouteTimeAxisView
*tv
= 0;
2282 boost::shared_ptr
<Playlist
> playlist
;
2284 if (clicked_routeview
!= 0) {
2285 tv
= clicked_routeview
;
2286 } else if (!selection
->tracks
.empty()) {
2287 if ((tv
= dynamic_cast<RouteTimeAxisView
*>(selection
->tracks
.front())) == 0) {
2290 } else if (entered_track
!= 0) {
2291 if ((tv
= dynamic_cast<RouteTimeAxisView
*>(entered_track
)) == 0) {
2298 if ((playlist
= tv
->playlist()) == 0) {
2302 boost::shared_ptr
<Region
> region
= _regions
->get_single_selection ();
2307 begin_reversible_command (_("insert region"));
2308 playlist
->clear_history ();
2309 playlist
->add_region ((RegionFactory::create (region
)), get_preferred_edit_position(), times
);
2310 _session
->add_command(new StatefulDiffCommand (playlist
));
2311 commit_reversible_command ();
2314 /* BUILT-IN EFFECTS */
2317 Editor::reverse_selection ()
2322 /* GAIN ENVELOPE EDITING */
2325 Editor::edit_envelope ()
2332 Editor::transition_to_rolling (bool fwd
)
2338 if (_session
->config
.get_external_sync()) {
2339 switch (_session
->config
.get_sync_source()) {
2343 /* transport controlled by the master */
2348 if (_session
->is_auditioning()) {
2349 _session
->cancel_audition ();
2353 _session
->request_transport_speed (fwd
? 1.0f
: -1.0f
);
2357 Editor::play_from_start ()
2359 _session
->request_locate (_session
->current_start_frame(), true);
2363 Editor::play_from_edit_point ()
2365 _session
->request_locate (get_preferred_edit_position(), true);
2369 Editor::play_from_edit_point_and_return ()
2371 nframes64_t start_frame
;
2372 nframes64_t return_frame
;
2374 start_frame
= get_preferred_edit_position (true);
2376 if (_session
->transport_rolling()) {
2377 _session
->request_locate (start_frame
, false);
2381 /* don't reset the return frame if its already set */
2383 if ((return_frame
= _session
->requested_return_frame()) < 0) {
2384 return_frame
= _session
->audible_frame();
2387 if (start_frame
>= 0) {
2388 _session
->request_roll_at_and_return (start_frame
, return_frame
);
2393 Editor::play_selection ()
2395 if (selection
->time
.empty()) {
2399 _session
->request_play_range (&selection
->time
, true);
2403 Editor::loop_selected_region ()
2407 get_regions_for_action (rs
);
2410 RegionView
*rv
= *(rs
.begin());
2413 if ((tll
= transport_loop_location()) != 0) {
2415 tll
->set (rv
->region()->position(), rv
->region()->last_frame());
2417 // enable looping, reposition and start rolling
2419 _session
->request_play_loop (true);
2420 _session
->request_locate (tll
->start(), false);
2421 _session
->request_transport_speed (1.0f
);
2427 Editor::play_location (Location
& location
)
2429 if (location
.start() <= location
.end()) {
2433 _session
->request_bounded_roll (location
.start(), location
.end());
2437 Editor::loop_location (Location
& location
)
2439 if (location
.start() <= location
.end()) {
2445 if ((tll
= transport_loop_location()) != 0) {
2446 tll
->set (location
.start(), location
.end());
2448 // enable looping, reposition and start rolling
2449 _session
->request_play_loop (true);
2450 _session
->request_locate (tll
->start(), true);
2455 Editor::raise_region ()
2457 selection
->foreach_region (&Region::raise
);
2461 Editor::raise_region_to_top ()
2463 selection
->foreach_region (&Region::raise_to_top
);
2467 Editor::lower_region ()
2469 selection
->foreach_region (&Region::lower
);
2473 Editor::lower_region_to_bottom ()
2475 selection
->foreach_region (&Region::lower_to_bottom
);
2478 /** Show the region editor for the selected regions */
2480 Editor::edit_region ()
2482 selection
->foreach_regionview (&RegionView::show_region_editor
);
2485 /** Show the midi list editor for the selected MIDI regions */
2487 Editor::show_midi_list_editor ()
2489 selection
->foreach_midi_regionview (&MidiRegionView::show_list_editor
);
2493 Editor::rename_region()
2497 get_regions_for_action (rs
);
2503 ArdourDialog
d (*this, _("Rename Region"), true, false);
2505 Label
label (_("New name:"));
2508 hbox
.set_spacing (6);
2509 hbox
.pack_start (label
, false, false);
2510 hbox
.pack_start (entry
, true, true);
2512 d
.get_vbox()->set_border_width (12);
2513 d
.get_vbox()->pack_start (hbox
, false, false);
2515 d
.add_button(Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
2516 d
.add_button(Gtk::Stock::OK
, Gtk::RESPONSE_OK
);
2518 d
.set_size_request (300, -1);
2519 d
.set_position (Gtk::WIN_POS_MOUSE
);
2521 entry
.set_text (rs
.front()->region()->name());
2522 entry
.select_region (0, -1);
2524 entry
.signal_activate().connect (sigc::bind (sigc::mem_fun (d
, &Dialog::response
), RESPONSE_OK
));
2534 if (ret
== RESPONSE_OK
) {
2535 std::string str
= entry
.get_text();
2536 strip_whitespace_edges (str
);
2538 rs
.front()->region()->set_name (str
);
2539 _regions
->redisplay ();
2545 Editor::audition_playlist_region_via_route (boost::shared_ptr
<Region
> region
, Route
& route
)
2547 if (_session
->is_auditioning()) {
2548 _session
->cancel_audition ();
2551 // note: some potential for creativity here, because region doesn't
2552 // have to belong to the playlist that Route is handling
2554 // bool was_soloed = route.soloed();
2556 route
.set_solo (true, this);
2558 _session
->request_bounded_roll (region
->position(), region
->position() + region
->length());
2560 /* XXX how to unset the solo state ? */
2563 /** Start an audition of the first selected region */
2565 Editor::play_edit_range ()
2567 nframes64_t start
, end
;
2569 if (get_edit_op_range (start
, end
)) {
2570 _session
->request_bounded_roll (start
, end
);
2575 Editor::play_selected_region ()
2577 nframes64_t start
= max_frames
;
2578 nframes64_t end
= 0;
2581 get_regions_for_action (rs
);
2587 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
2588 if ((*i
)->region()->position() < start
) {
2589 start
= (*i
)->region()->position();
2591 if ((*i
)->region()->last_frame() + 1 > end
) {
2592 end
= (*i
)->region()->last_frame() + 1;
2596 _session
->request_bounded_roll (start
, end
);
2600 Editor::audition_playlist_region_standalone (boost::shared_ptr
<Region
> region
)
2602 _session
->audition_region (region
);
2606 Editor::region_from_selection ()
2608 if (clicked_axisview
== 0) {
2612 if (selection
->time
.empty()) {
2616 nframes64_t start
= selection
->time
[clicked_selection
].start
;
2617 nframes64_t end
= selection
->time
[clicked_selection
].end
;
2619 TrackViewList tracks
= get_tracks_for_range_action ();
2621 nframes64_t selection_cnt
= end
- start
+ 1;
2623 for (TrackSelection::iterator i
= tracks
.begin(); i
!= tracks
.end(); ++i
) {
2624 boost::shared_ptr
<Region
> current
;
2625 boost::shared_ptr
<Playlist
> pl
;
2626 nframes64_t internal_start
;
2629 if ((pl
= (*i
)->playlist()) == 0) {
2633 if ((current
= pl
->top_region_at (start
)) == 0) {
2637 internal_start
= start
- current
->position();
2638 RegionFactory::region_name (new_name
, current
->name(), true);
2642 plist
.add (ARDOUR::Properties::start
, current
->start() + internal_start
);
2643 plist
.add (ARDOUR::Properties::length
, selection_cnt
);
2644 plist
.add (ARDOUR::Properties::name
, new_name
);
2645 plist
.add (ARDOUR::Properties::layer
, 0);
2647 boost::shared_ptr
<Region
> region (RegionFactory::create (current
, plist
));
2652 Editor::create_region_from_selection (vector
<boost::shared_ptr
<Region
> >& new_regions
)
2654 if (selection
->time
.empty() || selection
->tracks
.empty()) {
2658 nframes64_t start
= selection
->time
[clicked_selection
].start
;
2659 nframes64_t end
= selection
->time
[clicked_selection
].end
;
2661 sort_track_selection ();
2663 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
2664 boost::shared_ptr
<Region
> current
;
2665 boost::shared_ptr
<Playlist
> playlist
;
2666 nframes64_t internal_start
;
2669 if ((playlist
= (*i
)->playlist()) == 0) {
2673 if ((current
= playlist
->top_region_at(start
)) == 0) {
2677 internal_start
= start
- current
->position();
2678 RegionFactory::region_name (new_name
, current
->name(), true);
2682 plist
.add (ARDOUR::Properties::start
, current
->start() + internal_start
);
2683 plist
.add (ARDOUR::Properties::length
, end
- start
+ 1);
2684 plist
.add (ARDOUR::Properties::name
, new_name
);
2686 new_regions
.push_back (RegionFactory::create (current
, plist
));
2691 Editor::split_multichannel_region ()
2695 get_regions_for_action (rs
);
2701 vector
< boost::shared_ptr
<Region
> > v
;
2703 for (list
<RegionView
*>::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
2704 (*x
)->region()->separate_by_channel (*_session
, v
);
2709 Editor::new_region_from_selection ()
2711 region_from_selection ();
2712 cancel_selection ();
2716 add_if_covered (RegionView
* rv
, const AudioRange
* ar
, RegionSelection
* rs
)
2718 switch (rv
->region()->coverage (ar
->start
, ar
->end
- 1)) {
2727 * - selected tracks, or if there are none...
2728 * - tracks containing selected regions, or if there are none...
2733 Editor::get_tracks_for_range_action () const
2737 if (selection
->tracks
.empty()) {
2739 /* use tracks with selected regions */
2741 RegionSelection rs
= selection
->regions
;
2743 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
2744 TimeAxisView
* tv
= &(*i
)->get_time_axis_view();
2746 if (!t
.contains (tv
)) {
2752 /* no regions and no tracks: use all tracks */
2758 t
= selection
->tracks
;
2765 Editor::separate_regions_between (const TimeSelection
& ts
)
2767 bool in_command
= false;
2768 boost::shared_ptr
<Playlist
> playlist
;
2769 RegionSelection new_selection
;
2771 TrackViewList tmptracks
= get_tracks_for_range_action ();
2772 sort_track_selection (&tmptracks
);
2774 for (TrackSelection::iterator i
= tmptracks
.begin(); i
!= tmptracks
.end(); ++i
) {
2776 RouteTimeAxisView
* rtv
;
2778 if ((rtv
= dynamic_cast<RouteTimeAxisView
*> ((*i
))) != 0) {
2780 if (rtv
->is_track()) {
2782 /* no edits to destructive tracks */
2784 if (rtv
->track()->destructive()) {
2788 if ((playlist
= rtv
->playlist()) != 0) {
2790 playlist
->clear_history ();
2792 /* XXX need to consider musical time selections here at some point */
2794 double speed
= rtv
->track()->speed();
2797 for (list
<AudioRange
>::const_iterator t
= ts
.begin(); t
!= ts
.end(); ++t
) {
2799 sigc::connection c
= rtv
->view()->RegionViewAdded
.connect (
2800 sigc::mem_fun(*this, &Editor::collect_new_region_view
));
2801 latest_regionviews
.clear ();
2803 playlist
->partition ((nframes64_t
)((*t
).start
* speed
),
2804 (nframes64_t
)((*t
).end
* speed
), true);
2808 if (!latest_regionviews
.empty()) {
2810 rtv
->view()->foreach_regionview (sigc::bind (
2811 sigc::ptr_fun (add_if_covered
),
2812 &(*t
), &new_selection
));
2815 begin_reversible_command (_("separate"));
2819 _session
->add_command(new StatefulDiffCommand (playlist
));
2828 selection
->set (new_selection
);
2829 set_mouse_mode (MouseObject
);
2831 commit_reversible_command ();
2835 /** Take tracks from get_tracks_for_range_action and cut any regions
2836 * on those tracks so that the tracks are empty over the time
2840 Editor::separate_region_from_selection ()
2842 /* preferentially use *all* ranges in the time selection if we're in range mode
2843 to allow discontiguous operation, since get_edit_op_range() currently
2844 returns a single range.
2847 if (mouse_mode
== MouseRange
&& !selection
->time
.empty()) {
2849 separate_regions_between (selection
->time
);
2856 if (get_edit_op_range (start
, end
)) {
2858 AudioRange
ar (start
, end
, 1);
2862 separate_regions_between (ts
);
2868 Editor::separate_region_from_punch ()
2870 Location
* loc
= _session
->locations()->auto_punch_location();
2872 separate_regions_using_location (*loc
);
2877 Editor::separate_region_from_loop ()
2879 Location
* loc
= _session
->locations()->auto_loop_location();
2881 separate_regions_using_location (*loc
);
2886 Editor::separate_regions_using_location (Location
& loc
)
2888 if (loc
.is_mark()) {
2892 AudioRange
ar (loc
.start(), loc
.end(), 1);
2897 separate_regions_between (ts
);
2901 Editor::crop_region_to_selection ()
2903 if (!selection
->time
.empty()) {
2905 crop_region_to (selection
->time
.start(), selection
->time
.end_frame());
2912 if (get_edit_op_range (start
, end
)) {
2913 crop_region_to (start
, end
);
2920 Editor::crop_region_to (nframes64_t start
, nframes64_t end
)
2922 vector
<boost::shared_ptr
<Playlist
> > playlists
;
2923 boost::shared_ptr
<Playlist
> playlist
;
2926 if (selection
->tracks
.empty()) {
2929 sort_track_selection ();
2930 ts
= &selection
->tracks
;
2933 for (TrackSelection::iterator i
= ts
->begin(); i
!= ts
->end(); ++i
) {
2935 RouteTimeAxisView
* rtv
;
2937 if ((rtv
= dynamic_cast<RouteTimeAxisView
*> ((*i
))) != 0) {
2939 boost::shared_ptr
<Track
> t
= rtv
->track();
2941 if (t
!= 0 && ! t
->destructive()) {
2943 if ((playlist
= rtv
->playlist()) != 0) {
2944 playlists
.push_back (playlist
);
2950 if (playlists
.empty()) {
2954 nframes64_t the_start
;
2955 nframes64_t the_end
;
2958 begin_reversible_command (_("trim to selection"));
2960 for (vector
<boost::shared_ptr
<Playlist
> >::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
2962 boost::shared_ptr
<Region
> region
;
2966 if ((region
= (*i
)->top_region_at(the_start
)) == 0) {
2970 /* now adjust lengths to that we do the right thing
2971 if the selection extends beyond the region
2974 the_start
= max (the_start
, (nframes64_t
) region
->position());
2975 if (max_frames
- the_start
< region
->length()) {
2976 the_end
= the_start
+ region
->length() - 1;
2978 the_end
= max_frames
;
2980 the_end
= min (end
, the_end
);
2981 cnt
= the_end
- the_start
+ 1;
2983 region
->clear_history ();
2984 region
->trim_to (the_start
, cnt
, this);
2985 _session
->add_command (new StatefulDiffCommand (region
));
2988 commit_reversible_command ();
2992 Editor::region_fill_track ()
2997 get_regions_for_action (rs
);
2999 if (!_session
|| rs
.empty()) {
3003 end
= _session
->current_end_frame ();
3005 begin_reversible_command (_("region fill"));
3007 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
3009 boost::shared_ptr
<Region
> region ((*i
)->region());
3011 boost::shared_ptr
<Playlist
> pl
= region
->playlist();
3013 if (end
<= region
->last_frame()) {
3017 double times
= (double) (end
- region
->last_frame()) / (double) region
->length();
3023 pl
->clear_history ();
3024 pl
->add_region (RegionFactory::create (region
), region
->last_frame(), times
);
3025 _session
->add_command (new StatefulDiffCommand (pl
));
3028 commit_reversible_command ();
3032 Editor::region_fill_selection ()
3034 if (clicked_routeview
== 0 || !clicked_routeview
->is_audio_track()) {
3038 if (selection
->time
.empty()) {
3042 boost::shared_ptr
<Region
> region
= _regions
->get_single_selection ();
3047 nframes64_t start
= selection
->time
[clicked_selection
].start
;
3048 nframes64_t end
= selection
->time
[clicked_selection
].end
;
3050 boost::shared_ptr
<Playlist
> playlist
;
3052 if (selection
->tracks
.empty()) {
3056 nframes64_t selection_length
= end
- start
;
3057 float times
= (float)selection_length
/ region
->length();
3059 begin_reversible_command (_("fill selection"));
3061 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
3063 if ((playlist
= (*i
)->playlist()) == 0) {
3067 playlist
->clear_history ();
3068 playlist
->add_region (RegionFactory::create (region
), start
, times
);
3069 _session
->add_command (new StatefulDiffCommand (playlist
));
3072 commit_reversible_command ();
3076 Editor::set_region_sync_from_edit_point ()
3078 nframes64_t where
= get_preferred_edit_position ();
3080 get_regions_for_action (rs
);
3081 set_sync_point (where
, rs
);
3085 Editor::set_sync_point (nframes64_t where
, const RegionSelection
& rs
)
3087 bool in_command
= false;
3089 for (RegionSelection::const_iterator r
= rs
.begin(); r
!= rs
.end(); ++r
) {
3091 if (!(*r
)->region()->covers (where
)) {
3095 boost::shared_ptr
<Region
> region ((*r
)->region());
3098 begin_reversible_command (_("set sync point"));
3102 region
->clear_history ();
3103 region
->set_sync_position (where
);
3104 _session
->add_command(new StatefulDiffCommand (region
));
3108 commit_reversible_command ();
3112 /** Remove the sync positions of the selection */
3114 Editor::remove_region_sync ()
3118 get_regions_for_action (rs
);
3124 begin_reversible_command (_("remove sync"));
3125 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
3127 (*i
)->region()->clear_history ();
3128 (*i
)->region()->clear_sync_position ();
3129 _session
->add_command(new StatefulDiffCommand ((*i
)->region()));
3131 commit_reversible_command ();
3135 Editor::naturalize ()
3139 get_regions_for_action (rs
);
3145 begin_reversible_command (_("naturalize"));
3146 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
3147 (*i
)->region()->clear_history ();
3148 (*i
)->region()->move_to_natural_position (this);
3149 _session
->add_command (new StatefulDiffCommand ((*i
)->region()));
3151 commit_reversible_command ();
3155 Editor::align (RegionPoint what
)
3159 get_regions_for_action (rs
);
3160 nframes64_t where
= get_preferred_edit_position();
3163 align_selection (what
, where
, rs
);
3167 get_regions_at (rs
, where
, selection
->tracks
);
3168 align_selection (what
, where
, rs
);
3173 Editor::align_relative (RegionPoint what
)
3175 nframes64_t where
= get_preferred_edit_position();
3178 get_regions_for_action (rs
);
3181 align_selection_relative (what
, where
, rs
);
3185 struct RegionSortByTime
{
3186 bool operator() (const RegionView
* a
, const RegionView
* b
) {
3187 return a
->region()->position() < b
->region()->position();
3192 Editor::align_selection_relative (RegionPoint point
, nframes64_t position
, const RegionSelection
& rs
)
3198 nframes64_t distance
= 0;
3199 nframes64_t pos
= 0;
3202 list
<RegionView
*> sorted
;
3203 rs
.by_position (sorted
);
3205 boost::shared_ptr
<Region
> r ((*sorted
.begin())->region());
3210 if (position
> r
->position()) {
3211 distance
= position
- r
->position();
3213 distance
= r
->position() - position
;
3219 if (position
> r
->last_frame()) {
3220 distance
= position
- r
->last_frame();
3221 pos
= r
->position() + distance
;
3223 distance
= r
->last_frame() - position
;
3224 pos
= r
->position() - distance
;
3230 pos
= r
->adjust_to_sync (position
);
3231 if (pos
> r
->position()) {
3232 distance
= pos
- r
->position();
3234 distance
= r
->position() - pos
;
3240 if (pos
== r
->position()) {
3244 begin_reversible_command (_("align selection (relative)"));
3246 /* move first one specially */
3248 r
->clear_history ();
3249 r
->set_position (pos
, this);
3250 _session
->add_command(new StatefulDiffCommand (r
));
3252 /* move rest by the same amount */
3256 for (list
<RegionView
*>::iterator i
= sorted
.begin(); i
!= sorted
.end(); ++i
) {
3258 boost::shared_ptr
<Region
> region ((*i
)->region());
3260 region
->clear_history ();
3263 region
->set_position (region
->position() + distance
, this);
3265 region
->set_position (region
->position() - distance
, this);
3268 _session
->add_command(new StatefulDiffCommand (region
));
3272 commit_reversible_command ();
3276 Editor::align_selection (RegionPoint point
, nframes64_t position
, const RegionSelection
& rs
)
3282 begin_reversible_command (_("align selection"));
3284 for (RegionSelection::const_iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
3285 align_region_internal ((*i
)->region(), point
, position
);
3288 commit_reversible_command ();
3292 Editor::align_region (boost::shared_ptr
<Region
> region
, RegionPoint point
, nframes64_t position
)
3294 begin_reversible_command (_("align region"));
3295 align_region_internal (region
, point
, position
);
3296 commit_reversible_command ();
3300 Editor::align_region_internal (boost::shared_ptr
<Region
> region
, RegionPoint point
, nframes64_t position
)
3302 region
->clear_history ();
3306 region
->set_position (region
->adjust_to_sync (position
), this);
3310 if (position
> region
->length()) {
3311 region
->set_position (position
- region
->length(), this);
3316 region
->set_position (position
, this);
3320 _session
->add_command(new StatefulDiffCommand (region
));
3324 Editor::trim_region_front ()
3330 Editor::trim_region_back ()
3332 trim_region (false);
3336 Editor::trim_region (bool front
)
3338 nframes64_t where
= get_preferred_edit_position();
3341 get_regions_for_action (rs
);
3347 begin_reversible_command (front
? _("trim front") : _("trim back"));
3349 for (list
<RegionView
*>::const_iterator i
= rs
.by_layer().begin(); i
!= rs
.by_layer().end(); ++i
) {
3350 if (!(*i
)->region()->locked()) {
3351 (*i
)->region()->clear_history ();
3353 (*i
)->region()->trim_front (where
, this);
3355 (*i
)->region()->trim_end (where
, this);
3357 _session
->add_command (new StatefulDiffCommand ((*i
)->region()));
3361 commit_reversible_command ();
3364 /** Trim the end of the selected regions to the position of the edit cursor */
3366 Editor::trim_region_to_loop ()
3368 Location
* loc
= _session
->locations()->auto_loop_location();
3372 trim_region_to_location (*loc
, _("trim to loop"));
3376 Editor::trim_region_to_punch ()
3378 Location
* loc
= _session
->locations()->auto_punch_location();
3382 trim_region_to_location (*loc
, _("trim to punch"));
3385 Editor::trim_region_to_location (const Location
& loc
, const char* str
)
3389 get_regions_for_action (rs
);
3391 begin_reversible_command (str
);
3393 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
3394 RegionView
* rv
= (*x
);
3396 /* require region to span proposed trim */
3397 switch (rv
->region()->coverage (loc
.start(), loc
.end())) {
3398 case OverlapInternal
:
3404 RouteTimeAxisView
* tav
= dynamic_cast<RouteTimeAxisView
*> (&rv
->get_time_axis_view());
3413 if (tav
->track() != 0) {
3414 speed
= tav
->track()->speed();
3417 start
= session_frame_to_track_frame (loc
.start(), speed
);
3418 end
= session_frame_to_track_frame (loc
.end(), speed
);
3420 rv
->region()->clear_history ();
3421 rv
->region()->trim_to (start
, (end
- start
), this);
3422 _session
->add_command(new StatefulDiffCommand (rv
->region()));
3425 commit_reversible_command ();
3429 Editor::trim_region_to_edit_point ()
3433 get_regions_for_action (rs
);
3435 nframes64_t where
= get_preferred_edit_position();
3437 begin_reversible_command (_("trim region start to edit point"));
3439 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
3440 RegionView
* rv
= (*x
);
3442 /* require region to cover trim */
3443 if (!rv
->region()->covers (where
)) {
3447 RouteTimeAxisView
* tav
= dynamic_cast<RouteTimeAxisView
*> (&rv
->get_time_axis_view());
3454 if (tav
->track() != 0) {
3455 speed
= tav
->track()->speed();
3458 rv
->region()->clear_history ();
3459 rv
->region()->trim_end (session_frame_to_track_frame(where
, speed
), this);
3460 _session
->add_command(new StatefulDiffCommand (rv
->region()));
3463 commit_reversible_command ();
3467 Editor::trim_region_from_edit_point ()
3471 get_regions_for_action (rs
);
3473 nframes64_t where
= get_preferred_edit_position();
3475 begin_reversible_command (_("trim region end to edit point"));
3477 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
3478 RegionView
* rv
= (*x
);
3480 /* require region to cover trim */
3481 if (!rv
->region()->covers (where
)) {
3485 RouteTimeAxisView
* tav
= dynamic_cast<RouteTimeAxisView
*> (&rv
->get_time_axis_view());
3492 if (tav
->track() != 0) {
3493 speed
= tav
->track()->speed();
3496 rv
->region()->clear_history ();
3497 rv
->region()->trim_front (session_frame_to_track_frame(where
, speed
), this);
3498 _session
->add_command(new StatefulDiffCommand (rv
->region()));
3501 commit_reversible_command ();
3505 Editor::trim_region_to_previous_region_end ()
3507 return trim_to_region(false);
3511 Editor::trim_region_to_next_region_start ()
3513 return trim_to_region(true);
3517 Editor::trim_to_region(bool forward
)
3521 get_regions_for_action (rs
);
3523 begin_reversible_command (_("trim to region"));
3525 boost::shared_ptr
<Region
> next_region
;
3527 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
3529 AudioRegionView
* arv
= dynamic_cast<AudioRegionView
*> (*x
);
3535 AudioTimeAxisView
* atav
= dynamic_cast<AudioTimeAxisView
*> (&arv
->get_time_axis_view());
3543 if (atav
->track() != 0) {
3544 speed
= atav
->track()->speed();
3548 boost::shared_ptr
<Region
> region
= arv
->region();
3549 boost::shared_ptr
<Playlist
> playlist (region
->playlist());
3551 region
->clear_history ();
3555 next_region
= playlist
->find_next_region (region
->first_frame(), Start
, 1);
3561 region
->trim_end((nframes64_t
) (next_region
->first_frame() * speed
), this);
3562 arv
->region_changed (PropertyChange (ARDOUR::Properties::length
));
3566 next_region
= playlist
->find_next_region (region
->first_frame(), Start
, 0);
3572 region
->trim_front((nframes64_t
) ((next_region
->last_frame() + 1) * speed
), this);
3574 arv
->region_changed (ARDOUR::bounds_change
);
3577 _session
->add_command(new StatefulDiffCommand (region
));
3580 commit_reversible_command ();
3584 Editor::unfreeze_route ()
3586 if (clicked_routeview
== 0 || !clicked_routeview
->is_track()) {
3590 clicked_routeview
->track()->unfreeze ();
3594 Editor::_freeze_thread (void* arg
)
3596 SessionEvent::create_per_thread_pool ("freeze events", 64);
3598 return static_cast<Editor
*>(arg
)->freeze_thread ();
3602 Editor::freeze_thread ()
3604 clicked_routeview
->audio_track()->freeze_me (*current_interthread_info
);
3605 current_interthread_info
->done
= true;
3610 Editor::freeze_route ()
3612 if (clicked_routeview
== 0 || !clicked_routeview
->is_audio_track()) {
3616 InterThreadInfo itt
;
3617 current_interthread_info
= &itt
;
3619 InterthreadProgressWindow
ipw (current_interthread_info
, _("Freeze"), _("Cancel Freeze"));
3621 pthread_create_and_store (X_("freezer"), &itt
.thread
, _freeze_thread
, this);
3623 track_canvas
->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH
));
3625 while (!itt
.done
&& !itt
.cancel
) {
3626 gtk_main_iteration ();
3629 current_interthread_info
= 0;
3630 track_canvas
->get_window()->set_cursor (*current_canvas_cursor
);
3634 Editor::bounce_range_selection (bool replace
, bool enable_processing
)
3636 if (selection
->time
.empty()) {
3640 TrackSelection views
= selection
->tracks
;
3642 nframes64_t start
= selection
->time
[clicked_selection
].start
;
3643 nframes64_t end
= selection
->time
[clicked_selection
].end
;
3644 nframes64_t cnt
= end
- start
+ 1;
3646 begin_reversible_command (_("bounce range"));
3648 for (TrackViewList::iterator i
= views
.begin(); i
!= views
.end(); ++i
) {
3650 RouteTimeAxisView
* rtv
;
3652 if ((rtv
= dynamic_cast<RouteTimeAxisView
*> (*i
)) == 0) {
3656 boost::shared_ptr
<Playlist
> playlist
;
3658 if ((playlist
= rtv
->playlist()) == 0) {
3662 InterThreadInfo itt
;
3664 playlist
->clear_history ();
3665 boost::shared_ptr
<Region
> r
= rtv
->track()->bounce_range (start
, start
+cnt
, itt
, enable_processing
);
3668 list
<AudioRange
> ranges
;
3669 ranges
.push_back (AudioRange (start
, start
+cnt
, 0));
3670 playlist
->cut (ranges
); // discard result
3671 playlist
->add_region (r
, start
);
3674 _session
->add_command (new StatefulDiffCommand (playlist
));
3677 commit_reversible_command ();
3680 /** Cut selected regions, automation points or a time range */
3687 /** Copy selected regions, automation points or a time range */
3695 /** @return true if a Cut, Copy or Clear is possible */
3697 Editor::can_cut_copy () const
3699 switch (current_mouse_mode()) {
3702 if (!selection
->regions
.empty() || !selection
->points
.empty()) {
3708 if (!selection
->time
.empty()) {
3721 /** Cut, copy or clear selected regions, automation points or a time range.
3722 * @param op Operation (Cut, Copy or Clear)
3725 Editor::cut_copy (CutCopyOp op
)
3727 /* only cancel selection if cut/copy is successful.*/
3739 opname
= _("clear");
3743 /* if we're deleting something, and the mouse is still pressed,
3744 the thing we started a drag for will be gone when we release
3745 the mouse button(s). avoid this. see part 2 at the end of
3749 if (op
== Cut
|| op
== Clear
) {
3750 if (_drags
->active ()) {
3755 cut_buffer
->clear ();
3757 if (entered_marker
) {
3759 /* cut/delete op while pointing at a marker */
3762 Location
* loc
= find_location_from_marker (entered_marker
, ignored
);
3764 if (_session
&& loc
) {
3765 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker
), loc
));
3772 if (internal_editing()) {
3774 switch (current_mouse_mode()) {
3787 /* we only want to cut regions if some are selected */
3789 if (!selection
->regions
.empty()) {
3790 get_regions_for_action (rs
, false, false);
3793 switch (current_mouse_mode()) {
3795 if (!rs
.empty() || !selection
->points
.empty()) {
3797 begin_reversible_command (opname
+ _(" objects"));
3800 cut_copy_regions (op
, rs
);
3803 selection
->clear_regions ();
3807 if (!selection
->points
.empty()) {
3808 cut_copy_points (op
);
3811 selection
->clear_points ();
3815 commit_reversible_command ();
3816 break; // terminate case statement here
3818 if (!selection
->time
.empty()) {
3819 /* don't cause suprises */
3822 // fall thru if there was nothing selected
3825 if (selection
->time
.empty()) {
3826 nframes64_t start
, end
;
3827 if (!get_edit_op_range (start
, end
)) {
3830 selection
->set (start
, end
);
3833 begin_reversible_command (opname
+ _(" range"));
3834 cut_copy_ranges (op
);
3835 commit_reversible_command ();
3838 selection
->clear_time ();
3848 if (op
== Cut
|| op
== Clear
) {
3853 /** Cut, copy or clear selected automation points.
3854 * @param op Operation (Cut, Copy or Clear)
3857 Editor::cut_copy_points (CutCopyOp op
)
3859 for (PointSelection::iterator i
= selection
->points
.begin(); i
!= selection
->points
.end(); ++i
) {
3861 AutomationTimeAxisView
* atv
= dynamic_cast<AutomationTimeAxisView
*>((*i
).track
);
3864 atv
->cut_copy_clear_objects (selection
->points
, op
);
3869 /** Cut, copy or clear selected automation points.
3870 * @param op Operation (Cut, Copy or Clear)
3873 Editor::cut_copy_midi (CutCopyOp op
)
3875 for (MidiRegionSelection::iterator i
= selection
->midi_regions
.begin(); i
!= selection
->midi_regions
.end(); ++i
) {
3876 MidiRegionView
* mrv
= *i
;
3877 mrv
->cut_copy_clear (op
);
3881 struct PlaylistMapping
{
3883 boost::shared_ptr
<Playlist
> pl
;
3885 PlaylistMapping (TimeAxisView
* tvp
) : tv (tvp
) {}
3888 /** Remove `clicked_regionview' */
3890 Editor::remove_clicked_region ()
3892 if (clicked_routeview
== 0 || clicked_regionview
== 0) {
3896 boost::shared_ptr
<Playlist
> playlist
= clicked_routeview
->playlist();
3898 begin_reversible_command (_("remove region"));
3899 playlist
->clear_history ();
3900 playlist
->remove_region (clicked_regionview
->region());
3901 _session
->add_command(new StatefulDiffCommand (playlist
));
3902 commit_reversible_command ();
3906 /** Remove the selected regions */
3908 Editor::remove_selected_regions ()
3911 get_regions_for_action (rs
);
3921 begin_reversible_command (_("remove region"));
3923 list
<boost::shared_ptr
<Region
> > regions_to_remove
;
3925 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
3926 // we can't just remove the region(s) in this loop because
3927 // this removes them from the RegionSelection, and they thus
3928 // disappear from underneath the iterator, and the ++i above
3929 // SEGVs in a puzzling fashion.
3931 // so, first iterate over the regions to be removed from rs and
3932 // add them to the regions_to_remove list, and then
3933 // iterate over the list to actually remove them.
3935 regions_to_remove
.push_back ((*i
)->region());
3938 vector
<boost::shared_ptr
<Playlist
> > playlists
;
3940 for (list
<boost::shared_ptr
<Region
> >::iterator rl
= regions_to_remove
.begin(); rl
!= regions_to_remove
.end(); ++rl
) {
3942 boost::shared_ptr
<Playlist
> playlist
= (*rl
)->playlist();
3945 // is this check necessary?
3949 vector
<boost::shared_ptr
<Playlist
> >::iterator i
;
3951 //only prep history if this is a new playlist.
3952 for (i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
3953 if ((*i
) == playlist
) {
3958 if (i
== playlists
.end()) {
3960 playlist
->clear_history ();
3961 playlist
->freeze ();
3963 playlists
.push_back (playlist
);
3966 playlist
->remove_region (*rl
);
3969 vector
<boost::shared_ptr
<Playlist
> >::iterator pl
;
3971 for (pl
= playlists
.begin(); pl
!= playlists
.end(); ++pl
) {
3973 _session
->add_command(new StatefulDiffCommand (*pl
));
3976 commit_reversible_command ();
3979 /** Cut, copy or clear selected regions.
3980 * @param op Operation (Cut, Copy or Clear)
3983 Editor::cut_copy_regions (CutCopyOp op
, RegionSelection
& rs
)
3985 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3986 a map when we want ordered access to both elements. i think.
3989 vector
<PlaylistMapping
> pmap
;
3991 nframes64_t first_position
= max_frames
;
3993 typedef set
<boost::shared_ptr
<Playlist
> > FreezeList
;
3994 FreezeList freezelist
;
3996 /* get ordering correct before we cut/copy */
3998 rs
.sort_by_position_and_track ();
4000 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
4002 first_position
= min ((nframes64_t
) (*x
)->region()->position(), first_position
);
4004 if (op
== Cut
|| op
== Clear
) {
4005 boost::shared_ptr
<Playlist
> pl
= (*x
)->region()->playlist();
4008 FreezeList::iterator fl
;
4010 //only take state if this is a new playlist.
4011 for (fl
= freezelist
.begin(); fl
!= freezelist
.end(); ++fl
) {
4017 if (fl
== freezelist
.end()) {
4018 pl
->clear_history();
4020 freezelist
.insert (pl
);
4025 TimeAxisView
* tv
= &(*x
)->get_trackview();
4026 vector
<PlaylistMapping
>::iterator z
;
4028 for (z
= pmap
.begin(); z
!= pmap
.end(); ++z
) {
4029 if ((*z
).tv
== tv
) {
4034 if (z
== pmap
.end()) {
4035 pmap
.push_back (PlaylistMapping (tv
));
4039 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ) {
4041 boost::shared_ptr
<Playlist
> pl
= (*x
)->region()->playlist();
4044 /* impossible, but this handles it for the future */
4048 TimeAxisView
& tv
= (*x
)->get_trackview();
4049 boost::shared_ptr
<Playlist
> npl
;
4050 RegionSelection::iterator tmp
;
4055 vector
<PlaylistMapping
>::iterator z
;
4057 for (z
= pmap
.begin(); z
!= pmap
.end(); ++z
) {
4058 if ((*z
).tv
== &tv
) {
4063 assert (z
!= pmap
.end());
4066 npl
= PlaylistFactory::create (pl
->data_type(), *_session
, "cutlist", true);
4073 boost::shared_ptr
<Region
> r
= (*x
)->region();
4074 boost::shared_ptr
<Region
> _xx
;
4080 _xx
= RegionFactory::create (r
);
4081 npl
->add_region (_xx
, r
->position() - first_position
);
4082 pl
->remove_region (r
);
4086 /* copy region before adding, so we're not putting same object into two different playlists */
4087 npl
->add_region (RegionFactory::create (r
), r
->position() - first_position
);
4091 pl
->remove_region (r
);
4098 list
<boost::shared_ptr
<Playlist
> > foo
;
4100 /* the pmap is in the same order as the tracks in which selected regions occured */
4102 for (vector
<PlaylistMapping
>::iterator i
= pmap
.begin(); i
!= pmap
.end(); ++i
) {
4104 foo
.push_back ((*i
).pl
);
4109 cut_buffer
->set (foo
);
4112 for (FreezeList::iterator pl
= freezelist
.begin(); pl
!= freezelist
.end(); ++pl
) {
4114 _session
->add_command (new StatefulDiffCommand (*pl
));
4119 Editor::cut_copy_ranges (CutCopyOp op
)
4122 TrackViewList entered
;
4124 if (selection
->tracks
.empty()) {
4125 if (!entered_track
) {
4128 entered
.push_back (entered_track
);
4131 ts
= &selection
->tracks
;
4134 for (TrackSelection::iterator i
= ts
->begin(); i
!= ts
->end(); ++i
) {
4135 (*i
)->cut_copy_clear (*selection
, op
);
4140 Editor::paste (float times
)
4142 paste_internal (get_preferred_edit_position(), times
);
4146 Editor::mouse_paste ()
4151 if (!mouse_frame (where
, ignored
)) {
4156 paste_internal (where
, 1);
4160 Editor::paste_internal (nframes64_t position
, float times
)
4162 bool commit
= false;
4164 if (internal_editing()) {
4165 if (cut_buffer
->midi_notes
.empty()) {
4169 if (cut_buffer
->empty()) {
4174 if (position
== max_frames
) {
4175 position
= get_preferred_edit_position();
4178 begin_reversible_command (_("paste"));
4181 TrackViewList::iterator i
;
4184 /* get everything in the correct order */
4186 if (!selection
->tracks
.empty()) {
4187 sort_track_selection ();
4188 ts
= selection
->tracks
;
4189 } else if (entered_track
) {
4190 ts
.push_back (entered_track
);
4193 for (nth
= 0, i
= ts
.begin(); i
!= ts
.end(); ++i
, ++nth
) {
4195 /* undo/redo is handled by individual tracks/regions */
4197 if (internal_editing()) {
4200 RegionSelection::iterator r
;
4201 MidiNoteSelection::iterator cb
;
4203 get_regions_at (rs
, position
, ts
);
4205 for (cb
= cut_buffer
->midi_notes
.begin(), r
= rs
.begin();
4206 cb
!= cut_buffer
->midi_notes
.end() && r
!= rs
.end(); ++r
) {
4207 MidiRegionView
* mrv
= dynamic_cast<MidiRegionView
*> (*r
);
4209 mrv
->paste (position
, times
, **cb
);
4216 if ((*i
)->paste (position
, times
, *cut_buffer
, nth
)) {
4223 commit_reversible_command ();
4228 Editor::duplicate_some_regions (RegionSelection
& regions
, float times
)
4230 boost::shared_ptr
<Playlist
> playlist
;
4231 RegionSelection sel
= regions
; // clear (below) may clear the argument list if its the current region selection
4232 RegionSelection foo
;
4234 nframes_t
const start_frame
= regions
.start ();
4235 nframes_t
const end_frame
= regions
.end_frame ();
4237 begin_reversible_command (_("duplicate region"));
4239 selection
->clear_regions ();
4241 for (RegionSelection::iterator i
= sel
.begin(); i
!= sel
.end(); ++i
) {
4243 boost::shared_ptr
<Region
> r ((*i
)->region());
4245 TimeAxisView
& tv
= (*i
)->get_time_axis_view();
4246 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (&tv
);
4247 latest_regionviews
.clear ();
4248 sigc::connection c
= rtv
->view()->RegionViewAdded
.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view
));
4250 playlist
= (*i
)->region()->playlist();
4251 playlist
->clear_history ();
4252 playlist
->duplicate (r
, end_frame
+ (r
->first_frame() - start_frame
) + 1, times
);
4253 _session
->add_command(new StatefulDiffCommand (playlist
));
4257 foo
.insert (foo
.end(), latest_regionviews
.begin(), latest_regionviews
.end());
4260 commit_reversible_command ();
4263 selection
->set (foo
);
4268 Editor::duplicate_selection (float times
)
4270 if (selection
->time
.empty() || selection
->tracks
.empty()) {
4274 boost::shared_ptr
<Playlist
> playlist
;
4275 vector
<boost::shared_ptr
<Region
> > new_regions
;
4276 vector
<boost::shared_ptr
<Region
> >::iterator ri
;
4278 create_region_from_selection (new_regions
);
4280 if (new_regions
.empty()) {
4284 begin_reversible_command (_("duplicate selection"));
4286 ri
= new_regions
.begin();
4288 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
4289 if ((playlist
= (*i
)->playlist()) == 0) {
4292 playlist
->clear_history ();
4293 playlist
->duplicate (*ri
, selection
->time
[clicked_selection
].end
, times
);
4294 _session
->add_command (new StatefulDiffCommand (playlist
));
4297 if (ri
== new_regions
.end()) {
4302 commit_reversible_command ();
4306 Editor::reset_point_selection ()
4308 /* reset all selected points to the relevant default value */
4310 for (PointSelection::iterator i
= selection
->points
.begin(); i
!= selection
->points
.end(); ++i
) {
4312 AutomationTimeAxisView
* atv
= dynamic_cast<AutomationTimeAxisView
*>((*i
).track
);
4315 atv
->reset_objects (selection
->points
);
4321 Editor::center_playhead ()
4323 float page
= _canvas_width
* frames_per_unit
;
4324 center_screen_internal (playhead_cursor
->current_frame
, page
);
4328 Editor::center_edit_point ()
4330 float page
= _canvas_width
* frames_per_unit
;
4331 center_screen_internal (get_preferred_edit_position(), page
);
4335 Editor::clear_playlist (boost::shared_ptr
<Playlist
> playlist
)
4337 begin_reversible_command (_("clear playlist"));
4338 playlist
->clear_history ();
4340 _session
->add_command (new StatefulDiffCommand (playlist
));
4341 commit_reversible_command ();
4345 Editor::nudge_track (bool use_edit
, bool forwards
)
4347 boost::shared_ptr
<Playlist
> playlist
;
4348 nframes64_t distance
;
4349 nframes64_t next_distance
;
4353 start
= get_preferred_edit_position();
4358 if ((distance
= get_nudge_distance (start
, next_distance
)) == 0) {
4362 if (selection
->tracks
.empty()) {
4366 begin_reversible_command (_("nudge track"));
4368 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
4370 if ((playlist
= (*i
)->playlist()) == 0) {
4374 playlist
->clear_history ();
4375 playlist
->clear_owned_history ();
4377 playlist
->nudge_after (start
, distance
, forwards
);
4379 vector
<StatefulDiffCommand
*> cmds
;
4381 playlist
->rdiff (cmds
);
4383 for (vector
<StatefulDiffCommand
*>::iterator c
= cmds
.begin(); c
!= cmds
.end(); ++c
) {
4384 _session
->add_command (*c
);
4387 _session
->add_command (new StatefulDiffCommand (playlist
));
4390 commit_reversible_command ();
4394 Editor::remove_last_capture ()
4396 vector
<string
> choices
;
4403 if (Config
->get_verify_remove_last_capture()) {
4404 prompt
= _("Do you really want to destroy the last capture?"
4405 "\n(This is destructive and cannot be undone)");
4407 choices
.push_back (_("No, do nothing."));
4408 choices
.push_back (_("Yes, destroy it."));
4410 Gtkmm2ext::Choice
prompter (_("Destroy last capture"), prompt
, choices
);
4412 if (prompter
.run () == 1) {
4413 _session
->remove_last_capture ();
4417 _session
->remove_last_capture();
4422 Editor::normalize_region ()
4429 get_regions_for_action (rs
);
4435 Dialog
dialog (rs
.size() > 1 ? _("Normalize regions") : _("Normalize region"));
4437 hbox
.set_spacing (6);
4438 hbox
.set_border_width (6);
4439 hbox
.pack_start (*manage (new Label (_("Normalize to:"))));
4440 SpinButton
spin (0.2, 2);
4441 spin
.set_range (-112, 0);
4442 spin
.set_increments (0.1, 1);
4444 hbox
.pack_start (spin
);
4445 spin
.set_value (_last_normalization_value
);
4446 hbox
.pack_start (*manage (new Label (_("dbFS"))));
4448 dialog
.get_vbox()->set_spacing (12);
4449 dialog
.get_vbox()->pack_start (hbox
);
4450 dialog
.add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
4451 dialog
.add_button (_("Normalize"), RESPONSE_ACCEPT
);
4453 if (dialog
.run () == RESPONSE_CANCEL
) {
4457 begin_reversible_command (_("normalize"));
4459 track_canvas
->get_window()->set_cursor (*wait_cursor
);
4462 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ++r
) {
4463 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*r
);
4466 arv
->region()->clear_history ();
4467 arv
->audio_region()->normalize_to (spin
.get_value());
4468 _session
->add_command (new StatefulDiffCommand (arv
->region()));
4472 commit_reversible_command ();
4473 track_canvas
->get_window()->set_cursor (*current_canvas_cursor
);
4475 _last_normalization_value
= spin
.get_value ();
4480 Editor::reset_region_scale_amplitude ()
4488 get_regions_for_action (rs
);
4494 begin_reversible_command ("reset gain");
4496 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ++r
) {
4497 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*r
);
4500 arv
->region()->clear_history ();
4501 arv
->audio_region()->set_scale_amplitude (1.0f
);
4502 _session
->add_command (new StatefulDiffCommand (arv
->region()));
4505 commit_reversible_command ();
4509 Editor::adjust_region_scale_amplitude (bool up
)
4517 get_regions_for_action (rs
);
4523 begin_reversible_command ("denormalize");
4525 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ++r
) {
4526 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*r
);
4531 arv
->region()->clear_history ();
4533 double fraction
= gain_to_slider_position (arv
->audio_region()->scale_amplitude ());
4537 fraction
= min (fraction
, 1.0);
4540 fraction
= max (fraction
, 0.0);
4543 if (!up
&& fraction
<= 0) {
4547 fraction
= slider_position_to_gain (fraction
);
4549 if (up
&& fraction
>= 2.0) {
4553 arv
->audio_region()->set_scale_amplitude (fraction
);
4554 _session
->add_command (new StatefulDiffCommand (arv
->region()));
4557 commit_reversible_command ();
4562 Editor::reverse_region ()
4568 Reverse
rev (*_session
);
4569 apply_filter (rev
, _("reverse regions"));
4573 Editor::strip_region_silence ()
4580 get_regions_for_action (rs
);
4586 std::list
<boost::shared_ptr
<AudioRegion
> > ar
;
4588 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4589 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*> (*i
);
4591 ar
.push_back (arv
->audio_region ());
4595 StripSilenceDialog
d (_session
, ar
);
4596 int const r
= d
.run ();
4598 if (r
== Gtk::RESPONSE_OK
) {
4599 StripSilence
s (*_session
, d
.threshold (), d
.minimum_length (), d
.fade_length ());
4600 apply_filter (s
, _("strip silence"));
4605 Editor::apply_midi_note_edit_op_to_region (MidiOperator
& op
, MidiRegionView
& mrv
)
4607 Evoral::Sequence
<Evoral::MusicalTime
>::Notes selected
;
4608 mrv
.selection_as_notelist (selected
, true);
4610 vector
<Evoral::Sequence
<Evoral::MusicalTime
>::Notes
> v
;
4611 v
.push_back (selected
);
4613 return op (mrv
.midi_region()->model(), v
);
4617 Editor::apply_midi_note_edit_op (MidiOperator
& op
)
4622 get_regions_for_action (rs
);
4628 begin_reversible_command (op
.name ());
4630 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ) {
4631 RegionSelection::iterator tmp
= r
;
4634 MidiRegionView
* const mrv
= dynamic_cast<MidiRegionView
*> (*r
);
4637 cmd
= apply_midi_note_edit_op_to_region (op
, *mrv
);
4640 _session
->add_command (cmd
);
4647 commit_reversible_command ();
4652 Editor::fork_region ()
4656 get_regions_for_action (rs
);
4662 begin_reversible_command (_("Fork Region(s)"));
4664 track_canvas
->get_window()->set_cursor (*wait_cursor
);
4667 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ) {
4668 RegionSelection::iterator tmp
= r
;
4671 MidiRegionView
* const mrv
= dynamic_cast<MidiRegionView
*>(*r
);
4674 boost::shared_ptr
<Playlist
> playlist
= mrv
->region()->playlist();
4675 boost::shared_ptr
<MidiRegion
> newregion
= mrv
->midi_region()->clone ();
4677 playlist
->clear_history ();
4678 cerr
<< "Replace region with " << newregion
->name() << endl
;
4679 playlist
->replace_region (mrv
->region(), newregion
, mrv
->region()->position());
4680 _session
->add_command(new StatefulDiffCommand (playlist
));
4686 commit_reversible_command ();
4689 track_canvas
->get_window()->set_cursor (*current_canvas_cursor
);
4693 Editor::quantize_region ()
4699 QuantizeDialog
* qd
= new QuantizeDialog (*this);
4702 const int r
= qd
->run ();
4705 if (r
== Gtk::RESPONSE_OK
) {
4706 Quantize
quant (*_session
, Plain
,
4707 qd
->snap_start(), qd
->snap_end(),
4708 qd
->start_grid_size(), qd
->end_grid_size(),
4709 qd
->strength(), qd
->swing(), qd
->threshold());
4711 apply_midi_note_edit_op (quant
);
4716 Editor::apply_filter (Filter
& filter
, string command
)
4720 get_regions_for_action (rs
);
4726 begin_reversible_command (command
);
4728 track_canvas
->get_window()->set_cursor (*wait_cursor
);
4731 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ) {
4732 RegionSelection::iterator tmp
= r
;
4735 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*r
);
4737 boost::shared_ptr
<Playlist
> playlist
= arv
->region()->playlist();
4739 if (arv
->audio_region()->apply (filter
) == 0) {
4741 playlist
->clear_history ();
4743 if (filter
.results
.empty ()) {
4745 /* no regions returned; remove the old one */
4746 playlist
->remove_region (arv
->region ());
4750 std::vector
<boost::shared_ptr
<Region
> >::iterator res
= filter
.results
.begin ();
4752 /* first region replaces the old one */
4753 playlist
->replace_region (arv
->region(), *res
, (*res
)->position());
4757 while (res
!= filter
.results
.end()) {
4758 playlist
->add_region (*res
, (*res
)->position());
4764 _session
->add_command(new StatefulDiffCommand (playlist
));
4773 commit_reversible_command ();
4777 track_canvas
->get_window()->set_cursor (*current_canvas_cursor
);
4781 Editor::region_selection_op (void (Region::*pmf
)(void))
4783 for (RegionSelection::iterator i
= selection
->regions
.begin(); i
!= selection
->regions
.end(); ++i
) {
4784 Region
* region
= (*i
)->region().get();
4791 Editor::region_selection_op (void (Region::*pmf
)(void*), void *arg
)
4793 for (RegionSelection::iterator i
= selection
->regions
.begin(); i
!= selection
->regions
.end(); ++i
) {
4794 Region
* region
= (*i
)->region().get();
4795 (region
->*pmf
)(arg
);
4800 Editor::region_selection_op (void (Region::*pmf
)(bool), bool yn
)
4802 for (RegionSelection::iterator i
= selection
->regions
.begin(); i
!= selection
->regions
.end(); ++i
) {
4803 Region
* region
= (*i
)->region().get();
4809 Editor::external_edit_region ()
4815 Editor::brush (nframes64_t pos
)
4817 RegionSelection sel
;
4820 get_regions_for_action (rs
);
4828 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4829 mouse_brush_insert_region ((*i
), pos
);
4834 Editor::reset_region_gain_envelopes ()
4836 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4838 if (!_session
|| rs
.empty()) {
4842 _session
->begin_reversible_command (_("reset region gain"));
4844 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4845 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*i
);
4847 boost::shared_ptr
<AutomationList
> alist (arv
->audio_region()->envelope());
4848 XMLNode
& before (alist
->get_state());
4850 arv
->audio_region()->set_default_envelope ();
4851 _session
->add_command (new MementoCommand
<AutomationList
>(*arv
->audio_region()->envelope().get(), &before
, &alist
->get_state()));
4855 _session
->commit_reversible_command ();
4859 Editor::toggle_gain_envelope_visibility ()
4861 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4863 if (!_session
|| rs
.empty()) {
4867 _session
->begin_reversible_command (_("region gain envelope visible"));
4869 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4870 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*i
);
4872 arv
->region()->clear_history ();
4873 arv
->set_envelope_visible (!arv
->envelope_visible());
4874 _session
->add_command (new StatefulDiffCommand (arv
->region()));
4878 _session
->commit_reversible_command ();
4882 Editor::toggle_gain_envelope_active ()
4884 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4886 if (!_session
|| rs
.empty()) {
4890 _session
->begin_reversible_command (_("region gain envelope active"));
4892 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4893 AudioRegionView
* const arv
= dynamic_cast<AudioRegionView
*>(*i
);
4895 arv
->region()->clear_history ();
4896 arv
->audio_region()->set_envelope_active (!arv
->audio_region()->envelope_active());
4897 _session
->add_command (new StatefulDiffCommand (arv
->region()));
4901 _session
->commit_reversible_command ();
4905 Editor::toggle_region_lock ()
4907 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4909 if (!_session
|| rs
.empty()) {
4913 _session
->begin_reversible_command (_("region lock"));
4915 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4916 (*i
)->region()->clear_history ();
4917 (*i
)->region()->set_locked (!(*i
)->region()->locked());
4918 _session
->add_command (new StatefulDiffCommand ((*i
)->region()));
4921 _session
->commit_reversible_command ();
4925 Editor::toggle_region_lock_style ()
4927 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4929 if (!_session
|| rs
.empty()) {
4933 _session
->begin_reversible_command (_("region lock style"));
4935 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4936 (*i
)->region()->clear_history ();
4937 Region::PositionLockStyle
const ns
= (*i
)->region()->positional_lock_style() == Region::AudioTime
? Region::MusicTime
: Region::AudioTime
;
4938 (*i
)->region()->set_position_lock_style (ns
);
4939 _session
->add_command (new StatefulDiffCommand ((*i
)->region()));
4942 _session
->commit_reversible_command ();
4947 Editor::toggle_region_mute ()
4949 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4951 if (!_session
|| rs
.empty()) {
4955 _session
->begin_reversible_command (_("region mute"));
4957 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4958 (*i
)->region()->clear_history ();
4959 (*i
)->region()->set_muted (!(*i
)->region()->muted());
4960 _session
->add_command (new StatefulDiffCommand ((*i
)->region()));
4963 _session
->commit_reversible_command ();
4967 Editor::toggle_region_opaque ()
4969 RegionSelection rs
= get_equivalent_regions (selection
->regions
, ARDOUR::Properties::edit
.property_id
);
4971 if (!_session
|| rs
.empty()) {
4975 _session
->begin_reversible_command (_("region opacity"));
4977 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
4978 (*i
)->region()->clear_history ();
4979 (*i
)->region()->set_opaque (!(*i
)->region()->opaque());
4980 _session
->add_command (new StatefulDiffCommand ((*i
)->region()));
4983 _session
->commit_reversible_command ();
4987 Editor::toggle_record_enable ()
4989 bool new_state
= false;
4991 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
4992 RouteTimeAxisView
*rtav
= dynamic_cast<RouteTimeAxisView
*>(*i
);
4995 if (!rtav
->is_track())
4999 new_state
= !rtav
->track()->record_enabled();
5003 rtav
->track()->set_record_enable(new_state
, this);
5009 Editor::set_fade_length (bool in
)
5013 get_regions_for_action (rs
, true);
5019 /* we need a region to measure the offset from the start */
5021 RegionView
* rv
= rs
.front ();
5023 nframes64_t pos
= get_preferred_edit_position();
5027 if (pos
> rv
->region()->last_frame() || pos
< rv
->region()->first_frame()) {
5028 /* edit point is outside the relevant region */
5033 if (pos
<= rv
->region()->position()) {
5037 len
= pos
- rv
->region()->position();
5038 cmd
= _("set fade in length");
5040 if (pos
>= rv
->region()->last_frame()) {
5044 len
= rv
->region()->last_frame() - pos
;
5045 cmd
= _("set fade out length");
5048 begin_reversible_command (cmd
);
5050 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
5051 AudioRegionView
* tmp
= dynamic_cast<AudioRegionView
*> (*x
);
5057 boost::shared_ptr
<AutomationList
> alist
;
5059 alist
= tmp
->audio_region()->fade_in();
5061 alist
= tmp
->audio_region()->fade_out();
5064 XMLNode
&before
= alist
->get_state();
5067 tmp
->audio_region()->set_fade_in_length (len
);
5068 tmp
->audio_region()->set_fade_in_active (true);
5070 tmp
->audio_region()->set_fade_out_length (len
);
5071 tmp
->audio_region()->set_fade_out_active (true);
5074 XMLNode
&after
= alist
->get_state();
5075 _session
->add_command(new MementoCommand
<AutomationList
>(*alist
, &before
, &after
));
5078 commit_reversible_command ();
5082 Editor::toggle_fade_active (bool in
)
5086 get_regions_for_action (rs
);
5092 const char* cmd
= (in
? _("toggle fade in active") : _("toggle fade out active"));
5093 bool have_switch
= false;
5096 begin_reversible_command (cmd
);
5098 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
5099 AudioRegionView
* tmp
= dynamic_cast<AudioRegionView
*> (*x
);
5105 boost::shared_ptr
<AudioRegion
> region (tmp
->audio_region());
5107 /* make the behaviour consistent across all regions */
5111 yn
= region
->fade_in_active();
5113 yn
= region
->fade_out_active();
5118 region
->clear_history ();
5121 region
->set_fade_in_active (!yn
);
5123 region
->set_fade_out_active (!yn
);
5126 _session
->add_command(new StatefulDiffCommand (region
));
5129 commit_reversible_command ();
5133 Editor::set_fade_in_shape (AudioRegion::FadeShape shape
)
5137 get_regions_for_action (rs
);
5143 begin_reversible_command (_("set fade in shape"));
5145 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
5146 AudioRegionView
* tmp
= dynamic_cast<AudioRegionView
*> (*x
);
5152 boost::shared_ptr
<AutomationList
> alist
= tmp
->audio_region()->fade_in();
5153 XMLNode
&before
= alist
->get_state();
5155 tmp
->audio_region()->set_fade_in_shape (shape
);
5157 XMLNode
&after
= alist
->get_state();
5158 _session
->add_command(new MementoCommand
<AutomationList
>(*alist
.get(), &before
, &after
));
5161 commit_reversible_command ();
5166 Editor::set_fade_out_shape (AudioRegion::FadeShape shape
)
5170 get_regions_for_action (rs
);
5176 begin_reversible_command (_("set fade out shape"));
5178 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
5179 AudioRegionView
* tmp
= dynamic_cast<AudioRegionView
*> (*x
);
5185 boost::shared_ptr
<AutomationList
> alist
= tmp
->audio_region()->fade_out();
5186 XMLNode
&before
= alist
->get_state();
5188 tmp
->audio_region()->set_fade_out_shape (shape
);
5190 XMLNode
&after
= alist
->get_state();
5191 _session
->add_command(new MementoCommand
<AutomationList
>(*alist
.get(), &before
, &after
));
5194 commit_reversible_command ();
5198 Editor::set_fade_in_active (bool yn
)
5202 get_regions_for_action (rs
);
5208 begin_reversible_command (_("set fade in active"));
5210 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
5211 AudioRegionView
* tmp
= dynamic_cast<AudioRegionView
*> (*x
);
5218 boost::shared_ptr
<AudioRegion
> ar (tmp
->audio_region());
5220 ar
->clear_history ();
5221 ar
->set_fade_in_active (yn
);
5222 _session
->add_command (new StatefulDiffCommand (ar
));
5225 commit_reversible_command ();
5229 Editor::set_fade_out_active (bool yn
)
5233 get_regions_for_action (rs
);
5239 begin_reversible_command (_("set fade out active"));
5241 for (RegionSelection::iterator x
= rs
.begin(); x
!= rs
.end(); ++x
) {
5242 AudioRegionView
* tmp
= dynamic_cast<AudioRegionView
*> (*x
);
5248 boost::shared_ptr
<AudioRegion
> ar (tmp
->audio_region());
5250 ar
->clear_history ();
5251 ar
->set_fade_out_active (yn
);
5252 _session
->add_command(new StatefulDiffCommand (ar
));
5255 commit_reversible_command ();
5259 Editor::toggle_selected_region_fades (int dir
)
5262 RegionSelection::iterator i
;
5263 boost::shared_ptr
<AudioRegion
> ar
;
5266 get_regions_for_action (rs
);
5272 for (i
= rs
.begin(); i
!= rs
.end(); ++i
) {
5273 if ((ar
= boost::dynamic_pointer_cast
<AudioRegion
>((*i
)->region())) != 0) {
5275 yn
= ar
->fade_out_active ();
5277 yn
= ar
->fade_in_active ();
5283 if (i
== rs
.end()) {
5287 /* XXX should this undo-able? */
5289 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
5290 if ((ar
= boost::dynamic_pointer_cast
<AudioRegion
>((*i
)->region())) == 0) {
5293 if (dir
== 1 || dir
== 0) {
5294 ar
->set_fade_in_active (!yn
);
5297 if (dir
== -1 || dir
== 0) {
5298 ar
->set_fade_out_active (!yn
);
5304 /** Update region fade visibility after its configuration has been changed */
5306 Editor::update_region_fade_visibility ()
5308 bool _fade_visibility
= _session
->config
.get_show_region_fades ();
5310 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
5311 AudioTimeAxisView
* v
= dynamic_cast<AudioTimeAxisView
*>(*i
);
5313 if (_fade_visibility
) {
5314 v
->audio_view()->show_all_fades ();
5316 v
->audio_view()->hide_all_fades ();
5322 /** Update crossfade visibility after its configuration has been changed */
5324 Editor::update_xfade_visibility ()
5326 _xfade_visibility
= _session
->config
.get_xfades_visible ();
5328 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
5329 AudioTimeAxisView
* v
= dynamic_cast<AudioTimeAxisView
*>(*i
);
5331 if (_xfade_visibility
) {
5332 v
->show_all_xfades ();
5334 v
->hide_all_xfades ();
5341 Editor::set_edit_point ()
5346 if (!mouse_frame (where
, ignored
)) {
5352 if (selection
->markers
.empty()) {
5354 mouse_add_new_marker (where
);
5359 Location
* loc
= find_location_from_marker (selection
->markers
.front(), ignored
);
5362 loc
->move_to (where
);
5368 Editor::set_playhead_cursor ()
5370 if (entered_marker
) {
5371 _session
->request_locate (entered_marker
->position(), _session
->transport_rolling());
5376 if (!mouse_frame (where
, ignored
)) {
5383 _session
->request_locate (where
, _session
->transport_rolling());
5393 get_regions_for_action (rs
, true);
5395 nframes64_t where
= get_preferred_edit_position();
5401 split_regions_at (where
, rs
);
5405 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected
)
5407 if (entered_track
&& mouse_mode
== MouseObject
) {
5408 if (!selection
->tracks
.empty()) {
5409 if (!selection
->selected (entered_track
)) {
5410 selection
->add (entered_track
);
5413 /* there is no selection, but this operation requires/prefers selected objects */
5415 if (op_really_wants_one_track_if_none_are_selected
) {
5416 selection
->set (entered_track
);
5422 struct EditorOrderRouteSorter
{
5423 bool operator() (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
5424 /* use of ">" forces the correct sort order */
5425 return a
->order_key ("editor") < b
->order_key ("editor");
5430 Editor::select_next_route()
5432 if (selection
->tracks
.empty()) {
5433 selection
->set (track_views
.front());
5437 TimeAxisView
* current
= selection
->tracks
.front();
5441 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
5442 if (*i
== current
) {
5444 if (i
!= track_views
.end()) {
5447 current
= (*(track_views
.begin()));
5448 //selection->set (*(track_views.begin()));
5453 rui
= dynamic_cast<RouteUI
*>(current
);
5454 } while ( current
->hidden() || (rui
!= NULL
&& !rui
->route()->active()));
5456 selection
->set(current
);
5458 ensure_track_visible(current
);
5462 Editor::select_prev_route()
5464 if (selection
->tracks
.empty()) {
5465 selection
->set (track_views
.front());
5469 TimeAxisView
* current
= selection
->tracks
.front();
5473 for (TrackViewList::reverse_iterator i
= track_views
.rbegin(); i
!= track_views
.rend(); ++i
) {
5474 if (*i
== current
) {
5476 if (i
!= track_views
.rend()) {
5479 current
= *(track_views
.rbegin());
5484 rui
= dynamic_cast<RouteUI
*>(current
);
5485 } while ( current
->hidden() || (rui
!= NULL
&& !rui
->route()->active()));
5487 selection
->set (current
);
5489 ensure_track_visible(current
);
5493 Editor::ensure_track_visible(TimeAxisView
*track
)
5495 if (track
->hidden())
5498 double const current_view_min_y
= vertical_adjustment
.get_value();
5499 double const current_view_max_y
= vertical_adjustment
.get_value() + vertical_adjustment
.get_page_size() - canvas_timebars_vsize
;
5501 double const track_min_y
= track
->y_position ();
5502 double const track_max_y
= track
->y_position () + track
->effective_height ();
5504 if (track_min_y
>= current_view_min_y
&&
5505 track_max_y
<= current_view_max_y
) {
5511 if (track_min_y
< current_view_min_y
) {
5512 // Track is above the current view
5513 new_value
= track_min_y
;
5515 // Track is below the current view
5516 new_value
= track
->y_position () + track
->effective_height() + canvas_timebars_vsize
- vertical_adjustment
.get_page_size();
5519 vertical_adjustment
.set_value(new_value
);
5523 Editor::set_loop_from_selection (bool play
)
5525 if (_session
== 0 || selection
->time
.empty()) {
5529 nframes64_t start
= selection
->time
[clicked_selection
].start
;
5530 nframes64_t end
= selection
->time
[clicked_selection
].end
;
5532 set_loop_range (start
, end
, _("set loop range from selection"));
5535 _session
->request_play_loop (true);
5536 _session
->request_locate (start
, true);
5541 Editor::set_loop_from_edit_range (bool play
)
5543 if (_session
== 0) {
5550 if (!get_edit_op_range (start
, end
)) {
5554 set_loop_range (start
, end
, _("set loop range from edit range"));
5557 _session
->request_play_loop (true);
5558 _session
->request_locate (start
, true);
5563 Editor::set_loop_from_region (bool play
)
5565 nframes64_t start
= max_frames
;
5566 nframes64_t end
= 0;
5570 get_regions_for_action (rs
);
5576 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
5577 if ((*i
)->region()->position() < start
) {
5578 start
= (*i
)->region()->position();
5580 if ((*i
)->region()->last_frame() + 1 > end
) {
5581 end
= (*i
)->region()->last_frame() + 1;
5585 set_loop_range (start
, end
, _("set loop range from region"));
5588 _session
->request_play_loop (true);
5589 _session
->request_locate (start
, true);
5594 Editor::set_punch_from_selection ()
5596 if (_session
== 0 || selection
->time
.empty()) {
5600 nframes64_t start
= selection
->time
[clicked_selection
].start
;
5601 nframes64_t end
= selection
->time
[clicked_selection
].end
;
5603 set_punch_range (start
, end
, _("set punch range from selection"));
5607 Editor::set_punch_from_edit_range ()
5609 if (_session
== 0) {
5616 if (!get_edit_op_range (start
, end
)) {
5620 set_punch_range (start
, end
, _("set punch range from edit range"));
5624 Editor::set_punch_from_region ()
5626 nframes64_t start
= max_frames
;
5627 nframes64_t end
= 0;
5631 get_regions_for_action (rs
);
5637 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
5638 if ((*i
)->region()->position() < start
) {
5639 start
= (*i
)->region()->position();
5641 if ((*i
)->region()->last_frame() + 1 > end
) {
5642 end
= (*i
)->region()->last_frame() + 1;
5646 set_punch_range (start
, end
, _("set punch range from region"));
5650 Editor::pitch_shift_regions ()
5654 get_regions_for_action (rs
);
5660 pitch_shift (rs
, 1.2);
5664 Editor::use_region_as_bar ()
5672 get_regions_for_action (rs
);
5678 RegionView
* rv
= rs
.front();
5680 define_one_bar (rv
->region()->position(), rv
->region()->last_frame() + 1);
5684 Editor::use_range_as_bar ()
5686 nframes64_t start
, end
;
5687 if (get_edit_op_range (start
, end
)) {
5688 define_one_bar (start
, end
);
5693 Editor::define_one_bar (nframes64_t start
, nframes64_t end
)
5695 nframes64_t length
= end
- start
;
5697 const Meter
& m (_session
->tempo_map().meter_at (start
));
5699 /* length = 1 bar */
5701 /* now we want frames per beat.
5702 we have frames per bar, and beats per bar, so ...
5705 double frames_per_beat
= length
/ m
.beats_per_bar();
5707 /* beats per minute = */
5709 double beats_per_minute
= (_session
->frame_rate() * 60.0) / frames_per_beat
;
5711 /* now decide whether to:
5713 (a) set global tempo
5714 (b) add a new tempo marker
5718 const TempoSection
& t (_session
->tempo_map().tempo_section_at (start
));
5720 bool do_global
= false;
5722 if ((_session
->tempo_map().n_tempos() == 1) && (_session
->tempo_map().n_meters() == 1)) {
5724 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5725 at the start, or create a new marker
5728 vector
<string
> options
;
5729 options
.push_back (_("Cancel"));
5730 options
.push_back (_("Add new marker"));
5731 options
.push_back (_("Set global tempo"));
5734 _("Define one bar"),
5735 _("Do you want to set the global tempo or add a new tempo marker?"),
5739 c
.set_default_response (2);
5755 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5756 if the marker is at the region starter, change it, otherwise add
5761 begin_reversible_command (_("set tempo from region"));
5762 XMLNode
& before (_session
->tempo_map().get_state());
5765 _session
->tempo_map().change_initial_tempo (beats_per_minute
, t
.note_type());
5766 } else if (t
.frame() == start
) {
5767 _session
->tempo_map().change_existing_tempo_at (start
, beats_per_minute
, t
.note_type());
5769 _session
->tempo_map().add_tempo (Tempo (beats_per_minute
, t
.note_type()), start
);
5772 XMLNode
& after (_session
->tempo_map().get_state());
5774 _session
->add_command (new MementoCommand
<TempoMap
>(_session
->tempo_map(), &before
, &after
));
5775 commit_reversible_command ();
5779 Editor::split_region_at_transients ()
5781 AnalysisFeatureList positions
;
5789 get_regions_for_action (rs
);
5795 _session
->begin_reversible_command (_("split regions"));
5797 for (RegionSelection::iterator i
= rs
.begin(); i
!= rs
.end(); ) {
5799 RegionSelection::iterator tmp
;
5804 boost::shared_ptr
<AudioRegion
> ar
= boost::dynamic_pointer_cast
<AudioRegion
> ((*i
)->region());
5806 if (ar
&& (ar
->get_transients (positions
) == 0)) {
5807 split_region_at_points ((*i
)->region(), positions
, true);
5814 _session
->commit_reversible_command ();
5819 Editor::split_region_at_points (boost::shared_ptr
<Region
> r
, AnalysisFeatureList
& positions
, bool can_ferret
)
5821 bool use_rhythmic_rodent
= false;
5823 boost::shared_ptr
<Playlist
> pl
= r
->playlist();
5829 if (positions
.empty()) {
5834 if (positions
.size() > 20) {
5835 Glib::ustring msgstr
= string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r
->name(), positions
.size() + 1);
5836 MessageDialog
msg (msgstr
,
5839 Gtk::BUTTONS_OK_CANCEL
);
5842 msg
.add_button (_("Call for the Ferret!"), RESPONSE_APPLY
);
5843 msg
.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5845 msg
.set_secondary_text (_("Press OK to continue with this split operation"));
5848 msg
.set_title (_("Excessive split?"));
5851 int response
= msg
.run();
5856 case RESPONSE_APPLY
:
5857 use_rhythmic_rodent
= true;
5864 if (use_rhythmic_rodent
) {
5865 show_rhythm_ferret ();
5869 AnalysisFeatureList::const_iterator x
;
5871 nframes64_t pos
= r
->position();
5873 pl
->clear_history ();
5875 x
= positions
.begin();
5877 while (x
!= positions
.end()) {
5884 if (x
== positions
.end()) {
5889 pl
->remove_region (r
);
5891 while (x
!= positions
.end()) {
5893 /* file start = original start + how far we from the initial position ?
5896 nframes64_t file_start
= r
->start() + (pos
- r
->position());
5898 /* length = next position - current position
5901 nframes64_t len
= (*x
) - pos
;
5903 /* XXX we do we really want to allow even single-sample regions?
5904 shouldn't we have some kind of lower limit on region size?
5913 if (RegionFactory::region_name (new_name
, r
->name())) {
5917 /* do NOT announce new regions 1 by one, just wait till they are all done */
5921 plist
.add (ARDOUR::Properties::start
, file_start
);
5922 plist
.add (ARDOUR::Properties::length
, len
);
5923 plist
.add (ARDOUR::Properties::name
, new_name
);
5924 plist
.add (ARDOUR::Properties::layer
, 0);
5926 boost::shared_ptr
<Region
> nr
= RegionFactory::create (r
->sources(), plist
, false);
5927 pl
->add_region (nr
, pos
);
5932 if (*x
> r
->last_frame()) {
5934 /* add final fragment */
5936 file_start
= r
->start() + (pos
- r
->position());
5937 len
= r
->last_frame() - pos
;
5939 PropertyList plist2
;
5941 plist2
.add (ARDOUR::Properties::start
, file_start
);
5942 plist2
.add (ARDOUR::Properties::length
, len
);
5943 plist2
.add (ARDOUR::Properties::name
, new_name
);
5944 plist2
.add (ARDOUR::Properties::layer
, 0);
5946 nr
= RegionFactory::create (r
->sources(), plist2
);
5947 pl
->add_region (nr
, pos
);
5955 _session
->add_command (new StatefulDiffCommand (pl
));
5959 Editor::tab_to_transient (bool forward
)
5961 AnalysisFeatureList positions
;
5967 nframes64_t pos
= _session
->audible_frame ();
5969 if (!selection
->tracks
.empty()) {
5971 for (TrackSelection::iterator t
= selection
->tracks
.begin(); t
!= selection
->tracks
.end(); ++t
) {
5973 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (*t
);
5976 boost::shared_ptr
<Track
> tr
= rtv
->track();
5978 boost::shared_ptr
<Playlist
> pl
= tr
->playlist ();
5980 nframes64_t result
= pl
->find_next_transient (pos
, forward
? 1 : -1);
5983 positions
.push_back (result
);
5994 get_regions_for_action (rs
);
6000 for (RegionSelection::iterator r
= rs
.begin(); r
!= rs
.end(); ++r
) {
6001 (*r
)->region()->get_transients (positions
);
6005 TransientDetector::cleanup_transients (positions
, _session
->frame_rate(), 3.0);
6008 AnalysisFeatureList::iterator x
;
6010 for (x
= positions
.begin(); x
!= positions
.end(); ++x
) {
6016 if (x
!= positions
.end ()) {
6017 _session
->request_locate (*x
);
6021 AnalysisFeatureList::reverse_iterator x
;
6023 for (x
= positions
.rbegin(); x
!= positions
.rend(); ++x
) {
6029 if (x
!= positions
.rend ()) {
6030 _session
->request_locate (*x
);
6035 Editor::playhead_forward_to_grid ()
6037 if (!_session
) return;
6038 nframes64_t pos
= playhead_cursor
->current_frame
;
6039 if (pos
< max_frames
- 1) {
6041 snap_to_internal (pos
, 1, false);
6042 _session
->request_locate (pos
);
6048 Editor::playhead_backward_to_grid ()
6050 if (!_session
) return;
6051 nframes64_t pos
= playhead_cursor
->current_frame
;
6054 snap_to_internal (pos
, -1, false);
6055 _session
->request_locate (pos
);
6060 Editor::set_track_height (Height h
)
6062 TrackSelection
& ts (selection
->tracks
);
6064 for (TrackSelection::iterator x
= ts
.begin(); x
!= ts
.end(); ++x
) {
6065 (*x
)->set_height (h
);
6070 Editor::toggle_tracks_active ()
6072 TrackSelection
& ts (selection
->tracks
);
6074 bool target
= false;
6080 for (TrackSelection::iterator x
= ts
.begin(); x
!= ts
.end(); ++x
) {
6081 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*>(*x
);
6085 target
= !rtv
->_route
->active();
6088 rtv
->_route
->set_active (target
);
6094 Editor::remove_tracks ()
6096 TrackSelection
& ts (selection
->tracks
);
6102 vector
<string
> choices
;
6106 const char* trackstr
;
6108 vector
<boost::shared_ptr
<Route
> > routes
;
6110 for (TrackSelection::iterator x
= ts
.begin(); x
!= ts
.end(); ++x
) {
6111 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (*x
);
6113 if (rtv
->is_track()) {
6119 routes
.push_back (rtv
->_route
);
6122 if (ntracks
+ nbusses
== 0) {
6127 trackstr
= _("tracks");
6129 trackstr
= _("track");
6133 busstr
= _("busses");
6140 prompt
= string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6141 "(You may also lose the playlists associated with the %2)\n\n"
6142 "This action cannot be undone!"),
6143 ntracks
, trackstr
, nbusses
, busstr
);
6145 prompt
= string_compose (_("Do you really want to remove %1 %2?\n"
6146 "(You may also lose the playlists associated with the %2)\n\n"
6147 "This action cannot be undone!"),
6150 } else if (nbusses
) {
6151 prompt
= string_compose (_("Do you really want to remove %1 %2?"),
6155 choices
.push_back (_("No, do nothing."));
6156 if (ntracks
+ nbusses
> 1) {
6157 choices
.push_back (_("Yes, remove them."));
6159 choices
.push_back (_("Yes, remove it."));
6164 title
= string_compose (_("Remove %1"), trackstr
);
6166 title
= string_compose (_("Remove %1"), busstr
);
6169 Choice
prompter (title
, prompt
, choices
);
6171 if (prompter
.run () != 1) {
6175 for (vector
<boost::shared_ptr
<Route
> >::iterator x
= routes
.begin(); x
!= routes
.end(); ++x
) {
6176 _session
->remove_route (*x
);
6181 Editor::do_insert_time ()
6183 if (selection
->tracks
.empty()) {
6187 ArdourDialog
d (*this, _("Insert Time"));
6189 nframes64_t
const pos
= get_preferred_edit_position ();
6191 d
.get_vbox()->set_border_width (12);
6192 d
.get_vbox()->set_spacing (4);
6195 table
.set_spacings (4);
6197 Label
time_label (_("Time to insert:"));
6198 time_label
.set_alignment (1, 0.5);
6199 table
.attach (time_label
, 0, 1, 0, 1, FILL
| EXPAND
);
6200 AudioClock
clock ("insertTimeClock", true, X_("InsertTimeClock"), true, false, true, true);
6202 clock
.set_session (_session
);
6203 clock
.set_bbt_reference (pos
);
6204 table
.attach (clock
, 1, 2, 0, 1);
6206 Label
intersected_label (_("Intersected regions should:"));
6207 intersected_label
.set_alignment (1, 0.5);
6208 table
.attach (intersected_label
, 0, 1, 1, 2, FILL
| EXPAND
);
6209 ComboBoxText intersected_combo
;
6210 intersected_combo
.append_text (_("stay in position"));
6211 intersected_combo
.append_text (_("move"));
6212 intersected_combo
.append_text (_("be split"));
6213 intersected_combo
.set_active (0);
6214 table
.attach (intersected_combo
, 1, 2, 1, 2);
6216 d
.get_vbox()->pack_start (table
);
6218 CheckButton
move_glued (_("Move glued regions"));
6219 d
.get_vbox()->pack_start (move_glued
);
6220 CheckButton
move_markers (_("Move markers"));
6221 d
.get_vbox()->pack_start (move_markers
);
6222 CheckButton
move_tempos (_("Move tempo and meter changes"));
6223 d
.get_vbox()->pack_start (move_tempos
);
6225 d
.add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
6226 d
.add_button (_("Insert time"), Gtk::RESPONSE_OK
);
6229 int response
= d
.run ();
6231 if (response
!= RESPONSE_OK
) {
6235 nframes64_t distance
= clock
.current_duration (pos
);
6237 if (distance
== 0) {
6241 /* only setting this to keep GCC quiet */
6242 InsertTimeOption opt
= LeaveIntersected
;
6244 switch (intersected_combo
.get_active_row_number ()) {
6246 opt
= LeaveIntersected
;
6249 opt
= MoveIntersected
;
6252 opt
= SplitIntersected
;
6256 insert_time (pos
, distance
, opt
, move_glued
.get_active(), move_markers
.get_active(), move_tempos
.get_active());
6260 Editor::insert_time (nframes64_t pos
, nframes64_t frames
, InsertTimeOption opt
,
6261 bool ignore_music_glue
, bool markers_too
, bool tempo_too
)
6263 bool commit
= false;
6265 if (Config
->get_edit_mode() == Lock
) {
6269 begin_reversible_command (_("insert time"));
6271 for (TrackSelection::iterator x
= selection
->tracks
.begin(); x
!= selection
->tracks
.end(); ++x
) {
6273 boost::shared_ptr
<Playlist
> pl
= (*x
)->playlist();
6277 pl
->clear_history ();
6278 pl
->clear_owned_history ();
6280 if (opt
== SplitIntersected
) {
6284 pl
->shift (pos
, frames
, (opt
== MoveIntersected
), ignore_music_glue
);
6286 vector
<StatefulDiffCommand
*> cmds
;
6290 cerr
<< "Shift generated " << cmds
.size() << " sdc's\n";
6292 for (vector
<StatefulDiffCommand
*>::iterator c
= cmds
.begin(); c
!= cmds
.end(); ++c
) {
6293 _session
->add_command (*c
);
6296 _session
->add_command (new StatefulDiffCommand (pl
));
6301 RouteTimeAxisView
* rtav
= dynamic_cast<RouteTimeAxisView
*> (*x
);
6303 rtav
->route ()->shift (pos
, frames
);
6311 XMLNode
& before (_session
->locations()->get_state());
6312 Locations::LocationList
copy (_session
->locations()->list());
6314 for (Locations::LocationList::iterator i
= copy
.begin(); i
!= copy
.end(); ++i
) {
6316 Locations::LocationList::const_iterator tmp
;
6318 if ((*i
)->start() >= pos
) {
6319 (*i
)->set_start ((*i
)->start() + frames
);
6320 if (!(*i
)->is_mark()) {
6321 (*i
)->set_end ((*i
)->end() + frames
);
6328 XMLNode
& after (_session
->locations()->get_state());
6329 _session
->add_command (new MementoCommand
<Locations
>(*_session
->locations(), &before
, &after
));
6334 _session
->tempo_map().insert_time (pos
, frames
);
6338 commit_reversible_command ();
6343 Editor::fit_selected_tracks ()
6345 fit_tracks (selection
->tracks
);
6349 Editor::fit_tracks (TrackViewList
& tracks
)
6351 if (tracks
.empty()) {
6355 uint32_t child_heights
= 0;
6357 for (TrackSelection::iterator t
= tracks
.begin(); t
!= tracks
.end(); ++t
) {
6359 if (!(*t
)->marked_for_display()) {
6363 child_heights
+= (*t
)->effective_height() - (*t
)->current_height();
6366 uint32_t h
= (uint32_t) floor ((_canvas_height
- child_heights
- canvas_timebars_vsize
) / tracks
.size());
6367 double first_y_pos
= DBL_MAX
;
6369 if (h
< TimeAxisView::preset_height (HeightSmall
)) {
6370 MessageDialog
msg (*this, _("There are too many tracks to fit in the current window"));
6371 /* too small to be displayed */
6375 undo_visual_stack
.push_back (current_visual_state());
6377 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6379 bool prev_was_selected
= false;
6380 bool is_selected
= tracks
.contains (track_views
.front());
6381 bool next_is_selected
;
6383 for (TrackViewList::iterator t
= track_views
.begin(); t
!= track_views
.end(); ++t
) {
6385 TrackViewList::iterator next
;
6390 if (next
!= track_views
.end()) {
6391 next_is_selected
= tracks
.contains (*next
);
6393 next_is_selected
= false;
6397 (*t
)->set_height (h
);
6398 first_y_pos
= std::min ((*t
)->y_position (), first_y_pos
);
6400 if (prev_was_selected
&& next_is_selected
) {
6401 hide_track_in_display (*t
);
6405 prev_was_selected
= is_selected
;
6406 is_selected
= next_is_selected
;
6410 set the controls_layout height now, because waiting for its size
6411 request signal handler will cause the vertical adjustment setting to fail
6414 controls_layout
.property_height () = full_canvas_height
- canvas_timebars_vsize
;
6415 vertical_adjustment
.set_value (first_y_pos
);
6417 redo_visual_stack
.push_back (current_visual_state());
6421 Editor::save_visual_state (uint32_t n
)
6423 while (visual_states
.size() <= n
) {
6424 visual_states
.push_back (0);
6427 delete visual_states
[n
];
6429 visual_states
[n
] = current_visual_state (true);
6434 Editor::goto_visual_state (uint32_t n
)
6436 if (visual_states
.size() <= n
) {
6440 if (visual_states
[n
] == 0) {
6444 use_visual_state (*visual_states
[n
]);
6448 Editor::start_visual_state_op (uint32_t n
)
6450 if (visual_state_op_connection
.empty()) {
6451 visual_state_op_connection
= Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::end_visual_state_op
), n
), 1000);
6456 Editor::cancel_visual_state_op (uint32_t n
)
6458 if (!visual_state_op_connection
.empty()) {
6459 visual_state_op_connection
.disconnect();
6460 goto_visual_state (n
);
6462 //we land here if called from the menu OR if end_visual_state_op has been called
6463 //so check if we are already in visual state n
6464 // XXX not yet checking it at all, but redoing does not hurt
6465 goto_visual_state (n
);
6470 Editor::end_visual_state_op (uint32_t n
)
6472 visual_state_op_connection
.disconnect();
6473 save_visual_state (n
);
6475 PopUp
* pup
= new PopUp (WIN_POS_MOUSE
, 1000, true);
6477 snprintf (buf
, sizeof (buf
), _("Saved view %u"), n
+1);
6478 pup
->set_text (buf
);
6481 return false; // do not call again