icanhasaudio 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Manifest.txt +24 -14
- data/README.txt +2 -0
- data/Rakefile +15 -8
- data/ext/icanhasaudio/audio_mpeg_decoder.c +220 -0
- data/ext/icanhasaudio/audio_mpeg_decoder.h +8 -0
- data/ext/icanhasaudio/audio_mpeg_decoder_mp3data.c +96 -0
- data/ext/icanhasaudio/audio_mpeg_decoder_mp3data.h +8 -0
- data/ext/{mpeg_encoder.c → icanhasaudio/audio_mpeg_encoder.c} +94 -102
- data/ext/icanhasaudio/audio_mpeg_encoder.h +8 -0
- data/ext/{rb_ogg.c → icanhasaudio/audio_ogg_decoder.c} +18 -9
- data/ext/icanhasaudio/audio_ogg_decoder.h +8 -0
- data/ext/{extconf.rb → icanhasaudio/extconf.rb} +2 -2
- data/ext/{get_audio.c → icanhasaudio/get_audio.c} +1 -6
- data/ext/{get_audio.h → icanhasaudio/get_audio.h} +2 -0
- data/ext/icanhasaudio/native.c +9 -0
- data/ext/icanhasaudio/native.h +21 -0
- data/ext/{rb_wav.c → icanhasaudio/rb_wav.c} +1 -2
- data/ext/{rb_wav.h → icanhasaudio/rb_wav.h} +1 -2
- data/lib/icanhasaudio.rb +4 -0
- data/lib/icanhasaudio/mpeg.rb +1 -24
- data/lib/icanhasaudio/mpeg/decoder.rb +95 -0
- data/lib/icanhasaudio/ogg.rb +1 -21
- data/lib/icanhasaudio/ogg/decoder.rb +31 -0
- data/lib/icanhasaudio/version.rb +8 -0
- data/lib/icanhasaudio/wav.rb +1 -0
- data/lib/icanhasaudio/wav/file.rb +62 -0
- data/test/assets/icha.mp3 +0 -0
- data/test/helper.rb +15 -0
- data/test/mpeg/test_decoder.rb +20 -0
- data/test/test_mpeg_encoder.rb +2 -4
- metadata +31 -18
- data/ext/decoder.c +0 -95
- data/ext/decoder.h +0 -3
- data/ext/icanhasaudio.c +0 -183
- data/ext/icanhasaudio.h +0 -8
- data/ext/mpeg_encoder.h +0 -10
- data/ext/syncword.c +0 -45
- data/ext/syncword.h +0 -3
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -6,22 +6,32 @@ Rakefile
|
|
6
6
|
examples/decoder.rb
|
7
7
|
examples/encoder.rb
|
8
8
|
examples/kexp.rb
|
9
|
-
ext/
|
10
|
-
ext/
|
11
|
-
ext/
|
12
|
-
ext/
|
13
|
-
ext/
|
14
|
-
ext/icanhasaudio.
|
15
|
-
ext/icanhasaudio.
|
16
|
-
ext/
|
17
|
-
ext/
|
18
|
-
ext/
|
19
|
-
ext/
|
20
|
-
ext/
|
21
|
-
ext/
|
22
|
-
ext/
|
9
|
+
ext/icanhasaudio/audio_mpeg_decoder.c
|
10
|
+
ext/icanhasaudio/audio_mpeg_decoder.h
|
11
|
+
ext/icanhasaudio/audio_mpeg_decoder_mp3data.c
|
12
|
+
ext/icanhasaudio/audio_mpeg_decoder_mp3data.h
|
13
|
+
ext/icanhasaudio/audio_mpeg_encoder.c
|
14
|
+
ext/icanhasaudio/audio_mpeg_encoder.h
|
15
|
+
ext/icanhasaudio/audio_ogg_decoder.c
|
16
|
+
ext/icanhasaudio/audio_ogg_decoder.h
|
17
|
+
ext/icanhasaudio/extconf.rb
|
18
|
+
ext/icanhasaudio/get_audio.c
|
19
|
+
ext/icanhasaudio/get_audio.h
|
20
|
+
ext/icanhasaudio/native.c
|
21
|
+
ext/icanhasaudio/native.h
|
22
|
+
ext/icanhasaudio/rb_wav.c
|
23
|
+
ext/icanhasaudio/rb_wav.h
|
24
|
+
lib/icanhasaudio.rb
|
23
25
|
lib/icanhasaudio/mpeg.rb
|
26
|
+
lib/icanhasaudio/mpeg/decoder.rb
|
24
27
|
lib/icanhasaudio/mpeg/encoder.rb
|
25
28
|
lib/icanhasaudio/ogg.rb
|
29
|
+
lib/icanhasaudio/ogg/decoder.rb
|
30
|
+
lib/icanhasaudio/version.rb
|
31
|
+
lib/icanhasaudio/wav.rb
|
32
|
+
lib/icanhasaudio/wav/file.rb
|
33
|
+
test/assets/icha.mp3
|
26
34
|
test/assets/testcase.wav
|
35
|
+
test/helper.rb
|
36
|
+
test/mpeg/test_decoder.rb
|
27
37
|
test/test_mpeg_encoder.rb
|
data/README.txt
CHANGED
data/Rakefile
CHANGED
@@ -4,26 +4,33 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "lib")
|
|
4
4
|
|
5
5
|
kind = Config::CONFIG["DLEXT"]
|
6
6
|
|
7
|
-
|
7
|
+
require 'icanhasaudio/version'
|
8
|
+
|
9
|
+
Hoe.new('icanhasaudio', Audio::MPEG::Decoder::VERSION) do |p|
|
8
10
|
p.rubyforge_name = 'seattlerb'
|
9
11
|
p.author = 'Aaron Patterson'
|
10
12
|
p.email = 'aaronp@rubyforge.org'
|
11
13
|
p.summary = "icanhasaudio is a lame/vorbis wrapper for decoding ur mp3s and ur oggs."
|
12
14
|
p.description = p.paragraphs_of('README.txt', 3..6).join("\n\n")
|
13
15
|
p.url = p.paragraphs_of('README.txt', 1).first.strip
|
14
|
-
p.spec_extras = {
|
15
|
-
|
16
|
+
p.spec_extras = {
|
17
|
+
:extensions => ['ext/icanhasaudio/extconf.rb']
|
18
|
+
}
|
19
|
+
p.clean_globs = [
|
20
|
+
"ext/icanhasaudio/Makefile",
|
21
|
+
"ext/icanhasaudio/*.{o,so,bundle,log}"
|
22
|
+
]
|
16
23
|
end
|
17
24
|
|
18
25
|
Rake::Task[:test].prerequisites << :extension
|
19
26
|
|
20
27
|
desc "I can haz binary"
|
21
|
-
task :extension => ["ext/icanhasaudio.#{kind}"]
|
28
|
+
task :extension => ["ext/icanhasaudio/native.#{kind}"]
|
22
29
|
|
23
|
-
file "ext/Makefile" => "ext/extconf.rb" do
|
24
|
-
Dir.chdir("ext") { ruby "extconf.rb" }
|
30
|
+
file "ext/icanhasaudio/Makefile" => "ext/icanhasaudio/extconf.rb" do
|
31
|
+
Dir.chdir("ext/icanhasaudio") { ruby "extconf.rb" }
|
25
32
|
end
|
26
33
|
|
27
|
-
file "ext/icanhasaudio.#{kind}" => FileList["ext/Makefile", "ext/*.{c,h}"] do
|
28
|
-
Dir.chdir("ext") { sh "make" }
|
34
|
+
file "ext/icanhasaudio/native.#{kind}" => FileList["ext/icanhasaudio/Makefile", "ext/icanhasaudio/*.{c,h}"] do
|
35
|
+
Dir.chdir("ext/icanhasaudio") { sh "make" }
|
29
36
|
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
/*
|
2
|
+
* Most of this code was take from the lame front end. So thank you to the
|
3
|
+
* lame team! The good parts are theirs, the bad parts are mine.
|
4
|
+
*
|
5
|
+
* The rest of it is (c) 2007 Aaron Patterson <aaronp@tenderlovemaking.com>
|
6
|
+
*
|
7
|
+
* Released under the GPL
|
8
|
+
*/
|
9
|
+
#include <audio_mpeg_decoder.h>
|
10
|
+
|
11
|
+
static void reader_mark(lame_global_flags * lgf) {}
|
12
|
+
static void reader_free(lame_global_flags * gfp) {
|
13
|
+
lame_close(gfp);
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* call-seq:
|
18
|
+
* Audio::MPEG::Decoder.new
|
19
|
+
*
|
20
|
+
* Returns a new MPEG Decoder object.
|
21
|
+
*/
|
22
|
+
static VALUE
|
23
|
+
reader_allocate(VALUE klass) {
|
24
|
+
int i = 0;
|
25
|
+
lame_global_flags * gfp = lame_init();
|
26
|
+
lame_set_decode_only(gfp, 1);
|
27
|
+
i = lame_init_params(gfp);
|
28
|
+
|
29
|
+
if(i < 0) {
|
30
|
+
rb_raise(rb_eRuntimeError, "Fatal error during initialization.\n");
|
31
|
+
}
|
32
|
+
lame_decode_init();
|
33
|
+
return Data_Wrap_Struct(klass, reader_mark, reader_free, gfp);
|
34
|
+
}
|
35
|
+
|
36
|
+
/*
|
37
|
+
* call-seq:
|
38
|
+
* Audio::MPEG::Decoder.lame_version
|
39
|
+
*
|
40
|
+
* Returns the version of lame you are using.
|
41
|
+
*/
|
42
|
+
static VALUE method_lame_version(VALUE klass) {
|
43
|
+
const char * version = get_lame_version();
|
44
|
+
return rb_str_new(version, strlen(version));
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
* call-seq:
|
49
|
+
* decode_headers_for(buffer)
|
50
|
+
*
|
51
|
+
* Decode the mp3 headers for +buffer+.
|
52
|
+
*/
|
53
|
+
static VALUE decode_headers_for(VALUE self, VALUE rb_buffer)
|
54
|
+
{
|
55
|
+
int enc_delay;
|
56
|
+
int enc_padding;
|
57
|
+
mp3data_struct * mp3data;
|
58
|
+
|
59
|
+
unsigned char * buf = (unsigned char *)StringValuePtr(rb_buffer);
|
60
|
+
int len = NUM2INT(rb_funcall(rb_buffer, rb_intern("length"), 0));
|
61
|
+
short int pcm_l[1152], pcm_r[1152];
|
62
|
+
|
63
|
+
VALUE rb_mp3data = rb_funcall(self, rb_intern("mp3data"), 0);
|
64
|
+
Data_Get_Struct(rb_mp3data, mp3data_struct, mp3data);
|
65
|
+
|
66
|
+
int ret = lame_decode1_headersB(buf,
|
67
|
+
len,
|
68
|
+
pcm_l,
|
69
|
+
pcm_r,
|
70
|
+
mp3data,
|
71
|
+
&enc_delay,
|
72
|
+
&enc_padding
|
73
|
+
);
|
74
|
+
|
75
|
+
if(ret == -1)
|
76
|
+
rb_raise(rb_eRuntimeError, "Decode headers failed.\n");
|
77
|
+
|
78
|
+
return rb_mp3data;
|
79
|
+
}
|
80
|
+
|
81
|
+
/*
|
82
|
+
* call-seq:
|
83
|
+
* native_decode(input_io, output_io)
|
84
|
+
*
|
85
|
+
* Decode the input IO and write it to the output IO.
|
86
|
+
*/
|
87
|
+
static VALUE native_decode(VALUE self, VALUE infile, VALUE outf) {
|
88
|
+
lame_global_flags * gfp;
|
89
|
+
short int Buffer[2][1152];
|
90
|
+
int iread;
|
91
|
+
double wavsize;
|
92
|
+
int i;
|
93
|
+
int tmp_num_channels;
|
94
|
+
int skip;
|
95
|
+
VALUE raw;
|
96
|
+
mp3data_struct * mp3data;
|
97
|
+
|
98
|
+
VALUE rb_mp3data = rb_funcall(self, rb_intern("mp3data"), 0);
|
99
|
+
Data_Get_Struct(rb_mp3data, mp3data_struct, mp3data);
|
100
|
+
|
101
|
+
raw = rb_iv_get(self, "@raw");
|
102
|
+
|
103
|
+
Data_Get_Struct(self, lame_global_flags, gfp);
|
104
|
+
tmp_num_channels = lame_get_num_channels( gfp );
|
105
|
+
lame_set_num_samples(gfp, MAX_U_32_NUM);
|
106
|
+
|
107
|
+
skip = lame_get_encoder_delay(gfp)+528+1;
|
108
|
+
|
109
|
+
rb_iv_set(self, "@bits", INT2NUM(16));
|
110
|
+
|
111
|
+
wavsize = -skip;
|
112
|
+
if(lame_get_num_samples(gfp) == MAX_U_32_NUM) {
|
113
|
+
rb_funcall(self, rb_intern("determine_samples_for"), 1, infile);
|
114
|
+
}
|
115
|
+
mp3data->totalframes = mp3data->nsamp / mp3data->framesize;
|
116
|
+
|
117
|
+
assert(tmp_num_channels >= 1 && tmp_num_channels <= 2);
|
118
|
+
|
119
|
+
do {
|
120
|
+
char BitBuffer16[1152 * 4];
|
121
|
+
int bit_16_i = 0;
|
122
|
+
iread = get_audio16(self, infile, Buffer, mp3data);
|
123
|
+
mp3data->framenum += iread / mp3data->framesize;
|
124
|
+
wavsize += iread;
|
125
|
+
|
126
|
+
memset(&BitBuffer16, 0, 1152 * 4);
|
127
|
+
|
128
|
+
skip -= (i = skip < iread ? skip : iread); /* 'i' samples are to skip in this frame */
|
129
|
+
|
130
|
+
for (; i < iread; i++) {
|
131
|
+
/* Write the 0 channel */
|
132
|
+
BitBuffer16[bit_16_i] = Buffer[0][i] & 0xFF;
|
133
|
+
BitBuffer16[bit_16_i + 1] = ((Buffer[0][i] >> 8) & 0xFF);
|
134
|
+
|
135
|
+
if (tmp_num_channels == 2) {
|
136
|
+
BitBuffer16[bit_16_i + 2] = Buffer[1][i] & 0xFF;
|
137
|
+
BitBuffer16[bit_16_i + 3] = ((Buffer[1][i] >> 8) & 0xFF);
|
138
|
+
bit_16_i += 4;
|
139
|
+
} else {
|
140
|
+
bit_16_i += 2;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
rb_funcall(outf, rb_intern("write"), 1, rb_str_new(BitBuffer16, bit_16_i));
|
144
|
+
} while (iread);
|
145
|
+
|
146
|
+
i = (16 / 8) * tmp_num_channels;
|
147
|
+
assert(i > 0);
|
148
|
+
if (wavsize <= 0) {
|
149
|
+
wavsize = 0;
|
150
|
+
}
|
151
|
+
else if (wavsize > 0xFFFFFFD0 / i) {
|
152
|
+
wavsize = 0xFFFFFFD0;
|
153
|
+
}
|
154
|
+
else {
|
155
|
+
wavsize *= i;
|
156
|
+
}
|
157
|
+
|
158
|
+
rb_iv_set(self, "@wavsize", INT2NUM(wavsize));
|
159
|
+
return Qnil;
|
160
|
+
}
|
161
|
+
|
162
|
+
/*
|
163
|
+
* call-seq:
|
164
|
+
* num_channels
|
165
|
+
*
|
166
|
+
* Get the number of channels
|
167
|
+
*/
|
168
|
+
static VALUE get_num_channels(VALUE self)
|
169
|
+
{
|
170
|
+
lame_global_flags * gfp;
|
171
|
+
Data_Get_Struct(self, lame_global_flags, gfp);
|
172
|
+
return INT2NUM(lame_get_num_channels(gfp));
|
173
|
+
}
|
174
|
+
|
175
|
+
/*
|
176
|
+
* call-seq:
|
177
|
+
* num_samples=(number)
|
178
|
+
*
|
179
|
+
* Set the number of samples
|
180
|
+
*/
|
181
|
+
static VALUE set_num_samples(VALUE self, VALUE sample_count)
|
182
|
+
{
|
183
|
+
lame_global_flags * gfp;
|
184
|
+
Data_Get_Struct(self, lame_global_flags, gfp);
|
185
|
+
lame_set_num_samples(gfp, NUM2INT(sample_count));
|
186
|
+
return sample_count;
|
187
|
+
}
|
188
|
+
|
189
|
+
/*
|
190
|
+
* call-seq:
|
191
|
+
* in_samplerate
|
192
|
+
*
|
193
|
+
* Get the input samplerate
|
194
|
+
*/
|
195
|
+
static VALUE get_in_samplerate(VALUE self)
|
196
|
+
{
|
197
|
+
lame_global_flags * gfp;
|
198
|
+
Data_Get_Struct(self, lame_global_flags, gfp);
|
199
|
+
return INT2NUM(lame_get_in_samplerate(gfp));
|
200
|
+
}
|
201
|
+
|
202
|
+
void init_audio_mpeg_decoder() {
|
203
|
+
VALUE rb_mAudio = rb_define_module("Audio");
|
204
|
+
VALUE rb_mMpeg = rb_define_module_under(rb_mAudio, "MPEG");
|
205
|
+
VALUE rb_cDecoder = rb_define_class_under(rb_mMpeg, "Decoder", rb_cObject);
|
206
|
+
|
207
|
+
rb_define_singleton_method(
|
208
|
+
rb_cDecoder,
|
209
|
+
"lame_version",
|
210
|
+
method_lame_version,
|
211
|
+
0
|
212
|
+
);
|
213
|
+
|
214
|
+
rb_define_alloc_func(rb_cDecoder, reader_allocate);
|
215
|
+
rb_define_method(rb_cDecoder, "num_samples=", set_num_samples, 1);
|
216
|
+
rb_define_method(rb_cDecoder, "in_samplerate", get_in_samplerate, 0);
|
217
|
+
rb_define_private_method(rb_cDecoder, "native_decode", native_decode, 2);
|
218
|
+
rb_define_private_method(rb_cDecoder, "decode_headers_for", decode_headers_for, 1);
|
219
|
+
rb_define_private_method(rb_cDecoder, "num_channels", get_num_channels, 0);
|
220
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
#include <audio_mpeg_decoder_mp3data.h>
|
2
|
+
|
3
|
+
/*
|
4
|
+
* call-seq:
|
5
|
+
* header_parsed?
|
6
|
+
*
|
7
|
+
* Has the mp3 header been parsed yet?
|
8
|
+
*/
|
9
|
+
static VALUE header_parsed_eh(VALUE self)
|
10
|
+
{
|
11
|
+
mp3data_struct * mp3data;
|
12
|
+
Data_Get_Struct(self, mp3data_struct, mp3data);
|
13
|
+
|
14
|
+
if(mp3data->header_parsed == 1) return Qtrue;
|
15
|
+
return Qfalse;
|
16
|
+
}
|
17
|
+
|
18
|
+
/*
|
19
|
+
* call-seq:
|
20
|
+
* bitrate
|
21
|
+
*
|
22
|
+
* Get the bitrate
|
23
|
+
*/
|
24
|
+
static VALUE bitrate(VALUE self)
|
25
|
+
{
|
26
|
+
mp3data_struct * mp3data;
|
27
|
+
Data_Get_Struct(self, mp3data_struct, mp3data);
|
28
|
+
return INT2NUM(mp3data->bitrate);
|
29
|
+
}
|
30
|
+
|
31
|
+
/*
|
32
|
+
* call-seq:
|
33
|
+
* total_frames
|
34
|
+
*
|
35
|
+
* Get the total frames for this mp3
|
36
|
+
*/
|
37
|
+
static VALUE total_frames(VALUE self)
|
38
|
+
{
|
39
|
+
mp3data_struct * mp3data;
|
40
|
+
Data_Get_Struct(self, mp3data_struct, mp3data);
|
41
|
+
return INT2NUM(mp3data->totalframes);
|
42
|
+
}
|
43
|
+
|
44
|
+
/*
|
45
|
+
* call-seq:
|
46
|
+
* nsamp
|
47
|
+
*
|
48
|
+
* Get the number of samples
|
49
|
+
*/
|
50
|
+
static VALUE get_nsamp(VALUE self)
|
51
|
+
{
|
52
|
+
mp3data_struct * mp3data;
|
53
|
+
Data_Get_Struct(self, mp3data_struct, mp3data);
|
54
|
+
return LONG2NUM(mp3data->nsamp);
|
55
|
+
}
|
56
|
+
|
57
|
+
/*
|
58
|
+
* call-seq:
|
59
|
+
* nsamp=(num)
|
60
|
+
*
|
61
|
+
* Set the number of samples to +num+
|
62
|
+
*/
|
63
|
+
static VALUE set_nsamp(VALUE self, VALUE num)
|
64
|
+
{
|
65
|
+
mp3data_struct * mp3data;
|
66
|
+
Data_Get_Struct(self, mp3data_struct, mp3data);
|
67
|
+
mp3data->nsamp = NUM2LONG(num);
|
68
|
+
return num;
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE deallocate(mp3data_struct * mp3data)
|
72
|
+
{
|
73
|
+
free(mp3data);
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE allocate(VALUE klass)
|
77
|
+
{
|
78
|
+
mp3data_struct * mp3data = calloc(1, sizeof(mp3data_struct));
|
79
|
+
return Data_Wrap_Struct(klass, 0, deallocate, mp3data);
|
80
|
+
}
|
81
|
+
|
82
|
+
void init_audio_mpeg_decoder_mp3data()
|
83
|
+
{
|
84
|
+
VALUE rb_mAudio = rb_define_module("Audio");
|
85
|
+
VALUE rb_mMpeg = rb_define_module_under(rb_mAudio, "MPEG");
|
86
|
+
VALUE rb_cDecoder = rb_define_class_under(rb_mMpeg, "Decoder", rb_cObject);
|
87
|
+
VALUE klass = rb_define_class_under(rb_cDecoder, "MP3Data", rb_cObject);
|
88
|
+
|
89
|
+
rb_const_set(klass, rb_intern("MAX_U_32_NUM"), INT2NUM(MAX_U_32_NUM));
|
90
|
+
rb_define_method(klass, "header_parsed?", header_parsed_eh, 0);
|
91
|
+
rb_define_method(klass, "bitrate", bitrate, 0);
|
92
|
+
rb_define_method(klass, "total_frames", total_frames, 0);
|
93
|
+
rb_define_method(klass, "nsamp", get_nsamp, 0);
|
94
|
+
rb_define_method(klass, "nsamp=", set_nsamp, 1);
|
95
|
+
rb_define_alloc_func(klass, allocate);
|
96
|
+
}
|