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);
244 (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
247 SessionEvent::init_event_pool ();
249 SessionObject::make_property_quarks ();
250 Region::make_property_quarks ();
251 MidiRegion::make_property_quarks ();
252 AudioRegion::make_property_quarks ();
253 RouteGroup::make_property_quarks ();
254 Playlist::make_property_quarks ();
255 AudioPlaylist::make_property_quarks ();
257 /* this is a useful ready to use PropertyChange that many
258 things need to check. This avoids having to compose
259 it every time we want to check for any of the relevant
263 bounds_change.add (ARDOUR::Properties::start);
264 bounds_change.add (ARDOUR::Properties::position);
265 bounds_change.add (ARDOUR::Properties::length);
267 /* provide a state version for the few cases that need it and are not
268 driven by reading state from disk (e.g. undo/redo)
271 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
273 ARDOUR::setup_enum_writer ();
275 // allow ardour the absolute maximum number of open files
276 lotsa_files_please ();
281 Library = new AudioLibrary;
283 BootMessage (_("Loading configuration"));
285 Config = new RCConfiguration;
287 if (Config->load_state ()) {
291 Config->set_use_windows_vst (use_windows_vst);
293 Config->set_use_lxvst(true);
296 Profile = new RuntimeProfile;
299 #ifdef WINDOWS_VST_SUPPORT
300 if (Config->get_use_windows_vst() && fst_init (0)) {
306 if (Config->get_use_lxvst() && vstfx_init (0)) {
311 #ifdef AUDIOUNIT_SUPPORT
312 AUPluginInfo::load_cached_info ();
315 setup_hardware_optimization (try_optimization);
317 SourceFactory::init ();
320 /* singleton - first object is "it" */
321 (void) PluginManager::instance();
323 ProcessThread::init ();
324 /* the + 4 is a bit of a handwave. i don't actually know
325 how many more per-thread buffer sets we need above
326 the h/w concurrency, but its definitely > 1 more.
328 BufferManager::init (hardware_concurrency() + 4);
330 PannerManager::instance().discover_panners();
332 // Initialize parameter metadata
333 EventTypeMap::instance().new_parameter(NullAutomation);
334 EventTypeMap::instance().new_parameter(GainAutomation);
335 EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
336 EventTypeMap::instance().new_parameter(PanElevationAutomation);
337 EventTypeMap::instance().new_parameter(PanWidthAutomation);
338 EventTypeMap::instance().new_parameter(PluginAutomation);
339 EventTypeMap::instance().new_parameter(SoloAutomation);
340 EventTypeMap::instance().new_parameter(MuteAutomation);
341 EventTypeMap::instance().new_parameter(MidiCCAutomation);
342 EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
343 EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
344 EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
345 EventTypeMap::instance().new_parameter(FadeInAutomation);
346 EventTypeMap::instance().new_parameter(FadeOutAutomation);
347 EventTypeMap::instance().new_parameter(EnvelopeAutomation);
348 EventTypeMap::instance().new_parameter(MidiCCAutomation);
350 ARDOUR::AudioEngine::create ();
352 libardour_initialized = true;
358 ARDOUR::init_post_engine ()
360 ControlProtocolManager::instance().discover_control_protocols ();
363 if ((node = Config->control_protocol_state()) != 0) {
364 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
369 ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start());
375 if (!libardour_initialized) {
379 ARDOUR::AudioEngine::destroy ();
385 delete &ControlProtocolManager::instance();
386 #ifdef WINDOWS_VST_SUPPORT
399 ARDOUR::find_bindings_files (map<string,string>& files)
401 vector<std::string> found;
402 Searchpath spath = ardour_config_search_path();
404 if (getenv ("ARDOUR_SAE")) {
405 Glib::PatternSpec pattern("*SAE-*.bindings");
406 find_matching_files_in_search_path (spath, pattern, found);
408 Glib::PatternSpec pattern("*.bindings");
409 find_matching_files_in_search_path (spath, pattern, found);
416 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
417 std::string path(*x);
418 pair<string,string> namepath;
419 namepath.second = path;
420 namepath.first = PBD::basename_nosuffix (path);
421 files.insert (namepath);
426 ARDOUR::no_auto_connect()
428 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
435 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
436 // valgrind doesn't understand this assembler stuff
437 // September 10th, 2007
441 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
446 /* XXX use real code to determine if the processor supports
447 DenormalsAreZero and FlushToZero
450 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
454 MXCSR = _mm_getcsr();
456 #ifdef DEBUG_DENORMAL_EXCEPTION
457 /* This will raise a FP exception if a denormal is detected */
458 MXCSR &= ~_MM_MASK_DENORM;
461 switch (Config->get_denormal_model()) {
463 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
467 if (fpu.has_flush_to_zero()) {
468 MXCSR |= _MM_FLUSH_ZERO_ON;
473 MXCSR &= ~_MM_FLUSH_ZERO_ON;
474 if (fpu.has_denormals_are_zero()) {
480 if (fpu.has_flush_to_zero()) {
481 if (fpu.has_denormals_are_zero()) {
482 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
484 MXCSR |= _MM_FLUSH_ZERO_ON;
495 /* this can be changed to modify the translation behaviour for
496 cases where the user has never expressed a preference.
498 static const bool translate_by_default = true;
501 ARDOUR::translation_enable_path ()
503 return Glib::build_filename (user_config_directory(), ".translate");
507 ARDOUR::translations_are_enabled ()
509 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
512 return translate_by_default;
518 if (::read (fd, &c, 1) == 1 && c == '1') {
528 ARDOUR::set_translations_enabled (bool yn)
530 string i18n_enabler = ARDOUR::translation_enable_path();
531 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
545 (void) ::write (fd, &c, 1);
553 ARDOUR::get_available_sync_options ()
555 vector<SyncSource> ret;
557 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
558 if (backend && backend->name() == "JACK") {
559 ret.push_back (Engine);
563 ret.push_back (MIDIClock);
569 /** Return a monotonic value for the number of microseconds that have elapsed
570 * since an arbitrary zero origin.
574 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
576 #include <mach/mach_time.h>
577 #define CLOCK_REALTIME 0
578 #define CLOCK_MONOTONIC 0
580 clock_gettime (int /*clk_id*/, struct timespec *t)
582 static bool initialized = false;
583 static mach_timebase_info_data_t timebase;
585 mach_timebase_info(&timebase);
589 time = mach_absolute_time();
590 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
591 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
593 t->tv_nsec = nseconds;
599 ARDOUR::get_microseconds ()
601 #ifdef PLATFORM_WINDOWS
602 microseconds_t ret = 0;
603 LARGE_INTEGER freq, time;
605 if (QueryPerformanceFrequency(&freq))
606 if (QueryPerformanceCounter(&time))
607 ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
612 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
616 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);