X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=blobdiff_plain;f=libs%2Fardour%2Fglobals.cc;h=974247aef57cb08d26daebf280485cee9bc1da8e;hp=5874ac3b1b25d183cea69ba2766e2497605947b8;hb=c8c6bca6587450ff64303dbc994a4cd28d6ce7aa;hpb=1745340c67d66d8dd92e5b3a377e935ed5eea973 diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 5874ac3b1b..974247aef5 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -37,6 +37,14 @@ #include #include +#include +#include "pbd/gstdio_compat.h" + +#ifdef PLATFORM_WINDOWS +#include // for _setmaxstdio +#include // for LARGE_INTEGER +#endif + #ifdef WINDOWS_VST_SUPPORT #include #endif @@ -55,7 +63,7 @@ #ifdef check #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */ -#endif +#endif #include #include @@ -72,7 +80,6 @@ #include "pbd/fpu.h" #include "pbd/file_utils.h" #include "pbd/enumwriter.h" -#include "pbd/basename.h" #include "midi++/port.h" #include "midi++/mmc.h" @@ -85,12 +92,17 @@ #include "ardour/audioregion.h" #include "ardour/buffer_manager.h" #include "ardour/control_protocol_manager.h" +#include "ardour/directory_names.h" +#include "ardour/event_type_map.h" #include "ardour/filesystem_paths.h" #include "ardour/midi_region.h" +#include "ardour/midi_ui.h" #include "ardour/midiport_manager.h" #include "ardour/mix.h" +#include "ardour/operations.h" #include "ardour/panner_manager.h" #include "ardour/plugin_manager.h" +#include "ardour/presentation_info.h" #include "ardour/process_thread.h" #include "ardour/profile.h" #include "ardour/rc_configuration.h" @@ -99,14 +111,15 @@ #include "ardour/runtime_functions.h" #include "ardour/session_event.h" #include "ardour/source_factory.h" +#include "ardour/uri_map.h" #include "audiographer/routines.h" #if defined (__APPLE__) - #include // For Gestalt +#include #endif -#include "i18n.h" +#include "pbd/i18n.h" ARDOUR::RCConfiguration* ARDOUR::Config = 0; ARDOUR::RuntimeProfile* ARDOUR::Profile = 0; @@ -123,9 +136,17 @@ find_peaks_t ARDOUR::find_peaks = 0; apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0; mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0; mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0; +copy_vector_t ARDOUR::copy_vector = 0; PBD::Signal1 ARDOUR::BootMessage; +PBD::Signal3 ARDOUR::PluginScanMessage; +PBD::Signal1 ARDOUR::PluginScanTimeout; PBD::Signal0 ARDOUR::GUIIdle; +PBD::Signal3 ARDOUR::CopyConfigurationFiles; + +std::vector ARDOUR::reserved_io_names; + +static bool have_old_configuration_files = false; namespace ARDOUR { extern void setup_enum_writer (); @@ -143,11 +164,32 @@ setup_hardware_optimization (bool try_optimization) if (try_optimization) { - FPU fpu; + FPU* fpu = FPU::instance(); #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS) - if (fpu.has_sse()) { +#ifdef PLATFORM_WINDOWS + /* We have AVX-optimized code for Windows */ + + if (fpu->has_avx()) { +#else + /* AVX code doesn't compile on Linux yet */ + + if (false) { +#endif + info << "Using AVX optimized routines" << endmsg; + + // AVX SET + compute_peak = x86_sse_avx_compute_peak; + find_peaks = x86_sse_avx_find_peaks; + apply_gain_to_buffer = x86_sse_avx_apply_gain_to_buffer; + mix_buffers_with_gain = x86_sse_avx_mix_buffers_with_gain; + mix_buffers_no_gain = x86_sse_avx_mix_buffers_no_gain; + copy_vector = x86_sse_avx_copy_vector; + + generic_mix_functions = false; + + } else if (fpu->has_sse()) { info << "Using SSE optimized routines" << endmsg; @@ -157,23 +199,21 @@ setup_hardware_optimization (bool try_optimization) apply_gain_to_buffer = x86_sse_apply_gain_to_buffer; mix_buffers_with_gain = x86_sse_mix_buffers_with_gain; mix_buffers_no_gain = x86_sse_mix_buffers_no_gain; + copy_vector = default_copy_vector; generic_mix_functions = false; } #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS) - SInt32 sysVersion = 0; - - if (noErr != Gestalt(gestaltSystemVersion, &sysVersion)) - sysVersion = 0; - if (sysVersion >= 0x00001040) { // Tiger at least + if (floor (kCFCoreFoundationVersionNumber) > kCFCoreFoundationVersionNumber10_4) { /* at least Tiger */ compute_peak = veclib_compute_peak; find_peaks = veclib_find_peaks; apply_gain_to_buffer = veclib_apply_gain_to_buffer; mix_buffers_with_gain = veclib_mix_buffers_with_gain; mix_buffers_no_gain = veclib_mix_buffers_no_gain; + copy_vector = default_copy_vector; generic_mix_functions = false; @@ -193,6 +233,7 @@ setup_hardware_optimization (bool try_optimization) apply_gain_to_buffer = default_apply_gain_to_buffer; mix_buffers_with_gain = default_mix_buffers_with_gain; mix_buffers_no_gain = default_mix_buffers_no_gain; + copy_vector = default_copy_vector; info << "No H/W specific optimizations in use" << endmsg; } @@ -209,7 +250,12 @@ lotsa_files_please () if (getrlimit (RLIMIT_NOFILE, &rl) == 0) { +#ifdef __APPLE__ + /* See the COMPATIBILITY note on the Apple setrlimit() man page */ + rl.rlim_cur = min ((rlim_t) OPEN_MAX, rl.rlim_max); +#else rl.rlim_cur = rl.rlim_max; +#endif if (setrlimit (RLIMIT_NOFILE, &rl) != 0) { if (rl.rlim_cur == RLIM_INFINITY) { @@ -225,9 +271,150 @@ lotsa_files_please () } else { error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg; } +#else + /* this only affects stdio. 2048 is the maxium possible (512 the default). + * + * If we want more, we'll have to replaces the POSIX I/O interfaces with + * Win32 API calls (CreateFile, WriteFile, etc) which allows for 16K. + * + * see http://stackoverflow.com/questions/870173/is-there-a-limit-on-number-of-open-files-in-windows + * and http://bugs.mysql.com/bug.php?id=24509 + */ + int newmax = _setmaxstdio (2048); + if (newmax > 0) { + info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, newmax) << endmsg; + } else { + error << string_compose (_("Could not set system open files limit. Current limit is %1 open files"), _getmaxstdio) << endmsg; + } #endif } +static int +copy_configuration_files (string const & old_dir, string const & new_dir, int old_version) +{ + string old_name; + string new_name; + + /* ensure target directory exists */ + + if (g_mkdir_with_parents (new_dir.c_str(), 0755)) { + return -1; + } + + if (old_version >= 3) { + + old_name = Glib::build_filename (old_dir, X_("recent")); + new_name = Glib::build_filename (new_dir, X_("recent")); + + copy_file (old_name, new_name); + + old_name = Glib::build_filename (old_dir, X_("sfdb")); + new_name = Glib::build_filename (new_dir, X_("sfdb")); + + copy_file (old_name, new_name); + + /* can only copy ardour.rc/config - UI config is not compatible */ + + /* users who have been using git/nightlies since the last + * release of 3.5 will have $CONFIG/config rather than + * $CONFIG/ardour.rc. Pick up the newer "old" config file, + * to avoid confusion. + */ + + string old_name = Glib::build_filename (old_dir, X_("config")); + + if (!Glib::file_test (old_name, Glib::FILE_TEST_EXISTS)) { + old_name = Glib::build_filename (old_dir, X_("ardour.rc")); + } + + new_name = Glib::build_filename (new_dir, X_("config")); + + copy_file (old_name, new_name); + + /* copy templates and route templates */ + + old_name = Glib::build_filename (old_dir, X_("templates")); + new_name = Glib::build_filename (new_dir, X_("templates")); + + copy_recurse (old_name, new_name); + + old_name = Glib::build_filename (old_dir, X_("route_templates")); + new_name = Glib::build_filename (new_dir, X_("route_templates")); + + copy_recurse (old_name, new_name); + + /* presets */ + + old_name = Glib::build_filename (old_dir, X_("presets")); + new_name = Glib::build_filename (new_dir, X_("presets")); + + copy_recurse (old_name, new_name); + + /* presets */ + + old_name = Glib::build_filename (old_dir, X_("plugin_statuses")); + new_name = Glib::build_filename (new_dir, X_("plugin_statuses")); + + copy_file (old_name, new_name); + + /* export formats */ + + old_name = Glib::build_filename (old_dir, export_formats_dir_name); + new_name = Glib::build_filename (new_dir, export_formats_dir_name); + + vector export_formats; + g_mkdir_with_parents (Glib::build_filename (new_dir, export_formats_dir_name).c_str(), 0755); + find_files_matching_pattern (export_formats, old_name, X_("*.format")); + for (vector::iterator i = export_formats.begin(); i != export_formats.end(); ++i) { + std::string from = *i; + std::string to = Glib::build_filename (new_name, Glib::path_get_basename (*i)); + copy_file (from, to); + } + } + + return 0; +} + +void +ARDOUR::check_for_old_configuration_files () +{ + int current_version = atoi (X_(PROGRAM_VERSION)); + + if (current_version <= 1) { + return; + } + + int old_version = current_version - 1; + + string old_config_dir = user_config_directory (old_version); + /* pass in the current version explicitly to avoid creation */ + string current_config_dir = user_config_directory (current_version); + + if (!Glib::file_test (current_config_dir, Glib::FILE_TEST_IS_DIR)) { + if (Glib::file_test (old_config_dir, Glib::FILE_TEST_IS_DIR)) { + have_old_configuration_files = true; + } + } +} + +int +ARDOUR::handle_old_configuration_files (boost::function ui_handler) +{ + if (have_old_configuration_files) { + int current_version = atoi (X_(PROGRAM_VERSION)); + assert (current_version > 1); // established in check_for_old_configuration_files () + int old_version = current_version - 1; + string old_config_dir = user_config_directory (old_version); + string current_config_dir = user_config_directory (current_version); + + if (ui_handler (old_config_dir, current_config_dir, old_version)) { + copy_configuration_files (old_config_dir, current_config_dir, old_version); + return 1; + } + } + return 0; +} + bool ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir) { @@ -239,10 +426,12 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir #ifdef ENABLE_NLS (void) bindtextdomain(PACKAGE, localedir); + (void) bind_textdomain_codeset (PACKAGE, "UTF-8"); #endif SessionEvent::init_event_pool (); + Operations::make_operations_quarks (); SessionObject::make_property_quarks (); Region::make_property_quarks (); MidiRegion::make_property_quarks (); @@ -250,6 +439,7 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir RouteGroup::make_property_quarks (); Playlist::make_property_quarks (); AudioPlaylist::make_property_quarks (); + PresentationInfo::make_property_quarks (); /* this is a useful ready to use PropertyChange that many things need to check. This avoids having to compose @@ -314,38 +504,61 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir SourceFactory::init (); Analyser::init (); - /* singleton - first object is "it" */ + /* singletons - first object is "it" */ (void) PluginManager::instance(); +#ifdef LV2_SUPPORT + (void) URIMap::instance(); +#endif + (void) EventTypeMap::instance(); + + ControlProtocolManager::instance().discover_control_protocols (); + + /* for each control protocol, check for a request buffer factory method + and if it exists, store it in the EventLoop list of such + methods. This allows the relevant threads to register themselves + with EventLoops so that signal emission can be RT-safe. + */ + + ControlProtocolManager::instance().register_request_buffer_factories (); + /* it would be nice if this could auto-register itself in the + constructor, since MidiControlUI is a singleton, but it can't be + created until after the engine is running. Therefore we have to + explicitly register it here. + */ + EventLoop::register_request_buffer_factory (X_("midiUI"), MidiControlUI::request_factory); ProcessThread::init (); /* the + 4 is a bit of a handwave. i don't actually know how many more per-thread buffer sets we need above the h/w concurrency, but its definitely > 1 more. */ - BufferManager::init (hardware_concurrency() + 4); + BufferManager::init (hardware_concurrency() + 4); PannerManager::instance().discover_panners(); - // Initialize parameter metadata - EventTypeMap::instance().new_parameter(NullAutomation); - EventTypeMap::instance().new_parameter(GainAutomation); - EventTypeMap::instance().new_parameter(PanAzimuthAutomation); - EventTypeMap::instance().new_parameter(PanElevationAutomation); - EventTypeMap::instance().new_parameter(PanWidthAutomation); - EventTypeMap::instance().new_parameter(PluginAutomation); - EventTypeMap::instance().new_parameter(SoloAutomation); - EventTypeMap::instance().new_parameter(MuteAutomation); - EventTypeMap::instance().new_parameter(MidiCCAutomation); - EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation); - EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation); - EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation); - EventTypeMap::instance().new_parameter(FadeInAutomation); - EventTypeMap::instance().new_parameter(FadeOutAutomation); - EventTypeMap::instance().new_parameter(EnvelopeAutomation); - EventTypeMap::instance().new_parameter(MidiCCAutomation); - ARDOUR::AudioEngine::create (); + /* it is unfortunate that we need to include reserved names here that + refer to control surfaces. But there's no way to ensure a complete + lack of collisions without doing this, since the control surface + support may not even be active. Without adding an API to control + surface support that would list their port names, we do have to + list them here. + */ + + char const * const reserved[] = { + _("Monitor"), + _("Master"), + _("Control"), + _("Click"), + _("Mackie"), + 0 + }; + + for (int n = 0; reserved[n]; ++n) { + reserved_io_names.push_back (reserved[n]); + } + libardour_initialized = true; return true; @@ -354,8 +567,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir void ARDOUR::init_post_engine () { - ControlProtocolManager::instance().discover_control_protocols (); - XMLNode* node; if ((node = Config->control_protocol_state()) != 0) { ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version); @@ -363,11 +574,11 @@ ARDOUR::init_post_engine () /* find plugins */ - ARDOUR::PluginManager::instance().refresh (); + ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start()); } void -ARDOUR::cleanup () +ARDOUR::cleanup () { if (!libardour_initialized) { return; @@ -387,38 +598,13 @@ ARDOUR::cleanup () #ifdef LXVST_SUPPORT vstfx_exit(); #endif + delete &PluginManager::instance(); + delete Config; PBD::cleanup (); return; } -void -ARDOUR::find_bindings_files (map& files) -{ - vector found; - Searchpath spath = ardour_config_search_path(); - - if (getenv ("ARDOUR_SAE")) { - Glib::PatternSpec pattern("*SAE-*.bindings"); - find_matching_files_in_search_path (spath, pattern, found); - } else { - Glib::PatternSpec pattern("*.bindings"); - find_matching_files_in_search_path (spath, pattern, found); - } - - if (found.empty()) { - return; - } - - for (vector::iterator x = found.begin(); x != found.end(); ++x) { - std::string path(*x); - pair namepath; - namepath.second = path; - namepath.first = PBD::basename_nosuffix (path); - files.insert (namepath); - } -} - bool ARDOUR::no_auto_connect() { @@ -428,6 +614,7 @@ ARDOUR::no_auto_connect() void ARDOUR::setup_fpu () { + FPU* fpu = FPU::instance (); if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) { // valgrind doesn't understand this assembler stuff @@ -438,13 +625,8 @@ ARDOUR::setup_fpu () #if defined(ARCH_X86) && defined(USE_XMMINTRIN) int MXCSR; - FPU fpu; - - /* XXX use real code to determine if the processor supports - DenormalsAreZero and FlushToZero - */ - if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) { + if (!fpu->has_flush_to_zero() && !fpu->has_denormals_are_zero()) { return; } @@ -453,7 +635,7 @@ ARDOUR::setup_fpu () #ifdef DEBUG_DENORMAL_EXCEPTION /* This will raise a FP exception if a denormal is detected */ MXCSR &= ~_MM_MASK_DENORM; -#endif +#endif switch (Config->get_denormal_model()) { case DenormalNone: @@ -461,21 +643,21 @@ ARDOUR::setup_fpu () break; case DenormalFTZ: - if (fpu.has_flush_to_zero()) { + if (fpu->has_flush_to_zero()) { MXCSR |= _MM_FLUSH_ZERO_ON; } break; case DenormalDAZ: MXCSR &= ~_MM_FLUSH_ZERO_ON; - if (fpu.has_denormals_are_zero()) { + if (fpu->has_denormals_are_zero()) { MXCSR |= 0x40; } break; case DenormalFTZDAZ: - if (fpu.has_flush_to_zero()) { - if (fpu.has_denormals_are_zero()) { + if (fpu->has_flush_to_zero()) { + if (fpu->has_denormals_are_zero()) { MXCSR |= _MM_FLUSH_ZERO_ON | 0x40; } else { MXCSR |= _MM_FLUSH_ZERO_ON; @@ -503,7 +685,7 @@ ARDOUR::translation_enable_path () bool ARDOUR::translations_are_enabled () { - int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY); + int fd = g_open (ARDOUR::translation_enable_path().c_str(), O_RDONLY, 0444); if (fd < 0) { return translate_by_default; @@ -525,20 +707,20 @@ bool ARDOUR::set_translations_enabled (bool yn) { string i18n_enabler = ARDOUR::translation_enable_path(); - int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644); + int fd = g_open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd < 0) { return false; } - + char c; - + if (yn) { c = '1'; } else { c = '0'; } - + (void) ::write (fd, &c, 1); (void) ::close (fd); @@ -573,7 +755,7 @@ ARDOUR::get_available_sync_options () #include #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 0 -int +int clock_gettime (int /*clk_id*/, struct timespec *t) { static bool initialized = false; @@ -591,7 +773,7 @@ clock_gettime (int /*clk_id*/, struct timespec *t) return 0; } #endif - + microseconds_t ARDOUR::get_microseconds () { @@ -613,3 +795,26 @@ ARDOUR::get_microseconds () return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000); #endif } + +/** Return the number of bits per sample for a given sample format. + * + * This is closely related to sndfile_data_width() but does NOT + * return a "magic" value to differentiate between 32 bit integer + * and 32 bit floating point values. + */ + +int +ARDOUR::format_data_width (ARDOUR::SampleFormat format) +{ + + + + switch (format) { + case ARDOUR::FormatInt16: + return 16; + case ARDOUR::FormatInt24: + return 24; + default: + return 32; + } +}