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 = 0;
31 float* DB::topower_base = 0;
32 int* Freq::freqtable = 0;
35 DB::DB(float infinitygain)
37 this->infinitygain = infinitygain;
38 if(!topower) { // db to power table
39 topower_base = new float[(MAXGAIN - INFINITYGAIN) * 10 + 1];
40 topower = topower_base + -INFINITYGAIN * 10;
41 for(int i = INFINITYGAIN * 10; i <= MAXGAIN * 10; i++) {
42 topower[i] = pow(10, (float)i / 10 / 20);
43 //printf("%f %f\n", (float)i/10, topower[i]);
45 topower[INFINITYGAIN * 10] = 0; // infinity gain
50 float DB::fromdb_table()
52 return db = topower[(int)(db*10)];
55 float DB::fromdb_table(float db)
57 if(db > MAXGAIN) db = MAXGAIN;
58 if(db <= INFINITYGAIN) return 0;
59 return db = topower[(int)(db*10)];
64 return pow(10, db/20);
67 float DB::fromdb(float db)
69 return pow(10, db/20);
72 // set db to the power given using a formula
73 float DB::todb(float power)
77 db = 20 * log10(power);
78 if(db < -100) db = -100;
88 if( !freqtable ) init_table();
92 Freq::Freq(const Freq& oldfreq)
94 this->freq = oldfreq.freq;
97 void Freq::init_table()
99 freqtable = new int[TOTALFREQS + 1];
100 // starting frequency
101 double freq1 = 27.5, freq2 = 55;
102 // Some number divisable by three. This depends on the value of TOTALFREQS
106 for(int i = 1, j = 0; i <= TOTALFREQS; i++, j++) {
107 freqtable[i] = (int)(freq1 + (freq2 - freq1) / scale * j + 0.5);
108 //printf("Freq::init_table %d\n", freqtable[i]);
120 if( !freqtable ) init_table();
121 while( i<TOTALFREQS && freqtable[i]<freq ) ++i;
125 int Freq::fromfreq(int index)
128 if( !freqtable ) init_table();
129 while( i<TOTALFREQS && freqtable[i]<index ) ++i;
133 int Freq::tofreq(int index)
135 if( !freqtable ) init_table();
136 if(index >= TOTALFREQS) index = TOTALFREQS - 1;
137 return freqtable[index];
140 Freq& Freq::operator++()
142 if(freq < TOTALFREQS) ++freq;
146 Freq& Freq::operator--()
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 // give text representation as time
161 char* Units::totext(char *text, double seconds, int time_format,
162 int sample_rate, float frame_rate, float frames_per_foot)
164 int64_t hour, feet, frame;
165 int minute, second, thousandths;
167 switch(time_format) {
169 // add 1.0e-6 to prevent round off truncation from glitching a bunch of digits
170 seconds = fabs(seconds) + 1.0e-6;
172 seconds -= (int64_t)seconds;
173 thousandths = (int64_t)(seconds*1000) % 1000;
174 sprintf(text, "%04d.%03d", second, thousandths);
178 seconds = fabs(seconds) + 1.0e-6;
180 minute = seconds/60 - hour*60;
181 second = seconds - (hour*3600 + minute*60);
182 seconds -= (int64_t)seconds;
183 thousandths = (int64_t)(seconds*1000) % 1000;
184 sprintf(text, "%d:%02d:%02d.%03d",
185 (int)hour, minute, second, thousandths);
189 seconds = fabs(seconds) + 1.0e-6;
191 minute = seconds/60 - hour*60;
192 second = seconds - (hour*3600 + minute*60);
193 sprintf(text, "%d:%02d:%02d", (int)hour, minute, second);
197 seconds = fabs(seconds) + 1.0e-6;
199 minute = seconds/60 - hour*60;
200 second = seconds - (hour*3600 + minute*60);
201 sprintf(text, "%02d:%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 seconds -= (int64_t)seconds;
210 // frame = round(frame_rate * (seconds-(int)seconds));
211 frame = frame_rate*seconds + 1.0e-6;
212 sprintf(text, "%01d:%02d:%02d:%02d", (int)hour, minute, second, (int)frame);
216 sprintf(text, "%09jd", to_int64(seconds * sample_rate));
219 case TIME_SAMPLES_HEX: {
220 sprintf(text, "%08jx", to_int64(seconds * sample_rate));
224 frame = to_int64(seconds * frame_rate);
225 sprintf(text, "%06jd", frame);
228 case TIME_FEET_FRAMES: {
229 frame = to_int64(seconds * frame_rate);
230 feet = (int64_t)(frame / frames_per_foot);
231 sprintf(text, "%05jd-%02jd", feet,
232 (int64_t)(frame - feet * frames_per_foot));
236 seconds = fabs(seconds) + 1.0e-6;
238 second = seconds - minute*60;
239 sprintf(text, "%d:%02d", minute, second);
243 int sign = seconds >= 0 ? '+' : '-';
244 seconds = fabs(seconds) + 1.0e-6;
246 second = seconds - minute*60;
247 sprintf(text, "%c%d:%02d", sign, minute, second);
257 // give text representation as time
258 char* Units::totext(char *text, int64_t samples, int samplerate,
259 int time_format, float frame_rate, float frames_per_foot)
261 return totext(text, (double)samples/samplerate, time_format,
262 samplerate, frame_rate, frames_per_foot);
265 int64_t Units::get_int64(const char *&bp)
267 char string[BCTEXTLEN], *sp=&string[0];
269 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
274 double Units::get_double(const char *&bp)
276 char string[BCTEXTLEN], *sp=&string[0];
278 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
281 for( int j=0; j<10 && isdigit(*cp); ++j ) *sp++ = *cp++;
284 return strtod(string,0);
287 void Units::skip_seperators(const char *&bp)
290 for( int j=0; j<10 && *cp && !isdigit(*cp); ++j ) ++cp;
294 int64_t Units::fromtext(const char *text, int samplerate, int time_format,
295 float frame_rate, float frames_per_foot)
297 int64_t hours, total_samples;
298 int minutes, frames, feet;
299 double seconds, total_seconds;
302 switch(time_format) {
304 total_seconds = get_double(text);
310 hours = get_int64(text); skip_seperators(text);
311 minutes = get_int64(text); skip_seperators(text);
312 seconds = get_int64(text);
313 total_seconds = seconds + minutes*60 + hours*3600;
317 hours = get_int64(text); skip_seperators(text);
318 minutes = get_int64(text); skip_seperators(text);
319 seconds = get_int64(text); skip_seperators(text);
320 frames = get_int64(text);
321 total_seconds = frames/frame_rate + seconds + minutes*60 + hours*3600;
325 return get_int64(text); }
327 case TIME_SAMPLES_HEX: {
328 sscanf(text, "%jx", &total_samples);
329 return total_samples; }
332 total_seconds = get_double(text) / frame_rate;
335 case TIME_FEET_FRAMES: {
336 feet = get_int64(text); skip_seperators(text);
337 frames = get_int64(text);
338 total_seconds = (feet*frames_per_foot + frames) / frame_rate;
343 case '+': sign = 1; ++text; break;
344 case '-': sign = -1; ++text; break;
347 minutes = get_int64(text); skip_seperators(text);
348 seconds = get_double(text);
349 total_seconds = sign * (seconds + minutes*60);
356 total_samples = total_seconds * samplerate;
357 return total_samples;
360 double Units::text_to_seconds(const char *text, int samplerate, int time_format,
361 float frame_rate, float frames_per_foot)
363 return (double)fromtext(text, samplerate, time_format,
364 frame_rate, frames_per_foot) / samplerate;
370 int Units::timeformat_totype(char *tcf)
372 if (!strcmp(tcf,TIME_SECONDS__STR)) return(TIME_SECONDS);
373 if (!strcmp(tcf,TIME_HMS__STR)) return(TIME_HMS);
374 if (!strcmp(tcf,TIME_HMS2__STR)) return(TIME_HMS2);
375 if (!strcmp(tcf,TIME_HMS3__STR)) return(TIME_HMS3);
376 if (!strcmp(tcf,TIME_HMSF__STR)) return(TIME_HMSF);
377 if (!strcmp(tcf,TIME_SAMPLES__STR)) return(TIME_SAMPLES);
378 if (!strcmp(tcf,TIME_SAMPLES_HEX__STR)) return(TIME_SAMPLES_HEX);
379 if (!strcmp(tcf,TIME_FRAMES__STR)) return(TIME_FRAMES);
380 if (!strcmp(tcf,TIME_FEET_FRAMES__STR)) return(TIME_FEET_FRAMES);
385 float Units::toframes(int64_t samples, int sample_rate, float framerate)
387 return (double)samples/sample_rate * framerate;
388 } // give position in frames
390 int64_t Units::toframes_round(int64_t samples, int sample_rate, float framerate)
393 float result_f = (float)samples / sample_rate * framerate;
394 int64_t result_l = (int64_t)(result_f + 0.5);
398 double Units::fix_framerate(double value)
400 if(value > 29.5 && value < 30)
401 value = (double)30000 / (double)1001;
402 else if(value > 59.5 && value < 60)
403 value = (double)60000 / (double)1001;
404 else if(value > 23.5 && value < 24)
405 value = (double)24000 / (double)1001;
409 double Units::atoframerate(const char *text)
411 double result = get_double(text);
412 return fix_framerate(result);
416 int64_t Units::tosamples(double frames, int sample_rate, float framerate)
418 double result = frames/framerate * sample_rate;
419 if(result - (int)result >= 1.0e-6 ) result += 1;
420 return (int64_t)result;
421 } // give position in samples
424 float Units::xy_to_polar(int x, int y)
428 angle = atan((float)-y / x) / (2*M_PI) * 360;
429 else if(x < 0 && y <= 0)
430 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
431 else if(x < 0 && y > 0)
432 angle = 180 - atan((float)-y / -x) / (2*M_PI) * 360;
433 else if(x > 0 && y > 0)
434 angle = 360 + atan((float)-y / x) / (2*M_PI) * 360;
435 else if(x == 0 && y < 0)
437 else if(x == 0 && y > 0)
439 else if(x == 0 && y == 0)
444 void Units::polar_to_xy(float angle, int radius, int &x, int &y)
447 angle += ((int)(-angle)/360 + 1) * 360;
448 else if( angle >= 360 )
449 angle -= ((int)(angle)/360) * 360;
451 x = (int)(cos(angle / 360 * (2*M_PI)) * radius);
452 y = (int)(-sin(angle / 360 * (2*M_PI)) * radius);
455 int64_t Units::round(double result)
457 return (int64_t)(result < 0 ? result - 0.5 : result + 0.5);
460 float Units::quantize10(float value)
462 int64_t temp = (int64_t)(value*10 + 0.5);
466 float Units::quantize(float value, float precision)
468 int64_t temp = (int64_t)(value/precision + 0.5);
469 return temp*precision;
472 int64_t Units::to_int64(double result)
474 // This must round up if result is one sample within ceiling.
475 // Sampling rates below 48000 may cause more problems.
476 return (int64_t)(result < 0 ? (result - 0.005) : (result + 0.005));
479 const char* Units::print_time_format(int time_format, char *string)
481 const char *fmt = "Unknown";
482 switch(time_format) {
483 case TIME_HMS: fmt = TIME_HMS_TEXT; break;
484 case TIME_HMSF: fmt = TIME_HMSF_TEXT; break;
485 case TIME_SAMPLES: fmt = TIME_SAMPLES_TEXT; break;
486 case TIME_SAMPLES_HEX: fmt = TIME_SAMPLES_HEX_TEXT; break;
487 case TIME_FRAMES: fmt = TIME_FRAMES_TEXT; break;
488 case TIME_FEET_FRAMES: fmt = TIME_FEET_FRAMES_TEXT; break;
490 case TIME_HMS3: fmt = TIME_HMS3_TEXT; break;
491 case TIME_SECONDS: fmt = TIME_SECONDS_TEXT; break;
493 case TIME_MS2: fmt = TIME_MS2_TEXT; break;
495 return strcpy(string,fmt);
498 int Units::text_to_format(const char *string)
500 if(!strcmp(string, TIME_HMS_TEXT)) return TIME_HMS;
501 if(!strcmp(string, TIME_HMSF_TEXT)) return TIME_HMSF;
502 if(!strcmp(string, TIME_SAMPLES_TEXT)) return TIME_SAMPLES;
503 if(!strcmp(string, TIME_SAMPLES_HEX_TEXT)) return TIME_SAMPLES_HEX;
504 if(!strcmp(string, TIME_FRAMES_TEXT)) return TIME_FRAMES;
505 if(!strcmp(string, TIME_FEET_FRAMES_TEXT)) return TIME_FEET_FRAMES;
506 if(!strcmp(string, TIME_HMS3_TEXT)) return TIME_HMS3;
507 if(!strcmp(string, TIME_SECONDS_TEXT)) return TIME_SECONDS;
508 if(!strcmp(string, TIME_MS2_TEXT)) return TIME_MS2;
512 char* Units::size_totext(int64_t bytes, char *text)
514 char string[BCTEXTLEN];
515 static const char *sz[] = { "bytes", "KB", "MB", "GB", "TB" };
517 int i = (sizeof(sz) / sizeof(sz[0]));
518 while( --i > 0 && bytes < ((int64_t)1 << (10*i)) );
522 int frac = bytes % 1000;
523 sprintf(string, "%jd", bytes/1000);
524 if( bytes > 1000 ) punctuate(string);
525 sprintf(text, "%s.%03d %s", string, frac, sz[i]);
528 sprintf(string, "%jd", bytes);
529 if( bytes > 1000 ) punctuate(string);
530 sprintf(text, "%s %s", string, sz[i]);
537 #define BYTE_ORDER ((*(const uint32_t*)"a ") & 0x00000001)
539 void* Units::int64_to_ptr(uint64_t value)
541 unsigned char *value_dissected = (unsigned char*)&value;
543 unsigned char *data = (unsigned char*)&result;
545 // Must be done behind the compiler's back
546 if(sizeof(void*) == 4) {
548 data[0] = value_dissected[4];
549 data[1] = value_dissected[5];
550 data[2] = value_dissected[6];
551 data[3] = value_dissected[7];
554 data[0] = value_dissected[0];
555 data[1] = value_dissected[1];
556 data[2] = value_dissected[2];
557 data[3] = value_dissected[3];
561 data[0] = value_dissected[0];
562 data[1] = value_dissected[1];
563 data[2] = value_dissected[2];
564 data[3] = value_dissected[3];
565 data[4] = value_dissected[4];
566 data[5] = value_dissected[5];
567 data[6] = value_dissected[6];
568 data[7] = value_dissected[7];
573 uint64_t Units::ptr_to_int64(void *ptr)
575 unsigned char *ptr_dissected = (unsigned char*)&ptr;
577 unsigned char *data = (unsigned char*)&result;
578 // Don't do this at home.
579 if(sizeof(void*) == 4) {
581 data[4] = ptr_dissected[0];
582 data[5] = ptr_dissected[1];
583 data[6] = ptr_dissected[2];
584 data[7] = ptr_dissected[3];
587 data[0] = ptr_dissected[0];
588 data[1] = ptr_dissected[1];
589 data[2] = ptr_dissected[2];
590 data[3] = ptr_dissected[3];
594 data[0] = ptr_dissected[0];
595 data[1] = ptr_dissected[1];
596 data[2] = ptr_dissected[2];
597 data[3] = ptr_dissected[3];
598 data[4] = ptr_dissected[4];
599 data[5] = ptr_dissected[5];
600 data[6] = ptr_dissected[6];
601 data[7] = ptr_dissected[7];
606 const char* Units::format_to_separators(int time_format)
608 switch(time_format) {
609 case TIME_SECONDS: return "0000.000";
610 case TIME_HMS: return "0:00:00.000";
611 case TIME_HMS2: return "0:00:00";
612 case TIME_HMS3: return "00:00:00";
613 case TIME_HMSF: return "0:00:00:00";
614 case TIME_SAMPLES: return 0;
615 case TIME_SAMPLES_HEX: return 0;
616 case TIME_FRAMES: return 0;
617 case TIME_FEET_FRAMES: return "00000-00";
618 case TIME_MS1: return "0:00";
619 case TIME_MS2: return "+0:00";
624 void Units::punctuate(char *string)
626 int len = strlen(string);
627 int commas = (len - 1) / 3;
628 for(int i = len + commas, j = len, k; j >= 0 && i >= 0; i--, j--) {
629 k = (len - j - 1) / 3;
630 if(k * 3 == len - j - 1 && j != len - 1 && string[j] != 0) {
633 string[i] = string[j];
637 void Units::fix_double(double *x)