111b824c28053f90566af452d350c22943000b94
[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
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
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 VST_SUPPORT
34 #include <fst.h>
35 #endif
36
37 #ifdef HAVE_AUDIOUNITS
38 #include "ardour/audio_unit.h"
39 #endif
40
41 #ifdef __SSE__
42 #include <xmmintrin.h>
43 #endif
44
45 #include <glibmm/fileutils.h>
46 #include <glibmm/miscutils.h>
47
48 #include <lrdf.h>
49
50 #include "pbd/error.h"
51 #include "pbd/id.h"
52 #include "pbd/strsplit.h"
53 #include "pbd/fpu.h"
54 #include "pbd/file_utils.h"
55 #include "pbd/enumwriter.h"
56
57 #include "midi++/port.h"
58 #include "midi++/manager.h"
59 #include "midi++/mmc.h"
60
61 #include "ardour/analyser.h"
62 #include "ardour/ardour.h"
63 #include "ardour/audio_library.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/audiosource.h"
67 #include "ardour/buffer_manager.h"
68 #include "ardour/control_protocol_manager.h"
69 #include "ardour/debug.h"
70 #include "ardour/filesystem_paths.h"
71 #include "ardour/mix.h"
72 #include "ardour/playlist.h"
73 #include "ardour/plugin_manager.h"
74 #include "ardour/process_thread.h"
75 #include "ardour/profile.h"
76 #include "ardour/region.h"
77 #include "ardour/rc_configuration.h"
78 #include "ardour/route_group.h"
79 #include "ardour/runtime_functions.h"
80 #include "ardour/session.h"
81 #include "ardour/session_event.h"
82 #include "ardour/source_factory.h"
83 #include "ardour/utils.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 void ARDOUR::setup_enum_writer ();
110
111 /* this is useful for quite a few things that want to check
112    if any bounds-related property has changed
113 */
114 PBD::PropertyChange ARDOUR::bounds_change;
115
116 namespace ARDOUR { 
117         namespace Properties {
118
119                 /* the envelope and fades are not scalar items and so
120                    currently (2010/02) are not stored using Property.
121                    However, these descriptors enable us to notify
122                    about changes to them via PropertyChange. 
123
124                    Declared in ardour/audioregion.h ...
125                 */
126
127                 PBD::PropertyDescriptor<bool> fade_in;
128                 PBD::PropertyDescriptor<bool> fade_out;
129                 PBD::PropertyDescriptor<bool> envelope;
130         }
131 }
132
133 void
134 ARDOUR::make_property_quarks ()
135 {
136         Properties::fade_in.property_id = g_quark_from_static_string (X_("fade_in_FAKE"));
137         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_in_FAKE = %1\n",        Properties::fade_in.property_id));
138         Properties::fade_out.property_id = g_quark_from_static_string (X_("fade_out_FAKE"));
139         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_out_FAKE = %1\n",       Properties::fade_out.property_id));
140         Properties::envelope.property_id = g_quark_from_static_string (X_("envelope_FAKE"));
141         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope_FAKE = %1\n",       Properties::envelope.property_id));
142 }
143
144 void
145 setup_hardware_optimization (bool try_optimization)
146 {
147         bool generic_mix_functions = true;
148
149         if (try_optimization) {
150
151                 FPU fpu;
152
153 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
154
155                 if (fpu.has_sse()) {
156
157                         info << "Using SSE optimized routines" << endmsg;
158
159                         // SSE SET
160                         compute_peak          = x86_sse_compute_peak;
161                         find_peaks            = x86_sse_find_peaks;
162                         apply_gain_to_buffer  = x86_sse_apply_gain_to_buffer;
163                         mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
164                         mix_buffers_no_gain   = x86_sse_mix_buffers_no_gain;
165
166                         generic_mix_functions = false;
167
168                 }
169
170 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
171                 long sysVersion = 0;
172
173                 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
174                         sysVersion = 0;
175
176                 if (sysVersion >= 0x00001040) { // Tiger at least
177                         compute_peak           = veclib_compute_peak;
178                         find_peaks             = veclib_find_peaks;
179                         apply_gain_to_buffer   = veclib_apply_gain_to_buffer;
180                         mix_buffers_with_gain  = veclib_mix_buffers_with_gain;
181                         mix_buffers_no_gain    = veclib_mix_buffers_no_gain;
182
183                         generic_mix_functions = false;
184
185                         info << "Apple VecLib H/W specific optimizations in use" << endmsg;
186                 }
187 #endif
188
189                 /* consider FPU denormal handling to be "h/w optimization" */
190
191                 setup_fpu ();
192         }
193
194         if (generic_mix_functions) {
195
196                 compute_peak          = default_compute_peak;
197                 find_peaks            = default_find_peaks;
198                 apply_gain_to_buffer  = default_apply_gain_to_buffer;
199                 mix_buffers_with_gain = default_mix_buffers_with_gain;
200                 mix_buffers_no_gain   = default_mix_buffers_no_gain;
201
202                 info << "No H/W specific optimizations in use" << endmsg;
203         }
204         
205         AudioGrapher::Routines::override_compute_peak (compute_peak);
206         AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
207 }
208
209 static void
210 lotsa_files_please ()
211 {
212         struct rlimit rl;
213
214         if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
215
216                 rl.rlim_cur = rl.rlim_max;
217
218                 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
219                         if (rl.rlim_cur == RLIM_INFINITY) {
220                                 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
221                         } else {
222                                 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
223                         }
224                 } else {
225                         if (rl.rlim_cur == RLIM_INFINITY) {
226                                 info << _("Removed open file count limit. Excellent!") << endmsg;
227                         } else {
228                                 info << string_compose (_("%1 will be limited to %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
229                         }
230                 }
231         } else {
232                 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
233         }
234 }
235
236 int
237 ARDOUR::init (bool use_vst, bool try_optimization)
238 {
239         if (!Glib::thread_supported()) {
240                 Glib::thread_init();
241         }
242
243         (void) bindtextdomain(PACKAGE, LOCALEDIR);
244
245         PBD::ID::init ();
246         SessionEvent::init_event_pool ();
247         
248         make_property_quarks ();
249         SessionObject::make_property_quarks ();
250         Region::make_property_quarks ();
251         AudioRegion::make_property_quarks ();
252         RouteGroup::make_property_quarks ();
253         Playlist::make_property_quarks ();
254
255         /* this is a useful ready to use PropertyChange that many
256            things need to check. This avoids having to compose
257            it every time we want to check for any of the relevant
258            property changes.
259         */
260
261         bounds_change.add (ARDOUR::Properties::start);
262         bounds_change.add (ARDOUR::Properties::position);
263         bounds_change.add (ARDOUR::Properties::length);
264
265         /* provide a state version for the few cases that need it and are not
266            driven by reading state from disk (e.g. undo/redo)
267         */
268
269         Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
270
271         setup_enum_writer ();
272
273         // allow ardour the absolute maximum number of open files
274         lotsa_files_please ();
275
276         lrdf_init();
277         Library = new AudioLibrary;
278
279         BootMessage (_("Loading configuration"));
280
281         Config = new RCConfiguration;
282
283         if (Config->load_state ()) {
284                 return -1;
285         }
286
287         
288         Config->set_use_vst (use_vst);
289
290         Profile = new RuntimeProfile;
291
292
293 #ifdef VST_SUPPORT
294         if (Config->get_use_vst() && fst_init (0)) {
295                 return -1;
296         }
297 #endif
298
299 #ifdef HAVE_AUDIOUNITS
300         AUPluginInfo::load_cached_info ();
301 #endif
302
303         /* Make VAMP look in our library ahead of anything else */
304
305         char *p = getenv ("VAMP_PATH");
306         string vamppath = VAMP_DIR;
307         if (p) {
308                 vamppath += ':';
309                 vamppath += p;
310         }
311         setenv ("VAMP_PATH", vamppath.c_str(), 1);
312
313
314         setup_hardware_optimization (try_optimization);
315
316         SourceFactory::init ();
317         Analyser::init ();
318
319         /* singleton - first object is "it" */
320         new PluginManager ();
321
322         ProcessThread::init ();
323         BufferManager::init (10); // XX should be num_processors_for_dsp
324
325         return 0;
326 }
327
328 void
329 ARDOUR::init_post_engine ()
330 {
331         ControlProtocolManager::instance().discover_control_protocols ();
332
333         XMLNode* node;
334         if ((node = Config->control_protocol_state()) != 0) {
335                 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
336         }
337 }
338
339 int
340 ARDOUR::cleanup ()
341 {
342         delete Library;
343         lrdf_cleanup ();
344         delete &ControlProtocolManager::instance();
345 #ifdef VST_SUPPORT
346         fst_exit ();
347 #endif
348         return 0;
349 }
350
351 string
352 ARDOUR::get_ardour_revision ()
353 {
354         return "$Rev$";
355 }
356
357 void
358 ARDOUR::find_bindings_files (map<string,string>& files)
359 {
360         vector<sys::path> found;
361         SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
362
363         if (getenv ("ARDOUR_SAE")) {
364                 Glib::PatternSpec pattern("*SAE-*.bindings");
365                 find_matching_files_in_search_path (spath, pattern, found);
366         } else {
367                 Glib::PatternSpec pattern("*.bindings");
368                 find_matching_files_in_search_path (spath, pattern, found);
369         }
370
371         if (found.empty()) {
372                 return;
373         }
374
375         for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
376                 sys::path path = *x;
377                 pair<string,string> namepath;
378                 namepath.second = path.to_string();
379                 namepath.first = path.leaf().substr (0, path.leaf().find_first_of ('.'));
380                 files.insert (namepath);
381         }
382 }
383
384 bool
385 ARDOUR::no_auto_connect()
386 {
387         return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
388 }
389
390 void
391 ARDOUR::setup_fpu ()
392 {
393
394         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
395                 // valgrind doesn't understand this assembler stuff
396                 // September 10th, 2007
397                 return;
398         }
399
400 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
401
402         int MXCSR;
403         FPU fpu;
404
405         /* XXX use real code to determine if the processor supports
406            DenormalsAreZero and FlushToZero
407         */
408
409         if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
410                 return;
411         }
412
413         MXCSR  = _mm_getcsr();
414
415         switch (Config->get_denormal_model()) {
416         case DenormalNone:
417                 MXCSR &= ~(_MM_FLUSH_ZERO_ON|0x8000);
418                 break;
419
420         case DenormalFTZ:
421                 if (fpu.has_flush_to_zero()) {
422                         MXCSR |= _MM_FLUSH_ZERO_ON;
423                 }
424                 break;
425
426         case DenormalDAZ:
427                 MXCSR &= ~_MM_FLUSH_ZERO_ON;
428                 if (fpu.has_denormals_are_zero()) {
429                         MXCSR |= 0x8000;
430                 }
431                 break;
432
433         case DenormalFTZDAZ:
434                 if (fpu.has_flush_to_zero()) {
435                         if (fpu.has_denormals_are_zero()) {
436                                 MXCSR |= _MM_FLUSH_ZERO_ON | 0x8000;
437                         } else {
438                                 MXCSR |= _MM_FLUSH_ZERO_ON;
439                         }
440                 }
441                 break;
442         }
443
444         _mm_setcsr (MXCSR);
445
446 #endif
447 }
448
449 ARDOUR::OverlapType
450 ARDOUR::coverage (framepos_t sa, framepos_t ea,
451                   framepos_t sb, framepos_t eb)
452 {
453         /* OverlapType returned reflects how the second (B)
454            range overlaps the first (A).
455
456            The diagrams show various relative placements
457            of A and B for each OverlapType.
458
459            Notes:
460               Internal: the start points cannot coincide
461               External: the start and end points can coincide
462               Start: end points can coincide
463               End: start points can coincide
464
465            XXX Logically, Internal should disallow end
466            point equality.
467         */
468
469         /*
470              |--------------------|   A
471                   |------|            B
472                 |-----------------|   B
473
474
475              "B is internal to A"
476
477         */
478
479         if ((sb > sa) && (eb <= ea)) {
480                 return OverlapInternal;
481         }
482
483         /*
484              |--------------------|   A
485            ----|                      B
486            -----------------------|   B
487            --|                        B
488
489              "B overlaps the start of A"
490
491         */
492
493         if ((eb >= sa) && (eb <= ea)) {
494                 return OverlapStart;
495         }
496         /*
497              |---------------------|  A
498                    |----------------- B
499              |----------------------- B
500                                    |- B
501
502             "B overlaps the end of A"
503
504         */
505         if ((sb > sa) && (sb <= ea)) {
506                 return OverlapEnd;
507         }
508         /*
509              |--------------------|     A
510            --------------------------  B
511              |-----------------------  B
512             ----------------------|    B
513              |--------------------|    B
514
515
516            "B overlaps all of A"
517         */
518         if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
519                 return OverlapExternal;
520         }
521
522         return OverlapNone;
523 }
524