Skip to content

LevelMeterCanvas

A canvas-based level meter visualization component for displaying audio levels with peak indicators, clipping detection, and optional dB scale markings.

Features

  • Real-time RMS level and peak level display
  • Clipping detection with visual feedback
  • Horizontal and vertical orientations
  • Color gradient from green to red based on level
  • Peak hold indicator
  • Optional dB scale markings
  • Glow effects on clipping
  • Responsive sizing with device pixel ratio support
  • Completely customizable via className and style props

Import

tsx
import { LevelMeterCanvas } from '@mode-7/mod';

Props

PropTypeDefaultDescription
levelnumberRequiredCurrent RMS level (0-1)
peaknumberRequiredPeak level (0-1)
isClippingbooleanRequiredWhether audio is clipping
widthnumber | string'100%'Canvas width
heightnumber | string60Canvas height
orientation'horizontal' | 'vertical''horizontal'Meter orientation
backgroundColorstring'#0a0a0a'Canvas background color
showScalebooleantrueShow dB scale markings
classNamestring''Additional CSS classes for container
canvasClassNamestring''Additional CSS classes for canvas

Usage

Basic Usage with LevelMeter Component

tsx
import { LevelMeter, LevelMeterCanvas, useModStream } from '@mode-7/mod';

function AudioLevelDisplay() {
  const input = useModStream();

  return (
    <LevelMeter input={input}>
      {({ level, peak, isClipping }) => (
        <LevelMeterCanvas
          level={level}
          peak={peak}
          isClipping={isClipping}
        />
      )}
    </LevelMeter>
  );
}

Horizontal Meter (Default)

tsx
<LevelMeterCanvas
  level={level}
  peak={peak}
  isClipping={isClipping}
  orientation="horizontal"
  height={60}
/>

Vertical Meter

tsx
<LevelMeterCanvas
  level={level}
  peak={peak}
  isClipping={isClipping}
  orientation="vertical"
  width={40}
  height={200}
/>

Without Scale

tsx
<LevelMeterCanvas
  level={level}
  peak={peak}
  isClipping={isClipping}
  showScale={false}
/>

Custom Size

tsx
<LevelMeterCanvas
  level={level}
  peak={peak}
  isClipping={isClipping}
  width={600}
  height={80}
/>

Custom Background

tsx
<LevelMeterCanvas
  level={level}
  peak={peak}
  isClipping={isClipping}
  backgroundColor="#000000"
/>

Complete Integration Example

tsx
import {
  AudioProvider,
  ToneGenerator,
  LevelMeter,
  LevelMeterCanvas,
  Slider,
  useModStream
} from '@mode-7/mod';
import { useState } from 'react';

function AudioLevelMonitor() {
  const output = useModStream();
  const [gain, setGain] = useState(0.5);

  return (
    <AudioProvider>
      <div className="level-monitor">
        <ToneGenerator
          output={output}
          frequency={440}
          gain={gain}
          onGainChange={setGain}
        />

        <Slider
          value={gain}
          onChange={setGain}
          min={0}
          max={1}
          step={0.01}
          label="Gain"
        />

        <LevelMeter input={output}>
          {({ level, peak, isClipping }) => (
            <LevelMeterCanvas
              level={level}
              peak={peak}
              isClipping={isClipping}
            />
          )}
        </LevelMeter>
      </div>
    </AudioProvider>
  );
}

CSS Classes

The LevelMeterCanvas component uses the following CSS classes:

  • .modui-level-meter - Container element
  • .modui-level-meter-horizontal - Applied for horizontal orientation
  • .modui-level-meter-vertical - Applied for vertical orientation
  • .modui-level-meter-canvas - Canvas element

Styling Examples

Custom Container

css
.custom-meter {
  border: 2px solid #3949ab;
  border-radius: 8px;
  overflow: hidden;
}

With Shadow

css
.glowing-meter {
  box-shadow: 0 2px 12px rgba(0, 255, 136, 0.2);
  border-radius: 4px;
}

Color Gradient

The level meter displays a color gradient based on the current level:

  • 0% - 70%: Green (#00ff00) → Yellow (#ffff00)
  • 70% - 90%: Yellow (#ffff00) → Orange (#ff8800)
  • 90% - 100%: Orange (#ff8800) → Red (#ff0000)

This provides clear visual feedback about signal levels and helps identify when levels are approaching clipping.

Peak Indicator

The peak indicator:

  • Shows as a white line at the peak level position
  • Turns red when clipping is detected
  • Has a glow effect when clipping
  • Persists until the peak level decays

Scale Markings

When showScale={true}, the meter displays dB markings at:

  • 0%: -∞ dB
  • 25%: Calculated dB value
  • 50%: Calculated dB value
  • 75%: Calculated dB value
  • 100%: 0 dB

The dB calculation uses: 20 * log10(level)

Data Source

The level, peak, and isClipping values come from the LevelMeter component which analyzes the audio stream:

tsx
// Inside LevelMeter component
const analyser = audioContext.createAnalyser();
const dataArray = new Uint8Array(analyser.frequencyBinCount);

// Calculate RMS level
analyser.getByteTimeDomainData(dataArray);
const rms = calculateRMS(dataArray);

// Track peak with decay
if (rms > peak) {
  setPeak(rms);
} else {
  setPeak(peak * 0.95); // Decay
}

// Detect clipping
const isClipping = rms > 0.99;

The LevelMeter component handles all this automatically when you use it with LevelMeterCanvas.

Performance

  • Device Pixel Ratio: Automatically scales canvas for retina displays
  • Resize Handling: Responds to window resize events
  • Optimized Rendering: Smooth updates with requestAnimationFrame
  • Conditional Glow: Only applies glow effect when clipping

Common Patterns

Stereo Level Meters

tsx
<div className="stereo-meters">
  <div className="meter-label">L</div>
  <LevelMeter input={leftChannel}>
    {({ level, peak, isClipping }) => (
      <LevelMeterCanvas
        level={level}
        peak={peak}
        isClipping={isClipping}
        height={40}
      />
    )}
  </LevelMeter>

  <div className="meter-label">R</div>
  <LevelMeter input={rightChannel}>
    {({ level, peak, isClipping }) => (
      <LevelMeterCanvas
        level={level}
        peak={peak}
        isClipping={isClipping}
        height={40}
      />
    )}
  </LevelMeter>
</div>

Vertical Meters Side-by-Side

tsx
<div style={{ display: 'flex', gap: '16px' }}>
  <div>
    <div>L</div>
    <LevelMeterCanvas
      level={leftLevel}
      peak={leftPeak}
      isClipping={leftClipping}
      orientation="vertical"
      width={30}
      height={200}
    />
  </div>

  <div>
    <div>R</div>
    <LevelMeterCanvas
      level={rightLevel}
      peak={rightPeak}
      isClipping={rightClipping}
      orientation="vertical"
      width={30}
      height={200}
    />
  </div>
</div>

Compact Meter (No Scale)

tsx
<LevelMeterCanvas
  level={level}
  peak={peak}
  isClipping={isClipping}
  height={20}
  showScale={false}
/>

Master Output Meter

tsx
<div className="master-section">
  <h3>Master Output</h3>
  <LevelMeter input={masterOutput}>
    {({ level, peak, isClipping }) => (
      <>
        <LevelMeterCanvas
          level={level}
          peak={peak}
          isClipping={isClipping}
          height={80}
        />
        {isClipping && (
          <div className="clip-warning">CLIPPING!</div>
        )}
      </>
    )}
  </LevelMeter>
</div>

With Numeric Display

tsx
<LevelMeter input={input}>
  {({ level, peak, isClipping }) => (
    <div className="meter-with-display">
      <LevelMeterCanvas
        level={level}
        peak={peak}
        isClipping={isClipping}
      />
      <div className="level-display">
        <span>RMS: {(20 * Math.log10(level || 0.001)).toFixed(1)} dB</span>
        <span>Peak: {(20 * Math.log10(peak || 0.001)).toFixed(1)} dB</span>
      </div>
    </div>
  )}
</LevelMeter>

Orientation Comparison

Horizontal

  • Best for: Single channel monitoring, master output, compact displays
  • Default height: 60px
  • Scale appears below the meter
  • Fills left to right

Vertical

  • Best for: Channel strips, mixer panels, stereo pairs
  • Common heights: 150-300px
  • Scale appears on the right side
  • Fills bottom to top

Released under the MIT License.