lib/scissor/sound_file.rb in scissor-0.4.0 vs lib/scissor/sound_file.rb in scissor-0.5.0

- old
+ new

@@ -1,6 +1,7 @@ require 'mp3info' +require 'mp4info' require 'pathname' require 'riff/reader' module Scissor class SoundFile @@ -42,13 +43,31 @@ def fmt @fmt ||= riff.root_chunk['fmt '] end end + class M4a < SoundFile + def length + info.SECS_NOROUND + end + + # FIXME + def mono? + false + end + + private + + def info + @info ||= MP4Info.open(@filename.to_s) + end + end + SUPPORTED_FORMATS = { :mp3 => Mp3, - :wav => Wav + :wav => Wav, + :m4a => M4a } class Error < StandardError; end class UnknownFormat < Error; end @@ -63,7 +82,40 @@ end def initialize(filename) @filename = Pathname.new(filename) end + end +end + +class MP4Info + private + + def parse_mvhd(io_stream, level, size) + raise "Parse error" if size < 32 + data = read_or_raise(io_stream, size, "Premature end of file") + + version = data.unpack("C")[0] & 255 + if (version == 0) + scale, duration = data[12..19].unpack("NN") + elsif (version == 1) + scale, hi, low = data[20..31].unpack("NNN") + duration = hi * (2**32) + low + else + return + end + + printf " %sDur/Scl=#{duration}/#{scale}\n", ' ' * ( 2 * level ) if $DEBUG + + secs = (duration * 1.0) / scale + + # add + @info_atoms["SECS_NOROUND"] = secs + + @info_atoms["SECS"] = (secs).round + @info_atoms["MM"] = (secs / 60).floor + @info_atoms["SS"] = (secs - @info_atoms["MM"] * 60).floor + @info_atoms["MS"] = (1000 * (secs - secs.floor)).round + @info_atoms["TIME"] = sprintf "%02d:%02d", @info_atoms["MM"], + @info_atoms["SECS"] - @info_atoms["MM"] * 60; end end