Skip to content

feat(peaks): server-side peaks JSON generator (per-channel) #28

Description

@nanxingw

Slice 1 of 8 — Phase A of Multi-Track Stacking + Industrial Waveform PRD

Implement src/server/audio/peaks.ts: take an audio file, invoke ffmpeg to extract per-channel Float32 PCM, reduce into 32-buckets-per-second JSON, and write <asset>.peaks.json atomically.

Scope

  • New file src/server/audio/peaks.ts + __tests__/peaks.test.ts
  • JSON shape (frozen): { version: 2, sampleRate, durationSec, sampleCount, channels: number[][] }
  • PEAKS_PER_SEC = 32 (frozen constant)
  • ffmpeg command: ffmpeg -i <src> -ac <channels> -ar 48000 -f f32le -hide_banner pipe:1
  • Float32 stream reducer: max-abs over each 48000/32 = 1500-sample window
  • Atomic write via .tmp + rename
  • Idempotent: skip if existing <file>.peaks.json mtime ≥ asset mtime

Pitfalls to dodge

  • Per-channel array, NOT summed (pitfall Parker's #3 from PRD industry survey — Shotcut's summed waveform hides L/R imbalance). Test must assert result.channels.length === fileChannelCount.
  • Last-bucket partial-window edge case (emit whatever samples are there).

Acceptance criteria

  • Unit tests pass against fixtures: short mono mp3, 30s stereo wav, 0-byte file (rejects without writing)
  • Per-channel assertion explicit in tests
  • Idempotence test: second invocation on unchanged file is a no-op
  • Atomic write verified (no half-written JSON visible mid-process)

See docs/superpowers/plans/2026-05-25-multi-track-stacking.md for the full design.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentReady for an AFK agent to pick up — fully specified

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions