Project

sonus

0.0
No release in over 3 years
Sonus extracts time-domain, spectral, and perceptual audio features in pure Ruby with optional FFTW acceleration.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 13.0
~> 3.0
~> 0.9

Runtime

~> 0.1.0
 Project Readme

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 sonus

Or 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-dev

You 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 = :fftw

Setting :fftw raises Sonus::FFTBackendError when FFTW is unavailable.

Quick Start

Runnable scripts are available in examples/:

  • examples/extract_basic.rb
  • examples/extract_spectral_flux.rb
  • examples/analyze_wav.rb
  • examples/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].length

Frame-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]
end

WAV 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.close

Public 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:

  • signal must be an Array or 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_size samples
  • feature dependencies are resolved automatically
  • features can 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_size defaults to buffer_size
  • overlapping analysis is supported with hop_size < buffer_size
  • each_frame(path) returns an enumerator when no block is given
  • sample_rate must match the WAV file sample rate for analyze_file and each_frame
  • previous-frame state is reset at the start of each each_frame run

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:

  • frames returns 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_extractors

Current 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 = 512
  • sample_rate = 44_100
  • windowing_function = :hanning
  • number_of_mfcc_coefficients = 13
  • number_of_mel_filters = 26
  • number_of_chroma_bands = 12
  • number_of_bark_bands = 24

Supported windowing functions:

  • :rect
  • :hann
  • :hanning
  • :hamming
  • :blackman
  • :sine

Supported aliases:

  • mel_bands: for number_of_mel_filters:
  • chroma_bands: for number_of_chroma_bands:

Errors

Sonus raises domain-specific errors for common failure cases:

  • Sonus::InvalidSignalError
  • Sonus::InvalidFeatureError
  • Sonus::WAVFormatError
  • Sonus::FFTBackendError

Development

Install dependencies:

bundle install

Run tests:

bundle exec rspec
bundle exec rake

Run the benchmark:

bundle exec ruby benchmark/extract_all_features.rb

Contributing

Pull requests and issue reports are welcome.

License

MIT License.