major redesign of MIDI port heirarchy and management (part 2)
[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 <cstdlib>
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>
32
33 #ifdef WINDOWS_VST_SUPPORT
34 #include <fst.h>
35 #endif
36
37 #ifdef LXVST_SUPPORT
38 #include "ardour/linux_vst_support.h"
39 #endif
40
41 #ifdef AUDIOUNIT_SUPPORT
42 #include "ardour/audio_unit.h"
43 #endif
44
45 #ifdef __SSE__
46 #include <xmmintrin.h>
47 #endif
48
49 #ifdef check
50 #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
51 #endif 
52
53 #include <giomm.h>
54
55 #include <glibmm/fileutils.h>
56 #include <glibmm/miscutils.h>
57
58 #include <lrdf.h>
59
60 #include "pbd/cpus.h"
61 #include "pbd/error.h"
62 #include "pbd/id.h"
63 #include "pbd/strsplit.h"
64 #include "pbd/fpu.h"
65 #include "pbd/file_utils.h"
66 #include "pbd/enumwriter.h"
67 #include "pbd/basename.h"
68
69 #include "midi++/port.h"
70 #include "midi++/mmc.h"
71
72 #include "ardour/analyser.h"
73 #include "ardour/audio_library.h"
74 #include "ardour/audio_backend.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audioplaylist.h"
77 #include "ardour/audioregion.h"
78 #include "ardour/buffer_manager.h"
79 #include "ardour/control_protocol_manager.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/midi_region.h"
82 #include "ardour/midiport_manager.h"
83 #include "ardour/mix.h"
84 #include "ardour/panner_manager.h"
85 #include "ardour/plugin_manager.h"
86 #include "ardour/process_thread.h"
87 #include "ardour/profile.h"
88 #include "ardour/rc_configuration.h"
89 #include "ardour/region.h"
90 #include "ardour/route_group.h"
91 #include "ardour/runtime_functions.h"
92 #include "ardour/session_event.h"
93 #include "ardour/source_factory.h"
94
95 #include "audiographer/routines.h"
96
97 #if defined (__APPLE__)
98        #include <Carbon/Carbon.h> // For Gestalt
99 #endif
100
101 #include "i18n.h"
102
103 ARDOUR::RCConfiguration* ARDOUR::Config = 0;
104 ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
105 ARDOUR::AudioLibrary* ARDOUR::Library = 0;
106
107 using namespace ARDOUR;
108 using namespace std;
109 using namespace PBD;
110
111 compute_peak_t          ARDOUR::compute_peak = 0;
112 find_peaks_t            ARDOUR::find_peaks = 0;
113 apply_gain_to_buffer_t  ARDOUR::apply_gain_to_buffer = 0;
114 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
115 mix_buffers_no_gain_t   ARDOUR::mix_buffers_no_gain = 0;
116
117 PBD::Signal1<void,std::string> ARDOUR::BootMessage;
118 PBD::Signal0<void> ARDOUR::GUIIdle;
119
120 namespace ARDOUR {
121 extern void setup_enum_writer ();
122 }
123
124 /* this is useful for quite a few things that want to check
125    if any bounds-related property has changed
126 */
127 PBD::PropertyChange ARDOUR::bounds_change;
128
129 void
130 setup_hardware_optimization (bool try_optimization)
131 {
132         bool generic_mix_functions = true;
133
134         if (try_optimization) {
135
136                 FPU fpu;
137
138 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
139
140                 if (fpu.has_sse()) {
141
142                         info << "Using SSE optimized routines" << endmsg;
143
144                         // SSE SET
145                         compute_peak          = x86_sse_compute_peak;
146                         find_peaks            = x86_sse_find_peaks;
147                         apply_gain_to_buffer  = x86_sse_apply_gain_to_buffer;
148                         mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
149                         mix_buffers_no_gain   = x86_sse_mix_buffers_no_gain;
150
151                         generic_mix_functions = false;
152
153                 }
154
155 #elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
156                 SInt32 sysVersion = 0;
157
158                 if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
159                         sysVersion = 0;
160
161                 if (sysVersion >= 0x00001040) { // Tiger at least
162                         compute_peak           = veclib_compute_peak;
163                         find_peaks             = veclib_find_peaks;
164                         apply_gain_to_buffer   = veclib_apply_gain_to_buffer;
165                         mix_buffers_with_gain  = veclib_mix_buffers_with_gain;
166                         mix_buffers_no_gain    = veclib_mix_buffers_no_gain;
167
168                         generic_mix_functions = false;
169
170                         info << "Apple VecLib H/W specific optimizations in use" << endmsg;
171                 }
172 #endif
173
174                 /* consider FPU denormal handling to be "h/w optimization" */
175
176                 setup_fpu ();
177         }
178
179         if (generic_mix_functions) {
180
181                 compute_peak          = default_compute_peak;
182                 find_peaks            = default_find_peaks;
183                 apply_gain_to_buffer  = default_apply_gain_to_buffer;
184                 mix_buffers_with_gain = default_mix_buffers_with_gain;
185                 mix_buffers_no_gain   = default_mix_buffers_no_gain;
186
187                 info << "No H/W specific optimizations in use" << endmsg;
188         }
189
190         AudioGrapher::Routines::override_compute_peak (compute_peak);
191         AudioGrapher::Routines::override_apply_gain_to_buffer (apply_gain_to_buffer);
192 }
193
194 static void
195 lotsa_files_please ()
196 {
197         struct rlimit rl;
198
199         if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
200
201                 rl.rlim_cur = rl.rlim_max;
202
203                 if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
204                         if (rl.rlim_cur == RLIM_INFINITY) {
205                                 error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
206                         } else {
207                                 error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
208                         }
209                 } else {
210                         if (rl.rlim_cur != RLIM_INFINITY) {
211                                 info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, rl.rlim_cur) << endmsg;
212                         }
213                 }
214         } else {
215                 error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
216         }
217 }
218
219 int
220 ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
221 {
222         if (!Glib::thread_supported()) {
223                 Glib::thread_init();
224         }
225
226         // this really should be in PBD::init..if there was one
227         Gio::init ();
228
229 #ifdef ENABLE_NLS
230         (void) bindtextdomain(PACKAGE, localedir);
231 #endif
232
233         PBD::ID::init ();
234         SessionEvent::init_event_pool ();
235
236         SessionObject::make_property_quarks ();
237         Region::make_property_quarks ();
238         MidiRegion::make_property_quarks ();
239         AudioRegion::make_property_quarks ();
240         RouteGroup::make_property_quarks ();
241         Playlist::make_property_quarks ();
242         AudioPlaylist::make_property_quarks ();
243
244         /* this is a useful ready to use PropertyChange that many
245            things need to check. This avoids having to compose
246            it every time we want to check for any of the relevant
247            property changes.
248         */
249
250         bounds_change.add (ARDOUR::Properties::start);
251         bounds_change.add (ARDOUR::Properties::position);
252         bounds_change.add (ARDOUR::Properties::length);
253
254         /* provide a state version for the few cases that need it and are not
255            driven by reading state from disk (e.g. undo/redo)
256         */
257
258         Stateful::current_state_version = CURRENT_SESSION_FILE_VERSION;
259
260         ARDOUR::setup_enum_writer ();
261
262         // allow ardour the absolute maximum number of open files
263         lotsa_files_please ();
264
265         lrdf_init();
266         Library = new AudioLibrary;
267
268         BootMessage (_("Loading configuration"));
269
270         Config = new RCConfiguration;
271
272         if (Config->load_state ()) {
273                 return -1;
274         }
275
276         Config->set_use_windows_vst (use_windows_vst);
277 #ifdef LXVST_SUPPORT
278         Config->set_use_lxvst(true);
279 #endif
280
281         Profile = new RuntimeProfile;
282
283
284 #ifdef WINDOWS_VST_SUPPORT
285         if (Config->get_use_windows_vst() && fst_init (0)) {
286                 return -1;
287         }
288 #endif
289
290 #ifdef LXVST_SUPPORT
291         if (Config->get_use_lxvst() && vstfx_init (0)) {
292                 return -1;
293         }
294 #endif
295
296 #ifdef AUDIOUNIT_SUPPORT
297         AUPluginInfo::load_cached_info ();
298 #endif
299
300         setup_hardware_optimization (try_optimization);
301
302         SourceFactory::init ();
303         Analyser::init ();
304
305         /* singleton - first object is "it" */
306         (void) PluginManager::instance();
307
308         ProcessThread::init ();
309         /* the + 4 is a bit of a handwave. i don't actually know
310            how many more per-thread buffer sets we need above
311            the h/w concurrency, but its definitely > 1 more.
312         */
313         BufferManager::init (hardware_concurrency() + 4); 
314
315         PannerManager::instance().discover_panners();
316
317         // Initialize parameter metadata
318         EventTypeMap::instance().new_parameter(NullAutomation);
319         EventTypeMap::instance().new_parameter(GainAutomation);
320         EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
321         EventTypeMap::instance().new_parameter(PanElevationAutomation);
322         EventTypeMap::instance().new_parameter(PanWidthAutomation);
323         EventTypeMap::instance().new_parameter(PluginAutomation);
324         EventTypeMap::instance().new_parameter(SoloAutomation);
325         EventTypeMap::instance().new_parameter(MuteAutomation);
326         EventTypeMap::instance().new_parameter(MidiCCAutomation);
327         EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
328         EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
329         EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
330         EventTypeMap::instance().new_parameter(FadeInAutomation);
331         EventTypeMap::instance().new_parameter(FadeOutAutomation);
332         EventTypeMap::instance().new_parameter(EnvelopeAutomation);
333         EventTypeMap::instance().new_parameter(MidiCCAutomation);
334
335         ARDOUR::AudioEngine::create ();
336
337         return 0;
338 }
339
340 void
341 ARDOUR::init_post_engine ()
342 {
343         ControlProtocolManager::instance().discover_control_protocols ();
344
345         XMLNode* node;
346         if ((node = Config->control_protocol_state()) != 0) {
347                 ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
348         }
349
350         /* find plugins */
351
352         ARDOUR::PluginManager::instance().refresh ();
353 }
354
355 int
356 ARDOUR::cleanup ()
357 {
358         delete Library;
359         lrdf_cleanup ();
360         delete &ControlProtocolManager::instance();
361 #ifdef WINDOWS_VST_SUPPORT
362         fst_exit ();
363 #endif
364
365 #ifdef LXVST_SUPPORT
366         vstfx_exit();
367 #endif
368         EnumWriter::destroy ();
369         return 0;
370 }
371
372 void
373 ARDOUR::find_bindings_files (map<string,string>& files)
374 {
375         vector<std::string> found;
376         SearchPath spath = ardour_config_search_path();
377
378         if (getenv ("ARDOUR_SAE")) {
379                 Glib::PatternSpec pattern("*SAE-*.bindings");
380                 find_matching_files_in_search_path (spath, pattern, found);
381         } else {
382                 Glib::PatternSpec pattern("*.bindings");
383                 find_matching_files_in_search_path (spath, pattern, found);
384         }
385
386         if (found.empty()) {
387                 return;
388         }
389
390         for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
391                 std::string path(*x);
392                 pair<string,string> namepath;
393                 namepath.second = path;
394                 namepath.first = PBD::basename_nosuffix (path);
395                 files.insert (namepath);
396         }
397 }
398
399 bool
400 ARDOUR::no_auto_connect()
401 {
402         return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
403 }
404
405 void
406 ARDOUR::setup_fpu ()
407 {
408
409         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
410                 // valgrind doesn't understand this assembler stuff
411                 // September 10th, 2007
412                 return;
413         }
414
415 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
416
417         int MXCSR;
418         FPU fpu;
419
420         /* XXX use real code to determine if the processor supports
421            DenormalsAreZero and FlushToZero
422         */
423
424         if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
425                 return;
426         }
427
428         MXCSR  = _mm_getcsr();
429
430 #ifdef DEBUG_DENORMAL_EXCEPTION
431         /* This will raise a FP exception if a denormal is detected */
432         MXCSR &= ~_MM_MASK_DENORM;
433 #endif  
434
435         switch (Config->get_denormal_model()) {
436         case DenormalNone:
437                 MXCSR &= ~(_MM_FLUSH_ZERO_ON | 0x40);
438                 break;
439
440         case DenormalFTZ:
441                 if (fpu.has_flush_to_zero()) {
442                         MXCSR |= _MM_FLUSH_ZERO_ON;
443                 }
444                 break;
445
446         case DenormalDAZ:
447                 MXCSR &= ~_MM_FLUSH_ZERO_ON;
448                 if (fpu.has_denormals_are_zero()) {
449                         MXCSR |= 0x40;
450                 }
451                 break;
452
453         case DenormalFTZDAZ:
454                 if (fpu.has_flush_to_zero()) {
455                         if (fpu.has_denormals_are_zero()) {
456                                 MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
457                         } else {
458                                 MXCSR |= _MM_FLUSH_ZERO_ON;
459                         }
460                 }
461                 break;
462         }
463
464         _mm_setcsr (MXCSR);
465
466 #endif
467 }
468
469 /* this can be changed to modify the translation behaviour for
470    cases where the user has never expressed a preference.
471 */
472 static const bool translate_by_default = true;
473
474 string
475 ARDOUR::translation_enable_path ()
476 {
477         return Glib::build_filename (user_config_directory(), ".translate");
478 }
479
480 bool
481 ARDOUR::translations_are_enabled ()
482 {
483         int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
484
485         if (fd < 0) {
486                 return translate_by_default;
487         }
488
489         char c;
490         bool ret = false;
491
492         if (::read (fd, &c, 1) == 1 && c == '1') {
493                 ret = true;
494         }
495
496         ::close (fd);
497
498         return ret;
499 }
500
501 bool
502 ARDOUR::set_translations_enabled (bool yn)
503 {
504         string i18n_enabler = ARDOUR::translation_enable_path();
505         int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
506
507         if (fd < 0) {
508                 return false;
509         }
510         
511         char c;
512         
513         if (yn) {
514                 c = '1';
515         } else {
516                 c = '0';
517         }
518         
519         ::write (fd, &c, 1);
520         ::close (fd);
521
522         return true;
523 }
524
525
526 vector<SyncSource>
527 ARDOUR::get_available_sync_options ()
528 {
529         vector<SyncSource> ret;
530
531         ret.push_back (JACK);
532         ret.push_back (MTC);
533         ret.push_back (MIDIClock);
534         ret.push_back (LTC);
535
536         return ret;
537 }