riffy 0.1.0
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/bin/test.wav +0 -0
- data/lib/chunk.rb +63 -0
- data/lib/chunk_data.rb +47 -0
- data/lib/four_cc.rb +34 -0
- data/lib/riffy.rb +72 -0
- data/lib/wav_fmt.rb +42 -0
- metadata +51 -0
data/bin/test.wav
ADDED
Binary file
|
data/lib/chunk.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative 'four_cc'
|
2
|
+
require_relative 'chunk_data'
|
3
|
+
|
4
|
+
class Chunk < Struct.new(:id, :size, :data)
|
5
|
+
|
6
|
+
# MIN_SIZE = "\x00\x00\x00\x00".unpack("L<")
|
7
|
+
# MAX_SIZE = "\xFF\xFF\xFF\xFF".unpack("L<")
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
|
11
|
+
self.id = file.each_char.first(4).join
|
12
|
+
self.size = file.each_char.first(4).join.unpack("L<")[0]
|
13
|
+
self.data = ChunkData.new(file, self)
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
|
19
|
+
print "\n\t\"#{self.id}\" <#{self.size}> (\n"
|
20
|
+
print "\t \"#{self.data.form_type}\",\n"
|
21
|
+
comma_count = self.data.chunks.length - 1
|
22
|
+
self.data.chunks.each do |chunk|
|
23
|
+
|
24
|
+
#if chunk.id.eql? "fmt "
|
25
|
+
print "\t < \"#{chunk.id}\" <#{chunk.size}> "
|
26
|
+
chunk.data.chunks.each do |sub_chunk|
|
27
|
+
print "< \"#{sub_chunk.id}\" <#{sub_chunk.size}> >"
|
28
|
+
end
|
29
|
+
#print "\n"
|
30
|
+
case chunk.id
|
31
|
+
when "fmt "
|
32
|
+
print chunk.data.data.to_s
|
33
|
+
when "LIST"
|
34
|
+
end
|
35
|
+
print "\t >"
|
36
|
+
if comma_count > 0
|
37
|
+
print ",\n"
|
38
|
+
else
|
39
|
+
print "\n"
|
40
|
+
end
|
41
|
+
comma_count -= 1
|
42
|
+
|
43
|
+
# else
|
44
|
+
|
45
|
+
# print "\t < \"#{chunk.id}\" <#{chunk.size}> "
|
46
|
+
# chunk.data.chunks.each do |sub_chunk|
|
47
|
+
# print "< \"#{sub_chunk.id}\" <#{sub_chunk.size}> >"
|
48
|
+
# end
|
49
|
+
# print " >"
|
50
|
+
# if comma_count > 0
|
51
|
+
# print ",\n"
|
52
|
+
# else
|
53
|
+
# print "\n"
|
54
|
+
# end
|
55
|
+
# comma_count -= 1
|
56
|
+
|
57
|
+
# end
|
58
|
+
end
|
59
|
+
print "\t)\n"
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/chunk_data.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'wav_fmt'
|
2
|
+
|
3
|
+
class ChunkData < Struct.new(:form_type, :chunks, :parent, :data)
|
4
|
+
|
5
|
+
|
6
|
+
def initialize(file, parent)
|
7
|
+
|
8
|
+
self.parent = parent
|
9
|
+
self.chunks ||= []
|
10
|
+
|
11
|
+
case self.parent.id
|
12
|
+
when "RIFF"
|
13
|
+
|
14
|
+
self.form_type = file.each_char.first(4).join
|
15
|
+
|
16
|
+
until file.eof?
|
17
|
+
|
18
|
+
self.chunks << Chunk.new(file)
|
19
|
+
file.pos += self.chunks.last.size
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
when "fmt "
|
24
|
+
temp_pos = file.pos
|
25
|
+
|
26
|
+
self.data = WavFmt.new(file.each_char.first(16).join)
|
27
|
+
|
28
|
+
file.pos = temp_pos
|
29
|
+
else
|
30
|
+
|
31
|
+
@file_position_of_data = file.pos
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
|
39
|
+
|
40
|
+
print "\n <#{self.form_type}>"
|
41
|
+
self.chunks.each do |chunk|
|
42
|
+
print "\n <#{chunk.id}> <#{chunk.size}>"
|
43
|
+
end;""
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/lib/four_cc.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
class FourCC < Struct.new(:value)
|
2
|
+
|
3
|
+
# A FOURCC is represented as a sequence of one to four
|
4
|
+
# ASCII alphanumeric characters, padded on the right with
|
5
|
+
# blank characters (ASCII character value 32) as
|
6
|
+
# required, with no embedded blanks (i.e. "H DL" invalid).
|
7
|
+
|
8
|
+
def initialize(value=" ")
|
9
|
+
|
10
|
+
begin
|
11
|
+
raise "FourCC invalid." unless FourCC.verify(value)
|
12
|
+
self.value = value
|
13
|
+
rescue
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
self.value
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def self.verify(value)
|
26
|
+
|
27
|
+
valid = true
|
28
|
+
|
29
|
+
return false unless valid
|
30
|
+
return true
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/riffy.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative 'chunk'
|
2
|
+
|
3
|
+
class Riffy < Chunk
|
4
|
+
|
5
|
+
attr_reader :type
|
6
|
+
|
7
|
+
def initialize(file)
|
8
|
+
|
9
|
+
begin
|
10
|
+
raise "File corrupt or unreadable." unless Riffy.verify(file)
|
11
|
+
rescue
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
self.id = FourCC.new('RIFF')
|
16
|
+
super(file)
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def format #return the format of the RIFF file. e.g. "WAVE"
|
21
|
+
|
22
|
+
self.data.form_type
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def bit_rate
|
27
|
+
self.data.chunks[0].data.data.bit_rate
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
def self.open(file)
|
33
|
+
|
34
|
+
begin
|
35
|
+
f = File.open(file, "rb")
|
36
|
+
rescue
|
37
|
+
puts "The file failed to load for some reason."
|
38
|
+
end
|
39
|
+
|
40
|
+
Riffy.new(f)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def self.parse_riff(file)
|
47
|
+
|
48
|
+
# parse file by creating chunk objects etc.
|
49
|
+
f = File.open(file)
|
50
|
+
|
51
|
+
attr_array = []
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
self.id = f.each_char.first(4).join
|
56
|
+
self.size = f.each_char.first(4).join.unpack("L<")[0]
|
57
|
+
|
58
|
+
puts self.id
|
59
|
+
puts self.size
|
60
|
+
|
61
|
+
self.data = ChunkData.new(f, :riff)
|
62
|
+
|
63
|
+
# @type = file[8..11]
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.verify(file)
|
68
|
+
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
data/lib/wav_fmt.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
class WavFmt
|
2
|
+
|
3
|
+
attr_reader :bit_rate
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
|
7
|
+
# Byte Number Size Description Value
|
8
|
+
# 0-3 4 Chunk ID "fmt " (0x666D7420)
|
9
|
+
#@chunk_id = data[0..3]
|
10
|
+
# 4-7 4 Chunk Data Size Length Of format Chunk (always 0x10)
|
11
|
+
#@chunk_size = data[4..7]
|
12
|
+
# 8-9 2 Compression code Always 0x01
|
13
|
+
#puts data
|
14
|
+
@compression_code = data[0..1].unpack("C")[0]
|
15
|
+
# 10 - 11 2 Channel Numbers 0x01=Mono, 0x02=Stereo
|
16
|
+
#puts data[2..3].inspect
|
17
|
+
@channels = data[2..3].unpack("C")[0]
|
18
|
+
# 12 - 15 4 Sample Rate Binary, in Hz
|
19
|
+
@sample_rate = data[4..7].unpack("L")[0]/1000
|
20
|
+
# 16 - 19 4 Bytes Per Second
|
21
|
+
@kbps = data[8..11].unpack("L")[0]/1000*8
|
22
|
+
@bit_rate = @kbps
|
23
|
+
# 20 - 21 2 Bytes Per Sample 1=8 bit Mono, 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo
|
24
|
+
@bytes_per_sample = data[12..13].unpack("C")[0]
|
25
|
+
# 22 - 23 2 Bits Per Sample
|
26
|
+
@bits_per_sample = data[14..15].unpack("C")[0]
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
|
32
|
+
puts "\n\tcompression_code: #{@compression_code}"
|
33
|
+
puts "\t channels: #{(@channels == 1) ? "Mono" : "Stereo"}"
|
34
|
+
puts "\t Sample Rate: #{@sample_rate} kHz"
|
35
|
+
puts "\t Bit Rate: #{@kbps} kbps"
|
36
|
+
puts "\tbytes_per_sample: #{@bytes_per_sample}"
|
37
|
+
print "\t bits_per_sample: #{@bits_per_sample}"
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: riffy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dominic Muller
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-01-14 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Converts RIFF files into Ruby objects
|
15
|
+
email: nicklink483@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/riffy.rb
|
21
|
+
- lib/chunk.rb
|
22
|
+
- lib/chunk_data.rb
|
23
|
+
- lib/four_cc.rb
|
24
|
+
- lib/wav_fmt.rb
|
25
|
+
- bin/test.wav
|
26
|
+
homepage: http://rubygems.org/gems/riffy
|
27
|
+
licenses:
|
28
|
+
- ''
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 1.8.28
|
48
|
+
signing_key:
|
49
|
+
specification_version: 3
|
50
|
+
summary: RIFF file parser
|
51
|
+
test_files: []
|