X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=blobdiff_plain;f=libs%2Fardour%2Fglobals.cc;h=77aff20c1acf273d15d72673b2603d2b818c242d;hp=8bee4ec9023cc0f8c4d4c098283ab8cc8a26ca6c;hb=dd2e80467bed5e48fa5c38c62581c966a9c7fce7;hpb=86343b6c15a3a43f082802484d2bc813d34db821 diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 8bee4ec902..77aff20c1a 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,11 +80,12 @@ #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" +#include "LuaBridge/LuaBridge.h" + #include "ardour/analyser.h" #include "ardour/audio_library.h" #include "ardour/audio_backend.h" @@ -85,12 +94,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 +113,17 @@ #include "ardour/runtime_functions.h" #include "ardour/session_event.h" #include "ardour/source_factory.h" - +#include "ardour/transport_master_manager.h" +#ifdef LV2_SUPPORT +#include "ardour/uri_map.h" +#endif #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,11 +140,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::map ARDOUR::reserved_io_names; + +static bool have_old_configuration_files = false; namespace ARDOUR { extern void setup_enum_writer (); @@ -145,11 +168,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; @@ -159,23 +203,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; @@ -195,6 +237,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; } @@ -211,7 +254,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) { @@ -221,15 +269,166 @@ lotsa_files_please () } } else { if (rl.rlim_cur != RLIM_INFINITY) { - info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg; + info << string_compose (_("Your system is configured to limit %1 to %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg; } } } 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 %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); + + /* plugin status */ + g_mkdir_with_parents (Glib::build_filename (new_dir, plugin_metadata_dir_name).c_str(), 0755); + + old_name = Glib::build_filename (old_dir, X_("plugin_statuses")); /* until 6.0 */ + new_name = Glib::build_filename (new_dir, plugin_metadata_dir_name, X_("plugin_statuses")); + copy_file (old_name, new_name); /* can fail silently */ + + old_name = Glib::build_filename (old_dir, plugin_metadata_dir_name, X_("plugin_statuses")); + copy_file (old_name, new_name); + + /* plugin tags */ + + old_name = Glib::build_filename (old_dir, plugin_metadata_dir_name, X_("plugin_tags")); + new_name = Glib::build_filename (new_dir, plugin_metadata_dir_name, X_("plugin_tags")); + + 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) { @@ -237,14 +436,22 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir return true; } +#ifndef NDEBUG + if (getenv("LUA_METATABLES")) { + luabridge::Security::setHideMetatables (false); + } +#endif + if (!PBD::init()) return false; -#ifdef ENABLE_NLS +#if 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 (); @@ -252,6 +459,8 @@ 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 (); + TransportMaster::make_property_quarks (); /* this is a useful ready to use PropertyChange that many things need to check. This avoids having to compose @@ -316,38 +525,69 @@ 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. + + We also need to know if the given I/O is an actual route. + For routes (e.g. "master"), bus creation needs to be allowed the first time, + while for pure I/O (e.g. "Click") track/bus creation must always fail. + */ + + reserved_io_names[_("Monitor")] = true; + reserved_io_names[_("Master")] = true; + reserved_io_names["auditioner"] = true; // auditioner.cc Track (s, "auditioner",...) + + /* pure I/O */ + reserved_io_names[X_("Click")] = false; // session.cc ClickIO (*this, X_("Click") + reserved_io_names[_("Control")] = false; + reserved_io_names[_("Mackie")] = false; + reserved_io_names[_("FaderPort Recv")] = false; + reserved_io_names[_("FaderPort Send")] = false; + reserved_io_names[_("FaderPort2 Recv")] = false; + reserved_io_names[_("FaderPort2 Send")] = false; + reserved_io_names[_("FaderPort8 Recv")] = false; + reserved_io_names[_("FaderPort8 Send")] = false; + reserved_io_names[_("FaderPort16 Recv")] = false; + reserved_io_names[_("FaderPort16 Send")] = false; + libardour_initialized = true; return true; @@ -356,11 +596,22 @@ 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); + ControlProtocolManager::instance().set_state (*node, 0 /* here: global-config state */); + } + + if ((node = Config->transport_master_state()) != 0) { + if (TransportMasterManager::instance().set_state (*node, Stateful::loading_state_version)) { + error << _("Cannot restore transport master manager") << endmsg; + /* XXX now what? */ + } + } else { + if (TransportMasterManager::instance().set_default_configuration ()) { + error << _("Cannot initialize transport master manager") << endmsg; + /* XXX now what? */ + } } /* find plugins */ @@ -369,19 +620,19 @@ ARDOUR::init_post_engine () } void -ARDOUR::cleanup () + ARDOUR::cleanup () { if (!libardour_initialized) { return; } + delete &ControlProtocolManager::instance(); ARDOUR::AudioEngine::destroy (); delete Library; #ifdef HAVE_LRDF lrdf_cleanup (); #endif - delete &ControlProtocolManager::instance(); #ifdef WINDOWS_VST_SUPPORT fst_exit (); #endif @@ -389,38 +640,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() { @@ -430,6 +656,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 @@ -440,13 +667,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; } @@ -455,7 +677,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: @@ -463,21 +685,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; @@ -505,7 +727,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; @@ -527,23 +749,24 @@ 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); + Config->ParameterChanged ("enable-translation"); return true; } @@ -575,7 +798,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; @@ -593,7 +816,7 @@ clock_gettime (int /*clk_id*/, struct timespec *t) return 0; } #endif - + microseconds_t ARDOUR::get_microseconds () { @@ -615,3 +838,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; + } +}