icanhasaudio 0.1.1 → 0.1.2
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/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
|
+
}
|