raiff 0.1.0

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ .DS_Store
data/README.rdoc ADDED
@@ -0,0 +1,9 @@
1
+ = raiff
2
+
3
+ Ruby AIFF parsing library.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ == Copyright
8
+
9
+ Copyright (c) 2010 Scott Tadman, The Working Group. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "raiff"
8
+ gem.summary = %Q{Ruby AIFF Reading Library}
9
+ gem.description = %Q{Reads in AIFF file data and audio contents}
10
+ gem.email = "github@tadman.ca"
11
+ gem.homepage = "http://github.com/twg/raiff"
12
+ gem.authors = [ "Scott Tadman" ]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/test_*.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ task :test => :check_dependencies
28
+
29
+ task :default => :test
30
+
31
+ require 'rake/rdoctask'
32
+ Rake::RDocTask.new do |rdoc|
33
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
34
+
35
+ rdoc.rdoc_dir = 'rdoc'
36
+ rdoc.title = "raiff #{version}"
37
+ rdoc.rdoc_files.include('README*')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/raiff.rb ADDED
@@ -0,0 +1,63 @@
1
+ class Raiff
2
+ # == Submodules ===========================================================
3
+
4
+ autoload(:Chunk, 'raiff/chunk')
5
+ autoload(:File, 'raiff/file')
6
+
7
+ # == Properties ===========================================================
8
+
9
+ attr_reader :channels, :sample_frames, :sample_size, :sample_rate
10
+ attr_reader :samples
11
+
12
+ # == Callbacks ============================================================
13
+
14
+ # == Class Methods ========================================================
15
+
16
+ def self.open(file)
17
+ raiff = new(file)
18
+
19
+ yield(raiff) if (block_given?)
20
+
21
+ raiff
22
+ end
23
+
24
+ # == Instance Methods =====================================================
25
+
26
+ def initialize(file = nil)
27
+ @offset = 0
28
+
29
+ if (file)
30
+ @file = Raiff::File.new(file)
31
+
32
+ @form = Raiff::Chunk::Form.new(@file)
33
+ @chunks = @form.chunks
34
+
35
+ common_chunk = (@chunks['COMM'] and @chunks['COMM'][0])
36
+
37
+ if (common_chunk)
38
+ @channels = common_chunk.channels
39
+ @sample_frames = common_chunk.sample_frames
40
+ @sample_size = common_chunk.sample_size
41
+ @sample_rate = common_chunk.sample_rate
42
+ end
43
+
44
+ @samples = [ ]
45
+
46
+ if (@chunks['SSND'])
47
+ @chunks['SSND'].each do |sound_data|
48
+ @samples += sound_data.samples
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def inspect
55
+ "<Raiff\##{object_id} channels=#{channels} sample_frames=#{sample_frames} sample_size=#{sample_size} sample_rate=#{sample_rate}>"
56
+ end
57
+
58
+ def each_sample(&block)
59
+ @chunks['SSND'].each do |sound_data|
60
+ sound_data.samples.each(&:block)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,25 @@
1
+ class Raiff::Chunk
2
+ # == Constants ============================================================
3
+
4
+ autoload(:Common, 'raiff/chunk/common')
5
+ autoload(:Data, 'raiff/chunk/data')
6
+ autoload(:Form, 'raiff/chunk/form')
7
+ autoload(:SoundData, 'raiff/chunk/sound_data')
8
+
9
+ # == Properties ===========================================================
10
+
11
+ attr_reader :id, :size
12
+
13
+ # == Class Methods ========================================================
14
+
15
+ # == Instance Methods =====================================================
16
+
17
+ def initialize(file)
18
+ @id = file.read(4)
19
+ @size = file.unpack('N')[0]
20
+ end
21
+
22
+ def inspect
23
+ "<#{self.class}\##{object_id} #{@id} #{@size}>"
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ class Raiff::Chunk::Common < Raiff::Chunk
2
+ # == Properties ===========================================================
3
+
4
+ attr_reader :channels, :sample_frames, :sample_size, :sample_rate
5
+ attr_reader :bytes_per_sample
6
+
7
+ # == Class Methods ========================================================
8
+
9
+ # == Instance Methods =====================================================
10
+
11
+ def initialize(file)
12
+ super(file)
13
+
14
+ chunk_end = file.offset + @size
15
+
16
+ @channels, @sample_frames, @sample_size = file.unpack('nNn')
17
+
18
+ @sample_rate = file.unpack_extended_float
19
+
20
+ @bytes_per_sample = (@sample_size - 1) / 8 + 1
21
+ end
22
+
23
+ def inspect
24
+ "<#{self.class}\##{object_id} #{@id} #{@size} channels=#{channels} sample_frames=#{sample_frames} sample_size=#{sample_size} sample_rate=#{'%.2f' % sample_rate}>"
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ class Raiff::Chunk::Data < Raiff::Chunk
2
+ # == Properties ===========================================================
3
+
4
+ attr_reader :data
5
+
6
+ # == Class Methods ========================================================
7
+
8
+ # == Instance Methods =====================================================
9
+
10
+ def initialize(file)
11
+ super(file)
12
+
13
+ @data = file.read(@size)
14
+
15
+ if (@size % 2 == 1)
16
+ file.read(1)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ class Raiff::Chunk::Form < Raiff::Chunk
2
+ # == Properties ===========================================================
3
+
4
+ attr_reader :chunks
5
+
6
+ # == Class Methods ========================================================
7
+
8
+ # == Instance Methods =====================================================
9
+
10
+ def initialize(file)
11
+ super(file)
12
+
13
+ @type = file.read(4)
14
+
15
+ @chunks = { }
16
+ common_chunk = nil
17
+
18
+ while (!file.eof?)
19
+ chunk =
20
+ case (file.peek(4))
21
+ when 'COMM'
22
+ common_chunk = Raiff::Chunk::Common.new(file)
23
+ when 'SSND'
24
+ # FIX: Raise exception when there is no common block, but
25
+ # a SoundData block occurs.
26
+ Raiff::Chunk::SoundData.new(file, common_chunk)
27
+ else
28
+ Raiff::Chunk::Data.new(file)
29
+ end
30
+
31
+ @chunks[chunk.id] ||= [ ]
32
+ @chunks[chunk.id] << chunk
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ class Raiff::Chunk::SoundData < Raiff::Chunk
2
+ # == Properties ===========================================================
3
+
4
+ attr_reader :offset, :block_size
5
+ attr_reader :samples
6
+
7
+ # == Class Methods ========================================================
8
+
9
+ # == Instance Methods =====================================================
10
+
11
+ def initialize(file, common)
12
+ super(file)
13
+
14
+ end_offset = file.offset + @size
15
+
16
+ @offset, @block_size = file.unpack('NN')
17
+
18
+ file.read(@offset)
19
+
20
+ sample_count = (end_offset - file.offset) / common.bytes_per_sample
21
+ bit_offset = common.bytes_per_sample * 8 - common.sample_size
22
+ value_offset = (1 << common.sample_size) - 1
23
+
24
+ @samples = [ ]
25
+
26
+ case (common.bytes_per_sample)
27
+ when 3
28
+ format = 'B24' * common.channels
29
+
30
+ sample_count.times do
31
+ if (sample = file.unpack(format))
32
+ @samples << sample.collect { |s| (s.to_i(2) >> bit_offset) - value_offset }
33
+ end
34
+ end
35
+ else
36
+ format = %w[ C n x N ][common.bytes_per_sample] * common.channels
37
+
38
+ sample_count.times do
39
+ @samples << file.unpack(format).collect { |i| (i >> bit_offset) - value_offset }
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/raiff/file.rb ADDED
@@ -0,0 +1,68 @@
1
+ class Raiff::File
2
+ # == Constants ============================================================
3
+
4
+ # == Properties ===========================================================
5
+
6
+ attr_reader :offset
7
+
8
+ # == Class Methods ========================================================
9
+
10
+ # == Instance Methods =====================================================
11
+
12
+ def initialize(file)
13
+ case (file)
14
+ when IO
15
+ @handle = file
16
+ else
17
+ @handle = File.open(file.to_s, 'r:BINARY')
18
+ end
19
+
20
+ @data = @handle.read
21
+ @offset = 0
22
+ end
23
+
24
+ def eof?
25
+ @offset >= @data.length
26
+ end
27
+
28
+ def advance(count = 1)
29
+ @offset += count
30
+ end
31
+
32
+ def seek(offset)
33
+ @offset = offset
34
+ end
35
+
36
+ def peek(bytes)
37
+ @data[@offset, bytes]
38
+ end
39
+
40
+ def read(bytes)
41
+ data = @data[@offset, bytes]
42
+
43
+ @offset += bytes
44
+
45
+ data
46
+ end
47
+
48
+ def unpack_extended_float
49
+ extended = read(10).unpack('B80')[0]
50
+
51
+ sign = extended[0, 1]
52
+ exponent = extended[1, 15].to_i(2) - ((1 << 14) - 1)
53
+ fraction = extended[16, 64].to_i(2)
54
+
55
+ ((sign == '1') ? -1.0 : 1.0) * (fraction.to_f / ((1 << 63) - 1)) * (2 ** exponent)
56
+ end
57
+
58
+ def unpack(format)
59
+ return if (@offset >= @data.length)
60
+
61
+ part = @data[@offset, @data.length].unpack(format)
62
+ advance(part.pack(format).length)
63
+ part
64
+
65
+ rescue TypeError
66
+ [ ]
67
+ end
68
+ end
data/raiff.gemspec ADDED
@@ -0,0 +1,56 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{raiff}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Scott Tadman"]
12
+ s.date = %q{2010-12-06}
13
+ s.description = %q{Reads in AIFF file data and audio contents}
14
+ s.email = %q{github@tadman.ca}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ ".gitignore",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/raiff.rb",
25
+ "lib/raiff/chunk.rb",
26
+ "lib/raiff/chunk/common.rb",
27
+ "lib/raiff/chunk/data.rb",
28
+ "lib/raiff/chunk/form.rb",
29
+ "lib/raiff/chunk/sound_data.rb",
30
+ "lib/raiff/file.rb",
31
+ "raiff.gemspec",
32
+ "sample/example-24bit.aiff",
33
+ "test/helper.rb",
34
+ "test/test_raiff.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/twg/raiff}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.7}
40
+ s.summary = %q{Ruby AIFF Reading Library}
41
+ s.test_files = [
42
+ "test/helper.rb",
43
+ "test/test_raiff.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ else
52
+ end
53
+ else
54
+ end
55
+ end
56
+
Binary file
data/test/helper.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'raiff'
8
+
9
+ class Test::Unit::TestCase
10
+ def sample_file(name)
11
+ File.expand_path(File.join('..', 'sample', name), File.dirname(__FILE__))
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+
3
+ class TestRaiff < Test::Unit::TestCase
4
+ def test_empty
5
+ raiff = Raiff.new
6
+
7
+ assert raiff
8
+ end
9
+
10
+ def test_open_short_sample
11
+ raiff = Raiff.open(sample_file('example-24bit.aiff'))
12
+
13
+ assert raiff
14
+
15
+ assert_equal 23493, raiff.sample_frames
16
+ end
17
+
18
+ def test_failed_open
19
+ raised = false
20
+
21
+ raiff = Raiff.open('does.not.exist')
22
+
23
+ rescue Errno::ENOENT
24
+ raised = true
25
+ ensure
26
+ assert raised
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: raiff
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Scott Tadman
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-06 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Reads in AIFF file data and audio contents
22
+ email: github@tadman.ca
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ files:
30
+ - .document
31
+ - .gitignore
32
+ - README.rdoc
33
+ - Rakefile
34
+ - VERSION
35
+ - lib/raiff.rb
36
+ - lib/raiff/chunk.rb
37
+ - lib/raiff/chunk/common.rb
38
+ - lib/raiff/chunk/data.rb
39
+ - lib/raiff/chunk/form.rb
40
+ - lib/raiff/chunk/sound_data.rb
41
+ - lib/raiff/file.rb
42
+ - raiff.gemspec
43
+ - sample/example-24bit.aiff
44
+ - test/helper.rb
45
+ - test/test_raiff.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/twg/raiff
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.7
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Ruby AIFF Reading Library
78
+ test_files:
79
+ - test/helper.rb
80
+ - test/test_raiff.rb