wavファイルのdata chunkを取り出す
WavFile.rbでは今まで全chunksを配列で取り出していたが、よく考えたらformat chunkとdata chunk以外は捨てても構わない情報なので
chunk配列からdata chunkだけを取り出す関数を追加した。
readDataChunk.rb
http://shokai.org/projects/ruby-wavfile/index.cgi/file/65d418d256b4/readDataChunk.rb
#!/usr/bin/env ruby require File.dirname(__FILE__) + '/WavFile' if ARGV.size < 1 puts 'ruby readDataChunk.rb input.wav' exit 1 end File.open(ARGV[0]){|file| format = WavFile::readFormat(file) puts format.to_s dataChunk = WavFile::readDataChunk(file) puts "#{dataChunk.name} #{dataChunk.size}" }
実行
ruby readDataChunk.rb input.wav
ファイルに書き戻す時はこう
open("out.wav"){|out| WavFile.write(out, format, [dataChunk]) }
WavFile.rb
http://shokai.org/projects/ruby-wavfile/index.cgi/file/65d418d256b4/WavFile.rb
# -*- coding: utf-8 -*- module WavFile class WavFormatError < StandardError end class Chunk attr_accessor(:name, :size, :data) def initialize(file) @name = file.read(4) @size = file.read(4).unpack("V")[0].to_i @data = file.read(@size) end def to_bin @name + [@data.size].pack('V') + @data end end class Format attr_accessor(:id, :channel, :hz, :bytePerSec, :blockSize, :bitPerSample) def initialize(chunk) return if chunk.class != Chunk return if chunk.name != 'fmt ' @id = chunk.data.slice(0,2)[0].to_i @channel = chunk.data.slice(2,2)[0].to_i @hz = chunk.data.slice(4,4).unpack('V').join.to_i @bytePerSec = chunk.data.slice(8,4).unpack('V').join.to_i @blockSize = chunk.data.slice(12,2)[0].to_i @bitPerSample = chunk.data.slice(14,2)[0].to_i end def to_s <<EOS フォーマットID: #{@id} チャンネル数: #{@channel} サンプリングレート: #{@hz} (Hz) byte per sec: #{@bytePerSec} bit per sample: #{@bitPerSample} ブロックサイズ: #{blockSize} EOS end def to_bin [@id].pack('v')+ [@channel].pack('v') + [@hz].pack('V') + [@bytePerSec].pack('V') + [@blockSize].pack('v') + [@bitPerSample].pack('v') end def ==(target) @id == target.id && @channel == target.channel && @hz == target.hz && @bytePerSec == target.bytePerSec && @bitPerSample == target.bitPerSample && @blockSize == target.blockSize end end def WavFile.readFormat(f) f.binmode f.seek(0) header = f.read(12) riff = header.slice(0,4) data_size = header.slice(4,4).unpack('V')[0].to_i wave = header.slice(8,4) raise(WavFormatError) if riff != 'RIFF' or wave != 'WAVE' formatChunk = Chunk.new(f) Format.new(formatChunk) end def WavFile.readAll(f) format = readFormat(f) chunks = Array.new while !f.eof? chunk = Chunk.new(f) chunks << chunk end return format, chunks end def WavFile.readDataChunk(f) format, chunks = readAll(f) chunks.each{|c| return c if c.name == 'data' } return nil end def WavFile.write(f, format, dataChunks) header_file_size = 4 dataChunks.each{|c| header_file_size += c.data.size + 8 } f.write('RIFF' + [header_file_size].pack('V') + 'WAVE') f.write("fmt ") f.write([format.to_bin.size].pack('V')) f.write(format.to_bin) dataChunks.each{|c| f.write(c.to_bin) } end end