ardour
editor_ops.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2004 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 /* Note: public Editor methods are documented in public_editor.h */
21 
22 #include <unistd.h>
23 
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <limits>
28 #include <map>
29 #include <set>
30 
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
38 
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
42 
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
58 #include "ardour/strip_silence.h"
60 
61 #include "canvas/canvas.h"
62 
63 #include "actions.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
71 #include "debug.h"
72 #include "editing.h"
73 #include "editor.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
81 #include "item_counts.h"
82 #include "keyboard.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
87 #include "note.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.h"
101 
102 #include "i18n.h"
103 
104 using namespace std;
105 using namespace ARDOUR;
106 using namespace PBD;
107 using namespace Gtk;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
111 
112 /***********************************************************************
113  Editor operations
114  ***********************************************************************/
115 
116 void
117 Editor::undo (uint32_t n)
118 {
119  if (_drags->active ()) {
120  _drags->abort ();
121  }
122 
123  if (_session) {
124  _session->undo (n);
125  if (_session->undo_depth() == 0) {
126  undo_action->set_sensitive(false);
127  }
128  redo_action->set_sensitive(true);
129  begin_selection_op_history ();
130  }
131 }
132 
133 void
134 Editor::redo (uint32_t n)
135 {
136  if (_drags->active ()) {
137  _drags->abort ();
138  }
139 
140  if (_session) {
141  _session->redo (n);
142  if (_session->redo_depth() == 0) {
143  redo_action->set_sensitive(false);
144  }
145  undo_action->set_sensitive(true);
146  begin_selection_op_history ();
147  }
148 }
149 
150 void
152 {
153  bool frozen = false;
154 
155  RegionSelection pre_selected_regions = selection->regions;
156  bool working_on_selection = !pre_selected_regions.empty();
157 
158  list<boost::shared_ptr<Playlist> > used_playlists;
159  list<RouteTimeAxisView*> used_trackviews;
160 
161  if (regions.empty()) {
162  return;
163  }
164 
165  begin_reversible_command (_("split"));
166 
167  // if splitting a single region, and snap-to is using
168  // region boundaries, don't pay attention to them
169 
170  if (regions.size() == 1) {
171  switch (_snap_type) {
172  case SnapToRegionStart:
173  case SnapToRegionSync:
174  case SnapToRegionEnd:
175  break;
176  default:
177  snap_to (where);
178  }
179  } else {
180  snap_to (where);
181 
182  frozen = true;
183  EditorFreeze(); /* Emit Signal */
184  }
185 
186  for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
187 
188  RegionSelection::iterator tmp;
189 
190  /* XXX this test needs to be more complicated, to make sure we really
191  have something to split.
192  */
193 
194  if (!(*a)->region()->covers (where)) {
195  ++a;
196  continue;
197  }
198 
199  tmp = a;
200  ++tmp;
201 
202  boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
203 
204  if (!pl) {
205  a = tmp;
206  continue;
207  }
208 
209  if (!pl->frozen()) {
210  /* we haven't seen this playlist before */
211 
212  /* remember used playlists so we can thaw them later */
213  used_playlists.push_back(pl);
214 
215  TimeAxisView& tv = (*a)->get_time_axis_view();
216  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
217  if (rtv) {
218  used_trackviews.push_back (rtv);
219  }
220  pl->freeze();
221  }
222 
223 
224  if (pl) {
225  pl->clear_changes ();
226  pl->split_region ((*a)->region(), where);
227  _session->add_command (new StatefulDiffCommand (pl));
228  }
229 
230  a = tmp;
231  }
232 
233  latest_regionviews.clear ();
234 
235  vector<sigc::connection> region_added_connections;
236 
237  for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238  region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
239  }
240 
241  while (used_playlists.size() > 0) {
242  list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
243  (*i)->thaw();
244  used_playlists.pop_front();
245  }
246 
247  for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
248  (*c).disconnect ();
249  }
250 
251  if (frozen){
252  EditorThaw(); /* Emit Signal */
253  }
254 
255  if (working_on_selection) {
256  // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
257 
258  _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
259  RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260  /* There are three classes of regions that we might want selected after
261  splitting selected regions:
262  - regions selected before the split operation, and unaffected by it
263  - newly-created regions before the split
264  - newly-created regions after the split
265  */
266 
267  if (rsas & Existing) {
268  // region selections that existed before the split.
269  selection->add ( pre_selected_regions );
270  }
271 
272  for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273  if ((*ri)->region()->position() < where) {
274  // new regions created before the split
275  if (rsas & NewlyCreatedLeft) {
276  selection->add (*ri);
277  }
278  } else {
279  // new regions created after the split
280  if (rsas & NewlyCreatedRight) {
281  selection->add (*ri);
282  }
283  }
284  }
285  _ignore_follow_edits = false;
286  } else {
287  _ignore_follow_edits = true;
288  if( working_on_selection ) {
289  selection->add (latest_regionviews); //these are the new regions created after the split
290  }
291  _ignore_follow_edits = false;
292  }
293 
294  commit_reversible_command ();
295 }
296 
305 void
307 {
308  if (selection->time.start() == selection->time.end_frame()) {
309  return;
310  }
311 
312  framepos_t start = selection->time.start ();
313  framepos_t end = selection->time.end_frame ();
314 
315  /* the position of the thing we may move */
316  framepos_t pos = move_end ? end : start;
317  int dir = next ? 1 : -1;
318 
319  /* so we don't find the current region again */
320  if (dir > 0 || pos > 0) {
321  pos += dir;
322  }
323 
324  framepos_t const target = get_region_boundary (pos, dir, true, false);
325  if (target < 0) {
326  return;
327  }
328 
329  if (move_end) {
330  end = target;
331  } else {
332  start = target;
333  }
334 
335  if (end < start) {
336  return;
337  }
338 
339  begin_reversible_command (_("alter selection"));
340  selection->set_preserving_all_ranges (start, end);
341  commit_reversible_command ();
342 }
343 
344 bool
345 Editor::nudge_forward_release (GdkEventButton* ev)
346 {
347  if (ev->state & Keyboard::PrimaryModifier) {
348  nudge_forward (false, true);
349  } else {
350  nudge_forward (false, false);
351  }
352  return false;
353 }
354 
355 bool
356 Editor::nudge_backward_release (GdkEventButton* ev)
357 {
358  if (ev->state & Keyboard::PrimaryModifier) {
359  nudge_backward (false, true);
360  } else {
361  nudge_backward (false, false);
362  }
363  return false;
364 }
365 
366 
367 void
368 Editor::nudge_forward (bool next, bool force_playhead)
369 {
370  framepos_t distance;
371  framepos_t next_distance;
372 
373  if (!_session) {
374  return;
375  }
376 
377  RegionSelection rs = get_regions_from_selection_and_entered ();
378 
379  if (!force_playhead && !rs.empty()) {
380 
381  begin_reversible_command (_("nudge regions forward"));
382 
383  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384  boost::shared_ptr<Region> r ((*i)->region());
385 
386  distance = get_nudge_distance (r->position(), next_distance);
387 
388  if (next) {
389  distance = next_distance;
390  }
391 
392  r->clear_changes ();
393  r->set_position (r->position() + distance);
394  _session->add_command (new StatefulDiffCommand (r));
395  }
396 
397  commit_reversible_command ();
398 
399 
400  } else if (!force_playhead && !selection->markers.empty()) {
401 
402  bool is_start;
403 
404  begin_reversible_command (_("nudge location forward"));
405 
406  for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
407 
408  Location* loc = find_location_from_marker ((*i), is_start);
409 
410  if (loc) {
411 
412  XMLNode& before (loc->get_state());
413 
414  if (is_start) {
415  distance = get_nudge_distance (loc->start(), next_distance);
416  if (next) {
417  distance = next_distance;
418  }
419  if (max_framepos - distance > loc->start() + loc->length()) {
420  loc->set_start (loc->start() + distance);
421  } else {
422  loc->set_start (max_framepos - loc->length());
423  }
424  } else {
425  distance = get_nudge_distance (loc->end(), next_distance);
426  if (next) {
427  distance = next_distance;
428  }
429  if (max_framepos - distance > loc->end()) {
430  loc->set_end (loc->end() + distance);
431  } else {
432  loc->set_end (max_framepos);
433  }
434  }
435  XMLNode& after (loc->get_state());
436  _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
437  }
438  }
439 
440  commit_reversible_command ();
441 
442  } else {
443  distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
444  _session->request_locate (playhead_cursor->current_frame () + distance);
445  }
446 }
447 
448 void
449 Editor::nudge_backward (bool next, bool force_playhead)
450 {
451  framepos_t distance;
452  framepos_t next_distance;
453 
454  if (!_session) {
455  return;
456  }
457 
458  RegionSelection rs = get_regions_from_selection_and_entered ();
459 
460  if (!force_playhead && !rs.empty()) {
461 
462  begin_reversible_command (_("nudge regions backward"));
463 
464  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
465  boost::shared_ptr<Region> r ((*i)->region());
466 
467  distance = get_nudge_distance (r->position(), next_distance);
468 
469  if (next) {
470  distance = next_distance;
471  }
472 
473  r->clear_changes ();
474 
475  if (r->position() > distance) {
476  r->set_position (r->position() - distance);
477  } else {
478  r->set_position (0);
479  }
480  _session->add_command (new StatefulDiffCommand (r));
481  }
482 
483  commit_reversible_command ();
484 
485  } else if (!force_playhead && !selection->markers.empty()) {
486 
487  bool is_start;
488 
489  begin_reversible_command (_("nudge location forward"));
490 
491  for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
492 
493  Location* loc = find_location_from_marker ((*i), is_start);
494 
495  if (loc) {
496 
497  XMLNode& before (loc->get_state());
498 
499  if (is_start) {
500  distance = get_nudge_distance (loc->start(), next_distance);
501  if (next) {
502  distance = next_distance;
503  }
504  if (distance < loc->start()) {
505  loc->set_start (loc->start() - distance);
506  } else {
507  loc->set_start (0);
508  }
509  } else {
510  distance = get_nudge_distance (loc->end(), next_distance);
511 
512  if (next) {
513  distance = next_distance;
514  }
515 
516  if (distance < loc->end() - loc->length()) {
517  loc->set_end (loc->end() - distance);
518  } else {
519  loc->set_end (loc->length());
520  }
521  }
522 
523  XMLNode& after (loc->get_state());
524  _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
525  }
526  }
527 
528  commit_reversible_command ();
529 
530  } else {
531 
532  distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
533 
534  if (playhead_cursor->current_frame () > distance) {
535  _session->request_locate (playhead_cursor->current_frame () - distance);
536  } else {
537  _session->goto_start();
538  }
539  }
540 }
541 
542 void
544 {
545  RegionSelection rs = get_regions_from_selection_and_entered ();
546 
547  if (!_session || rs.empty()) {
548  return;
549  }
550 
551  begin_reversible_command (_("nudge forward"));
552 
553  framepos_t const distance = _session->worst_output_latency();
554 
555  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
556  boost::shared_ptr<Region> r ((*i)->region());
557 
558  r->clear_changes ();
559  r->set_position (r->position() + distance);
560  _session->add_command(new StatefulDiffCommand (r));
561  }
562 
563  commit_reversible_command ();
564 }
565 
566 void
568 {
569  RegionSelection rs = get_regions_from_selection_and_entered ();
570 
571  if (!_session || rs.empty()) {
572  return;
573  }
574 
575  begin_reversible_command (_("nudge backward"));
576 
577  framepos_t const distance = _session->worst_output_latency();
578 
579  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
580  boost::shared_ptr<Region> r ((*i)->region());
581 
582  r->clear_changes ();
583 
584  if (r->position() > distance) {
585  r->set_position (r->position() - distance);
586  } else {
587  r->set_position (0);
588  }
589  _session->add_command(new StatefulDiffCommand (r));
590  }
591 
592  commit_reversible_command ();
593 }
594 
596  bool operator() (RegionView* a, RegionView* b) {
597  return a->region()->position() < b->region()->position();
598  }
599 };
600 
601 void
603 {
604  framepos_t r_end;
605  framepos_t r_end_prev;
606 
607  int iCount=0;
608 
609  if (!_session) {
610  return;
611  }
612 
613  RegionSelection rs = get_regions_from_selection_and_entered ();
615 
616  if (!rs.empty()) {
617 
618  begin_reversible_command (_("sequence regions"));
619  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
620  boost::shared_ptr<Region> r ((*i)->region());
621 
622  r->clear_changes();
623 
624  if(r->locked())
625  {
626  continue;
627  }
628  if(r->position_locked())
629  {
630  continue;
631  }
632  if(iCount>0)
633  {
634  r_end_prev=r_end;
635  r->set_position(r_end_prev);
636  }
637 
638  _session->add_command (new StatefulDiffCommand (r));
639 
640  r_end=r->position() + r->length();
641 
642  iCount++;
643  }
644  commit_reversible_command ();
645  }
646 }
647 
648 
649 /* DISPLAY MOTION */
650 
651 void
653 {
654  _session->goto_start ();
655 }
656 
657 void
659 {
660 
661  _session->request_locate (_session->current_end_frame());
662 }
663 
664 void
666 {
667  framepos_t pos = 0;
668  vector<RegionPoint> interesting_points;
670  TrackViewList tracks;
671  bool at_end = false;
672 
673  region_boundary_cache.clear ();
674 
675  if (_session == 0) {
676  return;
677  }
678 
679  switch (_snap_type) {
680  case SnapToRegionStart:
681  interesting_points.push_back (Start);
682  break;
683  case SnapToRegionEnd:
684  interesting_points.push_back (End);
685  break;
686  case SnapToRegionSync:
687  interesting_points.push_back (SyncPoint);
688  break;
689  case SnapToRegionBoundary:
690  interesting_points.push_back (Start);
691  interesting_points.push_back (End);
692  break;
693  default:
694  fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
695  abort(); /*NOTREACHED*/
696  return;
697  }
698 
699  TimeAxisView *ontrack = 0;
700  TrackViewList tlist;
701 
702  if (!selection->tracks.empty()) {
703  tlist = selection->tracks.filter_to_unique_playlists ();
704  } else {
705  tlist = track_views.filter_to_unique_playlists ();
706  }
707 
708  while (pos < _session->current_end_frame() && !at_end) {
709 
710  framepos_t rpos;
711  framepos_t lpos = max_framepos;
712 
713  for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
714 
715  if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
716  if (*p == interesting_points.back()) {
717  at_end = true;
718  }
719  /* move to next point type */
720  continue;
721  }
722 
723  switch (*p) {
724  case Start:
725  rpos = r->first_frame();
726  break;
727 
728  case End:
729  rpos = r->last_frame();
730  break;
731 
732  case SyncPoint:
733  rpos = r->sync_position ();
734  break;
735 
736  default:
737  break;
738  }
739 
740  float speed = 1.0f;
741  RouteTimeAxisView *rtav;
742 
743  if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
744  if (rtav->track() != 0) {
745  speed = rtav->track()->speed();
746  }
747  }
748 
749  rpos = track_frame_to_session_frame (rpos, speed);
750 
751  if (rpos < lpos) {
752  lpos = rpos;
753  }
754 
755  /* prevent duplicates, but we don't use set<> because we want to be able
756  to sort later.
757  */
758 
759  vector<framepos_t>::iterator ri;
760 
761  for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
762  if (*ri == rpos) {
763  break;
764  }
765  }
766 
767  if (ri == region_boundary_cache.end()) {
768  region_boundary_cache.push_back (rpos);
769  }
770  }
771 
772  pos = lpos + 1;
773  }
774 
775  /* finally sort to be sure that the order is correct */
776 
777  sort (region_boundary_cache.begin(), region_boundary_cache.end());
778 }
779 
781 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
782 {
783  TrackViewList::iterator i;
784  framepos_t closest = max_framepos;
786  framepos_t rpos = 0;
787 
788  float track_speed;
789  framepos_t track_frame;
790  RouteTimeAxisView *rtav;
791 
792  for (i = tracks.begin(); i != tracks.end(); ++i) {
793 
794  framecnt_t distance;
796 
797  track_speed = 1.0f;
798  if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
799  if (rtav->track()!=0)
800  track_speed = rtav->track()->speed();
801  }
802 
803  track_frame = session_frame_to_track_frame(frame, track_speed);
804 
805  if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
806  continue;
807  }
808 
809  switch (point) {
810  case Start:
811  rpos = r->first_frame ();
812  break;
813 
814  case End:
815  rpos = r->last_frame ();
816  break;
817 
818  case SyncPoint:
819  rpos = r->sync_position ();
820  break;
821  }
822 
823  // rpos is a "track frame", converting it to "_session frame"
824  rpos = track_frame_to_session_frame(rpos, track_speed);
825 
826  if (rpos > frame) {
827  distance = rpos - frame;
828  } else {
829  distance = frame - rpos;
830  }
831 
832  if (distance < closest) {
833  closest = distance;
834  if (ontrack != 0)
835  *ontrack = (*i);
836  ret = r;
837  }
838  }
839 
840  return ret;
841 }
842 
845 {
846  framecnt_t distance = max_framepos;
847  framepos_t current_nearest = -1;
848 
849  for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
850  framepos_t contender;
851  framecnt_t d;
852 
853  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
854 
855  if (!rtv) {
856  continue;
857  }
858 
859  if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
860  continue;
861  }
862 
863  d = ::llabs (pos - contender);
864 
865  if (d < distance) {
866  current_nearest = contender;
867  distance = d;
868  }
869  }
870 
871  return current_nearest;
872 }
873 
875 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
876 {
877  framepos_t target;
878  TrackViewList tvl;
879 
880  if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
881 
882  if (!selection->tracks.empty()) {
883 
884  target = find_next_region_boundary (pos, dir, selection->tracks);
885 
886  } else {
887 
888  if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
889  get_onscreen_tracks (tvl);
890  target = find_next_region_boundary (pos, dir, tvl);
891  } else {
892  target = find_next_region_boundary (pos, dir, track_views);
893  }
894  }
895 
896  } else {
897 
898  if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
899  get_onscreen_tracks (tvl);
900  target = find_next_region_boundary (pos, dir, tvl);
901  } else {
902  target = find_next_region_boundary (pos, dir, track_views);
903  }
904  }
905 
906  return target;
907 }
908 
909 void
910 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
911 {
912  framepos_t pos = playhead_cursor->current_frame ();
913  framepos_t target;
914 
915  if (!_session) {
916  return;
917  }
918 
919  // so we don't find the current region again..
920  if (dir > 0 || pos > 0) {
921  pos += dir;
922  }
923 
924  if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
925  return;
926  }
927 
928  _session->request_locate (target);
929 }
930 
931 void
933 {
934  cursor_to_region_boundary (with_selection, 1);
935 }
936 
937 void
939 {
940  cursor_to_region_boundary (with_selection, -1);
941 }
942 
943 void
945 {
947  framepos_t pos = cursor->current_frame ();
948 
949  if (!_session) {
950  return;
951  }
952 
953  TimeAxisView *ontrack = 0;
954 
955  // so we don't find the current region again..
956  if (dir>0 || pos>0)
957  pos+=dir;
958 
959  if (!selection->tracks.empty()) {
960 
961  r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
962 
963  } else if (clicked_axisview) {
964 
965  TrackViewList t;
966  t.push_back (clicked_axisview);
967 
968  r = find_next_region (pos, point, dir, t, &ontrack);
969 
970  } else {
971 
972  r = find_next_region (pos, point, dir, track_views, &ontrack);
973  }
974 
975  if (r == 0) {
976  return;
977  }
978 
979  switch (point) {
980  case Start:
981  pos = r->first_frame ();
982  break;
983 
984  case End:
985  pos = r->last_frame ();
986  break;
987 
988  case SyncPoint:
989  pos = r->sync_position ();
990  break;
991  }
992 
993  float speed = 1.0f;
994  RouteTimeAxisView *rtav;
995 
996  if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
997  if (rtav->track() != 0) {
998  speed = rtav->track()->speed();
999  }
1000  }
1001 
1002  pos = track_frame_to_session_frame(pos, speed);
1003 
1004  if (cursor == playhead_cursor) {
1005  _session->request_locate (pos);
1006  } else {
1007  cursor->set_position (pos);
1008  }
1009 }
1010 
1011 void
1013 {
1014  cursor_to_region_point (cursor, point, 1);
1015 }
1016 
1017 void
1019 {
1020  cursor_to_region_point (cursor, point, -1);
1021 }
1022 
1023 void
1025 {
1026  framepos_t pos = 0;
1027 
1028  switch (mouse_mode) {
1029  case MouseObject:
1030  if (!selection->regions.empty()) {
1031  pos = selection->regions.start();
1032  }
1033  break;
1034 
1035  case MouseRange:
1036  if (!selection->time.empty()) {
1037  pos = selection->time.start ();
1038  }
1039  break;
1040 
1041  default:
1042  return;
1043  }
1044 
1045  if (cursor == playhead_cursor) {
1046  _session->request_locate (pos);
1047  } else {
1048  cursor->set_position (pos);
1049  }
1050 }
1051 
1052 void
1054 {
1055  framepos_t pos = 0;
1056 
1057  switch (mouse_mode) {
1058  case MouseObject:
1059  if (!selection->regions.empty()) {
1060  pos = selection->regions.end_frame();
1061  }
1062  break;
1063 
1064  case MouseRange:
1065  if (!selection->time.empty()) {
1066  pos = selection->time.end_frame ();
1067  }
1068  break;
1069 
1070  default:
1071  return;
1072  }
1073 
1074  if (cursor == playhead_cursor) {
1075  _session->request_locate (pos);
1076  } else {
1077  cursor->set_position (pos);
1078  }
1079 }
1080 
1081 void
1082 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1083 {
1084  framepos_t target;
1085  Location* loc;
1086  bool ignored;
1087 
1088  if (!_session) {
1089  return;
1090  }
1091 
1092  if (selection->markers.empty()) {
1093  framepos_t mouse;
1094  bool ignored;
1095 
1096  if (!mouse_frame (mouse, ignored)) {
1097  return;
1098  }
1099 
1100  add_location_mark (mouse);
1101  }
1102 
1103  if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1104  return;
1105  }
1106 
1107  framepos_t pos = loc->start();
1108 
1109  // so we don't find the current region again..
1110  if (dir > 0 || pos > 0) {
1111  pos += dir;
1112  }
1113 
1114  if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1115  return;
1116  }
1117 
1118  loc->move_to (target);
1119 }
1120 
1121 void
1123 {
1124  selected_marker_to_region_boundary (with_selection, 1);
1125 }
1126 
1127 void
1129 {
1130  selected_marker_to_region_boundary (with_selection, -1);
1131 }
1132 
1133 void
1135 {
1137  framepos_t pos;
1138  Location* loc;
1139  bool ignored;
1140 
1141  if (!_session || selection->markers.empty()) {
1142  return;
1143  }
1144 
1145  if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1146  return;
1147  }
1148 
1149  TimeAxisView *ontrack = 0;
1150 
1151  pos = loc->start();
1152 
1153  // so we don't find the current region again..
1154  if (dir>0 || pos>0)
1155  pos+=dir;
1156 
1157  if (!selection->tracks.empty()) {
1158 
1159  r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1160 
1161  } else {
1162 
1163  r = find_next_region (pos, point, dir, track_views, &ontrack);
1164  }
1165 
1166  if (r == 0) {
1167  return;
1168  }
1169 
1170  switch (point) {
1171  case Start:
1172  pos = r->first_frame ();
1173  break;
1174 
1175  case End:
1176  pos = r->last_frame ();
1177  break;
1178 
1179  case SyncPoint:
1180  pos = r->adjust_to_sync (r->first_frame());
1181  break;
1182  }
1183 
1184  float speed = 1.0f;
1185  RouteTimeAxisView *rtav;
1186 
1187  if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1188  if (rtav->track() != 0) {
1189  speed = rtav->track()->speed();
1190  }
1191  }
1192 
1193  pos = track_frame_to_session_frame(pos, speed);
1194 
1195  loc->move_to (pos);
1196 }
1197 
1198 void
1200 {
1201  selected_marker_to_region_point (point, 1);
1202 }
1203 
1204 void
1206 {
1207  selected_marker_to_region_point (point, -1);
1208 }
1209 
1210 void
1212 {
1213  framepos_t pos = 0;
1214  Location* loc;
1215  bool ignored;
1216 
1217  if (!_session || selection->markers.empty()) {
1218  return;
1219  }
1220 
1221  if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1222  return;
1223  }
1224 
1225  switch (mouse_mode) {
1226  case MouseObject:
1227  if (!selection->regions.empty()) {
1228  pos = selection->regions.start();
1229  }
1230  break;
1231 
1232  case MouseRange:
1233  if (!selection->time.empty()) {
1234  pos = selection->time.start ();
1235  }
1236  break;
1237 
1238  default:
1239  return;
1240  }
1241 
1242  loc->move_to (pos);
1243 }
1244 
1245 void
1247 {
1248  framepos_t pos = 0;
1249  Location* loc;
1250  bool ignored;
1251 
1252  if (!_session || selection->markers.empty()) {
1253  return;
1254  }
1255 
1256  if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1257  return;
1258  }
1259 
1260  switch (mouse_mode) {
1261  case MouseObject:
1262  if (!selection->regions.empty()) {
1263  pos = selection->regions.end_frame();
1264  }
1265  break;
1266 
1267  case MouseRange:
1268  if (!selection->time.empty()) {
1269  pos = selection->time.end_frame ();
1270  }
1271  break;
1272 
1273  default:
1274  return;
1275  }
1276 
1277  loc->move_to (pos);
1278 }
1279 
1280 void
1282 {
1283  framepos_t pos = playhead_cursor->current_frame ();
1284  framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1285 
1286  if (forward) {
1287  if (pos == max_framepos) {
1288  return;
1289  }
1290 
1291  if (pos < max_framepos - delta) {
1292  pos += delta ;
1293  } else {
1294  pos = max_framepos;
1295  }
1296 
1297  } else {
1298 
1299  if (pos == 0) {
1300  return;
1301  }
1302 
1303  if (pos > delta) {
1304  pos -= delta;
1305  } else {
1306  pos = 0;
1307  }
1308  }
1309 
1310  _session->request_locate (pos);
1311 }
1312 
1313 void
1314 Editor::cursor_align (bool playhead_to_edit)
1315 {
1316  if (!_session) {
1317  return;
1318  }
1319 
1320  if (playhead_to_edit) {
1321 
1322  if (selection->markers.empty()) {
1323  return;
1324  }
1325 
1326  _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1327 
1328  } else {
1329  /* move selected markers to playhead */
1330 
1331  for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1332  bool ignored;
1333 
1334  Location* loc = find_location_from_marker (*i, ignored);
1335 
1336  if (loc->is_mark()) {
1337  loc->set_start (playhead_cursor->current_frame ());
1338  } else {
1339  loc->set (playhead_cursor->current_frame (),
1340  playhead_cursor->current_frame () + loc->length());
1341  }
1342  }
1343  }
1344 }
1345 
1346 void
1348 {
1349  framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1350  framepos_t const cnt = (framepos_t) floor (pages * one_page);
1351 
1352  framepos_t frame;
1353  if (leftmost_frame < cnt) {
1354  frame = 0;
1355  } else {
1356  frame = leftmost_frame - cnt;
1357  }
1358 
1359  reset_x_origin (frame);
1360 }
1361 
1362 void
1364 {
1365  framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1366  framepos_t const cnt = (framepos_t) floor (pages * one_page);
1367 
1368  framepos_t frame;
1369  if (max_framepos - cnt < leftmost_frame) {
1370  frame = max_framepos - cnt;
1371  } else {
1372  frame = leftmost_frame + cnt;
1373  }
1374 
1375  reset_x_origin (frame);
1376 }
1377 
1378 void
1380 {
1381  double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1382  if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1383  vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1384  }
1385 
1386  vertical_adjustment.set_value (vert_value);
1387 }
1388 
1389 void
1391 {
1392  vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1393 }
1394 
1395 void
1397 {
1398  double vert_value = vertical_adjustment.get_value() + 60;
1399 
1400  if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401  vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1402  }
1403 
1404  vertical_adjustment.set_value (vert_value);
1405 }
1406 
1407 void
1409 {
1410  reset_y_origin (vertical_adjustment.get_value() - 60);
1411 }
1412 
1413 bool
1414 Editor::scroll_down_one_track (bool skip_child_views)
1415 {
1416  TrackViewList::reverse_iterator next = track_views.rend();
1417  const double top_of_trackviews = vertical_adjustment.get_value();
1418 
1419  for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1420  if ((*t)->hidden()) {
1421  continue;
1422  }
1423 
1424  /* If this is the upper-most visible trackview, we want to display
1425  * the one above it (next)
1426  *
1427  * Note that covers_y_position() is recursive and includes child views
1428  */
1429  std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1430 
1431  if (res.first) {
1432  if (skip_child_views) {
1433  break;
1434  }
1435  /* automation lane (one level, non-recursive)
1436  *
1437  * - if no automation lane exists -> move to next tack
1438  * - if the first (here: bottom-most) matches -> move to next tack
1439  * - if no y-axis match is found -> the current track is at the top
1440  * -> move to last (here: top-most) automation lane
1441  */
1442  TimeAxisView::Children kids = (*t)->get_child_list();
1443  TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1444 
1445  for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1446  if ((*ci)->hidden()) {
1447  continue;
1448  }
1449 
1450  std::pair<TimeAxisView*,double> dev;
1451  dev = (*ci)->covers_y_position (top_of_trackviews);
1452  if (dev.first) {
1453  /* some automation lane is currently at the top */
1454  if (ci == kids.rbegin()) {
1455  /* first (bottom-most) autmation lane is at the top.
1456  * -> move to next track
1457  */
1458  nkid = kids.rend();
1459  }
1460  break;
1461  }
1462  nkid = ci;
1463  }
1464 
1465  if (nkid != kids.rend()) {
1466  ensure_time_axis_view_is_visible (**nkid, true);
1467  return true;
1468  }
1469  break;
1470  }
1471  next = t;
1472  }
1473 
1474  /* move to the track below the first one that covers the */
1475 
1476  if (next != track_views.rend()) {
1477  ensure_time_axis_view_is_visible (**next, true);
1478  return true;
1479  }
1480 
1481  return false;
1482 }
1483 
1484 bool
1485 Editor::scroll_up_one_track (bool skip_child_views)
1486 {
1487  TrackViewList::iterator prev = track_views.end();
1488  double top_of_trackviews = vertical_adjustment.get_value ();
1489 
1490  for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1491 
1492  if ((*t)->hidden()) {
1493  continue;
1494  }
1495 
1496  /* find the trackview at the top of the trackview group
1497  *
1498  * Note that covers_y_position() is recursive and includes child views
1499  */
1500  std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1501 
1502  if (res.first) {
1503  if (skip_child_views) {
1504  break;
1505  }
1506  /* automation lane (one level, non-recursive)
1507  *
1508  * - if no automation lane exists -> move to prev tack
1509  * - if no y-axis match is found -> the current track is at the top -> move to prev track
1510  * (actually last automation lane of previous track, see below)
1511  * - if first (top-most) lane is at the top -> move to this track
1512  * - else move up one lane
1513  */
1514  TimeAxisView::Children kids = (*t)->get_child_list();
1515  TimeAxisView::Children::iterator pkid = kids.end();
1516 
1517  for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1518  if ((*ci)->hidden()) {
1519  continue;
1520  }
1521 
1522  std::pair<TimeAxisView*,double> dev;
1523  dev = (*ci)->covers_y_position (top_of_trackviews);
1524  if (dev.first) {
1525  /* some automation lane is currently at the top */
1526  if (ci == kids.begin()) {
1527  /* first (top-most) autmation lane is at the top.
1528  * jump directly to this track's top
1529  */
1530  ensure_time_axis_view_is_visible (**t, true);
1531  return true;
1532  }
1533  else if (pkid != kids.end()) {
1534  /* some other automation lane is at the top.
1535  * move up to prev automation lane.
1536  */
1537  ensure_time_axis_view_is_visible (**pkid, true);
1538  return true;
1539  }
1540  assert(0); // not reached
1541  break;
1542  }
1543  pkid = ci;
1544  }
1545  break;
1546  }
1547 
1548  prev = t;
1549  }
1550 
1551  if (prev != track_views.end()) {
1552  // move to bottom-most automation-lane of the previous track
1553  TimeAxisView::Children kids = (*prev)->get_child_list();
1554  TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1555  if (!skip_child_views) {
1556  // find the last visible lane
1557  for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1558  if (!(*ci)->hidden()) {
1559  pkid = ci;
1560  break;
1561  }
1562  }
1563  }
1564  if (pkid != kids.rend()) {
1565  ensure_time_axis_view_is_visible (**pkid, true);
1566  } else {
1567  ensure_time_axis_view_is_visible (**prev, true);
1568  }
1569  return true;
1570  }
1571 
1572  return false;
1573 }
1574 
1575 /* ZOOM */
1576 
1577 void
1579 {
1580  DisplaySuspender ds;
1581 
1582  TrackViewList* ts;
1583 
1584  if (selection->tracks.empty()) {
1585  ts = &track_views;
1586  } else {
1587  ts = &selection->tracks;
1588  }
1589 
1590  for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1591  TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1592  tv->step_height (coarser);
1593  }
1594 }
1595 
1596 void
1597 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1598 {
1599  DisplaySuspender ds;
1600 
1601  TrackViewList* ts;
1602 
1603  if (selection->tracks.empty() || force_all) {
1604  ts = &track_views;
1605  } else {
1606  ts = &selection->tracks;
1607  }
1608 
1609  for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1610  TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1611  uint32_t h = tv->current_height ();
1612 
1613  if (coarser) {
1614  if (h > 5) {
1615  h -= 5; // pixels
1617  tv->set_height (h);
1618  }
1619  }
1620  } else {
1621  tv->set_height (h + 5);
1622  }
1623  }
1624 }
1625 
1626 
1627 void
1629 {
1631 
1632  framecnt_t nspp = samples_per_pixel;
1633 
1634  if (coarser) {
1635  nspp *= 2;
1636  } else {
1637  nspp /= 2;
1638  }
1639 
1640  temporal_zoom (nspp);
1641 }
1642 
1643 void
1645 {
1646  if (!_session) {
1647  return;
1648  }
1649 
1650  framepos_t current_page = current_page_samples();
1651  framepos_t current_leftmost = leftmost_frame;
1652  framepos_t current_rightmost;
1653  framepos_t current_center;
1654  framepos_t new_page_size;
1655  framepos_t half_page_size;
1656  framepos_t leftmost_after_zoom = 0;
1657  framepos_t where;
1658  bool in_track_canvas;
1659  framecnt_t nfpp;
1660  double l;
1661 
1662  if (fpp == samples_per_pixel) {
1663  return;
1664  }
1665 
1666  // Imposing an arbitrary limit to zoom out as too much zoom out produces
1667  // segfaults for lack of memory. If somebody decides this is not high enough I
1668  // believe it can be raisen to higher values but some limit must be in place.
1669  //
1670  // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1671  // all of which is used for the editor track displays. The whole day
1672  // would be 4147200000 samples, so 2592000 samples per pixel.
1673 
1674  nfpp = min (fpp, (framecnt_t) 2592000);
1675  nfpp = max ((framecnt_t) 1, nfpp);
1676 
1677  new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1678  half_page_size = new_page_size / 2;
1679 
1680  switch (zoom_focus) {
1681  case ZoomFocusLeft:
1682  leftmost_after_zoom = current_leftmost;
1683  break;
1684 
1685  case ZoomFocusRight:
1686  current_rightmost = leftmost_frame + current_page;
1687  if (current_rightmost < new_page_size) {
1688  leftmost_after_zoom = 0;
1689  } else {
1690  leftmost_after_zoom = current_rightmost - new_page_size;
1691  }
1692  break;
1693 
1694  case ZoomFocusCenter:
1695  current_center = current_leftmost + (current_page/2);
1696  if (current_center < half_page_size) {
1697  leftmost_after_zoom = 0;
1698  } else {
1699  leftmost_after_zoom = current_center - half_page_size;
1700  }
1701  break;
1702 
1703  case ZoomFocusPlayhead:
1704  /* centre playhead */
1705  l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1706 
1707  if (l < 0) {
1708  leftmost_after_zoom = 0;
1709  } else if (l > max_framepos) {
1710  leftmost_after_zoom = max_framepos - new_page_size;
1711  } else {
1712  leftmost_after_zoom = (framepos_t) l;
1713  }
1714  break;
1715 
1716  case ZoomFocusMouse:
1717  /* try to keep the mouse over the same point in the display */
1718 
1719  if (!mouse_frame (where, in_track_canvas)) {
1720  /* use playhead instead */
1721  where = playhead_cursor->current_frame ();
1722 
1723  if (where < half_page_size) {
1724  leftmost_after_zoom = 0;
1725  } else {
1726  leftmost_after_zoom = where - half_page_size;
1727  }
1728 
1729  } else {
1730 
1731  l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1732 
1733  if (l < 0) {
1734  leftmost_after_zoom = 0;
1735  } else if (l > max_framepos) {
1736  leftmost_after_zoom = max_framepos - new_page_size;
1737  } else {
1738  leftmost_after_zoom = (framepos_t) l;
1739  }
1740  }
1741 
1742  break;
1743 
1744  case ZoomFocusEdit:
1745  /* try to keep the edit point in the same place */
1746  where = get_preferred_edit_position ();
1747 
1748  if (where > 0) {
1749 
1750  double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1751 
1752  if (l < 0) {
1753  leftmost_after_zoom = 0;
1754  } else if (l > max_framepos) {
1755  leftmost_after_zoom = max_framepos - new_page_size;
1756  } else {
1757  leftmost_after_zoom = (framepos_t) l;
1758  }
1759 
1760  } else {
1761  /* edit point not defined */
1762  return;
1763  }
1764  break;
1765 
1766  }
1767 
1768  // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1769 
1770  reposition_and_zoom (leftmost_after_zoom, nfpp);
1771 }
1772 
1773 void
1775 {
1776  /* this func helps make sure we leave a little space
1777  at each end of the editor so that the zoom doesn't fit the region
1778  precisely to the screen.
1779  */
1780 
1781  GdkScreen* screen = gdk_screen_get_default ();
1782  const gint pixwidth = gdk_screen_get_width (screen);
1783  const gint mmwidth = gdk_screen_get_width_mm (screen);
1784  const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1785  const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1786 
1787  const framepos_t range = end - start;
1788  const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1789  const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1790 
1791  if (start > extra_samples) {
1792  start -= extra_samples;
1793  } else {
1794  start = 0;
1795  }
1796 
1797  if (max_framepos - extra_samples > end) {
1798  end += extra_samples;
1799  } else {
1800  end = max_framepos;
1801  }
1802 }
1803 
1804 void
1806 {
1808  framepos_t end = 0;
1809  set<TimeAxisView*> tracks;
1810 
1811  if ( !get_selection_extents(start, end) )
1812  return;
1813 
1814  calc_extra_zoom_edges (start, end);
1815 
1816  /* if we're zooming on both axes we need to save track heights etc.
1817  */
1818 
1819  undo_visual_stack.push_back (current_visual_state (both_axes));
1820 
1821  PBD::Unwinder<bool> nsv (no_save_visual, true);
1822 
1823  temporal_zoom_by_frame (start, end);
1824 
1825  if (both_axes) {
1826  uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1827 
1828  /* set visible track heights appropriately */
1829 
1830  for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1831  (*t)->set_height (per_track_height);
1832  }
1833 
1834  /* hide irrelevant tracks */
1835 
1836  DisplaySuspender ds;
1837 
1838  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1839  if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1840  hide_track_in_display (*i);
1841  }
1842  }
1843 
1844  vertical_adjustment.set_value (0.0);
1845  }
1846 
1847  redo_visual_stack.push_back (current_visual_state (both_axes));
1848 }
1849 
1850 
1851 bool
1853 {
1854  start = max_framepos;
1855  end = 0;
1856  bool ret = true;
1857 
1858  //ToDo: if notes are selected, set extents to that selection
1859 
1860  //ToDo: if control points are selected, set extents to that selection
1861 
1862  if ( !selection->regions.empty() ) {
1863  RegionSelection rs = get_regions_from_selection_and_entered ();
1864 
1865  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1866 
1867  if ((*i)->region()->position() < start) {
1868  start = (*i)->region()->position();
1869  }
1870 
1871  if ((*i)->region()->last_frame() + 1 > end) {
1872  end = (*i)->region()->last_frame() + 1;
1873  }
1874  }
1875 
1876  } else if (!selection->time.empty()) {
1877  start = selection->time.start();
1878  end = selection->time.end_frame();
1879  } else
1880  ret = false; //no selection found
1881 
1882  //range check
1883  if ((start == 0 && end == 0) || end < start) {
1884  ret = false;
1885  }
1886 
1887  return ret;
1888 }
1889 
1890 
1891 void
1893 {
1894  if (!selection) return;
1895 
1896  //ToDo: if notes are selected, zoom to that
1897 
1898  //ToDo: if control points are selected, zoom to that
1899 
1900  //if region(s) are selected, zoom to that
1901  if ( !selection->regions.empty() )
1902  temporal_zoom_region (both_axes);
1903 
1904  //if a range is selected, zoom to that
1905  if (!selection->time.empty()) {
1906 
1907  framepos_t start, end;
1908  if (get_selection_extents (start, end)) {
1909  calc_extra_zoom_edges(start, end);
1910  temporal_zoom_by_frame (start, end);
1911  }
1912 
1913  if (both_axes)
1914  fit_selection();
1915  }
1916 
1917 }
1918 
1919 void
1921 {
1923 
1924  if (_session) {
1925  framecnt_t start = _session->current_start_frame();
1926  framecnt_t end = _session->current_end_frame();
1927 
1928  if (_session->actively_recording () ) {
1929  framepos_t cur = playhead_cursor->current_frame ();
1930  if (cur > end) {
1931  /* recording beyond the end marker; zoom out
1932  * by 5 seconds more so that if 'follow
1933  * playhead' is active we don't immediately
1934  * scroll.
1935  */
1936  end = cur + _session->frame_rate() * 5;
1937  }
1938  }
1939 
1940  if ((start == 0 && end == 0) || end < start) {
1941  return;
1942  }
1943 
1944  calc_extra_zoom_edges(start, end);
1945 
1946  temporal_zoom_by_frame (start, end);
1947  }
1948 }
1949 
1950 void
1952 {
1953  if (!_session) return;
1954 
1955  if ((start == 0 && end == 0) || end < start) {
1956  return;
1957  }
1958 
1959  framepos_t range = end - start;
1960 
1961  const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1962 
1963  framepos_t new_page = range;
1964  framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1965  framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1966 
1967  if (new_leftmost > middle) {
1968  new_leftmost = 0;
1969  }
1970 
1971  if (new_leftmost < 0) {
1972  new_leftmost = 0;
1973  }
1974 
1975  reposition_and_zoom (new_leftmost, new_fpp);
1976 }
1977 
1978 void
1980 {
1981  if (!_session) {
1982  return;
1983  }
1984 
1985  framecnt_t range_before = frame - leftmost_frame;
1986  framecnt_t new_spp;
1987 
1988  if (coarser) {
1989  if (samples_per_pixel <= 1) {
1990  new_spp = 2;
1991  } else {
1992  new_spp = samples_per_pixel + (samples_per_pixel/2);
1993  }
1994  range_before += range_before/2;
1995  } else {
1996  if (samples_per_pixel >= 1) {
1997  new_spp = samples_per_pixel - (samples_per_pixel/2);
1998  } else {
1999  /* could bail out here since we cannot zoom any finer,
2000  but leave that to the equality test below
2001  */
2002  new_spp = samples_per_pixel;
2003  }
2004 
2005  range_before -= range_before/2;
2006  }
2007 
2008  if (new_spp == samples_per_pixel) {
2009  return;
2010  }
2011 
2012  /* zoom focus is automatically taken as @param frame when this
2013  method is used.
2014  */
2015 
2016  framepos_t new_leftmost = frame - (framepos_t)range_before;
2017 
2018  if (new_leftmost > frame) {
2019  new_leftmost = 0;
2020  }
2021 
2022  if (new_leftmost < 0) {
2023  new_leftmost = 0;
2024  }
2025 
2026  reposition_and_zoom (new_leftmost, new_spp);
2027 }
2028 
2029 
2030 bool
2032 
2033  if (!ARDOUR_UI::config()->get_name_new_markers()) {
2034  /* don't prompt user for a new name */
2035  return true;
2036  }
2037 
2038  ArdourPrompter dialog (true);
2039 
2040  dialog.set_prompt (_("New Name:"));
2041 
2042  dialog.set_title (_("New Location Marker"));
2043 
2044  dialog.set_name ("MarkNameWindow");
2045  dialog.set_size_request (250, -1);
2046  dialog.set_position (Gtk::WIN_POS_MOUSE);
2047 
2048  dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2049  dialog.set_initial_text (name);
2050 
2051  dialog.show ();
2052 
2053  switch (dialog.run ()) {
2054  case RESPONSE_ACCEPT:
2055  break;
2056  default:
2057  return false;
2058  }
2059 
2060  dialog.get_result(name);
2061  return true;
2062 
2063 }
2064 
2065 
2066 void
2068 {
2069  string rangename;
2070 
2071  if (selection->time.empty()) {
2072  return;
2073  }
2074 
2075  if (_session == 0 || clicked_axisview == 0) {
2076  return;
2077  }
2078 
2079  framepos_t start = selection->time[clicked_selection].start;
2080  framepos_t end = selection->time[clicked_selection].end;
2081 
2082  _session->locations()->next_available_name(rangename,"selection");
2083  Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2084 
2085  begin_reversible_command (_("add marker"));
2086 
2087  XMLNode &before = _session->locations()->get_state();
2088  _session->locations()->add (location, true);
2089  XMLNode &after = _session->locations()->get_state();
2090  _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2091 
2092  commit_reversible_command ();
2093 }
2094 
2095 void
2097 {
2098  string markername;
2099 
2100  select_new_marker = true;
2101 
2102  _session->locations()->next_available_name(markername,"mark");
2103  if (!choose_new_marker_name(markername)) {
2104  return;
2105  }
2106  Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2107  begin_reversible_command (_("add marker"));
2108 
2109  XMLNode &before = _session->locations()->get_state();
2110  _session->locations()->add (location, true);
2111  XMLNode &after = _session->locations()->get_state();
2112  _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2113 
2114  commit_reversible_command ();
2115 }
2116 
2117 void
2119 {
2120  if (!_session)
2121  return;
2122 
2123  Location* loc;
2124  if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2125  _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2126  } else {
2127  XMLNode &before = loc->get_state();
2128 
2129  _session->set_session_extents ( _session->audible_frame(), loc->end() );
2130 
2131  XMLNode &after = loc->get_state();
2132 
2133  begin_reversible_command (_("Set session start"));
2134 
2135  _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2136 
2137  commit_reversible_command ();
2138  }
2139 }
2140 
2141 void
2143 {
2144  if (!_session)
2145  return;
2146 
2147  Location* loc;
2148  if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2149  _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2150  } else {
2151  XMLNode &before = loc->get_state();
2152 
2153  _session->set_session_extents ( loc->start(), _session->audible_frame() );
2154 
2155  XMLNode &after = loc->get_state();
2156 
2157  begin_reversible_command (_("Set session start"));
2158 
2159  _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2160 
2161  commit_reversible_command ();
2162  }
2163 }
2164 
2165 void
2167 {
2168  add_location_mark (_session->audible_frame());
2169 }
2170 
2171 void
2173 {
2174  if (_session) {
2175 
2176  //set up for undo
2177  begin_reversible_command (_("remove marker"));
2178 
2179  XMLNode &before = _session->locations()->get_state();
2180  bool removed = false;
2181 
2182  //find location(s) at this time
2184  _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2185  for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2186  if ((*i)->is_mark()) {
2187  _session->locations()->remove (*i);
2188  removed = true;
2189  }
2190  }
2191 
2192  //store undo
2193  if (removed) {
2194  XMLNode &after = _session->locations()->get_state();
2195  _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2196 
2197  commit_reversible_command ();
2198  }
2199  }
2200 }
2201 
2203 void
2205 {
2206  RegionSelection rs = get_regions_from_selection_and_entered ();
2207 
2208  if (rs.empty()) {
2209  return;
2210  }
2211 
2212  begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2213 
2214  XMLNode &before = _session->locations()->get_state();
2215 
2216  for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2217 
2218  boost::shared_ptr<Region> region = (*i)->region ();
2219 
2220  Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2221 
2222  _session->locations()->add (location, true);
2223  }
2224 
2225  XMLNode &after = _session->locations()->get_state();
2226  _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2227 
2228  commit_reversible_command ();
2229 }
2230 
2232 void
2234 {
2235  RegionSelection rs = get_regions_from_selection_and_entered ();
2236 
2237  if (rs.empty()) {
2238  return;
2239  }
2240 
2241  begin_reversible_command (_("add marker"));
2242 
2243  XMLNode &before = _session->locations()->get_state();
2244 
2245  string markername;
2246 
2247  if (rs.size() > 1) {
2248  _session->locations()->next_available_name(markername, "regions");
2249  } else {
2250  RegionView* rv = *(rs.begin());
2251  boost::shared_ptr<Region> region = rv->region();
2252  markername = region->name();
2253  }
2254 
2255  if (!choose_new_marker_name(markername)) {
2256  return;
2257  }
2258 
2259  // single range spanning all selected
2260  Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2261  _session->locations()->add (location, true);
2262 
2263  XMLNode &after = _session->locations()->get_state();
2264  _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2265 
2266  commit_reversible_command ();
2267 }
2268 
2269 /* MARKS */
2270 
2271 void
2273 {
2274  if (!_session) {
2275  return;
2276  }
2277 
2278  framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2279 
2280  if (pos < 0) {
2281  return;
2282  }
2283 
2284  _session->request_locate (pos, _session->transport_rolling());
2285 }
2286 
2287 void
2289 {
2290  if (!_session) {
2291  return;
2292  }
2293 
2294  framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2295 
2296  if (pos < 0) {
2297  return;
2298  }
2299 
2300  _session->request_locate (pos, _session->transport_rolling());
2301 }
2302 
2303 void
2305 {
2306  framepos_t const pos = _session->audible_frame ();
2307 
2308  string markername;
2309  _session->locations()->next_available_name (markername, "mark");
2310 
2311  if (!choose_new_marker_name (markername)) {
2312  return;
2313  }
2314 
2315  _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2316 }
2317 
2318 void
2320 {
2321  if (_session) {
2322  begin_reversible_command (_("clear markers"));
2323 
2324  XMLNode &before = _session->locations()->get_state();
2325  _session->locations()->clear_markers ();
2326  XMLNode &after = _session->locations()->get_state();
2327  _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2328 
2329  commit_reversible_command ();
2330  }
2331 }
2332 
2333 void
2335 {
2336  if (_session) {
2337  begin_reversible_command (_("clear ranges"));
2338 
2339  XMLNode &before = _session->locations()->get_state();
2340 
2341  _session->locations()->clear_ranges ();
2342 
2343  XMLNode &after = _session->locations()->get_state();
2344  _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2345 
2346  commit_reversible_command ();
2347  }
2348 }
2349 
2350 void
2352 {
2353  begin_reversible_command (_("clear locations"));
2354 
2355  XMLNode &before = _session->locations()->get_state();
2356  _session->locations()->clear ();
2357  XMLNode &after = _session->locations()->get_state();
2358  _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2359 
2360  commit_reversible_command ();
2361 }
2362 
2363 void
2365 {
2366  for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2367  Location *l = (*i).first;
2368  if (l->is_hidden() && l->is_mark()) {
2369  l->set_hidden(false, this);
2370  }
2371  }
2372 }
2373 
2374 void
2376 {
2377  for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2378  Location *l = (*i).first;
2379  if (l->is_hidden() && l->is_range_marker()) {
2380  l->set_hidden(false, this);
2381  }
2382  }
2383 }
2384 
2385 /* INSERT/REPLACE */
2386 
2387 void
2389 {
2390  RouteTimeAxisView *tv = 0;
2391  boost::shared_ptr<Playlist> playlist;
2392 
2393  if (clicked_routeview != 0) {
2394  tv = clicked_routeview;
2395  } else if (!selection->tracks.empty()) {
2396  if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2397  return;
2398  }
2399  } else if (entered_track != 0) {
2400  if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2401  return;
2402  }
2403  } else {
2404  return;
2405  }
2406 
2407  if ((playlist = tv->playlist()) == 0) {
2408  return;
2409  }
2410 
2411  boost::shared_ptr<Region> region = _regions->get_single_selection ();
2412  if (region == 0) {
2413  return;
2414  }
2415 
2416  begin_reversible_command (_("insert region"));
2417  playlist->clear_changes ();
2418  playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2419  if (Config->get_edit_mode() == Ripple)
2420  playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2421 
2422  _session->add_command(new StatefulDiffCommand (playlist));
2423  commit_reversible_command ();
2424 }
2425 
2426 /* BUILT-IN EFFECTS */
2427 
2428 void
2430 {
2431 
2432 }
2433 
2434 /* GAIN ENVELOPE EDITING */
2435 
2436 void
2438 {
2439 }
2440 
2441 /* PLAYBACK */
2442 
2443 void
2445 {
2446  if (!_session) {
2447  return;
2448  }
2449 
2450  if (_session->config.get_external_sync()) {
2451  switch (Config->get_sync_source()) {
2452  case Engine:
2453  break;
2454  default:
2455  /* transport controlled by the master */
2456  return;
2457  }
2458  }
2459 
2460  if (_session->is_auditioning()) {
2461  _session->cancel_audition ();
2462  return;
2463  }
2464 
2465  _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2466 }
2467 
2468 void
2470 {
2471  _session->request_locate (_session->current_start_frame(), true);
2472 }
2473 
2474 void
2476 {
2477  _session->request_locate (get_preferred_edit_position(), true);
2478 }
2479 
2480 void
2482 {
2483  framepos_t start_frame;
2484  framepos_t return_frame;
2485 
2486  start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2487 
2488  if (_session->transport_rolling()) {
2489  _session->request_locate (start_frame, false);
2490  return;
2491  }
2492 
2493  /* don't reset the return frame if its already set */
2494 
2495  if ((return_frame = _session->requested_return_frame()) < 0) {
2496  return_frame = _session->audible_frame();
2497  }
2498 
2499  if (start_frame >= 0) {
2500  _session->request_roll_at_and_return (start_frame, return_frame);
2501  }
2502 }
2503 
2504 void
2506 {
2507  framepos_t start, end;
2508  if (!get_selection_extents ( start, end))
2509  return;
2510 
2511  AudioRange ar (start, end, 0);
2512  list<AudioRange> lar;
2513  lar.push_back (ar);
2514 
2515  _session->request_play_range (&lar, true);
2516 }
2517 
2518 framepos_t
2520 {
2521  return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2522 }
2523 
2524 
2525 void
2527 {
2528  if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2529  return;
2530 
2531  location -= get_preroll();
2532 
2533  //don't try to locate before the beginning of time
2534  if ( location < 0 )
2535  location = 0;
2536 
2537  //if follow_playhead is on, keep the playhead on the screen
2538  if ( _follow_playhead )
2539  if ( location < leftmost_frame )
2540  location = leftmost_frame;
2541 
2542  _session->request_locate( location );
2543 }
2544 
2545 void
2547 {
2548  {
2549  framepos_t preroll = get_preroll();
2550 
2551  framepos_t start, end;
2552  if (!get_selection_extents ( start, end))
2553  return;
2554 
2555  if (start > preroll)
2556  start = start - preroll;
2557 
2558  end = end + preroll; //"post-roll"
2559 
2560  AudioRange ar (start, end, 0);
2561  list<AudioRange> lar;
2562  lar.push_back (ar);
2563 
2564  _session->request_play_range (&lar, true);
2565  }
2566 }
2567 
2568 void
2570 {
2571  if (location.start() <= location.end()) {
2572  return;
2573  }
2574 
2575  _session->request_bounded_roll (location.start(), location.end());
2576 }
2577 
2578 void
2580 {
2581  if (location.start() <= location.end()) {
2582  return;
2583  }
2584 
2585  Location* tll;
2586 
2587  if ((tll = transport_loop_location()) != 0) {
2588  tll->set (location.start(), location.end());
2589 
2590  // enable looping, reposition and start rolling
2591  _session->request_locate (tll->start(), true);
2592  _session->request_play_loop (true);
2593  }
2594 }
2595 
2596 void
2598 {
2599  if (selection->regions.empty ()) {
2600  return;
2601  }
2602 
2603  bool const multiple = selection->regions.size() > 1;
2604  switch (op) {
2605  case Raise:
2606  if (multiple) {
2607  begin_reversible_command (_("raise regions"));
2608  } else {
2609  begin_reversible_command (_("raise region"));
2610  }
2611  break;
2612 
2613  case RaiseToTop:
2614  if (multiple) {
2615  begin_reversible_command (_("raise regions to top"));
2616  } else {
2617  begin_reversible_command (_("raise region to top"));
2618  }
2619  break;
2620 
2621  case Lower:
2622  if (multiple) {
2623  begin_reversible_command (_("lower regions"));
2624  } else {
2625  begin_reversible_command (_("lower region"));
2626  }
2627  break;
2628 
2629  case LowerToBottom:
2630  if (multiple) {
2631  begin_reversible_command (_("lower regions to bottom"));
2632  } else {
2633  begin_reversible_command (_("lower region"));
2634  }
2635  break;
2636  }
2637 
2638  set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2639  for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2640  (*i)->clear_owned_changes ();
2641  }
2642 
2643  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2644  boost::shared_ptr<Region> r = (*i)->region ();
2645  switch (op) {
2646  case Raise:
2647  r->raise ();
2648  break;
2649  case RaiseToTop:
2650  r->raise_to_top ();
2651  break;
2652  case Lower:
2653  r->lower ();
2654  break;
2655  case LowerToBottom:
2656  r->lower_to_bottom ();
2657  }
2658  }
2659 
2660  for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2661  vector<Command*> cmds;
2662  (*i)->rdiff (cmds);
2663  _session->add_commands (cmds);
2664  }
2665 
2666  commit_reversible_command ();
2667 }
2668 
2669 void
2671 {
2672  do_layer_operation (Raise);
2673 }
2674 
2675 void
2677 {
2678  do_layer_operation (RaiseToTop);
2679 }
2680 
2681 void
2683 {
2684  do_layer_operation (Lower);
2685 }
2686 
2687 void
2689 {
2690  do_layer_operation (LowerToBottom);
2691 }
2692 
2694 void
2696 {
2697  selection->foreach_regionview (&RegionView::show_region_editor);
2698 }
2699 
2701 void
2703 {
2704  selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2705 }
2706 
2707 void
2709 {
2710  RegionSelection rs = get_regions_from_selection_and_entered ();
2711 
2712  if (rs.empty()) {
2713  return;
2714  }
2715 
2716  ArdourDialog d (*this, _("Rename Region"), true, false);
2717  Entry entry;
2718  Label label (_("New name:"));
2719  HBox hbox;
2720 
2721  hbox.set_spacing (6);
2722  hbox.pack_start (label, false, false);
2723  hbox.pack_start (entry, true, true);
2724 
2725  d.get_vbox()->set_border_width (12);
2726  d.get_vbox()->pack_start (hbox, false, false);
2727 
2728  d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2729  d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2730 
2731  d.set_size_request (300, -1);
2732 
2733  entry.set_text (rs.front()->region()->name());
2734  entry.select_region (0, -1);
2735 
2736  entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2737 
2738  d.show_all ();
2739 
2740  entry.grab_focus();
2741 
2742  int const ret = d.run();
2743 
2744  d.hide ();
2745 
2746  if (ret != RESPONSE_OK) {
2747  return;
2748  }
2749 
2750  std::string str = entry.get_text();
2751  strip_whitespace_edges (str);
2752  if (!str.empty()) {
2753  rs.front()->region()->set_name (str);
2754  _regions->redisplay ();
2755  }
2756 }
2757 
2758 void
2760 {
2761  if (_session->is_auditioning()) {
2762  _session->cancel_audition ();
2763  }
2764 
2765  // note: some potential for creativity here, because region doesn't
2766  // have to belong to the playlist that Route is handling
2767 
2768  // bool was_soloed = route.soloed();
2769 
2770  route.set_solo (true, this);
2771 
2772  _session->request_bounded_roll (region->position(), region->position() + region->length());
2773 
2774  /* XXX how to unset the solo state ? */
2775 }
2776 
2778 void
2780 {
2781  framepos_t start, end;
2782 
2783  if (get_edit_op_range (start, end)) {
2784  _session->request_bounded_roll (start, end);
2785  }
2786 }
2787 
2788 void
2790 {
2792  framepos_t end = 0;
2793 
2794  RegionSelection rs = get_regions_from_selection_and_entered ();
2795 
2796  if (rs.empty()) {
2797  return;
2798  }
2799 
2800  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2801  if ((*i)->region()->position() < start) {
2802  start = (*i)->region()->position();
2803  }
2804  if ((*i)->region()->last_frame() + 1 > end) {
2805  end = (*i)->region()->last_frame() + 1;
2806  }
2807  }
2808 
2809  _session->request_bounded_roll (start, end);
2810 }
2811 
2812 void
2814 {
2815  _session->audition_region (region);
2816 }
2817 
2818 void
2820 {
2821  if (clicked_axisview == 0) {
2822  return;
2823  }
2824 
2825  if (selection->time.empty()) {
2826  return;
2827  }
2828 
2829  framepos_t start = selection->time[clicked_selection].start;
2830  framepos_t end = selection->time[clicked_selection].end;
2831 
2832  TrackViewList tracks = get_tracks_for_range_action ();
2833 
2834  framepos_t selection_cnt = end - start + 1;
2835 
2836  for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2837  boost::shared_ptr<Region> current;
2839  framepos_t internal_start;
2840  string new_name;
2841 
2842  if ((pl = (*i)->playlist()) == 0) {
2843  continue;
2844  }
2845 
2846  if ((current = pl->top_region_at (start)) == 0) {
2847  continue;
2848  }
2849 
2850  internal_start = start - current->position();
2851  RegionFactory::region_name (new_name, current->name(), true);
2852 
2853  PropertyList plist;
2854 
2855  plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2856  plist.add (ARDOUR::Properties::length, selection_cnt);
2857  plist.add (ARDOUR::Properties::name, new_name);
2858  plist.add (ARDOUR::Properties::layer, 0);
2859 
2860  boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2861  }
2862 }
2863 
2864 void
2866 {
2867  if (selection->time.empty() || selection->tracks.empty()) {
2868  return;
2869  }
2870 
2871  framepos_t start, end;
2872  if (clicked_selection) {
2873  start = selection->time[clicked_selection].start;
2874  end = selection->time[clicked_selection].end;
2875  } else {
2876  start = selection->time.start();
2877  end = selection->time.end_frame();
2878  }
2879 
2880  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2881  sort_track_selection (ts);
2882 
2883  for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2884  boost::shared_ptr<Region> current;
2885  boost::shared_ptr<Playlist> playlist;
2886  framepos_t internal_start;
2887  string new_name;
2888 
2889  if ((playlist = (*i)->playlist()) == 0) {
2890  continue;
2891  }
2892 
2893  if ((current = playlist->top_region_at(start)) == 0) {
2894  continue;
2895  }
2896 
2897  internal_start = start - current->position();
2898  RegionFactory::region_name (new_name, current->name(), true);
2899 
2900  PropertyList plist;
2901 
2902  plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2903  plist.add (ARDOUR::Properties::length, end - start + 1);
2904  plist.add (ARDOUR::Properties::name, new_name);
2905 
2906  new_regions.push_back (RegionFactory::create (current, plist));
2907  }
2908 }
2909 
2910 void
2912 {
2913  RegionSelection rs = get_regions_from_selection_and_entered ();
2914 
2915  if (rs.empty()) {
2916  return;
2917  }
2918 
2919  vector< boost::shared_ptr<Region> > v;
2920 
2921  for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2922  (*x)->region()->separate_by_channel (*_session, v);
2923  }
2924 }
2925 
2926 void
2928 {
2929  region_from_selection ();
2930  cancel_selection ();
2931 }
2932 
2933 static void
2935 {
2936  switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2937  // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2938  case Evoral::OverlapNone:
2939  break;
2940  default:
2941  rs->push_back (rv);
2942  }
2943 }
2944 
2953 {
2954  TrackViewList t;
2955 
2956  if (selection->tracks.empty()) {
2957 
2958  /* use tracks with selected regions */
2959 
2960  RegionSelection rs = selection->regions;
2961 
2962  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2963  TimeAxisView* tv = &(*i)->get_time_axis_view();
2964 
2965  if (!t.contains (tv)) {
2966  t.push_back (tv);
2967  }
2968  }
2969 
2970  if (t.empty()) {
2971  /* no regions and no tracks: use all tracks */
2972  t = track_views;
2973  }
2974 
2975  } else {
2976 
2977  t = selection->tracks;
2978  }
2979 
2980  return t.filter_to_unique_playlists();
2981 }
2982 
2983 void
2985 {
2986  bool in_command = false;
2987  boost::shared_ptr<Playlist> playlist;
2988  RegionSelection new_selection;
2989 
2990  TrackViewList tmptracks = get_tracks_for_range_action ();
2991  sort_track_selection (tmptracks);
2992 
2993  for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2994 
2995  RouteTimeAxisView* rtv;
2996 
2997  if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2998 
2999  if (rtv->is_track()) {
3000 
3001  /* no edits to destructive tracks */
3002 
3003  if (rtv->track()->destructive()) {
3004  continue;
3005  }
3006 
3007  if ((playlist = rtv->playlist()) != 0) {
3008 
3009  playlist->clear_changes ();
3010 
3011  /* XXX need to consider musical time selections here at some point */
3012 
3013  double speed = rtv->track()->speed();
3014 
3015 
3016  for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3017 
3018  sigc::connection c = rtv->view()->RegionViewAdded.connect (
3019  sigc::mem_fun(*this, &Editor::collect_new_region_view));
3020 
3021  latest_regionviews.clear ();
3022 
3023  playlist->partition ((framepos_t)((*t).start * speed),
3024  (framepos_t)((*t).end * speed), false);
3025 
3026  c.disconnect ();
3027 
3028  if (!latest_regionviews.empty()) {
3029 
3030  rtv->view()->foreach_regionview (sigc::bind (
3031  sigc::ptr_fun (add_if_covered),
3032  &(*t), &new_selection));
3033 
3034  if (!in_command) {
3035  begin_reversible_command (_("separate"));
3036  in_command = true;
3037  }
3038 
3039  /* pick up changes to existing regions */
3040 
3041  vector<Command*> cmds;
3042  playlist->rdiff (cmds);
3043  _session->add_commands (cmds);
3044 
3045  /* pick up changes to the playlist itself (adds/removes)
3046  */
3047 
3048  _session->add_command(new StatefulDiffCommand (playlist));
3049  }
3050  }
3051  }
3052  }
3053  }
3054  }
3055 
3056  if (in_command) {
3057 // selection->set (new_selection);
3058 
3059  commit_reversible_command ();
3060  }
3061 }
3062 
3066 };
3067 
3072 void
3074 {
3075  /* preferentially use *all* ranges in the time selection if we're in range mode
3076  to allow discontiguous operation, since get_edit_op_range() currently
3077  returns a single range.
3078  */
3079 
3080  if (!selection->time.empty()) {
3081 
3082  separate_regions_between (selection->time);
3083 
3084  } else {
3085 
3086  framepos_t start;
3087  framepos_t end;
3088 
3089  if (get_edit_op_range (start, end)) {
3090 
3091  AudioRange ar (start, end, 1);
3092  TimeSelection ts;
3093  ts.push_back (ar);
3094 
3095  separate_regions_between (ts);
3096  }
3097  }
3098 }
3099 
3100 void
3102 {
3103  Location* loc = _session->locations()->auto_punch_location();
3104  if (loc) {
3105  separate_regions_using_location (*loc);
3106  }
3107 }
3108 
3109 void
3111 {
3112  Location* loc = _session->locations()->auto_loop_location();
3113  if (loc) {
3114  separate_regions_using_location (*loc);
3115  }
3116 }
3117 
3118 void
3120 {
3121  if (loc.is_mark()) {
3122  return;
3123  }
3124 
3125  AudioRange ar (loc.start(), loc.end(), 1);
3126  TimeSelection ts;
3127 
3128  ts.push_back (ar);
3129 
3130  separate_regions_between (ts);
3131 }
3132 
3134 void
3136 {
3137  vector<PlaylistState> playlists;
3138 
3139  RegionSelection rs;
3140 
3141  rs = get_regions_from_selection_and_entered();
3142 
3143  if (!_session || rs.empty()) {
3144  return;
3145  }
3146 
3147  begin_reversible_command (_("separate region under"));
3148 
3149  list<boost::shared_ptr<Region> > regions_to_remove;
3150 
3151  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3152  // we can't just remove the region(s) in this loop because
3153  // this removes them from the RegionSelection, and they thus
3154  // disappear from underneath the iterator, and the ++i above
3155  // SEGVs in a puzzling fashion.
3156 
3157  // so, first iterate over the regions to be removed from rs and
3158  // add them to the regions_to_remove list, and then
3159  // iterate over the list to actually remove them.
3160 
3161  regions_to_remove.push_back ((*i)->region());
3162  }
3163 
3164  for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3165 
3166  boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3167 
3168  if (!playlist) {
3169  // is this check necessary?
3170  continue;
3171  }
3172 
3173  vector<PlaylistState>::iterator i;
3174 
3175  //only take state if this is a new playlist.
3176  for (i = playlists.begin(); i != playlists.end(); ++i) {
3177  if ((*i).playlist == playlist) {
3178  break;
3179  }
3180  }
3181 
3182  if (i == playlists.end()) {
3183 
3184  PlaylistState before;
3185  before.playlist = playlist;
3186  before.before = &playlist->get_state();
3187 
3188  playlist->freeze ();
3189  playlists.push_back(before);
3190  }
3191 
3192  //Partition on the region bounds
3193  playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3194 
3195  //Re-add region that was just removed due to the partition operation
3196  playlist->add_region( (*rl), (*rl)->first_frame() );
3197  }
3198 
3199  vector<PlaylistState>::iterator pl;
3200 
3201  for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3202  (*pl).playlist->thaw ();
3203  _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3204  }
3205 
3206  commit_reversible_command ();
3207 }
3208 
3209 void
3211 {
3212  if (!selection->time.empty()) {
3213 
3214  crop_region_to (selection->time.start(), selection->time.end_frame());
3215 
3216  } else {
3217 
3218  framepos_t start;
3219  framepos_t end;
3220 
3221  if (get_edit_op_range (start, end)) {
3222  crop_region_to (start, end);
3223  }
3224  }
3225 
3226 }
3227 
3228 void
3230 {
3231  vector<boost::shared_ptr<Playlist> > playlists;
3232  boost::shared_ptr<Playlist> playlist;
3233  TrackViewList ts;
3234 
3235  if (selection->tracks.empty()) {
3236  ts = track_views.filter_to_unique_playlists();
3237  } else {
3238  ts = selection->tracks.filter_to_unique_playlists ();
3239  }
3240 
3241  sort_track_selection (ts);
3242 
3243  for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3244 
3245  RouteTimeAxisView* rtv;
3246 
3247  if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3248 
3249  boost::shared_ptr<Track> t = rtv->track();
3250 
3251  if (t != 0 && ! t->destructive()) {
3252 
3253  if ((playlist = rtv->playlist()) != 0) {
3254  playlists.push_back (playlist);
3255  }
3256  }
3257  }
3258  }
3259 
3260  if (playlists.empty()) {
3261  return;
3262  }
3263 
3264  framepos_t the_start;
3265  framepos_t the_end;
3266  framepos_t cnt;
3267 
3268  begin_reversible_command (_("trim to selection"));
3269 
3270  for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3271 
3273 
3274  the_start = start;
3275 
3276  if ((region = (*i)->top_region_at(the_start)) == 0) {
3277  continue;
3278  }
3279 
3280  /* now adjust lengths to that we do the right thing
3281  if the selection extends beyond the region
3282  */
3283 
3284  the_start = max (the_start, (framepos_t) region->position());
3285  if (max_framepos - the_start < region->length()) {
3286  the_end = the_start + region->length() - 1;
3287  } else {
3288  the_end = max_framepos;
3289  }
3290  the_end = min (end, the_end);
3291  cnt = the_end - the_start + 1;
3292 
3293  region->clear_changes ();
3294  region->trim_to (the_start, cnt);
3295  _session->add_command (new StatefulDiffCommand (region));
3296  }
3297 
3298  commit_reversible_command ();
3299 }
3300 
3301 void
3303 {
3304  RegionSelection rs = get_regions_from_selection_and_entered ();
3305 
3306  if (!_session || rs.empty()) {
3307  return;
3308  }
3309 
3310  framepos_t const end = _session->current_end_frame ();
3311 
3312  begin_reversible_command (Operations::region_fill);
3313 
3314  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3315 
3316  boost::shared_ptr<Region> region ((*i)->region());
3317 
3318  boost::shared_ptr<Playlist> pl = region->playlist();
3319 
3320  if (end <= region->last_frame()) {
3321  return;
3322  }
3323 
3324  double times = (double) (end - region->last_frame()) / (double) region->length();
3325 
3326  if (times == 0) {
3327  return;
3328  }
3329 
3330  pl->clear_changes ();
3331  pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3332  _session->add_command (new StatefulDiffCommand (pl));
3333  }
3334 
3335  commit_reversible_command ();
3336 }
3337 
3338 void
3340 {
3341  if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3342  return;
3343  }
3344 
3345  if (selection->time.empty()) {
3346  return;
3347  }
3348 
3349  boost::shared_ptr<Region> region = _regions->get_single_selection ();
3350  if (region == 0) {
3351  return;
3352  }
3353 
3354  framepos_t start = selection->time[clicked_selection].start;
3355  framepos_t end = selection->time[clicked_selection].end;
3356 
3357  boost::shared_ptr<Playlist> playlist;
3358 
3359  if (selection->tracks.empty()) {
3360  return;
3361  }
3362 
3363  framepos_t selection_length = end - start;
3364  float times = (float)selection_length / region->length();
3365 
3366  begin_reversible_command (Operations::fill_selection);
3367 
3368  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3369 
3370  for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3371 
3372  if ((playlist = (*i)->playlist()) == 0) {
3373  continue;
3374  }
3375 
3376  playlist->clear_changes ();
3377  playlist->add_region (RegionFactory::create (region, true), start, times);
3378  _session->add_command (new StatefulDiffCommand (playlist));
3379  }
3380 
3381  commit_reversible_command ();
3382 }
3383 
3384 void
3386 {
3387  set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3388 }
3389 
3390 void
3392 {
3393  bool in_command = false;
3394 
3395  for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3396 
3397  if (!(*r)->region()->covers (where)) {
3398  continue;
3399  }
3400 
3401  boost::shared_ptr<Region> region ((*r)->region());
3402 
3403  if (!in_command) {
3404  begin_reversible_command (_("set sync point"));
3405  in_command = true;
3406  }
3407 
3408  region->clear_changes ();
3409  region->set_sync_position (where);
3410  _session->add_command(new StatefulDiffCommand (region));
3411  }
3412 
3413  if (in_command) {
3414  commit_reversible_command ();
3415  }
3416 }
3417 
3419 void
3421 {
3422  RegionSelection rs = get_regions_from_selection_and_entered ();
3423 
3424  if (rs.empty()) {
3425  return;
3426  }
3427 
3428  begin_reversible_command (_("remove region sync"));
3429 
3430  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3431 
3432  (*i)->region()->clear_changes ();
3433  (*i)->region()->clear_sync_position ();
3434  _session->add_command(new StatefulDiffCommand ((*i)->region()));
3435  }
3436 
3437  commit_reversible_command ();
3438 }
3439 
3440 void
3442 {
3443  RegionSelection rs = get_regions_from_selection_and_entered ();
3444 
3445  if (rs.empty()) {
3446  return;
3447  }
3448 
3449  if (rs.size() > 1) {
3450  begin_reversible_command (_("move regions to original position"));
3451  } else {
3452  begin_reversible_command (_("move region to original position"));
3453  }
3454 
3455  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3456  (*i)->region()->clear_changes ();
3457  (*i)->region()->move_to_natural_position ();
3458  _session->add_command (new StatefulDiffCommand ((*i)->region()));
3459  }
3460 
3461  commit_reversible_command ();
3462 }
3463 
3464 void
3466 {
3467  RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3468 
3469  if (rs.empty()) {
3470  return;
3471  }
3472 
3473  begin_reversible_command (_("align selection"));
3474 
3475  framepos_t const position = get_preferred_edit_position ();
3476 
3477  for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3478  align_region_internal ((*i)->region(), what, position);
3479  }
3480 
3481  commit_reversible_command ();
3482 }
3483 
3485  bool operator() (const RegionView* a, const RegionView* b) {
3486  return a->region()->position() < b->region()->position();
3487  }
3488 };
3489 
3490 void
3492 {
3493  RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3494 
3495  if (rs.empty()) {
3496  return;
3497  }
3498 
3499  framepos_t const position = get_preferred_edit_position ();
3500 
3501  framepos_t distance = 0;
3502  framepos_t pos = 0;
3503  int dir = 1;
3504 
3505  list<RegionView*> sorted;
3506  rs.by_position (sorted);
3507 
3508  boost::shared_ptr<Region> r ((*sorted.begin())->region());
3509 
3510  switch (point) {
3511  case Start:
3512  pos = position;
3513  if (position > r->position()) {
3514  distance = position - r->position();
3515  } else {
3516  distance = r->position() - position;
3517  dir = -1;
3518  }
3519  break;
3520 
3521  case End:
3522  if (position > r->last_frame()) {
3523  distance = position - r->last_frame();
3524  pos = r->position() + distance;
3525  } else {
3526  distance = r->last_frame() - position;
3527  pos = r->position() - distance;
3528  dir = -1;
3529  }
3530  break;
3531 
3532  case SyncPoint:
3533  pos = r->adjust_to_sync (position);
3534  if (pos > r->position()) {
3535  distance = pos - r->position();
3536  } else {
3537  distance = r->position() - pos;
3538  dir = -1;
3539  }
3540  break;
3541  }
3542 
3543  if (pos == r->position()) {
3544  return;
3545  }
3546 
3547  begin_reversible_command (_("align selection (relative)"));
3548 
3549  /* move first one specially */
3550 
3551  r->clear_changes ();
3552  r->set_position (pos);
3553  _session->add_command(new StatefulDiffCommand (r));
3554 
3555  /* move rest by the same amount */
3556 
3557  sorted.pop_front();
3558 
3559  for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3560 
3561  boost::shared_ptr<Region> region ((*i)->region());
3562 
3563  region->clear_changes ();
3564 
3565  if (dir > 0) {
3566  region->set_position (region->position() + distance);
3567  } else {
3568  region->set_position (region->position() - distance);
3569  }
3570 
3571  _session->add_command(new StatefulDiffCommand (region));
3572 
3573  }
3574 
3575  commit_reversible_command ();
3576 }
3577 
3578 void
3580 {
3581  begin_reversible_command (_("align region"));
3582  align_region_internal (region, point, position);
3583  commit_reversible_command ();
3584 }
3585 
3586 void
3588 {
3589  region->clear_changes ();
3590 
3591  switch (point) {
3592  case SyncPoint:
3593  region->set_position (region->adjust_to_sync (position));
3594  break;
3595 
3596  case End:
3597  if (position > region->length()) {
3598  region->set_position (position - region->length());
3599  }
3600  break;
3601 
3602  case Start:
3603  region->set_position (position);
3604  break;
3605  }
3606 
3607  _session->add_command(new StatefulDiffCommand (region));
3608 }
3609 
3610 void
3612 {
3613  trim_region (true);
3614 }
3615 
3616 void
3618 {
3619  trim_region (false);
3620 }
3621 
3622 void
3624 {
3625  framepos_t where = get_preferred_edit_position();
3626  RegionSelection rs = get_regions_from_selection_and_edit_point ();
3627 
3628  if (rs.empty()) {
3629  return;
3630  }
3631 
3632  begin_reversible_command (front ? _("trim front") : _("trim back"));
3633 
3634  for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3635  if (!(*i)->region()->locked()) {
3636 
3637  (*i)->region()->clear_changes ();
3638 
3639  if (front) {
3640  (*i)->region()->trim_front (where);
3641  maybe_locate_with_edit_preroll ( where );
3642  } else {
3643  (*i)->region()->trim_end (where);
3644  maybe_locate_with_edit_preroll ( where );
3645  }
3646 
3647  _session->add_command (new StatefulDiffCommand ((*i)->region()));
3648  }
3649  }
3650 
3651  commit_reversible_command ();
3652 }
3653 
3655 void
3657 {
3658  Location* loc = _session->locations()->auto_loop_location();
3659  if (!loc) {
3660  return;
3661  }
3662  trim_region_to_location (*loc, _("trim to loop"));
3663 }
3664 
3665 void
3667 {
3668  Location* loc = _session->locations()->auto_punch_location();
3669  if (!loc) {
3670  return;
3671  }
3672  trim_region_to_location (*loc, _("trim to punch"));
3673 }
3674 
3675 void
3676 Editor::trim_region_to_location (const Location& loc, const char* str)
3677 {
3678  RegionSelection rs = get_regions_from_selection_and_entered ();
3679 
3680  begin_reversible_command (str);
3681 
3682  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3683  RegionView* rv = (*x);
3684 
3685  /* require region to span proposed trim */
3686  switch (rv->region()->coverage (loc.start(), loc.end())) {
3688  break;
3689  default:
3690  continue;
3691  }
3692 
3693  RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3694  if (!tav) {
3695  return;
3696  }
3697 
3698  float speed = 1.0;
3699  framepos_t start;
3700  framepos_t end;
3701 
3702  if (tav->track() != 0) {
3703  speed = tav->track()->speed();
3704  }
3705 
3706  start = session_frame_to_track_frame (loc.start(), speed);
3707  end = session_frame_to_track_frame (loc.end(), speed);
3708 
3709  rv->region()->clear_changes ();
3710  rv->region()->trim_to (start, (end - start));
3711  _session->add_command(new StatefulDiffCommand (rv->region()));
3712  }
3713 
3714  commit_reversible_command ();
3715 }
3716 
3717 void
3719 {
3720  return trim_to_region(false);
3721 }
3722 
3723 void
3725 {
3726  return trim_to_region(true);
3727 }
3728 
3729 void
3731 {
3732  RegionSelection rs = get_regions_from_selection_and_entered ();
3733 
3734  begin_reversible_command (_("trim to region"));
3735 
3736  boost::shared_ptr<Region> next_region;
3737 
3738  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3739 
3740  AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3741 
3742  if (!arv) {
3743  continue;
3744  }
3745 
3746  AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3747 
3748  if (!atav) {
3749  return;
3750  }
3751 
3752  float speed = 1.0;
3753 
3754  if (atav->track() != 0) {
3755  speed = atav->track()->speed();
3756  }
3757 
3758 
3759  boost::shared_ptr<Region> region = arv->region();
3760  boost::shared_ptr<Playlist> playlist (region->playlist());
3761 
3762  region->clear_changes ();
3763 
3764  if (forward) {
3765 
3766  next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3767 
3768  if (!next_region) {
3769  continue;
3770  }
3771 
3772  region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3774  }
3775  else {
3776 
3777  next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3778 
3779  if(!next_region){
3780  continue;
3781  }
3782 
3783  region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3784 
3786  }
3787 
3788  _session->add_command(new StatefulDiffCommand (region));
3789  }
3790 
3791  commit_reversible_command ();
3792 }
3793 
3794 void
3796 {
3797  if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3798  return;
3799  }
3800 
3801  clicked_routeview->track()->unfreeze ();
3802 }
3803 
3804 void*
3806 {
3807  return static_cast<Editor*>(arg)->freeze_thread ();
3808 }
3809 
3810 void*
3812 {
3813  /* create event pool because we may need to talk to the session */
3814  SessionEvent::create_per_thread_pool ("freeze events", 64);
3815  /* create per-thread buffers for process() tree to use */
3816  clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3817  current_interthread_info->done = true;
3818  return 0;
3819 }
3820 
3821 void
3823 {
3824  if (!_session) {
3825  return;
3826  }
3827 
3828  /* stop transport before we start. this is important */
3829 
3830  _session->request_transport_speed (0.0);
3831 
3832  /* wait for just a little while, because the above call is asynchronous */
3833 
3834  Glib::usleep (250000);
3835 
3836  if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3837  return;
3838  }
3839 
3840  if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3841  MessageDialog d (
3842  _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3843  "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3844  );
3845  d.set_title (_("Cannot freeze"));
3846  d.run ();
3847  return;
3848  }
3849 
3850  if (clicked_routeview->track()->has_external_redirects()) {
3851  MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3852  "Freezing will only process the signal as far as the first send/insert/return."),
3853  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3854 
3855  d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3856  d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3857  d.set_title (_("Freeze Limits"));
3858 
3859  int response = d.run ();
3860 
3861  switch (response) {
3862  case Gtk::RESPONSE_CANCEL:
3863  return;
3864  default:
3865  break;
3866  }
3867  }
3868 
3869  InterThreadInfo itt;
3870  current_interthread_info = &itt;
3871 
3872  InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3873 
3874  pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3875 
3876  CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3877 
3878  while (!itt.done && !itt.cancel) {
3879  gtk_main_iteration ();
3880  }
3881 
3882  current_interthread_info = 0;
3883 }
3884 
3885 void
3886 Editor::bounce_range_selection (bool replace, bool enable_processing)
3887 {
3888  if (selection->time.empty()) {
3889  return;
3890  }
3891 
3892  TrackSelection views = selection->tracks;
3893 
3894  for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3895 
3896  if (enable_processing) {
3897 
3898  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3899 
3900  if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3901  MessageDialog d (
3902  _("You can't perform this operation because the processing of the signal "
3903  "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3904  "You can do this without processing, which is a different operation.")
3905  );
3906  d.set_title (_("Cannot bounce"));
3907  d.run ();
3908  return;
3909  }
3910  }
3911  }
3912 
3913  framepos_t start = selection->time[clicked_selection].start;
3914  framepos_t end = selection->time[clicked_selection].end;
3915  framepos_t cnt = end - start + 1;
3916 
3917  begin_reversible_command (_("bounce range"));
3918 
3919  for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3920 
3921  RouteTimeAxisView* rtv;
3922 
3923  if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3924  continue;
3925  }
3926 
3927  boost::shared_ptr<Playlist> playlist;
3928 
3929  if ((playlist = rtv->playlist()) == 0) {
3930  return;
3931  }
3932 
3933  InterThreadInfo itt;
3934 
3935  playlist->clear_changes ();
3936  playlist->clear_owned_changes ();
3937 
3939 
3940  if (enable_processing) {
3941  r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3942  } else {
3943  r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3944  }
3945 
3946  if (!r) {
3947  continue;
3948  }
3949 
3950  if (replace) {
3951  list<AudioRange> ranges;
3952  ranges.push_back (AudioRange (start, start+cnt, 0));
3953  playlist->cut (ranges); // discard result
3954  playlist->add_region (r, start);
3955  }
3956 
3957  vector<Command*> cmds;
3958  playlist->rdiff (cmds);
3959  _session->add_commands (cmds);
3960 
3961  _session->add_command (new StatefulDiffCommand (playlist));
3962  }
3963 
3964  commit_reversible_command ();
3965 }
3966 
3968 void
3970 {
3971  //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3972  //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3973  bool deleted = false;
3974  if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3975  deleted = current_mixer_strip->delete_processors ();
3976 
3977  if (!deleted)
3978  cut_copy (Delete);
3979 }
3980 
3982 void
3984 {
3985  cut_copy (Cut);
3986 }
3987 
3989 void
3991 {
3992  cut_copy (Copy);
3993 }
3994 
3995 
3997 bool
3999 {
4000  if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4001  return true;
4002 
4003  return false;
4004 }
4005 
4006 
4010 void
4012 {
4013  /* only cancel selection if cut/copy is successful.*/
4014 
4015  string opname;
4016 
4017  switch (op) {
4018  case Delete:
4019  opname = _("delete");
4020  break;
4021  case Cut:
4022  opname = _("cut");
4023  break;
4024  case Copy:
4025  opname = _("copy");
4026  break;
4027  case Clear:
4028  opname = _("clear");
4029  break;
4030  }
4031 
4032  /* if we're deleting something, and the mouse is still pressed,
4033  the thing we started a drag for will be gone when we release
4034  the mouse button(s). avoid this. see part 2 at the end of
4035  this function.
4036  */
4037 
4038  if (op == Delete || op == Cut || op == Clear) {
4039  if (_drags->active ()) {
4040  _drags->abort ();
4041  }
4042  }
4043 
4044  if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4045  cut_buffer->clear ();
4046 
4047  if (entered_marker) {
4048 
4049  /* cut/delete op while pointing at a marker */
4050 
4051  bool ignored;
4052  Location* loc = find_location_from_marker (entered_marker, ignored);
4053 
4054  if (_session && loc) {
4055  Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4056  }
4057 
4058  _drags->abort ();
4059  return;
4060  }
4061 
4062  switch (mouse_mode) {
4063  case MouseDraw:
4064  case MouseContent:
4065  begin_reversible_command (opname + ' ' + X_("MIDI"));
4066  cut_copy_midi (op);
4067  commit_reversible_command ();
4068  return;
4069  default:
4070  break;
4071  }
4072 
4073  bool did_edit = false;
4074 
4075  if (!selection->regions.empty() || !selection->points.empty()) {
4076  begin_reversible_command (opname + ' ' + _("objects"));
4077  did_edit = true;
4078 
4079  if (!selection->regions.empty()) {
4080  cut_copy_regions (op, selection->regions);
4081 
4082  if (op == Cut || op == Delete) {
4083  selection->clear_regions ();
4084  }
4085  }
4086 
4087  if (!selection->points.empty()) {
4088  cut_copy_points (op);
4089 
4090  if (op == Cut || op == Delete) {
4091  selection->clear_points ();
4092  }
4093  }
4094  } else if (selection->time.empty()) {
4095  framepos_t start, end;
4096  /* no time selection, see if we can get an edit range
4097  and use that.
4098  */
4099  if (get_edit_op_range (start, end)) {
4100  selection->set (start, end);
4101  }
4102  } else if (!selection->time.empty()) {
4103  begin_reversible_command (opname + ' ' + _("range"));
4104 
4105  did_edit = true;
4106  cut_copy_ranges (op);
4107 
4108  if (op == Cut || op == Delete) {
4109  selection->clear_time ();
4110  }
4111  }
4112 
4113  if (did_edit) {
4114  /* reset repeated paste state */
4115  paste_count = 0;
4116  last_paste_pos = 0;
4117  commit_reversible_command ();
4118  }
4119 
4120  if (op == Delete || op == Cut || op == Clear) {
4121  _drags->abort ();
4122  }
4123 }
4124 
4126  AutomationRecord () : state (0) , line(NULL) {}
4127  AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4128 
4132 };
4133 
4137 void
4139 {
4140  if (selection->points.empty ()) {
4141  return;
4142  }
4143 
4144  /* XXX: not ideal, as there may be more than one track involved in the point selection */
4145  _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4146 
4147  /* Keep a record of the AutomationLists that we end up using in this operation */
4148  typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4149  Lists lists;
4150 
4151  /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4152  for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4153  const AutomationLine& line = (*i)->line();
4154  const boost::shared_ptr<AutomationList> al = line.the_list();
4155  if (lists.find (al) == lists.end ()) {
4156  /* We haven't seen this list yet, so make a record for it. This includes
4157  taking a copy of its current state, in case this is needed for undo later.
4158  */
4159  lists[al] = AutomationRecord (&al->get_state (), &line);
4160  }
4161  }
4162 
4163  if (op == Cut || op == Copy) {
4164  /* This operation will involve putting things in the cut buffer, so create an empty
4165  ControlList for each of our source lists to put the cut buffer data in.
4166  */
4167  for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4168  i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4169  }
4170 
4171  /* Add all selected points to the relevant copy ControlLists */
4172  framepos_t start = std::numeric_limits<framepos_t>::max();
4173  for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4174  boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4175  AutomationList::const_iterator j = (*i)->model();
4176 
4177  lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4178  if (midi) {
4179  /* Update earliest MIDI start time in beats */
4180  earliest = std::min(earliest, Evoral::Beats((*j)->when));
4181  } else {
4182  /* Update earliest session start time in frames */
4183  start = std::min(start, (*i)->line().session_position(j));
4184  }
4185  }
4186 
4187  /* Snap start time backwards, so copy/paste is snap aligned. */
4188  if (midi) {
4189  if (earliest == Evoral::Beats::max()) {
4190  earliest = Evoral::Beats(); // Weird... don't offset
4191  }
4192  earliest.round_down_to_beat();
4193  } else {
4194  if (start == std::numeric_limits<double>::max()) {
4195  start = 0; // Weird... don't offset
4196  }
4197  snap_to(start, RoundDownMaybe);
4198  }
4199 
4200  const double line_offset = midi ? earliest.to_double() : start;
4201  for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4202  /* Correct this copy list so that it is relative to the earliest
4203  start time, so relative ordering between points is preserved
4204  when copying from several lists and the paste starts at the
4205  earliest copied piece of data. */
4206  for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4207  (*j)->when -= line_offset;
4208  }
4209 
4210  /* And add it to the cut buffer */
4211  cut_buffer->add (i->second.copy);
4212  }
4213  }
4214 
4215  if (op == Delete || op == Cut) {
4216  /* This operation needs to remove things from the main AutomationList, so do that now */
4217 
4218  for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4219  i->first->freeze ();
4220  }
4221 
4222  /* Remove each selected point from its AutomationList */
4223  for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4224  boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4225  al->erase ((*i)->model ());
4226  }
4227 
4228  /* Thaw the lists and add undo records for them */
4229  for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4230  boost::shared_ptr<AutomationList> al = i->first;
4231  al->thaw ();
4232  _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4233  }
4234  }
4235 }
4236 
4240 void
4242 {
4243  Evoral::Beats earliest = Evoral::Beats::max();
4244  for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4245  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4246  if (mrv) {
4247  if (!mrv->selection().empty()) {
4248  earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4249  }
4250  mrv->cut_copy_clear (op);
4251 
4252  /* XXX: not ideal, as there may be more than one track involved in the selection */
4253  _last_cut_copy_source_track = &mrv->get_time_axis_view();
4254  }
4255  }
4256 
4257  if (!selection->points.empty()) {
4258  cut_copy_points (op, earliest, true);
4259  if (op == Cut || op == Delete) {
4260  selection->clear_points ();
4261  }
4262  }
4263 }
4264 
4265 struct lt_playlist {
4266  bool operator () (const PlaylistState& a, const PlaylistState& b) {
4267  return a.playlist < b.playlist;
4268  }
4269 };
4270 
4274 
4275  PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4276 };
4277 
4279 void
4281 {
4282  if (clicked_routeview == 0 || clicked_regionview == 0) {
4283  return;
4284  }
4285 
4286  begin_reversible_command (_("remove region"));
4287 
4288  boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4289 
4290  playlist->clear_changes ();
4291  playlist->clear_owned_changes ();
4292  playlist->remove_region (clicked_regionview->region());
4293  if (Config->get_edit_mode() == Ripple)
4294  playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4295 
4296  /* We might have removed regions, which alters other regions' layering_index,
4297  so we need to do a recursive diff here.
4298  */
4299  vector<Command*> cmds;
4300  playlist->rdiff (cmds);
4301  _session->add_commands (cmds);
4302 
4303  _session->add_command(new StatefulDiffCommand (playlist));
4304  commit_reversible_command ();
4305 }
4306 
4307 
4309 void
4311 {
4312  RegionSelection rs = get_regions_from_selection_and_entered ();
4313 
4314  if (!_session || rs.empty()) {
4315  return;
4316  }
4317 
4318  begin_reversible_command (_("remove region"));
4319 
4320  list<boost::shared_ptr<Region> > regions_to_remove;
4321 
4322  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4323  // we can't just remove the region(s) in this loop because
4324  // this removes them from the RegionSelection, and they thus
4325  // disappear from underneath the iterator, and the ++i above
4326  // SEGVs in a puzzling fashion.
4327 
4328  // so, first iterate over the regions to be removed from rs and
4329  // add them to the regions_to_remove list, and then
4330  // iterate over the list to actually remove them.
4331 
4332  regions_to_remove.push_back ((*i)->region());
4333  }
4334 
4335  vector<boost::shared_ptr<Playlist> > playlists;
4336 
4337  for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4338 
4339  boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4340 
4341  if (!playlist) {
4342  // is this check necessary?
4343  continue;
4344  }
4345 
4346  /* get_regions_from_selection_and_entered() guarantees that
4347  the playlists involved are unique, so there is no need
4348  to check here.
4349  */
4350 
4351  playlists.push_back (playlist);
4352 
4353  playlist->clear_changes ();
4354  playlist->clear_owned_changes ();
4355  playlist->freeze ();
4356  playlist->remove_region (*rl);
4357  if (Config->get_edit_mode() == Ripple)
4358  playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4359 
4360  }
4361 
4362  vector<boost::shared_ptr<Playlist> >::iterator pl;
4363 
4364  for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4365  (*pl)->thaw ();
4366 
4367  /* We might have removed regions, which alters other regions' layering_index,
4368  so we need to do a recursive diff here.
4369  */
4370  vector<Command*> cmds;
4371  (*pl)->rdiff (cmds);
4372  _session->add_commands (cmds);
4373 
4374  _session->add_command(new StatefulDiffCommand (*pl));
4375  }
4376 
4377  commit_reversible_command ();
4378 }
4379 
4383 void
4385 {
4386  /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4387  a map when we want ordered access to both elements. i think.
4388  */
4389 
4390  vector<PlaylistMapping> pmap;
4391 
4392  framepos_t first_position = max_framepos;
4393 
4394  typedef set<boost::shared_ptr<Playlist> > FreezeList;
4395  FreezeList freezelist;
4396 
4397  /* get ordering correct before we cut/copy */
4398 
4400 
4401  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4402 
4403  first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4404 
4405  if (op == Cut || op == Clear || op == Delete) {
4406  boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4407 
4408  if (pl) {
4409  FreezeList::iterator fl;
4410 
4411  // only take state if this is a new playlist.
4412  for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4413  if ((*fl) == pl) {
4414  break;
4415  }
4416  }
4417 
4418  if (fl == freezelist.end()) {
4419  pl->clear_changes();
4420  pl->clear_owned_changes ();
4421  pl->freeze ();
4422  freezelist.insert (pl);
4423  }
4424  }
4425  }
4426 
4427  TimeAxisView* tv = &(*x)->get_time_axis_view();
4428  vector<PlaylistMapping>::iterator z;
4429 
4430  for (z = pmap.begin(); z != pmap.end(); ++z) {
4431  if ((*z).tv == tv) {
4432  break;
4433  }
4434  }
4435 
4436  if (z == pmap.end()) {
4437  pmap.push_back (PlaylistMapping (tv));
4438  }
4439  }
4440 
4441  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4442 
4443  boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4444 
4445  if (!pl) {
4446  /* region not yet associated with a playlist (e.g. unfinished
4447  capture pass.
4448  */
4449  ++x;
4450  continue;
4451  }
4452 
4453  TimeAxisView& tv = (*x)->get_time_axis_view();
4455  RegionSelection::iterator tmp;
4456 
4457  tmp = x;
4458  ++tmp;
4459 
4460  if (op != Delete) {
4461 
4462  vector<PlaylistMapping>::iterator z;
4463 
4464  for (z = pmap.begin(); z != pmap.end(); ++z) {
4465  if ((*z).tv == &tv) {
4466  break;
4467  }
4468  }
4469 
4470  assert (z != pmap.end());
4471 
4472  if (!(*z).pl) {
4473  npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4474  npl->freeze();
4475  (*z).pl = npl;
4476  } else {
4477  npl = (*z).pl;
4478  }
4479  }
4480 
4481  boost::shared_ptr<Region> r = (*x)->region();
4483 
4484  assert (r != 0);
4485 
4486  switch (op) {
4487  case Delete:
4488  pl->remove_region (r);
4489  if (Config->get_edit_mode() == Ripple)
4490  pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4491  break;
4492 
4493  case Cut:
4494  _xx = RegionFactory::create (r);
4495  npl->add_region (_xx, r->position() - first_position);
4496  pl->remove_region (r);
4497  if (Config->get_edit_mode() == Ripple)
4498  pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4499  break;
4500 
4501  case Copy:
4502  /* copy region before adding, so we're not putting same object into two different playlists */
4503  npl->add_region (RegionFactory::create (r), r->position() - first_position);
4504  break;
4505 
4506  case Clear:
4507  pl->remove_region (r);
4508  if (Config->get_edit_mode() == Ripple)
4509  pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4510  break;
4511  }
4512 
4513  x = tmp;
4514  }
4515 
4516  if (op != Delete) {
4517 
4518  list<boost::shared_ptr<Playlist> > foo;
4519 
4520  /* the pmap is in the same order as the tracks in which selected regions occured */
4521 
4522  for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4523  if ((*i).pl) {
4524  (*i).pl->thaw();
4525  foo.push_back ((*i).pl);
4526  }
4527  }
4528 
4529  if (!foo.empty()) {
4530  cut_buffer->set (foo);
4531  }
4532 
4533  if (pmap.empty()) {
4534  _last_cut_copy_source_track = 0;
4535  } else {
4536  _last_cut_copy_source_track = pmap.front().tv;
4537  }
4538  }
4539 
4540  for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4541  (*pl)->thaw ();
4542 
4543  /* We might have removed regions, which alters other regions' layering_index,
4544  so we need to do a recursive diff here.
4545  */
4546  vector<Command*> cmds;
4547  (*pl)->rdiff (cmds);
4548  _session->add_commands (cmds);
4549 
4550  _session->add_command (new StatefulDiffCommand (*pl));
4551  }
4552 }
4553 
4554 void
4556 {
4557  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4558 
4559  /* Sort the track selection now, so that it if is used, the playlists
4560  selected by the calls below to cut_copy_clear are in the order that
4561  their tracks appear in the editor. This makes things like paste
4562  of ranges work properly.
4563  */
4564 
4565  sort_track_selection (ts);
4566 
4567  if (ts.empty()) {
4568  if (!entered_track) {
4569  return;
4570  }
4571  ts.push_back (entered_track);
4572  }
4573 
4574  for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4575  (*i)->cut_copy_clear (*selection, op);
4576  }
4577 }
4578 
4579 void
4580 Editor::paste (float times, bool from_context)
4581 {
4582  DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4583 
4584  paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4585 }
4586 
4587 void
4589 {
4590  framepos_t where;
4591  bool ignored;
4592 
4593  if (!mouse_frame (where, ignored)) {
4594  return;
4595  }
4596 
4597  snap_to (where);
4598  paste_internal (where, 1);
4599 }
4600 
4601 void
4603 {
4604  DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4605 
4606  if (cut_buffer->empty(internal_editing())) {
4607  return;
4608  }
4609 
4610  if (position == max_framepos) {
4611  position = get_preferred_edit_position();
4612  DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4613  }
4614 
4615  if (position == last_paste_pos) {
4616  /* repeated paste in the same position */
4617  ++paste_count;
4618  } else {
4619  /* paste in new location, reset repeated paste state */
4620  paste_count = 0;
4621  last_paste_pos = position;
4622  }
4623 
4624  /* get everything in the correct order */
4625 
4626  TrackViewList ts;
4627  if (!selection->tracks.empty()) {
4628  /* If there is a track selection, paste into exactly those tracks and
4629  only those tracks. This allows the user to be explicit and override
4630  the below "do the reasonable thing" logic. */
4631  ts = selection->tracks.filter_to_unique_playlists ();
4632  sort_track_selection (ts);
4633  } else {
4634  /* Figure out which track to base the paste at. */
4635  TimeAxisView* base_track = NULL;
4636  if (_edit_point == Editing::EditAtMouse && entered_track) {
4637  /* With the mouse edit point, paste onto the track under the mouse. */
4638  base_track = entered_track;
4639  } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4640  /* With the mouse edit point, paste onto the track of the region under the mouse. */
4641  base_track = &entered_regionview->get_time_axis_view();
4642  } else if (_last_cut_copy_source_track) {
4643  /* Paste to the track that the cut/copy came from (see mantis #333). */
4644  base_track = _last_cut_copy_source_track;
4645  } else {
4646  /* This is "impossible" since we've copied... well, do nothing. */
4647  return;
4648  }
4649 
4650  /* Walk up to parent if necessary, so base track is a route. */
4651  while (base_track->get_parent()) {
4652  base_track = base_track->get_parent();
4653  }
4654 
4655  /* Add base track and all tracks below it. The paste logic will select
4656  the appropriate object types from the cut buffer in relative order. */
4657  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4658  if ((*i)->order() >= base_track->order()) {
4659  ts.push_back(*i);
4660  }
4661  }
4662 
4663  /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4664  sort_track_selection (ts);
4665 
4666  /* Add automation children of each track in order, for pasting several lines. */
4667  for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4668  /* Add any automation children for pasting several lines */
4669  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4670  if (!rtv) {
4671  continue;
4672  }
4673 
4674  typedef RouteTimeAxisView::AutomationTracks ATracks;
4675  const ATracks& atracks = rtv->automation_tracks();
4676  for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4677  i = ts.insert(i, a->second.get());
4678  ++i;
4679  }
4680  }
4681 
4682  /* We now have a list of trackviews starting at base_track, including
4683  automation children, in the order shown in the editor, e.g. R1,
4684  R1.A1, R1.A2, R2, R2.A1, ... */
4685  }
4686 
4687  begin_reversible_command (Operations::paste);
4688 
4689  if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4690  dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4691  /* Only one line copied, and one automation track selected. Do a
4692  "greedy" paste from one automation type to another. */
4693 
4694  PasteContext ctx(paste_count, times, ItemCounts(), true);
4695  ts.front()->paste (position, *cut_buffer, ctx);
4696 
4697  } else {
4698 
4699  /* Paste into tracks */
4700 
4701  PasteContext ctx(paste_count, times, ItemCounts(), false);
4702  for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4703  (*i)->paste (position, *cut_buffer, ctx);
4704  }
4705  }
4706 
4707  commit_reversible_command ();
4708 }
4709 
4710 void
4712 {
4713  boost::shared_ptr<Playlist> playlist;
4714  RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4715  RegionSelection foo;
4716 
4717  framepos_t const start_frame = regions.start ();
4718  framepos_t const end_frame = regions.end_frame ();
4719 
4720  begin_reversible_command (Operations::duplicate_region);
4721 
4722  selection->clear_regions ();
4723 
4724  for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4725 
4726  boost::shared_ptr<Region> r ((*i)->region());
4727 
4728  TimeAxisView& tv = (*i)->get_time_axis_view();
4729  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4730  latest_regionviews.clear ();
4731  sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4732 
4733  playlist = (*i)->region()->playlist();
4734  playlist->clear_changes ();
4735  playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4736  _session->add_command(new StatefulDiffCommand (playlist));
4737 
4738  c.disconnect ();
4739 
4740  foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4741  }
4742 
4743  if (!foo.empty()) {
4744  selection->set (foo);
4745  }
4746 
4747  commit_reversible_command ();
4748 }
4749 
4750 void
4752 {
4753  if (selection->time.empty() || selection->tracks.empty()) {
4754  return;
4755  }
4756 
4757  boost::shared_ptr<Playlist> playlist;
4758  vector<boost::shared_ptr<Region> > new_regions;
4759  vector<boost::shared_ptr<Region> >::iterator ri;
4760 
4761  create_region_from_selection (new_regions);
4762 
4763  if (new_regions.empty()) {
4764  return;
4765  }
4766 
4767  begin_reversible_command (_("duplicate selection"));
4768 
4769  ri = new_regions.begin();
4770 
4771  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4772 
4773  for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4774  if ((playlist = (*i)->playlist()) == 0) {
4775  continue;
4776  }
4777  playlist->clear_changes ();
4778  framepos_t end;
4779  if (clicked_selection) {
4780  end = selection->time[clicked_selection].end;
4781  } else {
4782  end = selection->time.end_frame();
4783  }
4784  playlist->duplicate (*ri, end, times);
4785  _session->add_command (new StatefulDiffCommand (playlist));
4786 
4787  ++ri;
4788  if (ri == new_regions.end()) {
4789  --ri;
4790  }
4791  }
4792 
4793  commit_reversible_command ();
4794 }
4795 
4797 void
4799 {
4800  for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4801  ARDOUR::AutomationList::iterator j = (*i)->model ();
4802  (*j)->value = (*i)->line().the_list()->default_value ();
4803  }
4804 }
4805 
4806 void
4808 {
4809  float const page = _visible_canvas_width * samples_per_pixel;
4810  center_screen_internal (playhead_cursor->current_frame (), page);
4811 }
4812 
4813 void
4815 {
4816  float const page = _visible_canvas_width * samples_per_pixel;
4817  center_screen_internal (get_preferred_edit_position(), page);
4818 }
4819 
4821 void
4823 {
4824  playlist->clear_changes ();
4825  playlist->clear ();
4826  _session->add_command (new StatefulDiffCommand (playlist));
4827 }
4828 
4829 void
4830 Editor::nudge_track (bool use_edit, bool forwards)
4831 {
4832  boost::shared_ptr<Playlist> playlist;
4833  framepos_t distance;
4834  framepos_t next_distance;
4835  framepos_t start;
4836 
4837  if (use_edit) {
4838  start = get_preferred_edit_position();
4839  } else {
4840  start = 0;
4841  }
4842 
4843  if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4844  return;
4845  }
4846 
4847  if (selection->tracks.empty()) {
4848  return;
4849  }
4850 
4851  begin_reversible_command (_("nudge track"));
4852 
4853  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4854 
4855  for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4856 
4857  if ((playlist = (*i)->playlist()) == 0) {
4858  continue;
4859  }
4860 
4861  playlist->clear_changes ();
4862  playlist->clear_owned_changes ();
4863 
4864  playlist->nudge_after (start, distance, forwards);
4865 
4866  vector<Command*> cmds;
4867 
4868  playlist->rdiff (cmds);
4869  _session->add_commands (cmds);
4870 
4871  _session->add_command (new StatefulDiffCommand (playlist));
4872  }
4873 
4874  commit_reversible_command ();
4875 }
4876 
4877 void
4879 {
4880  vector<string> choices;
4881  string prompt;
4882 
4883  if (!_session) {
4884  return;
4885  }
4886 
4887  if (Config->get_verify_remove_last_capture()) {
4888  prompt = _("Do you really want to destroy the last capture?"
4889  "\n(This is destructive and cannot be undone)");
4890 
4891  choices.push_back (_("No, do nothing."));
4892  choices.push_back (_("Yes, destroy it."));
4893 
4894  Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4895 
4896  if (prompter.run () == 1) {
4897  _session->remove_last_capture ();
4898  _regions->redisplay ();
4899  }
4900 
4901  } else {
4902  _session->remove_last_capture();
4903  _regions->redisplay ();
4904  }
4905 }
4906 
4907 void
4909 {
4910  if (!_session) {
4911  return;
4912  }
4913 
4914  RegionSelection rs = get_regions_from_selection_and_entered ();
4915 
4916  if (rs.empty()) {
4917  return;
4918  }
4919 
4920  NormalizeDialog dialog (rs.size() > 1);
4921 
4922  if (dialog.run () == RESPONSE_CANCEL) {
4923  return;
4924  }
4925 
4926  CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4927  gdk_flush ();
4928 
4929  /* XXX: should really only count audio regions here */
4930  int const regions = rs.size ();
4931 
4932  /* Make a list of the selected audio regions' maximum amplitudes, and also
4933  obtain the maximum amplitude of them all.
4934  */
4935  list<double> max_amps;
4936  double max_amp = 0;
4937  for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4938  AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4939  if (arv) {
4940  dialog.descend (1.0 / regions);
4941  double const a = arv->audio_region()->maximum_amplitude (&dialog);
4942 
4943  if (a == -1) {
4944  /* the user cancelled the operation */
4945  return;
4946  }
4947 
4948  max_amps.push_back (a);
4949  max_amp = max (max_amp, a);
4950  dialog.ascend ();
4951  }
4952  }
4953 
4954  begin_reversible_command (_("normalize"));
4955 
4956  list<double>::const_iterator a = max_amps.begin ();
4957 
4958  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4959  AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4960  if (!arv) {
4961  continue;
4962  }
4963 
4964  arv->region()->clear_changes ();
4965 
4966  double const amp = dialog.normalize_individually() ? *a : max_amp;
4967 
4968  arv->audio_region()->normalize (amp, dialog.target ());
4969  _session->add_command (new StatefulDiffCommand (arv->region()));
4970 
4971  ++a;
4972  }
4973 
4974  commit_reversible_command ();
4975 }
4976 
4977 
4978 void
4980 {
4981  if (!_session) {
4982  return;
4983  }
4984 
4985  RegionSelection rs = get_regions_from_selection_and_entered ();
4986 
4987  if (rs.empty()) {
4988  return;
4989  }
4990 
4991  begin_reversible_command ("reset gain");
4992 
4993  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4994  AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4995  if (!arv)
4996  continue;
4997  arv->region()->clear_changes ();
4998  arv->audio_region()->set_scale_amplitude (1.0f);
4999  _session->add_command (new StatefulDiffCommand (arv->region()));
5000  }
5001 
5002  commit_reversible_command ();
5003 }
5004 
5005 void
5007 {
5008  RegionSelection rs = get_regions_from_selection_and_entered ();
5009 
5010  if (!_session || rs.empty()) {
5011  return;
5012  }
5013 
5014  begin_reversible_command ("adjust region gain");
5015 
5016  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5017  AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5018  if (!arv) {
5019  continue;
5020  }
5021 
5022  arv->region()->clear_changes ();
5023 
5024  double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5025 
5026  if (up) {
5027  dB += 1;
5028  } else {
5029  dB -= 1;
5030  }
5031 
5033  _session->add_command (new StatefulDiffCommand (arv->region()));
5034  }
5035 
5036  commit_reversible_command ();
5037 }
5038 
5039 
5040 void
5042 {
5043  if (!_session) {
5044  return;
5045  }
5046 
5047  Reverse rev (*_session);
5048  apply_filter (rev, _("reverse regions"));
5049 }
5050 
5051 void
5053 {
5054  if (!_session) {
5055  return;
5056  }
5057 
5058  RegionSelection rs = get_regions_from_selection_and_entered ();
5059 
5060  if (rs.empty()) {
5061  return;
5062  }
5063 
5064  std::list<RegionView*> audio_only;
5065 
5066  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5067  AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5068  if (arv) {
5069  audio_only.push_back (arv);
5070  }
5071  }
5072 
5073  StripSilenceDialog d (_session, audio_only);
5074  int const r = d.run ();
5075 
5076  d.drop_rects ();
5077 
5078  if (r == Gtk::RESPONSE_OK) {
5079  ARDOUR::AudioIntervalMap silences;
5080  d.silences (silences);
5081  StripSilence s (*_session, silences, d.fade_length());
5082  apply_filter (s, _("strip silence"), &d);
5083  }
5084 }
5085 
5086 Command*
5088 {
5090  mrv.selection_as_notelist (selected, true);
5091 
5092  vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5093  v.push_back (selected);
5094 
5095  framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5096  Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5097 
5098  return op (mrv.midi_region()->model(), pos_beats, v);
5099 }
5100 
5101 void
5103 {
5104  if (rs.empty()) {
5105  return;
5106  }
5107 
5108  begin_reversible_command (op.name ());
5109 
5110  for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5111  RegionSelection::const_iterator tmp = r;
5112  ++tmp;
5113 
5114  MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5115 
5116  if (mrv) {
5117  Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5118  if (cmd) {
5119  (*cmd)();
5120  _session->add_command (cmd);
5121  }
5122  }
5123 
5124  r = tmp;
5125  }
5126 
5127  commit_reversible_command ();
5128 }
5129 
5130 void
5132 {
5133  RegionSelection rs = get_regions_from_selection_and_entered ();
5134 
5135  if (rs.empty()) {
5136  return;
5137  }
5138 
5139  begin_reversible_command (_("Fork Region(s)"));
5140 
5141  CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5142  gdk_flush ();
5143 
5144  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5145  RegionSelection::iterator tmp = r;
5146  ++tmp;
5147 
5148  MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5149 
5150  if (mrv) {
5151  try {
5152  boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5153  boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5154  boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5155 
5156  playlist->clear_changes ();
5157  playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5158  _session->add_command(new StatefulDiffCommand (playlist));
5159  } catch (...) {
5160  error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5161  }
5162  }
5163 
5164  r = tmp;
5165  }
5166 
5167  commit_reversible_command ();
5168 }
5169 
5170 void
5172 {
5173  if (_session) {
5174  quantize_regions(get_regions_from_selection_and_entered ());
5175  }
5176 }
5177 
5178 void
5180 {
5181  if (rs.n_midi_regions() == 0) {
5182  return;
5183  }
5184 
5185  QuantizeDialog* qd = new QuantizeDialog (*this);
5186 
5187  qd->present ();
5188  const int r = qd->run ();
5189  qd->hide ();
5190 
5191  if (r == Gtk::RESPONSE_OK) {
5192  Quantize quant (qd->snap_start(), qd->snap_end(),
5193  qd->start_grid_size(), qd->end_grid_size(),
5194  qd->strength(), qd->swing(), qd->threshold());
5195 
5196  apply_midi_note_edit_op (quant, rs);
5197  }
5198 }
5199 
5200 void
5201 Editor::legatize_region (bool shrink_only)
5202 {
5203  if (_session) {
5204  legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5205  }
5206 }
5207 
5208 void
5209 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5210 {
5211  if (rs.n_midi_regions() == 0) {
5212  return;
5213  }
5214 
5215  Legatize legatize(shrink_only);
5216  apply_midi_note_edit_op (legatize, rs);
5217 }
5218 
5219 void
5221 {
5222  if (_session) {
5223  transform_regions(get_regions_from_selection_and_entered ());
5224  }
5225 }
5226 
5227 void
5229 {
5230  if (rs.n_midi_regions() == 0) {
5231  return;
5232  }
5233 
5234  TransformDialog* td = new TransformDialog();
5235 
5236  td->present();
5237  const int r = td->run();
5238  td->hide();
5239 
5240  if (r == Gtk::RESPONSE_OK) {
5241  Transform transform(td->get());
5242  apply_midi_note_edit_op(transform, rs);
5243  }
5244 }
5245 
5246 void
5247 Editor::insert_patch_change (bool from_context)
5248 {
5249  RegionSelection rs = get_regions_from_selection_and_entered ();
5250 
5251  if (rs.empty ()) {
5252  return;
5253  }
5254 
5255  const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5256 
5257  /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5258  there may be more than one, but the PatchChangeDialog can only offer
5259  one set of patch menus.
5260  */
5261  MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5262 
5264  PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5265 
5266  if (d.run() == RESPONSE_CANCEL) {
5267  return;
5268  }
5269 
5270  for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5271  MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5272  if (mrv) {
5273  if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5274  mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5275  }
5276  }
5277  }
5278 }
5279 
5280 void
5281 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5282 {
5283  RegionSelection rs = get_regions_from_selection_and_entered ();
5284 
5285  if (rs.empty()) {
5286  return;
5287  }
5288 
5289  begin_reversible_command (command);
5290 
5291  CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5292  gdk_flush ();
5293 
5294  int n = 0;
5295  int const N = rs.size ();
5296 
5297  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5298  RegionSelection::iterator tmp = r;
5299  ++tmp;
5300 
5301  AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5302  if (arv) {
5303  boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5304 
5305  if (progress) {
5306  progress->descend (1.0 / N);
5307  }
5308 
5309  if (arv->audio_region()->apply (filter, progress) == 0) {
5310 
5311  playlist->clear_changes ();
5312  playlist->clear_owned_changes ();
5313 
5314  if (filter.results.empty ()) {
5315 
5316  /* no regions returned; remove the old one */
5317  playlist->remove_region (arv->region ());
5318 
5319  } else {
5320 
5321  std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5322 
5323  /* first region replaces the old one */
5324  playlist->replace_region (arv->region(), *res, (*res)->position());
5325  ++res;
5326 
5327  /* add the rest */
5328  while (res != filter.results.end()) {
5329  playlist->add_region (*res, (*res)->position());
5330  ++res;
5331  }
5332 
5333  }
5334 
5335  /* We might have removed regions, which alters other regions' layering_index,
5336  so we need to do a recursive diff here.
5337  */
5338  vector<Command*> cmds;
5339  playlist->rdiff (cmds);
5340  _session->add_commands (cmds);
5341 
5342  _session->add_command(new StatefulDiffCommand (playlist));
5343  } else {
5344  return;
5345  }
5346 
5347  if (progress) {
5348  progress->ascend ();
5349  }
5350  }
5351 
5352  r = tmp;
5353  ++n;
5354  }
5355 
5356  commit_reversible_command ();
5357 }
5358 
5359 void
5361 {
5362  /* more to come */
5363 }
5364 
5365 void
5367 {
5368  RegionSelection rs = get_regions_from_selection_and_entered ();
5369 
5370  if (!_session || rs.empty()) {
5371  return;
5372  }
5373 
5374  begin_reversible_command (_("reset region gain"));
5375 
5376  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5377  AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5378  if (arv) {
5380  XMLNode& before (alist->get_state());
5381 
5383  _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5384  }
5385  }
5386 
5387  commit_reversible_command ();
5388 }
5389 
5390 void
5392 {
5393  AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5394  if (arv) {
5396  }
5397 }
5398 
5399 void
5401 {
5402  if (!_session) {
5403  return;
5404  }
5405 
5406  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5407  AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5408  if (v) {
5409  v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5410  }
5411  }
5412 }
5413 
5414 void
5416 {
5417  if (_ignore_region_action) {
5418  return;
5419  }
5420 
5421  RegionSelection rs = get_regions_from_selection_and_entered ();
5422 
5423  if (!_session || rs.empty()) {
5424  return;
5425  }
5426 
5427  begin_reversible_command (_("region gain envelope active"));
5428 
5429  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5430  AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5431  if (arv) {
5432  arv->region()->clear_changes ();
5434  _session->add_command (new StatefulDiffCommand (arv->region()));
5435  }
5436  }
5437 
5438  commit_reversible_command ();
5439 }
5440 
5441 void
5443 {
5444  if (_ignore_region_action) {
5445  return;
5446  }
5447 
5448  RegionSelection rs = get_regions_from_selection_and_entered ();
5449 
5450  if (!_session || rs.empty()) {
5451  return;
5452  }
5453 
5454  begin_reversible_command (_("toggle region lock"));
5455 
5456  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5457  (*i)->region()->clear_changes ();
5458  (*i)->region()->set_locked (!(*i)->region()->locked());
5459  _session->add_command (new StatefulDiffCommand ((*i)->region()));
5460  }
5461 
5462  commit_reversible_command ();
5463 }
5464 
5465 void
5467 {
5468  if (_ignore_region_action) {
5469  return;
5470  }
5471 
5472  RegionSelection rs = get_regions_from_selection_and_entered ();
5473 
5474  if (!_session || rs.empty()) {
5475  return;
5476  }
5477 
5478  begin_reversible_command (_("Toggle Video Lock"));
5479 
5480  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5481  (*i)->region()->clear_changes ();
5482  (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5483  _session->add_command (new StatefulDiffCommand ((*i)->region()));
5484  }
5485 
5486  commit_reversible_command ();
5487 }
5488 
5489 void
5491 {
5492  if (_ignore_region_action) {
5493  return;
5494  }
5495 
5496  RegionSelection rs = get_regions_from_selection_and_entered ();
5497 
5498  if (!_session || rs.empty()) {
5499  return;
5500  }
5501 
5502  begin_reversible_command (_("region lock style"));
5503 
5504  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5505  (*i)->region()->clear_changes ();
5506  PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5507  (*i)->region()->set_position_lock_style (ns);
5508  _session->add_command (new StatefulDiffCommand ((*i)->region()));
5509  }
5510 
5511  commit_reversible_command ();
5512 }
5513 
5514 void
5516 {
5517  if (_ignore_region_action) {
5518  return;
5519  }
5520 
5521  RegionSelection rs = get_regions_from_selection_and_entered ();
5522 
5523  if (!_session || rs.empty()) {
5524  return;
5525  }
5526 
5527  begin_reversible_command (_("change region opacity"));
5528 
5529  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5530  (*i)->region()->clear_changes ();
5531  (*i)->region()->set_opaque (!(*i)->region()->opaque());
5532  _session->add_command (new StatefulDiffCommand ((*i)->region()));
5533  }
5534 
5535  commit_reversible_command ();
5536 }
5537 
5538 void
5540 {
5541  bool new_state = false;
5542  bool first = true;
5543  for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5544  RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5545  if (!rtav)
5546  continue;
5547  if (!rtav->is_track())
5548  continue;
5549 
5550  if (first) {
5551  new_state = !rtav->track()->record_enabled();
5552  first = false;
5553  }
5554 
5555  rtav->track()->set_record_enabled (new_state, this);
5556  }
5557 }
5558 
5559 void
5561 {
5562  bool new_state = false;
5563  bool first = true;
5565 
5566  for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5567  RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5568 
5569  if (!rtav) {
5570  continue;
5571  }
5572 
5573  if (first) {
5574  new_state = !rtav->route()->soloed ();
5575  first = false;
5576  }
5577 
5578  rl->push_back (rtav->route());
5579  }
5580 
5581  _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5582 }
5583 
5584 void
5586 {
5587  bool new_state = false;
5588  bool first = true;
5590 
5591  for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5592  RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5593 
5594  if (!rtav) {
5595  continue;
5596  }
5597 
5598  if (first) {
5599  new_state = !rtav->route()->muted();
5600  first = false;
5601  }
5602 
5603  rl->push_back (rtav->route());
5604  }
5605 
5606  _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5607 }
5608 
5609 void
5611 {
5612 }
5613 
5614 
5615 void
5617 {
5618  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5619 
5620  begin_reversible_command (_("fade range"));
5621 
5622  for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5623  (*i)->fade_range (selection->time);
5624  }
5625 
5626  commit_reversible_command ();
5627 }
5628 
5629 
5630 void
5632 {
5633  RegionSelection rs = get_regions_from_selection_and_entered ();
5634 
5635  if (rs.empty()) {
5636  return;
5637  }
5638 
5639  /* we need a region to measure the offset from the start */
5640 
5641  RegionView* rv = rs.front ();
5642 
5643  framepos_t pos = get_preferred_edit_position();
5644  framepos_t len;
5645  char const * cmd;
5646 
5647  if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5648  /* edit point is outside the relevant region */
5649  return;
5650  }
5651 
5652  if (in) {
5653  if (pos <= rv->region()->position()) {
5654  /* can't do it */
5655  return;
5656  }
5657  len = pos - rv->region()->position();
5658  cmd = _("set fade in length");
5659  } else {
5660  if (pos >= rv->region()->last_frame()) {
5661  /* can't do it */
5662  return;
5663  }
5664  len = rv->region()->last_frame() - pos;
5665  cmd = _("set fade out length");
5666  }
5667 
5668  begin_reversible_command (cmd);
5669 
5670  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5671  AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5672 
5673  if (!tmp) {
5674  return;
5675  }
5676 
5678  if (in) {
5679  alist = tmp->audio_region()->fade_in();
5680  } else {
5681  alist = tmp->audio_region()->fade_out();
5682  }
5683 
5684  XMLNode &before = alist->get_state();
5685 
5686  if (in) {
5687  tmp->audio_region()->set_fade_in_length (len);
5688  tmp->audio_region()->set_fade_in_active (true);
5689  } else {
5690  tmp->audio_region()->set_fade_out_length (len);
5691  tmp->audio_region()->set_fade_out_active (true);
5692  }
5693 
5694  XMLNode &after = alist->get_state();
5695  _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5696  }
5697 
5698  commit_reversible_command ();
5699 }
5700 
5701 void
5703 {
5704  RegionSelection rs = get_regions_from_selection_and_entered ();
5705 
5706  if (rs.empty()) {
5707  return;
5708  }
5709 
5710  begin_reversible_command (_("set fade in shape"));
5711 
5712  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5713  AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5714 
5715  if (!tmp) {
5716  return;
5717  }
5718 
5720  XMLNode &before = alist->get_state();
5721 
5722  tmp->audio_region()->set_fade_in_shape (shape);
5723 
5724  XMLNode &after = alist->get_state();
5725  _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5726  }
5727 
5728  commit_reversible_command ();
5729 
5730 }
5731 
5732 void
5734 {
5735  RegionSelection rs = get_regions_from_selection_and_entered ();
5736 
5737  if (rs.empty()) {
5738  return;
5739  }
5740 
5741  begin_reversible_command (_("set fade out shape"));
5742 
5743  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5744  AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5745 
5746  if (!tmp) {
5747  return;
5748  }
5749 
5751  XMLNode &before = alist->get_state();
5752 
5753  tmp->audio_region()->set_fade_out_shape (shape);
5754 
5755  XMLNode &after = alist->get_state();
5756  _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5757  }
5758 
5759  commit_reversible_command ();
5760 }
5761 
5762 void
5764 {
5765  RegionSelection rs = get_regions_from_selection_and_entered ();
5766 
5767  if (rs.empty()) {
5768  return;
5769  }
5770 
5771  begin_reversible_command (_("set fade in active"));
5772 
5773  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5774  AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5775 
5776  if (!tmp) {
5777  return;
5778  }
5779 
5780 
5782 
5783  ar->clear_changes ();
5784  ar->set_fade_in_active (yn);
5785  _session->add_command (new StatefulDiffCommand (ar));
5786  }
5787 
5788  commit_reversible_command ();
5789 }
5790 
5791 void
5793 {
5794  RegionSelection rs = get_regions_from_selection_and_entered ();
5795 
5796  if (rs.empty()) {
5797  return;
5798  }
5799 
5800  begin_reversible_command (_("set fade out active"));
5801 
5802  for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5803  AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5804 
5805  if (!tmp) {
5806  return;
5807  }
5808 
5810 
5811  ar->clear_changes ();
5812  ar->set_fade_out_active (yn);
5813  _session->add_command(new StatefulDiffCommand (ar));
5814  }
5815 
5816  commit_reversible_command ();
5817 }
5818 
5819 void
5821 {
5822  if (_ignore_region_action) {
5823  return;
5824  }
5825 
5827  bool yn = false;
5828 
5829  RegionSelection rs = get_regions_from_selection_and_entered ();
5830 
5831  if (rs.empty()) {
5832  return;
5833  }
5834 
5835  RegionSelection::iterator i;
5836  for (i = rs.begin(); i != rs.end(); ++i) {
5837  if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5838  if (dir == -1) {
5839  yn = ar->fade_out_active ();
5840  } else {
5841  yn = ar->fade_in_active ();
5842  }
5843  break;
5844  }
5845  }
5846 
5847  if (i == rs.end()) {
5848  return;
5849  }
5850 
5851  /* XXX should this undo-able? */
5852 
5853  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5854  if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5855  continue;
5856  }
5857  if (dir == 1 || dir == 0) {
5858  ar->set_fade_in_active (!yn);
5859  }
5860 
5861  if (dir == -1 || dir == 0) {
5862  ar->set_fade_out_active (!yn);
5863  }
5864  }
5865 }
5866 
5867 
5869 void
5871 {
5872  bool _fade_visibility = _session->config.get_show_region_fades ();
5873 
5874  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5875  AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5876  if (v) {
5877  if (_fade_visibility) {
5878  v->audio_view()->show_all_fades ();
5879  } else {
5880  v->audio_view()->hide_all_fades ();
5881  }
5882  }
5883  }
5884 }
5885 
5886 void
5888 {
5889  framepos_t where;
5890  bool ignored;
5891 
5892  if (!mouse_frame (where, ignored)) {
5893  return;
5894  }
5895 
5896  snap_to (where);
5897 
5898  if (selection->markers.empty()) {
5899 
5900  mouse_add_new_marker (where);
5901 
5902  } else {
5903  bool ignored;
5904 
5905  Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5906 
5907  if (loc) {
5908  loc->move_to (where);
5909  }
5910  }
5911 }
5912 
5913 void
5915 {
5916  if (entered_marker) {
5917  _session->request_locate (entered_marker->position(), _session->transport_rolling());
5918  } else {
5919  framepos_t where;
5920  bool ignored;
5921 
5922  if (!mouse_frame (where, ignored)) {
5923  return;
5924  }
5925 
5926  snap_to (where);
5927 
5928  if (_session) {
5929  _session->request_locate (where, _session->transport_rolling());
5930  }
5931  }
5932 
5933  if (ARDOUR_UI::config()->get_follow_edits()) {
5934  cancel_time_selection();
5935  }
5936 }
5937 
5938 void
5940 {
5941  //if a range is selected, separate it
5942  if ( !selection->time.empty()) {
5943  separate_regions_between (selection->time);
5944  return;
5945  }
5946 
5947  //if no range was selected, try to find some regions to split
5948  if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
5949 
5950  RegionSelection rs = get_regions_from_selection_and_edit_point ();
5951 
5952  framepos_t where = get_preferred_edit_position ();
5953 
5954  if (rs.empty()) {
5955  return;
5956  }
5957 
5958  split_regions_at (where, rs);
5959  }
5960 }
5961 
5964  return a->order_key () < b->order_key ();
5965  }
5966 };
5967 
5968 void
5970 {
5971  if (selection->tracks.empty()) {
5972  selection->set (track_views.front());
5973  return;
5974  }
5975 
5976  TimeAxisView* current = selection->tracks.front();
5977 
5978  RouteUI *rui;
5979  do {
5980  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5981  if (*i == current) {
5982  ++i;
5983  if (i != track_views.end()) {
5984  current = (*i);
5985  } else {
5986  current = (*(track_views.begin()));
5987  //selection->set (*(track_views.begin()));
5988  }
5989  break;
5990  }
5991  }
5992  rui = dynamic_cast<RouteUI *>(current);
5993  } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5994 
5995  selection->set(current);
5996 
5997  ensure_time_axis_view_is_visible (*current, false);
5998 }
5999 
6000 void
6002 {
6003  if (selection->tracks.empty()) {
6004  selection->set (track_views.front());
6005  return;
6006  }
6007 
6008  TimeAxisView* current = selection->tracks.front();
6009 
6010  RouteUI *rui;
6011  do {
6012  for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6013  if (*i == current) {
6014  ++i;
6015  if (i != track_views.rend()) {
6016  current = (*i);
6017  } else {
6018  current = *(track_views.rbegin());
6019  }
6020  break;
6021  }
6022  }
6023  rui = dynamic_cast<RouteUI *>(current);
6024  } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6025 
6026  selection->set (current);
6027 
6028  ensure_time_axis_view_is_visible (*current, false);
6029 }
6030 
6031 void
6033 {
6034  if (_session == 0) {
6035  return;
6036  }
6037 
6038  framepos_t start, end;
6039  if (!get_selection_extents ( start, end))
6040  return;
6041 
6042  set_loop_range (start, end, _("set loop range from selection"));
6043 
6044  if (play) {
6045  _session->request_play_loop (true, true);
6046  }
6047 }
6048 
6049 void
6051 {
6052  framepos_t start, end;
6053  if (!get_selection_extents ( start, end))
6054  return;
6055 
6056  set_loop_range (start, end, _("set loop range from region"));
6057 
6058  if (play) {
6059  _session->request_locate (start, true);
6060  _session->request_play_loop (true);
6061  }
6062 }
6063 
6064 void
6066 {
6067  if (_session == 0) {
6068  return;
6069  }
6070 
6071  framepos_t start, end;
6072  if (!get_selection_extents ( start, end))
6073  return;
6074 
6075  set_punch_range (start, end, _("set punch range from selection"));
6076 }
6077 
6078 void
6080 {
6081  if (_session == 0) {
6082  return;
6083  }
6084 
6085  framepos_t start, end;
6086  if (!get_selection_extents ( start, end))
6087  return;
6088 
6089  Location* loc;
6090  if ((loc = _session->locations()->session_range_location()) == 0) {
6091  _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6092  } else {
6093  XMLNode &before = loc->get_state();
6094 
6095  _session->set_session_extents ( start, end );
6096 
6097  XMLNode &after = loc->get_state();
6098 
6099  begin_reversible_command (_("set session start/end from selection"));
6100 
6101  _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6102 
6103  commit_reversible_command ();
6104  }
6105 }
6106 
6107 void
6109 {
6110  framepos_t start, end;
6111  if (!get_selection_extents ( start, end))
6112  return;
6113 
6114  set_punch_range (start, end, _("set punch range from region"));
6115 }
6116 
6117 void
6119 {
6120  RegionSelection rs = get_regions_from_selection_and_entered ();
6121 
6122  RegionSelection audio_rs;
6123  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6124  if (dynamic_cast<AudioRegionView*> (*i)) {
6125  audio_rs.push_back (*i);
6126  }
6127  }
6128 
6129  if (audio_rs.empty()) {
6130  return;
6131  }
6132 
6133  pitch_shift (audio_rs, 1.2);
6134 }
6135 
6136 void
6138 {
6139  RegionSelection rs = get_regions_from_selection_and_entered ();
6140 
6141  list<MidiRegionView*> midi_region_views;
6142  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6143  MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6144  if (mrv) {
6145  midi_region_views.push_back (mrv);
6146  }
6147  }
6148 
6149  TransposeDialog d;
6150  int const r = d.run ();
6151  if (r != RESPONSE_ACCEPT) {
6152  return;
6153  }
6154 
6155  for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6156  (*i)->midi_region()->transpose (d.semitones ());
6157  }
6158 }
6159 
6160 void
6162 {
6163  RegionSelection rs = get_regions_from_selection_and_entered ();
6164 
6165  if (!_session || rs.empty()) {
6166  return;
6167  }
6168 
6169  RegionView* rv = rs.front();
6170 
6171  define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6172 }
6173 
6174 void
6176 {
6177  framepos_t start, end;
6178  if (get_edit_op_range (start, end)) {
6179  define_one_bar (start, end);
6180  }
6181 }
6182 
6183 void
6185 {
6186  framepos_t length = end - start;
6187 
6188  const Meter& m (_session->tempo_map().meter_at (start));
6189 
6190  /* length = 1 bar */
6191 
6192  /* now we want frames per beat.
6193  we have frames per bar, and beats per bar, so ...
6194  */
6195 
6196  /* XXXX METER MATH */
6197 
6198  double frames_per_beat = length / m.divisions_per_bar();
6199 
6200  /* beats per minute = */
6201 
6202  double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6203 
6204  /* now decide whether to:
6205 
6206  (a) set global tempo
6207  (b) add a new tempo marker
6208 
6209  */
6210 
6211  const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6212 
6213  bool do_global = false;
6214 
6215  if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6216 
6217  /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6218  at the start, or create a new marker
6219  */
6220 
6221  vector<string> options;
6222  options.push_back (_("Cancel"));
6223  options.push_back (_("Add new marker"));
6224  options.push_back (_("Set global tempo"));
6225 
6226  Choice c (
6227  _("Define one bar"),
6228  _("Do you want to set the global tempo or add a new tempo marker?"),
6229  options
6230  );
6231 
6232  c.set_default_response (2);
6233 
6234  switch (c.run()) {
6235  case 0:
6236  return;
6237 
6238  case 2:
6239  do_global = true;
6240  break;
6241 
6242  default:
6243  do_global = false;
6244  }
6245 
6246  } else {
6247 
6248  /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6249  if the marker is at the region starter, change it, otherwise add
6250  a new tempo marker
6251  */
6252  }
6253 
6254  begin_reversible_command (_("set tempo from region"));
6255  XMLNode& before (_session->tempo_map().get_state());
6256 
6257  if (do_global) {
6258  _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6259  } else if (t.frame() == start) {
6260  _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6261  } else {
6262  Timecode::BBT_Time bbt;
6263  _session->tempo_map().bbt_time (start, bbt);
6264  _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6265  }
6266 
6267  XMLNode& after (_session->tempo_map().get_state());
6268 
6269  _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6270  commit_reversible_command ();
6271 }
6272 
6273 void
6275 {
6276  AnalysisFeatureList positions;
6277 
6278  RegionSelection rs = get_regions_from_selection_and_entered ();
6279 
6280  if (!_session || rs.empty()) {
6281  return;
6282  }
6283 
6284  begin_reversible_command (_("split regions"));
6285 
6286  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6287 
6288  RegionSelection::iterator tmp;
6289 
6290  tmp = i;
6291  ++tmp;
6292 
6294 
6295  if (ar && (ar->get_transients (positions) == 0)) {
6296  split_region_at_points ((*i)->region(), positions, true);
6297  positions.clear ();
6298  }
6299 
6300  i = tmp;
6301  }
6302 
6303  commit_reversible_command ();
6304 
6305 }
6306 
6307 void
6308 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6309 {
6310  bool use_rhythmic_rodent = false;
6311 
6313 
6314  list<boost::shared_ptr<Region> > new_regions;
6315 
6316  if (!pl) {
6317  return;
6318  }
6319 
6320  if (positions.empty()) {
6321  return;
6322  }
6323 
6324 
6325  if (positions.size() > 20 && can_ferret) {
6326  std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6327  MessageDialog msg (msgstr,
6328  false,
6329  Gtk::MESSAGE_INFO,
6330  Gtk::BUTTONS_OK_CANCEL);
6331 
6332  if (can_ferret) {
6333  msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6334  msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6335  } else {
6336  msg.set_secondary_text (_("Press OK to continue with this split operation"));
6337  }
6338 
6339  msg.set_title (_("Excessive split?"));
6340  msg.present ();
6341 
6342  int response = msg.run();
6343  msg.hide ();
6344 
6345  switch (response) {
6346  case RESPONSE_OK:
6347  break;
6348  case RESPONSE_APPLY:
6349  use_rhythmic_rodent = true;
6350  break;
6351  default:
6352  return;
6353  }
6354  }
6355 
6356  if (use_rhythmic_rodent) {
6357  show_rhythm_ferret ();
6358  return;
6359  }
6360 
6361  AnalysisFeatureList::const_iterator x;
6362 
6363  pl->clear_changes ();
6364  pl->clear_owned_changes ();
6365 
6366  x = positions.begin();
6367 
6368  if (x == positions.end()) {
6369  return;
6370  }
6371 
6372  pl->freeze ();
6373  pl->remove_region (r);
6374 
6375  framepos_t pos = 0;
6376 
6377  while (x != positions.end()) {
6378 
6379  /* deal with positons that are out of scope of present region bounds */
6380  if (*x <= 0 || *x > r->length()) {
6381  ++x;
6382  continue;
6383  }
6384 
6385  /* file start = original start + how far we from the initial position ?
6386  */
6387 
6388  framepos_t file_start = r->start() + pos;
6389 
6390  /* length = next position - current position
6391  */
6392 
6393  framepos_t len = (*x) - pos;
6394 
6395  /* XXX we do we really want to allow even single-sample regions?
6396  shouldn't we have some kind of lower limit on region size?
6397  */
6398 
6399  if (len <= 0) {
6400  break;
6401  }
6402 
6403  string new_name;
6404 
6405  if (RegionFactory::region_name (new_name, r->name())) {
6406  break;
6407  }
6408 
6409  /* do NOT announce new regions 1 by one, just wait till they are all done */
6410 
6411  PropertyList plist;
6412 
6413  plist.add (ARDOUR::Properties::start, file_start);
6414  plist.add (ARDOUR::Properties::length, len);
6415  plist.add (ARDOUR::Properties::name, new_name);
6416  plist.add (ARDOUR::Properties::layer, 0);
6417 
6418  boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6419  /* because we set annouce to false, manually add the new region to the
6420  RegionFactory map
6421  */
6422  RegionFactory::map_add (nr);
6423 
6424  pl->add_region (nr, r->position() + pos);
6425 
6426  if (select_new) {
6427  new_regions.push_front(nr);
6428  }
6429 
6430  pos += len;
6431  ++x;
6432  }
6433 
6434  string new_name;
6435 
6436  RegionFactory::region_name (new_name, r->name());
6437 
6438  /* Add the final region */
6439  PropertyList plist;
6440 
6441  plist.add (ARDOUR::Properties::start, r->start() + pos);
6442  plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6443  plist.add (ARDOUR::Properties::name, new_name);
6444  plist.add (ARDOUR::Properties::layer, 0);
6445 
6446  boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6447  /* because we set annouce to false, manually add the new region to the
6448  RegionFactory map
6449  */
6450  RegionFactory::map_add (nr);
6451  pl->add_region (nr, r->position() + pos);
6452 
6453  if (select_new) {
6454  new_regions.push_front(nr);
6455  }
6456 
6457  pl->thaw ();
6458 
6459  /* We might have removed regions, which alters other regions' layering_index,
6460  so we need to do a recursive diff here.
6461  */
6462  vector<Command*> cmds;
6463  pl->rdiff (cmds);
6464  _session->add_commands (cmds);
6465 
6466  _session->add_command (new StatefulDiffCommand (pl));
6467 
6468  if (select_new) {
6469 
6470  for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6471  set_selected_regionview_from_region_list ((*i), Selection::Add);
6472  }
6473  }
6474 }
6475 
6476 void
6478 {
6479  if (!_session) {
6480  return;
6481  }
6482 
6483  RegionSelection rs = get_regions_from_selection_and_edit_point ();
6484 
6485  if (rs.empty()) {
6486  return;
6487  }
6488 
6489  framepos_t where = get_preferred_edit_position();
6490 
6491  begin_reversible_command (_("place transient"));
6492 
6493  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6494  framepos_t position = (*r)->region()->position();
6495  (*r)->region()->add_transient(where - position);
6496  }
6497 
6498  commit_reversible_command ();
6499 }
6500 
6501 void
6502 Editor::remove_transient(ArdourCanvas::Item* item)
6503 {
6504  if (!_session) {
6505  return;
6506  }
6507 
6508  ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6509  assert (_line);
6510 
6511  AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6512  _arv->remove_transient (*(float*) _line->get_data ("position"));
6513 }
6514 
6515 void
6517 {
6518  list <boost::shared_ptr<Playlist > > used_playlists;
6519 
6520  RegionSelection rs = get_regions_from_selection_and_entered ();
6521 
6522  if (!_session || rs.empty()) {
6523  return;
6524  }
6525 
6526  begin_reversible_command (_("snap regions to grid"));
6527 
6528  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6529 
6530  boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6531 
6532  if (!pl->frozen()) {
6533  /* we haven't seen this playlist before */
6534 
6535  /* remember used playlists so we can thaw them later */
6536  used_playlists.push_back(pl);
6537  pl->freeze();
6538  }
6539 
6540  framepos_t start_frame = (*r)->region()->first_frame ();
6541  snap_to (start_frame);
6542  (*r)->region()->set_position (start_frame);
6543  }
6544 
6545  while (used_playlists.size() > 0) {
6546  list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6547  (*i)->thaw();
6548  used_playlists.pop_front();
6549  }
6550 
6551  commit_reversible_command ();
6552 }
6553 
6554 void
6556 {
6557  list <boost::shared_ptr<Playlist > > used_playlists;
6558 
6559  RegionSelection rs = get_regions_from_selection_and_entered ();
6560 
6561  if (!_session || rs.empty()) {
6562  return;
6563  }
6564 
6565  Dialog dialog (_("Close Region Gaps"));
6566 
6567  Table table (2, 3);
6568  table.set_spacings (12);
6569  table.set_border_width (12);
6570  Label* l = manage (left_aligned_label (_("Crossfade length")));
6571  table.attach (*l, 0, 1, 0, 1);
6572 
6573  SpinButton spin_crossfade (1, 0);
6574  spin_crossfade.set_range (0, 15);
6575  spin_crossfade.set_increments (1, 1);
6576  spin_crossfade.set_value (5);
6577  table.attach (spin_crossfade, 1, 2, 0, 1);
6578 
6579  table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6580 
6581  l = manage (left_aligned_label (_("Pull-back length")));
6582  table.attach (*l, 0, 1, 1, 2);
6583 
6584  SpinButton spin_pullback (1, 0);
6585  spin_pullback.set_range (0, 100);
6586  spin_pullback.set_increments (1, 1);
6587  spin_pullback.set_value(30);
6588  table.attach (spin_pullback, 1, 2, 1, 2);
6589 
6590  table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6591 
6592  dialog.get_vbox()->pack_start (table);
6593  dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6594  dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6595  dialog.show_all ();
6596 
6597  if (dialog.run () == RESPONSE_CANCEL) {
6598  return;
6599  }
6600 
6601  framepos_t crossfade_len = spin_crossfade.get_value();
6602  framepos_t pull_back_frames = spin_pullback.get_value();
6603 
6604  crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6605  pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6606 
6607  /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6608 
6609  begin_reversible_command (_("close region gaps"));
6610 
6611  int idx = 0;
6612  boost::shared_ptr<Region> last_region;
6613 
6615 
6616  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6617 
6618  boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6619 
6620  if (!pl->frozen()) {
6621  /* we haven't seen this playlist before */
6622 
6623  /* remember used playlists so we can thaw them later */
6624  used_playlists.push_back(pl);
6625  pl->freeze();
6626  }
6627 
6628  framepos_t position = (*r)->region()->position();
6629 
6630  if (idx == 0 || position < last_region->position()){
6631  last_region = (*r)->region();
6632  idx++;
6633  continue;
6634  }
6635 
6636  (*r)->region()->trim_front( (position - pull_back_frames));
6637  last_region->trim_end( (position - pull_back_frames + crossfade_len));
6638 
6639  last_region = (*r)->region();
6640 
6641  idx++;
6642  }
6643 
6644  while (used_playlists.size() > 0) {
6645  list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6646  (*i)->thaw();
6647  used_playlists.pop_front();
6648  }
6649 
6650  commit_reversible_command ();
6651 }
6652 
6653 void
6655 {
6656  AnalysisFeatureList positions;
6657 
6658  RegionSelection rs = get_regions_from_selection_and_entered ();
6659 
6660  if (!_session) {
6661  return;
6662  }
6663 
6664  framepos_t pos = _session->audible_frame ();
6665 
6666  if (!selection->tracks.empty()) {
6667 
6668  /* don't waste time searching for transients in duplicate playlists.
6669  */
6670 
6671  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6672 
6673  for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6674 
6675  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6676 
6677  if (rtv) {
6678  boost::shared_ptr<Track> tr = rtv->track();
6679  if (tr) {
6681  if (pl) {
6682  framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6683 
6684  if (result >= 0) {
6685  positions.push_back (result);
6686  }
6687  }
6688  }
6689  }
6690  }
6691 
6692  } else {
6693 
6694  if (rs.empty()) {
6695  return;
6696  }
6697 
6698  for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6699  (*r)->region()->get_transients (positions);
6700  }
6701  }
6702 
6703  TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6704 
6705  if (forward) {
6706  AnalysisFeatureList::iterator x;
6707 
6708  for (x = positions.begin(); x != positions.end(); ++x) {
6709  if ((*x) > pos) {
6710  break;
6711  }
6712  }
6713 
6714  if (x != positions.end ()) {
6715  _session->request_locate (*x);
6716  }
6717 
6718  } else {
6719  AnalysisFeatureList::reverse_iterator x;
6720 
6721  for (x = positions.rbegin(); x != positions.rend(); ++x) {
6722  if ((*x) < pos) {
6723  break;
6724  }
6725  }
6726 
6727  if (x != positions.rend ()) {
6728  _session->request_locate (*x);
6729  }
6730  }
6731 }
6732 
6733 void
6735 {
6736  if (!_session) {
6737  return;
6738  }
6739 
6740  framepos_t pos = playhead_cursor->current_frame ();
6741  if (pos < max_framepos - 1) {
6742  pos += 2;
6743  snap_to_internal (pos, RoundUpAlways, false);
6744  _session->request_locate (pos);
6745  }
6746 }
6747 
6748 
6749 void
6751 {
6752  if (!_session) {
6753  return;
6754  }
6755 
6756  framepos_t pos = playhead_cursor->current_frame ();
6757  if (pos > 2) {
6758  pos -= 2;
6759  snap_to_internal (pos, RoundDownAlways, false);
6760  _session->request_locate (pos);
6761  }
6762 }
6763 
6764 void
6766 {
6767  TrackSelection& ts (selection->tracks);
6768 
6769  for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6770  (*x)->set_height_enum (h);
6771  }
6772 }
6773 
6774 void
6776 {
6777  TrackSelection& ts (selection->tracks);
6778  bool first = true;
6779  bool target = false;
6780 
6781  if (ts.empty()) {
6782  return;
6783  }
6784 
6785  for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6786  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6787 
6788  if (rtv) {
6789  if (first) {
6790  target = !rtv->_route->active();
6791  first = false;
6792  }
6793  rtv->_route->set_active (target, this);
6794  }
6795  }
6796 }
6797 
6798 void
6800 {
6801  /* this will delete GUI objects that may be the subject of an event
6802  handler in which this method is called. Defer actual deletion to the
6803  next idle callback, when all event handling is finished.
6804  */
6805  Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6806 }
6807 
6808 bool
6810 {
6811  _remove_tracks ();
6812  return false; /* do not call again */
6813 }
6814 
6815 void
6817 {
6818  TrackSelection& ts (selection->tracks);
6819 
6820  if (ts.empty()) {
6821  return;
6822  }
6823 
6824  vector<string> choices;
6825  string prompt;
6826  int ntracks = 0;
6827  int nbusses = 0;
6828  const char* trackstr;
6829  const char* busstr;
6830  vector<boost::shared_ptr<Route> > routes;
6831  bool special_bus = false;
6832 
6833  for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6834  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6835  if (!rtv) {
6836  continue;
6837  }
6838  if (rtv->is_track()) {
6839  ntracks++;
6840  } else {
6841  nbusses++;
6842  }
6843  routes.push_back (rtv->_route);
6844 
6845  if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6846  special_bus = true;
6847  }
6848  }
6849 
6850  if (special_bus && !Config->get_allow_special_bus_removal()) {
6851  MessageDialog msg (_("That would be bad news ...."),
6852  false,
6853  Gtk::MESSAGE_INFO,
6854  Gtk::BUTTONS_OK);
6855  msg.set_secondary_text (string_compose (_(
6856  "Removing the master or monitor bus is such a bad idea\n\
6857 that %1 is not going to allow it.\n\
6858 \n\
6859 If you really want to do this sort of thing\n\
6860 edit your ardour.rc file to set the\n\
6861 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6862 
6863  msg.present ();
6864  msg.run ();
6865  return;
6866  }
6867 
6868  if (ntracks + nbusses == 0) {
6869  return;
6870  }
6871 
6872  trackstr = P_("track", "tracks", ntracks);
6873  busstr = P_("bus", "busses", nbusses);
6874 
6875  if (ntracks) {
6876  if (nbusses) {
6877  prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6878  "(You may also lose the playlists associated with the %2)\n\n"
6879  "This action cannot be undone, and the session file will be overwritten!"),
6880  ntracks, trackstr, nbusses, busstr);
6881  } else {
6882  prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6883  "(You may also lose the playlists associated with the %2)\n\n"
6884  "This action cannot be undone, and the session file will be overwritten!"),
6885  ntracks, trackstr);
6886  }
6887  } else if (nbusses) {
6888  prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6889  "This action cannot be undone, and the session file will be overwritten"),
6890  nbusses, busstr);
6891  }
6892 
6893  choices.push_back (_("No, do nothing."));
6894  if (ntracks + nbusses > 1) {
6895  choices.push_back (_("Yes, remove them."));
6896  } else {
6897  choices.push_back (_("Yes, remove it."));
6898  }
6899 
6900  string title;
6901  if (ntracks) {
6902  title = string_compose (_("Remove %1"), trackstr);
6903  } else {
6904  title = string_compose (_("Remove %1"), busstr);
6905  }
6906 
6907  Choice prompter (title, prompt, choices);
6908 
6909  if (prompter.run () != 1) {
6910  return;
6911  }
6912 
6913  {
6914  Session::StateProtector sp (_session);
6915  DisplaySuspender ds;
6916  for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6917  _session->remove_route (*x);
6918  }
6919  }
6920 }
6921 
6922 void
6924 {
6925  if (selection->tracks.empty()) {
6926  return;
6927  }
6928 
6929  InsertTimeDialog d (*this);
6930  int response = d.run ();
6931 
6932  if (response != RESPONSE_OK) {
6933  return;
6934  }
6935 
6936  if (d.distance() == 0) {
6937  return;
6938  }
6939 
6941 
6942  insert_time (
6943  get_preferred_edit_position(),
6944  d.distance(),
6945  opt,
6946  d.all_playlists(),
6947  d.move_glued(),
6948  d.move_markers(),
6949  d.move_glued_markers(),
6950  d.move_locked_markers(),
6951  d.move_tempos()
6952  );
6953 }
6954 
6955 void
6957  framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6958  bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6959  )
6960 {
6961  bool commit = false;
6962 
6963  if (Config->get_edit_mode() == Lock) {
6964  return;
6965  }
6966 
6967  begin_reversible_command (_("insert time"));
6968 
6969  TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6970 
6971  for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6972 
6973  /* regions */
6974 
6975  /* don't operate on any playlist more than once, which could
6976  * happen if "all playlists" is enabled, but there is more
6977  * than 1 track using playlists "from" a given track.
6978  */
6979 
6980  set<boost::shared_ptr<Playlist> > pl;
6981 
6982  if (all_playlists) {
6983  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6984  if (rtav) {
6985  vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6986  for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6987  pl.insert (*p);
6988  }
6989  }
6990  } else {
6991  if ((*x)->playlist ()) {
6992  pl.insert ((*x)->playlist ());
6993  }
6994  }
6995 
6996  for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6997 
6998  (*i)->clear_changes ();
6999  (*i)->clear_owned_changes ();
7000 
7001  if (opt == SplitIntersected) {
7002  (*i)->split (pos);
7003  }
7004 
7005  (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7006 
7007  vector<Command*> cmds;
7008  (*i)->rdiff (cmds);
7009  _session->add_commands (cmds);
7010 
7011  _session->add_command (new StatefulDiffCommand (*i));
7012  commit = true;
7013  }
7014 
7015  /* automation */
7016  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7017  if (rtav) {
7018  rtav->route ()->shift (pos, frames);
7019  commit = true;
7020  }
7021  }
7022 
7023  /* markers */
7024  if (markers_too) {
7025  bool moved = false;
7026  XMLNode& before (_session->locations()->get_state());
7027  Locations::LocationList copy (_session->locations()->list());
7028 
7029  for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7030 
7031  Locations::LocationList::const_iterator tmp;
7032 
7033  bool const was_locked = (*i)->locked ();
7034  if (locked_markers_too) {
7035  (*i)->unlock ();
7036  }
7037 
7038  if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7039 
7040  if ((*i)->start() >= pos) {
7041  (*i)->set_start ((*i)->start() + frames);
7042  if (!(*i)->is_mark()) {
7043  (*i)->set_end ((*i)->end() + frames);
7044  }
7045  moved = true;
7046  }
7047 
7048  }
7049 
7050  if (was_locked) {
7051  (*i)->lock ();
7052  }
7053  }
7054 
7055  if (moved) {
7056  XMLNode& after (_session->locations()->get_state());
7057  _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7058  }
7059  }
7060 
7061  if (tempo_too) {
7062  _session->tempo_map().insert_time (pos, frames);
7063  }
7064 
7065  if (commit) {
7066  commit_reversible_command ();
7067  }
7068 }
7069 void
7071 {
7072  if (selection->tracks.empty()) {
7073  return;
7074  }
7075 
7076  framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7077  ArdourDialog d (*this, _("Cut Time"));
7078  VButtonBox button_box;
7079  VBox option_box;
7080 
7081  CheckButton glue_button (_("Move Glued Regions")); glue_button.set_active();
7082  CheckButton marker_button (_("Move Markers")); marker_button.set_active();
7083  CheckButton tempo_button (_("Move Tempo & Meters")); tempo_button.set_active();
7084  AudioClock clock ("cutTimeClock", true, "", true, false, true, false);
7085  HBox clock_box;
7086 
7087  clock.set (0);
7088  clock.set_session (_session);
7089  clock.set_bbt_reference (pos);
7090 
7091  clock_box.pack_start (clock, false, true);
7092 
7093  option_box.set_spacing (6);
7094  option_box.pack_start (button_box, false, false);
7095  option_box.pack_start (glue_button, false, false);
7096  option_box.pack_start (marker_button, false, false);
7097  option_box.pack_start (tempo_button, false, false);
7098 
7099  d.get_vbox()->set_border_width (12);
7100  d.get_vbox()->pack_start (clock_box, false, false);
7101  d.get_vbox()->pack_start (option_box, false, false);
7102 
7103  option_box.show ();
7104  button_box.show ();
7105  glue_button.show ();
7106  clock.show_all();
7107  clock_box.show ();
7108  marker_button.show ();
7109  tempo_button.show ();
7110 
7111  d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
7112  d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
7113  d.show ();
7114 
7115  int response = d.run ();
7116 
7117  if (response != RESPONSE_OK) {
7118  return;
7119  }
7120 
7121  framecnt_t distance = clock.current_duration (pos);
7122 
7123  if (distance == 0) {
7124  return;
7125  }
7126 
7127  cut_time (pos, distance, SplitIntersected, glue_button.get_active(), marker_button.get_active(), tempo_button.get_active());
7128 }
7129 
7130 void
7132  bool ignore_music_glue, bool markers_too, bool tempo_too)
7133 {
7134  bool commit = false;
7135 
7136  if (Config->get_edit_mode() == Lock) {
7137  error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7138  return;
7139  }
7140 
7141  begin_reversible_command (_("cut time"));
7142 
7143  for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7144  /* regions */
7145  boost::shared_ptr<Playlist> pl = (*x)->playlist();
7146 
7147  if (pl) {
7148 
7149  XMLNode &before = pl->get_state();
7150 
7151  std::list<AudioRange> rl;
7152  AudioRange ar(pos, pos+frames, 0);
7153  rl.push_back(ar);
7154  pl->cut (rl);
7155  pl->shift (pos, -frames, true, ignore_music_glue);
7156 
7157  XMLNode &after = pl->get_state();
7158 
7159  _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7160  commit = true;
7161  }
7162 
7163  /* automation */
7164  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7165  if (rtav) {
7166  rtav->route ()->shift (pos, -frames);
7167  commit = true;
7168  }
7169  }
7170 
7171  std::list<Location*> loc_kill_list;
7172 
7173  /* markers */
7174  if (markers_too) {
7175  bool moved = false;
7176  XMLNode& before (_session->locations()->get_state());
7177  Locations::LocationList copy (_session->locations()->list());
7178 
7179  for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7180 
7181  if (!(*i)->is_mark()) { //range; have to handle both start and end
7182  if ((*i)->end() >= pos
7183  && (*i)->end() < pos+frames
7184  && (*i)->start() >= pos
7185  && (*i)->end() < pos+frames) { //range is completely enclosed; kill it
7186  moved = true;
7187  loc_kill_list.push_back(*i);
7188  } else { //ony start or end is included, try to do the right thing
7189  if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7190  (*i)->set_end (pos); //bring the end to the cut
7191  moved = true;
7192  } else if ((*i)->end() >= pos) {
7193  (*i)->set_end ((*i)->end()-frames); //slip the end marker back
7194  moved = true;
7195  }
7196  if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7197  (*i)->set_start (pos); //bring the start marker to the beginning of the cut
7198  moved = true;
7199  } else if ((*i)->start() >= pos) {
7200  (*i)->set_start ((*i)->start() -frames); //slip the end marker back
7201  moved = true;
7202  }
7203  }
7204  } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7205  loc_kill_list.push_back(*i);
7206  moved = true;
7207  } else if ((*i)->start() >= pos) {
7208  (*i)->set_start ((*i)->start() -frames);
7209  moved = true;
7210  }
7211  }
7212 
7213  for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7214  _session->locations()->remove( *i );
7215  }
7216 
7217  if (moved) {
7218  XMLNode& after (_session->locations()->get_state());
7219  _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7220  commit = true;
7221  }
7222  }
7223 
7224  if (tempo_too) {
7225  XMLNode& before (_session->tempo_map().get_state());
7226 
7227  if (_session->tempo_map().cut_time (pos, frames) ) {
7228  XMLNode& after (_session->tempo_map().get_state());
7229  _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7230  commit = true;
7231  }
7232  }
7233 
7234  if (commit) {
7235  commit_reversible_command ();
7236  }
7237 }
7238 
7239 void
7241 {
7242  if (!selection->tracks.empty()) {
7243  fit_tracks (selection->tracks);
7244  } else {
7245  TrackViewList tvl;
7246 
7247  /* no selected tracks - use tracks with selected regions */
7248 
7249  if (!selection->regions.empty()) {
7250  for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7251  tvl.push_back (&(*r)->get_time_axis_view ());
7252  }
7253 
7254  if (!tvl.empty()) {
7255  fit_tracks (tvl);
7256  }
7257  } else if (internal_editing()) {
7258  /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7259  the entered track
7260  */
7261  if (entered_track) {
7262  tvl.push_back (entered_track);
7263  fit_tracks (tvl);
7264  }
7265  }
7266  }
7267 
7268 }
7269 
7270 void
7272 {
7273  if (tracks.empty()) {
7274  return;
7275  }
7276 
7277  uint32_t child_heights = 0;
7278  int visible_tracks = 0;
7279 
7280  for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7281 
7282  if (!(*t)->marked_for_display()) {
7283  continue;
7284  }
7285 
7286  child_heights += (*t)->effective_height() - (*t)->current_height();
7287  ++visible_tracks;
7288  }
7289 
7290  /* compute the per-track height from:
7291 
7292  total canvas visible height -
7293  height that will be taken by visible children of selected
7294  tracks - height of the ruler/hscroll area
7295  */
7296  uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7297  double first_y_pos = DBL_MAX;
7298 
7300  MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7301  /* too small to be displayed */
7302  return;
7303  }
7304 
7305  undo_visual_stack.push_back (current_visual_state (true));
7306  PBD::Unwinder<bool> nsv (no_save_visual, true);
7307 
7308  /* build a list of all tracks, including children */
7309 
7310  TrackViewList all;
7311  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7312  all.push_back (*i);
7313  TimeAxisView::Children c = (*i)->get_child_list ();
7314  for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7315  all.push_back (j->get());
7316  }
7317  }
7318 
7319 
7320  // find selection range.
7321  // if someone knows how to user TrackViewList::iterator for this
7322  // I'm all ears.
7323  int selected_top = -1;
7324  int selected_bottom = -1;
7325  int i = 0;
7326  for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7327  if ((*t)->marked_for_display ()) {
7328  if (tracks.contains(*t)) {
7329  if (selected_top == -1) {
7330  selected_top = i;
7331  }
7332  selected_bottom = i;
7333  }
7334  }
7335  }
7336 
7337  i = 0;
7338  for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7339  if ((*t)->marked_for_display ()) {
7340  if (tracks.contains(*t)) {
7341  (*t)->set_height (h);
7342  first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7343  } else {
7344  if (i > selected_top && i < selected_bottom) {
7345  hide_track_in_display (*t);
7346  }
7347  }
7348  }
7349  }
7350 
7351  /*
7352  set the controls_layout height now, because waiting for its size
7353  request signal handler will cause the vertical adjustment setting to fail
7354  */
7355 
7356  controls_layout.property_height () = _full_canvas_height;
7357  vertical_adjustment.set_value (first_y_pos);
7358 
7359  redo_visual_stack.push_back (current_visual_state (true));
7360 
7361  visible_tracks_selector.set_text (_("Sel"));
7362 }
7363 
7364 void
7366 {
7367  while (visual_states.size() <= n) {
7368  visual_states.push_back (0);
7369  }
7370 
7371  if (visual_states[n] != 0) {
7372  delete visual_states[n];
7373  }
7374 
7375  visual_states[n] = current_visual_state (true);
7376  gdk_beep ();
7377 }
7378 
7379 void
7381 {
7382  if (visual_states.size() <= n) {
7383  return;
7384  }
7385 
7386  if (visual_states[n] == 0) {
7387  return;
7388  }
7389 
7390  use_visual_state (*visual_states[n]);
7391 }
7392 
7393 void
7395 {
7396  save_visual_state (n);
7397 
7398  PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7399  char buf[32];
7400  snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7401  pup->set_text (buf);
7402  pup->touch();
7403 }
7404 
7405 void
7407 {
7408  goto_visual_state (n);
7409 }
7410 
7411 void
7413 {
7414  if (_ignore_region_action) {
7415  return;
7416  }
7417 
7418  RegionSelection rs = get_regions_from_selection_and_entered ();
7419 
7420  if (rs.empty ()) {
7421  return;
7422  }
7423 
7424  if (rs.size() > 1) {
7425  begin_reversible_command (_("mute regions"));
7426  } else {
7427  begin_reversible_command (_("mute region"));
7428  }
7429 
7430  for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7431 
7432  (*i)->region()->playlist()->clear_changes ();
7433  (*i)->region()->set_muted (!(*i)->region()->muted ());
7434  _session->add_command (new StatefulDiffCommand ((*i)->region()));
7435 
7436  }
7437 
7438  commit_reversible_command ();
7439 }
7440 
7441 void
7443 {
7444  /* foreach track with selected regions, take all selected regions
7445  and join them into a new region containing the subregions (as a
7446  playlist)
7447  */
7448 
7449  typedef set<RouteTimeAxisView*> RTVS;
7450  RTVS tracks;
7451 
7452  if (selection->regions.empty()) {
7453  return;
7454  }
7455 
7456  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7457  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7458 
7459  if (rtv) {
7460  tracks.insert (rtv);
7461  }
7462  }
7463 
7464  begin_reversible_command (_("combine regions"));
7465 
7466  vector<RegionView*> new_selection;
7467 
7468  for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7469  RegionView* rv;
7470 
7471  if ((rv = (*i)->combine_regions ()) != 0) {
7472  new_selection.push_back (rv);
7473  }
7474  }
7475 
7476  selection->clear_regions ();
7477  for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7478  selection->add (*i);
7479  }
7480 
7481  commit_reversible_command ();
7482 }
7483 
7484 void
7486 {
7487  typedef set<RouteTimeAxisView*> RTVS;
7488  RTVS tracks;
7489 
7490  if (selection->regions.empty()) {
7491  return;
7492  }
7493 
7494  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7495  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7496 
7497  if (rtv) {
7498  tracks.insert (rtv);
7499  }
7500  }
7501 
7502  begin_reversible_command (_("uncombine regions"));
7503 
7504  for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7505  (*i)->uncombine_regions ();
7506  }
7507 
7508  commit_reversible_command ();
7509 }
7510 
7511 void
7513 {
7514  bool onoff = false;
7516 
7517  for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7518  RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7519 
7520  if (!rtav) {
7521  continue;
7522  }
7523 
7525 
7526  if (mt) {
7527  rl->push_back (rtav->route());
7528  onoff = !mt->input_active();
7529  }
7530  }
7531 
7532  _session->set_exclusive_input_active (rl, onoff, flip_others);
7533 }
7534 
7535 void
7537 {
7538  if (!lock_dialog) {
7539  lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7540 
7541  Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7542  lock_dialog->get_vbox()->pack_start (*padlock);
7543 
7544  ArdourButton* b = manage (new ArdourButton);
7545  b->set_name ("lock button");
7546  b->set_text (_("Click to unlock"));
7547  b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7548  lock_dialog->get_vbox()->pack_start (*b);
7549 
7550  lock_dialog->get_vbox()->show_all ();
7551  lock_dialog->set_size_request (200, 200);
7552  }
7553 
7554 #ifdef __APPLE__
7555  /* The global menu bar continues to be accessible to applications
7556  with modal dialogs, which means that we need to desensitize
7557  all items in the menu bar. Since those items are really just
7558  proxies for actions, that means disabling all actions.
7559  */
7561 #endif
7562  lock_dialog->present ();
7563 }
7564 
7565 void
7567 {
7568  lock_dialog->hide ();
7569 
7570 #ifdef __APPLE__
7572 #endif
7573 
7574  if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7575  start_lock_event_timing ();
7576  }
7577 }
7578 
7579 void
7580 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7581 {
7582  Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7583 }
7584 
7585 void
7586 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7587 {
7588  label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7590 }
7591 
7592 void
7594 {
7595  if (!_session) {
7596  return;
7597  }
7598 
7599  Gtk::Label msg;
7600  ArdourDialog w (_("Moving embedded files into session folder"));
7601  w.get_vbox()->pack_start (msg);
7602  w.present ();
7603 
7604  /* flush all pending GUI events because we're about to start copying
7605  * files
7606  */
7607 
7609 
7610  cerr << " Do it\n";
7611 
7612  _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7613 }
float threshold() const
MidiTimeAxisView * midi_view() const
void set_text(std::string)
Definition: popup.cc:121
void transpose_region()
Definition: editor_ops.cc:6137
void set_region_gain_visibility(RegionView *)
Definition: editor_ops.cc:5391
void selected_marker_to_selection_end()
Definition: editor_ops.cc:1246
boost::shared_ptr< ARDOUR::Playlist > playlist() const
void set_record_enabled(bool yn, void *src)
Definition: track.cc:273
void raise_region_to_top()
Definition: editor_ops.cc:2676
LIBPBD_API Transmitter fatal
void ripple(framepos_t at, framecnt_t distance, RegionList *exclude)
Definition: playlist.cc:2812
bool move_tempos() const
bool scroll_up_one_track(bool skip_child_views=false)
Definition: editor_ops.cc:1485
void cut_copy_points(Editing::CutCopyOp, Evoral::Beats earliest=Evoral::Beats(), bool midi=false)
Definition: editor_ops.cc:4138
void set_session_extents_from_selection()
Definition: editor_ops.cc:6079
void show_midi_list_editor()
Definition: editor_ops.cc:2702
void clear_markers()
Definition: editor_ops.cc:2319
Beats round_down_to_beat() const
Definition: Beats.hpp:71
void add_location_mark(framepos_t where)
Definition: editor_ops.cc:2096
void scroll_tracks_up_line()
Definition: editor_ops.cc:1408
TimeAxisView & get_time_axis_view() const
void fit_selection()
Definition: editor_ops.cc:7240
void split_region_at_transients()
Definition: editor_ops.cc:6274
std::multiset< NotePtr, EarlierNoteComparator > Notes
Definition: Sequence.hpp:153
InsertTimeOption
Definition: editing.h:188
void trim_front(framepos_t new_position)
Definition: region.cc:746
void set_session_start_from_playhead()
Definition: editor_ops.cc:2118
void nudge_track(bool use_edit_point, bool forwards)
Definition: editor_ops.cc:4830
boost::shared_ptr< ARDOUR::MidiTrack > midi_track() const
Definition: route_ui.cc:1762
void set(framepos_t, bool force=false, ARDOUR::framecnt_t offset=0)
Definition: audio_clock.cc:956
void jump_backward_to_mark()
Definition: editor_ops.cc:2288
ARDOUR::framepos_t find_next_region_boundary(ARDOUR::framepos_t, int32_t dir, const TrackViewList &)
Definition: editor_ops.cc:844
void copy()
Definition: editor_ops.cc:3990
bool frozen() const
Definition: playlist.h:115
void redo(uint32_t n=1)
Definition: editor_ops.cc:134
sigc::signal< void > signal_clicked
bool can_cut_copy() const
Definition: editor_ops.cc:3998
void sort_by_position_and_track()
void _remove_tracks()
Definition: editor_ops.cc:6816
void cursor_to_previous_region_point(EditorCursor *, ARDOUR::RegionPoint)
Definition: editor_ops.cc:1018
bool all_playlists() const
TimeAxisView * get_parent()
void set_session(ARDOUR::Session *s)
void set_fade_out_length(framecnt_t)
std::list< Location * > LocationList
Definition: location.h:167
Editing::InsertTimeOption intersected_region_action()
void selected_marker_to_next_region_point(ARDOUR::RegionPoint)
Definition: editor_ops.cc:1199
void trim_region(bool front)
Definition: editor_ops.cc:3623
void play_with_preroll()
Definition: editor_ops.cc:2546
void duplicate_some_regions(RegionSelection &, float times)
Definition: editor_ops.cc:4711
LIBARDOUR_API PBD::PropertyDescriptor< layer_t > layer
Definition: region.cc:67
void toggle_record_enable()
Definition: editor_ops.cc:5539
void cursor_align(bool playhead_to_edit)
Definition: editor_ops.cc:1314
void toggle_opaque_region()
Definition: editor_ops.cc:5515
sigc::signal< void, RegionView * > RegionViewAdded
Definition: streamview.h:122
void reset_region_scale_amplitude()
Definition: editor_ops.cc:4979
void new_region_from_selection()
Definition: editor_ops.cc:2927
void set_envelope_active(bool yn)
Definition: audioregion.cc:404
void pitch_shift_region()
Definition: editor_ops.cc:6118
void sequence_regions()
Definition: editor_ops.cc:602
void tav_zoom_smooth(bool coarser, bool force_all)
Definition: editor_ops.cc:1597
void separate_regions_between(const TimeSelection &)
Definition: editor_ops.cc:2984
bool idle_remove_tracks()
Definition: editor_ops.cc:6809
const DataType & data_type() const
Definition: playlist.h:113
void normalize_region()
Definition: editor_ops.cc:4908
virtual void set_height(uint32_t h, TrackHeightMode m=OnlySelf)
void transition_to_rolling(bool forward)
Definition: editor_ops.cc:2444
Definition: ardour_ui.h:130
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
void set_playhead_cursor()
Definition: editor_ops.cc:5914
TrackViewList get_tracks_for_range_action() const
Definition: editor_ops.cc:2952
void clear_locations()
Definition: editor_ops.cc:2351
framepos_t end_frame() const
void cut()
Definition: editor_ops.cc:3983
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
boost::shared_ptr< ARDOUR::AutomationList > the_list() const
XMLNode & state(bool full)
boost::shared_ptr< AutomationList > fade_in()
Definition: audioregion.h:87
void audition_playlist_region_via_route(boost::shared_ptr< ARDOUR::Region >, ARDOUR::Route &)
Definition: editor_ops.cc:2759
void trim_region_to_punch()
Definition: editor_ops.cc:3666
void scroll_tracks_down_line()
Definition: editor_ops.cc:1396
void undo(uint32_t n=1)
Definition: editor_ops.cc:117
void unlock()
Definition: editor_ops.cc:7566
std::vector< boost::shared_ptr< TimeAxisView > > Children
void set_fade_length(bool in)
Definition: editor_ops.cc:5631
void cut_copy_regions(Editing::CutCopyOp, RegionSelection &)
Definition: editor_ops.cc:4384
virtual void clear(bool with_signals=true)
Definition: playlist.cc:1669
void toggle_region_fades(int dir)
Definition: editor_ops.cc:5820
void split_region()
Definition: editor_ops.cc:5939
void align_regions_relative(ARDOUR::RegionPoint point)
Definition: editor_ops.cc:3491
Dialog box to set options for the `strip silence' filter.
XMLNode & get_state()
Definition: playlist.cc:2184
void remove_region(boost::shared_ptr< Region >)
Definition: playlist.cc:789
const SourceList & sources() const
Definition: region.h:261
Always round up, even if on a division.
Definition: types.h:225
void legatize_region(bool shrink_only)
Definition: editor_ops.cc:5201
static void * _freeze_thread(void *)
Definition: editor_ops.cc:3805
void set_punch_from_selection()
Definition: editor_ops.cc:6065
void temporal_zoom(framecnt_t samples_per_pixel)
Definition: editor_ops.cc:1644
boost::shared_ptr< AutomationList > fade_out()
Definition: audioregion.h:89
void quantize_regions(const RegionSelection &rs)
Definition: editor_ops.cc:5179
bool move_locked_markers() const
static int N
Definition: signals_test.cc:27
ARDOUR::framecnt_t fade_length() const
LIBARDOUR_API GQuark region_fill
Definition: operations.cc:32
size_t n_midi_regions() const
tuple f
Definition: signals.py:35
void toggle_region_video_lock()
Definition: editor_ops.cc:5466
void remove_location_at_playhead_cursor()
Definition: editor_ops.cc:2172
framepos_t end() const
Definition: location.h:72
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
void touch()
Definition: popup.cc:94
void fork_region()
Definition: editor_ops.cc:5131
void toggle_region_mute()
Definition: editor_ops.cc:7412
void clear_owned_changes()
Definition: playlist.cc:2054
void align_region_internal(boost::shared_ptr< ARDOUR::Region >, ARDOUR::RegionPoint point, framepos_t position)
Definition: editor_ops.cc:3587
void cursor_to_region_point(EditorCursor *, ARDOUR::RegionPoint, int32_t dir)
Definition: editor_ops.cc:944
LIBARDOUR_API GQuark paste
Definition: operations.cc:25
void play_from_start()
Definition: editor_ops.cc:2469
ARDOUR::InstrumentInfo & instrument_info() const
void delete_()
Definition: editor_ops.cc:3969
boost::shared_ptr< MidiRegion > clone(std::string path=std::string()) const
LIBARDOUR_API GQuark duplicate_region
Definition: operations.cc:26
void add_locations_from_region()
Definition: editor_ops.cc:2204
const AutomationTracks & automation_tracks() const
virtual void step_height(bool)
void selected_marker_to_selection_start()
Definition: editor_ops.cc:1211
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
void insert_region_list_selection(float times)
Definition: editor_ops.cc:2388
const AutomationLine * line
line this came from
Definition: editor_ops.cc:4130
void temporal_zoom_step(bool coarser)
Definition: editor_ops.cc:1628
#define P_(Singular, Plural, HowMany)
Definition: i18n.h:41
StreamView * view() const
boost::shared_ptr< ARDOUR::AudioRegion > audio_region() const
void quantize_region()
Definition: editor_ops.cc:5171
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
int move_to(framepos_t pos)
Definition: location.cc:415
void insert_time(framepos_t, framecnt_t, Editing::InsertTimeOption, bool, bool, bool, bool, bool, bool)
Definition: editor_ops.cc:6956
void audition_playlist_region_standalone(boost::shared_ptr< ARDOUR::Region >)
Definition: editor_ops.cc:2813
bool get_selection_extents(framepos_t &start, framepos_t &end)
Definition: editor_ops.cc:1852
uint32_t current_height() const
LIBPBD_API void strip_whitespace_edges(std::string &str)
void trim_region_back()
Definition: editor_ops.cc:3617
void by_position(std::list< RegionView * > &) const
bool snap_end() const
bool is_hidden() const
Definition: location.h:95
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
void cut_time(framepos_t pos, framecnt_t distance, Editing::InsertTimeOption opt, bool ignore_music_glue, bool markers_too, bool tempo_too)
Definition: editor_ops.cc:7131
double start_grid_size() const
ARDOUR::Transform::Program get()
void cursor_to_previous_region_boundary(bool with_selection)
Definition: editor_ops.cc:938
#define invalidator(x)
Definition: gui_thread.h:40
bool fade_in_active() const
Definition: audioregion.h:84
void selected_marker_to_region_point(ARDOUR::RegionPoint, int32_t dir)
Definition: editor_ops.cc:1134
void thaw(bool from_undo=false)
Definition: playlist.cc:422
void remove_transient(float pos)
void external_edit_region()
Definition: editor_ops.cc:5360
framepos_t sync_position() const
Definition: region.cc:1082
void trim_region_front()
Definition: editor_ops.cc:3611
void set_initial_text(std::string txt)
Definition: prompter.h:50
void cut_copy_ranges(Editing::CutCopyOp)
Definition: editor_ops.cc:4555
bool empty(bool internal_selection=false)
Definition: selection.cc:938
static float accurate_coefficient_to_dB(float coeff)
Definition: dB.h:38
static UI * instance()
Definition: gtk_ui.h:119
void cut_copy_clear(Editing::CutCopyOp)
std::map< boost::shared_ptr< ARDOUR::Region >, AudioIntervalResult > AudioIntervalMap
Definition: types.h:85
void selected_marker_to_previous_region_boundary(bool with_selection)
Definition: editor_ops.cc:1128
static Handle create(Editor &editor, Gdk::Cursor *cursor)
void update_bring_in_message(Gtk::Label *label, uint32_t n, uint32_t total, std::string name)
Definition: editor_ops.cc:7586
void region_changed(const PBD::PropertyChange &)
void raise_to_top()
Definition: region.cc:1112
void nudge_forward_capture_offset()
Definition: editor_ops.cc:543
void trim_region_to_location(const ARDOUR::Location &, const char *cmd)
Definition: editor_ops.cc:3676
void selected_marker_to_region_boundary(bool with_selection, int32_t dir)
Definition: editor_ops.cc:1082
static void add_if_covered(RegionView *rv, const AudioRange *ar, RegionSelection *rs)
Definition: editor_ops.cc:2934
void nudge_backward(bool next, bool force_playhead)
Definition: editor_ops.cc:449
void set_fade_out_shape(FadeShape)
Definition: audioregion.cc:995
Selection selection() const
void set_track_height(Height)
Definition: editor_ops.cc:6765
void edit_envelope()
Definition: editor_ops.cc:2437
void maybe_locate_with_edit_preroll(framepos_t)
Definition: editor_ops.cc:2526
void set_punch_from_region()
Definition: editor_ops.cc:6108
LIBGTKMM2EXT_API void disable_all_actions()
Definition: actions.cc:349
#define _(Text)
Definition: i18n.h:11
void center_playhead()
Definition: editor_ops.cc:4807
void trim_end(framepos_t new_position)
Definition: region.cc:836
bool soloed() const
Definition: route.h:158
void toggle_region_lock_style()
Definition: editor_ops.cc:5490
void bounce_range_selection(bool replace, bool enable_processing)
Definition: editor_ops.cc:3886
void duplicate_selection(float times)
Definition: editor_ops.cc:4751
ArdourCanvas::PolyLine * line
boost::shared_ptr< ARDOUR::Route > _route
Definition: route_ui.h:87
boost::shared_ptr< AutomationList > envelope()
Definition: audioregion.h:91
LIBGTKMM2EXT_API uint64_t Keyboard
Definition: debug.cc:23
framepos_t current_frame() const
void set_fade_in_shape(ARDOUR::FadeShape)
Definition: editor_ops.cc:5702
void add_region(boost::shared_ptr< Region >, framepos_t position, float times=1, bool auto_partition=false)
Definition: playlist.cc:668
void foreach_regionview(sigc::slot< void, RegionView * > slot)
Definition: streamview.cc:506
A filter to strip silence from regions.
Definition: strip_silence.h:25
void combine_regions()
Definition: editor_ops.cc:7442
#define X_(Text)
Definition: i18n.h:13
void temporal_zoom_region(bool both_axes)
Definition: editor_ops.cc:1805
void bring_all_sources_into_session()
Definition: editor_ops.cc:7593
int64_t framecnt_t
Definition: types.h:76
void cut_copy(Editing::CutCopyOp)
Definition: editor_ops.cc:4011
uint32_t order_key() const
Definition: route.cc:306
void partition(framepos_t start, framepos_t end, bool cut=false)
Definition: playlist.cc:871
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
void move_to_end()
Definition: editor_ops.cc:658
void set_position(framepos_t)
Definition: region.cc:579
void cursor_to_selection_end(EditorCursor *)
Definition: editor_ops.cc:1053
int set(framepos_t start, framepos_t end, bool allow_bbt_recompute=true)
Definition: location.cc:321
void center_edit_point()
Definition: editor_ops.cc:4814
bool move_glued_markers() const
double maximum_amplitude(Progress *p=0) const
void raise_region()
Definition: editor_ops.cc:2670
void define_one_bar(framepos_t start, framepos_t end)
Definition: editor_ops.cc:6184
const std::list< RegionView * > & by_layer() const
void clear_ranges()
Definition: editor_ops.cc:2334
void set_fade_out_active(bool)
Definition: editor_ops.cc:5792
boost::shared_ptr< ARDOUR::Region > region() const
Definition: region_view.h:66
void set_prompt(std::string prompt)
Definition: prompter.h:46
void show_region_properties()
Definition: editor_ops.cc:2695
void set_position(framepos_t)
void rename_region()
Definition: editor_ops.cc:2708
bool snap_start() const
std::list< framepos_t > AnalysisFeatureList
Definition: types.h:530
void replace_region(boost::shared_ptr< Region > old, boost::shared_ptr< Region > newr, framepos_t pos)
Definition: playlist.cc:772
PlaylistMapping(TimeAxisView *tvp)
Definition: editor_ops.cc:4275
void flush_pending()
Definition: gtk_ui.cc:681
void region_from_selection()
Definition: editor_ops.cc:2819
framepos_t get_preroll()
Definition: editor_ops.cc:2519
boost::shared_ptr< Region > top_region_at(framepos_t frame)
Definition: playlist.cc:1727
void play_from_edit_point()
Definition: editor_ops.cc:2475
void reverse_region()
Definition: editor_ops.cc:5041
void move_range_selection_start_or_end_to_region_boundary(bool, bool)
Definition: editor_ops.cc:306
const boost::shared_ptr< ARDOUR::MidiRegion > midi_region() const
void selection_as_notelist(Notes &selected, bool allow_all_if_none_selected=false)
void remove_clicked_region()
Definition: editor_ops.cc:4280
void region_fill_selection()
Definition: editor_ops.cc:3339
bool fade_out_active() const
Definition: audioregion.h:85
void do_cut_time()
Definition: editor_ops.cc:7070
LIBARDOUR_API GQuark fill_selection
Definition: operations.cc:33
boost::shared_ptr< Delivery > main_outs() const
Definition: route.h:237
Round down only if necessary.
Definition: types.h:222
void shift(framepos_t, framecnt_t)
Definition: route.cc:3794
Definition: amp.h:29
void scroll_tracks_down()
Definition: editor_ops.cc:1379
void toggle_solo_isolate()
Definition: editor_ops.cc:5610
void unfreeze_route()
Definition: editor_ops.cc:3795
void remove_region_sync()
Definition: editor_ops.cc:3420
void nudge_backward_capture_offset()
Definition: editor_ops.cc:567
Height
Definition: enums.h:47
void select_prev_route()
Definition: editor_ops.cc:6001
void set_solo(bool yn, void *src)
Definition: route.cc:810
virtual boost::shared_ptr< ControlList > create(const Parameter &id, const ParameterDescriptor &desc)
void set_fade_in_length(framecnt_t)
void cursor_to_region_boundary(bool with_selection, int32_t dir)
Definition: editor_ops.cc:910
gain_t scale_amplitude() const
Definition: audioregion.h:78
void temporal_zoom_to_frame(bool coarser, framepos_t frame)
Definition: editor_ops.cc:1979
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
void legatize_regions(const RegionSelection &rs, bool shrink_only)
Definition: editor_ops.cc:5209
AutomationRecord(XMLNode *s, const AutomationLine *l)
Definition: editor_ops.cc:4127
void scroll_forward(float pages=0.8f)
Definition: editor_ops.cc:1363
void split_multichannel_region()
Definition: editor_ops.cc:2911
void split_region_at_points(boost::shared_ptr< ARDOUR::Region >, ARDOUR::AnalysisFeatureList &, bool can_ferret, bool select_new=false)
Definition: editor_ops.cc:6308
XMLNode * state
state before any operation
Definition: editor_ops.cc:4129
void goto_visual_state(uint32_t)
Definition: editor_ops.cc:7380
void reset_region_gain_envelopes()
Definition: editor_ops.cc:5366
void close_region_gaps()
Definition: editor_ops.cc:6555
Evoral::OverlapType coverage(framepos_t start, framepos_t end) const
Definition: region.h:195
bool nudge_backward_release(GdkEventButton *)
Definition: editor_ops.cc:356
framepos_t get_region_boundary(framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
Definition: editor_ops.cc:875
void paste_internal(framepos_t position, float times)
Definition: editor_ops.cc:4602
LIBGTKMM2EXT_API Gtk::Label * left_aligned_label(std::string const &)
boost::shared_ptr< Playlist > playlist()
Definition: track.cc:590
void lower_region()
Definition: editor_ops.cc:2682
void scroll_tracks_up()
Definition: editor_ops.cc:1390
boost::shared_ptr< ARDOUR::Region > find_next_region(ARDOUR::framepos_t, ARDOUR::RegionPoint, int32_t dir, TrackViewList &, TimeAxisView **=0)
Definition: editor_ops.cc:781
XMLNode & get_state(void)
Definition: location.cc:566
void * freeze_thread()
Definition: editor_ops.cc:3811
double end_grid_size() const
void save_visual_state(uint32_t)
Definition: editor_ops.cc:7365
static Beats max()
Definition: Beats.hpp:195
void calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
Definition: editor_ops.cc:1774
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
int get_transients(AnalysisFeatureList &, bool force_new=false)
void set_fade_out_active(bool yn)
bool record_enabled() const
Definition: track.cc:215
void selected_marker_to_previous_region_point(ARDOUR::RegionPoint)
Definition: editor_ops.cc:1205
void play_selected_region()
Definition: editor_ops.cc:2789
gint really_remove_marker(ARDOUR::Location *loc)
int64_t framepos_t
Definition: types.h:66
bool hidden() const
void duplicate(boost::shared_ptr< Region >, framepos_t position, float times)
Definition: playlist.cc:1246
void fit_tracks(TrackViewList &)
Definition: editor_ops.cc:7271
RegionSelectionAfterSplit
Definition: types.h:358
void crop_region_to_selection()
Definition: editor_ops.cc:3210
void region_fill_track()
Definition: editor_ops.cc:3302
float strength() const
framepos_t distance() const
FadeShape
Definition: types.h:592
virtual void show_region_editor()
Definition: region_view.cc:547
TrackViewList filter_to_unique_playlists()
void erase(iterator)
void fade_range()
Definition: editor_ops.cc:5616
bool move_glued() const
LIBARDOUR_API PBD::PropertyDescriptor< bool > regions
Definition: playlist.cc:51
T * get() const
Definition: shared_ptr.hpp:268
void raise()
Definition: region.cc:1093
LayerOperation
Definition: editor.h:1209
void separate_region_from_punch()
Definition: editor_ops.cc:3101
framepos_t adjust_to_sync(framepos_t) const
Definition: region.cc:1058
void toggle_solo()
Definition: editor_ops.cc:5560
void set_edit_point()
Definition: editor_ops.cc:5887
void lower_region_to_bottom()
Definition: editor_ops.cc:2688
void set_mark()
Definition: editor_ops.cc:2304
void get_result(std::string &str, bool strip=true)
Definition: prompter.cc:104
void set_fade_in_shape(FadeShape)
Definition: audioregion.cc:989
bool is_mark() const
Definition: location.h:94
void set_fade_in_active(bool yn)
bool is_track() const
Definition: route_ui.cc:1732
static MixerStrip * entered_mixer_strip()
Definition: mixer_strip.h:137
void loop_location(ARDOUR::Location &)
Definition: editor_ops.cc:2579
CutCopyOp
Definition: editing.h:198
void tav_zoom_step(bool coarser)
Definition: editor_ops.cc:1578
framepos_t position() const
Definition: region.h:112
void strip_region_silence()
Definition: editor_ops.cc:5052
void call_slot(EventLoop::InvalidationRecord *, const boost::function< void()> &)
Definition: abstract_ui.cc:368
void do_insert_time()
Definition: editor_ops.cc:6923
int semitones() const
void separate_under_selected_regions()
Definition: editor_ops.cc:3135
void unhide_markers()
Definition: editor_ops.cc:2364
virtual bool bounceable(boost::shared_ptr< Processor > endpoint, bool include_endpoint) const =0
void set_region_sync_position()
Definition: editor_ops.cc:3385
void toggle_mute()
Definition: editor_ops.cc:5585
void jump_forward_to_mark()
Definition: editor_ops.cc:2272
void snap_regions_to_grid()
Definition: editor_ops.cc:6516
int set_start(framepos_t s, bool force=false, bool allow_bbt_recompute=true)
Definition: location.cc:181
void lower()
Definition: region.cc:1102
bool active() const
Definition: route.h:95
std::vector< boost::shared_ptr< ARDOUR::Region > > results
Definition: filter.h:41
bool muted() const
Definition: route.cc:1031
framepos_t start
Definition: types.h:289
void trim_to(framepos_t position, framecnt_t length)
Definition: region.cc:842
void cursor_to_selection_start(EditorCursor *)
Definition: editor_ops.cc:1024
void bring_in_callback(Gtk::Label *, uint32_t n, uint32_t total, std::string name)
Definition: editor_ops.cc:7580
void play_location(ARDOUR::Location &)
Definition: editor_ops.cc:2569
void add_location_from_playhead_cursor()
Definition: editor_ops.cc:2166
void cut_copy_midi(Editing::CutCopyOp)
Definition: editor_ops.cc:4241
void set_gain_envelope_visibility()
Definition: editor_ops.cc:5400
boost::shared_ptr< Playlist > playlist
Definition: editor_ops.cc:3064
void uncombine_regions()
Definition: editor_ops.cc:7485
void create_region_from_selection(std::vector< boost::shared_ptr< ARDOUR::Region > > &)
Definition: editor_ops.cc:2865
XMLNode * before
Definition: editor_ops.cc:3065
AudioStreamView * audio_view()
void remove_last_capture()
Definition: editor_ops.cc:4878
void align_region(boost::shared_ptr< ARDOUR::Region >, ARDOUR::RegionPoint point, framepos_t position)
Definition: editor_ops.cc:3579
void add_location_from_selection()
Definition: editor_ops.cc:2067
framepos_t start() const
virtual std::string name() const =0
const char * name
void insert_patch_change(bool from_context)
Definition: editor_ops.cc:5247
void add_location_from_region()
Definition: editor_ops.cc:2233
void apply_midi_note_edit_op(ARDOUR::MidiOperator &op, const RegionSelection &rs)
Definition: editor_ops.cc:5102
boost::shared_ptr< ControlList > copy(double, double)
void trim_region_to_previous_region_end()
Definition: editor_ops.cc:3718
void set_active(bool yn, void *)
Definition: route.cc:4002
bool scroll_down_one_track(bool skip_child_views=false)
Definition: editor_ops.cc:1414
static ARDOUR::framepos_t track_frame_to_session_frame(ARDOUR::framepos_t track_frame, double speed)
Definition: types.h:694
void unhide_ranges()
Definition: editor_ops.cc:2375
void set_sync_point(framepos_t, const RegionSelection &)
Definition: editor_ops.cc:3391
Definition: editor.h:134
void toggle_tracks_active()
Definition: editor_ops.cc:6775
void set_fade_out_shape(ARDOUR::FadeShape)
Definition: editor_ops.cc:5733
void naturalize_region()
Definition: editor_ops.cc:3441
static ARDOUR::framepos_t session_frame_to_track_frame(ARDOUR::framepos_t session_frame, double speed)
Definition: types.h:688
bool is_master() const
Definition: route.h:111
void use_range_as_bar()
Definition: editor_ops.cc:6175
Definition: xml++.h:95
void remove_transient(ArdourCanvas::Item *item)
Definition: editor_ops.cc:6502
std::string name() const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
uint64_t CutNPaste
Definition: debug.cc:29
static UIConfiguration * config()
Definition: ardour_ui.h:188
void nudge_after(framepos_t start, framecnt_t distance, bool forwards)
Definition: playlist.cc:2531
void set_loop_from_selection(bool play)
Definition: editor_ops.cc:6032
void toggle_gain_envelope_active()
Definition: editor_ops.cc:5415
void set_text(const std::string &)
void toggle_region_lock()
Definition: editor_ops.cc:5442
void remove_selected_regions()
Definition: editor_ops.cc:4310
float swing() const
void rdiff(std::vector< Command * > &) const
Definition: playlist.cc:2047
void set_bbt_reference(framepos_t)
void transform_region()
Definition: editor_ops.cc:5220
void remove_tracks()
Definition: editor_ops.cc:6799
void playhead_backward_to_grid()
Definition: editor_ops.cc:6750
void set_scale_amplitude(gain_t)
void split_region(boost::shared_ptr< Region >, framepos_t position)
Definition: playlist.cc:1334
bool input_active() const
Definition: midi_track.cc:820
Definition: debug.h:30
void adjust_region_gain(bool up)
Definition: editor_ops.cc:5006
framecnt_t length() const
Definition: location.h:73
virtual boost::shared_ptr< Region > bounce_range(framepos_t start, framepos_t end, InterThreadInfo &, boost::shared_ptr< Processor > endpoint, bool include_endpoint)=0
double divisions_per_bar() const
Definition: tempo.h:70
double to_double() const
Definition: Beats.hpp:185
void toggle_midi_input_active(bool flip_others)
Definition: editor_ops.cc:7512
void place_transient()
Definition: editor_ops.cc:6477
void trim_region_to_next_region_start()
Definition: editor_ops.cc:3724
void select_next_route()
Definition: editor_ops.cc:5969
bool contains(TimeAxisView const *) const
bool choose_new_marker_name(std::string &name)
Definition: editor_ops.cc:2031
static float dB_to_coefficient(float dB)
Definition: dB.h:30
framepos_t current_duration(framepos_t position=0) const
void freeze_route()
Definition: editor_ops.cc:3822
void temporal_zoom_by_frame(framepos_t start, framepos_t end)
Definition: editor_ops.cc:1951
void reset_point_selection()
Definition: editor_ops.cc:4798
void set_fade_in_active(bool)
Definition: editor_ops.cc:5763
bool nudge_forward_release(GdkEventButton *)
Definition: editor_ops.cc:345
LIBGTKMM2EXT_API void pop_action_state()
Definition: actions.cc:333
LIBEVORAL_API uint64_t Beats
void temporal_zoom_session()
Definition: editor_ops.cc:1920
framepos_t start() const
Definition: location.h:71
void paste(float times, bool from_context_menu=false)
Definition: editor_ops.cc:4580
std::map< Evoral::Parameter, boost::shared_ptr< AutomationTimeAxisView > > AutomationTracks
void crop_region_to(framepos_t start, framepos_t end)
Definition: editor_ops.cc:3229
void trim_to_region(bool forward)
Definition: editor_ops.cc:3730
framecnt_t length() const
Definition: region.h:114
framepos_t end
Definition: types.h:290
static const framepos_t max_framepos
Definition: types.h:78
PositionLockStyle
Definition: types.h:553
void split_regions_at(framepos_t, RegionSelection &)
Definition: editor_ops.cc:151
bool is_range_marker() const
Definition: location.h:98
framepos_t first_frame() const
Definition: region.h:141
void lower_to_bottom()
Definition: region.cc:1121
boost::shared_ptr< Playlist > pl
Definition: editor_ops.cc:4273
void move_to_start()
Definition: editor_ops.cc:652
framepos_t start() const
Definition: region.h:113
static uint32_t preset_height(Height)
void mouse_paste()
Definition: editor_ops.cc:4588
bool destructive() const
Definition: track.cc:608
void separate_region_from_selection()
Definition: editor_ops.cc:3073
void silences(ARDOUR::AudioIntervalMap &)
void nudge_forward(bool next, bool force_playhead)
Definition: editor_ops.cc:368
void play_selection()
Definition: editor_ops.cc:2505
void play_from_edit_point_and_return()
Definition: editor_ops.cc:2481
void cursor_to_next_region_boundary(bool with_selection)
Definition: editor_ops.cc:932
void descend(float)
Definition: progress.cc:41
void collect_new_region_view(RegionView *)
void apply_filter(ARDOUR::Filter &, std::string cmd, ProgressReporter *progress=0)
Definition: editor_ops.cc:5281
int apply(Filter &, Progress *progress=0)
Definition: region.cc:1601
void build_region_boundary_cache()
Definition: editor_ops.cc:665
void set_tempo_from_region()
Definition: editor_ops.cc:6161
Glib::RefPtr< Gdk::Pixbuf > get_icon(const char *cname)
Definition: utils.cc:674
void selected_marker_to_next_region_boundary(bool with_selection)
Definition: editor_ops.cc:1122
void normalize(float, float target_in_dB=0.0f)
RegionPoint
Definition: types.h:369
std::list< boost::shared_ptr< Route > > RouteList
Definition: types.h:532
void separate_regions_using_location(ARDOUR::Location &)
Definition: editor_ops.cc:3119
TimeAxisView * tv
Definition: editor_ops.cc:4272
boost::shared_ptr< Playlist > cut(std::list< AudioRange > &, bool result_is_hidden=true)
Definition: playlist.cc:1157
int64_t framepos_t
void playhead_forward_to_grid()
Definition: editor_ops.cc:6734
bool move_markers() const
void set_loop_from_region(bool play)
Definition: editor_ops.cc:6050
void clear_changes()
Definition: stateful.cc:184
void shift(framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
Definition: playlist.cc:1281
LIBPBD_API int pthread_create_and_store(std::string name, pthread_t *thread, void *(*start_routine)(void *), void *arg)
void clear_playlist(boost::shared_ptr< ARDOUR::Playlist >)
Definition: editor_ops.cc:4822
void tab_to_transient(bool forward)
Definition: editor_ops.cc:6654
void update_region_fade_visibility()
Definition: editor_ops.cc:5870
void separate_region_from_loop()
Definition: editor_ops.cc:3110
void do_layer_operation(LayerOperation)
Definition: editor_ops.cc:2597
void set_hidden(bool yn, void *src)
Definition: location.cc:441
bool add(PropertyBase *prop)
boost::shared_ptr< ARDOUR::Route > route() const
Definition: route_ui.h:76
boost::shared_ptr< MidiModel > model()
Definition: midi_region.cc:378
void trim_region_to_loop()
Definition: editor_ops.cc:3656
Always round down, even if on a division.
Definition: types.h:223
void cursor_to_next_region_point(EditorCursor *, ARDOUR::RegionPoint)
Definition: editor_ops.cc:1012
void play_edit_range()
Definition: editor_ops.cc:2779
framepos_t find_next_region_boundary(framepos_t pos, int32_t dir)
void scroll_backward(float pages=0.8f)
Definition: editor_ops.cc:1347
EventList::iterator iterator
Definition: ControlList.hpp:82
int order() const
LIBARDOUR_API PBD::PropertyChange bounds_change
Definition: globals.cc:150
void lock()
Definition: editor_ops.cc:7536
int set_end(framepos_t e, bool force=false, bool allow_bbt_recompute=true)
Definition: location.cc:258
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void cancel_visual_state_op(uint32_t n)
Definition: editor_ops.cc:7406
void transform_regions(const RegionSelection &rs)
Definition: editor_ops.cc:5228
framepos_t find_next_transient(framepos_t position, int dir)
Definition: playlist.cc:1845
void add_patch_change(framecnt_t, Evoral::PatchChange< Evoral::Beats > const &)
boost::shared_ptr< ARDOUR::Playlist > playlist() const
Definition: region.h:251
void temporal_zoom_selection(bool both_axes=false)
Definition: editor_ops.cc:1892
void align_regions(ARDOUR::RegionPoint)
Definition: editor_ops.cc:3465
void scroll_playhead(bool forward)
Definition: editor_ops.cc:1281
bool is_monitor() const
Definition: route.h:112
boost::shared_ptr< Evoral::ControlList > copy
copied events for the cut buffer
Definition: editor_ops.cc:4131
framepos_t last_frame() const
Definition: region.h:142
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
double speed() const
Definition: track.cc:759
Command * apply_midi_note_edit_op_to_region(ARDOUR::MidiOperator &op, MidiRegionView &mrv)
Definition: editor_ops.cc:5087
void start_visual_state_op(uint32_t n)
Definition: editor_ops.cc:7394
void reverse_selection()
Definition: editor_ops.cc:2429
void set_session_end_from_playhead()
Definition: editor_ops.cc:2142
bool envelope_active() const
Definition: audioregion.h:83