Skip to main content

High-performance Python DSP toolkit built on C++ libraries via nanobind

Project description

nanodsp

High-performance Python DSP toolkit built on C++ libraries via nanobind. All processing uses float32 in a planar [channels, frames] layout with block-based APIs that accept and return AudioBuffer objects.

Backends

Library License What it provides
signalsmith-dsp MIT Filters, FFT, delay, envelopes, spectral processing, rates, mix
DaisySP MIT Oscillators, effects, dynamics, drums, physical modeling, noise
STK MIT Physical modeling instruments, generators, filters, delays, effects
madronalib MIT FDN reverbs, resampling, generators, projections, windows
HISSTools Library BSD-3 Convolution, spectral processing, statistical analysis, windows
CHOC ISC FLAC codec (read/write)
GrainflowLib MIT Granular synthesis (grain collections, panning, recording, phasor)
fxdsp MIT Antialiased waveshaping, Schroeder/Moorer reverbs, formant filter, PSOLA pitch shift, MinBLEP oscillators
DspFilters MIT Multi-order IIR filter design (Butterworth, Chebyshev I/II, Elliptic, Bessel)
vafilters MIT Virtual analog filters (Moog, Diode, Korg35, Oberheim) via Faust
PolyBLEP et al. MIT Band-limited oscillators (PolyBLEP, BLIT, DPW, MinBLEP, wavetable)

Requirements

  • Python >= 3.10
  • numpy
  • C++17 compiler
  • CMake >= 3.15

Install

pip install nanodsp

Or if you prefer to build from source (requires uv and cmake):

git clone https://github.com/shakfu/nanodsp.git
cd nanodsp
uv sync            # install dependencies + build extension
uv run pytest      # run tests
uv build           # build wheel

Use make help for additional targets (build, test, lint, format, typecheck, qa, coverage, etc.).

CLI

nanodsp ships with a command-line interface accessible via nanodsp or python -m nanodsp.

# File info
nanodsp info drums.wav
nanodsp info drums.wav --json

# Process with effect chain (single file)
nanodsp process input.wav -o output.wav \
  -f highpass:cutoff_hz=80 \
  -f compress:ratio=4,threshold=-18 \
  -f normalize_peak:target_db=-1

# Apply a preset
nanodsp process vocals.wav -o out.wav -p vocal_chain
nanodsp process input.wav -o out.wav -f lowpass:cutoff_hz=12000 -p master

# Batch mode -- process multiple files to a directory
nanodsp process *.wav -O out/ -f lowpass:cutoff_hz=2000

# Dry run -- show chain without reading/writing files
nanodsp process input.wav -n -f highpass:cutoff_hz=80 -f compress:ratio=4

# Verbose / quiet
nanodsp -v process input.wav -o out.wav -f lowpass:cutoff_hz=1000
nanodsp -q process input.wav -o out.wav -p master

# Analyze
nanodsp analyze input.wav loudness
nanodsp analyze input.wav pitch --fmin=80 --fmax=800
nanodsp analyze input.wav onsets --json
nanodsp analyze input.wav info

# Synthesize
nanodsp synth tone.wav sine --freq=440 --duration=2.0
nanodsp synth kick.wav drum --type=analog_bass_drum --freq=60
nanodsp synth melody.wav note --instrument=clarinet --freq=440 --duration=1.0
nanodsp synth seq.wav sequence --instrument=flute \
  --notes='[{"freq":440,"start":0,"dur":0.5},{"freq":554,"start":0.5,"dur":0.5}]'

# Convert
nanodsp convert input.wav output.flac
nanodsp convert input.wav output.wav --sample-rate=44100 --channels=1 -b 24

# Presets
nanodsp preset list
nanodsp preset list spatial
nanodsp preset info master
nanodsp preset apply master input.wav output.wav target_lufs=-16

# Pipe (stdin/stdout streaming)
cat input.wav | nanodsp pipe -f lowpass:cutoff_hz=1000 > output.wav
cat input.wav | nanodsp pipe -p telephone > output.wav
nanodsp pipe -f highpass:cutoff_hz=80 < in.wav | nanodsp pipe -f compress:ratio=4 > out.wav

# Benchmark
nanodsp benchmark lowpass:cutoff_hz=1000
nanodsp benchmark compress:ratio=4,threshold=-20 -n 100 --duration=2.0
nanodsp benchmark reverb:preset=hall --channels=2 --json

# List available functions
nanodsp list
nanodsp list filters
nanodsp list effects

Presets

30 built-in presets across 8 categories:

Category Presets
mastering master, master_pop, master_hiphop, master_classical, master_edm, master_podcast
voice vocal_chain
spatial room, hall, plate, cathedral, chamber
dynamics gentle_compress, heavy_compress, brick_wall
creative radio, underwater, megaphone, tape_warmth, shimmer, vaporwave, walkie_talkie
lofi telephone, lo_fi, vinyl, 8bit
cleanup dc_remove, de_noise, normalize, normalize_lufs

Quick start

from nanodsp.buffer import AudioBuffer
from nanodsp import effects, analysis

# Read, process, write
buf = (
    AudioBuffer.from_file("input.wav")
    .pipe(effects.highpass, freq=80.0)
    .pipe(effects.compress, threshold=-18.0, ratio=4.0)
    .pipe(analysis.normalize_lufs, target_lufs=-14.0)
)
buf.write("output.wav")

Modules

nanodsp.buffer -- AudioBuffer

The central data type. A 2D float32 array with shape [channels, frames] plus metadata (sample_rate, channel_layout, label).

from nanodsp.buffer import AudioBuffer

# Construction
buf = AudioBuffer(np.zeros((2, 44100), dtype=np.float32), sample_rate=44100)
buf = AudioBuffer.from_file("input.wav")       # read WAV/FLAC
buf = AudioBuffer.sine(440.0, channels=1, frames=44100, sample_rate=44100)
buf = AudioBuffer.noise(channels=2, frames=44100, sample_rate=44100)
buf = AudioBuffer.zeros(channels=1, frames=1024, sample_rate=44100)
buf = AudioBuffer.impulse(channels=1, frames=1024, sample_rate=44100)

# Properties
buf.channels        # number of channels
buf.frames          # number of frames
buf.sample_rate     # sample rate in Hz
buf.duration        # duration in seconds
buf.mono            # 1D view (mono buffers only)
buf.channel(0)      # 1D view of channel 0

# Channel operations
buf.to_mono("mean")                    # downmix
buf.to_channels(2)                     # upmix mono to stereo
AudioBuffer.concat_channels(a, b)      # stack channels

# Arithmetic
buf + other          # add
buf * 0.5            # scale
buf.gain_db(-6.0)    # apply dB gain

# I/O
buf.write("output.wav")                # write WAV/FLAC (detected by extension)
buf.write("output.flac", bit_depth=24)

# Pipeline
buf.pipe(effects.lowpass, freq=1000.0)

nanodsp.io -- Audio file I/O

Read and write WAV (8/16/24/32-bit PCM) and FLAC (16/24-bit) files. Zero external dependencies for WAV (uses stdlib wave); FLAC uses the CHOC codec.

from nanodsp import io

buf = io.read("file.wav")          # auto-detect by extension
buf = io.read("file.flac")
io.write("out.wav", buf)           # 16-bit default
io.write("out.flac", buf, bit_depth=24)

# Format-specific
buf = io.read_wav("file.wav")
io.write_wav("out.wav", buf, bit_depth=24)
buf = io.read_flac("file.flac")
io.write_flac("out.flac", buf, bit_depth=16)

# Byte-level (for stdin/stdout/pipe workflows)
buf = io.read_wav_bytes(raw_bytes)           # parse WAV from bytes
raw = io.write_wav_bytes(buf, bit_depth=16)  # serialize to WAV bytes

nanodsp.ops -- Core DSP operations

Low-level building blocks: delay, envelopes, FFT, convolution, sample rates, mixing, panning, normalization, cross-correlation, Hilbert transform, median filter, LMS adaptive filter.

from nanodsp import ops

# Delay
ops.delay(buf, delay_samples=100)
ops.delay_varying(buf, delays=delay_curve)

# Envelopes
ops.box_filter(buf, length=64)
ops.box_stack_filter(buf, size=32, layers=4)
ops.peak_hold(buf, length=128)
ops.peak_decay(buf, length=256)

# FFT
spectra = ops.rfft(buf)                        # forward real FFT
buf = ops.irfft(spectra, size=1024, sample_rate=44100)  # inverse

# Convolution
ops.convolve(buf, ir, normalize=True)

# Sample rates
ops.upsample_2x(buf)
ops.oversample_roundtrip(buf)

# Mixing
ops.hadamard(buf)              # Hadamard matrix mixing
ops.householder(buf)           # Householder reflection
ops.crossfade(buf_a, buf_b, x=0.5)
ops.mix_buffers(a, b, c, gains=[1.0, 0.5, 0.8])

# LFO
lfo_signal = ops.lfo(frames=44100, low=0.0, high=1.0, rate=2.0)

# Normalization
ops.normalize_peak(buf, target_db=-1.0)
ops.trim_silence(buf, threshold_db=-60.0)

# Fades
ops.fade_in(buf, duration_ms=10.0)
ops.fade_out(buf, duration_ms=50.0, curve="exp")

# Panning and stereo
ops.pan(buf, position=0.3)     # equal-power pan
ops.mid_side_encode(buf)
ops.mid_side_decode(buf)
ops.stereo_widen(buf, width=1.5)

# Cross-correlation
corr = ops.xcorr(buf_a, buf_b)        # cross-correlation
auto = ops.xcorr(buf)                  # autocorrelation

# Hilbert / envelope
env = ops.hilbert(buf)                 # analytic signal envelope
env = ops.envelope(buf)                # alias for hilbert

# Median filter
ops.median_filter(buf, kernel_size=5)

# LMS adaptive filter
output, error = ops.lms_filter(buf, ref, filter_len=32, step_size=0.01)

nanodsp.effects -- Filters, effects, dynamics, mastering

70 functions covering signalsmith biquad filters, DaisySP effects/filters/dynamics, composed effects, reverbs, mastering chains, STK effects, automatic gain control, antialiased waveshaping, classic reverbs, formant filtering, PSOLA pitch shifting, and multi-order IIR filters.

Biquad filters (signalsmith)

All filter functions take freq in Hz, auto-converted to normalized frequency.

from nanodsp import effects

effects.lowpass(buf, freq=1000.0, q=0.707)
effects.highpass(buf, freq=80.0)
effects.bandpass(buf, freq=1000.0, q=2.0)
effects.notch(buf, freq=50.0)
effects.peak(buf, freq=1000.0, gain=2.0, q=1.0)
effects.peak_db(buf, freq=1000.0, db=6.0)
effects.high_shelf(buf, freq=8000.0, gain=1.5)
effects.high_shelf_db(buf, freq=8000.0, db=3.0)
effects.low_shelf(buf, freq=200.0, gain=0.8)
effects.low_shelf_db(buf, freq=200.0, db=-2.0)
effects.allpass(buf, freq=1000.0)

DaisySP effects

effects.autowah(buf, wah=0.5)
effects.chorus(buf, rate=1.0, depth=0.5)
effects.decimator(buf, downsample_factor=0.5, bitcrush_factor=0.5)
effects.flanger(buf, rate=0.2, depth=0.5, feedback=0.5)
effects.overdrive(buf, drive=0.7)
effects.phaser(buf, rate=0.3, depth=0.5, feedback=0.5)
effects.pitch_shift(buf, semitones=12.0)
effects.sample_rate_reduce(buf, factor=0.5)
effects.tremolo(buf, rate=5.0, depth=0.8)
effects.wavefold(buf, gain=2.0)
effects.bitcrush(buf, bits=8)
effects.fold(buf, gain=2.0)
effects.reverb_sc(buf, feedback=0.8, lpfreq=10000.0)
effects.dc_block(buf)

DaisySP filters

effects.svf_lowpass(buf, freq=1000.0, res=0.5)
effects.svf_highpass(buf, freq=200.0, res=0.5)
effects.svf_bandpass(buf, freq=1000.0, res=0.7)
effects.svf_notch(buf, freq=1000.0, res=0.5)
effects.svf_peak(buf, freq=1000.0, res=0.8)
effects.ladder_filter(buf, freq=800.0, res=0.6, mode="lp24")
effects.moog_ladder(buf, freq=1000.0, res=0.7)
effects.tone_lowpass(buf, freq=2000.0)
effects.tone_highpass(buf, freq=100.0)
effects.modal_bandpass(buf, freq=440.0, q=50.0)
effects.comb_filter(buf, freq=500.0, revtime=0.5)

Dynamics

effects.compress(buf, threshold=-20.0, ratio=4.0, attack=0.01, release=0.1)
effects.limit(buf, threshold=-1.0)

Composed effects

effects.saturate(buf, drive=0.7, mode="soft")    # soft, hard, or tape
effects.exciter(buf, freq=3000.0, drive=0.4)
effects.de_esser(buf, freq=6000.0, threshold=-20.0)
effects.parallel_compress(buf, mix=0.5, threshold=-24.0, ratio=8.0)
effects.noise_gate(buf, threshold_db=-40.0)
effects.stereo_delay(buf, delay_l=0.25, delay_r=0.375, feedback=0.4, ping_pong=True)
effects.multiband_compress(buf, crossovers=[200.0, 2000.0, 8000.0])

Reverb

effects.reverb(buf, preset="hall", decay=2.0, mix=0.3)
# Presets: room, hall, plate, chamber, cathedral

Mastering and vocal chains

effects.master(buf, target_lufs=-14.0)
effects.vocal_chain(buf, de_ess_freq=6000.0, comp_threshold=-18.0)

STK effects

effects.stk_reverb(buf, algorithm="freeverb", decay=1.5, mix=0.3)
effects.stk_chorus(buf, mod_depth=0.02, mod_freq=1.0, mix=0.5)
effects.stk_echo(buf, delay=0.25, max_delay=1.0, mix=0.5)

Automatic gain control

effects.agc(buf, target_level=1.0, max_gain_db=60.0, average_len=100, attack=0.01, release=0.01)

Antialiased waveshaping (fxdsp)

effects.aa_hard_clip(buf, drive=2.0)       # 1st-order antiderivative hard clip
effects.aa_soft_clip(buf, drive=2.0)       # 1st-order antiderivative soft clip
effects.aa_wavefold(buf, drive=2.0)        # 2nd-order Buchla-style wavefolder

Classic reverbs (fxdsp)

effects.schroeder_reverb(buf, feedback=0.7, diffusion=0.5, mod_depth=0.0)
effects.moorer_reverb(buf, feedback=0.7, diffusion=0.7, mod_depth=0.1)

Formant filter and PSOLA pitch shifting (fxdsp)

effects.formant_filter(buf, vowel="a")           # 'a','e','i','o','u'
effects.psola_pitch_shift(buf, semitones=5.0)     # pitch-synchronous overlap-add

Multi-order IIR filters (DspFilters)

effects.iir_filter(buf, family="butterworth", filter_type="lowpass", order=4, freq=1000.0)
effects.iir_filter(buf, family="chebyshev1", filter_type="highpass", order=6, freq=200.0, ripple_db=1.0)
effects.iir_filter(buf, family="elliptic", filter_type="bandpass", order=4, freq=1000.0, width=500.0)
effects.iir_filter(buf, family="bessel", filter_type="lowpass", order=8, freq=5000.0)

# Return SOS coefficients without applying
sos = effects.iir_design("butterworth", "lowpass", order=4, sample_rate=44100, freq=1000.0)

nanodsp.spectral -- STFT and spectral processing

Short-time Fourier transform, spectral utilities, and spectral transforms.

from nanodsp import spectral

# STFT
spec = spectral.stft(buf, window_size=2048, hop_size=512)
buf = spectral.istft(spec)

# Spectral utilities
mag = spectral.magnitude(spec)
ph = spectral.phase(spec)
spec = spectral.from_polar(mag, ph)
spec = spectral.apply_mask(spec, mask)
spec = spectral.spectral_gate(spec, threshold_db=-40.0)
spec = spectral.spectral_emphasis(spec, low_db=-3.0, high_db=3.0)
freq = spectral.bin_freq(bin_index=10, fft_size=2048, sample_rate=44100)
b = spectral.freq_to_bin(freq=1000.0, fft_size=2048, sample_rate=44100)

# Spectral transforms
stretched = spectral.time_stretch(buf, rate=0.5)        # half speed
locked = spectral.phase_lock(spec)                       # identity phase-locking
frozen = spectral.spectral_freeze(buf, frame_index=10)   # frozen texture
morphed = spectral.spectral_morph(spec_a, spec_b, x=0.5)
shifted = spectral.pitch_shift_spectral(buf, semitones=5.0)
denoised = spectral.spectral_denoise(buf, noise_frames=10)

# EQ matching
matched = spectral.eq_match(source_buf, target_buf, strength=1.0)

nanodsp.synthesis -- Oscillators, noise, drums, physical modeling

Sound generators using DaisySP and STK backends.

from nanodsp import synthesis

# Oscillators
synthesis.oscillator(freq=440.0, waveform="saw", frames=44100)
synthesis.fm2(freq=440.0, ratio=2.0, index=1.0, frames=44100)
synthesis.formant_oscillator(freq=440.0, formant_freq=800.0, frames=44100)
synthesis.bl_oscillator(freq=440.0, waveform="saw", frames=44100)

# Noise
synthesis.white_noise(frames=44100, amp=0.5)
synthesis.clocked_noise(freq=1000.0, frames=44100)
synthesis.dust(density=100.0, frames=44100)

# Drums
synthesis.analog_bass_drum(freq=60.0, frames=44100)
synthesis.analog_snare_drum(freq=200.0, frames=44100)
synthesis.hihat(freq=3000.0, frames=44100)
synthesis.synthetic_bass_drum(freq=60.0, frames=44100)
synthesis.synthetic_snare_drum(freq=200.0, frames=44100)

# Physical modeling
synthesis.karplus_strong(buf, freq=440.0, brightness=0.5, damping=0.5)
synthesis.modal_voice(freq=440.0, frames=44100)
synthesis.string_voice(freq=440.0, frames=44100)
synthesis.pluck(freq=440.0, frames=44100)
synthesis.drip(freq=1000.0, frames=44100)

# STK synthesis
synthesis.synth_note("clarinet", freq=440.0, amplitude=0.8, duration=1.0)
synthesis.synth_sequence("flute", notes=[
    {"freq": 440.0, "amp": 0.8, "start": 0.0, "dur": 0.5},
    {"freq": 554.37, "amp": 0.7, "start": 0.5, "dur": 0.5},
])

# MinBLEP oscillators (fxdsp)
synthesis.minblep(frames=44100, freq=440.0, waveform="saw")     # saw, rsaw, square, triangle
synthesis.minblep(frames=44100, freq=440.0, waveform="square", pulse_width=0.3)

Available STK instruments: clarinet, flute, brass, bowed, plucked, sitar, stifkarp, saxofony, recorder, blowbotl, blowhole, whistle.

nanodsp.analysis -- Loudness, spectral features, pitch, onsets, resampling

from nanodsp import analysis

# Loudness (ITU-R BS.1770-4)
lufs = analysis.loudness_lufs(buf)
buf = analysis.normalize_lufs(buf, target_lufs=-14.0)

# Spectral features
centroid = analysis.spectral_centroid(buf)
bandwidth = analysis.spectral_bandwidth(buf)
rolloff = analysis.spectral_rolloff(buf, percentile=0.85)
flux = analysis.spectral_flux(buf, rectify=True)
flatness = analysis.spectral_flatness_curve(buf)
chroma = analysis.chromagram(buf, n_chroma=12, tuning_hz=440.0)

# Pitch detection (YIN algorithm)
f0, confidence = analysis.pitch_detect(buf, method="yin", fmin=50.0, fmax=2000.0)

# Onset detection
onsets = analysis.onset_detect(buf, method="spectral_flux", threshold=0.5)

# Resampling
buf_48k = analysis.resample(buf, target_sr=48000.0)       # madronalib backend
buf_22k = analysis.resample_fft(buf, target_sr=22050.0)   # FFT-based

# GCC-PHAT delay estimation
delay_sec, corr = analysis.gcc_phat(buf, ref)

nanodsp.stream -- Real-time streaming infrastructure

Block-based processing, ring buffers, and processor chains for streaming audio.

from nanodsp.stream import (
    RingBuffer, BlockProcessor, CallbackProcessor, ProcessorChain, process_blocks
)

# Ring buffer
rb = RingBuffer(channels=2, capacity=8192)
rb.write(frame_data)
chunk = rb.read(512)

# Block processor
class MyProcessor(BlockProcessor):
    def process_block(self, block):
        return block * 0.5

proc = MyProcessor(block_size=512)
out = proc.process(buf)

# Callback processor
proc = CallbackProcessor(block_size=512, fn=lambda b: b * 0.5)

# Chain processors
chain = ProcessorChain([proc1, proc2, proc3])
out = chain.process(buf)

# Process with overlap-add
out = process_blocks(buf, block_size=2048, hop_size=512, fn=my_spectral_fn)

nanodsp._core.grainflow -- Granular synthesis (low-level)

Direct access to GrainflowLib's granular synthesis engine.

from nanodsp._core import grainflow as gf

# Create a buffer and fill with audio data
buf = gf.GfBuffer(4096, 1, 48000)
buf.set_data(audio_array)  # [channels, frames] float32

# Create a grain collection
gc = gf.GrainCollection(num_grains=8, samplerate=48000)
gc.set_buffer(buf, gf.BUF_BUFFER, 0)  # 0 = set for all grains

# Set parameters (enum-based or string reflection)
gc.param_set(0, gf.PARAM_RATE, gf.PTYPE_BASE, 1.0)
gc.param_set_str(0, "delayRandom", 10.0)

# Generate a clock and process
phasor = gf.Phasor(rate=10.0, samplerate=48000)
clock = phasor.perform(256).reshape(1, 256)
traversal = np.linspace(0, 0.5, 256, dtype=np.float32).reshape(1, 256)
fm = np.zeros((1, 256), dtype=np.float32)
am = np.zeros((1, 256), dtype=np.float32)

# Returns 8-element tuple: (output, state, progress, playhead, amp, envelope, buf_ch, stream_ch)
result = gc.process(clock, traversal, fm, am, 48000)
grain_output = result[0]  # [num_grains, block_size]

# Pan grains to stereo
panner = gf.Panner(in_channels=8, out_channels=2, pan_mode=gf.PAN_STEREO)
panner.set_pan_spread(0.5)
stereo = panner.process(grain_output, result[1], out_channels=2)  # [2, block_size]

nanodsp._core -- C++ bindings (low-level)

Direct access to the C++ extension module with 17 submodules. All high-level Python modules build on these.

Submodule Backend Contents
filters signalsmith Biquad with 16 filter designs, BiquadDesign enum
fft signalsmith FFT (complex), RealFFT (real)
delay signalsmith Delay (linear), DelayCubic (cubic interpolation)
envelopes signalsmith CubicLfo, BoxFilter, BoxStackFilter, PeakHold, PeakDecayLinear
spectral signalsmith STFT (multi-channel analysis/synthesis)
rates signalsmith Oversampler2x
mix signalsmith Hadamard, Householder, cheap_energy_crossfade
daisysp DaisySP 9 submodules, ~60 classes (oscillators, filters, effects, dynamics, drums, noise, physical modeling, control, utility)
stk STK 5 submodules, 39 classes (instruments, generators, filters, delays, effects)
madronalib madronalib FDN reverbs, resampling, generators, 18 projection functions, 6 window functions
hisstools HISSTools Convolution (mono/multi), spectral processing, 24 statistics functions, 28 window functions, partial tracking
choc CHOC FLAC read/write
grainflow GrainflowLib GfBuffer, GrainCollection, Panner, Recorder, Phasor, 37 enum constants
vafilters vafilters (Faust) 6 virtual analog filters (Moog ladder, Diode ladder, Korg35 LP/HP, Oberheim multi-mode)
bloscillators PolyBLEP et al. 5 band-limited oscillator algorithms (PolyBLEP, BLIT, DPW, MinBLEP, wavetable)
fxdsp fxdsp Antialiased clippers/wavefolder, Schroeder/Moorer reverbs, formant filter, PSOLA, MinBLEP oscillator
iirdesign DspFilters Multi-order IIR filter design (Butterworth, Chebyshev I/II, Elliptic, Bessel, orders 1-16)
from nanodsp._core import filters, fft, delay, daisysp, stk, madronalib, hisstools, grainflow, vafilters, bloscillators, fxdsp, iirdesign

# Example: direct biquad usage
bq = filters.Biquad()
bq.lowpass(0.1, 0.707)
out = bq.process(input_array)

# Example: direct FFT
f = fft.RealFFT(1024)
spectrum = f.fft(signal)

# Example: DaisySP oscillator
osc = daisysp.oscillators.Oscillator()
osc.init(44100.0)
osc.set_freq(440.0)
samples = osc.process(1024)

Full type stubs are provided in _core.pyi for IDE autocompletion and type checking.

Architecture

nanodsp/
  __init__.py          # package root (__version__ only)
  __main__.py          # CLI entry point (argparse, subcommand handlers)
  _cli.py              # function/preset registries, fx parser, type coercion
  _core.cpython-*.so   # compiled C++ extension (nanobind)
  _core.pyi            # type stubs for C++ extension
  _helpers.py          # shared private utilities
  buffer.py            # AudioBuffer class
  io.py                # audio file I/O (WAV + FLAC)
  ops.py               # delay, envelopes, FFT, convolution, rates, mix, pan, xcorr, hilbert, median, LMS
  effects.py           # filters, effects, dynamics, reverb, mastering, AGC
  spectral.py          # STFT, spectral transforms, eq_match
  synthesis.py         # oscillators, noise, drums, physical modeling
  analysis.py          # loudness, spectral features, pitch, onsets, resample, gcc_phat
  stream.py            # ring buffer, block processors, overlap-add

Performance Guidance

Computational cost tiers

Cost estimates assume a typical stereo buffer at 44.1 kHz. Actual times vary with buffer length, sample rate, and hardware.

Tier Typical latency Functions
Cheap (< 1 ms) Near-instant lowpass, highpass, bandpass, notch, peak, allpass, shelving filters, gain_db, normalize_peak, box_filter, peak_hold, peak_decay, delay, pan, mix_buffers, crossfade, hadamard, householder, fade_in, fade_out, trim_silence, dc_block
Moderate (1--10 ms) Noticeable in tight loops chorus, flanger, phaser, tremolo, autowah, compress, limit, noise_gate, saturate, overdrive, exciter, de_esser, parallel_compress, svf_*, ladder_filter, moog_ladder, iir_filter, agc, aa_hard_clip, aa_soft_clip, aa_wavefold, formant_filter
Expensive (> 10 ms) Dominates processing time stft/istft, convolve, reverb (FDN, reverb_sc), schroeder_reverb, moorer_reverb, time_stretch, pitch_shift_spectral, eq_match, spectral_denoise, spectral_freeze, psola_pitch_shift, resample, resample_fft, multiband_compress, lms_filter, master, vocal_chain

Block size recommendations

  • Offline processing: Pass the full file as a single AudioBuffer. This minimizes per-block overhead and is the simplest approach.
  • Streaming / real-time: Use BlockProcessor or process_blocks with 256--1024 samples per block. This range balances throughput against latency.
  • Throughput vs. latency: Larger blocks amortize fixed overhead (function calls, GIL acquire/release) but increase latency proportionally. At 44.1 kHz, a 512-sample block is ~11.6 ms of latency.
  • Stateful effects: Effects with internal state (IIR filters, compressors, FDN reverb, delays) must be initialized once and reused across blocks. BlockProcessor and ProcessorChain handle this automatically.

GIL release

All C++ processing functions release the Python GIL during computation. This means you can process multiple AudioBuffer objects in parallel using threading or concurrent.futures.ThreadPoolExecutor and achieve true multi-core parallelism -- no need for multiprocessing.

Benchmarking

The CLI provides a built-in benchmark command for measuring function throughput:

nanodsp benchmark lowpass:cutoff_hz=1000
nanodsp benchmark compress:ratio=4,threshold=-20 -n 100 --duration=2.0
nanodsp benchmark reverb:preset=hall --channels=2 --json

This reports iterations per second, mean time per call, and buffer throughput in seconds-of-audio per wall-second.

Demos

18 demo scripts in demos/ showcase the full API surface. Run them all at once:

make demos                              # uses demos/s01.wav
make demos DEMO_INPUT=my_audio.wav      # use a custom input file

Or run individual demos:

uv run python demos/demo_filters.py demos/s01.wav
uv run python demos/demo_reverb.py demos/s01.wav -o /tmp/reverb-output
uv run python demos/demo_distortion.py demos/s01.wav --no-normalize
uv run python demos/demo_synthesis.py                # no input file needed
uv run python demos/demo_analysis.py demos/s01.wav   # prints to stdout
Script Variants What it demonstrates
demo_filters.py 13 Lowpass, highpass, bandpass, notch, peak EQ, high/low shelf
demo_modulation.py 10 Chorus, flanger, phaser, tremolo
demo_distortion.py 14 Overdrive, wavefold, bitcrush, decimator, saturation, fold
demo_reverb.py 12 FDN presets, ReverbSc, STK freeverb/jcrev/nrev/prcrev
demo_dynamics.py 9 Compression, limiting, noise gate, parallel/multiband compression
demo_delay.py 8 Stereo delay, ping-pong, slapback, STK echo
demo_pitch.py 10 Time-domain and spectral pitch shifting
demo_spectral.py 12 Time stretch, phase lock, spectral gate, tilt EQ, freeze
demo_daisysp_filters.py 21 SVF, ladder, moog, tone, modal, comb filters
demo_composed.py 13 Autowah, SR reduce, DC block, exciter, de-esser, vocal chain, mastering, STK chorus
demo_spectral_extra.py 8 Spectral denoise, EQ match, spectral morph
demo_ops.py 29 Delay, vibrato, convolution, envelopes, fades, panning, stereo widening, crossfade
demo_resample.py 6 Madronalib and FFT resampling at 22k/48k/96k
demo_synthesis.py 44 Oscillators, FM, noise, drums, physical modeling, STK instruments (no input file)
demo_analysis.py -- Loudness, spectral features, pitch, onsets, chromagram (stdout only)
demo_grainflow.py 7 Granular clouds (basic, dense), pitch shift, sparse stochastic, stereo panning, recorder
demo_fxdsp.py 28 Antialiased waveshaping, Schroeder/Moorer reverbs, formant filter, PSOLA pitch shift, MinBLEP oscillators
demo_iir_filters.py 23 Butterworth, Chebyshev I/II, Elliptic, Bessel filters at various orders

File-processing scripts share the same interface:

usage: demo_*.py [-h] [-o OUT_DIR] [-n] infile

positional arguments:
  infile                Input .wav file

options:
  -o, --out-dir DIR     Output directory (default: build/demo-output)
  -n, --no-normalize    Skip peak normalization (may clip on PCM output)

demo_synthesis.py generates sounds from scratch (no input file; takes -o and -n only). demo_analysis.py prints measurements to stdout (no audio output). demo_grainflow.py processes an input file through granular synthesis.

Development

make build    # rebuild extension after C++ changes
make test     # run 1431 tests
make demos    # run all 18 demo scripts
make qa       # test + lint + typecheck + format
make coverage # tests with coverage report

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nanodsp-0.1.4.tar.gz (36.1 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

nanodsp-0.1.4-cp314-cp314-win_amd64.whl (746.8 kB view details)

Uploaded CPython 3.14Windows x86-64

nanodsp-0.1.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (829.0 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

nanodsp-0.1.4-cp314-cp314-macosx_11_0_arm64.whl (701.1 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

nanodsp-0.1.4-cp314-cp314-macosx_10_15_x86_64.whl (767.5 kB view details)

Uploaded CPython 3.14macOS 10.15+ x86-64

nanodsp-0.1.4-cp313-cp313-win_amd64.whl (724.8 kB view details)

Uploaded CPython 3.13Windows x86-64

nanodsp-0.1.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (828.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

nanodsp-0.1.4-cp313-cp313-macosx_11_0_arm64.whl (700.9 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

nanodsp-0.1.4-cp313-cp313-macosx_10_15_x86_64.whl (767.5 kB view details)

Uploaded CPython 3.13macOS 10.15+ x86-64

nanodsp-0.1.4-cp312-cp312-win_amd64.whl (724.9 kB view details)

Uploaded CPython 3.12Windows x86-64

nanodsp-0.1.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (828.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

nanodsp-0.1.4-cp312-cp312-macosx_11_0_arm64.whl (701.0 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

nanodsp-0.1.4-cp312-cp312-macosx_10_15_x86_64.whl (767.6 kB view details)

Uploaded CPython 3.12macOS 10.15+ x86-64

nanodsp-0.1.4-cp311-cp311-win_amd64.whl (724.7 kB view details)

Uploaded CPython 3.11Windows x86-64

nanodsp-0.1.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (829.3 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

nanodsp-0.1.4-cp311-cp311-macosx_11_0_arm64.whl (701.5 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

nanodsp-0.1.4-cp311-cp311-macosx_10_15_x86_64.whl (763.0 kB view details)

Uploaded CPython 3.11macOS 10.15+ x86-64

nanodsp-0.1.4-cp310-cp310-win_amd64.whl (724.6 kB view details)

Uploaded CPython 3.10Windows x86-64

nanodsp-0.1.4-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (828.8 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

nanodsp-0.1.4-cp310-cp310-macosx_11_0_arm64.whl (701.2 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

nanodsp-0.1.4-cp310-cp310-macosx_10_15_x86_64.whl (762.6 kB view details)

Uploaded CPython 3.10macOS 10.15+ x86-64

File details

Details for the file nanodsp-0.1.4.tar.gz.

File metadata

  • Download URL: nanodsp-0.1.4.tar.gz
  • Upload date:
  • Size: 36.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nanodsp-0.1.4.tar.gz
Algorithm Hash digest
SHA256 c11ff83991381c9d1684a0e055b9149adb43ea8c206b2ef80b2b1d9844ad9488
MD5 7a960840756457c770202ca10eb02b98
BLAKE2b-256 2f7f0bd7b663c1b104915184767ad703876f379209d8e877bce62e8ae4ccd2bd

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: nanodsp-0.1.4-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 746.8 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nanodsp-0.1.4-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 e9ac82a1d164fea3ef6d8ea469f7783f9341ae05a4a3b1d0ca0411751b210cbd
MD5 20618143867d3000d433bbf9522c6c92
BLAKE2b-256 f273a7538369444045750c2713d46258dc3c3b24b34a9b51e52ddb15e0d36dc0

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e1b3a4edbe3512c185e5f03cc71d4c5a7c442ba85df981222e6be6496a614361
MD5 4de93997db659f067b85f214fa76ec35
BLAKE2b-256 7d9ebd387ebbf0c0ad808e428c63a359ca9b57ca976ae13bc02758272af65774

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c4e9f76282971972e644225317ad440651ee858831357a0eb13040bfbde6009b
MD5 e572f42f2d618025b9ae0819506d841d
BLAKE2b-256 25b81c8f64c5a9db336b890640bc4274257a64e7d16a41503f5c99408f59b5e7

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp314-cp314-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp314-cp314-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 fc5c4a5577f471a4251d0307c82a044a1bb855fa6556b33b71c8148baa4a72fd
MD5 b76b4ed4fb0ec23b6200a21daad0bf0a
BLAKE2b-256 99f5680fdf156d76f595c442818d540cf770496f1447ff289236f332eaa8db83

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: nanodsp-0.1.4-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 724.8 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nanodsp-0.1.4-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 77d990d1982728d08aff478d4877c412f667bd402d0573028d7c58233d59d675
MD5 f2181e8dfdf87650ee64f7fb9b90a53b
BLAKE2b-256 dd2c5ec03211987facfe53f22286a2b451d3408a489f0ad71702108b5b6e4cb9

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d6019d7857e9e2da7b5e03d2a59019d2bbb9d814d7a60501e29983d16d36e7d5
MD5 ab8271b7e26d05ac5e97581fc56bca6e
BLAKE2b-256 5b1630c37ac6954138fead478b458af861a681e941d42b2e8c6d3a785d5184be

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8894e40845db4d0d81bacbdc2c66e635486999c37a5a71c4fee65c4bf84e8bb4
MD5 432b44d9ad208af6107f5d73685dcf96
BLAKE2b-256 c7f76d8bf218e1e4f0400ea356acf9606f200b79ad8dff7c3ff845bf32dc8d4a

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp313-cp313-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp313-cp313-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 534e4d6ca058155e2e22fd54b946e6f2b9c9f8bdef7377f5c70397aa52902cc4
MD5 1e925ac03711dab003752d14a489ffa6
BLAKE2b-256 a52eefbcb2fcebfcc15d77e7e4963dfc0d822a8894d7e238c3c63f451161da68

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: nanodsp-0.1.4-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 724.9 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nanodsp-0.1.4-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 9b7e2fd4ff8044cc63ef5002518af8f8b94e128ac8a68564838bf921ea70e52e
MD5 fd28821358b4be4977bad9651c53cacb
BLAKE2b-256 1872a3ecdb4f07b344124a40df5e53be9738e69e3da206135a12ca80d5dc0a7c

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 969a6356611ccac9a6c34fdab46f7bce31b54bc6fcefe60c74f41dc99a182df7
MD5 96c464f3b68d50621a9ff62402f83262
BLAKE2b-256 d0bfecfcaa1b18cda4fa25408b96f737da89a6d706fc04d689e6ce3d8479eef7

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 52cf5514d660bafe9721b0a2ca36e64ce1c2ebaa2630dff8e458c727b9cd4f2a
MD5 7b775fe6c3e44b236597f32845a99b53
BLAKE2b-256 ffab53d0c3001d93d699ebf2f06bff1adc8a83f19cd5f4b982aea68fa812bb35

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp312-cp312-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp312-cp312-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 9ef7091499ed19dd6ca465bf9b3abef4ee8f28927f1340b647d20d8c59af2ab9
MD5 18331512c32ec1487dac067675f99a0d
BLAKE2b-256 80f5490a65319966e5974afbea154fe2c3a11e3298a98eae5215fcd828cbf705

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: nanodsp-0.1.4-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 724.7 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nanodsp-0.1.4-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 5a000bb27cb00002e545bc203f5643e7d4d4ca65057b5ebaad0d91ee44fdffff
MD5 fe2b43b4199afeeb919465dee906bc9f
BLAKE2b-256 154d1e63a4781ecbc965d3b95a22680762f4864ec07df16360ddeaba54929276

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d7a677e5f80084b43567ed021a2e5e534666517f7eec0b0549675ac1d32ea89b
MD5 cc304d78fe9bf3617c6e2c6a0c26cb1a
BLAKE2b-256 568fbb615797f95a0e8107c3fe04a0b543b4218c9693b821354e361efdfd7993

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 287f99db76244bb62d74e1bcf6c456c81cb45a5e0e7897f3b34457ccfef4bb43
MD5 6a99ca39cc989aaee464163b54f8f5aa
BLAKE2b-256 a00e61fe7c8df3f6f0dbebb00b805cc76860104ba9454c2f46e9b31423dd76b1

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp311-cp311-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp311-cp311-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 a7669e4b08eaf0b0928080a067536c7e14816509b50b79476fb259020f88ccbc
MD5 0d714ee3d7b13cdc359744f2ab9f1671
BLAKE2b-256 3c84b716dda0028e1cc38cd12b0f0068bfe484ade61733341041e656be72a44c

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: nanodsp-0.1.4-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 724.6 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nanodsp-0.1.4-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 4b59523402f176929909ed96fef0028d142337bd75645eabd903f05e7d02e25d
MD5 a5d7f24b805cdcd5d1c0d9492d5deb94
BLAKE2b-256 08a4b05d8e433be0f4d2440e963f0b0773f3cd5ff0df374a97daaeb925a89c72

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 462cbc11fcee0514887f74539ff3dbbf0b04dc7dd6aca60e03b206409105ee0b
MD5 18bd71713c0014d0b8d4977d4ef037c9
BLAKE2b-256 7e843626bfc3c467cc37437f8bb273562d02f3abee788e706c21d6239ceea716

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3e645785cad39dee096b8c1c311e488398ca5d6c786ccbf06648565162b11c81
MD5 a2e895c90a81d2955c6896b08a6a120e
BLAKE2b-256 f50babc6227863d3738ec19da58d3aa8eb47841f61b5d9c04aca1ee493bf8d72

See more details on using hashes here.

File details

Details for the file nanodsp-0.1.4-cp310-cp310-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nanodsp-0.1.4-cp310-cp310-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 f2f3064adb07a9fafa35a32d7510dc6255ef41e9b8ff05d05bc0ae46653f9905
MD5 8a82680828b2cd41e2fe27aa15eadb84
BLAKE2b-256 37bb6d5c45b05ceb5fa6e87f92bd69d3a48cca16e98ea19417f3b84ad6d11973

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page