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) {
217 rl.rlim_cur = rl.rlim_max;
219 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
220 if (rl.rlim_cur == RLIM_INFINITY) {
221 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
223 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
226 if (rl.rlim_cur != RLIM_INFINITY) {
227 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
231 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
237 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
239 if (libardour_initialized) {
243 if (!PBD::init()) return false;
246 (void) bindtextdomain(PACKAGE, localedir);
247 (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
250 SessionEvent::init_event_pool ();
252 Operations::make_operations_quarks ();
253 SessionObject::make_property_quarks ();
254 Region::make_property_quarks ();
255 MidiRegion::make_property_quarks ();
256 AudioRegion::make_property_quarks ();
257 RouteGroup::make_property_quarks ();
258 Playlist::make_property_quarks ();
259 AudioPlaylist::make_property_quarks ();
261 /* this is a useful ready to use PropertyChange that many
262 things need to check. This avoids having to compose
263 it every time we want to check for any of the relevant
267 bounds_change.add (ARDOUR::Properties::start);
268 bounds_change.add (ARDOUR::Properties::position);
269 bounds_change.add (ARDOUR::Properties::length);
271 /* provide a state version for the few cases that need it and are not
272 driven by reading state from disk (e.g. undo/redo)
275 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
277 ARDOUR::setup_enum_writer ();
279 // allow ardour the absolute maximum number of open files
280 lotsa_files_please ();
285 Library = new AudioLibrary;
287 BootMessage (_("Loading configuration"));
289 Config = new RCConfiguration;
291 if (Config->load_state ()) {
295 Config->set_use_windows_vst (use_windows_vst);
297 Config->set_use_lxvst(true);
300 Profile = new RuntimeProfile;
303 #ifdef WINDOWS_VST_SUPPORT
304 if (Config->get_use_windows_vst() && fst_init (0)) {
310 if (Config->get_use_lxvst() && vstfx_init (0)) {
315 #ifdef AUDIOUNIT_SUPPORT
316 AUPluginInfo::load_cached_info ();
319 setup_hardware_optimization (try_optimization);
321 SourceFactory::init ();
324 /* singletons - first object is "it" */
325 (void) PluginManager::instance();
326 (void) URIMap::instance();
327 (void) EventTypeMap::instance();
329 ProcessThread::init ();
330 /* the + 4 is a bit of a handwave. i don't actually know
331 how many more per-thread buffer sets we need above
332 the h/w concurrency, but its definitely > 1 more.
334 BufferManager::init (hardware_concurrency() + 4);
336 PannerManager::instance().discover_panners();
338 ARDOUR::AudioEngine::create ();
340 libardour_initialized = true;
346 ARDOUR::init_post_engine ()
348 ControlProtocolManager::instance().discover_control_protocols ();
351 if ((node = Config->control_protocol_state()) != 0) {
352 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
357 ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start());
363 if (!libardour_initialized) {
367 ARDOUR::AudioEngine::destroy ();
373 delete &ControlProtocolManager::instance();
374 #ifdef WINDOWS_VST_SUPPORT
381 delete &PluginManager::instance();
389 ARDOUR::find_bindings_files (map<string,string>& files)
391 vector<std::string> found;
392 Searchpath spath = ardour_config_search_path();
394 if (getenv ("ARDOUR_SAE")) {
395 find_files_matching_pattern (found, spath, "*SAE-*.bindings");
397 find_files_matching_pattern (found, spath, "*.bindings");
404 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
405 std::string path(*x);
406 pair<string,string> namepath;
407 namepath.second = path;
408 namepath.first = PBD::basename_nosuffix (path);
409 files.insert (namepath);
414 ARDOUR::no_auto_connect()
416 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
423 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
424 // valgrind doesn't understand this assembler stuff
425 // September 10th, 2007
429 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
434 /* XXX use real code to determine if the processor supports
435 DenormalsAreZero and FlushToZero
438 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
442 MXCSR = _mm_getcsr();
444 #ifdef DEBUG_DENORMAL_EXCEPTION
445 /* This will raise a FP exception if a denormal is detected */
446 MXCSR &= ~_MM_MASK_DENORM;
449 switch (Config->get_denormal_model()) {
451 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
455 if (fpu.has_flush_to_zero()) {
456 MXCSR |= _MM_FLUSH_ZERO_ON;
461 MXCSR &= ~_MM_FLUSH_ZERO_ON;
462 if (fpu.has_denormals_are_zero()) {
468 if (fpu.has_flush_to_zero()) {
469 if (fpu.has_denormals_are_zero()) {
470 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
472 MXCSR |= _MM_FLUSH_ZERO_ON;
483 /* this can be changed to modify the translation behaviour for
484 cases where the user has never expressed a preference.
486 static const bool translate_by_default = true;
489 ARDOUR::translation_enable_path ()
491 return Glib::build_filename (user_config_directory(), ".translate");
495 ARDOUR::translations_are_enabled ()
497 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
500 return translate_by_default;
506 if (::read (fd, &c, 1) == 1 && c == '1') {
516 ARDOUR::set_translations_enabled (bool yn)
518 string i18n_enabler = ARDOUR::translation_enable_path();
519 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
533 (void) ::write (fd, &c, 1);
541 ARDOUR::get_available_sync_options ()
543 vector<SyncSource> ret;
545 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
546 if (backend && backend->name() == "JACK") {
547 ret.push_back (Engine);
551 ret.push_back (MIDIClock);
557 /** Return a monotonic value for the number of microseconds that have elapsed
558 * since an arbitrary zero origin.
562 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
564 #include <mach/mach_time.h>
565 #define CLOCK_REALTIME 0
566 #define CLOCK_MONOTONIC 0
568 clock_gettime (int /*clk_id*/, struct timespec *t)
570 static bool initialized = false;
571 static mach_timebase_info_data_t timebase;
573 mach_timebase_info(&timebase);
577 time = mach_absolute_time();
578 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
579 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
581 t->tv_nsec = nseconds;
587 ARDOUR::get_microseconds ()
589 #ifdef PLATFORM_WINDOWS
590 microseconds_t ret = 0;
591 LARGE_INTEGER freq, time;
593 if (QueryPerformanceFrequency(&freq))
594 if (QueryPerformanceCounter(&time))
595 ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
600 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
604 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);