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.
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.rvmrc +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +181 -0
- data/Rakefile +6 -0
- data/docs/id3v2.4.0-structure.txt +731 -0
- data/docs/lame-3.99.5.h +1323 -0
- data/lame.gemspec +28 -0
- data/lib/lame.rb +31 -0
- data/lib/lame/buffer.rb +21 -0
- data/lib/lame/configuration.rb +228 -0
- data/lib/lame/decoder.rb +38 -0
- data/lib/lame/decoding/decoded_frame.rb +25 -0
- data/lib/lame/decoding/id3_tag_parser.rb +53 -0
- data/lib/lame/decoding/mp3_data_header_parser.rb +64 -0
- data/lib/lame/decoding/mpeg_audio_frame_finder.rb +46 -0
- data/lib/lame/decoding/mpeg_audio_frame_matcher.rb +98 -0
- data/lib/lame/decoding/single_frame_decoder.rb +51 -0
- data/lib/lame/decoding/stream_decoder.rb +37 -0
- data/lib/lame/delegation.rb +68 -0
- data/lib/lame/encoder.rb +73 -0
- data/lib/lame/encoding/encode_short_buffer.rb +26 -0
- data/lib/lame/encoding/flusher.rb +22 -0
- data/lib/lame/encoding/id3.rb +46 -0
- data/lib/lame/encoding/vbr_info.rb +22 -0
- data/lib/lame/error.rb +13 -0
- data/lib/lame/ffi.rb +20 -0
- data/lib/lame/ffi/decode_flags.rb +19 -0
- data/lib/lame/ffi/enums.rb +75 -0
- data/lib/lame/ffi/functions.rb +272 -0
- data/lib/lame/ffi/global_flags.rb +20 -0
- data/lib/lame/ffi/mp3_data.rb +37 -0
- data/lib/lame/ffi/version.rb +17 -0
- data/lib/lame/version.rb +3 -0
- data/spec/buffer_spec.rb +26 -0
- data/spec/configuration_spec.rb +391 -0
- data/spec/decoder_spec.rb +120 -0
- data/spec/decoding/decoded_frame_spec.rb +44 -0
- data/spec/decoding/id3_tag_parser_spec.rb +54 -0
- data/spec/decoding/mp3_data_header_parser_spec.rb +95 -0
- data/spec/decoding/mpeg_audio_frame_finder_spec.rb +50 -0
- data/spec/decoding/mpeg_audio_frame_matcher_spec.rb +179 -0
- data/spec/decoding/single_frame_decoder_spec.rb +104 -0
- data/spec/decoding/stream_decoder_spec.rb +43 -0
- data/spec/delegation_spec.rb +146 -0
- data/spec/encoder_spec.rb +279 -0
- data/spec/encoding/encode_short_buffer_spec.rb +72 -0
- data/spec/encoding/flusher_spec.rb +47 -0
- data/spec/encoding/id3_spec.rb +106 -0
- data/spec/encoding/vbr_info_spec.rb +47 -0
- data/spec/ffi/decode_flags_spec.rb +16 -0
- data/spec/ffi/encoding_spec.rb +223 -0
- data/spec/ffi/global_flags_spec.rb +542 -0
- data/spec/ffi/id3tag_spec.rb +135 -0
- data/spec/ffi/mp3_data_spec.rb +26 -0
- data/spec/files/dies-irae.wav +0 -0
- data/spec/integration/decoding_spec.rb +179 -0
- data/spec/integration/encoding_spec.rb +126 -0
- data/spec/integration/id3_tags_spec.rb +96 -0
- data/spec/spec_helper.rb +175 -0
- metadata +254 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LAME
|
4
|
+
describe "FFI calls to id3tag setters" do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@flags_pointer = LAME.lame_init
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
LAME.lame_close(@flags_pointer)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has all the genres" do
|
15
|
+
genres = {}
|
16
|
+
|
17
|
+
genre_collector_callback = ::FFI::Function.new(:void, [:int, :string, :pointer]) do |id, name, _|
|
18
|
+
genres[id] = name
|
19
|
+
end
|
20
|
+
|
21
|
+
LAME.id3tag_genre_list(genre_collector_callback, nil)
|
22
|
+
|
23
|
+
genres.should have(148).items
|
24
|
+
genres[0].should eql "Blues"
|
25
|
+
genres[147].should eql "SynthPop"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "initializes" do
|
29
|
+
LAME.id3tag_init(@flags_pointer).should eql nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "adds v2" do
|
33
|
+
LAME.id3tag_add_v2(@flags_pointer).should eql nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "set v1 only" do
|
37
|
+
LAME.id3tag_v1_only(@flags_pointer).should eql nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "set v2 only" do
|
41
|
+
LAME.id3tag_v2_only(@flags_pointer).should eql nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "pads with spaces" do
|
45
|
+
LAME.id3tag_space_v1(@flags_pointer).should eql nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "pads v2 with 128 extra bytes" do
|
49
|
+
LAME.id3tag_pad_v2(@flags_pointer).should eql nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "pads v2 with extra bytes" do
|
53
|
+
LAME.id3tag_set_pad(@flags_pointer, 256).should eql nil
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets the title" do
|
57
|
+
LAME.id3tag_set_title(@flags_pointer, pointer_from_string("foo")).should eql nil
|
58
|
+
end
|
59
|
+
|
60
|
+
it "sets the artist" do
|
61
|
+
LAME.id3tag_set_artist(@flags_pointer, pointer_from_string("foo")).should eql nil
|
62
|
+
end
|
63
|
+
|
64
|
+
it "sets the album" do
|
65
|
+
LAME.id3tag_set_album(@flags_pointer, pointer_from_string("foo")).should eql nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "sets the year" do
|
69
|
+
LAME.id3tag_set_year(@flags_pointer, pointer_from_string("foo")).should eql nil
|
70
|
+
end
|
71
|
+
|
72
|
+
it "sets the comment" do
|
73
|
+
LAME.id3tag_set_comment(@flags_pointer, pointer_from_string("foo")).should eql nil
|
74
|
+
end
|
75
|
+
|
76
|
+
it "sets the track" do
|
77
|
+
LAME.id3tag_set_track(@flags_pointer, pointer_from_string("1")).should eql 0
|
78
|
+
end
|
79
|
+
|
80
|
+
it "ignores out of range track numbers for id3" do
|
81
|
+
LAME.id3tag_set_track(@flags_pointer, pointer_from_string("256")).should eql -1
|
82
|
+
end
|
83
|
+
|
84
|
+
it "sets the genre" do
|
85
|
+
LAME.id3tag_set_genre(@flags_pointer, pointer_from_string("Rock")).should eql 0
|
86
|
+
end
|
87
|
+
|
88
|
+
# There is a fixed set of allowed fields (see id3tag.c)
|
89
|
+
# LAME 3.99.4 fixed some bugs in setting field values, this could crash for certain tags.
|
90
|
+
it "sets the fieldvalue" do
|
91
|
+
LAME.id3tag_set_fieldvalue(@flags_pointer, pointer_from_string("TIT2=foofoo")).should eql 0
|
92
|
+
end
|
93
|
+
|
94
|
+
# it "sets the fieldvalue (utf16)" do
|
95
|
+
# LAME.id3tag_set_fieldvalue_utf16(@flags_pointer, "LINK=foofoo".encode("UTF-16")).should eql 0
|
96
|
+
# end
|
97
|
+
|
98
|
+
it "sets album art" do
|
99
|
+
buffer_size = 1024
|
100
|
+
|
101
|
+
# fake JPG image
|
102
|
+
buffer = ::FFI::MemoryPointer.new(:char, buffer_size)
|
103
|
+
buffer.put_char(0, 0xff)
|
104
|
+
buffer.put_char(1, 0xd8)
|
105
|
+
|
106
|
+
LAME.id3tag_set_albumart(@flags_pointer, buffer, buffer_size).should eql 0
|
107
|
+
end
|
108
|
+
|
109
|
+
it "creates id3v1 tag" do
|
110
|
+
buffer_size = 1024
|
111
|
+
buffer = ::FFI::MemoryPointer.new(:uchar, buffer_size)
|
112
|
+
LAME.id3tag_set_title(@flags_pointer, pointer_from_string("foo"))
|
113
|
+
LAME.id3tag_set_album(@flags_pointer, pointer_from_string("bar"))
|
114
|
+
LAME.lame_get_id3v1_tag(@flags_pointer, buffer, buffer_size).should eql 128
|
115
|
+
end
|
116
|
+
|
117
|
+
it "creates id3v2 tag" do
|
118
|
+
buffer_size = 1024
|
119
|
+
buffer = ::FFI::MemoryPointer.new(:uchar, buffer_size)
|
120
|
+
LAME.id3tag_add_v2(@flags_pointer)
|
121
|
+
LAME.id3tag_set_title(@flags_pointer, pointer_from_string("foo"))
|
122
|
+
LAME.id3tag_set_album(@flags_pointer, pointer_from_string("bar"))
|
123
|
+
LAME.lame_get_id3v2_tag(@flags_pointer, buffer, buffer_size).should eql 38
|
124
|
+
end
|
125
|
+
|
126
|
+
it "sets id3tag automatic" do
|
127
|
+
LAME.should have_flag(:write_id3tag_automatic).with_value(1).for(@flags_pointer)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "gets id3tag automatic" do
|
131
|
+
LAME.should be_able_to_set(:write_id3tag_automatic).to(0).for(@flags_pointer).and_return(nil)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LAME
|
4
|
+
module FFI
|
5
|
+
describe MP3Data do
|
6
|
+
|
7
|
+
subject(:mp3_data) { MP3Data.new }
|
8
|
+
|
9
|
+
it "is stereo for two channels" do
|
10
|
+
mp3_data[:stereo] = 2
|
11
|
+
mp3_data.channel_mode.should eql :stereo
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is mono for one channel" do
|
15
|
+
mp3_data[:stereo] = 1
|
16
|
+
mp3_data.channel_mode.should eql :mono
|
17
|
+
end
|
18
|
+
|
19
|
+
it "has a sample rate" do
|
20
|
+
mp3_data[:samplerate] = 44100
|
21
|
+
mp3_data.sample_rate.should eql 44100
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
Binary file
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'wavefile'
|
3
|
+
|
4
|
+
describe "Decoding", :slow => true do
|
5
|
+
|
6
|
+
let(:mp3_file_path) { File.expand_path(File.join(File.dirname(__FILE__), '../files/dies-irae-cli-id3v2.mp3')) }
|
7
|
+
let(:mp3_file) { File.open(mp3_file_path, "r") }
|
8
|
+
|
9
|
+
it "decodes an MP3 file by api" do
|
10
|
+
decoder = LAME::Decoder.new(mp3_file)
|
11
|
+
|
12
|
+
format = WaveFile::Format.new(decoder.channel_mode, :pcm_16, decoder.sample_rate)
|
13
|
+
|
14
|
+
WaveFile::Writer.new("output1.wav", format) do |writer|
|
15
|
+
|
16
|
+
decoder.each_decoded_frame do |decoded_frame|
|
17
|
+
buffer = WaveFile::Buffer.new(decoded_frame.samples, format)
|
18
|
+
|
19
|
+
writer.write(buffer)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "decodes an MP3 file" do
|
26
|
+
# id3
|
27
|
+
id3_length = id3_length(mp3_file)
|
28
|
+
puts "ID3 length: #{id3_length} bytes"
|
29
|
+
mp3_file.read(id3_length)
|
30
|
+
|
31
|
+
# aid TODO (ignored for now)
|
32
|
+
|
33
|
+
# find MP3 sync frame
|
34
|
+
|
35
|
+
mp3_offset = mpeg_audio_offset(mp3_file, id3_length)
|
36
|
+
puts "offset: #{mp3_offset}"
|
37
|
+
|
38
|
+
@decode_flags = LAME::FFI::DecodeFlags.new
|
39
|
+
@mp3_data = LAME::FFI::MP3Data.new
|
40
|
+
|
41
|
+
# Decode until we have parsed an MP3 header
|
42
|
+
mp3_file.seek(mp3_offset)
|
43
|
+
begin
|
44
|
+
find_header(mp3_file)
|
45
|
+
end until @mp3_data.header_parsed?
|
46
|
+
|
47
|
+
# Results:
|
48
|
+
if @mp3_data.header_parsed?
|
49
|
+
puts "stereo: #{@mp3_data[:stereo]}"
|
50
|
+
puts "samplerate: #{@mp3_data[:samplerate]}"
|
51
|
+
puts "bitrate: #{@mp3_data[:bitrate]}"
|
52
|
+
puts "mode: #{@mp3_data[:mode]}"
|
53
|
+
puts "mod_ext: #{@mp3_data[:mod_ext]}"
|
54
|
+
puts "framesize: #{@mp3_data[:framesize]}"
|
55
|
+
puts "nsamp: #{@mp3_data[:nsamp]}"
|
56
|
+
puts "totalframes: #{@mp3_data[:totalframes]}"
|
57
|
+
puts "framenum: #{@mp3_data[:framenum]}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# read mp3_data (number of frames etc)
|
61
|
+
format = WaveFile::Format.new(:stereo, :pcm_16, 44100)
|
62
|
+
WaveFile::Writer.new("output2.wav", format) do |writer|
|
63
|
+
|
64
|
+
# See get_audio.c:2082 #lame_decode_fromfile
|
65
|
+
#
|
66
|
+
# Read until we have decode some MP3 data:
|
67
|
+
@result = 0
|
68
|
+
begin
|
69
|
+
@result = decode(mp3_file)
|
70
|
+
|
71
|
+
if @result && @result.any?
|
72
|
+
left = @result[0].read_array_of_short(@result[0].size/2)
|
73
|
+
right = @result[1].read_array_of_short(@result[1].size/2)
|
74
|
+
buffer = WaveFile::Buffer.new(left.zip(right), format)
|
75
|
+
|
76
|
+
writer.write(buffer)
|
77
|
+
end
|
78
|
+
end until !@result
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_header(mp3_file)
|
83
|
+
size = 100 # arbitrary, taken from get_audio.c#lame_decode_initfile
|
84
|
+
in_data = mp3_file.read(size)
|
85
|
+
|
86
|
+
in_buffer = LAME::Buffer.create_uchar(in_data)
|
87
|
+
out_left = LAME::Buffer.create_empty(:short, 0)
|
88
|
+
out_right = LAME::Buffer.create_empty(:short, 0)
|
89
|
+
|
90
|
+
enc_delay = ::FFI::MemoryPointer.new(:int, 1)
|
91
|
+
enc_padding = ::FFI::MemoryPointer.new(:int, 1)
|
92
|
+
|
93
|
+
result = LAME.hip_decode1_headersB(@decode_flags, in_buffer, size, out_left, out_right, @mp3_data, enc_delay, enc_padding)
|
94
|
+
|
95
|
+
if @mp3_data.header_parsed?
|
96
|
+
puts "header parsed @ #{mp3_file.pos}"
|
97
|
+
puts "enc_delay: #{enc_delay.read_array_of_int(1)}"
|
98
|
+
puts "enc_padding: #{enc_padding.read_array_of_int(1)}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def decode(mp3_file)
|
103
|
+
size = 1024 # arbitrary, taken from get_audio.c#lame_decode_fromfile
|
104
|
+
out_left = LAME::Buffer.create_empty(:short, 1152)
|
105
|
+
out_right = LAME::Buffer.create_empty(:short, 1152)
|
106
|
+
|
107
|
+
in_buffer = LAME::Buffer.create_empty(:uchar, 0)
|
108
|
+
|
109
|
+
# see if we have anything left in the internal decode buffer
|
110
|
+
result = LAME.hip_decode1_headers(@decode_flags, in_buffer, 0, out_left, out_right, @mp3_data)
|
111
|
+
|
112
|
+
case result
|
113
|
+
when -1
|
114
|
+
raise "decoding error (a)"
|
115
|
+
when 0
|
116
|
+
# need more data
|
117
|
+
else
|
118
|
+
return [out_left, out_right]
|
119
|
+
end
|
120
|
+
|
121
|
+
in_data = mp3_file.read(size)
|
122
|
+
if !in_data
|
123
|
+
return nil
|
124
|
+
end
|
125
|
+
|
126
|
+
in_buffer = LAME::Buffer.create_uchar(in_data)
|
127
|
+
|
128
|
+
# else read more data and try again
|
129
|
+
result = LAME.hip_decode1_headers(@decode_flags, in_buffer, size, out_left, out_right, @mp3_data)
|
130
|
+
|
131
|
+
case result
|
132
|
+
when -1
|
133
|
+
raise "decoding error (b)"
|
134
|
+
when 0
|
135
|
+
# need more data
|
136
|
+
else
|
137
|
+
return [out_left, out_right]
|
138
|
+
end
|
139
|
+
|
140
|
+
[]
|
141
|
+
end
|
142
|
+
|
143
|
+
def mpeg_audio_offset(mp3_file, offset = 0)
|
144
|
+
mp3_file.seek(offset)
|
145
|
+
|
146
|
+
window_size = 4
|
147
|
+
begin
|
148
|
+
in_data = mp3_file.read(window_size)
|
149
|
+
|
150
|
+
if LAME::Decoding::MPEGAudioFrameMatcher.new(in_data).match?
|
151
|
+
puts "match offset @ #{offset} : #{in_data.bytes.to_a[0].to_s(2)} #{in_data.bytes.to_a[1].to_s(2)} #{in_data.bytes.to_a[2].to_s(2)} #{in_data.bytes.to_a[3].to_s(2)}"
|
152
|
+
return offset
|
153
|
+
end
|
154
|
+
|
155
|
+
offset += 1
|
156
|
+
mp3_file.seek(offset)
|
157
|
+
end while in_data.length == window_size
|
158
|
+
end
|
159
|
+
|
160
|
+
def id3_length(file)
|
161
|
+
header = file.read(10)
|
162
|
+
if id3?(header)
|
163
|
+
size = header[-4..-1]
|
164
|
+
|
165
|
+
b0 = size[0].ord
|
166
|
+
b1 = size[1].ord
|
167
|
+
b2 = size[2].ord
|
168
|
+
b3 = size[3].ord
|
169
|
+
|
170
|
+
# rubify this sometime:
|
171
|
+
(((((b0 << 7) + b1) << 7) + b2) << 7) + b3
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def id3?(header)
|
176
|
+
header.start_with?("ID3")
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'wavefile'
|
3
|
+
# require 'digest'
|
4
|
+
|
5
|
+
describe "Encoding", :slow => true do
|
6
|
+
|
7
|
+
let(:wav_path) { File.expand_path(File.join(File.dirname(__FILE__), '../files/dies-irae.wav')) }
|
8
|
+
let(:mp3_path_raw) { File.expand_path(File.join(File.dirname(__FILE__), '../files/dies-irae-raw.mp3')) }
|
9
|
+
let(:mp3_path_api) { File.expand_path(File.join(File.dirname(__FILE__), '../files/dies-irae-api.mp3')) }
|
10
|
+
|
11
|
+
let(:wav_reader) { WaveFile::Reader.new(wav_path) }
|
12
|
+
|
13
|
+
# This test serves as an example how to use the LAME API
|
14
|
+
it "encodes a wav file" do
|
15
|
+
|
16
|
+
# setup
|
17
|
+
flags_pointer = LAME.lame_init
|
18
|
+
LAME.lame_init_params(flags_pointer)
|
19
|
+
|
20
|
+
# LAME.id3tag_init(flags_pointer) # needed?
|
21
|
+
# LAME.id3tag_set_title(flags_pointer, "foo")
|
22
|
+
|
23
|
+
# number of samples to read
|
24
|
+
framesize = LAME.lame_get_framesize(flags_pointer)
|
25
|
+
|
26
|
+
# input buffers
|
27
|
+
left_buffer = ::FFI::MemoryPointer.new(:short, framesize)
|
28
|
+
right_buffer = ::FFI::MemoryPointer.new(:short, framesize)
|
29
|
+
|
30
|
+
# output buffer
|
31
|
+
buffer_size = (128*1024)+16384
|
32
|
+
buffer = ::FFI::MemoryPointer.new(:uchar, buffer_size)
|
33
|
+
|
34
|
+
File.open(mp3_path_raw, "wb") do |file|
|
35
|
+
wav_reader.each_buffer(framesize) do |read_buffer|
|
36
|
+
|
37
|
+
# read samples (ranges from -32k to +32k)
|
38
|
+
read_buffer.samples.each.with_index do |(left, right), index|
|
39
|
+
byte_offset = index * 2
|
40
|
+
left_buffer.put_short(byte_offset, left)
|
41
|
+
right_buffer.put_short(byte_offset, right)
|
42
|
+
end
|
43
|
+
|
44
|
+
input_buffer_size = read_buffer.samples.size
|
45
|
+
|
46
|
+
# encode to mp3 frame
|
47
|
+
size = LAME.lame_encode_buffer(
|
48
|
+
flags_pointer,
|
49
|
+
left_buffer, right_buffer, input_buffer_size,
|
50
|
+
buffer, buffer_size
|
51
|
+
)
|
52
|
+
|
53
|
+
# write to file
|
54
|
+
file.write buffer.get_bytes(0, size)
|
55
|
+
end
|
56
|
+
|
57
|
+
# flush final frame
|
58
|
+
size = LAME.lame_encode_flush(flags_pointer, buffer, buffer_size)
|
59
|
+
file.write buffer.get_bytes(0, size)
|
60
|
+
|
61
|
+
# write "lametag" frame with extra info
|
62
|
+
size = LAME.lame_get_lametag_frame(flags_pointer, buffer, buffer_size)
|
63
|
+
file.seek(0)
|
64
|
+
file.write buffer.get_bytes(0, size)
|
65
|
+
end
|
66
|
+
|
67
|
+
# close
|
68
|
+
LAME.lame_close(flags_pointer)
|
69
|
+
|
70
|
+
# TODO: Need a better way to test output..
|
71
|
+
# Digest::MD5.hexdigest(File.read(mp3_path_raw)).should eql "84a1ce7994bb4a54fc13fb5381ebac40"
|
72
|
+
end
|
73
|
+
|
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
|
+
end
|