raiff 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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