2 Copyright (C) 2000-2003 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"
26 #include <cstdio> /* for sprintf */
33 #include <sys/types.h>
40 #include <glibmm/miscutils.h>
41 #include <glibmm/fileutils.h>
48 #include "pbd/error.h"
49 #include "pbd/stacktrace.h"
50 #include "pbd/xml++.h"
51 #include "pbd/basename.h"
52 #include "pbd/strsplit.h"
54 #include "ardour/utils.h"
55 #include "ardour/rc_configuration.h"
59 using namespace ARDOUR
;
64 legalize_for_path (const string
& str
)
66 string::size_type pos
;
67 string illegal_chars
= "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
73 while ((pos
= legal
.find_first_of (illegal_chars
, pos
)) != string::npos
) {
74 legal
.replace (pos
, 1, "_");
82 bump_name_once (const std::string
& name
, char delimiter
)
84 string::size_type delim
;
87 if ((delim
= name
.find_last_of (delimiter
)) == string::npos
) {
93 const char *last_element
= name
.c_str() + delim
+ 1;
94 for (size_t i
= 0; i
< strlen(last_element
); i
++) {
95 if (!isdigit(last_element
[i
])) {
102 int32_t version
= strtol (name
.c_str()+delim
+1, (char **)NULL
, 10);
104 if (isnumber
== 0 || errno
!= 0) {
105 // last_element is not a number, or is too large
107 newname
+= delimiter
;
112 snprintf (buf
, sizeof(buf
), "%d", version
+1);
114 newname
= name
.substr (0, delim
+1);
124 could_be_a_valid_path (const string
& path
)
126 vector
<string
> posix_dirs
;
127 vector
<string
> dos_dirs
;
130 split (path
, posix_dirs
, '/');
131 split (path
, dos_dirs
, '\\');
133 /* remove the last component of each */
135 posix_dirs
.erase (--posix_dirs
.end());
136 dos_dirs
.erase (--dos_dirs
.end());
138 if (G_DIR_SEPARATOR
== '/') {
139 for (vector
<string
>::iterator x
= posix_dirs
.begin(); x
!= posix_dirs
.end(); ++x
) {
140 testpath
= Glib::build_filename (testpath
, *x
);
141 cerr
<< "Testing " << testpath
<< endl
;
142 if (!Glib::file_test (testpath
, Glib::FILE_TEST_IS_DIR
|Glib::FILE_TEST_EXISTS
)) {
148 if (G_DIR_SEPARATOR
== '\\') {
150 for (vector
<string
>::iterator x
= dos_dirs
.begin(); x
!= dos_dirs
.end(); ++x
) {
151 testpath
= Glib::build_filename (testpath
, *x
);
152 cerr
<< "Testing " << testpath
<< endl
;
153 if (!Glib::file_test (testpath
, Glib::FILE_TEST_IS_DIR
|Glib::FILE_TEST_EXISTS
)) {
164 find_named_node (const XMLNode
& node
, string name
)
167 XMLNodeConstIterator niter
;
170 nlist
= node
.children();
172 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
176 if (child
->name() == name
) {
185 cmp_nocase (const string
& s
, const string
& s2
)
187 string::const_iterator p
= s
.begin();
188 string::const_iterator p2
= s2
.begin();
190 while (p
!= s
.end() && p2
!= s2
.end()) {
191 if (toupper(*p
) != toupper(*p2
)) {
192 return (toupper(*p
) < toupper(*p2
)) ? -1 : 1;
198 return (s2
.size() == s
.size()) ? 0 : (s
.size() < s2
.size()) ? -1 : 1;
202 touch_file (string path
)
204 int fd
= open (path
.c_str(), O_RDWR
|O_CREAT
, 0660);
213 region_name_from_path (string path
, bool strip_channels
, bool add_channel_suffix
, uint32_t total
, uint32_t this_one
)
215 path
= PBD::basename_nosuffix (path
);
217 if (strip_channels
) {
219 /* remove any "?R", "?L" or "?[a-z]" channel identifier */
221 string::size_type len
= path
.length();
223 if (len
> 3 && (path
[len
-2] == '%' || path
[len
-2] == '?' || path
[len
-2] == '.') &&
224 (path
[len
-1] == 'R' || path
[len
-1] == 'L' || (islower (path
[len
-1])))) {
226 path
= path
.substr (0, path
.length() - 2);
230 if (add_channel_suffix
) {
235 path
+= (char) ('a' + this_one
);
237 path
+= (char) (this_one
== 0 ? 'L' : 'R');
245 path_is_paired (string path
, string
& pair_base
)
247 string::size_type pos
;
249 /* remove any leading path */
251 if ((pos
= path
.find_last_of (G_DIR_SEPARATOR
)) != string::npos
) {
252 path
= path
.substr(pos
+1);
255 /* remove filename suffixes etc. */
257 if ((pos
= path
.find_last_of ('.')) != string::npos
) {
258 path
= path
.substr (0, pos
);
261 string::size_type len
= path
.length();
263 /* look for possible channel identifier: "?R", "%R", ".L" etc. */
265 if (len
> 3 && (path
[len
-2] == '%' || path
[len
-2] == '?' || path
[len
-2] == '.') &&
266 (path
[len
-1] == 'R' || path
[len
-1] == 'L' || (islower (path
[len
-1])))) {
268 pair_base
= path
.substr (0, len
-2);
277 path_expand (string path
)
284 /* Handle tilde and environment variable expansion in session path */
288 switch (wordexp (path
.c_str(), &expansion
, WRDE_NOCMD
|WRDE_UNDEF
)) {
292 error
<< string_compose (_("illegal or badly-formed string used for path (%1)"), path
) << endmsg
;
296 if (expansion
.we_wordc
> 1) {
297 error
<< string_compose (_("path (%1) is ambiguous"), path
) << endmsg
;
301 ret
= expansion
.we_wordv
[0];
303 wordfree (&expansion
);
313 CFStringRefToStdString(CFStringRef stringRef
)
316 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef
) ,
317 kCFStringEncodingUTF8
);
318 char *buf
= new char[size
];
322 if(CFStringGetCString(stringRef
, buf
, size
, kCFStringEncodingUTF8
)) {
331 compute_equal_power_fades (framecnt_t nframes
, float* in
, float* out
)
335 step
= 1.0/(nframes
-1);
339 for (framecnt_t i
= 1; i
< nframes
- 1; ++i
) {
340 in
[i
] = in
[i
-1] + step
;
345 const float pan_law_attenuation
= -3.0f
;
346 const float scale
= 2.0f
- 4.0f
* powf (10.0f
,pan_law_attenuation
/20.0f
);
348 for (framecnt_t n
= 0; n
< nframes
; ++n
) {
350 float outVal
= 1 - inVal
;
351 out
[n
] = outVal
* (scale
* outVal
+ 1.0f
- scale
);
352 in
[n
] = inVal
* (scale
* inVal
+ 1.0f
- scale
);
357 string_to_edit_mode (string str
)
359 if (str
== _("Splice")) {
361 } else if (str
== _("Slide")) {
363 } else if (str
== _("Lock")) {
366 fatal
<< string_compose (_("programming error: unknown edit mode string \"%1\""), str
) << endmsg
;
372 edit_mode_to_string (EditMode mode
)
388 string_to_sync_source (string str
)
390 if (str
== _("MIDI Timecode") || str
== _("MTC")) {
394 if (str
== _("MIDI Clock")) {
398 if (str
== _("JACK")) {
402 fatal
<< string_compose (_("programming error: unknown sync source string \"%1\""), str
) << endmsg
;
407 /** @param sh Return a short version of the string */
409 sync_source_to_string (SyncSource src
, bool sh
)
419 return _("MIDI Timecode");
423 return _("MIDI Clock");
425 /* GRRRR .... stupid, stupid gcc - you can't get here from there, all enum values are handled */
430 meter_falloff_to_float (MeterFalloff falloff
)
433 case MeterFalloffOff
:
434 return METER_FALLOFF_OFF
;
435 case MeterFalloffSlowest
:
436 return METER_FALLOFF_SLOWEST
;
437 case MeterFalloffSlow
:
438 return METER_FALLOFF_SLOW
;
439 case MeterFalloffMedium
:
440 return METER_FALLOFF_MEDIUM
;
441 case MeterFalloffFast
:
442 return METER_FALLOFF_FAST
;
443 case MeterFalloffFaster
:
444 return METER_FALLOFF_FASTER
;
445 case MeterFalloffFastest
:
446 return METER_FALLOFF_FASTEST
;
448 return METER_FALLOFF_FAST
;
453 meter_falloff_from_float (float val
)
455 if (val
== METER_FALLOFF_OFF
) {
456 return MeterFalloffOff
;
458 else if (val
<= METER_FALLOFF_SLOWEST
) {
459 return MeterFalloffSlowest
;
461 else if (val
<= METER_FALLOFF_SLOW
) {
462 return MeterFalloffSlow
;
464 else if (val
<= METER_FALLOFF_MEDIUM
) {
465 return MeterFalloffMedium
;
467 else if (val
<= METER_FALLOFF_FAST
) {
468 return MeterFalloffFast
;
470 else if (val
<= METER_FALLOFF_FASTER
) {
471 return MeterFalloffFaster
;
474 return MeterFalloffFastest
;
479 ARDOUR::string_to_auto_state (std::string str
)
481 if (str
== X_("Off")) {
483 } else if (str
== X_("Play")) {
485 } else if (str
== X_("Write")) {
487 } else if (str
== X_("Touch")) {
491 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str
) << endmsg
;
497 ARDOUR::auto_state_to_string (AutoState as
)
499 /* to be used only for XML serialization, no i18n done */
515 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as
) << endmsg
;
521 ARDOUR::string_to_auto_style (std::string str
)
523 if (str
== X_("Absolute")) {
525 } else if (str
== X_("Trim")) {
529 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str
) << endmsg
;
535 ARDOUR::auto_style_to_string (AutoStyle as
)
537 /* to be used only for XML serialization, no i18n done */
541 return X_("Absolute");
548 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as
) << endmsg
;
554 bool_as_string (bool yn
)
556 return (yn
? "yes" : "no");
560 string_is_affirmative (const std::string
& str
)
562 /* to be used only with XML data - not intended to handle user input */
564 return str
== "1" || str
== "y" || str
== "Y" || (!g_strncasecmp(str
.c_str(), "yes", str
.length()));
568 native_header_format_extension (HeaderFormat hf
, const DataType
& type
)
570 if (type
== DataType::MIDI
) {
591 fatal
<< string_compose (_("programming error: unknown native header format: %1"), hf
);
597 matching_unsuffixed_filename_exists_in (const string
& dir
, const string
& path
)
599 string bws
= basename_nosuffix (path
);
600 struct dirent
* dentry
;
605 if ((dead
= ::opendir (dir
.c_str())) == 0) {
606 error
<< string_compose (_("cannot open directory %1 (%2)"), dir
, strerror (errno
)) << endl
;
610 while ((dentry
= ::readdir (dead
)) != 0) {
612 /* avoid '.' and '..' */
614 if ((dentry
->d_name
[0] == '.' && dentry
->d_name
[1] == '\0') ||
615 (dentry
->d_name
[2] == '\0' && dentry
->d_name
[0] == '.' && dentry
->d_name
[1] == '.')) {
619 string fullpath
= Glib::build_filename (dir
, dentry
->d_name
);
621 if (::stat (fullpath
.c_str(), &statbuf
)) {
625 if (!S_ISREG (statbuf
.st_mode
)) {
629 string bws2
= basename_nosuffix (dentry
->d_name
);
642 how_many_dsp_threads ()
644 /* CALLER MUST HOLD PROCESS LOCK */
646 int num_cpu
= hardware_concurrency();
647 int pu
= Config
->get_processor_usage ();
648 uint32_t num_threads
= max (num_cpu
- 1, 2); // default to number of cpus minus one, or 2, whichever is larger
651 /* pu is negative: use "pu" less cores for DSP than appear to be available
655 num_threads
= num_cpu
+ pu
;
658 } else if (pu
== 0) {
660 /* use all available CPUs
663 num_threads
= num_cpu
;
666 /* use "pu" cores, if available
669 num_threads
= min (num_cpu
, pu
);
676 void c_stacktrace() { stacktrace (cerr
); }