Sonus
Sonus is a Ruby audio feature extraction library for in-memory signals and WAV files. It exposes a small public API around feature extraction, frame-based analysis, and WAV decoding.
Sonus always works with the built-in Ruby FFT backend, and automatically uses FFTW through fftw3-ruby when the system FFTW library is available.
Highlights
- Ruby
>= 3.1 - Single-frame extraction with
Sonus.extract - Cached extraction with
Sonus.extract_with_cache - Frame-by-frame WAV analysis with
Sonus::Analyzer - WAV decoding and inspection with
Sonus::WAV::Reader - Pure Ruby FFT fallback with optional FFTW acceleration
Installation
Install the gem:
gem install sonusOr add it to your Gemfile:
gem "sonus"Optional FFTW acceleration
fftw3-ruby is installed as a Sonus dependency.
To enable the FFTW backend, install the native FFTW shared library on your system:
# macOS
brew install fftw
# Debian / Ubuntu
sudo apt-get install libfftw3-devYou can inspect or force the backend at runtime:
require "sonus"
Sonus::DSP::FFT.backend
# => :ruby or :fftw
Sonus::DSP::FFT.backend = :ruby
Sonus::DSP::FFT.backend = :fftwSetting :fftw raises Sonus::FFTBackendError when FFTW is unavailable.
Quick Start
Runnable scripts are available in examples/:
examples/extract_basic.rbexamples/extract_spectral_flux.rbexamples/analyze_wav.rbexamples/read_wav.rb
Single-frame extraction
require "sonus"
sample_rate = 44_100
buffer_size = 512
signal = Array.new(buffer_size) do |index|
Math.sin((2.0 * Math::PI * 440.0 * index) / sample_rate)
end
features = Sonus.extract(
signal,
%i[rms spectral_centroid mfcc],
buffer_size: buffer_size,
sample_rate: sample_rate
)
puts features[:rms]
puts features[:spectral_centroid]
puts features[:mfcc].lengthFrame-based WAV analysis
require "sonus"
analyzer = Sonus::Analyzer.new(
buffer_size: 1024,
hop_size: 512,
sample_rate: 44_100,
features: %i[rms spectral_flux mfcc]
)
results = analyzer.analyze_file("audio.wav")
puts results.first[:rms]
analyzer.each_frame("audio.wav").first(3).each do |frame|
puts frame[:spectral_flux]
endWAV reading
require "sonus"
reader = Sonus::WAV::Reader.new("audio.wav")
puts reader.sample_rate
puts reader.channels
puts reader.bit_depth
puts reader.duration
samples = reader.frames
reader.closePublic API
Sonus.extract
Use Sonus.extract(signal, features, **options) for one analysis frame.
It returns a hash containing only the requested public features.
Important behavior:
-
signalmust be anArrayor respond to#to_a - signal values must be finite numeric values
- shorter input is zero-padded to
buffer_size - longer input is truncated to the first
buffer_sizesamples - feature dependencies are resolved automatically
-
featurescan be a symbol, string, or array of them
For previous-frame features such as :spectral_flux, pass either previous_signal or prev_amplitude_spectrum:
previous = Array.new(512, 0.0)
current = Array.new(512) { |i| Math.sin((2.0 * Math::PI * 440.0 * i) / 44_100.0) }
result = Sonus.extract(
current,
:spectral_flux,
buffer_size: 512,
sample_rate: 44_100,
previous_signal: previous
)
puts result[:spectral_flux]Sonus.extract_with_cache
Use Sonus.extract_with_cache when you need both the requested result and intermediate feature values.
It returns [result, cache], where result includes only requested public features and cache includes dependency outputs as well.
This is the API used internally by Sonus::Analyzer.
Sonus::Analyzer
Use Sonus::Analyzer for repeated frame analysis with stable configuration.
analyzer = Sonus::Analyzer.new(
buffer_size: 1024,
hop_size: 512,
sample_rate: 44_100,
features: %i[rms spectral_centroid]
)
analyzer.analyze(Array.new(1024, 1.0))
analyzer.analyze_file("audio.wav")
analyzer.each_frame("audio.wav")Important behavior:
-
features:defaults to[:rms] -
hop_sizedefaults tobuffer_size - overlapping analysis is supported with
hop_size < buffer_size -
each_frame(path)returns an enumerator when no block is given -
sample_ratemust match the WAV file sample rate foranalyze_fileandeach_frame - previous-frame state is reset at the start of each
each_framerun
Sonus::WAV::Reader
Sonus::WAV::Reader accepts a filesystem path or an IO object that responds to #read and #seek.
Supported WAV input:
- PCM: 8-bit, 16-bit, 24-bit, 32-bit
- IEEE float: 32-bit, 64-bit
- mono and multi-channel files
Important behavior:
-
framesreturns normalized floats - for multi-channel files, Sonus decodes the first channel of each frame
-
each_buffer(size)returns an enumerator when no block is given -
each_buffer(size)zero-pads the final buffer
Features
Inspect the public feature set at runtime:
Sonus.available_features
Sonus.list_available_feature_extractorsCurrent public features:
Time-domain and raw outputs
:buffer:rms:zcr:energy:complex_spectrum:amplitude_spectrum:power_spectrum
Spectral features
:spectral_centroid:spectral_flatness:spectral_flux:spectral_slope:spectral_rolloff:spectral_spread:spectral_skewness:spectral_kurtosis:spectral_crest:chroma:mel_bands:mfcc
Perceptual features
:loudness:perceptual_spread:perceptual_sharpness
Configuration
Default values:
buffer_size = 512sample_rate = 44_100windowing_function = :hanningnumber_of_mfcc_coefficients = 13number_of_mel_filters = 26number_of_chroma_bands = 12number_of_bark_bands = 24
Supported windowing functions:
:rect:hann:hanning:hamming:blackman:sine
Supported aliases:
-
mel_bands:fornumber_of_mel_filters: -
chroma_bands:fornumber_of_chroma_bands:
Errors
Sonus raises domain-specific errors for common failure cases:
Sonus::InvalidSignalErrorSonus::InvalidFeatureErrorSonus::WAVFormatErrorSonus::FFTBackendError
Development
Install dependencies:
bundle installRun tests:
bundle exec rspec
bundle exec rakeRun the benchmark:
bundle exec ruby benchmark/extract_all_features.rbContributing
Pull requests and issue reports are welcome.
License
MIT License.