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