-
Notifications
You must be signed in to change notification settings - Fork 24
WaveFile Tutorial
The example below shows the preferred way of reading an entire wave file:
require 'wavefile'
include WaveFile
SAMPLE_FRAMES_PER_BUFFER = 4096
Reader.new("my_file.wav").each_buffer(SAMPLE_FRAMES_PER_BUFFER) do |buffer|
puts "Read #{buffer.samples.length} samples."
end
First construct a Reader
object, then call each_buffer()
on it. Successive sample buffers will be read from the file and passed to the given block, until all sample data in the file has been read. Finally, the Reader
will automatically be closed. (Note that this is essentially the same as how IO.open
works if you pass it a block).
Note that when calling each_buffer()
(and read()
), the number you pass indicates the number of samples to read for each channel. That is, if you call each_buffer(1024)
on a stereo/16-bit file, then the returned buffer will contain 1024 samples for the left channel, and 1024 samples for the right channel.
Alternately, you can manually call read()
to control exactly how much of the file to read. When doing this, make sure to close the Reader
when you're done.
require 'wavefile'
include WaveFile
SAMPLES_PER_BUFFER = 4096
reader = Reader.new("my_file.wav")
begin
while true do
buffer = reader.read(SAMPLES_PER_BUFFER)
puts "Read #{buffer.samples.length} samples."
end
rescue EOFError
reader.close()
end
It's easy to read sample data out of a file in whatever format you need, regardless of what format is used inside the file. For example, suppose that my_file.wav
is stereo/16-bit, but you need mono normalized floating point samples. No problem, as shown below.
require 'wavefile'
include WaveFile
SAMPLES_PER_BUFFER = 4096
# Samples will be read as monophonic floating point,
# regardless of the actual sample format on disk
format = Format.new(:mono, :float, 44100)
reader = Reader.new("my_file.wav", format).each_buffer(SAMPLES_PER_BUFFER) do |buffer|
puts "Read #{buffer.samples.length} samples."
end
require 'wavefile'
include WaveFile
info = Reader.info("my_file.wav")
puts " Audio Format: #{info.audio_format}"
puts " Channels: #{info.channels}"
puts " Bits per sample: #{info.bits_per_sample}"
puts " Samples per second: #{info.sample_rate}"
puts " Bytes per second: #{info.byte_rate}"
puts " Block align: #{info.block_align}"
puts " Sample frame count: #{info.sample_frame_count}"
duration = info.duration
formatted_duration = duration.hours.to_s.rjust(2, "0") << ":" <<
duration.minutes.to_s.rjust(2, "0") << ":" <<
duration.seconds.to_s.rjust(2, "0") << ":" <<
duration.milliseconds.to_s.rjust(3, "0")
puts " Play time: #{formatted_duration}"
The Writer
object is used to write data to a wave file. The example below shows how to write a basic square wave to a file.
require 'wavefile'
include WaveFile
format = Format.new(:mono, :pcm_16, 44100)
writer = Writer.new("my_file.wav", format)
# Write a 1 second long 440Hz square wave
cycle = ([0.5] * 50) + ([-0.5] * 50)
buffer = Buffer.new(cycle, Format.new(:mono, :float, 44100))
220.times do
writer.write(buffer)
end
writer.close()
In this example, the sample data in the file original.wav
will be written to copy.wav
as stereo/16-bit with a 44,100Hz sample rate, regardless of what format the sample data in original.wav
is stored in.
This example also shows that you can also pass a block to Writer.new()
, and the Writer
will automatically be closed when the block exits.
require 'wavefile'
include WaveFile
SAMPLES_PER_BUFFER = 4096
Writer.new("copy.wav", Format.new(:stereo, :pcm_16, 44100) do |writer|
Reader.new("original.wav").each_buffer(SAMPLES_PER_BUFFER) do |buffer|
writer.write(buffer)
end
end
require 'wavefile'
include WaveFile
FILES_TO_APPEND = ["file1.wav", "file2.wav", "file3.wav"]
SAMPLES_PER_BUFFER = 4096
Writer.new("append.wav", Format.new(:stereo, :pcm_16, 44100) do |writer|
FILES_TO_APPEND.each do |file_name|
Reader.new(file_name).each_buffer(SAMPLES_PER_BUFFER) do |buffer|
writer.write(buffer)
end
end
end