# Spectrum analyzer

> A real-time spectrum analyzer for Python — bars, LED blocks, lines, mirrored or radial, log-spaced bands, falloff, peak caps and color palettes.

Source: https://albakore.github.io/pyzed/audio/components/spectrum/

(Image: Six spectrum analyzers dancing to the same song: bars, blocks, line, filled, mirror and radial)

**In plain words:**

A spectrum analyzer splits a sound into its pitches: bass on the left, treble on the right, and
the taller the bar, the louder that pitch. It is the classic music visualizer.

```python
class Visualizer(pz.App):
    def subscriptions(self):
        return [pz.frames(lambda dt: None)]   # redraw every frame

    def view(self):
        return ui.audio.Spectrum(magnitudes=engine.spectrum(512), variant="blocks", colors="fl")
```

## From FFT bins to bands

`magnitudes` are decibels (−120 to 0), one per frequency bin — exactly what `node.spectrum()`
and `engine.spectrum()` return. The analyzer groups them into `bands` bands spaced
**logarithmically** (each band a little wider than the one before), the way the ear hears: an
octave takes the same width at 100 Hz as at 5 kHz. Each band shows its loudest bin.

`spacing` says how your bins are spaced:

- `"log"` (the default): already log-spaced from 20 Hz to half the sample rate, like the engine's
  spectrum. They are only regrouped into `bands`.
- `"linear"`: evenly spaced from 0 Hz, like the output of a plain FFT (`numpy.fft.rfft`). The
  analyzer works out which bins belong to each band from `sample_rate`.

`min_db` and `max_db` are the bottom and top of the display.

## Motion

Bars jump up at once and fall at `falloff` decibels per second (0 makes them follow the input
exactly), so the display looks smooth even when the input flickers. With `peaks=True` a small
cap stays on top of each bar and drops more slowly. The speed is measured in real time, so it
is the same at 30 or 144 frames per second.

## Looks and colors

| `variant` | Looks like |
| --- | --- |
| `"bars"` | Solid bars. |
| `"blocks"` | LED segments, like a hi-fi. |
| `"line"` | A glowing line through the band tops. |
| `"filled"` | The same line with the area below filled. |
| `"mirror"` | Bars centered vertically, for a symmetric look. |
| `"radial"` | Bars around a circle, like a music visualizer. |

`colors` is a palette (`"fl"`, `"neon"`, `"fire"`, `"ice"`, `"magma"`, `"viridis"`...) or a list of
colors. `color_by="level"` paints each bar from quiet (bottom) to loud (top);
`color_by="frequency"` gives each band its own color from bass to treble. `labels=True` marks
100 Hz, 1 kHz and 10 kHz.

| Property | Default | What it does |
| --- | --- | --- |
| `magnitudes` | `()` | dB per frequency bin. |
| `width`, `height` | `360`, `140` | Size in pixels. |
| `variant` | `"bars"` | See the table above. |
| `bands` | `48` | Number of bands. |
| `spacing` | `"log"` | How `magnitudes` are spaced: `"log"` (the engine) or `"linear"` (a plain FFT). |
| `min_db`, `max_db` | `-90`, `0` | Range shown. |
| `colors`, `color_by` | `"fl"`, `"level"` | Palette and what it follows. |
| `falloff`, `peaks` | `48`, `True` | Fall speed (dB/s) and peak caps. |
| `sample_rate` | `48000` | For the labels and the band edges. |
| `labels`, `gap`, `background` | `False`, `2`, `"#0f1012"` | |

**Tip:**

`ui.audio.bands(magnitudes, 16)` gives you the same log-spaced bands as numbers, to drive
anything else with the music: the size of a logo, the color of the window, a particle system.
