#include "item_counts.h"
#include "keyboard.h"
#include "midi_region_view.h"
+#include "mixer_ui.h"
#include "mixer_strip.h"
#include "mouse_cursors.h"
#include "normalize_dialog.h"
#include "transform_dialog.h"
#include "ui_config.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
using namespace std;
using namespace ARDOUR;
void
Editor::undo (uint32_t n)
{
+ if (_session && _session->actively_recording()) {
+ /* no undo allowed while recording. Session will check also,
+ but we don't even want to get to that.
+ */
+ return;
+ }
+
if (_drags->active ()) {
_drags->abort ();
}
void
Editor::redo (uint32_t n)
{
+ if (_session && _session->actively_recording()) {
+ /* no redo allowed while recording. Session will check also,
+ but we don't even want to get to that.
+ */
+ return;
+ }
+
if (_drags->active ()) {
_drags->abort ();
}
if (_session) {
- _session->redo (n);
+ _session->redo (n);
if (_session->redo_depth() == 0) {
redo_action->set_sensitive(false);
}
}
void
-Editor::split_regions_at (framepos_t where, RegionSelection& regions)
+Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t sub_num,
+ bool snap_frame)
{
bool frozen = false;
case SnapToRegionEnd:
break;
default:
- snap_to (where);
+ if (snap_frame) {
+ snap_to (where);
+ }
}
} else {
- snap_to (where);
+ if (snap_frame) {
+ snap_to (where);
+ }
frozen = true;
EditorFreeze(); /* Emit Signal */
if (pl) {
pl->clear_changes ();
- pl->split_region ((*a)->region(), where);
+ pl->split_region ((*a)->region(), where, sub_num);
_session->add_command (new StatefulDiffCommand (pl));
}
if (working_on_selection) {
// IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
- _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
/* There are three classes of regions that we might want selected after
splitting selected regions:
}
}
}
- _ignore_follow_edits = false;
} else {
- _ignore_follow_edits = true;
if( working_on_selection ) {
selection->add (latest_regionviews); //these are the new regions created after the split
}
- _ignore_follow_edits = false;
}
commit_reversible_command ();
bool is_start;
bool in_command = false;
+ const int32_t divisions = get_grid_music_divisions (0);
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
distance = next_distance;
}
if (max_framepos - distance > loc->start() + loc->length()) {
- loc->set_start (loc->start() + distance);
+ loc->set_start (loc->start() + distance, false, true, divisions);
} else {
- loc->set_start (max_framepos - loc->length());
+ loc->set_start (max_framepos - loc->length(), false, true, divisions);
}
} else {
distance = get_nudge_distance (loc->end(), next_distance);
distance = next_distance;
}
if (max_framepos - distance > loc->end()) {
- loc->set_end (loc->end() + distance);
+ loc->set_end (loc->end() + distance, false, true, divisions);
} else {
- loc->set_end (max_framepos);
+ loc->set_end (max_framepos, false, true, divisions);
+ }
+ if (loc->is_session_range()) {
+ _session->set_end_is_free (false);
}
}
if (!in_command) {
distance = next_distance;
}
if (distance < loc->start()) {
- loc->set_start (loc->start() - distance);
+ loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
} else {
- loc->set_start (0);
+ loc->set_start (0, false, true, get_grid_music_divisions(0));
}
} else {
distance = get_nudge_distance (loc->end(), next_distance);
}
if (distance < loc->end() - loc->length()) {
- loc->set_end (loc->end() - distance);
+ loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
} else {
- loc->set_end (loc->length());
+ loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
+ }
+ if (loc->is_session_range()) {
+ _session->set_end_is_free (false);
}
}
if (!in_command) {
return;
}
- loc->move_to (target);
+ loc->move_to (target, 0);
}
void
pos = track_frame_to_session_frame(pos, speed);
- loc->move_to (pos);
+ loc->move_to (pos, 0);
}
void
return;
}
- loc->move_to (pos);
+ loc->move_to (pos, 0);
}
void
return;
}
- loc->move_to (pos);
+ loc->move_to (pos, 0);
}
void
_session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
} else {
+ const int32_t divisions = get_grid_music_divisions (0);
/* move selected markers to playhead */
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
Location* loc = find_location_from_marker (*i, ignored);
if (loc->is_mark()) {
- loc->set_start (playhead_cursor->current_frame ());
+ loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
} else {
loc->set (playhead_cursor->current_frame (),
- playhead_cursor->current_frame () + loc->length());
+ playhead_cursor->current_frame () + loc->length(), true, divisions);
}
}
}
}
void
-Editor::temporal_zoom_step_mouse_focus (bool coarser)
+Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
{
Editing::ZoomFocus temp_focus = zoom_focus;
zoom_focus = Editing::ZoomFocusMouse;
- temporal_zoom_step (coarser);
+ temporal_zoom_step_scale (zoom_out, scale);
zoom_focus = temp_focus;
}
void
-Editor::temporal_zoom_step (bool coarser)
+Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
{
- ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
+ temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
+}
+
+void
+Editor::temporal_zoom_step (bool zoom_out)
+{
+ temporal_zoom_step_scale (zoom_out, 2.0);
+}
+
+void
+Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
+{
+ ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
framecnt_t nspp = samples_per_pixel;
- if (coarser) {
- nspp *= 2;
+ if (zoom_out) {
+ nspp *= scale;
+ if (nspp == samples_per_pixel) {
+ nspp *= 2.0;
+ }
} else {
- nspp /= 2;
+ nspp /= scale;
+ if (nspp == samples_per_pixel) {
+ nspp /= 2.0;
+ }
}
temporal_zoom (nspp);
framepos_t leftmost_after_zoom = 0;
framepos_t where;
bool in_track_canvas;
+ bool use_mouse_frame = true;
framecnt_t nfpp;
double l;
case ZoomFocusMouse:
/* try to keep the mouse over the same point in the display */
- if (!mouse_frame (where, in_track_canvas)) {
- /* use playhead instead */
- where = playhead_cursor->current_frame ();
-
- if (where < half_page_size) {
- leftmost_after_zoom = 0;
- } else {
- leftmost_after_zoom = where - half_page_size;
- }
-
- } else {
+ if (_drags->active()) {
+ where = _drags->current_pointer_frame ();
+ } else if (!mouse_frame (where, in_track_canvas)) {
+ use_mouse_frame = false;
+ }
+ if (use_mouse_frame) {
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
if (l < 0) {
} else {
leftmost_after_zoom = (framepos_t) l;
}
- }
+ } else {
+ /* use playhead instead */
+ where = playhead_cursor->current_frame ();
+ if (where < half_page_size) {
+ leftmost_after_zoom = 0;
+ } else {
+ leftmost_after_zoom = where - half_page_size;
+ }
+ }
break;
case ZoomFocusEdit:
}
}
-void
-Editor::temporal_zoom_region (bool both_axes)
-{
- framepos_t start = max_framepos;
- framepos_t end = 0;
- set<TimeAxisView*> tracks;
-
- if ( !get_selection_extents(start, end) )
- return;
-
- calc_extra_zoom_edges (start, end);
-
- /* if we're zooming on both axes we need to save track heights etc.
- */
-
- undo_visual_stack.push_back (current_visual_state (both_axes));
-
- PBD::Unwinder<bool> nsv (no_save_visual, true);
-
- temporal_zoom_by_frame (start, end);
-
- if (both_axes) {
- uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
-
- /* set visible track heights appropriately */
-
- for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
- (*t)->set_height (per_track_height);
- }
-
- /* hide irrelevant tracks */
-
- DisplaySuspender ds;
-
- for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
- if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
- hide_track_in_display (*i);
- }
- }
-
- vertical_adjustment.set_value (0.0);
- }
-
- redo_visual_stack.push_back (current_visual_state (both_axes));
-}
-
-
bool
Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
{
void
-Editor::temporal_zoom_selection (bool both_axes)
+Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
{
if (!selection) return;
//ToDo: if control points are selected, zoom to that
- //if region(s) are selected, zoom to that
- if ( !selection->regions.empty() )
- temporal_zoom_region (both_axes);
-
- //if a range is selected, zoom to that
- if (!selection->time.empty()) {
+ if (axes == Horizontal || axes == Both) {
- framepos_t start, end;
+ framepos_t start, end;
if (get_selection_extents (start, end)) {
- calc_extra_zoom_edges(start, end);
+ calc_extra_zoom_edges (start, end);
temporal_zoom_by_frame (start, end);
}
-
- if (both_axes)
- fit_selection();
}
+ if (axes == Vertical || axes == Both) {
+ fit_selection ();
+ }
}
void
framepos_t end = selection->time[clicked_selection].end;
_session->locations()->next_available_name(rangename,"selection");
- Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
+ Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
begin_reversible_command (_("add marker"));
if (!choose_new_marker_name(markername)) {
return;
}
- Location *location = new Location (*_session, where, where, markername, Location::IsMark);
+ Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
begin_reversible_command (_("add marker"));
XMLNode &before = _session->locations()->get_state();
commit_reversible_command ();
}
+
+ _session->set_end_is_free (false);
+}
+
+
+void
+Editor::toggle_location_at_playhead_cursor ()
+{
+ if (!do_remove_location_at_playhead_cursor())
+ {
+ add_location_from_playhead_cursor();
+ }
}
void
add_location_mark (_session->audible_frame());
}
-void
-Editor::remove_location_at_playhead_cursor ()
+bool
+Editor::do_remove_location_at_playhead_cursor ()
{
+ bool removed = false;
if (_session) {
//set up for undo
XMLNode &before = _session->locations()->get_state();
- bool removed = false;
//find location(s) at this time
Locations::LocationList locs;
commit_reversible_command ();
}
}
+ return removed;
+}
+
+void
+Editor::remove_location_at_playhead_cursor ()
+{
+ do_remove_location_at_playhead_cursor ();
}
/** Add a range marker around each selected region */
boost::shared_ptr<Region> region = (*i)->region ();
- Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
+ Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
_session->locations()->add (location, true);
commit = true;
}
// single range spanning all selected
- Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
+ Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
_session->locations()->add (location, true);
begin_reversible_command (_("add marker"));
framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
+ //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
+ if ( _session->transport_rolling() ) {
+ if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
+ framepos_t prior = _session->locations()->first_mark_before ( pos );
+ pos = prior;
+ }
+ }
+
if (pos < 0) {
return;
}
return;
}
- _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
+ _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
}
void
void
Editor::play_selection ()
{
- framepos_t start, end;
+ framepos_t start, end;
if (!get_selection_extents ( start, end))
return;
_session->request_play_range (&lar, true);
}
-framepos_t
-Editor::get_preroll ()
-{
- return Config->get_preroll_seconds() * _session->frame_rate();
-}
-
void
-Editor::maybe_locate_with_edit_preroll ( framepos_t location )
+Editor::maybe_locate_with_edit_preroll (framepos_t location)
{
- if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
+ if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
return;
- location -= get_preroll();
+ location -= _session->preroll_samples (location);
//don't try to locate before the beginning of time
- if ( location < 0 )
+ if (location < 0) {
location = 0;
+ }
//if follow_playhead is on, keep the playhead on the screen
if ( _follow_playhead )
void
Editor::play_with_preroll ()
{
- {
- framepos_t preroll = get_preroll();
-
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
- return;
+ framepos_t start, end;
+ if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
+ const framepos_t preroll = _session->preroll_samples (start);
- if (start > preroll)
+ framepos_t ret = start;
+
+ if (start > preroll) {
start = start - preroll;
+ }
end = end + preroll; //"post-roll"
lar.push_back (ar);
_session->request_play_range (&lar, true);
+ _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
+ } else {
+ framepos_t ph = playhead_cursor->current_frame ();
+ const framepos_t preroll = _session->preroll_samples (ph);
+ framepos_t start;
+ if (ph > preroll) {
+ start = ph - preroll;
+ } else {
+ start = 0;
+ }
+ _session->request_locate (start, true);
+ _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
}
}
+void
+Editor::rec_with_preroll ()
+{
+ framepos_t ph = playhead_cursor->current_frame ();
+ framepos_t preroll = _session->preroll_samples (ph);
+ _session->request_preroll_record_trim (ph, preroll);
+}
+
+
void
Editor::play_location (Location& location)
{
for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
- RouteTimeAxisView* rtv;
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
- if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
+ if (!rtv) {
+ continue;
+ }
- if (rtv->is_track()) {
+ if (!rtv->is_track()) {
+ continue;
+ }
- /* no edits to destructive tracks */
+ /* no edits to destructive tracks */
- if (rtv->track()->destructive()) {
- continue;
- }
-
- if ((playlist = rtv->playlist()) != 0) {
+ if (rtv->track()->destructive()) {
+ continue;
+ }
- playlist->clear_changes ();
+ if ((playlist = rtv->playlist()) != 0) {
- /* XXX need to consider musical time selections here at some point */
+ playlist->clear_changes ();
- double speed = rtv->track()->speed();
+ /* XXX need to consider musical time selections here at some point */
+ double speed = rtv->track()->speed();
- for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
+ for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
- sigc::connection c = rtv->view()->RegionViewAdded.connect (
- sigc::mem_fun(*this, &Editor::collect_new_region_view));
+ sigc::connection c = rtv->view()->RegionViewAdded.connect (
+ sigc::mem_fun(*this, &Editor::collect_new_region_view));
- latest_regionviews.clear ();
+ latest_regionviews.clear ();
- playlist->partition ((framepos_t)((*t).start * speed),
- (framepos_t)((*t).end * speed), false);
+ playlist->partition ((framepos_t)((*t).start * speed),
+ (framepos_t)((*t).end * speed), false);
- c.disconnect ();
+ c.disconnect ();
- if (!latest_regionviews.empty()) {
+ if (!latest_regionviews.empty()) {
- rtv->view()->foreach_regionview (sigc::bind (
- sigc::ptr_fun (add_if_covered),
- &(*t), &new_selection));
+ rtv->view()->foreach_regionview (sigc::bind (
+ sigc::ptr_fun (add_if_covered),
+ &(*t), &new_selection));
- if (!in_command) {
- begin_reversible_command (_("separate"));
- in_command = true;
- }
+ if (!in_command) {
+ begin_reversible_command (_("separate"));
+ in_command = true;
+ }
- /* pick up changes to existing regions */
+ /* pick up changes to existing regions */
- vector<Command*> cmds;
- playlist->rdiff (cmds);
- _session->add_commands (cmds);
+ vector<Command*> cmds;
+ playlist->rdiff (cmds);
+ _session->add_commands (cmds);
- /* pick up changes to the playlist itself (adds/removes)
- */
+ /* pick up changes to the playlist itself (adds/removes)
+ */
- _session->add_command(new StatefulDiffCommand (playlist));
- }
- }
+ _session->add_command(new StatefulDiffCommand (playlist));
}
}
}
if (!playlist) {
// is this check necessary?
- continue;
+ continue;
}
vector<PlaylistState>::iterator i;
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
- RouteTimeAxisView* rtv;
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
- if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
+ if (!rtv) {
+ continue;
+ }
- boost::shared_ptr<Track> t = rtv->track();
+ boost::shared_ptr<Track> t = rtv->track();
- if (t != 0 && ! t->destructive()) {
+ if (t != 0 && ! t->destructive()) {
- if ((playlist = rtv->playlist()) != 0) {
- playlists.push_back (playlist);
- }
+ if ((playlist = rtv->playlist()) != 0) {
+ playlists.push_back (playlist);
}
}
}
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
- playlist = (*i)->region()->playlist();
+ playlist = (*i)->region()->playlist();
playlist->clear_changes ();
playlist->duplicate_until (r, position, gap, end);
_session->add_command(new StatefulDiffCommand (playlist));
if (front) {
(*i)->region()->trim_front (where);
- maybe_locate_with_edit_preroll ( where );
} else {
(*i)->region()->trim_end (where);
- maybe_locate_with_edit_preroll ( where );
}
_session->add_command (new StatefulDiffCommand ((*i)->region()));
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
- RouteTimeAxisView* rtv;
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
- if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
+ if (!rtv) {
continue;
}
}
}
+
struct AutomationRecord {
AutomationRecord () : state (0) , line(NULL) {}
AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
const AutomationLine* line; ///< line this came from
boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
};
-
+struct PointsSelectionPositionSorter {
+ bool operator() (ControlPoint* a, ControlPoint* b) {
+ return (*(a->model()))->when < (*(b->model()))->when;
+ }
+};
/** Cut, copy or clear selected automation points.
* @param op Operation (Cut, Copy or Clear)
*/
typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
Lists lists;
+ /* user could select points in any order */
+ selection->points.sort(PointsSelectionPositionSorter ());
+
/* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
- for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
- const AutomationLine& line = (*i)->line();
+ for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
+ const AutomationLine& line = (*sel_point)->line();
const boost::shared_ptr<AutomationList> al = line.the_list();
if (lists.find (al) == lists.end ()) {
/* We haven't seen this list yet, so make a record for it. This includes
/* Add all selected points to the relevant copy ControlLists */
framepos_t start = std::numeric_limits<framepos_t>::max();
- for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
- boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
- AutomationList::const_iterator j = (*i)->model();
+ for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
+ boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
+ AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
- lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
+ lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
if (midi) {
/* Update earliest MIDI start time in beats */
- earliest = std::min(earliest, Evoral::Beats((*j)->when));
+ earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
} else {
/* Update earliest session start time in frames */
- start = std::min(start, (*i)->line().session_position(j));
+ start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
}
}
start time, so relative ordering between points is preserved
when copying from several lists and the paste starts at the
earliest copied piece of data. */
- for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
- (*j)->when -= line_offset;
+ boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
+ for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
+ (*ctrl_evt)->when -= line_offset;
}
/* And add it to the cut buffer */
- cut_buffer->add (i->second.copy);
+ cut_buffer->add (al_cpy);
}
}
}
/* Remove each selected point from its AutomationList */
- for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
- boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
- al->erase ((*i)->model ());
+ for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
+ AutomationLine& line = (*sel_point)->line ();
+ boost::shared_ptr<AutomationList> al = line.the_list();
+
+ bool erase = true;
+
+ if (dynamic_cast<AudioRegionGainLine*> (&line)) {
+ /* removing of first and last gain point in region gain lines is prohibited*/
+ if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
+ erase = false;
+ }
+ }
+
+ if(erase) {
+ al->erase ((*sel_point)->model ());
+ }
}
/* Thaw the lists and add undo records for them */
if (!playlist) {
// is this check necessary?
- continue;
+ continue;
}
/* get_regions_from_selection_and_entered() guarantees that
{
DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
- paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
+ paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
}
void
}
snap_to (where);
- paste_internal (where, 1);
+ paste_internal (where, 1, get_grid_music_divisions (0));
}
void
-Editor::paste_internal (framepos_t position, float times)
+Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
{
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
"greedy" paste from one automation type to another. */
PasteContext ctx(paste_count, times, ItemCounts(), true);
- ts.front()->paste (position, *cut_buffer, ctx);
+ ts.front()->paste (position, *cut_buffer, ctx, sub_num);
} else {
PasteContext ctx(paste_count, times, ItemCounts(), false);
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
- (*i)->paste (position, *cut_buffer, ctx);
+ (*i)->paste (position, *cut_buffer, ctx, sub_num);
}
}
commit_reversible_command ();
}
+void
+Editor::duplicate_regions (float times)
+{
+ RegionSelection rs (get_regions_from_selection_and_entered());
+ duplicate_some_regions (rs, times);
+}
+
void
Editor::duplicate_some_regions (RegionSelection& regions, float times)
{
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
- playlist = (*i)->region()->playlist();
+ playlist = (*i)->region()->playlist();
playlist->clear_changes ();
playlist->duplicate (r, position, gap, times);
_session->add_command(new StatefulDiffCommand (playlist));
}
if (in_command) {
- // now "move" range selection to after the current range selection
- framecnt_t distance = 0;
+ if (times == 1.0f) {
+ // now "move" range selection to after the current range selection
+ framecnt_t distance = 0;
- if (clicked_selection) {
- distance = selection->time[clicked_selection].end -
- selection->time[clicked_selection].start;
- } else {
- distance = selection->time.end_frame() - selection->time.start();
- }
-
- selection->move_time (distance);
+ if (clicked_selection) {
+ distance =
+ selection->time[clicked_selection].end - selection->time[clicked_selection].start;
+ } else {
+ distance = selection->time.end_frame () - selection->time.start ();
+ }
+ selection->move_time (distance);
+ }
commit_reversible_command ();
}
}
NormalizeDialog dialog (rs.size() > 1);
- if (dialog.run () == RESPONSE_CANCEL) {
+ if (dialog.run () != RESPONSE_ACCEPT) {
return;
}
obtain the maximum amplitude of them all.
*/
list<double> max_amps;
+ list<double> rms_vals;
double max_amp = 0;
+ double max_rms = 0;
+ bool use_rms = dialog.constrain_rms ();
+
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
- if (arv) {
- dialog.descend (1.0 / regions);
- double const a = arv->audio_region()->maximum_amplitude (&dialog);
-
- if (a == -1) {
- /* the user cancelled the operation */
- return;
- }
+ if (!arv) {
+ continue;
+ }
+ dialog.descend (1.0 / regions);
+ double const a = arv->audio_region()->maximum_amplitude (&dialog);
+ if (use_rms) {
+ double r = arv->audio_region()->rms (&dialog);
+ max_rms = max (max_rms, r);
+ rms_vals.push_back (r);
+ }
- max_amps.push_back (a);
- max_amp = max (max_amp, a);
- dialog.ascend ();
+ if (a == -1) {
+ /* the user cancelled the operation */
+ return;
}
+
+ max_amps.push_back (a);
+ max_amp = max (max_amp, a);
+ dialog.ascend ();
}
list<double>::const_iterator a = max_amps.begin ();
+ list<double>::const_iterator l = rms_vals.begin ();
bool in_command = false;
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
arv->region()->clear_changes ();
- double const amp = dialog.normalize_individually() ? *a : max_amp;
+ double amp = dialog.normalize_individually() ? *a : max_amp;
+ double target = dialog.target_peak (); // dB
+
+ if (use_rms) {
+ double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
+ const double t_rms = dialog.target_rms ();
+ const gain_t c_peak = dB_to_coefficient (target);
+ const gain_t c_rms = dB_to_coefficient (t_rms);
+ if ((amp_rms / c_rms) > (amp / c_peak)) {
+ amp = amp_rms;
+ target = t_rms;
+ }
+ }
- arv->audio_region()->normalize (amp, dialog.target ());
+ arv->audio_region()->normalize (amp, target);
if (!in_command) {
begin_reversible_command (_("normalize"));
_session->add_command (new StatefulDiffCommand (arv->region()));
++a;
+ ++l;
}
if (in_command) {
vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
v.push_back (selected);
- framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
- Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
+ Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
return op (mrv.midi_region()->model(), pos_beats, v);
}
quantize_dialog = new QuantizeDialog (*this);
}
+ if (quantize_dialog->is_mapped()) {
+ /* in progress already */
+ return;
+ }
+
quantize_dialog->present ();
const int r = quantize_dialog->run ();
quantize_dialog->hide ();
continue;
if (first) {
- new_state = !rtav->track()->record_enabled();
+ new_state = !rtav->track()->rec_enable_control()->get_value();
first = false;
}
- rtav->track()->set_record_enabled (new_state, Controllable::UseGroup);
+ rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
}
}
{
bool new_state = false;
bool first = true;
- boost::shared_ptr<RouteList> rl (new RouteList);
+ boost::shared_ptr<ControlList> cl (new ControlList);
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
first = false;
}
- rl->push_back (rtav->route());
+ cl->push_back (rtav->route()->solo_control());
}
- _session->set_solo (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
+ _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
}
void
rl->push_back (rtav->route());
}
- _session->set_mute (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
+ _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
}
void
Location* loc = find_location_from_marker (selection->markers.front(), ignored);
if (loc) {
- loc->move_to (where);
+ loc->move_to (where, get_grid_music_divisions(0));
}
}
}
}
}
- if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
- cancel_time_selection();
- }
+//not sure what this was for; remove it for now.
+// if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
+// cancel_time_selection();
+// }
+
}
void
return;
}
- split_regions_at (where, rs);
+ if (snap_musical()) {
+ split_regions_at (where, rs, get_grid_music_divisions (0));
+ } else {
+ split_regions_at (where, rs, 0);
+ }
}
}
-struct EditorOrderRouteSorter {
- bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- return a->order_key () < b->order_key ();
- }
-};
-
void
Editor::select_next_route()
{
RouteUI *rui;
do {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+
if (*i == current) {
++i;
if (i != track_views.end()) {
break;
}
}
+
rui = dynamic_cast<RouteUI *>(current);
- } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
- selection->set(current);
+ } while (current->hidden() || (rui == NULL) || !rui->route()->active());
+
+ selection->set (current);
ensure_time_axis_view_is_visible (*current, false);
}
RouteUI *rui;
do {
for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
+
if (*i == current) {
++i;
if (i != track_views.rend()) {
}
}
rui = dynamic_cast<RouteUI *>(current);
- } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
+
+ } while (current->hidden() || (rui == NULL) || !rui->route()->active());
selection->set (current);
set_punch_range (start, end, _("set punch range from selection"));
}
+void
+Editor::set_auto_punch_range ()
+{
+ // auto punch in/out button from a single button
+ // If Punch In is unset, set punch range from playhead to end, enable punch in
+ // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
+ // rewound beyond the Punch In marker, in which case that marker will be moved back
+ // to the current playhead position.
+ // If punch out is set, it clears the punch range and Punch In/Out buttons
+
+ if (_session == 0) {
+ return;
+ }
+
+ Location* tpl = transport_punch_location();
+ framepos_t now = playhead_cursor->current_frame();
+ framepos_t begin = now;
+ framepos_t end = _session->current_end_frame();
+
+ if (!_session->config.get_punch_in()) {
+ // First Press - set punch in and create range from here to eternity
+ set_punch_range (begin, end, _("Auto Punch In"));
+ _session->config.set_punch_in(true);
+ } else if (tpl && !_session->config.get_punch_out()) {
+ // Second press - update end range marker and set punch_out
+ if (now < tpl->start()) {
+ // playhead has been rewound - move start back and pretend nothing happened
+ begin = now;
+ set_punch_range (begin, end, _("Auto Punch In/Out"));
+ } else {
+ // normal case for 2nd press - set the punch out
+ end = playhead_cursor->current_frame ();
+ set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
+ _session->config.set_punch_out(true);
+ }
+ } else {
+ if (_session->config.get_punch_out()) {
+ _session->config.set_punch_out(false);
+ }
+
+ if (_session->config.get_punch_in()) {
+ _session->config.set_punch_in(false);
+ }
+
+ if (tpl)
+ {
+ // third press - unset punch in/out and remove range
+ _session->locations()->remove(tpl);
+ }
+ }
+
+}
+
void
Editor::set_session_extents_from_selection ()
{
Location* loc;
if ((loc = _session->locations()->session_range_location()) == 0) {
- _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
+ _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
} else {
XMLNode &before = loc->get_state();
- _session->set_session_extents ( start, end );
+ _session->set_session_extents (start, end);
XMLNode &after = loc->get_state();
commit_reversible_command ();
}
+
+ _session->set_end_is_free (false);
}
void
{
framepos_t length = end - start;
- const Meter& m (_session->tempo_map().meter_at (start));
+ const Meter& m (_session->tempo_map().meter_at_frame (start));
/* length = 1 bar */
*/
- const TempoSection& t (_session->tempo_map().tempo_section_at (start));
+ const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
bool do_global = false;
} else if (t.frame() == start) {
_session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
} else {
- Timecode::BBT_Time bbt;
- _session->tempo_map().bbt_time (start, bbt);
- _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt, TempoSection::Type::Constant);
+ const Tempo tempo (beats_per_minute, t.note_type());
+ _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
}
XMLNode& after (_session->tempo_map().get_state());
continue;
}
+ (*r)->region()->clear_changes ();
(*r)->region()->trim_front( (position - pull_back_frames));
last_region->trim_end( (position - pull_back_frames + crossfade_len));
+ _session->add_command (new StatefulDiffCommand ((*r)->region()));
last_region = (*r)->region();
idx++;
return;
}
+ if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
+ /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
+ * route). If the deleted route is currently displayed in the Editor-Mixer (highly
+ * likely because deletion requires selection) this will call
+ * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
+ * It's likewise likely that the route that has just been displayed in the
+ * Editor-Mixer will be next in line for deletion.
+ *
+ * So simply switch to the master-bus (if present)
+ */
+ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ if ((*i)->stripable ()->is_master ()) {
+ set_selected_mixer_strip (*(*i));
+ break;
+ }
+ }
+ }
+
{
+ PresentationInfo::ChangeSuspender cs;
DisplaySuspender ds;
+
boost::shared_ptr<RouteList> rl (new RouteList);
for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
rl->push_back (*x);
}
insert_time (
- get_preferred_edit_position (EDIT_IGNORE_MOUSE),
+ d.position(),
d.distance(),
d.intersected_region_action (),
d.all_playlists(),
(*i)->clear_owned_changes ();
if (opt == SplitIntersected) {
- (*i)->split (pos);
+ /* non musical split */
+ (*i)->split (pos, 0);
}
(*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
/* markers */
if (markers_too) {
bool moved = false;
+ const int32_t divisions = get_grid_music_divisions (0);
XMLNode& before (_session->locations()->get_state());
Locations::LocationList copy (_session->locations()->list());
if ((*i)->start() >= pos) {
// move end first, in case we're moving by more than the length of the range
if (!(*i)->is_mark()) {
- (*i)->set_end ((*i)->end() + frames);
+ (*i)->set_end ((*i)->end() + frames, false, true, divisions);
}
- (*i)->set_start ((*i)->start() + frames);
+ (*i)->set_start ((*i)->start() + frames, false, true, divisions);
moved = true;
}
return;
}
- framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
InsertRemoveTimeDialog d (*this, true);
int response = d.run ();
}
remove_time (
- pos,
+ d.position(),
distance,
SplitIntersected,
d.move_glued(),
}
}
+ const int32_t divisions = get_grid_music_divisions (0);
std::list<Location*> loc_kill_list;
/* markers */
// if we're removing more time than the length of the range
if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
// start is within cut
- (*i)->set_start (pos); // bring the start marker to the beginning of the cut
+ (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
moved = true;
} else if ((*i)->start() >= pos+frames) {
// start (and thus entire range) lies beyond end of cut
- (*i)->set_start ((*i)->start() - frames); // slip the start marker back
+ (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
moved = true;
}
if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
// end is inside cut
- (*i)->set_end (pos); // bring the end to the cut
+ (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
moved = true;
} else if ((*i)->end() >= pos+frames) {
// end is beyond end of cut
- (*i)->set_end ((*i)->end() - frames); // slip the end marker back
+ (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
moved = true;
}
loc_kill_list.push_back(*i);
moved = true;
} else if ((*i)->start() >= pos) {
- (*i)->set_start ((*i)->start() -frames);
+ (*i)->set_start ((*i)->start() -frames, false, true, divisions);
moved = true;
}
_session->set_exclusive_input_active (rl, onoff, flip_others);
}
+static bool ok_fine (GdkEventAny*) { return true; }
+
void
Editor::lock ()
{
Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
lock_dialog->get_vbox()->pack_start (*padlock);
+ lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
ArdourButton* b = manage (new ArdourButton);
b->set_name ("lock button");
_main_menu_disabler = new MainMenuDisabler;
lock_dialog->present ();
+
+ lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
}
void
{
Timers::TimerSuspender t;
label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
- Gtkmm2ext::UI::instance()->flush_pending ();
+ Gtkmm2ext::UI::instance()->flush_pending (1);
}
void
*/
Timers::TimerSuspender t;
- Gtkmm2ext::UI::instance()->flush_pending ();
+ Gtkmm2ext::UI::instance()->flush_pending (3);
cerr << " Do it\n";