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
24 #include "bcresources.h"
31 // Which source image to replicate
32 #define METER_NORMAL 0
35 #define METER_YELLOW 3
38 #define METER_DOWNMIX 6
40 // Region of source image to replicate
46 BC_Meter::BC_Meter(int x, int y, int orientation, int pixels,
47 int min, int max, int mode, int use_titles,
48 int span, int is_downmix, int is_gain_change)
49 : BC_SubWindow(x, y, -1, -1)
51 this->over_delay = 150;
52 this->peak_delay = 15;
53 this->use_titles = use_titles;
57 this->orientation = orientation;
58 this->pixels = pixels;
60 this->is_downmix = is_downmix;
61 this->is_gain_change = is_gain_change;
62 //printf("BC_Meter::draw_face %d w=%d pixels=%d\n", __LINE__, w, pixels);
63 for( int i = 0; i < TOTAL_METER_IMAGES; i++ ) images[i] = 0;
64 db_titles.set_array_delete();
69 db_titles.remove_all_objects();
70 title_pixels.remove_all();
72 tick_pixels.remove_all();
73 for( int i = 0; i < TOTAL_METER_IMAGES; i++ ) delete images[i];
76 int BC_Meter::get_title_w()
78 return get_resources()->meter_title_w;
81 int BC_Meter::get_meter_w()
83 return get_resources()->ymeter_images[0]->get_w();
87 int BC_Meter::set_delays(int over_delay, int peak_delay)
89 this->over_delay = over_delay;
90 this->peak_delay = peak_delay;
94 int BC_Meter::initialize()
97 level_pixel = peak_pixel = 0;
101 if( is_gain_change ) {
108 if( orientation == METER_VERT ) {
109 set_images(get_resources()->ymeter_images);
112 w = images[0]->get_w();
113 if( use_titles ) w += get_title_w();
119 set_images(get_resources()->xmeter_images);
120 h = images[0]->get_h();
122 if( use_titles ) h += get_title_w();
125 // calibrate the db titles
128 BC_SubWindow::initialize();
135 void BC_Meter::set_images(VFrame **data)
137 for( int i = 0; i < TOTAL_METER_IMAGES; i++ ) delete images[i];
138 for( int i = 0; i < TOTAL_METER_IMAGES; i++ )
139 images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
142 int BC_Meter::reposition_window(int x, int y, int span, int pixels)
144 if( pixels < 0 ) pixels = this->pixels;
146 this->pixels = pixels;
147 if( orientation == METER_VERT )
148 BC_SubWindow::reposition_window(x, y,
149 this->span < 0 ? w : span, pixels);
151 BC_SubWindow::reposition_window(x, y, pixels, get_h());
153 //printf("BC_Meter::reposition_window 1 %d %d %d %d\n", x, y, w, h);
157 //draw_box(0, 0, w, h);
165 int BC_Meter::reset(int downmix)
169 level_pixel = peak_pixel = 0;
174 is_downmix = downmix;
179 int BC_Meter::button_press_event()
181 if( cursor_inside() && is_event_win() ) {
189 int BC_Meter::reset_over()
195 int BC_Meter::change_format(int mode, int min, int max)
200 reposition_window(get_x(), get_y(), w, pixels);
204 int BC_Meter::level_to_pixel(float level)
207 if( mode == METER_DB ) {
208 result = (int)(pixels * (level - min) / (max - min));
209 if( level <= min ) result = 0;
212 // Not implemented anymore
220 void BC_Meter::get_divisions()
222 char string[BCTEXTLEN];
226 db_titles.remove_all_objects();
227 title_pixels.remove_all();
228 tick_pixels.remove_all();
233 high_division = pixels;
236 // Create tick marks and titles in one pass
237 for( int current = min; current <= max; current++ ) {
238 if( orientation == METER_VERT ) {
240 current_pixel = (pixels - METER_MARGIN * 2 - 2) *
241 (current - min) / (max - min) + 2;
242 tick_pixels.append(current_pixel);
244 // Create titles in selected positions
245 if( current == min || current == max || current == 0 ||
246 (current - min > 4 && max - current > 4 && !(current % 5)) ) {
247 int title_pixel = (pixels - METER_MARGIN * 2) *
248 (current - min) / (max - min);
249 sprintf(string, "%d", (int)labs(current));
250 new_string = new char[strlen(string) + 1];
251 strcpy(new_string, string);
252 db_titles.append(new_string);
253 title_pixels.append(title_pixel);
254 tick_w.append(TICK_W1);
257 tick_w.append(TICK_W2);
261 current_pixel = (pixels - METER_MARGIN * 2) *
264 tick_pixels.append(current_pixel);
265 tick_w.append(TICK_W1);
266 // Titles not supported for horizontal
269 // Create color divisions
270 if( current == -20 ) {
271 low_division = current_pixel;
274 if( current == -5 ) {
275 medium_division = current_pixel;
279 high_division = current_pixel;
282 // if( orientation == METER_VERT )
283 // printf("BC_Meter::get_divisions %d %d %d %d\n",
284 // low_division, medium_division, high_division, pixels);
287 void BC_Meter::draw_titles(int flush)
289 if( !use_titles ) return;
290 int tick_xfudge = xS(1);
292 set_font(get_resources()->meter_font);
294 if( orientation == METER_HORIZ ) {
295 draw_top_background(parent_window, 0, 0, get_w(), get_title_w());
297 for( int i = 0; i < db_titles.total; i++ ) {
298 draw_text(0, title_pixels.values[i], db_titles.values[i]);
301 flash(0, 0, get_w(), get_title_w(), flush);
304 if( orientation == METER_VERT ) {
305 draw_top_background(parent_window, 0, 0, get_title_w(), get_h());
308 for( int i = 0; i < db_titles.total; i++ ) {
309 int title_y = pixels - title_pixels.values[i];
311 title_y -= get_text_descent(get_resources()->meter_font);
313 if( i == db_titles.total - 1 )
314 title_y += get_text_ascent(get_resources()->meter_font);
316 title_y += get_text_ascent(get_resources()->meter_font) / 2;
317 int title_x = get_title_w() - TICK_W1 - tick_xfudge -
318 get_text_width(get_resources()->meter_font, db_titles.values[i]);
320 set_color(get_resources()->meter_font_color);
321 draw_text(title_x, title_y, db_titles.values[i]);
324 for( int i = 0; i < tick_pixels.total; i++ ) {
326 int tick_y = pixels - tick_pixels.values[i] - METER_MARGIN;
327 set_color(get_resources()->meter_font_color);
328 draw_line(get_title_w() - tick_w.get(i) - tick_xfudge,
329 tick_y, get_title_w() - tick_xfudge, tick_y);
331 if( get_resources()->meter_3d ) {
333 draw_line(get_title_w() - tick_w.get(i),
334 tick_y + 1, get_title_w(), tick_y + 1);
338 flash(0, 0, get_title_w(), get_h(), flush);
342 int BC_Meter::region_pixel(int region)
344 VFrame **reference_images = get_resources()->xmeter_images;
347 if( region == METER_RIGHT )
348 result = region * reference_images[0]->get_w() / 4;
350 result = region * reference_images[0]->get_w() / 4;
355 int BC_Meter::region_pixels(int region)
360 VFrame **reference_images = get_resources()->xmeter_images;
362 x1 = region * reference_images[0]->get_w() / 4;
363 x2 = (region + 1) * reference_images[0]->get_w() / 4;
364 if( region == METER_MID )
365 result = (x2 - x1) * 2;
371 void BC_Meter::draw_face(int flush)
373 int level_pixel = level_to_pixel(level);
374 int peak_pixel2 = level_to_pixel(peak);
375 int peak_pixel1 = peak_pixel2 - 2;
376 int left_pixel = region_pixel(METER_MID);
377 int right_pixel = pixels - region_pixels(METER_RIGHT);
379 int image_number = 0, region = 0;
380 int in_span, in_start;
381 int x = use_titles ? get_title_w() : 0;
382 int w = use_titles ? (this->w - get_title_w()) : this->w;
384 draw_top_background(parent_window, x, 0, w, h);
386 // printf("BC_Meter::draw_face %d span=%d this->w=%d get_title_w()=%d %d %d\n",
387 // __LINE__, span, this->w, get_title_w(), w, h);
388 if( is_gain_change ) {
389 int in_h = images[0]->get_h();
390 int in_third = in_h / 3;
391 int in_third3 = in_h - in_third * 2;
393 // printf("BC_Meter::draw_face %d level=%f level_pixel=%d high_division=%d\n",
394 // __LINE__, level, level_pixel, high_division);
397 // fudge a line when no gain change
398 if( level_pixel == high_division ) {
402 while( pixel < pixels ) {
403 // Select image to draw & extents
404 if( level_pixel < high_division ) {
406 if( pixel < level_pixel ) {
407 image_number = METER_NORMAL;
408 in_span = level_pixel - pixel;
411 if( pixel < high_division ) {
412 image_number = METER_RED;
413 in_span = high_division - pixel;
416 image_number = METER_NORMAL;
417 in_span = pixels - pixel;
421 // determine pixel range & image to draw
422 if( pixel < high_division ) {
423 image_number = METER_NORMAL;
424 in_span = high_division - pixel;
427 if( pixel < level_pixel ) {
428 image_number = METER_GREEN;
429 in_span = level_pixel - pixel;
432 image_number = METER_NORMAL;
433 in_span = pixels - pixel;
437 // determine starting point in source to draw
438 // draw starting section
443 // draw middle section
444 if( pixels - pixel > in_third3 ) {
450 in_start = in_third * 2;
453 // clamp the region to the source dimensions
454 if( in_start < in_third * 2 ) {
455 if( in_span > in_third ) {
461 if( pixels - pixel < in_third3 ) {
462 in_span = pixels - pixel;
463 in_start = in_h - in_span;
466 // printf("BC_Meter::draw_face %d dst_y=%d src_y=%d"
467 // " pixels=%d pixel=%d in_h=%d in_start=%d in_span=%d in_third=%d in_third3=%d\n",
468 // __LINE__, get_h() - pixel - in_span, in_h - in_start - in_span,
469 // pixels, pixel, in_h, in_start, in_span, in_third, in_third3);
470 draw_pixmap(images[image_number], x, get_h() - pixel - in_span,
471 get_w(), in_span + 1, 0, in_h - in_start - in_span);
476 while( pixel < pixels ) {
477 // Select image to draw
478 if( pixel < level_pixel ||
479 (pixel >= peak_pixel1 && pixel < peak_pixel2) ) {
480 if( pixel < low_division )
481 image_number = METER_GREEN;
483 if( pixel < medium_division )
484 image_number = METER_YELLOW;
486 if( pixel < high_division )
487 image_number = METER_RED;
489 image_number = METER_WHITE;
492 image_number = METER_NORMAL;
495 // Select region of image to duplicate
496 if( pixel < left_pixel ) {
498 in_start = pixel + region_pixel(region);
499 in_span = region_pixels(region) - (in_start - region_pixel(region));
502 if( pixel < right_pixel ) {
504 in_start = region_pixel(region);
505 in_span = region_pixels(region);
508 region = METER_RIGHT;
509 in_start = (pixel - right_pixel) + region_pixel(region);
510 in_span = region_pixels(region) - (in_start - region_pixel(region));;
513 //printf("BC_Meter::draw_face region %d pixel %d pixels %d in_start %d in_span %d\n", region, pixel, pixels, in_start, in_span);
515 // Clip length to peaks
516 if( pixel < level_pixel && pixel + in_span > level_pixel )
517 in_span = level_pixel - pixel;
519 if( pixel < peak_pixel1 && pixel + in_span > peak_pixel1 )
520 in_span = peak_pixel1 - pixel;
522 if( pixel < peak_pixel2 && pixel + in_span > peak_pixel2 )
523 in_span = peak_pixel2 - pixel;
525 // Clip length to color changes
526 if( image_number == METER_GREEN && pixel + in_span > low_division )
527 in_span = low_division - pixel;
529 if( image_number == METER_YELLOW && pixel + in_span > medium_division )
530 in_span = medium_division - pixel;
532 if( image_number == METER_RED && pixel + in_span > high_division )
533 in_span = high_division - pixel;
535 // Clip length to regions
536 if( pixel < left_pixel && pixel + in_span > left_pixel )
537 in_span = left_pixel - pixel;
539 if( pixel < right_pixel && pixel + in_span > right_pixel )
540 in_span = right_pixel - pixel;
542 //printf("BC_Meter::draw_face image_number %d pixel %d pixels %d in_start %d in_span %d\n", image_number, pixel, pixels, in_start, in_span);
543 //printf("BC_Meter::draw_face %d %d %d %d\n", orientation, region, images[image_number]->get_h() - in_start - in_span);
544 if( orientation == METER_HORIZ ) {
545 draw_pixmap(images[image_number], pixel,
546 x, in_span + 1, get_h(), in_start, 0);
549 //printf("BC_Meter::draw_face %d %d\n", __LINE__, span);
551 draw_pixmap(images[image_number],
552 x, get_h() - pixel - in_span,
553 get_w(), in_span + 1, 0,
554 images[image_number]->get_h() - in_start - in_span);
557 int total_w = get_w() - x;
558 int third = images[image_number]->get_w() / 3 + 1;
561 for( int x1 = 0; x1 < total_w; x1 += third ) {
564 if( x1 >= third ) in_x = third;
565 if( x1 >= total_w - third ) {
566 in_x = images[image_number]->get_w() -
571 int in_y = images[image_number]->get_h() - in_start - in_span;
572 //printf("BC_Meter::draw_face %d %d %d\n", __LINE__, get_w(), x + x1 + in_w, in_x, in_y, in_w, span);
575 draw_pixmap(images[image_number],
576 x + x1, get_h() - pixel - in_span,
577 in_w, in_span + 1, in_x, in_y);
592 if( orientation == METER_HORIZ )
593 draw_pixmap(images[METER_DOWNMIX], 0, 0);
595 draw_pixmap(images[METER_DOWNMIX],
596 x, get_h() - images[METER_DOWNMIX]->get_h() - 1);
599 if( orientation == METER_HORIZ )
600 draw_pixmap(images[METER_OVER], xS(20), yS(2));
602 draw_pixmap(images[METER_OVER],
603 x + xS(2), get_h() - yS(100));
608 if( orientation == METER_HORIZ )
609 flash(0, 0, pixels, get_h(), flush);
611 flash(x, 0, w, pixels, flush);
614 int BC_Meter::update(float new_value, int over, int downmix)
618 if( mode == METER_DB ) {
622 level = DB::todb(new_value); // db value
626 if( is_gain_change && fabs(level) > fabs(peak) ||
627 !is_gain_change && level > peak ||
628 peak_timer > peak_delay ) {
633 // if( orientation == METER_HORIZ )
634 // printf("BC_Meter::update %f\n", level);
635 if( over ) over_timer = over_delay;
636 // only draw if window is visible
638 is_downmix = downmix;