4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcwindowbase.inc"
30 float* DB::topower_base = 0;
31 int* Freq::freqtable = 0;
34 DB::DB(float infinitygain)
36 this->infinitygain = infinitygain;
38 this->topower = topower_base + -INFINITYGAIN * 10;
42 float DB::fromdb_table()
44 return db = topower[(int)(db*10)];
47 float DB::fromdb_table(float db)
49 if(db > MAXGAIN) db = MAXGAIN;
50 if(db <= INFINITYGAIN) return 0;
51 return db = topower[(int)(db*10)];
56 return pow(10, db/20);
59 float DB::fromdb(float db)
61 return pow(10, db/20);
64 // set db to the power given using a formula
65 float DB::todb(float power)
69 db = 20 * log10(power);
70 if(db < -100) db = -100;
83 Freq::Freq(const Freq& oldfreq)
85 this->freq = oldfreq.freq;
91 while( i<TOTALFREQS && freqtable[i]<freq ) ++i;
95 int Freq::fromfreq(int index)
98 while( i<TOTALFREQS && freqtable[i]<index ) ++i;
102 int Freq::tofreq(int index)
104 if(index >= TOTALFREQS) index = TOTALFREQS - 1;
105 return freqtable[index];
108 // frequency doubles for every OCTAVE slots. OCTAVE must be divisible by 3
115 double Freq::tofreq_f(double index)
117 if( index < 0.5 ) return 0;
118 return 440.0 * pow(2, (double)(index - 421) / OCTAVE);
120 double Freq::fromfreq_f(double f)
122 if( f < 0.5 ) return 0;
123 double result = log(f / 440) / log(2.0) * OCTAVE + 421;
124 return result < 0 ? 0 : result;
127 Freq& Freq::operator++()
129 if(freq < TOTALFREQS) ++freq;
133 Freq& Freq::operator--()
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; }
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
157 Freq::freqtable = new int[TOTALFREQS + 1];
158 for( int i=0; i<=TOTALFREQS; ++i )
159 Freq::freqtable[i] = Freq::tofreq_f(i);
163 delete [] DB::topower_base; DB::topower_base = 0;
164 delete [] Freq::freqtable; Freq::freqtable = 0;
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)
172 int64_t hour, feet, frame;
173 int minute, second, thousandths;
175 switch(time_format) {
177 // add 1.0e-6 to prevent round off truncation from glitching a bunch of digits
178 seconds = fabs(seconds) + 1.0e-6;
180 seconds -= (int64_t)seconds;
181 thousandths = (int64_t)(seconds*1000) % 1000;
182 sprintf(text, "%04d.%03d", second, thousandths);
186 seconds = fabs(seconds) + 1.0e-6;
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);
197 seconds = fabs(seconds) + 1.0e-6;
199 minute = seconds/60 - hour*60;
200 second = seconds - (hour*3600 + minute*60);
201 sprintf(text, "%d:%02d:%02d", (int)hour, minute, second);
205 seconds = fabs(seconds) + 1.0e-6;
207 minute = seconds/60 - hour*60;
208 second = seconds - (hour*3600 + minute*60);
209 sprintf(text, "%02d:%02d:%02d", (int)hour, minute, second);
213 seconds += timecode_offset; // fall thru
215 seconds = fabs(seconds) + 1.0e-6;
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);
226 sprintf(text, "%09jd", to_int64(seconds * sample_rate));
229 case TIME_SAMPLES_HEX: {
230 sprintf(text, "%08jx", to_int64(seconds * sample_rate));
234 frame = to_int64(seconds * frame_rate);
235 sprintf(text, "%06jd", frame);
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));
246 seconds = fabs(seconds) + 1.0e-6;
248 second = seconds - minute*60;
249 sprintf(text, "%d:%02d", minute, second);
253 int sign = seconds >= 0 ? '+' : '-';
254 seconds = fabs(seconds) + 1.0e-6;
256 second = seconds - minute*60;
257 sprintf(text, "%c%d:%02d", sign, minute, second);
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)
272 return totext(text, (double)samples/samplerate, time_format,
273 samplerate, frame_rate, frames_per_foot, timecode_offset);
276 int64_t Units::get_int64(const char *&bp)
278 char string[BCTEXTLEN], *sp=&string[0];
280 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
285 double Units::get_double(const char *&bp)
287 char string[BCTEXTLEN], *sp=&string[0];
289 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
292 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
295 return strtod(string,0);
298 void Units::skip_seperators(const char *&bp)
301 for( int j=0; j<10 && *cp && !isdigit(*cp); ++j ) ++cp;
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)
309 int64_t hours, total_samples;
310 int minutes, frames, feet;
311 double seconds, total_seconds;
314 switch(time_format) {
316 total_seconds = get_double(text);
322 hours = get_int64(text); skip_seperators(text);
323 minutes = get_int64(text); skip_seperators(text);
324 seconds = get_double(text);
325 total_seconds = seconds + minutes*60 + hours*3600;
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_double(text);
334 total_seconds = frames/frame_rate + seconds + minutes*60 + hours*3600;
335 if( time_format == TIME_TIMECODE )
336 total_seconds -= timecode_offset;
340 return get_int64(text); }
342 case TIME_SAMPLES_HEX: {
343 sscanf(text, "%jx", &total_samples);
344 return total_samples; }
347 total_seconds = get_double(text) / frame_rate;
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;
358 case '+': sign = 1; ++text; break;
359 case '-': sign = -1; ++text; break;
362 minutes = get_int64(text); skip_seperators(text);
363 seconds = get_double(text);
364 total_seconds = sign * (seconds + minutes*60);
371 total_samples = total_seconds * samplerate;
372 return total_samples;
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)
379 return (double)fromtext(text, samplerate, time_format,
380 frame_rate, frames_per_foot, timecode_offset) / samplerate;
385 const char *Units::timetype_toformat(int type)
388 case TIME_HMS: return TIME_HMS__STR;
389 case TIME_HMSF: return TIME_HMSF__STR;
390 case TIME_SAMPLES: return TIME_SAMPLES__STR;
391 case TIME_SAMPLES_HEX: return TIME_SAMPLES_HEX__STR;
392 case TIME_FRAMES: return TIME_FRAMES__STR;
393 case TIME_FEET_FRAMES: return TIME_FEET_FRAMES__STR;
394 case TIME_HMS2: return TIME_HMS2__STR;
395 case TIME_HMS3: return TIME_HMS3__STR;
396 case TIME_SECONDS: return TIME_SECONDS__STR;
397 case TIME_MS1: return TIME_MS1__STR;
398 case TIME_MS2: return TIME_MS2__STR;
399 case TIME_TIMECODE: return TIME_TIMECODE__STR;
404 int Units::timeformat_totype(const char *tcf)
406 if (!strcmp(tcf,TIME_SECONDS__STR)) return(TIME_SECONDS);
407 if (!strcmp(tcf,TIME_HMS__STR)) return(TIME_HMS);
408 if (!strcmp(tcf,TIME_HMS2__STR)) return(TIME_HMS2);
409 if (!strcmp(tcf,TIME_HMS3__STR)) return(TIME_HMS3);
410 if (!strcmp(tcf,TIME_HMSF__STR)) return(TIME_HMSF);
411 if (!strcmp(tcf,TIME_TIMECODE__STR)) return(TIME_TIMECODE);
412 if (!strcmp(tcf,TIME_SAMPLES__STR)) return(TIME_SAMPLES);
413 if (!strcmp(tcf,TIME_SAMPLES_HEX__STR)) return(TIME_SAMPLES_HEX);
414 if (!strcmp(tcf,TIME_FRAMES__STR)) return(TIME_FRAMES);
415 if (!strcmp(tcf,TIME_FEET_FRAMES__STR)) return(TIME_FEET_FRAMES);
420 float Units::toframes(int64_t samples, int sample_rate, float framerate)
422 return (double)samples/sample_rate * framerate;
423 } // give position in frames
425 int64_t Units::toframes_round(int64_t samples, int sample_rate, float framerate)
428 float result_f = (float)samples / sample_rate * framerate;
429 int64_t result_l = (int64_t)(result_f + 0.5);
433 double Units::fix_framerate(double value)
435 if(value > 29.5 && value < 30)
436 value = (double)30000 / (double)1001;
437 else if(value > 59.5 && value < 60)
438 value = (double)60000 / (double)1001;
439 else if(value > 23.5 && value < 24)
440 value = (double)24000 / (double)1001;
444 double Units::atoframerate(const char *text)
446 double result = get_double(text);
447 return fix_framerate(result);
451 int64_t Units::tosamples(double frames, int sample_rate, float framerate)
453 double result = frames/framerate * sample_rate;
454 if(result - (int)result >= 1.0e-6 ) result += 1;
455 return (int64_t)result;
456 } // give position in samples
459 float Units::xy_to_polar(int x, int y)
463 angle = atan((float)-y / x) / (2*M_PI) * 360;
464 else if(x < 0 && y <= 0)
465 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
466 else if(x < 0 && y > 0)
467 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
468 else if(x > 0 && y > 0)
469 angle = 360 + atan((float)-y / x) / (2*M_PI) * 360;
470 else if(x == 0 && y < 0)
472 else if(x == 0 && y > 0)
474 else if(x == 0 && y == 0)
479 void Units::polar_to_xy(float angle, int radius, int &x, int &y)
482 angle += ((int)(-angle)/360 + 1) * 360;
483 else if( angle >= 360 )
484 angle -= ((int)(angle)/360) * 360;
486 x = (int)(cos(angle / 360 * (2*M_PI)) * radius);
487 y = (int)(-sin(angle / 360 * (2*M_PI)) * radius);
490 int64_t Units::round(double result)
492 return (int64_t)(result < 0 ? result - 0.5 : result + 0.5);
495 float Units::quantize10(float value)
497 int64_t temp = (int64_t)(value*10 + 0.5);
501 float Units::quantize(float value, float precision)
503 int64_t temp = (int64_t)(value/precision + 0.5);
504 return temp*precision;
507 int64_t Units::to_int64(double result)
509 // This must round up if result is one sample within ceiling.
510 // Sampling rates below 48000 may cause more problems.
511 return (int64_t)(result < 0 ? (result - 0.005) : (result + 0.005));
514 const char* Units::print_time_format(int time_format, char *string)
516 const char *fmt = "Unknown";
517 switch(time_format) {
518 case TIME_HMS: fmt = TIME_HMS_TEXT; break;
519 case TIME_HMSF: fmt = TIME_HMSF_TEXT; break;
520 case TIME_SAMPLES: fmt = TIME_SAMPLES_TEXT; break;
521 case TIME_SAMPLES_HEX: fmt = TIME_SAMPLES_HEX_TEXT; break;
522 case TIME_FRAMES: fmt = TIME_FRAMES_TEXT; break;
523 case TIME_FEET_FRAMES: fmt = TIME_FEET_FRAMES_TEXT; break;
525 case TIME_HMS3: fmt = TIME_HMS3_TEXT; break;
526 case TIME_SECONDS: fmt = TIME_SECONDS_TEXT; break;
528 case TIME_MS2: fmt = TIME_MS2_TEXT; break;
529 case TIME_TIMECODE: fmt = TIME_TIMECODE_TEXT; break;
531 return strcpy(string,fmt);
534 int Units::text_to_format(const char *string)
536 if(!strcmp(string, TIME_HMS_TEXT)) return TIME_HMS;
537 if(!strcmp(string, TIME_HMSF_TEXT)) return TIME_HMSF;
538 if(!strcmp(string, TIME_SAMPLES_TEXT)) return TIME_SAMPLES;
539 if(!strcmp(string, TIME_SAMPLES_HEX_TEXT)) return TIME_SAMPLES_HEX;
540 if(!strcmp(string, TIME_FRAMES_TEXT)) return TIME_FRAMES;
541 if(!strcmp(string, TIME_FEET_FRAMES_TEXT)) return TIME_FEET_FRAMES;
542 if(!strcmp(string, TIME_HMS3_TEXT)) return TIME_HMS3;
543 if(!strcmp(string, TIME_SECONDS_TEXT)) return TIME_SECONDS;
544 if(!strcmp(string, TIME_MS2_TEXT)) return TIME_MS2;
545 if(!strcmp(string, TIME_TIMECODE_TEXT)) return TIME_TIMECODE;
549 char* Units::size_totext(int64_t bytes, char *text)
551 char string[BCTEXTLEN];
552 static const char *sz[] = { "bytes", "KB", "MB", "GB", "TB" };
554 int i = (sizeof(sz) / sizeof(sz[0]));
555 while( --i > 0 && bytes < ((int64_t)1 << (10*i)) );
559 int frac = bytes % 1000;
560 sprintf(string, "%jd", bytes/1000);
561 if( bytes > 1000 ) punctuate(string);
562 sprintf(text, "%s.%03d %s", string, frac, sz[i]);
565 sprintf(string, "%jd", bytes);
566 if( bytes > 1000 ) punctuate(string);
567 sprintf(text, "%s %s", string, sz[i]);
574 #define BYTE_ORDER ((*(const uint32_t*)"a ") & 0x00000001)
576 void* Units::int64_to_ptr(uint64_t value)
578 unsigned char *value_dissected = (unsigned char*)&value;
580 unsigned char *data = (unsigned char*)&result;
582 // Must be done behind the compiler's back
583 if(sizeof(void*) == 4) {
585 data[0] = value_dissected[4];
586 data[1] = value_dissected[5];
587 data[2] = value_dissected[6];
588 data[3] = value_dissected[7];
591 data[0] = value_dissected[0];
592 data[1] = value_dissected[1];
593 data[2] = value_dissected[2];
594 data[3] = value_dissected[3];
598 data[0] = value_dissected[0];
599 data[1] = value_dissected[1];
600 data[2] = value_dissected[2];
601 data[3] = value_dissected[3];
602 data[4] = value_dissected[4];
603 data[5] = value_dissected[5];
604 data[6] = value_dissected[6];
605 data[7] = value_dissected[7];
610 uint64_t Units::ptr_to_int64(void *ptr)
612 unsigned char *ptr_dissected = (unsigned char*)&ptr;
614 unsigned char *data = (unsigned char*)&result;
615 // Don't do this at home.
616 if(sizeof(void*) == 4) {
618 data[4] = ptr_dissected[0];
619 data[5] = ptr_dissected[1];
620 data[6] = ptr_dissected[2];
621 data[7] = ptr_dissected[3];
624 data[0] = ptr_dissected[0];
625 data[1] = ptr_dissected[1];
626 data[2] = ptr_dissected[2];
627 data[3] = ptr_dissected[3];
631 data[0] = ptr_dissected[0];
632 data[1] = ptr_dissected[1];
633 data[2] = ptr_dissected[2];
634 data[3] = ptr_dissected[3];
635 data[4] = ptr_dissected[4];
636 data[5] = ptr_dissected[5];
637 data[6] = ptr_dissected[6];
638 data[7] = ptr_dissected[7];
643 const char* Units::format_to_separators(int time_format)
645 switch(time_format) {
646 case TIME_SECONDS: return "0000.000";
647 case TIME_HMS: return "0:00:00.000";
648 case TIME_HMS2: return "0:00:00";
649 case TIME_HMS3: return "00:00:00";
651 case TIME_HMSF: return "0:00:00:00";
652 case TIME_SAMPLES: return 0;
653 case TIME_SAMPLES_HEX: return 0;
654 case TIME_FRAMES: return 0;
655 case TIME_FEET_FRAMES: return "00000-00";
656 case TIME_MS1: return "0:00";
657 case TIME_MS2: return "+0:00";
662 void Units::punctuate(char *string)
664 int sep = ',', len = strlen(string), commas = (len - 1) / 3;
665 char *cp = string + len, *bp = cp + commas;
667 for( int k=3; cp < bp && bp > string; ) {
669 if( --k > 0 ) continue;
674 void Units::fix_double(double *x)