Documentation
¶
Overview ¶
Package dither provides bit-depth quantization with configurable dither PDFs and noise-shaping filters.
Index ¶
- func SharpPresetForSampleRate(sampleRate float64) []float64
- type DitherType
- type FIRShaper
- type IIRShelfShaper
- type NoiseShaper
- type Option
- func WithBitDepth(bits int) Option
- func WithDitherAmplitude(amp float64) Option
- func WithDitherType(dt DitherType) Option
- func WithFIRPreset(p Preset) Option
- func WithIIRShelf(freq float64) Option
- func WithLimit(enabled bool) Option
- func WithNoiseShaper(ns NoiseShaper) Option
- func WithRNG(rng *rand.Rand) Option
- func WithSharpPreset() Option
- type Preset
- type Quantizer
- func (q *Quantizer) BitDepth() int
- func (q *Quantizer) DitherAmplitude() float64
- func (q *Quantizer) DitherType() DitherType
- func (q *Quantizer) Limit() bool
- func (q *Quantizer) ProcessInPlace(buf []float64)
- func (q *Quantizer) ProcessInteger(input float64) int
- func (q *Quantizer) ProcessSample(input float64) float64
- func (q *Quantizer) Reset()
- func (q *Quantizer) SampleRate() float64
- func (q *Quantizer) SetBitDepth(bits int) error
- func (q *Quantizer) SetDitherAmplitude(amp float64) error
- func (q *Quantizer) SetDitherType(dt DitherType) error
- func (q *Quantizer) SetLimit(enabled bool)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SharpPresetForSampleRate ¶
SharpPresetForSampleRate returns the sharp 15 kHz noise-shaping coefficients optimized for the given sample rate. The selection logic matches the legacy TDitherSharpNoiseShaper32.ChooseNoiseshaper implementation.
Types ¶
type DitherType ¶
type DitherType int
DitherType selects the probability distribution used for dither noise.
const ( // DitherNone applies no dither (plain rounding/truncation). DitherNone DitherType = iota // DitherRectangular uses a uniform (rectangular) PDF. DitherRectangular // DitherTriangular uses a triangular PDF (TPDF), the most common choice. DitherTriangular // DitherGaussian uses an exact Gaussian PDF. DitherGaussian // DitherFastGaussian uses an approximated Gaussian PDF (sum of uniform draws). DitherFastGaussian )
func (DitherType) String ¶
func (dt DitherType) String() string
String returns the name of the dither type.
func (DitherType) Valid ¶
func (dt DitherType) Valid() bool
Valid reports whether dt is a known dither type.
type FIRShaper ¶
type FIRShaper struct {
// contains filtered or unexported fields
}
FIRShaper implements error-feedback noise shaping with FIR coefficients and a circular buffer for quantization error history.
func NewFIRShaper ¶
NewFIRShaper creates a new FIR noise shaper with the given coefficients. A nil or empty slice creates a pass-through (no shaping).
func (*FIRShaper) RecordError ¶
RecordError stores the quantization error for the current sample. Must be called once after each Shape call.
type IIRShelfShaper ¶
type IIRShelfShaper struct {
// contains filtered or unexported fields
}
IIRShelfShaper implements noise shaping using a biquad low-shelf filter applied to the quantization error signal. This provides a lightweight alternative to FIR noise shaping with less precise spectral control but lower CPU cost.
func NewIIRShelfShaper ¶
func NewIIRShelfShaper(freq, sampleRate float64) (*IIRShelfShaper, error)
NewIIRShelfShaper creates an IIR shelf noise shaper with the given corner frequency and sample rate. The shelf applies -5 dB of low-frequency de-emphasis to the error signal, pushing quantization noise above the shelf frequency where human hearing is less sensitive.
func (*IIRShelfShaper) RecordError ¶
func (s *IIRShelfShaper) RecordError(quantizationError float64)
RecordError stores the quantization error for the next Shape call.
func (*IIRShelfShaper) Reset ¶
func (s *IIRShelfShaper) Reset()
Reset clears the biquad filter state and stored error.
func (*IIRShelfShaper) Shape ¶
func (s *IIRShelfShaper) Shape(input float64) float64
Shape applies the IIR shelf filter to the previous error and subtracts it from the input.
type NoiseShaper ¶
type NoiseShaper interface {
// Shape applies the noise-shaping filter to the input sample using
// previously recorded quantization errors.
Shape(input float64) float64
// RecordError stores the quantization error from the current sample
// for use in subsequent Shape calls.
RecordError(quantizationError float64)
// Reset clears all internal state (error history, filter state).
Reset()
}
NoiseShaper applies spectral shaping to quantization error via feedback filtering. The typical usage cycle per sample is:
- shaped := shaper.Shape(scaledInput)
- quantized := round(shaped + dither)
- shaper.RecordError(float64(quantized) - shaped)
type Option ¶
type Option func(*config) error
Option configures a Quantizer.
func WithBitDepth ¶
WithBitDepth sets the target bit depth for quantization (1–32, default 16).
func WithDitherAmplitude ¶
WithDitherAmplitude sets the dither noise amplitude (default 1.0, must be >= 0).
func WithDitherType ¶
func WithDitherType(dt DitherType) Option
WithDitherType sets the dither noise PDF (default DitherTriangular).
func WithFIRPreset ¶
WithFIRPreset creates an FIRShaper from a predefined coefficient Preset.
func WithIIRShelf ¶
WithIIRShelf creates an IIRShelfShaper with the given corner frequency. The sample rate is taken from the Quantizer constructor.
func WithLimit ¶
WithLimit enables or disables output limiting to the bit-depth range (default true).
func WithNoiseShaper ¶
func WithNoiseShaper(ns NoiseShaper) Option
WithNoiseShaper sets a custom NoiseShaper implementation.
func WithSharpPreset ¶
func WithSharpPreset() Option
WithSharpPreset enables sample-rate-adaptive sharp noise shaping. The coefficient set is selected automatically based on the Quantizer's sample rate.
type Preset ¶
type Preset int
Preset identifies a predefined FIR noise-shaping coefficient set.
const ( PresetNone Preset = iota // No shaping PresetEFB // Simple error feedback, 1st order Preset2SC // Simple 2nd-order highpass Preset2MEC // Modified E-weighted, 2nd order Preset3MEC // Modified E-weighted, 3rd order Preset9MEC // Modified E-weighted, 9th order Preset5IEC // Improved E-weighted, 5th order Preset9IEC // Improved E-weighted, 9th order Preset3FC // F-weighted, 3rd order Preset9FC // F-weighted, 9th order (default) PresetSBM // Sony Super Bit Mapping, 12th order PresetSBMReduced // Reduced Super Bit Mapping, 10th order PresetSharp14k // Sharp 14 kHz rolloff, 7th order (44.1 kHz) PresetSharp15k // Sharp 15 kHz rolloff, 8th order (44.1 kHz) PresetSharp16k // Sharp 16 kHz rolloff, 9th order (44.1 kHz) PresetExperimental // Experimental, 9th order )
func (Preset) Coefficients ¶
Coefficients returns a copy of the FIR noise-shaping coefficients for this preset. Returns nil for PresetNone.
type Quantizer ¶
type Quantizer struct {
// contains filtered or unexported fields
}
Quantizer performs bit-depth quantization with optional dither noise and noise shaping.
func NewQuantizer ¶
NewQuantizer creates a new Quantizer. The default configuration is: 16-bit, triangular dither, amplitude 1.0, limiting enabled, F-weighted 9th-order FIR noise shaper (Preset9FC).
Example ¶
package main
import (
"fmt"
"math"
"math/rand/v2"
"github.com/cwbudde/algo-dsp/dsp/dither"
)
func main() {
quant, err := dither.NewQuantizer(
44100,
dither.WithBitDepth(16),
dither.WithDitherType(dither.DitherTriangular),
dither.WithRNG(rand.New(rand.NewPCG(42, 0))),
)
if err != nil {
panic(err)
}
// Quantize a sine wave sample.
input := 0.5 * math.Sin(2*math.Pi*1000/44100)
output := quant.ProcessSample(input)
fmt.Printf("quantized: %.6f\n", output)
}
Output: quantized: 0.071000
Example (SharpPreset) ¶
package main
import (
"fmt"
"math/rand/v2"
"github.com/cwbudde/algo-dsp/dsp/dither"
)
func main() {
// The sharp preset automatically selects coefficients
// optimized for the given sample rate.
quant, err := dither.NewQuantizer(
48000,
dither.WithSharpPreset(),
dither.WithBitDepth(16),
dither.WithRNG(rand.New(rand.NewPCG(42, 0))),
)
if err != nil {
panic(err)
}
output := quant.ProcessSample(0.5)
fmt.Printf("sharp: %.6f\n", output)
}
Output: sharp: 0.499992
func (*Quantizer) DitherAmplitude ¶
DitherAmplitude returns the current dither noise amplitude.
func (*Quantizer) DitherType ¶
func (q *Quantizer) DitherType() DitherType
DitherType returns the current dither noise type.
func (*Quantizer) ProcessInPlace ¶
ProcessInPlace quantizes each sample in buf in-place.
Example ¶
package main
import (
"fmt"
"github.com/cwbudde/algo-dsp/dsp/dither"
)
func main() {
quant, err := dither.NewQuantizer(
44100,
dither.WithBitDepth(16),
dither.WithDitherType(dither.DitherNone),
dither.WithFIRPreset(dither.PresetNone),
)
if err != nil {
panic(err)
}
buf := []float64{0.0, 0.25, 0.5, 0.75}
quant.ProcessInPlace(buf)
for _, val := range buf {
fmt.Printf("%.6f ", val)
}
fmt.Println()
}
Output: 0.000015 0.249989 0.499992 0.749996
func (*Quantizer) ProcessInteger ¶
ProcessInteger quantizes the input (expected in [-1, +1]) to an integer in the bit-depth range.
func (*Quantizer) ProcessSample ¶
ProcessSample quantizes the input and returns a normalized float64 in approximately [-1, +1].
func (*Quantizer) Reset ¶
func (q *Quantizer) Reset()
Reset clears all internal state (noise shaper history).
func (*Quantizer) SampleRate ¶
SampleRate returns the configured sample rate.
func (*Quantizer) SetBitDepth ¶
SetBitDepth changes the target bit depth (1–32).
func (*Quantizer) SetDitherAmplitude ¶
SetDitherAmplitude changes the dither noise amplitude.
func (*Quantizer) SetDitherType ¶
func (q *Quantizer) SetDitherType(dt DitherType) error
SetDitherType changes the dither noise PDF.