wav

Version, currently main branch1 version
  • main branchlatestMar 11, 2026

github.com/leite/wav

a tiny library for reading, writing and synthesizing WAV audio files.

3 stars
0 dependents
License: MIT

Installation

# Add this to your shard.yml
dependencies:
  wav:
    github: leite/wav
    branch: main

main is a branch, not a release, so this tracks it rather than pinning a version.

Then run:

shards install

shard.yml

Crystal
>= 1.8.0
License
MIT
Author
xico

Dependencies

This version declares no dependencies.

README

wav

wav

a tiny library for reading, writing and synthesizing WAV audio files.

installation

add this to your shard.yml

dependencies:
  wav:
    github: leite/wav
    version: ~> 0.1.0

usage

synthesis

create audio from scratch using Wav.build block.

require "wav"

wav = Wav.build(44_100.0, 2) do |w|
  w.sine 440.0, 1.0             # a4 sine, 1 sec
  w.sawtooth 110.0, 0.5         # a2 saw, .5 sec
  w.noise 0.1, 0.5              # white noise
  w.generate(1.0, 0.8) do |t|   # fm
    mod = Math.sin(2 * Math::PI * 6.0 * t) * 10.0
    Math.sin 2 * Math::PI * (440.0 + mod) * t
  end
end

stereo & cursor

position the cursor and target channels independently.

stereo = Wav.build(44_100.0, 2) do |w|
  w.left
  w.sine 440.0, 1.0              # left channel only
  w.right
  w.rewind
  w.sine 660.0, 1.0              # right channel only
  w.all
  w.forward
  w.noise 0.5, 0.3               # both channels
end

processing & dsp

chainable effects.

lead = Wav.read "lead.wav"
beat = Wav.read "drums.wav"

lead.mix(beat)
    .trim(0.0, 5.0)
    .low_pass(1_200.0)
    .delay(0.3, 0.4)
    .chorus(depth: 0.003, lfo_rate: 1.2)
    .fade(2.0, head: true, tail: true)
    .normalize(0.98)
    .to_mono

io

read/write to files, memory or any IO.

wav.write "output.wav"
loaded = Wav.read "output.wav"

mem = IO::Memory.new
wav.write mem

mem.rewind
loaded = Wav.read mem

reference

constructor

  • Wav.new(rate: 44_100.0, channels: 1, bits: 16, samples: [] of Float64, cursor: 0, target: nil) creates a new Wav instance. rate is samples per second, channels is the number of channels (1 = mono, 2 = stereo), bits is bit depth (8 or 16). The optional samples array can pre‑fill audio data (interleaved Float64 in -1.0..1.0). cursor and target are used internally for sequential generation. Raises if parameters are invalid.

I/O

  • Wav.read(path : String) : Wav reads a WAV file from the given file path. Raises if the file does not exist or is invalid.

  • Wav.read(io : IO) : Wav reads a WAV file from any IO object. The IO must be positioned at the start of a valid WAV stream. Raises on error.

  • write(path : String) : self writes the current audio data to a file at the given path as a PCM WAV file.

  • write(io : IO) : self writes the WAV data to any IO object.

generators

all generator methods append samples to the audio, respecting the current cursor position and channel target. They return self for chaining.

  • sine(frequency : Float64, duration : Float64, amplitude: 1.0) : self appends a sine wave of the given frequency (Hz) for duration seconds, scaled by amplitude.

  • square(frequency : Float64, duration : Float64, amplitude: 1.0) : self appends a square wave.

  • sawtooth(frequency : Float64, duration : Float64, amplitude: 1.0) : self appends a sawtooth wave (rising ramp).

  • saw(frequency : Float64, duration : Float64, amplitude: 1.0) : self alias for sawtooth.

  • triangle(frequency : Float64, duration : Float64, amplitude: 1.0) : self appends a triangle wave.

  • noise(duration : Float64, amplitude: 1.0) : self appends white noise (uniform distribution -1..1).

  • silence(duration : Float64) : self appends silent samples (all zero) for the given duration.

  • generate(duration : Float64, amplitude: 1.0, &block : Float64 -> Float64) : self appends custom samples generated by the block. The block receives the current time in seconds (starting from the beginning of the generated segment) and should return a sample value between -1.0 and 1.0. The block is called for each sample frame.

effects

all effects modify the existing samples in place and return self.

  • mix(other : Wav) : self mixes the samples of another Wav instance into the current one (additive). The two must have identical sample rates and channel counts. Mixing stops at the shorter length.

  • delay(time : Float64, feedback: 0.4) : self adds an echo/delay effect. time is delay in seconds, feedback controls the decay of repeats (0..1).

  • low_pass(cutoff : Float64) : self applies a simple first‑order low‑pass filter with the given cutoff frequency (Hz).

  • chorus(depth: 0.002, lfo_rate: 1.5, mix: 0.5) : self applies a chorus effect. depth is modulation depth in seconds, lfo_rate is modulation rate in Hz, mix is the wet/dry balance (0 = dry only, 1 = wet only).

  • normalize(target: 0.95) : self scales the entire audio so that the peak absolute amplitude becomes target (must be between 0 and 1). Does nothing if all samples are zero.

  • fade(duration : Float64, head: false, tail: false) : self applies a linear fade. If both head and tail are false, fades in from the start. If head is true, fades in from the start. If tail is true, fades out at the end. Both can be combined.

  • fade_in(duration : Float64) : self shorthand for fade(duration, head: true).

  • fade_out(duration : Float64) : self shorthand for fade(duration, tail: true).

transforms

  • resample(new_rate : Float64) : Wav resamples the audio to a new sample rate using linear interpolation. Returns a new Wav instance with the new rate.

  • trim(start : Float64, finish : Float64) : self keeps only the portion between start and finish seconds (inclusive). Cuts samples outside that range.

  • to_mono : Wav converts multi‑channel audio to mono by averaging channels. Returns a new Wav instance with one channel.

cursor & channels

these methods control where generated samples are written and which channels are affected. They return self.

  • at(time : Float64) : self moves the internal write cursor to the sample at time seconds from the start. Subsequent generators will insert/overwrite samples starting at that position.

  • rewind : self moves the cursor to the beginning (time 0).

  • forward(time : Float64 = 0.0) : self moves the cursor forward by time seconds. If time is 0 (default), moves to the end of the current audio.

  • left : self sets the channel target to the left channel (index 0). Generators will write only to this channel.

  • right : self sets the channel target to the right channel (index 1).

  • all : self resets the channel target so that generators write to all channels (default).

  • channel(target : Int32?) : self sets the channel target to a specific index (0‑based). Pass nil to write to all channels. Raises if the channel index is out of range.

information

  • to_s(io) : Nil returns a human‑readable summary, e.g. #<Wav r=44100 ch=2 b=16 t=1.5s>.

attributes

  • rate : Float64 – sample rate in Hz.
  • channels : Int32 – number of channels.
  • bits : Int32 – bit depth (8 or 16).
  • samples : Array(Float64) – raw sample array (interleaved, values in -1.0..1.0).

Notes

  • all samples are internally stored as Float64 in the range -1.0 to 1.0.
  • methods that modify the audio (effects, generation) generally operate on the existing samples and may extend or overwrite them depending on cursor position.
  • the library only supports 8‑bit (unsigned) and 16‑bit (signed) PCM WAV files. Reading other formats will raise an error.
  • when mixing or combining Wav instances, ensure they have compatible sample rates and channel counts.