#include <errno.h>
#include <time.h>
+#include <glib.h>
+#include "pbd/gstdio_compat.h"
+
+#ifdef PLATFORM_WINDOWS
+#include <stdio.h> // for _setmaxstdio
+#include <windows.h> // for LARGE_INTEGER
+#endif
+
#ifdef WINDOWS_VST_SUPPORT
#include <fst.h>
#endif
#ifdef check
#undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
-#endif
+#endif
#include <glibmm/fileutils.h>
#include <glibmm/miscutils.h>
#include "pbd/fpu.h"
#include "pbd/file_utils.h"
#include "pbd/enumwriter.h"
-#include "pbd/basename.h"
#include "midi++/port.h"
#include "midi++/mmc.h"
+#include "LuaBridge/LuaBridge.h"
+
#include "ardour/analyser.h"
#include "ardour/audio_library.h"
#include "ardour/audio_backend.h"
#include "ardour/audioregion.h"
#include "ardour/buffer_manager.h"
#include "ardour/control_protocol_manager.h"
+#include "ardour/directory_names.h"
+#include "ardour/event_type_map.h"
#include "ardour/filesystem_paths.h"
#include "ardour/midi_region.h"
+#include "ardour/midi_ui.h"
#include "ardour/midiport_manager.h"
#include "ardour/mix.h"
+#include "ardour/operations.h"
#include "ardour/panner_manager.h"
#include "ardour/plugin_manager.h"
+#include "ardour/presentation_info.h"
#include "ardour/process_thread.h"
#include "ardour/profile.h"
#include "ardour/rc_configuration.h"
#include "ardour/runtime_functions.h"
#include "ardour/session_event.h"
#include "ardour/source_factory.h"
-
+#ifdef LV2_SUPPORT
+#include "ardour/uri_map.h"
+#endif
#include "audiographer/routines.h"
#if defined (__APPLE__)
- #include <Carbon/Carbon.h> // For Gestalt
+#include <CoreFoundation/CoreFoundation.h>
#endif
-#include "i18n.h"
+#include "pbd/i18n.h"
ARDOUR::RCConfiguration* ARDOUR::Config = 0;
ARDOUR::RuntimeProfile* ARDOUR::Profile = 0;
apply_gain_to_buffer_t ARDOUR::apply_gain_to_buffer = 0;
mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0;
+copy_vector_t ARDOUR::copy_vector = 0;
PBD::Signal1<void,std::string> ARDOUR::BootMessage;
+PBD::Signal3<void,std::string,std::string,bool> ARDOUR::PluginScanMessage;
+PBD::Signal1<void,int> ARDOUR::PluginScanTimeout;
PBD::Signal0<void> ARDOUR::GUIIdle;
+PBD::Signal3<bool,std::string,std::string,int> ARDOUR::CopyConfigurationFiles;
+
+std::map<std::string, bool> ARDOUR::reserved_io_names;
+
+static bool have_old_configuration_files = false;
namespace ARDOUR {
extern void setup_enum_writer ();
if (try_optimization) {
- FPU fpu;
+ FPU* fpu = FPU::instance();
#if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
- if (fpu.has_sse()) {
+#ifdef PLATFORM_WINDOWS
+ /* We have AVX-optimized code for Windows */
+
+ if (fpu->has_avx()) {
+#else
+ /* AVX code doesn't compile on Linux yet */
+
+ if (false) {
+#endif
+ info << "Using AVX optimized routines" << endmsg;
+
+ // AVX SET
+ compute_peak = x86_sse_avx_compute_peak;
+ find_peaks = x86_sse_avx_find_peaks;
+ apply_gain_to_buffer = x86_sse_avx_apply_gain_to_buffer;
+ mix_buffers_with_gain = x86_sse_avx_mix_buffers_with_gain;
+ mix_buffers_no_gain = x86_sse_avx_mix_buffers_no_gain;
+ copy_vector = x86_sse_avx_copy_vector;
+
+ generic_mix_functions = false;
+
+ } else if (fpu->has_sse()) {
info << "Using SSE optimized routines" << endmsg;
apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
+ copy_vector = default_copy_vector;
generic_mix_functions = false;
}
#elif defined (__APPLE__) && defined (BUILD_VECLIB_OPTIMIZATIONS)
- SInt32 sysVersion = 0;
-
- if (noErr != Gestalt(gestaltSystemVersion, &sysVersion))
- sysVersion = 0;
- if (sysVersion >= 0x00001040) { // Tiger at least
+ if (floor (kCFCoreFoundationVersionNumber) > kCFCoreFoundationVersionNumber10_4) { /* at least Tiger */
compute_peak = veclib_compute_peak;
find_peaks = veclib_find_peaks;
apply_gain_to_buffer = veclib_apply_gain_to_buffer;
mix_buffers_with_gain = veclib_mix_buffers_with_gain;
mix_buffers_no_gain = veclib_mix_buffers_no_gain;
+ copy_vector = default_copy_vector;
generic_mix_functions = false;
apply_gain_to_buffer = default_apply_gain_to_buffer;
mix_buffers_with_gain = default_mix_buffers_with_gain;
mix_buffers_no_gain = default_mix_buffers_no_gain;
+ copy_vector = default_copy_vector;
info << "No H/W specific optimizations in use" << endmsg;
}
if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
+#ifdef __APPLE__
+ /* See the COMPATIBILITY note on the Apple setrlimit() man page */
+ rl.rlim_cur = min ((rlim_t) OPEN_MAX, rl.rlim_max);
+#else
rl.rlim_cur = rl.rlim_max;
+#endif
if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
if (rl.rlim_cur == RLIM_INFINITY) {
} else {
error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
}
+#else
+ /* this only affects stdio. 2048 is the maxium possible (512 the default).
+ *
+ * If we want more, we'll have to replaces the POSIX I/O interfaces with
+ * Win32 API calls (CreateFile, WriteFile, etc) which allows for 16K.
+ *
+ * see http://stackoverflow.com/questions/870173/is-there-a-limit-on-number-of-open-files-in-windows
+ * and http://bugs.mysql.com/bug.php?id=24509
+ */
+ int newmax = _setmaxstdio (2048);
+ if (newmax > 0) {
+ info << string_compose (_("Your system is configured to limit %1 to only %2 open files"), PROGRAM_NAME, newmax) << endmsg;
+ } else {
+ error << string_compose (_("Could not set system open files limit. Current limit is %1 open files"), _getmaxstdio()) << endmsg;
+ }
#endif
}
+static int
+copy_configuration_files (string const & old_dir, string const & new_dir, int old_version)
+{
+ string old_name;
+ string new_name;
+
+ /* ensure target directory exists */
+
+ if (g_mkdir_with_parents (new_dir.c_str(), 0755)) {
+ return -1;
+ }
+
+ if (old_version >= 3) {
+
+ old_name = Glib::build_filename (old_dir, X_("recent"));
+ new_name = Glib::build_filename (new_dir, X_("recent"));
+
+ copy_file (old_name, new_name);
+
+ old_name = Glib::build_filename (old_dir, X_("sfdb"));
+ new_name = Glib::build_filename (new_dir, X_("sfdb"));
+
+ copy_file (old_name, new_name);
+
+ /* can only copy ardour.rc/config - UI config is not compatible */
+
+ /* users who have been using git/nightlies since the last
+ * release of 3.5 will have $CONFIG/config rather than
+ * $CONFIG/ardour.rc. Pick up the newer "old" config file,
+ * to avoid confusion.
+ */
+
+ string old_name = Glib::build_filename (old_dir, X_("config"));
+
+ if (!Glib::file_test (old_name, Glib::FILE_TEST_EXISTS)) {
+ old_name = Glib::build_filename (old_dir, X_("ardour.rc"));
+ }
+
+ new_name = Glib::build_filename (new_dir, X_("config"));
+
+ copy_file (old_name, new_name);
+
+ /* copy templates and route templates */
+
+ old_name = Glib::build_filename (old_dir, X_("templates"));
+ new_name = Glib::build_filename (new_dir, X_("templates"));
+
+ copy_recurse (old_name, new_name);
+
+ old_name = Glib::build_filename (old_dir, X_("route_templates"));
+ new_name = Glib::build_filename (new_dir, X_("route_templates"));
+
+ copy_recurse (old_name, new_name);
+
+ /* presets */
+
+ old_name = Glib::build_filename (old_dir, X_("presets"));
+ new_name = Glib::build_filename (new_dir, X_("presets"));
+
+ copy_recurse (old_name, new_name);
+
+ /* presets */
+
+ old_name = Glib::build_filename (old_dir, X_("plugin_statuses"));
+ new_name = Glib::build_filename (new_dir, X_("plugin_statuses"));
+
+ copy_file (old_name, new_name);
+
+ /* export formats */
+
+ old_name = Glib::build_filename (old_dir, export_formats_dir_name);
+ new_name = Glib::build_filename (new_dir, export_formats_dir_name);
+
+ vector<string> export_formats;
+ g_mkdir_with_parents (Glib::build_filename (new_dir, export_formats_dir_name).c_str(), 0755);
+ find_files_matching_pattern (export_formats, old_name, X_("*.format"));
+ for (vector<string>::iterator i = export_formats.begin(); i != export_formats.end(); ++i) {
+ std::string from = *i;
+ std::string to = Glib::build_filename (new_name, Glib::path_get_basename (*i));
+ copy_file (from, to);
+ }
+ }
+
+ return 0;
+}
+
+void
+ARDOUR::check_for_old_configuration_files ()
+{
+ int current_version = atoi (X_(PROGRAM_VERSION));
+
+ if (current_version <= 1) {
+ return;
+ }
+
+ int old_version = current_version - 1;
+
+ string old_config_dir = user_config_directory (old_version);
+ /* pass in the current version explicitly to avoid creation */
+ string current_config_dir = user_config_directory (current_version);
+
+ if (!Glib::file_test (current_config_dir, Glib::FILE_TEST_IS_DIR)) {
+ if (Glib::file_test (old_config_dir, Glib::FILE_TEST_IS_DIR)) {
+ have_old_configuration_files = true;
+ }
+ }
+}
+
+int
+ARDOUR::handle_old_configuration_files (boost::function<bool (std::string const&, std::string const&, int)> ui_handler)
+{
+ if (have_old_configuration_files) {
+ int current_version = atoi (X_(PROGRAM_VERSION));
+ assert (current_version > 1); // established in check_for_old_configuration_files ()
+ int old_version = current_version - 1;
+ string old_config_dir = user_config_directory (old_version);
+ string current_config_dir = user_config_directory (current_version);
+
+ if (ui_handler (old_config_dir, current_config_dir, old_version)) {
+ copy_configuration_files (old_config_dir, current_config_dir, old_version);
+ return 1;
+ }
+ }
+ return 0;
+}
+
bool
ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
{
return true;
}
+#ifndef NDEBUG
+ if (getenv("LUA_METATABLES")) {
+ luabridge::Security::setHideMetatables (false);
+ }
+#endif
+
if (!PBD::init()) return false;
#ifdef ENABLE_NLS
(void) bindtextdomain(PACKAGE, localedir);
+ (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
#endif
SessionEvent::init_event_pool ();
+ Operations::make_operations_quarks ();
SessionObject::make_property_quarks ();
Region::make_property_quarks ();
MidiRegion::make_property_quarks ();
RouteGroup::make_property_quarks ();
Playlist::make_property_quarks ();
AudioPlaylist::make_property_quarks ();
+ PresentationInfo::make_property_quarks ();
/* this is a useful ready to use PropertyChange that many
things need to check. This avoids having to compose
SourceFactory::init ();
Analyser::init ();
- /* singleton - first object is "it" */
+ /* singletons - first object is "it" */
(void) PluginManager::instance();
+#ifdef LV2_SUPPORT
+ (void) URIMap::instance();
+#endif
+ (void) EventTypeMap::instance();
+
+ ControlProtocolManager::instance().discover_control_protocols ();
+
+ /* for each control protocol, check for a request buffer factory method
+ and if it exists, store it in the EventLoop list of such
+ methods. This allows the relevant threads to register themselves
+ with EventLoops so that signal emission can be RT-safe.
+ */
+
+ ControlProtocolManager::instance().register_request_buffer_factories ();
+ /* it would be nice if this could auto-register itself in the
+ constructor, since MidiControlUI is a singleton, but it can't be
+ created until after the engine is running. Therefore we have to
+ explicitly register it here.
+ */
+ EventLoop::register_request_buffer_factory (X_("midiUI"), MidiControlUI::request_factory);
ProcessThread::init ();
/* the + 4 is a bit of a handwave. i don't actually know
how many more per-thread buffer sets we need above
the h/w concurrency, but its definitely > 1 more.
*/
- BufferManager::init (hardware_concurrency() + 4);
+ BufferManager::init (hardware_concurrency() + 4);
PannerManager::instance().discover_panners();
- // Initialize parameter metadata
- EventTypeMap::instance().new_parameter(NullAutomation);
- EventTypeMap::instance().new_parameter(GainAutomation);
- EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
- EventTypeMap::instance().new_parameter(PanElevationAutomation);
- EventTypeMap::instance().new_parameter(PanWidthAutomation);
- EventTypeMap::instance().new_parameter(PluginAutomation);
- EventTypeMap::instance().new_parameter(SoloAutomation);
- EventTypeMap::instance().new_parameter(MuteAutomation);
- EventTypeMap::instance().new_parameter(MidiCCAutomation);
- EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
- EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
- EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
- EventTypeMap::instance().new_parameter(FadeInAutomation);
- EventTypeMap::instance().new_parameter(FadeOutAutomation);
- EventTypeMap::instance().new_parameter(EnvelopeAutomation);
- EventTypeMap::instance().new_parameter(MidiCCAutomation);
-
ARDOUR::AudioEngine::create ();
+ /* it is unfortunate that we need to include reserved names here that
+ refer to control surfaces. But there's no way to ensure a complete
+ lack of collisions without doing this, since the control surface
+ support may not even be active. Without adding an API to control
+ surface support that would list their port names, we do have to
+ list them here.
+
+ We also need to know if the given I/O is an actual route.
+ For routes (e.g. "master"), bus creation needs to be allowed the first time,
+ while for pure I/O (e.g. "Click") track/bus creation must always fail.
+ */
+
+ reserved_io_names[_("Monitor")] = true;
+ reserved_io_names[_("Master")] = true;
+ reserved_io_names["auditioner"] = true; // auditioner.cc Track (s, "auditioner",...)
+
+ /* pure I/O */
+ reserved_io_names[X_("Click")] = false; // session.cc ClickIO (*this, X_("Click")
+ reserved_io_names[_("Control")] = false;
+ reserved_io_names[_("Mackie")] = false;
+ reserved_io_names[_("FaderPort Recv")] = false;
+ reserved_io_names[_("FaderPort Send")] = false;
+ reserved_io_names[_("FaderPort8 Recv")] = false;
+ reserved_io_names[_("FaderPort8 Send")] = false;
+
libardour_initialized = true;
return true;
void
ARDOUR::init_post_engine ()
{
- ControlProtocolManager::instance().discover_control_protocols ();
-
XMLNode* node;
if ((node = Config->control_protocol_state()) != 0) {
ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
/* find plugins */
- ARDOUR::PluginManager::instance().refresh ();
+ ARDOUR::PluginManager::instance().refresh (!Config->get_discover_vst_on_start());
}
void
-ARDOUR::cleanup ()
+ARDOUR::cleanup ()
{
if (!libardour_initialized) {
return;
}
+ delete &ControlProtocolManager::instance();
ARDOUR::AudioEngine::destroy ();
delete Library;
#ifdef HAVE_LRDF
lrdf_cleanup ();
#endif
- delete &ControlProtocolManager::instance();
#ifdef WINDOWS_VST_SUPPORT
fst_exit ();
#endif
#ifdef LXVST_SUPPORT
vstfx_exit();
#endif
+ delete &PluginManager::instance();
+ delete Config;
PBD::cleanup ();
return;
}
-void
-ARDOUR::find_bindings_files (map<string,string>& files)
-{
- vector<std::string> found;
- Searchpath spath = ardour_config_search_path();
-
- if (getenv ("ARDOUR_SAE")) {
- Glib::PatternSpec pattern("*SAE-*.bindings");
- find_matching_files_in_search_path (spath, pattern, found);
- } else {
- Glib::PatternSpec pattern("*.bindings");
- find_matching_files_in_search_path (spath, pattern, found);
- }
-
- if (found.empty()) {
- return;
- }
-
- for (vector<std::string>::iterator x = found.begin(); x != found.end(); ++x) {
- std::string path(*x);
- pair<string,string> namepath;
- namepath.second = path;
- namepath.first = PBD::basename_nosuffix (path);
- files.insert (namepath);
- }
-}
-
bool
ARDOUR::no_auto_connect()
{
void
ARDOUR::setup_fpu ()
{
+ FPU* fpu = FPU::instance ();
if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
// valgrind doesn't understand this assembler stuff
#if defined(ARCH_X86) && defined(USE_XMMINTRIN)
int MXCSR;
- FPU fpu;
- /* XXX use real code to determine if the processor supports
- DenormalsAreZero and FlushToZero
- */
-
- if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
+ if (!fpu->has_flush_to_zero() && !fpu->has_denormals_are_zero()) {
return;
}
#ifdef DEBUG_DENORMAL_EXCEPTION
/* This will raise a FP exception if a denormal is detected */
MXCSR &= ~_MM_MASK_DENORM;
-#endif
+#endif
switch (Config->get_denormal_model()) {
case DenormalNone:
break;
case DenormalFTZ:
- if (fpu.has_flush_to_zero()) {
+ if (fpu->has_flush_to_zero()) {
MXCSR |= _MM_FLUSH_ZERO_ON;
}
break;
case DenormalDAZ:
MXCSR &= ~_MM_FLUSH_ZERO_ON;
- if (fpu.has_denormals_are_zero()) {
+ if (fpu->has_denormals_are_zero()) {
MXCSR |= 0x40;
}
break;
case DenormalFTZDAZ:
- if (fpu.has_flush_to_zero()) {
- if (fpu.has_denormals_are_zero()) {
+ if (fpu->has_flush_to_zero()) {
+ if (fpu->has_denormals_are_zero()) {
MXCSR |= _MM_FLUSH_ZERO_ON | 0x40;
} else {
MXCSR |= _MM_FLUSH_ZERO_ON;
bool
ARDOUR::translations_are_enabled ()
{
- int fd = ::open (ARDOUR::translation_enable_path().c_str(), O_RDONLY);
+ int fd = g_open (ARDOUR::translation_enable_path().c_str(), O_RDONLY, 0444);
if (fd < 0) {
return translate_by_default;
ARDOUR::set_translations_enabled (bool yn)
{
string i18n_enabler = ARDOUR::translation_enable_path();
- int fd = ::open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ int fd = g_open (i18n_enabler.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd < 0) {
return false;
}
-
+
char c;
-
+
if (yn) {
c = '1';
} else {
c = '0';
}
-
+
(void) ::write (fd, &c, 1);
(void) ::close (fd);
+ Config->ParameterChanged ("enable-translation");
return true;
}
#include <mach/mach_time.h>
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 0
-int
+int
clock_gettime (int /*clk_id*/, struct timespec *t)
{
static bool initialized = false;
return 0;
}
#endif
-
+
microseconds_t
ARDOUR::get_microseconds ()
{
return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);
#endif
}
+
+/** Return the number of bits per sample for a given sample format.
+ *
+ * This is closely related to sndfile_data_width() but does NOT
+ * return a "magic" value to differentiate between 32 bit integer
+ * and 32 bit floating point values.
+ */
+
+int
+ARDOUR::format_data_width (ARDOUR::SampleFormat format)
+{
+
+
+
+ switch (format) {
+ case ARDOUR::FormatInt16:
+ return 16;
+ case ARDOUR::FormatInt24:
+ return 24;
+ default:
+ return 32;
+ }
+}