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.
20 #include <cstdio> /* for sprintf */
26 #include <sys/types.h>
36 #include <pbd/error.h>
37 #include <pbd/stacktrace.h>
38 #include <pbd/xml++.h>
39 #include <pbd/basename.h>
40 #include <ardour/utils.h>
44 using namespace ARDOUR
;
50 elapsed_time_to_str (char *buf
, uint32_t seconds
)
59 days
= s
/ (3600 * 24);
60 s
-= (days
* 3600 * 24);
67 snprintf (buf
, sizeof (buf
), "%" PRIu32
" day%s %" PRIu32
" hour%s",
71 hours
> 1 ? "s" : "");
73 snprintf (buf
, sizeof (buf
), "%" PRIu32
" hour%s %" PRIu32
" minute%s",
77 minutes
> 1 ? "s" : "");
79 snprintf (buf
, sizeof (buf
), "%" PRIu32
" minute%s",
81 minutes
> 1 ? "s" : "");
83 snprintf (buf
, sizeof (buf
), "%" PRIu32
" second%s",
85 seconds
> 1 ? "s" : "");
87 snprintf (buf
, sizeof (buf
), "no time");
92 legalize_for_path (ustring str
)
94 ustring::size_type pos
;
95 ustring legal_chars
= "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=: ";
101 while ((pos
= legal
.find_first_not_of (legal_chars
, pos
)) != string::npos
) {
102 legal
.replace (pos
, 1, "_");
109 string
bump_name_once(std::string name
)
111 string::size_type period
;
114 if ((period
= name
.find_last_of ('.')) == string::npos
) {
119 const char *last_element
= name
.c_str() + period
+ 1;
120 for (size_t i
= 0; i
< strlen(last_element
); i
++) {
121 if (!isdigit(last_element
[i
])) {
128 long int version
= strtol (name
.c_str()+period
+1, (char **)NULL
, 10);
130 if (isnumber
== 0 || errno
!= 0) {
131 // last_element is not a number, or is too large
137 snprintf (buf
, sizeof(buf
), "%ld", version
+1);
139 newname
= name
.substr (0, period
+1);
149 operator<< (ostream
& o
, const BBT_Time
& bbt
)
151 o
<< bbt
.bars
<< '|' << bbt
.beats
<< '|' << bbt
.ticks
;
156 find_named_node (const XMLNode
& node
, string name
)
159 XMLNodeConstIterator niter
;
162 nlist
= node
.children();
164 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
168 if (child
->name() == name
) {
177 cmp_nocase (const string
& s
, const string
& s2
)
179 string::const_iterator p
= s
.begin();
180 string::const_iterator p2
= s2
.begin();
182 while (p
!= s
.end() && p2
!= s2
.end()) {
183 if (toupper(*p
) != toupper(*p2
)) {
184 return (toupper(*p
) < toupper(*p2
)) ? -1 : 1;
190 return (s2
.size() == s
.size()) ? 0 : (s
.size() < s2
.size()) ? -1 : 1;
194 tokenize_fullpath (string fullpath
, string
& path
, string
& name
)
196 string::size_type m
= fullpath
.find_last_of("/");
198 if (m
== string::npos
) {
204 // does it look like just a directory?
205 if (m
== fullpath
.length()-1) {
208 path
= fullpath
.substr(0, m
+1);
210 string::size_type n
= fullpath
.find(".ardour", m
);
212 if (n
== string::npos
) {
215 name
= fullpath
.substr(m
+1, n
- m
- 1);
220 touch_file (ustring path
)
222 int fd
= open (path
.c_str(), O_RDWR
|O_CREAT
, 0660);
231 region_name_from_path (ustring path
, bool strip_channels
, bool add_channel_suffix
, uint32_t total
, uint32_t this_one
)
233 path
= PBD::basename_nosuffix (path
);
235 if (strip_channels
) {
237 /* remove any "?R", "?L" or "?[a-z]" channel identifier */
239 ustring::size_type len
= path
.length();
241 if (len
> 3 && (path
[len
-2] == '%' || path
[len
-2] == '?' || path
[len
-2] == '.') &&
242 (path
[len
-1] == 'R' || path
[len
-1] == 'L' || (islower (path
[len
-1])))) {
244 path
= path
.substr (0, path
.length() - 2);
248 if (add_channel_suffix
) {
253 path
+= (char) ('a' + this_one
);
255 path
+= (char) (this_one
== 0 ? 'L' : 'R');
263 path_is_paired (ustring path
, ustring
& pair_base
)
265 ustring::size_type pos
;
267 /* remove filename suffixes etc. */
269 if ((pos
= path
.find_last_of ('.')) != string::npos
) {
270 path
= path
.substr (0, pos
);
273 ustring::size_type len
= path
.length();
275 /* look for possible channel identifier: "?R", "%R", ".L" etc. */
277 if (len
> 3 && (path
[len
-2] == '%' || path
[len
-2] == '?' || path
[len
-2] == '.') &&
278 (path
[len
-1] == 'R' || path
[len
-1] == 'L' || (islower (path
[len
-1])))) {
280 pair_base
= path
.substr (0, len
-2);
289 path_expand (ustring path
)
292 /* Handle tilde and environment variable expansion in session path */
296 switch (wordexp (path
.c_str(), &expansion
, WRDE_NOCMD
|WRDE_UNDEF
)) {
300 error
<< string_compose (_("illegal or badly-formed string used for path (%1)"), path
) << endmsg
;
304 if (expansion
.we_wordc
> 1) {
305 error
<< string_compose (_("path (%1) is ambiguous"), path
) << endmsg
;
309 ret
= expansion
.we_wordv
[0];
311 wordfree (&expansion
);
319 #if defined(HAVE_COREAUDIO) || defined(HAVE_AUDIOUNITS)
321 CFStringRefToStdString(CFStringRef stringRef
)
324 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef
) ,
325 kCFStringEncodingUTF8
);
326 char *buf
= new char[size
];
330 if(CFStringGetCString(stringRef
, buf
, size
, kCFStringEncodingUTF8
)) {
336 #endif // HAVE_COREAUDIO
339 compute_equal_power_fades (nframes_t nframes
, float* in
, float* out
)
343 step
= 1.0/(nframes
-1);
347 for (nframes_t i
= 1; i
< nframes
- 1; ++i
) {
348 in
[i
] = in
[i
-1] + step
;
353 const float pan_law_attenuation
= -3.0f
;
354 const float scale
= 2.0f
- 4.0f
* powf (10.0f
,pan_law_attenuation
/20.0f
);
356 for (nframes_t n
= 0; n
< nframes
; ++n
) {
358 float outVal
= 1 - inVal
;
359 out
[n
] = outVal
* (scale
* outVal
+ 1.0f
- scale
);
360 in
[n
] = inVal
* (scale
* inVal
+ 1.0f
- scale
);
365 string_to_edit_mode (string str
)
367 if (str
== _("Splice Edit")) {
369 } else if (str
== _("Slide Edit")) {
371 } else if (str
== _("Lock Edit")) {
374 fatal
<< string_compose (_("programming error: unknown edit mode string \"%1\""), str
) << endmsg
;
380 edit_mode_to_string (EditMode mode
)
384 return _("Slide Edit");
387 return _("Lock Edit");
391 return _("Splice Edit");
396 string_to_slave_source (string str
)
398 if (str
== _("Internal")) {
402 if (str
== _("MTC")) {
406 if (str
== _("JACK")) {
410 fatal
<< string_compose (_("programming error: unknown slave source string \"%1\""), str
) << endmsg
;
416 slave_source_to_string (SlaveSource src
)
427 return _("Internal");
432 /* I don't really like hard-coding these falloff rates here
433 * Probably should use a map of some kind that could be configured
434 * These rates are db/sec.
437 #define METER_FALLOFF_OFF 0.0f
438 #define METER_FALLOFF_SLOWEST 6.6f // BBC standard
439 #define METER_FALLOFF_SLOW 8.6f // BBC standard
440 #define METER_FALLOFF_MEDIUM 20.0f
441 #define METER_FALLOFF_FAST 32.0f
442 #define METER_FALLOFF_FASTER 46.0f
443 #define METER_FALLOFF_FASTEST 70.0f
446 meter_falloff_to_float (MeterFalloff falloff
)
449 case MeterFalloffOff
:
450 return METER_FALLOFF_OFF
;
451 case MeterFalloffSlowest
:
452 return METER_FALLOFF_SLOWEST
;
453 case MeterFalloffSlow
:
454 return METER_FALLOFF_SLOW
;
455 case MeterFalloffMedium
:
456 return METER_FALLOFF_MEDIUM
;
457 case MeterFalloffFast
:
458 return METER_FALLOFF_FAST
;
459 case MeterFalloffFaster
:
460 return METER_FALLOFF_FASTER
;
461 case MeterFalloffFastest
:
462 return METER_FALLOFF_FASTEST
;
464 return METER_FALLOFF_FAST
;
469 meter_falloff_from_float (float val
)
471 if (val
== METER_FALLOFF_OFF
) {
472 return MeterFalloffOff
;
474 else if (val
<= METER_FALLOFF_SLOWEST
) {
475 return MeterFalloffSlowest
;
477 else if (val
<= METER_FALLOFF_SLOW
) {
478 return MeterFalloffSlow
;
480 else if (val
<= METER_FALLOFF_MEDIUM
) {
481 return MeterFalloffMedium
;
483 else if (val
<= METER_FALLOFF_FAST
) {
484 return MeterFalloffFast
;
486 else if (val
<= METER_FALLOFF_FASTER
) {
487 return MeterFalloffFaster
;
490 return MeterFalloffFastest
;
495 meter_hold_to_float (MeterHold hold
)
502 case MeterHoldMedium
:
511 ARDOUR::string_to_auto_state (std::string str
)
513 if (str
== X_("Off")) {
515 } else if (str
== X_("Play")) {
517 } else if (str
== X_("Write")) {
519 } else if (str
== X_("Touch")) {
523 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str
) << endmsg
;
529 ARDOUR::auto_state_to_string (AutoState as
)
531 /* to be used only for XML serialization, no i18n done */
547 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as
) << endmsg
;
553 ARDOUR::string_to_auto_style (std::string str
)
555 if (str
== X_("Absolute")) {
557 } else if (str
== X_("Trim")) {
561 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str
) << endmsg
;
567 ARDOUR::auto_style_to_string (AutoStyle as
)
569 /* to be used only for XML serialization, no i18n done */
573 return X_("Absolute");
580 fatal
<< string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as
) << endmsg
;
586 string_is_affirmative (const std::string
& str
)
588 /* to be used only with XML data - not intended to handle user input */
590 return str
== "1" || str
== "y" || str
== "Y" || (!g_strncasecmp(str
.c_str(), "yes", str
.length()));
594 void c_stacktrace() { stacktrace (cerr
); }