try some alternate, hard numbers when resetting open file limits on OS X
[ardour.git] / libs / ardour / globals.cc
1 /*
2     Copyright (C) 2000 Paul Davis
3
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.
8
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.
13
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.
17 */
18
19 #ifdef WAF_BUILD
20 #include "libardour-config.h"
21 #endif
22
23 #ifdef interface
24 #undef interface
25 #endif
26
27 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
28 #include <cstdlib>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
34 #endif
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <time.h>
39
40 #ifdef WINDOWS_VST_SUPPORT
41 #include <fst.h>
42 #endif
43
44 #ifdef LXVST_SUPPORT
45 #include "ardour/linux_vst_support.h"
46 #endif
47
48 #ifdef AUDIOUNIT_SUPPORT
49 #include "ardour/audio_unit.h"
50 #endif
51
52 #if defined(__SSE__) || defined(USE_XMMINTRIN)
53 #include <xmmintrin.h>
54 #endif
55
56 #ifdef check
57 #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
58 #endif 
59
60 #include <glibmm/fileutils.h>
61 #include <glibmm/miscutils.h>
62
63 #ifdef HAVE_LRDF
64 #include <lrdf.h>
65 #endif
66
67 #include "pbd/cpus.h"
68 #include "pbd/error.h"
69 #include "pbd/id.h"
70 #include "pbd/pbd.h"
71 #include "pbd/strsplit.h"
72 #include "pbd/fpu.h"
73 #include "pbd/file_utils.h"
74 #include "pbd/enumwriter.h"
75 #include "pbd/basename.h"
76
77 #include "midi++/port.h"
78 #include "midi++/mmc.h"
79
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/event_type_map.h"
89 #include "ardour/filesystem_paths.h"
90 #include "ardour/midi_region.h"
91 #include "ardour/midiport_manager.h"
92 #include "ardour/mix.h"
93 #include "ardour/operations.h"
94 #include "ardour/panner_manager.h"
95 #include "ardour/plugin_manager.h"
96 #include "ardour/process_thread.h"
97 #include "ardour/profile.h"
98 #include "ardour/rc_configuration.h"
99 #include "ardour/region.h"
100 #include "ardour/route_group.h"
101 #include "ardour/runtime_functions.h"
102 #include "ardour/session_event.h"
103 #include "ardour/source_factory.h"
104 #include "ardour/uri_map.h"
105
106 #include "audiographer/routines.h"
107
108 #if defined (__APPLE__)
109        #include <Carbon/Carbon.h> // For Gestalt
110 #endif
111
112 #include "i18n.h"
113
114 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
115 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
116 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
117
118 using namespace ARDOUR;
119 using namespace std;
120 using namespace PBD;
121
122 bool libardour_initialized = false;
123
124 compute_peak_t          ARDOUR::compute_peak = 0;
125 find_peaks_t            ARDOUR::find_peaks = 0;
126 apply_gain_to_buffer_t  ARDOUR::apply_gain_to_buffer = 0;
127 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
128 mix_buffers_no_gain_t   ARDOUR::mix_buffers_no_gain = 0;
129
130 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
131 PBD::Signal3<void,std::string,std::string,bool> ARDOUR::PluginScanMessage;
132 PBD::Signal1<void,int> ARDOUR::PluginScanTimeout;
133 PBD::Signal0<void> ARDOUR::GUIIdle;
134
135 namespace ARDOUR {
136 extern void setup_enum_writer ();
137 }
138
139 /* this is useful for quite a few things that want to check
140    if any bounds-related property has changed
141 */
142 PBD::PropertyChange ARDOUR::bounds_change;
143
144 void
145 setup_hardware_optimization (bool try_optimization)
146 {
147         bool generic_mix_functions = true;
148
149         if (try_optimization) {
150
151                 FPU fpu;
152
153 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
154
155                 if (fpu.has_sse()) {
156
157                         info << "Using SSE optimized routines" << endmsg;
158
159                         // SSE SET
160                         compute_peak          = x86_sse_compute_peak;
161                         find_peaks            = x86_sse_find_peaks;
162                         apply_gain_to_buffer  = x86_sse_apply_gain_to_buffer;
163                         mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
164                         mix_buffers_no_gain   = x86_sse_mix_buffers_no_gain;
165
166                         generic_mix_functions = false;
167
168                 }
169
170 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
171                 SInt32 sysVersion = 0;
172
173                 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
174                         sysVersion = 0;
175
176                 if (sysVersion >= 0x00001040) { // Tiger at least
177                         compute_peak           = veclib_compute_peak;
178                         find_peaks             = veclib_find_peaks;
179                         apply_gain_to_buffer   = veclib_apply_gain_to_buffer;
180                         mix_buffers_with_gain  = veclib_mix_buffers_with_gain;
181                         mix_buffers_no_gain    = veclib_mix_buffers_no_gain;
182
183                         generic_mix_functions = false;
184
185                         info << "Apple VecLib H/W specific optimizations in use" << endmsg;
186                 }
187 #endif
188
189                 /* consider FPU denormal handling to be "h/w optimization" */
190
191                 setup_fpu ();
192         }
193
194         if (generic_mix_functions) {
195
196                 compute_peak          = default_compute_peak;
197                 find_peaks            = default_find_peaks;
198                 apply_gain_to_buffer  = default_apply_gain_to_buffer;
199                 mix_buffers_with_gain = default_mix_buffers_with_gain;
200                 mix_buffers_no_gain   = default_mix_buffers_no_gain;
201
202                 info << "No H/W specific optimizations in use" << endmsg;
203         }
204
205         AudioGrapher::Routines::override_compute_peak (compute_peak);
206         AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
207 }
208
209 static void
210 lotsa_files_please ()
211 {
212 #ifndef PLATFORM_WINDOWS
213         struct rlimit rl;
214
215         if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
216
217                 rl.rlim_cur = rl.rlim_max;
218
219                 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
220                         if (rl.rlim_cur == RLIM_INFINITY) {
221 #if __APPLE__
222                                 /* For some reason, Apple doesn't do this the
223                                  * same way as Linux, and asking for
224                                  * RLIM_INFINITY even though that is
225                                  * rl.rlim_cur doesn't work.
226                                  * 
227                                  * So try some actual large numbers in the hope
228                                  * that one of them will work.
229                                  */
230
231                                 rl.rlim_cur = 10000;
232                                 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
233                                         rl.rlim_cur = 4096;
234                                         if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
235                                                 rl.rlim_cur = 1000;
236                                                 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
237                                                         error << _("Could not set system open files limit to a reasonable value. Be careful!") << endmsg;
238                                                 }
239                                         }
240                                 }
241                                 info << string_compose ("Configured system open file limit to %1", rl.rlim_cur) << endmsg;
242 #else
243                                 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
244 #endif                          
245                         } else {
246                                 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
247                         }
248                 } else {
249                         if (rl.rlim_cur != RLIM_INFINITY) {
250                                 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
251                         }
252                 }
253         } else {
254                 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
255         }
256 #endif
257 }
258
259 bool
260 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
261 {
262         if (libardour_initialized) {
263                 return true;
264         }
265
266         if (!PBD::init()) return false;
267
268 #ifdef ENABLE_NLS
269         (void) bindtextdomain(PACKAGE, localedir);
270         (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
271 #endif
272
273         SessionEvent::init_event_pool ();
274
275         Operations::make_operations_quarks ();
276         SessionObject::make_property_quarks ();
277         Region::make_property_quarks ();
278         MidiRegion::make_property_quarks ();
279         AudioRegion::make_property_quarks ();
280         RouteGroup::make_property_quarks ();
281         Playlist::make_property_quarks ();
282         AudioPlaylist::make_property_quarks ();
283
284         /* this is a useful ready to use PropertyChange that many
285            things need to check. This avoids having to compose
286            it every time we want to check for any of the relevant
287            property changes.
288         */
289
290         bounds_change.add (ARDOUR::Properties::start);
291         bounds_change.add (ARDOUR::Properties::position);
292         bounds_change.add (ARDOUR::Properties::length);
293
294         /* provide a state version for the few cases that need it and are not
295            driven by reading state from disk (e.g. undo/redo)
296         */
297
298         Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
299
300         ARDOUR::setup_enum_writer ();
301
302         // allow ardour the absolute maximum number of open files
303         lotsa_files_please ();
304
305 #ifdef HAVE_LRDF
306         lrdf_init();
307 #endif
308         Library = new AudioLibrary;
309
310         BootMessage (_("Loading configuration"));
311
312         Config = new RCConfiguration;
313
314         if (Config->load_state ()) {
315                 return false;
316         }
317
318         Config->set_use_windows_vst (use_windows_vst);
319 #ifdef LXVST_SUPPORT
320         Config->set_use_lxvst(true);
321 #endif
322
323         Profile = new RuntimeProfile;
324
325
326 #ifdef WINDOWS_VST_SUPPORT
327         if (Config->get_use_windows_vst() && fst_init (0)) {
328                 return false;
329         }
330 #endif
331
332 #ifdef LXVST_SUPPORT
333         if (Config->get_use_lxvst() && vstfx_init (0)) {
334                 return false;
335         }
336 #endif
337
338 #ifdef AUDIOUNIT_SUPPORT
339         AUPluginInfo::load_cached_info ();
340 #endif
341
342         setup_hardware_optimization (try_optimization);
343
344         SourceFactory::init ();
345         Analyser::init ();
346
347         /* singletons - first object is "it" */
348         (void) PluginManager::instance();
349         (void) URIMap::instance();
350         (void) EventTypeMap::instance();
351
352         ProcessThread::init ();
353         /* the + 4 is a bit of a handwave. i don't actually know
354            how many more per-thread buffer sets we need above
355            the h/w concurrency, but its definitely > 1 more.
356         */
357         BufferManager::init (hardware_concurrency() + 4); 
358
359         PannerManager::instance().discover_panners();
360
361         ARDOUR::AudioEngine::create ();
362
363         libardour_initialized = true;
364
365         return true;
366 }
367
368 void
369 ARDOUR::init_post_engine ()
370 {
371         ControlProtocolManager::instance().discover_control_protocols ();
372
373         XMLNode* node;
374         if ((node = Config->control_protocol_state()) != 0) {
375                 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
376         }
377
378         /* find plugins */
379
380         ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start());
381 }
382
383 void
384 ARDOUR::cleanup () 
385 {
386         if (!libardour_initialized) {
387                 return;
388         }
389
390         ARDOUR::AudioEngine::destroy ();
391
392         delete Library;
393 #ifdef HAVE_LRDF
394         lrdf_cleanup ();
395 #endif
396         delete &ControlProtocolManager::instance();
397 #ifdef WINDOWS_VST_SUPPORT
398         fst_exit ();
399 #endif
400
401 #ifdef LXVST_SUPPORT
402         vstfx_exit();
403 #endif
404         delete &PluginManager::instance();
405         delete Config;
406         PBD::cleanup ();
407
408         return;
409 }
410
411 void
412 ARDOUR::find_bindings_files (map<string,string>& files)
413 {
414         vector<std::string> found;
415         Searchpath spath = ardour_config_search_path();
416
417         if (getenv ("ARDOUR_SAE")) {
418                 find_files_matching_pattern (found, spath, "*SAE-*.bindings");
419         } else {
420                 find_files_matching_pattern (found, spath, "*.bindings");
421         }
422
423         if (found.empty()) {
424                 return;
425         }
426
427         for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
428                 std::string path(*x);
429                 pair<string,string> namepath;
430                 namepath.second = path;
431                 namepath.first = PBD::basename_nosuffix (path);
432                 files.insert (namepath);
433         }
434 }
435
436 bool
437 ARDOUR::no_auto_connect()
438 {
439         return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
440 }
441
442 void
443 ARDOUR::setup_fpu ()
444 {
445
446         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
447                 // valgrind doesn't understand this assembler stuff
448                 // September 10th, 2007
449                 return;
450         }
451
452 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
453
454         int MXCSR;
455         FPU fpu;
456
457         /* XXX use real code to determine if the processor supports
458            DenormalsAreZero and FlushToZero
459         */
460
461         if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
462                 return;
463         }
464
465         MXCSR  = _mm_getcsr();
466
467 #ifdef DEBUG_DENORMAL_EXCEPTION
468         /* This will raise a FP exception if a denormal is detected */
469         MXCSR &= ~_MM_MASK_DENORM;
470 #endif  
471
472         switch (Config->get_denormal_model()) {
473         case DenormalNone:
474                 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
475                 break;
476
477         case DenormalFTZ:
478                 if (fpu.has_flush_to_zero()) {
479                         MXCSR |= _MM_FLUSH_ZERO_ON;
480                 }
481                 break;
482
483         case DenormalDAZ:
484                 MXCSR &= ~_MM_FLUSH_ZERO_ON;
485                 if (fpu.has_denormals_are_zero()) {
486                         MXCSR |= 0x40;
487                 }
488                 break;
489
490         case DenormalFTZDAZ:
491                 if (fpu.has_flush_to_zero()) {
492                         if (fpu.has_denormals_are_zero()) {
493                                 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
494                         } else {
495                                 MXCSR |= _MM_FLUSH_ZERO_ON;
496                         }
497                 }
498                 break;
499         }
500
501         _mm_setcsr (MXCSR);
502
503 #endif
504 }
505
506 /* this can be changed to modify the translation behaviour for
507    cases where the user has never expressed a preference.
508 */
509 static const bool translate_by_default = true;
510
511 string
512 ARDOUR::translation_enable_path ()
513 {
514         return Glib::build_filename (user_config_directory(), ".translate");
515 }
516
517 bool
518 ARDOUR::translations_are_enabled ()
519 {
520         int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
521
522         if (fd < 0) {
523                 return translate_by_default;
524         }
525
526         char c;
527         bool ret = false;
528
529         if (::read (fd, &c, 1) == 1 && c == '1') {
530                 ret = true;
531         }
532
533         ::close (fd);
534
535         return ret;
536 }
537
538 bool
539 ARDOUR::set_translations_enabled (bool yn)
540 {
541         string i18n_enabler = ARDOUR::translation_enable_path();
542         int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
543
544         if (fd < 0) {
545                 return false;
546         }
547         
548         char c;
549         
550         if (yn) {
551                 c = '1';
552         } else {
553                 c = '0';
554         }
555         
556         (void) ::write (fd, &c, 1);
557         (void) ::close (fd);
558
559         return true;
560 }
561
562
563 vector<SyncSource>
564 ARDOUR::get_available_sync_options ()
565 {
566         vector<SyncSource> ret;
567
568         boost::shared_ptr<AudioBackend> backend = AudioEngine::instance()->current_backend();
569         if (backend && backend->name() == "JACK") {
570                 ret.push_back (Engine);
571         }
572
573         ret.push_back (MTC);
574         ret.push_back (MIDIClock);
575         ret.push_back (LTC);
576
577         return ret;
578 }
579
580 /** Return a monotonic value for the number of microseconds that have elapsed
581  * since an arbitrary zero origin.
582  */
583
584 #ifdef __MACH__
585 /* Thanks Apple for not implementing this basic SUSv2, POSIX.1-2001 function
586  */
587 #include <mach/mach_time.h>
588 #define CLOCK_REALTIME 0
589 #define CLOCK_MONOTONIC 0
590 int 
591 clock_gettime (int /*clk_id*/, struct timespec *t)
592 {
593         static bool initialized = false;
594         static mach_timebase_info_data_t timebase;
595         if (!initialized) {
596                 mach_timebase_info(&timebase);
597                 initialized = true;
598         }
599         uint64_t time;
600         time = mach_absolute_time();
601         double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
602         double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
603         t->tv_sec = seconds;
604         t->tv_nsec = nseconds;
605         return 0;
606 }
607 #endif
608  
609 microseconds_t
610 ARDOUR::get_microseconds ()
611 {
612 #ifdef PLATFORM_WINDOWS
613         microseconds_t ret = 0;
614         LARGE_INTEGER freq, time;
615
616         if (QueryPerformanceFrequency(&freq))
617                 if (QueryPerformanceCounter(&time))
618                         ret = (microseconds_t)((time.QuadPart * 1000000) / freq.QuadPart);
619
620         return ret;
621 #else
622         struct timespec ts;
623         if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0) {
624                 /* EEEK! */
625                 return 0;
626         }
627         return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);
628 #endif
629 }