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>
31 #include <pbd/memento_command.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/choice.h>
36 #include <ardour/audioengine.h>
37 #include <ardour/session.h>
38 #include <ardour/audioplaylist.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/utils.h>
42 #include <ardour/location.h>
43 #include <ardour/named_selection.h>
44 #include <ardour/audio_track.h>
45 #include <ardour/audioplaylist.h>
46 #include <ardour/region_factory.h>
47 #include <ardour/reverse.h>
49 #include "ardour_ui.h"
51 #include "time_axis_view.h"
52 #include "audio_time_axis.h"
53 #include "automation_time_axis.h"
54 #include "streamview.h"
55 #include "audio_region_view.h"
56 #include "rgb_macros.h"
57 #include "selection_templates.h"
58 #include "selection.h"
61 #include "gtk-custom-hruler.h"
62 #include "gui_thread.h"
67 using namespace ARDOUR;
71 using namespace Editing;
73 /***********************************************************************
75 ***********************************************************************/
78 Editor::undo (uint32_t n)
86 Editor::redo (uint32_t n)
94 Editor::set_meter_hold (int32_t cnt)
96 Config->set_meter_hold_off(false);
97 Config->set_meter_hold_short(false);
98 Config->set_meter_hold_medium(false);
99 Config->set_meter_hold_long(false);
104 Config->set_meter_hold_off(true);
107 Config->set_meter_hold_short(true);
110 Config->set_meter_hold_medium(true);
113 Config->set_meter_hold_long(true);
118 session->set_meter_hold (cnt);
123 Editor::set_meter_falloff (int intval)
125 float val = 0.0f; /* off */
128 Config->set_meter_falloff_off(false);
129 Config->set_meter_falloff_slowest(false);
130 Config->set_meter_falloff_slow(false);
131 Config->set_meter_falloff_medium(false);
132 Config->set_meter_falloff_fast(false);
133 Config->set_meter_falloff_faster(false);
134 Config->set_meter_falloff_fastest(false);
140 Config->set_meter_falloff_off(true);
144 Config->set_meter_falloff_slowest(true);
148 Config->set_meter_falloff_slow(true);
152 Config->set_meter_falloff_medium(true);
156 Config->set_meter_falloff_fast(true);
160 Config->set_meter_falloff_faster(true);
164 Config->set_meter_falloff_fastest(true);
169 session->set_meter_falloff (val);
175 Editor::ensure_cursor (jack_nframes_t *pos)
177 *pos = edit_cursor->current_frame;
182 Editor::split_region ()
184 split_region_at (edit_cursor->current_frame);
188 Editor::split_region_at (jack_nframes_t where)
190 split_regions_at (where, selection->regions);
194 Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions)
196 begin_reversible_command (_("split"));
199 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
201 RegionSelection::iterator tmp;
206 Playlist* pl = (*a)->region()->playlist();
208 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
210 _new_regionviews_show_envelope = arv->envelope_visible();
213 XMLNode &before = pl->get_state();
214 pl->split_region ((*a)->region(), where);
215 XMLNode &after = pl->get_state();
216 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
222 commit_reversible_command ();
223 _new_regionviews_show_envelope = false;
227 Editor::remove_clicked_region ()
229 if (clicked_routeview == 0 || clicked_regionview == 0) {
233 Playlist* playlist = clicked_routeview->playlist();
235 begin_reversible_command (_("remove region"));
236 XMLNode &before = playlist->get_state();
237 playlist->remove_region (clicked_regionview->region());
238 XMLNode &after = playlist->get_state();
239 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
240 commit_reversible_command ();
244 Editor::destroy_clicked_region ()
246 int32_t selected = selection->regions.size();
248 if (!session || clicked_regionview == 0 && selected == 0) {
252 vector<string> choices;
255 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
256 It cannot be undone\n\
257 Do you really want to destroy %1 ?"),
259 _("these regions") : _("this region")));
261 choices.push_back (_("No, do nothing."));
264 choices.push_back (_("Yes, destroy them."));
266 choices.push_back (_("Yes, destroy it."));
269 Gtkmm2ext::Choice prompter (prompt, choices);
271 if (prompter.run() == 0) { /* first choice */
276 list<boost::shared_ptr<Region> > r;
278 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
279 r.push_back ((*i)->region());
282 session->destroy_regions (r);
284 } else if (clicked_regionview) {
285 session->destroy_region (clicked_regionview->region());
289 boost::shared_ptr<Region>
290 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
293 boost::shared_ptr<Region> region;
294 jack_nframes_t start = 0;
296 if (selection->time.start () == selection->time.end_frame ()) {
298 /* no current selection-> is there a selected regionview? */
300 if (selection->regions.empty()) {
306 if (!selection->regions.empty()) {
308 rv = *(selection->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 RouteTimeAxisView* rtv;
318 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
321 if ((pl = rtv->playlist()) == 0) {
325 region = pl->top_region_at (start);
333 Editor::extend_selection_to_end_of_region (bool next)
336 boost::shared_ptr<Region> region;
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)
364 boost::shared_ptr<Region> region;
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->regions.empty()) {
399 begin_reversible_command (_("nudge forward"));
401 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
402 boost::shared_ptr<Region> 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 (new 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->regions.empty()) {
434 begin_reversible_command (_("nudge forward"));
436 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
437 boost::shared_ptr<Region> 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(new 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->regions.empty()) {
479 begin_reversible_command (_("nudge forward"));
481 distance = session->worst_output_latency();
483 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
484 boost::shared_ptr<Region> r ((*i)->region());
486 XMLNode &before = r->playlist()->get_state();
487 r->set_position (r->position() + distance, this);
488 XMLNode &after = r->playlist()->get_state();
489 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
492 commit_reversible_command ();
498 Editor::nudge_backward_capture_offset ()
500 jack_nframes_t distance;
502 if (!session) return;
504 if (!selection->regions.empty()) {
506 begin_reversible_command (_("nudge forward"));
508 distance = session->worst_output_latency();
510 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
511 boost::shared_ptr<Region> r ((*i)->region());
513 XMLNode &before = r->playlist()->get_state();
515 if (r->position() > distance) {
516 r->set_position (r->position() - distance, this);
518 r->set_position (0, this);
520 XMLNode &after = r->playlist()->get_state();
521 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
524 commit_reversible_command ();
531 Editor::move_to_start ()
533 session->goto_start ();
537 Editor::move_to_end ()
540 session->request_locate (session->current_end_frame());
544 Editor::build_region_boundary_cache ()
546 jack_nframes_t pos = 0;
548 boost::shared_ptr<Region> r;
549 TrackViewList tracks;
551 region_boundary_cache.clear ();
558 case SnapToRegionStart:
561 case SnapToRegionEnd:
564 case SnapToRegionSync:
567 case SnapToRegionBoundary:
571 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
576 TimeAxisView *ontrack = 0;
578 while (pos < session->current_end_frame()) {
580 if (!selection->tracks.empty()) {
582 if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
586 } else if (clicked_axisview) {
589 t.push_back (clicked_axisview);
591 if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
597 if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
605 case SnapToRegionStart:
606 rpos = r->first_frame();
608 case SnapToRegionEnd:
609 rpos = r->last_frame();
611 case SnapToRegionSync:
612 rpos = r->adjust_to_sync (r->first_frame());
615 case SnapToRegionBoundary:
616 rpos = r->last_frame();
623 AudioTimeAxisView *atav;
625 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
626 if (atav->get_diskstream() != 0) {
627 speed = atav->get_diskstream()->speed();
631 rpos = track_frame_to_session_frame(rpos, speed);
633 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
634 if (snap_type == SnapToRegionBoundary) {
635 region_boundary_cache.push_back (r->first_frame());
637 region_boundary_cache.push_back (rpos);
644 boost::shared_ptr<Region>
645 Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
647 TrackViewList::iterator i;
648 jack_nframes_t closest = max_frames;
649 boost::shared_ptr<Region> ret;
650 jack_nframes_t rpos = 0;
653 jack_nframes_t track_frame;
654 AudioTimeAxisView *atav;
656 for (i = tracks.begin(); i != tracks.end(); ++i) {
658 jack_nframes_t distance;
659 boost::shared_ptr<Region> r;
662 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
663 if (atav->get_diskstream()!=0)
664 track_speed = atav->get_diskstream()->speed();
667 track_frame = session_frame_to_track_frame(frame, track_speed);
669 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
675 rpos = r->first_frame ();
679 rpos = r->last_frame ();
683 rpos = r->adjust_to_sync (r->first_frame());
686 // rpos is a "track frame", converting it to "session frame"
687 rpos = track_frame_to_session_frame(rpos, track_speed);
690 distance = rpos - frame;
692 distance = frame - rpos;
695 if (distance < closest) {
707 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
709 boost::shared_ptr<Region> r;
710 jack_nframes_t pos = cursor->current_frame;
716 TimeAxisView *ontrack = 0;
718 // so we don't find the current region again..
722 if (!selection->tracks.empty()) {
724 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
726 } else if (clicked_axisview) {
729 t.push_back (clicked_axisview);
731 r = find_next_region (pos, point, dir, t, &ontrack);
735 r = find_next_region (pos, point, dir, track_views, &ontrack);
744 pos = r->first_frame ();
748 pos = r->last_frame ();
752 pos = r->adjust_to_sync (r->first_frame());
757 AudioTimeAxisView *atav;
759 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
760 if (atav->get_diskstream() != 0) {
761 speed = atav->get_diskstream()->speed();
765 pos = track_frame_to_session_frame(pos, speed);
767 if (cursor == playhead_cursor) {
768 session->request_locate (pos);
770 cursor->set_position (pos);
775 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
777 cursor_to_region_point (cursor, point, 1);
781 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
783 cursor_to_region_point (cursor, point, -1);
787 Editor::cursor_to_selection_start (Cursor *cursor)
789 jack_nframes_t pos = 0;
790 switch (mouse_mode) {
792 if (!selection->regions.empty()) {
793 pos = selection->regions.start();
798 if (!selection->time.empty()) {
799 pos = selection->time.start ();
807 if (cursor == playhead_cursor) {
808 session->request_locate (pos);
810 cursor->set_position (pos);
815 Editor::cursor_to_selection_end (Cursor *cursor)
817 jack_nframes_t pos = 0;
819 switch (mouse_mode) {
821 if (!selection->regions.empty()) {
822 pos = selection->regions.end_frame();
827 if (!selection->time.empty()) {
828 pos = selection->time.end_frame ();
836 if (cursor == playhead_cursor) {
837 session->request_locate (pos);
839 cursor->set_position (pos);
844 Editor::playhead_backward ()
851 if (get_prefix (prefix, was_floating)) {
855 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
857 cnt = (jack_nframes_t) prefix;
861 pos = playhead_cursor->current_frame;
863 if ((jack_nframes_t) pos < cnt) {
869 /* XXX this is completely insane. with the current buffering
870 design, we'll force a complete track buffer flush and
871 reload, just to move 1 sample !!!
874 session->request_locate (pos);
878 Editor::playhead_forward ()
885 if (get_prefix (prefix, was_floating)) {
889 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
891 cnt = (jack_nframes_t) floor (prefix);
895 pos = playhead_cursor->current_frame;
897 /* XXX this is completely insane. with the current buffering
898 design, we'll force a complete track buffer flush and
899 reload, just to move 1 sample !!!
902 session->request_locate (pos+cnt);
906 Editor::cursor_align (bool playhead_to_edit)
908 if (playhead_to_edit) {
910 session->request_locate (edit_cursor->current_frame);
913 edit_cursor->set_position (playhead_cursor->current_frame);
918 Editor::edit_cursor_backward ()
925 if (get_prefix (prefix, was_floating)) {
929 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
931 cnt = (jack_nframes_t) prefix;
935 pos = edit_cursor->current_frame;
937 if ((jack_nframes_t) pos < cnt) {
943 edit_cursor->set_position (pos);
947 Editor::edit_cursor_forward ()
954 if (get_prefix (prefix, was_floating)) {
958 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
960 cnt = (jack_nframes_t) floor (prefix);
964 pos = edit_cursor->current_frame;
965 edit_cursor->set_position (pos+cnt);
969 Editor::goto_frame ()
973 jack_nframes_t frame;
975 if (get_prefix (prefix, was_floating)) {
980 frame = (jack_nframes_t) floor (prefix * session->frame_rate());
982 frame = (jack_nframes_t) floor (prefix);
985 session->request_locate (frame);
989 Editor::scroll_backward (float pages)
991 jack_nframes_t frame;
992 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
997 if (get_prefix (prefix, was_floating)) {
998 cnt = (jack_nframes_t) floor (pages * one_page);
1001 cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
1003 cnt = (jack_nframes_t) floor (prefix * one_page);
1007 if (leftmost_frame < cnt) {
1010 frame = leftmost_frame - cnt;
1013 reposition_x_origin (frame);
1017 Editor::scroll_forward (float pages)
1019 jack_nframes_t frame;
1020 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1025 if (get_prefix (prefix, was_floating)) {
1026 cnt = (jack_nframes_t) floor (pages * one_page);
1029 cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
1031 cnt = (jack_nframes_t) floor (prefix * one_page);
1035 if (ULONG_MAX - cnt < leftmost_frame) {
1036 frame = ULONG_MAX - cnt;
1038 frame = leftmost_frame + cnt;
1041 reposition_x_origin (frame);
1045 Editor::scroll_tracks_down ()
1051 if (get_prefix (prefix, was_floating)) {
1054 cnt = (int) floor (prefix);
1057 double vert_value = vertical_adjustment.get_value() + (cnt *
1058 vertical_adjustment.get_page_size());
1059 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1060 vert_value = vertical_adjustment.get_upper() - canvas_height;
1062 vertical_adjustment.set_value (vert_value);
1066 Editor::scroll_tracks_up ()
1072 if (get_prefix (prefix, was_floating)) {
1075 cnt = (int) floor (prefix);
1078 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1082 Editor::scroll_tracks_down_line ()
1085 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1086 double vert_value = adj->get_value() + 20;
1088 if (vert_value>adj->get_upper() - canvas_height) {
1089 vert_value = adj->get_upper() - canvas_height;
1091 adj->set_value (vert_value);
1095 Editor::scroll_tracks_up_line ()
1097 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1098 adj->set_value (adj->get_value() - 20);
1104 Editor::temporal_zoom_step (bool coarser)
1106 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1110 nfpu = frames_per_unit;
1115 nfpu = max(1.0,(nfpu/2.0));
1118 temporal_zoom (nfpu);
1122 Editor::temporal_zoom (gdouble fpu)
1124 if (!session) return;
1126 jack_nframes_t current_page = current_page_frames();
1127 jack_nframes_t current_leftmost = leftmost_frame;
1128 jack_nframes_t current_rightmost;
1129 jack_nframes_t current_center;
1130 jack_nframes_t new_page;
1131 jack_nframes_t leftmost_after_zoom = 0;
1136 new_page = (jack_nframes_t) floor (canvas_width * nfpu);
1138 switch (zoom_focus) {
1140 leftmost_after_zoom = current_leftmost;
1143 case ZoomFocusRight:
1144 current_rightmost = leftmost_frame + current_page;
1145 if (current_rightmost > new_page) {
1146 leftmost_after_zoom = current_rightmost - new_page;
1148 leftmost_after_zoom = 0;
1152 case ZoomFocusCenter:
1153 current_center = current_leftmost + (current_page/2);
1154 if (current_center > (new_page/2)) {
1155 leftmost_after_zoom = current_center - (new_page / 2);
1157 leftmost_after_zoom = 0;
1161 case ZoomFocusPlayhead:
1162 /* try to keep the playhead in the center */
1163 if (playhead_cursor->current_frame > new_page/2) {
1164 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1166 leftmost_after_zoom = 0;
1171 /* try to keep the edit cursor in the center */
1172 if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
1173 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1175 leftmost_after_zoom = 0;
1181 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1183 // begin_reversible_command (_("zoom"));
1184 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1185 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1186 // commit_reversible_command ();
1188 reposition_and_zoom (leftmost_after_zoom, nfpu);
1192 Editor::temporal_zoom_selection ()
1194 if (!selection) return;
1196 if (selection->time.empty()) {
1200 jack_nframes_t start = selection->time[clicked_selection].start;
1201 jack_nframes_t end = selection->time[clicked_selection].end;
1203 temporal_zoom_by_frame (start, end, "zoom to selection");
1207 Editor::temporal_zoom_session ()
1209 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1212 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1217 Editor::temporal_zoom_by_frame (jack_nframes_t start, jack_nframes_t end, const string & op)
1219 if (!session) return;
1221 if ((start == 0 && end == 0) || end < start) {
1225 jack_nframes_t range = end - start;
1227 double new_fpu = (double)range / (double)canvas_width;
1230 // while (p2 < new_fpu) {
1235 jack_nframes_t new_page = (jack_nframes_t) floor (canvas_width * new_fpu);
1236 jack_nframes_t middle = (jack_nframes_t) floor( (double)start + ((double)range / 2.0f ));
1237 jack_nframes_t new_leftmost = (jack_nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1239 if (new_leftmost > middle) new_leftmost = 0;
1241 // begin_reversible_command (op);
1242 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1243 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1244 // commit_reversible_command ();
1246 reposition_and_zoom (new_leftmost, new_fpu);
1250 Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
1252 if (!session) return;
1254 jack_nframes_t range_before = frame - leftmost_frame;
1257 new_fpu = frames_per_unit;
1263 new_fpu = max(1.0,(new_fpu/2.0));
1267 if (new_fpu == frames_per_unit) return;
1269 jack_nframes_t new_leftmost = frame - range_before;
1271 if (new_leftmost > frame) new_leftmost = 0;
1273 // begin_reversible_command (_("zoom to frame"));
1274 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1275 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1276 // commit_reversible_command ();
1278 reposition_and_zoom (new_leftmost, new_fpu);
1282 Editor::add_location_from_selection ()
1284 if (selection->time.empty()) {
1288 if (session == 0 || clicked_axisview == 0) {
1292 jack_nframes_t start = selection->time[clicked_selection].start;
1293 jack_nframes_t end = selection->time[clicked_selection].end;
1295 Location *location = new Location (start, end, "selection");
1297 session->begin_reversible_command (_("add marker"));
1298 XMLNode &before = session->locations()->get_state();
1299 session->locations()->add (location, true);
1300 XMLNode &after = session->locations()->get_state();
1301 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1302 session->commit_reversible_command ();
1306 Editor::add_location_from_playhead_cursor ()
1308 jack_nframes_t where = session->audible_frame();
1310 Location *location = new Location (where, where, "mark", Location::IsMark);
1311 session->begin_reversible_command (_("add marker"));
1312 XMLNode &before = session->locations()->get_state();
1313 session->locations()->add (location, true);
1314 XMLNode &after = session->locations()->get_state();
1315 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1316 session->commit_reversible_command ();
1320 Editor::add_location_from_audio_region ()
1322 if (selection->regions.empty()) {
1326 RegionView* rv = *(selection->regions.begin());
1327 boost::shared_ptr<Region> region = rv->region();
1329 Location *location = new Location (region->position(), region->last_frame(), region->name());
1330 session->begin_reversible_command (_("add marker"));
1331 XMLNode &before = session->locations()->get_state();
1332 session->locations()->add (location, true);
1333 XMLNode &after = session->locations()->get_state();
1334 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1335 session->commit_reversible_command ();
1339 Editor::select_all_in_track (Selection::Operation op)
1341 list<Selectable *> touched;
1343 if (!clicked_axisview) {
1347 clicked_axisview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1350 case Selection::Toggle:
1351 selection->add (touched);
1353 case Selection::Set:
1354 selection->set (touched);
1356 case Selection::Extend:
1357 /* not defined yet */
1363 Editor::select_all (Selection::Operation op)
1365 list<Selectable *> touched;
1367 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1368 if ((*iter)->hidden()) {
1371 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1373 begin_reversible_command (_("select all"));
1375 case Selection::Toggle:
1376 selection->add (touched);
1378 case Selection::Set:
1379 selection->set (touched);
1381 case Selection::Extend:
1382 /* not defined yet */
1385 commit_reversible_command ();
1389 Editor::invert_selection_in_track ()
1391 list<Selectable *> touched;
1393 if (!clicked_axisview) {
1397 clicked_axisview->get_inverted_selectables (*selection, touched);
1398 selection->set (touched);
1402 Editor::invert_selection ()
1404 list<Selectable *> touched;
1406 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1407 if ((*iter)->hidden()) {
1410 (*iter)->get_inverted_selectables (*selection, touched);
1413 selection->set (touched);
1417 Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, Selection::Operation op)
1419 list<Selectable *> touched;
1421 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1422 if ((*iter)->hidden()) {
1425 (*iter)->get_selectables (start, end, top, bot, touched);
1428 cerr << "select all within found " << touched.size() << endl;
1430 begin_reversible_command (_("select all within"));
1432 case Selection::Toggle:
1434 selection->add (touched);
1436 case Selection::Set:
1438 selection->set (touched);
1440 case Selection::Extend:
1442 /* not defined yet */
1446 cerr << "selection now has " << selection->points.size() << endl;
1448 commit_reversible_command ();
1449 return !touched.empty();
1453 Editor::set_selection_from_audio_region ()
1455 if (selection->regions.empty()) {
1459 RegionView* rv = *(selection->regions.begin());
1460 boost::shared_ptr<Region> region = rv->region();
1462 begin_reversible_command (_("set selection from region"));
1463 selection->set (0, region->position(), region->last_frame());
1464 commit_reversible_command ();
1466 set_mouse_mode (Editing::MouseRange, false);
1470 Editor::set_selection_from_punch()
1474 if ((location = session->locations()->auto_punch_location()) == 0) {
1478 set_selection_from_range (*location);
1482 Editor::set_selection_from_loop()
1486 if ((location = session->locations()->auto_loop_location()) == 0) {
1489 set_selection_from_range (*location);
1493 Editor::set_selection_from_range (Location& loc)
1495 begin_reversible_command (_("set selection from range"));
1496 selection->set (0, loc.start(), loc.end());
1497 commit_reversible_command ();
1499 set_mouse_mode (Editing::MouseRange, false);
1503 Editor::select_all_selectables_using_time_selection ()
1505 list<Selectable *> touched;
1507 if (selection->time.empty()) {
1511 jack_nframes_t start = selection->time[clicked_selection].start;
1512 jack_nframes_t end = selection->time[clicked_selection].end;
1514 if (end - start < 1) {
1518 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1519 if ((*iter)->hidden()) {
1522 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1525 begin_reversible_command (_("select all from range"));
1526 selection->set (touched);
1527 commit_reversible_command ();
1532 Editor::select_all_selectables_using_punch()
1534 Location* location = session->locations()->auto_punch_location();
1535 list<Selectable *> touched;
1537 if (location == 0 || (location->end() - location->start() <= 1)) {
1541 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1542 if ((*iter)->hidden()) {
1545 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1547 begin_reversible_command (_("select all from punch"));
1548 selection->set (touched);
1549 commit_reversible_command ();
1554 Editor::select_all_selectables_using_loop()
1556 Location* location = session->locations()->auto_loop_location();
1557 list<Selectable *> touched;
1559 if (location == 0 || (location->end() - location->start() <= 1)) {
1563 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1564 if ((*iter)->hidden()) {
1567 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1569 begin_reversible_command (_("select all from loop"));
1570 selection->set (touched);
1571 commit_reversible_command ();
1576 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1578 jack_nframes_t start;
1580 list<Selectable *> touched;
1583 begin_reversible_command (_("select all after cursor"));
1584 start = cursor->current_frame ;
1585 end = session->current_end_frame();
1587 if (cursor->current_frame > 0) {
1588 begin_reversible_command (_("select all before cursor"));
1590 end = cursor->current_frame - 1;
1596 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1597 if ((*iter)->hidden()) {
1600 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1602 selection->set (touched);
1603 commit_reversible_command ();
1607 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1609 jack_nframes_t start;
1611 list<Selectable *> touched;
1612 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1614 if (cursor->current_frame == other_cursor->current_frame) {
1618 begin_reversible_command (_("select all between cursors"));
1619 if (other_cursor_is_first) {
1620 start = other_cursor->current_frame;
1621 end = cursor->current_frame - 1;
1624 start = cursor->current_frame;
1625 end = other_cursor->current_frame - 1;
1628 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1629 if ((*iter)->hidden()) {
1632 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1634 selection->set (touched);
1635 commit_reversible_command ();
1639 Editor::amplitude_zoom_step (bool in)
1653 #ifdef FIX_FOR_CANVAS
1654 /* XXX DO SOMETHING */
1663 Editor::delete_sample_forward ()
1668 Editor::delete_sample_backward ()
1673 Editor::delete_screen ()
1680 Editor::search_backwards ()
1686 Editor::search_forwards ()
1694 Editor::jump_forward_to_mark ()
1700 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1703 session->request_locate (location->start(), session->transport_rolling());
1705 session->request_locate (session->current_end_frame());
1710 Editor::jump_backward_to_mark ()
1716 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1719 session->request_locate (location->start(), session->transport_rolling());
1721 session->goto_start ();
1732 if (get_prefix (prefix, was_floating)) {
1733 pos = session->audible_frame ();
1736 pos = (jack_nframes_t) floor (prefix * session->frame_rate ());
1738 pos = (jack_nframes_t) floor (prefix);
1742 session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1746 Editor::clear_markers ()
1749 session->begin_reversible_command (_("clear markers"));
1750 XMLNode &before = session->locations()->get_state();
1751 session->locations()->clear_markers ();
1752 XMLNode &after = session->locations()->get_state();
1753 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1754 session->commit_reversible_command ();
1759 Editor::clear_ranges ()
1762 session->begin_reversible_command (_("clear ranges"));
1763 XMLNode &before = session->locations()->get_state();
1765 Location * looploc = session->locations()->auto_loop_location();
1766 Location * punchloc = session->locations()->auto_punch_location();
1768 session->locations()->clear_ranges ();
1770 if (looploc) session->locations()->add (looploc);
1771 if (punchloc) session->locations()->add (punchloc);
1773 XMLNode &after = session->locations()->get_state();
1774 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1775 session->commit_reversible_command ();
1780 Editor::clear_locations ()
1782 session->begin_reversible_command (_("clear locations"));
1783 XMLNode &before = session->locations()->get_state();
1784 session->locations()->clear ();
1785 XMLNode &after = session->locations()->get_state();
1786 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1787 session->commit_reversible_command ();
1788 session->locations()->clear ();
1791 /* INSERT/REPLACE */
1794 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1799 jack_nframes_t where;
1800 AudioTimeAxisView *atv = 0;
1803 track_canvas.window_to_world (x, y, wx, wy);
1804 wx += horizontal_adjustment.get_value();
1805 wy += vertical_adjustment.get_value();
1808 event.type = GDK_BUTTON_RELEASE;
1809 event.button.x = wx;
1810 event.button.y = wy;
1812 where = event_frame (&event, &cx, &cy);
1814 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1815 /* clearly outside canvas area */
1819 if ((tv = trackview_by_y_position (cy)) == 0) {
1823 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1827 if ((playlist = atv->playlist()) == 0) {
1833 begin_reversible_command (_("insert dragged region"));
1834 XMLNode &before = playlist->get_state();
1835 playlist->add_region (RegionFactory::create (region), where, 1.0);
1836 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1837 commit_reversible_command ();
1841 Editor::insert_region_list_selection (float times)
1843 RouteTimeAxisView *tv = 0;
1846 if (clicked_routeview != 0) {
1847 tv = clicked_routeview;
1848 } else if (!selection->tracks.empty()) {
1849 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1856 if ((playlist = tv->playlist()) == 0) {
1860 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1862 if (selected->count_selected_rows() != 1) {
1866 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
1867 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
1869 begin_reversible_command (_("insert region"));
1870 XMLNode &before = playlist->get_state();
1871 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1872 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1873 commit_reversible_command ();
1877 /* BUILT-IN EFFECTS */
1880 Editor::reverse_selection ()
1885 /* GAIN ENVELOPE EDITING */
1888 Editor::edit_envelope ()
1895 Editor::toggle_playback (bool with_abort)
1901 switch (session->slave_source()) {
1906 /* transport controlled by the master */
1910 if (session->is_auditioning()) {
1911 session->cancel_audition ();
1915 if (session->transport_rolling()) {
1916 session->request_stop (with_abort);
1917 if (session->get_auto_loop()) {
1918 session->request_auto_loop (false);
1921 session->request_transport_speed (1.0f);
1926 Editor::play_from_start ()
1928 session->request_locate (session->current_start_frame(), true);
1932 Editor::play_selection ()
1934 if (selection->time.empty()) {
1938 session->request_play_range (true);
1942 Editor::play_selected_region ()
1944 if (!selection->regions.empty()) {
1945 RegionView *rv = *(selection->regions.begin());
1947 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1952 Editor::loop_selected_region ()
1954 if (!selection->regions.empty()) {
1955 RegionView *rv = *(selection->regions.begin());
1958 if ((tll = transport_loop_location()) != 0) {
1960 tll->set (rv->region()->position(), rv->region()->last_frame());
1962 // enable looping, reposition and start rolling
1964 session->request_auto_loop (true);
1965 session->request_locate (tll->start(), false);
1966 session->request_transport_speed (1.0f);
1972 Editor::play_location (Location& location)
1974 if (location.start() <= location.end()) {
1978 session->request_bounded_roll (location.start(), location.end());
1982 Editor::loop_location (Location& location)
1984 if (location.start() <= location.end()) {
1990 if ((tll = transport_loop_location()) != 0) {
1991 tll->set (location.start(), location.end());
1993 // enable looping, reposition and start rolling
1994 session->request_auto_loop (true);
1995 session->request_locate (tll->start(), true);
2000 Editor::toggle_region_mute ()
2002 if (clicked_regionview) {
2003 clicked_regionview->region()->set_muted (!clicked_regionview->region()->muted());
2004 } else if (!selection->regions.empty()) {
2005 bool yn = ! (*selection->regions.begin())->region()->muted();
2006 selection->foreach_region (&Region::set_muted, yn);
2011 Editor::toggle_region_opaque ()
2013 if (clicked_regionview) {
2014 clicked_regionview->region()->set_opaque (!clicked_regionview->region()->opaque());
2015 } else if (!selection->regions.empty()) {
2016 bool yn = ! (*selection->regions.begin())->region()->opaque();
2017 selection->foreach_region (&Region::set_opaque, yn);
2022 Editor::raise_region ()
2024 selection->foreach_region (&Region::raise);
2028 Editor::raise_region_to_top ()
2030 selection->foreach_region (&Region::raise_to_top);
2034 Editor::lower_region ()
2036 selection->foreach_region (&Region::lower);
2040 Editor::lower_region_to_bottom ()
2042 selection->foreach_region (&Region::lower_to_bottom);
2046 Editor::edit_region ()
2048 if (clicked_regionview == 0) {
2052 clicked_regionview->show_region_editor ();
2056 Editor::rename_region ()
2060 Button ok_button (_("OK"));
2061 Button cancel_button (_("Cancel"));
2063 if (selection->regions.empty()) {
2067 dialog.set_title (_("ardour: rename region"));
2068 dialog.set_name ("RegionRenameWindow");
2069 dialog.set_size_request (300, -1);
2070 dialog.set_position (Gtk::WIN_POS_MOUSE);
2071 dialog.set_modal (true);
2073 dialog.get_vbox()->set_border_width (10);
2074 dialog.get_vbox()->pack_start (entry);
2075 dialog.get_action_area()->pack_start (ok_button);
2076 dialog.get_action_area()->pack_start (cancel_button);
2078 entry.set_name ("RegionNameDisplay");
2079 ok_button.set_name ("EditorGTKButton");
2080 cancel_button.set_name ("EditorGTKButton");
2082 region_renamed = false;
2084 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2085 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2086 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2093 if (region_renamed) {
2094 (*selection->regions.begin())->region()->set_name (entry.get_text());
2095 redisplay_regions ();
2100 Editor::rename_region_finished (bool status)
2103 region_renamed = status;
2108 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2110 if (session->is_auditioning()) {
2111 session->cancel_audition ();
2114 // note: some potential for creativity here, because region doesn't
2115 // have to belong to the playlist that Route is handling
2117 // bool was_soloed = route.soloed();
2119 route.set_solo (true, this);
2121 session->request_bounded_roll (region->position(), region->position() + region->length());
2123 /* XXX how to unset the solo state ? */
2127 Editor::audition_selected_region ()
2129 if (!selection->regions.empty()) {
2130 RegionView* rv = *(selection->regions.begin());
2131 session->audition_region (rv->region());
2136 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2138 session->audition_region (region);
2142 Editor::build_interthread_progress_window ()
2144 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2146 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2148 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2149 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2151 // GTK2FIX: this button needs a modifiable label
2153 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2154 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2156 interthread_cancel_button.add (interthread_cancel_label);
2158 interthread_progress_window->set_default_size (200, 100);
2162 Editor::interthread_cancel_clicked ()
2164 if (current_interthread_info) {
2165 current_interthread_info->cancel = true;
2170 Editor::region_from_selection ()
2172 if (clicked_axisview == 0) {
2176 if (selection->time.empty()) {
2180 jack_nframes_t start = selection->time[clicked_selection].start;
2181 jack_nframes_t end = selection->time[clicked_selection].end;
2183 jack_nframes_t selection_cnt = end - start + 1;
2185 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2186 boost::shared_ptr<AudioRegion> current;
2187 boost::shared_ptr<Region> current_r;
2190 jack_nframes_t internal_start;
2193 if ((pl = (*i)->playlist()) == 0) {
2197 if ((current_r = pl->top_region_at (start)) == 0) {
2201 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2202 assert(current); // FIXME
2204 internal_start = start - current->position();
2205 session->region_name (new_name, current->name(), true);
2206 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2212 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2214 if (selection->time.empty() || selection->tracks.empty()) {
2218 jack_nframes_t start = selection->time[clicked_selection].start;
2219 jack_nframes_t end = selection->time[clicked_selection].end;
2221 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2223 boost::shared_ptr<AudioRegion> current;
2224 boost::shared_ptr<Region> current_r;
2226 jack_nframes_t internal_start;
2229 if ((playlist = (*i)->playlist()) == 0) {
2233 if ((current_r = playlist->top_region_at(start)) == 0) {
2237 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2241 internal_start = start - current->position();
2242 session->region_name (new_name, current->name(), true);
2244 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2249 Editor::split_multichannel_region ()
2251 vector<AudioRegion*> v;
2253 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2255 if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2259 clicked_arv->audio_region()->separate_by_channel (*session, v);
2261 /* nothing else to do, really */
2265 Editor::new_region_from_selection ()
2267 region_from_selection ();
2268 cancel_selection ();
2272 Editor::separate_region_from_selection ()
2276 bool doing_undo = false;
2278 if (selection->time.empty()) {
2284 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2286 AudioTimeAxisView* atv;
2288 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2290 if (atv->is_audio_track()) {
2292 if ((playlist = atv->playlist()) != 0) {
2294 begin_reversible_command (_("separate"));
2299 before = &(playlist->get_state());
2301 /* XXX need to consider musical time selections here at some point */
2303 double speed = atv->get_diskstream()->speed();
2305 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2306 playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
2310 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2316 if (doing_undo) commit_reversible_command ();
2320 Editor::separate_regions_using_location (Location& loc)
2324 bool doing_undo = false;
2326 if (loc.is_mark()) {
2332 /* XXX i'm unsure as to whether this should operate on selected tracks only
2333 or the entire enchillada. uncomment the below line to correct the behaviour
2334 (currently set for all tracks)
2337 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2338 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2340 AudioTimeAxisView* atv;
2342 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2344 if (atv->is_audio_track()) {
2346 if ((playlist = atv->playlist()) != 0) {
2349 begin_reversible_command (_("separate"));
2353 before = &(playlist->get_state());
2356 /* XXX need to consider musical time selections here at some point */
2358 double speed = atv->get_diskstream()->speed();
2361 playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true);
2363 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2369 if (doing_undo) commit_reversible_command ();
2373 Editor::crop_region_to_selection ()
2375 if (selection->time.empty()) {
2379 vector<Playlist*> playlists;
2382 if (clicked_axisview != 0) {
2384 if ((playlist = clicked_axisview->playlist()) == 0) {
2388 playlists.push_back (playlist);
2392 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2394 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i);
2396 if (rtv && rtv->is_track()) {
2398 if ((playlist = rtv->playlist()) != 0) {
2399 playlists.push_back (playlist);
2405 if (!playlists.empty()) {
2407 jack_nframes_t start;
2411 begin_reversible_command (_("trim to selection"));
2413 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 boost::shared_ptr<Region> region;
2417 start = selection->time.start();
2419 if ((region = (*i)->top_region_at(start)) == 0) {
2423 /* now adjust lengths to that we do the right thing
2424 if the selection extends beyond the region
2427 start = max (start, region->position());
2428 end = min (selection->time.end_frame(), start + region->length() - 1);
2429 cnt = end - start + 1;
2431 XMLNode &before = (*i)->get_state();
2432 region->trim_to (start, cnt, this);
2433 XMLNode &after = (*i)->get_state();
2434 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2437 commit_reversible_command ();
2442 Editor::region_fill_track ()
2446 if (!session || selection->regions.empty()) {
2450 end = session->current_end_frame ();
2452 begin_reversible_command (_("region fill"));
2454 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2456 boost::shared_ptr<Region> region ((*i)->region());
2459 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2462 Playlist* pl = region->playlist();
2464 if (end <= region->last_frame()) {
2468 double times = (double) (end - region->last_frame()) / (double) region->length();
2474 XMLNode &before = pl->get_state();
2475 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2476 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2479 commit_reversible_command ();
2483 Editor::region_fill_selection ()
2485 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2489 if (selection->time.empty()) {
2494 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2496 if (selected->count_selected_rows() != 1) {
2500 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2501 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2503 jack_nframes_t start = selection->time[clicked_selection].start;
2504 jack_nframes_t end = selection->time[clicked_selection].end;
2508 if (selection->tracks.empty()) {
2512 jack_nframes_t selection_length = end - start;
2513 float times = (float)selection_length / region->length();
2515 begin_reversible_command (_("fill selection"));
2517 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2519 if ((playlist = (*i)->playlist()) == 0) {
2523 XMLNode &before = playlist->get_state();
2524 playlist->add_region (RegionFactory::create (region), start, times);
2525 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2528 commit_reversible_command ();
2532 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, jack_nframes_t position)
2535 if (!region->covers (position)) {
2536 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2539 begin_reversible_command (_("set region sync position"));
2540 XMLNode &before = region->playlist()->get_state();
2541 region->set_sync_position (position);
2542 XMLNode &after = region->playlist()->get_state();
2543 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2544 commit_reversible_command ();
2548 Editor::set_region_sync_from_edit_cursor ()
2550 if (clicked_regionview == 0) {
2554 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2555 error << _("Place the edit cursor at the desired sync point") << endmsg;
2559 boost::shared_ptr<Region> region (clicked_regionview->region());
2560 begin_reversible_command (_("set sync from edit cursor"));
2561 XMLNode &before = region->playlist()->get_state();
2562 region->set_sync_position (edit_cursor->current_frame);
2563 XMLNode &after = region->playlist()->get_state();
2564 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2565 commit_reversible_command ();
2569 Editor::remove_region_sync ()
2571 if (clicked_regionview) {
2572 boost::shared_ptr<Region> region (clicked_regionview->region());
2573 begin_reversible_command (_("remove sync"));
2574 XMLNode &before = region->playlist()->get_state();
2575 region->clear_sync_position ();
2576 XMLNode &after = region->playlist()->get_state();
2577 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2578 commit_reversible_command ();
2583 Editor::naturalize ()
2585 if (selection->regions.empty()) {
2588 begin_reversible_command (_("naturalize"));
2589 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2590 XMLNode &before = (*i)->region()->get_state();
2591 (*i)->region()->move_to_natural_position (this);
2592 XMLNode &after = (*i)->region()->get_state();
2593 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2595 commit_reversible_command ();
2599 Editor::align (RegionPoint what)
2601 align_selection (what, edit_cursor->current_frame);
2605 Editor::align_relative (RegionPoint what)
2607 align_selection_relative (what, edit_cursor->current_frame);
2610 struct RegionSortByTime {
2611 bool operator() (const RegionView* a, const RegionView* b) {
2612 return a->region()->position() < b->region()->position();
2617 Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
2619 if (selection->regions.empty()) {
2623 jack_nframes_t distance;
2624 jack_nframes_t pos = 0;
2627 list<RegionView*> sorted;
2628 selection->regions.by_position (sorted);
2629 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2633 pos = r->first_frame ();
2637 pos = r->last_frame();
2641 pos = r->adjust_to_sync (r->first_frame());
2645 if (pos > position) {
2646 distance = pos - position;
2649 distance = position - pos;
2653 begin_reversible_command (_("align selection (relative)"));
2655 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2657 boost::shared_ptr<Region> region ((*i)->region());
2659 XMLNode &before = region->playlist()->get_state();
2662 region->set_position (region->position() + distance, this);
2664 region->set_position (region->position() - distance, this);
2667 XMLNode &after = region->playlist()->get_state();
2668 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2672 commit_reversible_command ();
2676 Editor::align_selection (RegionPoint point, jack_nframes_t position)
2678 if (selection->regions.empty()) {
2682 begin_reversible_command (_("align selection"));
2684 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2685 align_region_internal ((*i)->region(), point, position);
2688 commit_reversible_command ();
2692 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, jack_nframes_t position)
2694 begin_reversible_command (_("align region"));
2695 align_region_internal (region, point, position);
2696 commit_reversible_command ();
2700 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, jack_nframes_t position)
2702 XMLNode &before = region->playlist()->get_state();
2706 region->set_position (region->adjust_to_sync (position), this);
2710 if (position > region->length()) {
2711 region->set_position (position - region->length(), this);
2716 region->set_position (position, this);
2720 XMLNode &after = region->playlist()->get_state();
2721 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2725 Editor::trim_region_to_edit_cursor ()
2727 if (clicked_regionview == 0) {
2731 boost::shared_ptr<Region> region (clicked_regionview->region());
2734 AudioTimeAxisView *atav;
2736 if ( clicked_axisview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_axisview)) != 0 ) {
2737 if (atav->get_diskstream() != 0) {
2738 speed = atav->get_diskstream()->speed();
2742 begin_reversible_command (_("trim to edit"));
2743 XMLNode &before = region->playlist()->get_state();
2744 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2745 XMLNode &after = region->playlist()->get_state();
2746 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2747 commit_reversible_command ();
2751 Editor::trim_region_from_edit_cursor ()
2753 if (clicked_regionview == 0) {
2757 boost::shared_ptr<Region> region (clicked_regionview->region());
2760 AudioTimeAxisView *atav;
2762 if ( clicked_axisview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_axisview)) != 0 ) {
2763 if (atav->get_diskstream() != 0) {
2764 speed = atav->get_diskstream()->speed();
2768 begin_reversible_command (_("trim to edit"));
2769 XMLNode &before = region->playlist()->get_state();
2770 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2771 XMLNode &after = region->playlist()->get_state();
2772 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2773 commit_reversible_command ();
2777 Editor::unfreeze_route ()
2779 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2783 clicked_routeview->track()->unfreeze ();
2787 Editor::_freeze_thread (void* arg)
2789 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2790 return static_cast<Editor*>(arg)->freeze_thread ();
2794 Editor::freeze_thread ()
2796 clicked_routeview->audio_track()->freeze (*current_interthread_info);
2801 Editor::freeze_progress_timeout (void *arg)
2803 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2804 return !(current_interthread_info->done || current_interthread_info->cancel);
2808 Editor::freeze_route ()
2810 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2814 InterThreadInfo itt;
2816 if (interthread_progress_window == 0) {
2817 build_interthread_progress_window ();
2820 interthread_progress_window->set_title (_("ardour: freeze"));
2821 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2822 interthread_progress_window->show_all ();
2823 interthread_progress_bar.set_fraction (0.0f);
2824 interthread_progress_label.set_text ("");
2825 interthread_cancel_label.set_text (_("Cancel Freeze"));
2826 current_interthread_info = &itt;
2828 interthread_progress_connection =
2829 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2833 itt.progress = 0.0f;
2835 pthread_create (&itt.thread, 0, _freeze_thread, this);
2837 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2839 while (!itt.done && !itt.cancel) {
2840 gtk_main_iteration ();
2843 interthread_progress_connection.disconnect ();
2844 interthread_progress_window->hide_all ();
2845 current_interthread_info = 0;
2846 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2850 Editor::bounce_range_selection ()
2852 if (selection->time.empty()) {
2856 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2858 jack_nframes_t start = selection->time[clicked_selection].start;
2859 jack_nframes_t end = selection->time[clicked_selection].end;
2860 jack_nframes_t cnt = end - start + 1;
2862 begin_reversible_command (_("bounce range"));
2864 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2866 AudioTimeAxisView* atv;
2868 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2874 if ((playlist = atv->playlist()) == 0) {
2878 InterThreadInfo itt;
2882 itt.progress = false;
2884 XMLNode &before = playlist->get_state();
2885 atv->audio_track()->bounce_range (start, cnt, itt);
2886 XMLNode &after = playlist->get_state();
2887 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2890 commit_reversible_command ();
2908 Editor::cut_copy (CutCopyOp op)
2910 /* only cancel selection if cut/copy is successful.*/
2922 opname = _("clear");
2926 cut_buffer->clear ();
2928 switch (current_mouse_mode()) {
2930 if (!selection->regions.empty() || !selection->points.empty()) {
2932 begin_reversible_command (opname + _(" objects"));
2934 if (!selection->regions.empty()) {
2936 cut_copy_regions (op);
2939 selection->clear_regions ();
2943 if (!selection->points.empty()) {
2944 cut_copy_points (op);
2947 selection->clear_points ();
2951 commit_reversible_command ();
2956 if (!selection->time.empty()) {
2958 begin_reversible_command (opname + _(" range"));
2959 cut_copy_ranges (op);
2960 commit_reversible_command ();
2963 selection->clear_time ();
2975 Editor::cut_copy_points (CutCopyOp op)
2977 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2979 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2982 atv->cut_copy_clear_objects (selection->points, op);
2988 Editor::cut_copy_regions (CutCopyOp op)
2990 typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
2991 PlaylistMapping pmap;
2992 jack_nframes_t first_position = max_frames;
2993 set<Playlist*> freezelist;
2994 pair<set<Playlist*>::iterator,bool> insert_result;
2996 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2997 first_position = min ((*x)->region()->position(), first_position);
2999 if (op == Cut || op == Clear) {
3000 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
3002 insert_result = freezelist.insert (pl);
3003 if (insert_result.second) {
3005 session->add_command (new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
3011 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3013 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
3015 RegionSelection::iterator tmp;
3022 PlaylistMapping::iterator pi = pmap.find (pl);
3024 if (pi == pmap.end()) {
3025 npl = new AudioPlaylist (*session, "cutlist", true);
3033 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3038 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3039 pl->remove_region (((*x)->region()));
3045 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3049 pl->remove_region (((*x)->region()));
3057 list<Playlist*> foo;
3059 for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3060 foo.push_back (i->second);
3064 cut_buffer->set (foo);
3067 for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3069 session->add_command (new MementoCommand<Playlist>(*(*pl), 0, &(*pl)->get_state()));
3074 Editor::cut_copy_ranges (CutCopyOp op)
3076 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3077 (*i)->cut_copy_clear (*selection, op);
3082 Editor::paste (float times)
3084 paste_internal (edit_cursor->current_frame, times);
3088 Editor::mouse_paste ()
3093 track_canvas.get_pointer (x, y);
3094 track_canvas.window_to_world (x, y, wx, wy);
3095 wx += horizontal_adjustment.get_value();
3096 wy += vertical_adjustment.get_value();
3099 event.type = GDK_BUTTON_RELEASE;
3100 event.button.x = wx;
3101 event.button.y = wy;
3103 jack_nframes_t where = event_frame (&event, 0, 0);
3105 paste_internal (where, 1);
3109 Editor::paste_internal (jack_nframes_t position, float times)
3111 bool commit = false;
3113 if (cut_buffer->empty() || selection->tracks.empty()) {
3117 if (position == max_frames) {
3118 position = edit_cursor->current_frame;
3121 begin_reversible_command (_("paste"));
3123 TrackSelection::iterator i;
3126 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3128 /* undo/redo is handled by individual tracks */
3130 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3136 commit_reversible_command ();
3141 Editor::paste_named_selection (float times)
3143 TrackSelection::iterator t;
3145 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3147 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3151 TreeModel::iterator i = selected->get_selected();
3152 NamedSelection* ns = (*i)[named_selection_columns.selection];
3154 list<Playlist*>::iterator chunk;
3155 list<Playlist*>::iterator tmp;
3157 chunk = ns->playlists.begin();
3159 begin_reversible_command (_("paste chunk"));
3161 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3163 AudioTimeAxisView* atv;
3167 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3171 if ((pl = atv->playlist()) == 0) {
3175 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3182 XMLNode &before = apl->get_state();
3183 apl->paste (**chunk, edit_cursor->current_frame, times);
3184 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3186 if (tmp != ns->playlists.end()) {
3191 commit_reversible_command();
3195 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3198 RegionSelection sel = regions; // clear (below) will clear the argument list
3200 begin_reversible_command (_("duplicate region"));
3202 selection->clear_regions ();
3204 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3206 boost::shared_ptr<Region> r ((*i)->region());
3208 TimeAxisView& tv = (*i)->get_time_axis_view();
3209 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3210 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3212 playlist = (*i)->region()->playlist();
3213 XMLNode &before = playlist->get_state();
3214 playlist->duplicate (r, r->last_frame(), times);
3215 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3219 if (latest_regionview) {
3220 selection->add (latest_regionview);
3225 commit_reversible_command ();
3229 Editor::duplicate_selection (float times)
3231 if (selection->time.empty() || selection->tracks.empty()) {
3236 vector<boost::shared_ptr<AudioRegion> > new_regions;
3237 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3239 create_region_from_selection (new_regions);
3241 if (new_regions.empty()) {
3245 begin_reversible_command (_("duplicate selection"));
3247 ri = new_regions.begin();
3249 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3250 if ((playlist = (*i)->playlist()) == 0) {
3253 XMLNode &before = playlist->get_state();
3254 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3255 XMLNode &after = playlist->get_state();
3256 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3259 if (ri == new_regions.end()) {
3264 commit_reversible_command ();
3268 Editor::reset_point_selection ()
3270 /* reset all selected points to the relevant default value */
3272 cerr << "point selection has " << selection->points.size() << " entries\n";
3274 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3276 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3279 atv->reset_objects (selection->points);
3285 Editor::center_playhead ()
3287 float page = canvas_width * frames_per_unit;
3289 center_screen_internal (playhead_cursor->current_frame, page);
3293 Editor::center_edit_cursor ()
3295 float page = canvas_width * frames_per_unit;
3297 center_screen_internal (edit_cursor->current_frame, page);
3301 Editor::clear_playlist (Playlist& playlist)
3303 begin_reversible_command (_("clear playlist"));
3304 XMLNode &before = playlist.get_state();
3306 XMLNode &after = playlist.get_state();
3307 session->add_command (new MementoCommand<Playlist>(playlist, &before, &after));
3308 commit_reversible_command ();
3312 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3315 jack_nframes_t distance;
3316 jack_nframes_t next_distance;
3317 jack_nframes_t start;
3319 if (use_edit_cursor) {
3320 start = edit_cursor->current_frame;
3325 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3329 if (selection->tracks.empty()) {
3333 begin_reversible_command (_("nudge track"));
3335 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3337 if ((playlist = (*i)->playlist()) == 0) {
3341 XMLNode &before = playlist->get_state();
3342 playlist->nudge_after (start, distance, forwards);
3343 XMLNode &after = playlist->get_state();
3344 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3347 commit_reversible_command ();
3351 Editor::remove_last_capture ()
3353 vector<string> choices;
3360 if (Config->get_verify_remove_last_capture()) {
3361 prompt = _("Do you really want to destroy the last capture?"
3362 "\n(This is destructive and cannot be undone)");
3364 choices.push_back (_("No, do nothing."));
3365 choices.push_back (_("Yes, destroy it."));
3367 Gtkmm2ext::Choice prompter (prompt, choices);
3369 if (prompter.run () == 1) {
3370 session->remove_last_capture ();
3374 session->remove_last_capture();
3379 Editor::normalize_region ()
3385 if (selection->regions.empty()) {
3389 begin_reversible_command (_("normalize"));
3391 track_canvas.get_window()->set_cursor (*wait_cursor);
3394 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3395 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3398 XMLNode &before = arv->region()->get_state();
3399 arv->audio_region()->normalize_to (0.0f);
3400 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3403 commit_reversible_command ();
3404 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3409 Editor::denormalize_region ()
3415 if (selection->regions.empty()) {
3419 begin_reversible_command ("denormalize");
3421 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3422 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3425 XMLNode &before = arv->region()->get_state();
3426 arv->audio_region()->set_scale_amplitude (1.0f);
3427 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3430 commit_reversible_command ();
3435 Editor::reverse_region ()
3441 Reverse rev (*session);
3442 apply_filter (rev, _("reverse regions"));
3446 Editor::apply_filter (AudioFilter& filter, string command)
3448 if (selection->regions.empty()) {
3452 begin_reversible_command (command);
3454 track_canvas.get_window()->set_cursor (*wait_cursor);
3457 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3458 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3462 Playlist* playlist = arv->region()->playlist();
3464 RegionSelection::iterator tmp;
3469 if (arv->audio_region()->apply (filter) == 0) {
3471 XMLNode &before = playlist->get_state();
3472 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3473 XMLNode &after = playlist->get_state();
3474 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3482 commit_reversible_command ();
3483 selection->regions.clear ();
3486 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3490 Editor::region_selection_op (void (Region::*pmf)(void))
3492 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3493 Region* region = (*i)->region().get();
3500 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3502 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3503 Region* region = (*i)->region().get();
3504 (region->*pmf)(arg);
3509 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3511 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3512 Region* region = (*i)->region().get();
3518 Editor::external_edit_region ()
3520 if (!clicked_regionview) {
3528 Editor::brush (jack_nframes_t pos)
3530 RegionSelection sel;
3533 if (selection->regions.empty()) {
3534 /* XXX get selection from region list */
3536 sel = selection->regions;
3543 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3544 mouse_brush_insert_region ((*i), pos);
3549 Editor::toggle_gain_envelope_visibility ()
3551 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3552 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3554 arv->set_envelope_visible (!arv->envelope_visible());
3559 Editor::toggle_gain_envelope_active ()
3561 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3562 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3564 arv->audio_region()->set_envelope_active (true);