lame 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +69 -14
- data/lib/lame.rb +7 -1
- data/lib/lame/encoder.rb +52 -6
- data/lib/lame/encoding/float_buffer_encoder.rb +15 -0
- data/lib/lame/encoding/flusher.rb +3 -1
- data/lib/lame/encoding/id3.rb +3 -1
- data/lib/lame/encoding/interleaved_buffer_encoder.rb +27 -0
- data/lib/lame/encoding/interleaved_float_buffer_encoder.rb +15 -0
- data/lib/lame/encoding/interleaved_short_buffer_encoder.rb +15 -0
- data/lib/lame/encoding/long_buffer_encoder.rb +15 -0
- data/lib/lame/encoding/short_buffer_encoder.rb +15 -0
- data/lib/lame/encoding/stereo_buffer_encoder.rb +28 -0
- data/lib/lame/encoding/vbr_info.rb +3 -1
- data/lib/lame/version.rb +1 -1
- data/spec/encoder_spec.rb +156 -45
- data/spec/encoding/interleaved_buffer_encoder_spec.rb +81 -0
- data/spec/encoding/{encode_short_buffer_spec.rb → stereo_buffer_encoder_spec.rb} +31 -10
- data/spec/integration/decoding_spec.rb +5 -2
- data/spec/integration/encoding_spec.rb +56 -55
- data/spec/integration/id3_tags_spec.rb +2 -1
- data/spec/lib/custom_matchers.rb +116 -0
- data/spec/lib/setter_getter.rb +32 -0
- data/spec/lib/wave_file_generator.rb +46 -0
- data/spec/spec_helper.rb +4 -147
- metadata +20 -8
- data/lib/lame/encoding/encode_short_buffer.rb +0 -26
- data/spec/files/dies-irae.wav +0 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LAME
|
4
|
+
module Encoding
|
5
|
+
|
6
|
+
shared_examples_for "a interleaved buffer encoder" do
|
7
|
+
# stubbing galore!
|
8
|
+
|
9
|
+
let(:framesize) { 1152 }
|
10
|
+
let(:samples) { stub(:size => framesize*2) }
|
11
|
+
let(:global_flags) { stub }
|
12
|
+
let(:configuration) { stub(Configuration, :global_flags => global_flags, :framesize => framesize, :output_buffer_size => 8640) }
|
13
|
+
|
14
|
+
subject(:encoder) { described_class.new(configuration) }
|
15
|
+
|
16
|
+
it "creates input buffers" do
|
17
|
+
LAME.stub(lame_function).and_return(0)
|
18
|
+
|
19
|
+
Buffer.should_receive(:create).with(data_type, samples)
|
20
|
+
|
21
|
+
encoder.encode_frame(samples)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "creates output buffer" do
|
25
|
+
LAME.stub(lame_function).and_return(0)
|
26
|
+
|
27
|
+
Buffer.stub(:create)
|
28
|
+
Buffer.should_receive(:create_empty).with(:uchar, 8640).and_return(stub.as_null_object)
|
29
|
+
|
30
|
+
encoder.encode_frame(samples)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "encodes the input" do
|
34
|
+
samples_stub = stub("samples")
|
35
|
+
output_stub = stub("output", :get_bytes => [])
|
36
|
+
|
37
|
+
Buffer.stub(:create).with(data_type, samples).and_return(samples_stub)
|
38
|
+
Buffer.stub(:create_empty).with(:uchar, 8640).and_return(output_stub)
|
39
|
+
|
40
|
+
LAME.should_receive(lame_function) do |flags, interleaved_buffer, framesize, output, output_size|
|
41
|
+
flags.should eql global_flags
|
42
|
+
interleaved_buffer.should eql samples_stub
|
43
|
+
framesize.should eql 1152
|
44
|
+
output.should eql output_stub
|
45
|
+
output_size.should eql 8640
|
46
|
+
|
47
|
+
0 # return value
|
48
|
+
end
|
49
|
+
|
50
|
+
encoder.encode_frame(samples)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns the encoded data" do
|
54
|
+
LAME.stub(lame_function).and_return(512)
|
55
|
+
|
56
|
+
mp3_data = stub
|
57
|
+
output = stub
|
58
|
+
output.stub(:get_bytes).with(0, 512).and_return(mp3_data)
|
59
|
+
|
60
|
+
Buffer.stub(:create)
|
61
|
+
Buffer.stub(:create_empty).with(:uchar, 8640).and_return(output)
|
62
|
+
|
63
|
+
encoder.encode_frame(samples).should eql mp3_data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe InterleavedShortBufferEncoder do
|
68
|
+
it_should_behave_like "a interleaved buffer encoder" do
|
69
|
+
let(:data_type) { :short }
|
70
|
+
let(:lame_function) { :lame_encode_buffer_interleaved }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe InterleavedFloatBufferEncoder do
|
75
|
+
it_should_behave_like "a interleaved buffer encoder" do
|
76
|
+
let(:data_type) { :float }
|
77
|
+
let(:lame_function) { :lame_encode_buffer_interleaved_ieee_float }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module LAME
|
4
4
|
module Encoding
|
5
|
-
describe EncodeShortBuffer do
|
6
5
|
|
6
|
+
shared_examples_for "a stereo buffer encoder" do
|
7
7
|
# stubbing galore!
|
8
8
|
|
9
9
|
let(:framesize) { 1152 }
|
@@ -12,19 +12,19 @@ module LAME
|
|
12
12
|
let(:global_flags) { stub }
|
13
13
|
let(:configuration) { stub(Configuration, :global_flags => global_flags, :framesize => framesize, :output_buffer_size => 8640) }
|
14
14
|
|
15
|
-
subject(:encoder) {
|
15
|
+
subject(:encoder) { described_class.new(configuration) }
|
16
16
|
|
17
17
|
it "creates input buffers" do
|
18
|
-
LAME.stub(
|
18
|
+
LAME.stub(lame_function).and_return(0)
|
19
19
|
|
20
|
-
Buffer.should_receive(:create).with(
|
21
|
-
Buffer.should_receive(:create).with(
|
20
|
+
Buffer.should_receive(:create).with(data_type, left)
|
21
|
+
Buffer.should_receive(:create).with(data_type, right)
|
22
22
|
|
23
23
|
encoder.encode_frame(left, right)
|
24
24
|
end
|
25
25
|
|
26
26
|
it "creates output buffer" do
|
27
|
-
LAME.stub(
|
27
|
+
LAME.stub(lame_function).and_return(0)
|
28
28
|
|
29
29
|
Buffer.stub(:create)
|
30
30
|
Buffer.should_receive(:create_empty).with(:uchar, 8640).and_return(stub.as_null_object)
|
@@ -37,11 +37,11 @@ module LAME
|
|
37
37
|
right_stub = stub("right")
|
38
38
|
output_stub = stub("output", :get_bytes => [])
|
39
39
|
|
40
|
-
Buffer.stub(:create).with(
|
41
|
-
Buffer.stub(:create).with(
|
40
|
+
Buffer.stub(:create).with(data_type, left).and_return(left_stub)
|
41
|
+
Buffer.stub(:create).with(data_type, right).and_return(right_stub)
|
42
42
|
Buffer.stub(:create_empty).with(:uchar, 8640).and_return(output_stub)
|
43
43
|
|
44
|
-
LAME.should_receive(
|
44
|
+
LAME.should_receive(lame_function) do |flags, left_buffer, right_buffer, framesize, output, output_size|
|
45
45
|
flags.should eql global_flags
|
46
46
|
left_buffer.should eql left_stub
|
47
47
|
right_buffer.should eql right_stub
|
@@ -56,7 +56,7 @@ module LAME
|
|
56
56
|
end
|
57
57
|
|
58
58
|
it "returns the encoded data" do
|
59
|
-
LAME.stub(
|
59
|
+
LAME.stub(lame_function).and_return(512)
|
60
60
|
|
61
61
|
mp3_data = stub
|
62
62
|
output = stub
|
@@ -68,5 +68,26 @@ module LAME
|
|
68
68
|
encoder.encode_frame(left, right).should eql mp3_data
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
describe ShortBufferEncoder do
|
73
|
+
it_should_behave_like "a stereo buffer encoder" do
|
74
|
+
let(:data_type) { :short }
|
75
|
+
let(:lame_function) { :lame_encode_buffer }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe FloatBufferEncoder do
|
80
|
+
it_should_behave_like "a stereo buffer encoder" do
|
81
|
+
let(:data_type) { :float }
|
82
|
+
let(:lame_function) { :lame_encode_buffer_ieee_float }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe LongBufferEncoder do
|
87
|
+
it_should_behave_like "a stereo buffer encoder" do
|
88
|
+
let(:data_type) { :long }
|
89
|
+
let(:lame_function) { :lame_encode_buffer_long2 }
|
90
|
+
end
|
91
|
+
end
|
71
92
|
end
|
72
93
|
end
|
@@ -10,8 +10,9 @@ describe "Decoding", :slow => true do
|
|
10
10
|
decoder = LAME::Decoder.new(mp3_file)
|
11
11
|
|
12
12
|
format = WaveFile::Format.new(decoder.channel_mode, :pcm_16, decoder.sample_rate)
|
13
|
+
output = Tempfile.new('output.wav')
|
13
14
|
|
14
|
-
WaveFile::Writer.new(
|
15
|
+
WaveFile::Writer.new(output.path, format) do |writer|
|
15
16
|
|
16
17
|
decoder.each_decoded_frame do |decoded_frame|
|
17
18
|
buffer = WaveFile::Buffer.new(decoded_frame.samples, format)
|
@@ -57,9 +58,11 @@ describe "Decoding", :slow => true do
|
|
57
58
|
puts "framenum: #{@mp3_data[:framenum]}"
|
58
59
|
end
|
59
60
|
|
61
|
+
output = Tempfile.new('output.wav')
|
62
|
+
|
60
63
|
# read mp3_data (number of frames etc)
|
61
64
|
format = WaveFile::Format.new(:stereo, :pcm_16, 44100)
|
62
|
-
WaveFile::Writer.new(
|
65
|
+
WaveFile::Writer.new(output.path, format) do |writer|
|
63
66
|
|
64
67
|
# See get_audio.c:2082 #lame_decode_fromfile
|
65
68
|
#
|
@@ -4,12 +4,65 @@ require 'wavefile'
|
|
4
4
|
|
5
5
|
describe "Encoding", :slow => true do
|
6
6
|
|
7
|
-
let(:
|
8
|
-
let(:
|
9
|
-
let(:
|
7
|
+
let(:wav_file) { WaveFileGenerator.new(:length => 2).generate }
|
8
|
+
let(:wav_path) { wav_file.path }
|
9
|
+
let(:mp3_path_raw) { Tempfile.new("output-raw.mp3") }
|
10
|
+
let(:mp3_path_api) { Tempfile.new("output-api.mp3") }
|
10
11
|
|
11
12
|
let(:wav_reader) { WaveFile::Reader.new(wav_path) }
|
12
13
|
|
14
|
+
it "encodes a file by api" do
|
15
|
+
|
16
|
+
encoder = LAME::Encoder.new
|
17
|
+
|
18
|
+
encoder.configure do |config|
|
19
|
+
config.id3.write_automatic = false
|
20
|
+
config.id3.v2 = true
|
21
|
+
config.id3.title = "Dies Irae"
|
22
|
+
config.id3.genre = "Classical"
|
23
|
+
|
24
|
+
#config.bitrate = 192
|
25
|
+
|
26
|
+
# config.preset = :V0 # doesn't work?
|
27
|
+
config.vbr.mode = :vbr_default
|
28
|
+
config.vbr.q = 0
|
29
|
+
end
|
30
|
+
|
31
|
+
File.open(mp3_path_api, "wb") do |file|
|
32
|
+
|
33
|
+
id3v2_size = 0
|
34
|
+
encoder.id3v2 do |tag|
|
35
|
+
file.write tag
|
36
|
+
id3v2_size = tag.size
|
37
|
+
end
|
38
|
+
|
39
|
+
wav_reader.each_buffer(encoder.framesize) do |read_buffer|
|
40
|
+
left = read_buffer.samples.map { |s| s[0] }
|
41
|
+
right = read_buffer.samples.map { |s| s[1] }
|
42
|
+
|
43
|
+
encoder.encode_short(left, right) do |mp3|
|
44
|
+
file.write mp3
|
45
|
+
end
|
46
|
+
end
|
47
|
+
encoder.flush do |flush_frame|
|
48
|
+
file.write(flush_frame)
|
49
|
+
end
|
50
|
+
|
51
|
+
encoder.id3v1 do |tag|
|
52
|
+
file.write tag
|
53
|
+
end
|
54
|
+
|
55
|
+
encoder.vbr_frame do |vbr_frame|
|
56
|
+
file.seek(id3v2_size)
|
57
|
+
file.write(vbr_frame)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO: Need a better way to test output..
|
63
|
+
# Digest::MD5.hexdigest(File.read(mp3_path_api)).should eql "d1cd92c106e7aac4f5291fd141a19e10"
|
64
|
+
end
|
65
|
+
|
13
66
|
# This test serves as an example how to use the LAME API
|
14
67
|
it "encodes a wav file" do
|
15
68
|
|
@@ -71,56 +124,4 @@ describe "Encoding", :slow => true do
|
|
71
124
|
# Digest::MD5.hexdigest(File.read(mp3_path_raw)).should eql "84a1ce7994bb4a54fc13fb5381ebac40"
|
72
125
|
end
|
73
126
|
|
74
|
-
it "encodes a file by api" do
|
75
|
-
|
76
|
-
encoder = LAME::Encoder.new
|
77
|
-
|
78
|
-
encoder.configure do |config|
|
79
|
-
config.id3.write_automatic = false
|
80
|
-
config.id3.v2 = true
|
81
|
-
config.id3.title = "Dies Irae"
|
82
|
-
config.id3.genre = "Classical"
|
83
|
-
|
84
|
-
#config.bitrate = 192
|
85
|
-
|
86
|
-
# config.preset = :V0 # doesn't work?
|
87
|
-
config.vbr.mode = :vbr_default
|
88
|
-
config.vbr.q = 0
|
89
|
-
end
|
90
|
-
|
91
|
-
File.open(mp3_path_api, "wb") do |file|
|
92
|
-
|
93
|
-
id3v2_size = 0
|
94
|
-
encoder.id3v2 do |tag|
|
95
|
-
file.write tag
|
96
|
-
id3v2_size = tag.size
|
97
|
-
end
|
98
|
-
|
99
|
-
wav_reader.each_buffer(encoder.framesize) do |read_buffer|
|
100
|
-
left = read_buffer.samples.map { |s| s[0] }
|
101
|
-
right = read_buffer.samples.map { |s| s[1] }
|
102
|
-
|
103
|
-
encoder.encode_short(left, right) do |mp3|
|
104
|
-
file.write mp3
|
105
|
-
end
|
106
|
-
end
|
107
|
-
encoder.flush do |flush_frame|
|
108
|
-
file.write(flush_frame)
|
109
|
-
end
|
110
|
-
|
111
|
-
encoder.id3v1 do |tag|
|
112
|
-
file.write tag
|
113
|
-
end
|
114
|
-
|
115
|
-
encoder.vbr_frame do |vbr_frame|
|
116
|
-
file.seek(id3v2_size)
|
117
|
-
file.write(vbr_frame)
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
121
|
-
|
122
|
-
# TODO: Need a better way to test output..
|
123
|
-
# Digest::MD5.hexdigest(File.read(mp3_path_api)).should eql "d1cd92c106e7aac4f5291fd141a19e10"
|
124
|
-
end
|
125
|
-
|
126
127
|
end
|
@@ -4,7 +4,8 @@ require 'mp3info'
|
|
4
4
|
|
5
5
|
describe "ID3 tags", :slow => true do
|
6
6
|
|
7
|
-
let(:
|
7
|
+
let(:wav_file) { WaveFileGenerator.new(:length => 2).generate }
|
8
|
+
let(:wav_path) { wav_file.path }
|
8
9
|
let(:mp3_id3_path) { File.expand_path(File.join(File.dirname(__FILE__), '../files/dies-irae-id3-raw.mp3')) }
|
9
10
|
let(:wav_reader) { WaveFile::Reader.new(wav_path) }
|
10
11
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# Validate existence of a getter, setter and the default value.
|
2
|
+
RSpec::Matchers.define :have_flag do |expected|
|
3
|
+
include SetterGetter
|
4
|
+
|
5
|
+
chain :for do |flags_pointer|
|
6
|
+
@flags_pointer = flags_pointer
|
7
|
+
end
|
8
|
+
|
9
|
+
chain :with_value do |value|
|
10
|
+
@value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
match do |actual|
|
14
|
+
has_getter?(actual, expected) &&
|
15
|
+
has_setter?(actual, expected) &&
|
16
|
+
has_value?(actual, expected)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validate setting a value.
|
21
|
+
RSpec::Matchers.define :be_able_to_set do |expected|
|
22
|
+
include SetterGetter
|
23
|
+
|
24
|
+
chain :for do |flags_pointer|
|
25
|
+
@flags_pointer = flags_pointer
|
26
|
+
end
|
27
|
+
|
28
|
+
chain :to do |value|
|
29
|
+
@value = value
|
30
|
+
end
|
31
|
+
|
32
|
+
chain :and_return do |value|
|
33
|
+
@return = value
|
34
|
+
end
|
35
|
+
|
36
|
+
match do |actual|
|
37
|
+
set_value(actual, expected) &&
|
38
|
+
has_value?(actual, expected)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Validate getting a value.
|
43
|
+
RSpec::Matchers.define :have_getter do |expected|
|
44
|
+
include SetterGetter
|
45
|
+
|
46
|
+
chain :for do |flags_pointer|
|
47
|
+
@flags_pointer = flags_pointer
|
48
|
+
end
|
49
|
+
|
50
|
+
chain :with_value do |value|
|
51
|
+
@value = value
|
52
|
+
end
|
53
|
+
|
54
|
+
match do |actual|
|
55
|
+
has_getter?(actual, expected) &&
|
56
|
+
has_value?(actual, expected)
|
57
|
+
end
|
58
|
+
|
59
|
+
failure_message_for_should do |actual|
|
60
|
+
if !has_getter?(actual, expected)
|
61
|
+
"expected that #{actual} would have a getter for field :#{expected}"
|
62
|
+
elsif @value && !has_value?(actual, expected)
|
63
|
+
actual_value = actual_value(actual, expected)
|
64
|
+
"expected field :#{expected} to have a value of #{@value}, but got #{actual_value}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Validate delegation to global_flags.
|
70
|
+
RSpec::Matchers.define :delegate do |from|
|
71
|
+
include SetterGetter
|
72
|
+
|
73
|
+
chain :to do |target|
|
74
|
+
@target = target
|
75
|
+
end
|
76
|
+
|
77
|
+
match do |subject|
|
78
|
+
@from = from
|
79
|
+
has_setter?(LAME, target) &&
|
80
|
+
delegates_setter? &&
|
81
|
+
has_getter?(LAME, target) &&
|
82
|
+
delegates_getter?
|
83
|
+
end
|
84
|
+
|
85
|
+
def delegates_setter?
|
86
|
+
LAME.should_receive(:"lame_set_#{target}").with(subject.global_flags, anything)
|
87
|
+
subject.send(:"#{from}=", double)
|
88
|
+
true
|
89
|
+
rescue => e
|
90
|
+
# TODO: save raised exception for better failure message
|
91
|
+
false
|
92
|
+
end
|
93
|
+
|
94
|
+
def delegates_getter?
|
95
|
+
LAME.should_receive(:"lame_get_#{target}").with(subject.global_flags)
|
96
|
+
subject.send(:"#{from}")
|
97
|
+
true
|
98
|
+
rescue => e
|
99
|
+
# TODO: save raised exception for better failure message
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
failure_message_for_should do |actual|
|
104
|
+
"expected #{subject.class} to delegate :#{from} to LAME.lame_set_#{target}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def target
|
108
|
+
@target || from
|
109
|
+
end
|
110
|
+
|
111
|
+
def from
|
112
|
+
@from
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SetterGetter
|
2
|
+
def has_getter?(lame, flag)
|
3
|
+
lame.respond_to?(:"lame_get_#{flag}")
|
4
|
+
end
|
5
|
+
|
6
|
+
def has_setter?(lame, flag)
|
7
|
+
lame.respond_to?(:"lame_set_#{flag}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_value(lame, flag)
|
11
|
+
lame.send(:"lame_set_#{flag}", @flags_pointer, @value) == return_value
|
12
|
+
end
|
13
|
+
|
14
|
+
def return_value
|
15
|
+
defined?(@return) ? @return : 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_value?(lame, flag)
|
19
|
+
if @value && @value.is_a?(Float)
|
20
|
+
actual = actual_value(lame, flag)
|
21
|
+
(actual - @value).abs < 0.0001
|
22
|
+
elsif @value
|
23
|
+
actual_value(lame, flag) == @value
|
24
|
+
else
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def actual_value(lame, flag)
|
30
|
+
lame.send(:"lame_get_#{flag}", @flags_pointer)
|
31
|
+
end
|
32
|
+
end
|