Compare commits

...

13 Commits

Author SHA1 Message Date
Paul Davis 9630d83573 playhead priority: if rolling and range selection vanishes while we are paying attention, ignore the change 2015-01-28 22:15:11 -05:00
Paul Davis 5cdd708648 new read tester for investigating read bandwidth issues 2015-01-19 14:54:49 -05:00
Paul Davis 7163d9db3e correctly track range selection trim and drag creation w.r.t playback priority 2015-01-17 12:40:46 -05:00
Paul Davis dd4b65412f make editor_drag.h fully self-contained as a header file (it was missing more than a dozen necessary fwd decls etc) 2015-01-17 12:01:08 -05:00
Paul Davis 35c50cdf6e properly track, update, maintain and set auto return state 2015-01-17 12:00:34 -05:00
Paul Davis d7fb135e5c start work on auto return target dropdown rather than button 2015-01-16 20:01:59 -05:00
Paul Davis e7b634c977 change ArdourDropdown API to allow other types of menu elements 2015-01-16 20:01:34 -05:00
Paul Davis 6765889807 follow various events related to playhead priority (loop changes, parameter changes); remove debug output 2015-01-16 17:50:10 -05:00
Paul Davis ab7d69539d remove debug output 2015-01-16 17:49:06 -05:00
Paul Davis 574763c65e fix copy-n-paste errors that used wrong buttons for playhead priorities 2015-01-16 16:01:33 -05:00
Paul Davis f5a1d2cbe7 fix copy-n-paste errors that used incorrect enum values for playhead priorities 2015-01-16 15:33:46 -05:00
Paul Davis dd91e6b375 add preferences GUI elements to allow control of playhead priority items 2015-01-16 15:19:17 -05:00
Paul Davis 7caa67b9ac initial version of playback priority design. No GUI control over options yet 2015-01-16 12:17:09 -05:00
20 changed files with 626 additions and 84 deletions

View File

@ -76,7 +76,7 @@ ArdourDropdown::clear_items ()
}
void
ArdourDropdown::AddMenuElem (Menu_Helpers::MenuElem e)
ArdourDropdown::AddMenuElem (Menu_Helpers::Element e)
{
using namespace Menu_Helpers;

View File

@ -39,7 +39,7 @@ class ArdourDropdown : public ArdourButton
bool on_button_press_event (GdkEventButton*);
void clear_items ();
void AddMenuElem (Gtk::Menu_Helpers::MenuElem e);
void AddMenuElem (Gtk::Menu_Helpers::Element e);
private:
Gtk::Menu _menu;

View File

@ -187,9 +187,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
, play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
, rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
, auto_return_button (ArdourButton::led_default_elements)
, follow_edits_button (ArdourButton::led_default_elements)
, auto_input_button (ArdourButton::led_default_elements)
, auditioning_alert_button (_("Audition"))
, solo_alert_button (_("Solo"))
@ -4558,16 +4556,16 @@ ARDOUR_UI::transport_numpad_event (int num)
_pending_locate_num = _pending_locate_num*10 + num;
} else {
switch (num) {
case 0: toggle_roll(false, false); break;
case 1: transport_rewind(1); break;
case 2: transport_forward(1); break;
case 3: transport_record(true); break;
case 4: toggle_session_auto_loop(); break;
case 5: transport_record(false); toggle_session_auto_loop(); break;
case 6: toggle_punch(); break;
case 7: toggle_click(); break;
case 8: toggle_auto_return(); break;
case 9: toggle_follow_edits(); break;
case 0: toggle_roll(false, false); break;
case 1: transport_rewind(1); break;
case 2: transport_forward(1); break;
case 3: transport_record(true); break;
case 4: toggle_session_auto_loop(); break;
case 5: transport_record(false); toggle_session_auto_loop(); break;
case 6: toggle_punch(); break;
case 7: toggle_click(); break;
case 8: toggle_all_auto_return (); break;
case 9: toggle_follow_edits(); break;
}
}
}
@ -4577,3 +4575,50 @@ ARDOUR_UI::set_flat_buttons ()
{
CairoWidget::set_flat_buttons( config()->get_flat_buttons() );
}
void
ARDOUR_UI::toggle_auto_return_state (AutoReturnTarget t)
{
AutoReturnTarget art = Config->get_auto_return_target_list ();
CheckMenuItem* check_menu_item = 0;
switch (t) {
case LastLocate:
check_menu_item = auto_return_last_locate;
break;
case Loop:
check_menu_item = auto_return_loop;
break;
case RangeSelectionStart:
check_menu_item = auto_return_range_selection;
break;
case RegionSelectionStart:
check_menu_item = auto_return_region_selection;
break;
}
if (!check_menu_item) {
return;
}
if (check_menu_item->get_active()) {
Config->set_auto_return_target_list (AutoReturnTarget (art | t));
} else {
Config->set_auto_return_target_list (AutoReturnTarget (art & ~t));
}
}
void
ARDOUR_UI::toggle_all_auto_return ()
{
AutoReturnTarget art = Config->get_auto_return_target_list ();
if (art) {
Config->set_auto_return_target_list (AutoReturnTarget (0));
} else {
Config->set_auto_return_target_list (AutoReturnTarget (LastLocate|
RangeSelectionStart|
RegionSelectionStart|
Loop));
}
}

View File

@ -70,6 +70,7 @@
#include "about.h"
#include "ardour_button.h"
#include "ardour_dialog.h"
#include "ardour_dropdown.h"
#include "ardour_window.h"
#include "editing.h"
#include "engine_dialog.h"
@ -314,7 +315,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
void toggle_punch_out ();
void show_loop_punch_ruler_and_disallow_hide ();
void reenable_hide_loop_punch_ruler_if_appropriate ();
void toggle_auto_return ();
void toggle_click ();
void toggle_audio_midi_setup ();
void toggle_session_auto_loop ();
@ -445,7 +445,16 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
ShuttleControl* shuttle_box;
ArdourButton auto_return_button;
ArdourDropdown auto_return_dropdown;
Gtk::CheckMenuItem *auto_return_last_locate;
Gtk::CheckMenuItem *auto_return_range_selection;
Gtk::CheckMenuItem *auto_return_region_selection;
Gtk::CheckMenuItem *auto_return_loop;
Gtk::MenuItem *auto_return_toggle;
void toggle_auto_return_state (ARDOUR::AutoReturnTarget);
void toggle_all_auto_return ();
ArdourButton follow_edits_button;
ArdourButton auto_input_button;
ArdourButton click_button;

View File

@ -136,7 +136,6 @@ ARDOUR_UI::setup_tooltips ()
set_tip (goto_end_button, _("Go to end of session"));
set_tip (auto_loop_button, _("Play loop range"));
set_tip (midi_panic_button, _("MIDI Panic\nSend note off and reset controller messages on all MIDI channels"));
set_tip (auto_return_button, _("Return to last playback start when stopped"));
set_tip (follow_edits_button, _("Playhead follows Range Selections and Edits"));
set_tip (auto_input_button, _("Be sensible about input monitoring"));
set_tip (click_button, _("Enable/Disable audio click"));
@ -245,7 +244,31 @@ ARDOUR_UI::setup_transport ()
transport_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::reattach_tearoff), static_cast<Box*> (&top_packer),
static_cast<Widget*> (&transport_frame), 1));
auto_return_button.set_text(_("Auto Return"));
/* build auto-return dropdown */
auto_return_dropdown.set_text (_("Auto Return"));
auto_return_last_locate = manage (new CheckMenuItem (_("Play from last roll")));
auto_return_last_locate->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::toggle_auto_return_state), LastLocate));
auto_return_last_locate->show ();
auto_return_dropdown.AddMenuElem (Gtk::Menu_Helpers::CheckMenuElem (*auto_return_last_locate));
auto_return_region_selection = manage (new CheckMenuItem (_("Play from region selection")));
auto_return_region_selection->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::toggle_auto_return_state), RegionSelectionStart));
auto_return_region_selection->show ();
auto_return_dropdown.AddMenuElem (Gtk::Menu_Helpers::CheckMenuElem (*auto_return_region_selection));
auto_return_range_selection = manage (new CheckMenuItem (_("Play from range selection")));
auto_return_range_selection->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::toggle_auto_return_state), RangeSelectionStart));
auto_return_range_selection->show ();
auto_return_dropdown.AddMenuElem (Gtk::Menu_Helpers::CheckMenuElem (*auto_return_range_selection));
auto_return_loop = manage (new CheckMenuItem (_("Play from loop")));
auto_return_loop->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::toggle_auto_return_state), Loop));
auto_return_loop->show ();
auto_return_dropdown.AddMenuElem (Gtk::Menu_Helpers::CheckMenuElem (*auto_return_loop));
auto_return_dropdown.AddMenuElem (Gtk::Menu_Helpers::MenuElem (_("Disable/Enable All Options"), sigc::mem_fun (*this, &ARDOUR_UI::toggle_all_auto_return)));
follow_edits_button.set_text(_("Follow Edits"));
@ -256,7 +279,6 @@ ARDOUR_UI::setup_transport ()
click_button.set_related_action (act);
click_button.signal_button_press_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::click_button_clicked), false);
auto_return_button.set_name ("transport option button");
follow_edits_button.set_name ("transport option button");
auto_input_button.set_name ("transport option button");
@ -308,8 +330,6 @@ ARDOUR_UI::setup_transport ()
secondary_clock->ValueChanged.connect (sigc::mem_fun(*this, &ARDOUR_UI::secondary_clock_value_changed));
big_clock->ValueChanged.connect (sigc::mem_fun(*this, &ARDOUR_UI::big_clock_value_changed));
act = ActionManager::get_action ("Transport", "ToggleAutoReturn");
auto_return_button.set_related_action (act);
act = ActionManager::get_action (X_("Transport"), X_("ToggleFollowEdits"));
follow_edits_button.set_related_action (act);
act = ActionManager::get_action ("Transport", "ToggleAutoInput");
@ -425,7 +445,7 @@ ARDOUR_UI::setup_transport ()
auto_box->pack_start (sync_button, true, true);
if (!ARDOUR::Profile->get_trx()) {
auto_box->pack_start (follow_edits_button, true, true);
auto_box->pack_start (auto_return_button, true, true);
auto_box->pack_start (auto_return_dropdown, true, true);
}
if (!ARDOUR::Profile->get_trx()) {

View File

@ -216,7 +216,7 @@ if (Profile->get_mixbus())
ActionManager::register_action (common_actions, X_("Forums"), _("User Forums"), mem_fun(*this, &ARDOUR_UI::launch_forums));
ActionManager::register_action (common_actions, X_("Howto_Report"), _("How to report a bug"), mem_fun(*this, &ARDOUR_UI::launch_howto_report));
act = ActionManager::register_action (common_actions, X_("Save"), _("Save"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::save_state), string(""), false));
act = ActionManager::register_action (common_actions, X_("Save"), _("Save"), sigc::hide_return (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::save_state), string(""), false)));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::write_sensitive_actions.push_back (act);
@ -400,7 +400,7 @@ if (Profile->get_mixbus())
act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoPlay"), _("Auto Play"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_auto_play));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoReturn"), _("Auto Return"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_auto_return));
act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoReturn"), _("Auto Return"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_all_auto_return));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
act = ActionManager::register_toggle_action (transport_actions, X_("ToggleFollowEdits"), _("Follow Edits"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_follow_edits));

View File

@ -130,12 +130,6 @@ ARDOUR_UI::toggle_auto_play ()
ActionManager::toggle_config_state_foo ("Transport", "ToggleAutoPlay", sigc::mem_fun (_session->config, &SessionConfiguration::set_auto_play), sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_play));
}
void
ARDOUR_UI::toggle_auto_return ()
{
ActionManager::toggle_config_state_foo ("Transport", "ToggleAutoReturn", sigc::mem_fun (_session->config, &SessionConfiguration::set_auto_return), sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_return));
}
void
ARDOUR_UI::toggle_click ()
{
@ -421,6 +415,12 @@ ARDOUR_UI::parameter_changed (std::string p)
? ArdourCanvas::WaveView::Rectified : ArdourCanvas::WaveView::Normal);
} else if (p == "show-waveform-clipping") {
ArdourCanvas::WaveView::set_global_show_waveform_clipping (ARDOUR_UI::config()->get_show_waveform_clipping());
} else if (p == "auto-return-target-list") {
AutoReturnTarget art = Config->get_auto_return_target_list ();
auto_return_loop->set_active ((bool) (art & Loop));
auto_return_range_selection->set_active ((bool) (art & RangeSelectionStart));
auto_return_region_selection->set_active ((bool) (art & RegionSelectionStart));
auto_return_last_locate->set_active ((bool) (art & LastLocate));
}
}

View File

@ -96,8 +96,6 @@ DragManager::abort ()
{
_ending = true;
cerr << "Aborting drag\n";
for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
(*i)->abort ();
delete *i;
@ -4390,7 +4388,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
/* XXX what if its a music time selection? */
if (s) {
if ( s->get_play_range() && s->transport_rolling() ) {
if (s->get_play_range() && s->transport_rolling()) {
s->request_play_range (&_editor->selection->time, true);
} else {
if (ARDOUR_UI::config()->get_follow_edits() && !s->transport_rolling()) {
@ -4400,8 +4398,14 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
s->request_locate (_editor->get_selection().time.start());
}
}
}
if (_editor->get_selection().time.length() != 0) {
s->set_range_selection (_editor->get_selection().time.start(), _editor->get_selection().time.end_frame());
} else {
s->clear_range_selection ();
}
}
} else {
/* just a click, no pointer movement.
*/

View File

@ -27,13 +27,22 @@
#include "ardour/types.h"
#include "canvas/types.h"
#include "cursor_context.h"
#include "editor_items.h"
#include "editing.h"
namespace ARDOUR {
class Location;
}
namespace ArdourCanvas {
class Item;
class Line;
class Rectangle;
}
namespace PBD {
class StatefulDiffCommand;
}
@ -45,6 +54,18 @@ class TimeAxisView;
class MidiTimeAxisView;
class Drag;
class NoteBase;
class RegionView;
class TimeAxisView;
class RouteTimeAxisView;
class RegionSelection;
class MidiRegionView;
class MeterMarker;
class Marker;
class TempoMarker;
class ControlPoint;
class AudioRegionView;
class AutomationLine;
class AutomationTimeAxisView;
/** Class to manage current drags */
class DragManager
@ -433,13 +454,13 @@ protected:
private:
TimeAxisView *prev_tav; // where regions were most recently dragged from
TimeAxisView *orig_tav; // where drag started
framecnt_t prev_amount;
framepos_t prev_position;
framecnt_t selection_length;
ARDOUR::framecnt_t prev_amount;
ARDOUR::framepos_t prev_position;
ARDOUR::framecnt_t selection_length;
bool allow_moves_across_tracks; // only if all selected regions are on one track
ARDOUR::RegionList *exclude;
void add_all_after_to_views (TimeAxisView *tav, framepos_t where, const RegionSelection &exclude, bool drag_in_progress);
void remove_unselected_from_views (framecnt_t amount, bool move_regions);
void add_all_after_to_views (TimeAxisView *tav, ARDOUR::framepos_t where, const RegionSelection &exclude, bool drag_in_progress);
void remove_unselected_from_views (ARDOUR::framecnt_t amount, bool move_regions);
};
@ -535,7 +556,7 @@ public:
private:
double y_to_region (double) const;
framecnt_t grid_frames (framepos_t) const;
ARDOUR::framecnt_t grid_frames (framepos_t) const;
MidiRegionView* _region_view;
ArdourCanvas::Rectangle* _drag_rect;

View File

@ -30,6 +30,7 @@
#include "control_protocol/control_protocol.h"
#include "editor_drag.h"
#include "editor.h"
#include "actions.h"
#include "audio_time_axis.h"
@ -652,9 +653,12 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
if (press)
goto out;
else {
get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
selection->set(all_equivalent_regions);
commit = true;
if (selection->regions.size() > 1) {
/* collapse region selection down to just this one region (and its equivalents) */
get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
selection->set(all_equivalent_regions);
commit = true;
}
}
}
break;
@ -1027,6 +1031,19 @@ Editor::time_selection_changed ()
} else {
ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
}
/* propagate into backend, but only when there is no drag or we are at
* the end of a drag, otherwise this is too expensive (could case a
* locate per mouse motion event.
*/
if (_session && !_drags->active()) {
if (selection->time.length() != 0) {
_session->set_range_selection (selection->time.start(), selection->time.end_frame());
} else {
_session->clear_range_selection ();
}
}
}
/** Set all region actions to have a given sensitivity */
@ -1337,6 +1354,17 @@ Editor::region_selection_changed ()
if (_session && !_session->transport_rolling() && !selection->regions.empty()) {
maybe_locate_with_edit_preroll (selection->regions.start());
}
/* propagate into backend */
if (_session) {
if (!selection->regions.empty()) {
_session->set_object_selection (selection->regions.start(), selection->regions.end_frame());
} else {
_session->clear_object_selection ();
}
}
}
void

View File

@ -65,6 +65,121 @@ using namespace PBD;
using namespace ARDOUR;
using namespace ARDOUR_UI_UTILS;
class AutoReturnTargetOptions : public OptionEditorBox
{
public:
AutoReturnTargetOptions (RCConfiguration* c, Gtk::Window* p)
: _rc_config (c)
, range_selection_button (_("Play Range Selection"))
, last_roll_button (_("Play from Last Roll"))
, loop_button (_("Play Loop"))
, region_selection_button (_("Play Region Selection"))
, toggle_button (_("Enable/Disable all options"))
{
_box->pack_start (range_selection_button, false, false);
range_selection_button.signal_toggled().connect (sigc::mem_fun (*this, &AutoReturnTargetOptions::range_selection_toggled));
_box->pack_start (loop_button, false, false);
loop_button.signal_toggled().connect (sigc::mem_fun (*this, &AutoReturnTargetOptions::loop_toggled));
_box->pack_start (region_selection_button, false, false);
region_selection_button.signal_toggled().connect (sigc::mem_fun (*this, &AutoReturnTargetOptions::region_selection_toggled));
_box->pack_start (last_roll_button, false, false);
last_roll_button.signal_toggled().connect (sigc::mem_fun (*this, &AutoReturnTargetOptions::last_roll_toggled));
HBox* hbox = manage (new HBox);
/* keep the toggle button small */
hbox->pack_start (toggle_button, false, false);
_box->pack_start (*hbox, false, false);
toggle_button.signal_clicked().connect (sigc::mem_fun (*this, &AutoReturnTargetOptions::toggle));
Gtkmm2ext::UI::instance()->set_tip (range_selection_button,
_("If enabled, playhead will always start from the beginning of the current range selection.\n\nIf disabled or no range selection, see the next choice in this list"));
Gtkmm2ext::UI::instance()->set_tip (loop_button,
_("If enabled, playhead will always start from the beginning of the loop range.\n\nIf disabled or no loop range, see the next choice in this list"));
Gtkmm2ext::UI::instance()->set_tip (region_selection_button,
_("If enabled, playhead will always start from the beginning of the first selected region.\n\nIf disabled or no region selection, see the next choice in this list"));
Gtkmm2ext::UI::instance()->set_tip (last_roll_button,
_("If enabled, playhead will always start from the last position where it was started.\n\nIf disabled it will start from wherever it is currently located"));
Gtkmm2ext::UI::instance()->set_tip (toggle_button,
_("Change status of all buttons above to all enabled or all disabled"));
}
void parameter_changed (string const & p)
{
if (p == "auto-return-target-list") {
AutoReturnTarget art = _rc_config->get_auto_return_target_list();
range_selection_button.set_active (art & RangeSelectionStart);
loop_button.set_active (art & Loop);
region_selection_button.set_active (art & RegionSelectionStart);
last_roll_button.set_active (art & LastLocate);
}
}
void set_state_from_config ()
{
parameter_changed ("auto-return-target-list");
}
private:
void range_selection_toggled () {
AutoReturnTarget art = _rc_config->get_auto_return_target_list ();
if (range_selection_button.get_active ()) {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art | RangeSelectionStart));
} else {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art & ~RangeSelectionStart));
}
}
void last_roll_toggled () {
AutoReturnTarget art = _rc_config->get_auto_return_target_list ();
if (last_roll_button.get_active ()) {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art | LastLocate));
} else {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art & ~LastLocate));
}
}
void region_selection_toggled () {
AutoReturnTarget art = _rc_config->get_auto_return_target_list ();
if (region_selection_button.get_active ()) {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art | RegionSelectionStart));
} else {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art & ~RegionSelectionStart));
}
}
void loop_toggled () {
AutoReturnTarget art = _rc_config->get_auto_return_target_list ();
if (loop_button.get_active ()) {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art | Loop));
} else {
_rc_config->set_auto_return_target_list (AutoReturnTarget (art & ~Loop));
}
}
void toggle () {
AutoReturnTarget art = _rc_config->get_auto_return_target_list ();
if (art) {
_rc_config->set_auto_return_target_list (AutoReturnTarget (0));
} else {
_rc_config->set_auto_return_target_list (AutoReturnTarget (RangeSelectionStart|
RegionSelectionStart|
Loop|
LastLocate));
}
}
RCConfiguration* _rc_config;
Gtk::CheckButton range_selection_button;
Gtk::CheckButton last_roll_button;
Gtk::CheckButton loop_button;
Gtk::CheckButton region_selection_button;
Gtk::Button toggle_button;
};
class ClickOptions : public OptionEditorBox
{
public:
@ -1381,6 +1496,10 @@ RCOptionEditor::RCOptionEditor ()
/* TRANSPORT */
add_option (_("Transport"), new OptionEditorHeading (S_("Playhead Behaviour")));
add_option (_("Transport"), new AutoReturnTargetOptions (_rc_config, this));
add_option (_("Transport"), new OptionEditorHeading (S_("Transport Options")));
BoolOption* tsf;
tsf = new BoolOption (

View File

@ -142,6 +142,7 @@ CONFIG_VARIABLE (ShuttleBehaviour, shuttle_behaviour, "shuttle-behaviour", Sprun
CONFIG_VARIABLE (ShuttleUnits, shuttle_units, "shuttle-units", Percentage)
CONFIG_VARIABLE (bool, locate_while_waiting_for_sync, "locate-while-waiting-for-sync", false)
CONFIG_VARIABLE (bool, disable_disarm_during_roll, "disable-disarm-during-roll", false)
CONFIG_VARIABLE (AutoReturnTarget, auto_return_target_list, "auto-return-target-list", AutoReturnTarget(LastLocate|RangeSelectionStart|Loop|RegionSelectionStart))
/* metering */

View File

@ -774,6 +774,14 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void maybe_update_session_range (framepos_t, framepos_t);
/* temporary hacks to allow selection to be pushed from GUI into backend.
Whenever we move the selection object into libardour, these will go away.
*/
void set_range_selection (framepos_t start, framepos_t end);
void set_object_selection (framepos_t start, framepos_t end);
void clear_range_selection ();
void clear_object_selection ();
/* buffers for gain and pan */
gain_t* gain_automation_buffer () const;
@ -1339,13 +1347,15 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void post_transport ();
void engine_halted ();
void xrun_recovery ();
bool select_playhead_priority_target (framepos_t&);
void follow_playhead_priority ();
/* These are synchronous and so can only be called from within the process
* cycle
*/
/* These are synchronous and so can only be called from within the process
* cycle
*/
int send_full_time_code (framepos_t, pframes_t nframes);
void send_song_position_pointer (framepos_t);
int send_full_time_code (framepos_t, pframes_t nframes);
void send_song_position_pointer (framepos_t);
TempoMap *_tempo_map;
void tempo_map_changed (const PBD::PropertyChange&);
@ -1558,6 +1568,12 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void set_play_range (std::list<AudioRange>&, bool leave_rolling);
void unset_play_range ();
/* temporary hacks to allow selection to be pushed from GUI into backend
Whenever we move the selection object into libardour, these will go away.
*/
Evoral::Range<framepos_t> _range_selection;
Evoral::Range<framepos_t> _object_selection;
/* main outs */
uint32_t main_outs;

View File

@ -612,6 +612,13 @@ namespace ARDOUR {
uint32_t max; //< samples
};
enum AutoReturnTarget {
LastLocate = 0x1,
RangeSelectionStart = 0x2,
Loop = 0x4,
RegionSelectionStart = 0x8,
};
} // namespace ARDOUR
@ -636,6 +643,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::DenormalModel& sf);
std::istream& operator>>(std::istream& o, ARDOUR::PositionLockStyle& sf);
std::istream& operator>>(std::istream& o, ARDOUR::FadeShape& sf);
std::istream& operator>>(std::istream& o, ARDOUR::RegionSelectionAfterSplit& sf);
std::istream& operator>>(std::istream& o, ARDOUR::AutoReturnTarget& sf);
std::ostream& operator<<(std::ostream& o, const ARDOUR::SampleFormat& sf);
std::ostream& operator<<(std::ostream& o, const ARDOUR::HeaderFormat& sf);
@ -655,6 +663,7 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::DenormalModel& sf);
std::ostream& operator<<(std::ostream& o, const ARDOUR::PositionLockStyle& sf);
std::ostream& operator<<(std::ostream& o, const ARDOUR::FadeShape& sf);
std::ostream& operator<<(std::ostream& o, const ARDOUR::RegionSelectionAfterSplit& sf);
std::ostream& operator<<(std::ostream& o, const ARDOUR::AutoReturnTarget& sf);
/* because these operators work on types which can be used when making

View File

@ -127,7 +127,8 @@ setup_enum_writer ()
Session::SlaveState _Session_SlaveState;
MTC_Status _MIDI_MTC_Status;
Evoral::OverlapType _OverlapType;
AutoReturnTarget _AutoReturnTarget;
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
@ -640,6 +641,13 @@ setup_enum_writer ()
REGISTER_ENUM (Evoral::OverlapEnd);
REGISTER_ENUM (Evoral::OverlapExternal);
REGISTER(_OverlapType);
REGISTER_ENUM (LastLocate);
REGISTER_ENUM (RangeSelectionStart);
REGISTER_ENUM (Loop);
REGISTER_ENUM (RegionSelectionStart);
REGISTER_BITS (_AutoReturnTarget);
}
} /* namespace ARDOUR */
@ -957,3 +965,17 @@ std::ostream& operator<<(std::ostream& o, const RegionSelectionAfterSplit& var)
std::string s = enum_2_string (var);
return o << s;
}
std::istream& operator>>(std::istream& o, AutoReturnTarget& var)
{
std::string s;
o >> s;
var = (AutoReturnTarget) string_2_enum (s, var);
return o;
}
std::ostream& operator<<(std::ostream& o, const AutoReturnTarget& var)
{
std::string s = enum_2_string (var);
return o << s;
}

View File

@ -256,6 +256,8 @@ Session::Session (AudioEngine &eng,
, click_emphasis_length (0)
, _clicks_cleared (0)
, _play_range (false)
, _range_selection (-1,-1)
, _object_selection (-1,-1)
, main_outs (0)
, first_file_data_format_reset (true)
, first_file_header_format_reset (true)
@ -1204,6 +1206,19 @@ Session::auto_loop_changed (Location* location)
}
}
/* possibly move playhead if not rolling; if we are rolling we'll move
to the loop start on stop if that is appropriate.
*/
framepos_t pos;
if (!transport_rolling() && select_playhead_priority_target (pos)) {
if (pos == location->start()) {
request_locate (pos);
}
}
last_loopend = location->end();
}
@ -5368,3 +5383,31 @@ Session::reconnect_ltc_output ()
#endif
}
}
void
Session::set_range_selection (framepos_t start, framepos_t end)
{
_range_selection = Evoral::Range<framepos_t> (start, end);
follow_playhead_priority ();
}
void
Session::set_object_selection (framepos_t start, framepos_t end)
{
_object_selection = Evoral::Range<framepos_t> (start, end);
follow_playhead_priority ();
}
void
Session::clear_range_selection ()
{
_range_selection = Evoral::Range<framepos_t> (-1,-1);
follow_playhead_priority ();
}
void
Session::clear_object_selection ()
{
_object_selection = Evoral::Range<framepos_t> (-1,-1);
follow_playhead_priority ();
}

View File

@ -3516,6 +3516,8 @@ Session::config_changed (std::string p, bool ours)
reconnect_ltc_output ();
} else if (p == "timecode-generator-offset") {
ltc_tx_parse_offset();
} else if (p == "auto-return-target-list") {
follow_playhead_priority ();
}
set_dirty ();

View File

@ -459,6 +459,69 @@ Session::non_realtime_locate ()
clear_clicks ();
}
bool
Session::select_playhead_priority_target (framepos_t& jump_to)
{
jump_to = -1;
AutoReturnTarget autoreturn = Config->get_auto_return_target_list ();
if (!autoreturn) {
return false;
}
/* Note that the order of checking each AutoReturnTarget flag defines
the priority each flag.
*/
if (autoreturn & LastLocate) {
jump_to = _last_roll_location;
}
if (jump_to < 0 && (autoreturn & RangeSelectionStart)) {
if (!_range_selection.empty()) {
jump_to = _range_selection.from;
} else {
if (transport_rolling()) {
/* Range selection no longer exists, but we're playing,
so do nothing. Next stop will put us where
we need to be.
*/
return false;
}
}
}
if (jump_to < 0 && (autoreturn & Loop)) {
/* don't try to handle loop play when synced to JACK */
if (!synced_to_engine()) {
Location *location = _locations->auto_loop_location();
if (location) {
jump_to = location->start();
}
}
}
if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
if (!_object_selection.empty()) {
jump_to = _object_selection.from;
}
}
return jump_to >= 0;
}
void
Session::follow_playhead_priority ()
{
framepos_t target;
if (select_playhead_priority_target (target)) {
request_locate (target);
}
}
void
Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
@ -542,8 +605,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
update_latency_compensation ();
}
bool const auto_return_enabled =
(!config.get_external_sync() && (config.get_auto_return() || abort));
bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
if (auto_return_enabled ||
(ptw & PostTransportLocate) ||
@ -569,40 +631,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
do_locate = true;
} else {
if (config.get_auto_return()) {
framepos_t jump_to;
if (play_loop) {
if (select_playhead_priority_target (jump_to)) {
/* don't try to handle loop play when synced to JACK */
_transport_frame = jump_to;
do_locate = true;
if (!synced_to_engine()) {
Location *location = _locations->auto_loop_location();
if (location != 0) {
_transport_frame = location->start();
} else {
_transport_frame = _last_roll_location;
}
do_locate = true;
}
} else if (_play_range) {
/* return to start of range */
if (!current_audio_range.empty()) {
_transport_frame = current_audio_range.front().start;
do_locate = true;
}
} else {
/* regular auto-return */
_transport_frame = _last_roll_location;
do_locate = true;
}
} else if (abort) {
_transport_frame = _last_roll_location;
@ -1138,7 +1173,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
}
_engine.transport_stop ();
} else {
bool const auto_return_enabled = (!config.get_external_sync() && (config.get_auto_return() || abort));
bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
if (!auto_return_enabled) {
_requested_return_frame = destination_frame;

View File

@ -32,6 +32,7 @@
<Option name="periodic-safety-backup-interval" value="120"/>
<Option name="timecode-format" value="timecode_30"/>
<Option name="seamless-loop" value="1"/>
<Option name="auto-return-target-list" value="RangeSelectionStart,Loop,RegionSelectionStart"/>
</Config>
<extra>
<Keyboard edit-button="3" edit-modifier="4" delete-button="3" delete-modifier="1" snap-modifier="32"/>

167
tools/sfrtest.cc Normal file
View File

@ -0,0 +1,167 @@
/* g++ -o sfrtest sfrtest.cc `pkg-config --cflags --libs sndfile` `pkg-config --cflags --libs glibmm-2.4` */
#include <vector>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
#include <cerrno>
#include <unistd.h>
#include <sndfile.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
using namespace std;
SF_INFO format_info;
float* data = 0;
bool with_sync = false;
int
read_one (SNDFILE* sf, uint32_t nframes)
{
if (sf_read_float (sf, (float*) data, nframes) != nframes) {
return -1;
}
if (with_sync) {
sf_write_sync (sf);
}
return 0;
}
void
usage ()
{
cout << "sfrtest [ -n NFILES ] [ -b BLOCKSIZE ] [ -s ] [ -D ] filename-template" << endl;
}
int
main (int argc, char* argv[])
{
vector<SNDFILE*> sndfiles;
uint32_t sample_size;
char optstring[] = "n:b:s";
uint32_t block_size = 64 * 1024;
uint32_t nfiles = 100;
bool direct = false;
const struct option longopts[] = {
{ "nfiles", 1, 0, 'n' },
{ "blocksize", 1, 0, 'b' },
{ "sync", 0, 0, 's' },
{ "direct", 0, 0, 'D' },
{ 0, 0, 0, 0 }
};
int option_index = 0;
int c = 0;
char const * name_template = 0;
int samplerate;
while (1) {
if ((c = getopt_long (argc, argv, optstring, longopts, &option_index)) == -1) {
break;
}
switch (c) {
case 'n':
nfiles = atoi (optarg);
break;
case 'b':
block_size = atoi (optarg);
break;
case 's':
with_sync = true;
break;
case 'D':
direct = true;
break;
default:
usage ();
return 0;
}
}
if (optind < argc) {
name_template = argv[optind];
} else {
usage ();
return 1;
}
for (uint32_t n = 1; n <= nfiles; ++n) {
SNDFILE* sf;
char path[PATH_MAX+1];
snprintf (path, sizeof (path), name_template, n);
if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
break;
}
int flags = O_RDONLY;
int fd = open (path, flags, 0644);
if (fd < 0) {
cerr << "Could not open file #" << n << " @ " << path << " (" << strerror (errno) << ")" << endl;
return 1;
}
#ifdef __APPLE__
if (direct) {
/* Apple man pages say only that it returns "a value other than -1 on success",
which probably means zero, but you just can't be too careful with
those guys.
*/
if (fcntl (fd, F_NOCACHE, 1) == -1) {
cerr << "Cannot set F_NOCACHE on file # " << n << endl;
}
}
#endif
if ((sf = sf_open_fd (fd, SFM_READ, &format_info, true)) == 0) {
cerr << "Could not open SNDFILE #" << n << " @ " << path << " (" << sf_strerror (0) << ")" << endl;
return 1;
}
samplerate = format_info.samplerate;
sndfiles.push_back (sf);
}
cout << "Discovered " << nfiles+1 << " files using " << name_template << endl;
data = new float[block_size];
uint64_t read = 0;
while (true) {
gint64 before;
before = g_get_monotonic_time();
for (vector<SNDFILE*>::iterator s = sndfiles.begin(); s != sndfiles.end(); ++s) {
if (read_one (*s, block_size)) {
cerr << "Read failed for file #" << distance (sndfiles.begin(), s) << endl;
return 1;
}
}
read += block_size;
gint64 elapsed = g_get_monotonic_time() - before;
double bandwidth = (sndfiles.size() * block_size * sample_size) / (elapsed/1000000.0);
double data_minutes = read / (double) (60.0 * 48000.0);
const double data_rate = sndfiles.size() * sample_size * samplerate;
stringstream ds;
ds << setprecision (1) << data_minutes;
cout << "BW @ " << read << " frames (" << ds.str() << " minutes) = " << (bandwidth/1048576.0) << " MB/sec " << bandwidth / data_rate << " x faster than necessary " << endl;
}
return 0;
}