cf48af1722b85a9733f56ba89f4dec9d9297ed3b
[goodguy/cinelerra.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 // frequency doubles for every OCTAVE slots.  OCTAVE must be divisible by 3
109 // 27.5 is at i=1
110 // 55 is at i=106
111 // 110 is at i=211
112 // 220 is at i=316
113 // 440 is at i=421
114 // 880 is at i=526
115 double Freq::tofreq_f(double index)
116 {
117         if( index < 0.5 ) return 0;
118         return 440.0 * pow(2, (double)(index - 421) / OCTAVE);
119 }
120 double Freq::fromfreq_f(double f)
121 {
122         if( f < 0.5 ) return 0;
123         double result = log(f / 440) / log(2.0) * OCTAVE + 421;
124         return result < 0 ? 0 : result;
125 }
126
127 Freq& Freq::operator++()
128 {
129         if(freq < TOTALFREQS) ++freq;
130         return *this;
131 }
132
133 Freq& Freq::operator--()
134 {
135         if(freq > 0) --freq;
136         return *this;
137 }
138
139 int Freq::operator>(Freq &newfreq) { return freq > newfreq.freq; }
140 int Freq::operator<(Freq &newfreq) { return freq < newfreq.freq; }
141 Freq& Freq::operator=(const Freq &newfreq) { freq = newfreq.freq; return *this; }
142 int Freq::operator=(const int newfreq) { freq = newfreq; return newfreq; }
143 int Freq::operator!=(Freq &newfreq) { return freq != newfreq.freq; }
144 int Freq::operator==(Freq &newfreq) { return freq == newfreq.freq; }
145 int Freq::operator==(int newfreq) { return freq == newfreq; }
146
147
148
149 void Units::init()
150 {
151         DB::topower_base = new float[(MAXGAIN - INFINITYGAIN) * 10 + 1];
152         float *topower = DB::topower_base + -INFINITYGAIN * 10;
153         for(int i = INFINITYGAIN * 10; i <= MAXGAIN * 10; i++)
154                 topower[i] = pow(10, (float)i / 10 / 20);
155         topower[INFINITYGAIN * 10] = 0;   // infinity gain
156
157         Freq::freqtable = new int[TOTALFREQS + 1];
158         for( int i=0; i<=TOTALFREQS; ++i )
159                 Freq::freqtable[i] = Freq::tofreq_f(i);
160 }
161 void Units::finit()
162 {
163         delete [] DB::topower_base;  DB::topower_base = 0;
164         delete [] Freq::freqtable;   Freq::freqtable = 0;
165 }
166
167 // give text representation as time
168 char* Units::totext(char *text, double seconds, int time_format,
169                         int sample_rate, float frame_rate, float frames_per_foot,
170                         double timecode_offset)
171 {
172         int64_t hour, feet, frame;
173         int minute, second, thousandths;
174
175         switch(time_format) {
176         case TIME_SECONDS: {
177 // add 1.0e-6 to prevent round off truncation from glitching a bunch of digits
178                 seconds = fabs(seconds) + 1.0e-6;
179                 second = seconds;
180                 seconds -= (int64_t)seconds;
181                 thousandths = (int64_t)(seconds*1000) % 1000;
182                 sprintf(text, "%04d.%03d", second, thousandths);
183                 break; }
184
185         case TIME_HMS: {
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                 seconds -= (int64_t)seconds;
191                 thousandths = (int64_t)(seconds*1000) % 1000;
192                 sprintf(text, "%d:%02d:%02d.%03d",
193                         (int)hour, minute, second, thousandths);
194                 break; }
195
196         case TIME_HMS2: {
197                 seconds = fabs(seconds) + 1.0e-6;
198                 hour = seconds/3600;
199                 minute = seconds/60 - hour*60;
200                 second = seconds - (hour*3600 + minute*60);
201                 sprintf(text, "%d:%02d:%02d", (int)hour, minute, second);
202                 break; }
203
204         case TIME_HMS3: {
205                 seconds = fabs(seconds) + 1.0e-6;
206                 hour = seconds/3600;
207                 minute = seconds/60 - hour*60;
208                 second = seconds - (hour*3600 + minute*60);
209                 sprintf(text, "%02d:%02d:%02d", (int)hour, minute, second);
210                 break; }
211
212         case TIME_TIMECODE:
213                 seconds += timecode_offset; // fall thru
214         case TIME_HMSF: {
215                 seconds = fabs(seconds) + 1.0e-6;
216                 hour = seconds/3600;
217                 minute = seconds/60 - hour*60;
218                 second = seconds - (hour*3600 + minute*60);
219                 seconds -= (int64_t)seconds;
220 //              frame = round(frame_rate * (seconds-(int)seconds));
221                 frame = frame_rate*seconds + 1.0e-6;
222                 sprintf(text, "%01d:%02d:%02d:%02d", (int)hour, minute, second, (int)frame);
223                 break; }
224
225         case TIME_SAMPLES: {
226                 sprintf(text, "%09jd", to_int64(seconds * sample_rate));
227                 break; }
228
229         case TIME_SAMPLES_HEX: {
230                 sprintf(text, "%08jx", to_int64(seconds * sample_rate));
231                 break; }
232
233         case TIME_FRAMES: {
234                 frame = to_int64(seconds * frame_rate);
235                 sprintf(text, "%06jd", frame);
236                 break; }
237
238         case TIME_FEET_FRAMES: {
239                 frame = to_int64(seconds * frame_rate);
240                 feet = (int64_t)(frame / frames_per_foot);
241                 sprintf(text, "%05jd-%02jd", feet,
242                         (int64_t)(frame - feet * frames_per_foot));
243                 break; }
244
245         case TIME_MS1: {
246                 seconds = fabs(seconds) + 1.0e-6;
247                 minute = seconds/60;
248                 second = seconds - minute*60;
249                 sprintf(text, "%d:%02d", minute, second);
250                 break; }
251
252         case TIME_MS2: {
253                 int sign = seconds >= 0 ? '+' : '-';
254                 seconds = fabs(seconds) + 1.0e-6;
255                 minute = seconds/60;
256                 second = seconds - minute*60;
257                 sprintf(text, "%c%d:%02d", sign, minute, second);
258                 break; }
259         default: {
260                 *text = 0;
261                 break; }
262         }
263         return text;
264 }
265
266
267 // give text representation as time
268 char* Units::totext(char *text, int64_t samples, int samplerate,
269                 int time_format, float frame_rate, float frames_per_foot,
270                 double timecode_offset)
271 {
272         return totext(text, (double)samples/samplerate, time_format,
273                 samplerate, frame_rate, frames_per_foot, timecode_offset);
274 }
275
276 int64_t Units::get_int64(const char *&bp)
277 {
278         char string[BCTEXTLEN], *sp=&string[0];
279         const char *cp = bp;
280         for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
281         *sp = 0;  bp = cp;
282         return atol(string);
283 }
284
285 double Units::get_double(const char *&bp)
286 {
287         char string[BCTEXTLEN], *sp=&string[0];
288         const char *cp = bp;
289         for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
290         if( *cp == '.' ) {
291                 *sp++ = *cp++;
292                 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
293         }
294         *sp = 0;  bp = cp;
295         return strtod(string,0);
296 }
297
298 void Units::skip_seperators(const char *&bp)
299 {
300         const char *cp = bp;
301         for( int j=0; j<10 && *cp && !isdigit(*cp); ++j ) ++cp;
302         bp = cp;
303 }
304
305 int64_t Units::fromtext(const char *text, int samplerate, int time_format,
306                         float frame_rate, float frames_per_foot,
307                         double timecode_offset)
308 {
309         int64_t hours, total_samples;
310         int minutes, frames, feet;
311         double seconds, total_seconds;
312         int sign = 1;
313
314         switch(time_format) {
315         case TIME_SECONDS: {
316                 total_seconds = get_double(text);
317                 break; }
318
319         case TIME_HMS:
320         case TIME_HMS2:
321         case TIME_HMS3: {
322                 hours = get_int64(text);    skip_seperators(text);
323                 minutes = get_int64(text);  skip_seperators(text);
324                 seconds = get_int64(text);
325                 total_seconds = seconds + minutes*60 + hours*3600;
326                 break; }
327
328         case TIME_TIMECODE:
329         case TIME_HMSF: {
330                 hours = get_int64(text);    skip_seperators(text);
331                 minutes = get_int64(text);  skip_seperators(text);
332                 seconds = get_int64(text);  skip_seperators(text);
333                 frames = get_int64(text);
334                 total_seconds = frames/frame_rate + seconds + minutes*60 + hours*3600;
335                 if( time_format == TIME_TIMECODE )
336                         total_seconds -= timecode_offset;
337                 break; }
338
339         case TIME_SAMPLES: {
340                 return get_int64(text); }
341
342         case TIME_SAMPLES_HEX: {
343                 sscanf(text, "%jx", &total_samples);
344                 return total_samples; }
345
346         case TIME_FRAMES: {
347                 total_seconds = get_double(text) / frame_rate;
348                 break; }
349
350         case TIME_FEET_FRAMES: {
351                 feet = get_int64(text);    skip_seperators(text);
352                 frames = get_int64(text);
353                 total_seconds = (feet*frames_per_foot + frames) / frame_rate;
354                 break; }
355
356         case TIME_MS2: {
357                 switch( *text ) {
358                 case '+':  sign = 1;   ++text;  break;
359                 case '-':  sign = -1;  ++text;  break;
360                 } } // fall through
361         case TIME_MS1: {
362                 minutes = get_int64(text);   skip_seperators(text);
363                 seconds = get_double(text);
364                 total_seconds = sign * (seconds + minutes*60);
365                 break; }
366         default: {
367                 total_seconds = 0;
368                 break; }
369         }
370
371         total_samples = total_seconds * samplerate;
372         return total_samples;
373 }
374
375 double Units::text_to_seconds(const char *text, int samplerate, int time_format,
376                                 float frame_rate, float frames_per_foot,
377                                 double timecode_offset)
378 {
379         return (double)fromtext(text, samplerate, time_format,
380                 frame_rate, frames_per_foot, timecode_offset) / samplerate;
381 }
382
383
384
385
386 int Units::timeformat_totype(char *tcf)
387 {
388         if (!strcmp(tcf,TIME_SECONDS__STR)) return(TIME_SECONDS);
389         if (!strcmp(tcf,TIME_HMS__STR)) return(TIME_HMS);
390         if (!strcmp(tcf,TIME_HMS2__STR)) return(TIME_HMS2);
391         if (!strcmp(tcf,TIME_HMS3__STR)) return(TIME_HMS3);
392         if (!strcmp(tcf,TIME_HMSF__STR)) return(TIME_HMSF);
393         if (!strcmp(tcf,TIME_TIMECODE__STR)) return(TIME_TIMECODE);
394         if (!strcmp(tcf,TIME_SAMPLES__STR)) return(TIME_SAMPLES);
395         if (!strcmp(tcf,TIME_SAMPLES_HEX__STR)) return(TIME_SAMPLES_HEX);
396         if (!strcmp(tcf,TIME_FRAMES__STR)) return(TIME_FRAMES);
397         if (!strcmp(tcf,TIME_FEET_FRAMES__STR)) return(TIME_FEET_FRAMES);
398         return(-1);
399 }
400
401
402 float Units::toframes(int64_t samples, int sample_rate, float framerate)
403 {
404         return (double)samples/sample_rate * framerate;
405 } // give position in frames
406
407 int64_t Units::toframes_round(int64_t samples, int sample_rate, float framerate)
408 {
409 // used in editing
410         float result_f = (float)samples / sample_rate * framerate;
411         int64_t result_l = (int64_t)(result_f + 0.5);
412         return result_l;
413 }
414
415 double Units::fix_framerate(double value)
416 {
417         if(value > 29.5 && value < 30)
418                 value = (double)30000 / (double)1001;
419         else if(value > 59.5 && value < 60)
420                 value = (double)60000 / (double)1001;
421         else if(value > 23.5 && value < 24)
422                 value = (double)24000 / (double)1001;
423         return value;
424 }
425
426 double Units::atoframerate(const char *text)
427 {
428         double result = get_double(text);
429         return fix_framerate(result);
430 }
431
432
433 int64_t Units::tosamples(double frames, int sample_rate, float framerate)
434 {
435         double result = frames/framerate * sample_rate;
436         if(result - (int)result >= 1.0e-6 ) result += 1;
437         return (int64_t)result;
438 } // give position in samples
439
440
441 float Units::xy_to_polar(int x, int y)
442 {
443         float angle = 0.;
444         if(x > 0 && y <= 0)
445                 angle = atan((float)-y / x) / (2*M_PI) * 360;
446         else if(x < 0 && y <= 0)
447                 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
448         else if(x < 0 && y > 0)
449                 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
450         else if(x > 0 && y > 0)
451                 angle = 360 + atan((float)-y / x) / (2*M_PI) * 360;
452         else if(x == 0 && y < 0)
453                 angle = 90;
454         else if(x == 0 && y > 0)
455                 angle = 270;
456         else if(x == 0 && y == 0)
457                 angle = 0;
458         return angle;
459 }
460
461 void Units::polar_to_xy(float angle, int radius, int &x, int &y)
462 {
463         if( angle < 0 )
464                 angle += ((int)(-angle)/360 + 1) * 360;
465         else if( angle >= 360 )
466                 angle -= ((int)(angle)/360) * 360;
467
468         x = (int)(cos(angle / 360 * (2*M_PI)) * radius);
469         y = (int)(-sin(angle / 360 * (2*M_PI)) * radius);
470 }
471
472 int64_t Units::round(double result)
473 {
474         return (int64_t)(result < 0 ? result - 0.5 : result + 0.5);
475 }
476
477 float Units::quantize10(float value)
478 {
479         int64_t temp = (int64_t)(value*10 + 0.5);
480         return temp/10.;
481 }
482
483 float Units::quantize(float value, float precision)
484 {
485         int64_t temp = (int64_t)(value/precision + 0.5);
486         return temp*precision;
487 }
488
489 int64_t Units::to_int64(double result)
490 {
491 // This must round up if result is one sample within ceiling.
492 // Sampling rates below 48000 may cause more problems.
493         return (int64_t)(result < 0 ? (result - 0.005) : (result + 0.005));
494 }
495
496 const char* Units::print_time_format(int time_format, char *string)
497 {
498         const char *fmt = "Unknown";
499         switch(time_format) {
500         case TIME_HMS:         fmt = TIME_HMS_TEXT;                   break;
501         case TIME_HMSF:        fmt = TIME_HMSF_TEXT;                  break;
502         case TIME_SAMPLES:     fmt = TIME_SAMPLES_TEXT;               break;
503         case TIME_SAMPLES_HEX: fmt = TIME_SAMPLES_HEX_TEXT;           break;
504         case TIME_FRAMES:      fmt = TIME_FRAMES_TEXT;                break;
505         case TIME_FEET_FRAMES: fmt = TIME_FEET_FRAMES_TEXT;           break;
506         case TIME_HMS2:
507         case TIME_HMS3:        fmt = TIME_HMS3_TEXT;                  break;
508         case TIME_SECONDS:     fmt = TIME_SECONDS_TEXT;               break;
509         case TIME_MS1:
510         case TIME_MS2:         fmt = TIME_MS2_TEXT;                   break;
511         case TIME_TIMECODE:    fmt = TIME_TIMECODE_TEXT;              break;
512         }
513         return strcpy(string,fmt);
514 }
515
516 int Units::text_to_format(const char *string)
517 {
518         if(!strcmp(string, TIME_HMS_TEXT)) return TIME_HMS;
519         if(!strcmp(string, TIME_HMSF_TEXT)) return TIME_HMSF;
520         if(!strcmp(string, TIME_SAMPLES_TEXT)) return TIME_SAMPLES;
521         if(!strcmp(string, TIME_SAMPLES_HEX_TEXT)) return TIME_SAMPLES_HEX;
522         if(!strcmp(string, TIME_FRAMES_TEXT)) return TIME_FRAMES;
523         if(!strcmp(string, TIME_FEET_FRAMES_TEXT)) return TIME_FEET_FRAMES;
524         if(!strcmp(string, TIME_HMS3_TEXT)) return TIME_HMS3;
525         if(!strcmp(string, TIME_SECONDS_TEXT)) return TIME_SECONDS;
526         if(!strcmp(string, TIME_MS2_TEXT)) return TIME_MS2;
527         if(!strcmp(string, TIME_TIMECODE_TEXT)) return TIME_TIMECODE;
528         return TIME_HMS;
529 }
530
531 char* Units::size_totext(int64_t bytes, char *text)
532 {
533         char string[BCTEXTLEN];
534         static const char *sz[] = { "bytes", "KB", "MB", "GB", "TB" };
535
536         int i = (sizeof(sz) / sizeof(sz[0]));
537         while( --i > 0 && bytes < ((int64_t)1 << (10*i)) );
538
539         if( i > 0 ) {
540                 bytes >>= 10*(i-1);
541                 int frac = bytes % 1000;
542                 sprintf(string, "%jd", bytes/1000);
543                 if( bytes > 1000 ) punctuate(string);
544                 sprintf(text, "%s.%03d %s", string, frac, sz[i]);
545         }
546         else {
547                 sprintf(string, "%jd", bytes);
548                 if( bytes > 1000 ) punctuate(string);
549                 sprintf(text, "%s %s", string, sz[i]);
550         }
551         return text;
552 }
553
554
555 #undef BYTE_ORDER
556 #define BYTE_ORDER ((*(const uint32_t*)"a   ") & 0x00000001)
557
558 void* Units::int64_to_ptr(uint64_t value)
559 {
560         unsigned char *value_dissected = (unsigned char*)&value;
561         void *result;
562         unsigned char *data = (unsigned char*)&result;
563
564 // Must be done behind the compiler's back
565         if(sizeof(void*) == 4) {
566                 if(!BYTE_ORDER) {
567                         data[0] = value_dissected[4];
568                         data[1] = value_dissected[5];
569                         data[2] = value_dissected[6];
570                         data[3] = value_dissected[7];
571                 }
572                 else {
573                         data[0] = value_dissected[0];
574                         data[1] = value_dissected[1];
575                         data[2] = value_dissected[2];
576                         data[3] = value_dissected[3];
577                 }
578         }
579         else {
580                 data[0] = value_dissected[0];
581                 data[1] = value_dissected[1];
582                 data[2] = value_dissected[2];
583                 data[3] = value_dissected[3];
584                 data[4] = value_dissected[4];
585                 data[5] = value_dissected[5];
586                 data[6] = value_dissected[6];
587                 data[7] = value_dissected[7];
588         }
589         return result;
590 }
591
592 uint64_t Units::ptr_to_int64(void *ptr)
593 {
594         unsigned char *ptr_dissected = (unsigned char*)&ptr;
595         int64_t result = 0;
596         unsigned char *data = (unsigned char*)&result;
597 // Don't do this at home.
598         if(sizeof(void*) == 4) {
599                 if(!BYTE_ORDER) {
600                         data[4] = ptr_dissected[0];
601                         data[5] = ptr_dissected[1];
602                         data[6] = ptr_dissected[2];
603                         data[7] = ptr_dissected[3];
604                 }
605                 else {
606                         data[0] = ptr_dissected[0];
607                         data[1] = ptr_dissected[1];
608                         data[2] = ptr_dissected[2];
609                         data[3] = ptr_dissected[3];
610                 }
611         }
612         else {
613                 data[0] = ptr_dissected[0];
614                 data[1] = ptr_dissected[1];
615                 data[2] = ptr_dissected[2];
616                 data[3] = ptr_dissected[3];
617                 data[4] = ptr_dissected[4];
618                 data[5] = ptr_dissected[5];
619                 data[6] = ptr_dissected[6];
620                 data[7] = ptr_dissected[7];
621         }
622         return result;
623 }
624
625 const char* Units::format_to_separators(int time_format)
626 {
627         switch(time_format) {
628                 case TIME_SECONDS:     return "0000.000";
629                 case TIME_HMS:         return "0:00:00.000";
630                 case TIME_HMS2:        return "0:00:00";
631                 case TIME_HMS3:        return "00:00:00";
632                 case TIME_TIMECODE:
633                 case TIME_HMSF:        return "0:00:00:00";
634                 case TIME_SAMPLES:     return 0;
635                 case TIME_SAMPLES_HEX: return 0;
636                 case TIME_FRAMES:      return 0;
637                 case TIME_FEET_FRAMES: return "00000-00";
638                 case TIME_MS1:         return "0:00";
639                 case TIME_MS2:         return "+0:00";
640         }
641         return 0;
642 }
643
644 void Units::punctuate(char *string)
645 {
646         int sep = ',', len = strlen(string), commas = (len - 1) / 3;
647         char *cp = string + len, *bp = cp + commas;
648         *bp = 0;
649         for( int k=3; cp < bp && bp > string; ) {
650                 *--bp = *--cp;
651                 if( --k > 0 ) continue;
652                 *--bp = sep;  k = 3;
653         }
654 }
655
656 void Units::fix_double(double *x)
657 {
658         *x = *x;
659 }
660
661