Move panner bypass state up to the PannerShell so that it is preserved even when...
[ardour2.git] / libs / ardour / globals.cc
blob6e6dd7085673026f1c64f27264e6122cf36c3a32
1 /*
2 Copyright (C) 2000 Paul Davis
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.
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.
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.
19 #ifdef WAF_BUILD
20 #include "libardour-config.h"
21 #endif
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>
32 #ifdef VST_SUPPORT
33 #include <fst.h>
34 #endif
36 #ifdef HAVE_AUDIOUNITS
37 #include "ardour/audio_unit.h"
38 #endif
40 #ifdef __SSE__
41 #include <xmmintrin.h>
42 #endif
44 #include <glibmm/fileutils.h>
45 #include <glibmm/miscutils.h>
47 #include <lrdf.h>
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"
56 #include "midi++/port.h"
57 #include "midi++/manager.h"
58 #include "midi++/mmc.h"
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/dB.h"
69 #include "ardour/debug.h"
70 #include "ardour/filesystem_paths.h"
71 #include "ardour/midi_region.h"
72 #include "ardour/mix.h"
73 #include "ardour/audioplaylist.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/region.h"
79 #include "ardour/rc_configuration.h"
80 #include "ardour/route_group.h"
81 #include "ardour/runtime_functions.h"
82 #include "ardour/session.h"
83 #include "ardour/session_event.h"
84 #include "ardour/source_factory.h"
85 #include "ardour/utils.h"
87 #include "audiographer/routines.h"
89 #if defined (__APPLE__)
90 #include <Carbon/Carbon.h> // For Gestalt
91 #endif
93 #include "i18n.h"
95 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
96 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
97 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
99 using namespace ARDOUR;
100 using namespace std;
101 using namespace PBD;
103 compute_peak_t ARDOUR::compute_peak = 0;
104 find_peaks_t ARDOUR::find_peaks = 0;
105 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
106 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
107 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
109 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
111 void ARDOUR::setup_enum_writer ();
113 /* this is useful for quite a few things that want to check
114 if any bounds-related property has changed
116 PBD::PropertyChange ARDOUR::bounds_change;
118 namespace ARDOUR {
119 namespace Properties {
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.
126 Declared in ardour/audioregion.h ...
129 PBD::PropertyDescriptor<bool> fade_in;
130 PBD::PropertyDescriptor<bool> fade_out;
131 PBD::PropertyDescriptor<bool> envelope;
135 void
136 ARDOUR::make_property_quarks ()
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));
146 void
147 setup_hardware_optimization (bool try_optimization)
149 bool generic_mix_functions = true;
151 if (try_optimization) {
153 FPU fpu;
155 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
157 if (fpu.has_sse()) {
159 info << "Using SSE optimized routines" << endmsg;
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;
169 generic_mix_functions = false;
173 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
174 long sysVersion = 0;
176 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
177 sysVersion = 0;
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;
186 generic_mix_functions = false;
188 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
190 #endif
192 /* consider FPU denormal handling to be "h/w optimization" */
194 setup_fpu ();
197 if (generic_mix_functions) {
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;
205 info << "No H/W specific optimizations in use" << endmsg;
208 AudioGrapher::Routines::override_compute_peak (compute_peak);
209 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
212 static void
213 lotsa_files_please ()
215 struct rlimit rl;
217 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
219 rl.rlim_cur = rl.rlim_max;
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;
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;
234 } else {
235 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
240 ARDOUR::init (bool use_vst, bool try_optimization)
242 if (!Glib::thread_supported()) {
243 Glib::thread_init();
246 (void) bindtextdomain(PACKAGE, LOCALEDIR);
248 PBD::ID::init ();
249 SessionEvent::init_event_pool ();
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 ();
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.
266 bounds_change.add (ARDOUR::Properties::start);
267 bounds_change.add (ARDOUR::Properties::position);
268 bounds_change.add (ARDOUR::Properties::length);
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)
274 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
276 setup_enum_writer ();
278 // allow ardour the absolute maximum number of open files
279 lotsa_files_please ();
281 lrdf_init();
282 Library = new AudioLibrary;
284 BootMessage (_("Loading configuration"));
286 Config = new RCConfiguration;
288 if (Config->load_state ()) {
289 return -1;
292 Config->set_use_vst (use_vst);
294 Profile = new RuntimeProfile;
297 #ifdef VST_SUPPORT
298 if (Config->get_use_vst() && fst_init (0)) {
299 return -1;
301 #endif
303 #ifdef HAVE_AUDIOUNITS
304 AUPluginInfo::load_cached_info ();
305 #endif
307 /* Make VAMP look in our library ahead of anything else */
309 char *p = getenv ("VAMP_PATH");
310 string vamppath = VAMP_DIR;
311 if (p) {
312 vamppath += ':';
313 vamppath += p;
315 setenv ("VAMP_PATH", vamppath.c_str(), 1);
318 setup_hardware_optimization (try_optimization);
320 SourceFactory::init ();
321 Analyser::init ();
323 /* singleton - first object is "it" */
324 new PluginManager ();
326 ProcessThread::init ();
327 BufferManager::init (10); // XX should be num_processors_for_dsp
329 PannerManager::instance().discover_panners();
331 return 0;
334 void
335 ARDOUR::init_post_engine ()
337 /* the MIDI Manager is needed by the ControlProtocolManager */
338 MIDI::Manager::create (AudioEngine::instance()->jack());
340 ControlProtocolManager::instance().discover_control_protocols ();
342 XMLNode* node;
343 if ((node = Config->control_protocol_state()) != 0) {
344 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
349 ARDOUR::cleanup ()
351 delete Library;
352 lrdf_cleanup ();
353 delete &ControlProtocolManager::instance();
354 #ifdef VST_SUPPORT
355 fst_exit ();
356 #endif
357 return 0;
360 void
361 ARDOUR::find_bindings_files (map<string,string>& files)
363 vector<sys::path> found;
364 SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
366 if (getenv ("ARDOUR_SAE")) {
367 Glib::PatternSpec pattern("*SAE-*.bindings");
368 find_matching_files_in_search_path (spath, pattern, found);
369 } else {
370 Glib::PatternSpec pattern("*.bindings");
371 find_matching_files_in_search_path (spath, pattern, found);
374 if (found.empty()) {
375 return;
378 for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
379 sys::path path = *x;
380 pair<string,string> namepath;
381 namepath.second = path.to_string();
382 namepath.first = path.leaf().substr (0, path.leaf().find_first_of ('.'));
383 files.insert (namepath);
387 bool
388 ARDOUR::no_auto_connect()
390 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
393 void
394 ARDOUR::setup_fpu ()
397 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
398 // valgrind doesn't understand this assembler stuff
399 // September 10th, 2007
400 return;
403 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
405 int MXCSR;
406 FPU fpu;
408 /* XXX use real code to determine if the processor supports
409 DenormalsAreZero and FlushToZero
412 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
413 return;
416 MXCSR = _mm_getcsr();
418 switch (Config->get_denormal_model()) {
419 case DenormalNone:
420 MXCSR &= ~(_MM_FLUSH_ZERO_ON|0x8000);
421 break;
423 case DenormalFTZ:
424 if (fpu.has_flush_to_zero()) {
425 MXCSR |= _MM_FLUSH_ZERO_ON;
427 break;
429 case DenormalDAZ:
430 MXCSR &= ~_MM_FLUSH_ZERO_ON;
431 if (fpu.has_denormals_are_zero()) {
432 MXCSR |= 0x8000;
434 break;
436 case DenormalFTZDAZ:
437 if (fpu.has_flush_to_zero()) {
438 if (fpu.has_denormals_are_zero()) {
439 MXCSR |= _MM_FLUSH_ZERO_ON | 0x8000;
440 } else {
441 MXCSR |= _MM_FLUSH_ZERO_ON;
444 break;
447 _mm_setcsr (MXCSR);
449 #endif
452 ARDOUR::OverlapType
453 ARDOUR::coverage (framepos_t sa, framepos_t ea,
454 framepos_t sb, framepos_t eb)
456 /* OverlapType returned reflects how the second (B)
457 range overlaps the first (A).
459 The diagrams show various relative placements
460 of A and B for each OverlapType.
462 Notes:
463 Internal: the start points cannot coincide
464 External: the start and end points can coincide
465 Start: end points can coincide
466 End: start points can coincide
468 XXX Logically, Internal should disallow end
469 point equality.
473 |--------------------| A
474 |------| B
475 |-----------------| B
478 "B is internal to A"
482 if ((sb > sa) && (eb <= ea)) {
483 return OverlapInternal;
487 |--------------------| A
488 ----| B
489 -----------------------| B
490 --| B
492 "B overlaps the start of A"
496 if ((eb >= sa) && (eb <= ea)) {
497 return OverlapStart;
500 |---------------------| A
501 |----------------- B
502 |----------------------- B
503 |- B
505 "B overlaps the end of A"
508 if ((sb > sa) && (sb <= ea)) {
509 return OverlapEnd;
512 |--------------------| A
513 -------------------------- B
514 |----------------------- B
515 ----------------------| B
516 |--------------------| B
519 "B overlaps all of A"
521 if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
522 return OverlapExternal;
525 return OverlapNone;
528 string
529 ARDOUR::translation_kill_path ()
531 return Glib::build_filename (user_config_directory().to_string(), ".love_is_the_language_of_audio");
534 bool
535 ARDOUR::translations_are_disabled ()
537 /* if file does not exist, we don't translate (bundled ardour only) */
538 return Glib::file_test (translation_kill_path(), Glib::FILE_TEST_EXISTS) == false;