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 ();
362 delete &ControlProtocolManager::instance();
363 #ifdef WINDOWS_VST_SUPPORT
375 ARDOUR::find_bindings_files (map<string,string>& files)
377 vector<std::string> found;
378 SearchPath spath = ardour_config_search_path();
380 if (getenv ("ARDOUR_SAE")) {
381 Glib::PatternSpec pattern("*SAE-*.bindings");
382 find_matching_files_in_search_path (spath, pattern, found);
384 Glib::PatternSpec pattern("*.bindings");
385 find_matching_files_in_search_path (spath, pattern, found);
392 for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
393 std::string path(*x);
394 pair<string,string> namepath;
395 namepath.second = path;
396 namepath.first = PBD::basename_nosuffix (path);
397 files.insert (namepath);
402 ARDOUR::no_auto_connect()
404 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
411 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
412 // valgrind doesn't understand this assembler stuff
413 // September 10th, 2007
417 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
422 /* XXX use real code to determine if the processor supports
423 DenormalsAreZero and FlushToZero
426 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
430 MXCSR = _mm_getcsr();
432 #ifdef DEBUG_DENORMAL_EXCEPTION
433 /* This will raise a FP exception if a denormal is detected */
434 MXCSR &= ~_MM_MASK_DENORM;
437 switch (Config->get_denormal_model()) {
439 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
443 if (fpu.has_flush_to_zero()) {
444 MXCSR |= _MM_FLUSH_ZERO_ON;
449 MXCSR &= ~_MM_FLUSH_ZERO_ON;
450 if (fpu.has_denormals_are_zero()) {
456 if (fpu.has_flush_to_zero()) {
457 if (fpu.has_denormals_are_zero()) {
458 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
460 MXCSR |= _MM_FLUSH_ZERO_ON;
471 /* this can be changed to modify the translation behaviour for
472 cases where the user has never expressed a preference.
474 static const bool translate_by_default = true;
477 ARDOUR::translation_enable_path ()
479 return Glib::build_filename (user_config_directory(), ".translate");
483 ARDOUR::translations_are_enabled ()
485 int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
488 return translate_by_default;
494 if (::read (fd, &c, 1) == 1 && c == '1') {
504 ARDOUR::set_translations_enabled (bool yn)
506 string i18n_enabler = ARDOUR::translation_enable_path();
507 int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
529 ARDOUR::get_available_sync_options ()
531 vector<SyncSource> ret;
533 ret.push_back (JACK);
535 ret.push_back (MIDIClock);
541 /** Return a monotonic value for the number of microseconds that have elapsed
542 * since an arbitrary zero origin.
546 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
548 #include <mach/mach_time.h>
549 #define CLOCK_REALTIME 0
550 #define CLOCK_MONOTONIC 0
552 clock_gettime (int /*clk_id*/, struct timespec *t)
554 static bool initialized = false;
555 static mach_timebase_info_data_t timebase;
557 mach_timebase_info(&timebase);
561 time = mach_absolute_time();
562 double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
563 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
565 t->tv_nsec = nseconds;
571 ARDOUR::get_microseconds ()
574 if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
578 return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);