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