riff 0.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -1
- data/examples/readchunks.rb +32 -3
- data/lib/riff/info.rb +52 -10
- data/lib/riff/reader.rb +36 -55
- data/lib/riff/util.rb +46 -0
- data/lib/riff/writer.rb +83 -18
- data/test/builder_test.rb +67 -0
- data/test/riff_test.rb +19 -11
- data/test/riff_test_suite.rb +3 -0
- data/test/wav_test.rb +24 -24
- metadata +45 -34
data/Rakefile
CHANGED
data/examples/readchunks.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'lib/riff/reader.rb'
|
2
|
+
require 'optparse'
|
2
3
|
|
3
4
|
def print_chunk(ck,margin = "")
|
4
5
|
if ck.is_list? then
|
@@ -11,6 +12,34 @@ def print_chunk(ck,margin = "")
|
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
@chunk = nil
|
16
|
+
cl_options = OptionParser.new do |ops|
|
17
|
+
ops.on('-c CHUNK','--chunk CHUNK','Output the first first-tier chunk with fourcc',
|
18
|
+
'CHUNK to stdout') do |chk|
|
19
|
+
@chunk = chk
|
20
|
+
end
|
21
|
+
ops.on('-h','-?','--help','Print this Message') do
|
22
|
+
puts ops
|
23
|
+
exit 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
rest = cl_options.parse!
|
28
|
+
|
29
|
+
rest.each do |path|
|
30
|
+
if @chunk
|
31
|
+
Riff::Reader.open(path,"r") do |wav|
|
32
|
+
wav.root_chunk.each do |a_chunk|
|
33
|
+
if a_chunk.fourcc == @chunk
|
34
|
+
$stdout.print a_chunk.body
|
35
|
+
exit 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
else
|
41
|
+
Riff::Reader.open(path,"r") do |wav|
|
42
|
+
print_chunk( wav.root_chunk )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # rest.each
|
data/lib/riff/info.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#--
|
2
|
+
#riff.rb -- Library for reading generic Microsoft RIFF Files
|
3
|
+
#Copyright (C) 2009 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 'riff/reader.rb'
|
21
|
+
require 'riff/writer.rb'
|
3
22
|
|
4
23
|
module Riff
|
5
24
|
|
@@ -15,6 +34,10 @@ module Riff
|
|
15
34
|
# editor['IART'] = "Me Myself"
|
16
35
|
#
|
17
36
|
# Note that some names map to the same fourcc.
|
37
|
+
#
|
38
|
+
# Also note that RIFF INFO datums are generally encoded using ISO-8859-1 WinANSI.
|
39
|
+
# We expect to be able to support this more fully with Ruby 1.9 and its integrated
|
40
|
+
# text encoding facilities.
|
18
41
|
class MetaEditor
|
19
42
|
|
20
43
|
# the path to the file being edited
|
@@ -62,6 +85,7 @@ module Riff
|
|
62
85
|
ATTRIBUTE_FOURCCs.each do |key|
|
63
86
|
class_eval <<-TXT
|
64
87
|
def #{key.downcase}=(val)
|
88
|
+
@dirty = true
|
65
89
|
@metadata['#{key}'] = val
|
66
90
|
end
|
67
91
|
def #{key.downcase}
|
@@ -73,6 +97,7 @@ module Riff
|
|
73
97
|
ATTRIBUTE_NAMES.each_pair do |key,value|
|
74
98
|
class_eval <<-TXT
|
75
99
|
def #{key.downcase.gsub(/ /,'_').gsub(/[^a-z_]/,'')}=(val)
|
100
|
+
@dirty = true
|
76
101
|
@metadata['#{value}'] = val
|
77
102
|
end
|
78
103
|
|
@@ -98,30 +123,43 @@ module Riff
|
|
98
123
|
end
|
99
124
|
|
100
125
|
# Creates a MetaEditor object for the file locates at +path+
|
101
|
-
|
126
|
+
#
|
127
|
+
# If you provide a block, the MetaEditor itself will be yielded, and
|
128
|
+
# a +save!+ will be called upon the block closing.
|
129
|
+
def initialize(path) #:yields: self
|
102
130
|
reader = Reader.open(path,'r')
|
103
131
|
@pad_out = 1024
|
104
132
|
@path = path
|
105
133
|
@metadata = {}
|
134
|
+
@dirty = false
|
106
135
|
infoChunk = reader.root_chunk.find {|c| c.signature == 'INFO'}
|
107
136
|
if infoChunk && infoChunk.is_list?
|
108
137
|
infoChunk.each do |subChunk|
|
109
138
|
@metadata[subChunk.fourcc] = subChunk.body
|
110
139
|
end
|
111
140
|
end
|
141
|
+
if block_given?
|
142
|
+
yield self
|
143
|
+
save!
|
144
|
+
end
|
145
|
+
self
|
112
146
|
end
|
113
147
|
|
114
|
-
|
115
|
-
|
148
|
+
# Get a metadatum by +fourcc+
|
149
|
+
def [](fourcc)
|
150
|
+
return @metadata[fourcc]
|
116
151
|
end
|
117
152
|
|
118
|
-
|
119
|
-
|
153
|
+
# Set a metadatum by +fourcc+
|
154
|
+
def []=(fourcc,value)
|
155
|
+
@dirty = true
|
156
|
+
@metadata[fourcc] = value
|
120
157
|
end
|
121
158
|
|
159
|
+
# Yields each metadatum
|
122
160
|
def each_metadatum
|
123
|
-
@metadata.each_pair do |
|
124
|
-
yield
|
161
|
+
@metadata.each_pair do |fourcc,value|
|
162
|
+
yield fourcc,value
|
125
163
|
end
|
126
164
|
end
|
127
165
|
|
@@ -130,8 +168,12 @@ module Riff
|
|
130
168
|
#
|
131
169
|
# If a pad_out number is specified, a "JUNK" chunk with a payload of pad_out
|
132
170
|
# bytes will be added after the INFO chunk.
|
171
|
+
#
|
172
|
+
# If you have not modified any metadatums of the file, this method will have no
|
173
|
+
# effect on the system.
|
133
174
|
def save!
|
134
|
-
|
175
|
+
return unless @dirty
|
176
|
+
tempPath = File.dirname(path) + "/" + (([?a] *16).map {|i| (i + rand(26)).chr}).join + ".tmp"
|
135
177
|
Reader.open(path,'r') do |reader|
|
136
178
|
begin
|
137
179
|
Builder.create(tempPath,reader.root_chunk.signature) do |riffwriter|
|
data/lib/riff/reader.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#--
|
2
|
-
#riff.rb --
|
3
|
-
#Copyright (C)
|
2
|
+
#riff.rb -- Library for reading generic Microsoft RIFF Files
|
3
|
+
#Copyright (C) 2009 Jamie Hardt
|
4
4
|
|
5
5
|
#This library is free software; you can redistribute it and/or
|
6
6
|
#modify it under the terms of the GNU Lesser General Public
|
@@ -32,7 +32,7 @@
|
|
32
32
|
# = Examples
|
33
33
|
# === Getting iXML metadata from a broadcast-WAV file
|
34
34
|
#
|
35
|
-
# require 'riff/
|
35
|
+
# require 'riff/reader'
|
36
36
|
# Riff::Reader.open(ARGV[0],"r") do |wav|
|
37
37
|
# xml = wav.root_chunk['ixml'].body
|
38
38
|
# end
|
@@ -56,60 +56,55 @@
|
|
56
56
|
# print_chunk( wav.root_chunk )
|
57
57
|
# end
|
58
58
|
#
|
59
|
+
|
60
|
+
require 'libc/riff/riff.bundle'
|
61
|
+
#require 'riff/util'
|
62
|
+
|
59
63
|
module Riff
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end #module version
|
65
|
-
|
64
|
+
|
65
|
+
# The Reader class provides a front-end to the other objects of the library.
|
66
|
+
# It's the only object that you interact with directly, and calling its methods
|
67
|
+
# will return the other objects of the class.
|
66
68
|
class Reader
|
67
|
-
# The Reader 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
69
|
|
71
70
|
# Returns the File object for this reader.
|
72
|
-
|
71
|
+
# attr_reader :file
|
73
72
|
|
74
73
|
# Opens a RIFF file for reading. Pass a string path and string mode, as you would
|
75
74
|
# 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
75
|
# * If you provide a block, the Riff object will be yielded to the block as the
|
79
76
|
# sole parameter, and will be automatically closed at the end of the block.
|
80
77
|
# * If you pass a file which does not start with the RIFF fourcc, the file
|
81
78
|
# is invalid and a FileTypeError will be thrown.
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
riff_obj
|
87
|
-
|
88
|
-
|
89
|
-
|
79
|
+
# * _mode_ is ignored and will be removed in a future version
|
80
|
+
# def Reader.open(path,mode = nil) # :yields: riff_object
|
81
|
+
# riff_obj = Riff::Reader.new(path)
|
82
|
+
# if block_given? && riff_obj then
|
83
|
+
# yield riff_obj
|
84
|
+
# riff_obj.close
|
85
|
+
# end
|
86
|
+
# riff_obj
|
87
|
+
# end
|
90
88
|
|
91
89
|
# Returns the Root Chunk of the RIFF file as a ListChunk
|
92
|
-
def root_chunk
|
93
|
-
@file.rewind
|
94
|
-
the_chunk = Chunk.read_chunk(@file)
|
95
|
-
end
|
90
|
+
# def root_chunk
|
91
|
+
# @file.rewind
|
92
|
+
# the_chunk = Chunk.read_chunk(@file)
|
93
|
+
# end
|
96
94
|
|
97
95
|
# Closes the Riff object. Subsequent calls to the Riff object or any of its
|
98
96
|
# chunk objects will fail.
|
99
|
-
def close
|
100
|
-
@file.close
|
101
|
-
end
|
97
|
+
# def close
|
98
|
+
# @file.close
|
99
|
+
# end
|
102
100
|
|
103
|
-
|
101
|
+
# class FileTypeError < StandardError ; end #:nodoc:
|
104
102
|
|
105
|
-
private
|
106
|
-
|
107
|
-
def initialize(path
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
@file = File.open(path,mode)
|
112
|
-
end #def initialize
|
103
|
+
# private
|
104
|
+
#
|
105
|
+
# def initialize(path) #:nodoc:
|
106
|
+
# @file = File.open(path)
|
107
|
+
# end #def initialize
|
113
108
|
|
114
109
|
end
|
115
110
|
|
@@ -169,25 +164,11 @@ module Riff
|
|
169
164
|
|
170
165
|
protected
|
171
166
|
|
172
|
-
def Chunk.read_bytes_to_int(file,bytes) # :nodoc:
|
173
|
-
|
174
|
-
ary = [ ]
|
175
|
-
bytes.times { ary << file.getc }
|
176
|
-
|
177
|
-
result = 0
|
178
|
-
ary.each_with_index do |n, i|
|
179
|
-
7.downto(0) do |bit|
|
180
|
-
result += 2 ** ((bit) + i * 8) if n[bit] == 1
|
181
|
-
end
|
182
|
-
end
|
183
|
-
return result
|
184
|
-
end
|
185
|
-
|
186
167
|
def initialize(fp) #:nodoc:
|
187
168
|
@file = fp
|
188
169
|
@offset = @file.pos
|
189
170
|
@fourcc = @file.read(4)
|
190
|
-
@length =
|
171
|
+
@length = Util.read_bytes_to_int(@file,4)
|
191
172
|
end
|
192
173
|
|
193
174
|
end #class Chunk
|
@@ -195,7 +176,7 @@ module Riff
|
|
195
176
|
# ListChunk is a subclass of Chunk, and so you can access its fourcc and size
|
196
177
|
#
|
197
178
|
# <em>Note:</em> The +body+ method is not permitted on ListChunk
|
198
|
-
class ListChunk
|
179
|
+
class ListChunk #< Chunk
|
199
180
|
|
200
181
|
include Enumerable
|
201
182
|
|
data/lib/riff/util.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'libc/riff/riff.bundle'
|
2
|
+
|
3
|
+
module Riff
|
4
|
+
|
5
|
+
# module VERSION
|
6
|
+
# MAJOR = 0
|
7
|
+
# MINOR = 4
|
8
|
+
# end #module version
|
9
|
+
|
10
|
+
# The Util module contains various methods
|
11
|
+
module Util
|
12
|
+
|
13
|
+
# Reads +bytes+ bytes from file and converts the bytes into an unsigned int, assuming that
|
14
|
+
# the bytes are little-endian
|
15
|
+
# def self.read_bytes_to_int(file,bytes)
|
16
|
+
# ary = [ ]
|
17
|
+
# bytes.times { ary << file.getc }
|
18
|
+
#
|
19
|
+
# result = 0
|
20
|
+
# ary.each_with_index do |n, i|
|
21
|
+
# 7.downto(0) do |bit|
|
22
|
+
# result += 2 ** ((bit) + i * 8) if n[bit] == 1
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# return result
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def self.int_to_four_little_endian_bytes(i)
|
29
|
+
# n = [ i.abs , 2 ** 32 ].min
|
30
|
+
# [(n.to_i & 0xff) , (n.to_i & 0xff00)>>8,
|
31
|
+
# (n.to_i & 0xff0000)>>16,(n.to_i & 0xff000000)>>24 ]
|
32
|
+
# end
|
33
|
+
|
34
|
+
# def self.int_to_four_big_endian_bytes(i)
|
35
|
+
# return int_to_four_little_endian_bytes(i).reverse
|
36
|
+
# end
|
37
|
+
|
38
|
+
|
39
|
+
# def self.sanitize_fourcc(fourcc)
|
40
|
+
# fourcc[0,4].ljust(4,"\0")
|
41
|
+
# end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/riff/writer.rb
CHANGED
@@ -1,9 +1,80 @@
|
|
1
|
+
#--
|
2
|
+
#riff.rb -- Library for reading generic Microsoft RIFF Files
|
3
|
+
#Copyright (C) 2009 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
|
+
|
1
20
|
require 'stringio'
|
21
|
+
require 'riff/util.rb'
|
2
22
|
|
3
23
|
module Riff
|
4
24
|
|
5
25
|
# A Builder allows you to create a 'de novo' RIFF file recursively, similar
|
6
|
-
# in style to the XML Builder class.
|
26
|
+
# in style to the XML Builder class. The client uses +Builder.create+
|
27
|
+
# to create an empty file at a given filesystem location, and yields a block,
|
28
|
+
# allowing the client to construct chunks and LISTs semantically with Ruby
|
29
|
+
# blocks.
|
30
|
+
#
|
31
|
+
# In the following example, a new .wav file is created containing 1 second
|
32
|
+
# of 1 K tone and descriptive metadata.
|
33
|
+
#
|
34
|
+
## require 'lib/riff/reader.rb'
|
35
|
+
## require 'lib/riff/writer.rb'
|
36
|
+
##
|
37
|
+
## include Riff
|
38
|
+
## SAMPLES_PER_SECOND = 48000
|
39
|
+
## FREQ = 1000
|
40
|
+
## AMPLITUDE = 0x0fff
|
41
|
+
##
|
42
|
+
## Builder.create(ARGV[0],"WAVE") do |w|
|
43
|
+
## w.list("INFO") { |info|
|
44
|
+
## info.chunk("ICOP") {|c| # "copyright"
|
45
|
+
## c << "(c) 2007 Joe User.
|
46
|
+
## }
|
47
|
+
## info.chunk("INAM") {|c| # "name" or "title"
|
48
|
+
## c << "1K tone with metadata"
|
49
|
+
## }
|
50
|
+
## info.chunk("ISFT") {|c| # "software"
|
51
|
+
## c << "libRiff v" + "%i.%i" % [Riff::VERSION::MAJOR, Riff::VERSION::MINOR]
|
52
|
+
## }
|
53
|
+
## info.chunk("IART") {|c| # "artist" (maps to kMDItemAuthors in Spotlight)
|
54
|
+
## c << "Joe User"
|
55
|
+
## }
|
56
|
+
## }
|
57
|
+
## w.chunk("fmt ") { |c|
|
58
|
+
## c.putc(1);c.putc(0) #format 1, PCM
|
59
|
+
## c.putc(1);c.putc(0) #1 channel
|
60
|
+
##
|
61
|
+
## # samples per second
|
62
|
+
## Builder.int_to_four_little_endian_bytes(SAMPLES_PER_SECOND).each {|byte| c.putc(byte)}
|
63
|
+
##
|
64
|
+
## # avg. bytes per second
|
65
|
+
## Builder.int_to_four_little_endian_bytes(SAMPLES_PER_SECOND * 2).each {|byte| c.putc(byte)}
|
66
|
+
## c.putc(2);c.putc(0) #block alignment 2
|
67
|
+
## c.putc(16);c.putc(0) #16 bits per sample
|
68
|
+
## }
|
69
|
+
## w.chunk("data") { |c|
|
70
|
+
## factor = Math::PI / (SAMPLES_PER_SECOND / (FREQ * 2))
|
71
|
+
## 1.upto(SAMPLES_PER_SECOND) do |i|
|
72
|
+
## val = ( Math::sin( i * factor ) * AMPLITUDE ).floor
|
73
|
+
## Builder::int_to_four_little_endian_bytes(val)[0,2].each {|byte| c.putc(byte)}
|
74
|
+
## end
|
75
|
+
## }
|
76
|
+
## end
|
77
|
+
|
7
78
|
class Builder
|
8
79
|
|
9
80
|
class IOProxy #:nodoc:
|
@@ -36,8 +107,12 @@ module Riff
|
|
36
107
|
end #class IOProxy
|
37
108
|
|
38
109
|
class << self
|
39
|
-
# Create a new RIFF file at +path+, using +type+ for the top-level
|
40
|
-
|
110
|
+
# Create a new RIFF file at +path+, using +type+ for the top-level
|
111
|
+
# chunk's type or signature.
|
112
|
+
#
|
113
|
+
# At this time, you must provide a block to this method to add chunks.
|
114
|
+
def create(path,type) #:yields: builder
|
115
|
+
raise RuntimeError unless block_given?
|
41
116
|
file = File.open(path,"w")
|
42
117
|
w = Builder.new(file)
|
43
118
|
w.container('RIFF',type) do |body_io|
|
@@ -46,16 +121,6 @@ module Riff
|
|
46
121
|
file.close
|
47
122
|
end
|
48
123
|
|
49
|
-
def int_to_four_little_endian_bytes(i) #:nodoc:
|
50
|
-
n =i # [ i.abs , 2^32 ].min
|
51
|
-
[(n.to_i & 0xff) , (n.to_i & 0xff00)>>8,
|
52
|
-
(n.to_i & 0xff0000)>>16,(n.to_i & 0xff000000)>>24 ]
|
53
|
-
end
|
54
|
-
|
55
|
-
def sanitize_fourcc(fourcc) #:nodoc:
|
56
|
-
fourcc[0,4].ljust(4,"\0")
|
57
|
-
end
|
58
|
-
|
59
124
|
end #class << self
|
60
125
|
|
61
126
|
# Add a data chunk to the Builder. The method yields a write-only pseudo-IO
|
@@ -63,14 +128,14 @@ module Riff
|
|
63
128
|
# here; the fourcc and size will be written for you. Do not pad the data you write to
|
64
129
|
# an even boundary, either.
|
65
130
|
def chunk(fourcc) #:yields: stream
|
66
|
-
@io.write(
|
67
|
-
4.times {@io.putc(0)}
|
131
|
+
@io.write( Util::sanitize_fourcc(fourcc) )
|
132
|
+
4.times { @io.putc(0) }
|
68
133
|
oldPos = @io.pos
|
69
134
|
yield IOProxy.new(@io)
|
70
135
|
length = @io.pos - oldPos
|
71
136
|
@io.putc(0) if (length % 2) == 1
|
72
137
|
@io.seek(oldPos-4,IO::SEEK_SET)
|
73
|
-
bytes =
|
138
|
+
bytes = Util::int_to_four_little_endian_bytes(length)
|
74
139
|
bytes.each {|byte| @io.putc(byte)}
|
75
140
|
@io.seek(0,IO::SEEK_END)
|
76
141
|
end
|
@@ -88,8 +153,8 @@ module Riff
|
|
88
153
|
end
|
89
154
|
|
90
155
|
def container(fourcc,type) # :nodoc:
|
91
|
-
chunk(
|
92
|
-
io.write(
|
156
|
+
chunk(Util::sanitize_fourcc(fourcc)) do |io|
|
157
|
+
io.write(Util::sanitize_fourcc(type))
|
93
158
|
yield io
|
94
159
|
end
|
95
160
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'riff/writer'
|
4
|
+
|
5
|
+
class RiffBuilder_Test < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Riff::Builder.create("testfile.wav","WAVE") do |w|
|
9
|
+
w.list("INFO") { |info|
|
10
|
+
info.chunk("ICOP") {|c| # "copyright"
|
11
|
+
c << "00000000."
|
12
|
+
}
|
13
|
+
}
|
14
|
+
w.chunk("JUNK") { |c|
|
15
|
+
c << "00000000"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
%x{rm testfile.wav}
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_file_made
|
26
|
+
assert(File.exist?("testfile.wav"))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_length
|
30
|
+
assert_equal(58, File.stat("testfile.wav").size)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_file_fourcc
|
34
|
+
sig = IO.read("testfile.wav",4,0)
|
35
|
+
assert_equal("RIFF",sig)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_riff_chunk_size
|
39
|
+
File.open("testfile.wav",'r') do |f|
|
40
|
+
f.read(4);
|
41
|
+
assert_equal(50, Riff::Util::read_bytes_to_int(f,4) )
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_icop_chunk
|
46
|
+
File.open("testfile.wav",'r') do |f|
|
47
|
+
f.read(24);
|
48
|
+
assert_equal('ICOP',f.read(4))
|
49
|
+
assert_equal(9, Riff::Util::read_bytes_to_int(f,4) )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_info_chunk
|
54
|
+
File.open("testfile.wav",'r') do |f|
|
55
|
+
f.read(12);
|
56
|
+
assert_equal('LIST',f.read(4))
|
57
|
+
assert_equal(22, Riff::Util::read_bytes_to_int(f,4) )
|
58
|
+
assert_equal('INFO',f.read(4))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_file_sig
|
63
|
+
sig = IO.read("testfile.wav",4,8)
|
64
|
+
assert_equal("WAVE",sig)
|
65
|
+
end
|
66
|
+
|
67
|
+
end #class
|
data/test/riff_test.rb
CHANGED
@@ -18,7 +18,8 @@
|
|
18
18
|
#++
|
19
19
|
|
20
20
|
require 'test/unit'
|
21
|
-
|
21
|
+
|
22
|
+
require 'riff/reader'
|
22
23
|
|
23
24
|
class Riff_Test < Test::Unit::TestCase
|
24
25
|
|
@@ -37,7 +38,7 @@ class Riff_Test < Test::Unit::TestCase
|
|
37
38
|
def test_open_close
|
38
39
|
|
39
40
|
@test_media.each do |file|
|
40
|
-
@riff_obj_array << Riff::
|
41
|
+
@riff_obj_array << Riff::Reader.open(@test_media_basepath + file ,"r")
|
41
42
|
end
|
42
43
|
|
43
44
|
@riff_obj_array.each do |r|
|
@@ -46,23 +47,30 @@ class Riff_Test < Test::Unit::TestCase
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
50
|
+
def test_file_accessor
|
51
|
+
@test_media.each do |file|
|
52
|
+
r = Riff::Reader.open(@test_media_basepath + file , "r")
|
53
|
+
assert(r.file,"file accessor failed")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
49
57
|
def test_root
|
50
58
|
|
51
59
|
@test_media.each do |file|
|
52
|
-
Riff::
|
60
|
+
Riff::Reader.open(@test_media_basepath + file,"r") do |riff|
|
53
61
|
root_chunk = riff.root_chunk
|
54
62
|
|
55
63
|
assert_equal root_chunk.fourcc , "RIFF"
|
56
64
|
assert_equal root_chunk.signature , "WAVE"
|
57
|
-
assert_instance_of Riff::
|
65
|
+
assert_instance_of Riff::Reader::ListChunk , root_chunk
|
58
66
|
end
|
59
67
|
end
|
60
68
|
end
|
61
69
|
|
62
70
|
def test_hashing
|
63
|
-
Riff::
|
64
|
-
assert_instance_of Riff::
|
65
|
-
assert_instance_of Riff::
|
71
|
+
Riff::Reader.open(@test_media_basepath + @enumerable_file,"r") do |riff|
|
72
|
+
assert_instance_of Riff::Reader::Chunk , riff.root_chunk['bext']
|
73
|
+
assert_instance_of Riff::Reader::Chunk , riff.root_chunk['fmt ']
|
66
74
|
assert_equal riff.root_chunk[0].fourcc , 'bext'
|
67
75
|
assert_equal riff.root_chunk[0..1].collect {|c|c.fourcc} , ['bext','fmt ']
|
68
76
|
end
|
@@ -74,13 +82,13 @@ class Riff_Test < Test::Unit::TestCase
|
|
74
82
|
end
|
75
83
|
|
76
84
|
def test_simple_read
|
77
|
-
Riff::
|
85
|
+
Riff::Reader.open(@test_media_basepath + @enumerable_file,"r") do |riff|
|
78
86
|
assert_equal riff.root_chunk.length , 8272
|
79
87
|
end
|
80
88
|
end
|
81
89
|
|
82
90
|
def test_each_byte
|
83
|
-
Riff::
|
91
|
+
Riff::Reader.open(@test_media_basepath + @enumerable_file,"r") do |riff|
|
84
92
|
riff.root_chunk['fmt '].each_byte do |b|
|
85
93
|
assert b >= 0 and b <= 255
|
86
94
|
end
|
@@ -88,14 +96,14 @@ class Riff_Test < Test::Unit::TestCase
|
|
88
96
|
end
|
89
97
|
|
90
98
|
def test_is_list
|
91
|
-
Riff::
|
99
|
+
Riff::Reader.open(@test_media_basepath + @enumerable_file, 'r') do |r|
|
92
100
|
assert r.root_chunk.is_list?
|
93
101
|
assert_equal r.root_chunk['bext'].is_list? , false
|
94
102
|
end
|
95
103
|
end
|
96
104
|
|
97
105
|
def test_riff_enumerable
|
98
|
-
Riff::
|
106
|
+
Riff::Reader.open(@test_media_basepath + @enumerable_file, 'r') do |r|
|
99
107
|
|
100
108
|
count = 0
|
101
109
|
r.root_chunk.each_with_index do |chunk, i|
|
data/test/riff_test_suite.rb
CHANGED
data/test/wav_test.rb
CHANGED
@@ -18,27 +18,27 @@
|
|
18
18
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
19
19
|
#++
|
20
20
|
|
21
|
-
|
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
|
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
|
metadata
CHANGED
@@ -1,38 +1,33 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.1
|
3
|
-
specification_version: 1
|
4
2
|
name: riff
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version:
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
- lib
|
11
|
-
email:
|
12
|
-
homepage: http://riff.rubyforge.org
|
13
|
-
rubyforge_project: riff
|
14
|
-
description:
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jamie Hardt
|
15
8
|
autorequire:
|
16
|
-
default_executable:
|
17
9
|
bindir: bin
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-22 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: jhardt@soundepartment.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
30
23
|
|
31
24
|
files:
|
32
25
|
- lib/riff/info.rb
|
33
26
|
- lib/riff/reader.rb
|
27
|
+
- lib/riff/util.rb
|
34
28
|
- lib/riff/writer.rb
|
35
29
|
- Rakefile
|
30
|
+
- test/builder_test.rb
|
36
31
|
- test/riff_test.rb
|
37
32
|
- test/riff_test_suite.rb
|
38
33
|
- test/wav_test.rb
|
@@ -41,17 +36,33 @@ files:
|
|
41
36
|
- examples/maketone.rb
|
42
37
|
- examples/metariff.rb
|
43
38
|
- examples/readchunks.rb
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
extra_rdoc_files: []
|
49
|
-
|
50
|
-
executables: []
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://riff.rubyforge.org
|
41
|
+
licenses: []
|
51
42
|
|
52
|
-
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
53
45
|
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.8.2
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
54
60
|
requirements: []
|
55
61
|
|
56
|
-
|
57
|
-
|
62
|
+
rubyforge_project: riff
|
63
|
+
rubygems_version: 1.3.5
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Library for reading and writing RIFF (Resource Interchange File Format) files. RIFF is a meta-format which is a common wrapper for multimedia files, such as .wav and .avi files. Classes for reading and writing generic RIFF files are provided, as well as convenient INFO tag editing.
|
67
|
+
test_files:
|
68
|
+
- test/riff_test_suite.rb
|