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