13
0

Merge branch 'ardour'

This commit is contained in:
Robin Gareus 2024-10-10 03:13:01 +02:00
commit be4dab7336
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
84 changed files with 854 additions and 620 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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());

View File

@ -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 ();
}

View File

@ -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"/>

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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 */

View File

@ -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(); }

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -861,6 +861,7 @@ enum PlaylistDisposition {
enum MidiTrackNameSource {
SMFTrackNumber,
SMFTrackName,
SMFFileAndTrackName,
SMFInstrumentName
};

View File

@ -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>(); }

View File

@ -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

View File

@ -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 ()
{

View File

@ -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 ();

View File

@ -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;

View File

@ -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));
}

View File

@ -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 ();
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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 ();

View File

@ -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 ()

View File

@ -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),

View File

@ -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

View File

@ -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 ();

View File

@ -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);

View File

@ -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 ();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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();
}

View File

@ -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)));
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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));

View File

@ -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) {

View File

@ -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;

View 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");

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 (&param, 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, &param);
}
@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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));

View File

@ -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);

View File

@ -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);
}

View File

@ -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");

View File

@ -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.
*/

View File

@ -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

View File

@ -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 ();

View File

@ -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>

View File

@ -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
View File

@ -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')