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.
21 #include "libardour-config.h"
24 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
26 #include <sys/types.h>
28 #include <sys/resource.h>
37 #ifdef HAVE_AUDIOUNITS
38 #include "ardour/audio_unit.h"
42 #include <xmmintrin.h>
45 #include <glibmm/fileutils.h>
46 #include <glibmm/miscutils.h>
50 #include "pbd/error.h"
52 #include "pbd/strsplit.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/plugin_manager.h"
72 #include "ardour/profile.h"
73 #include "ardour/region.h"
74 #include "ardour/rc_configuration.h"
75 #include "ardour/route_group.h"
76 #include "ardour/runtime_functions.h"
77 #include "ardour/session.h"
78 #include "ardour/session_event.h"
79 #include "ardour/source_factory.h"
80 #include "ardour/utils.h"
82 #include "audiographer/routines.h"
84 #if defined (__APPLE__)
85 #include <Carbon/Carbon.h> // For Gestalt
90 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
91 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
92 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
94 using namespace ARDOUR;
98 uint64_t ARDOUR::debug_bits = 0x0;
100 MIDI::Port *ARDOUR::default_mmc_port = 0;
101 MIDI::Port *ARDOUR::default_mtc_port = 0;
102 MIDI::Port *ARDOUR::default_midi_port = 0;
103 MIDI::Port *ARDOUR::default_midi_clock_port = 0;
105 compute_peak_t ARDOUR::compute_peak = 0;
106 find_peaks_t ARDOUR::find_peaks = 0;
107 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
108 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
109 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
111 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
113 void ARDOUR::setup_enum_writer ();
115 /* this is useful for quite a few things that want to check
116 if any bounds-related property has changed
118 PBD::PropertyChange ARDOUR::bounds_change;
121 namespace Properties {
123 /* the envelope and fades are not scalar items and so
124 currently (2010/02) are not stored using Property.
125 However, these descriptors enable us to notify
126 about changes to them via PropertyChange.
128 Declared in ardour/audioregion.h ...
131 PBD::PropertyDescriptor<bool> fade_in;
132 PBD::PropertyDescriptor<bool> fade_out;
133 PBD::PropertyDescriptor<bool> envelope;
138 ARDOUR::make_property_quarks ()
140 Properties::fade_in.id = g_quark_from_static_string (X_("fade_in_FAKE"));
141 Properties::fade_out.id = g_quark_from_static_string (X_("fade_out_FAKE"));
142 Properties::envelope.id = g_quark_from_static_string (X_("envelope_FAKE"));
146 ARDOUR::setup_midi ()
148 if (Config->midi_ports.size() == 0) {
152 BootMessage (_("Configuring MIDI ports"));
154 for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
155 MIDI::Manager::instance()->add_port (i->second);
159 const MIDI::Manager::PortList& ports = MIDI::Manager::instance()->get_midi_ports();
161 if (ports.size() > 1) {
163 first = ports.front();
165 /* More than one port, so try using specific names for each port */
167 default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name());
168 default_mtc_port = MIDI::Manager::instance()->port (Config->get_mtc_port_name());
169 default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_port_name());
170 default_midi_clock_port = MIDI::Manager::instance()->port (Config->get_midi_clock_port_name());
172 /* If that didn't work, just use the first listed port */
174 if (default_mmc_port == 0) {
175 default_mmc_port = first;
178 if (default_mtc_port == 0) {
179 default_mtc_port = first;
182 if (default_midi_port == 0) {
183 default_midi_port = first;
186 if (default_midi_clock_port == 0) {
187 default_midi_clock_port = first;
190 } else if (ports.size() == 1) {
192 first = ports.front();
194 /* Only one port described, so use it for both MTC and MMC */
196 default_mmc_port = first;
197 default_mtc_port = default_mmc_port;
198 default_midi_port = default_mmc_port;
199 default_midi_clock_port = default_mmc_port;
202 if (default_mmc_port == 0) {
203 warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name())
208 if (default_mtc_port == 0) {
209 warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name())
213 if (default_midi_port == 0) {
214 warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name())
218 if (default_midi_clock_port == 0) {
219 warning << string_compose (_("No MIDI Clock support (MIDI port \"%1\" not available)"), Config->get_midi_clock_port_name())
227 setup_hardware_optimization (bool try_optimization)
229 bool generic_mix_functions = true;
231 if (try_optimization) {
235 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
239 info << "Using SSE optimized routines" << endmsg;
242 compute_peak = x86_sse_compute_peak;
243 find_peaks = x86_sse_find_peaks;
244 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
245 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
246 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
248 generic_mix_functions = false;
252 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
255 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
258 if (sysVersion >= 0x00001040) { // Tiger at least
259 compute_peak = veclib_compute_peak;
260 find_peaks = veclib_find_peaks;
261 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
262 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
263 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
265 generic_mix_functions = false;
267 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
271 /* consider FPU denormal handling to be "h/w optimization" */
276 if (generic_mix_functions) {
278 compute_peak = default_compute_peak;
279 find_peaks = default_find_peaks;
280 apply_gain_to_buffer = default_apply_gain_to_buffer;
281 mix_buffers_with_gain = default_mix_buffers_with_gain;
282 mix_buffers_no_gain = default_mix_buffers_no_gain;
284 info << "No H/W specific optimizations in use" << endmsg;
287 AudioGrapher::Routines::override_compute_peak (compute_peak);
288 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
292 lotsa_files_please ()
296 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
298 rl.rlim_cur = rl.rlim_max;
300 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
301 if (rl.rlim_cur == RLIM_INFINITY) {
302 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
304 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
307 if (rl.rlim_cur == RLIM_INFINITY) {
308 info << _("Removed open file count limit. Excellent!") << endmsg;
310 info << string_compose (_("Ardour will be limited to %1 open files"), rl.rlim_cur) << endmsg;
314 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
319 ARDOUR::init (bool use_vst, bool try_optimization)
321 if (!Glib::thread_supported()) {
325 (void) bindtextdomain(PACKAGE, LOCALEDIR);
328 SessionEvent::init_event_pool ();
330 make_property_quarks ();
331 SessionObject::make_property_quarks ();
332 Region::make_property_quarks ();
333 AudioRegion::make_property_quarks ();
334 RouteGroup::make_property_quarks ();
336 /* this is a useful ready to use PropertyChange that many
337 things need to check. This avoids having to compose
338 it every time we want to check for any of the relevant
342 bounds_change.add (ARDOUR::Properties::start);
343 bounds_change.add (ARDOUR::Properties::position);
344 bounds_change.add (ARDOUR::Properties::length);
346 /* provide a state version for the few cases that need it and are not
347 driven by reading state from disk (e.g. undo/redo)
350 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
352 setup_enum_writer ();
354 // allow ardour the absolute maximum number of open files
355 lotsa_files_please ();
358 Library = new AudioLibrary;
360 BootMessage (_("Loading configuration"));
362 Config = new RCConfiguration;
364 if (Config->load_state ()) {
369 Config->set_use_vst (use_vst);
371 cerr << "After config loaded, MTC port name = " << Config->get_mtc_port_name() << endl;
373 Profile = new RuntimeProfile;
377 if (Config->get_use_vst() && fst_init (0)) {
382 #ifdef HAVE_AUDIOUNITS
383 AUPluginInfo::load_cached_info ();
386 /* Make VAMP look in our library ahead of anything else */
388 char *p = getenv ("VAMP_PATH");
389 string vamppath = VAMP_DIR;
394 setenv ("VAMP_PATH", vamppath.c_str(), 1);
397 setup_hardware_optimization (try_optimization);
399 SourceFactory::init ();
402 /* singleton - first object is "it" */
403 new PluginManager ();
409 ARDOUR::init_post_engine ()
411 ControlProtocolManager::instance().discover_control_protocols ();
414 if ((node = Config->control_protocol_state()) != 0) {
415 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
424 delete &ControlProtocolManager::instance();
432 ARDOUR::get_ardour_revision ()
438 ARDOUR::find_bindings_files (map<string,string>& files)
440 vector<sys::path> found;
441 SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
443 if (getenv ("ARDOUR_SAE")) {
444 Glib::PatternSpec pattern("*SAE-*.bindings");
445 find_matching_files_in_search_path (spath, pattern, found);
447 Glib::PatternSpec pattern("*.bindings");
448 find_matching_files_in_search_path (spath, pattern, found);
455 for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
457 pair<string,string> namepath;
458 namepath.second = path.to_string();
459 namepath.first = path.leaf().substr (0, path.leaf().find_first_of ('.'));
460 files.insert (namepath);
465 ARDOUR::no_auto_connect()
467 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
474 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
475 // valgrind doesn't understand this assembler stuff
476 // September 10th, 2007
480 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
485 /* XXX use real code to determine if the processor supports
486 DenormalsAreZero and FlushToZero
489 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
493 MXCSR = _mm_getcsr();
495 switch (Config->get_denormal_model()) {
497 MXCSR &= ~(_MM_FLUSH_ZERO_ON|0x8000);
501 if (fpu.has_flush_to_zero()) {
502 MXCSR |= _MM_FLUSH_ZERO_ON;
507 MXCSR &= ~_MM_FLUSH_ZERO_ON;
508 if (fpu.has_denormals_are_zero()) {
514 if (fpu.has_flush_to_zero()) {
515 if (fpu.has_denormals_are_zero()) {
516 MXCSR |= _MM_FLUSH_ZERO_ON | 0x8000;
518 MXCSR |= _MM_FLUSH_ZERO_ON;
530 ARDOUR::coverage (nframes_t sa, nframes_t ea,
531 nframes_t sb, nframes_t eb)
533 /* OverlapType returned reflects how the second (B)
534 range overlaps the first (A).
536 The diagrams show various relative placements
537 of A and B for each OverlapType.
540 Internal: the start points cannot coincide
541 External: the start and end points can coincide
542 Start: end points can coincide
543 End: start points can coincide
545 XXX Logically, Internal should disallow end
550 |--------------------| A
552 |-----------------| B
559 if ((sb >= sa) && (eb <= ea)) {
561 if ((sb > sa) && (eb <= ea)) {
563 return OverlapInternal;
567 |--------------------| A
569 -----------------------| B
572 "B overlaps the start of A"
576 if ((eb >= sa) && (eb <= ea)) {
580 |---------------------| A
582 |----------------------- B
585 "B overlaps the end of A"
588 if ((sb > sa) && (sb <= ea)) {
592 |--------------------| A
593 -------------------------- B
594 |----------------------- B
595 ----------------------| B
596 |--------------------| B
599 "B overlaps all of A"
601 if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
602 return OverlapExternal;