class WaveInfo
Constants
- VERSION
Attributes
debug[RW]
Public Class Methods
new(file)
click to toggle source
Create a new WaveInfo
object to get information and metadata about a Wave file (.wav). 'file' can either be a filename or an IO object.
# File lib/waveinfo.rb, line 13 def initialize(file) # Set default values @audio_format_id = 0 @bits_per_sample = nil @block_align = nil @byte_rate = nil @channels = nil @data_size = nil @sample_rate = nil @samples = nil # What was passed in to us? if file.is_a?(String) @io = File.new(file, 'rb') @filepath = @io.path read_headers @io.close else @io = file @filepath = @io.path if @io.respond_to?(:path) read_headers end end
Public Instance Methods
audio_format()
click to toggle source
Get the name of the audio codec (for example 'PCM').
# File lib/waveinfo.rb, line 49 def audio_format case @audio_format_id when 0x01 then "PCM" when 0x02 then "Microsoft ADPCM" when 0x06 then "a-law" when 0x07 then "u-law" when 0x11 then "IMA ADPCM" when 0x14 then "G.723" when 0x31 then "GSM" when 0x40 then "G.721" when 0x50 then "MPEG-1 Audio" when 0x55 then "MPEG Audio Layer 3" when 0xFFFE "Extensible wave format" else sprintf("Unknown (0x%2.2x)",@audio_format_id) end end
audio_format_id()
click to toggle source
Get the identifier of the audio codec (for example PCM would be 1).
# File lib/waveinfo.rb, line 44 def audio_format_id @audio_format_id end
bits_per_sample()
click to toggle source
Get the number of bits per sample.
# File lib/waveinfo.rb, line 99 def bits_per_sample @bits_per_sample end
block_align()
click to toggle source
Get the number of bytes per sample slice.
# File lib/waveinfo.rb, line 94 def block_align @block_align end
byte_rate()
click to toggle source
Get the average number of bytes per second.
# File lib/waveinfo.rb, line 89 def byte_rate @byte_rate end
channels()
click to toggle source
Get the number of channels.
# File lib/waveinfo.rb, line 79 def channels @channels end
duration()
click to toggle source
Get the duration of the audio (in seconds).
# File lib/waveinfo.rb, line 120 def duration if sample_rate.to_f.nonzero? sample_rate ? samples.to_f / sample_rate.to_f : 0.0 else 0.0 end end
filename()
click to toggle source
Return the name of the input file.
# File lib/waveinfo.rb, line 39 def filename File.basename(@filepath) end
sample_rate()
click to toggle source
Get the sample rate (in Hz).
# File lib/waveinfo.rb, line 84 def sample_rate @sample_rate end
samples()
click to toggle source
Get the total number of samples.
# File lib/waveinfo.rb, line 104 def samples if @samples @samples elsif @block_align.to_f.nonzero? @data_size && @block_align ? @data_size / @block_align : 0.0 else 0.0 end end
size()
click to toggle source
Get the length of the audio data (in bytes).
# File lib/waveinfo.rb, line 115 def size @data_size end
Private Instance Methods
read_ds64_chunk()
click to toggle source
# File lib/waveinfo.rb, line 204 def read_ds64_chunk subchunk_id = read_fourchar raise FileFormatError.new("First sub-chunk of RF64 file is not 'ds64'") unless subchunk_id == 'ds64' subchunk_size = read_longint riff_size_low = read_longint riff_size_high = read_longint data_size_low = read_longint data_size_high = read_longint sample_count_low = read_longint sample_count_high = read_longint @data_size = (data_size_high << 32) + data_size_low @samples = (sample_count_high << 32) + sample_count_low @chunk_size = (riff_size_high << 32) + riff_size_low # Skip any extra data @io.seek(subchunk_size-24,IO::SEEK_CUR) if subchunk_size > 24 end
read_fact_chunk(size)
click to toggle source
# File lib/waveinfo.rb, line 193 def read_fact_chunk(size) # Read in the number of samples sample_count = read_longint unless sample_count == 0xFFFFFFFF @samples = sample_count end # Skip any extra data @io.seek(size-4,IO::SEEK_CUR) if size > 4 end
read_fmt_chunk(size)
click to toggle source
# File lib/waveinfo.rb, line 181 def read_fmt_chunk(size) @audio_format_id = read_shortint @channels = read_shortint @sample_rate = read_longint @byte_rate = read_longint @block_align = read_shortint @bits_per_sample = read_shortint # Skip any extra parameters @io.seek(size-16,IO::SEEK_CUR) if size > 16 end
read_fourchar()
click to toggle source
# File lib/waveinfo.rb, line 224 def read_fourchar @io.read(4) end
read_headers()
click to toggle source
# File lib/waveinfo.rb, line 131 def read_headers # Read in the chunk header @chunk_id = read_fourchar @chunk_size = read_longint @chunk_format = read_fourchar raise FileFormatError.new("Chunk format is not 'WAVE'") unless @chunk_format == 'WAVE' if @chunk_id == 'RIFF' position = 0xC elsif @chunk_id == 'RF64' # Next sub-chunk *has* to be a 'ds64' subchunk_size = read_ds64_chunk position = 0xC + subchunk_size else raise FileFormatError.new("Primary chunk id is not 'RIFF' or 'RF64'") end read_subchunks(position) end
read_longint()
click to toggle source
# File lib/waveinfo.rb, line 228 def read_longint bytes = @io.read(4) bytes ? bytes.unpack('V').first : nil end
read_shortint()
click to toggle source
# File lib/waveinfo.rb, line 233 def read_shortint bytes = @io.read(2) bytes ? bytes.unpack('v').first : nil end
read_subchunks(position)
click to toggle source
# File lib/waveinfo.rb, line 151 def read_subchunks(position) # Read in each of the sub-chunks while(@chunk_size - position) > 0 do subchunk_id = read_fourchar subchunk_size = read_longint case subchunk_id when 'fmt ' read_fmt_chunk(subchunk_size) when 'fact' read_fact_chunk(subchunk_size) when 'data' unless subchunk_size == 0xFFFFFFFF @data_size = subchunk_size end # Skip over the wave data @io.seek(@data_size,IO::SEEK_CUR) when nil # Give up if read fails $stderr.puts "Warning: read error before reaching end of file" if WaveInfo.debug break else pos = sprintf("0x%x", position) $stderr.puts "Warning: unsupported sub-chunk at #{pos}: #{subchunk_id}" if WaveInfo.debug @io.seek(subchunk_size,IO::SEEK_CUR) end position += subchunk_size + 8 end end