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/filesystem_paths.h"
89 #include "ardour/midi_region.h"
90 #include "ardour/midiport_manager.h"
91 #include "ardour/mix.h"
92 #include "ardour/panner_manager.h"
93 #include "ardour/plugin_manager.h"
94 #include "ardour/process_thread.h"
95 #include "ardour/profile.h"
96 #include "ardour/rc_configuration.h"
97 #include "ardour/region.h"
98 #include "ardour/route_group.h"
99 #include "ardour/runtime_functions.h"
100 #include "ardour/session_event.h"
101 #include "ardour/source_factory.h"
103 #include "audiographer/routines.h"
105 #if defined (__APPLE__)
106 #include <Carbon/Carbon.h> // For Gestalt
111 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
112 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
113 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
115 using namespace ARDOUR;
119 bool libardour_initialized = false;
121 compute_peak_t ARDOUR::compute_peak = 0;
122 find_peaks_t ARDOUR::find_peaks = 0;
123 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
124 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
125 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
127 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
128 PBD::Signal3<void,std::string,std::string,bool> ARDOUR::PluginScanMessage;
129 PBD::Signal1<void,int> ARDOUR::PluginScanTimeout;
130 PBD::Signal0<void> ARDOUR::GUIIdle;
133 extern void setup_enum_writer ();
136 /* this is useful for quite a few things that want to check
137 if any bounds-related property has changed
139 PBD::PropertyChange ARDOUR::bounds_change;
142 setup_hardware_optimization (bool try_optimization)
144 bool generic_mix_functions = true;
146 if (try_optimization) {
150 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
154 info << "Using SSE optimized routines" << endmsg;
157 compute_peak = x86_sse_compute_peak;
158 find_peaks = x86_sse_find_peaks;
159 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
160 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
161 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
163 generic_mix_functions = false;
167 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
168 SInt32 sysVersion = 0;
170 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
173 if (sysVersion >= 0x00001040) { // Tiger at least
174 compute_peak = veclib_compute_peak;
175 find_peaks = veclib_find_peaks;
176 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
177 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
178 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
180 generic_mix_functions = false;
182 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
186 /* consider FPU denormal handling to be "h/w optimization" */
191 if (generic_mix_functions) {
193 compute_peak = default_compute_peak;
194 find_peaks = default_find_peaks;
195 apply_gain_to_buffer = default_apply_gain_to_buffer;
196 mix_buffers_with_gain = default_mix_buffers_with_gain;
197 mix_buffers_no_gain = default_mix_buffers_no_gain;
199 info << "No H/W specific optimizations in use" << endmsg;
202 AudioGrapher::Routines::override_compute_peak (compute_peak);
203 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
207 lotsa_files_please ()
209 #ifndef PLATFORM_WINDOWS
212 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
214 rl.rlim_cur = rl.rlim_max;
216 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
217 if (rl.rlim_cur == RLIM_INFINITY) {
218 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
220 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
223 if (rl.rlim_cur != RLIM_INFINITY) {
224 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
228 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
234 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
236 if (libardour_initialized) {
240 if (!PBD::init()) return false;
243 (void) bindtextdomain(PACKAGE, localedir);
246 SessionEvent::init_event_pool ();
248 SessionObject::make_property_quarks ();
249 Region::make_property_quarks ();
250 MidiRegion::make_property_quarks ();
251 AudioRegion::make_property_quarks ();
252 RouteGroup::make_property_quarks ();
253 Playlist::make_property_quarks ();
254 AudioPlaylist::make_property_quarks ();
256 /* this is a useful ready to use PropertyChange that many
257 things need to check. This avoids having to compose
258 it every time we want to check for any of the relevant
262 bounds_change.add (ARDOUR::Properties::start);
263 bounds_change.add (ARDOUR::Properties::position);
264 bounds_change.add (ARDOUR::Properties::length);
266 /* provide a state version for the few cases that need it and are not
267 driven by reading state from disk (e.g. undo/redo)
270 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
272 ARDOUR::setup_enum_writer ();
274 // allow ardour the absolute maximum number of open files
275 lotsa_files_please ();
280 Library = new AudioLibrary;
282 BootMessage (_("Loading configuration"));
284 Config = new RCConfiguration;
286 if (Config->load_state ()) {
290 Config->set_use_windows_vst (use_windows_vst);
292 Config->set_use_lxvst(true);
295 Profile = new RuntimeProfile;
298 #ifdef WINDOWS_VST_SUPPORT
299 if (Config->get_use_windows_vst() && fst_init (0)) {
305 if (Config->get_use_lxvst() && vstfx_init (0)) {
310 #ifdef AUDIOUNIT_SUPPORT
311 AUPluginInfo::load_cached_info ();
314 setup_hardware_optimization (try_optimization);
316 SourceFactory::init ();
319 /* singleton - first object is "it" */
320 (void) PluginManager::instance();
322 ProcessThread::init ();
323 /* the + 4 is a bit of a handwave. i don't actually know
324 how many more per-thread buffer sets we need above
325 the h/w concurrency, but its definitely > 1 more.
327 BufferManager::init (hardware_concurrency() + 4);
329 PannerManager::instance().discover_panners();
331 // Initialize parameter metadata
332 EventTypeMap::instance().new_parameter(NullAutomation);
333 EventTypeMap::instance().new_parameter(GainAutomation);
334 EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
335 EventTypeMap::instance().new_parameter(PanElevationAutomation);
336 EventTypeMap::instance().new_parameter(PanWidthAutomation);
337 EventTypeMap::instance().new_parameter(PluginAutomation);
338 EventTypeMap::instance().new_parameter(SoloAutomation);
339 EventTypeMap::instance().new_parameter(MuteAutomation);
340 EventTypeMap::instance().new_parameter(MidiCCAutomation);
341 EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
342 EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
343 EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
344 EventTypeMap::instance().new_parameter(FadeInAutomation);
345 EventTypeMap::instance().new_parameter(FadeOutAutomation);
346 EventTypeMap::instance().new_parameter(EnvelopeAutomation);
347 EventTypeMap::instance().new_parameter(MidiCCAutomation);
349 ARDOUR::AudioEngine::create ();
351 libardour_initialized = true;
357 ARDOUR::init_post_engine ()
359 ControlProtocolManager::instance().discover_control_protocols ();
362 if ((node = Config->control_protocol_state()) != 0) {
363 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
368 ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start());
374 if (!libardour_initialized) {
378 ARDOUR::AudioEngine::destroy ();
384 delete &ControlProtocolManager::instance();
385 #ifdef WINDOWS_VST_SUPPORT
398 ARDOUR::find_bindings_files (map<string,string>& files)
400 vector<std::string> found;
401 Searchpath spath = ardour_config_search_path();
403 if (getenv ("ARDOUR_SAE")) {
404 Glib::PatternSpec pattern("*SAE-*.bindings");
405 find_matching_files_in_search_path (spath, pattern, found);
407 Glib::PatternSpec pattern("*.bindings");
408 find_matching_files_in_search_path (spath, pattern, found);
415 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
416 std::string path(*x);
417 pair<string,string> namepath;
418 namepath.second = path;
419 namepath.first = PBD::basename_nosuffix (path);
420 files.insert (namepath);
425 ARDOUR::no_auto_connect()
427 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
434 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
435 // valgrind doesn't understand this assembler stuff
436 // September 10th, 2007
440 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
445 /* XXX use real code to determine if the processor supports
446 DenormalsAreZero and FlushToZero
449 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
453 MXCSR = _mm_getcsr();
455 #ifdef DEBUG_DENORMAL_EXCEPTION
456 /* This will raise a FP exception if a denormal is detected */
457 MXCSR &= ~_MM_MASK_DENORM;
460 switch (Config->get_denormal_model()) {
462 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
466 if (fpu.has_flush_to_zero()) {
467 MXCSR |= _MM_FLUSH_ZERO_ON;
472 MXCSR &= ~_MM_FLUSH_ZERO_ON;
473 if (fpu.has_denormals_are_zero()) {
479 if (fpu.has_flush_to_zero()) {
480 if (fpu.has_denormals_are_zero()) {
481 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
483 MXCSR |= _MM_FLUSH_ZERO_ON;
494 /* this can be changed to modify the translation behaviour for
495 cases where the user has never expressed a preference.
497 static const bool translate_by_default = true;
500 ARDOUR::translation_enable_path ()
502 return Glib::build_filename (user_config_directory(), ".translate");
506 ARDOUR::translations_are_enabled ()
508 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
511 return translate_by_default;
517 if (::read (fd, &c, 1) == 1 && c == '1') {
527 ARDOUR::set_translations_enabled (bool yn)
529 string i18n_enabler = ARDOUR::translation_enable_path();
530 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
544 (void) ::write (fd, &c, 1);
552 ARDOUR::get_available_sync_options ()
554 vector<SyncSource> ret;
556 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
557 if (backend && backend->name() == "JACK") {
558 ret.push_back (Engine);
562 ret.push_back (MIDIClock);
568 /** Return a monotonic value for the number of microseconds that have elapsed
569 * since an arbitrary zero origin.
573 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
575 #include <mach/mach_time.h>
576 #define CLOCK_REALTIME 0
577 #define CLOCK_MONOTONIC 0
579 clock_gettime (int /*clk_id*/, struct timespec *t)
581 static bool initialized = false;
582 static mach_timebase_info_data_t timebase;
584 mach_timebase_info(&timebase);
588 time = mach_absolute_time();
589 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
590 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
592 t->tv_nsec = nseconds;
598 ARDOUR::get_microseconds ()
600 #ifdef PLATFORM_WINDOWS
601 microseconds_t ret = 0;
602 LARGE_INTEGER freq, time;
604 if (QueryPerformanceFrequency(&freq))
605 if (QueryPerformanceCounter(&time))
606 ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
611 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
615 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);