+string
+ARDOUR::auto_state_to_string (AutoState as)
+{
+ /* to be used only for XML serialization, no i18n done */
+
+ switch (as) {
+ case Off:
+ return X_("Off");
+ break;
+ case Play:
+ return X_("Play");
+ break;
+ case Write:
+ return X_("Write");
+ break;
+ case Touch:
+ return X_("Touch");
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as) << endmsg;
+ /*NOTREACHED*/
+ return "";
+}
+
+AutoStyle
+ARDOUR::string_to_auto_style (std::string str)
+{
+ if (str == X_("Absolute")) {
+ return Absolute;
+ } else if (str == X_("Trim")) {
+ return Trim;
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str) << endmsg;
+ /*NOTREACHED*/
+ return Trim;
+}
+
+string
+ARDOUR::auto_style_to_string (AutoStyle as)
+{
+ /* to be used only for XML serialization, no i18n done */
+
+ switch (as) {
+ case Absolute:
+ return X_("Absolute");
+ break;
+ case Trim:
+ return X_("Trim");
+ break;
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as) << endmsg;
+ /*NOTREACHED*/
+ return "";
+}
+
+std::string
+bool_as_string (bool yn)
+{
+ return (yn ? "yes" : "no");
+}
+
+const char*
+native_header_format_extension (HeaderFormat hf, const DataType& type)
+{
+ if (type == DataType::MIDI) {
+ return ".mid";
+ }
+
+ switch (hf) {
+ case BWF:
+ return ".wav";
+ case WAVE:
+ return ".wav";
+ case WAVE64:
+ return ".w64";
+ case CAF:
+ return ".caf";
+ case AIFF:
+ return ".aif";
+ case iXML:
+ return ".ixml";
+ case RF64:
+ return ".rf64";
+ }
+
+ fatal << string_compose (_("programming error: unknown native header format: %1"), hf);
+ /*NOTREACHED*/
+ return ".wav";
+}
+
+bool
+matching_unsuffixed_filename_exists_in (const string& dir, const string& path)
+{
+ string bws = basename_nosuffix (path);
+ struct dirent* dentry;
+ struct stat statbuf;
+ DIR* dead;
+ bool ret = false;
+
+ if ((dead = ::opendir (dir.c_str())) == 0) {
+ error << string_compose (_("cannot open directory %1 (%2)"), dir, strerror (errno)) << endl;
+ return false;
+ }
+
+ while ((dentry = ::readdir (dead)) != 0) {
+
+ /* avoid '.' and '..' */
+
+ if ((dentry->d_name[0] == '.' && dentry->d_name[1] == '\0') ||
+ (dentry->d_name[2] == '\0' && dentry->d_name[0] == '.' && dentry->d_name[1] == '.')) {
+ continue;
+ }
+
+ string fullpath = Glib::build_filename (dir, dentry->d_name);
+
+ if (::stat (fullpath.c_str(), &statbuf)) {
+ continue;
+ }
+
+ if (!S_ISREG (statbuf.st_mode)) {
+ continue;
+ }
+
+ string bws2 = basename_nosuffix (dentry->d_name);
+
+ if (bws2 == bws) {
+ ret = true;
+ break;
+ }
+ }
+
+ ::closedir (dead);
+ return ret;
+}
+
+uint32_t
+how_many_dsp_threads ()
+{
+ /* CALLER MUST HOLD PROCESS LOCK */
+
+ int num_cpu = hardware_concurrency();
+ int pu = Config->get_processor_usage ();
+ uint32_t num_threads = max (num_cpu - 1, 2); // default to number of cpus minus one, or 2, whichever is larger
+
+ if (pu < 0) {
+ /* pu is negative: use "pu" less cores for DSP than appear to be available
+ */
+
+ if (-pu < num_cpu) {
+ num_threads = num_cpu + pu;
+ }
+
+ } else if (pu == 0) {
+
+ /* use all available CPUs
+ */
+
+ num_threads = num_cpu;
+
+ } else {
+ /* use "pu" cores, if available
+ */
+
+ num_threads = min (num_cpu, pu);
+ }
+
+ return num_threads;
+}
+
+double gain_to_slider_position_with_max (double g, double max_gain)
+{
+ return gain_to_slider_position (g * 2.0/max_gain);
+}
+
+double slider_position_to_gain_with_max (double g, double max_gain)
+{
+ return slider_position_to_gain (g * max_gain/2.0);
+}
+
+extern "C" {
+ void c_stacktrace() { stacktrace (cerr); }
+}