riff 0.2 → 0.3
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/examples/maketone.rb +70 -16
- data/examples/metariff.rb +15 -0
- data/examples/readchunks.rb +2 -2
- data/lib/riff/info.rb +162 -0
- data/lib/riff/{base.rb → reader.rb} +15 -30
- data/lib/riff/writer.rb +26 -25
- metadata +6 -4
data/examples/maketone.rb
CHANGED
@@ -3,52 +3,106 @@
|
|
3
3
|
# simple PCM WAVE file of a 1K tone and encodes some
|
4
4
|
# metadata into it.
|
5
5
|
|
6
|
-
require 'lib/riff/
|
6
|
+
require 'lib/riff/reader.rb'
|
7
7
|
require 'lib/riff/writer.rb'
|
8
8
|
|
9
|
-
|
10
9
|
include Riff
|
11
10
|
|
11
|
+
class Bext
|
12
|
+
|
13
|
+
attr_accessor :description,
|
14
|
+
:originator,
|
15
|
+
:originator_reference,
|
16
|
+
:origination_time,
|
17
|
+
:time_reference,
|
18
|
+
:coding_history
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def sanitize_for_length(field,length)
|
22
|
+
field.to_s[0,length].ljust(length,"\0")
|
23
|
+
end
|
24
|
+
|
25
|
+
def ethernet_addy
|
26
|
+
md = `/sbin/ifconfig | grep ether`.match(/([a-f0-9]{2})\:([a-f0-9]{2})\:([a-f0-9]{2})\:([a-f0-9]{2})\:([a-f0-9]{2})\:([a-f0-9]{2})/)
|
27
|
+
md[1,6].join.ljust(12,"0")
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@description = ""
|
34
|
+
@originator = ""
|
35
|
+
@originator_reference = "jamie" + Bext.ethernet_addy + Time.now.strftime("%H%M%S") +
|
36
|
+
(([0] * 10).map {|e| rand(10)}).join
|
37
|
+
@origination_time = Time.now
|
38
|
+
@time_reference = 0
|
39
|
+
@coding_history = ""
|
40
|
+
@smpte_umid = ""
|
41
|
+
end
|
42
|
+
|
43
|
+
def out
|
44
|
+
time_ref_bytes = Builder::int_to_four_little_endian_bytes(@time_reference).map {|b| b.chr}
|
45
|
+
Bext.sanitize_for_length(@description,256) +
|
46
|
+
Bext.sanitize_for_length(@originator,32) +
|
47
|
+
Bext.sanitize_for_length(@originator_reference,32) +
|
48
|
+
@origination_time.strftime("%Y-%m-%d%H:%M:%S") +
|
49
|
+
"\0\0\0\0\0\0\0\0" + "\001\000\000\000" +
|
50
|
+
Bext.sanitize_for_length(@smpte_umid,64) +
|
51
|
+
("\000" * 190)# + @coding_history
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
12
56
|
SAMPLES_PER_SECOND = 48000
|
13
57
|
FREQ = 1000
|
14
58
|
AMPLITUDE = 0x0fff
|
15
59
|
FILE_TO_MAKE = "test.wav"
|
16
60
|
|
61
|
+
DESCRIPTION = "This file is a 1K tone generated programatically with Ruby libRiff"
|
62
|
+
AUTHOR = "Jamie Hardt"
|
63
|
+
|
17
64
|
Builder.create(FILE_TO_MAKE,"WAVE") do |w|
|
18
65
|
w.list("INFO") { |info|
|
19
|
-
info.chunk("ICOP") {
|
66
|
+
info.chunk("ICOP") {|c| # "copyright"
|
20
67
|
c << "(c) 2007 Jamie Hardt. All Rights Reserved."
|
21
68
|
}
|
22
|
-
info.chunk("ICMT") {|c|
|
23
|
-
c <<
|
69
|
+
info.chunk("ICMT") {|c| # "comment"
|
70
|
+
c << DESCRIPTION
|
24
71
|
}
|
25
|
-
info.chunk("INAM") {|c|
|
26
|
-
c<< "1K tone with metadata"
|
72
|
+
info.chunk("INAM") {|c| # "name" or "title"
|
73
|
+
c << "1K tone with metadata"
|
27
74
|
}
|
28
75
|
info.chunk("ISFT") {|c| # "software"
|
29
|
-
c<< "libRiff v" + "%i.%i" % [Riff::VERSION::MAJOR, Riff::VERSION::MINOR]
|
76
|
+
c << "libRiff v" + "%i.%i" % [Riff::VERSION::MAJOR, Riff::VERSION::MINOR]
|
30
77
|
}
|
31
78
|
info.chunk("IART") {|c| # "artist" (maps to kMDItemAuthors in Spotlight)
|
32
|
-
c <<
|
79
|
+
c << AUTHOR
|
33
80
|
}
|
34
81
|
}
|
82
|
+
w.chunk("bext") {|b|
|
83
|
+
bext = Bext.new
|
84
|
+
bext.description = DESCRIPTION
|
85
|
+
bext.originator = AUTHOR
|
86
|
+
bext.coding_history = "Created by #{__FILE__}"
|
87
|
+
b << bext.out
|
88
|
+
}
|
35
89
|
w.chunk("fmt ") { |c|
|
36
|
-
c.putc(1);c.putc(0)
|
90
|
+
c.putc(1);c.putc(0) #format 1, PCM
|
37
91
|
c.putc(1);c.putc(0) #1 channel
|
38
92
|
|
39
93
|
# samples per second
|
40
|
-
int_to_four_little_endian_bytes(SAMPLES_PER_SECOND).each {|byte| c.putc(byte)}
|
94
|
+
Builder.int_to_four_little_endian_bytes(SAMPLES_PER_SECOND).each {|byte| c.putc(byte)}
|
41
95
|
|
42
96
|
# avg. bytes per second
|
43
|
-
int_to_four_little_endian_bytes(SAMPLES_PER_SECOND * 2).each {|byte| c.putc(byte)}
|
97
|
+
Builder.int_to_four_little_endian_bytes(SAMPLES_PER_SECOND * 2).each {|byte| c.putc(byte)}
|
44
98
|
c.putc(2);c.putc(0) #block alignment 2
|
45
99
|
c.putc(16);c.putc(0) #16 bits per sample
|
46
100
|
}
|
47
101
|
w.chunk("data") { |c|
|
48
|
-
|
49
|
-
|
50
|
-
val = (Math::sin(
|
51
|
-
int_to_four_little_endian_bytes(val)[0,2].each {|byte| c.putc(byte)}
|
102
|
+
factor = Math::PI / (SAMPLES_PER_SECOND / (FREQ * 2))
|
103
|
+
1.upto(SAMPLES_PER_SECOND) do |i|
|
104
|
+
val = ( Math::sin( i * factor ) * AMPLITUDE ).floor
|
105
|
+
Builder::int_to_four_little_endian_bytes(val)[0,2].each {|byte| c.putc(byte)}
|
52
106
|
end
|
53
107
|
}
|
54
108
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'lib/riff/info.rb'
|
2
|
+
|
3
|
+
i = Riff::MetaEditor.new(ARGV[0])
|
4
|
+
|
5
|
+
i.comment = "This is a test comment written by metariff"
|
6
|
+
|
7
|
+
i.save!
|
8
|
+
|
9
|
+
j = Riff::MetaEditor.new(ARGV[0])
|
10
|
+
|
11
|
+
puts "%-4s %s" % ['4CC','Value']
|
12
|
+
puts "%-4s %s" % ["-"*4,"-"*74]
|
13
|
+
j.each_metadatum do |fourcc, value|
|
14
|
+
puts "%-4s %s" % [fourcc, value[0,74]]
|
15
|
+
end
|
data/examples/readchunks.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'lib/riff/
|
1
|
+
require 'lib/riff/reader.rb'
|
2
2
|
|
3
3
|
def print_chunk(ck,margin = "")
|
4
4
|
if ck.is_list? then
|
@@ -11,6 +11,6 @@ def print_chunk(ck,margin = "")
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
Riff::
|
14
|
+
Riff::Reader.open(ARGV[0],"r") do |wav|
|
15
15
|
print_chunk( wav.root_chunk )
|
16
16
|
end
|
data/lib/riff/info.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'lib/riff/reader.rb'
|
2
|
+
require 'lib/riff/writer.rb'
|
3
|
+
|
4
|
+
module Riff
|
5
|
+
|
6
|
+
# Th MetaEditor class provides a reader-writer for the INFO meta-chunk on RIFF
|
7
|
+
# AVI and WAVE files.
|
8
|
+
#
|
9
|
+
# Aside from the stated methods, there is a convenience method for every attribute
|
10
|
+
# name listed in the <tt>MetaEditor.available_names</tt> array, thus, these lines are
|
11
|
+
# equivalent:
|
12
|
+
#
|
13
|
+
# editor.author = "Me Myself"
|
14
|
+
# editor.artist = "Me Myself"
|
15
|
+
# editor['IART'] = "Me Myself"
|
16
|
+
#
|
17
|
+
# Note that some names map to the same fourcc.
|
18
|
+
class MetaEditor
|
19
|
+
|
20
|
+
# the path to the file being edited
|
21
|
+
attr_reader :path
|
22
|
+
|
23
|
+
# the number of bytes padding to add after the INFO
|
24
|
+
# chunk. The default is 1024 bytes.
|
25
|
+
attr_accessor :pad_out
|
26
|
+
|
27
|
+
ATTRIBUTE_FOURCCs = [ 'IARL', 'IART','ICSM','ICMT', 'ICOP', 'ICRD',
|
28
|
+
'ICRP', 'IDIM', 'IDPI', 'IENG','IGNR', 'IKEY',
|
29
|
+
'ILGT', 'IMED', 'INAM', 'IPLT', 'IPRD', 'ISBJ',
|
30
|
+
'ISFT', 'ISHP', 'ISRC', 'ISRF', 'ITCH']
|
31
|
+
|
32
|
+
ATTRIBUTE_NAMES = {
|
33
|
+
'Archival Location' => 'IARL',
|
34
|
+
'Artist' => 'IART',
|
35
|
+
'Author' => 'IART',
|
36
|
+
'Comissioned' => 'ICSM',
|
37
|
+
'Comment' => 'ICMT',
|
38
|
+
'Description' => 'ICMT',
|
39
|
+
'Copyright' => 'ICOP',
|
40
|
+
'Date Created' => 'ICRD',
|
41
|
+
'Cropped' => 'ICRP',
|
42
|
+
'Dimensions' => 'IDIM',
|
43
|
+
'Dots Per Inch' => 'IDPI',
|
44
|
+
'Engineer' => 'IENG',
|
45
|
+
'Genre' => 'IGNR',
|
46
|
+
'Keywords' => 'IKEY',
|
47
|
+
'Lightness' => 'ILGT',
|
48
|
+
'Medium' => 'IMED',
|
49
|
+
'Title' => 'INAM',
|
50
|
+
'Name' => 'INAM',
|
51
|
+
'Number of Colors' => 'IPLT',
|
52
|
+
'Product' => 'IPRD',
|
53
|
+
'Subject' => 'ISBJ',
|
54
|
+
'Software' => 'ISFT',
|
55
|
+
'Encoding Application' => 'ISFT',
|
56
|
+
'Sharpness' => 'ISHP',
|
57
|
+
'Source' => 'ISRC',
|
58
|
+
'Source Form' => 'ISRF',
|
59
|
+
'Technician' => 'ITCH'
|
60
|
+
}
|
61
|
+
|
62
|
+
ATTRIBUTE_FOURCCs.each do |key|
|
63
|
+
class_eval <<-TXT
|
64
|
+
def #{key.downcase}=(val)
|
65
|
+
@metadata['#{key}'] = val
|
66
|
+
end
|
67
|
+
def #{key.downcase}
|
68
|
+
return @metadata['#{key}']
|
69
|
+
end
|
70
|
+
TXT
|
71
|
+
end
|
72
|
+
|
73
|
+
ATTRIBUTE_NAMES.each_pair do |key,value|
|
74
|
+
class_eval <<-TXT
|
75
|
+
def #{key.downcase.gsub(/ /,'_').gsub(/[^a-z_]/,'')}=(val)
|
76
|
+
@metadata['#{value}'] = val
|
77
|
+
end
|
78
|
+
|
79
|
+
def #{key.downcase.gsub(/ /,'_').gsub(/[^a-z_]/,'')}
|
80
|
+
return @metadata['#{value}']
|
81
|
+
end
|
82
|
+
TXT
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns an array of English names for a fourcc tag
|
86
|
+
def MetaEditor.names_for_fourcc(fourcc)
|
87
|
+
return (ATTRIBUTE_NAMES.select {|k,v| v == fourcc}).map {|a| a[0]}
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns an array of all the settable attributes for the file
|
91
|
+
def MetaEditor.available_names(fourcc)
|
92
|
+
return ATTRIBUTE_NAMES.keys
|
93
|
+
end
|
94
|
+
|
95
|
+
# Gives the fourcc the class will map to a given English name
|
96
|
+
def MetaEditor.fourcc_for_name(name)
|
97
|
+
return ATTRIBUTE_NAMES[name]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Creates a MetaEditor object for the file locates at +path+
|
101
|
+
def initialize(path)
|
102
|
+
reader = Reader.open(path,'r')
|
103
|
+
@pad_out = 1024
|
104
|
+
@path = path
|
105
|
+
@metadata = {}
|
106
|
+
infoChunk = reader.root_chunk.find {|c| c.signature == 'INFO'}
|
107
|
+
if infoChunk && infoChunk.is_list?
|
108
|
+
infoChunk.each do |subChunk|
|
109
|
+
@metadata[subChunk.fourcc] = subChunk.body
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def [](k)
|
115
|
+
return @metadata[k]
|
116
|
+
end
|
117
|
+
|
118
|
+
def []=(k,v)
|
119
|
+
@metadata[k] = v
|
120
|
+
end
|
121
|
+
|
122
|
+
def each_metadatum
|
123
|
+
@metadata.each_pair do |key,value|
|
124
|
+
yield key,value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Commit the changed metadata to the file. Presently, the complete file
|
129
|
+
# is rewritten to a temp file and then is moved to the name of the target.
|
130
|
+
#
|
131
|
+
# If a pad_out number is specified, a "JUNK" chunk with a payload of pad_out
|
132
|
+
# bytes will be added after the INFO chunk.
|
133
|
+
def save!
|
134
|
+
tempPath = File.dirname(path) + "/" + (([?a] *8).map {|i| (i + rand(26)).chr}).join + ".tmp"
|
135
|
+
Reader.open(path,'r') do |reader|
|
136
|
+
begin
|
137
|
+
Builder.create(tempPath,reader.root_chunk.signature) do |riffwriter|
|
138
|
+
riffwriter.list('INFO') do |infochunk|
|
139
|
+
@metadata.each_pair do |key,value|
|
140
|
+
infochunk.chunk(key) { |io| io << value }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
if @pad_out > 0
|
144
|
+
riffwriter.chunk("JUNK") do |jnk|
|
145
|
+
jnk << "\0" * @pad_out
|
146
|
+
end
|
147
|
+
end
|
148
|
+
reader.root_chunk.each do |ck|
|
149
|
+
unless ck.is_list? && ck.signature == 'INFO' then
|
150
|
+
riffwriter.chunk(ck.fourcc) {|io| io << ck.body}
|
151
|
+
end #unless
|
152
|
+
end
|
153
|
+
end
|
154
|
+
rescue Exception => e
|
155
|
+
File.unlink(tempPath) if FileTest.exist?(tempPath)
|
156
|
+
raise e
|
157
|
+
end
|
158
|
+
end
|
159
|
+
File.rename(tempPath,path)
|
160
|
+
end #save!
|
161
|
+
end #class
|
162
|
+
end # moule Riff
|
@@ -33,12 +33,12 @@
|
|
33
33
|
# === Getting iXML metadata from a broadcast-WAV file
|
34
34
|
#
|
35
35
|
# require 'riff/base'
|
36
|
-
# Riff::
|
36
|
+
# Riff::Reader.open(ARGV[0],"r") do |wav|
|
37
37
|
# xml = wav.root_chunk['ixml'].body
|
38
38
|
# end
|
39
39
|
#
|
40
40
|
# === Listing all the chunks in a file
|
41
|
-
# require 'riff/
|
41
|
+
# require 'riff/reader'
|
42
42
|
#
|
43
43
|
# def print_chunk(ck,margin = "")
|
44
44
|
# if ck.is_list? then
|
@@ -52,7 +52,7 @@
|
|
52
52
|
# end
|
53
53
|
# end
|
54
54
|
#
|
55
|
-
# Riff::
|
55
|
+
# Riff::Reader.open(ARGV[0],"r") do |wav|
|
56
56
|
# print_chunk( wav.root_chunk )
|
57
57
|
# end
|
58
58
|
#
|
@@ -60,15 +60,15 @@ module Riff
|
|
60
60
|
|
61
61
|
module VERSION
|
62
62
|
MAJOR = 0
|
63
|
-
MINOR =
|
63
|
+
MINOR = 3
|
64
64
|
end #module version
|
65
65
|
|
66
|
-
class
|
67
|
-
# The
|
66
|
+
class Reader
|
67
|
+
# The Reader class provides a front-end to the other objects of the library.
|
68
68
|
# It's the only object that you interact with directly, and calling its methods
|
69
69
|
# will return the other objects of the class.
|
70
70
|
|
71
|
-
# Returns the File object for this
|
71
|
+
# Returns the File object for this reader.
|
72
72
|
attr_reader :file
|
73
73
|
|
74
74
|
# Opens a RIFF file for reading. Pass a string path and string mode, as you would
|
@@ -79,8 +79,8 @@ module Riff
|
|
79
79
|
# sole parameter, and will be automatically closed at the end of the block.
|
80
80
|
# * If you pass a file which does not start with the RIFF fourcc, the file
|
81
81
|
# is invalid and a FileTypeError will be thrown.
|
82
|
-
def
|
83
|
-
riff_obj = Riff::
|
82
|
+
def Reader.open(path,mode) # :yields: riff_object
|
83
|
+
riff_obj = Riff::Reader.new(path,"r")
|
84
84
|
if block_given? && riff_obj then
|
85
85
|
yield riff_obj
|
86
86
|
riff_obj.close
|
@@ -102,26 +102,19 @@ module Riff
|
|
102
102
|
|
103
103
|
class FileTypeError < StandardError ; end #:nodoc:
|
104
104
|
|
105
|
-
protected
|
106
|
-
|
107
|
-
def valid?
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
105
|
private
|
112
106
|
|
113
|
-
def initialize(path, mode)
|
107
|
+
def initialize(path, mode) #:nodoc:
|
114
108
|
raise(ArgumentError, "Riff.open only supports mode 'r' or 'rb'.") \
|
115
109
|
unless mode == "r" || mode == "rb"
|
116
110
|
|
117
111
|
@file = File.open(path,mode)
|
118
|
-
return nil unless valid?
|
119
112
|
end #def initialize
|
120
113
|
|
121
114
|
end
|
122
115
|
|
123
116
|
|
124
|
-
class
|
117
|
+
class Reader
|
125
118
|
|
126
119
|
# The Chunk object represents a chunk of a larger RIFF file. The chunk may be
|
127
120
|
# interrogated to reveal its fourcc and the size of its body. The chunk also
|
@@ -129,7 +122,6 @@ module Riff
|
|
129
122
|
# Keep in mind that this bit of data can be very, very large in media files
|
130
123
|
# (like .wav files) and that reading them in a language like ruby will be quite
|
131
124
|
# slow.
|
132
|
-
|
133
125
|
class Chunk
|
134
126
|
|
135
127
|
# the four-character code of this chunk, always four characters long
|
@@ -145,7 +137,7 @@ module Riff
|
|
145
137
|
# the offset of this chunk from the start of its file
|
146
138
|
attr_reader :offset
|
147
139
|
|
148
|
-
|
140
|
+
|
149
141
|
def self.read_chunk(fp) #:nodoc:
|
150
142
|
code = fp.read(4)
|
151
143
|
fp.pos -= 4
|
@@ -165,9 +157,10 @@ module Riff
|
|
165
157
|
# Returns <tt>true</tt> if this object is a ListChunk. A convenience to typing
|
166
158
|
# <tt>instance_of? Riff::ListChunk</tt>
|
167
159
|
def is_list?
|
168
|
-
instance_of? Riff::
|
160
|
+
instance_of? Riff::Reader::ListChunk
|
169
161
|
end
|
170
|
-
|
162
|
+
|
163
|
+
# Yields each byte of the data chunk.
|
171
164
|
def each_byte
|
172
165
|
while @file.pos < @offset + 8 + @length
|
173
166
|
yield @file.getc
|
@@ -234,14 +227,6 @@ module Riff
|
|
234
227
|
end
|
235
228
|
end
|
236
229
|
|
237
|
-
def body # :nodoc:
|
238
|
-
raise NoMethodError , "ListChunk#body is not permitted!"
|
239
|
-
end
|
240
|
-
|
241
|
-
def each_byte
|
242
|
-
raise NoMethodError
|
243
|
-
end
|
244
|
-
|
245
230
|
protected
|
246
231
|
|
247
232
|
def initialize(fp)
|
data/lib/riff/writer.rb
CHANGED
@@ -2,21 +2,11 @@ require 'stringio'
|
|
2
2
|
|
3
3
|
module Riff
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
[(n.to_i & 0xff) , (n.to_i & 0xff00)>>8,
|
8
|
-
(n.to_i & 0xff0000)>>16,(n.to_i & 0xff000000)>>24 ]
|
9
|
-
end
|
10
|
-
|
11
|
-
def sanitize_fourcc(fourcc)
|
12
|
-
fourcc[0,4].ljust(4,"\0")
|
13
|
-
end
|
14
|
-
|
15
|
-
# A Builder allows you to create a 'de novo' RIFF file. At this time
|
16
|
-
# we do not support modifying RIFF files, only creating new ones.
|
5
|
+
# A Builder allows you to create a 'de novo' RIFF file recursively, similar
|
6
|
+
# in style to the XML Builder class.
|
17
7
|
class Builder
|
18
8
|
|
19
|
-
class IOProxy
|
9
|
+
class IOProxy #:nodoc:
|
20
10
|
|
21
11
|
def initialize(i)
|
22
12
|
@io = i
|
@@ -56,39 +46,50 @@ module Riff
|
|
56
46
|
file.close
|
57
47
|
end
|
58
48
|
|
59
|
-
|
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
|
60
58
|
|
61
|
-
|
59
|
+
end #class << self
|
62
60
|
|
61
|
+
# Add a data chunk to the Builder. The method yields a write-only pseudo-IO
|
62
|
+
# object that you write the chunk data to. Only write the payload of the chunk
|
63
|
+
# here; the fourcc and size will be written for you. Do not pad the data you write to
|
64
|
+
# an even boundary, either.
|
63
65
|
def chunk(fourcc) #:yields: stream
|
64
|
-
|
65
|
-
@io.write(sanitize_fourcc(fourcc))
|
66
|
+
@io.write(self.class.sanitize_fourcc(fourcc))
|
66
67
|
4.times {@io.putc(0)}
|
67
68
|
oldPos = @io.pos
|
68
69
|
yield IOProxy.new(@io)
|
69
70
|
length = @io.pos - oldPos
|
70
71
|
@io.putc(0) if (length % 2) == 1
|
71
72
|
@io.seek(oldPos-4,IO::SEEK_SET)
|
72
|
-
bytes = int_to_four_little_endian_bytes(length)
|
73
|
-
$stderr.print("will write bytes size: #{bytes.inspect}\n")
|
73
|
+
bytes = self.class.int_to_four_little_endian_bytes(length)
|
74
74
|
bytes.each {|byte| @io.putc(byte)}
|
75
75
|
@io.seek(0,IO::SEEK_END)
|
76
|
-
$stderr.print("ascending from chunk #{fourcc}, total written #{length}\n")
|
77
76
|
end
|
78
77
|
|
79
|
-
|
78
|
+
# Add a RIFF "LIST" chunk. The method yields a builder, which you can add
|
79
|
+
# chunks and other lists to.
|
80
|
+
def list(type) #:yields: builder
|
80
81
|
container("LIST",type) do |io|
|
81
82
|
yield Builder.new(io)
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
|
-
def initialize(stream)
|
86
|
+
def initialize(stream) # :nodoc:
|
86
87
|
@io = stream
|
87
88
|
end
|
88
89
|
|
89
|
-
def container(fourcc,type)
|
90
|
-
chunk(sanitize_fourcc(fourcc)) do |io|
|
91
|
-
io.write(sanitize_fourcc(type))
|
90
|
+
def container(fourcc,type) # :nodoc:
|
91
|
+
chunk(self.class.sanitize_fourcc(fourcc)) do |io|
|
92
|
+
io.write(self.class.sanitize_fourcc(type))
|
92
93
|
yield io
|
93
94
|
end
|
94
95
|
end
|
metadata
CHANGED
@@ -3,9 +3,9 @@ rubygems_version: 0.9.1
|
|
3
3
|
specification_version: 1
|
4
4
|
name: riff
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2007-12-
|
8
|
-
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.
|
6
|
+
version: "0.3"
|
7
|
+
date: 2007-12-27 00:00:00 -08:00
|
8
|
+
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.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email:
|
@@ -29,7 +29,8 @@ post_install_message:
|
|
29
29
|
authors: []
|
30
30
|
|
31
31
|
files:
|
32
|
-
- lib/riff/
|
32
|
+
- lib/riff/info.rb
|
33
|
+
- lib/riff/reader.rb
|
33
34
|
- lib/riff/writer.rb
|
34
35
|
- Rakefile
|
35
36
|
- test/riff_test.rb
|
@@ -38,6 +39,7 @@ files:
|
|
38
39
|
- test_media/bad.riff
|
39
40
|
- test_media/Pop.wav
|
40
41
|
- examples/maketone.rb
|
42
|
+
- examples/metariff.rb
|
41
43
|
- examples/readchunks.rb
|
42
44
|
test_files:
|
43
45
|
- test/riff_test_suite.rb
|