"Ardour" -> PROGRAM_NAME change for libardour and setup for gtk2_ardour
[ardour2.git] / libs / ardour / globals.cc
blob9f3d99ead4e0edbee50b7a64072243dacc697205
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.
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
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>
33 #ifdef VST_SUPPORT
34 #include <fst.h>
35 #endif
37 #ifdef HAVE_AUDIOUNITS
38 #include "ardour/audio_unit.h"
39 #endif
41 #ifdef __SSE__
42 #include <xmmintrin.h>
43 #endif
45 #include <glibmm/fileutils.h>
46 #include <glibmm/miscutils.h>
48 #include <lrdf.h>
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"
57 #include "midi++/port.h"
58 #include "midi++/manager.h"
59 #include "midi++/mmc.h"
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/control_protocol_manager.h"
68 #include "ardour/debug.h"
69 #include "ardour/filesystem_paths.h"
70 #include "ardour/mix.h"
71 #include "ardour/playlist.h"
72 #include "ardour/plugin_manager.h"
73 #include "ardour/profile.h"
74 #include "ardour/region.h"
75 #include "ardour/rc_configuration.h"
76 #include "ardour/route_group.h"
77 #include "ardour/runtime_functions.h"
78 #include "ardour/session.h"
79 #include "ardour/session_event.h"
80 #include "ardour/source_factory.h"
81 #include "ardour/utils.h"
83 #include "audiographer/routines.h"
85 #if defined (__APPLE__)
86 #include <Carbon/Carbon.h> // For Gestalt
87 #endif
89 #include "i18n.h"
91 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
92 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
93 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
95 using namespace ARDOUR;
96 using namespace std;
97 using namespace PBD;
99 MIDI::Port *ARDOUR::default_mmc_port = 0;
100 MIDI::Port *ARDOUR::default_mtc_port = 0;
101 MIDI::Port *ARDOUR::default_midi_port = 0;
102 MIDI::Port *ARDOUR::default_midi_clock_port = 0;
104 compute_peak_t ARDOUR::compute_peak = 0;
105 find_peaks_t ARDOUR::find_peaks = 0;
106 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
107 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
108 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
110 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
112 void ARDOUR::setup_enum_writer ();
114 /* this is useful for quite a few things that want to check
115 if any bounds-related property has changed
117 PBD::PropertyChange ARDOUR::bounds_change;
119 namespace ARDOUR {
120 namespace Properties {
122 /* the envelope and fades are not scalar items and so
123 currently (2010/02) are not stored using Property.
124 However, these descriptors enable us to notify
125 about changes to them via PropertyChange.
127 Declared in ardour/audioregion.h ...
130 PBD::PropertyDescriptor<bool> fade_in;
131 PBD::PropertyDescriptor<bool> fade_out;
132 PBD::PropertyDescriptor<bool> envelope;
136 void
137 ARDOUR::make_property_quarks ()
139 Properties::fade_in.property_id = g_quark_from_static_string (X_("fade_in_FAKE"));
140 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_in_FAKE = %1\n", Properties::fade_in.property_id));
141 Properties::fade_out.property_id = g_quark_from_static_string (X_("fade_out_FAKE"));
142 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_out_FAKE = %1\n", Properties::fade_out.property_id));
143 Properties::envelope.property_id = g_quark_from_static_string (X_("envelope_FAKE"));
144 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope_FAKE = %1\n", Properties::envelope.property_id));
148 ARDOUR::setup_midi ()
150 if (Config->midi_ports.size() == 0) {
151 return 0;
154 BootMessage (_("Configuring MIDI ports"));
156 for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
157 MIDI::Manager::instance()->add_port (i->second);
160 MIDI::Port* first;
161 const MIDI::Manager::PortList& ports = MIDI::Manager::instance()->get_midi_ports();
163 if (ports.size() > 1) {
165 first = ports.front();
167 /* More than one port, so try using specific names for each port */
169 default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name());
170 default_mtc_port = MIDI::Manager::instance()->port (Config->get_mtc_port_name());
171 default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_port_name());
172 default_midi_clock_port = MIDI::Manager::instance()->port (Config->get_midi_clock_port_name());
174 /* If that didn't work, just use the first listed port */
176 if (default_mmc_port == 0) {
177 default_mmc_port = first;
180 if (default_mtc_port == 0) {
181 default_mtc_port = first;
184 if (default_midi_port == 0) {
185 default_midi_port = first;
188 if (default_midi_clock_port == 0) {
189 default_midi_clock_port = first;
192 } else if (ports.size() == 1) {
194 first = ports.front();
196 /* Only one port described, so use it for both MTC and MMC */
198 default_mmc_port = first;
199 default_mtc_port = default_mmc_port;
200 default_midi_port = default_mmc_port;
201 default_midi_clock_port = default_mmc_port;
204 if (default_mmc_port == 0) {
205 warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name())
206 << endmsg;
210 if (default_mtc_port == 0) {
211 warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name())
212 << endmsg;
215 if (default_midi_port == 0) {
216 warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name())
217 << endmsg;
220 if (default_midi_clock_port == 0) {
221 warning << string_compose (_("No MIDI Clock support (MIDI port \"%1\" not available)"), Config->get_midi_clock_port_name())
222 << endmsg;
225 return 0;
228 void
229 setup_hardware_optimization (bool try_optimization)
231 bool generic_mix_functions = true;
233 if (try_optimization) {
235 FPU fpu;
237 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
239 if (fpu.has_sse()) {
241 info << "Using SSE optimized routines" << endmsg;
243 // SSE SET
244 compute_peak = x86_sse_compute_peak;
245 find_peaks = x86_sse_find_peaks;
246 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
247 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
248 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
250 generic_mix_functions = false;
254 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
255 long sysVersion = 0;
257 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
258 sysVersion = 0;
260 if (sysVersion >= 0x00001040) { // Tiger at least
261 compute_peak = veclib_compute_peak;
262 find_peaks = veclib_find_peaks;
263 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
264 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
265 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
267 generic_mix_functions = false;
269 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
271 #endif
273 /* consider FPU denormal handling to be "h/w optimization" */
275 setup_fpu ();
278 if (generic_mix_functions) {
280 compute_peak = default_compute_peak;
281 find_peaks = default_find_peaks;
282 apply_gain_to_buffer = default_apply_gain_to_buffer;
283 mix_buffers_with_gain = default_mix_buffers_with_gain;
284 mix_buffers_no_gain = default_mix_buffers_no_gain;
286 info << "No H/W specific optimizations in use" << endmsg;
289 AudioGrapher::Routines::override_compute_peak (compute_peak);
290 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
293 static void
294 lotsa_files_please ()
296 struct rlimit rl;
298 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
300 rl.rlim_cur = rl.rlim_max;
302 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
303 if (rl.rlim_cur == RLIM_INFINITY) {
304 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
305 } else {
306 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
308 } else {
309 if (rl.rlim_cur == RLIM_INFINITY) {
310 info << _("Removed open file count limit. Excellent!") << endmsg;
311 } else {
312 info << string_compose (_("%1 will be limited to %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
315 } else {
316 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
321 ARDOUR::init (bool use_vst, bool try_optimization)
323 if (!Glib::thread_supported()) {
324 Glib::thread_init();
327 (void) bindtextdomain(PACKAGE, LOCALEDIR);
329 PBD::ID::init ();
330 SessionEvent::init_event_pool ();
332 make_property_quarks ();
333 SessionObject::make_property_quarks ();
334 Region::make_property_quarks ();
335 AudioRegion::make_property_quarks ();
336 RouteGroup::make_property_quarks ();
337 Playlist::make_property_quarks ();
339 /* this is a useful ready to use PropertyChange that many
340 things need to check. This avoids having to compose
341 it every time we want to check for any of the relevant
342 property changes.
345 bounds_change.add (ARDOUR::Properties::start);
346 bounds_change.add (ARDOUR::Properties::position);
347 bounds_change.add (ARDOUR::Properties::length);
349 /* provide a state version for the few cases that need it and are not
350 driven by reading state from disk (e.g. undo/redo)
353 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
355 setup_enum_writer ();
357 // allow ardour the absolute maximum number of open files
358 lotsa_files_please ();
360 lrdf_init();
361 Library = new AudioLibrary;
363 BootMessage (_("Loading configuration"));
365 Config = new RCConfiguration;
367 if (Config->load_state ()) {
368 return -1;
372 Config->set_use_vst (use_vst);
374 cerr << "After config loaded, MTC port name = " << Config->get_mtc_port_name() << endl;
376 Profile = new RuntimeProfile;
379 #ifdef VST_SUPPORT
380 if (Config->get_use_vst() && fst_init (0)) {
381 return -1;
383 #endif
385 #ifdef HAVE_AUDIOUNITS
386 AUPluginInfo::load_cached_info ();
387 #endif
389 /* Make VAMP look in our library ahead of anything else */
391 char *p = getenv ("VAMP_PATH");
392 string vamppath = VAMP_DIR;
393 if (p) {
394 vamppath += ':';
395 vamppath += p;
397 setenv ("VAMP_PATH", vamppath.c_str(), 1);
400 setup_hardware_optimization (try_optimization);
402 SourceFactory::init ();
403 Analyser::init ();
405 /* singleton - first object is "it" */
406 new PluginManager ();
408 return 0;
411 void
412 ARDOUR::init_post_engine ()
414 ControlProtocolManager::instance().discover_control_protocols ();
416 XMLNode* node;
417 if ((node = Config->control_protocol_state()) != 0) {
418 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
423 ARDOUR::cleanup ()
425 delete Library;
426 lrdf_cleanup ();
427 delete &ControlProtocolManager::instance();
428 #ifdef VST_SUPPORT
429 fst_exit ();
430 #endif
431 return 0;
434 string
435 ARDOUR::get_ardour_revision ()
437 return "$Rev$";
440 void
441 ARDOUR::find_bindings_files (map<string,string>& files)
443 vector<sys::path> found;
444 SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
446 if (getenv ("ARDOUR_SAE")) {
447 Glib::PatternSpec pattern("*SAE-*.bindings");
448 find_matching_files_in_search_path (spath, pattern, found);
449 } else {
450 Glib::PatternSpec pattern("*.bindings");
451 find_matching_files_in_search_path (spath, pattern, found);
454 if (found.empty()) {
455 return;
458 for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
459 sys::path path = *x;
460 pair<string,string> namepath;
461 namepath.second = path.to_string();
462 namepath.first = path.leaf().substr (0, path.leaf().find_first_of ('.'));
463 files.insert (namepath);
467 bool
468 ARDOUR::no_auto_connect()
470 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
473 void
474 ARDOUR::setup_fpu ()
477 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
478 // valgrind doesn't understand this assembler stuff
479 // September 10th, 2007
480 return;
483 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
485 int MXCSR;
486 FPU fpu;
488 /* XXX use real code to determine if the processor supports
489 DenormalsAreZero and FlushToZero
492 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
493 return;
496 MXCSR = _mm_getcsr();
498 switch (Config->get_denormal_model()) {
499 case DenormalNone:
500 MXCSR &= ~(_MM_FLUSH_ZERO_ON|0x8000);
501 break;
503 case DenormalFTZ:
504 if (fpu.has_flush_to_zero()) {
505 MXCSR |= _MM_FLUSH_ZERO_ON;
507 break;
509 case DenormalDAZ:
510 MXCSR &= ~_MM_FLUSH_ZERO_ON;
511 if (fpu.has_denormals_are_zero()) {
512 MXCSR |= 0x8000;
514 break;
516 case DenormalFTZDAZ:
517 if (fpu.has_flush_to_zero()) {
518 if (fpu.has_denormals_are_zero()) {
519 MXCSR |= _MM_FLUSH_ZERO_ON | 0x8000;
520 } else {
521 MXCSR |= _MM_FLUSH_ZERO_ON;
524 break;
527 _mm_setcsr (MXCSR);
529 #endif
532 ARDOUR::OverlapType
533 ARDOUR::coverage (nframes_t sa, nframes_t ea,
534 nframes_t sb, nframes_t eb)
536 /* OverlapType returned reflects how the second (B)
537 range overlaps the first (A).
539 The diagrams show various relative placements
540 of A and B for each OverlapType.
542 Notes:
543 Internal: the start points cannot coincide
544 External: the start and end points can coincide
545 Start: end points can coincide
546 End: start points can coincide
548 XXX Logically, Internal should disallow end
549 point equality.
553 |--------------------| A
554 |------| B
555 |-----------------| B
558 "B is internal to A"
561 #ifdef OLD_COVERAGE
562 if ((sb >= sa) && (eb <= ea)) {
563 #else
564 if ((sb > sa) && (eb <= ea)) {
565 #endif
566 return OverlapInternal;
570 |--------------------| A
571 ----| B
572 -----------------------| B
573 --| B
575 "B overlaps the start of A"
579 if ((eb >= sa) && (eb <= ea)) {
580 return OverlapStart;
583 |---------------------| A
584 |----------------- B
585 |----------------------- B
586 |- B
588 "B overlaps the end of A"
591 if ((sb > sa) && (sb <= ea)) {
592 return OverlapEnd;
595 |--------------------| A
596 -------------------------- B
597 |----------------------- B
598 ----------------------| B
599 |--------------------| B
602 "B overlaps all of A"
604 if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
605 return OverlapExternal;
608 return OverlapNone;