noisereduce

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: MIT Imports: 11 Imported by: 0

README

noisereduce

Pure-Go spectral-gating noise reduction for audio-rate signals. This project is a Go port of the Python noisereduce library. The package supports stationary and non-stationary noise reduction, includes a small WAV reader/writer, and ships a CLI for processing WAV files. Please refer to the original Python project for more details on the underlying algorithms and their parameters.

Features

  • Pure Go library API for mono or multichannel signals shaped [channels][frames]float64.
  • In-memory WAV byte input/output for services and pipelines that do not use files.
  • Non-stationary spectral gating with a continuously estimated noise floor.
  • Stationary spectral gating with an optional noise reference clip.
  • Chunked processing with parallel workers for long recordings.
  • WAV input support for PCM and IEEE float data, with 16-bit PCM WAV output.
  • No cgo dependency.

Install

go get github.com/cemremengu/noisereduce

CLI Usage

Run the CLI from the repository:

go run ./cmd/noisereduce -in noisy.wav -out clean.wav

Use stationary mode with a separate noise reference:

go run ./cmd/noisereduce \
  -in noisy.wav \
  -out clean.wav \
  -stationary \
  -noise sample_noise.wav

Build and install the command:

go install github.com/cemremengu/noisereduce/cmd/noisereduce@latest
noisereduce -in noisy.wav -out clean.wav

Common CLI flags:

Flag Description Default
-in Input WAV path. Required.
-out Output WAV path. Required. Writes 16-bit PCM.
-stationary Use stationary gating instead of non-stationary gating. false
-noise Noise reference WAV for stationary mode.
-prop-decrease Proportion of noise to suppress, from 0 to 1. 1.0
-n-fft FFT size. 1024
-win-length STFT window length. 0 means n-fft. 0
-hop-length STFT hop length. 0 means win-length/4. 0
-time-constant Non-stationary IIR time constant in seconds. 2.0
-n-std-thresh Stationary standard-deviation threshold multiplier. 1.5
-chunk-size Frames per chunk. 0 disables chunking. 600000
-padding Frames of padding around each chunk. 30000
-jobs Parallel chunk workers. 0 uses GOMAXPROCS. 0

Library Usage

Read a WAV, reduce noise with the default non-stationary gate, and write a new WAV:

package main

import (
    "log"

    noisereduce "github.com/cemremengu/noisereduce"
)

func main() {
    samples, sr, err := noisereduce.ReadWAV("noisy.wav")
    if err != nil {
        log.Fatal(err)
    }

    opt := noisereduce.DefaultOptions()
    opt.Algorithm = noisereduce.NonStationary
    opt.PropDecrease = 1.0

    denoised, err := noisereduce.ReduceNoise(samples, sr, opt)
    if err != nil {
        log.Fatal(err)
    }

    if err := noisereduce.WriteWAVPCM16("clean.wav", denoised, sr); err != nil {
        log.Fatal(err)
    }
}

Use stationary mode with an explicit noise clip:

samples, sr, err := noisereduce.ReadWAV("noisy.wav")
if err != nil {
    log.Fatal(err)
}

noise, noiseSR, err := noisereduce.ReadWAV("noise.wav")
if err != nil {
    log.Fatal(err)
}
if noiseSR != sr {
    log.Fatalf("noise sample rate %d does not match input sample rate %d", noiseSR, sr)
}

opt := noisereduce.DefaultOptions()
opt.Algorithm = noisereduce.Stationary
opt.YNoise = noise
opt.NStdThreshStationary = 1.5
opt.NJobs = 0

clean, err := noisereduce.ReduceNoise(samples, sr, opt)
if err != nil {
    log.Fatal(err)
}

Use the mono helper when your data is a single []float64 channel:

cleanMono, err := noisereduce.ReduceNoiseMono(noisyMono, sampleRate, noisereduce.DefaultOptions())
if err != nil {
    log.Fatal(err)
}

Process WAV data already held in memory:

cleanWAV, err := noisereduce.ReduceNoiseWAVBytes(noisyWAV, noisereduce.DefaultOptions())
if err != nil {
    log.Fatal(err)
}

Or decode and encode WAV bytes explicitly:

samples, sr, err := noisereduce.ReadWAVBytes(noisyWAV)
if err != nil {
    log.Fatal(err)
}

clean, err := noisereduce.ReduceNoise(samples, sr, noisereduce.DefaultOptions())
if err != nil {
    log.Fatal(err)
}

cleanWAV, err := noisereduce.WriteWAVPCM16Bytes(clean, sr)
if err != nil {
    log.Fatal(err)
}

Options

Start with DefaultOptions() and override only the fields you need.

opt := noisereduce.DefaultOptions()
opt.Algorithm = noisereduce.NonStationary
opt.PropDecrease = 0.8
opt.TimeConstantS = 1.5
opt.FreqMaskSmoothHz = 500
opt.TimeMaskSmoothMs = 50
opt.ChunkSize = 0 // one-shot processing

Important fields:

Field Description
Algorithm NonStationary or Stationary.
YNoise Optional stationary-mode noise reference shaped [channels][frames].
PropDecrease Blend amount for suppression. 0 preserves the signal, 1 applies full suppression.
TimeConstantS Time constant for non-stationary floor estimation.
FreqMaskSmoothHz Frequency smoothing width for the spectral mask. 0 disables frequency smoothing.
TimeMaskSmoothMs Time smoothing width for the spectral mask. 0 disables time smoothing.
ThreshNMultNonstationary Non-stationary sigmoid shift.
SigmoidSlopeNonstationary Non-stationary sigmoid slope.
NStdThreshStationary Stationary threshold multiplier.
NFFT, WinLength, HopLength STFT geometry.
ChunkSize, Padding, NJobs Chunking and parallelism controls.

Choosing An Algorithm

Stationary gating is useful when you have a representative noise-only clip or when the noise floor is stable across the recording. If YNoise is not supplied, the input signal is also used as the noise reference.

Non-stationary gating is useful when background noise changes over time. It estimates a time-smoothed noise floor from the input itself and does not use a separate noise clip.

Development

Run tests:

go test ./...

Run the noise-reduction benchmarks:

go test -run '^$' -bench 'BenchmarkReduceNoise' -benchmem

Capture a CPU profile while running the same benchmarks:

go test -run '^$' -bench 'BenchmarkReduceNoise' -benchmem -cpuprofile cpu.out

Build the CLI:

go build ./cmd/noisereduce

Disclaimer

This library was built with significant help from Claude and Codex and may include inaccuracies, inefficient code patterns, or potential security vulnerabilities. Please use it with caution. If you encounter any issues, feel free to open an issue or submit a pull request.

Documentation

Overview

Package noisereduce performs spectral-gating noise reduction on audio-rate signals. It is a pure-Go implementation with two algorithms:

  • Stationary spectral gating (NStdThreshStationary, optional noise clip). Statistics are computed once over a noise sample (or the signal itself) and a fixed threshold is applied to the entire input.
  • Non-stationary spectral gating, where the noise floor is estimated continuously from a time-smoothed magnitude spectrogram.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BandLimitedNoise

func BandLimitedNoise(minFreq, maxFreq float64, samples, sampleRate int, r *rand.Rand) []float64

BandLimitedNoise generates a band-limited noise signal of the given length and sample rate.

minFreq and maxFreq are inclusive Hz bounds.

func FFTNoise

func FFTNoise(f []float64, r *rand.Rand) []float64

FFTNoise randomises phases in a real-valued half-symmetric spectrum f and returns the inverse FFT real part.

f is a length-N real spectrum (typically a band-pass mask). The output is a length-N real time-domain signal.

func ReadWAV

func ReadWAV(path string) (samples [][]float64, sampleRate int, err error)

ReadWAV reads a WAVE file and returns samples shaped [channels][frames] as float64 in [-1, 1] (PCM normalised by 32768).

func ReadWAVBytes

func ReadWAVBytes(data []byte) (samples [][]float64, sampleRate int, err error)

ReadWAVBytes reads WAVE data from memory and returns samples shaped [channels][frames] as float64 in [-1, 1] (PCM normalised by 32768).

func ReduceNoise

func ReduceNoise(y [][]float64, sr int, opt Options) ([][]float64, error)

ReduceNoise applies spectral-gating noise reduction to a multichannel signal shaped [channels][frames]. The output has the same shape.

func ReduceNoiseMono

func ReduceNoiseMono(y []float64, sr int, opt Options) ([]float64, error)

ReduceNoiseMono is a convenience wrapper for single-channel input.

func ReduceNoiseWAVBytes

func ReduceNoiseWAVBytes(data []byte, opt Options) ([]byte, error)

ReduceNoiseWAVBytes reads WAV data from memory, applies ReduceNoise, and returns a 16-bit PCM WAV byte slice.

func WriteWAVPCM16

func WriteWAVPCM16(path string, samples [][]float64, sampleRate int) error

WriteWAVPCM16 writes [channels][frames] float64 samples as 16-bit PCM. Samples are clamped to [-1, 1] and scaled by 32767.

func WriteWAVPCM16Bytes

func WriteWAVPCM16Bytes(samples [][]float64, sampleRate int) ([]byte, error)

WriteWAVPCM16Bytes encodes [channels][frames] float64 samples as a 16-bit PCM WAV byte slice. Samples are clamped to [-1, 1] and scaled by 32767.

Types

type Algorithm

type Algorithm int

Algorithm selects between stationary and non-stationary spectral gating.

const (
	// NonStationary estimates the noise floor continuously from a
	// time-smoothed magnitude spectrogram. Default.
	NonStationary Algorithm = iota
	// Stationary uses a fixed threshold derived from a noise clip
	// (or the signal itself if no clip is supplied).
	Stationary
)

type Options

type Options struct {
	Algorithm Algorithm

	// YNoise is an optional noise reference for the stationary gate.
	// Shape [channels][frames]. Channels are averaged before STFT.
	// If nil, Y itself is used as the noise reference.
	YNoise [][]float64

	PropDecrease              float64 // proportion to suppress (0..1); default 1.0
	TimeConstantS             float64 // IIR time constant in seconds; default 2.0
	FreqMaskSmoothHz          float64 // freq smoothing width (Hz); 0 disables; default 500
	TimeMaskSmoothMs          float64 // time smoothing width (ms); 0 disables; default 50
	ThreshNMultNonstationary  float64 // sigmoid shift; default 2
	SigmoidSlopeNonstationary float64 // sigmoid slope; default 10
	NStdThreshStationary      float64 // stddev multiplier; default 1.5

	ChunkSize int // frames per chunk; 0 disables chunking; default 600000
	Padding   int // pad applied around each chunk; default 30000

	NFFT      int // FFT length; default 1024
	WinLength int // window length; 0 => NFFT
	HopLength int // hop between frames; 0 => WinLength/4

	ClipNoiseStationary bool // stationary: clip noise to ChunkSize. Default true.

	NJobs int // parallel chunk workers; 0 => runtime.GOMAXPROCS(0)
}

Options controls ReduceNoise.

Start from DefaultOptions() to get the standard spectral-gating settings, then override the knobs you care about. A zero-valued Options{} is also valid: every field's zero value has a well-defined meaning (e.g. PropDecrease=0 disables suppression, ChunkSize=0 disables chunking, FreqMaskSmoothHz=0 disables freq smoothing). Only NFFT is auto-defaulted, since 0 makes the STFT undefined; pass DefaultOptions().NFFT (1024) explicitly if you prefer.

Field names use Go exported identifiers for the algorithm parameters.

func DefaultOptions

func DefaultOptions() Options

DefaultOptions returns the recommended option set for spectral gating.

Directories

Path Synopsis
cmd
noisereduce command
Command noisereduce applies spectral-gating noise reduction to a WAV file.
Command noisereduce applies spectral-gating noise reduction to a WAV file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL