r717: Made the highlighted text color of the menus WHITE
[cinelerra_cv/mob.git] / guicast / units.C
blob03d61bb574c436acb5d3cbad523ff30315f2eca9
1 #include "bcwindowbase.inc"
2 #include "units.h"
5 #include <stdlib.h>
6 #include <string.h>
8 // NOTE: DB::allocated is the original allocation, to which we keep a
9 // pointer so that in theory we could have a destructor. DB::topower
10 // is a pointer into the middle of DB::allocated, which allows us to
11 // do lookups using negative array coefficients.
12 float* DB::topower = 0;
13 float* DB::allocated = NULL;
15 int* Freq::freqtable = 0;
18 DB::DB(float infinitygain)
20         this->infinitygain = infinitygain;
21         if(allocated == NULL)
22         {
23                 int i;
24                 float value;
26                 // db to power table
27                 allocated = new float[(MAXGAIN - INFINITYGAIN) * 10 + 1];
28                 topower = allocated + (-INFINITYGAIN * 10);
29                 for(i = INFINITYGAIN * 10; i <= MAXGAIN * 10; i++)
30                 {
31                         topower[i] = pow(10, (float)i / 10 / 20);
32                         
33 //printf("%f %f\n", (float)i/10, topower[i]);
34                 }
35                 topower[INFINITYGAIN * 10] = 0;   // infinity gain
36         }
37         db = 0;
40 // FUTURE: would bounds checking be possible here?  Or at least make private?
41 float DB::fromdb_table() 
42
43         return db = topower[(int)(db * 10)]; 
46 float DB::fromdb_table(float db) 
47
48         if(db > MAXGAIN) db = MAXGAIN;
49         if(db <= INFINITYGAIN) return 0;
50         return db = topower[(int)(db * 10)]; 
53 float DB::fromdb()
55         return pow(10, db / 20);
58 float DB::fromdb(float db)
60         return pow(10, db / 20);
63 // set db to the power given using a formula
64 float DB::todb(float power)
66         float db;
67         if(power == 0) 
68                 db = -100;
69         else 
70         {
71                 db = (float)(20 * log10(power));
72                 if(db < -100) db = -100;
73         }
74         return db;
78 Freq::Freq()
80         init_table();
81         freq = 0;
84 Freq::Freq(const Freq& oldfreq)
86         this->freq = oldfreq.freq;
89 void Freq::init_table()
91         if(!freqtable)
92         {
93                 freqtable = new int[TOTALFREQS + 1];
94 // starting frequency
95                 double freq1 = 27.5, freq2 = 55;  
96 // Some number divisable by three.  This depends on the value of TOTALFREQS
97                 int scale = 105;   
99                 freqtable[0] = 0;
100                 for(int i = 1, j = 0; i <= TOTALFREQS; i++, j++)
101                 {
102                 freqtable[i] = (int)(freq1 + (freq2 - freq1) / scale * j + 0.5);
103 //printf("Freq::init_table %d\n", freqtable[i]);
104                 if(j >= scale)
105                         {
106                                 freq1 = freq2;
107                                 freq2 *= 2;
108                                 j = 0;
109                         }
110                 }
111         }
114 int Freq::fromfreq() 
116         int i;
118         for(i = 0; i < TOTALFREQS && freqtable[i] < freq; i++)
119         ;
120         return(i);
123 int Freq::fromfreq(int index) 
125         int i;
127         init_table();
128         for(i = 0; i < TOTALFREQS && freqtable[i] < index; i++)
129         ;
130         return(i);
133 int Freq::tofreq(int index)
135         init_table();
136         int freq = freqtable[index]; 
137         return freq; 
140 Freq& Freq::operator++() 
142         if(freq < TOTALFREQS) freq++;
143         return *this;
145         
146 Freq& Freq::operator--()
148         if(freq > 0) freq--;
149         return *this;
151         
152 int Freq::operator>(Freq &newfreq) { return freq > newfreq.freq; }
153 int Freq::operator<(Freq &newfreq) { return freq < newfreq.freq; }
154 Freq& Freq::operator=(const Freq &newfreq) { freq = newfreq.freq; return *this; }
155 int Freq::operator=(const int newfreq) { freq = newfreq; return newfreq; }
156 int Freq::operator!=(Freq &newfreq) { return freq != newfreq.freq; }
157 int Freq::operator==(Freq &newfreq) { return freq == newfreq.freq; }
158 int Freq::operator==(int newfreq) { return freq == newfreq; }
160 char* Units::totext(char *text, 
161                         double seconds, 
162                         int time_format, 
163                         int sample_rate, 
164                         float frame_rate, 
165                         float frames_per_foot)    // give text representation as time
167         int hour, minute, second, thousandths;
168         int64_t frame, feet;
170         switch(time_format)
171         {
172                 case TIME_SECONDS:
173                         seconds = fabs(seconds);
174                         sprintf(text, "%04d.%03d", (int)seconds, (int)(seconds * 1000) % 1000);
175                         return text;
176                         break;
178                 case TIME_HMS:
179                         seconds = fabs(seconds);
180                         hour = (int)(seconds / 3600);
181                         minute = (int)(seconds / 60 - hour * 60);
182                         second = (int)seconds - (int64_t)hour * 3600 - (int64_t)minute * 60;
183                         thousandths = (int)(seconds * 1000) % 1000;
184                         sprintf(text, "%d:%02d:%02d.%03d", 
185                                 hour, 
186                                 minute, 
187                                 second, 
188                                 thousandths);
189                         return text;
190                   break;
191                 
192                 case TIME_HMS2:
193                 {
194                         float second;
195                         seconds = fabs(seconds);
196                         hour = (int)(seconds / 3600);
197                         minute = (int)(seconds / 60 - hour * 60);
198                         second = (float)seconds - (int64_t)hour * 3600 - (int64_t)minute * 60;
199                         sprintf(text, "%d:%02d:%02d", hour, minute, (int)second);
200                         return text;
201                 }
202                   break;
204                 case TIME_HMS3:
205                 {
206                         float second;
207                         seconds = fabs(seconds);
208                         hour = (int)(seconds / 3600);
209                         minute = (int)(seconds / 60 - hour * 60);
210                         second = (float)seconds - (int64_t)hour * 3600 - (int64_t)minute * 60;
211                         sprintf(text, "%02d:%02d:%02d", hour, minute, (int)second);
212                         return text;
213                 }
214                   break;
216                 case TIME_HMSF:
217                 {
218                         int second;
219                         seconds = fabs(seconds);
220                         hour = (int)(seconds / 3600);
221                         minute = (int)(seconds / 60 - hour * 60);
222                         second = (int)(seconds - hour * 3600 - minute * 60);
223 //                      frame = (int64_t)round(frame_rate * 
224 //                               (float)((float)seconds - (int64_t)hour * 3600 - (int64_t)minute * 60 - second));
225 //                      sprintf(text, "%01d:%02d:%02d:%02ld", hour, minute, second, frame);
226                         frame = (int64_t)((double)frame_rate * 
227                                         seconds + 
228                                         0.0000001) - 
229                                 (int64_t)((double)frame_rate * 
230                                         (hour * 
231                                         3600 + 
232                                         minute * 
233                                         60 + 
234                                         second) + 
235                                 0.0000001);   
236                         sprintf(text, "%01d:%02d:%02d:%02ld", hour, minute, second, frame);
237                         return text;
238                 }
239                         break;
240                         
241                 case TIME_SAMPLES:
242                         sprintf(text, "%09ld", to_int64(seconds * sample_rate));
243                         break;
244                 
245                 case TIME_SAMPLES_HEX:
246                         sprintf(text, "%08x", to_int64(seconds * sample_rate));
247                         break;
248                 
249                 case TIME_FRAMES:
250                         frame = to_int64(seconds * frame_rate);
251                         sprintf(text, "%06ld", frame);
252                         return text;
253                         break;
254                 
255                 case TIME_FEET_FRAMES:
256                         frame = to_int64(seconds * frame_rate);
257                         feet = (int64_t)(frame / frames_per_foot);
258                         sprintf(text, "%05ld-%02ld", 
259                                 feet, 
260                                 (int64_t)(frame - feet * frames_per_foot));
261                         return text;
262                         break;
263         }
264         return text;
268 // give text representation as time
269 char* Units::totext(char *text, 
270                 int64_t samples, 
271                 int samplerate, 
272                 int time_format, 
273                 float frame_rate,
274                 float frames_per_foot)
276         return totext(text, (double)samples / samplerate, time_format, samplerate, frame_rate, frames_per_foot);
277 }    
279 int64_t Units::fromtext(char *text, 
280                         int samplerate, 
281                         int time_format, 
282                         float frame_rate,
283                         float frames_per_foot)
285         int64_t hours, minutes, frames, total_samples, i, j;
286         int64_t feet;
287         double seconds;
288         char string[BCTEXTLEN];
289         
290         switch(time_format)
291         {
292                 case TIME_SECONDS:
293                         seconds = atof(text);
294                         return (int64_t)(seconds * samplerate);
295                         break;
297                 case TIME_HMS:
298                 case TIME_HMS2:
299                 case TIME_HMS3:
300 // get hours
301                         i = 0;
302                         j = 0;
303                         while(text[i] >=48 && text[i] <= 57 && j < 10) string[j++] = text[i++];
304                         string[j] = 0;
305                         hours = atol(string);
306 // get minutes
307                         j = 0;
308 // skip separator
309                         while((text[i] < 48 || text[i] > 57) && text[i] != 0) i++;
310                         while(text[i] >=48 && text[i] <= 57 && j < 10) string[j++] = text[i++];
311                         string[j] = 0;
312                         minutes = atol(string);
313                         
314 // get seconds
315                         j = 0;
316 // skip separator
317                         while((text[i] < 48 || text[i] > 57) && text[i] != 0) i++;
318                         while((text[i] == '.' || (text[i] >=48 && text[i] <= 57)) && j < 10) string[j++] = text[i++];
319                         string[j] = 0;
320                         seconds = atof(string);
322                         total_samples = (uint64_t)(((double)seconds + minutes * 60 + hours * 3600) * samplerate);
323                         return total_samples;
324                         break;
326                 case TIME_HMSF:
327 // get hours
328                         i = 0;
329                         j = 0;
330                         while(text[i] >=48 && text[i] <= 57 && j < 10) string[j++] = text[i++];
331                         string[j] = 0;
332                         hours = atol(string);
333                         
334 // get minutes
335                         j = 0;
336 // skip separator
337                         while((text[i] < 48 || text[i] > 57) && text[i] != 0) i++;
338                         while(text[i] >=48 && text[i] <= 57 && j < 10) string[j++] = text[i++];
339                         string[j] = 0;
340                         minutes = atol(string);
341                         
342 // get seconds
343                         j = 0;
344 // skip separator
345                         while((text[i] < 48 || text[i] > 57) && text[i] != 0) i++;
346                         while(text[i] >=48 && text[i] <= 57 && j < 10) string[j++] = text[i++];
347                         string[j] = 0;
348                         seconds = atof(string);
349                         
350 // skip separator
351                         while((text[i] < 48 || text[i] > 57) && text[i] != 0) i++;
352 // get frames
353                         j = 0;
354                         while(text[i] >=48 && text[i] <= 57 && j < 10) string[j++] = text[i++];
355                         string[j] = 0;
356                         frames = atol(string);
357                         
358                         total_samples = (int64_t)(((float)frames / frame_rate + seconds + minutes*60 + hours*3600) * samplerate);
359                         return total_samples;
360                         break;
362                 case TIME_SAMPLES:
363                         return atol(text);
364                         break;
365                 
366                 case TIME_SAMPLES_HEX:
367                         sscanf(text, "%x", &total_samples);
368                         return total_samples;
369                 
370                 case TIME_FRAMES:
371                         return (int64_t)(atof(text) / frame_rate * samplerate);
372                         break;
373                 
374                 case TIME_FEET_FRAMES:
375 // Get feet
376                         i = 0;
377                         j = 0;
378                         while(text[i] >=48 && text[i] <= 57 && text[i] != 0 && j < 10) string[j++] = text[i++];
379                         string[j] = 0;
380                         feet = atol(string);
382 // skip separator
383                         while((text[i] < 48 || text[i] > 57) && text[i] != 0) i++;
385 // Get frames
386                         j = 0;
387                         while(text[i] >=48 && text[i] <= 57 && text[i] != 0 && j < 10) string[j++] = text[i++];
388                         string[j] = 0;
389                         frames = atol(string);
390                         return (int64_t)(((float)feet * frames_per_foot + frames) / frame_rate * samplerate);
391                         break;
392         }
393         return 0;
396 double Units::text_to_seconds(char *text, 
397                                 int samplerate, 
398                                 int time_format, 
399                                 float frame_rate, 
400                                 float frames_per_foot)
402         return (double)fromtext(text, 
403                 samplerate, 
404                 time_format, 
405                 frame_rate, 
406                 frames_per_foot) / samplerate;
414 float Units::toframes(int64_t samples, int sample_rate, float framerate) 
416         return (float)samples / sample_rate * framerate; 
417 } // give position in frames
419 int64_t Units::toframes_round(int64_t samples, int sample_rate, float framerate) 
421 // used in editing
422         float result_f = (float)samples / sample_rate * framerate; 
423         int64_t result_l = (int64_t)(result_f + 0.5);
424         return result_l;
427 double Units::fix_framerate(double value)
429         if(value > 29.5 && value < 30) 
430                 value = (double)30000 / (double)1001;
431         else
432         if(value > 59.5 && value < 60) 
433                 value = (double)60000 / (double)1001;
434         else
435         if(value > 23.5 && value < 24) 
436                 value = (double)24000 / (double)1001;
437         
438         return value;
441 double Units::atoframerate(char *text)
443         double result = atof(text);
444         return fix_framerate(result);
448 int64_t Units::tosamples(float frames, int sample_rate, float framerate) 
450         float result = (frames / framerate * sample_rate);
451         
452         if(result - (int)result) result += 1;
453         return (int64_t)result;
454 } // give position in samples
457 float Units::xy_to_polar(int x, int y)
459         float angle;
460         if(x > 0 && y <= 0)
461         {
462                 angle = atan((float)-y / x) / (2 * M_PI) * 360;
463         }
464         else
465         if(x < 0 && y <= 0)
466         {
467                 angle = 180 - atan((float)-y / -x) / (2 * M_PI) * 360;
468         }
469         else
470         if(x < 0 && y > 0)
471         {
472                 angle = 180 - atan((float)-y / -x) / (2 * M_PI) * 360;
473         }
474         else
475         if(x > 0 && y > 0)
476         {
477                 angle = 360 + atan((float)-y / x) / (2 * M_PI) * 360;
478         }
479         else
480         if(x == 0 && y < 0)
481         {
482                 angle = 90;
483         }
484         else
485         if(x == 0 && y > 0)
486         {
487                 angle = 270;
488         }
489         else
490         if(x == 0 && y == 0)
491         {
492                 angle = 0;
493         }
495         return angle;
498 void Units::polar_to_xy(float angle, int radius, int &x, int &y)
500         while(angle < 0) angle += 360;
502         x = (int)(cos(angle / 360 * (2 * M_PI)) * radius);
503         y = (int)(-sin(angle / 360 * (2 * M_PI)) * radius);
506 int64_t Units::round(double result)
508         return (int64_t)(result < 0 ? result - 0.5 : result + 0.5);
511 float Units::quantize10(float value)
513         int64_t temp = (int64_t)(value * 10 + 0.5);
514         value = (float)temp / 10;
515         return value;
518 float Units::quantize(float value, float precision)
520         int64_t temp = (int64_t)(value / precision + 0.5);
521         value = (float)temp * precision;
522         return value;
526 int64_t Units::to_int64(double result)
528 // This must round up if result is one sample within cieling.
529 // Sampling rates below 48000 may cause more problems.
530         return (int64_t)(result < 0 ? (result - 0.005) : (result + 0.005));
533 char* Units::print_time_format(int time_format, char *string)
535         switch(time_format)
536         {
537                 case 0: sprintf(string, "Hours:Minutes:Seconds.xxx"); break;
538                 case 1: sprintf(string, "Hours:Minutes:Seconds:Frames"); break;
539                 case 2: sprintf(string, "Samples"); break;
540                 case 3: sprintf(string, "Hex Samples"); break;
541                 case 4: sprintf(string, "Frames"); break;
542                 case 5: sprintf(string, "Feet-frames"); break;
543                 case 8: sprintf(string, "Seconds"); break;
544         }
545         
546         return string;
549 #undef BYTE_ORDER
550 #define BYTE_ORDER ((*(u_int32_t*)"a   ") & 0x00000001)
552 void* Units::int64_to_ptr(uint64_t value)
554         unsigned char *value_dissected = (unsigned char*)&value;
555         void *result;
556         unsigned char *data = (unsigned char*)&result;
558 // Must be done behind the compiler's back
559         if(sizeof(void*) == 4)
560         {
561                 if(!BYTE_ORDER)
562                 {
563                         data[0] = value_dissected[4];
564                         data[1] = value_dissected[5];
565                         data[2] = value_dissected[6];
566                         data[3] = value_dissected[7];
567                 }
568                 else
569                 {
570                         data[0] = value_dissected[0];
571                         data[1] = value_dissected[1];
572                         data[2] = value_dissected[2];
573                         data[3] = value_dissected[3];
574                 }
575         }
576         else
577         {
578                 data[0] = value_dissected[0];
579                 data[1] = value_dissected[1];
580                 data[2] = value_dissected[2];
581                 data[3] = value_dissected[3];
582                 data[4] = value_dissected[4];
583                 data[5] = value_dissected[5];
584                 data[6] = value_dissected[6];
585                 data[7] = value_dissected[7];
586         }
587         return result;
590 uint64_t Units::ptr_to_int64(void *ptr)
592         unsigned char *ptr_dissected = (unsigned char*)&ptr;
593         int64_t result = 0;
594         unsigned char *data = (unsigned char*)&result;
595 // Don't do this at home.
596         if(sizeof(void*) == 4)
597         {
598                 if(!BYTE_ORDER)
599                 {
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                 {
607                         data[0] = ptr_dissected[0];
608                         data[1] = ptr_dissected[1];
609                         data[2] = ptr_dissected[2];
610                         data[3] = ptr_dissected[3];
611                 }
612         }
613         else
614         {
615                 data[0] = ptr_dissected[0];
616                 data[1] = ptr_dissected[1];
617                 data[2] = ptr_dissected[2];
618                 data[3] = ptr_dissected[3];
619                 data[4] = ptr_dissected[4];
620                 data[5] = ptr_dissected[5];
621                 data[6] = ptr_dissected[6];
622                 data[7] = ptr_dissected[7];
623         }
624         return result;
627 char* Units::format_to_separators(int time_format)
629         switch(time_format)
630         {
631                 case TIME_SECONDS:     return "0000.000";
632                 case TIME_HMS:         return "0:00:00.000";
633                 case TIME_HMS2:        return "0:00:00";
634                 case TIME_HMS3:        return "00:00:00";
635                 case TIME_HMSF:        return "0:00:00:00";
636                 case TIME_SAMPLES:     return 0;
637                 case TIME_SAMPLES_HEX: return 0;
638                 case TIME_FRAMES:      return 0;
639                 case TIME_FEET_FRAMES: return "00000-00";
640         }
641         return 0;
644 void Units::punctuate(char *string)
646         int len = strlen(string);
647         int commas = (len - 1) / 3;
648         for(int i = len + commas, j = len, k; j >= 0 && i >= 0; i--, j--)
649         {
650                 k = (len - j - 1) / 3;
651                 if(k * 3 == len - j - 1 && j != len - 1 && string[j] != 0)
652                 {
653                         string[i--] = ',';
654                 }
656                 string[i] = string[j];
657         }