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"
23 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
26 #include <sys/types.h>
28 #include <sys/resource.h>
34 #ifdef WINDOWS_VST_SUPPORT
39 #include "ardour/linux_vst_support.h"
42 #ifdef AUDIOUNIT_SUPPORT
43 #include "ardour/audio_unit.h"
47 #include <xmmintrin.h>
51 #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
54 #include <glibmm/fileutils.h>
55 #include <glibmm/miscutils.h>
60 #include "pbd/error.h"
63 #include "pbd/strsplit.h"
65 #include "pbd/file_utils.h"
66 #include "pbd/enumwriter.h"
67 #include "pbd/basename.h"
69 #include "midi++/port.h"
70 #include "midi++/mmc.h"
72 #include "ardour/analyser.h"
73 #include "ardour/audio_library.h"
74 #include "ardour/audio_backend.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audioplaylist.h"
77 #include "ardour/audioregion.h"
78 #include "ardour/buffer_manager.h"
79 #include "ardour/control_protocol_manager.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/midi_region.h"
82 #include "ardour/midiport_manager.h"
83 #include "ardour/mix.h"
84 #include "ardour/panner_manager.h"
85 #include "ardour/plugin_manager.h"
86 #include "ardour/process_thread.h"
87 #include "ardour/profile.h"
88 #include "ardour/rc_configuration.h"
89 #include "ardour/region.h"
90 #include "ardour/route_group.h"
91 #include "ardour/runtime_functions.h"
92 #include "ardour/session_event.h"
93 #include "ardour/source_factory.h"
95 #include "audiographer/routines.h"
97 #if defined (__APPLE__)
98 #include <Carbon/Carbon.h> // For Gestalt
103 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
104 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
105 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
107 using namespace ARDOUR;
111 bool libardour_initialized = false;
113 compute_peak_t ARDOUR::compute_peak = 0;
114 find_peaks_t ARDOUR::find_peaks = 0;
115 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
116 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
117 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
119 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
120 PBD::Signal0<void> ARDOUR::GUIIdle;
123 extern void setup_enum_writer ();
126 /* this is useful for quite a few things that want to check
127 if any bounds-related property has changed
129 PBD::PropertyChange ARDOUR::bounds_change;
132 setup_hardware_optimization (bool try_optimization)
134 bool generic_mix_functions = true;
136 if (try_optimization) {
140 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
144 info << "Using SSE optimized routines" << endmsg;
147 compute_peak = x86_sse_compute_peak;
148 find_peaks = x86_sse_find_peaks;
149 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
150 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
151 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
153 generic_mix_functions = false;
157 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
158 SInt32 sysVersion = 0;
160 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
163 if (sysVersion >= 0x00001040) { // Tiger at least
164 compute_peak = veclib_compute_peak;
165 find_peaks = veclib_find_peaks;
166 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
167 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
168 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
170 generic_mix_functions = false;
172 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
176 /* consider FPU denormal handling to be "h/w optimization" */
181 if (generic_mix_functions) {
183 compute_peak = default_compute_peak;
184 find_peaks = default_find_peaks;
185 apply_gain_to_buffer = default_apply_gain_to_buffer;
186 mix_buffers_with_gain = default_mix_buffers_with_gain;
187 mix_buffers_no_gain = default_mix_buffers_no_gain;
189 info << "No H/W specific optimizations in use" << endmsg;
192 AudioGrapher::Routines::override_compute_peak (compute_peak);
193 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
197 lotsa_files_please ()
201 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
203 rl.rlim_cur = rl.rlim_max;
205 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
206 if (rl.rlim_cur == RLIM_INFINITY) {
207 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
209 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
212 if (rl.rlim_cur != RLIM_INFINITY) {
213 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
217 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
222 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
224 if (libardour_initialized) {
228 if (!PBD::init()) return false;
231 (void) bindtextdomain(PACKAGE, localedir);
234 SessionEvent::init_event_pool ();
236 SessionObject::make_property_quarks ();
237 Region::make_property_quarks ();
238 MidiRegion::make_property_quarks ();
239 AudioRegion::make_property_quarks ();
240 RouteGroup::make_property_quarks ();
241 Playlist::make_property_quarks ();
242 AudioPlaylist::make_property_quarks ();
244 /* this is a useful ready to use PropertyChange that many
245 things need to check. This avoids having to compose
246 it every time we want to check for any of the relevant
250 bounds_change.add (ARDOUR::Properties::start);
251 bounds_change.add (ARDOUR::Properties::position);
252 bounds_change.add (ARDOUR::Properties::length);
254 /* provide a state version for the few cases that need it and are not
255 driven by reading state from disk (e.g. undo/redo)
258 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
260 ARDOUR::setup_enum_writer ();
262 // allow ardour the absolute maximum number of open files
263 lotsa_files_please ();
266 Library = new AudioLibrary;
268 BootMessage (_("Loading configuration"));
270 Config = new RCConfiguration;
272 if (Config->load_state ()) {
276 Config->set_use_windows_vst (use_windows_vst);
278 Config->set_use_lxvst(true);
281 Profile = new RuntimeProfile;
284 #ifdef WINDOWS_VST_SUPPORT
285 if (Config->get_use_windows_vst() && fst_init (0)) {
291 if (Config->get_use_lxvst() && vstfx_init (0)) {
296 #ifdef AUDIOUNIT_SUPPORT
297 AUPluginInfo::load_cached_info ();
300 setup_hardware_optimization (try_optimization);
302 SourceFactory::init ();
305 /* singleton - first object is "it" */
306 (void) PluginManager::instance();
308 ProcessThread::init ();
309 /* the + 4 is a bit of a handwave. i don't actually know
310 how many more per-thread buffer sets we need above
311 the h/w concurrency, but its definitely > 1 more.
313 BufferManager::init (hardware_concurrency() + 4);
315 PannerManager::instance().discover_panners();
317 // Initialize parameter metadata
318 EventTypeMap::instance().new_parameter(NullAutomation);
319 EventTypeMap::instance().new_parameter(GainAutomation);
320 EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
321 EventTypeMap::instance().new_parameter(PanElevationAutomation);
322 EventTypeMap::instance().new_parameter(PanWidthAutomation);
323 EventTypeMap::instance().new_parameter(PluginAutomation);
324 EventTypeMap::instance().new_parameter(SoloAutomation);
325 EventTypeMap::instance().new_parameter(MuteAutomation);
326 EventTypeMap::instance().new_parameter(MidiCCAutomation);
327 EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
328 EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
329 EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
330 EventTypeMap::instance().new_parameter(FadeInAutomation);
331 EventTypeMap::instance().new_parameter(FadeOutAutomation);
332 EventTypeMap::instance().new_parameter(EnvelopeAutomation);
333 EventTypeMap::instance().new_parameter(MidiCCAutomation);
335 ARDOUR::AudioEngine::create ();
337 libardour_initialized = true;
343 ARDOUR::init_post_engine ()
345 ControlProtocolManager::instance().discover_control_protocols ();
348 if ((node = Config->control_protocol_state()) != 0) {
349 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
354 ARDOUR::PluginManager::instance().refresh ();
360 if (!libardour_initialized) {
364 ARDOUR::AudioEngine::destroy ();
368 delete &ControlProtocolManager::instance();
369 #ifdef WINDOWS_VST_SUPPORT
382 ARDOUR::find_bindings_files (map<string,string>& files)
384 vector<std::string> found;
385 SearchPath spath = ardour_config_search_path();
387 if (getenv ("ARDOUR_SAE")) {
388 Glib::PatternSpec pattern("*SAE-*.bindings");
389 find_matching_files_in_search_path (spath, pattern, found);
391 Glib::PatternSpec pattern("*.bindings");
392 find_matching_files_in_search_path (spath, pattern, found);
399 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
400 std::string path(*x);
401 pair<string,string> namepath;
402 namepath.second = path;
403 namepath.first = PBD::basename_nosuffix (path);
404 files.insert (namepath);
409 ARDOUR::no_auto_connect()
411 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
418 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
419 // valgrind doesn't understand this assembler stuff
420 // September 10th, 2007
424 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
429 /* XXX use real code to determine if the processor supports
430 DenormalsAreZero and FlushToZero
433 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
437 MXCSR = _mm_getcsr();
439 #ifdef DEBUG_DENORMAL_EXCEPTION
440 /* This will raise a FP exception if a denormal is detected */
441 MXCSR &= ~_MM_MASK_DENORM;
444 switch (Config->get_denormal_model()) {
446 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
450 if (fpu.has_flush_to_zero()) {
451 MXCSR |= _MM_FLUSH_ZERO_ON;
456 MXCSR &= ~_MM_FLUSH_ZERO_ON;
457 if (fpu.has_denormals_are_zero()) {
463 if (fpu.has_flush_to_zero()) {
464 if (fpu.has_denormals_are_zero()) {
465 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
467 MXCSR |= _MM_FLUSH_ZERO_ON;
478 /* this can be changed to modify the translation behaviour for
479 cases where the user has never expressed a preference.
481 static const bool translate_by_default = true;
484 ARDOUR::translation_enable_path ()
486 return Glib::build_filename (user_config_directory(), ".translate");
490 ARDOUR::translations_are_enabled ()
492 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
495 return translate_by_default;
501 if (::read (fd, &c, 1) == 1 && c == '1') {
511 ARDOUR::set_translations_enabled (bool yn)
513 string i18n_enabler = ARDOUR::translation_enable_path();
514 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
536 ARDOUR::get_available_sync_options ()
538 vector<SyncSource> ret;
540 boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
541 if (backend && backend->name() == "JACK") {
542 ret.push_back (Engine);
546 ret.push_back (MIDIClock);
552 /** Return a monotonic value for the number of microseconds that have elapsed
553 * since an arbitrary zero origin.
557 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
559 #include <mach/mach_time.h>
560 #define CLOCK_REALTIME 0
561 #define CLOCK_MONOTONIC 0
563 clock_gettime (int /*clk_id*/, struct timespec *t)
565 static bool initialized = false;
566 static mach_timebase_info_data_t timebase;
568 mach_timebase_info(&timebase);
572 time = mach_absolute_time();
573 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
574 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
576 t->tv_nsec = nseconds;
582 ARDOUR::get_microseconds ()
585 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
589 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);