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 ();
376 delete &ControlProtocolManager::instance();
377 #ifdef WINDOWS_VST_SUPPORT
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 Glib::PatternSpec pattern("*SAE-*.bindings");
396 find_matching_files_in_search_path (spath, pattern, found);
398 Glib::PatternSpec pattern("*.bindings");
399 find_matching_files_in_search_path (spath, pattern, found);
406 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
407 std::string path(*x);
408 pair<string,string> namepath;
409 namepath.second = path;
410 namepath.first = PBD::basename_nosuffix (path);
411 files.insert (namepath);
416 ARDOUR::no_auto_connect()
418 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
425 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
426 // valgrind doesn't understand this assembler stuff
427 // September 10th, 2007
431 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
436 /* XXX use real code to determine if the processor supports
437 DenormalsAreZero and FlushToZero
440 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
444 MXCSR = _mm_getcsr();
446 #ifdef DEBUG_DENORMAL_EXCEPTION
447 /* This will raise a FP exception if a denormal is detected */
448 MXCSR &= ~_MM_MASK_DENORM;
451 switch (Config->get_denormal_model()) {
453 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
457 if (fpu.has_flush_to_zero()) {
458 MXCSR |= _MM_FLUSH_ZERO_ON;
463 MXCSR &= ~_MM_FLUSH_ZERO_ON;
464 if (fpu.has_denormals_are_zero()) {
470 if (fpu.has_flush_to_zero()) {
471 if (fpu.has_denormals_are_zero()) {
472 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
474 MXCSR |= _MM_FLUSH_ZERO_ON;
485 /* this can be changed to modify the translation behaviour for
486 cases where the user has never expressed a preference.
488 static const bool translate_by_default = true;
491 ARDOUR::translation_enable_path ()
493 return Glib::build_filename (user_config_directory(), ".translate");
497 ARDOUR::translations_are_enabled ()
499 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
502 return translate_by_default;
508 if (::read (fd, &c, 1) == 1 && c == '1') {
518 ARDOUR::set_translations_enabled (bool yn)
520 string i18n_enabler = ARDOUR::translation_enable_path();
521 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
543 ARDOUR::get_available_sync_options ()
545 vector<SyncSource> ret;
547 ret.push_back (JACK);
549 ret.push_back (MIDIClock);
555 /** Return a monotonic value for the number of microseconds that have elapsed
556 * since an arbitrary zero origin.
560 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
562 #include <mach/mach_time.h>
563 #define CLOCK_REALTIME 0
564 #define CLOCK_MONOTONIC 0
566 clock_gettime (int /*clk_id*/, struct timespec *t)
568 static bool initialized = false;
569 static mach_timebase_info_data_t timebase;
571 mach_timebase_info(&timebase);
575 time = mach_absolute_time();
576 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
577 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
579 t->tv_nsec = nseconds;
585 ARDOUR::get_microseconds ()
588 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
592 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);