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::Signal0<void> ARDOUR::GUIIdle;
131 extern void setup_enum_writer ();
134 /* this is useful for quite a few things that want to check
135 if any bounds-related property has changed
137 PBD::PropertyChange ARDOUR::bounds_change;
140 setup_hardware_optimization (bool try_optimization)
142 bool generic_mix_functions = true;
144 if (try_optimization) {
148 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
152 info << "Using SSE optimized routines" << endmsg;
155 compute_peak = x86_sse_compute_peak;
156 find_peaks = x86_sse_find_peaks;
157 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
158 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
159 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
161 generic_mix_functions = false;
165 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
166 SInt32 sysVersion = 0;
168 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
171 if (sysVersion >= 0x00001040) { // Tiger at least
172 compute_peak = veclib_compute_peak;
173 find_peaks = veclib_find_peaks;
174 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
175 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
176 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
178 generic_mix_functions = false;
180 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
184 /* consider FPU denormal handling to be "h/w optimization" */
189 if (generic_mix_functions) {
191 compute_peak = default_compute_peak;
192 find_peaks = default_find_peaks;
193 apply_gain_to_buffer = default_apply_gain_to_buffer;
194 mix_buffers_with_gain = default_mix_buffers_with_gain;
195 mix_buffers_no_gain = default_mix_buffers_no_gain;
197 info << "No H/W specific optimizations in use" << endmsg;
200 AudioGrapher::Routines::override_compute_peak (compute_peak);
201 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
205 lotsa_files_please ()
207 #ifndef PLATFORM_WINDOWS
210 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
212 rl.rlim_cur = rl.rlim_max;
214 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
215 if (rl.rlim_cur == RLIM_INFINITY) {
216 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
218 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
221 if (rl.rlim_cur != RLIM_INFINITY) {
222 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
226 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
232 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
234 if (libardour_initialized) {
238 if (!PBD::init()) return false;
241 (void) bindtextdomain(PACKAGE, localedir);
244 SessionEvent::init_event_pool ();
246 SessionObject::make_property_quarks ();
247 Region::make_property_quarks ();
248 MidiRegion::make_property_quarks ();
249 AudioRegion::make_property_quarks ();
250 RouteGroup::make_property_quarks ();
251 Playlist::make_property_quarks ();
252 AudioPlaylist::make_property_quarks ();
254 /* this is a useful ready to use PropertyChange that many
255 things need to check. This avoids having to compose
256 it every time we want to check for any of the relevant
260 bounds_change.add (ARDOUR::Properties::start);
261 bounds_change.add (ARDOUR::Properties::position);
262 bounds_change.add (ARDOUR::Properties::length);
264 /* provide a state version for the few cases that need it and are not
265 driven by reading state from disk (e.g. undo/redo)
268 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
270 ARDOUR::setup_enum_writer ();
272 // allow ardour the absolute maximum number of open files
273 lotsa_files_please ();
278 Library = new AudioLibrary;
280 BootMessage (_("Loading configuration"));
282 Config = new RCConfiguration;
284 if (Config->load_state ()) {
288 Config->set_use_windows_vst (use_windows_vst);
290 Config->set_use_lxvst(true);
293 Profile = new RuntimeProfile;
296 #ifdef WINDOWS_VST_SUPPORT
297 if (Config->get_use_windows_vst() && fst_init (0)) {
303 if (Config->get_use_lxvst() && vstfx_init (0)) {
308 #ifdef AUDIOUNIT_SUPPORT
309 AUPluginInfo::load_cached_info ();
312 setup_hardware_optimization (try_optimization);
314 SourceFactory::init ();
317 /* singleton - first object is "it" */
318 (void) PluginManager::instance();
320 ProcessThread::init ();
321 /* the + 4 is a bit of a handwave. i don't actually know
322 how many more per-thread buffer sets we need above
323 the h/w concurrency, but its definitely > 1 more.
325 BufferManager::init (hardware_concurrency() + 4);
327 PannerManager::instance().discover_panners();
329 // Initialize parameter metadata
330 EventTypeMap::instance().new_parameter(NullAutomation);
331 EventTypeMap::instance().new_parameter(GainAutomation);
332 EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
333 EventTypeMap::instance().new_parameter(PanElevationAutomation);
334 EventTypeMap::instance().new_parameter(PanWidthAutomation);
335 EventTypeMap::instance().new_parameter(PluginAutomation);
336 EventTypeMap::instance().new_parameter(SoloAutomation);
337 EventTypeMap::instance().new_parameter(MuteAutomation);
338 EventTypeMap::instance().new_parameter(MidiCCAutomation);
339 EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
340 EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
341 EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
342 EventTypeMap::instance().new_parameter(FadeInAutomation);
343 EventTypeMap::instance().new_parameter(FadeOutAutomation);
344 EventTypeMap::instance().new_parameter(EnvelopeAutomation);
345 EventTypeMap::instance().new_parameter(MidiCCAutomation);
347 ARDOUR::AudioEngine::create ();
349 libardour_initialized = true;
355 ARDOUR::init_post_engine ()
357 ControlProtocolManager::instance().discover_control_protocols ();
360 if ((node = Config->control_protocol_state()) != 0) {
361 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
366 ARDOUR::PluginManager::instance().refresh ();
372 if (!libardour_initialized) {
376 ARDOUR::AudioEngine::destroy ();
382 delete &ControlProtocolManager::instance();
383 #ifdef WINDOWS_VST_SUPPORT
396 ARDOUR::find_bindings_files (map<string,string>& files)
398 vector<std::string> found;
399 Searchpath spath = ardour_config_search_path();
401 if (getenv ("ARDOUR_SAE")) {
402 Glib::PatternSpec pattern("*SAE-*.bindings");
403 find_matching_files_in_search_path (spath, pattern, found);
405 Glib::PatternSpec pattern("*.bindings");
406 find_matching_files_in_search_path (spath, pattern, found);
413 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
414 std::string path(*x);
415 pair<string,string> namepath;
416 namepath.second = path;
417 namepath.first = PBD::basename_nosuffix (path);
418 files.insert (namepath);
423 ARDOUR::no_auto_connect()
425 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
432 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
433 // valgrind doesn't understand this assembler stuff
434 // September 10th, 2007
438 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
443 /* XXX use real code to determine if the processor supports
444 DenormalsAreZero and FlushToZero
447 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
451 MXCSR = _mm_getcsr();
453 #ifdef DEBUG_DENORMAL_EXCEPTION
454 /* This will raise a FP exception if a denormal is detected */
455 MXCSR &= ~_MM_MASK_DENORM;
458 switch (Config->get_denormal_model()) {
460 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
464 if (fpu.has_flush_to_zero()) {
465 MXCSR |= _MM_FLUSH_ZERO_ON;
470 MXCSR &= ~_MM_FLUSH_ZERO_ON;
471 if (fpu.has_denormals_are_zero()) {
477 if (fpu.has_flush_to_zero()) {
478 if (fpu.has_denormals_are_zero()) {
479 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
481 MXCSR |= _MM_FLUSH_ZERO_ON;
492 /* this can be changed to modify the translation behaviour for
493 cases where the user has never expressed a preference.
495 static const bool translate_by_default = true;
498 ARDOUR::translation_enable_path ()
500 return Glib::build_filename (user_config_directory(), ".translate");
504 ARDOUR::translations_are_enabled ()
506 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
509 return translate_by_default;
515 if (::read (fd, &c, 1) == 1 && c == '1') {
525 ARDOUR::set_translations_enabled (bool yn)
527 string i18n_enabler = ARDOUR::translation_enable_path();
528 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
542 (void) ::write (fd, &c, 1);
550 ARDOUR::get_available_sync_options ()
552 vector<SyncSource> ret;
554 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
555 if (backend && backend->name() == "JACK") {
556 ret.push_back (Engine);
560 ret.push_back (MIDIClock);
566 /** Return a monotonic value for the number of microseconds that have elapsed
567 * since an arbitrary zero origin.
571 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
573 #include <mach/mach_time.h>
574 #define CLOCK_REALTIME 0
575 #define CLOCK_MONOTONIC 0
577 clock_gettime (int /*clk_id*/, struct timespec *t)
579 static bool initialized = false;
580 static mach_timebase_info_data_t timebase;
582 mach_timebase_info(&timebase);
586 time = mach_absolute_time();
587 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
588 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
590 t->tv_nsec = nseconds;
596 ARDOUR::get_microseconds ()
598 #ifdef PLATFORM_WINDOWS
599 microseconds_t ret = 0;
600 LARGE_INTEGER freq, time;
602 if (QueryPerformanceFrequency(&freq))
603 if (QueryPerformanceCounter(&time))
604 ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
609 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
613 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);