riff 0.1 → 0.2
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 +54 -0
- data/examples/{example1.rb → readchunks.rb} +0 -0
- data/lib/riff/base.rb +3 -32
- data/lib/riff/writer.rb +97 -0
- metadata +28 -24
- data/examples/example2.rb +0 -6
- data/lib/riff/bwav.rb +0 -8
- data/lib/riff/wav.rb +0 -8
@@ -0,0 +1,54 @@
|
|
1
|
+
# Author:: Jamie Hardt
|
2
|
+
# maketone.rb is a simple program that creates a
|
3
|
+
# simple PCM WAVE file of a 1K tone and encodes some
|
4
|
+
# metadata into it.
|
5
|
+
|
6
|
+
require 'lib/riff/base.rb'
|
7
|
+
require 'lib/riff/writer.rb'
|
8
|
+
|
9
|
+
|
10
|
+
include Riff
|
11
|
+
|
12
|
+
SAMPLES_PER_SECOND = 48000
|
13
|
+
FREQ = 1000
|
14
|
+
AMPLITUDE = 0x0fff
|
15
|
+
FILE_TO_MAKE = "test.wav"
|
16
|
+
|
17
|
+
Builder.create(FILE_TO_MAKE,"WAVE") do |w|
|
18
|
+
w.list("INFO") { |info|
|
19
|
+
info.chunk("ICOP") { |c| #"copyright"
|
20
|
+
c << "(c) 2007 Jamie Hardt. All Rights Reserved."
|
21
|
+
}
|
22
|
+
info.chunk("ICMT") {|c| # "comment"
|
23
|
+
c << "This file is a 1K tone generated programatically with Ruby libRiff"
|
24
|
+
}
|
25
|
+
info.chunk("INAM") {|c| # "name" or "title"
|
26
|
+
c<< "1K tone with metadata"
|
27
|
+
}
|
28
|
+
info.chunk("ISFT") {|c| # "software"
|
29
|
+
c<< "libRiff v" + "%i.%i" % [Riff::VERSION::MAJOR, Riff::VERSION::MINOR]
|
30
|
+
}
|
31
|
+
info.chunk("IART") {|c| # "artist" (maps to kMDItemAuthors in Spotlight)
|
32
|
+
c << "Jamie Hardt"
|
33
|
+
}
|
34
|
+
}
|
35
|
+
w.chunk("fmt ") { |c|
|
36
|
+
c.putc(1);c.putc(0); #format 1, PCM
|
37
|
+
c.putc(1);c.putc(0) #1 channel
|
38
|
+
|
39
|
+
# samples per second
|
40
|
+
int_to_four_little_endian_bytes(SAMPLES_PER_SECOND).each {|byte| c.putc(byte)}
|
41
|
+
|
42
|
+
# avg. bytes per second
|
43
|
+
int_to_four_little_endian_bytes(SAMPLES_PER_SECOND * 2).each {|byte| c.putc(byte)}
|
44
|
+
c.putc(2);c.putc(0) #block alignment 2
|
45
|
+
c.putc(16);c.putc(0) #16 bits per sample
|
46
|
+
}
|
47
|
+
w.chunk("data") { |c|
|
48
|
+
denom = SAMPLES_PER_SECOND / (FREQ * 2)
|
49
|
+
0.upto(SAMPLES_PER_SECOND) do |i|
|
50
|
+
val = (Math::sin(Math::PI * i/denom) * AMPLITUDE).floor
|
51
|
+
int_to_four_little_endian_bytes(val)[0,2].each {|byte| c.putc(byte)}
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
File without changes
|
data/lib/riff/base.rb
CHANGED
@@ -60,7 +60,7 @@ module Riff
|
|
60
60
|
|
61
61
|
module VERSION
|
62
62
|
MAJOR = 0
|
63
|
-
MINOR =
|
63
|
+
MINOR = 2
|
64
64
|
end #module version
|
65
65
|
|
66
66
|
class Base
|
@@ -87,35 +87,6 @@ module Riff
|
|
87
87
|
end
|
88
88
|
riff_obj
|
89
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
90
|
|
120
91
|
# Returns the Root Chunk of the RIFF file as a ListChunk
|
121
92
|
def root_chunk
|
@@ -199,8 +170,7 @@ module Riff
|
|
199
170
|
|
200
171
|
def each_byte
|
201
172
|
while @file.pos < @offset + 8 + @length
|
202
|
-
yield @file.getc
|
203
|
-
@file.pos +=1
|
173
|
+
yield @file.getc
|
204
174
|
end
|
205
175
|
end
|
206
176
|
|
@@ -280,6 +250,7 @@ module Riff
|
|
280
250
|
end
|
281
251
|
|
282
252
|
end #class ListChunk
|
253
|
+
|
283
254
|
end #class Riff
|
284
255
|
|
285
256
|
end #module
|
data/lib/riff/writer.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Riff
|
4
|
+
|
5
|
+
def int_to_four_little_endian_bytes(i) # :nodoc:
|
6
|
+
n =i # [ i.abs , 2^32 ].min
|
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.
|
17
|
+
class Builder
|
18
|
+
|
19
|
+
class IOProxy
|
20
|
+
|
21
|
+
def initialize(i)
|
22
|
+
@io = i
|
23
|
+
@startPos = i.pos
|
24
|
+
end
|
25
|
+
|
26
|
+
def write(data)
|
27
|
+
@io.write data
|
28
|
+
end
|
29
|
+
|
30
|
+
def <<(data)
|
31
|
+
write(data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def pos
|
35
|
+
@io.pos
|
36
|
+
end
|
37
|
+
|
38
|
+
def seek(offset,whence)
|
39
|
+
@io.seek(offset,whence)
|
40
|
+
end
|
41
|
+
|
42
|
+
def putc(c)
|
43
|
+
@io.putc(c)
|
44
|
+
end
|
45
|
+
|
46
|
+
end #class IOProxy
|
47
|
+
|
48
|
+
class << self
|
49
|
+
# Create a new RIFF file at +path+, using +type+ for the top-level chunk's type or signature.
|
50
|
+
def create(path,type) #:yields: riff_file
|
51
|
+
file = File.open(path,"w")
|
52
|
+
w = Builder.new(file)
|
53
|
+
w.container('RIFF',type) do |body_io|
|
54
|
+
yield Builder.new(body_io)
|
55
|
+
end
|
56
|
+
file.close
|
57
|
+
end
|
58
|
+
|
59
|
+
end #class << self
|
60
|
+
|
61
|
+
attr_reader :io
|
62
|
+
|
63
|
+
def chunk(fourcc) #:yields: stream
|
64
|
+
$stderr.print("descending into chunk #{fourcc}, starts at #{@io.pos}\n")
|
65
|
+
@io.write(sanitize_fourcc(fourcc))
|
66
|
+
4.times {@io.putc(0)}
|
67
|
+
oldPos = @io.pos
|
68
|
+
yield IOProxy.new(@io)
|
69
|
+
length = @io.pos - oldPos
|
70
|
+
@io.putc(0) if (length % 2) == 1
|
71
|
+
@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")
|
74
|
+
bytes.each {|byte| @io.putc(byte)}
|
75
|
+
@io.seek(0,IO::SEEK_END)
|
76
|
+
$stderr.print("ascending from chunk #{fourcc}, total written #{length}\n")
|
77
|
+
end
|
78
|
+
|
79
|
+
def list(type)
|
80
|
+
container("LIST",type) do |io|
|
81
|
+
yield Builder.new(io)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(stream)
|
86
|
+
@io = stream
|
87
|
+
end
|
88
|
+
|
89
|
+
def container(fourcc,type)
|
90
|
+
chunk(sanitize_fourcc(fourcc)) do |io|
|
91
|
+
io.write(sanitize_fourcc(type))
|
92
|
+
yield io
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end #class Wrtier
|
96
|
+
|
97
|
+
end #module Riff
|
metadata
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.
|
2
|
+
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:
|
8
|
-
summary:
|
9
|
-
RIFF is a meta-format which is a common wrapper for multimedia files, such as
|
10
|
-
.wav and .avi files."
|
6
|
+
version: "0.2"
|
7
|
+
date: 2007-12-24 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.
|
11
9
|
require_paths:
|
12
|
-
|
10
|
+
- lib
|
13
11
|
email:
|
14
12
|
homepage: http://riff.rubyforge.org
|
15
13
|
rubyforge_project: riff
|
@@ -20,32 +18,38 @@ bindir: bin
|
|
20
18
|
has_rdoc: true
|
21
19
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
22
20
|
requirements:
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
version: 1.8.2
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.2
|
27
24
|
version:
|
28
25
|
platform: ruby
|
29
26
|
signing_key:
|
30
27
|
cert_chain:
|
28
|
+
post_install_message:
|
31
29
|
authors: []
|
30
|
+
|
32
31
|
files:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
- examples/example2.rb
|
32
|
+
- lib/riff/base.rb
|
33
|
+
- lib/riff/writer.rb
|
34
|
+
- Rakefile
|
35
|
+
- test/riff_test.rb
|
36
|
+
- test/riff_test_suite.rb
|
37
|
+
- test/wav_test.rb
|
38
|
+
- test_media/bad.riff
|
39
|
+
- test_media/Pop.wav
|
40
|
+
- examples/maketone.rb
|
41
|
+
- examples/readchunks.rb
|
44
42
|
test_files:
|
45
|
-
|
43
|
+
- test/riff_test_suite.rb
|
46
44
|
rdoc_options: []
|
45
|
+
|
47
46
|
extra_rdoc_files: []
|
47
|
+
|
48
48
|
executables: []
|
49
|
+
|
49
50
|
extensions: []
|
51
|
+
|
50
52
|
requirements: []
|
51
|
-
|
53
|
+
|
54
|
+
dependencies: []
|
55
|
+
|
data/examples/example2.rb
DELETED
data/lib/riff/bwav.rb
DELETED