Call PBD::init in ARDOUR::init and PBD::cleanup in ARDOUR::cleanup
[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 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
24 #include <cstdlib>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32
33 #ifdef WINDOWS_VST_SUPPORT
34 #include <fst.h>
35 #endif
36
37 #ifdef LXVST_SUPPORT
38 #include "ardour/linux_vst_support.h"
39 #endif
40
41 #ifdef AUDIOUNIT_SUPPORT
42 #include "ardour/audio_unit.h"
43 #endif
44
45 #ifdef __SSE__
46 #include <xmmintrin.h>
47 #endif
48
49 #ifdef check
50 #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
51 #endif 
52
53 #include <giomm.h>
54
55 #include <glibmm/fileutils.h>
56 #include <glibmm/miscutils.h>
57
58 #include <lrdf.h>
59
60 #include "pbd/cpus.h"
61 #include "pbd/error.h"
62 #include "pbd/id.h"
63 #include "pbd/pbd.h"
64 #include "pbd/strsplit.h"
65 #include "pbd/fpu.h"
66 #include "pbd/file_utils.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/basename.h"
69
70 #include "midi++/port.h"
71 #include "midi++/manager.h"
72 #include "midi++/mmc.h"
73
74 #include "ardour/analyser.h"
75 #include "ardour/audio_library.h"
76 #include "ardour/audioengine.h"
77 #include "ardour/audioplaylist.h"
78 #include "ardour/audioregion.h"
79 #include "ardour/buffer_manager.h"
80 #include "ardour/control_protocol_manager.h"
81 #include "ardour/filesystem_paths.h"
82 #include "ardour/midi_region.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"
94
95 #include "audiographer/routines.h"
96
97 #if defined (__APPLE__)
98        #include <Carbon/Carbon.h> // For Gestalt
99 #endif
100
101 #include "i18n.h"
102
103 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
104 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
105 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
106
107 using namespace ARDOUR;
108 using namespace std;
109 using namespace PBD;
110
111 bool libardour_initialized = false;
112
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;
118
119 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
120 PBD::Signal0<void> ARDOUR::GUIIdle;
121
122 namespace ARDOUR {
123 extern void setup_enum_writer ();
124 }
125
126 /* this is useful for quite a few things that want to check
127    if any bounds-related property has changed
128 */
129 PBD::PropertyChange ARDOUR::bounds_change;
130
131 void
132 setup_hardware_optimization (bool try_optimization)
133 {
134         bool generic_mix_functions = true;
135
136         if (try_optimization) {
137
138                 FPU fpu;
139
140 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
141
142                 if (fpu.has_sse()) {
143
144                         info << "Using SSE optimized routines" << endmsg;
145
146                         // SSE SET
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;
152
153                         generic_mix_functions = false;
154
155                 }
156
157 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
158                 SInt32 sysVersion = 0;
159
160                 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
161                         sysVersion = 0;
162
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;
169
170                         generic_mix_functions = false;
171
172                         info << "Apple VecLib H/W specific optimizations in use" << endmsg;
173                 }
174 #endif
175
176                 /* consider FPU denormal handling to be "h/w optimization" */
177
178                 setup_fpu ();
179         }
180
181         if (generic_mix_functions) {
182
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;
188
189                 info << "No H/W specific optimizations in use" << endmsg;
190         }
191
192         AudioGrapher::Routines::override_compute_peak (compute_peak);
193         AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
194 }
195
196 static void
197 lotsa_files_please ()
198 {
199         struct rlimit rl;
200
201         if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
202
203                 rl.rlim_cur = rl.rlim_max;
204
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;
208                         } else {
209                                 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
210                         }
211                 } else {
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;
214                         }
215                 }
216         } else {
217                 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
218         }
219 }
220
221 bool
222 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
223 {
224         if (libardour_initialized) {
225                 return true;
226         }
227
228         if (!PBD::init()) return false;
229
230         // this really should be in PBD::init..if there was one
231         Gio::init ();
232
233 #ifdef ENABLE_NLS
234         (void) bindtextdomain(PACKAGE, localedir);
235 #endif
236
237         SessionEvent::init_event_pool ();
238
239         SessionObject::make_property_quarks ();
240         Region::make_property_quarks ();
241         MidiRegion::make_property_quarks ();
242         AudioRegion::make_property_quarks ();
243         RouteGroup::make_property_quarks ();
244         Playlist::make_property_quarks ();
245         AudioPlaylist::make_property_quarks ();
246
247         /* this is a useful ready to use PropertyChange that many
248            things need to check. This avoids having to compose
249            it every time we want to check for any of the relevant
250            property changes.
251         */
252
253         bounds_change.add (ARDOUR::Properties::start);
254         bounds_change.add (ARDOUR::Properties::position);
255         bounds_change.add (ARDOUR::Properties::length);
256
257         /* provide a state version for the few cases that need it and are not
258            driven by reading state from disk (e.g. undo/redo)
259         */
260
261         Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
262
263         ARDOUR::setup_enum_writer ();
264
265         // allow ardour the absolute maximum number of open files
266         lotsa_files_please ();
267
268         lrdf_init();
269         Library = new AudioLibrary;
270
271         BootMessage (_("Loading configuration"));
272
273         Config = new RCConfiguration;
274
275         if (Config->load_state ()) {
276                 return false;
277         }
278
279         Config->set_use_windows_vst (use_windows_vst);
280 #ifdef LXVST_SUPPORT
281         Config->set_use_lxvst(true);
282 #endif
283
284         Profile = new RuntimeProfile;
285
286
287 #ifdef WINDOWS_VST_SUPPORT
288         if (Config->get_use_windows_vst() && fst_init (0)) {
289                 return false;
290         }
291 #endif
292
293 #ifdef LXVST_SUPPORT
294         if (Config->get_use_lxvst() && vstfx_init (0)) {
295                 return false;
296         }
297 #endif
298
299 #ifdef AUDIOUNIT_SUPPORT
300         AUPluginInfo::load_cached_info ();
301 #endif
302
303         setup_hardware_optimization (try_optimization);
304
305         SourceFactory::init ();
306         Analyser::init ();
307
308         /* singleton - first object is "it" */
309         (void) PluginManager::instance();
310
311         ProcessThread::init ();
312         /* the + 4 is a bit of a handwave. i don't actually know
313            how many more per-thread buffer sets we need above
314            the h/w concurrency, but its definitely > 1 more.
315         */
316         BufferManager::init (hardware_concurrency() + 4); 
317
318         PannerManager::instance().discover_panners();
319
320         // Initialize parameter metadata
321         EventTypeMap::instance().new_parameter(NullAutomation);
322         EventTypeMap::instance().new_parameter(GainAutomation);
323         EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
324         EventTypeMap::instance().new_parameter(PanElevationAutomation);
325         EventTypeMap::instance().new_parameter(PanWidthAutomation);
326         EventTypeMap::instance().new_parameter(PluginAutomation);
327         EventTypeMap::instance().new_parameter(SoloAutomation);
328         EventTypeMap::instance().new_parameter(MuteAutomation);
329         EventTypeMap::instance().new_parameter(MidiCCAutomation);
330         EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
331         EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
332         EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
333         EventTypeMap::instance().new_parameter(FadeInAutomation);
334         EventTypeMap::instance().new_parameter(FadeOutAutomation);
335         EventTypeMap::instance().new_parameter(EnvelopeAutomation);
336         EventTypeMap::instance().new_parameter(MidiCCAutomation);
337
338         libardour_initialized = true;
339
340         return true;
341 }
342
343 void
344 ARDOUR::init_post_engine ()
345 {
346         /* the MIDI Manager is needed by the ControlProtocolManager */
347         MIDI::Manager::create (AudioEngine::instance()->jack());
348
349         ControlProtocolManager::instance().discover_control_protocols ();
350
351         XMLNode* node;
352         if ((node = Config->control_protocol_state()) != 0) {
353                 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
354         }
355
356         /* find plugins */
357
358         ARDOUR::PluginManager::instance().refresh ();
359 }
360
361 int
362 ARDOUR::cleanup ()
363 {
364         delete Library;
365         lrdf_cleanup ();
366         delete &ControlProtocolManager::instance();
367 #ifdef WINDOWS_VST_SUPPORT
368         fst_exit ();
369 #endif
370
371 #ifdef LXVST_SUPPORT
372         vstfx_exit();
373 #endif
374         PBD::cleanup ();
375         return 0;
376 }
377
378 void
379 ARDOUR::find_bindings_files (map<string,string>& files)
380 {
381         vector<std::string> found;
382         SearchPath spath = ardour_config_search_path();
383
384         if (getenv ("ARDOUR_SAE")) {
385                 Glib::PatternSpec pattern("*SAE-*.bindings");
386                 find_matching_files_in_search_path (spath, pattern, found);
387         } else {
388                 Glib::PatternSpec pattern("*.bindings");
389                 find_matching_files_in_search_path (spath, pattern, found);
390         }
391
392         if (found.empty()) {
393                 return;
394         }
395
396         for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
397                 std::string path(*x);
398                 pair<string,string> namepath;
399                 namepath.second = path;
400                 namepath.first = PBD::basename_nosuffix (path);
401                 files.insert (namepath);
402         }
403 }
404
405 bool
406 ARDOUR::no_auto_connect()
407 {
408         return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
409 }
410
411 void
412 ARDOUR::setup_fpu ()
413 {
414
415         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
416                 // valgrind doesn't understand this assembler stuff
417                 // September 10th, 2007
418                 return;
419         }
420
421 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
422
423         int MXCSR;
424         FPU fpu;
425
426         /* XXX use real code to determine if the processor supports
427            DenormalsAreZero and FlushToZero
428         */
429
430         if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
431                 return;
432         }
433
434         MXCSR  = _mm_getcsr();
435
436 #ifdef DEBUG_DENORMAL_EXCEPTION
437         /* This will raise a FP exception if a denormal is detected */
438         MXCSR &= ~_MM_MASK_DENORM;
439 #endif  
440
441         switch (Config->get_denormal_model()) {
442         case DenormalNone:
443                 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
444                 break;
445
446         case DenormalFTZ:
447                 if (fpu.has_flush_to_zero()) {
448                         MXCSR |= _MM_FLUSH_ZERO_ON;
449                 }
450                 break;
451
452         case DenormalDAZ:
453                 MXCSR &= ~_MM_FLUSH_ZERO_ON;
454                 if (fpu.has_denormals_are_zero()) {
455                         MXCSR |= 0x40;
456                 }
457                 break;
458
459         case DenormalFTZDAZ:
460                 if (fpu.has_flush_to_zero()) {
461                         if (fpu.has_denormals_are_zero()) {
462                                 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
463                         } else {
464                                 MXCSR |= _MM_FLUSH_ZERO_ON;
465                         }
466                 }
467                 break;
468         }
469
470         _mm_setcsr (MXCSR);
471
472 #endif
473 }
474
475 /* this can be changed to modify the translation behaviour for
476    cases where the user has never expressed a preference.
477 */
478 static const bool translate_by_default = true;
479
480 string
481 ARDOUR::translation_enable_path ()
482 {
483         return Glib::build_filename (user_config_directory(), ".translate");
484 }
485
486 bool
487 ARDOUR::translations_are_enabled ()
488 {
489         int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
490
491         if (fd < 0) {
492                 return translate_by_default;
493         }
494
495         char c;
496         bool ret = false;
497
498         if (::read (fd, &c, 1) == 1 && c == '1') {
499                 ret = true;
500         }
501
502         ::close (fd);
503
504         return ret;
505 }
506
507 bool
508 ARDOUR::set_translations_enabled (bool yn)
509 {
510         string i18n_enabler = ARDOUR::translation_enable_path();
511         int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
512
513         if (fd < 0) {
514                 return false;
515         }
516         
517         char c;
518         
519         if (yn) {
520                 c = '1';
521         } else {
522                 c = '0';
523         }
524         
525         ::write (fd, &c, 1);
526         ::close (fd);
527
528         return true;
529 }
530
531
532 vector<SyncSource>
533 ARDOUR::get_available_sync_options ()
534 {
535         vector<SyncSource> ret;
536
537         ret.push_back (JACK);
538         ret.push_back (MTC);
539         ret.push_back (MIDIClock);
540         ret.push_back (LTC);
541
542         return ret;
543 }