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/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"
85 #include "audiographer/routines.h"
87 #if defined (__APPLE__)
88 #include <Carbon/Carbon.h> // For Gestalt
93 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
94 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
95 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
97 using namespace ARDOUR;
101 MIDI::Port *ARDOUR::default_mmc_port = 0;
102 MIDI::Port *ARDOUR::default_mtc_port = 0;
103 MIDI::Port *ARDOUR::default_midi_port = 0;
104 MIDI::Port *ARDOUR::default_midi_clock_port = 0;
106 compute_peak_t ARDOUR::compute_peak = 0;
107 find_peaks_t ARDOUR::find_peaks = 0;
108 apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
109 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
110 mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
112 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
114 void ARDOUR::setup_enum_writer ();
116 /* this is useful for quite a few things that want to check
117 if any bounds-related property has changed
119 PBD::PropertyChange ARDOUR::bounds_change;
122 namespace Properties {
124 /* the envelope and fades are not scalar items and so
125 currently (2010/02) are not stored using Property.
126 However, these descriptors enable us to notify
127 about changes to them via PropertyChange.
129 Declared in ardour/audioregion.h ...
132 PBD::PropertyDescriptor<bool> fade_in;
133 PBD::PropertyDescriptor<bool> fade_out;
134 PBD::PropertyDescriptor<bool> envelope;
139 ARDOUR::make_property_quarks ()
141 Properties::fade_in.property_id = g_quark_from_static_string (X_("fade_in_FAKE"));
142 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_in_FAKE = %1\n", Properties::fade_in.property_id));
143 Properties::fade_out.property_id = g_quark_from_static_string (X_("fade_out_FAKE"));
144 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_out_FAKE = %1\n", Properties::fade_out.property_id));
145 Properties::envelope.property_id = g_quark_from_static_string (X_("envelope_FAKE"));
146 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope_FAKE = %1\n", Properties::envelope.property_id));
150 ARDOUR::setup_midi ()
152 if (Config->midi_ports.size() == 0) {
156 BootMessage (_("Configuring MIDI ports"));
158 for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
159 MIDI::Manager::instance()->add_port (i->second);
163 const MIDI::Manager::PortList& ports = MIDI::Manager::instance()->get_midi_ports();
165 if (ports.size() > 1) {
167 first = ports.front();
169 /* More than one port, so try using specific names for each port */
171 default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name());
172 default_mtc_port = MIDI::Manager::instance()->port (Config->get_mtc_port_name());
173 default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_port_name());
174 default_midi_clock_port = MIDI::Manager::instance()->port (Config->get_midi_clock_port_name());
176 /* If that didn't work, just use the first listed port */
178 if (default_mmc_port == 0) {
179 default_mmc_port = first;
182 if (default_mtc_port == 0) {
183 default_mtc_port = first;
186 if (default_midi_port == 0) {
187 default_midi_port = first;
190 if (default_midi_clock_port == 0) {
191 default_midi_clock_port = first;
194 } else if (ports.size() == 1) {
196 first = ports.front();
198 /* Only one port described, so use it for both MTC and MMC */
200 default_mmc_port = first;
201 default_mtc_port = default_mmc_port;
202 default_midi_port = default_mmc_port;
203 default_midi_clock_port = default_mmc_port;
206 if (default_mmc_port == 0) {
207 warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name())
212 if (default_mtc_port == 0) {
213 warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name())
217 if (default_midi_port == 0) {
218 warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name())
222 if (default_midi_clock_port == 0) {
223 warning << string_compose (_("No MIDI Clock support (MIDI port \"%1\" not available)"), Config->get_midi_clock_port_name())
231 setup_hardware_optimization (bool try_optimization)
233 bool generic_mix_functions = true;
235 if (try_optimization) {
239 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
243 info << "Using SSE optimized routines" << endmsg;
246 compute_peak = x86_sse_compute_peak;
247 find_peaks = x86_sse_find_peaks;
248 apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
249 mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
250 mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
252 generic_mix_functions = false;
256 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
259 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
262 if (sysVersion >= 0x00001040) { // Tiger at least
263 compute_peak = veclib_compute_peak;
264 find_peaks = veclib_find_peaks;
265 apply_gain_to_buffer = veclib_apply_gain_to_buffer;
266 mix_buffers_with_gain = veclib_mix_buffers_with_gain;
267 mix_buffers_no_gain = veclib_mix_buffers_no_gain;
269 generic_mix_functions = false;
271 info << "Apple VecLib H/W specific optimizations in use" << endmsg;
275 /* consider FPU denormal handling to be "h/w optimization" */
280 if (generic_mix_functions) {
282 compute_peak = default_compute_peak;
283 find_peaks = default_find_peaks;
284 apply_gain_to_buffer = default_apply_gain_to_buffer;
285 mix_buffers_with_gain = default_mix_buffers_with_gain;
286 mix_buffers_no_gain = default_mix_buffers_no_gain;
288 info << "No H/W specific optimizations in use" << endmsg;
291 AudioGrapher::Routines::override_compute_peak (compute_peak);
292 AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
296 lotsa_files_please ()
300 if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
302 rl.rlim_cur = rl.rlim_max;
304 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
305 if (rl.rlim_cur == RLIM_INFINITY) {
306 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
308 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
311 if (rl.rlim_cur == RLIM_INFINITY) {
312 info << _("Removed open file count limit. Excellent!") << endmsg;
314 info << string_compose (_("%1 will be limited to %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
318 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
323 ARDOUR::init (bool use_vst, bool try_optimization)
325 if (!Glib::thread_supported()) {
329 (void) bindtextdomain(PACKAGE, LOCALEDIR);
332 SessionEvent::init_event_pool ();
334 make_property_quarks ();
335 SessionObject::make_property_quarks ();
336 Region::make_property_quarks ();
337 AudioRegion::make_property_quarks ();
338 RouteGroup::make_property_quarks ();
339 Playlist::make_property_quarks ();
341 /* this is a useful ready to use PropertyChange that many
342 things need to check. This avoids having to compose
343 it every time we want to check for any of the relevant
347 bounds_change.add (ARDOUR::Properties::start);
348 bounds_change.add (ARDOUR::Properties::position);
349 bounds_change.add (ARDOUR::Properties::length);
351 /* provide a state version for the few cases that need it and are not
352 driven by reading state from disk (e.g. undo/redo)
355 Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
357 setup_enum_writer ();
359 // allow ardour the absolute maximum number of open files
360 lotsa_files_please ();
363 Library = new AudioLibrary;
365 BootMessage (_("Loading configuration"));
367 Config = new RCConfiguration;
369 if (Config->load_state ()) {
374 Config->set_use_vst (use_vst);
376 cerr << "After config loaded, MTC port name = " << Config->get_mtc_port_name() << endl;
378 Profile = new RuntimeProfile;
382 if (Config->get_use_vst() && fst_init (0)) {
387 #ifdef HAVE_AUDIOUNITS
388 AUPluginInfo::load_cached_info ();
391 /* Make VAMP look in our library ahead of anything else */
393 char *p = getenv ("VAMP_PATH");
394 string vamppath = VAMP_DIR;
399 setenv ("VAMP_PATH", vamppath.c_str(), 1);
402 setup_hardware_optimization (try_optimization);
404 SourceFactory::init ();
407 /* singleton - first object is "it" */
408 new PluginManager ();
410 ProcessThread::init ();
411 BufferManager::init (10); // XX should be num_processors_for_dsp
417 ARDOUR::init_post_engine ()
419 ControlProtocolManager::instance().discover_control_protocols ();
422 if ((node = Config->control_protocol_state()) != 0) {
423 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
432 delete &ControlProtocolManager::instance();
440 ARDOUR::get_ardour_revision ()
446 ARDOUR::find_bindings_files (map<string,string>& files)
448 vector<sys::path> found;
449 SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
451 if (getenv ("ARDOUR_SAE")) {
452 Glib::PatternSpec pattern("*SAE-*.bindings");
453 find_matching_files_in_search_path (spath, pattern, found);
455 Glib::PatternSpec pattern("*.bindings");
456 find_matching_files_in_search_path (spath, pattern, found);
463 for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
465 pair<string,string> namepath;
466 namepath.second = path.to_string();
467 namepath.first = path.leaf().substr (0, path.leaf().find_first_of ('.'));
468 files.insert (namepath);
473 ARDOUR::no_auto_connect()
475 return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
482 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
483 // valgrind doesn't understand this assembler stuff
484 // September 10th, 2007
488 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
493 /* XXX use real code to determine if the processor supports
494 DenormalsAreZero and FlushToZero
497 if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
501 MXCSR = _mm_getcsr();
503 switch (Config->get_denormal_model()) {
505 MXCSR &= ~(_MM_FLUSH_ZERO_ON|0x8000);
509 if (fpu.has_flush_to_zero()) {
510 MXCSR |= _MM_FLUSH_ZERO_ON;
515 MXCSR &= ~_MM_FLUSH_ZERO_ON;
516 if (fpu.has_denormals_are_zero()) {
522 if (fpu.has_flush_to_zero()) {
523 if (fpu.has_denormals_are_zero()) {
524 MXCSR |= _MM_FLUSH_ZERO_ON | 0x8000;
526 MXCSR |= _MM_FLUSH_ZERO_ON;
538 ARDOUR::coverage (framepos_t sa, framepos_t ea,
539 framepos_t sb, framepos_t eb)
541 /* OverlapType returned reflects how the second (B)
542 range overlaps the first (A).
544 The diagrams show various relative placements
545 of A and B for each OverlapType.
548 Internal: the start points cannot coincide
549 External: the start and end points can coincide
550 Start: end points can coincide
551 End: start points can coincide
553 XXX Logically, Internal should disallow end
558 |--------------------| A
560 |-----------------| B
567 if ((sb > sa) && (eb <= ea)) {
568 return OverlapInternal;
572 |--------------------| A
574 -----------------------| B
577 "B overlaps the start of A"
581 if ((eb >= sa) && (eb <= ea)) {
585 |---------------------| A
587 |----------------------- B
590 "B overlaps the end of A"
593 if ((sb > sa) && (sb <= ea)) {
597 |--------------------| A
598 -------------------------- B
599 |----------------------- B
600 ----------------------| B
601 |--------------------| B
604 "B overlaps all of A"
606 if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
607 return OverlapExternal;