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::Signal2<void,std::string,std::string> ARDOUR::PluginScanMessage;
129 PBD::Signal0<void> ARDOUR::GUIIdle;
132 extern void setup_enum_writer ();
135 /* this is useful for quite a few things that want to check
136 if any bounds-related property has changed
138 PBD::PropertyChange ARDOUR::bounds_change;
141 setup_hardware_optimization (bool try_optimization)
143 bool generic_mix_functions = true;
145 if (try_optimization) {
149 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
153 info << "Using SSE optimized routines" << endmsg;
156 compute_peak = x86_sse_compute_peak;
157 find_peaks = x86_sse_find_peaks;
158 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
159 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
160 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
162 generic_mix_functions = false;
166 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
167 SInt32 sysVersion = 0;
169 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
172 if (sysVersion >= 0x00001040) { // Tiger at least
173 compute_peak = veclib_compute_peak;
174 find_peaks = veclib_find_peaks;
175 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
176 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
177 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
179 generic_mix_functions = false;
181 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
185 /* consider FPU denormal handling to be "h/w optimization" */
190 if (generic_mix_functions) {
192 compute_peak = default_compute_peak;
193 find_peaks = default_find_peaks;
194 apply_gain_to_buffer = default_apply_gain_to_buffer;
195 mix_buffers_with_gain = default_mix_buffers_with_gain;
196 mix_buffers_no_gain = default_mix_buffers_no_gain;
198 info << "No H/W specific optimizations in use" << endmsg;
201 AudioGrapher::Routines::override_compute_peak (compute_peak);
202 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
206 lotsa_files_please ()
208 #ifndef PLATFORM_WINDOWS
211 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
213 rl.rlim_cur = rl.rlim_max;
215 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
216 if (rl.rlim_cur == RLIM_INFINITY) {
217 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
219 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
222 if (rl.rlim_cur != RLIM_INFINITY) {
223 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
227 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
233 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
235 if (libardour_initialized) {
239 if (!PBD::init()) return false;
242 (void) bindtextdomain(PACKAGE, localedir);
245 SessionEvent::init_event_pool ();
247 SessionObject::make_property_quarks ();
248 Region::make_property_quarks ();
249 MidiRegion::make_property_quarks ();
250 AudioRegion::make_property_quarks ();
251 RouteGroup::make_property_quarks ();
252 Playlist::make_property_quarks ();
253 AudioPlaylist::make_property_quarks ();
255 /* this is a useful ready to use PropertyChange that many
256 things need to check. This avoids having to compose
257 it every time we want to check for any of the relevant
261 bounds_change.add (ARDOUR::Properties::start);
262 bounds_change.add (ARDOUR::Properties::position);
263 bounds_change.add (ARDOUR::Properties::length);
265 /* provide a state version for the few cases that need it and are not
266 driven by reading state from disk (e.g. undo/redo)
269 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
271 ARDOUR::setup_enum_writer ();
273 // allow ardour the absolute maximum number of open files
274 lotsa_files_please ();
279 Library = new AudioLibrary;
281 BootMessage (_("Loading configuration"));
283 Config = new RCConfiguration;
285 if (Config->load_state ()) {
289 Config->set_use_windows_vst (use_windows_vst);
291 Config->set_use_lxvst(true);
294 Profile = new RuntimeProfile;
297 #ifdef WINDOWS_VST_SUPPORT
298 if (Config->get_use_windows_vst() && fst_init (0)) {
304 if (Config->get_use_lxvst() && vstfx_init (0)) {
309 #ifdef AUDIOUNIT_SUPPORT
310 AUPluginInfo::load_cached_info ();
313 setup_hardware_optimization (try_optimization);
315 SourceFactory::init ();
318 /* singleton - first object is "it" */
319 (void) PluginManager::instance();
321 ProcessThread::init ();
322 /* the + 4 is a bit of a handwave. i don't actually know
323 how many more per-thread buffer sets we need above
324 the h/w concurrency, but its definitely > 1 more.
326 BufferManager::init (hardware_concurrency() + 4);
328 PannerManager::instance().discover_panners();
330 // Initialize parameter metadata
331 EventTypeMap::instance().new_parameter(NullAutomation);
332 EventTypeMap::instance().new_parameter(GainAutomation);
333 EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
334 EventTypeMap::instance().new_parameter(PanElevationAutomation);
335 EventTypeMap::instance().new_parameter(PanWidthAutomation);
336 EventTypeMap::instance().new_parameter(PluginAutomation);
337 EventTypeMap::instance().new_parameter(SoloAutomation);
338 EventTypeMap::instance().new_parameter(MuteAutomation);
339 EventTypeMap::instance().new_parameter(MidiCCAutomation);
340 EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
341 EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
342 EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
343 EventTypeMap::instance().new_parameter(FadeInAutomation);
344 EventTypeMap::instance().new_parameter(FadeOutAutomation);
345 EventTypeMap::instance().new_parameter(EnvelopeAutomation);
346 EventTypeMap::instance().new_parameter(MidiCCAutomation);
348 ARDOUR::AudioEngine::create ();
350 libardour_initialized = true;
356 ARDOUR::init_post_engine ()
358 ControlProtocolManager::instance().discover_control_protocols ();
361 if ((node = Config->control_protocol_state()) != 0) {
362 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
367 ARDOUR::PluginManager::instance().refresh ();
373 if (!libardour_initialized) {
377 ARDOUR::AudioEngine::destroy ();
383 delete &ControlProtocolManager::instance();
384 #ifdef WINDOWS_VST_SUPPORT
397 ARDOUR::find_bindings_files (map<string,string>& files)
399 vector<std::string> found;
400 Searchpath spath = ardour_config_search_path();
402 if (getenv ("ARDOUR_SAE")) {
403 Glib::PatternSpec pattern("*SAE-*.bindings");
404 find_matching_files_in_search_path (spath, pattern, found);
406 Glib::PatternSpec pattern("*.bindings");
407 find_matching_files_in_search_path (spath, pattern, found);
414 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
415 std::string path(*x);
416 pair<string,string> namepath;
417 namepath.second = path;
418 namepath.first = PBD::basename_nosuffix (path);
419 files.insert (namepath);
424 ARDOUR::no_auto_connect()
426 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
433 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
434 // valgrind doesn't understand this assembler stuff
435 // September 10th, 2007
439 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
444 /* XXX use real code to determine if the processor supports
445 DenormalsAreZero and FlushToZero
448 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
452 MXCSR = _mm_getcsr();
454 #ifdef DEBUG_DENORMAL_EXCEPTION
455 /* This will raise a FP exception if a denormal is detected */
456 MXCSR &= ~_MM_MASK_DENORM;
459 switch (Config->get_denormal_model()) {
461 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
465 if (fpu.has_flush_to_zero()) {
466 MXCSR |= _MM_FLUSH_ZERO_ON;
471 MXCSR &= ~_MM_FLUSH_ZERO_ON;
472 if (fpu.has_denormals_are_zero()) {
478 if (fpu.has_flush_to_zero()) {
479 if (fpu.has_denormals_are_zero()) {
480 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
482 MXCSR |= _MM_FLUSH_ZERO_ON;
493 /* this can be changed to modify the translation behaviour for
494 cases where the user has never expressed a preference.
496 static const bool translate_by_default = true;
499 ARDOUR::translation_enable_path ()
501 return Glib::build_filename (user_config_directory(), ".translate");
505 ARDOUR::translations_are_enabled ()
507 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
510 return translate_by_default;
516 if (::read (fd, &c, 1) == 1 && c == '1') {
526 ARDOUR::set_translations_enabled (bool yn)
528 string i18n_enabler = ARDOUR::translation_enable_path();
529 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
543 (void) ::write (fd, &c, 1);
551 ARDOUR::get_available_sync_options ()
553 vector<SyncSource> ret;
555 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
556 if (backend && backend->name() == "JACK") {
557 ret.push_back (Engine);
561 ret.push_back (MIDIClock);
567 /** Return a monotonic value for the number of microseconds that have elapsed
568 * since an arbitrary zero origin.
572 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
574 #include <mach/mach_time.h>
575 #define CLOCK_REALTIME 0
576 #define CLOCK_MONOTONIC 0
578 clock_gettime (int /*clk_id*/, struct timespec *t)
580 static bool initialized = false;
581 static mach_timebase_info_data_t timebase;
583 mach_timebase_info(&timebase);
587 time = mach_absolute_time();
588 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
589 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
591 t->tv_nsec = nseconds;
597 ARDOUR::get_microseconds ()
599 #ifdef PLATFORM_WINDOWS
600 microseconds_t ret = 0;
601 LARGE_INTEGER freq, time;
603 if (QueryPerformanceFrequency(&freq))
604 if (QueryPerformanceCounter(&time))
605 ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
610 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
614 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);