new/reworked audio plugins ported from hv72 compressor/multi/reverb, glyph workaround...
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcmeter.C
index e4eb2bd91dd5b18c1751f430fa2617c865ca8173..673a684a166c39a01a1c1925014de509afb27de5 100644 (file)
@@ -16,7 +16,6 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "bcbutton.h"
@@ -24,7 +23,7 @@
 #include "bcpixmap.h"
 #include "bcresources.h"
 #include "bcwindow.h"
-#include "bccolors.h"
+#include "colors.h"
 #include "fonts.h"
 #include "vframe.h"
 #include <string.h>
 #define METER_RIGHT 3
 
 
-BC_Meter::BC_Meter(int x,
-       int y,
-       int orientation,
-       int pixels,
-       int min,
-       int max,
-       int mode,
-       int use_titles,
-       int span,
-       int downmix)
+BC_Meter::BC_Meter(int x, int y, int orientation, int pixels,
+       int min, int max, int mode, int use_titles,
+       int span, int is_downmix, int is_gain_change)
  : BC_SubWindow(x, y, -1, -1)
 {
        this->over_delay = 150;
@@ -65,10 +57,10 @@ BC_Meter::BC_Meter(int x,
        this->orientation = orientation;
        this->pixels = pixels;
        this->span = span;
-       this->downmix = downmix;
-
+       this->is_downmix = is_downmix;
+       this->is_gain_change = is_gain_change;
 //printf("BC_Meter::draw_face %d w=%d pixels=%d\n", __LINE__, w, pixels);
-       for(int i = 0; i < TOTAL_METER_IMAGES; i++) images[i] = 0;
+       for( int i = 0; i < TOTAL_METER_IMAGES; i++ ) images[i] = 0;
        db_titles.set_array_delete();
 }
 
@@ -76,8 +68,9 @@ BC_Meter::~BC_Meter()
 {
        db_titles.remove_all_objects();
        title_pixels.remove_all();
+       tick_w.remove_all();
        tick_pixels.remove_all();
-       for(int i = 0; i < TOTAL_METER_IMAGES; i++) delete images[i];
+       for( int i = 0; i < TOTAL_METER_IMAGES; i++ ) delete images[i];
 }
 
 int BC_Meter::get_title_w()
@@ -104,26 +97,29 @@ int BC_Meter::initialize()
        level_pixel = peak_pixel = 0;
        over_timer = 0;
        over_count = 0;
-       peak = level = -100;
 
-       if(orientation == METER_VERT)
-       {
+       if( is_gain_change ) {
+               peak = level = 0;
+       }
+       else {
+               peak = level = -100;
+       }
+
+       if( orientation == METER_VERT ) {
                set_images(get_resources()->ymeter_images);
                h = pixels;
-               if(span < 0)
-               {
+               if( span < 0 ) {
                        w = images[0]->get_w();
-                       if(use_titles) w += get_title_w();
+                       if( use_titles ) w += get_title_w();
                }
                else
                        w = span;
        }
-       else
-       {
+       else {
                set_images(get_resources()->xmeter_images);
                h = images[0]->get_h();
                w = pixels;
-               if(use_titles) h += get_title_w();
+               if( use_titles ) h += get_title_w();
        }
 
 // calibrate the db titles
@@ -138,21 +134,19 @@ int BC_Meter::initialize()
 
 void BC_Meter::set_images(VFrame **data)
 {
-       for(int i = 0; i < TOTAL_METER_IMAGES; i++) delete images[i];
-       for(int i = 0; i < TOTAL_METER_IMAGES; i++)
+       for( int i = 0; i < TOTAL_METER_IMAGES; i++ ) delete images[i];
+       for( int i = 0; i < TOTAL_METER_IMAGES; i++ )
                images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
 }
 
 int BC_Meter::reposition_window(int x, int y, int span, int pixels)
 {
-       if(pixels < 0) pixels = this->pixels;
+       if( pixels < 0 ) pixels = this->pixels;
        this->span = span;
        this->pixels = pixels;
-       if(orientation == METER_VERT)
-               BC_SubWindow::reposition_window(x,
-                       y,
-                       this->span < 0 ? w : span,
-                       pixels);
+       if( orientation == METER_VERT )
+               BC_SubWindow::reposition_window(x, y,
+                       this->span < 0 ? w : span, pixels);
        else
                BC_SubWindow::reposition_window(x, y, pixels, get_h());
 
@@ -168,7 +162,7 @@ int BC_Meter::reposition_window(int x, int y, int span, int pixels)
        return 0;
 }
 
-int BC_Meter::reset(int dmix)
+int BC_Meter::reset(int downmix)
 {
        level = min;
        peak = min;
@@ -176,15 +170,15 @@ int BC_Meter::reset(int dmix)
        peak_timer = 0;
        over_timer = 0;
        over_count = 0;
-       if(dmix >= 0) downmix = dmix;
+       if( downmix >= 0 )
+               is_downmix = downmix;
        draw_face(1);
        return 0;
 }
 
 int BC_Meter::button_press_event()
 {
-       if(cursor_inside() && is_event_win())
-       {
+       if( cursor_inside() && is_event_win() ) {
                reset_over();
                return 1;
        }
@@ -210,15 +204,11 @@ int BC_Meter::change_format(int mode, int min, int max)
 int BC_Meter::level_to_pixel(float level)
 {
        int result;
-       if(mode == METER_DB)
-       {
-               result = (int)(pixels *
-                       (level - min) /
-                       (max - min));
-               if(level <= min) result = 0;
+       if( mode == METER_DB ) {
+               result = (int)(pixels * (level - min) / (max - min));
+               if( level <= min ) result = 0;
        }
-       else
-       {
+       else {
 // Not implemented anymore
                result = 0;
        }
@@ -236,6 +226,7 @@ void BC_Meter::get_divisions()
        db_titles.remove_all_objects();
        title_pixels.remove_all();
        tick_pixels.remove_all();
+       tick_w.remove_all();
 
        low_division = 0;
        medium_division = 0;
@@ -243,111 +234,104 @@ void BC_Meter::get_divisions()
 
        int current_pixel;
 // Create tick marks and titles in one pass
-       for(int current = min; current <= max; current++)
-       {
-               if(orientation == METER_VERT)
-               {
+       for( int current = min; current <= max; current++ ) {
+               if( orientation == METER_VERT ) {
 // Create tick mark
                        current_pixel = (pixels - METER_MARGIN * 2 - 2) *
                                (current - min) / (max - min) + 2;
                        tick_pixels.append(current_pixel);
 
 // Create titles in selected positions
-                       if(current == min ||
-                               current == max ||
-                               current == 0 ||
-                               (current - min > 4 && max - current > 4 && !(current % 5)))
-                       {
-                               int title_pixel = (pixels -
-                                       METER_MARGIN * 2) * (current - min) / (max - min);
-                               sprintf(string, "%ld", labs(current));
+                       if( current == min || current == max || current == 0 ||
+                               (current - min > 4 && max - current > 4 && !(current % 5)) ) {
+                               int title_pixel = (pixels - METER_MARGIN * 2) *
+                                       (current - min) / (max - min);
+                               sprintf(string, "%d", (int)labs(current));
                                new_string = new char[strlen(string) + 1];
                                strcpy(new_string, string);
                                db_titles.append(new_string);
                                title_pixels.append(title_pixel);
+                               tick_w.append(TICK_W1);
+                       }
+                       else {
+                               tick_w.append(TICK_W2);
                        }
                }
-               else
-               {
+               else {
                        current_pixel = (pixels - METER_MARGIN * 2) *
                                (current - min) /
                                (max - min);
                        tick_pixels.append(current_pixel);
+                       tick_w.append(TICK_W1);
 // Titles not supported for horizontal
                }
 
 // Create color divisions
-               if(current == -20)
-               {
+               if( current == -20 ) {
                        low_division = current_pixel;
                }
                else
-               if(current == -5)
-               {
+               if( current == -5 ) {
                        medium_division = current_pixel;
                }
                else
-               if(current == 0)
-               {
+               if( current == 0 ) {
                        high_division = current_pixel;
                }
        }
-// if(orientation == METER_VERT)
+// if( orientation == METER_VERT )
 // printf("BC_Meter::get_divisions %d %d %d %d\n",
 // low_division, medium_division, high_division, pixels);
 }
 
 void BC_Meter::draw_titles(int flush)
 {
-       if(!use_titles) return;
+       if( !use_titles ) return;
+       int tick_xfudge = xS(1);
 
        set_font(get_resources()->meter_font);
 
-       if(orientation == METER_HORIZ)
-       {
+       if( orientation == METER_HORIZ ) {
                draw_top_background(parent_window, 0, 0, get_w(), get_title_w());
 
-               for(int i = 0; i < db_titles.total; i++)
-               {
+               for( int i = 0; i < db_titles.total; i++ ) {
                        draw_text(0, title_pixels.values[i], db_titles.values[i]);
                }
 
                flash(0, 0, get_w(), get_title_w(), flush);
        }
        else
-       if(orientation == METER_VERT)
-       {
+       if( orientation == METER_VERT ) {
                draw_top_background(parent_window, 0, 0, get_title_w(), get_h());
 
 // Titles
-               for(int i = 0; i < db_titles.total; i++)
-               {
-                       int title_y = pixels -
-                               title_pixels.values[i];
-                       if(i == 0)
-                               title_y -= get_text_descent(SMALLFONT_3D);
+               for( int i = 0; i < db_titles.total; i++ ) {
+                       int title_y = pixels - title_pixels.values[i];
+                       if( i == 0 )
+                               title_y -= get_text_descent(get_resources()->meter_font);
                        else
-                       if(i == db_titles.total - 1)
-                               title_y += get_text_ascent(SMALLFONT_3D);
+                       if( i == db_titles.total - 1 )
+                               title_y += get_text_ascent(get_resources()->meter_font);
                        else
-                               title_y += get_text_ascent(SMALLFONT_3D) / 2;
+                               title_y += get_text_ascent(get_resources()->meter_font) / 2;
+                       int title_x = get_title_w() - TICK_W1 - tick_xfudge -
+                               get_text_width(get_resources()->meter_font, db_titles.values[i]);
 
                        set_color(get_resources()->meter_font_color);
-                       draw_text(0,
-                               title_y,
-                               db_titles.values[i]);
+                       draw_text(title_x, title_y, db_titles.values[i]);
                }
 
-               for(int i = 0; i < tick_pixels.total; i++)
-               {
+               for( int i = 0; i < tick_pixels.total; i++ ) {
 // Tick marks
                        int tick_y = pixels - tick_pixels.values[i] - METER_MARGIN;
                        set_color(get_resources()->meter_font_color);
-                       draw_line(get_title_w() - xS(10) - 1, tick_y, get_title_w() - 1, tick_y);
-                       if(get_resources()->meter_3d)
-                       {
+                       draw_line(get_title_w() - tick_w.get(i) - tick_xfudge,
+                               tick_y, get_title_w() - tick_xfudge, tick_y);
+
+                       if( get_resources()->meter_3d ) {
                                set_color(BLACK);
-                               draw_line(get_title_w() - xS(10), tick_y + 1, get_title_w(), tick_y + 1);
+                               draw_line(get_title_w() - tick_w.get(i),
+                                       tick_y + 1, get_title_w(), tick_y + 1);
                        }
                }
 
@@ -358,9 +342,9 @@ void BC_Meter::draw_titles(int flush)
 int BC_Meter::region_pixel(int region)
 {
        VFrame **reference_images = get_resources()->xmeter_images;
-       int result;
+       int result = 0;
 
-       if(region == METER_RIGHT)
+       if( region == METER_RIGHT )
                result = region * reference_images[0]->get_w() / 4;
        else
                result = region * reference_images[0]->get_w() / 4;
@@ -377,7 +361,7 @@ int BC_Meter::region_pixels(int region)
 
        x1 = region * reference_images[0]->get_w() / 4;
        x2 = (region + 1) * reference_images[0]->get_w() / 4;
-       if(region == METER_MID)
+       if( region == METER_MID )
                result = (x2 - x1) * 2;
        else
                result = x2 - x1;
@@ -400,197 +384,258 @@ void BC_Meter::draw_face(int flush)
        draw_top_background(parent_window, x, 0, w, h);
 
 // printf("BC_Meter::draw_face %d span=%d this->w=%d get_title_w()=%d %d %d\n",
-// __LINE__,
-// span,
-// this->w,
-// get_title_w(),
-// w,
-// h);
-
-       while(pixel < pixels)
-       {
-// Select image to draw
-               if(pixel < level_pixel ||
-                       (pixel >= peak_pixel1 && pixel < peak_pixel2))
-               {
-                       if(pixel < low_division)
-                               image_number = METER_GREEN;
-                       else
-                       if(pixel < medium_division)
-                               image_number = METER_YELLOW;
-                       else
-                       if(pixel < high_division)
-                               image_number = METER_RED;
-                       else
-                               image_number = METER_WHITE;
-               }
-               else
-               {
-                       image_number = METER_NORMAL;
-               }
+// __LINE__, span, this->w, get_title_w(), w, h);
+       if( is_gain_change ) {
+               int in_h = images[0]->get_h();
+               int in_third = in_h / 3;
+               int in_third3 = in_h - in_third * 2;
 
-// Select region of image to duplicate
-               if(pixel < left_pixel)
-               {
-                       region = METER_LEFT;
-                       in_start = pixel + region_pixel(region);
-                       in_span = region_pixels(region) - (in_start - region_pixel(region));
-               }
-               else
-               if(pixel < right_pixel)
-               {
-                       region = METER_MID;
-                       in_start = region_pixel(region);
-                       in_span = region_pixels(region);
-               }
-               else
-               {
-                       region = METER_RIGHT;
-                       in_start = (pixel - right_pixel) + region_pixel(region);
-                       in_span = region_pixels(region) - (in_start - region_pixel(region));;
+// printf("BC_Meter::draw_face %d level=%f level_pixel=%d high_division=%d\n",
+// __LINE__, level, level_pixel, high_division);
+
+
+// fudge a line when no gain change
+               if( level_pixel == high_division ) {
+                       level_pixel += 1;
                }
 
-//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);
-               if(in_span > 0)
-               {
-// Clip length to peaks
-                       if(pixel < level_pixel && pixel + in_span > level_pixel)
-                               in_span = level_pixel - pixel;
-                       else
-                       if(pixel < peak_pixel1 && pixel + in_span > peak_pixel1)
-                               in_span = peak_pixel1 - pixel;
-                       else
-                       if(pixel < peak_pixel2 && pixel + in_span > peak_pixel2)
-                               in_span = peak_pixel2 - pixel;
+               while( pixel < pixels ) {
+// Select image to draw & extents
+                       if( level_pixel < high_division ) {
+// always vertical
+                               if( pixel < level_pixel ) {
+                                       image_number = METER_NORMAL;
+                                       in_span = level_pixel - pixel;
+                               }
+                               else
+                               if( pixel < high_division ) {
+                                       image_number = METER_RED;
+                                       in_span = high_division - pixel;
+                               }
+                               else {
+                                       image_number = METER_NORMAL;
+                                       in_span = pixels - pixel;
+                               }
+                       }
+                       else {
+// determine pixel range & image to draw
+                               if( pixel < high_division ) {
+                                       image_number = METER_NORMAL;
+                                       in_span = high_division - pixel;
+                               }
+                               else
+                               if( pixel < level_pixel ) {
+                                       image_number = METER_GREEN;
+                                       in_span = level_pixel - pixel;
+                               }
+                               else {
+                                       image_number = METER_NORMAL;
+                                       in_span = pixels - pixel;
+                               }
+                       }
 
-// Clip length to color changes
-                       if(image_number == METER_GREEN && pixel + in_span > low_division)
-                               in_span = low_division - pixel;
+// determine starting point in source to draw
+// draw starting section
+                       if( pixel == 0 ) {
+                               in_start = 0;
+                       }
                        else
-                       if(image_number == METER_YELLOW && pixel + in_span > medium_division)
-                               in_span = medium_division - pixel;
+// draw middle section
+                       if( pixels - pixel > in_third3 ) {
+                               in_start = in_third;
+                       }
                        else
-                       if(image_number == METER_RED && pixel + in_span > high_division)
-                               in_span = high_division - pixel;
+// draw last section
+                       {
+                               in_start = in_third * 2;
+                       }
 
-// Clip length to regions
-                       if(pixel < left_pixel && pixel + in_span > left_pixel)
-                               in_span = left_pixel - pixel;
+// clamp the region to the source dimensions
+                       if( in_start < in_third * 2 ) {
+                               if( in_span > in_third ) {
+                                       in_span = in_third;
+                               }
+                       }
                        else
-                       if(pixel < right_pixel && pixel + in_span > right_pixel)
-                               in_span = right_pixel - pixel;
+// last segment
+                       if( pixels - pixel < in_third3 ) {
+                               in_span = pixels - pixel;
+                               in_start = in_h - in_span;
+                       }
 
-//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);
-//printf("BC_Meter::draw_face %d %d %d %d\n", orientation, region, images[image_number]->get_h() - in_start - in_span);
-                       if(orientation == METER_HORIZ)
-                       {
-                               draw_pixmap(images[image_number],
-                                       pixel,
-                                       x,
-                                       in_span + 1,
-                                       get_h(),
-                                       in_start,
-                                       0);
+// printf("BC_Meter::draw_face %d dst_y=%d src_y=%d"
+// " pixels=%d pixel=%d in_h=%d in_start=%d in_span=%d in_third=%d in_third3=%d\n",
+// __LINE__, get_h() - pixel - in_span, in_h - in_start - in_span,
+// pixels, pixel, in_h, in_start, in_span, in_third, in_third3);
+                       draw_pixmap(images[image_number], x, get_h() - pixel - in_span,
+                               get_w(), in_span + 1, 0, in_h - in_start - in_span);
+                       pixel += in_span;
+               }
+       }
+       else {
+               while( pixel < pixels ) {
+// Select image to draw
+                       if( pixel < level_pixel ||
+                               (pixel >= peak_pixel1 && pixel < peak_pixel2) ) {
+                               if( pixel < low_division )
+                                       image_number = METER_GREEN;
+                               else
+                               if( pixel < medium_division )
+                                       image_number = METER_YELLOW;
+                               else
+                               if( pixel < high_division )
+                                       image_number = METER_RED;
+                               else
+                                       image_number = METER_WHITE;
+                       }
+                       else {
+                               image_number = METER_NORMAL;
+                       }
+
+// Select region of image to duplicate
+                       if( pixel < left_pixel ) {
+                               region = METER_LEFT;
+                               in_start = pixel + region_pixel(region);
+                               in_span = region_pixels(region) - (in_start - region_pixel(region));
                        }
                        else
-                       {
-//printf("BC_Meter::draw_face %d %d\n", __LINE__, span);
-                               if(span < 0)
-                               {
-                                       draw_pixmap(images[image_number],
-                                               x,
-                                               get_h() - pixel - in_span,
-                                               get_w(),
-                                               in_span + 1,
-                                               0,
-                                               images[image_number]->get_h() - in_start - in_span);
-                               }
-                               else
-                               {
-                                       int total_w = get_w() - x;
-                                       int third = images[image_number]->get_w() / 3 + 1;
-
-
-                                       for(int x1 = 0; x1 < total_w; x1 += third)
-                                       {
-                                               int in_x = 0;
-                                               int in_w = third;
-                                               if(x1 >= third) in_x = third;
-                                               if(x1 >= total_w - third)
-                                               {
-                                                       in_x = images[image_number]->get_w() -
-                                                               (total_w - x1);
-                                                       in_w = total_w - x1;
-                                               }
+                       if( pixel < right_pixel ) {
+                               region = METER_MID;
+                               in_start = region_pixel(region);
+                               in_span = region_pixels(region);
+                       }
+                       else {
+                               region = METER_RIGHT;
+                               in_start = (pixel - right_pixel) + region_pixel(region);
+                               in_span = region_pixels(region) - (in_start - region_pixel(region));;
+                       }
 
-                                               int in_y = images[image_number]->get_h() - in_start - in_span;
-//printf("BC_Meter::draw_face %d %d %d\n", __LINE__, get_w(), x + x1 + in_w, in_x, in_y, in_w, span);
+       //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);
+                       if( in_span > 0 ) {
+       // Clip length to peaks
+                               if( pixel < level_pixel && pixel + in_span > level_pixel )
+                                       in_span = level_pixel - pixel;
+                               else
+                               if( pixel < peak_pixel1 && pixel + in_span > peak_pixel1 )
+                                       in_span = peak_pixel1 - pixel;
+                               else
+                               if( pixel < peak_pixel2 && pixel + in_span > peak_pixel2 )
+                                       in_span = peak_pixel2 - pixel;
 
+       // Clip length to color changes
+                               if( image_number == METER_GREEN && pixel + in_span > low_division )
+                                       in_span = low_division - pixel;
+                               else
+                               if( image_number == METER_YELLOW && pixel + in_span > medium_division )
+                                       in_span = medium_division - pixel;
+                               else
+                               if( image_number == METER_RED && pixel + in_span > high_division )
+                                       in_span = high_division - pixel;
 
+       // Clip length to regions
+                               if( pixel < left_pixel && pixel + in_span > left_pixel )
+                                       in_span = left_pixel - pixel;
+                               else
+                               if( pixel < right_pixel && pixel + in_span > right_pixel )
+                                       in_span = right_pixel - pixel;
+
+       //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);
+       //printf("BC_Meter::draw_face %d %d %d %d\n", orientation, region, images[image_number]->get_h() - in_start - in_span);
+                               if( orientation == METER_HORIZ ) {
+                                       draw_pixmap(images[image_number], pixel,
+                                               x, in_span + 1, get_h(), in_start, 0);
+                               }
+                               else {
+       //printf("BC_Meter::draw_face %d %d\n", __LINE__, span);
+                                       if( span < 0 ) {
                                                draw_pixmap(images[image_number],
-                                                       x + x1, get_h() - pixel - in_span,
-                                                       in_w, in_span + 1, in_x, in_y);
+                                                       x, get_h() - pixel - in_span,
+                                                       get_w(), in_span + 1, 0,
+                                                       images[image_number]->get_h() - in_start - in_span);
+                                       }
+                                       else {
+                                               int total_w = get_w() - x;
+                                               int third = images[image_number]->get_w() / 3 + 1;
+
+
+                                               for( int x1 = 0; x1 < total_w; x1 += third ) {
+                                                       int in_x = 0;
+                                                       int in_w = third;
+                                                       if( x1 >= third ) in_x = third;
+                                                       if( x1 >= total_w - third ) {
+                                                               in_x = images[image_number]->get_w() -
+                                                                       (total_w - x1);
+                                                               in_w = total_w - x1;
+                                                       }
+
+                                                       int in_y = images[image_number]->get_h() - in_start - in_span;
+       //printf("BC_Meter::draw_face %d %d %d\n", __LINE__, get_w(), x + x1 + in_w, in_x, in_y, in_w, span);
+
+
+                                                       draw_pixmap(images[image_number],
+                                                               x + x1, get_h() - pixel - in_span,
+                                                               in_w, in_span + 1, in_x, in_y);
+                                               }
                                        }
                                }
-                       }
 
-                       pixel += in_span;
-               }
-               else
-               {
-// Sanity check
-                       break;
+                               pixel += in_span;
+                       }
+                       else {
+       // Sanity check
+                               break;
+                       }
                }
        }
 
-       if(downmix) {
-               if(orientation == METER_HORIZ)
+       if( is_downmix ) {
+               if( orientation == METER_HORIZ )
                        draw_pixmap(images[METER_DOWNMIX], 0, 0);
                else
-                       draw_pixmap(images[METER_DOWNMIX], x,
-                               get_h() - images[METER_DOWNMIX]->get_h()-1);
+                       draw_pixmap(images[METER_DOWNMIX],
+                               x, get_h() - images[METER_DOWNMIX]->get_h() - 1);
        }
-
-       if(over_timer)
-       {
-               if(orientation == METER_HORIZ)
+       if( over_timer ) {
+               if( orientation == METER_HORIZ )
                        draw_pixmap(images[METER_OVER], xS(20), yS(2));
                else
-                       draw_pixmap(images[METER_OVER], x, get_h() - yS(100));
+                       draw_pixmap(images[METER_OVER],
+                               x + xS(2), get_h() - yS(100));
 
                over_timer--;
        }
 
-       if(orientation == METER_HORIZ)
+       if( orientation == METER_HORIZ )
                flash(0, 0, pixels, get_h(), flush);
        else
                flash(x, 0, w, pixels, flush);
 }
 
-int BC_Meter::update(float new_value, int over, int dmix)
+int BC_Meter::update(float new_value, int over, int downmix)
 {
        peak_timer++;
 
-       if(mode == METER_DB)
-       {
-               if(new_value == 0)
+       if( mode == METER_DB ) {
+               if( new_value == 0 )
                        level = min;
                else
-                       level = db.todb(new_value);        // db value
+                       level = DB::todb(new_value);            // db value
        }
 
-       if(level > peak || peak_timer > peak_delay)
-       {
+
+       if( is_gain_change && fabs(level) > fabs(peak) ||
+               !is_gain_change && level > peak ||
+               peak_timer > peak_delay ) {
                peak = level;
                peak_timer = 0;
        }
 
-// if(orientation == METER_HORIZ)
+// if( orientation == METER_HORIZ )
 // printf("BC_Meter::update %f\n", level);
-       if(over) over_timer = over_delay;
+       if( over ) over_timer = over_delay;
 // only draw if window is visible
-       if(dmix >= 0) downmix = dmix;
-
+       if( downmix >= 0 )
+               is_downmix = downmix;
        draw_face(1);
        return 0;
 }