summaryrefslogtreecommitdiff
path: root/src/ui/levelmeter.cpp
blob: 52412de898d937f2dda217af0627ed69e77e5067 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "levelmeter.h"
#include <tqpainter.h>
#include <math.h>

LevelMeter::LevelMeter( TQWidget *parent )
    : TQWidget(parent), m_level(0.0f)
{
    setBackgroundMode( NoBackground );
}

// Map linear 0..1 amplitude to dB display position 0..1 over a 60dB range.
// -60dB = bottom, 0dB = top. Matches how real VU meters look.
static float toDisplayLevel( float linear )
{
    if ( linear < 0.001f ) return 0.0f;
    float db = 20.0f * log10f( linear );  // e.g. 0.3 → -10.5 dB
    float pos = ( db + 60.0f ) / 60.0f;  // -60..0 dB → 0..1
    if ( pos < 0.0f ) pos = 0.0f;
    if ( pos > 1.0f ) pos = 1.0f;
    return pos;
}

void LevelMeter::setLevel( float level )
{
    if ( level < 0.0f ) level = 0.0f;
    if ( level > 1.0f ) level = 1.0f;

    float display = toDisplayLevel( level );
    if ( display > m_level )
        m_level = m_level * 0.3f + display * 0.7f;  // fast attack, not instant
    else {
        m_level *= 0.94f;                            // slow decay ~1.5s to floor
        if ( m_level < 0.001f ) m_level = 0.0f;
    }
    update();
}

TQSize LevelMeter::sizeHint() const
{
    return TQSize( 8, 48 );
}

void LevelMeter::paintEvent( TQPaintEvent * )
{
    TQPainter p( this );
    int w = width();
    int h = height();

    p.fillRect( 0, 0, w, h, TQColor( 40, 40, 40 ) );

    if ( m_level <= 0.0f ) return;

    struct Zone { float lo, hi; TQColor col; };
    static const Zone zones[3] = {
        { 0.00f, 0.70f, TQColor(  50, 200,  50 ) },
        { 0.70f, 0.90f, TQColor( 230, 200,   0 ) },
        { 0.90f, 1.00f, TQColor( 220,  40,  40 ) },
    };

    for ( int z = 0; z < 3; z++ ) {
        if ( m_level <= zones[z].lo ) break;
        float segEnd = ( m_level < zones[z].hi ) ? m_level : zones[z].hi;
        int yTop = h - (int)( segEnd      * h );
        int yBot = h - (int)( zones[z].lo * h );
        p.fillRect( 0, yTop, w, yBot - yTop, zones[z].col );
    }
}