LTC generator update
[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 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <stdint.h>
25
26 #include <cstdio> /* for sprintf */
27 #include <cstring>
28 #include <climits>
29 #include <cstdlib>
30 #include <cmath>
31 #include <cctype>
32 #include <cstring>
33 #include <cerrno>
34 #include <iostream>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <fcntl.h>
39 #include <dirent.h>
40 #include <errno.h>
41 #include <regex.h>
42
43 #include <glibmm/miscutils.h>
44 #include <glibmm/fileutils.h>
45
46 #include "pbd/cpus.h"
47 #include "pbd/error.h"
48 #include "pbd/stacktrace.h"
49 #include "pbd/xml++.h"
50 #include "pbd/basename.h"
51 #include "pbd/strsplit.h"
52 #include "pbd/replace_all.h"
53
54 #include "ardour/utils.h"
55 #include "ardour/rc_configuration.h"
56
57 #include "i18n.h"
58
59 using namespace ARDOUR;
60 using namespace std;
61 using namespace PBD;
62
63 /** take an arbitrary string as an argument, and return a version of it
64  * suitable for use as a path (directory/folder name). This is the Ardour 3.X
65  * and later version of this code. It defines a very small number
66  * of characters that are not allowed in a path on any of our target
67  * filesystems, and replaces any instances of them with an underscore.
68  */
69
70 string
71 legalize_for_path (const string& str)
72 {
73         string::size_type pos;
74         string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
75         Glib::ustring legal;
76
77         /* this is the one place in Ardour where we need to iterate across
78          * potential multibyte characters, and thus we need Glib::ustring
79          */
80
81         legal = str;
82         pos = 0;
83
84         while ((pos = legal.find_first_of (illegal_chars, pos)) != string::npos) {
85                 legal.replace (pos, 1, "_");
86                 pos += 1;
87         }
88
89         return string (legal);
90 }
91
92 /** take an arbitrary string as an argument, and return a version of it
93  * suitable for use as a path (directory/folder name). This is the Ardour 2.X
94  * version of this code, which used an approach that came to be seen as
95  * problematic: defining the characters that were allowed and replacing all
96  * others with underscores. See legalize_for_path() for the 3.X and later
97  * version.
98  */
99
100 string 
101 legalize_for_path_2X (const string& str)
102 {
103         string::size_type pos;
104         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=: ";
105         Glib::ustring legal;
106         
107         /* this is the one place in Ardour where we need to iterate across
108          * potential multibyte characters, and thus we need Glib::ustring
109          */
110
111         legal = str;
112         pos = 0;
113
114         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
115                 legal.replace (pos, 1, "_");
116                 pos += 1;
117         }
118
119         return string (legal);
120 }
121
122 string
123 bump_name_once (const std::string& name, char delimiter)
124 {
125         string::size_type delim;
126         string newname;
127
128         if ((delim = name.find_last_of (delimiter)) == string::npos) {
129                 newname  = name;
130                 newname += delimiter;
131                 newname += "1";
132         } else {
133                 int isnumber = 1;
134                 const char *last_element = name.c_str() + delim + 1;
135                 for (size_t i = 0; i < strlen(last_element); i++) {
136                         if (!isdigit(last_element[i])) {
137                                 isnumber = 0;
138                                 break;
139                         }
140                 }
141
142                 errno = 0;
143                 int32_t version = strtol (name.c_str()+delim+1, (char **)NULL, 10);
144
145                 if (isnumber == 0 || errno != 0) {
146                         // last_element is not a number, or is too large
147                         newname  = name;
148                         newname  += delimiter;
149                         newname += "1";
150                 } else {
151                         char buf[32];
152
153                         snprintf (buf, sizeof(buf), "%d", version+1);
154
155                         newname  = name.substr (0, delim+1);
156                         newname += buf;
157                 }
158         }
159
160         return newname;
161
162 }
163
164 XMLNode *
165 find_named_node (const XMLNode& node, string name)
166 {
167         XMLNodeList nlist;
168         XMLNodeConstIterator niter;
169         XMLNode* child;
170
171         nlist = node.children();
172
173         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
174
175                 child = *niter;
176
177                 if (child->name() == name) {
178                         return child;
179                 }
180         }
181
182         return 0;
183 }
184
185 int
186 cmp_nocase (const string& s, const string& s2)
187 {
188         string::const_iterator p = s.begin();
189         string::const_iterator p2 = s2.begin();
190
191         while (p != s.end() && p2 != s2.end()) {
192                 if (toupper(*p) != toupper(*p2)) {
193                         return (toupper(*p) < toupper(*p2)) ? -1 : 1;
194                 }
195                 ++p;
196                 ++p2;
197         }
198
199         return (s2.size() == s.size()) ? 0 : (s.size() < s2.size()) ? -1 : 1;
200 }
201
202 int
203 touch_file (string path)
204 {
205         int fd = open (path.c_str(), O_RDWR|O_CREAT, 0660);
206         if (fd >= 0) {
207                 close (fd);
208                 return 0;
209         }
210         return 1;
211 }
212
213 string
214 region_name_from_path (string path, bool strip_channels, bool add_channel_suffix, uint32_t total, uint32_t this_one)
215 {
216         path = PBD::basename_nosuffix (path);
217
218         if (strip_channels) {
219
220                 /* remove any "?R", "?L" or "?[a-z]" channel identifier */
221
222                 string::size_type len = path.length();
223
224                 if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
225                     (path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
226
227                         path = path.substr (0, path.length() - 2);
228                 }
229         }
230
231         if (add_channel_suffix) {
232
233                 path += '%';
234
235                 if (total > 2) {
236                         path += (char) ('a' + this_one);
237                 } else {
238                         path += (char) (this_one == 0 ? 'L' : 'R');
239                 }
240         }
241
242         return path;
243 }
244
245 bool
246 path_is_paired (string path, string& pair_base)
247 {
248         string::size_type pos;
249
250         /* remove any leading path */
251
252         if ((pos = path.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
253                 path = path.substr(pos+1);
254         }
255
256         /* remove filename suffixes etc. */
257
258         if ((pos = path.find_last_of ('.')) != string::npos) {
259                 path = path.substr (0, pos);
260         }
261
262         string::size_type len = path.length();
263
264         /* look for possible channel identifier: "?R", "%R", ".L" etc. */
265
266         if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
267             (path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
268
269                 pair_base = path.substr (0, len-2);
270                 return true;
271
272         }
273
274         return false;
275 }
276
277 string
278 path_expand (string path)
279 {
280         if (path.empty()) {
281                 return path;
282         }
283
284         /* tilde expansion */
285
286         if (path[0] == '~') {
287                 if (path.length() == 1) {
288                         return Glib::get_home_dir();
289                 }
290
291                 if (path[1] == '/') {
292                         path.replace (0, 1, Glib::get_home_dir());
293                 } else {
294                         /* can't handle ~roger, so just leave it */
295                 }
296         }
297
298         /* now do $VAR substitution, since wordexp isn't reliable */
299
300         regex_t compiled_pattern;
301         const int nmatches = 100;
302         regmatch_t matches[nmatches];
303         
304         if (regcomp (&compiled_pattern, "\\$([a-zA-Z_][a-zA-Z0-9_]*|\\{[a-zA-Z_][a-zA-Z0-9_]*\\})", REG_EXTENDED)) {
305                 cerr << "bad regcomp\n";
306                 return path;
307         }
308
309         while (true) { 
310
311                 if (regexec (&compiled_pattern, path.c_str(), nmatches, matches, 0)) {
312                         break;
313                 }
314                 
315                 /* matches[0] gives the entire match */
316                 
317                 string match = path.substr (matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so);
318                 
319                 /* try to get match from the environment */
320
321                 if (match[1] == '{') {
322                         /* ${FOO} form */
323                         match = match.substr (2, match.length() - 3);
324                 }
325
326                 char* matched_value = getenv (match.c_str());
327
328                 if (matched_value) {
329                         path.replace (matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so, matched_value);
330                 } else {
331                         path.replace (matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so, string());
332                 }
333
334                 /* go back and do it again with whatever remains after the
335                  * substitution 
336                  */
337         }
338
339         regfree (&compiled_pattern);
340
341         /* canonicalize */
342
343         char buf[PATH_MAX+1];
344
345         if (realpath (path.c_str(), buf)) {
346                 return buf;
347         } else {
348                 return string();
349         }
350 }
351
352 string
353 search_path_expand (string path)
354 {
355         if (path.empty()) {
356                 return path;
357         }
358
359         vector<string> s;
360         vector<string> n;
361
362         split (path, s, ':');
363
364         for (vector<string>::iterator i = s.begin(); i != s.end(); ++i) {
365                 string exp = path_expand (*i);
366                 if (!exp.empty()) {
367                         n.push_back (exp);
368                 }
369         }
370
371         string r;
372
373         for (vector<string>::iterator i = n.begin(); i != n.end(); ++i) {
374                 if (!r.empty()) {
375                         r += ':';
376                 }
377                 r += *i;
378         }
379
380         return r;
381 }
382
383 #if __APPLE__
384 string
385 CFStringRefToStdString(CFStringRef stringRef)
386 {
387         CFIndex size =
388                 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) ,
389                 kCFStringEncodingUTF8);
390             char *buf = new char[size];
391
392         std::string result;
393
394         if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingUTF8)) {
395             result = buf;
396         }
397         delete [] buf;
398         return result;
399 }
400 #endif // __APPLE__
401
402 void
403 compute_equal_power_fades (framecnt_t nframes, float* in, float* out)
404 {
405         double step;
406
407         step = 1.0/(nframes-1);
408
409         in[0] = 0.0f;
410
411         for (framecnt_t i = 1; i < nframes - 1; ++i) {
412                 in[i] = in[i-1] + step;
413         }
414
415         in[nframes-1] = 1.0;
416
417         const float pan_law_attenuation = -3.0f;
418         const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
419
420         for (framecnt_t n = 0; n < nframes; ++n) {
421                 float inVal = in[n];
422                 float outVal = 1 - inVal;
423                 out[n] = outVal * (scale * outVal + 1.0f - scale);
424                 in[n] = inVal * (scale * inVal + 1.0f - scale);
425         }
426 }
427
428 EditMode
429 string_to_edit_mode (string str)
430 {
431         if (str == _("Splice")) {
432                 return Splice;
433         } else if (str == _("Slide")) {
434                 return Slide;
435         } else if (str == _("Lock")) {
436                 return Lock;
437         }
438         fatal << string_compose (_("programming error: unknown edit mode string \"%1\""), str) << endmsg;
439         /*NOTREACHED*/
440         return Slide;
441 }
442
443 const char*
444 edit_mode_to_string (EditMode mode)
445 {
446         switch (mode) {
447         case Slide:
448                 return _("Slide");
449
450         case Lock:
451                 return _("Lock");
452
453         default:
454         case Splice:
455                 return _("Splice");
456         }
457 }
458
459 SyncSource
460 string_to_sync_source (string str)
461 {
462         if (str == _("MIDI Timecode") || str == _("MTC")) {
463                 return MTC;
464         }
465
466         if (str == _("MIDI Clock")) {
467                 return MIDIClock;
468         }
469
470         if (str == _("JACK")) {
471                 return JACK;
472         }
473
474         fatal << string_compose (_("programming error: unknown sync source string \"%1\""), str) << endmsg;
475         /*NOTREACHED*/
476         return JACK;
477 }
478
479 /** @param sh Return a short version of the string */
480 const char*
481 sync_source_to_string (SyncSource src, bool sh)
482 {
483         switch (src) {
484         case JACK:
485                 return _("JACK");
486
487         case MTC:
488                 if (sh) {
489                         return _("MTC");
490                 } else {
491                         return _("MIDI Timecode");
492                 }
493
494         case MIDIClock:
495                 if (sh) {
496                         return _("M-Clock");
497                 } else {
498                         return _("MIDI Clock");
499                 }
500
501         case LTC:
502                 return _("LTC");
503         }
504         /* GRRRR .... stupid, stupid gcc - you can't get here from there, all enum values are handled */
505         return _("JACK");
506 }
507
508 float
509 meter_falloff_to_float (MeterFalloff falloff)
510 {
511         switch (falloff) {
512         case MeterFalloffOff:
513                 return METER_FALLOFF_OFF;
514         case MeterFalloffSlowest:
515                 return METER_FALLOFF_SLOWEST;
516         case MeterFalloffSlow:
517                 return METER_FALLOFF_SLOW;
518         case MeterFalloffMedium:
519                 return METER_FALLOFF_MEDIUM;
520         case MeterFalloffFast:
521                 return METER_FALLOFF_FAST;
522         case MeterFalloffFaster:
523                 return METER_FALLOFF_FASTER;
524         case MeterFalloffFastest:
525                 return METER_FALLOFF_FASTEST;
526         default:
527                 return METER_FALLOFF_FAST;
528         }
529 }
530
531 MeterFalloff
532 meter_falloff_from_float (float val)
533 {
534         if (val == METER_FALLOFF_OFF) {
535                 return MeterFalloffOff;
536         }
537         else if (val <= METER_FALLOFF_SLOWEST) {
538                 return MeterFalloffSlowest;
539         }
540         else if (val <= METER_FALLOFF_SLOW) {
541                 return MeterFalloffSlow;
542         }
543         else if (val <= METER_FALLOFF_MEDIUM) {
544                 return MeterFalloffMedium;
545         }
546         else if (val <= METER_FALLOFF_FAST) {
547                 return MeterFalloffFast;
548         }
549         else if (val <= METER_FALLOFF_FASTER) {
550                 return MeterFalloffFaster;
551         }
552         else {
553                 return MeterFalloffFastest;
554         }
555 }
556
557 AutoState
558 ARDOUR::string_to_auto_state (std::string str)
559 {
560         if (str == X_("Off")) {
561                 return Off;
562         } else if (str == X_("Play")) {
563                 return Play;
564         } else if (str == X_("Write")) {
565                 return Write;
566         } else if (str == X_("Touch")) {
567                 return Touch;
568         }
569
570         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str) << endmsg;
571         /*NOTREACHED*/
572         return Touch;
573 }
574
575 string
576 ARDOUR::auto_state_to_string (AutoState as)
577 {
578         /* to be used only for XML serialization, no i18n done */
579
580         switch (as) {
581         case Off:
582                 return X_("Off");
583                 break;
584         case Play:
585                 return X_("Play");
586                 break;
587         case Write:
588                 return X_("Write");
589                 break;
590         case Touch:
591                 return X_("Touch");
592         }
593
594         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as) << endmsg;
595         /*NOTREACHED*/
596         return "";
597 }
598
599 AutoStyle
600 ARDOUR::string_to_auto_style (std::string str)
601 {
602         if (str == X_("Absolute")) {
603                 return Absolute;
604         } else if (str == X_("Trim")) {
605                 return Trim;
606         }
607
608         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str) << endmsg;
609         /*NOTREACHED*/
610         return Trim;
611 }
612
613 string
614 ARDOUR::auto_style_to_string (AutoStyle as)
615 {
616         /* to be used only for XML serialization, no i18n done */
617
618         switch (as) {
619         case Absolute:
620                 return X_("Absolute");
621                 break;
622         case Trim:
623                 return X_("Trim");
624                 break;
625         }
626
627         fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as) << endmsg;
628         /*NOTREACHED*/
629         return "";
630 }
631
632 std::string
633 bool_as_string (bool yn)
634 {
635         return (yn ? "yes" : "no");
636 }
637
638 const char*
639 native_header_format_extension (HeaderFormat hf, const DataType& type)
640 {
641         if (type == DataType::MIDI) {
642                 return ".mid";
643         }
644
645         switch (hf) {
646         case BWF:
647                 return ".wav";
648         case WAVE:
649                 return ".wav";
650         case WAVE64:
651                 return ".w64";
652         case CAF:
653                 return ".caf";
654         case AIFF:
655                 return ".aif";
656         case iXML:
657                 return ".ixml";
658         case RF64:
659                 return ".rf64";
660         }
661
662         fatal << string_compose (_("programming error: unknown native header format: %1"), hf);
663         /*NOTREACHED*/
664         return ".wav";
665 }
666
667 bool
668 matching_unsuffixed_filename_exists_in (const string& dir, const string& path)
669 {
670         string bws = basename_nosuffix (path);
671         struct dirent* dentry;
672         struct stat statbuf;
673         DIR* dead;
674         bool ret = false;
675
676         if ((dead = ::opendir (dir.c_str())) == 0) {
677                 error << string_compose (_("cannot open directory %1 (%2)"), dir, strerror (errno)) << endl;
678                 return false;
679         }
680
681         while ((dentry = ::readdir (dead)) != 0) {
682
683                 /* avoid '.' and '..' */
684
685                 if ((dentry->d_name[0] == '.' && dentry->d_name[1] == '\0') ||
686                     (dentry->d_name[2] == '\0' && dentry->d_name[0] == '.' && dentry->d_name[1] == '.')) {
687                         continue;
688                 }
689
690                 string fullpath = Glib::build_filename (dir, dentry->d_name);
691
692                 if (::stat (fullpath.c_str(), &statbuf)) {
693                         continue;
694                 }
695
696                 if (!S_ISREG (statbuf.st_mode)) {
697                         continue;
698                 }
699
700                 string bws2 = basename_nosuffix (dentry->d_name);
701
702                 if (bws2 == bws) {
703                         ret = true;
704                         break;
705                 }
706         }
707
708         ::closedir (dead);
709         return ret;
710 }
711
712 uint32_t
713 how_many_dsp_threads ()
714 {
715         /* CALLER MUST HOLD PROCESS LOCK */
716
717         int num_cpu = hardware_concurrency();
718         int pu = Config->get_processor_usage ();
719         uint32_t num_threads = max (num_cpu - 1, 2); // default to number of cpus minus one, or 2, whichever is larger
720
721         if (pu < 0) {
722                 /* pu is negative: use "pu" less cores for DSP than appear to be available
723                  */
724
725                 if (-pu < num_cpu) {
726                         num_threads = num_cpu + pu;
727                 }
728
729         } else if (pu == 0) {
730
731                 /* use all available CPUs
732                  */
733
734                 num_threads = num_cpu;
735
736         } else {
737                 /* use "pu" cores, if available
738                  */
739
740                 num_threads = min (num_cpu, pu);
741         }
742
743         return num_threads;
744 }
745
746 double gain_to_slider_position_with_max (double g, double max_gain)
747 {
748         return gain_to_slider_position (g * 2.0/max_gain);
749 }
750
751 double slider_position_to_gain_with_max (double g, double max_gain)
752 {
753         return slider_position_to_gain (g * max_gain/2.0);
754 }
755
756 extern "C" {
757         void c_stacktrace() { stacktrace (cerr); }
758 }