lame 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.
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