ruby-cafinfo 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +3 -0
 - data/LICENSE +21 -0
 - data/README +76 -0
 - data/Rakefile +43 -0
 - data/lib/caf/chunk.rb +15 -0
 - data/lib/caf/chunk/audio_description.rb +57 -0
 - data/lib/caf/chunk/base.rb +43 -0
 - data/lib/caf/chunk/data.rb +47 -0
 - data/lib/caf/chunk/free.rb +24 -0
 - data/lib/caf/chunk/helper.rb +35 -0
 - data/lib/caf/chunk/magic_cookie.rb +35 -0
 - data/lib/caf/chunk/types.rb +5 -0
 - data/lib/caf/errors.rb +4 -0
 - data/lib/caf/extension_modules.rb +41 -0
 - data/lib/cafinfo.rb +203 -0
 - metadata +80 -0
 
    
        data/CHANGELOG
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2009 Oleguer Huguet Ibars
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            The MIT License
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 13 
     | 
    
         
            +
            all copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
      
 21 
     | 
    
         
            +
            THE SOFTWARE.
         
     | 
    
        data/README
    ADDED
    
    | 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ruby-cafinfo
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            by Oleguer Huguet Ibars
         
     | 
| 
      
 4 
     | 
    
         
            +
            * http://rubyforge.org/projects/ruby-cafinfo
         
     | 
| 
      
 5 
     | 
    
         
            +
            * git repository: git://rubyforge.org/ruby-cafinfo.git
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            == DESCRIPTION:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            A ruby library to retrieve information of CAF (Core Audio Format) files, heavily inspired by the excellent ruby-mp3info[http://ruby-mp3info.rubyforge.org/].
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            From the CAF format specification:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            "Apple's Core Audio Format (CAF) is a file format for storing and transporting digital
         
     | 
| 
      
 14 
     | 
    
         
            +
            audio data. It simplifies the management and manipulation of many types of audio data
         
     | 
| 
      
 15 
     | 
    
         
            +
            without the file-size limitations of other audio file formats."
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            Specs for CAF format can be found here[http://developer.apple.com/DOCUMENTATION/MusicAudio/Reference/CAFSpec/CAF_intro/CAF_intro.html].
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            == FEATURES:
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            * written in pure ruby
         
     | 
| 
      
 22 
     | 
    
         
            +
            * read low-level informations like bitrate, length, samplerate, etc...
         
     | 
| 
      
 23 
     | 
    
         
            +
            * only some chunk types are recognized (Audio Description, Data, Free, Magick Cookie)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            == SYNOPSIS:
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            Using as a lib is easy:
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              require "cafinfo"
         
     | 
| 
      
 30 
     | 
    
         
            +
              # read and display info
         
     | 
| 
      
 31 
     | 
    
         
            +
              CafInfo.open("myfile.caf") do |cafinfo|
         
     | 
| 
      
 32 
     | 
    
         
            +
                puts cafinfo
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              # read and display some attributes
         
     | 
| 
      
 36 
     | 
    
         
            +
              CafInfo.open("myfile.caf") do |caf|
         
     | 
| 
      
 37 
     | 
    
         
            +
                puts caf.length
         
     | 
| 
      
 38 
     | 
    
         
            +
                puts caf.samplerate
         
     | 
| 
      
 39 
     | 
    
         
            +
                puts caf.format
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              # extract payload audio data from a (small) CAF and write to another file
         
     | 
| 
      
 43 
     | 
    
         
            +
              audio_pos, audio_length = CafInfo.open("myfile.caf") { |caf| caf.audio_content }
         
     | 
| 
      
 44 
     | 
    
         
            +
              File.open("myfile.caf", "rb") do |caf_file|
         
     | 
| 
      
 45 
     | 
    
         
            +
                File.open("myaudio.data", "wb") do |f|
         
     | 
| 
      
 46 
     | 
    
         
            +
                  caf_file.seek(audio_pos)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  data = caf_file.read(audio_length)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  f.write(data)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              # extract payload audio data from an arbitrarily large CAF and write
         
     | 
| 
      
 53 
     | 
    
         
            +
              # to another file, considering that data chunk may not be at the end
         
     | 
| 
      
 54 
     | 
    
         
            +
              # of caf file
         
     | 
| 
      
 55 
     | 
    
         
            +
              audio_pos, audio_length = CafInfo.open("myfile.caf") { |caf| caf.audio_content }
         
     | 
| 
      
 56 
     | 
    
         
            +
              File.open("myfile.caf", "rb") do |caf_file|
         
     | 
| 
      
 57 
     | 
    
         
            +
                File.open("myaudio-buffered.data", "wb") do |f|
         
     | 
| 
      
 58 
     | 
    
         
            +
                  caf_file.seek(audio_pos)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  while buffer = caf_file.read([4096, audio_length].min) and buffer.size > 0
         
     | 
| 
      
 60 
     | 
    
         
            +
                    f.write(buffer)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    audio_length -= buffer.size
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            == INSTALL:
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
             # gem install ruby-cafinfo
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            == LICENSE:
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            MIT license
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            == TODO:
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            * support for other chunk types
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rake'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rake/clean'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rake/gempackagetask'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rake/rdoctask'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'rake/testtask'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            spec = Gem::Specification.new do |s|
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.name = 'ruby-cafinfo'
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.version = '0.1'
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.has_rdoc = true
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.extra_rdoc_files = ['README', 'LICENSE', 'CHANGELOG']
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.summary = 'ruby-cafinfo is a ruby library to retrieve low level informations on CAF files'
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.description = s.summary
         
     | 
| 
      
 15 
     | 
    
         
            +
              s.author = 'Oleguer Huguet Ibars'
         
     | 
| 
      
 16 
     | 
    
         
            +
              s.email = 'olegueret@rubyforge.org'
         
     | 
| 
      
 17 
     | 
    
         
            +
              # s.executables = ['your_executable_here']
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.files = %w(LICENSE README Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.require_path = "lib"
         
     | 
| 
      
 20 
     | 
    
         
            +
              #s.bindir = "bin"
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.add_dependency 'float-formats', '>=0.1.1'
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.rubyforge_project = 'ruby-cafinfo'
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.homepage = 'http://ruby-cafinfo.rubyforge.org'
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            Rake::GemPackageTask.new(spec) do |p|
         
     | 
| 
      
 27 
     | 
    
         
            +
              p.gem_spec = spec
         
     | 
| 
      
 28 
     | 
    
         
            +
              p.need_tar = true
         
     | 
| 
      
 29 
     | 
    
         
            +
              p.need_zip = true
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            Rake::RDocTask.new do |rdoc|
         
     | 
| 
      
 33 
     | 
    
         
            +
              files =['README', 'LICENSE', 'CHANGELOG', 'lib/**/*.rb']
         
     | 
| 
      
 34 
     | 
    
         
            +
              rdoc.rdoc_files.add(files)
         
     | 
| 
      
 35 
     | 
    
         
            +
              rdoc.main = "README" # page to start on
         
     | 
| 
      
 36 
     | 
    
         
            +
              rdoc.title = "ruby-cafinfo Docs"
         
     | 
| 
      
 37 
     | 
    
         
            +
              rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
         
     | 
| 
      
 38 
     | 
    
         
            +
              rdoc.options << '--line-numbers'
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            Rake::TestTask.new do |t|
         
     | 
| 
      
 42 
     | 
    
         
            +
              t.test_files = FileList['test/**/*.rb']
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/caf/chunk.rb
    ADDED
    
    | 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'caf/chunk/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Caf
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Chunk
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.available_chunk_types
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @available_chunk_types ||= {}
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.build(chunk_header)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  klass = available_chunk_types[(chunk_header[:chunk_type] || "").downcase]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  klass = Base if klass.nil?
         
     | 
| 
      
 12 
     | 
    
         
            +
                  klass.new(chunk_header)
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'caf/chunk/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'caf/chunk/helper'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'caf/errors'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Caf::Chunk
         
     | 
| 
      
 6 
     | 
    
         
            +
              include Helper
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              class AudioDescription < Base
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
                implements 'desc'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                attr_accessor :samplerate, :format_id, :format_flags, :bytes_per_packet,
         
     | 
| 
      
 13 
     | 
    
         
            +
                  :frames_per_packet, :channels_per_frame, :bits_per_channel
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(chunk_header)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  super chunk_header
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 20 
     | 
    
         
            +
                  "#{chunk_type} (audio description chunk):\n"+
         
     | 
| 
      
 21 
     | 
    
         
            +
                    " -samplerate:         #{samplerate}\n"+
         
     | 
| 
      
 22 
     | 
    
         
            +
                    " -format ID:          #{format_id}\n"+
         
     | 
| 
      
 23 
     | 
    
         
            +
                    " -format flags:       #{format_flags}\n"+
         
     | 
| 
      
 24 
     | 
    
         
            +
                    " -bytes per packet:   #{bytes_per_packet}\n"+
         
     | 
| 
      
 25 
     | 
    
         
            +
                    " -frames per packet:  #{frames_per_packet}\n"+
         
     | 
| 
      
 26 
     | 
    
         
            +
                    " -channels per frame: #{channels_per_frame}\n"+
         
     | 
| 
      
 27 
     | 
    
         
            +
                    " -bits per channel:   #{bits_per_channel}\n"
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def validate
         
     | 
| 
      
 31 
     | 
    
         
            +
                  raise(Caf::Error, "invalid audio description chunk: sample rate cannot be 0") if samplerate == 0
         
     | 
| 
      
 32 
     | 
    
         
            +
                  raise(Caf::Error, "invalid audio description chunk: format ID cannot be 0") if format_id == 0
         
     | 
| 
      
 33 
     | 
    
         
            +
                  raise(Caf::Error, "invalid audio description chunk: channels per frame cannot be 0") if channels_per_frame == 0
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def fields_size
         
     | 
| 
      
 37 
     | 
    
         
            +
                  32
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def read_data(file)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  data = file.read(self.fields_size)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  raise(Caf::Error, "chunk data too short: #{self}") if file.eof?
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  @samplerate        = Helper.read_double(data)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @format_id          = Helper.read_chars(4, data, 8)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @format_flags       = Helper.read_int(data, 12)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @bytes_per_packet   = Helper.read_int(data, 16)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  @frames_per_packet  = Helper.read_int(data, 20)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @channels_per_frame = Helper.read_int(data, 24)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @bits_per_channel   = Helper.read_int(data, 28)
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  self.validate
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  data.size
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'caf/chunk'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'caf/chunk/helper'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'caf/errors'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Caf::Chunk
         
     | 
| 
      
 6 
     | 
    
         
            +
              include Helper
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def self.implements(chunk_type)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  Caf::Chunk.available_chunk_types[chunk_type] = self
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                attr_reader :chunk_type, :chunk_size
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def initialize(chunk_header)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @chunk_type = chunk_header[:chunk_type]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @chunk_size = chunk_header[:chunk_size]
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 22 
     | 
    
         
            +
                  "#{chunk_type} (unknown chunk)"
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def validate
         
     | 
| 
      
 26 
     | 
    
         
            +
                  raise(Caf::Error, "chunk must implement validate method: #{chunk_type}") unless self.instance_of?(Base)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  true
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def fields_size
         
     | 
| 
      
 31 
     | 
    
         
            +
                  raise(Caf::Error, "chunk must implement fields_size method: #{chunk_type}") unless self.instance_of?(Base)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def read_data(file)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  file.seek(chunk_size, IO::SEEK_CUR) unless chunk_size == -1
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def check_type_and_size(expected_klass, expected_chunk_type)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  raise(Caf::Error, "expected an #{expected_chunk_type} chunk") unless self.instance_of?(expected_klass)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  raise(Caf::Error, "corrupted chunk: wrong size (expected #{fields_size}, got #{chunk_size}") if fields_size != chunk_size
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'caf/chunk/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'caf/chunk/helper'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'caf/errors'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Caf::Chunk
         
     | 
| 
      
 6 
     | 
    
         
            +
              include Helper
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              class Data < Base
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              implements 'data'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                attr_accessor :edit_count, :size, :position
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize(chunk_header)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  super chunk_header
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 19 
     | 
    
         
            +
                  "#{chunk_type} (data chunk):\n"+
         
     | 
| 
      
 20 
     | 
    
         
            +
                    " -edit count:         #{edit_count}\n" +
         
     | 
| 
      
 21 
     | 
    
         
            +
                    " -data size:          #{size}\n" +
         
     | 
| 
      
 22 
     | 
    
         
            +
                    " -data position:      #{position}\n"
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def validate
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def fields_size
         
     | 
| 
      
 29 
     | 
    
         
            +
                  raise(Caf::Error, "not implemented")
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def read_data(file)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  edit = file.read(4)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @edit_count = (edit.getbyte(0) << 32) + (edit.getbyte(1) << 16) + (edit.getbyte(2) << 8) + edit.getbyte(3)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @position = file.pos
         
     | 
| 
      
 36 
     | 
    
         
            +
                  unless chunk_size == -1
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @size = chunk_size - 4  # 4 bytes are from edit_count field
         
     | 
| 
      
 38 
     | 
    
         
            +
                    file.seek(@size, IO::SEEK_CUR)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  else
         
     | 
| 
      
 40 
     | 
    
         
            +
                    file.seek(0, IO::SEEK_END)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @size = file.pos - @position
         
     | 
| 
      
 42 
     | 
    
         
            +
                    # TODO should update chunk_size field with @size + 4 if file is writable
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'caf/chunk/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'caf/errors'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Caf::Chunk
         
     | 
| 
      
 5 
     | 
    
         
            +
              include Helper
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              class Free < Base
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                implements 'free'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 12 
     | 
    
         
            +
                  "#{chunk_type} (free chunk)"
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def validate
         
     | 
| 
      
 16 
     | 
    
         
            +
                  true
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def fields_size
         
     | 
| 
      
 20 
     | 
    
         
            +
                  raise(Caf::Error, "not implemented")
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'float-formats'
         
     | 
| 
      
 3 
     | 
    
         
            +
            include FltPnt
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Caf::Chunk
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Helper
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                BIT_SHIFTS_8 = [64, 56, 48, 40, 32, 24, 16, 8]
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def self.read_bytes(number, data, offset = 0)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  buffer = 0
         
     | 
| 
      
 12 
     | 
    
         
            +
                  number_minus = number - 1
         
     | 
| 
      
 13 
     | 
    
         
            +
                  number_minus.downto(0) do |i|
         
     | 
| 
      
 14 
     | 
    
         
            +
                    buffer += (data.getbyte(offset + number_minus - i) << (8 * i))
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  buffer
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def self.read_chars(number, data, offset = 0)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  buffer = ''
         
     | 
| 
      
 21 
     | 
    
         
            +
                  0.upto(number-1) { |i| buffer += data.getbyte(offset+i).chr }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  buffer
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def self.read_double(data, offset = 0)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  num = read_bytes(8, data, offset)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  IEEE_binary64.from_bits_integer(num).to_number(Float)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def self.read_int(data, offset = 0)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  read_bytes(4, data, offset).to_i
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'caf/chunk/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'caf/errors'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Caf::Chunk
         
     | 
| 
      
 5 
     | 
    
         
            +
              include Helper
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              class MagicCookie < Base
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                implements 'kuki'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :size, :position #, :data
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 14 
     | 
    
         
            +
                  "#{chunk_type} (magic cookie chunk)\n" +
         
     | 
| 
      
 15 
     | 
    
         
            +
                    " -cookie size:        #{size}\n" +
         
     | 
| 
      
 16 
     | 
    
         
            +
                    " -cookie position:    #{position}\n"
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def validate
         
     | 
| 
      
 20 
     | 
    
         
            +
                  true
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def fields_size
         
     | 
| 
      
 24 
     | 
    
         
            +
                  raise(Caf::Error, "not implemented")
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def read_data(file)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @size = chunk_size
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @position = file.pos
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #@data = file.read(chunk_size)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  super(file)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/caf/errors.rb
    ADDED
    
    
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class CafInfo
         
     | 
| 
      
 2 
     | 
    
         
            +
              module HashKeys #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                ### lets you specify hash["key"] as hash.key
         
     | 
| 
      
 4 
     | 
    
         
            +
                ### this came from CodingInRuby on RubyGarden
         
     | 
| 
      
 5 
     | 
    
         
            +
                ### http://www.rubygarden.org/ruby?CodingInRuby
         
     | 
| 
      
 6 
     | 
    
         
            +
                def method_missing(meth,*args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  m = meth.id2name
         
     | 
| 
      
 8 
     | 
    
         
            +
                  if /=$/ =~ m
         
     | 
| 
      
 9 
     | 
    
         
            +
            	self[m.chop] = (args.length<2 ? args[0] : args)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  else
         
     | 
| 
      
 11 
     | 
    
         
            +
            	self[m]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              class ::String
         
     | 
| 
      
 17 
     | 
    
         
            +
                if RUBY_VERSION < "1.9.0"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  alias getbyte []
         
     | 
| 
      
 19 
     | 
    
         
            +
                else
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def getbyte(i)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    self[i].ord
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              module CafFileMethods #:nodoc:
         
     | 
| 
      
 27 
     | 
    
         
            +
                if RUBY_VERSION < "1.9.0"
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def getbyte
         
     | 
| 
      
 29 
     | 
    
         
            +
                    getc
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def get32bits
         
     | 
| 
      
 34 
     | 
    
         
            +
                  (getbyte << 24) + (getbyte << 16) + (getbyte << 8) + getbyte
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def get_syncsafe
         
     | 
| 
      
 38 
     | 
    
         
            +
                  (getbyte << 21) + (getbyte << 14) + (getbyte << 7) + getbyte
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/cafinfo.rb
    ADDED
    
    | 
         @@ -0,0 +1,203 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # coding:utf-8
         
     | 
| 
      
 3 
     | 
    
         
            +
            # License:: Mit
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Author:: Oleguer Huguet Ibars (mailto:oleguer_DOT_huguet_AT__gmail_DOT_com)
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Website:: http://ruby-cafinfo.rubyforge.org/
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require "fileutils"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            $:.unshift "#{File.dirname(__FILE__)}"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'caf/extension_modules'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'caf/errors'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'caf/chunk/types'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # ruby -d to display debugging infos
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            class CafInfo
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              VERSION = "0.1"
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              # the original filename
         
     | 
| 
      
 21 
     | 
    
         
            +
              attr_reader(:filename)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              # duration in seconds of audio
         
     | 
| 
      
 24 
     | 
    
         
            +
              attr_reader(:length)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              # the number of sample frames per second of the data
         
     | 
| 
      
 27 
     | 
    
         
            +
              attr_reader(:samplerate)
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              # a four-character code indicating the general kind of data in the stream
         
     | 
| 
      
 30 
     | 
    
         
            +
              attr_reader(:format)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              # flags specific to each format
         
     | 
| 
      
 33 
     | 
    
         
            +
              attr_reader(:format_flags)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              # the number of bytes in a packet of data.
         
     | 
| 
      
 36 
     | 
    
         
            +
              attr_reader(:bytes_per_packet)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              # the number of sample frames in each packet of data
         
     | 
| 
      
 39 
     | 
    
         
            +
              attr_reader(:frames_per_packet)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              # the number of channels in each frame of data
         
     | 
| 
      
 42 
     | 
    
         
            +
              attr_reader(:channels_per_frame)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              # the number of bits of sample data for each channel in a frame of data.
         
     | 
| 
      
 45 
     | 
    
         
            +
              # 0 if the data format does not contain separate samples for each channel (for instance any compressed format)
         
     | 
| 
      
 46 
     | 
    
         
            +
              attr_reader(:bits_per_channel)
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              # variable bitrate => true or false
         
     | 
| 
      
 49 
     | 
    
         
            +
              attr_reader(:vbr)
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              # variable frame rate => true or false
         
     | 
| 
      
 52 
     | 
    
         
            +
              attr_reader(:vfr)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              # Instantiate CafInfo object with name +filename+.
         
     | 
| 
      
 55 
     | 
    
         
            +
              def initialize(filename)
         
     | 
| 
      
 56 
     | 
    
         
            +
                warn("#{self.class}::new() does not take block; use #{self.class}::open() instead") if block_given?
         
     | 
| 
      
 57 
     | 
    
         
            +
                @filename = filename
         
     | 
| 
      
 58 
     | 
    
         
            +
                @header = {}
         
     | 
| 
      
 59 
     | 
    
         
            +
                reload
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              # reload (or load for the first time) the file from disk
         
     | 
| 
      
 63 
     | 
    
         
            +
              def reload
         
     | 
| 
      
 64 
     | 
    
         
            +
                raise(Caf::Error, "empty file") unless File.size?(@filename)
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                @file = File.new(filename, "rb")
         
     | 
| 
      
 67 
     | 
    
         
            +
                @file.extend(CafFileMethods)
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                @chunks = {}
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                begin
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @header = read_file_header
         
     | 
| 
      
 73 
     | 
    
         
            +
                  chunk = read_audio_description_chunk
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @chunks[chunk.chunk_type.to_sym] = chunk
         
     | 
| 
      
 75 
     | 
    
         
            +
                  puts "Found chunk: #{@chunks[chunk.chunk_type.to_sym]}" if $DEBUG
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  until @file.eof? do
         
     | 
| 
      
 78 
     | 
    
         
            +
                    chunk = read_chunk_header
         
     | 
| 
      
 79 
     | 
    
         
            +
                    chunk.read_data(@file)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    @chunks[chunk.chunk_type.to_sym] = chunk
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    puts "Found chunk: #{chunk}" if $DEBUG
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 85 
     | 
    
         
            +
                  @file.close
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                raise(Caf::Error, "data chunk not found") if @chunks[:data].nil?
         
     | 
| 
      
 89 
     | 
    
         
            +
                @length = (@frames_per_packet * @chunks[:data].size) / (@samplerate * @bytes_per_packet)
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              # "block version" of CafInfo::new()
         
     | 
| 
      
 93 
     | 
    
         
            +
              def self.open(*params)
         
     | 
| 
      
 94 
     | 
    
         
            +
                m = self.new(*params)
         
     | 
| 
      
 95 
     | 
    
         
            +
                ret = nil
         
     | 
| 
      
 96 
     | 
    
         
            +
                if block_given?
         
     | 
| 
      
 97 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 98 
     | 
    
         
            +
                    ret = yield(m)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 100 
     | 
    
         
            +
                    m.close
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
                else
         
     | 
| 
      
 103 
     | 
    
         
            +
                  ret = m
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
                ret
         
     | 
| 
      
 106 
     | 
    
         
            +
              end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              # write to another filename at close()
         
     | 
| 
      
 109 
     | 
    
         
            +
              def rename(new_filename)
         
     | 
| 
      
 110 
     | 
    
         
            +
                @filename = new_filename
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
              # this method returns the "audio-only" data boundaries of the file,
         
     | 
| 
      
 114 
     | 
    
         
            +
              # i.e. data chunk content. Returned value is an array
         
     | 
| 
      
 115 
     | 
    
         
            +
              # [position_in_the_file, length_of_the_data]
         
     | 
| 
      
 116 
     | 
    
         
            +
              def audio_content
         
     | 
| 
      
 117 
     | 
    
         
            +
                [@chunks[:data].position, @chunks[:data].size]
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              # Flush pending modifications and close the file
         
     | 
| 
      
 121 
     | 
    
         
            +
              def close
         
     | 
| 
      
 122 
     | 
    
         
            +
                puts "close" if $DEBUG
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              # close and reopen the file, i.e. commit changes to disk and
         
     | 
| 
      
 126 
     | 
    
         
            +
              # reload it
         
     | 
| 
      
 127 
     | 
    
         
            +
              def flush
         
     | 
| 
      
 128 
     | 
    
         
            +
                close
         
     | 
| 
      
 129 
     | 
    
         
            +
                reload
         
     | 
| 
      
 130 
     | 
    
         
            +
              end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
              # inspect inside CafInfo
         
     | 
| 
      
 133 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 134 
     | 
    
         
            +
                s = "CAF (version #{@header[:file_version]}) #{@format} #{"VFR " if @vfr}#{@vbr ? "VBR" : "CBR"} #{@samplerate} Hz length #{@length} sec."
         
     | 
| 
      
 135 
     | 
    
         
            +
                s << ""
         
     | 
| 
      
 136 
     | 
    
         
            +
                s
         
     | 
| 
      
 137 
     | 
    
         
            +
              end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
            private
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
              ### reads through @file to find its header
         
     | 
| 
      
 142 
     | 
    
         
            +
              def read_file_header
         
     | 
| 
      
 143 
     | 
    
         
            +
                header = {}
         
     | 
| 
      
 144 
     | 
    
         
            +
                head = @file.read(8)
         
     | 
| 
      
 145 
     | 
    
         
            +
                raise(Caf::Error, "file header too short") if @file.eof?
         
     | 
| 
      
 146 
     | 
    
         
            +
                raise(Caf::Error, "not a CAF file") unless head.match(/^caff/)
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                header[:file_version] = (head.getbyte(4) << 8) + head.getbyte(5)
         
     | 
| 
      
 149 
     | 
    
         
            +
                raise(Caf::Error, "invalid CAF file version (supported only version 1)") if header[:file_version] != 1
         
     | 
| 
      
 150 
     | 
    
         
            +
                
         
     | 
| 
      
 151 
     | 
    
         
            +
                header[:file_flags] = (head.getbyte(6) << 8) + head.getbyte(7)
         
     | 
| 
      
 152 
     | 
    
         
            +
                raise(Caf::Error, "invalid CAF file flags") if header[:file_flags] != 0
         
     | 
| 
      
 153 
     | 
    
         
            +
                header
         
     | 
| 
      
 154 
     | 
    
         
            +
              end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
              def read_chunk_header
         
     | 
| 
      
 157 
     | 
    
         
            +
                header = {}
         
     | 
| 
      
 158 
     | 
    
         
            +
                head = @file.read(12)
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                raise(Caf::Error, "chunk header too short: #{head.size}") if head && head.size < 12
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                header[:chunk_type] = head.getbyte(0).chr + head.getbyte(1).chr + head.getbyte(2).chr + head.getbyte(3).chr
         
     | 
| 
      
 163 
     | 
    
         
            +
                header[:chunk_size] = (head.getbyte(4) << 512) + (head.getbyte(5) << 256) + (head.getbyte(6) << 128) + (head.getbyte(7) << 64)+
         
     | 
| 
      
 164 
     | 
    
         
            +
                                      (head.getbyte(8) << 32) + (head.getbyte(9) << 16) + (head.getbyte(10) << 8) + head.getbyte(11)
         
     | 
| 
      
 165 
     | 
    
         
            +
                Caf::Chunk.build(header)
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
              def read_audio_description_chunk
         
     | 
| 
      
 169 
     | 
    
         
            +
                chunk = read_chunk_header
         
     | 
| 
      
 170 
     | 
    
         
            +
                chunk.check_type_and_size(Caf::Chunk::AudioDescription, 'audio description')
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                chunk.read_data(@file)
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                @vbr = chunk.bytes_per_packet == 0
         
     | 
| 
      
 175 
     | 
    
         
            +
                @vfr = chunk.frames_per_packet == 0
         
     | 
| 
      
 176 
     | 
    
         
            +
                @samplerate = chunk.samplerate.to_i
         
     | 
| 
      
 177 
     | 
    
         
            +
                @format = chunk.format_id
         
     | 
| 
      
 178 
     | 
    
         
            +
                @format_flags = chunk.format_flags
         
     | 
| 
      
 179 
     | 
    
         
            +
                @bytes_per_packet = chunk.bytes_per_packet
         
     | 
| 
      
 180 
     | 
    
         
            +
                @frames_per_packet = chunk.frames_per_packet
         
     | 
| 
      
 181 
     | 
    
         
            +
                @channels_per_frame = chunk.channels_per_frame
         
     | 
| 
      
 182 
     | 
    
         
            +
                @bits_per_channel = chunk.bits_per_channel
         
     | 
| 
      
 183 
     | 
    
         
            +
                
         
     | 
| 
      
 184 
     | 
    
         
            +
                chunk
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
            end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            if $0 == __FILE__
         
     | 
| 
      
 190 
     | 
    
         
            +
              error = 0
         
     | 
| 
      
 191 
     | 
    
         
            +
              while filename = ARGV.shift
         
     | 
| 
      
 192 
     | 
    
         
            +
                begin
         
     | 
| 
      
 193 
     | 
    
         
            +
                  info = CafInfo.new(filename)
         
     | 
| 
      
 194 
     | 
    
         
            +
                  puts filename
         
     | 
| 
      
 195 
     | 
    
         
            +
                  puts info
         
     | 
| 
      
 196 
     | 
    
         
            +
                rescue Caf::Error => e
         
     | 
| 
      
 197 
     | 
    
         
            +
                  puts "#{filename}\nERROR: #{e}"
         
     | 
| 
      
 198 
     | 
    
         
            +
                  error = 1
         
     | 
| 
      
 199 
     | 
    
         
            +
                end
         
     | 
| 
      
 200 
     | 
    
         
            +
                puts
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
              exit(error)
         
     | 
| 
      
 203 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: ruby-cafinfo
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: "0.1"
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Oleguer Huguet Ibars
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2009-03-19 00:00:00 +01:00
         
     | 
| 
      
 13 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 14 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 15 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 16 
     | 
    
         
            +
              name: float-formats
         
     | 
| 
      
 17 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 18 
     | 
    
         
            +
              version_requirement: 
         
     | 
| 
      
 19 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 20 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 21 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 22 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 23 
     | 
    
         
            +
                    version: 0.1.1
         
     | 
| 
      
 24 
     | 
    
         
            +
                version: 
         
     | 
| 
      
 25 
     | 
    
         
            +
            description: ruby-cafinfo is a ruby library to retrieve low level informations on CAF files
         
     | 
| 
      
 26 
     | 
    
         
            +
            email: olegueret@rubyforge.org
         
     | 
| 
      
 27 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            extra_rdoc_files: 
         
     | 
| 
      
 32 
     | 
    
         
            +
            - README
         
     | 
| 
      
 33 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 34 
     | 
    
         
            +
            - CHANGELOG
         
     | 
| 
      
 35 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 36 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 37 
     | 
    
         
            +
            - README
         
     | 
| 
      
 38 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 39 
     | 
    
         
            +
            - lib/cafinfo.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            - lib/caf
         
     | 
| 
      
 41 
     | 
    
         
            +
            - lib/caf/chunk
         
     | 
| 
      
 42 
     | 
    
         
            +
            - lib/caf/chunk/audio_description.rb
         
     | 
| 
      
 43 
     | 
    
         
            +
            - lib/caf/chunk/magic_cookie.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            - lib/caf/chunk/base.rb
         
     | 
| 
      
 45 
     | 
    
         
            +
            - lib/caf/chunk/free.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/caf/chunk/types.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/caf/chunk/data.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib/caf/chunk/helper.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            - lib/caf/extension_modules.rb
         
     | 
| 
      
 50 
     | 
    
         
            +
            - lib/caf/errors.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/caf/chunk.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - CHANGELOG
         
     | 
| 
      
 53 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 54 
     | 
    
         
            +
            homepage: http://ruby-cafinfo.rubyforge.org
         
     | 
| 
      
 55 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 56 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 59 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 60 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 61 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 62 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 63 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 64 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 65 
     | 
    
         
            +
              version: 
         
     | 
| 
      
 66 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 67 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 68 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 69 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 70 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 71 
     | 
    
         
            +
              version: 
         
     | 
| 
      
 72 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            rubyforge_project: ruby-cafinfo
         
     | 
| 
      
 75 
     | 
    
         
            +
            rubygems_version: 1.3.1
         
     | 
| 
      
 76 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 77 
     | 
    
         
            +
            specification_version: 2
         
     | 
| 
      
 78 
     | 
    
         
            +
            summary: ruby-cafinfo is a ruby library to retrieve low level informations on CAF files
         
     | 
| 
      
 79 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     |