version update, msg txt
[goodguy/history.git] / cinelerra-5.1 / guicast / units.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcwindowbase.inc"
23 #include "units.h"
24 #include "language.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 float* DB::topower_base = 0;
31 int* Freq::freqtable = 0;
32
33
34 DB::DB(float infinitygain)
35 {
36         this->infinitygain = infinitygain;
37         this->db = 0;
38         this->topower = topower_base + -INFINITYGAIN * 10;
39 }
40
41
42 float DB::fromdb_table()
43 {
44         return db = topower[(int)(db*10)];
45 }
46
47 float DB::fromdb_table(float db)
48 {
49         if(db > MAXGAIN) db = MAXGAIN;
50         if(db <= INFINITYGAIN) return 0;
51         return db = topower[(int)(db*10)];
52 }
53
54 float DB::fromdb()
55 {
56         return pow(10, db/20);
57 }
58
59 float DB::fromdb(float db)
60 {
61         return pow(10, db/20);
62 }
63
64 // set db to the power given using a formula
65 float DB::todb(float power)
66 {
67         float db;
68         if(power > 0) {
69                 db = 20 * log10(power);
70                 if(db < -100) db = -100;
71         }
72         else
73                 db = -100;
74         return db;
75 }
76
77
78 Freq::Freq()
79 {
80         freq = 0;
81 }
82
83 Freq::Freq(const Freq& oldfreq)
84 {
85         this->freq = oldfreq.freq;
86 }
87
88 int Freq::fromfreq()
89 {
90         int i = 0;
91         while( i<TOTALFREQS && freqtable[i]<freq ) ++i;
92         return i;
93 };
94
95 int Freq::fromfreq(int index)
96 {
97         int i = 0;
98         while( i<TOTALFREQS && freqtable[i]<index ) ++i;
99         return i;
100 };
101
102 int Freq::tofreq(int index)
103 {
104         if(index >= TOTALFREQS) index = TOTALFREQS - 1;
105         return freqtable[index];
106 }
107
108 Freq& Freq::operator++()
109 {
110         if(freq < TOTALFREQS) ++freq;
111         return *this;
112 }
113
114 Freq& Freq::operator--()
115 {
116         if(freq > 0) --freq;
117         return *this;
118 }
119
120 int Freq::operator>(Freq &newfreq) { return freq > newfreq.freq; }
121 int Freq::operator<(Freq &newfreq) { return freq < newfreq.freq; }
122 Freq& Freq::operator=(const Freq &newfreq) { freq = newfreq.freq; return *this; }
123 int Freq::operator=(const int newfreq) { freq = newfreq; return newfreq; }
124 int Freq::operator!=(Freq &newfreq) { return freq != newfreq.freq; }
125 int Freq::operator==(Freq &newfreq) { return freq == newfreq.freq; }
126 int Freq::operator==(int newfreq) { return freq == newfreq; }
127
128
129
130 void Units::init()
131 {
132         DB::topower_base = new float[(MAXGAIN - INFINITYGAIN) * 10 + 1];
133         float *topower = DB::topower_base + -INFINITYGAIN * 10;
134         for(int i = INFINITYGAIN * 10; i <= MAXGAIN * 10; i++)
135                 topower[i] = pow(10, (float)i / 10 / 20);
136         topower[INFINITYGAIN * 10] = 0;   // infinity gain
137
138         Freq::freqtable = new int[TOTALFREQS + 1];
139 // starting frequency
140         double freq1 = 27.5, freq2 = 55;
141 // Some number divisable by three.  This depends on the value of TOTALFREQS
142         int scale = 105;
143
144         Freq::freqtable[0] = 0;
145         for(int i = 1, j = 0; i <= TOTALFREQS; i++, j++) {
146                 Freq::freqtable[i] = (int)(freq1 + (freq2 - freq1) / scale * j + 0.5);
147                 if(j < scale) continue;
148                 freq1 = freq2;  freq2 *= 2;  j = 0;
149         }
150 }
151 void Units::finit()
152 {
153         delete [] DB::topower_base;  DB::topower_base = 0;
154         delete [] Freq::freqtable;   Freq::freqtable = 0;
155 }
156
157 // give text representation as time
158 char* Units::totext(char *text, double seconds, int time_format,
159                         int sample_rate, float frame_rate, float frames_per_foot)
160 {
161         int64_t hour, feet, frame;
162         int minute, second, thousandths;
163
164         switch(time_format) {
165         case TIME_SECONDS: {
166 // add 1.0e-6 to prevent round off truncation from glitching a bunch of digits
167                 seconds = fabs(seconds) + 1.0e-6;
168                 second = seconds;
169                 seconds -= (int64_t)seconds;
170                 thousandths = (int64_t)(seconds*1000) % 1000;
171                 sprintf(text, "%04d.%03d", second, thousandths);
172                 break; }
173
174         case TIME_HMS: {
175                 seconds = fabs(seconds) + 1.0e-6;
176                 hour = seconds/3600;
177                 minute = seconds/60 - hour*60;
178                 second = seconds - (hour*3600 + minute*60);
179                 seconds -= (int64_t)seconds;
180                 thousandths = (int64_t)(seconds*1000) % 1000;
181                 sprintf(text, "%d:%02d:%02d.%03d",
182                         (int)hour, minute, second, thousandths);
183                 break; }
184
185         case TIME_HMS2: {
186                 seconds = fabs(seconds) + 1.0e-6;
187                 hour = seconds/3600;
188                 minute = seconds/60 - hour*60;
189                 second = seconds - (hour*3600 + minute*60);
190                 sprintf(text, "%d:%02d:%02d", (int)hour, minute, second);
191                 break; }
192
193         case TIME_HMS3: {
194                 seconds = fabs(seconds) + 1.0e-6;
195                 hour = seconds/3600;
196                 minute = seconds/60 - hour*60;
197                 second = seconds - (hour*3600 + minute*60);
198                 sprintf(text, "%02d:%02d:%02d", (int)hour, minute, second);
199                 break; }
200
201         case TIME_HMSF: {
202                 seconds = fabs(seconds) + 1.0e-6;
203                 hour = seconds/3600;
204                 minute = seconds/60 - hour*60;
205                 second = seconds - (hour*3600 + minute*60);
206                 seconds -= (int64_t)seconds;
207 //              frame = round(frame_rate * (seconds-(int)seconds));
208                 frame = frame_rate*seconds + 1.0e-6;
209                 sprintf(text, "%01d:%02d:%02d:%02d", (int)hour, minute, second, (int)frame);
210                 break; }
211
212         case TIME_SAMPLES: {
213                 sprintf(text, "%09jd", to_int64(seconds * sample_rate));
214                 break; }
215
216         case TIME_SAMPLES_HEX: {
217                 sprintf(text, "%08jx", to_int64(seconds * sample_rate));
218                 break; }
219
220         case TIME_FRAMES: {
221                 frame = to_int64(seconds * frame_rate);
222                 sprintf(text, "%06jd", frame);
223                 break; }
224
225         case TIME_FEET_FRAMES: {
226                 frame = to_int64(seconds * frame_rate);
227                 feet = (int64_t)(frame / frames_per_foot);
228                 sprintf(text, "%05jd-%02jd", feet,
229                         (int64_t)(frame - feet * frames_per_foot));
230                 break; }
231
232         case TIME_MS1: {
233                 seconds = fabs(seconds) + 1.0e-6;
234                 minute = seconds/60;
235                 second = seconds - minute*60;
236                 sprintf(text, "%d:%02d", minute, second);
237                 break; }
238
239         case TIME_MS2: {
240                 int sign = seconds >= 0 ? '+' : '-';
241                 seconds = fabs(seconds) + 1.0e-6;
242                 minute = seconds/60;
243                 second = seconds - minute*60;
244                 sprintf(text, "%c%d:%02d", sign, minute, second);
245                 break; }
246         default: {
247                 *text = 0;
248                 break; }
249         }
250         return text;
251 }
252
253
254 // give text representation as time
255 char* Units::totext(char *text, int64_t samples, int samplerate,
256                 int time_format, float frame_rate, float frames_per_foot)
257 {
258         return totext(text, (double)samples/samplerate, time_format,
259                         samplerate, frame_rate, frames_per_foot);
260 }
261
262 int64_t Units::get_int64(const char *&bp)
263 {
264         char string[BCTEXTLEN], *sp=&string[0];
265         const char *cp = bp;
266         for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
267         *sp = 0;  bp = cp;
268         return atol(string);
269 }
270
271 double Units::get_double(const char *&bp)
272 {
273         char string[BCTEXTLEN], *sp=&string[0];
274         const char *cp = bp;
275         for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
276         if( *cp == '.' ) {
277                 *sp++ = *cp++;
278                 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
279         }
280         *sp = 0;  bp = cp;
281         return strtod(string,0);
282 }
283
284 void Units::skip_seperators(const char *&bp)
285 {
286         const char *cp = bp;
287         for( int j=0; j<10 && *cp && !isdigit(*cp); ++j ) ++cp;
288         bp = cp;
289 }
290
291 int64_t Units::fromtext(const char *text, int samplerate, int time_format,
292                         float frame_rate, float frames_per_foot)
293 {
294         int64_t hours, total_samples;
295         int minutes, frames, feet;
296         double seconds, total_seconds;
297         int sign = 1;
298
299         switch(time_format) {
300         case TIME_SECONDS: {
301                 total_seconds = get_double(text);
302                 break; }
303
304         case TIME_HMS:
305         case TIME_HMS2:
306         case TIME_HMS3: {
307                 hours = get_int64(text);    skip_seperators(text);
308                 minutes = get_int64(text);  skip_seperators(text);
309                 seconds = get_int64(text);
310                 total_seconds = seconds + minutes*60 + hours*3600;
311                 break; }
312
313         case TIME_HMSF: {
314                 hours = get_int64(text);    skip_seperators(text);
315                 minutes = get_int64(text);  skip_seperators(text);
316                 seconds = get_int64(text);  skip_seperators(text);
317                 frames = get_int64(text);
318                 total_seconds = frames/frame_rate + seconds + minutes*60 + hours*3600;
319                 break; }
320
321         case TIME_SAMPLES: {
322                 return get_int64(text); }
323
324         case TIME_SAMPLES_HEX: {
325                 sscanf(text, "%jx", &total_samples);
326                 return total_samples; }
327
328         case TIME_FRAMES: {
329                 total_seconds = get_double(text) / frame_rate;
330                 break; }
331
332         case TIME_FEET_FRAMES: {
333                 feet = get_int64(text);    skip_seperators(text);
334                 frames = get_int64(text);
335                 total_seconds = (feet*frames_per_foot + frames) / frame_rate;
336                 break; }
337
338         case TIME_MS2: {
339                 switch( *text ) {
340                 case '+':  sign = 1;   ++text;  break;
341                 case '-':  sign = -1;  ++text;  break;
342                 } } // fall through
343         case TIME_MS1: {
344                 minutes = get_int64(text);   skip_seperators(text);
345                 seconds = get_double(text);
346                 total_seconds = sign * (seconds + minutes*60);
347                 break; }
348         default: {
349                 total_seconds = 0;
350                 break; }
351         }
352
353         total_samples = total_seconds * samplerate;
354         return total_samples;
355 }
356
357 double Units::text_to_seconds(const char *text, int samplerate, int time_format,
358                                 float frame_rate, float frames_per_foot)
359 {
360         return (double)fromtext(text, samplerate, time_format,
361                                 frame_rate, frames_per_foot) / samplerate;
362 }
363
364
365
366
367 int Units::timeformat_totype(char *tcf)
368 {
369         if (!strcmp(tcf,TIME_SECONDS__STR)) return(TIME_SECONDS);
370         if (!strcmp(tcf,TIME_HMS__STR)) return(TIME_HMS);
371         if (!strcmp(tcf,TIME_HMS2__STR)) return(TIME_HMS2);
372         if (!strcmp(tcf,TIME_HMS3__STR)) return(TIME_HMS3);
373         if (!strcmp(tcf,TIME_HMSF__STR)) return(TIME_HMSF);
374         if (!strcmp(tcf,TIME_SAMPLES__STR)) return(TIME_SAMPLES);
375         if (!strcmp(tcf,TIME_SAMPLES_HEX__STR)) return(TIME_SAMPLES_HEX);
376         if (!strcmp(tcf,TIME_FRAMES__STR)) return(TIME_FRAMES);
377         if (!strcmp(tcf,TIME_FEET_FRAMES__STR)) return(TIME_FEET_FRAMES);
378         return(-1);
379 }
380
381
382 float Units::toframes(int64_t samples, int sample_rate, float framerate)
383 {
384         return (double)samples/sample_rate * framerate;
385 } // give position in frames
386
387 int64_t Units::toframes_round(int64_t samples, int sample_rate, float framerate)
388 {
389 // used in editing
390         float result_f = (float)samples / sample_rate * framerate;
391         int64_t result_l = (int64_t)(result_f + 0.5);
392         return result_l;
393 }
394
395 double Units::fix_framerate(double value)
396 {
397         if(value > 29.5 && value < 30)
398                 value = (double)30000 / (double)1001;
399         else if(value > 59.5 && value < 60)
400                 value = (double)60000 / (double)1001;
401         else if(value > 23.5 && value < 24)
402                 value = (double)24000 / (double)1001;
403         return value;
404 }
405
406 double Units::atoframerate(const char *text)
407 {
408         double result = get_double(text);
409         return fix_framerate(result);
410 }
411
412
413 int64_t Units::tosamples(double frames, int sample_rate, float framerate)
414 {
415         double result = frames/framerate * sample_rate;
416         if(result - (int)result >= 1.0e-6 ) result += 1;
417         return (int64_t)result;
418 } // give position in samples
419
420
421 float Units::xy_to_polar(int x, int y)
422 {
423         float angle = 0.;
424         if(x > 0 && y <= 0)
425                 angle = atan((float)-y / x) / (2*M_PI) * 360;
426         else if(x < 0 && y <= 0)
427                 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
428         else if(x < 0 && y > 0)
429                 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
430         else if(x > 0 && y > 0)
431                 angle = 360 + atan((float)-y / x) / (2*M_PI) * 360;
432         else if(x == 0 && y < 0)
433                 angle = 90;
434         else if(x == 0 && y > 0)
435                 angle = 270;
436         else if(x == 0 && y == 0)
437                 angle = 0;
438         return angle;
439 }
440
441 void Units::polar_to_xy(float angle, int radius, int &x, int &y)
442 {
443         if( angle < 0 )
444                 angle += ((int)(-angle)/360 + 1) * 360;
445         else if( angle >= 360 )
446                 angle -= ((int)(angle)/360) * 360;
447
448         x = (int)(cos(angle / 360 * (2*M_PI)) * radius);
449         y = (int)(-sin(angle / 360 * (2*M_PI)) * radius);
450 }
451
452 int64_t Units::round(double result)
453 {
454         return (int64_t)(result < 0 ? result - 0.5 : result + 0.5);
455 }
456
457 float Units::quantize10(float value)
458 {
459         int64_t temp = (int64_t)(value*10 + 0.5);
460         return temp/10.;
461 }
462
463 float Units::quantize(float value, float precision)
464 {
465         int64_t temp = (int64_t)(value/precision + 0.5);
466         return temp*precision;
467 }
468
469 int64_t Units::to_int64(double result)
470 {
471 // This must round up if result is one sample within ceiling.
472 // Sampling rates below 48000 may cause more problems.
473         return (int64_t)(result < 0 ? (result - 0.005) : (result + 0.005));
474 }
475
476 const char* Units::print_time_format(int time_format, char *string)
477 {
478         const char *fmt = "Unknown";
479         switch(time_format) {
480         case TIME_HMS:         fmt = TIME_HMS_TEXT;                   break;
481         case TIME_HMSF:        fmt = TIME_HMSF_TEXT;                  break;
482         case TIME_SAMPLES:     fmt = TIME_SAMPLES_TEXT;               break;
483         case TIME_SAMPLES_HEX: fmt = TIME_SAMPLES_HEX_TEXT;           break;
484         case TIME_FRAMES:      fmt = TIME_FRAMES_TEXT;                break;
485         case TIME_FEET_FRAMES: fmt = TIME_FEET_FRAMES_TEXT;           break;
486         case TIME_HMS2:
487         case TIME_HMS3:        fmt = TIME_HMS3_TEXT;                  break;
488         case TIME_SECONDS:     fmt = TIME_SECONDS_TEXT;               break;
489         case TIME_MS1:
490         case TIME_MS2:         fmt = TIME_MS2_TEXT;                   break;
491         }
492         return strcpy(string,fmt);
493 }
494
495 int Units::text_to_format(const char *string)
496 {
497         if(!strcmp(string, TIME_HMS_TEXT)) return TIME_HMS;
498         if(!strcmp(string, TIME_HMSF_TEXT)) return TIME_HMSF;
499         if(!strcmp(string, TIME_SAMPLES_TEXT)) return TIME_SAMPLES;
500         if(!strcmp(string, TIME_SAMPLES_HEX_TEXT)) return TIME_SAMPLES_HEX;
501         if(!strcmp(string, TIME_FRAMES_TEXT)) return TIME_FRAMES;
502         if(!strcmp(string, TIME_FEET_FRAMES_TEXT)) return TIME_FEET_FRAMES;
503         if(!strcmp(string, TIME_HMS3_TEXT)) return TIME_HMS3;
504         if(!strcmp(string, TIME_SECONDS_TEXT)) return TIME_SECONDS;
505         if(!strcmp(string, TIME_MS2_TEXT)) return TIME_MS2;
506         return TIME_HMS;
507 }
508
509 char* Units::size_totext(int64_t bytes, char *text)
510 {
511         char string[BCTEXTLEN];
512         static const char *sz[] = { "bytes", "KB", "MB", "GB", "TB" };
513
514         int i = (sizeof(sz) / sizeof(sz[0]));
515         while( --i > 0 && bytes < ((int64_t)1 << (10*i)) );
516
517         if( i > 0 ) {
518                 bytes >>= 10*(i-1);
519                 int frac = bytes % 1000;
520                 sprintf(string, "%jd", bytes/1000);
521                 if( bytes > 1000 ) punctuate(string);
522                 sprintf(text, "%s.%03d %s", string, frac, sz[i]);
523         }
524         else {
525                 sprintf(string, "%jd", bytes);
526                 if( bytes > 1000 ) punctuate(string);
527                 sprintf(text, "%s %s", string, sz[i]);
528         }
529         return text;
530 }
531
532
533 #undef BYTE_ORDER
534 #define BYTE_ORDER ((*(const uint32_t*)"a   ") & 0x00000001)
535
536 void* Units::int64_to_ptr(uint64_t value)
537 {
538         unsigned char *value_dissected = (unsigned char*)&value;
539         void *result;
540         unsigned char *data = (unsigned char*)&result;
541
542 // Must be done behind the compiler's back
543         if(sizeof(void*) == 4) {
544                 if(!BYTE_ORDER) {
545                         data[0] = value_dissected[4];
546                         data[1] = value_dissected[5];
547                         data[2] = value_dissected[6];
548                         data[3] = value_dissected[7];
549                 }
550                 else {
551                         data[0] = value_dissected[0];
552                         data[1] = value_dissected[1];
553                         data[2] = value_dissected[2];
554                         data[3] = value_dissected[3];
555                 }
556         }
557         else {
558                 data[0] = value_dissected[0];
559                 data[1] = value_dissected[1];
560                 data[2] = value_dissected[2];
561                 data[3] = value_dissected[3];
562                 data[4] = value_dissected[4];
563                 data[5] = value_dissected[5];
564                 data[6] = value_dissected[6];
565                 data[7] = value_dissected[7];
566         }
567         return result;
568 }
569
570 uint64_t Units::ptr_to_int64(void *ptr)
571 {
572         unsigned char *ptr_dissected = (unsigned char*)&ptr;
573         int64_t result = 0;
574         unsigned char *data = (unsigned char*)&result;
575 // Don't do this at home.
576         if(sizeof(void*) == 4) {
577                 if(!BYTE_ORDER) {
578                         data[4] = ptr_dissected[0];
579                         data[5] = ptr_dissected[1];
580                         data[6] = ptr_dissected[2];
581                         data[7] = ptr_dissected[3];
582                 }
583                 else {
584                         data[0] = ptr_dissected[0];
585                         data[1] = ptr_dissected[1];
586                         data[2] = ptr_dissected[2];
587                         data[3] = ptr_dissected[3];
588                 }
589         }
590         else {
591                 data[0] = ptr_dissected[0];
592                 data[1] = ptr_dissected[1];
593                 data[2] = ptr_dissected[2];
594                 data[3] = ptr_dissected[3];
595                 data[4] = ptr_dissected[4];
596                 data[5] = ptr_dissected[5];
597                 data[6] = ptr_dissected[6];
598                 data[7] = ptr_dissected[7];
599         }
600         return result;
601 }
602
603 const char* Units::format_to_separators(int time_format)
604 {
605         switch(time_format) {
606                 case TIME_SECONDS:     return "0000.000";
607                 case TIME_HMS:         return "0:00:00.000";
608                 case TIME_HMS2:        return "0:00:00";
609                 case TIME_HMS3:        return "00:00:00";
610                 case TIME_HMSF:        return "0:00:00:00";
611                 case TIME_SAMPLES:     return 0;
612                 case TIME_SAMPLES_HEX: return 0;
613                 case TIME_FRAMES:      return 0;
614                 case TIME_FEET_FRAMES: return "00000-00";
615                 case TIME_MS1:         return "0:00";
616                 case TIME_MS2:         return "+0:00";
617         }
618         return 0;
619 }
620
621 void Units::punctuate(char *string)
622 {
623         int sep = ',', len = strlen(string), commas = (len - 1) / 3;
624         char *cp = string + len, *bp = cp + commas;
625         *bp = 0;
626         for( int k=3; cp < bp && bp > string; ) {
627                 *--bp = *--cp;
628                 if( --k > 0 ) continue;
629                 *--bp = sep;  k = 3;
630         }
631 }
632
633 void Units::fix_double(double *x)
634 {
635         *x = *x;
636 }
637
638