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,120 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ describe Decoder do
5
+
6
+ let(:decode_flags) { stub("decode flags") }
7
+ let(:mp3_file) { stub("mp3 file") }
8
+ let(:id3_tag_parser) { stub("id3 tag parser", :skip! => nil) }
9
+ let(:mp3_data_header_parser) { stub("mp3 data header parser", :parse! => nil) }
10
+
11
+ # Stub away all collaborators:
12
+ before do
13
+ Decoding::Id3TagParser.stub(:new).and_return(id3_tag_parser)
14
+ Decoding::Mp3DataHeaderParser.stub(:new).and_return(mp3_data_header_parser)
15
+ FFI::DecodeFlags.stub(:new).and_return(decode_flags)
16
+ end
17
+
18
+ subject(:decoder) { Decoder.new(mp3_file) }
19
+
20
+ context "initialization" do
21
+
22
+ it "initializes DecodeFlags" do
23
+ FFI::DecodeFlags.should_receive(:new)
24
+ Decoder.new(mp3_file)
25
+ end
26
+
27
+ it "has the DecodeFlags" do
28
+ decode_flags = stub
29
+ FFI::DecodeFlags.stub(:new).and_return(decode_flags)
30
+ decoder.decode_flags.should eql decode_flags
31
+ end
32
+
33
+ it "has the mp3 file path" do
34
+ decoder.mp3_file.should eql mp3_file
35
+ end
36
+
37
+ it "skips the id3 offset" do
38
+ Decoding::Id3TagParser.should_receive(:new).with(mp3_file)
39
+ id3_tag_parser.should_receive(:skip!)
40
+
41
+ decoder
42
+ end
43
+
44
+ it "parses the mp3 data header" do
45
+ parser = stub
46
+ mp3_data = stub
47
+ Decoding::Mp3DataHeaderParser.should_receive(:new).with(decode_flags, mp3_file).and_return(parser)
48
+ parser.should_receive(:parse!).and_return(mp3_data)
49
+
50
+ decoder.mp3_data.should eql mp3_data
51
+ end
52
+
53
+ end
54
+
55
+ context "after initialization" do
56
+
57
+ let(:mp3_data) { stub("mp3 data") }
58
+
59
+ # stubbing galore!
60
+ before do
61
+ FFI::DecodeFlags.stub(:new).and_return(decode_flags)
62
+
63
+ parser = stub
64
+ Decoding::Mp3DataHeaderParser.stub(:new).and_return(parser)
65
+ parser.stub(:parse!).and_return(mp3_data)
66
+ end
67
+
68
+ describe "#each_decoded_frame" do
69
+
70
+ let(:stream_decoder) { stub }
71
+ before do
72
+ Decoding::StreamDecoder.stub(:new).and_return(stream_decoder)
73
+ end
74
+
75
+ it "initializes a stream decoder with mp3 file and mp3 data" do
76
+ stream_decoder.stub(:each_decoded_frame)
77
+
78
+ Decoding::StreamDecoder.should_receive(:new).with(decode_flags, mp3_data, mp3_file)
79
+
80
+ decoder.each_decoded_frame
81
+ end
82
+
83
+ it "delegates to a stream decoder" do
84
+ stream_decoder.should_receive(:each_decoded_frame)
85
+
86
+ decoder.each_decoded_frame
87
+ end
88
+
89
+ it "re-yields the stream decoder's yield" do
90
+ stream_decoder.stub(:each_decoded_frame).and_yield(:one).and_yield(:two)
91
+
92
+ expect { |block|
93
+ decoder.each_decoded_frame(&block)
94
+ }.to yield_successive_args(:one, :two)
95
+ end
96
+
97
+ end
98
+
99
+ describe "#channel_mode" do
100
+
101
+ it "delegates to mp3_data" do
102
+ mp3_data.should_receive(:channel_mode).and_return(:stereo)
103
+ decoder.channel_mode.should eql :stereo
104
+ end
105
+
106
+ end
107
+
108
+ describe "#sample_rate" do
109
+
110
+ it "delegates to mp3_data" do
111
+ mp3_data.should_receive(:sample_rate).and_return(44100)
112
+ decoder.sample_rate.should eql 44100
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe DecodedFrame do
6
+
7
+ it "is initialized with left and right samples" do
8
+ left = stub
9
+ right = stub
10
+
11
+ decoded_frame = DecodedFrame.new(left, right)
12
+
13
+ decoded_frame.left.should eql left
14
+ decoded_frame.right.should eql right
15
+ end
16
+
17
+ it "can be built with FFI Buffers" do
18
+ left_buffer = ::FFI::MemoryPointer.new(:short, 4)
19
+ right_buffer = ::FFI::MemoryPointer.new(:short, 4)
20
+
21
+ left_buffer.put_array_of_short(0, [1,2,3,4])
22
+ right_buffer.put_array_of_short(0, [5,6,7,8])
23
+
24
+ decoded_frame = DecodedFrame.from_short_buffers(left_buffer, right_buffer)
25
+
26
+ decoded_frame.left.should eql [1,2,3,4]
27
+ decoded_frame.right.should eql [5,6,7,8]
28
+ end
29
+
30
+ describe "#samples" do
31
+
32
+ it "returns zipped version of samples" do
33
+ left = [1,2,3,4]
34
+ right = [5,6,7,8]
35
+
36
+ decoded_frame = DecodedFrame.new(left, right)
37
+
38
+ decoded_frame.samples.should eql [[1,5],[2,6],[3,7],[4,8]]
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe Id3TagParser do
6
+
7
+ let(:stream) { StringIO.new(stream_string) }
8
+ let(:parser) { Id3TagParser.new(stream) }
9
+
10
+ describe "#skip!" do
11
+
12
+ context "valid header" do
13
+ let(:stream_string) do
14
+ header = "ID3 "
15
+ header << 0b00000000
16
+ header << 0b00000000
17
+ header << 0b00000010
18
+ header << 0b01010101
19
+ header << " "*341 # the above bits are '341'
20
+ end
21
+
22
+ it "seeks the file until after the id3 tag" do
23
+ parser.skip!
24
+ stream.pos.should eql 351
25
+ end
26
+
27
+ it "start from the start of the stream" do
28
+ stream.seek(42)
29
+ parser.skip!
30
+ stream.pos.should eql 351
31
+ end
32
+ end
33
+
34
+
35
+ context "no id3 tag" do
36
+ let(:stream_string) { " "*1024 }
37
+
38
+ it "does not crash if id3 tag is not present" do
39
+ expect {
40
+ parser.skip!
41
+ }.not_to raise_error
42
+ end
43
+
44
+ it "does not seek the stream if no header is present" do
45
+ parser.skip!
46
+ stream.pos.should eql 0
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe Mp3DataHeaderParser do
6
+
7
+ subject(:parser) { Mp3DataHeaderParser.new(decode_flags, stream) }
8
+
9
+ let(:decode_flags) { stub("decode flags") }
10
+ let(:stream) { StringIO.new(stream_string) }
11
+ let(:mpeg_finder) { stub }
12
+
13
+ let(:stream_string) { "a"*100 }
14
+
15
+ before do
16
+ LAME.stub(:hip_decode1_headersB) do |_, _, _, _, _, mp3_data, _, _|
17
+ # fake that the header was found
18
+ mp3_data[:header_parsed] = 1
19
+ end
20
+ end
21
+
22
+ it "seeks the input stream until the first mpeg frame" do
23
+ MPEGAudioFrameFinder.should_receive(:new).with(stream).and_return(mpeg_finder)
24
+ mpeg_finder.should_receive(:find!)
25
+
26
+ parser.parse!
27
+ end
28
+
29
+ context "decoding headers" do
30
+
31
+ before do
32
+ MPEGAudioFrameFinder.stub(:new => stub.as_null_object)
33
+ end
34
+
35
+ it "reads 100 bytes from the stream" do
36
+ stream.should_receive(:read).with(100).and_return("a"*100)
37
+ parser.parse!
38
+ end
39
+
40
+ it "parses headers with LAME" do
41
+ LAME.should_receive(:hip_decode1_headersB) do |decode_flags, in_buffer, size, _, _, mp3_data, _, _|
42
+ decode_flags.should eql decode_flags
43
+ in_buffer.get_string(0).should eql "a"*100
44
+ size.should eql 100
45
+ mp3_data.should be_a(LAME::FFI::MP3Data)
46
+
47
+ # fake that the header was found
48
+ mp3_data[:header_parsed] = 1
49
+ end
50
+ parser.parse!
51
+ end
52
+
53
+ context "larger input" do
54
+ let(:stream_string) { "a"*1000 }
55
+ let(:expected_reads) { 5 }
56
+
57
+ it "reads 100 bytes until a header was parsed" do
58
+ decode_count = 0
59
+
60
+ LAME.should_receive(:hip_decode1_headersB).exactly(expected_reads).times
61
+
62
+ LAME.stub(:hip_decode1_headersB) do |_, _, _, _, _, mp3_data, _, _|
63
+ decode_count += 1
64
+
65
+ # simulate parsed header after 5 reads:
66
+ mp3_data[:header_parsed] = (decode_count == expected_reads) ? 1 : 0
67
+ end
68
+
69
+ parser.parse!
70
+ end
71
+ end
72
+
73
+ it "returns the parsed mp3 data if a header was parsed" do
74
+ mp3_data = stub("mp3 data", :header_parsed? => true)
75
+ LAME::FFI::MP3Data.stub(:new).and_return(mp3_data)
76
+ LAME.stub(:hip_decode1_headersB)
77
+
78
+ parser.parse!.should eql mp3_data
79
+ end
80
+
81
+ it "raises an error if the header could not be parsed" do
82
+ mp3_data = stub("mp3 data", :header_parsed? => false)
83
+ LAME::FFI::MP3Data.stub(:new).and_return(mp3_data)
84
+ LAME.stub(:hip_decode1_headersB)
85
+
86
+ expect {
87
+ parser.parse!
88
+ }.to raise_error(Mp3DataHeaderNotFoundError)
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe MPEGAudioFrameFinder do
6
+
7
+ subject(:finder) { MPEGAudioFrameFinder.new(stream) }
8
+
9
+ let(:stream) { StringIO.new(stream_string) }
10
+ let(:stream_string) { "1234567890" }
11
+
12
+ it "tries to find the mpeg frame 4 bytes at a time until a header is found" do
13
+ matcher1 = stub("matcher", :match? => false)
14
+ matcher2 = stub("matcher", :match? => false)
15
+ matcher3 = stub("matcher", :match? => true)
16
+
17
+ MPEGAudioFrameMatcher.should_receive(:new).with("1234").and_return(matcher1)
18
+ MPEGAudioFrameMatcher.should_receive(:new).with("2345").and_return(matcher2)
19
+ MPEGAudioFrameMatcher.should_receive(:new).with("3456").and_return(matcher3)
20
+
21
+ finder.find!
22
+ end
23
+
24
+ it "seeks the stream at the position of the found frame" do
25
+ matcher1 = stub("matcher", :match? => false)
26
+ matcher2 = stub("matcher", :match? => false)
27
+ matcher3 = stub("matcher", :match? => true)
28
+
29
+ MPEGAudioFrameMatcher.stub(:new).with("1234").and_return(matcher1)
30
+ MPEGAudioFrameMatcher.stub(:new).with("2345").and_return(matcher2)
31
+ MPEGAudioFrameMatcher.stub(:new).with("3456").and_return(matcher3)
32
+
33
+ finder.find!
34
+
35
+ stream.pos.should eql 2
36
+ end
37
+
38
+ it "raises an error if no header could be found" do
39
+ matcher = stub("matcher", :match? => false)
40
+
41
+ MPEGAudioFrameMatcher.stub(:new).and_return(matcher)
42
+
43
+ expect {
44
+ finder.find!
45
+ }.to raise_error(MPEGAudioFrameNotFoundError)
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ module LAME
4
+ module Decoding
5
+ describe MPEGAudioFrameMatcher do
6
+
7
+ B_EMPTY = 0b00000000
8
+
9
+ B1_LEADING = 0b11111111
10
+ B2_LEADING = 0b11100000
11
+ B2_MPEG25 = 0b00000000
12
+ B2_MPEG_RESV = 0b00001000
13
+ B2_MPEG2 = 0b00010000
14
+ B2_MPEG1 = 0b00011000
15
+ B2_LAYER0 = 0b00000000 # reserved
16
+ B2_LAYER3 = 0b00000010 # Layer III
17
+ B2_LAYER2 = 0b00000100 # Layer II
18
+ B2_LAYER1 = 0b00000110 # Layer I
19
+
20
+ # Comments below are for MP3
21
+ B3_BITRATE0 = 0b00000000
22
+ B3_BITRATE1 = 0b00010000 # lowest (32 in MP3)
23
+ B3_BITRATE9 = 0b10010000 # 128kbit in MP3
24
+ B3_BITRATE11 = 0b10110000 # 192kbit in MP3
25
+ B3_BITRATE14 = 0b11100000 # highest (320 in MP3)
26
+ B3_BITRATE15 = 0b11110000
27
+ B3_SMPRATE0 = 0b00000000 # 44100
28
+ B3_SMPRATE1 = 0b00000100 # 48000
29
+ B3_SMPRATE2 = 0b00001000 # 32000
30
+ B3_SMPRATE3 = 0b00001100 # reserved
31
+
32
+ B4_STEREO = 0b00000000
33
+ B4_JOINT = 0b01000000
34
+ B4_DUAL = 0b10000000
35
+ B4_MONO = 0b11000000
36
+ B4_EMPH_NONE = 0b00000000
37
+ B4_EMPH_5015 = 0b00000001
38
+ B4_EMPH_RESV = 0b00000010 # reserved
39
+ B4_EMPH_CCIT = 0b00000011
40
+
41
+ shared_examples_for "4 valid bytes" do
42
+ it "matches" do
43
+ bytes = [b1, b2, b3, b4].pack("C*")
44
+ MPEGAudioFrameMatcher.new(bytes).match?.should be_true
45
+ end
46
+ end
47
+
48
+ shared_examples_for "4 invalid bytes" do
49
+ it "does not match" do
50
+ bytes = [b1, b2, b3, b4].pack("C*")
51
+ MPEGAudioFrameMatcher.new(bytes).match?.should be_false
52
+ end
53
+ end
54
+
55
+ context "MPEG1, Layer III, 128kbit, 44khz, stereo, no-emph" do
56
+ let(:b1) { B1_LEADING }
57
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER3 }
58
+ let(:b3) { B3_BITRATE9 | B3_SMPRATE0 }
59
+ let(:b4) { B4_STEREO | B4_EMPH_NONE }
60
+
61
+ it_behaves_like "4 valid bytes"
62
+ end
63
+
64
+ context "MPEG2, Layer II, 160kbit, 24khz, mono, 50/15ms emph" do
65
+ let(:b1) { B1_LEADING }
66
+ let(:b2) { B2_LEADING | B2_MPEG2 | B2_LAYER2 }
67
+ let(:b3) { B3_BITRATE14 | B3_SMPRATE1 }
68
+ let(:b4) { B4_MONO | B4_EMPH_5015 }
69
+
70
+ it_behaves_like "4 valid bytes"
71
+ end
72
+
73
+ context "all 0 bites" do
74
+ let(:b1) { B_EMPTY }
75
+ let(:b2) { B_EMPTY }
76
+ let(:b3) { B_EMPTY }
77
+ let(:b4) { B_EMPTY }
78
+
79
+ it_behaves_like "4 invalid bytes"
80
+ end
81
+
82
+ context "reserved MPEG" do
83
+ let(:b1) { B1_LEADING }
84
+ let(:b2) { B2_LEADING | B2_MPEG_RESV | B2_LAYER3 } # <-- B2_MPEG_RESV
85
+ let(:b3) { B3_BITRATE9 | B3_SMPRATE0 }
86
+ let(:b4) { B4_STEREO | B4_EMPH_NONE }
87
+
88
+ it_behaves_like "4 invalid bytes"
89
+ end
90
+
91
+ context "reserved Layer" do
92
+ let(:b1) { B1_LEADING }
93
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER0 } # <-- B2_LAYER0
94
+ let(:b3) { B3_BITRATE9 | B3_SMPRATE0 }
95
+ let(:b4) { B4_STEREO | B4_EMPH_NONE }
96
+
97
+ it_behaves_like "4 invalid bytes"
98
+ end
99
+
100
+ context "reserved bitrate" do
101
+ let(:b1) { B1_LEADING }
102
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER3 }
103
+ let(:b3) { B3_BITRATE15 | B3_SMPRATE0 } # <-- B3_BITRATE15
104
+ let(:b4) { B4_STEREO | B4_EMPH_NONE }
105
+
106
+ it_behaves_like "4 invalid bytes"
107
+ end
108
+
109
+ context "reserved sampling rate" do
110
+ let(:b1) { B1_LEADING }
111
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER3 }
112
+ let(:b3) { B3_BITRATE9 | B3_SMPRATE3 } # <-- B3_SMPRATE3
113
+ let(:b4) { B4_STEREO | B4_EMPH_NONE }
114
+
115
+ it_behaves_like "4 invalid bytes"
116
+ end
117
+
118
+ context "valid MPEG1 Layer II bitrate/channel mode combination" do
119
+ let(:b1) { B1_LEADING }
120
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER2 }
121
+ let(:b3) { B3_BITRATE1 | B3_SMPRATE2 }
122
+ let(:b4) { B4_MONO | B4_EMPH_NONE }
123
+
124
+ # bitrate '1' and 'mono' is valid
125
+ it_behaves_like "4 valid bytes"
126
+ end
127
+
128
+ context "another valid MPEG1 Layer II bitrate/channel mode combination" do
129
+ let(:b1) { B1_LEADING }
130
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER2 }
131
+ let(:b3) { B3_BITRATE11 | B3_SMPRATE2 }
132
+ let(:b4) { B4_JOINT | B4_EMPH_NONE }
133
+
134
+ # bitrate '11' and 'joint_stereo' is valid
135
+ it_behaves_like "4 valid bytes"
136
+ end
137
+
138
+ context "yet another valid MPEG1 Layer II bitrate/channel mode combination" do
139
+ let(:b1) { B1_LEADING }
140
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER2 }
141
+ let(:b3) { B3_BITRATE9 | B3_SMPRATE2 }
142
+ let(:b4) { B4_JOINT | B4_EMPH_NONE }
143
+
144
+ # bitrate '9' and 'joint_stereo' is valid
145
+ it_behaves_like "4 valid bytes"
146
+ end
147
+
148
+ context "invalid MPEG1 Layer II bitrate/channel mode combination" do
149
+ let(:b1) { B1_LEADING }
150
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER2 }
151
+ let(:b3) { B3_BITRATE1 | B3_SMPRATE2 }
152
+ let(:b4) { B4_STEREO | B4_EMPH_NONE }
153
+
154
+ # bitrate '1' and 'stereo' is invalid
155
+ it_behaves_like "4 invalid bytes"
156
+ end
157
+
158
+ context "another invalid MPEG1 Layer II bitrate/channel mode combination" do
159
+ let(:b1) { B1_LEADING }
160
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER2 }
161
+ let(:b3) { B3_BITRATE11 | B3_SMPRATE2 }
162
+ let(:b4) { B4_MONO | B4_EMPH_NONE }
163
+
164
+ # bitrate '11' and 'mono' is invalid
165
+ it_behaves_like "4 invalid bytes"
166
+ end
167
+
168
+ context "invalid emphasis" do
169
+ let(:b1) { B1_LEADING }
170
+ let(:b2) { B2_LEADING | B2_MPEG1 | B2_LAYER3 }
171
+ let(:b3) { B3_BITRATE9 | B3_SMPRATE0 }
172
+ let(:b4) { B4_STEREO | B4_EMPH_RESV }
173
+
174
+ it_behaves_like "4 invalid bytes"
175
+ end
176
+
177
+ end
178
+ end
179
+ end