waveinfo 0.0.1
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/COPYING +56 -0
- data/README +43 -0
- data/Rakefile +112 -0
- data/bin/waveinfo +25 -0
- data/lib/waveinfo.rb +186 -0
- data/samples/sine_11k_mono_16bit_pcm.wav +0 -0
- data/samples/sine_11k_mono_8bit_pcm.wav +0 -0
- data/samples/sine_11k_mono_alaw.wav +0 -0
- data/samples/sine_11k_mono_ima_adpcm.wav +0 -0
- data/samples/sine_11k_mono_ms_adpcm.wav +0 -0
- data/samples/sine_11k_mono_ulaw.wav +0 -0
- data/samples/sine_8k_mono_16bit_pcm.wav +0 -0
- data/samples/sine_8k_mono_gsm.wav +0 -0
- data/samples/testcase_44k_stereo_16bit_pcm.wav +0 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/waveinfo_spec.rb +433 -0
- metadata +68 -0
data/COPYING
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
ruby-mpris is copyrighted free software by Nicholas J Humfrey <njh@aelius.com>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the GPL
|
3
|
+
version 2 (see the file GPL), or the conditions below:
|
4
|
+
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
6
|
+
software without restriction, provided that you duplicate all of the
|
7
|
+
original copyright notices and associated disclaimers.
|
8
|
+
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
10
|
+
you do at least ONE of the following:
|
11
|
+
|
12
|
+
a) place your modifications in the Public Domain or otherwise
|
13
|
+
make them Freely Available, such as by posting said
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
15
|
+
the author to include your modifications in the software.
|
16
|
+
|
17
|
+
b) use the modified software only within your corporation or
|
18
|
+
organization.
|
19
|
+
|
20
|
+
c) give non-standard binaries non-standard names, with
|
21
|
+
instructions on where to get the original software distribution.
|
22
|
+
|
23
|
+
d) make other distribution arrangements with the author.
|
24
|
+
|
25
|
+
3. You may distribute the software in object code or binary form,
|
26
|
+
provided that you do at least ONE of the following:
|
27
|
+
|
28
|
+
a) distribute the binaries and library files of the software,
|
29
|
+
together with instructions (in the manual page or equivalent)
|
30
|
+
on where to get the original distribution.
|
31
|
+
|
32
|
+
b) accompany the distribution with the machine-readable source of
|
33
|
+
the software.
|
34
|
+
|
35
|
+
c) give non-standard binaries non-standard names, with
|
36
|
+
instructions on where to get the original software distribution.
|
37
|
+
|
38
|
+
d) make other distribution arrangements with the author.
|
39
|
+
|
40
|
+
4. You may modify and include the part of the software into any other
|
41
|
+
software (possibly commercial). But some files in the distribution
|
42
|
+
are not written by the author, so that they are not under these terms.
|
43
|
+
|
44
|
+
For the list of those files and their copying conditions, see the
|
45
|
+
file LEGAL.
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
data/README
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
== waveinfo
|
2
|
+
|
3
|
+
waveinfo is a pure-ruby gem to get the information from the headers of Wave (.wav) files.
|
4
|
+
|
5
|
+
RubyForge Project Page http://rubyforge.org/projects/waveinfo/
|
6
|
+
|
7
|
+
== Installing
|
8
|
+
|
9
|
+
You may get the latest stable version from Rubyforge. Source gems are also available.
|
10
|
+
|
11
|
+
$ gem install waveinfo
|
12
|
+
|
13
|
+
== Synopsis
|
14
|
+
|
15
|
+
require 'rubygems'
|
16
|
+
require 'waveinfo'
|
17
|
+
|
18
|
+
wave = WaveInfo.new('example.wav')
|
19
|
+
puts "Channels: #{wave.channels}"
|
20
|
+
puts "Sample Rate: #{wave.sample_rate} Hz"
|
21
|
+
puts "Duration: #{wave.duration} secs"
|
22
|
+
|
23
|
+
== TODO
|
24
|
+
|
25
|
+
* Add support for the extensible format which uses GUIDs
|
26
|
+
* Inplement more validity checks
|
27
|
+
- file is shorter than reported chunk size
|
28
|
+
- file is longer than reported chunk size
|
29
|
+
* Implement more chunk types
|
30
|
+
- bext - Broadcast Wave Extention
|
31
|
+
- mext - MPEG audio extension chunk
|
32
|
+
- DISP - Title
|
33
|
+
- cart - CartChunk/aes46-2002
|
34
|
+
- LIST
|
35
|
+
* Test against more weird Wave files
|
36
|
+
|
37
|
+
== Contact
|
38
|
+
|
39
|
+
Author:: Nicholas J Humfrey
|
40
|
+
Email:: njh@aelius.com
|
41
|
+
Home Page:: http://www.aelius.com/njh/
|
42
|
+
License:: Distributes under the same terms as Ruby
|
43
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'spec/rake/spectask'
|
7
|
+
require 'spec/rake/verify_rcov'
|
8
|
+
|
9
|
+
|
10
|
+
NAME = "waveinfo"
|
11
|
+
VERS = "0.0.1"
|
12
|
+
CLEAN.include ['pkg', 'rdoc']
|
13
|
+
|
14
|
+
spec = Gem::Specification.new do |s|
|
15
|
+
s.name = NAME
|
16
|
+
s.version = VERS
|
17
|
+
s.author = "Nicholas J Humfrey"
|
18
|
+
s.email = "njh@aelius.com"
|
19
|
+
s.homepage = "http://waveinfo.rubyforge.org"
|
20
|
+
s.platform = Gem::Platform::RUBY
|
21
|
+
s.summary = "Pure-ruby gem to get the information from the headers of Wave (.wav) files."
|
22
|
+
s.rubyforge_project = "waveinfo"
|
23
|
+
s.description = "waveinfo is a pure-ruby gem to get the information from the headers of Wave (.wav) files."
|
24
|
+
s.files = FileList["Rakefile", "lib/waveinfo.rb", "spec/*.rb", "samples/*.wav"]
|
25
|
+
s.executables = ['waveinfo']
|
26
|
+
s.require_path = "lib"
|
27
|
+
|
28
|
+
# rdoc
|
29
|
+
s.has_rdoc = true
|
30
|
+
s.extra_rdoc_files = ["README", "COPYING"]
|
31
|
+
|
32
|
+
# Build Dependencies
|
33
|
+
#s.add_dependency 'rake' '~> 0.8'
|
34
|
+
#s.add_dependency 'rspec', '~> 1.1'
|
35
|
+
#s.add_dependency 'rcov', '~> 0.8'
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Default: test the gem."
|
39
|
+
task :default => [:check_syntax, :rdoc]
|
40
|
+
|
41
|
+
task :build_package => [:repackage]
|
42
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
43
|
+
pkg.need_zip = false
|
44
|
+
pkg.need_tar = true
|
45
|
+
pkg.gem_spec = spec
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Run :package and install the resulting .gem"
|
49
|
+
task :install => :package do
|
50
|
+
sh %{sudo gem install --local pkg/#{NAME}-#{VERS}.gem}
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Run :clean and uninstall the .gem"
|
54
|
+
task :uninstall => :clean do
|
55
|
+
sh %{sudo gem uninstall #{NAME}}
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
## Testing
|
61
|
+
desc "Run all the specification tests"
|
62
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
63
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
64
|
+
t.spec_opts = ["--colour"]
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Check the syntax of all ruby files"
|
68
|
+
task :check_syntax do
|
69
|
+
`find . -name "*.rb" |xargs -n1 ruby -c |grep -v "Syntax OK"`
|
70
|
+
puts "* Done"
|
71
|
+
end
|
72
|
+
|
73
|
+
namespace :spec do
|
74
|
+
desc "Generate RCov report"
|
75
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
76
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
77
|
+
t.rcov = true
|
78
|
+
t.rcov_dir = 'coverage'
|
79
|
+
t.rcov_opts = ['--text-report', '--exclude', "spec/"]
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Generate specdoc"
|
83
|
+
Spec::Rake::SpecTask.new(:doc) do |t|
|
84
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
85
|
+
t.spec_opts = ["--format", "specdoc"]
|
86
|
+
end
|
87
|
+
|
88
|
+
namespace :doc do
|
89
|
+
desc "Generate html specdoc"
|
90
|
+
Spec::Rake::SpecTask.new(:html) do |t|
|
91
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
92
|
+
t.spec_opts = ["--format", "html:rspec_report.html", "--diff"]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
## Documentation
|
100
|
+
desc "Generate documentation for the library"
|
101
|
+
Rake::RDocTask.new("rdoc") { |rdoc|
|
102
|
+
rdoc.rdoc_dir = 'rdoc'
|
103
|
+
rdoc.title = "waveinfo Documentation"
|
104
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
105
|
+
rdoc.main = "README"
|
106
|
+
rdoc.rdoc_files.include("README", "COPYING", "lib/waveinfo.rb")
|
107
|
+
}
|
108
|
+
|
109
|
+
desc "Upload rdoc to rubyforge"
|
110
|
+
task :upload_rdoc => [:rdoc] do
|
111
|
+
sh %{/usr/bin/scp -r -p rdoc/* waveinfo.rubyforge.org:/var/www/gforge-projects/waveinfo}
|
112
|
+
end
|
data/bin/waveinfo
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'waveinfo'
|
5
|
+
|
6
|
+
if (ARGV.size < 1)
|
7
|
+
puts "Usage: waveinfo <file.wav> [<file2.wav> ...]"
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
ARGV.each do |arg|
|
12
|
+
wave = WaveInfo.new(arg)
|
13
|
+
puts "Filename : #{wave.filename}"
|
14
|
+
puts "Audio Format : #{wave.audio_format} " +
|
15
|
+
sprintf("(0x%2.2x)",wave.audio_format_id)
|
16
|
+
puts "Duration : " + sprintf("%2.2fs", wave.duration)
|
17
|
+
puts "Channels : #{wave.channels}"
|
18
|
+
puts "Sample Rate : #{wave.sample_rate}Hz"
|
19
|
+
puts "Bits per Sample : #{wave.bits_per_sample}"
|
20
|
+
puts "Bytes per Block : #{wave.block_align}"
|
21
|
+
puts "Byte rate : #{wave.byte_rate}"
|
22
|
+
puts "Sample Count : #{wave.samples}"
|
23
|
+
puts "Audio Length : #{wave.size} bytes"
|
24
|
+
puts
|
25
|
+
end
|
data/lib/waveinfo.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class WaveInfo
|
4
|
+
|
5
|
+
# Create a new WaveInfo object to get information and metadata about a
|
6
|
+
# Wave file (.wav). 'file' can either be a filename or an IO object.
|
7
|
+
def initialize(file)
|
8
|
+
|
9
|
+
# Set default values
|
10
|
+
@audio_format_id = 0
|
11
|
+
@bits_per_sample = nil
|
12
|
+
@block_align = nil
|
13
|
+
@byte_rate = nil
|
14
|
+
@channels = nil
|
15
|
+
@data_size = nil
|
16
|
+
@sample_rate = nil
|
17
|
+
@samples = nil
|
18
|
+
|
19
|
+
# What was passed in to us?
|
20
|
+
if file.is_a?(String)
|
21
|
+
@io = File.new(file, 'rb')
|
22
|
+
@filepath = @io.path
|
23
|
+
read_headers
|
24
|
+
@io.close
|
25
|
+
else
|
26
|
+
@io = file
|
27
|
+
@filepath = @io.path
|
28
|
+
read_headers
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return the name of the input file.
|
33
|
+
def filename
|
34
|
+
File.basename(@filepath)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get the identifier of the audio codec (for example PCM would be 1).
|
38
|
+
def audio_format_id
|
39
|
+
@audio_format_id
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get the name of the audio codec (for example 'PCM').
|
43
|
+
def audio_format
|
44
|
+
case @audio_format_id
|
45
|
+
when 0x01 then
|
46
|
+
"PCM"
|
47
|
+
when 0x02 then
|
48
|
+
"Microsoft ADPCM"
|
49
|
+
when 0x06 then
|
50
|
+
"a-law"
|
51
|
+
when 0x07 then
|
52
|
+
"u-law"
|
53
|
+
when 0x11 then
|
54
|
+
"IMA ADPCM"
|
55
|
+
when 0x14 then
|
56
|
+
"G.723"
|
57
|
+
when 0x31 then
|
58
|
+
"GSM"
|
59
|
+
when 0x40 then
|
60
|
+
"G.721"
|
61
|
+
when 0x50 then
|
62
|
+
"MPEG-1 Audio"
|
63
|
+
when 0x55 then
|
64
|
+
"MPEG Audio Layer 3"
|
65
|
+
else
|
66
|
+
"Unknown (#{@audio_format_id})"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get the number of channels.
|
71
|
+
def channels
|
72
|
+
@channels
|
73
|
+
end
|
74
|
+
|
75
|
+
# Get the sample rate (in Hz).
|
76
|
+
def sample_rate
|
77
|
+
@sample_rate
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get the average number of bytes per second.
|
81
|
+
def byte_rate
|
82
|
+
@byte_rate
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get the number of bytes per sample slice.
|
86
|
+
def block_align
|
87
|
+
@block_align
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get the number of bits per sample.
|
91
|
+
def bits_per_sample
|
92
|
+
@bits_per_sample
|
93
|
+
end
|
94
|
+
|
95
|
+
# Get the total number of samples.
|
96
|
+
def samples
|
97
|
+
if @samples
|
98
|
+
@samples
|
99
|
+
else
|
100
|
+
@data_size / @block_align
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Get the length of the audio data (in bytes).
|
105
|
+
def size
|
106
|
+
@data_size
|
107
|
+
end
|
108
|
+
|
109
|
+
# Get the duration of the audio (in seconds).
|
110
|
+
def duration
|
111
|
+
samples.to_f / sample_rate.to_f
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def read_headers
|
117
|
+
# Read in the chunk header
|
118
|
+
chunk_id = read_fourchar
|
119
|
+
raise FileFormatError.new("Chunk id is not 'RIFF'") if chunk_id != 'RIFF'
|
120
|
+
chunk_size = read_longint
|
121
|
+
chunk_format = read_fourchar
|
122
|
+
raise FileFormatError.new("Chunk format is not 'WAVE'") if chunk_format != 'WAVE'
|
123
|
+
|
124
|
+
# Read in each of the sub-chunks
|
125
|
+
position = 0x0C
|
126
|
+
while(chunk_size-position) > 0 do
|
127
|
+
subchunk_id = read_fourchar
|
128
|
+
subchunk_size = read_longint
|
129
|
+
case subchunk_id
|
130
|
+
when 'fmt '
|
131
|
+
read_fmt_chunk(subchunk_size)
|
132
|
+
when 'fact'
|
133
|
+
read_fact_chunk(subchunk_size)
|
134
|
+
when 'data'
|
135
|
+
@data_size = subchunk_size
|
136
|
+
# Skip over the wave data
|
137
|
+
@io.seek(subchunk_size,IO::SEEK_CUR)
|
138
|
+
else
|
139
|
+
pos = sprintf("0x%x", position)
|
140
|
+
$stderr.puts "Warning: unsupported sub-chunk at #{pos}: #{subchunk_id}"
|
141
|
+
@io.seek(subchunk_size,IO::SEEK_CUR)
|
142
|
+
end
|
143
|
+
position += subchunk_size + 8
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
def read_fmt_chunk(size)
|
149
|
+
@audio_format_id = read_shortint
|
150
|
+
@channels = read_shortint
|
151
|
+
@sample_rate = read_longint
|
152
|
+
@byte_rate = read_longint
|
153
|
+
@block_align = read_shortint
|
154
|
+
@bits_per_sample = read_shortint
|
155
|
+
|
156
|
+
# Skip any extra parameters
|
157
|
+
@io.seek(size-16,IO::SEEK_CUR) if size > 16
|
158
|
+
end
|
159
|
+
|
160
|
+
def read_fact_chunk(size)
|
161
|
+
# Read in the number of samples
|
162
|
+
@samples = read_longint
|
163
|
+
|
164
|
+
# Skip any extra data
|
165
|
+
@io.seek(size-4,IO::SEEK_CUR) if size > 4
|
166
|
+
end
|
167
|
+
|
168
|
+
def read_fourchar
|
169
|
+
@io.read(4)
|
170
|
+
end
|
171
|
+
|
172
|
+
def read_longint
|
173
|
+
bytes = @io.read(4)
|
174
|
+
bytes ? bytes.unpack('V').first : nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def read_shortint
|
178
|
+
bytes = @io.read(2)
|
179
|
+
bytes ? bytes.unpack('v').first : nil
|
180
|
+
end
|
181
|
+
|
182
|
+
# Exception raised if there is a problem parsing the Wave file
|
183
|
+
class FileFormatError < Exception
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,433 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'waveinfo'
|
5
|
+
|
6
|
+
|
7
|
+
describe WaveInfo do
|
8
|
+
|
9
|
+
describe "parsing a Mono 11kHz PCM file with no 'fact' chunk" do
|
10
|
+
before :each do
|
11
|
+
@filepath = sample_path('sine_11k_mono_16bit_pcm')
|
12
|
+
@wav = WaveInfo.new( @filepath )
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should get the audio format id right" do
|
16
|
+
@wav.audio_format_id.should == 1
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should get the audio format name right" do
|
20
|
+
@wav.audio_format.should == 'PCM'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should get the number of channels right" do
|
24
|
+
@wav.channels.should == 1
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should get the sample rate right" do
|
28
|
+
@wav.sample_rate.should == 11025
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should get the byte rate right" do
|
32
|
+
@wav.byte_rate.should == 22050
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should get the block align value right" do
|
36
|
+
@wav.block_align.should == 2
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should get the bits per sample right" do
|
40
|
+
@wav.bits_per_sample.should == 16
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should get the audio length in bytes right" do
|
44
|
+
@wav.size.should == 8820
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should get the number of samples right" do
|
48
|
+
@wav.samples.should == 4410
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should get the audio duration right" do
|
52
|
+
@wav.duration.should == 0.4
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should know the name of the file read from" do
|
56
|
+
@wav.filename.should == File.basename(@filepath)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "parsing a Mono 8kHz GSM file with a 'fact' chunk" do
|
61
|
+
before :each do
|
62
|
+
@filepath = sample_path('sine_8k_mono_gsm')
|
63
|
+
@wav = WaveInfo.new( @filepath )
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should get the audio format id right" do
|
67
|
+
@wav.audio_format_id.should == 49
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should get the audio format name right" do
|
71
|
+
@wav.audio_format.should == 'GSM'
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should get the number of channels right" do
|
75
|
+
@wav.channels.should == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should get the sample rate right" do
|
79
|
+
@wav.sample_rate.should == 8000
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should get the byte rate right" do
|
83
|
+
@wav.byte_rate.should == 1625
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should get the block align value right" do
|
87
|
+
@wav.block_align.should == 65
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should get the bits per sample right" do
|
91
|
+
@wav.bits_per_sample.should == 0
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should get the audio length in bytes right" do
|
95
|
+
@wav.size.should == 650
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should get the number of samples right" do
|
99
|
+
@wav.samples.should == 3200
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should get the audio duration right" do
|
103
|
+
@wav.duration.should == 0.4
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should know the name of the file read from" do
|
107
|
+
@wav.filename.should == File.basename(@filepath)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "parsing a Stereo 44.1kHz 16-bit PCM file with a 'fact' chunk" do
|
112
|
+
before :each do
|
113
|
+
@filepath = sample_path('testcase_44k_stereo_16bit_pcm')
|
114
|
+
@wav = WaveInfo.new( @filepath )
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should get the audio format id right" do
|
118
|
+
@wav.audio_format_id.should == 1
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should get the audio format name right" do
|
122
|
+
@wav.audio_format.should == 'PCM'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should get the number of channels right" do
|
126
|
+
@wav.channels.should == 2
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should get the sample rate right" do
|
130
|
+
@wav.sample_rate.should == 44100
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should get the byte rate right" do
|
134
|
+
@wav.byte_rate.should == 176400
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should get the block align value right" do
|
138
|
+
@wav.block_align.should == 4
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should get the bits per sample right" do
|
142
|
+
@wav.bits_per_sample.should == 16
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should get the audio length in bytes right" do
|
146
|
+
@wav.size.should == 100000
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should get the number of samples right" do
|
150
|
+
@wav.samples.should == 25000
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should get the audio duration right" do
|
154
|
+
(@wav.duration * 1000).to_i.should == 566
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should know the name of the file read from" do
|
158
|
+
@wav.filename.should == File.basename(@filepath)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "parsing a Mono 11kHz Microsoft ADPCM file with a 'fact' chunk" do
|
163
|
+
before :each do
|
164
|
+
@filepath = sample_path('sine_11k_mono_ms_adpcm')
|
165
|
+
@wav = WaveInfo.new( @filepath )
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should get the audio format id right" do
|
169
|
+
@wav.audio_format_id.should == 2
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should get the audio format name right" do
|
173
|
+
@wav.audio_format.should == 'Microsoft ADPCM'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should get the number of channels right" do
|
177
|
+
@wav.channels.should == 1
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should get the sample rate right" do
|
181
|
+
@wav.sample_rate.should == 11025
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should get the byte rate right" do
|
185
|
+
@wav.byte_rate.should == 5784
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should get the block align value right" do
|
189
|
+
@wav.block_align.should == 128
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should get the bits per sample right" do
|
193
|
+
@wav.bits_per_sample.should == 4
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should get the audio length in bytes right" do
|
197
|
+
@wav.size.should == 2432
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should get the number of samples right" do
|
201
|
+
@wav.samples.should == 4410
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should get the audio duration right" do
|
205
|
+
@wav.duration.should == 0.4
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should know the name of the file read from" do
|
209
|
+
@wav.filename.should == File.basename(@filepath)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "parsing a Mono 11kHz 8-bit PCM file with no 'fact' chunk" do
|
214
|
+
before :each do
|
215
|
+
@filepath = sample_path('sine_11k_mono_8bit_pcm')
|
216
|
+
@wav = WaveInfo.new( @filepath )
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should get the audio format id right" do
|
220
|
+
@wav.audio_format_id.should == 1
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should get the audio format name right" do
|
224
|
+
@wav.audio_format.should == 'PCM'
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should get the number of channels right" do
|
228
|
+
@wav.channels.should == 1
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should get the sample rate right" do
|
232
|
+
@wav.sample_rate.should == 11025
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should get the byte rate right" do
|
236
|
+
@wav.byte_rate.should == 11025
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should get the block align value right" do
|
240
|
+
@wav.block_align.should == 1
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should get the bits per sample right" do
|
244
|
+
@wav.bits_per_sample.should == 8
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should get the audio length in bytes right" do
|
248
|
+
@wav.size.should == 4410
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should get the number of samples right" do
|
252
|
+
@wav.samples.should == 4410
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should get the audio duration right" do
|
256
|
+
@wav.duration.should == 0.4
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should know the name of the file read from" do
|
260
|
+
@wav.filename.should == File.basename(@filepath)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "parsing a Mono 11kHz a-law file with a 'fact' chunk" do
|
265
|
+
before :each do
|
266
|
+
@filepath = sample_path('sine_11k_mono_alaw')
|
267
|
+
@wav = WaveInfo.new( @filepath )
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should get the audio format id right" do
|
271
|
+
@wav.audio_format_id.should == 6
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should get the audio format name right" do
|
275
|
+
@wav.audio_format.should == 'a-law'
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should get the number of channels right" do
|
279
|
+
@wav.channels.should == 1
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should get the sample rate right" do
|
283
|
+
@wav.sample_rate.should == 11025
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should get the byte rate right" do
|
287
|
+
@wav.byte_rate.should == 11025
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should get the block align value right" do
|
291
|
+
@wav.block_align.should == 1
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should get the bits per sample right" do
|
295
|
+
@wav.bits_per_sample.should == 8
|
296
|
+
end
|
297
|
+
|
298
|
+
it "should get the audio length in bytes right" do
|
299
|
+
@wav.size.should == 4410
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should get the number of samples right" do
|
303
|
+
@wav.samples.should == 4410
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should get the audio duration right" do
|
307
|
+
@wav.duration.should == 0.4
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should know the name of the file read from" do
|
311
|
+
@wav.filename.should == File.basename(@filepath)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe "parsing a Mono 11kHz u-law file with a 'fact' chunk" do
|
316
|
+
before :each do
|
317
|
+
@filepath = sample_path('sine_11k_mono_ulaw')
|
318
|
+
@wav = WaveInfo.new( @filepath )
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should get the audio format id right" do
|
322
|
+
@wav.audio_format_id.should == 7
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should get the audio format name right" do
|
326
|
+
@wav.audio_format.should == 'u-law'
|
327
|
+
end
|
328
|
+
|
329
|
+
it "should get the number of channels right" do
|
330
|
+
@wav.channels.should == 1
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should get the sample rate right" do
|
334
|
+
@wav.sample_rate.should == 11025
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should get the byte rate right" do
|
338
|
+
@wav.byte_rate.should == 11025
|
339
|
+
end
|
340
|
+
|
341
|
+
it "should get the block align value right" do
|
342
|
+
@wav.block_align.should == 1
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should get the bits per sample right" do
|
346
|
+
@wav.bits_per_sample.should == 8
|
347
|
+
end
|
348
|
+
|
349
|
+
it "should get the audio length in bytes right" do
|
350
|
+
@wav.size.should == 4410
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should get the number of samples right" do
|
354
|
+
@wav.samples.should == 4410
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should get the audio duration right" do
|
358
|
+
@wav.duration.should == 0.4
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should know the name of the file read from" do
|
362
|
+
@wav.filename.should == File.basename(@filepath)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
describe "parsing a Mono 11kHz IMA ADPCM file with a 'fact' chunk" do
|
367
|
+
before :each do
|
368
|
+
@filepath = sample_path('sine_11k_mono_ima_adpcm')
|
369
|
+
@wav = WaveInfo.new( @filepath )
|
370
|
+
end
|
371
|
+
|
372
|
+
it "should get the audio format id right" do
|
373
|
+
@wav.audio_format_id.should == 17
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should get the audio format name right" do
|
377
|
+
@wav.audio_format.should == 'IMA ADPCM'
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should get the number of channels right" do
|
381
|
+
@wav.channels.should == 1
|
382
|
+
end
|
383
|
+
|
384
|
+
it "should get the sample rate right" do
|
385
|
+
@wav.sample_rate.should == 11025
|
386
|
+
end
|
387
|
+
|
388
|
+
it "should get the byte rate right" do
|
389
|
+
@wav.byte_rate.should == 5589
|
390
|
+
end
|
391
|
+
|
392
|
+
it "should get the block align value right" do
|
393
|
+
@wav.block_align.should == 256
|
394
|
+
end
|
395
|
+
|
396
|
+
it "should get the bits per sample right" do
|
397
|
+
@wav.bits_per_sample.should == 4
|
398
|
+
end
|
399
|
+
|
400
|
+
it "should get the audio length in bytes right" do
|
401
|
+
@wav.size.should == 2304
|
402
|
+
end
|
403
|
+
|
404
|
+
it "should get the number of samples right" do
|
405
|
+
@wav.samples.should == 4410
|
406
|
+
end
|
407
|
+
|
408
|
+
it "should get the audio duration right" do
|
409
|
+
@wav.duration.should == 0.4
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should know the name of the file read from" do
|
413
|
+
@wav.filename.should == File.basename(@filepath)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
describe "parsing an invalid WAVE file" do
|
418
|
+
it "should throw an exception if the first chunk id isn't 'RIFF'" do
|
419
|
+
data = StringIO.new("INVALID")
|
420
|
+
lambda { WaveInfo.new( data ) }.should raise_error(WaveInfo::FileFormatError)
|
421
|
+
end
|
422
|
+
|
423
|
+
it "should throw an exception if the chunk format isn't 'WAVE'" do
|
424
|
+
data = StringIO.new("RIFF\0\0\0\0INVALID")
|
425
|
+
lambda { WaveInfo.new( data ) }.should raise_error(WaveInfo::FileFormatError)
|
426
|
+
end
|
427
|
+
|
428
|
+
it "should not throw an exception if WAVE file is valid but has no sub-chunks" do
|
429
|
+
data = StringIO.new("RIFF\4\0\0\0WAVE")
|
430
|
+
lambda { WaveInfo.new( data ) }.should_not raise_error
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: waveinfo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas J Humfrey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-09 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: waveinfo is a pure-ruby gem to get the information from the headers of Wave (.wav) files.
|
17
|
+
email: njh@aelius.com
|
18
|
+
executables:
|
19
|
+
- waveinfo
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- COPYING
|
25
|
+
files:
|
26
|
+
- Rakefile
|
27
|
+
- lib/waveinfo.rb
|
28
|
+
- spec/spec_helper.rb
|
29
|
+
- spec/waveinfo_spec.rb
|
30
|
+
- samples/sine_11k_mono_16bit_pcm.wav
|
31
|
+
- samples/sine_11k_mono_8bit_pcm.wav
|
32
|
+
- samples/sine_11k_mono_alaw.wav
|
33
|
+
- samples/sine_11k_mono_ima_adpcm.wav
|
34
|
+
- samples/sine_11k_mono_ms_adpcm.wav
|
35
|
+
- samples/sine_11k_mono_ulaw.wav
|
36
|
+
- samples/sine_8k_mono_16bit_pcm.wav
|
37
|
+
- samples/sine_8k_mono_gsm.wav
|
38
|
+
- samples/testcase_44k_stereo_16bit_pcm.wav
|
39
|
+
- README
|
40
|
+
- COPYING
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://waveinfo.rubyforge.org
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: waveinfo
|
63
|
+
rubygems_version: 1.3.1
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: Pure-ruby gem to get the information from the headers of Wave (.wav) files.
|
67
|
+
test_files: []
|
68
|
+
|