Zero-dependency STFT/iSTFT for iOS & macOS in pure Swift.
Tired of wrapping
vDSPmanually every time you need spectrogram analysis? STFTKit gives you a clean Swift API for Short-Time Fourier Transform — nothing more, nothing less.
import STFTKit
let stft = STFT()
let spectrogram = stft.forward(audioSignal)
let reconstructed = stft.inverse(spectrogram) // Nearly identical to original!- ✅ Zero external dependencies — Only Swift + Apple Accelerate
- ✅ Perfect reconstruction — Overlap-add with window normalization
- ✅ Real-time ready — Single-frame FFT for streaming
- ✅ Pure Swift — No bridging, no C code
- ✅ Batteries included — Hann & Hamming windows, magnitude/phase extraction
If you've ever needed spectrogram analysis on iOS, you've probably run into one of these:
| Approach | Problem |
|---|---|
| AudioKit | Powerful, but massive surface area. You need to understand node graphs just to run an FFT. |
| vDSP directly | 50+ lines of boilerplate: split complex arrays, setup initialization, bin packing... every single time. |
| Third-party wrappers | Often incomplete — forward FFT only, no inverse transform, or no perfect reconstruction. |
STFTKit is different. It's a single-purpose library that does one thing: STFT, done right.
| Feature | STFTKit | AudioKit | AuraSignal | TempiFFT |
|---|---|---|---|---|
| Scope | STFT only | Full audio platform | DSP toolkit | Real-time spectrum |
| STFT + iSTFT | ✅ Perfect | ✅ | ❌ Forward only | |
| Dependencies | Zero | Heavy | Swift Numerics | Zero |
| Inverse transform | ✅ | ✅ | ❌ | |
| Center padding | ✅ | ❌ | ❌ | ❌ |
| Documentation | EN + CN | EN only | EN only | EN only |
| API complexity | Low | High | Medium | Medium |
// In Package.swift
dependencies: [
.package(url: "https://github.com/hohband/STFTKit.git", from: "1.0.0")
]// In your target
.target(name: "YourApp", dependencies: ["STFTKit"])File → Add Package Dependencies → https://github.com/hohband/STFTKit.git
import STFTKit
// Create with default config (fftSize=2048, hopSize=1024, Hann window)
let stft = STFT()
// Forward transform: signal → spectrogram
let spectrogram = stft.forward(audioSamples)
// Inverse transform: spectrogram → signal (nearly perfect reconstruction)
let reconstructed = stft.inverse(spectrogram)let config = STFTConfiguration(
fftSize: 4096, // FFT window size (power of 2)
hopSize: 1024, // Frame step
window: .hann(periodic: true), // Hann or .hamming
centerPadding: true // Zero-pad signal for edge-aligned analysis
)
let stft = STFT(configuration: config)let config = STFTConfiguration(
fftSize: 2048,
hopSize: 512, // 75% overlap → perfect reconstruction
window: .hann(periodic: true),
centerPadding: true
)public func forward(_ signal: [Float]) -> SpectrogramTransforms an entire audio signal into a spectrogram (time-frequency representation).
public func inverse(_ spectrogram: Spectrogram) -> [Float]Reconstructs a time-domain signal from a spectrogram using overlap-add with window normalization.
Note: With 75% overlap (hopSize = fftSize/4) and Hann window, reconstruction error is below
1e-5.
public func magnitudes(from spectrogram: Spectrogram) -> [Float]Extracts magnitude values from a spectrogram for visualization or further processing.
public func spectrogram(fromMagnitudes: [Float], phases: [Float], frameCount: Int) -> SpectrogramReconstructs a spectrogram from magnitude and phase arrays — useful for spectral editing, noise reduction, and more.
For real-time or streaming scenarios:
// Process one frame at a time (e.g., from audio buffer callback)
let spectrum: ComplexSpectrum = stft.processFrame(audioFrame)
// Reconstruct a single frame
let samples: [Float] = stft.reconstructFrame(spectrum)// Convert packed FFT → full spectrum (DC to Nyquist)
let fullBins: [ComplexBin] = stft.packedToFull(spectrum)
// Convert full spectrum → packed format for inverse FFT
let packed: ComplexSpectrum = stft.fullToPacked(fullBins)| Parameter | Default | Description |
|---|---|---|
fftSize |
2048 | FFT window size (must be power of 2) |
hopSize |
1024 | Step between frames (samples) |
window |
.hann(periodic: true) |
Window function |
centerPadding |
true |
Zero-pad signal center-aligned |
config.frequencyBins // fftSize / 2 + 1 (DC to Nyquist)
config.packedBins // fftSize / 2 (Accelerate packed format)STFTKit is ideal for:
- 🎤 Noise reduction — Analyze frequency content, apply spectral subtraction
- 📊 Spectrogram visualization — Display audio as a time-frequency heatmap
- 🎵 Audio effects — Time-stretching, pitch-shifting (via magnitude manipulation)
- 🔊 Sound analysis — Pitch detection, onset detection, instrument recognition
- 🎙 Voice processing — Voice activity detection, acoustic feature extraction
- 📱 Music apps — Tuners, audio editors, podcast tools
Container for the complex frequency-domain representation of multiple time frames.
public struct Spectrogram {
public var frames: [[ComplexBin]] // [frame][frequency_bin]
public var frameCount: Int { frames.count }
public var frequencyBins: Int { frames.first?.count ?? 0 }
// 2D subscript access
public subscript(frame: Int, bin: Int) -> ComplexBin
}Packed complex array for Accelerate FFT operations.
public struct ComplexSpectrum {
public var real: [Float] // Real parts
public var imag: [Float] // Imaginary parts
public var binCount: Int { real.count }
}Convenience type alias for a single frequency bin:
public typealias ComplexBin = (real: Float, imag: Float)public enum WindowFunction: Sendable {
case hann(periodic: Bool = true)
case hamming(periodic: Bool = true)
}| Requirement | Version |
|---|---|
| Swift | 5.9+ |
| iOS | 16.0+ |
| macOS | 13.0+ |
| Framework | Apple Accelerate |
STFTKit includes comprehensive test coverage:
# Run all tests
swift test --enable-test-discovery
# Run specific test suite
swift test --filter STFTTestsTests cover:
- ✅ Perfect reconstruction accuracy (NRMSE < 1e-4)
- ✅ Various FFT sizes (512, 1024, 2048, 4096)
- ✅ Different overlap ratios (50%, 75%, 87.5%)
- ✅ All window functions (Hann, Hamming, periodic, symmetric)
- ✅ Magnitude/phase extraction and reconstruction
- ✅ Edge cases (empty signal, short signal)
- ✅ Performance benchmarks
See the Examples/ directory for:
- macOS CLI Demo — Run FFT analysis from command line
- iOS Visualization — Real-time spectrogram display (coming soon)
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License — see LICENSE for details.
Built with Apple's Accelerate framework for hardware-optimized FFT operations.