riff 0.1

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