diff options
| author | Calvin Morrison <calvin@pobox.com> | 2026-05-15 10:10:04 -0400 |
|---|---|---|
| committer | Calvin Morrison <calvin@pobox.com> | 2026-05-15 10:10:04 -0400 |
| commit | e776bc768cf9afca1867200e25d64d315cd72a3e (patch) | |
| tree | 6745527b939c9d37147d7dc98e8664437ee433f6 /src/ui/levelmeter.cpp | |
| parent | 4e602e78cdfc210ab7781668df2a88afb923258b (diff) | |
Full mixer implementation — tray, popup, prefs, devices tab with port indicators
Adds the complete tmix feature set built since the initial skeleton:
balance knob, level meters, KLed mute button, system tray with scroll-wheel
volume and recording indicator, tray popup, preferences dialog, right-click
context menus, single-instance enforcement, scroll area, window geometry
persistence, and Devices tab with PA card profile switcher and live port
availability indicators (2-column layout, in-place updates on plug/unplug).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/ui/levelmeter.cpp')
| -rw-r--r-- | src/ui/levelmeter.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/ui/levelmeter.cpp b/src/ui/levelmeter.cpp new file mode 100644 index 0000000..52412de --- /dev/null +++ b/src/ui/levelmeter.cpp @@ -0,0 +1,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 ); + } +} |
