lame 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +20 -0
  2. data/.rspec +3 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +181 -0
  8. data/Rakefile +6 -0
  9. data/docs/id3v2.4.0-structure.txt +731 -0
  10. data/docs/lame-3.99.5.h +1323 -0
  11. data/lame.gemspec +28 -0
  12. data/lib/lame.rb +31 -0
  13. data/lib/lame/buffer.rb +21 -0
  14. data/lib/lame/configuration.rb +228 -0
  15. data/lib/lame/decoder.rb +38 -0
  16. data/lib/lame/decoding/decoded_frame.rb +25 -0
  17. data/lib/lame/decoding/id3_tag_parser.rb +53 -0
  18. data/lib/lame/decoding/mp3_data_header_parser.rb +64 -0
  19. data/lib/lame/decoding/mpeg_audio_frame_finder.rb +46 -0
  20. data/lib/lame/decoding/mpeg_audio_frame_matcher.rb +98 -0
  21. data/lib/lame/decoding/single_frame_decoder.rb +51 -0
  22. data/lib/lame/decoding/stream_decoder.rb +37 -0
  23. data/lib/lame/delegation.rb +68 -0
  24. data/lib/lame/encoder.rb +73 -0
  25. data/lib/lame/encoding/encode_short_buffer.rb +26 -0
  26. data/lib/lame/encoding/flusher.rb +22 -0
  27. data/lib/lame/encoding/id3.rb +46 -0
  28. data/lib/lame/encoding/vbr_info.rb +22 -0
  29. data/lib/lame/error.rb +13 -0
  30. data/lib/lame/ffi.rb +20 -0
  31. data/lib/lame/ffi/decode_flags.rb +19 -0
  32. data/lib/lame/ffi/enums.rb +75 -0
  33. data/lib/lame/ffi/functions.rb +272 -0
  34. data/lib/lame/ffi/global_flags.rb +20 -0
  35. data/lib/lame/ffi/mp3_data.rb +37 -0
  36. data/lib/lame/ffi/version.rb +17 -0
  37. data/lib/lame/version.rb +3 -0
  38. data/spec/buffer_spec.rb +26 -0
  39. data/spec/configuration_spec.rb +391 -0
  40. data/spec/decoder_spec.rb +120 -0
  41. data/spec/decoding/decoded_frame_spec.rb +44 -0
  42. data/spec/decoding/id3_tag_parser_spec.rb +54 -0
  43. data/spec/decoding/mp3_data_header_parser_spec.rb +95 -0
  44. data/spec/decoding/mpeg_audio_frame_finder_spec.rb +50 -0
  45. data/spec/decoding/mpeg_audio_frame_matcher_spec.rb +179 -0
  46. data/spec/decoding/single_frame_decoder_spec.rb +104 -0
  47. data/spec/decoding/stream_decoder_spec.rb +43 -0
  48. data/spec/delegation_spec.rb +146 -0
  49. data/spec/encoder_spec.rb +279 -0
  50. data/spec/encoding/encode_short_buffer_spec.rb +72 -0
  51. data/spec/encoding/flusher_spec.rb +47 -0
  52. data/spec/encoding/id3_spec.rb +106 -0
  53. data/spec/encoding/vbr_info_spec.rb +47 -0
  54. data/spec/ffi/decode_flags_spec.rb +16 -0
  55. data/spec/ffi/encoding_spec.rb +223 -0
  56. data/spec/ffi/global_flags_spec.rb +542 -0
  57. data/spec/ffi/id3tag_spec.rb +135 -0
  58. data/spec/ffi/mp3_data_spec.rb +26 -0
  59. data/spec/files/dies-irae.wav +0 -0
  60. data/spec/integration/decoding_spec.rb +179 -0
  61. data/spec/integration/encoding_spec.rb +126 -0
  62. data/spec/integration/id3_tags_spec.rb +96 -0
  63. data/spec/spec_helper.rb +175 -0
  64. metadata +254 -0
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe SingleFrameDecoder do
6
+
7
+ subject(:decoder) { SingleFrameDecoder.new(decode_flags, mp3_data) }
8
+
9
+ let(:decode_flags) { stub("decode flags") }
10
+ let(:mp3_data) { stub("mp3 data") }
11
+ let(:data) { "a"*1024 }
12
+
13
+ it "always checks if there is a decoded frame in the internal buffer" do
14
+ # initial decoded frame
15
+ LAME.should_receive(:hip_decode1_headers) do |flags, in_buffer, in_size, out_left, out_right, mp3_data_arg|
16
+ flags.should eql decode_flags
17
+ in_buffer.size.should eql 0
18
+ in_size.should eql 0
19
+ out_left.size.should eql 1152*2 # short is 2 bytes
20
+ out_right.size.should eql 1152*2
21
+ mp3_data_arg.should eql mp3_data
22
+ 0
23
+ end
24
+ # new data
25
+ LAME.stub(:hip_decode1_headers).and_return(0)
26
+
27
+ decoder.decode(data)
28
+ end
29
+
30
+ it "writes the input data into the LAME decoder" do
31
+ # initial
32
+ LAME.should_receive(:hip_decode1_headers) do |_, in_buffer, _, _ , _, _|
33
+ in_buffer.size.should eql 0
34
+ 0
35
+ end
36
+ # new data
37
+ LAME.should_receive(:hip_decode1_headers) do |flags, in_buffer, in_size, out_left, out_right, mp3_data_arg|
38
+ flags.should eql decode_flags
39
+ in_buffer.size.should eql 1024
40
+ in_size.should eql 1024
41
+ out_left.size.should eql 1152*2 # short is 2 bytes
42
+ out_right.size.should eql 1152*2
43
+ mp3_data_arg.should eql mp3_data
44
+ 0
45
+ end
46
+
47
+ decoder.decode(data)
48
+ end
49
+
50
+ it "decodes until no more frames were decoded" do
51
+ LAME.stub(:hip_decode1_headers).and_return(0, 1, 1, 0)
52
+ LAME.should_receive(:hip_decode1_headers).exactly(4).times
53
+
54
+ decoder.decode(data) {}
55
+ end
56
+
57
+ it "yields decoded frames if one is left in internal buffer" do
58
+ LAME.stub(:hip_decode1_headers).and_return(1, 0)
59
+
60
+ expect { |block|
61
+ decoder.decode(data, &block)
62
+ }.to yield_successive_args(DecodedFrame)
63
+ end
64
+
65
+ it "yields decoded frames for new data" do
66
+ LAME.stub(:hip_decode1_headers).and_return(0, 1, 1, 0)
67
+
68
+ expect { |block|
69
+ decoder.decode(data, &block)
70
+ }.to yield_successive_args(DecodedFrame, DecodedFrame)
71
+ end
72
+
73
+ it "raises an error if decoding failed" do
74
+ LAME.stub(:hip_decode1_headers).and_return(-1)
75
+
76
+ expect {
77
+ decoder.decode(data)
78
+ }.to raise_error(DecodingError)
79
+ end
80
+
81
+ # Enable these tests once next rspec-expectations has been released
82
+ xit "yields until no more data is decoded" do
83
+ LAME.stub(:hip_decode1_headers).and_return(0, 1, 1, 0)
84
+
85
+ LAME.should_receive(:hip_decode1_headers).exactly(4).times
86
+
87
+ expect {
88
+ decoder.decode(data)
89
+ }.to yield_control.exactly(2).times
90
+ end
91
+
92
+ xit "yields if the decoder had a decoded frame " do
93
+ LAME.stub(:hip_decode1_headers).and_return(1, 1, 1, 0)
94
+
95
+ LAME.should_receive(:hip_decode1_headers).exactly(4).times
96
+
97
+ expect {
98
+ decoder.decode(data)
99
+ }.to yield_control.exactly(3).times
100
+ end
101
+
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe StreamDecoder do
6
+
7
+ subject(:decoder) { StreamDecoder.new(decode_flags, mp3_data, stream) }
8
+
9
+ let(:decode_flags) { stub("decode flags") }
10
+ let(:mp3_data) { stub("mp3 data") }
11
+
12
+ let(:stream) { StringIO.new(stream_string) }
13
+ let(:stream_string) { "a" * 1024 + "b" * 1024}
14
+
15
+ it "creates a single frame decoder" do
16
+ SingleFrameDecoder.should_receive(:new).with(decode_flags, mp3_data)
17
+ decoder
18
+ end
19
+
20
+ it "it passes chunks of stream into the single frame decoder" do
21
+ single_frame_decoder = stub
22
+ SingleFrameDecoder.stub(:new).and_return(single_frame_decoder)
23
+
24
+ single_frame_decoder.should_receive(:decode).exactly(:twice)
25
+
26
+ decoder.each_decoded_frame
27
+ end
28
+
29
+ it "yields the decoded frame" do
30
+ single_frame_decoder = stub
31
+ SingleFrameDecoder.stub(:new).and_return(single_frame_decoder)
32
+
33
+ single_frame_decoder.stub(:decode).with("a"*1024).and_yield(:one)
34
+ single_frame_decoder.stub(:decode).with("b"*1024).and_yield(:two).and_yield(:three)
35
+
36
+ expect { |block|
37
+ decoder.each_decoded_frame(&block)
38
+ }.to yield_successive_args(:one, :two, :three)
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+
5
+ class FakeEncoder
6
+ extend Delegation
7
+
8
+ attr_accessor :global_flags
9
+
10
+ delegate_alias_to_lame :foo => :bar
11
+ delegate_to_lame :baz
12
+ delegate_id3_to_lame :qux
13
+ end
14
+
15
+ describe Delegation do
16
+
17
+ let(:global_flags) { stub }
18
+ subject { FakeEncoder.new }
19
+
20
+ before do
21
+ subject.global_flags = global_flags
22
+ end
23
+
24
+ context "#delegate_alias_to_lame" do
25
+ it "delegates #foo= to LAME" do
26
+ LAME.should_receive(:lame_set_bar).with(global_flags, anything)
27
+ subject.foo = stub
28
+ end
29
+
30
+ it "delegates #foo to LAME" do
31
+ LAME.should_receive(:lame_get_bar).with(global_flags)
32
+ subject.foo
33
+ end
34
+
35
+ it "delegates #foo? to LAME" do
36
+ LAME.should_receive(:lame_get_bar).with(global_flags)
37
+ subject.foo?
38
+ end
39
+ end
40
+
41
+ context "#delegate_to_lame" do
42
+ it "delegates #baz= to LAME" do
43
+ LAME.should_receive(:lame_set_baz).with(global_flags, anything)
44
+ subject.baz = stub
45
+ end
46
+
47
+ it "delegates #baz to LAME" do
48
+ LAME.should_receive(:lame_get_baz).with(global_flags)
49
+ subject.baz
50
+ end
51
+
52
+ it "delegates #baz? to LAME" do
53
+ LAME.should_receive(:lame_get_baz).with(global_flags)
54
+ subject.baz?
55
+ end
56
+ end
57
+
58
+ context "#delegate_id3_to_lame" do
59
+ it "delegates #qux= to LAME" do
60
+ LAME.should_receive(:id3tag_set_qux).with(global_flags, anything)
61
+ subject.qux = stub
62
+ end
63
+ end
64
+
65
+ context "type conversion" do
66
+ it "converts the input type" do
67
+ value = stub
68
+ Delegation::TypeConvertor.should_receive(:convert).with(value)
69
+ LAME.stub(:lame_set_baz)
70
+ subject.baz = value
71
+ end
72
+
73
+ it "passes on converted value to setter" do
74
+ value = stub
75
+ converted_value = stub
76
+ Delegation::TypeConvertor.stub(:convert).and_return(converted_value)
77
+ LAME.should_receive(:lame_set_baz).with(global_flags, converted_value)
78
+ subject.baz = value
79
+ end
80
+
81
+ it "converts question mark style getters to return booleans" do
82
+ LAME.stub(:lame_get_baz).and_return(0)
83
+ Delegation::TypeConvertor.should_receive(:convert_return).with(0)
84
+ subject.baz?
85
+ end
86
+
87
+ it "converts question mark style getters to return booleans" do
88
+ LAME.stub(:lame_get_baz)
89
+ Delegation::TypeConvertor.stub(:convert_return).and_return(false)
90
+ subject.baz?.should eql false
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ describe Delegation::TypeConvertor do
97
+
98
+ subject(:converter) { Delegation::TypeConvertor }
99
+
100
+ describe "#convert" do
101
+ it "converts true to 1" do
102
+ converter.convert(true).should eql 1
103
+ end
104
+
105
+ it "converts false to 0" do
106
+ converter.convert(false).should eql 0
107
+ end
108
+
109
+ it "converts a string to a pointer with correct value" do
110
+ input = "some string"
111
+ value = converter.convert(input)
112
+ value.should be_a(::FFI::MemoryPointer)
113
+ value.get_string(0).should eql input
114
+ end
115
+
116
+ it "does not convert other values" do
117
+ converter.convert(:foo).should eql :foo
118
+ converter.convert(1.2).should eql 1.2
119
+ end
120
+ end
121
+
122
+ describe "#convert_return" do
123
+ it "converts 1 to true" do
124
+ converter.convert_return(1).should eql true
125
+ end
126
+
127
+ it "converts 0 to false" do
128
+ converter.convert_return(0).should eql false
129
+ end
130
+
131
+ it "converts 0.0 to false" do
132
+ converter.convert_return(0.0).should eql false
133
+ end
134
+
135
+ it "returns truthy to true" do
136
+ converter.convert_return(:truthy).should eql true
137
+ converter.convert_return("truthy").should eql true
138
+ converter.convert_return(Object).should eql true
139
+ converter.convert_return(Object.new).should eql true
140
+ converter.convert_return(4.2).should eql true
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ end
@@ -0,0 +1,279 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ describe Encoder do
5
+
6
+ subject(:encoder) { Encoder.new }
7
+
8
+ context "initialization" do
9
+
10
+ it "initializes GlobalFlags" do
11
+ FFI::GlobalFlags.should_receive(:new)
12
+ Encoder.new
13
+ end
14
+
15
+ end
16
+
17
+ context "configuration" do
18
+
19
+ let(:configuration) { stub(Configuration).as_null_object }
20
+
21
+ before do
22
+ Configuration.stub(:new).and_return(configuration)
23
+ end
24
+
25
+ it "initializes a Configuration object" do
26
+ Configuration.should_receive(:new).with(kind_of(GlobalFlags))
27
+ encoder.configure { }
28
+ end
29
+
30
+ it "yields the Configuration object" do
31
+ expect { |block|
32
+ encoder.configure(&block)
33
+ }.to yield_with_args(configuration)
34
+ end
35
+
36
+ it "assigns the Configuration object" do
37
+ encoder.configure { }
38
+ encoder.configuration.should eql configuration
39
+ end
40
+
41
+ it "applies the configuration" do
42
+ configuration.stub(:applied?).and_return(false)
43
+ configuration.should_receive(:apply!)
44
+ encoder.configure { }
45
+ end
46
+
47
+ it "gets the framesize" do
48
+ configuration.should_receive(:framesize).and_return(1234)
49
+ encoder.framesize.should eql 1234
50
+ end
51
+ end
52
+
53
+ context "encoding" do
54
+
55
+ let(:left) { [0] }
56
+ let(:right) { [0] }
57
+ let(:global_flags) { subject.global_flags }
58
+ let(:configuration) { stub(Configuration, :framesize => 100) }
59
+
60
+ before do
61
+ Configuration.stub(:new).and_return(configuration)
62
+ configuration.stub(:applied?).and_return(true)
63
+ Encoding::EncodeShortBuffer.stub(:new).and_return(stub.as_null_object)
64
+ end
65
+
66
+ it "applies the configuration if not done already" do
67
+ configuration.stub(:applied?).and_return(false)
68
+ configuration.should_receive(:apply!)
69
+ encoder.encode_short(left, right) { }
70
+ end
71
+
72
+ it "does not apply the configuration if already applied" do
73
+ configuration.stub(:applied?).and_return(true)
74
+ configuration.should_not_receive(:apply!)
75
+ encoder.encode_short(left, right) { }
76
+ end
77
+
78
+ context "delegation" do
79
+ let(:short_encoder) { stub.as_null_object }
80
+
81
+ before do
82
+ Encoding::EncodeShortBuffer.stub(:new).and_return(short_encoder)
83
+ end
84
+
85
+ it "create a short encoder with configuration" do
86
+ Encoding::EncodeShortBuffer.should_receive(:new).with(configuration)
87
+
88
+ encoder.encode_short(left, right) { }
89
+ end
90
+
91
+ it "delegates encoding to the short encoder" do
92
+ left.stub(:length => 100) # exactly framesize
93
+ short_encoder.should_receive(:encode_frame).with(left, right)
94
+
95
+ encoder.encode_short(left, right) { }
96
+ end
97
+
98
+ it "yields the encoder results" do
99
+ mp3_data = stub
100
+ short_encoder.stub(:encode_frame).and_return(mp3_data)
101
+
102
+ expect { |block|
103
+ encoder.encode_short(left, right, &block)
104
+ }.to yield_with_args(mp3_data)
105
+ end
106
+
107
+ it "delegates multiple times for large input" do
108
+ right = left = [0]*150 # larger than framesize
109
+
110
+ short_encoder.should_receive(:encode_frame) do |left_frame, right_frame|
111
+ left_frame.length.should eql 100
112
+ right_frame.length.should eql 100
113
+ end
114
+
115
+ short_encoder.should_receive(:encode_frame) do |left_frame, right_frame|
116
+ left_frame.length.should eql 50
117
+ right_frame.length.should eql 50
118
+ end
119
+
120
+ encoder.encode_short(left, right) { }
121
+ end
122
+
123
+ it "yields multiple times for large input" do
124
+ mp3_data1 = stub("frame1")
125
+ mp3_data2 = stub("frame2")
126
+
127
+ left = [0]*150 # larger than framesize
128
+
129
+ short_encoder.stub(:encode_frame).and_return(mp3_data1, mp3_data2)
130
+
131
+ expect { |block|
132
+ encoder.encode_short(left, right, &block)
133
+ }.to yield_successive_args(mp3_data1, mp3_data2)
134
+ end
135
+
136
+ end
137
+ end
138
+
139
+ context "flushing" do
140
+
141
+ let(:global_flags) { subject.global_flags }
142
+ let(:configuration) { stub(Configuration) }
143
+ let(:flusher) { stub(Encoding::Flusher).as_null_object }
144
+
145
+ before do
146
+ Configuration.stub(:new).and_return(configuration)
147
+ configuration.stub(:applied?).and_return(true)
148
+ Encoding::Flusher.stub(:new).and_return(flusher)
149
+ end
150
+
151
+ it "creates a flusher" do
152
+ Encoding::Flusher.should_receive(:new).with(configuration)
153
+ encoder.flush { }
154
+ end
155
+
156
+ it "flushes the final frame" do
157
+ flusher.should_receive(:flush)
158
+ encoder.flush { }
159
+ end
160
+
161
+ it "yields the flushed mp3 data" do
162
+ mp3_data = stub
163
+ flusher.stub(:flush).and_return(mp3_data)
164
+
165
+ expect { |block|
166
+ encoder.flush(&block)
167
+ }.to yield_with_args(mp3_data)
168
+ end
169
+
170
+ it "returns the flushed data if no block was given" do
171
+ mp3_data = stub
172
+ flusher.stub(:flush).and_return(mp3_data)
173
+ encoder.flush.should eql mp3_data
174
+ end
175
+
176
+ end
177
+
178
+ context "lametag frame" do
179
+
180
+ let(:global_flags) { subject.global_flags }
181
+ let(:configuration) { stub(Configuration) }
182
+ let(:vbr_info) { stub(Encoding::VBRInfo).as_null_object }
183
+
184
+ before do
185
+ Configuration.stub(:new).and_return(configuration)
186
+ configuration.stub(:applied?).and_return(true)
187
+ Encoding::VBRInfo.stub(:new).and_return(vbr_info)
188
+ end
189
+
190
+ it "creates vbr info" do
191
+ Encoding::VBRInfo.should_receive(:new).with(configuration)
192
+ encoder.vbr_frame { }
193
+ end
194
+
195
+ it "creates the vbr frame" do
196
+ vbr_info.should_receive(:frame)
197
+ encoder.vbr_frame { }
198
+ end
199
+
200
+ it "yields the vbr frame" do
201
+ mp3_data = stub
202
+ vbr_info.stub(:frame).and_return(mp3_data)
203
+
204
+ expect { |block|
205
+ encoder.vbr_frame(&block)
206
+ }.to yield_with_args(mp3_data)
207
+ end
208
+
209
+ it "returns the vbr frame if no block was given" do
210
+ mp3_data = stub
211
+ vbr_info.stub(:frame).and_return(mp3_data)
212
+ encoder.vbr_frame.should eql mp3_data
213
+ end
214
+
215
+ end
216
+
217
+ context "id3" do
218
+ let(:global_flags) { subject.global_flags }
219
+ let(:configuration) { stub(Configuration) }
220
+ let(:id3) { stub(Encoding::Id3).as_null_object }
221
+
222
+ before do
223
+ Configuration.stub(:new).and_return(configuration)
224
+ configuration.stub(:applied?).and_return(true)
225
+ Encoding::Id3.stub(:new).and_return(id3)
226
+ end
227
+
228
+ it "creates vbr info" do
229
+ Encoding::Id3.should_receive(:new).with(configuration)
230
+ encoder.id3v1 { }
231
+ end
232
+
233
+ context "v1" do
234
+ it "creates the id3v1 frame" do
235
+ id3.should_receive(:v1)
236
+ encoder.id3v1 { }
237
+ end
238
+
239
+ it "yields the vbr frame" do
240
+ mp3_data = stub
241
+ id3.stub(:v1).and_return(mp3_data)
242
+
243
+ expect { |block|
244
+ encoder.id3v1(&block)
245
+ }.to yield_with_args(mp3_data)
246
+ end
247
+
248
+ it "returns the vbr frame if no block was given" do
249
+ mp3_data = stub
250
+ id3.stub(:v1).and_return(mp3_data)
251
+ encoder.id3v1.should eql mp3_data
252
+ end
253
+ end
254
+
255
+ context "v2" do
256
+ it "creates the id3v2 frame" do
257
+ id3.should_receive(:v2)
258
+ encoder.id3v2 { }
259
+ end
260
+
261
+ it "yields the vbr frame" do
262
+ mp3_data = stub
263
+ id3.stub(:v2).and_return(mp3_data)
264
+
265
+ expect { |block|
266
+ encoder.id3v2(&block)
267
+ }.to yield_with_args(mp3_data)
268
+ end
269
+
270
+ it "returns the vbr frame if no block was given" do
271
+ mp3_data = stub
272
+ id3.stub(:v2).and_return(mp3_data)
273
+ encoder.id3v2.should eql mp3_data
274
+ end
275
+ end
276
+ end
277
+
278
+ end
279
+ end