new logic for enabling translation in bundled releases of ardour
[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/strsplit.h"
64 #include "pbd/fpu.h"
65 #include "pbd/file_utils.h"
66 #include "pbd/enumwriter.h"
67 #include "pbd/basename.h"
68
69 #include "midi++/port.h"
70 #include "midi++/manager.h"
71 #include "midi++/mmc.h"
72
73 #include "ardour/analyser.h"
74 #include "ardour/audio_library.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/mix.h"
83 #include "ardour/panner_manager.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/rc_configuration.h"
88 #include "ardour/region.h"
89 #include "ardour/route_group.h"
90 #include "ardour/runtime_functions.h"
91 #include "ardour/session_event.h"
92 #include "ardour/source_factory.h"
93
94 #include "audiographer/routines.h"
95
96 #if defined (__APPLE__)
97        #include <Carbon/Carbon.h> // For Gestalt
98 #endif
99
100 #include "i18n.h"
101
102 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
103 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
104 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
105
106 using namespace ARDOUR;
107 using namespace std;
108 using namespace PBD;
109
110 compute_peak_t          ARDOUR::compute_peak = 0;
111 find_peaks_t            ARDOUR::find_peaks = 0;
112 apply_gain_to_buffer_t  ARDOUR::apply_gain_to_buffer = 0;
113 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
114 mix_buffers_no_gain_t   ARDOUR::mix_buffers_no_gain = 0;
115
116 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
117 PBD::Signal0<void> ARDOUR::GUIIdle;
118
119 namespace ARDOUR {
120 extern void setup_enum_writer ();
121 }
122
123 /* this is useful for quite a few things that want to check
124    if any bounds-related property has changed
125 */
126 PBD::PropertyChange ARDOUR::bounds_change;
127
128 void
129 setup_hardware_optimization (bool try_optimization)
130 {
131         bool generic_mix_functions = true;
132
133         if (try_optimization) {
134
135                 FPU fpu;
136
137 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
138
139                 if (fpu.has_sse()) {
140
141                         info << "Using SSE optimized routines" << endmsg;
142
143                         // SSE SET
144                         compute_peak          = x86_sse_compute_peak;
145                         find_peaks            = x86_sse_find_peaks;
146                         apply_gain_to_buffer  = x86_sse_apply_gain_to_buffer;
147                         mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
148                         mix_buffers_no_gain   = x86_sse_mix_buffers_no_gain;
149
150                         generic_mix_functions = false;
151
152                 }
153
154 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
155                 SInt32 sysVersion = 0;
156
157                 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
158                         sysVersion = 0;
159
160                 if (sysVersion >= 0x00001040) { // Tiger at least
161                         compute_peak           = veclib_compute_peak;
162                         find_peaks             = veclib_find_peaks;
163                         apply_gain_to_buffer   = veclib_apply_gain_to_buffer;
164                         mix_buffers_with_gain  = veclib_mix_buffers_with_gain;
165                         mix_buffers_no_gain    = veclib_mix_buffers_no_gain;
166
167                         generic_mix_functions = false;
168
169                         info << "Apple VecLib H/W specific optimizations in use" << endmsg;
170                 }
171 #endif
172
173                 /* consider FPU denormal handling to be "h/w optimization" */
174
175                 setup_fpu ();
176         }
177
178         if (generic_mix_functions) {
179
180                 compute_peak          = default_compute_peak;
181                 find_peaks            = default_find_peaks;
182                 apply_gain_to_buffer  = default_apply_gain_to_buffer;
183                 mix_buffers_with_gain = default_mix_buffers_with_gain;
184                 mix_buffers_no_gain   = default_mix_buffers_no_gain;
185
186                 info << "No H/W specific optimizations in use" << endmsg;
187         }
188
189         AudioGrapher::Routines::override_compute_peak (compute_peak);
190         AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
191 }
192
193 static void
194 lotsa_files_please ()
195 {
196         struct rlimit rl;
197
198         if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
199
200                 rl.rlim_cur = rl.rlim_max;
201
202                 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
203                         if (rl.rlim_cur == RLIM_INFINITY) {
204                                 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
205                         } else {
206                                 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
207                         }
208                 } else {
209                         if (rl.rlim_cur != RLIM_INFINITY) {
210                                 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
211                         }
212                 }
213         } else {
214                 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
215         }
216 }
217
218 int
219 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
220 {
221         if (!Glib::thread_supported()) {
222                 Glib::thread_init();
223         }
224
225         // this really should be in PBD::init..if there was one
226         Gio::init ();
227
228 #ifdef ENABLE_NLS
229         (void) bindtextdomain(PACKAGE, localedir);
230 #endif
231
232         PBD::ID::init ();
233         SessionEvent::init_event_pool ();
234
235         SessionObject::make_property_quarks ();
236         Region::make_property_quarks ();
237         MidiRegion::make_property_quarks ();
238         AudioRegion::make_property_quarks ();
239         RouteGroup::make_property_quarks ();
240         Playlist::make_property_quarks ();
241         AudioPlaylist::make_property_quarks ();
242
243         /* this is a useful ready to use PropertyChange that many
244            things need to check. This avoids having to compose
245            it every time we want to check for any of the relevant
246            property changes.
247         */
248
249         bounds_change.add (ARDOUR::Properties::start);
250         bounds_change.add (ARDOUR::Properties::position);
251         bounds_change.add (ARDOUR::Properties::length);
252
253         /* provide a state version for the few cases that need it and are not
254            driven by reading state from disk (e.g. undo/redo)
255         */
256
257         Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
258
259         ARDOUR::setup_enum_writer ();
260
261         // allow ardour the absolute maximum number of open files
262         lotsa_files_please ();
263
264         lrdf_init();
265         Library = new AudioLibrary;
266
267         BootMessage (_("Loading configuration"));
268
269         Config = new RCConfiguration;
270
271         if (Config->load_state ()) {
272                 return -1;
273         }
274
275         Config->set_use_windows_vst (use_windows_vst);
276 #ifdef LXVST_SUPPORT
277         Config->set_use_lxvst(true);
278 #endif
279
280         Profile = new RuntimeProfile;
281
282
283 #ifdef WINDOWS_VST_SUPPORT
284         if (Config->get_use_windows_vst() && fst_init (0)) {
285                 return -1;
286         }
287 #endif
288
289 #ifdef LXVST_SUPPORT
290         if (Config->get_use_lxvst() && vstfx_init (0)) {
291                 return -1;
292         }
293 #endif
294
295 #ifdef AUDIOUNIT_SUPPORT
296         AUPluginInfo::load_cached_info ();
297 #endif
298
299         setup_hardware_optimization (try_optimization);
300
301         SourceFactory::init ();
302         Analyser::init ();
303
304         /* singleton - first object is "it" */
305         (void) PluginManager::instance();
306
307         ProcessThread::init ();
308         /* the + 4 is a bit of a handwave. i don't actually know
309            how many more per-thread buffer sets we need above
310            the h/w concurrency, but its definitely > 1 more.
311         */
312         BufferManager::init (hardware_concurrency() + 4); 
313
314         PannerManager::instance().discover_panners();
315
316         // Initialize parameter metadata
317         EventTypeMap::instance().new_parameter(NullAutomation);
318         EventTypeMap::instance().new_parameter(GainAutomation);
319         EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
320         EventTypeMap::instance().new_parameter(PanElevationAutomation);
321         EventTypeMap::instance().new_parameter(PanWidthAutomation);
322         EventTypeMap::instance().new_parameter(PluginAutomation);
323         EventTypeMap::instance().new_parameter(SoloAutomation);
324         EventTypeMap::instance().new_parameter(MuteAutomation);
325         EventTypeMap::instance().new_parameter(MidiCCAutomation);
326         EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
327         EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
328         EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
329         EventTypeMap::instance().new_parameter(FadeInAutomation);
330         EventTypeMap::instance().new_parameter(FadeOutAutomation);
331         EventTypeMap::instance().new_parameter(EnvelopeAutomation);
332         EventTypeMap::instance().new_parameter(MidiCCAutomation);
333
334         return 0;
335 }
336
337 void
338 ARDOUR::init_post_engine ()
339 {
340         /* the MIDI Manager is needed by the ControlProtocolManager */
341         MIDI::Manager::create (AudioEngine::instance()->jack());
342
343         ControlProtocolManager::instance().discover_control_protocols ();
344
345         XMLNode* node;
346         if ((node = Config->control_protocol_state()) != 0) {
347                 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
348         }
349
350         /* find plugins */
351
352         ARDOUR::PluginManager::instance().refresh ();
353 }
354
355 int
356 ARDOUR::cleanup ()
357 {
358         delete Library;
359         lrdf_cleanup ();
360         delete &ControlProtocolManager::instance();
361 #ifdef WINDOWS_VST_SUPPORT
362         fst_exit ();
363 #endif
364
365 #ifdef LXVST_SUPPORT
366         vstfx_exit();
367 #endif
368         EnumWriter::destroy ();
369         return 0;
370 }
371
372 void
373 ARDOUR::find_bindings_files (map<string,string>& files)
374 {
375         vector<std::string> found;
376         SearchPath spath = ardour_config_search_path();
377
378         if (getenv ("ARDOUR_SAE")) {
379                 Glib::PatternSpec pattern("*SAE-*.bindings");
380                 find_matching_files_in_search_path (spath, pattern, found);
381         } else {
382                 Glib::PatternSpec pattern("*.bindings");
383                 find_matching_files_in_search_path (spath, pattern, found);
384         }
385
386         if (found.empty()) {
387                 return;
388         }
389
390         for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
391                 std::string path(*x);
392                 pair<string,string> namepath;
393                 namepath.second = path;
394                 namepath.first = PBD::basename_nosuffix (path);
395                 files.insert (namepath);
396         }
397 }
398
399 bool
400 ARDOUR::no_auto_connect()
401 {
402         return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
403 }
404
405 void
406 ARDOUR::setup_fpu ()
407 {
408
409         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
410                 // valgrind doesn't understand this assembler stuff
411                 // September 10th, 2007
412                 return;
413         }
414
415 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
416
417         int MXCSR;
418         FPU fpu;
419
420         /* XXX use real code to determine if the processor supports
421            DenormalsAreZero and FlushToZero
422         */
423
424         if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
425                 return;
426         }
427
428         MXCSR  = _mm_getcsr();
429
430 #ifdef DEBUG_DENORMAL_EXCEPTION
431         /* This will raise a FP exception if a denormal is detected */
432         MXCSR &= ~_MM_MASK_DENORM;
433 #endif  
434
435         switch (Config->get_denormal_model()) {
436         case DenormalNone:
437                 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
438                 break;
439
440         case DenormalFTZ:
441                 if (fpu.has_flush_to_zero()) {
442                         MXCSR |= _MM_FLUSH_ZERO_ON;
443                 }
444                 break;
445
446         case DenormalDAZ:
447                 MXCSR &= ~_MM_FLUSH_ZERO_ON;
448                 if (fpu.has_denormals_are_zero()) {
449                         MXCSR |= 0x40;
450                 }
451                 break;
452
453         case DenormalFTZDAZ:
454                 if (fpu.has_flush_to_zero()) {
455                         if (fpu.has_denormals_are_zero()) {
456                                 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
457                         } else {
458                                 MXCSR |= _MM_FLUSH_ZERO_ON;
459                         }
460                 }
461                 break;
462         }
463
464         _mm_setcsr (MXCSR);
465
466 #endif
467 }
468
469 /* this can be changed to modify the translation behaviour for
470    cases where the user has never expressed a preference.
471 */
472 static const bool translate_by_default = true;
473
474 string
475 ARDOUR::translation_enable_path ()
476 {
477         return Glib::build_filename (user_config_directory(), ".translate");
478 }
479
480 bool
481 ARDOUR::translations_are_enabled ()
482 {
483         if (Glib::file_test (translation_enable_path(), Glib::FILE_TEST_EXISTS)) {
484                 return true;
485         } 
486
487         return translate_by_default;
488 }
489
490 bool
491 ARDOUR::set_translations_enabled (bool yn)
492 {
493         string i18n_enabler = ARDOUR::translation_enable_path();
494
495         if (yn) {
496                 int fd = ::open (i18n_enabler.c_str(), O_RDONLY|O_CREAT, 0644);
497                 if (fd >= 0) {
498                         close (fd);
499                         return true;
500                 } 
501                 return false;
502         } 
503
504         return unlink (i18n_enabler.c_str()) == 0;
505 }
506
507
508 vector<SyncSource>
509 ARDOUR::get_available_sync_options ()
510 {
511         vector<SyncSource> ret;
512
513         ret.push_back (JACK);
514         ret.push_back (MTC);
515         ret.push_back (MIDIClock);
516         ret.push_back (LTC);
517
518         return ret;
519 }