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.
28 #include <pbd/error.h>
29 #include <pbd/basename.h>
30 #include <pbd/pthread_utils.h>
32 #include <gtkmm2ext/utils.h>
33 #include <gtkmm2ext/choice.h>
35 #include <ardour/audioengine.h>
36 #include <ardour/session.h>
37 #include <ardour/audioplaylist.h>
38 #include <ardour/audioregion.h>
39 #include <ardour/audio_diskstream.h>
40 #include <ardour/utils.h>
41 #include <ardour/location.h>
42 #include <ardour/named_selection.h>
43 #include <ardour/audio_track.h>
44 #include <ardour/audioplaylist.h>
45 #include <ardour/region_factory.h>
46 #include <ardour/reverse.h>
48 #include "ardour_ui.h"
50 #include "time_axis_view.h"
51 #include "audio_time_axis.h"
52 #include "automation_time_axis.h"
53 #include "streamview.h"
54 #include "regionview.h"
55 #include "rgb_macros.h"
56 #include "selection_templates.h"
57 #include "selection.h"
60 #include "gtk-custom-hruler.h"
61 #include "gui_thread.h"
66 using namespace ARDOUR;
70 using namespace Editing;
72 /***********************************************************************
74 ***********************************************************************/
77 Editor::undo (uint32_t n)
85 Editor::redo (uint32_t n)
93 Editor::set_meter_hold (int32_t cnt)
95 Config->set_meter_hold_off(false);
96 Config->set_meter_hold_short(false);
97 Config->set_meter_hold_medium(false);
98 Config->set_meter_hold_long(false);
103 Config->set_meter_hold_off(true);
106 Config->set_meter_hold_short(true);
109 Config->set_meter_hold_medium(true);
112 Config->set_meter_hold_long(true);
117 session->set_meter_hold (cnt);
122 Editor::set_meter_falloff (int intval)
124 float val = 0.0f; /* off */
127 Config->set_meter_falloff_off(false);
128 Config->set_meter_falloff_slowest(false);
129 Config->set_meter_falloff_slow(false);
130 Config->set_meter_falloff_medium(false);
131 Config->set_meter_falloff_fast(false);
132 Config->set_meter_falloff_faster(false);
133 Config->set_meter_falloff_fastest(false);
139 Config->set_meter_falloff_off(true);
143 Config->set_meter_falloff_slowest(true);
147 Config->set_meter_falloff_slow(true);
151 Config->set_meter_falloff_medium(true);
155 Config->set_meter_falloff_fast(true);
159 Config->set_meter_falloff_faster(true);
163 Config->set_meter_falloff_fastest(true);
168 session->set_meter_falloff (val);
174 Editor::ensure_cursor (jack_nframes_t *pos)
176 *pos = edit_cursor->current_frame;
181 Editor::split_region ()
183 split_region_at (edit_cursor->current_frame);
187 Editor::split_region_at (jack_nframes_t where)
189 split_regions_at (where, selection->audio_regions);
193 Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions)
195 begin_reversible_command (_("split"));
198 for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
200 AudioRegionSelection::iterator tmp;
205 Playlist* pl = (*a)->region.playlist();
207 _new_regionviews_show_envelope = (*a)->envelope_visible();
210 XMLNode &before, &after;
211 before = pl->get_state();
212 pl->split_region ((*a)->region, where);
213 after = pl->get_state();
214 session->add_command(MementoCommand<Playlist>(*pl, before, after));
220 commit_reversible_command ();
221 _new_regionviews_show_envelope = false;
225 Editor::remove_clicked_region ()
227 if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
231 Playlist* playlist = clicked_audio_trackview->playlist();
233 begin_reversible_command (_("remove region"));
234 XMLNode &before = playlist->get_state();
235 playlist->remove_region (&clicked_regionview->region);
236 XMLNode &after = playlist->get_state();
237 session->add_command(MementoCommand<Playlist>(*playlist, before, after));
238 commit_reversible_command ();
242 Editor::destroy_clicked_region ()
244 int32_t selected = selection->audio_regions.size();
246 if (!session || clicked_regionview == 0 && selected == 0) {
250 vector<string> choices;
253 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
254 It cannot be undone\n\
255 Do you really want to destroy %1 ?"),
257 _("these regions") : _("this region")));
259 choices.push_back (_("No, do nothing."));
262 choices.push_back (_("Yes, destroy them."));
264 choices.push_back (_("Yes, destroy it."));
267 Gtkmm2ext::Choice prompter (prompt, choices);
269 if (prompter.run() == 0) { /* first choice */
276 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
277 r.push_back (&(*i)->region);
280 session->destroy_regions (r);
282 } else if (clicked_regionview) {
283 session->destroy_region (&clicked_regionview->region);
288 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
292 jack_nframes_t start = 0;
294 if (selection->time.start () == selection->time.end_frame ()) {
296 /* no current selection-> is there a selected regionview? */
298 if (selection->audio_regions.empty()) {
306 if (!selection->audio_regions.empty()) {
308 rv = *(selection->audio_regions.begin());
309 (*tv) = &rv->get_time_axis_view();
310 region = &rv->region;
312 } else if (!selection->tracks.empty()) {
314 (*tv) = selection->tracks.front();
316 AudioTimeAxisView* atv;
318 if ((atv = dynamic_cast<AudioTimeAxisView*> (*tv)) != 0) {
321 if ((pl = atv->playlist()) == 0) {
325 region = dynamic_cast<AudioRegion*> (pl->top_region_at (start));
333 Editor::extend_selection_to_end_of_region (bool next)
337 jack_nframes_t start;
339 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
343 if (region && selection->time.start () == selection->time.end_frame ()) {
344 start = region->position();
346 start = selection->time.start ();
349 /* Try to leave the selection with the same route if possible */
351 if ((tv = selection->time.track) == 0) {
355 begin_reversible_command (_("extend selection"));
356 selection->set (tv, start, region->position() + region->length());
357 commit_reversible_command ();
361 Editor::extend_selection_to_start_of_region (bool previous)
367 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
371 if (region && selection->time.start () == selection->time.end_frame ()) {
372 end = region->position() + region->length();
374 end = selection->time.end_frame ();
377 /* Try to leave the selection with the same route if possible */
379 if ((tv = selection->time.track) == 0) {
383 begin_reversible_command (_("extend selection"));
384 selection->set (tv, region->position(), end);
385 commit_reversible_command ();
390 Editor::nudge_forward (bool next)
392 jack_nframes_t distance;
393 jack_nframes_t next_distance;
395 if (!session) return;
397 if (!selection->audio_regions.empty()) {
399 begin_reversible_command (_("nudge forward"));
401 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
402 AudioRegion& r ((*i)->region);
404 distance = get_nudge_distance (r.position(), next_distance);
407 distance = next_distance;
410 XMLNode &before = r.playlist()->get_state();
411 r.set_position (r.position() + distance, this);
412 XMLNode &after = r.playlist()->get_state();
413 session->add_command (MementoCommand<Playlist>(*(r.playlist()), before, after));
416 commit_reversible_command ();
419 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
420 session->request_locate (playhead_cursor->current_frame + distance);
425 Editor::nudge_backward (bool next)
427 jack_nframes_t distance;
428 jack_nframes_t next_distance;
430 if (!session) return;
432 if (!selection->audio_regions.empty()) {
434 begin_reversible_command (_("nudge forward"));
436 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
437 AudioRegion& r ((*i)->region);
439 distance = get_nudge_distance (r.position(), next_distance);
442 distance = next_distance;
445 XMLNode &before = r.playlist()->get_state();
447 if (r.position() > distance) {
448 r.set_position (r.position() - distance, this);
450 r.set_position (0, this);
452 XMLNode &after = r.playlist()->get_state();
453 session->add_command(MementoCommand<Playlist>(*(r.playlist()), before, after));
456 commit_reversible_command ();
460 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
462 if (playhead_cursor->current_frame > distance) {
463 session->request_locate (playhead_cursor->current_frame - distance);
465 session->goto_start();
471 Editor::nudge_forward_capture_offset ()
473 jack_nframes_t distance;
475 if (!session) return;
477 if (!selection->audio_regions.empty()) {
479 begin_reversible_command (_("nudge forward"));
481 distance = session->worst_output_latency();
483 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
484 AudioRegion& r ((*i)->region);
486 XMLNode &before, &after;
487 before = r.playlist()->get_state();
488 r.set_position (r.position() + distance, this);
489 after = r.playlist()->get_state();
490 session->add_command(MementoCommand<Playlist>(*(r.playlist()), before, after));
493 commit_reversible_command ();
499 Editor::nudge_backward_capture_offset ()
501 jack_nframes_t distance;
503 if (!session) return;
505 if (!selection->audio_regions.empty()) {
507 begin_reversible_command (_("nudge forward"));
509 distance = session->worst_output_latency();
511 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
512 AudioRegion& r ((*i)->region);
514 XMLNode &before = r.playlist()->get_state();
516 if (r.position() > distance) {
517 r.set_position (r.position() - distance, this);
519 r.set_position (0, this);
521 XMLNode &after = r.playlist()->get_state();
522 session->add_command(MementoCommand<Playlist>(*(r.playlist()), before, after));
525 commit_reversible_command ();
532 Editor::move_to_start ()
534 session->goto_start ();
538 Editor::move_to_end ()
541 session->request_locate (session->current_end_frame());
545 Editor::build_region_boundary_cache ()
547 jack_nframes_t pos = 0;
550 TrackViewList tracks;
552 region_boundary_cache.clear ();
559 case SnapToRegionStart:
562 case SnapToRegionEnd:
565 case SnapToRegionSync:
568 case SnapToRegionBoundary:
572 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
577 TimeAxisView *ontrack = 0;
579 while (pos < session->current_end_frame()) {
581 if (!selection->tracks.empty()) {
583 if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
587 } else if (clicked_trackview) {
590 t.push_back (clicked_trackview);
592 if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
598 if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
606 case SnapToRegionStart:
607 rpos = r->first_frame();
609 case SnapToRegionEnd:
610 rpos = r->last_frame();
612 case SnapToRegionSync:
613 rpos = r->adjust_to_sync (r->first_frame());
616 case SnapToRegionBoundary:
617 rpos = r->last_frame();
624 AudioTimeAxisView *atav;
626 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
627 if (atav->get_diskstream() != 0) {
628 speed = atav->get_diskstream()->speed();
632 rpos = track_frame_to_session_frame(rpos, speed);
634 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
635 if (snap_type == SnapToRegionBoundary) {
636 region_boundary_cache.push_back (r->first_frame());
638 region_boundary_cache.push_back (rpos);
646 Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
648 TrackViewList::iterator i;
649 jack_nframes_t closest = max_frames;
651 jack_nframes_t rpos = 0;
654 jack_nframes_t track_frame;
655 AudioTimeAxisView *atav;
657 for (i = tracks.begin(); i != tracks.end(); ++i) {
659 jack_nframes_t distance;
663 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
664 if (atav->get_diskstream()!=0)
665 track_speed = atav->get_diskstream()->speed();
668 track_frame = session_frame_to_track_frame(frame, track_speed);
670 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
676 rpos = r->first_frame ();
680 rpos = r->last_frame ();
684 rpos = r->adjust_to_sync (r->first_frame());
687 // rpos is a "track frame", converting it to "session frame"
688 rpos = track_frame_to_session_frame(rpos, track_speed);
691 distance = rpos - frame;
693 distance = frame - rpos;
696 if (distance < closest) {
708 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
711 jack_nframes_t pos = cursor->current_frame;
717 TimeAxisView *ontrack = 0;
719 // so we don't find the current region again..
723 if (!selection->tracks.empty()) {
725 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
727 } else if (clicked_trackview) {
730 t.push_back (clicked_trackview);
732 r = find_next_region (pos, point, dir, t, &ontrack);
736 r = find_next_region (pos, point, dir, track_views, &ontrack);
745 pos = r->first_frame ();
749 pos = r->last_frame ();
753 pos = r->adjust_to_sync (r->first_frame());
758 AudioTimeAxisView *atav;
760 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
761 if (atav->get_diskstream() != 0) {
762 speed = atav->get_diskstream()->speed();
766 pos = track_frame_to_session_frame(pos, speed);
768 if (cursor == playhead_cursor) {
769 session->request_locate (pos);
771 cursor->set_position (pos);
776 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
778 cursor_to_region_point (cursor, point, 1);
782 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
784 cursor_to_region_point (cursor, point, -1);
788 Editor::cursor_to_selection_start (Cursor *cursor)
790 jack_nframes_t pos = 0;
791 switch (mouse_mode) {
793 if (!selection->audio_regions.empty()) {
794 pos = selection->audio_regions.start();
799 if (!selection->time.empty()) {
800 pos = selection->time.start ();
808 if (cursor == playhead_cursor) {
809 session->request_locate (pos);
811 cursor->set_position (pos);
816 Editor::cursor_to_selection_end (Cursor *cursor)
818 jack_nframes_t pos = 0;
820 switch (mouse_mode) {
822 if (!selection->audio_regions.empty()) {
823 pos = selection->audio_regions.end_frame();
828 if (!selection->time.empty()) {
829 pos = selection->time.end_frame ();
837 if (cursor == playhead_cursor) {
838 session->request_locate (pos);
840 cursor->set_position (pos);
845 Editor::playhead_backward ()
852 if (get_prefix (prefix, was_floating)) {
856 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
858 cnt = (jack_nframes_t) prefix;
862 pos = playhead_cursor->current_frame;
864 if ((jack_nframes_t) pos < cnt) {
870 /* XXX this is completely insane. with the current buffering
871 design, we'll force a complete track buffer flush and
872 reload, just to move 1 sample !!!
875 session->request_locate (pos);
879 Editor::playhead_forward ()
886 if (get_prefix (prefix, was_floating)) {
890 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
892 cnt = (jack_nframes_t) floor (prefix);
896 pos = playhead_cursor->current_frame;
898 /* XXX this is completely insane. with the current buffering
899 design, we'll force a complete track buffer flush and
900 reload, just to move 1 sample !!!
903 session->request_locate (pos+cnt);
907 Editor::cursor_align (bool playhead_to_edit)
909 if (playhead_to_edit) {
911 session->request_locate (edit_cursor->current_frame);
914 edit_cursor->set_position (playhead_cursor->current_frame);
919 Editor::edit_cursor_backward ()
926 if (get_prefix (prefix, was_floating)) {
930 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
932 cnt = (jack_nframes_t) prefix;
936 pos = edit_cursor->current_frame;
938 if ((jack_nframes_t) pos < cnt) {
944 edit_cursor->set_position (pos);
948 Editor::edit_cursor_forward ()
955 if (get_prefix (prefix, was_floating)) {
959 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
961 cnt = (jack_nframes_t) floor (prefix);
965 pos = edit_cursor->current_frame;
966 edit_cursor->set_position (pos+cnt);
970 Editor::goto_frame ()
974 jack_nframes_t frame;
976 if (get_prefix (prefix, was_floating)) {
981 frame = (jack_nframes_t) floor (prefix * session->frame_rate());
983 frame = (jack_nframes_t) floor (prefix);
986 session->request_locate (frame);
990 Editor::scroll_backward (float pages)
992 jack_nframes_t frame;
993 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
998 if (get_prefix (prefix, was_floating)) {
999 cnt = (jack_nframes_t) floor (pages * one_page);
1002 cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
1004 cnt = (jack_nframes_t) floor (prefix * one_page);
1008 if (leftmost_frame < cnt) {
1011 frame = leftmost_frame - cnt;
1014 reposition_x_origin (frame);
1018 Editor::scroll_forward (float pages)
1020 jack_nframes_t frame;
1021 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1026 if (get_prefix (prefix, was_floating)) {
1027 cnt = (jack_nframes_t) floor (pages * one_page);
1030 cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
1032 cnt = (jack_nframes_t) floor (prefix * one_page);
1036 if (ULONG_MAX - cnt < leftmost_frame) {
1037 frame = ULONG_MAX - cnt;
1039 frame = leftmost_frame + cnt;
1042 reposition_x_origin (frame);
1046 Editor::scroll_tracks_down ()
1052 if (get_prefix (prefix, was_floating)) {
1055 cnt = (int) floor (prefix);
1058 double vert_value = vertical_adjustment.get_value() + (cnt *
1059 vertical_adjustment.get_page_size());
1060 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1061 vert_value = vertical_adjustment.get_upper() - canvas_height;
1063 vertical_adjustment.set_value (vert_value);
1067 Editor::scroll_tracks_up ()
1073 if (get_prefix (prefix, was_floating)) {
1076 cnt = (int) floor (prefix);
1079 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1083 Editor::scroll_tracks_down_line ()
1086 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1087 double vert_value = adj->get_value() + 20;
1089 if (vert_value>adj->get_upper() - canvas_height) {
1090 vert_value = adj->get_upper() - canvas_height;
1092 adj->set_value (vert_value);
1096 Editor::scroll_tracks_up_line ()
1098 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1099 adj->set_value (adj->get_value() - 20);
1105 Editor::temporal_zoom_step (bool coarser)
1107 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1111 nfpu = frames_per_unit;
1116 nfpu = max(1.0,(nfpu/2.0));
1119 temporal_zoom (nfpu);
1123 Editor::temporal_zoom (gdouble fpu)
1125 if (!session) return;
1127 jack_nframes_t current_page = current_page_frames();
1128 jack_nframes_t current_leftmost = leftmost_frame;
1129 jack_nframes_t current_rightmost;
1130 jack_nframes_t current_center;
1131 jack_nframes_t new_page;
1132 jack_nframes_t leftmost_after_zoom = 0;
1137 new_page = (jack_nframes_t) floor (canvas_width * nfpu);
1139 switch (zoom_focus) {
1141 leftmost_after_zoom = current_leftmost;
1144 case ZoomFocusRight:
1145 current_rightmost = leftmost_frame + current_page;
1146 if (current_rightmost > new_page) {
1147 leftmost_after_zoom = current_rightmost - new_page;
1149 leftmost_after_zoom = 0;
1153 case ZoomFocusCenter:
1154 current_center = current_leftmost + (current_page/2);
1155 if (current_center > (new_page/2)) {
1156 leftmost_after_zoom = current_center - (new_page / 2);
1158 leftmost_after_zoom = 0;
1162 case ZoomFocusPlayhead:
1163 /* try to keep the playhead in the center */
1164 if (playhead_cursor->current_frame > new_page/2) {
1165 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1167 leftmost_after_zoom = 0;
1172 /* try to keep the edit cursor in the center */
1173 if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
1174 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1176 leftmost_after_zoom = 0;
1182 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1184 // begin_reversible_command (_("zoom"));
1185 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1186 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1187 // commit_reversible_command ();
1189 reposition_and_zoom (leftmost_after_zoom, nfpu);
1193 Editor::temporal_zoom_selection ()
1195 if (!selection) return;
1197 if (selection->time.empty()) {
1201 jack_nframes_t start = selection->time[clicked_selection].start;
1202 jack_nframes_t end = selection->time[clicked_selection].end;
1204 temporal_zoom_by_frame (start, end, "zoom to selection");
1208 Editor::temporal_zoom_session ()
1210 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1213 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1218 Editor::temporal_zoom_by_frame (jack_nframes_t start, jack_nframes_t end, const string & op)
1220 if (!session) return;
1222 if ((start == 0 && end == 0) || end < start) {
1226 jack_nframes_t range = end - start;
1228 double new_fpu = (double)range / (double)canvas_width;
1231 // while (p2 < new_fpu) {
1236 jack_nframes_t new_page = (jack_nframes_t) floor (canvas_width * new_fpu);
1237 jack_nframes_t middle = (jack_nframes_t) floor( (double)start + ((double)range / 2.0f ));
1238 jack_nframes_t new_leftmost = (jack_nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1240 if (new_leftmost > middle) new_leftmost = 0;
1242 // begin_reversible_command (op);
1243 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1244 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1245 // commit_reversible_command ();
1247 reposition_and_zoom (new_leftmost, new_fpu);
1251 Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
1253 if (!session) return;
1255 jack_nframes_t range_before = frame - leftmost_frame;
1258 new_fpu = frames_per_unit;
1264 new_fpu = max(1.0,(new_fpu/2.0));
1268 if (new_fpu == frames_per_unit) return;
1270 jack_nframes_t new_leftmost = frame - range_before;
1272 if (new_leftmost > frame) new_leftmost = 0;
1274 // begin_reversible_command (_("zoom to frame"));
1275 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1276 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1277 // commit_reversible_command ();
1279 reposition_and_zoom (new_leftmost, new_fpu);
1283 Editor::add_location_from_selection ()
1285 if (selection->time.empty()) {
1289 if (session == 0 || clicked_trackview == 0) {
1293 jack_nframes_t start = selection->time[clicked_selection].start;
1294 jack_nframes_t end = selection->time[clicked_selection].end;
1296 Location *location = new Location (start, end, "selection");
1298 session->begin_reversible_command (_("add marker"));
1299 XMLNode &before = session->locations()->get_state();
1300 session->locations()->add (location, true);
1301 XMLNode &after = session->locations()->get_state();
1302 session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
1303 session->commit_reversible_command ();
1307 Editor::add_location_from_playhead_cursor ()
1309 jack_nframes_t where = session->audible_frame();
1311 Location *location = new Location (where, where, "mark", Location::IsMark);
1312 session->begin_reversible_command (_("add marker"));
1313 XMLNode &before = session->locations()->get_state();
1314 session->locations()->add (location, true);
1315 XMLNode &after = session->locations()->get_state();
1316 session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
1317 session->commit_reversible_command ();
1321 Editor::add_location_from_audio_region ()
1323 if (selection->audio_regions.empty()) {
1327 AudioRegionView* rv = *(selection->audio_regions.begin());
1328 Region& region = rv->region;
1330 Location *location = new Location (region.position(), region.last_frame(), region.name());
1331 session->begin_reversible_command (_("add marker"));
1332 XMLNode &before = session->locations()->get_state();
1333 session->locations()->add (location, true);
1334 XMLNode &after = session->locations()->get_state();
1335 session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
1336 session->commit_reversible_command ();
1340 Editor::select_all_in_track (Selection::Operation op)
1342 list<Selectable *> touched;
1344 if (!clicked_trackview) {
1348 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1351 case Selection::Toggle:
1352 selection->add (touched);
1354 case Selection::Set:
1355 selection->set (touched);
1357 case Selection::Extend:
1358 /* not defined yet */
1364 Editor::select_all (Selection::Operation op)
1366 list<Selectable *> touched;
1368 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1369 if ((*iter)->hidden()) {
1372 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1374 begin_reversible_command (_("select all"));
1376 case Selection::Toggle:
1377 selection->add (touched);
1379 case Selection::Set:
1380 selection->set (touched);
1382 case Selection::Extend:
1383 /* not defined yet */
1386 commit_reversible_command ();
1390 Editor::invert_selection_in_track ()
1392 list<Selectable *> touched;
1394 if (!clicked_trackview) {
1398 clicked_trackview->get_inverted_selectables (*selection, touched);
1399 selection->set (touched);
1403 Editor::invert_selection ()
1405 list<Selectable *> touched;
1407 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1408 if ((*iter)->hidden()) {
1411 (*iter)->get_inverted_selectables (*selection, touched);
1414 selection->set (touched);
1418 Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, Selection::Operation op)
1420 list<Selectable *> touched;
1422 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1423 if ((*iter)->hidden()) {
1426 (*iter)->get_selectables (start, end, top, bot, touched);
1429 cerr << "select all within found " << touched.size() << endl;
1431 begin_reversible_command (_("select all within"));
1433 case Selection::Toggle:
1435 selection->add (touched);
1437 case Selection::Set:
1439 selection->set (touched);
1441 case Selection::Extend:
1443 /* not defined yet */
1447 cerr << "selection now has " << selection->points.size() << endl;
1449 commit_reversible_command ();
1450 return !touched.empty();
1454 Editor::set_selection_from_audio_region ()
1456 if (selection->audio_regions.empty()) {
1460 AudioRegionView* rv = *(selection->audio_regions.begin());
1461 Region& region = rv->region;
1463 begin_reversible_command (_("set selection from region"));
1464 selection->set (0, region.position(), region.last_frame());
1465 commit_reversible_command ();
1467 set_mouse_mode (Editing::MouseRange, false);
1471 Editor::set_selection_from_punch()
1475 if ((location = session->locations()->auto_punch_location()) == 0) {
1479 set_selection_from_range (*location);
1483 Editor::set_selection_from_loop()
1487 if ((location = session->locations()->auto_loop_location()) == 0) {
1490 set_selection_from_range (*location);
1494 Editor::set_selection_from_range (Location& loc)
1496 begin_reversible_command (_("set selection from range"));
1497 selection->set (0, loc.start(), loc.end());
1498 commit_reversible_command ();
1500 set_mouse_mode (Editing::MouseRange, false);
1504 Editor::select_all_selectables_using_time_selection ()
1506 list<Selectable *> touched;
1508 if (selection->time.empty()) {
1512 jack_nframes_t start = selection->time[clicked_selection].start;
1513 jack_nframes_t end = selection->time[clicked_selection].end;
1515 if (end - start < 1) {
1519 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1520 if ((*iter)->hidden()) {
1523 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1526 begin_reversible_command (_("select all from range"));
1527 selection->set (touched);
1528 commit_reversible_command ();
1533 Editor::select_all_selectables_using_punch()
1535 Location* location = session->locations()->auto_punch_location();
1536 list<Selectable *> touched;
1538 if (location == 0 || (location->end() - location->start() <= 1)) {
1542 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1543 if ((*iter)->hidden()) {
1546 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1548 begin_reversible_command (_("select all from punch"));
1549 selection->set (touched);
1550 commit_reversible_command ();
1555 Editor::select_all_selectables_using_loop()
1557 Location* location = session->locations()->auto_loop_location();
1558 list<Selectable *> touched;
1560 if (location == 0 || (location->end() - location->start() <= 1)) {
1564 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1565 if ((*iter)->hidden()) {
1568 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1570 begin_reversible_command (_("select all from loop"));
1571 selection->set (touched);
1572 commit_reversible_command ();
1577 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1579 jack_nframes_t start;
1581 list<Selectable *> touched;
1584 begin_reversible_command (_("select all after cursor"));
1585 start = cursor->current_frame ;
1586 end = session->current_end_frame();
1588 if (cursor->current_frame > 0) {
1589 begin_reversible_command (_("select all before cursor"));
1591 end = cursor->current_frame - 1;
1597 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1598 if ((*iter)->hidden()) {
1601 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1603 selection->set (touched);
1604 commit_reversible_command ();
1608 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1610 jack_nframes_t start;
1612 list<Selectable *> touched;
1613 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1615 if (cursor->current_frame == other_cursor->current_frame) {
1619 begin_reversible_command (_("select all between cursors"));
1620 if (other_cursor_is_first) {
1621 start = other_cursor->current_frame;
1622 end = cursor->current_frame - 1;
1625 start = cursor->current_frame;
1626 end = other_cursor->current_frame - 1;
1629 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1630 if ((*iter)->hidden()) {
1633 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1635 selection->set (touched);
1636 commit_reversible_command ();
1640 Editor::amplitude_zoom_step (bool in)
1654 #ifdef FIX_FOR_CANVAS
1655 /* XXX DO SOMETHING */
1664 Editor::delete_sample_forward ()
1669 Editor::delete_sample_backward ()
1674 Editor::delete_screen ()
1681 Editor::search_backwards ()
1687 Editor::search_forwards ()
1695 Editor::jump_forward_to_mark ()
1701 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1704 session->request_locate (location->start(), session->transport_rolling());
1706 session->request_locate (session->current_end_frame());
1711 Editor::jump_backward_to_mark ()
1717 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1720 session->request_locate (location->start(), session->transport_rolling());
1722 session->goto_start ();
1733 if (get_prefix (prefix, was_floating)) {
1734 pos = session->audible_frame ();
1737 pos = (jack_nframes_t) floor (prefix * session->frame_rate ());
1739 pos = (jack_nframes_t) floor (prefix);
1743 session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1747 Editor::clear_markers ()
1750 session->begin_reversible_command (_("clear markers"));
1751 XMLNode &before = session->locations()->get_state();
1752 session->locations()->clear_markers ();
1753 XMLNode &after = session->locations()->get_state();
1754 session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
1755 session->commit_reversible_command ();
1760 Editor::clear_ranges ()
1763 session->begin_reversible_command (_("clear ranges"));
1764 XMLNode &before = session->locations()->get_state();
1766 Location * looploc = session->locations()->auto_loop_location();
1767 Location * punchloc = session->locations()->auto_punch_location();
1769 session->locations()->clear_ranges ();
1771 if (looploc) session->locations()->add (looploc);
1772 if (punchloc) session->locations()->add (punchloc);
1774 XMLNode &after = session->locations()->get_state();
1775 session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
1776 session->commit_reversible_command ();
1781 Editor::clear_locations ()
1783 session->begin_reversible_command (_("clear locations"));
1784 XMLNode &before = session->locations()->get_state();
1785 session->locations()->clear ();
1786 XMLNode &after = session->locations()->get_state();
1787 session->add_command(MementoCommand<Locations>(*(sessions->locations()), before, after));
1788 session->commit_reversible_command ();
1789 session->locations()->clear ();
1792 /* INSERT/REPLACE */
1795 Editor::insert_region_list_drag (AudioRegion& region, int x, int y)
1800 jack_nframes_t where;
1801 AudioTimeAxisView *atv = 0;
1804 track_canvas.window_to_world (x, y, wx, wy);
1805 wx += horizontal_adjustment.get_value();
1806 wy += vertical_adjustment.get_value();
1809 event.type = GDK_BUTTON_RELEASE;
1810 event.button.x = wx;
1811 event.button.y = wy;
1813 where = event_frame (&event, &cx, &cy);
1815 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1816 /* clearly outside canvas area */
1820 if ((tv = trackview_by_y_position (cy)) == 0) {
1824 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1828 if ((playlist = atv->playlist()) == 0) {
1834 begin_reversible_command (_("insert dragged region"));
1835 XMLNode &before = playlist->get_state();
1836 playlist->add_region (*(new AudioRegion (region)), where, 1.0);
1837 session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
1838 commit_reversible_command ();
1842 Editor::insert_region_list_selection (float times)
1844 AudioTimeAxisView *tv = 0;
1847 if (clicked_audio_trackview != 0) {
1848 tv = clicked_audio_trackview;
1849 } else if (!selection->tracks.empty()) {
1850 if ((tv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front())) == 0) {
1857 if ((playlist = tv->playlist()) == 0) {
1861 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1863 if (selected->count_selected_rows() != 1) {
1867 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
1868 Region* region = (*i)[region_list_columns.region];
1870 begin_reversible_command (_("insert region"));
1871 XMLNode &before = playlist->get_state();
1872 playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times);
1873 session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
1874 commit_reversible_command ();
1878 /* BUILT-IN EFFECTS */
1881 Editor::reverse_selection ()
1886 /* GAIN ENVELOPE EDITING */
1889 Editor::edit_envelope ()
1896 Editor::toggle_playback (bool with_abort)
1902 switch (session->slave_source()) {
1907 /* transport controlled by the master */
1911 if (session->is_auditioning()) {
1912 session->cancel_audition ();
1916 if (session->transport_rolling()) {
1917 session->request_stop (with_abort);
1918 if (session->get_auto_loop()) {
1919 session->request_auto_loop (false);
1922 session->request_transport_speed (1.0f);
1927 Editor::play_from_start ()
1929 session->request_locate (session->current_start_frame(), true);
1933 Editor::play_selection ()
1935 if (selection->time.empty()) {
1939 session->request_play_range (true);
1943 Editor::play_selected_region ()
1945 if (!selection->audio_regions.empty()) {
1946 AudioRegionView *rv = *(selection->audio_regions.begin());
1948 session->request_bounded_roll (rv->region.position(), rv->region.last_frame());
1953 Editor::loop_selected_region ()
1955 if (!selection->audio_regions.empty()) {
1956 AudioRegionView *rv = *(selection->audio_regions.begin());
1959 if ((tll = transport_loop_location()) != 0) {
1961 tll->set (rv->region.position(), rv->region.last_frame());
1963 // enable looping, reposition and start rolling
1965 session->request_auto_loop (true);
1966 session->request_locate (tll->start(), false);
1967 session->request_transport_speed (1.0f);
1973 Editor::play_location (Location& location)
1975 if (location.start() <= location.end()) {
1979 session->request_bounded_roll (location.start(), location.end());
1983 Editor::loop_location (Location& location)
1985 if (location.start() <= location.end()) {
1991 if ((tll = transport_loop_location()) != 0) {
1992 tll->set (location.start(), location.end());
1994 // enable looping, reposition and start rolling
1995 session->request_auto_loop (true);
1996 session->request_locate (tll->start(), true);
2001 Editor::toggle_region_mute ()
2003 if (clicked_regionview) {
2004 clicked_regionview->region.set_muted (!clicked_regionview->region.muted());
2005 } else if (!selection->audio_regions.empty()) {
2006 bool yn = ! (*selection->audio_regions.begin())->region.muted();
2007 selection->foreach_audio_region (&AudioRegion::set_muted, yn);
2012 Editor::toggle_region_opaque ()
2014 if (clicked_regionview) {
2015 clicked_regionview->region.set_opaque (!clicked_regionview->region.opaque());
2016 } else if (!selection->audio_regions.empty()) {
2017 bool yn = ! (*selection->audio_regions.begin())->region.opaque();
2018 selection->foreach_audio_region (&Region::set_opaque, yn);
2023 Editor::raise_region ()
2025 selection->foreach_audio_region (&Region::raise);
2029 Editor::raise_region_to_top ()
2031 selection->foreach_audio_region (&Region::raise_to_top);
2035 Editor::lower_region ()
2037 selection->foreach_audio_region (&Region::lower);
2041 Editor::lower_region_to_bottom ()
2043 selection->foreach_audio_region (&Region::lower_to_bottom);
2047 Editor::edit_region ()
2049 if (clicked_regionview == 0) {
2053 clicked_regionview->show_region_editor ();
2057 Editor::rename_region ()
2061 Button ok_button (_("OK"));
2062 Button cancel_button (_("Cancel"));
2064 if (selection->audio_regions.empty()) {
2068 dialog.set_title (_("ardour: rename region"));
2069 dialog.set_name ("RegionRenameWindow");
2070 dialog.set_size_request (300, -1);
2071 dialog.set_position (Gtk::WIN_POS_MOUSE);
2072 dialog.set_modal (true);
2074 dialog.get_vbox()->set_border_width (10);
2075 dialog.get_vbox()->pack_start (entry);
2076 dialog.get_action_area()->pack_start (ok_button);
2077 dialog.get_action_area()->pack_start (cancel_button);
2079 entry.set_name ("RegionNameDisplay");
2080 ok_button.set_name ("EditorGTKButton");
2081 cancel_button.set_name ("EditorGTKButton");
2083 region_renamed = false;
2085 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2086 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2087 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2094 if (region_renamed) {
2095 (*selection->audio_regions.begin())->region.set_name (entry.get_text());
2096 redisplay_regions ();
2101 Editor::rename_region_finished (bool status)
2104 region_renamed = status;
2109 Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route)
2111 if (session->is_auditioning()) {
2112 session->cancel_audition ();
2115 // note: some potential for creativity here, because region doesn't
2116 // have to belong to the playlist that Route is handling
2118 // bool was_soloed = route.soloed();
2120 route.set_solo (true, this);
2122 session->request_bounded_roll (region.position(), region.position() + region.length());
2124 /* XXX how to unset the solo state ? */
2128 Editor::audition_selected_region ()
2130 if (!selection->audio_regions.empty()) {
2131 AudioRegionView* rv = *(selection->audio_regions.begin());
2132 session->audition_region (rv->region);
2137 Editor::audition_playlist_region_standalone (AudioRegion& region)
2139 session->audition_region (region);
2143 Editor::build_interthread_progress_window ()
2145 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2147 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2149 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2150 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2152 // GTK2FIX: this button needs a modifiable label
2154 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2155 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2157 interthread_cancel_button.add (interthread_cancel_label);
2159 interthread_progress_window->set_default_size (200, 100);
2163 Editor::interthread_cancel_clicked ()
2165 if (current_interthread_info) {
2166 current_interthread_info->cancel = true;
2171 Editor::region_from_selection ()
2173 if (clicked_trackview == 0) {
2177 if (selection->time.empty()) {
2181 jack_nframes_t start = selection->time[clicked_selection].start;
2182 jack_nframes_t end = selection->time[clicked_selection].end;
2184 jack_nframes_t selection_cnt = end - start + 1;
2186 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2188 AudioRegion *region;
2189 AudioRegion *current;
2193 jack_nframes_t internal_start;
2196 if ((pl = (*i)->playlist()) == 0) {
2200 if ((current_r = pl->top_region_at (start)) == 0) {
2204 if ((current = dynamic_cast<AudioRegion*> (current_r)) != 0) {
2205 internal_start = start - current->position();
2206 session->region_name (new_name, current->name(), true);
2207 region = new AudioRegion (*current, internal_start, selection_cnt, new_name);
2213 Editor::create_region_from_selection (vector<AudioRegion *>& new_regions)
2215 if (selection->time.empty() || selection->tracks.empty()) {
2219 jack_nframes_t start = selection->time[clicked_selection].start;
2220 jack_nframes_t end = selection->time[clicked_selection].end;
2222 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2224 AudioRegion* current;
2227 jack_nframes_t internal_start;
2230 if ((playlist = (*i)->playlist()) == 0) {
2234 if ((current_r = playlist->top_region_at(start)) == 0) {
2238 if ((current = dynamic_cast<AudioRegion*>(current_r)) == 0) {
2242 internal_start = start - current->position();
2243 session->region_name (new_name, current->name(), true);
2245 new_regions.push_back (new AudioRegion (*current, internal_start, end - start + 1, new_name));
2250 Editor::split_multichannel_region ()
2252 vector<AudioRegion*> v;
2254 if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) {
2258 clicked_regionview->region.separate_by_channel (*session, v);
2260 /* nothing else to do, really */
2264 Editor::new_region_from_selection ()
2266 region_from_selection ();
2267 cancel_selection ();
2271 Editor::separate_region_from_selection ()
2273 bool doing_undo = false;
2275 if (selection->time.empty()) {
2281 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2283 AudioTimeAxisView* atv;
2285 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2287 if (atv->is_audio_track()) {
2289 if ((playlist = atv->playlist()) != 0) {
2291 begin_reversible_command (_("separate"));
2294 XMLNode &before, &after;
2296 before = playlist->get_state();
2298 /* XXX need to consider musical time selections here at some point */
2300 double speed = atv->get_diskstream()->speed();
2302 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2303 playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
2307 session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
2313 if (doing_undo) commit_reversible_command ();
2317 Editor::separate_regions_using_location (Location& loc)
2319 bool doing_undo = false;
2321 if (loc.is_mark()) {
2327 /* XXX i'm unsure as to whether this should operate on selected tracks only
2328 or the entire enchillada. uncomment the below line to correct the behaviour
2329 (currently set for all tracks)
2332 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2333 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2335 AudioTimeAxisView* atv;
2337 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2339 if (atv->is_audio_track()) {
2341 if ((playlist = atv->playlist()) != 0) {
2342 XMLNode &before, &after;
2344 begin_reversible_command (_("separate"));
2348 before = playlist->get_state();
2351 /* XXX need to consider musical time selections here at some point */
2353 double speed = atv->get_diskstream()->speed();
2356 playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true);
2358 session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
2364 if (doing_undo) commit_reversible_command ();
2368 Editor::crop_region_to_selection ()
2370 if (selection->time.empty()) {
2374 vector<Playlist*> playlists;
2377 if (clicked_trackview != 0) {
2379 if ((playlist = clicked_trackview->playlist()) == 0) {
2383 playlists.push_back (playlist);
2387 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2389 AudioTimeAxisView* atv;
2391 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2393 if (atv->is_audio_track()) {
2395 if ((playlist = atv->playlist()) != 0) {
2396 playlists.push_back (playlist);
2403 if (!playlists.empty()) {
2405 jack_nframes_t start;
2409 begin_reversible_command (_("trim to selection"));
2411 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 start = selection->time.start();
2417 if ((region = (*i)->top_region_at(start)) == 0) {
2421 /* now adjust lengths to that we do the right thing
2422 if the selection extends beyond the region
2425 start = max (start, region->position());
2426 end = min (selection->time.end_frame(), start + region->length() - 1);
2427 cnt = end - start + 1;
2429 XMLNode &before = (*i)->get_state();
2430 region->trim_to (start, cnt, this);
2431 XMLNode &after = (*i)->get_state();
2432 session->add_command (MementoCommand<Playlist>(*(*i), before, after));
2435 commit_reversible_command ();
2440 Editor::region_fill_track ()
2444 if (!session || selection->audio_regions.empty()) {
2448 end = session->current_end_frame ();
2450 begin_reversible_command (_("region fill"));
2452 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2454 AudioRegion& region ((*i)->region);
2455 Playlist* pl = region.playlist();
2457 if (end <= region.last_frame()) {
2461 double times = (double) (end - region.last_frame()) / (double) region.length();
2467 XMLNode &before = pl->get_state();
2468 pl->add_region (*(new AudioRegion (region)), region.last_frame(), times);
2469 session->add_command (MementoCommand<Playlist>(*pl, before, pl->get_state()));
2472 commit_reversible_command ();
2476 Editor::region_fill_selection ()
2478 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2482 if (selection->time.empty()) {
2488 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2490 if (selected->count_selected_rows() != 1) {
2494 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2495 region = (*i)[region_list_columns.region];
2497 jack_nframes_t start = selection->time[clicked_selection].start;
2498 jack_nframes_t end = selection->time[clicked_selection].end;
2502 if (selection->tracks.empty()) {
2506 jack_nframes_t selection_length = end - start;
2507 float times = (float)selection_length / region->length();
2509 begin_reversible_command (_("fill selection"));
2511 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2513 if ((playlist = (*i)->playlist()) == 0) {
2517 XMLNode &before = playlist->get_state();
2518 playlist->add_region (*(createRegion (*region)), start, times);
2519 session->add_command (MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
2522 commit_reversible_command ();
2526 Editor::set_a_regions_sync_position (Region& region, jack_nframes_t position)
2529 if (!region.covers (position)) {
2530 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2533 begin_reversible_command (_("set region sync position"));
2534 XMLNode &before = region.playlist()->get_state();
2535 region.set_sync_position (position);
2536 XMLNode &after = region.playlist()->get_state();
2537 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2538 commit_reversible_command ();
2542 Editor::set_region_sync_from_edit_cursor ()
2544 if (clicked_regionview == 0) {
2548 if (!clicked_regionview->region.covers (edit_cursor->current_frame)) {
2549 error << _("Place the edit cursor at the desired sync point") << endmsg;
2553 Region& region (clicked_regionview->region);
2554 begin_reversible_command (_("set sync from edit cursor"));
2555 XMLNode &before = region.playlist()->get_state();
2556 region.set_sync_position (edit_cursor->current_frame);
2557 XMLNode &after = region.playlist()->get_state();
2558 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2559 commit_reversible_command ();
2563 Editor::remove_region_sync ()
2565 if (clicked_regionview) {
2566 Region& region (clicked_regionview->region);
2567 begin_reversible_command (_("remove sync"));
2568 XMLNode &before = region.playlist()->get_state();
2569 region.clear_sync_position ();
2570 XMLNode &after = region.playlist()->get_state();
2571 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2572 commit_reversible_command ();
2577 Editor::naturalize ()
2579 if (selection->audio_regions.empty()) {
2582 begin_reversible_command (_("naturalize"));
2583 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2584 XMLNode &before = (*i)->region.get_state();
2585 (*i)->region.move_to_natural_position (this);
2586 XMLNode &after = (*i)->region.get_state();
2587 session->add_command (MementoCommand<AudioRegion>((*i)->region, before, after));
2589 commit_reversible_command ();
2593 Editor::align (RegionPoint what)
2595 align_selection (what, edit_cursor->current_frame);
2599 Editor::align_relative (RegionPoint what)
2601 align_selection_relative (what, edit_cursor->current_frame);
2604 struct RegionSortByTime {
2605 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2606 return a->region.position() < b->region.position();
2611 Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
2613 if (selection->audio_regions.empty()) {
2617 jack_nframes_t distance;
2618 jack_nframes_t pos = 0;
2621 list<AudioRegionView*> sorted;
2622 selection->audio_regions.by_position (sorted);
2623 Region& r ((*sorted.begin())->region);
2627 pos = r.first_frame ();
2631 pos = r.last_frame();
2635 pos = r.adjust_to_sync (r.first_frame());
2639 if (pos > position) {
2640 distance = pos - position;
2643 distance = position - pos;
2647 begin_reversible_command (_("align selection (relative)"));
2649 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2651 Region& region ((*i)->region);
2653 XMLNode &before = region.playlist()->get_state();
2656 region.set_position (region.position() + distance, this);
2658 region.set_position (region.position() - distance, this);
2661 XMLNode &after = region.playlist()->get_state();
2662 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2666 commit_reversible_command ();
2670 Editor::align_selection (RegionPoint point, jack_nframes_t position)
2672 if (selection->audio_regions.empty()) {
2676 begin_reversible_command (_("align selection"));
2678 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2679 align_region_internal ((*i)->region, point, position);
2682 commit_reversible_command ();
2686 Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position)
2688 begin_reversible_command (_("align region"));
2689 align_region_internal (region, point, position);
2690 commit_reversible_command ();
2694 Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position)
2696 XMLNode &before, &after;
2697 before = region.playlist()->get_state();
2701 region.set_position (region.adjust_to_sync (position), this);
2705 if (position > region.length()) {
2706 region.set_position (position - region.length(), this);
2711 region.set_position (position, this);
2715 after = region.playlist()->get_state();
2716 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2720 Editor::trim_region_to_edit_cursor ()
2722 if (clicked_regionview == 0) {
2726 Region& region (clicked_regionview->region);
2729 AudioTimeAxisView *atav;
2731 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2732 if (atav->get_diskstream() != 0) {
2733 speed = atav->get_diskstream()->speed();
2737 begin_reversible_command (_("trim to edit"));
2738 XMLNode &before = region.playlist()->get_state();
2739 region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2740 XMLNode &after = region.playlist()->get_state();
2741 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2742 commit_reversible_command ();
2746 Editor::trim_region_from_edit_cursor ()
2748 if (clicked_regionview == 0) {
2752 Region& region (clicked_regionview->region);
2755 AudioTimeAxisView *atav;
2757 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2758 if (atav->get_diskstream() != 0) {
2759 speed = atav->get_diskstream()->speed();
2763 begin_reversible_command (_("trim to edit"));
2764 XMLNode &before = region.playlist()->get_state();
2765 region.trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2766 XMLNode &after = region.playlist()->get_state();
2767 session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
2768 commit_reversible_command ();
2772 Editor::unfreeze_route ()
2774 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2778 clicked_audio_trackview->audio_track()->unfreeze ();
2782 Editor::_freeze_thread (void* arg)
2784 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2785 return static_cast<Editor*>(arg)->freeze_thread ();
2789 Editor::freeze_thread ()
2791 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2796 Editor::freeze_progress_timeout (void *arg)
2798 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2799 return !(current_interthread_info->done || current_interthread_info->cancel);
2803 Editor::freeze_route ()
2805 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2809 InterThreadInfo itt;
2811 if (interthread_progress_window == 0) {
2812 build_interthread_progress_window ();
2815 interthread_progress_window->set_title (_("ardour: freeze"));
2816 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2817 interthread_progress_window->show_all ();
2818 interthread_progress_bar.set_fraction (0.0f);
2819 interthread_progress_label.set_text ("");
2820 interthread_cancel_label.set_text (_("Cancel Freeze"));
2821 current_interthread_info = &itt;
2823 interthread_progress_connection =
2824 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2828 itt.progress = 0.0f;
2830 pthread_create (&itt.thread, 0, _freeze_thread, this);
2832 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2834 while (!itt.done && !itt.cancel) {
2835 gtk_main_iteration ();
2838 interthread_progress_connection.disconnect ();
2839 interthread_progress_window->hide_all ();
2840 current_interthread_info = 0;
2841 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2845 Editor::bounce_range_selection ()
2847 if (selection->time.empty()) {
2851 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2853 jack_nframes_t start = selection->time[clicked_selection].start;
2854 jack_nframes_t end = selection->time[clicked_selection].end;
2855 jack_nframes_t cnt = end - start + 1;
2857 begin_reversible_command (_("bounce range"));
2859 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2861 AudioTimeAxisView* atv;
2863 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2869 if ((playlist = atv->playlist()) == 0) {
2873 InterThreadInfo itt;
2877 itt.progress = false;
2879 XMLNode &before = playlist->get_state();
2880 atv->audio_track()->bounce_range (start, cnt, itt);
2881 XMLNode &after = playlist->get_state();
2882 session->add_command (MementoCommand<Playlist> (*playlist, before, after));
2885 commit_reversible_command ();
2903 Editor::cut_copy (CutCopyOp op)
2905 /* only cancel selection if cut/copy is successful.*/
2917 opname = _("clear");
2921 cut_buffer->clear ();
2923 switch (current_mouse_mode()) {
2925 if (!selection->audio_regions.empty() || !selection->points.empty()) {
2927 begin_reversible_command (opname + _(" objects"));
2929 if (!selection->audio_regions.empty()) {
2931 cut_copy_regions (op);
2934 selection->clear_audio_regions ();
2938 if (!selection->points.empty()) {
2939 cut_copy_points (op);
2942 selection->clear_points ();
2946 commit_reversible_command ();
2951 if (!selection->time.empty()) {
2953 begin_reversible_command (opname + _(" range"));
2954 cut_copy_ranges (op);
2955 commit_reversible_command ();
2958 selection->clear_time ();
2970 Editor::cut_copy_points (CutCopyOp op)
2972 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2974 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2977 atv->cut_copy_clear_objects (selection->points, op);
2983 Editor::cut_copy_regions (CutCopyOp op)
2985 typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
2986 PlaylistMapping pmap;
2987 jack_nframes_t first_position = max_frames;
2988 set<Playlist*> freezelist;
2989 pair<set<Playlist*>::iterator,bool> insert_result;
2991 for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) {
2992 first_position = min ((*x)->region.position(), first_position);
2994 if (op == Cut || op == Clear) {
2995 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
2997 insert_result = freezelist.insert (pl);
2998 if (insert_result.second) {
3000 session->add_command (MementoUndoCommand<Playlist>(*pl, pl->get_state()));
3006 for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) {
3008 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
3010 AudioRegionSelection::iterator tmp;
3017 PlaylistMapping::iterator pi = pmap.find (pl);
3019 if (pi == pmap.end()) {
3020 npl = new AudioPlaylist (*session, "cutlist", true);
3029 npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
3030 pl->remove_region (&((*x)->region));
3034 npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
3038 pl->remove_region (&((*x)->region));
3046 list<Playlist*> foo;
3048 for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3049 foo.push_back (i->second);
3053 cut_buffer->set (foo);
3056 for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3058 session->add_command (MementoRedoCommand<Playlist>(*(*pl), *(*pl)->get_state()));
3063 Editor::cut_copy_ranges (CutCopyOp op)
3065 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3066 (*i)->cut_copy_clear (*selection, op);
3071 Editor::paste (float times)
3073 paste_internal (edit_cursor->current_frame, times);
3077 Editor::mouse_paste ()
3082 track_canvas.get_pointer (x, y);
3083 track_canvas.window_to_world (x, y, wx, wy);
3084 wx += horizontal_adjustment.get_value();
3085 wy += vertical_adjustment.get_value();
3088 event.type = GDK_BUTTON_RELEASE;
3089 event.button.x = wx;
3090 event.button.y = wy;
3092 jack_nframes_t where = event_frame (&event, 0, 0);
3094 paste_internal (where, 1);
3098 Editor::paste_internal (jack_nframes_t position, float times)
3100 bool commit = false;
3102 if (cut_buffer->empty() || selection->tracks.empty()) {
3106 if (position == max_frames) {
3107 position = edit_cursor->current_frame;
3110 begin_reversible_command (_("paste"));
3112 TrackSelection::iterator i;
3115 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3117 /* undo/redo is handled by individual tracks */
3119 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3125 commit_reversible_command ();
3130 Editor::paste_named_selection (float times)
3132 TrackSelection::iterator t;
3134 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3136 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3140 TreeModel::iterator i = selected->get_selected();
3141 NamedSelection* ns = (*i)[named_selection_columns.selection];
3143 list<Playlist*>::iterator chunk;
3144 list<Playlist*>::iterator tmp;
3146 chunk = ns->playlists.begin();
3148 begin_reversible_command (_("paste chunk"));
3150 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3152 AudioTimeAxisView* atv;
3156 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3160 if ((pl = atv->playlist()) == 0) {
3164 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3171 XMLNode &before = apl->get_state();
3172 apl->paste (**chunk, edit_cursor->current_frame, times);
3173 session->add_command(MementoCommand<AudioPlaylist>(*apl, before, apl->get_state()));
3175 if (tmp != ns->playlists.end()) {
3180 commit_reversible_command();
3184 Editor::duplicate_some_regions (AudioRegionSelection& regions, float times)
3187 AudioRegionSelection sel = regions; // clear (below) will clear the argument list
3189 begin_reversible_command (_("duplicate region"));
3191 selection->clear_audio_regions ();
3193 for (AudioRegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3195 Region& r ((*i)->region);
3197 TimeAxisView& tv = (*i)->get_time_axis_view();
3198 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3199 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3201 playlist = (*i)->region.playlist();
3202 XMLNode &before = playlist->get_state();
3203 playlist->duplicate (r, r.last_frame(), times);
3204 session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
3208 if (latest_regionview) {
3209 selection->add (latest_regionview);
3214 commit_reversible_command ();
3218 Editor::duplicate_selection (float times)
3220 if (selection->time.empty() || selection->tracks.empty()) {
3225 vector<AudioRegion*> new_regions;
3226 vector<AudioRegion*>::iterator ri;
3228 create_region_from_selection (new_regions);
3230 if (new_regions.empty()) {
3234 begin_reversible_command (_("duplicate selection"));
3236 ri = new_regions.begin();
3238 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3239 if ((playlist = (*i)->playlist()) == 0) {
3242 XMLNode &before = playlist->get_state();
3243 playlist->duplicate (**ri, selection->time[clicked_selection].end, times);
3244 XMLNode &after = playlist->get_state();
3245 session->add_command (MementoCommand<Playlist>(*playlist, before, after));
3248 if (ri == new_regions.end()) {
3253 commit_reversible_command ();
3257 Editor::reset_point_selection ()
3259 /* reset all selected points to the relevant default value */
3261 cerr << "point selection has " << selection->points.size() << " entries\n";
3263 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3265 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3268 atv->reset_objects (selection->points);
3274 Editor::center_playhead ()
3276 float page = canvas_width * frames_per_unit;
3278 center_screen_internal (playhead_cursor->current_frame, page);
3282 Editor::center_edit_cursor ()
3284 float page = canvas_width * frames_per_unit;
3286 center_screen_internal (edit_cursor->current_frame, page);
3290 Editor::clear_playlist (Playlist& playlist)
3292 begin_reversible_command (_("clear playlist"));
3293 XMLNode &before = playlist.get_state();
3295 XMLNode &after = playlist.get_state();
3296 session->add_command (MementoCommand<Playlist>(playlist, before, after));
3297 commit_reversible_command ();
3301 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3304 jack_nframes_t distance;
3305 jack_nframes_t next_distance;
3306 jack_nframes_t start;
3308 if (use_edit_cursor) {
3309 start = edit_cursor->current_frame;
3314 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3318 if (selection->tracks.empty()) {
3322 begin_reversible_command (_("nudge track"));
3324 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3326 if ((playlist = (*i)->playlist()) == 0) {
3330 XMLNode &before = playlist->get_state();
3331 playlist->nudge_after (start, distance, forwards);
3332 XMLNode &after = playlist->get_state();
3333 session->add_command (MementoCommand<Playlist>(*playlist, before, after));
3336 commit_reversible_command ();
3340 Editor::remove_last_capture ()
3342 vector<string> choices;
3349 if (Config->get_verify_remove_last_capture()) {
3350 prompt = _("Do you really want to destroy the last capture?"
3351 "\n(This is destructive and cannot be undone)");
3353 choices.push_back (_("No, do nothing."));
3354 choices.push_back (_("Yes, destroy it."));
3356 Gtkmm2ext::Choice prompter (prompt, choices);
3358 if (prompter.run () == 1) {
3359 session->remove_last_capture ();
3363 session->remove_last_capture();
3368 Editor::normalize_region ()
3374 if (selection->audio_regions.empty()) {
3378 begin_reversible_command (_("normalize"));
3380 track_canvas.get_window()->set_cursor (*wait_cursor);
3383 for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
3384 XMLNode &before = (*r)->region.get_state();
3385 (*r)->region.normalize_to (0.0f);
3386 XMLNode &after = (*r)->region.get_state();
3387 session->add_command (MementoCommand<AudioRegion>((*r)->region, before, after));
3390 commit_reversible_command ();
3391 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3396 Editor::denormalize_region ()
3402 if (selection->audio_regions.empty()) {
3406 begin_reversible_command ("denormalize");
3408 for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
3409 XMLNode &before = (*r)->region.get_state();
3410 (*r)->region.set_scale_amplitude (1.0f);
3411 XMLNode &after = (*r)->region.get_state();
3412 session->add_command (MementoCommand<AudioRegion>((*r)->region, before, after));
3415 commit_reversible_command ();
3420 Editor::reverse_region ()
3426 Reverse rev (*session);
3427 apply_filter (rev, _("reverse regions"));
3431 Editor::apply_filter (AudioFilter& filter, string command)
3433 if (selection->audio_regions.empty()) {
3437 begin_reversible_command (command);
3439 track_canvas.get_window()->set_cursor (*wait_cursor);
3442 for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ) {
3444 AudioRegion& region ((*r)->region);
3445 Playlist* playlist = region.playlist();
3447 AudioRegionSelection::iterator tmp;
3452 if (region.apply (filter) == 0) {
3454 XMLNode &before = playlist->get_state();
3455 playlist->replace_region (region, *(filter.results.front()), region.position());
3456 XMLNode &after = playlist->get_state();
3457 session->add_command(MementoCommand<Playlist>(*playlist, before, after));
3465 commit_reversible_command ();
3466 selection->audio_regions.clear ();
3469 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3473 Editor::region_selection_op (void (Region::*pmf)(void))
3475 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3476 ((*i)->region.*pmf)();
3482 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3484 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3485 ((*i)->region.*pmf)(arg);
3490 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3492 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3493 ((*i)->region.*pmf)(yn);
3498 Editor::external_edit_region ()
3500 if (!clicked_regionview) {
3508 Editor::brush (jack_nframes_t pos)
3510 AudioRegionSelection sel;
3513 if (selection->audio_regions.empty()) {
3514 /* XXX get selection from region list */
3516 sel = selection->audio_regions;
3523 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3524 mouse_brush_insert_region ((*i), pos);
3529 Editor::toggle_gain_envelope_visibility ()
3531 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3532 (*i)->set_envelope_visible (!(*i)->envelope_visible());
3537 Editor::toggle_gain_envelope_active ()
3539 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3540 AudioRegion* ar = dynamic_cast<AudioRegion*>(&(*i)->region);
3542 ar->set_envelope_active (true);