Remove unused utility function elapsed_time_to_str
[ardour.git] / libs / ardour / utils.cc
1 /*
2     Copyright (C) 2000-2003 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
20 #define __STDC_FORMAT_MACROS 1
21 #include <stdint.h>
22
23 #include <cstdio> /* for sprintf */
24 #include <cmath>
25 #include <cctype>
26 #include <string>
27 #include <cerrno>
28 #include <iostream>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34
35 #ifdef HAVE_WORDEXP
36 #include <wordexp.h>
37 #endif
38
39 #include <pbd/error.h>
40 #include <pbd/stacktrace.h>
41 #include <pbd/xml++.h>
42 #include <pbd/basename.h>
43 #include <ardour/utils.h>
44
45 #include "i18n.h"
46
47 using namespace ARDOUR;
48 using namespace std;
49 using namespace PBD;
50 using Glib::ustring;
51
52 ustring 
53 legalize_for_path (ustring str)
54 {
55         ustring::size_type pos;
56         ustring legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=: ";
57         ustring legal;
58
59         legal = str;
60         pos = 0;
61
62         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
63                 legal.replace (pos, 1, "_");
64                 pos += 1;
65         }
66
67         return legal;
68 }
69 #if 0
70 string 
71 legalize_for_path (string str)
72 {
73         string::size_type pos;
74         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=: ";
75         string legal;
76
77         legal = str;
78         pos = 0;
79
80         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
81                 legal.replace (pos, 1, "_");
82                 pos += 1;
83         }
84
85         return legal;
86 }
87 #endif
88
89 ostream&
90 operator<< (ostream& o, const BBT_Time& bbt)
91 {
92         o << bbt.bars << '|' << bbt.beats << '|' << bbt.ticks;
93         return o;
94 }
95
96 XMLNode *
97 find_named_node (const XMLNode& node, string name)
98 {
99         XMLNodeList nlist;
100         XMLNodeConstIterator niter;
101         XMLNode* child;
102
103         nlist = node.children();
104
105         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
106
107                 child = *niter;
108
109                 if (child->name() == name) {
110                         return child;
111                 }
112         }
113
114         return 0;
115 }
116
117 int
118 cmp_nocase (const string& s, const string& s2)
119 {
120         string::const_iterator p = s.begin();
121         string::const_iterator p2 = s2.begin();
122         
123         while (p != s.end() && p2 != s2.end()) {
124                 if (toupper(*p) != toupper(*p2)) {
125                         return (toupper(*p) < toupper(*p2)) ? -1 : 1;
126                 }
127                 ++p;
128                 ++p2;
129         }
130         
131         return (s2.size() == s.size()) ? 0 : (s.size() < s2.size()) ? -1 : 1;
132 }
133
134 int
135 touch_file (ustring path)
136 {
137         int fd = open (path.c_str(), O_RDWR|O_CREAT, 0660);
138         if (fd >= 0) {
139                 close (fd);
140                 return 0;
141         }
142         return 1;
143 }
144
145 ustring
146 region_name_from_path (ustring path, bool strip_channels)
147 {
148         path = PBD::basename_nosuffix (path);
149
150         if (strip_channels) {
151
152                 /* remove any "?R", "?L" or "?[a-z]" channel identifier */
153                 
154                 ustring::size_type len = path.length();
155                 
156                 if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') && 
157                     (path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
158                         
159                         path = path.substr (0, path.length() - 2);
160                 }
161         }
162
163         return path;
164 }       
165
166 bool
167 path_is_paired (ustring path, ustring& pair_base)
168 {
169         ustring::size_type pos;
170
171         /* remove any leading path */
172
173         if ((pos = path.find_last_of ('/')) != string::npos) {
174                 path = path.substr(pos+1);
175         }
176
177         /* remove filename suffixes etc. */
178         
179         if ((pos = path.find_last_of ('.')) != string::npos) {
180                 path = path.substr (0, pos);
181         }
182
183         ustring::size_type len = path.length();
184
185         /* look for possible channel identifier: "?R", "%R", ".L" etc. */
186
187         if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') && 
188             (path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
189                 
190                 pair_base = path.substr (0, len-2);
191                 return true;
192
193         } 
194
195         return false;
196 }
197
198 ustring
199 path_expand (ustring path)
200 {
201 #ifdef HAVE_WORDEXP
202         /* Handle tilde and environment variable expansion in session path */
203         string ret = path;
204
205         wordexp_t expansion;
206         switch (wordexp (path.c_str(), &expansion, WRDE_NOCMD|WRDE_UNDEF)) {
207         case 0:
208                 break;
209         default:
210                 error << string_compose (_("illegal or badly-formed string used for path (%1)"), path) << endmsg;
211                 goto out;
212         }
213
214         if (expansion.we_wordc > 1) {
215                 error << string_compose (_("path (%1) is ambiguous"), path) << endmsg;
216                 goto out;
217         }
218
219         ret = expansion.we_wordv[0];
220   out:
221         wordfree (&expansion);
222         return ret;
223
224 #else 
225         return path;
226 #endif
227 }
228
229 #if defined(HAVE_COREAUDIO) || defined(HAVE_AUDIOUNITS)
230 string 
231 CFStringRefToStdString(CFStringRef stringRef)
232 {
233         CFIndex size = 
234                 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , 
235                 kCFStringEncodingUTF8);
236             char *buf = new char[size];
237         
238         std::string result;
239
240         if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingUTF8)) {
241             result = buf;
242         }
243         delete [] buf;
244         return result;
245 }
246 #endif // HAVE_COREAUDIO
247
248 void
249 compute_equal_power_fades (nframes_t nframes, float* in, float* out)
250 {
251         double step;
252
253         step = 1.0/nframes;
254
255         in[0] = 0.0f;
256         
257         for (nframes_t i = 1; i < nframes - 1; ++i) {
258                 in[i] = in[i-1] + step;
259         }
260         
261         in[nframes-1] = 1.0;
262
263         const float pan_law_attenuation = -3.0f;
264         const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
265
266         for (nframes_t n = 0; n < nframes; ++n) {
267                 float inVal = in[n];
268                 float outVal = 1 - inVal;
269                 out[n] = outVal * (scale * outVal + 1.0f - scale);
270                 in[n] = inVal * (scale * inVal + 1.0f - scale);
271         }
272 }
273
274 EditMode
275 string_to_edit_mode (string str)
276 {
277         if (str == _("Splice Edit")) {
278                 return Splice;
279         } else if (str == _("Slide Edit")) {
280                 return Slide;
281         }
282         fatal << string_compose (_("programming error: unknown edit mode string \"%1\""), str) << endmsg;
283         /*NOTREACHED*/
284         return Slide;
285 }
286
287 const char*
288 edit_mode_to_string (EditMode mode)
289 {
290         switch (mode) {
291         case Slide:
292                 return _("Slide Edit");
293
294         default:
295         case Splice:
296                 return _("Splice Edit");
297         }
298 }
299
300 SlaveSource
301 string_to_slave_source (string str)
302 {
303         if (str == _("Internal")) {
304                 return None;
305         }
306         
307         if (str == _("MTC")) {
308                 return MTC;
309         }
310
311         if (str == _("JACK")) {
312                 return JACK;
313         }
314
315         fatal << string_compose (_("programming error: unknown slave source string \"%1\""), str) << endmsg;
316         /*NOTREACHED*/
317         return None;
318 }
319
320 const char*
321 slave_source_to_string (SlaveSource src)
322 {
323         switch (src) {
324         case JACK:
325                 return _("JACK");
326
327         case MTC:
328                 return _("MTC");
329                 
330         default:
331         case None:
332                 return _("Internal");
333                 
334         }
335 }
336
337 /* I don't really like hard-coding these falloff rates here
338  * Probably should use a map of some kind that could be configured
339  * These rates are db/sec.
340 */
341
342 #define METER_FALLOFF_OFF     0.0f
343 #define METER_FALLOFF_SLOWEST 6.6f // BBC standard
344 #define METER_FALLOFF_SLOW    8.6f // BBC standard
345 #define METER_FALLOFF_MEDIUM  20.0f
346 #define METER_FALLOFF_FAST    32.0f
347 #define METER_FALLOFF_FASTER  46.0f
348 #define METER_FALLOFF_FASTEST 70.0f
349
350 float
351 meter_falloff_to_float (MeterFalloff falloff)
352 {
353         switch (falloff) {
354         case MeterFalloffOff:
355                 return METER_FALLOFF_OFF;
356         case MeterFalloffSlowest:
357                 return METER_FALLOFF_SLOWEST;
358         case MeterFalloffSlow:
359                 return METER_FALLOFF_SLOW;
360         case MeterFalloffMedium:
361                 return METER_FALLOFF_MEDIUM;
362         case MeterFalloffFast:
363                 return METER_FALLOFF_FAST;
364         case MeterFalloffFaster:
365                 return METER_FALLOFF_FASTER;
366         case MeterFalloffFastest:
367                 return METER_FALLOFF_FASTEST;
368         default:
369                 return METER_FALLOFF_FAST;
370         }
371 }
372
373 MeterFalloff
374 meter_falloff_from_float (float val)
375 {
376         if (val == METER_FALLOFF_OFF) {
377                 return MeterFalloffOff;
378         }
379         else if (val <= METER_FALLOFF_SLOWEST) {
380                 return MeterFalloffSlowest;
381         }
382         else if (val <= METER_FALLOFF_SLOW) {
383                 return MeterFalloffSlow;
384         }
385         else if (val <= METER_FALLOFF_MEDIUM) {
386                 return MeterFalloffMedium;
387         }
388         else if (val <= METER_FALLOFF_FAST) {
389                 return MeterFalloffFast;
390         }
391         else if (val <= METER_FALLOFF_FASTER) {
392                 return MeterFalloffFaster;
393         }
394         else {
395                 return MeterFalloffFastest;
396         }
397 }
398
399 float
400 meter_hold_to_float (MeterHold hold)
401 {
402         switch (hold) {
403         case MeterHoldOff:
404                 return 0.0f;
405         case MeterHoldShort:
406                 return 40.0f;
407         case MeterHoldMedium:
408                 return 100.0f;
409         case MeterHoldLong:
410         default:
411                 return 200.0f;
412         }
413 }
414
415 AutoState 
416 ARDOUR::string_to_auto_state (std::string str)
417 {
418         if (str == X_("Off")) {
419                 return Off;
420         } else if (str == X_("Play")) {
421                 return Play;
422         } else if (str == X_("Write")) {
423                 return Write;
424         } else if (str == X_("Touch")) {
425                 return Touch;
426         }
427
428         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str) << endmsg;
429         /*NOTREACHED*/
430         return Touch;
431 }
432
433 string 
434 ARDOUR::auto_state_to_string (AutoState as)
435 {
436         /* to be used only for XML serialization, no i18n done */
437
438         switch (as) {
439         case Off:
440                 return X_("Off");
441                 break;
442         case Play:
443                 return X_("Play");
444                 break;
445         case Write:
446                 return X_("Write");
447                 break;
448         case Touch:
449                 return X_("Touch");
450         }
451
452         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as) << endmsg;
453         /*NOTREACHED*/
454         return "";
455 }
456
457 AutoStyle 
458 ARDOUR::string_to_auto_style (std::string str)
459 {
460         if (str == X_("Absolute")) {
461                 return Absolute;
462         } else if (str == X_("Trim")) {
463                 return Trim;
464         }
465
466         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str) << endmsg;
467         /*NOTREACHED*/
468         return Trim;
469 }
470
471 string 
472 ARDOUR::auto_style_to_string (AutoStyle as)
473 {
474         /* to be used only for XML serialization, no i18n done */
475
476         switch (as) {
477         case Absolute:
478                 return X_("Absolute");
479                 break;
480         case Trim:
481                 return X_("Trim");
482                 break;
483         }
484
485         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as) << endmsg;
486         /*NOTREACHED*/
487         return "";
488 }
489
490 extern "C" {
491         void c_stacktrace() { stacktrace (cerr); }
492 }