Merge branch 'ardour'
This commit is contained in:
commit
be4dab7336
@ -754,7 +754,7 @@ ARDOUR_UI::check_memory_locking ()
|
||||
|
||||
XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
|
||||
|
||||
if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
|
||||
if (memory_warning_node == 0) {
|
||||
|
||||
struct rlimit limits;
|
||||
int64_t ram;
|
||||
|
@ -5516,7 +5516,12 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
|
||||
void
|
||||
Editor::set_loop_range (timepos_t const & start, timepos_t const & end, string cmd)
|
||||
{
|
||||
if (!_session) return;
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
if (_session->get_play_loop () && _session->actively_recording ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
begin_reversible_command (cmd);
|
||||
|
||||
|
@ -84,6 +84,10 @@ EditorSnapshots::button_press (GdkEventButton* ev)
|
||||
int cx;
|
||||
int cy;
|
||||
_snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
_snapshot_display.get_selection()->select (path);
|
||||
Gtk::TreeModel::iterator iter = _snapshot_model->get_iter (path);
|
||||
if (iter) {
|
||||
Gtk::TreeModel::Row row = *iter;
|
||||
@ -97,6 +101,9 @@ EditorSnapshots::button_press (GdkEventButton* ev)
|
||||
int cy;
|
||||
string snap_name;
|
||||
_snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
Gtk::TreeModel::iterator iter = _snapshot_model->get_iter (path);
|
||||
if (iter) {
|
||||
Gtk::TreeModel::Row row = *iter;
|
||||
|
@ -89,7 +89,7 @@ InsertRemoveTimeDialog::InsertRemoveTimeDialog (PublicEditor& e, bool remove)
|
||||
_intersected_combo.append (_("stay in position"));
|
||||
_intersected_combo.append (_("move"));
|
||||
_intersected_combo.append (_("be split"));
|
||||
_intersected_combo.set_active (0);
|
||||
_intersected_combo.set_active (2);
|
||||
table->attach (_intersected_combo, 1, 2, 2, 3);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <glib.h>
|
||||
#include <glibmm/timer.h>
|
||||
@ -42,7 +41,6 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct ERect{
|
||||
@ -319,9 +317,8 @@ any Xevents to all the UI callbacks plugins 'may' have registered on their
|
||||
windows, that is if they don't manage their own UIs **/
|
||||
|
||||
static void*
|
||||
gui_event_loop (void* ptr)
|
||||
gui_event_loop (void*)
|
||||
{
|
||||
pthread_set_name ("LXVSTEventLoop");
|
||||
VSTState* vstfx;
|
||||
int LXVST_sched_timer_interval = 40; //ms, 25fps
|
||||
XEvent event;
|
||||
@ -509,20 +506,6 @@ int vstfx_init (void* ptr)
|
||||
assert (gui_state == -1);
|
||||
pthread_mutex_init (&plugin_mutex, NULL);
|
||||
|
||||
int thread_create_result;
|
||||
|
||||
pthread_attr_t thread_attributes;
|
||||
|
||||
/*Init the attribs to defaults*/
|
||||
|
||||
pthread_attr_init (&thread_attributes);
|
||||
|
||||
/*Make sure the thread is joinable - this should be the default anyway -
|
||||
so we can join to it on vstfx_exit*/
|
||||
|
||||
pthread_attr_setdetachstate (&thread_attributes, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
|
||||
/*This is where we need to open a connection to X, and start the GUI thread*/
|
||||
|
||||
/*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
|
||||
@ -546,7 +529,7 @@ int vstfx_init (void* ptr)
|
||||
|
||||
/*Create the thread - use default attrs for now, don't think we need anything special*/
|
||||
|
||||
thread_create_result = pthread_create (&LXVST_gui_event_thread, &thread_attributes, gui_event_loop, NULL);
|
||||
int thread_create_result = pthread_create_and_store ("LXVSTEventLoop", &LXVST_gui_event_thread, gui_event_loop, NULL, 0);
|
||||
|
||||
if (thread_create_result != 0)
|
||||
{
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "ardour/route_group.h"
|
||||
#include "ardour/selection.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/utils.h"
|
||||
#include "ardour/vca.h"
|
||||
#include "ardour/vca_manager.h"
|
||||
|
||||
@ -1063,7 +1064,7 @@ Mixer_UI::fan_out (std::weak_ptr<Route> wr, bool to_busses, bool group)
|
||||
return;
|
||||
}
|
||||
|
||||
#define BUSNAME pd.group_name + "(" + route->name () + ")"
|
||||
#define BUSNAME legalize_for_universal_path (pd.group_name + " (" + route->name () + ")")
|
||||
|
||||
/* count busses and channels/bus */
|
||||
std::shared_ptr<Plugin> plugin = pi->plugin ();
|
||||
@ -4481,7 +4482,7 @@ Mixer_UI::toggle_surround_master ()
|
||||
if (want_sm) {
|
||||
_session->config.set_use_surround_master (true);
|
||||
} else {
|
||||
ArdourMessageDialog md (_("Disabling surround master will delete all existing surround panner state.\nThis cannot be undonoe. Proceed anyway?"), false, MESSAGE_QUESTION, BUTTONS_YES_NO);
|
||||
ArdourMessageDialog md (_("Disabling surround master will delete all existing surround panner state.\nThis cannot be undone. Proceed anyway?"), false, MESSAGE_QUESTION, BUTTONS_YES_NO);
|
||||
if (md.run () == RESPONSE_YES) {
|
||||
_session->config.set_use_surround_master (false);
|
||||
}
|
||||
|
@ -97,7 +97,6 @@ build_query_string (ArdourCurl::HttpGet const & h)
|
||||
static void*
|
||||
_pingback (void *arg)
|
||||
{
|
||||
pthread_set_name ("Pingback");
|
||||
ArdourCurl::HttpGet h;
|
||||
|
||||
//initialize curl
|
||||
@ -177,7 +176,7 @@ void pingback (const string& version, const string& announce_path)
|
||||
ping_call* cm = new ping_call (version, announce_path);
|
||||
pthread_t thread;
|
||||
|
||||
pthread_create_and_store ("pingback", &thread, _pingback, cm);
|
||||
pthread_create_and_store ("Pingback", &thread, _pingback, cm);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1356,7 +1356,6 @@ RouteTimeAxisView::find_next_region_boundary (timepos_t const & pos, int32_t dir
|
||||
void
|
||||
RouteTimeAxisView::fade_range (TimeSelection& selection)
|
||||
{
|
||||
std::shared_ptr<Playlist> what_we_got;
|
||||
std::shared_ptr<Track> tr = track ();
|
||||
std::shared_ptr<Playlist> playlist;
|
||||
|
||||
@ -1374,11 +1373,7 @@ RouteTimeAxisView::fade_range (TimeSelection& selection)
|
||||
|
||||
playlist->fade_range (time);
|
||||
|
||||
vector<Command*> cmds;
|
||||
playlist->rdiff (cmds);
|
||||
_session->add_commands (cmds);
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
|
||||
playlist->rdiff_and_add_command (_session);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -111,6 +111,8 @@ string2miditracknamesource (string const & str)
|
||||
return SMFTrackNumber;
|
||||
} else if (str == _("by track name")) {
|
||||
return SMFTrackName;
|
||||
} else if (str == _("by file and track name")) {
|
||||
return SMFFileAndTrackName;
|
||||
} else if (str == _("by instrument name")) {
|
||||
return SMFInstrumentName;
|
||||
}
|
||||
@ -1987,6 +1989,7 @@ SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
|
||||
str.clear ();
|
||||
str.push_back (_("by track number"));
|
||||
str.push_back (_("by track name"));
|
||||
str.push_back (_("by file and track name"));
|
||||
str.push_back (_("by instrument name"));
|
||||
set_popdown_strings (midi_track_name_combo, str);
|
||||
midi_track_name_combo.set_active_text (str.front());
|
||||
|
@ -132,7 +132,7 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
|
||||
/* Create a thread which runs while the dialogue is open to compute the silence regions */
|
||||
Completed.connect (_completed_connection, invalidator(*this), boost::bind (&StripSilenceDialog::update, this), gui_context ());
|
||||
_thread_should_finish = false;
|
||||
pthread_create (&_thread, 0, StripSilenceDialog::_detection_thread_work, this);
|
||||
pthread_create_and_store ("SilenceDetect", &_thread, StripSilenceDialog::_detection_thread_work, this, 0);
|
||||
|
||||
signal_response().connect(sigc::mem_fun (*this, &StripSilenceDialog::finished));
|
||||
}
|
||||
@ -248,7 +248,6 @@ void *
|
||||
StripSilenceDialog::_detection_thread_work (void* arg)
|
||||
{
|
||||
StripSilenceDialog* d = reinterpret_cast<StripSilenceDialog*> (arg);
|
||||
pthread_set_name ("SilenceDetect");
|
||||
return d->detection_thread_work ();
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@
|
||||
<ColorAlias name="location marker" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="location punch" alias="widget:ruddy"/>
|
||||
<ColorAlias name="location range" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="location arrangement marker" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="location arrangement marker" alias="theme:contrasting alt"/>
|
||||
<ColorAlias name="lock button: fill active" alias="widget:bg"/>
|
||||
<ColorAlias name="lock button: led active" alias="alert:red"/>
|
||||
<ColorAlias name="lua action button: fill" alias="widget:bg"/>
|
||||
@ -308,16 +308,19 @@
|
||||
<ColorAlias name="nudge clock: text" alias="theme:contrasting clock"/>
|
||||
<ColorAlias name="page switch button: fill" alias="widget:bg"/>
|
||||
<ColorAlias name="page switch button: fill active" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="pan knob" alias="widget:bg"/>
|
||||
<ColorAlias name="pan knob: arc end" alias="widget:orange"/>
|
||||
<ColorAlias name="pan knob: arc start" alias="widget:orange"/>
|
||||
<ColorAlias name="patch change button unnamed: fill" alias="neutral:background2"/>
|
||||
<ColorAlias name="patch change button unnamed: fill active" alias="widget:blue"/>
|
||||
<ColorAlias name="patch change button: fill" alias="widget:bg"/>
|
||||
<ColorAlias name="patch change button: fill active" alias="widget:blue"/>
|
||||
<ColorAlias name="piano key black" alias="neutral:background2"/>
|
||||
<ColorAlias name="piano key highlight" alias="alert:ruddy"/>
|
||||
<ColorAlias name="piano key white" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="piano roll black" alias="theme:contrasting selection"/>
|
||||
<ColorAlias name="piano roll black outline" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="piano roll white" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="piano key black" alias="neutral:background2"/>
|
||||
<ColorAlias name="piano key white" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="piano key highlight" alias="alert:ruddy"/>
|
||||
<ColorAlias name="pinrouting custom: led active" alias="alert:ruddy"/>
|
||||
<ColorAlias name="pinrouting sidechain: led active" alias="alert:green"/>
|
||||
<ColorAlias name="play head" alias="alert:orange"/>
|
||||
@ -363,8 +366,8 @@
|
||||
<ColorAlias name="range marker bar" alias="neutral:background"/>
|
||||
<ColorAlias name="record enable button: fill active" alias="alert:ruddy"/>
|
||||
<ColorAlias name="record enable button: led active" alias="alert:red"/>
|
||||
<ColorAlias name="recording rect" alias="alert:ruddy"/>
|
||||
<ColorAlias name="recording note" alias="neutral:foregroundest"/>
|
||||
<ColorAlias name="recording rect" alias="alert:ruddy"/>
|
||||
<ColorAlias name="recording waveform fill" alias="neutral:foregroundest"/>
|
||||
<ColorAlias name="recording waveform outline" alias="neutral:background2"/>
|
||||
<ColorAlias name="region automation line" alias="alert:blue"/>
|
||||
@ -414,8 +417,6 @@
|
||||
<ColorAlias name="send pan" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="shuttle" alias="widget:bg"/>
|
||||
<ColorAlias name="shuttle bg" alias="neutral:backgroundest"/>
|
||||
<ColorAlias name="vari button: fill" alias="widget:bg"/>
|
||||
<ColorAlias name="vari button: fill active" alias="alert:ruddy"/>
|
||||
<ColorAlias name="silence" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="silence text" alias="neutral:foreground"/>
|
||||
<ColorAlias name="solo button: fill" alias="widget:bg"/>
|
||||
@ -445,7 +446,7 @@
|
||||
<ColorAlias name="stretch clock: edited text" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="stretch clock: text" alias="theme:contrasting clock"/>
|
||||
<ColorAlias name="sync mark" alias="theme:contrasting clock"/>
|
||||
<ColorAlias name="region mark" alias="theme:contrasting less"/>
|
||||
<ColorAlias name="region mark" alias="theme:contrasting alt"/>
|
||||
<ColorAlias name="tempo bar" alias="neutral:background2"/>
|
||||
<ColorAlias name="tempo curve" alias="widget:blue"/>
|
||||
<ColorAlias name="tempo marker" alias="widget:orange"/>
|
||||
@ -486,9 +487,8 @@
|
||||
<ColorAlias name="trim knob" alias="widget:bg"/>
|
||||
<ColorAlias name="trim knob: arc end" alias="widget:blue"/>
|
||||
<ColorAlias name="trim knob: arc start" alias="widget:blue"/>
|
||||
<ColorAlias name="pan knob" alias="widget:bg"/>
|
||||
<ColorAlias name="pan knob: arc end" alias="widget:orange"/>
|
||||
<ColorAlias name="pan knob: arc start" alias="widget:orange"/>
|
||||
<ColorAlias name="vari button: fill" alias="widget:bg"/>
|
||||
<ColorAlias name="vari button: fill active" alias="alert:ruddy"/>
|
||||
<ColorAlias name="vca assign button: fill" alias="widget:bg"/>
|
||||
<ColorAlias name="verbose canvas cursor" alias="theme:contrasting clock"/>
|
||||
<ColorAlias name="video timeline bar" alias="neutral:background2"/>
|
||||
|
@ -315,7 +315,7 @@ UIConfiguration::color_file_name (bool use_my, bool with_version, bool fallback)
|
||||
std::string rev (revision);
|
||||
std::size_t pos = rev.find_first_of("-");
|
||||
|
||||
if (with_version && pos != string::npos && pos > 0) {
|
||||
if (with_version && pos > 0) {
|
||||
basename += "-";
|
||||
basename += rev.substr (0, pos); // COLORFILE_VERSION - program major.minor
|
||||
}
|
||||
@ -364,12 +364,6 @@ UIConfiguration::load_color_theme (bool allow_own)
|
||||
if (find_file (sp, color_file_name (true, true), cfile)) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (find_file (sp, color_file_name (true, false), cfile)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now search for a versioned color file (for this major.minor version) CURRENTLY UNUSED */
|
||||
@ -439,7 +433,7 @@ UIConfiguration::store_color_theme ()
|
||||
root->add_child_nocopy (*parent);
|
||||
|
||||
XMLTree tree;
|
||||
std::string colorfile = Glib::build_filename (user_config_directory(), color_file_name (true, true));;
|
||||
std::string colorfile = Glib::build_filename (user_config_directory(), color_file_name (true, true));
|
||||
|
||||
tree.set_root (root);
|
||||
|
||||
|
@ -770,7 +770,9 @@ string
|
||||
ARDOUR_UI_UTILS::rate_as_string (float r)
|
||||
{
|
||||
char buf[32];
|
||||
if (fmod (r, 1000.0f)) {
|
||||
if (fmod (r, 100.0f)) {
|
||||
snprintf (buf, sizeof (buf), "%.2f kHz", r / 1000.0);
|
||||
} else if (fmod (r, 1000.0f)) {
|
||||
snprintf (buf, sizeof (buf), "%.1f kHz", r / 1000.0);
|
||||
} else {
|
||||
snprintf (buf, sizeof (buf), "%.0f kHz", r / 1000.0);
|
||||
|
@ -274,6 +274,8 @@ VideoImageFrame::http_get (samplepos_t fn) {
|
||||
queued_request=false;
|
||||
req_video_frame_number=fn;
|
||||
pthread_mutex_unlock(&queue_lock);
|
||||
/* do not use `pbd pthread_create_and_store' here.
|
||||
* The request thread uses aync cancellation */
|
||||
int rv = pthread_create(&thread_id_tt, NULL, http_get_thread, this);
|
||||
thread_active=true;
|
||||
if (rv) {
|
||||
|
@ -164,7 +164,7 @@ public:
|
||||
/** Return true if the backed is JACK */
|
||||
virtual bool is_jack () const { return false; }
|
||||
|
||||
virtual int client_real_time_priority () { return PBD_RT_PRI_PROC; }
|
||||
virtual int client_real_time_priority () { return 0; }
|
||||
|
||||
/* Discovering devices and parameters */
|
||||
|
||||
|
@ -115,9 +115,6 @@ class LIBARDOUR_API AudioEngine : public PortManager, public SessionHandlePtr
|
||||
void request_device_list_update();
|
||||
void launch_device_control_app();
|
||||
|
||||
int client_real_time_priority ();
|
||||
bool is_realtime() const;
|
||||
|
||||
// for the user which hold state_lock to check if reset operation is pending
|
||||
bool is_reset_requested() const { return _hw_reset_request_count.load(); }
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include "pbd/gstdio_compat.h"
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
#include "ardour/export_pointers.h"
|
||||
#include "ardour/session.h"
|
||||
@ -146,7 +147,13 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory, public sigc::tr
|
||||
|
||||
/* Timespan management */
|
||||
|
||||
static void* start_timespan_bg (void*);
|
||||
void timespan_thread_wakeup ();
|
||||
|
||||
static void* _timespan_thread_run (void*);
|
||||
PBD::Thread* _timespan_thread;
|
||||
std::atomic<int> _timespan_thread_active;
|
||||
pthread_mutex_t _timespan_mutex;
|
||||
pthread_cond_t _timespan_cond;
|
||||
|
||||
int start_timespan ();
|
||||
int process_timespan (samplecnt_t samples);
|
||||
|
@ -227,6 +227,7 @@ CONFIG_VARIABLE (bool, allow_special_bus_removal, "allow-special-bus-removal", f
|
||||
CONFIG_VARIABLE (int32_t, processor_usage, "processor-usage", -1)
|
||||
CONFIG_VARIABLE (int32_t, cpu_dma_latency, "cpu-dma-latency", -1) /* >=0 to enable */
|
||||
CONFIG_VARIABLE (int32_t, io_thread_count, "io-thread-count", -2)
|
||||
CONFIG_VARIABLE (int32_t, io_thread_policy, "io-thread-policy", 0)
|
||||
CONFIG_VARIABLE (gain_t, max_gain, "max-gain", 2.0) /* +6.0dB */
|
||||
CONFIG_VARIABLE (uint32_t, max_recent_sessions, "max-recent-sessions", 10)
|
||||
CONFIG_VARIABLE (uint32_t, max_recent_templates, "max-recent-templates", 10)
|
||||
|
@ -559,7 +559,7 @@ public:
|
||||
std::shared_ptr<AutomationControl> mapped_control (enum WellKnownCtrl, uint32_t band = 0) const;
|
||||
std::shared_ptr<ReadOnlyControl> mapped_output (enum WellKnownData) const;
|
||||
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n) const;
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n, bool locked = false) const;
|
||||
std::shared_ptr<AutomationControl> send_enable_controllable (uint32_t n) const;
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_controllable (uint32_t n) const;
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_enable_controllable (uint32_t n) const;
|
||||
|
@ -299,7 +299,7 @@ public:
|
||||
RouteList new_route_from_template (uint32_t how_many, PresentationInfo::order_t insert_at, const std::string& template_path, const std::string& name, PlaylistDisposition pd = NewPlaylist);
|
||||
RouteList new_route_from_template (uint32_t how_many, PresentationInfo::order_t insert_at, XMLNode&, const std::string& name, PlaylistDisposition pd = NewPlaylist);
|
||||
std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path,
|
||||
uint32_t channels, std::vector<std::string> const & smf_track_names);
|
||||
uint32_t channels, std::vector<std::string> const & smf_track_names, bool use_smf_file_names);
|
||||
|
||||
int bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,std::string)> callback);
|
||||
|
||||
@ -812,7 +812,7 @@ public:
|
||||
|
||||
double engine_speed() const { return _engine_speed; }
|
||||
double actual_speed() const;
|
||||
double transport_speed() const;
|
||||
double transport_speed (bool incl_preroll = false) const;
|
||||
/** @return true if the transport state (TFSM) is stopped */
|
||||
bool transport_stopped() const;
|
||||
/** @return true if the transport state (TFSM) is stopped or stopping */
|
||||
@ -1659,10 +1659,11 @@ private:
|
||||
XMLTree* state_tree;
|
||||
StateOfTheState _state_of_the_state;
|
||||
|
||||
friend class StateProtector;
|
||||
std::atomic<int> _suspend_save;
|
||||
volatile bool _save_queued;
|
||||
volatile bool _save_queued_pending;
|
||||
friend class StateProtector;
|
||||
std::atomic<int> _suspend_save;
|
||||
volatile bool _save_queued;
|
||||
volatile bool _save_queued_pending;
|
||||
bool _no_save_signal;
|
||||
|
||||
Glib::Threads::Mutex save_state_lock;
|
||||
Glib::Threads::Mutex save_source_lock;
|
||||
|
@ -158,7 +158,7 @@ class LIBARDOUR_API Stripable : public SessionObject,
|
||||
* In Ardour, these are user-created sends that connect to user-created
|
||||
* Aux busses.
|
||||
*/
|
||||
virtual std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n, bool locked = false) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_enable_controllable (uint32_t n) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_pan_azimuth_controllable (uint32_t n) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_pan_azimuth_enable_controllable (uint32_t n) const = 0;
|
||||
|
@ -861,6 +861,7 @@ enum PlaylistDisposition {
|
||||
enum MidiTrackNameSource {
|
||||
SMFTrackNumber,
|
||||
SMFTrackName,
|
||||
SMFFileAndTrackName,
|
||||
SMFInstrumentName
|
||||
};
|
||||
|
||||
|
@ -134,7 +134,7 @@ class LIBARDOUR_API VCA : public Stripable,
|
||||
uint32_t eq_band_cnt () const { return 0; }
|
||||
std::string eq_band_name (uint32_t) const { return std::string(); }
|
||||
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n, bool locked = false) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_enable_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_enable_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
|
@ -359,6 +359,10 @@ private:
|
||||
bool _no_kMono;
|
||||
/* work around yabridge threading */
|
||||
bool _restart_component_is_synced;
|
||||
/* work around PSL calls during set_owner,
|
||||
* while the route holds a processor lock
|
||||
*/
|
||||
std::atomic<bool> _in_set_owner;
|
||||
};
|
||||
|
||||
} // namespace Steinberg
|
||||
|
@ -678,7 +678,6 @@ void
|
||||
AudioEngine::do_reset_backend()
|
||||
{
|
||||
SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 1024);
|
||||
pthread_set_name ("EngineWatchdog");
|
||||
|
||||
Glib::Threads::Mutex::Lock guard (_reset_request_lock);
|
||||
|
||||
@ -739,7 +738,6 @@ void
|
||||
AudioEngine::do_devicelist_update()
|
||||
{
|
||||
SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
|
||||
pthread_set_name ("DeviceList");
|
||||
|
||||
Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
|
||||
|
||||
@ -769,13 +767,13 @@ AudioEngine::start_hw_event_processing()
|
||||
if (_hw_reset_event_thread == 0) {
|
||||
_hw_reset_request_count.store (0);
|
||||
_stop_hw_reset_processing.store (0);
|
||||
_hw_reset_event_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
|
||||
_hw_reset_event_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this), "EngineWatchdog");
|
||||
}
|
||||
|
||||
if (_hw_devicelist_update_thread == 0) {
|
||||
_hw_devicelist_update_count.store (0);
|
||||
_stop_hw_devicelist_processing.store (0);
|
||||
_hw_devicelist_update_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
|
||||
_hw_devicelist_update_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this), "DeviceList");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1069,6 +1067,12 @@ AudioEngine::start (bool for_latency)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_backend->is_realtime ()) {
|
||||
pbd_set_engine_rt_priority (_backend->client_real_time_priority ());
|
||||
} else {
|
||||
pbd_set_engine_rt_priority (0);
|
||||
}
|
||||
|
||||
_running = true;
|
||||
|
||||
if (_session) {
|
||||
@ -1198,38 +1202,6 @@ AudioEngine::get_dsp_load() const
|
||||
return _backend->dsp_load ();
|
||||
}
|
||||
|
||||
bool
|
||||
AudioEngine::is_realtime() const
|
||||
{
|
||||
if (!_backend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _backend->is_realtime();
|
||||
}
|
||||
|
||||
int
|
||||
AudioEngine::client_real_time_priority ()
|
||||
{
|
||||
if (!_backend) {
|
||||
assert (0);
|
||||
return PBD_RT_PRI_PROC;
|
||||
}
|
||||
if (!_backend->is_realtime ()) {
|
||||
/* this is only an issue with the Dummy backend.
|
||||
* - with JACK, we require rt permissions.
|
||||
* - with ALSA/PulseAudio this can only happen if rt permissions
|
||||
* are n/a. Other attempts to get rt will fail likewise.
|
||||
*
|
||||
* perhaps:
|
||||
* TODO: use is_realtime () ? PBD_SCHED_FIFO : PBD_SCHED_OTHER
|
||||
*/
|
||||
return PBD_RT_PRI_PROC; // XXX
|
||||
}
|
||||
|
||||
return _backend->client_real_time_priority();
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::transport_start ()
|
||||
{
|
||||
|
@ -234,9 +234,9 @@ AudioRegion::register_properties ()
|
||||
, _fade_before_fx (Properties::fade_before_fx, other->_fade_before_fx) \
|
||||
, _scale_amplitude (Properties::scale_amplitude, other->_scale_amplitude) \
|
||||
, _fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_in.val()))) \
|
||||
, _inverse_fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_in.val()))) \
|
||||
, _fade_out (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_out.val()))) \
|
||||
, _inverse_fade_out (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_out.val())))
|
||||
, _inverse_fade_in (Properties::inverse_fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_in.val()))) \
|
||||
, _fade_out (Properties::fade_out, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_out.val()))) \
|
||||
, _inverse_fade_out (Properties::inverse_fade_out, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_out.val())))
|
||||
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
|
||||
|
||||
void
|
||||
@ -272,6 +272,7 @@ AudioRegion::send_change (const PropertyChange& what_changed)
|
||||
our_interests.add (Properties::envelope);
|
||||
our_interests.add (Properties::fade_in);
|
||||
our_interests.add (Properties::fade_out);
|
||||
our_interests.add (Properties::start);
|
||||
|
||||
if (what_changed.contains (our_interests)) {
|
||||
_invalidated.exchange (true);
|
||||
@ -733,7 +734,8 @@ AudioRegion::read_at (Sample* buf,
|
||||
boost::scoped_array<gain_t> gain_array;
|
||||
boost::scoped_array<Sample> mixdown_array;
|
||||
|
||||
// TODO optimize mono reader, w/o plugins -> old code
|
||||
bool nofx = false; // apply region fades at the end
|
||||
|
||||
if (n_chn > 1 && _cache_start < _cache_end && internal_offset + suffix >= _cache_start && internal_offset + suffix + can_read <= _cache_end) {
|
||||
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Region '%1' channel: %2 copy from cache %3 - %4 to_read: %5 can_read: %6\n",
|
||||
name(), chan_n, internal_offset + suffix, internal_offset + suffix + can_read, to_read, can_read));
|
||||
@ -746,11 +748,39 @@ AudioRegion::read_at (Sample* buf,
|
||||
lm.release ();
|
||||
|
||||
samplecnt_t n_read = to_read; //< data to read from disk
|
||||
samplecnt_t n_proc = to_read; //< silence pad data to process
|
||||
samplepos_t n_tail = 0; // further silence pad, read tail from FX
|
||||
samplepos_t readat = pos;
|
||||
sampleoffset_t offset = internal_offset;
|
||||
|
||||
/* don't use cache when there are no region FX */
|
||||
if (!have_fx) {
|
||||
cl.release ();
|
||||
if (read_from_sources (_sources, lsamples, mixdown_buffer, pos, n_read, chan_n) != to_read) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* APPLY REGULAR GAIN CURVES AND SCALING TO mixdown_buffer */
|
||||
if (envelope_active()) {
|
||||
_envelope->curve().get_vector (timepos_t (offset), timepos_t (offset + n_read), gain_buffer, n_read);
|
||||
|
||||
if (_scale_amplitude != 1.0f) {
|
||||
for (samplecnt_t n = 0; n < n_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
|
||||
}
|
||||
} else {
|
||||
for (samplecnt_t n = 0; n < n_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
} else if (_scale_amplitude != 1.0f) {
|
||||
apply_gain_to_buffer (mixdown_buffer, n_read, _scale_amplitude);
|
||||
}
|
||||
nofx = true;
|
||||
goto endread;
|
||||
}
|
||||
|
||||
samplecnt_t n_proc = to_read; //< silence pad data to process
|
||||
samplepos_t n_tail = 0; // further silence pad, read tail from FX
|
||||
samplepos_t readat = pos;
|
||||
|
||||
if (tsamples > 0 && cnt >= esamples) {
|
||||
n_tail = can_read - n_read;
|
||||
n_proc += n_tail;
|
||||
@ -799,7 +829,7 @@ AudioRegion::read_at (Sample* buf,
|
||||
*/
|
||||
|
||||
if (read_from_sources (_sources, lsamples, mixdown_buffer, readat, n_read, chn) != n_read) {
|
||||
return 0; // XXX
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* APPLY REGULAR GAIN CURVES AND SCALING TO mixdown_buffer */
|
||||
@ -907,6 +937,7 @@ AudioRegion::read_at (Sample* buf,
|
||||
_cache_tail = n_tail;
|
||||
cl.release ();
|
||||
}
|
||||
endread:
|
||||
|
||||
/* APPLY FADES TO THE DATA IN mixdown_buffer AND MIX THE RESULTS INTO
|
||||
* buf. The key things to realize here: (1) the fade being applied is
|
||||
@ -953,7 +984,7 @@ AudioRegion::read_at (Sample* buf,
|
||||
_fade_in->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + fade_in_limit), gain_buffer, fade_in_limit);
|
||||
}
|
||||
|
||||
if (!_fade_before_fx) {
|
||||
if (!_fade_before_fx || nofx) {
|
||||
/* Mix our newly-read data in, with the fade */
|
||||
for (samplecnt_t n = 0; n < fade_in_limit; ++n) {
|
||||
buf[n] += mixdown_buffer[n] * gain_buffer[n];
|
||||
@ -998,7 +1029,7 @@ AudioRegion::read_at (Sample* buf,
|
||||
_fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
|
||||
}
|
||||
|
||||
if (!_fade_before_fx) {
|
||||
if (!_fade_before_fx || nofx) {
|
||||
/* Mix our newly-read data with whatever was already there, with the fade out applied to our data. */
|
||||
for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
|
||||
buf[m] += mixdown_buffer[m] * gain_buffer[n];
|
||||
@ -1021,11 +1052,14 @@ AudioRegion::read_at (Sample* buf,
|
||||
mix_buffers_no_gain (buf + fade_in_limit, mixdown_buffer + fade_in_limit, N);
|
||||
}
|
||||
}
|
||||
|
||||
samplecnt_t T = _cache_tail;
|
||||
if (T > 0) {
|
||||
T = min (T, can_read);
|
||||
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Region %1 adding FX tail of %2 cut to_read %3 at %4 total len = %5 cnt was %6\n",
|
||||
name (), _cache_tail, T, to_read, to_read + T, cnt));
|
||||
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Region %1 adding FX tail of %2 cut to_read %3 at %4 total len = %5 cnt was %6\n",
|
||||
name (), _cache_tail, T, to_read, to_read + T, cnt));
|
||||
/* limit (to_read + T) == cnt, some cases (e.g. loop) will ignore tail data */
|
||||
T = min (T, cnt - to_read);
|
||||
/* AudioPlaylist::read reads regions in reverse order, so we can add the tail here */
|
||||
mix_buffers_no_gain (buf + to_read, mixdown_buffer + to_read, T);
|
||||
}
|
||||
@ -2538,6 +2572,13 @@ AudioRegion::remove_plugin (std::shared_ptr<RegionFxPlugin> fx)
|
||||
}
|
||||
_plugins.erase (i);
|
||||
|
||||
if (_plugins.empty ()) {
|
||||
Glib::Threads::Mutex::Lock cl (_cache_lock);
|
||||
_cache_start = _cache_end = -1;
|
||||
_cache_tail = 0;
|
||||
_readcache.clear ();
|
||||
}
|
||||
|
||||
lm.release ();
|
||||
|
||||
fx->drop_references ();
|
||||
|
@ -423,10 +423,6 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
|
||||
* least large enough for all the data in the audio file. if it
|
||||
* is too short, assume that a crash or other error truncated
|
||||
* it, and rebuild it from scratch.
|
||||
*
|
||||
* XXX this may not work for destructive recording, but we
|
||||
* might decided to get rid of that anyway.
|
||||
*
|
||||
*/
|
||||
|
||||
const off_t expected_file_size = (_length.samples() / (double) samples_per_file_peak) * sizeof (PeakData);
|
||||
@ -579,30 +575,36 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
|
||||
* to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
|
||||
*/
|
||||
|
||||
const samplecnt_t chunksize = (samplecnt_t) expected_peaks; // we read all the peaks we need in one hit.
|
||||
|
||||
/* compute the rounded up sample position */
|
||||
|
||||
samplepos_t current_stored_peak = (samplepos_t) ceil (start / (double) samples_per_file_peak);
|
||||
samplepos_t next_visual_peak = (samplepos_t) ceil (start / samples_per_visual_peak);
|
||||
double next_visual_peak_sample = next_visual_peak * samples_per_visual_peak;
|
||||
samplepos_t next_visual_peak = (samplepos_t) ceil (start / samples_per_visual_peak);
|
||||
double next_visual_peak_sample = next_visual_peak * samples_per_visual_peak;
|
||||
samplepos_t current_stored_peak = (samplepos_t) ceil (next_visual_peak_sample / (double) samples_per_file_peak);
|
||||
|
||||
samplepos_t stored_peak_before_next_visual_peak = (samplepos_t) next_visual_peak_sample / samples_per_file_peak;
|
||||
samplecnt_t nvisual_peaks = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
/* handle the case where the initial visual peak is on a pixel boundary */
|
||||
|
||||
current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
|
||||
|
||||
/* open ... close during out: handling */
|
||||
|
||||
off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
|
||||
off_t map_off = (uint32_t) (current_stored_peak) * sizeof(PeakData);
|
||||
off_t read_map_off = map_off & ~(bufsize - 1);
|
||||
off_t map_delta = map_off - read_map_off;
|
||||
off_t map_delta = map_off - read_map_off;
|
||||
|
||||
samplecnt_t max_chunk = (statbuf.st_size - read_map_off - map_delta) / sizeof(PeakData);
|
||||
samplecnt_t chunksize = std::min<samplecnt_t> (expected_peaks, max_chunk);
|
||||
|
||||
size_t raw_map_length = chunksize * sizeof(PeakData);
|
||||
size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
|
||||
size_t map_length = raw_map_length + map_delta;
|
||||
|
||||
assert (read_map_off + (off_t)map_length <= statbuf.st_size);
|
||||
assert (read_map_off + map_delta + (off_t)raw_map_length <= statbuf.st_size);
|
||||
|
||||
if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
|
||||
|
||||
/* offset between requested start, and first peak-file peak */
|
||||
samplecnt_t start_offset = next_visual_peak_sample - start;
|
||||
|
||||
peak_cache.reset (new PeakData[npeaks]);
|
||||
boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
|
||||
|
||||
@ -665,6 +667,22 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
|
||||
stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_sample / samples_per_file_peak;
|
||||
}
|
||||
|
||||
/* add data between start and sample corresponding to map_off */
|
||||
if (start_offset > 0) {
|
||||
boost::scoped_array<Sample> buf(new Sample[start_offset]);
|
||||
samplecnt_t samples_read = read_unlocked (buf.get(), start, start_offset);
|
||||
find_peaks (buf.get(), samples_read, &peak_cache[0].min, &peak_cache[0].max);
|
||||
}
|
||||
|
||||
/* fix end, add data not covered by Peak File */
|
||||
samplecnt_t last_sample_from_peakfile = current_stored_peak * samples_per_file_peak;
|
||||
if (last_sample_from_peakfile < start + cnt && nvisual_peaks > 0) {
|
||||
samplecnt_t to_read = start + cnt - last_sample_from_peakfile;
|
||||
boost::scoped_array<Sample> buf(new Sample[to_read]);
|
||||
samplecnt_t samples_read = read_unlocked (buf.get(), last_sample_from_peakfile, to_read);
|
||||
find_peaks (buf.get(), samples_read, &peak_cache[nvisual_peaks - 1].min, &peak_cache[nvisual_peaks - 1].max);
|
||||
}
|
||||
|
||||
if (zero_fill) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "Zero fill '" << _name << "' end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
|
||||
|
@ -201,8 +201,7 @@ AutomationWatch::timer ()
|
||||
void
|
||||
AutomationWatch::thread ()
|
||||
{
|
||||
pbd_set_thread_priority (pthread_self(), PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority() - 2); // XXX
|
||||
pthread_set_name ("AutomationWatch");
|
||||
pbd_set_thread_priority (pthread_self(), PBD_SCHED_FIFO, PBD_RT_PRI_CTRL);
|
||||
while (_run_thread) {
|
||||
Glib::usleep ((gulong) floor (Config->get_automation_interval_msecs() * 1000)); // TODO use pthread_cond_timedwait on _run_thread
|
||||
timer ();
|
||||
@ -224,7 +223,7 @@ AutomationWatch::set_session (Session* s)
|
||||
|
||||
if (_session) {
|
||||
_run_thread = true;
|
||||
_thread = PBD::Thread::create (boost::bind (&AutomationWatch::thread, this));
|
||||
_thread = PBD::Thread::create (boost::bind (&AutomationWatch::thread, this), "AutomationWatch");
|
||||
|
||||
_session->TransportStateChange.connect_same_thread (transport_connection, boost::bind (&AutomationWatch::transport_state_change, this));
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ Butler::start_thread ()
|
||||
|
||||
should_run = false;
|
||||
|
||||
if (pthread_create_and_store ("disk butler", &thread, _thread_work, this)) {
|
||||
if (pthread_create_and_store ("butler", &thread, _thread_work, this)) {
|
||||
error << _("Session: could not create butler thread") << endmsg;
|
||||
return -1;
|
||||
}
|
||||
@ -171,7 +171,6 @@ void*
|
||||
Butler::_thread_work (void* arg)
|
||||
{
|
||||
SessionEvent::create_per_thread_pool ("butler events", 4096);
|
||||
pthread_set_name (X_("butler"));
|
||||
/* get thread buffers for RegionFx */
|
||||
ARDOUR::ProcessThread* pt = new ProcessThread ();
|
||||
pt->get_buffers ();
|
||||
@ -273,7 +272,7 @@ Butler::thread_work ()
|
||||
RouteList rl_with_auditioner = *rl;
|
||||
rl_with_auditioner.push_back (_session.the_auditioner ());
|
||||
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("butler starts refill loop, twr = %1\n", transport_work_requested ()));
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("butler starts refill loop, twr = %1\n", should_do_transport_work.load ()));
|
||||
|
||||
std::shared_ptr<IOTaskList> tl = _session.io_tasklist ();
|
||||
|
||||
@ -413,8 +412,8 @@ Butler::flush_tracks_to_disk_normal (std::shared_ptr<RouteList const> rl, uint32
|
||||
void
|
||||
Butler::schedule_transport_work ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Butler, "requesting more transport work\n");
|
||||
should_do_transport_work.fetch_add (1);
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("requesting more transport work (now %1)\n", should_do_transport_work.load ()));
|
||||
summon ();
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ ControlProtocolManager::set_session (Session* s)
|
||||
usb_hotplug_cb, this,
|
||||
&_hpcp)) {
|
||||
_hotplug_thread_run = true;
|
||||
if (pthread_create (&_hotplug_thread, NULL, usb_hotplug_thread, this)) {
|
||||
if (pthread_create_and_store ("Ctrl USB Hotplug", &_hotplug_thread, usb_hotplug_thread, this, 0)) {
|
||||
_hotplug_thread_run = false;
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ Convolution::restart ()
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance ()->client_real_time_priority () - 1), PBD_SCHED_FIFO);
|
||||
rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, PBD_RT_PRI_PROC), PBD_SCHED_FIFO);
|
||||
}
|
||||
|
||||
assert (rv == 0); // bail out in debug builds
|
||||
|
@ -113,9 +113,10 @@ DiskReader::ReaderChannelInfo::resize_preloop (samplecnt_t bufsize)
|
||||
int
|
||||
DiskReader::add_channel_to (std::shared_ptr<ChannelList> c, uint32_t how_many)
|
||||
{
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler ()->audio_playback_buffer_size ());
|
||||
while (how_many--) {
|
||||
c->push_back (new ReaderChannelInfo (_session.butler ()->audio_playback_buffer_size (), loop_fade_length));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: new reader channel, write space = %2 read = %3\n",
|
||||
c->push_back (new ReaderChannelInfo (bufsz, loop_fade_length));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': new reader channel, write space = %2 read = %3\n",
|
||||
name (),
|
||||
c->back ()->rbuf->write_space (),
|
||||
c->back ()->rbuf->read_space ()));
|
||||
@ -236,8 +237,10 @@ DiskReader::adjust_buffering ()
|
||||
{
|
||||
std::shared_ptr<ChannelList const> c = channels.reader ();
|
||||
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler ()->audio_playback_buffer_size ());
|
||||
|
||||
for (auto const& chan : *c) {
|
||||
chan->resize (_session.butler ()->audio_playback_buffer_size ());
|
||||
chan->resize (bufsz);
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,7 +425,7 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
#ifndef NDEBUG // not rt-safe to print here
|
||||
cerr << "underrun for " << _name << " Available samples: " << available << " required: " << disk_samples_to_consume << endl;
|
||||
#endif
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 underrun in %2, total space = %3 vs %4\n", DEBUG_THREAD_SELF, name (), available, disk_samples_to_consume));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': underrun in thread %2, available = %3 need = %4\n", owner ()->name (), DEBUG_THREAD_SELF, available, disk_samples_to_consume));
|
||||
DEBUG_TRACE (DEBUG::AudioCacheRefill, string_compose ("DR '%1' underrun have %2 need %3 samples at pos %4\n",
|
||||
name (), available, disk_samples_to_consume,
|
||||
std::setprecision (3), std::fixed,
|
||||
@ -503,13 +506,14 @@ midi:
|
||||
if (!c->empty ()) {
|
||||
if (_slaved) {
|
||||
if (c->front ()->rbuf->write_space () >= c->front ()->rbuf->bufsize () / 2) {
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: slaved, write space = %2 of %3\n", name (), c->front ()->rbuf->write_space (), c->front ()->rbuf->bufsize ()));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': slaved, write space = %2 of %3\n",
|
||||
_owner->name (), c->front ()->rbuf->write_space (), c->front ()->rbuf->bufsize ()));
|
||||
butler_required = true;
|
||||
}
|
||||
} else {
|
||||
if ((samplecnt_t)c->front ()->rbuf->write_space () >= _chunk_samples) {
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: write space = %2 of %3\n", name (), c->front ()->rbuf->write_space (),
|
||||
_chunk_samples));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: write space = %2 chunk size = %3\n",
|
||||
_owner->name (), c->front ()->rbuf->write_space (), _chunk_samples));
|
||||
butler_required = true;
|
||||
}
|
||||
}
|
||||
@ -524,7 +528,7 @@ midi:
|
||||
}
|
||||
|
||||
if (_need_butler) {
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 reader run, needs butler = %2\n", name (), _need_butler));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1' reader run, needs butler = %2\n", _owner->name (), _need_butler));
|
||||
}
|
||||
}
|
||||
|
||||
@ -560,6 +564,7 @@ DiskReader::pending_overwrite () const
|
||||
void
|
||||
DiskReader::set_pending_overwrite (OverwriteReason why)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': set_pending_overwrite because %2%3%4)\n", owner ()->name (), std::hex, why, std::dec));
|
||||
std::shared_ptr<ChannelList const> c = channels.reader ();
|
||||
|
||||
/* called from audio thread, so we can use the read ptr and playback sample as we wish */
|
||||
@ -698,6 +703,8 @@ DiskReader::overwrite_existing_audio ()
|
||||
|
||||
const size_t to_overwrite = c->front ()->rbuf->overwritable_at (overwrite_offset);
|
||||
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': overwrite_existing_audio at %2 offset = %2 to_ovrwrt = %3\n", owner ()->name (), overwrite_sample, overwrite_offset, to_overwrite));
|
||||
|
||||
chunk1_offset = overwrite_offset;
|
||||
chunk1_cnt = min (c->front ()->rbuf->bufsize () - (size_t)overwrite_offset, to_overwrite);
|
||||
|
||||
@ -762,7 +769,7 @@ DiskReader::overwrite_existing_audio ()
|
||||
}
|
||||
|
||||
if (!rci->initialized) {
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("Init ReaderChannel '%1' overwriting at: %2, avail: %3\n", name (), overwrite_sample, chan->rbuf->read_space ()));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'1': Init ReaderChannel overwriting at: %2, avail: %3\n", name (), overwrite_sample, chan->rbuf->read_space ()));
|
||||
if (chan->rbuf->read_space () > 0) {
|
||||
rci->initialized = true;
|
||||
}
|
||||
@ -806,7 +813,7 @@ DiskReader::overwrite_existing_buffers ()
|
||||
{
|
||||
/* called from butler thread */
|
||||
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 overwriting existing buffers at %2 (because %3%4%5\n", owner ()->name (), overwrite_sample, std::hex, _pending_overwrite.load (), std::dec));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': overwriting existing buffers at %2 (because %3%4%5)\n", owner ()->name (), overwrite_sample, std::hex, _pending_overwrite.load (), std::dec));
|
||||
|
||||
bool ret = true;
|
||||
|
||||
@ -822,6 +829,7 @@ DiskReader::overwrite_existing_buffers ()
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': Clear _pending_overwrite\n", owner ()->name ()));
|
||||
_pending_overwrite.store (OverwriteReason (0));
|
||||
|
||||
return ret;
|
||||
@ -862,9 +870,10 @@ DiskReader::seek (samplepos_t sample, bool complete_refill)
|
||||
}
|
||||
}
|
||||
|
||||
_pending_overwrite.store (OverwriteReason (0));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': seek %2 -> %3 refill = %4 pending_overwrite = %5\n",
|
||||
owner ()->name (), playback_sample, sample, complete_refill, _pending_overwrite.load ()));
|
||||
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("DiskReader::seek %1 %2 -> %3 refill=%4\n", owner ()->name ().c_str (), playback_sample, sample, complete_refill));
|
||||
_pending_overwrite.store (OverwriteReason (0));
|
||||
|
||||
const samplecnt_t distance = sample - playback_sample;
|
||||
if (!complete_refill && can_internal_playback_seek (distance)) {
|
||||
@ -1192,7 +1201,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
|
||||
samplecnt_t total_space = c->front ()->rbuf->write_space ();
|
||||
|
||||
if (total_space == 0) {
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: no space to refill\n", name ()));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': no space to refill\n", name ()));
|
||||
/* nowhere to write to */
|
||||
return 0;
|
||||
}
|
||||
@ -1217,7 +1226,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
|
||||
* the playback buffer is empty.
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: space to refill %2 vs. chunk %3 (speed = %4)\n", name (), total_space, _chunk_samples, _session.transport_speed ()));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': space to refill %2 vs. chunk %3 (speed = %4)\n", name (), total_space, _chunk_samples, _session.transport_speed ()));
|
||||
if ((total_space < _chunk_samples) && fabs (_session.transport_speed ()) < 2.0f) {
|
||||
return 0;
|
||||
}
|
||||
@ -1228,7 +1237,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
|
||||
*/
|
||||
|
||||
if (_slaved && total_space < (samplecnt_t) (c->front ()->rbuf->bufsize () / 2)) {
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: not enough to refill while slaved\n", this));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': not enough to refill while slaved\n", this));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1286,7 +1295,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
|
||||
/* now back to samples */
|
||||
samplecnt_t samples_to_read = byte_size_for_read / (bits_per_sample / 8);
|
||||
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: will refill %2 channels with %3 samples\n", name (), c->size (), total_space));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': will refill %2 channels with %3 samples\n", name (), c->size (), total_space));
|
||||
|
||||
samplepos_t file_sample_tmp = fsa;
|
||||
|
||||
@ -1332,7 +1341,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
|
||||
}
|
||||
}
|
||||
if (!rci->initialized) {
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose (" -- Init ReaderChannel '%1' read: %2 samples, at: %4, avail: %5\n", name (), to_read, file_sample_tmp, rci->rbuf->read_space ()));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1' Init ReaderChannel read: %2 samples, at: %4, avail: %5\n", name (), to_read, file_sample_tmp, rci->rbuf->read_space ()));
|
||||
rci->initialized = true;
|
||||
}
|
||||
}
|
||||
|
@ -109,8 +109,9 @@ DiskWriter::WriterChannelInfo::resize (samplecnt_t bufsize)
|
||||
int
|
||||
DiskWriter::add_channel_to (std::shared_ptr<ChannelList> c, uint32_t how_many)
|
||||
{
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler()->audio_capture_buffer_size());
|
||||
while (how_many--) {
|
||||
c->push_back (new WriterChannelInfo (_session.butler()->audio_capture_buffer_size()));
|
||||
c->push_back (new WriterChannelInfo (bufsz));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: new writer channel, write space = %2 read = %3\n",
|
||||
name(),
|
||||
c->back()->wbuf->write_space(),
|
||||
@ -1386,8 +1387,9 @@ DiskWriter::adjust_buffering ()
|
||||
{
|
||||
std::shared_ptr<ChannelList const> c = channels.reader();
|
||||
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler()->audio_capture_buffer_size());
|
||||
for (auto const chan : *c) {
|
||||
chan->resize (_session.butler()->audio_capture_buffer_size());
|
||||
chan->resize (bufsz);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,15 @@ ExportHandler::ExportHandler (Session & session)
|
||||
, cue_tracknum (0)
|
||||
, cue_indexnum (0)
|
||||
{
|
||||
pthread_mutex_init (&_timespan_mutex, 0);
|
||||
pthread_cond_init (&_timespan_cond, 0);
|
||||
_timespan_thread_active.store (1);
|
||||
_timespan_thread = PBD::Thread::create (boost::bind (_timespan_thread_run, this), "ExportHandler");
|
||||
if (!_timespan_thread) {
|
||||
_timespan_thread_active.store (0);
|
||||
fatal << "Cannot create export handler helper thread" << endmsg;
|
||||
abort(); /* NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
ExportHandler::~ExportHandler ()
|
||||
@ -130,6 +139,51 @@ ExportHandler::~ExportHandler ()
|
||||
session.surround_master ()->surround_return ()->finalize_export ();
|
||||
}
|
||||
graph_builder->cleanup (export_status->aborted () );
|
||||
|
||||
pthread_mutex_lock (&_timespan_mutex);
|
||||
_timespan_thread_active.store (0);
|
||||
pthread_cond_signal (&_timespan_cond);
|
||||
pthread_mutex_unlock (&_timespan_mutex);
|
||||
|
||||
_timespan_thread->join ();
|
||||
|
||||
pthread_cond_destroy (&_timespan_cond);
|
||||
pthread_mutex_destroy (&_timespan_mutex);
|
||||
}
|
||||
|
||||
void*
|
||||
ExportHandler::_timespan_thread_run (void* me)
|
||||
{
|
||||
ExportHandler* self = static_cast<ExportHandler*> (me);
|
||||
|
||||
SessionEvent::create_per_thread_pool ("ExportHandler", 512);
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), "ExportHandler", 512);
|
||||
|
||||
pthread_mutex_lock (&self->_timespan_mutex);
|
||||
while (self->_timespan_thread_active.load ()) {
|
||||
pthread_cond_wait (&self->_timespan_cond, &self->_timespan_mutex);
|
||||
if (!self->_timespan_thread_active.load ()) {
|
||||
break;
|
||||
} else {
|
||||
Temporal::TempoMap::fetch ();
|
||||
self->process_connection.disconnect ();
|
||||
Glib::Threads::Mutex::Lock l (self->export_status->lock());
|
||||
DiskReader::allocate_working_buffers ();
|
||||
self->start_timespan ();
|
||||
DiskReader::free_working_buffers ();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&self->_timespan_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ExportHandler::timespan_thread_wakeup ()
|
||||
{
|
||||
if (pthread_mutex_trylock (&_timespan_mutex) == 0) {
|
||||
pthread_cond_signal (&_timespan_cond);
|
||||
pthread_mutex_unlock (&_timespan_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add an export to the `to-do' list */
|
||||
@ -372,22 +426,6 @@ ExportHandler::command_output(std::string output, size_t size)
|
||||
info << output << endmsg;
|
||||
}
|
||||
|
||||
void*
|
||||
ExportHandler::start_timespan_bg (void* eh)
|
||||
{
|
||||
char name[64];
|
||||
snprintf (name, 64, "Export-TS-%p", (void*)DEBUG_THREAD_SELF);
|
||||
pthread_set_name (name);
|
||||
ExportHandler* self = static_cast<ExportHandler*> (eh);
|
||||
self->process_connection.disconnect ();
|
||||
Glib::Threads::Mutex::Lock l (self->export_status->lock());
|
||||
SessionEvent::create_per_thread_pool (name, 512);
|
||||
DiskReader::allocate_working_buffers ();
|
||||
self->start_timespan ();
|
||||
DiskReader::free_working_buffers ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ExportHandler::finish_timespan ()
|
||||
{
|
||||
@ -543,9 +581,7 @@ ExportHandler::finish_timespan ()
|
||||
/* finish timespan is called in freewheeling rt-context,
|
||||
* we cannot start a new export from here */
|
||||
assert (AudioEngine::instance()->freewheeling ());
|
||||
pthread_t tid;
|
||||
pthread_create (&tid, NULL, ExportHandler::start_timespan_bg, this);
|
||||
pthread_detach (tid);
|
||||
timespan_thread_wakeup ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -815,7 +815,8 @@ ARDOUR::init_post_engine (uint32_t start_cnt)
|
||||
}
|
||||
}
|
||||
|
||||
BaseUI::set_thread_priority (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority () - 2));
|
||||
/* set/update thread priority relative to backend's [jack_]client_real_time_priority */
|
||||
BaseUI::set_thread_priority (PBD_RT_PRI_CTRL);
|
||||
|
||||
TransportMasterManager::instance ().restart ();
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ open_importable_source (const string& path, samplecnt_t samplerate, ARDOUR::SrcQ
|
||||
|
||||
vector<string>
|
||||
Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& import_file_path, uint32_t channels,
|
||||
vector<string> const & smf_names)
|
||||
vector<string> const & smf_names, bool use_smf_file_names)
|
||||
|
||||
{
|
||||
vector<string> new_paths;
|
||||
@ -159,8 +159,12 @@ Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& impo
|
||||
case DataType::MIDI:
|
||||
if (channels > 1) {
|
||||
assert (smf_names.size() == channels);
|
||||
string mchn_name = string_compose ("%1.%2", basename, smf_names[n]);
|
||||
filepath = new_midi_source_path (mchn_name);
|
||||
if (use_smf_file_names) {
|
||||
string mchn_name = string_compose ("%1.%2", basename, smf_names[n]);
|
||||
filepath = new_midi_source_path (mchn_name);
|
||||
} else {
|
||||
filepath = new_midi_source_path (smf_names[n]);
|
||||
}
|
||||
} else {
|
||||
filepath = new_midi_source_path (basename);
|
||||
}
|
||||
@ -552,7 +556,7 @@ Session::deinterlace_midi_region (std::shared_ptr<MidiRegion> mr)
|
||||
for (int i = 0; i<16; i++) {
|
||||
smf_names.push_back(string_compose("-ch%1", i+1));
|
||||
}
|
||||
vector<string> new_paths = get_paths_for_new_sources (false, source_path, 16, smf_names);
|
||||
vector<string> new_paths = get_paths_for_new_sources (false, source_path, 16, smf_names, true);
|
||||
|
||||
/* create source files and write 1 channel of midi data to each of them */
|
||||
if (create_mono_sources_for_writing (new_paths, *this, sample_rate(), newfiles, 0, false)) {
|
||||
@ -635,6 +639,7 @@ Session::import_files (ImportStatus& status)
|
||||
std::shared_ptr<SMFSource> smfs;
|
||||
uint32_t num_channels = 0;
|
||||
vector<string> smf_names;
|
||||
bool smf_keep_filename = false;
|
||||
|
||||
status.sources.clear ();
|
||||
|
||||
@ -689,6 +694,9 @@ Session::import_files (ImportStatus& status)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SMFFileAndTrackName:
|
||||
smf_keep_filename = true;
|
||||
/*FALLTHRU*/
|
||||
case SMFTrackName:
|
||||
if (status.split_midi_channels) {
|
||||
vector<string> temp;
|
||||
@ -728,7 +736,7 @@ Session::import_files (ImportStatus& status)
|
||||
continue;
|
||||
}
|
||||
|
||||
vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, num_channels, smf_names);
|
||||
vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, num_channels, smf_names, smf_keep_filename);
|
||||
Sources newfiles;
|
||||
samplepos_t natural_position = source ? source->natural_position() : 0;
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "ardour/disk_reader.h"
|
||||
#include "ardour/io_tasklist.h"
|
||||
#include "ardour/process_thread.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/session_event.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
@ -50,35 +51,41 @@ IOTaskList::IOTaskList (uint32_t n_threads)
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_attr_t attr;
|
||||
struct sched_param parm;
|
||||
parm.sched_priority = pbd_absolute_rt_priority (SCHED_RR, pbd_pthread_priority (THREAD_IO));
|
||||
bool use_rt;
|
||||
int policy;
|
||||
|
||||
switch (Config->get_io_thread_policy ()) {
|
||||
case 1:
|
||||
use_rt = true;
|
||||
policy = SCHED_FIFO;
|
||||
break;
|
||||
case 2:
|
||||
use_rt = true;
|
||||
policy = SCHED_RR;
|
||||
default:
|
||||
use_rt = false;
|
||||
policy = SCHED_OTHER;
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_attr_init (&attr);
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
pthread_attr_setschedpolicy (&attr, SCHED_OTHER);
|
||||
#else
|
||||
pthread_attr_setschedpolicy (&attr, SCHED_RR);
|
||||
policy = SCHED_OTHER;
|
||||
#endif
|
||||
pthread_attr_setschedparam (&attr, &parm);
|
||||
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::IOTaskList, string_compose ("IOTaskList starting %1 threads with priority = %2\n", _n_threads, parm.sched_priority));
|
||||
DEBUG_TRACE (PBD::DEBUG::IOTaskList, string_compose ("IOTaskList starting %1 threads with sched policy = %2\n", _n_threads, policy));
|
||||
|
||||
_workers.resize (_n_threads);
|
||||
for (uint32_t i = 0; i < _n_threads; ++i) {
|
||||
if (pthread_create (&_workers[i], &attr, &_worker_thread, this)) {
|
||||
if (pthread_create (&_workers[i], NULL, &_worker_thread, this)) {
|
||||
if (!use_rt || pbd_realtime_pthread_create (policy, THREAD_IO, 0, &_workers[i], &_worker_thread, this)) {
|
||||
if (use_rt && i == 0) {
|
||||
PBD::warning << _("IOTaskList: cannot acquire realtime permissions.") << endmsg;
|
||||
}
|
||||
if (pbd_pthread_create (0, &_workers[i], &_worker_thread, this)) {
|
||||
std::cerr << "Failed to start IOTaskList thread\n";
|
||||
throw failed_constructor ();
|
||||
}
|
||||
if (i == 0) {
|
||||
PBD::warning << _("IOTaskList: cannot acquire realtime permissions.") << endmsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_attr_destroy (&attr);
|
||||
}
|
||||
|
||||
IOTaskList::~IOTaskList ()
|
||||
@ -139,8 +146,8 @@ IOTaskList::_worker_thread (void* me)
|
||||
|
||||
#ifdef HAVE_IOPRIO
|
||||
/* compare to Butler::_thread_work */
|
||||
// ioprio_set (IOPRIO_WHO_PROCESS, 0 /*calling thread*/, IOPRIO_PRIO_VALUE (IOPRIO_CLASS_RT, 4))
|
||||
syscall (SYS_ioprio_set, 1, 0, (1 << 13) | 4);
|
||||
// ioprio_set (IOPRIO_WHO_PROCESS, 0 /*calling thread*/, IOPRIO_PRIO_VALUE (IOPRIO_CLASS_RT, 4))
|
||||
syscall (SYS_ioprio_set, 1, 0, (1 << 13) | 4);
|
||||
#endif
|
||||
|
||||
self->io_thread ();
|
||||
|
@ -2571,6 +2571,7 @@ LuaBindings::common (lua_State* L)
|
||||
.beginNamespace ("MidiTrackNameSource")
|
||||
.addConst ("SMFTrackNumber", ARDOUR::MidiTrackNameSource(SMFTrackNumber))
|
||||
.addConst ("SMFTrackName", ARDOUR::MidiTrackNameSource(SMFTrackName))
|
||||
.addConst ("SMFFileAndTrackName", ARDOUR::MidiTrackNameSource(SMFFileAndTrackName))
|
||||
.addConst ("SMFInstrumentName", ARDOUR::MidiTrackNameSource(SMFInstrumentName))
|
||||
.endNamespace ()
|
||||
|
||||
|
@ -607,7 +607,7 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
|
||||
static const int32_t _min_block_length = 1; // may happen during split-cycles
|
||||
static const int32_t _max_block_length = 8192; // max possible (with all engines and during export)
|
||||
static const int32_t rt_policy = PBD_SCHED_FIFO;
|
||||
static const int32_t rt_priority = pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority () - 1);
|
||||
static const int32_t rt_priority = pbd_absolute_rt_priority (PBD_SCHED_FIFO, PBD_RT_PRI_PROC);
|
||||
static const int32_t hw_concurrency = how_many_dsp_threads ();
|
||||
/* Consider updating max-block-size whenever the buffersize changes.
|
||||
* It requires re-instantiating the plugin (which is a non-realtime operation),
|
||||
|
@ -275,7 +275,6 @@ MidiPatchManager::load_midnams ()
|
||||
*/
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), "midi-patch-manager", 8);
|
||||
pthread_set_name ("MIDNAMLoader");
|
||||
|
||||
{
|
||||
PBD::Unwinder<bool> npc (no_patch_changed_messages, true);
|
||||
@ -291,7 +290,7 @@ MidiPatchManager::load_midnams ()
|
||||
void
|
||||
MidiPatchManager::load_midnams_in_thread ()
|
||||
{
|
||||
_midnam_load_thread = PBD::Thread::create (boost::bind (&MidiPatchManager::load_midnams, this));
|
||||
_midnam_load_thread = PBD::Thread::create (boost::bind (&MidiPatchManager::load_midnams, this), "MIDNAMLoader");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3413,17 +3413,14 @@ Playlist::fade_range (list<TimelineRange>& ranges)
|
||||
{
|
||||
ThawList thawlist;
|
||||
RegionReadLock rlock (this);
|
||||
for (list<TimelineRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
|
||||
list<TimelineRange>::iterator tmpr = r;
|
||||
++tmpr;
|
||||
for (RegionList::const_iterator i = regions.begin (); i != regions.end ();) {
|
||||
RegionList::const_iterator tmpi = i;
|
||||
++tmpi;
|
||||
thawlist.add (*i);
|
||||
(*i)->fade_range ((*r).start().samples(), (*r).end().samples());
|
||||
i = tmpi;
|
||||
/* add regions only once, not for each range */
|
||||
for (auto const& r : regions) {
|
||||
thawlist.add (r);
|
||||
}
|
||||
for (auto const& t: ranges) {
|
||||
for (auto const& r : regions) {
|
||||
r->fade_range (t.start().samples(), t.end().samples());
|
||||
}
|
||||
r = tmpr;
|
||||
}
|
||||
rlock.release ();
|
||||
thawlist.release ();
|
||||
|
@ -126,7 +126,7 @@ Region::get_region_operation_group_id (uint64_t old_region_group, RegionOperatio
|
||||
|
||||
/* if a region group has not been assigned for this key, assign one */
|
||||
if (_operation_rgroup_map.find (region_group_key) == _operation_rgroup_map.end ()) {
|
||||
_operation_rgroup_map[region_group_key] = _next_group_id++;
|
||||
_operation_rgroup_map[region_group_key] = ++_next_group_id;
|
||||
}
|
||||
|
||||
return ((_operation_rgroup_map[region_group_key] << 4) | expl);
|
||||
|
@ -410,7 +410,7 @@ Route::process_output_buffers (BufferSet& bufs,
|
||||
_pannable->automation_run (start_sample, nframes);
|
||||
}
|
||||
|
||||
const int speed = (is_auditioner() ? 1 : _session.transport_speed ());
|
||||
const int speed = (is_auditioner() ? 1 : _session.transport_speed (true));
|
||||
assert (speed == -1 || speed == 0 || speed == 1);
|
||||
|
||||
const samplecnt_t output_latency = speed * _output_latency;
|
||||
@ -4121,7 +4121,7 @@ Route::latency_preroll (pframes_t nframes, samplepos_t& start_sample, samplepos_
|
||||
return nframes;
|
||||
}
|
||||
if (!_disk_reader) {
|
||||
if (_session.transport_speed() < 0) {
|
||||
if (_session.transport_speed (true) < 0) {
|
||||
start_sample += latency_preroll;
|
||||
end_sample += latency_preroll;
|
||||
} else {
|
||||
@ -4136,7 +4136,7 @@ Route::latency_preroll (pframes_t nframes, samplepos_t& start_sample, samplepos_
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_session.transport_speed() < 0) {
|
||||
if (_session.transport_speed (true) < 0) {
|
||||
start_sample += latency_preroll;
|
||||
end_sample += latency_preroll;
|
||||
} else {
|
||||
@ -6014,8 +6014,15 @@ Route::send_pan_azimuth_controllable (uint32_t n) const
|
||||
}
|
||||
|
||||
std::shared_ptr<AutomationControl>
|
||||
Route::send_level_controllable (uint32_t n) const
|
||||
Route::send_level_controllable (uint32_t n, bool locked) const
|
||||
{
|
||||
if (locked) {
|
||||
/* calling thread has a WriterLock (_processor_lock)
|
||||
* we cannot call nth_send()
|
||||
*/
|
||||
return std::shared_ptr<AutomationControl>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Send> s = std::dynamic_pointer_cast<Send>(nth_send (n));
|
||||
if (s) {
|
||||
return s->gain_control ();
|
||||
|
@ -255,6 +255,7 @@ Session::Session (AudioEngine &eng,
|
||||
, _state_of_the_state (StateOfTheState (CannotSave | InitialConnecting | Loading))
|
||||
, _save_queued (false)
|
||||
, _save_queued_pending (false)
|
||||
, _no_save_signal (false)
|
||||
, _last_roll_location (0)
|
||||
, _last_roll_or_reversal_location (0)
|
||||
, _last_record_location (0)
|
||||
@ -8105,8 +8106,10 @@ Session::auto_connect_thread_start ()
|
||||
lx.release ();
|
||||
|
||||
_ac_thread_active.store (1);
|
||||
if (pthread_create (&_auto_connect_thread, NULL, auto_connect_thread, this)) {
|
||||
if (pthread_create_and_store ("AutoConnect", &_auto_connect_thread, auto_connect_thread, this, 0)) {
|
||||
_ac_thread_active.store (0);
|
||||
fatal << "Cannot create 'session auto connect' thread" << endmsg;
|
||||
abort(); /* NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -8141,9 +8144,7 @@ void *
|
||||
Session::auto_connect_thread (void *arg)
|
||||
{
|
||||
Session *s = static_cast<Session *>(arg);
|
||||
pthread_set_name (X_("autoconnect"));
|
||||
s->auto_connect_thread_run ();
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -348,6 +348,9 @@ Session::calc_preroll_subcycle (samplecnt_t ns) const
|
||||
{
|
||||
std::shared_ptr<RouteList const> r = routes.reader ();
|
||||
for (auto const& i : *r) {
|
||||
if (!i->active ()) {
|
||||
continue;
|
||||
}
|
||||
samplecnt_t route_offset = i->playback_latency ();
|
||||
if (_remaining_latency_preroll > route_offset + ns) {
|
||||
/* route will no-roll for complete pre-roll cycle */
|
||||
@ -911,7 +914,8 @@ Session::process_event (SessionEvent* ev)
|
||||
|
||||
/* except locates, which we have the capability to handle */
|
||||
|
||||
if (ev->type != SessionEvent::Locate) {
|
||||
if (ev->type != SessionEvent::Locate && ev->type != SessionEvent::AutoLoop) {
|
||||
DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("Postponing and moving event to immediate queue: %1 @ %2\n", enum_2_string (ev->type), _transport_sample));
|
||||
immediate_events.insert (immediate_events.end(), ev);
|
||||
_remove_event (ev);
|
||||
return;
|
||||
@ -1198,7 +1202,7 @@ Session::emit_thread_start ()
|
||||
}
|
||||
_rt_thread_active = true;
|
||||
|
||||
if (pthread_create (&_rt_emit_thread, NULL, emit_thread, this)) {
|
||||
if (pthread_create_and_store ("SessionSignals", &_rt_emit_thread, emit_thread, this, 0)) {
|
||||
_rt_thread_active = false;
|
||||
}
|
||||
}
|
||||
@ -1224,9 +1228,7 @@ void *
|
||||
Session::emit_thread (void *arg)
|
||||
{
|
||||
Session *s = static_cast<Session *>(arg);
|
||||
pthread_set_name ("SessionSignals");
|
||||
s->emit_thread_run ();
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -757,7 +757,9 @@ Session::remove_state (string snapshot_name)
|
||||
xml_path, g_strerror (errno)) << endmsg;
|
||||
}
|
||||
|
||||
StateSaved (snapshot_name); /* EMIT SIGNAL */
|
||||
if (!_no_save_signal) {
|
||||
StateSaved (snapshot_name); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
|
||||
/** @param snapshot_name Name to save under, without .ardour / .pending prefix */
|
||||
@ -930,7 +932,9 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
|
||||
unset_dirty (/* EMIT SIGNAL */ true);
|
||||
}
|
||||
|
||||
StateSaved (snapshot_name); /* EMIT SIGNAL */
|
||||
if (!_no_save_signal) {
|
||||
StateSaved (snapshot_name); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -5569,11 +5573,18 @@ Session::save_as (SaveAs& saveas)
|
||||
|
||||
store_recent_sessions (_name, _path);
|
||||
|
||||
std::cerr << "Saveas, switch to: " << saveas.switch_to << std::endl;
|
||||
|
||||
if (!saveas.switch_to) {
|
||||
|
||||
std::cerr << "no switch to!\n";
|
||||
|
||||
/* save the new state */
|
||||
|
||||
save_state ("", false, false, !saveas.include_media);
|
||||
{
|
||||
PBD::Unwinder<bool> uw (_no_save_signal, true);
|
||||
save_state ("", false, false, !saveas.include_media);
|
||||
}
|
||||
|
||||
/* switch back to the way things were */
|
||||
|
||||
|
@ -190,7 +190,7 @@ Session::locate (samplepos_t target_sample, bool for_loop_end, bool force, bool
|
||||
* changes in the value of _transport_sample.
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1 ts = %7, for loop end %2 force %3 mmc %4\n",
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1 ts = %5, for loop end %2 force %3 mmc %4\n",
|
||||
target_sample, for_loop_end, force, with_mmc, _transport_sample));
|
||||
|
||||
if (!force && (_transport_sample == target_sample) && !for_loop_end) {
|
||||
@ -202,9 +202,12 @@ Session::locate (samplepos_t target_sample, bool for_loop_end, bool force, bool
|
||||
// Update Timecode time
|
||||
_transport_sample = target_sample;
|
||||
_nominal_jack_transport_sample = boost::none;
|
||||
// Bump seek counter so that any in-process locate in the butler
|
||||
// thread(s?) can restart.
|
||||
_seek_counter.fetch_add (1);
|
||||
|
||||
/* Note that loop wrap-around locates do not need to call "seek" */
|
||||
if (force || !for_loop_end) {
|
||||
/* Bump seek counter so that any in-process locate in the butler can restart */
|
||||
_seek_counter.fetch_add (1);
|
||||
}
|
||||
_last_roll_or_reversal_location = target_sample;
|
||||
if (!for_loop_end && !_exporting) {
|
||||
_remaining_latency_preroll = worst_latency_preroll_buffer_size_ceil ();
|
||||
@ -671,7 +674,7 @@ Session::butler_completed_transport_work ()
|
||||
ENSURE_PROCESS_THREAD;
|
||||
PostTransportWork ptw = post_transport_work ();
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
|
||||
|
||||
if (ptw & PostTransportAudition) {
|
||||
if (auditioner && auditioner->auditioning()) {
|
||||
@ -1146,7 +1149,7 @@ Session::butler_transport_work (bool have_process_lock)
|
||||
uint64_t before = g_get_monotonic_time();
|
||||
#endif
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = [%1] (0x%3%4%5) at %2\n", enum_2_string (ptw), before, std::hex, ptw, std::dec));
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("Butler transport work, todo = [%1] (0x%3%4%5) twr = %6 @ %2\n", enum_2_string (ptw), before, std::hex, ptw, std::dec, on_entry));
|
||||
|
||||
if (ptw & PostTransportAdjustPlaybackBuffering) {
|
||||
/* need to prevent concurrency with ARDOUR::Reader::run(),
|
||||
@ -1200,10 +1203,11 @@ Session::butler_transport_work (bool have_process_lock)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (will_locate) {
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("nonrealtime locate invoked from BTW (butler has done %1, rtlocs %2)\n", butler, rtlocates));
|
||||
if (will_locate && transport_locating ()) {
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("nonrealtime locate invoked from BTW (butler has done %1, rtlocs %2)\n", butler, rtlocates));
|
||||
non_realtime_locate ();
|
||||
} else if (will_locate) {
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("skip nonrealtime locate (butler has done %1, rtlocs %2) ts = %3\n", butler, rtlocates, _transport_fsm->current_state()));
|
||||
}
|
||||
|
||||
if (ptw & PostTransportOverWrite) {
|
||||
@ -1220,7 +1224,7 @@ Session::butler_transport_work (bool have_process_lock)
|
||||
|
||||
(void) PBD::atomic_dec_and_test (_butler->should_do_transport_work);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose (X_("Butler transport work all done after %1 usecs @ %2 ptw %3 trw = %4\n"), g_get_monotonic_time() - before, _transport_sample, enum_2_string (post_transport_work()), _butler->transport_work_requested()));
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose (X_("Butler transport work all done after %1 usecs tsp = %2 ptw [%3] trw = %4\n"), g_get_monotonic_time() - before, _transport_sample, enum_2_string (post_transport_work()), _butler->should_do_transport_work.load ()));
|
||||
}
|
||||
|
||||
void
|
||||
@ -2144,11 +2148,14 @@ Session::transport_will_roll_forwards () const
|
||||
}
|
||||
|
||||
double
|
||||
Session::transport_speed() const
|
||||
Session::transport_speed (bool incl_preroll) const
|
||||
{
|
||||
if (_transport_fsm->transport_speed() != _transport_fsm->transport_speed()) {
|
||||
// cerr << "\n\n!!TS " << _transport_fsm->transport_speed() << " TFSM::speed " << _transport_fsm->transport_speed() << " via " << _transport_fsm->current_state() << endl;
|
||||
}
|
||||
if (incl_preroll) {
|
||||
return _transport_fsm->transport_speed();
|
||||
}
|
||||
return _count_in_samples > 0 ? 0. : _transport_fsm->transport_speed();
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,6 @@ static void
|
||||
peak_thread_work ()
|
||||
{
|
||||
SessionEvent::create_per_thread_pool (X_("PeakFile Builder "), 64);
|
||||
pthread_set_name ("PeakFileBuilder");
|
||||
|
||||
while (true) {
|
||||
SourceFactory::peak_building_lock.lock ();
|
||||
|
||||
@ -119,7 +117,7 @@ SourceFactory::init ()
|
||||
}
|
||||
peak_thread_run = true;
|
||||
for (int n = 0; n < 2; ++n) {
|
||||
peak_thread_pool.push_back (PBD::Thread::create (&peak_thread_work));
|
||||
peak_thread_pool.push_back (PBD::Thread::create (&peak_thread_work, string_compose ("PeakFileBuilder-%1", n)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,8 +218,8 @@ out:
|
||||
double
|
||||
MidiClockTicker::one_ppqn_in_samples (samplepos_t transport_position) const
|
||||
{
|
||||
Tempo const & tempo (TempoMap::use()->metric_at (timepos_t (transport_position)).tempo());
|
||||
const double samples_per_quarter_note = tempo.samples_per_quarter_note (_session.nominal_sample_rate());
|
||||
TempoPoint const & tempo (TempoMap::use()->metric_at (timepos_t (transport_position)).tempo());
|
||||
const double samples_per_quarter_note = superclock_to_samples (tempo.superclocks_per_note_type_at (timepos_t (transport_position)), _session.nominal_sample_rate());
|
||||
return samples_per_quarter_note / 24.0;
|
||||
}
|
||||
|
||||
|
@ -4885,7 +4885,7 @@ TriggerBoxThread::TriggerBoxThread ()
|
||||
: requests (1024)
|
||||
, _xthread (true)
|
||||
{
|
||||
if (pthread_create_and_store ("triggerbox thread", &thread, _thread_work, this)) {
|
||||
if (pthread_create_and_store ("TriggerBox Worker", &thread, _thread_work, this)) {
|
||||
error << _("Session: could not create triggerbox thread") << endmsg;
|
||||
throw failed_constructor ();
|
||||
}
|
||||
@ -4903,15 +4903,12 @@ void *
|
||||
TriggerBoxThread::_thread_work (void* arg)
|
||||
{
|
||||
SessionEvent::create_per_thread_pool ("tbthread events", 4096);
|
||||
pthread_set_name (X_("tbthread"));
|
||||
return ((TriggerBoxThread *) arg)->thread_work ();
|
||||
}
|
||||
|
||||
void *
|
||||
TriggerBoxThread::thread_work ()
|
||||
{
|
||||
pthread_set_name (X_("Trigger Worker"));
|
||||
|
||||
while (true) {
|
||||
|
||||
char msg;
|
||||
|
@ -1195,6 +1195,7 @@ VST3PI::VST3PI (std::shared_ptr<ARDOUR::VST3PluginModule> m, std::string unique_
|
||||
, _rpc_queue (RouteProcessorChange::NoProcessorChange, false)
|
||||
, _no_kMono (false)
|
||||
, _restart_component_is_synced (false)
|
||||
, _in_set_owner (false)
|
||||
{
|
||||
using namespace std;
|
||||
IPluginFactory* factory = m->factory ();
|
||||
@ -1835,9 +1836,13 @@ VST3PI::set_owner (SessionObject* o)
|
||||
return;
|
||||
}
|
||||
|
||||
_in_set_owner.store (true);
|
||||
|
||||
if (!setup_psl_info_handler ()) {
|
||||
setup_info_listener ();
|
||||
}
|
||||
|
||||
_in_set_owner.store (false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2809,7 +2814,7 @@ VST3PI::automation_state_changed (uint32_t port, AutoState s, std::weak_ptr<Auto
|
||||
/* ****************************************************************************/
|
||||
|
||||
static std::shared_ptr<AutomationControl>
|
||||
lookup_ac (SessionObject* o, FIDString id)
|
||||
lookup_ac (SessionObject* o, FIDString id, bool locked = false)
|
||||
{
|
||||
Stripable* s = dynamic_cast<Stripable*> (o);
|
||||
if (!s) {
|
||||
@ -2842,8 +2847,8 @@ lookup_ac (SessionObject* o, FIDString id)
|
||||
* recurive locks (deadlock, or double unlock crash).
|
||||
*/
|
||||
int send_id = atoi (id + strlen (ContextInfo::kSendLevel));
|
||||
if (s->send_enable_controllable (send_id)) {
|
||||
return s->send_level_controllable (send_id);
|
||||
if (send_id >=0 && s->send_enable_controllable (send_id)) {
|
||||
return s->send_level_controllable (send_id, locked);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -2964,12 +2969,13 @@ VST3PI::getContextInfoValue (double& value, FIDString id)
|
||||
if (0 == strcmp (id, ContextInfo::kMaxVolume)) {
|
||||
value = s->gain_control ()->upper ();
|
||||
} else if (0 == strcmp (id, ContextInfo::kMaxSendLevel)) {
|
||||
value = 2.0; // Config->get_max_gain();
|
||||
#ifdef MIXBUS
|
||||
if (s->send_level_controllable (0)) {
|
||||
if (s->send_enable_controllable (0)) {
|
||||
assert (s->send_level_controllable (0));
|
||||
value = s->send_level_controllable (0)->upper (); // pow (10.0, .05 * 15.0);
|
||||
}
|
||||
#endif
|
||||
value = 2.0; // Config->get_max_gain();
|
||||
} else if (0 == strcmp (id, ContextInfo::kVolume)) {
|
||||
std::shared_ptr<AutomationControl> ac = s->gain_control ();
|
||||
value = ac->get_value (); // gain coefficient 0..2 (1.0 = 0dB)
|
||||
@ -2983,11 +2989,12 @@ VST3PI::getContextInfoValue (double& value, FIDString id)
|
||||
value = 0.5; // center
|
||||
}
|
||||
} else if (0 == strncmp (id, ContextInfo::kSendLevel, strlen (ContextInfo::kSendLevel))) {
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id, _in_set_owner.load ());
|
||||
if (ac) {
|
||||
value = ac->get_value (); // gain cofficient
|
||||
psl_subscribe_to (ac, id);
|
||||
} else {
|
||||
value = 0;
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::getContextInfoValue<double> invalid AC %1\n", id));
|
||||
return kInvalidArgument; // send index out of bounds
|
||||
}
|
||||
@ -3023,14 +3030,14 @@ VST3PI::setContextInfoValue (FIDString id, double value)
|
||||
ac->set_value (ac->interface_to_internal (value, true), PBD::Controllable::NoGroup);
|
||||
}
|
||||
} else if (0 == strncmp (id, ContextInfo::kSendLevel, strlen (ContextInfo::kSendLevel))) {
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id, _in_set_owner.load ());
|
||||
if (ac) {
|
||||
ac->set_value (value, Controllable::NoGroup);
|
||||
} else {
|
||||
return kInvalidArgument; // send index out of bounds
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, "VST3PI::setContextInfoValue<double>: unsupported ID\n");
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::setContextInfoValue<double>: unsupported ID %1\n", id));
|
||||
return kInvalidArgument;
|
||||
}
|
||||
return kResultOk;
|
||||
@ -3071,7 +3078,7 @@ VST3PI::setContextInfoValue (FIDString id, int32 value)
|
||||
s->session ().set_control (ac, value != 0 ? 1 : 0, Controllable::NoGroup);
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, "VST3PI::setContextInfoValue<int>: unsupported ID\n");
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::setContextInfoValue<int>: unsupported ID %1\n", id));
|
||||
return kNotImplemented;
|
||||
}
|
||||
return kResultOk;
|
||||
@ -3101,6 +3108,7 @@ VST3PI::beginEditContextInfoValue (FIDString id)
|
||||
}
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
if (!ac) {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::beginEditContextInfoValue %1 -- invalid AC\n", id));
|
||||
return kInvalidArgument;
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::beginEditContextInfoValue %1\n", id));
|
||||
@ -3117,6 +3125,7 @@ VST3PI::endEditContextInfoValue (FIDString id)
|
||||
}
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
if (!ac) {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::endEditContextInfoValue %1 -- invalid AC\n", id));
|
||||
return kInvalidArgument;
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::endEditContextInfoValue %1\n", id));
|
||||
|
@ -41,7 +41,7 @@ Worker::Worker(Workee* workee, uint32_t ring_size, bool threaded)
|
||||
, _synchronous(!threaded)
|
||||
{
|
||||
if (threaded) {
|
||||
_thread = PBD::Thread::create (boost::bind (&Worker::run, this));
|
||||
_thread = PBD::Thread::create (boost::bind (&Worker::run, this), "LV2Worker");
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,8 +137,6 @@ Worker::emit_responses()
|
||||
void
|
||||
Worker::run()
|
||||
{
|
||||
pthread_set_name ("LV2Worker");
|
||||
|
||||
void* buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
while (true) {
|
||||
|
@ -113,7 +113,6 @@ private:
|
||||
samplecnt_t samples_written;
|
||||
ARDOUR::SystemExec* _proc;
|
||||
std::string _path;
|
||||
std::vector<char> _tmpfile_path_buf;
|
||||
int _tmp_fd;
|
||||
gchar* _tmp_file;
|
||||
|
||||
|
@ -136,9 +136,7 @@ class TmpFileRt
|
||||
static void * _disk_thread (void *arg)
|
||||
{
|
||||
TmpFileRt *d = static_cast<TmpFileRt *>(arg);
|
||||
pthread_set_name ("ExportDiskIO");
|
||||
d->disk_thread ();
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -158,7 +156,7 @@ class TmpFileRt
|
||||
pthread_mutex_init (&_disk_thread_lock, 0);
|
||||
pthread_cond_init (&_data_ready, 0);
|
||||
|
||||
if (pthread_create (&_thread_id, NULL, _disk_thread, this)) {
|
||||
if (pthread_create_and_store ("ExportDiskIO", &_thread_id, _disk_thread, this, 0)) {
|
||||
_capture = false;
|
||||
if (SndfileWriter<T>::throw_level (ThrowStrict)) {
|
||||
throw Exception (*this, "Cannot create export disk writer");
|
||||
|
@ -1385,7 +1385,7 @@ AlsaAudioBackend::midi_device_thread ()
|
||||
bool
|
||||
AlsaAudioBackend::listen_for_midi_device_changes ()
|
||||
{
|
||||
if (pthread_create (&_midi_device_thread_id, NULL, _midi_device_thread, this)) {
|
||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_HELP, &_midi_device_thread_id, _midi_device_thread, this)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -605,7 +605,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||
return PortReconnectError;
|
||||
}
|
||||
|
||||
if (pthread_create (&_freeewheel_thread, NULL, pthread_freewheel, this))
|
||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_PROC, &_freeewheel_thread, pthread_freewheel, this))
|
||||
{
|
||||
PBD::error << _("CoreAudioBackend: failed to create process thread.") << endmsg;
|
||||
delete _pcmio; _pcmio = 0;
|
||||
|
@ -856,7 +856,7 @@ static void* freewheel_thread(void* arg)
|
||||
bool
|
||||
PortAudioBackend::start_freewheel_process_thread ()
|
||||
{
|
||||
if (pthread_create(&_pthread_freewheel, NULL, freewheel_thread, this)) {
|
||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_PROC, &_pthread_freewheel, freewheel_thread, this)) {
|
||||
DEBUG_AUDIO("Failed to create main audio thread\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ using namespace PBD;
|
||||
using namespace Glib;
|
||||
|
||||
uint64_t BaseUI::rt_bit = 1;
|
||||
int BaseUI::_thread_priority = PBD_RT_PRI_PROC - 1;
|
||||
int BaseUI::_thread_priority = PBD_RT_PRI_CTRL;
|
||||
|
||||
BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type();
|
||||
BaseUI::RequestType BaseUI::Quit = BaseUI::new_request_type();
|
||||
@ -94,7 +94,6 @@ BaseUI::set_thread_priority () const
|
||||
void
|
||||
BaseUI::main_thread ()
|
||||
{
|
||||
pthread_set_name (string_compose ("UI:%1", event_loop_name ()).c_str ());
|
||||
DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: event loop running in thread %2\n", event_loop_name(), pthread_name()));
|
||||
set_event_loop_for_thread (this);
|
||||
thread_init ();
|
||||
@ -122,7 +121,7 @@ BaseUI::run ()
|
||||
attach_request_source ();
|
||||
|
||||
Glib::Threads::Mutex::Lock lm (_run_lock);
|
||||
_run_loop_thread = PBD::Thread::create (boost::bind (&BaseUI::main_thread, this));
|
||||
_run_loop_thread = PBD::Thread::create (boost::bind (&BaseUI::main_thread, this), string_compose ("UI:%1", event_loop_name ()));
|
||||
_running.wait (_run_lock);
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ DebugBits PBD::DEBUG::Configuration = PBD::new_debug_bit ("configuration");
|
||||
DebugBits PBD::DEBUG::UndoHistory = PBD::new_debug_bit ("undohistory");
|
||||
DebugBits PBD::DEBUG::Timing = PBD::new_debug_bit ("timing");
|
||||
DebugBits PBD::DEBUG::Threads = PBD::new_debug_bit ("threads");
|
||||
DebugBits PBD::DEBUG::ThreadName = PBD::new_debug_bit ("threadname");
|
||||
DebugBits PBD::DEBUG::Locale = PBD::new_debug_bit ("locale");
|
||||
DebugBits PBD::DEBUG::StringConvert = PBD::new_debug_bit ("stringconvert");
|
||||
DebugBits PBD::DEBUG::DebugTimestamps = PBD::new_debug_bit ("debugtimestamps");
|
||||
@ -103,7 +104,7 @@ PBD::new_debug_bit (const char* name)
|
||||
void
|
||||
PBD::debug_only_print (const char* prefix, string str)
|
||||
{
|
||||
if ((PBD::debug_bits & DEBUG::Threads).any()) {
|
||||
if ((PBD::debug_bits & DEBUG::ThreadName).any()) {
|
||||
printf ("0x%lx (%s) ", (intptr_t) DEBUG_THREAD_SELF, pthread_name());
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ Downloader::start ()
|
||||
|
||||
_cancel = false;
|
||||
_status = 0; /* unknown at this point */
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Downloader::download, this)));
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Downloader::download, this), "Downloader"));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -59,7 +59,6 @@ write_callback (void* buffer, size_t size, size_t nmemb, void* d)
|
||||
static void*
|
||||
get_url (void* arg)
|
||||
{
|
||||
pthread_set_name ("FileArchiveURL");
|
||||
FileArchive::Request* r = (FileArchive::Request*) arg;
|
||||
CURL* curl;
|
||||
|
||||
@ -328,7 +327,10 @@ std::vector<std::string>
|
||||
FileArchive::contents_url ()
|
||||
{
|
||||
_req.mp.reset ();
|
||||
pthread_create (&_tid, NULL, get_url, (void*)&_req);
|
||||
|
||||
if (pthread_create_and_store ("FileArchiveHTTP", &_tid, get_url, (void*)&_req, 0)) {
|
||||
return std::vector<std::string> ();
|
||||
}
|
||||
|
||||
struct archive* a = setup_archive ();
|
||||
archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
|
||||
@ -359,7 +361,9 @@ int
|
||||
FileArchive::extract_url ()
|
||||
{
|
||||
_req.mp.reset ();
|
||||
pthread_create (&_tid, NULL, get_url, (void*)&_req);
|
||||
if (pthread_create_and_store ("FileArchiveHTTP", &_tid, get_url, (void*)&_req)) {
|
||||
return -1;
|
||||
}
|
||||
struct archive* a = setup_archive ();
|
||||
archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
|
||||
int rv = do_extract (a);
|
||||
|
@ -45,7 +45,7 @@ Inflater::~Inflater ()
|
||||
int
|
||||
Inflater::start ()
|
||||
{
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Inflater::threaded_inflate, this)));
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Inflater::threaded_inflate, this), "Inflater"));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
namespace PBD {
|
||||
|
||||
typedef std::bitset<128> DebugBits;
|
||||
typedef std::bitset<192> DebugBits;
|
||||
|
||||
LIBPBD_API extern DebugBits debug_bits;
|
||||
LIBPBD_API DebugBits new_debug_bit (const char* name);
|
||||
@ -64,6 +64,7 @@ namespace PBD {
|
||||
LIBPBD_API extern DebugBits UndoHistory;
|
||||
LIBPBD_API extern DebugBits Timing;
|
||||
LIBPBD_API extern DebugBits Threads;
|
||||
LIBPBD_API extern DebugBits ThreadName;
|
||||
LIBPBD_API extern DebugBits Locale;
|
||||
LIBPBD_API extern DebugBits StringConvert;
|
||||
LIBPBD_API extern DebugBits DebugTimestamps;
|
||||
|
@ -57,6 +57,7 @@
|
||||
# define PBD_RT_PRI_MAIN pbd_pthread_priority (THREAD_MAIN)
|
||||
# define PBD_RT_PRI_MIDI pbd_pthread_priority (THREAD_MIDI)
|
||||
# define PBD_RT_PRI_PROC pbd_pthread_priority (THREAD_PROC)
|
||||
# define PBD_RT_PRI_CTRL pbd_pthread_priority (THREAD_CTRL)
|
||||
|
||||
LIBPBD_API int pthread_create_and_store (std::string name, pthread_t *thread, void * (*start_routine)(void *), void * arg, uint32_t stacklimit = 0x80000 /*512kB*/);
|
||||
LIBPBD_API void pthread_cancel_one (pthread_t thread);
|
||||
@ -65,10 +66,13 @@ LIBPBD_API void pthread_kill_all (int signum);
|
||||
LIBPBD_API const char* pthread_name ();
|
||||
LIBPBD_API void pthread_set_name (const char* name);
|
||||
|
||||
LIBPBD_API void pbd_set_engine_rt_priority (int);
|
||||
|
||||
enum PBDThreadClass {
|
||||
THREAD_MAIN, // main audio I/O thread
|
||||
THREAD_MIDI, // MIDI I/O threads
|
||||
THREAD_PROC, // realtime worker
|
||||
THREAD_CTRL, // Automation watch, BaseUI
|
||||
THREAD_IO // non-realtime I/O
|
||||
};
|
||||
|
||||
@ -88,7 +92,7 @@ LIBPBD_API int pbd_realtime_pthread_create (
|
||||
void *arg);
|
||||
|
||||
LIBPBD_API int pbd_absolute_rt_priority (int policy, int priority);
|
||||
LIBPBD_API int pbd_set_thread_priority (pthread_t, const int policy, int priority);
|
||||
LIBPBD_API int pbd_set_thread_priority (pthread_t, int policy, int priority);
|
||||
LIBPBD_API bool pbd_mach_set_realtime_policy (pthread_t thread_id, double period_ns, bool main);
|
||||
|
||||
namespace PBD {
|
||||
@ -97,7 +101,7 @@ namespace PBD {
|
||||
|
||||
class LIBPBD_API Thread {
|
||||
public:
|
||||
static Thread* create (boost::function<void ()> const&, std::string const& name = "");
|
||||
static Thread* create (boost::function<void ()> const&, std::string const& name);
|
||||
static Thread* self ();
|
||||
void join ();
|
||||
bool caller_is_self () const;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2015 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2007-2009 David Robillard <d@drobilla.net>
|
||||
* Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2015-2024 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -23,11 +23,17 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !defined PLATFORM_WINDOWS && defined __GLIBC__
|
||||
#include <climits>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/debug.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
@ -37,6 +43,8 @@ DECLARE_DEFAULT_COMPARISONS (pthread_t) // Needed for 'DECLARE_DEFAULT_COMPARISO
|
||||
// if the type of object being contained has no appropriate comparison operators
|
||||
// defined (specifically, if operators '<' and '==' are undefined). This seems
|
||||
// to be the case with ptw32 'pthread_t' which is a simple struct.
|
||||
|
||||
#define pthread_gethandle pthread_getw32threadhandle_np
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -47,10 +55,54 @@ DECLARE_DEFAULT_COMPARISONS (pthread_t) // Needed for 'DECLARE_DEFAULT_COMPARISO
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef std::list<pthread_t> ThreadMap;
|
||||
static ThreadMap all_threads;
|
||||
static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static Glib::Threads::Private<char> thread_name (free);
|
||||
typedef std::map<pthread_t, std::string> ThreadMap;
|
||||
static ThreadMap all_threads;
|
||||
static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static Glib::Threads::Private<char> thread_name (free);
|
||||
static int base_priority_relative_to_max = -20;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
static
|
||||
std::string GetLastErrorAsString()
|
||||
{
|
||||
DWORD err = ::GetLastError();
|
||||
if(err == 0) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
LPSTR buf = nullptr;
|
||||
size_t size = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
|
||||
|
||||
std::string rv (buf, size);
|
||||
LocalFree (buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_win_set_realtime_policy (pthread_t thread, int priority)
|
||||
{
|
||||
if (priority < 12) {
|
||||
return false;
|
||||
}
|
||||
bool ok = false;
|
||||
|
||||
if (SetPriorityClass (GetCurrentProcess (), 0x00000100 /* REALTIME_PRIORITY_CLASS */)) {
|
||||
/* see https://learn.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities */
|
||||
ok = SetThreadPriority (pthread_gethandle (thread), priority);
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Using Windows RT thread class. set priority: %1\n", ok ? "OK" : GetLastErrorAsString ()));
|
||||
} else {
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Cannot use Windows RT thread class: %1\n", GetLastErrorAsString ()));
|
||||
ok = SetPriorityClass (GetCurrentProcess (), 0x00000080 /* HIGH_PRIORITY_CLASS */);
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Using Windows high priority thread class: %1\n", ok ? "OK" : GetLastErrorAsString ()));
|
||||
if (ok) {
|
||||
ok = SetThreadPriority (pthread_gethandle (thread), priority);
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Set Windows high thread priority: %1\n", ok ? "OK" : GetLastErrorAsString ()));
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace PBD
|
||||
{
|
||||
@ -72,148 +124,6 @@ PBD::notify_event_loops_about_thread_creation (pthread_t thread, const std::stri
|
||||
ThreadCreatedWithRequestSize (thread, emitting_thread_name, request_count);
|
||||
}
|
||||
|
||||
struct ThreadStartWithName {
|
||||
void* (*thread_work) (void*);
|
||||
void* arg;
|
||||
std::string name;
|
||||
|
||||
ThreadStartWithName (void* (*f) (void*), void* a, const std::string& s)
|
||||
: thread_work (f)
|
||||
, arg (a)
|
||||
, name (s)
|
||||
{}
|
||||
};
|
||||
|
||||
static void*
|
||||
fake_thread_start (void* arg)
|
||||
{
|
||||
ThreadStartWithName* ts = (ThreadStartWithName*)arg;
|
||||
void* (*thread_work) (void*) = ts->thread_work;
|
||||
void* thread_arg = ts->arg;
|
||||
|
||||
/* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
|
||||
pthread_set_name (ts->name.c_str ());
|
||||
|
||||
/* we don't need this object anymore */
|
||||
delete ts;
|
||||
|
||||
/* actually run the thread's work function */
|
||||
void* ret = thread_work (thread_arg);
|
||||
|
||||
/* cleanup */
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end (); ++i) {
|
||||
if (pthread_equal ((*i), pthread_self ())) {
|
||||
all_threads.erase (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
|
||||
/* done */
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_create_and_store (string name, pthread_t* thread, void* (*start_routine) (void*), void* arg, uint32_t stacklimit)
|
||||
{
|
||||
pthread_attr_t default_attr;
|
||||
int ret;
|
||||
|
||||
/* set default stack size to sensible default for memlocking */
|
||||
pthread_attr_init (&default_attr);
|
||||
if (stacklimit > 0) {
|
||||
pthread_attr_setstacksize (&default_attr, stacklimit);
|
||||
}
|
||||
|
||||
ThreadStartWithName* ts = new ThreadStartWithName (start_routine, arg, name);
|
||||
|
||||
if ((ret = pthread_create (thread, &default_attr, fake_thread_start, ts)) == 0) {
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
all_threads.push_back (*thread);
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
pthread_attr_destroy (&default_attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
pthread_set_name (const char* str)
|
||||
{
|
||||
/* copy string and delete it when exiting */
|
||||
thread_name.set (strdup (str)); // leaks
|
||||
|
||||
#if !defined PTW32_VERSION && defined _GNU_SOURCE
|
||||
/* set public thread name, up to 16 chars */
|
||||
char ptn[16];
|
||||
memset (ptn, 0, 16);
|
||||
strncpy (ptn, str, 15);
|
||||
pthread_setname_np (pthread_self (), ptn);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char*
|
||||
pthread_name ()
|
||||
{
|
||||
const char* str = thread_name.get ();
|
||||
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void
|
||||
pthread_kill_all (int signum)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end (); ++i) {
|
||||
if (!pthread_equal ((*i), pthread_self ())) {
|
||||
pthread_kill ((*i), signum);
|
||||
}
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_all ()
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end ();) {
|
||||
ThreadMap::iterator nxt = i;
|
||||
++nxt;
|
||||
|
||||
if (!pthread_equal ((*i), pthread_self ())) {
|
||||
pthread_cancel ((*i));
|
||||
}
|
||||
|
||||
i = nxt;
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_one (pthread_t thread)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end (); ++i) {
|
||||
if (pthread_equal ((*i), thread)) {
|
||||
all_threads.erase (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cancel (thread);
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
static size_t
|
||||
pbd_stack_size ()
|
||||
{
|
||||
@ -250,6 +160,148 @@ pbd_stack_size ()
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct ThreadStartWithName {
|
||||
void* (*thread_work) (void*);
|
||||
void* arg;
|
||||
std::string name;
|
||||
|
||||
ThreadStartWithName (void* (*f) (void*), void* a, const std::string& s)
|
||||
: thread_work (f)
|
||||
, arg (a)
|
||||
, name (s)
|
||||
{}
|
||||
};
|
||||
|
||||
static void*
|
||||
fake_thread_start (void* arg)
|
||||
{
|
||||
ThreadStartWithName* ts = (ThreadStartWithName*)arg;
|
||||
void* (*thread_work) (void*) = ts->thread_work;
|
||||
void* thread_arg = ts->arg;
|
||||
|
||||
/* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
|
||||
pthread_set_name (ts->name.c_str ());
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Started: '%1'\n", ts->name));
|
||||
|
||||
/* we don't need this object anymore */
|
||||
delete ts;
|
||||
|
||||
/* actually run the thread's work function */
|
||||
void* ret = thread_work (thread_arg);
|
||||
|
||||
/* cleanup */
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Terminated: '%1'\n", t.second));
|
||||
all_threads.erase (t.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
|
||||
/* done */
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_create_and_store (string name, pthread_t* thread, void* (*start_routine) (void*), void* arg, uint32_t stacklimit)
|
||||
{
|
||||
pthread_attr_t default_attr;
|
||||
int ret;
|
||||
|
||||
/* set default stack size to sensible default for memlocking */
|
||||
pthread_attr_init (&default_attr);
|
||||
if (stacklimit > 0) {
|
||||
pthread_attr_setstacksize (&default_attr, stacklimit + pbd_stack_size ());
|
||||
}
|
||||
|
||||
ThreadStartWithName* ts = new ThreadStartWithName (start_routine, arg, name);
|
||||
|
||||
if ((ret = pthread_create (thread, &default_attr, fake_thread_start, ts)) == 0) {
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
all_threads[*thread] = name;
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
pthread_attr_destroy (&default_attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
pthread_set_name (const char* str)
|
||||
{
|
||||
/* copy string and delete it when exiting */
|
||||
thread_name.set (strdup (str)); // leaks
|
||||
|
||||
#if !defined PTW32_VERSION && defined _GNU_SOURCE
|
||||
/* set public thread name, up to 16 chars */
|
||||
char ptn[16];
|
||||
memset (ptn, 0, 16);
|
||||
strncpy (ptn, str, 15);
|
||||
pthread_setname_np (pthread_self (), ptn);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char*
|
||||
pthread_name ()
|
||||
{
|
||||
const char* str = thread_name.get ();
|
||||
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void
|
||||
pthread_kill_all (int signum)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
continue;
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Kill: '%1'\n", t.second));
|
||||
pthread_kill (t.first, signum);
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_all ()
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
continue;
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Cancel: '%1'\n", t.second));
|
||||
pthread_cancel (t.first);
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_one (pthread_t thread)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, thread)) {
|
||||
all_threads.erase (t.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cancel (thread);
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
int
|
||||
pbd_pthread_create (
|
||||
const size_t stacksize,
|
||||
@ -261,12 +313,28 @@ pbd_pthread_create (
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init (&attr);
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
if (stacksize > 0) {
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Start Non-RT Thread stacksize = 0x%1%2\n", std::hex, stacksize));
|
||||
rv = pthread_create (thread, &attr, start_routine, arg);
|
||||
pthread_attr_destroy (&attr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
pbd_set_engine_rt_priority (int p)
|
||||
{
|
||||
/* this is mainly for JACK's benefit */
|
||||
const int p_max = sched_get_priority_max (SCHED_FIFO);
|
||||
const int p_min = sched_get_priority_min (SCHED_FIFO);
|
||||
if (p <= 0 || p <= p_min + 10 || p > p_max) {
|
||||
base_priority_relative_to_max = -20;
|
||||
} else {
|
||||
base_priority_relative_to_max = p - p_max;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pbd_pthread_priority (PBDThreadClass which)
|
||||
{
|
||||
@ -274,24 +342,22 @@ pbd_pthread_priority (PBDThreadClass which)
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
switch (which) {
|
||||
case THREAD_MAIN:
|
||||
return -1;
|
||||
return -1; // THREAD_PRIORITY_TIME_CRITICAL (15)
|
||||
case THREAD_MIDI:
|
||||
return -2;
|
||||
default:
|
||||
case THREAD_PROC:
|
||||
return -2;
|
||||
case THREAD_CTRL:
|
||||
default:
|
||||
return -14; // THREAD_PRIORITY_HIGHEST (2)
|
||||
case THREAD_IO:
|
||||
/* https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/sched.c
|
||||
* -> THREAD_PRIORITY_HIGHEST
|
||||
*/
|
||||
return -13;
|
||||
/* https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/sched.c */
|
||||
return -15; // THREAD_PRIORITY_ABOVE_NORMAL (1)
|
||||
}
|
||||
#else
|
||||
int base = -20;
|
||||
int base = base_priority_relative_to_max;
|
||||
const char* p = getenv ("ARDOUR_SCHED_PRI");
|
||||
if (p && *p) {
|
||||
base = atoi (p);
|
||||
if (base > -5 && base < 5) {
|
||||
if (base > -5 || base < -85) {
|
||||
base = -20;
|
||||
}
|
||||
}
|
||||
@ -304,6 +370,8 @@ pbd_pthread_priority (PBDThreadClass which)
|
||||
default:
|
||||
case THREAD_PROC:
|
||||
return base - 2;
|
||||
case THREAD_CTRL:
|
||||
return base - 3;
|
||||
case THREAD_IO:
|
||||
return base - 10;
|
||||
}
|
||||
@ -314,26 +382,15 @@ int
|
||||
pbd_absolute_rt_priority (int policy, int priority)
|
||||
{
|
||||
/* POSIX requires a spread of at least 32 steps between min..max */
|
||||
const int p_min = sched_get_priority_min (policy); // Linux: 1
|
||||
const int p_max = sched_get_priority_max (policy); // Linux: 99
|
||||
const int p_min = sched_get_priority_min (policy); // Linux: 1 Windows -15
|
||||
const int p_max = sched_get_priority_max (policy); // Linux: 99 Windows +15
|
||||
|
||||
if (priority == 0) {
|
||||
assert (0);
|
||||
priority = (p_min + p_max) / 2;
|
||||
} else if (priority > 0) {
|
||||
/* value relative to minium */
|
||||
priority += p_min - 1;
|
||||
} else {
|
||||
/* value relative maximum */
|
||||
priority += p_max + 1;
|
||||
}
|
||||
/* priority is relative to the max */
|
||||
assert (priority < 0);
|
||||
priority += p_max + 1;
|
||||
|
||||
if (priority > p_max) {
|
||||
priority = p_max;
|
||||
}
|
||||
if (priority < p_min) {
|
||||
priority = p_min;
|
||||
}
|
||||
priority = std::min (p_max, priority);
|
||||
priority = std::max (p_min, priority);
|
||||
return priority;
|
||||
}
|
||||
|
||||
@ -356,19 +413,42 @@ pbd_realtime_pthread_create (
|
||||
pthread_attr_setschedparam (&attr, &parm);
|
||||
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
if (stacksize > 0) {
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Start Realtime Thread policy = %1 priority = %2 stacksize = 0x%3%4\n", policy, parm.sched_priority, std::hex, stacksize));
|
||||
rv = pthread_create (thread, &attr, start_routine, arg);
|
||||
pthread_attr_destroy (&attr);
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (0 == rv && thread && parm.sched_priority >= 12) {
|
||||
set_win_set_realtime_policy (*thread, parm.sched_priority);
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
pbd_set_thread_priority (pthread_t thread, const int policy, int priority)
|
||||
pbd_set_thread_priority (pthread_t thread, int policy, int priority)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
policy = SCHED_OTHER;
|
||||
#endif
|
||||
|
||||
struct sched_param param;
|
||||
memset (¶m, 0, sizeof (param));
|
||||
param.sched_priority = pbd_absolute_rt_priority (policy, priority);
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Change '%1' to policy = %2 priority = %3\n", pthread_name(), policy, param.sched_priority));
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (is_pthread_active (thread) && param.sched_priority >= 12) {
|
||||
if (set_win_set_realtime_policy (thread, param.sched_priority)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return pthread_setschedparam (thread, SCHED_FIFO, ¶m);
|
||||
}
|
||||
|
||||
@ -484,6 +564,12 @@ PBD::Thread::Thread (boost::function<void ()> const& slot, std::string const& na
|
||||
if (pthread_create (&_t, &thread_attributes, _run, this)) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
if (_joinable) {
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
all_threads[_t] = name;
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
@ -492,8 +578,22 @@ PBD::Thread::_run (void* arg) {
|
||||
if (!self->_name.empty ()) {
|
||||
pthread_set_name (self->_name.c_str ());
|
||||
}
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Started: '%1'\n", self->_name));
|
||||
|
||||
self->_slot ();
|
||||
|
||||
/* cleanup */
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Terminated: '%1'\n", t.second));
|
||||
all_threads.erase (t.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -278,9 +278,7 @@ SystemExec::~SystemExec ()
|
||||
static void*
|
||||
interposer_thread (void *arg) {
|
||||
SystemExec *sex = static_cast<SystemExec *>(arg);
|
||||
pthread_set_name ("ExecStdOut");
|
||||
sex->output_interposer();
|
||||
pthread_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -522,7 +520,7 @@ SystemExec::start (StdErrMode stderr_mode, const char * /*vfork_exec_wrapper*/)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rv = pthread_create (&thread_id_tt, NULL, interposer_thread, this);
|
||||
int rv = pthread_create_and_store ("ExecStdOut", &thread_id_tt, interposer_thread, this, 0);
|
||||
thread_active=true;
|
||||
if (rv) {
|
||||
thread_active=false;
|
||||
@ -560,7 +558,6 @@ SystemExec::output_interposer()
|
||||
ReadStdout(rv, bytesRead); /* EMIT SIGNAL */
|
||||
}
|
||||
Terminated(); /* EMIT SIGNAL */
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -808,7 +805,7 @@ SystemExec::start (StdErrMode stderr_mode, const char *vfork_exec_wrapper)
|
||||
close_fd (pout[1]);
|
||||
close_fd (pin[0]);
|
||||
|
||||
int rv = pthread_create (&thread_id_tt, NULL, interposer_thread, this);
|
||||
int rv = pthread_create_and_store ("ExecStdOut", &thread_id_tt, interposer_thread, this, 0);
|
||||
thread_active=true;
|
||||
|
||||
if (rv) {
|
||||
@ -917,7 +914,6 @@ again:
|
||||
ReadStdout (rv, r); /* EMIT SIGNAL */
|
||||
}
|
||||
Terminated (); /* EMIT SIGNAL */
|
||||
pthread_exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -258,8 +258,6 @@ CC121::stop ()
|
||||
void
|
||||
CC121::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -238,8 +238,6 @@ void
|
||||
ContourDesignControlProtocol::thread_init ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::ContourDesignControl, "thread_init()\n");
|
||||
|
||||
pthread_set_name (X_("contourdesign"));
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self (), X_("contourdesign"), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (X_("contourdesign"), 128);
|
||||
|
||||
|
@ -283,8 +283,6 @@ FaderPort8::stop ()
|
||||
void
|
||||
FaderPort8::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -308,8 +308,6 @@ GenericMidiControlProtocol::stop ()
|
||||
void
|
||||
GenericMidiControlProtocol::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -327,6 +327,10 @@ MIDIControllable::midi_sense_note (Parser &, EventTwoBytes *msg, bool /*is_on*/)
|
||||
void
|
||||
MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg)
|
||||
{
|
||||
if (control_additional != msg->controller_number) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_controllable) {
|
||||
if (lookup_controllable ()) {
|
||||
return;
|
||||
@ -337,109 +341,106 @@ MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg)
|
||||
|
||||
_surface->maybe_start_touch (_controllable);
|
||||
|
||||
if (control_additional == msg->controller_number) {
|
||||
if (!_controllable->is_toggle()) {
|
||||
if (get_encoder() == No_enc) {
|
||||
float new_value = msg->value;
|
||||
float max_value = max(last_controllable_value, new_value);
|
||||
float min_value = min(last_controllable_value, new_value);
|
||||
float range = max_value - min_value;
|
||||
float threshold = (float) _surface->threshold ();
|
||||
|
||||
if (!_controllable->is_toggle()) {
|
||||
if (get_encoder() == No_enc) {
|
||||
float new_value = msg->value;
|
||||
float max_value = max(last_controllable_value, new_value);
|
||||
float min_value = min(last_controllable_value, new_value);
|
||||
float range = max_value - min_value;
|
||||
float threshold = (float) _surface->threshold ();
|
||||
bool const in_sync = (
|
||||
range < threshold &&
|
||||
_controllable->get_value() <= midi_to_control(max_value) &&
|
||||
_controllable->get_value() >= midi_to_control(min_value)
|
||||
);
|
||||
|
||||
bool const in_sync = (
|
||||
range < threshold &&
|
||||
_controllable->get_value() <= midi_to_control(max_value) &&
|
||||
_controllable->get_value() >= midi_to_control(min_value)
|
||||
);
|
||||
|
||||
/* If the surface is not motorised, we try to prevent jumps when
|
||||
the MIDI controller and controllable are out of sync.
|
||||
There might be a better way of doing this.
|
||||
*/
|
||||
|
||||
if (in_sync || _surface->motorised ()) {
|
||||
_controllable->set_value (midi_to_control (new_value), Controllable::UseGroup);
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI CC %1 value %2 %3\n", (int) msg->controller_number, (float) midi_to_control(new_value), current_uri() ));
|
||||
|
||||
last_controllable_value = new_value;
|
||||
} else {
|
||||
uint32_t cur_val = control_to_midi(_controllable->get_value ());
|
||||
int offset = (msg->value & 0x3f);
|
||||
switch (get_encoder()) {
|
||||
case Enc_L:
|
||||
if (msg->value & 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val - offset), Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (midi_to_control (cur_val + offset + 1), Controllable::UseGroup);
|
||||
}
|
||||
break;
|
||||
case Enc_R:
|
||||
if (msg->value & 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val + offset + 1), Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (midi_to_control (cur_val - offset), Controllable::UseGroup);
|
||||
}
|
||||
break;
|
||||
case Enc_2:
|
||||
// 0x40 is max pos offset
|
||||
if (msg->value > 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val - (0x7f - msg->value)), Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (midi_to_control (cur_val + msg->value + 1), Controllable::UseGroup);
|
||||
}
|
||||
break;
|
||||
case Enc_B:
|
||||
if (msg->value > 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val + offset + 1), Controllable::UseGroup);
|
||||
} else if (msg->value < 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val - (0x40 - msg->value)), Controllable::UseGroup);
|
||||
} // 0x40 = 0 do nothing
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI CC %1 value %2 %3\n", (int) msg->controller_number, (int) cur_val, current_uri() ));
|
||||
/* If the surface is not motorised, we try to prevent jumps when
|
||||
the MIDI controller and controllable are out of sync.
|
||||
There might be a better way of doing this.
|
||||
*/
|
||||
|
||||
if (in_sync || _surface->motorised ()) {
|
||||
_controllable->set_value (midi_to_control (new_value), Controllable::UseGroup);
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI CC %1 value %2 %3\n", (int) msg->controller_number, (float) midi_to_control(new_value), current_uri() ));
|
||||
|
||||
switch (get_ctltype()) {
|
||||
case Ctl_Dial:
|
||||
/* toggle value whenever direction of knob motion changes */
|
||||
if (last_incoming > 127) {
|
||||
/* relax ... first incoming message */
|
||||
} else {
|
||||
if (msg->value > last_incoming) {
|
||||
_controllable->set_value (1.0, Controllable::UseGroup);
|
||||
last_controllable_value = new_value;
|
||||
} else {
|
||||
uint32_t cur_val = control_to_midi(_controllable->get_value ());
|
||||
int offset = (msg->value & 0x3f);
|
||||
switch (get_encoder()) {
|
||||
case Enc_L:
|
||||
if (msg->value & 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val - offset), Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (0.0, Controllable::UseGroup);
|
||||
_controllable->set_value (midi_to_control (cur_val + offset + 1), Controllable::UseGroup);
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("dial Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
|
||||
}
|
||||
last_incoming = msg->value;
|
||||
break;
|
||||
case Ctl_Momentary:
|
||||
/* toggle it if over 64, otherwise leave it alone. This behaviour that works with buttons which send a value > 64 each
|
||||
* time they are pressed.
|
||||
*/
|
||||
if (msg->value >= 0x40) {
|
||||
_controllable->set_value (_controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("toggle Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
|
||||
}
|
||||
break;
|
||||
case Ctl_Toggle:
|
||||
/* toggle if value is over 64, otherwise turn it off. This is behaviour designed for buttons which send a value > 64 when pressed,
|
||||
maintain state (i.e. they know they were pressed) and then send zero the next time.
|
||||
*/
|
||||
if (msg->value >= 0x40) {
|
||||
_controllable->set_value (_controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (0.0, Controllable::NoGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 0 %2\n", (int) msg->controller_number, current_uri()));
|
||||
break;
|
||||
case Enc_R:
|
||||
if (msg->value & 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val + offset + 1), Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (midi_to_control (cur_val - offset), Controllable::UseGroup);
|
||||
}
|
||||
break;
|
||||
case Enc_2:
|
||||
// 0x40 is max pos offset
|
||||
if (msg->value > 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val - (0x7f - msg->value)), Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (midi_to_control (cur_val + msg->value + 1), Controllable::UseGroup);
|
||||
}
|
||||
break;
|
||||
case Enc_B:
|
||||
if (msg->value > 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val + offset + 1), Controllable::UseGroup);
|
||||
} else if (msg->value < 0x40) {
|
||||
_controllable->set_value (midi_to_control (cur_val - (0x40 - msg->value)), Controllable::UseGroup);
|
||||
} // 0x40 = 0 do nothing
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI CC %1 value %2 %3\n", (int) msg->controller_number, (int) cur_val, current_uri() ));
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
switch (get_ctltype()) {
|
||||
case Ctl_Dial:
|
||||
/* toggle value whenever direction of knob motion changes */
|
||||
if (last_incoming > 127) {
|
||||
/* relax ... first incoming message */
|
||||
} else {
|
||||
if (msg->value > last_incoming) {
|
||||
_controllable->set_value (1.0, Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (0.0, Controllable::UseGroup);
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("dial Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
|
||||
}
|
||||
last_incoming = msg->value;
|
||||
break;
|
||||
case Ctl_Momentary:
|
||||
/* toggle it if over 64, otherwise leave it alone. This behaviour that works with buttons which send a value > 64 each
|
||||
* time they are pressed.
|
||||
*/
|
||||
if (msg->value >= 0x40) {
|
||||
_controllable->set_value (_controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("toggle Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
|
||||
}
|
||||
break;
|
||||
case Ctl_Toggle:
|
||||
/* toggle if value is over 64, otherwise turn it off. This is behaviour designed for buttons which send a value > 64 when pressed,
|
||||
maintain state (i.e. they know they were pressed) and then send zero the next time.
|
||||
*/
|
||||
if (msg->value >= 0x40) {
|
||||
_controllable->set_value (_controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
} else {
|
||||
_controllable->set_value (0.0, Controllable::NoGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 0 %2\n", (int) msg->controller_number, current_uri()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -448,6 +449,10 @@ MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg)
|
||||
void
|
||||
MIDIControllable::midi_sense_program_change (Parser &, MIDI::byte msg)
|
||||
{
|
||||
if (msg != control_additional) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_controllable) {
|
||||
if (lookup_controllable ()) {
|
||||
return;
|
||||
@ -458,16 +463,13 @@ MIDIControllable::midi_sense_program_change (Parser &, MIDI::byte msg)
|
||||
|
||||
_surface->maybe_start_touch (_controllable);
|
||||
|
||||
if (msg == control_additional) {
|
||||
|
||||
if (!_controllable->is_toggle()) {
|
||||
_controllable->set_value (1.0, Controllable::UseGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI program %1 value 1.0 %3\n", (int) msg, current_uri() ));
|
||||
} else {
|
||||
float new_value = _controllable->get_value() > 0.5f ? 0.0f : 1.0f;
|
||||
_controllable->set_value (new_value, Controllable::UseGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI program %1 value %2 %3\n", (int) msg, (float) new_value, current_uri()));
|
||||
}
|
||||
if (!_controllable->is_toggle()) {
|
||||
_controllable->set_value (1.0, Controllable::UseGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI program %1 value 1.0 %3\n", (int) msg, current_uri() ));
|
||||
} else {
|
||||
float new_value = _controllable->get_value() > 0.5f ? 0.0f : 1.0f;
|
||||
_controllable->set_value (new_value, Controllable::UseGroup);
|
||||
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI program %1 value %2 %3\n", (int) msg, (float) new_value, current_uri()));
|
||||
}
|
||||
|
||||
last_value = (MIDI::byte) (_controllable->get_value() * 127.0); // to prevent feedback fights
|
||||
|
@ -665,8 +665,6 @@ void LaunchControlXL::handle_midi_note_off_message(MIDI::Parser & parser, MIDI::
|
||||
void
|
||||
LaunchControlXL::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -194,8 +194,6 @@ MackieControlProtocol::~MackieControlProtocol()
|
||||
void
|
||||
MackieControlProtocol::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -307,16 +307,9 @@ Maschine2::stop ()
|
||||
void
|
||||
Maschine2::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 1024);
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 1024);
|
||||
|
||||
struct sched_param rtparam;
|
||||
memset (&rtparam, 0, sizeof (rtparam));
|
||||
rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
|
||||
if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
|
||||
// do we care? not particularly.
|
||||
}
|
||||
set_thread_priority ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -284,8 +284,6 @@ OSC::start ()
|
||||
void
|
||||
OSC::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
if (_osc_unix_server) {
|
||||
Glib::RefPtr<IOSource> src = IOSource::create (lo_server_get_socket_fd (_osc_unix_server), IO_IN|IO_HUP|IO_ERR);
|
||||
src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_unix_server));
|
||||
|
@ -174,8 +174,6 @@ US2400Protocol::~US2400Protocol()
|
||||
void
|
||||
US2400Protocol::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -76,7 +76,6 @@ ArdourWebsockets::set_active (bool yn)
|
||||
void
|
||||
ArdourWebsockets::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name ().c_str ());
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self (), event_loop_name (), 2048);
|
||||
SessionEvent::create_per_thread_pool (event_loop_name (), 128);
|
||||
}
|
||||
|
@ -154,8 +154,6 @@ WiimoteControlProtocol::thread_init ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init init\n");
|
||||
|
||||
pthread_set_name (X_("wiimote"));
|
||||
|
||||
// allow to make requests to the GUI and RT thread(s)
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self (), X_("wiimote"), 2048);
|
||||
BasicUI::register_thread ("wiimote");
|
||||
|
@ -263,7 +263,9 @@ class LIBTEMPORAL_API Tempo {
|
||||
superclock_t _end_superclocks_per_note_type;
|
||||
int8_t _note_type;
|
||||
bool _locked_to_meter; /* XXX name has unclear meaning with nutempo */
|
||||
bool _continuing;
|
||||
bool _continuing; /* true if our effective end tempo is defined
|
||||
* by the following tempo in the TempoMap;
|
||||
* false if we use our own end tempo. */
|
||||
|
||||
static inline superclock_t double_npm_to_scpn (double npm) { return (superclock_t) llround ((60./npm) * superclock_ticks_per_second()); }
|
||||
|
||||
@ -348,8 +350,8 @@ class /*LIBTEMPORAL_API*/ MeterPoint : public Meter, public meter_hook, public v
|
||||
};
|
||||
|
||||
/* A TempoPoint is a combination of a Tempo with a Point. However, if the temp
|
||||
* is ramped, then at some point we will need to compute the ramp coefficients
|
||||
* (c-per-quarter and c-per-superclock) and store them so that we can compute
|
||||
* is ramped, then at some point we will need to compute the ramp coefficient
|
||||
* (_omega) and store it so that we can compute tempo-at-time and
|
||||
* time-at-quarter-note on demand.
|
||||
*/
|
||||
|
||||
|
@ -307,7 +307,12 @@ WaveView::get_item_and_draw_rect_in_window_coords (Rect const& canvas_rect, Rect
|
||||
*/
|
||||
|
||||
double const width = region_length() / _props->samples_per_pixel;
|
||||
item_rect = item_to_window (Rect (0.0, 0.0, width, _props->height));
|
||||
item_rect = item_to_window (Rect (0.0, 0.0, width, _props->height), false);
|
||||
|
||||
item_rect.x0 = floor (item_rect.x0);
|
||||
item_rect.x1 = ceil (item_rect.x1);
|
||||
item_rect.y0 = round (item_rect.y0);
|
||||
item_rect.y1 = round (item_rect.y1);
|
||||
|
||||
/* Now lets get the intersection with the area we've been asked to draw */
|
||||
|
||||
@ -317,7 +322,6 @@ WaveView::get_item_and_draw_rect_in_window_coords (Rect const& canvas_rect, Rect
|
||||
// No intersection with drawing area
|
||||
return false;
|
||||
}
|
||||
|
||||
/* draw_rect now defines the rectangle we need to update/render the waveview
|
||||
* into, in window coordinate space.
|
||||
*
|
||||
@ -325,7 +329,7 @@ WaveView::get_item_and_draw_rect_in_window_coords (Rect const& canvas_rect, Rect
|
||||
* and/or end.
|
||||
*/
|
||||
draw_rect.x0 = floor (draw_rect.x0);
|
||||
draw_rect.x1 = floor (draw_rect.x1);
|
||||
draw_rect.x1 = ceil (draw_rect.x1);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1086,12 +1090,19 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
|
||||
|
||||
assert (image_to_draw);
|
||||
|
||||
/* Calculate the sample that corresponds to the region-rectangle's left edge
|
||||
* in the editor at current zoom (see TimeAxisViewItem::set_position).
|
||||
*/
|
||||
double const samples_per_pixel = _props->samples_per_pixel;
|
||||
samplepos_t const region_position = _region->position().samples();
|
||||
samplepos_t const region_view_x = round (round (region_position / samples_per_pixel) * samples_per_pixel);
|
||||
ARDOUR::sampleoffset_t region_view_dx = region_position - region_view_x;
|
||||
|
||||
/* compute the first pixel of the image that should be used when we
|
||||
* render the specified range.
|
||||
*/
|
||||
|
||||
double image_origin_in_self_coordinates =
|
||||
(image_to_draw->props.get_sample_start () - _props->region_start) / _props->samples_per_pixel;
|
||||
double image_origin_in_self_coordinates = (image_to_draw->props.get_sample_start () - _props->region_start + region_view_dx) / samples_per_pixel;
|
||||
|
||||
/* the image may only be a best-effort ... it may not span the entire
|
||||
* range requested, though it is guaranteed to cover the start. So
|
||||
|
@ -405,7 +405,7 @@ WaveViewDrawingThread::start ()
|
||||
{
|
||||
assert (!_thread);
|
||||
|
||||
_thread = PBD::Thread::create (&WaveViewThreads::thread_proc);
|
||||
_thread = PBD::Thread::create (&WaveViewThreads::thread_proc, "WaveViewDrawing");
|
||||
}
|
||||
|
||||
void
|
||||
@ -477,8 +477,6 @@ WaveViewThreads::thread_proc ()
|
||||
void
|
||||
WaveViewThreads::_thread_proc ()
|
||||
{
|
||||
pthread_set_name ("WaveViewDrawing");
|
||||
|
||||
while (true) {
|
||||
|
||||
_queue_mutex.lock ();
|
||||
|
@ -48,3 +48,5 @@
|
||||
<Binding channel="10" pgm="13" action="Editor/playhead-to-edit"/> <!-- -->
|
||||
<Binding channel="10" pgm="14" action="Common/jump-forward-to-mark"/> <!-- -->
|
||||
<Binding channel="10" pgm="15" function="next-bank"/> <!-- Next bank -->
|
||||
|
||||
</ArdourMIDIBindings>
|
@ -313,6 +313,7 @@ if test -n "$PACKAGE_GDB"; then
|
||||
cp -r ${SRCCACHE}/gdb12 $DESTDIR/gdb12
|
||||
cat > $DESTDIR/debug.bat << EOF
|
||||
set PYTHONPATH=%~dp0\gdb12\python3.10
|
||||
set PATH=%~dp0\gdb12\;%PATH%
|
||||
cd bin
|
||||
..\\gdb12\\gdb.exe -ex "set logging overwrite on" -ex "set height 0" -ex "set logging file %UserProfile%\\${PRODUCT_NAME}-debug.log" -ex "set logging enabled on" -ex "target exec ${PRODUCT_EXE}" -ex "run"
|
||||
EOF
|
||||
|
44
wscript
44
wscript
@ -150,7 +150,7 @@ clang_dict['xsaveintrin'] = ''
|
||||
clang_dict['xmmintrinsics'] = ''
|
||||
clang_dict['silence-unused-arguments'] = '-Qunused-arguments'
|
||||
clang_dict['extra-cxx-warnings'] = [ '-Woverloaded-virtual', '-Wno-mismatched-tags', '-Wno-cast-align', '-Wno-unused-local-typedefs', '-Wunneeded-internal-declaration' ]
|
||||
clang_dict['basic-warnings'] = [ '-Wall', '-Wpointer-arith', '-Wcast-qual', '-Wcast-align', '-Wno-unused-parameter', '-Wno-deprecated-declarations', '-Wno-deprecated-copy-with-user-provided-copy' ]
|
||||
clang_dict['basic-warnings'] = [ '-Wall', '-Wpointer-arith', '-Wcast-qual', '-Wcast-align', '-Wno-unused-parameter', '-Wno-deprecated-declarations' ]
|
||||
clang_dict['cxx-strict'] = [ '-ansi', '-Wnon-virtual-dtor', '-Woverloaded-virtual', '-fstrict-overflow' ]
|
||||
clang_dict['strict'] = ['-Wall', '-Wcast-align', '-Wextra', '-Wwrite-strings' ]
|
||||
clang_dict['generic-x86'] = [ '-arch', 'i386' ]
|
||||
@ -163,6 +163,11 @@ clang_darwin_dict['cxx-strict'] = [ '-ansi', '-Wnon-virtual-dtor', '-Woverloaded
|
||||
clang_darwin_dict['full-optimization'] = [ '-O3', '-ffast-math']
|
||||
compiler_flags_dictionaries['clang-darwin'] = clang_darwin_dict
|
||||
|
||||
# Xcode 15 does not like our boost version, producing warnings from almost every file
|
||||
clang15_darwin_dict = compiler_flags_dictionaries['clang-darwin'].copy()
|
||||
clang15_darwin_dict['basic-warnings'] = clang15_darwin_dict['basic-warnings'] + ["-Wno-deprecated-builtins", "-Wno-deprecated-copy-with-user-provided-copy"]
|
||||
compiler_flags_dictionaries['clang15-darwin'] = clang15_darwin_dict
|
||||
|
||||
# Version stuff
|
||||
|
||||
def fetch_git_revision_date ():
|
||||
@ -396,9 +401,25 @@ int main() { return 0; }''',
|
||||
execute = False,
|
||||
msg = 'Checking for clang')
|
||||
|
||||
|
||||
if platform == 'darwin' and is_clang:
|
||||
is_clang15_darwin = conf.check_cxx(fragment = '''
|
||||
#if !defined __clang_major__ || __clang_major__ < 15
|
||||
#error
|
||||
#endif
|
||||
int main() { return 0; }''',
|
||||
features = 'cxx',
|
||||
mandatory = False,
|
||||
execute = False,
|
||||
msg = 'Checking for clang >= 15')
|
||||
|
||||
|
||||
if is_clang:
|
||||
if platform == 'darwin':
|
||||
compiler_name = 'clang-darwin'
|
||||
if is_clang15_darwin:
|
||||
compiler_name = 'clang15-darwin'
|
||||
else:
|
||||
compiler_name = 'clang-darwin'
|
||||
else:
|
||||
compiler_name = 'clang'
|
||||
elif conf.env['MSVC_COMPILER']:
|
||||
@ -459,6 +480,8 @@ int main() { return 0; }''',
|
||||
conf.env['build_host'] = 'ventura'
|
||||
elif re.search ("^23[.]", version) is not None:
|
||||
conf.env['build_host'] = 'sonoma'
|
||||
elif re.search ("^24[.]", version) is not None:
|
||||
conf.env['build_host'] = 'sequoia'
|
||||
else:
|
||||
conf.env['build_host'] = 'irrelevant'
|
||||
|
||||
@ -500,6 +523,8 @@ int main() { return 0; }''',
|
||||
conf.env['build_target'] = 'ventura'
|
||||
elif re.search ("^23[.]", version) is not None:
|
||||
conf.env['build_target'] = 'sonoma'
|
||||
elif re.search ("^24[.]", version) is not None:
|
||||
conf.env['build_target'] = 'sequoia'
|
||||
else:
|
||||
conf.env['build_target'] = 'catalina'
|
||||
else:
|
||||
@ -560,20 +585,20 @@ int main() { return 0; }''',
|
||||
elif conf.options.cxx11:
|
||||
conf.check_cxx(cxxflags=["-std=c++11"])
|
||||
cxx_flags.append('-std=c++11')
|
||||
elif conf.env['build_host'] in [ 'bigsur', 'monterey', 'ventura', 'sonoma' ]:
|
||||
elif conf.env['build_host'] in [ 'bigsur', 'monterey', 'ventura', 'sonoma', 'sequoia' ]:
|
||||
conf.check_cxx(cxxflags=["-std=c++17"])
|
||||
cxx_flags.append('-std=c++17')
|
||||
elif conf.env['build_host'] in [ 'mavericks', 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina' ]:
|
||||
conf.check_cxx(cxxflags=["-std=c++11"])
|
||||
cxx_flags.append('-std=c++11')
|
||||
|
||||
if conf.options.cxx11 or conf.options.cxx17 or conf.env['build_host'] in [ 'mavericks', 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina' , 'bigsur', 'monterey', 'ventura', 'sonoma' ]:
|
||||
if conf.options.cxx11 or conf.options.cxx17 or conf.env['build_host'] in [ 'mavericks', 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina' , 'bigsur', 'monterey', 'ventura', 'sonoma', 'sequoia' ]:
|
||||
if platform == "darwin":
|
||||
# Mavericks and later changed the syntax to be used when including Carbon headers,
|
||||
# from requiring a full path to requiring just the header name.
|
||||
cxx_flags.append('-DCARBON_FLAT_HEADERS')
|
||||
|
||||
if not opt.use_libcpp and not conf.env['build_host'] in [ 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina', 'bigsur', 'monterey', 'ventura', 'sonoma' ]:
|
||||
if not opt.use_libcpp and not conf.env['build_host'] in [ 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina', 'bigsur', 'monterey', 'ventura', 'sonoma', 'sequoia' ]:
|
||||
cxx_flags.append('--stdlib=libstdc++')
|
||||
linker_flags.append('--stdlib=libstdc++')
|
||||
# Prevents visibility issues in standard headers
|
||||
@ -585,7 +610,7 @@ int main() { return 0; }''',
|
||||
cxx_flags.append('-DBOOST_NO_AUTO_PTR')
|
||||
cxx_flags.append('-DBOOST_BIND_GLOBAL_PLACEHOLDERS')
|
||||
|
||||
if (is_clang and platform == "darwin") or conf.env['build_host'] in [ 'mavericks', 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina' , 'bigsur', 'monterey', 'ventura', 'sonoma' ]:
|
||||
if (is_clang and platform == "darwin") or conf.env['build_host'] in [ 'mavericks', 'yosemite', 'el_capitan', 'sierra', 'high_sierra', 'mojave', 'catalina' , 'bigsur', 'monterey', 'ventura', 'sonoma', 'sequoia' ]:
|
||||
# Silence warnings about the non-existing osx clang compiler flags
|
||||
# -compatibility_version and -current_version. These are Waf
|
||||
# generated and not needed with clang
|
||||
@ -715,14 +740,11 @@ int main() { return 0; }''',
|
||||
"-mmacosx-version-min=10.11"))
|
||||
linker_flags.append("-mmacosx-version-min=10.11")
|
||||
|
||||
elif conf.env['build_target'] in ['bigsur', 'monterey', 'ventura', 'sonoma']:
|
||||
elif conf.env['build_target'] in ['bigsur', 'monterey', 'ventura', 'sonoma', 'sequoia']:
|
||||
compiler_flags.extend(
|
||||
("-DMAC_OS_X_VERSION_MAX_ALLOWED=110000",
|
||||
"-mmacosx-version-min=11.0"))
|
||||
linker_flags.append("-mmacosx-version-min=11.0")
|
||||
# Xcode 15 does not like our boost version, producing warnings from almost every file
|
||||
# boost/type_traits/has_trivial_destructor.hpp:30:86: warning: builtin __has_trivial_destructor is deprecated; use __is_trivially_destructible instead
|
||||
flags_dict['basic-warnings'].append ("-Wno-deprecated-builtins")
|
||||
|
||||
#
|
||||
# save off CPU element in an env
|
||||
@ -1501,7 +1523,7 @@ int main () { __int128 x = 0; return 0; }
|
||||
set_compiler_flags (conf, Options.options)
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
if conf.env['build_host'] not in [ 'mojave', 'catalina', 'bigsur', 'monterey', 'ventura', 'sonoma']:
|
||||
if conf.env['build_host'] not in [ 'mojave', 'catalina', 'bigsur', 'monterey', 'ventura', 'sonoma', 'sequoia']:
|
||||
conf.env.append_value('CXXFLAGS_OSX', '-F/System/Library/Frameworks')
|
||||
|
||||
conf.env.append_value('CXXFLAGS_OSX', '-F/Library/Frameworks')
|
||||
|
Loading…
Reference in New Issue
Block a user