Skip to content

ydah/wavify

Repository files navigation

Wavify Gem Version Ruby

Wavify is a Ruby audio processing toolkit with immutable transforms, codec I/O, streaming pipelines, DSP effects, and a sequencing DSL.

Use it to:

  • Read, inspect, transform, and write audio from Ruby scripts.
  • Process large files with streaming pipelines and stateful DSP effects.
  • Generate tones, small arrangements, and test fixtures without mandatory FFmpeg or SoX.

Requirements

  • Ruby >= 3.1
  • Bundler
  • Optional native build environment for OGG Vorbis gems (ogg-ruby, vorbis)

Installation

Add to your Gemfile:

gem "wavify"

Then install:

bundle install

Or install directly:

gem install wavify

WAV, AIFF, FLAC, and raw PCM work without OGG dependencies. Add ogg-ruby and vorbis to your Gemfile only when you need .ogg / .oga support.

Quick Start

require "wavify"

format = Wavify::Core::Format::CD_QUALITY

audio = Wavify::Audio.tone(
  frequency: 440.0,
  duration: 1.0,
  waveform: :sine,
  format: format
)

audio.fade_in(0.02, curve: :exp).fade_out(0.05, curve: :log).bit_depth(16, dither: true).write("tone.wav")

Codec-specific write options are forwarded with codec_options::

audio.write("master.flac", codec_options: { block_size: 2048 })
audio.write("preview.ogg", codec_options: { quality: 0.5 })
audio.write("tagged.wav", codec_options: { info: { title: "Tone", artist: "Wavify" } })
audio.write("master.wav", overwrite: false)

Core API

Wavify::Audio

Main constructors:

  • Audio.read(path_or_io, format: nil, codec_options: {}, strict: false, filename: nil)
  • Audio.metadata(path_or_io, format: nil, codec_options: {}, strict: false, filename: nil)
  • Audio.info(path_or_io, format: nil, codec_options: {}, strict: false, filename: nil)
  • Audio.stream(path_or_io, chunk_size: 4096, format: nil, codec_options: {}, strict: false, filename: nil)
  • Audio.tone(frequency:, duration:, waveform:, format:)
  • Audio.silence(duration_seconds, format:)
  • Audio.mix(*audios, strategy: :clip, gains: nil, align: :start)

Immutable transforms (each also has ! in-place variants):

  • gain, normalize, trim, fade_in, fade_out, pan, reverse, loop, apply
  • concat, append, prepend, overlay, crossfade, slice, crop, pad_start, pad_end, insert_silence
  • to_mono, to_stereo, resample, bit_depth, map_samples, map_frames

Utility methods:

  • convert, split(at:), duration, sample_frame_count, channels, sample_rate, frames, each_frame
  • peak_amplitude, rms_amplitude, peak_dbfs, rms_dbfs, lufs, stats, silent?, clipped?, dc_offset, zero_crossing_rate

Mix strategies are :clip (default), :normalize, :headroom, and :soft_limit. gains: accepts one dB value per source, and align: can be :start, :center, or :end. Normalize modes are :peak, :rms, and :lufs. Use bit_depth(16, dither: true) when reducing PCM bit depth and you want simple TPDF dither.

Duration helpers:

Wavify.ms(250)
Wavify.seconds(3)
Wavify::Core::Duration.parse("1:23.456")

Streaming pipeline

Wavify::Audio.stream("input.wav", chunk_size: 4096)
             .pipe(Wavify::Effects::Compressor.new(threshold: -18, ratio: 3.0), name: :comp)
             .map_chunks(name: :trim_preview) { |chunk| Wavify::Audio.new(chunk).trim(threshold: 0.005).buffer }
             .meter { |stats| puts stats[:peak_dbfs] }
             .tee("preview.wav")
             .write_to("output.aiff", format: Wavify::Core::Format::CD_QUALITY)

pipe accepts processors that respond to call, process, or apply. Stateful processors may implement reset, flush(format:), and tail_duration. Use take_duration, drop_duration, to_audio, progress, meter, tee, and pipeline_steps for common chunk workflows and inspection. Use dry_run(format:) to validate a stream pipeline without writing output.

write_to also accepts codec-specific output options:

stream.write_to("output.flac", codec_options: { block_size_strategy: :fixed, block_size: 2048 })

Format Support

Format Read Write Stream Read Stream Write Notes
WAV PCM + float WAV, extensible WAV, BWF metadata, RF64 read metadata
AIFF PCM AIFF plus uncompressed AIFF-C NONE / sowt
FLAC Pure Ruby implementation with comments, mid-side, and LPC write options
OGG Vorbis Optional ogg-ruby + vorbis gems
Raw PCM/Float ✅* ✅* format: is required for read/stream-read/metadata

Raw example:

raw_format = Wavify::Core::Format.new(channels: 2, sample_rate: 44_100, bit_depth: 16, sample_format: :pcm)
audio = Wavify::Audio.read("input.pcm", format: raw_format)
audio.write("output.wav")

For IO objects without magic bytes, pass filename: as a codec hint:

io = StringIO.new(raw_bytes)
audio = Wavify::Audio.read(io, filename: "input.raw", format: raw_format)

Metadata example:

metadata = Wavify::Audio.metadata("input.wav")
metadata[:format].sample_rate
metadata[:duration]

Codec registry helpers:

Wavify::Codecs.supported_formats
Wavify::Codecs.available_formats
Wavify::Codecs.detect("input.wav")
Wavify::Codecs.register(".custom", MyCodec)
Wavify::Adapters.known

OGG Vorbis notes

  • read / stream_read support sequential chained streams and interleaved multi-stream OGG.
  • Interleaved multi-stream decode is mixed into one output stream.
  • If interleaved streams have different sample rates, they are resampled to the first logical stream's sample rate before mix.
  • decode_mode: :strict and decode_mode: :placeholder are accepted for API compatibility.
  • OGG support is optional; wavify doctor reports whether the native gems are installed.
  • MP3, AAC, FFmpeg, MIDI, and spectrogram support are adapter-gem boundaries; use Wavify::Adapters.load(:ffmpeg) after installing a matching adapter gem.

Sequencer DSL

Use Wavify.build for one-shot rendering/writing, or Wavify::DSL.build_definition when you want timeline access.

song = Wavify::DSL.build_definition(format: Wavify::Core::Format::CD_QUALITY, tempo: 116, swing: 0.55, default_bars: 2) do
  sample_folder "samples"
  key :c, :minor

  track :kick do
    synth :sine
    notes "C2/8. . C2/8t .", resolution: 16
    envelope attack: 0.001, decay: 0.05, sustain: 0.0, release: 0.06
    gain(-4)
  end

  track :pad do
    chords ["Cmaj7/E@drop2"], voicing: :open
  end

  arrange do
    section :intro, bars: 1, tracks: %i[kick], markers: [:start]
    section :bridge, bars: 1, tracks: %i[kick pad], tempo: 92, beats_per_bar: 3, markers: [:bridge]
  end
end

timeline = song.timeline
song.timeline_json
song.timeline_text
stems = song.render(stems: true)
mix = song.render
mix.write("song.wav")

Pattern steps support rests (-/.), normal triggers (x, velocity 0.8), accents (X, velocity 1.0), explicit velocity suffixes (x0.5), probability metadata (x?50), and ratchets (x:3). Note tokens support fixed durations (C4/8), dotted values (C4/8.), triplets (C4/8t), and ties (D4~ D4). Use key :c, :minor for simple scale quantization, slash chords for inversions, and @drop2 / @open or voicing: for chord voicings. Arrangement sections can carry tempo:, beats_per_bar:, and markers:. Swing values start at 0.5 for straight timing; values such as 0.55 delay off-beat steps on even grids. Sample tracks can use sample_folder, per-sample pitch: semitones, preset :lofi_drums, and Wavify::DSL.validate for pre-render checks.

DSP

Built-in modules:

  • Oscillator waveforms: :sine, :square, :sawtooth, :triangle, :pulse, :white_noise, :pink_noise
  • Envelope (AHDSR with optional segment curves)
  • Automation and LFO modulation helpers
  • Biquad filters (lowpass/highpass/bandpass/notch/peaking/shelves)
  • Effects: Delay, Reverb, Chorus, Vibrato, Flanger, Phaser, Distortion, Compressor, Limiter, SoftLimiter, NoiseGate, Expander, Tremolo, AutoPan, StereoWidener, Bitcrusher, EQ
  • Preset chains: MasteringChain, PodcastChain

Register custom processors for pipelines and DSL tracks:

Wavify::Effects.register(:my_effect, MyEffect)
Wavify::DSL.effect(:my_effect, MyEffect)

Envelope supports hold: and curve: :linear | :exp | :log. Reverb supports pre_delay: for delaying only the wet path and width: for stereo wet width.

Examples

Scripts in examples/:

  • examples/format_convert.rb
  • examples/audio_processing.rb
  • examples/synth_pad.rb
  • examples/drum_machine.rb
  • examples/chill_vibes.rb
  • examples/hybrid_arrangement.rb
  • examples/streaming_master_chain.rb
  • examples/cinematic_transition.rb

Run:

ruby examples/synth_pad.rb

See examples/README.md for the full list.

CLI

The gem includes a small CLI for common scripting tasks:

wavify info input.wav
wavify convert input.wav output.flac
wavify tone --freq 440 --duration 1 tone.wav
wavify normalize input.wav output.wav --target -1
wavify trim input.wav output.wav --threshold 0.01
wavify chain input.wav output.wav --gain -3 --fade-in 0.02 --fade-out 0.05
wavify render song.rb out.wav --tempo 120 --swing 0.55 --bars 4
wavify timeline song.rb --tempo 120 --bars 4
wavify formats
wavify doctor

Documentation

  • docs/getting-started.md
  • docs/codecs.md
  • docs/dsp.md
  • docs/streaming.md
  • docs/sequencer.md
  • docs/limitations.md
  • docs/performance.md
  • ROADMAP.md
  • YARD docs can be generated with bundle exec rake docs:yard.

Limitations

  • MP3, AAC, and M4A are not built into core.
  • FFmpeg and SoX are not mandatory runtime dependencies.
  • OGG Vorbis uses optional native gems (ogg-ruby, vorbis).
  • Raw PCM/float requires format: for read, stream read, and metadata.
  • Streaming writes for header-based formats require seekable output IO.
  • Resampling defaults to linear interpolation; pass resampler: :windowed_sinc for higher-quality offline conversion.

Development

Install dependencies:

bundle install

Run tests:

bundle exec rspec
bundle exec rake spec:coverage COVERAGE_MINIMUM=90
bundle exec rake types:validate

Generate/check docs:

bundle exec rake docs:examples
bundle exec rake docs:yard
YARD_MINIMUM=85 bundle exec rake docs:check
bundle exec rake docs:all

docs:examples smoke-runs the self-contained example scripts. docs:yard generates YARD output under doc/. docs:check enforces the configured YARD documentation percentage.

Benchmarks:

bundle exec rake bench:wav_io
bundle exec rake bench:dsp
bundle exec rake bench:flac
bundle exec rake bench:stream
bundle exec rake bench:all
bundle exec rake bench:baseline
bundle exec rake bench:compare

Release checks:

bundle exec rake release:check

License

Wavify is released under the MIT License.

About

A pure Ruby audio processing gem focused on ergonomic APIs and immutable audio transforms.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages