2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "libardour-config.h"
27 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
30 #include <sys/types.h>
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
40 #ifdef WINDOWS_VST_SUPPORT
45 #include "ardour/linux_vst_support.h"
48 #ifdef AUDIOUNIT_SUPPORT
49 #include "ardour/audio_unit.h"
52 #if defined(__SSE__) || defined(USE_XMMINTRIN)
53 #include <xmmintrin.h>
57 #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
60 #include <glibmm/fileutils.h>
61 #include <glibmm/miscutils.h>
68 #include "pbd/error.h"
71 #include "pbd/strsplit.h"
73 #include "pbd/file_utils.h"
74 #include "pbd/enumwriter.h"
75 #include "pbd/basename.h"
77 #include "midi++/port.h"
78 #include "midi++/mmc.h"
80 #include "ardour/analyser.h"
81 #include "ardour/audio_library.h"
82 #include "ardour/audio_backend.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audioplaylist.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/buffer_manager.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/event_type_map.h"
89 #include "ardour/filesystem_paths.h"
90 #include "ardour/midi_region.h"
91 #include "ardour/midiport_manager.h"
92 #include "ardour/mix.h"
93 #include "ardour/operations.h"
94 #include "ardour/panner_manager.h"
95 #include "ardour/plugin_manager.h"
96 #include "ardour/process_thread.h"
97 #include "ardour/profile.h"
98 #include "ardour/rc_configuration.h"
99 #include "ardour/region.h"
100 #include "ardour/route_group.h"
101 #include "ardour/runtime_functions.h"
102 #include "ardour/session_event.h"
103 #include "ardour/source_factory.h"
104 #include "ardour/uri_map.h"
106 #include "audiographer/routines.h"
108 #if defined (__APPLE__)
109 #include <Carbon/Carbon.h> // For Gestalt
114 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
115 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
116 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
118 using namespace ARDOUR;
122 bool libardour_initialized = false;
124 compute_peak_t ARDOUR::compute_peak = 0;
125 find_peaks_t ARDOUR::find_peaks = 0;
126 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
127 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
128 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
130 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
131 PBD::Signal3<void,std::string,std::string,bool> ARDOUR::PluginScanMessage;
132 PBD::Signal1<void,int> ARDOUR::PluginScanTimeout;
133 PBD::Signal0<void> ARDOUR::GUIIdle;
136 extern void setup_enum_writer ();
139 /* this is useful for quite a few things that want to check
140 if any bounds-related property has changed
142 PBD::PropertyChange ARDOUR::bounds_change;
145 setup_hardware_optimization (bool try_optimization)
147 bool generic_mix_functions = true;
149 if (try_optimization) {
153 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
157 info << "Using SSE optimized routines" << endmsg;
160 compute_peak = x86_sse_compute_peak;
161 find_peaks = x86_sse_find_peaks;
162 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
163 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
164 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
166 generic_mix_functions = false;
170 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
171 SInt32 sysVersion = 0;
173 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
176 if (sysVersion >= 0x00001040) { // Tiger at least
177 compute_peak = veclib_compute_peak;
178 find_peaks = veclib_find_peaks;
179 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
180 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
181 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
183 generic_mix_functions = false;
185 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
189 /* consider FPU denormal handling to be "h/w optimization" */
194 if (generic_mix_functions) {
196 compute_peak = default_compute_peak;
197 find_peaks = default_find_peaks;
198 apply_gain_to_buffer = default_apply_gain_to_buffer;
199 mix_buffers_with_gain = default_mix_buffers_with_gain;
200 mix_buffers_no_gain = default_mix_buffers_no_gain;
202 info << "No H/W specific optimizations in use" << endmsg;
205 AudioGrapher::Routines::override_compute_peak (compute_peak);
206 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
210 lotsa_files_please ()
212 #ifndef PLATFORM_WINDOWS
215 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
218 /* See the COMPATIBILITY note on the Apple setrlimit() man page */
219 rl.rlim_cur = min ((rlim_t) OPEN_MAX, rl.rlim_max);
221 rl.rlim_cur = rl.rlim_max;
224 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
225 if (rl.rlim_cur == RLIM_INFINITY) {
226 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
228 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
231 if (rl.rlim_cur != RLIM_INFINITY) {
232 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
236 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
242 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
244 if (libardour_initialized) {
248 if (!PBD::init()) return false;
251 (void) bindtextdomain(PACKAGE, localedir);
252 (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
255 SessionEvent::init_event_pool ();
257 Operations::make_operations_quarks ();
258 SessionObject::make_property_quarks ();
259 Region::make_property_quarks ();
260 MidiRegion::make_property_quarks ();
261 AudioRegion::make_property_quarks ();
262 RouteGroup::make_property_quarks ();
263 Playlist::make_property_quarks ();
264 AudioPlaylist::make_property_quarks ();
266 /* this is a useful ready to use PropertyChange that many
267 things need to check. This avoids having to compose
268 it every time we want to check for any of the relevant
272 bounds_change.add (ARDOUR::Properties::start);
273 bounds_change.add (ARDOUR::Properties::position);
274 bounds_change.add (ARDOUR::Properties::length);
276 /* provide a state version for the few cases that need it and are not
277 driven by reading state from disk (e.g. undo/redo)
280 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
282 ARDOUR::setup_enum_writer ();
284 // allow ardour the absolute maximum number of open files
285 lotsa_files_please ();
290 Library = new AudioLibrary;
292 BootMessage (_("Loading configuration"));
294 Config = new RCConfiguration;
296 if (Config->load_state ()) {
300 Config->set_use_windows_vst (use_windows_vst);
302 Config->set_use_lxvst(true);
305 Profile = new RuntimeProfile;
308 #ifdef WINDOWS_VST_SUPPORT
309 if (Config->get_use_windows_vst() && fst_init (0)) {
315 if (Config->get_use_lxvst() && vstfx_init (0)) {
320 #ifdef AUDIOUNIT_SUPPORT
321 AUPluginInfo::load_cached_info ();
324 setup_hardware_optimization (try_optimization);
326 SourceFactory::init ();
329 /* singletons - first object is "it" */
330 (void) PluginManager::instance();
331 (void) URIMap::instance();
332 (void) EventTypeMap::instance();
334 ProcessThread::init ();
335 /* the + 4 is a bit of a handwave. i don't actually know
336 how many more per-thread buffer sets we need above
337 the h/w concurrency, but its definitely > 1 more.
339 BufferManager::init (hardware_concurrency() + 4);
341 PannerManager::instance().discover_panners();
343 ARDOUR::AudioEngine::create ();
345 libardour_initialized = true;
351 ARDOUR::init_post_engine ()
353 ControlProtocolManager::instance().discover_control_protocols ();
356 if ((node = Config->control_protocol_state()) != 0) {
357 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
362 ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start());
368 if (!libardour_initialized) {
372 ARDOUR::AudioEngine::destroy ();
378 delete &ControlProtocolManager::instance();
379 #ifdef WINDOWS_VST_SUPPORT
386 delete &PluginManager::instance();
394 ARDOUR::find_bindings_files (map<string,string>& files)
396 vector<std::string> found;
397 Searchpath spath = ardour_config_search_path();
399 if (getenv ("ARDOUR_SAE")) {
400 find_files_matching_pattern (found, spath, "*SAE-*.bindings");
402 find_files_matching_pattern (found, spath, "*.bindings");
409 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
410 std::string path(*x);
411 pair<string,string> namepath;
412 namepath.second = path;
413 namepath.first = PBD::basename_nosuffix (path);
414 files.insert (namepath);
419 ARDOUR::no_auto_connect()
421 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
428 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
429 // valgrind doesn't understand this assembler stuff
430 // September 10th, 2007
434 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
439 /* XXX use real code to determine if the processor supports
440 DenormalsAreZero and FlushToZero
443 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
447 MXCSR = _mm_getcsr();
449 #ifdef DEBUG_DENORMAL_EXCEPTION
450 /* This will raise a FP exception if a denormal is detected */
451 MXCSR &= ~_MM_MASK_DENORM;
454 switch (Config->get_denormal_model()) {
456 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
460 if (fpu.has_flush_to_zero()) {
461 MXCSR |= _MM_FLUSH_ZERO_ON;
466 MXCSR &= ~_MM_FLUSH_ZERO_ON;
467 if (fpu.has_denormals_are_zero()) {
473 if (fpu.has_flush_to_zero()) {
474 if (fpu.has_denormals_are_zero()) {
475 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
477 MXCSR |= _MM_FLUSH_ZERO_ON;
488 /* this can be changed to modify the translation behaviour for
489 cases where the user has never expressed a preference.
491 static const bool translate_by_default = true;
494 ARDOUR::translation_enable_path ()
496 return Glib::build_filename (user_config_directory(), ".translate");
500 ARDOUR::translations_are_enabled ()
502 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
505 return translate_by_default;
511 if (::read (fd, &c, 1) == 1 && c == '1') {
521 ARDOUR::set_translations_enabled (bool yn)
523 string i18n_enabler = ARDOUR::translation_enable_path();
524 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
538 (void) ::write (fd, &c, 1);
546 ARDOUR::get_available_sync_options ()
548 vector<SyncSource> ret;
550 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
551 if (backend && backend->name() == "JACK") {
552 ret.push_back (Engine);
556 ret.push_back (MIDIClock);
562 /** Return a monotonic value for the number of microseconds that have elapsed
563 * since an arbitrary zero origin.
567 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
569 #include <mach/mach_time.h>
570 #define CLOCK_REALTIME 0
571 #define CLOCK_MONOTONIC 0
573 clock_gettime (int /*clk_id*/, struct timespec *t)
575 static bool initialized = false;
576 static mach_timebase_info_data_t timebase;
578 mach_timebase_info(&timebase);
582 time = mach_absolute_time();
583 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
584 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
586 t->tv_nsec = nseconds;
592 ARDOUR::get_microseconds ()
594 #ifdef PLATFORM_WINDOWS
595 microseconds_t ret = 0;
596 LARGE_INTEGER freq, time;
598 if (QueryPerformanceFrequency(&freq))
599 if (QueryPerformanceCounter(&time))
600 ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
605 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
609 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);