#include "ardour/audio_track.h"
#include "ardour/audioregion.h"
+#include "ardour/boost_debug.h"
#include "ardour/dB.h"
#include "ardour/location.h"
#include "ardour/midi_region.h"
#include "ardour/session_playlists.h"
#include "ardour/strip_silence.h"
#include "ardour/transient_detector.h"
+#include "ardour/transpose.h"
#include "canvas/canvas.h"
#include "streamview.h"
#include "strip_silence_dialog.h"
#include "time_axis_view.h"
+#include "timers.h"
#include "transpose_dialog.h"
#include "transform_dialog.h"
#include "ui_config.h"
return false;
}
+void
+Editor::scroll_left_step ()
+{
+ framepos_t xdelta = (current_page_samples() / 8);
+
+ if (leftmost_frame > xdelta) {
+ reset_x_origin (leftmost_frame - xdelta);
+ } else {
+ reset_x_origin (0);
+ }
+}
+
+
+void
+Editor::scroll_right_step ()
+{
+ framepos_t xdelta = (current_page_samples() / 8);
+
+ if (max_framepos - xdelta > leftmost_frame) {
+ reset_x_origin (leftmost_frame + xdelta);
+ } else {
+ reset_x_origin (max_framepos - current_page_samples());
+ }
+}
+
+void
+Editor::scroll_left_half_page ()
+{
+ framepos_t xdelta = (current_page_samples() / 2);
+ if (leftmost_frame > xdelta) {
+ reset_x_origin (leftmost_frame - xdelta);
+ } else {
+ reset_x_origin (0);
+ }
+}
+
+void
+Editor::scroll_right_half_page ()
+{
+ framepos_t xdelta = (current_page_samples() / 2);
+ if (max_framepos - xdelta > leftmost_frame) {
+ reset_x_origin (leftmost_frame + xdelta);
+ } else {
+ reset_x_origin (max_framepos - current_page_samples());
+ }
+}
+
/* ZOOM */
void
}
}
+void
+Editor::temporal_zoom_step_mouse_focus (bool coarser)
+{
+ Editing::ZoomFocus temp_focus = zoom_focus;
+ zoom_focus = Editing::ZoomFocusMouse;
+ temporal_zoom_step (coarser);
+ zoom_focus = temp_focus;
+}
void
Editor::temporal_zoom_step (bool coarser)
bool
-Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
+Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
{
start = max_framepos;
end = 0;
framepos_t
Editor::get_preroll ()
{
- return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
+ return Config->get_preroll_seconds() * _session->frame_rate();
}
void
Editor::maybe_locate_with_edit_preroll ( framepos_t location )
{
- if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits )
+ if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
return;
location -= get_preroll();
return;
}
- ArdourDialog d (*this, _("Rename Region"), true, false);
+ ArdourDialog d (_("Rename Region"), true, false);
Entry entry;
Label label (_("New name:"));
HBox hbox;
return;
}
- framepos_t the_start;
- framepos_t the_end;
- framepos_t cnt;
+ framepos_t pos;
+ framepos_t new_start;
+ framepos_t new_end;
+ framecnt_t new_length;
bool in_command = false;
for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
- boost::shared_ptr<Region> region;
+ /* Only the top regions at start and end have to be cropped */
+ boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
+ boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
- the_start = start;
+ vector<boost::shared_ptr<Region> > regions;
- if ((region = (*i)->top_region_at(the_start)) == 0) {
- continue;
+ if (region_at_start != 0) {
+ regions.push_back (region_at_start);
+ }
+ if (region_at_end != 0) {
+ regions.push_back (region_at_end);
}
- /* now adjust lengths to that we do the right thing
- if the selection extends beyond the region
- */
+ /* now adjust lengths */
+ for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
- the_start = max (the_start, (framepos_t) region->position());
- if (max_framepos - the_start < region->length()) {
- the_end = the_start + region->length() - 1;
- } else {
- the_end = max_framepos;
- }
- the_end = min (end, the_end);
- cnt = the_end - the_start + 1;
+ pos = (*i)->position();
+ new_start = max (start, pos);
+ if (max_framepos - pos > (*i)->length()) {
+ new_end = pos + (*i)->length() - 1;
+ } else {
+ new_end = max_framepos;
+ }
+ new_end = min (end, new_end);
+ new_length = new_end - new_start + 1;
- if(!in_command) {
- begin_reversible_command (_("trim to selection"));
- in_command = true;
+ if(!in_command) {
+ begin_reversible_command (_("trim to selection"));
+ in_command = true;
+ }
+ (*i)->clear_changes ();
+ (*i)->trim_to (new_start, new_length);
+ _session->add_command (new StatefulDiffCommand (*i));
}
- region->clear_changes ();
- region->trim_to (the_start, cnt);
- _session->add_command (new StatefulDiffCommand (region));
}
if (in_command) {
void
Editor::region_fill_track ()
{
- RegionSelection rs = get_regions_from_selection_and_entered ();
-
- if (!_session || rs.empty()) {
- return;
- }
+ boost::shared_ptr<Playlist> playlist;
+ RegionSelection regions = get_regions_from_selection_and_entered ();
+ RegionSelection foo;
framepos_t const end = _session->current_end_frame ();
- RegionSelection foo;
- bool in_command = false;
- for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
+ if (regions.empty () || regions.end_frame () + 1 >= end) {
+ return;
+ }
- boost::shared_ptr<Region> region ((*i)->region());
+ framepos_t const start_frame = regions.start ();
+ framepos_t const end_frame = regions.end_frame ();
+ framecnt_t const gap = end_frame - start_frame + 1;
- boost::shared_ptr<Playlist> pl = region->playlist();
+ begin_reversible_command (Operations::region_fill);
- if (end <= region->last_frame()) {
- continue;
- }
+ selection->clear_regions ();
- double times = (double) (end - region->last_frame()) / (double) region->length();
+ for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
- if (times == 0) {
- continue;
- }
+ boost::shared_ptr<Region> r ((*i)->region());
- if (!in_command) {
- begin_reversible_command (Operations::region_fill);
- in_command = true;
- }
TimeAxisView& tv = (*i)->get_time_axis_view();
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
latest_regionviews.clear ();
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
- pl->clear_changes ();
- pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
- _session->add_command (new StatefulDiffCommand (pl));
+ framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
+ playlist = (*i)->region()->playlist();
+ playlist->clear_changes ();
+ playlist->duplicate_until (r, position, gap, end);
+ _session->add_command(new StatefulDiffCommand (playlist));
c.disconnect ();
foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
}
- if (in_command) {
- if (!foo.empty()) {
- selection->set (foo);
- }
- commit_reversible_command ();
- }
-}
-
-void
-Editor::region_fill_selection ()
-{
- if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
- return;
- }
-
- if (selection->time.empty()) {
- return;
- }
-
- boost::shared_ptr<Region> region = _regions->get_single_selection ();
- if (region == 0) {
- return;
- }
-
- framepos_t start = selection->time[clicked_selection].start;
- framepos_t end = selection->time[clicked_selection].end;
-
- boost::shared_ptr<Playlist> playlist;
-
- if (selection->tracks.empty()) {
- return;
- }
-
- framepos_t selection_length = end - start;
- float times = (float)selection_length / region->length();
- bool in_command = false;
-
- TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
- RegionSelection foo;
-
- for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
-
- if ((playlist = (*i)->playlist()) == 0) {
- continue;
- }
-
- if (!in_command) {
- begin_reversible_command (Operations::fill_selection);
- in_command = true;
- }
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
- latest_regionviews.clear ();
- sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
-
- playlist->clear_changes ();
- playlist->add_region (RegionFactory::create (region, true), start, times);
- _session->add_command (new StatefulDiffCommand (playlist));
- c.disconnect ();
- foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
+ if (!foo.empty()) {
+ selection->set (foo);
}
- if (in_command) {
- if (!foo.empty()) {
- selection->set (foo);
- }
- commit_reversible_command ();
- }
+ commit_reversible_command ();
}
void
gtk_main_iteration ();
}
+ pthread_join (itt.thread, 0);
current_interthread_info = 0;
}
Location* loc = find_location_from_marker (entered_marker, ignored);
if (_session && loc) {
+ entered_marker = NULL;
Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
}
list<boost::shared_ptr<Playlist> > foo;
- /* the pmap is in the same order as the tracks in which selected regions occured */
+ /* the pmap is in the same order as the tracks in which selected regions occurred */
for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
if ((*i).pl) {
framepos_t const start_frame = regions.start ();
framepos_t const end_frame = regions.end_frame ();
- framecnt_t const gap = end_frame - start_frame;
+ framecnt_t const gap = end_frame - start_frame + 1;
begin_reversible_command (Operations::duplicate_region);
latest_regionviews.clear ();
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);
+ framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
playlist = (*i)->region()->playlist();
playlist->clear_changes ();
playlist->duplicate (r, position, gap, times);
}
boost::shared_ptr<Playlist> playlist;
- vector<boost::shared_ptr<Region> > new_regions;
- vector<boost::shared_ptr<Region> >::iterator ri;
-
- create_region_from_selection (new_regions);
-
- if (new_regions.empty()) {
- return;
- }
-
- ri = new_regions.begin();
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+
bool in_command = false;
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
continue;
}
playlist->clear_changes ();
- framepos_t end;
+
if (clicked_selection) {
- end = selection->time[clicked_selection].end;
+ playlist->duplicate_range (selection->time[clicked_selection], times);
} else {
- end = selection->time.end_frame();
+ playlist->duplicate_ranges (selection->time, times);
}
- playlist->duplicate (*ri, end, times);
if (!in_command) {
- begin_reversible_command (_("duplicate selection"));
+ begin_reversible_command (_("duplicate range selection"));
in_command = true;
}
_session->add_command (new StatefulDiffCommand (playlist));
- ++ri;
- if (ri == new_regions.end()) {
- --ri;
- }
}
if (in_command) {
+ // 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);
+
commit_reversible_command ();
}
}
StripSilenceDialog d (_session, audio_only);
int const r = d.run ();
- d.drop_rects ();
+ d.drop_rects ();
- if (r == Gtk::RESPONSE_OK) {
- ARDOUR::AudioIntervalMap silences;
- d.silences (silences);
+ if (r == Gtk::RESPONSE_OK) {
+ ARDOUR::AudioIntervalMap silences;
+ d.silences (silences);
StripSilence s (*_session, silences, d.fade_length());
+
apply_filter (s, _("strip silence"), &d);
}
}
return;
}
- TransformDialog* td = new TransformDialog();
+ TransformDialog td;
- td->present();
- const int r = td->run();
- td->hide();
+ td.present();
+ const int r = td.run();
+ td.hide();
if (r == Gtk::RESPONSE_OK) {
- Transform transform(td->get());
+ Transform transform(td.get());
apply_midi_note_edit_op(transform, rs);
}
}
+void
+Editor::transpose_region ()
+{
+ if (_session) {
+ transpose_regions(get_regions_from_selection_and_entered ());
+ }
+}
+
+void
+Editor::transpose_regions (const RegionSelection& rs)
+{
+ if (rs.n_midi_regions() == 0) {
+ return;
+ }
+
+ TransposeDialog d;
+ int const r = d.run ();
+
+ if (r == RESPONSE_ACCEPT) {
+ Transpose transpose(d.semitones ());
+ apply_midi_note_edit_op (transpose, rs);
+ }
+}
+
void
Editor::insert_patch_change (bool from_context)
{
playlist->clear_changes ();
playlist->clear_owned_changes ();
+ if (!in_command) {
+ begin_reversible_command (command);
+ in_command = true;
+ }
+
if (filter.results.empty ()) {
/* no regions returned; remove the old one */
}
}
+
/* We might have removed regions, which alters other regions' layering_index,
so we need to do a recursive diff here.
*/
-
- if (!in_command) {
- begin_reversible_command (command);
- in_command = true;
- }
vector<Command*> cmds;
playlist->rdiff (cmds);
_session->add_commands (cmds);
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, this);
+ 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, true);
+ _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, true);
+ _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), new_state, Controllable::UseGroup);
}
void
}
}
- if (UIConfiguration::instance().get_follow_edits()) {
+ if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
cancel_time_selection();
}
}
}
}
-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()
{
pitch_shift (audio_rs, 1.2);
}
-void
-Editor::transpose_region ()
-{
- RegionSelection rs = get_regions_from_selection_and_entered ();
-
- list<MidiRegionView*> midi_region_views;
- for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
- MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
- if (mrv) {
- midi_region_views.push_back (mrv);
- }
- }
-
- TransposeDialog d;
- int const r = d.run ();
- if (r != RESPONSE_ACCEPT) {
- return;
- }
-
- for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
- (*i)->midi_region()->transpose (d.semitones ());
- }
-}
-
void
Editor::set_tempo_from_region ()
{
{
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 */
- /* now we want frames per beat.
+ /* We're going to deliver a constant tempo here,
+ so we can use frames per beat to determine length.
+ now we want frames per beat.
we have frames per bar, and beats per bar, so ...
*/
*/
- 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);
+ _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), 0.0, start, TempoSection::Constant, AudioTime);
}
XMLNode& after (_session->tempo_map().get_state());
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
- if (ar && (ar->get_transients (positions) == 0)) {
+ if (ar) {
+ ar->transients (positions);
split_region_at_points ((*i)->region(), positions, true);
positions.clear ();
}
return;
}
-
if (positions.size() > 20 && can_ferret) {
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);
MessageDialog msg (msgstr,
framepos_t pos = 0;
+ framepos_t rstart = r->first_frame ();
+ framepos_t rend = r->last_frame ();
+
while (x != positions.end()) {
/* deal with positons that are out of scope of present region bounds */
- if (*x <= 0 || *x > r->length()) {
+ if (*x <= rstart || *x > rend) {
++x;
continue;
}
- /* file start = original start + how far we from the initial position ?
- */
+ /* file start = original start + how far we from the initial position ? */
framepos_t file_start = r->start() + pos;
- /* length = next position - current position
- */
+ /* length = next position - current position */
- framepos_t len = (*x) - pos;
+ framepos_t len = (*x) - pos - rstart;
/* XXX we do we really want to allow even single-sample regions?
- shouldn't we have some kind of lower limit on region size?
- */
+ * shouldn't we have some kind of lower limit on region size?
+ */
if (len <= 0) {
break;
plist.add (ARDOUR::Properties::length, len);
plist.add (ARDOUR::Properties::name, new_name);
plist.add (ARDOUR::Properties::layer, 0);
+ // TODO set transients_offset
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
/* because we set annouce to false, manually add the new region to the
- RegionFactory map
- */
+ * RegionFactory map
+ */
RegionFactory::map_add (nr);
- pl->add_region (nr, r->position() + pos);
+ pl->add_region (nr, rstart + pos);
if (select_new) {
new_regions.push_front(nr);
begin_reversible_command (_("place transient"));
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
- framepos_t position = (*r)->region()->position();
- (*r)->region()->add_transient(where - position);
+ (*r)->region()->add_transient(where);
}
commit_reversible_command ();
bool
Editor::idle_remove_tracks ()
{
+ Session::StateProtector sp (_session);
_remove_tracks ();
return false; /* do not call again */
}
}
{
- Session::StateProtector sp (_session);
DisplaySuspender ds;
+ boost::shared_ptr<RouteList> rl (new RouteList);
for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
- _session->remove_route (*x);
+ rl->push_back (*x);
}
+ _session->remove_routes (rl);
}
+ /* TrackSelection and RouteList leave scope,
+ * destructors are called,
+ * diskstream drops references, save_state is called (again for every track)
+ */
}
void
return;
}
- InsertTimeOption opt = d.intersected_region_action ();
-
insert_time (
- get_preferred_edit_position(),
+ get_preferred_edit_position (EDIT_IGNORE_MOUSE),
d.distance(),
- opt,
+ d.intersected_region_action (),
d.all_playlists(),
d.move_glued(),
d.move_markers(),
pl->shift (pos, -frames, true, ignore_music_glue);
if (!in_command) {
- begin_reversible_command (_("cut time"));
+ begin_reversible_command (_("remove time"));
in_command = true;
}
XMLNode &after = pl->get_state();
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
if (rtav) {
if (!in_command) {
- begin_reversible_command (_("cut time"));
+ begin_reversible_command (_("remove time"));
in_command = true;
}
rtav->route ()->shift (pos, -frames);
if (moved) {
if (!in_command) {
- begin_reversible_command (_("cut time"));
+ begin_reversible_command (_("remove time"));
in_command = true;
}
XMLNode& after (_session->locations()->get_state());
double first_y_pos = DBL_MAX;
if (h < TimeAxisView::preset_height (HeightSmall)) {
- MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
+ MessageDialog msg (_("There are too many tracks to fit in the current window"));
/* too small to be displayed */
return;
}
lock_dialog->hide ();
delete _main_menu_disabler;
+ _main_menu_disabler = 0;
if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
start_lock_event_timing ();
void
Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
{
+ Timers::TimerSuspender t;
label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
Gtkmm2ext::UI::instance()->flush_pending ();
}
* files
*/
+ Timers::TimerSuspender t;
Gtkmm2ext::UI::instance()->flush_pending ();
cerr << " Do it\n";