riff 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.
@@ -0,0 +1,9 @@
1
+ task :default => [:test , :rdoc]
2
+
3
+ task :test do
4
+ ruby "test/riff_test_suite.rb"
5
+ end
6
+
7
+ task :rdoc do
8
+ system "rdoc"
9
+ end
@@ -0,0 +1,16 @@
1
+ require 'lib/riff/base.rb'
2
+
3
+ def print_chunk(ck,margin = "")
4
+ if ck.is_list? then
5
+ puts margin + "+ '%s' (%s): %i bytes" % [ck.fourcc , ck.signature , ck.length ]
6
+ ck.each_with_index do |k,i|
7
+ print_chunk(k,margin + " " + " ")
8
+ end
9
+ else
10
+ puts margin + "- '%s' : %i bytes" % [ck.fourcc , ck.length ]
11
+ end
12
+ end
13
+
14
+ Riff::Base.open(ARGV[0],"r") do |wav|
15
+ print_chunk( wav.root_chunk )
16
+ end
@@ -0,0 +1,6 @@
1
+ $: << "lib/"
2
+
3
+ require 'riff/bwav.rb'
4
+
5
+ Riff::WaveRiff.open(ARGV[0],"r").close
6
+ puts "This file is a WAV file."
@@ -0,0 +1,285 @@
1
+ #--
2
+ #riff.rb -- API for reading generic Microsoft RIFF Files
3
+ #Copyright (C) 2006 Jamie Hardt
4
+
5
+ #This library is free software; you can redistribute it and/or
6
+ #modify it under the terms of the GNU Lesser General Public
7
+ #License as published by the Free Software Foundation; either
8
+ #version 2.1 of the License, or (at your option) any later version.
9
+
10
+ #This library is distributed in the hope that it will be useful,
11
+ #but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ #Lesser General Public License for more details.
14
+
15
+ #You should have received a copy of the GNU Lesser General Public
16
+ #License along with this library; if not, write to the Free Software
17
+ #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ #++
19
+
20
+
21
+ # This library allows for the reading of RIFF (Resource Interchange File Format)
22
+ # files. Opening a RIFF file with the Riff.open method allows the individual
23
+ # chunks of the file to be accessed through the Riff#root_chunk method, and
24
+ # this object mixes-in Enumerable in order to allow iteration over each chunk
25
+ # and its sub-chunks (when applicable).
26
+ #
27
+ # Author:: Jamie Hardt
28
+ # License:: The Lesser GPL
29
+ #
30
+ # ---
31
+ #
32
+ # = Examples
33
+ # === Getting iXML metadata from a broadcast-WAV file
34
+ #
35
+ # require 'riff/base'
36
+ # Riff::Base.open(ARGV[0],"r") do |wav|
37
+ # xml = wav.root_chunk['ixml'].body
38
+ # end
39
+ #
40
+ # === Listing all the chunks in a file
41
+ # require 'riff/base'
42
+ #
43
+ # def print_chunk(ck,margin = "")
44
+ # if ck.is_list? then
45
+ # puts margin + "+ %s (%s): %i bytes" % \
46
+ # [ck.fourcc , ck.signature , ck.length ]
47
+ # ck.each_with_index do |k,i|
48
+ # print_chunk(k,margin + " ")
49
+ # end
50
+ # else
51
+ # puts margin + "- %s : %i bytes" % [ck.fourcc , ck.length ]
52
+ # end
53
+ # end
54
+ #
55
+ # Riff::Base.open(ARGV[0],"r") do |wav|
56
+ # print_chunk( wav.root_chunk )
57
+ # end
58
+ #
59
+ module Riff
60
+
61
+ module VERSION
62
+ MAJOR = 0
63
+ MINOR = 1
64
+ end #module version
65
+
66
+ class Base
67
+ # The Riff class provides a front-end to the other objects of the library.
68
+ # It's the only object that you interact with directly, and calling its methods
69
+ # will return the other objects of the class.
70
+
71
+ # Returns the File object for this Riff object.
72
+ attr_reader :file
73
+
74
+ # Opens a RIFF file for reading. Pass a string path and string mode, as you would
75
+ # for File::open. A Riff object will be returned.
76
+ # * At this time, only the "r" and "rb" modes are supported, others will raise
77
+ # and ArgumentError
78
+ # * If you provide a block, the Riff object will be yielded to the block as the
79
+ # sole parameter, and will be automatically closed at the end of the block.
80
+ # * If you pass a file which does not start with the RIFF fourcc, the file
81
+ # is invalid and a FileTypeError will be thrown.
82
+ def self.open(path,mode) # :yields: riff_object
83
+ riff_obj = Riff::Base.new(path,mode)
84
+ if block_given? && riff_obj then
85
+ yield riff_obj
86
+ riff_obj.close
87
+ end
88
+ riff_obj
89
+ end
90
+
91
+ # Class method for called by subclasses to set-up validations. If you
92
+ # write a subclass of the Riff object, say for reading AVIs, you can
93
+ # add validation code by calling this class method in your class like so:
94
+ #
95
+ # class RiffAVI
96
+ #
97
+ # validate do |riff|
98
+ # riff.root_chunk.signature == 'AVI '
99
+ # end
100
+ #
101
+ # ... class continues...
102
+ # end
103
+ #
104
+ # You provide a block, which is yielded the Riff object at the time
105
+ # it is created, and ths block should return either +true+ or +false+.
106
+ # If it returns +true+, the Riff subclass instance will be created. If
107
+ # the block returns +false+, the .new class method will return nil.
108
+ #
109
+ # Subclass validation methods are called in the order of the subclasses
110
+ # inheiritance, so that if you wrote a broadcast-wav class that inheirited
111
+ # from a wave class that inheirited from Riff, Riff's validate()
112
+ # would be called first, and then the wave validate(), and the bwav's validate().
113
+ # Thus, a subclass can run its validations with the guarantee that the Riff
114
+ # in question passed its validations for its superclass.
115
+ def self.validate(&block)
116
+ raise ArgumentError unless block.arity == 1
117
+
118
+ end
119
+
120
+ # Returns the Root Chunk of the RIFF file as a ListChunk
121
+ def root_chunk
122
+ @file.rewind
123
+ the_chunk = Chunk.read_chunk(@file)
124
+ end
125
+
126
+ # Closes the Riff object. Subsequent calls to the Riff object or any of its
127
+ # chunk objects will fail.
128
+ def close
129
+ @file.close
130
+ end
131
+
132
+ class FileTypeError < StandardError ; end #:nodoc:
133
+
134
+ protected
135
+
136
+ def valid?
137
+
138
+ end
139
+
140
+ private
141
+
142
+ def initialize(path, mode)
143
+ raise(ArgumentError, "Riff.open only supports mode 'r' or 'rb'.") \
144
+ unless mode == "r" || mode == "rb"
145
+
146
+ @file = File.open(path,mode)
147
+ return nil unless valid?
148
+ end #def initialize
149
+
150
+ end
151
+
152
+
153
+ class Base
154
+
155
+ # The Chunk object represents a chunk of a larger RIFF file. The chunk may be
156
+ # interrogated to reveal its fourcc and the size of its body. The chunk also
157
+ # provides the +body+ method to access the stream of data within the chunk.
158
+ # Keep in mind that this bit of data can be very, very large in media files
159
+ # (like .wav files) and that reading them in a language like ruby will be quite
160
+ # slow.
161
+
162
+ class Chunk
163
+
164
+ # the four-character code of this chunk, always four characters long
165
+ # (shorter fourcc's are padded with spaces)
166
+ attr_reader :fourcc
167
+
168
+ # the length of the body of the chunk (the length of the chunk minus
169
+ # the the fourcc and length bytes; thus the length of the chunk - 8)
170
+ # This data is read directly from the chunk's preamble and calling
171
+ # this is much, much faster than body.size
172
+ attr_reader :length
173
+
174
+ # the offset of this chunk from the start of its file
175
+ attr_reader :offset
176
+
177
+
178
+ def self.read_chunk(fp) #:nodoc:
179
+ code = fp.read(4)
180
+ fp.pos -= 4
181
+ if code == "RIFF" or code == "LIST" then
182
+ ListChunk.new(fp)
183
+ else
184
+ Chunk.new(fp)
185
+ end
186
+ end
187
+
188
+ # Reads the entire body of the chunk (all of the data following the fourcc and size)
189
+ def body
190
+ @file.pos = @offset + 8
191
+ @file.read @length
192
+ end
193
+
194
+ # Returns <tt>true</tt> if this object is a ListChunk. A convenience to typing
195
+ # <tt>instance_of? Riff::ListChunk</tt>
196
+ def is_list?
197
+ instance_of? Riff::Base::ListChunk
198
+ end
199
+
200
+ def each_byte
201
+ while @file.pos < @offset + 8 + @length
202
+ yield @file.getc
203
+ @file.pos +=1
204
+ end
205
+ end
206
+
207
+ protected
208
+
209
+ def Chunk.read_bytes_to_int(file,bytes) # :nodoc:
210
+
211
+ ary = [ ]
212
+ bytes.times { ary << file.getc }
213
+
214
+ result = 0
215
+ ary.each_with_index do |n, i|
216
+ 7.downto(0) do |bit|
217
+ result += 2 ** ((bit) + i * 8) if n[bit] == 1
218
+ end
219
+ end
220
+ return result
221
+ end
222
+
223
+ def initialize(fp) #:nodoc:
224
+ @file = fp
225
+ @offset = @file.pos
226
+ @fourcc = @file.read(4)
227
+ @length = Chunk.read_bytes_to_int(@file,4)
228
+ end
229
+
230
+ end #class Chunk
231
+
232
+ # ListChunk is a subclass of Chunk, and so you can access its fourcc and size
233
+ #
234
+ # <em>Note:</em> The +body+ method is not permitted on ListChunk
235
+ class ListChunk < Chunk
236
+
237
+ include Enumerable
238
+
239
+ # The four-character signature of the container chunk.
240
+ # In the case of a RIFF WAV container, this is "WAVE"
241
+ attr_reader :signature
242
+
243
+ # Accesses the chunks of the file by either a fourcc, an index, or a range.
244
+ # Be aware that ListChunks may contain many children chunk with the same
245
+ # fourcc, so using the index will always get you a paticular one, while
246
+ # using the fourcc will only get you the first of a class.
247
+ def [](chunk_spec) # :return: array or Chunk
248
+ if chunk_spec.instance_of? String then
249
+ detect {|chunk| chunk.fourcc == "%s" % [ chunk_spec ] }
250
+ elsif chunk_spec.instance_of? Fixnum or chunk_spec.instance_of? Range then
251
+ to_a[chunk_spec]
252
+ else
253
+ raise ArgumentError , "ListChunk#[] may only accept a String, Fixnum, or Range"
254
+ end
255
+ end
256
+
257
+ # Yields each chunk in the order it appears in the file
258
+ def each # :yields: chunk
259
+ @file.pos = @offset + 12
260
+ while @file.eof? == false && @file.pos < @offset + 8 + @length
261
+ a_chunk = Chunk.read_chunk(@file)
262
+ yield a_chunk
263
+ @file.pos = a_chunk.offset + 8 + a_chunk.length + (a_chunk.length % 2 == 0 ? 0 : 1)
264
+ end
265
+ end
266
+
267
+ def body # :nodoc:
268
+ raise NoMethodError , "ListChunk#body is not permitted!"
269
+ end
270
+
271
+ def each_byte
272
+ raise NoMethodError
273
+ end
274
+
275
+ protected
276
+
277
+ def initialize(fp)
278
+ super(fp)
279
+ @signature = @file.read(4)
280
+ end
281
+
282
+ end #class ListChunk
283
+ end #class Riff
284
+
285
+ end #module
@@ -0,0 +1,8 @@
1
+ require 'riff/wav'
2
+
3
+ module Riff
4
+ class BroadcastWave < WaveRiff
5
+
6
+
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'riff/base'
2
+
3
+ module Riff
4
+ class WaveRiff < Riff::Base
5
+
6
+
7
+ end
8
+ end
@@ -0,0 +1,130 @@
1
+ #--
2
+ #riff_test.rb -- Test suite for riff.rb -- API for reading generic Microsoft RIFF Files
3
+ #Copyright (C) 2006 Jamie Hardt
4
+
5
+ #This library is free software; you can redistribute it and/or
6
+ #modify it under the terms of the GNU Lesser General Public
7
+ #License as published by the Free Software Foundation; either
8
+ #version 2.1 of the License, or (at your option) any later version.
9
+
10
+ #This library is distributed in the hope that it will be useful,
11
+ #but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ #Lesser General Public License for more details.
14
+
15
+ #You should have received a copy of the GNU Lesser General Public
16
+ #License along with this library; if not, write to the Free Software
17
+ #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ #++
19
+
20
+ require 'test/unit'
21
+ require 'lib/riff/base'
22
+
23
+ class Riff_Test < Test::Unit::TestCase
24
+
25
+ def setup
26
+ @test_media_basepath = "test_media/"
27
+ @test_media = [ ]
28
+
29
+ @enumerable_file = "Pop.wav"
30
+ @malformed_file = "bad.riff"
31
+ @test_media << @enumerable_file
32
+
33
+ @riff_obj_array = []
34
+
35
+ end
36
+
37
+ def test_open_close
38
+
39
+ @test_media.each do |file|
40
+ @riff_obj_array << Riff::Base.open(@test_media_basepath + file ,"r")
41
+ end
42
+
43
+ @riff_obj_array.each do |r|
44
+ assert_instance_of File , r.file
45
+ r.close
46
+ end
47
+ end
48
+
49
+ def test_root
50
+
51
+ @test_media.each do |file|
52
+ Riff::Base.open(@test_media_basepath + file,"r") do |riff|
53
+ root_chunk = riff.root_chunk
54
+
55
+ assert_equal root_chunk.fourcc , "RIFF"
56
+ assert_equal root_chunk.signature , "WAVE"
57
+ assert_instance_of Riff::Base::ListChunk , root_chunk
58
+ end
59
+ end
60
+ end
61
+
62
+ def test_hashing
63
+ Riff::Base.open(@test_media_basepath + @enumerable_file,"r") do |riff|
64
+ assert_instance_of Riff::Base::Chunk , riff.root_chunk['bext']
65
+ assert_instance_of Riff::Base::Chunk , riff.root_chunk['fmt ']
66
+ assert_equal riff.root_chunk[0].fourcc , 'bext'
67
+ assert_equal riff.root_chunk[0..1].collect {|c|c.fourcc} , ['bext','fmt ']
68
+ end
69
+ end
70
+
71
+ def test_riff_validation
72
+
73
+
74
+ end
75
+
76
+ def test_simple_read
77
+ Riff::Base.open(@test_media_basepath + @enumerable_file,"r") do |riff|
78
+ assert_equal riff.root_chunk.length , 8272
79
+ end
80
+ end
81
+
82
+ def test_each_byte
83
+ Riff::Base.open(@test_media_basepath + @enumerable_file,"r") do |riff|
84
+ riff.root_chunk['fmt '].each_byte do |b|
85
+ assert b >= 0 and b <= 255
86
+ end
87
+ end
88
+ end
89
+
90
+ def test_is_list
91
+ Riff::Base.open(@test_media_basepath + @enumerable_file, 'r') do |r|
92
+ assert r.root_chunk.is_list?
93
+ assert_equal r.root_chunk['bext'].is_list? , false
94
+ end
95
+ end
96
+
97
+ def test_riff_enumerable
98
+ Riff::Base.open(@test_media_basepath + @enumerable_file, 'r') do |r|
99
+
100
+ count = 0
101
+ r.root_chunk.each_with_index do |chunk, i|
102
+ count +=1
103
+ case i
104
+ when 0; assert_equal chunk.fourcc , 'bext'
105
+ when 1; assert_equal chunk.fourcc , 'fmt '
106
+ when 2; assert_equal chunk.fourcc , 'minf'
107
+ when 3; assert_equal chunk.fourcc , 'elm1'
108
+ when 4; assert_equal chunk.fourcc , 'data'
109
+ when 5; assert_equal chunk.fourcc , 'regn'
110
+ when 6; assert_equal chunk.fourcc , 'ovwf'
111
+ when 7; assert_equal chunk.fourcc , 'umid'
112
+ when 8; assert(false,"Read too many chunks!")
113
+ end
114
+ end
115
+ assert_equal count , 8
116
+
117
+ lengths = r.root_chunk.collect {|c| c.length }
118
+
119
+ assert_equal lengths , [ 602 , 16 , 16 , 3410 , 4000 , 92 , 44 , 24]
120
+
121
+ assert_equal r.root_chunk.inject(0) {|i , c| c.length + i} , 8204
122
+ end
123
+ end
124
+
125
+
126
+ def teardown
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,4 @@
1
+ require 'test/unit'
2
+
3
+ require 'test/riff_test.rb'
4
+ require 'test/wav_test.rb'
@@ -0,0 +1,44 @@
1
+ #--
2
+ #wav_test.rb -- Test suite for riff/wav
3
+ # .rb -- API for reading generic Microsoft RIFF Files
4
+ #Copyright (C) 2006 Jamie Hardt
5
+
6
+ #This library is free software; you can redistribute it and/or
7
+ #modify it under the terms of the GNU Lesser General Public
8
+ #License as published by the Free Software Foundation; either
9
+ #version 2.1 of the License, or (at your option) any later version.
10
+
11
+ #This library is distributed in the hope that it will be useful,
12
+ #but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ #Lesser General Public License for more details.
15
+
16
+ #You should have received a copy of the GNU Lesser General Public
17
+ #License along with this library; if not, write to the Free Software
18
+ #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ $: << 'lib/'
22
+
23
+ require 'test/unit'
24
+ require 'lib/riff/wav.rb'
25
+
26
+ class Wav_Test < Test::Unit::TestCase
27
+
28
+ def setup
29
+ @test_wav = "Pop.wav"
30
+ @test_path = "test_media/"
31
+ @bad_wav = "bad.riff"
32
+ end
33
+
34
+ def teardown
35
+
36
+ end
37
+
38
+ def test_validation
39
+
40
+
41
+ end
42
+
43
+
44
+ end
Binary file
@@ -0,0 +1 @@
1
+ RIHS 82 eouorf 2u3hro 23
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: riff
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2006-06-03 00:00:00 -07:00
8
+ summary: "Library for accessing chunks of RIFF (Resource Interchange File Format) files.
9
+ RIFF is a meta-format which is a common wrapper for multimedia files, such as
10
+ .wav and .avi files."
11
+ require_paths:
12
+ - lib
13
+ email:
14
+ homepage: http://riff.rubyforge.org
15
+ rubyforge_project: riff
16
+ description:
17
+ autorequire:
18
+ default_executable:
19
+ bindir: bin
20
+ has_rdoc: true
21
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
22
+ requirements:
23
+ -
24
+ - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.8.2
27
+ version:
28
+ platform: ruby
29
+ signing_key:
30
+ cert_chain:
31
+ authors: []
32
+ files:
33
+ - lib/riff/base.rb
34
+ - lib/riff/bwav.rb
35
+ - lib/riff/wav.rb
36
+ - Rakefile
37
+ - test/riff_test.rb
38
+ - test/riff_test_suite.rb
39
+ - test/wav_test.rb
40
+ - test_media/bad.riff
41
+ - test_media/Pop.wav
42
+ - examples/example1.rb
43
+ - examples/example2.rb
44
+ test_files:
45
+ - test/riff_test_suite.rb
46
+ rdoc_options: []
47
+ extra_rdoc_files: []
48
+ executables: []
49
+ extensions: []
50
+ requirements: []
51
+ dependencies: []