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