Compare commits
13 Commits
master
...
playhead-p
Author | SHA1 | Date |
---|---|---|
|
9630d83573 | |
|
5cdd708648 | |
|
7163d9db3e | |
|
dd4b65412f | |
|
35c50cdf6e | |
|
d7fb135e5c | |
|
e7b634c977 | |
|
6765889807 | |
|
ab7d69539d | |
|
574763c65e | |
|
f5a1d2cbe7 | |
|
dd91e6b375 | |
|
7caa67b9ac |
|
@ -76,7 +76,7 @@ ArdourDropdown::clear_items ()
|
|||
}
|
||||
|
||||
void
|
||||
ArdourDropdown::AddMenuElem (Menu_Helpers::MenuElem e)
|
||||
ArdourDropdown::AddMenuElem (Menu_Helpers::Element e)
|
||||
{
|
||||
using namespace Menu_Helpers;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue