coreaudio 0.0.2 → 0.0.3
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/Gemfile +2 -0
- data/Gemfile.lock +4 -1
- data/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/coreaudio.gemspec +11 -3
- data/examples/convert_wav_to_m4a.rb +19 -0
- data/ext/audiofile.m +214 -57
- data/ext/coreaudio.h +16 -1
- data/ext/coreaudio.m +1 -1
- data/ext/coreaudio_missing.c +24 -0
- data/ext/extconf.rb +9 -0
- metadata +32 -8
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -9,10 +9,10 @@ CoreAudio (Audio Framework of Mac OS X) wrapper library for ruby 1.9
|
|
9
9
|
* Output audio data (Loop buffer, Stream buffer)
|
10
10
|
* Input audio data (Stream buffer)
|
11
11
|
* Save audio data to WAV/M4A file (wrapper for ExtAudioFile)
|
12
|
+
* Ream audio file (WAV/M4A)
|
12
13
|
|
13
14
|
== ToDo
|
14
|
-
* Switch input/output audio sample type (signed 16bit integer,
|
15
|
-
* Read audio file (wrapper for ExtAudioFile)
|
15
|
+
* Switch input/output audio sample type (signed 16bit integer, packed String)
|
16
16
|
* Wrapper for AudioUnit/AudioGraph
|
17
17
|
|
18
18
|
== Contributing to coreaudio
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ require 'jeweler'
|
|
15
15
|
Jeweler::Tasks.new do |gem|
|
16
16
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
17
|
gem.name = "coreaudio"
|
18
|
-
gem.homepage = "
|
18
|
+
gem.homepage = "https://github.com/nagachika/ruby-coreaudio"
|
19
19
|
gem.license = "BSDL"
|
20
20
|
gem.summary = %Q{Mac OS X CoreAudio wrapper library}
|
21
21
|
gem.description = %Q{Mac OS X CoreAudio wrapper library}
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/coreaudio.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "coreaudio"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["CHIKANAGA Tomoyuki"]
|
12
|
-
s.date = "2011-10-
|
12
|
+
s.date = "2011-10-16"
|
13
13
|
s.description = "Mac OS X CoreAudio wrapper library"
|
14
14
|
s.email = "nagachika00@gmail.com"
|
15
15
|
s.extensions = ["ext/extconf.rb"]
|
@@ -26,17 +26,19 @@ Gem::Specification.new do |s|
|
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"coreaudio.gemspec",
|
29
|
+
"examples/convert_wav_to_m4a.rb",
|
29
30
|
"examples/outbuffer_sine.rb",
|
30
31
|
"examples/outloop_sine.rb",
|
31
32
|
"examples/record_to_wave.rb",
|
32
33
|
"ext/audiofile.m",
|
33
34
|
"ext/coreaudio.h",
|
34
35
|
"ext/coreaudio.m",
|
36
|
+
"ext/coreaudio_missing.c",
|
35
37
|
"ext/depend",
|
36
38
|
"ext/extconf.rb",
|
37
39
|
"lib/coreaudio.rb"
|
38
40
|
]
|
39
|
-
s.homepage = "
|
41
|
+
s.homepage = "https://github.com/nagachika/ruby-coreaudio"
|
40
42
|
s.licenses = ["BSDL"]
|
41
43
|
s.require_paths = ["lib"]
|
42
44
|
s.rubygems_version = "1.8.11"
|
@@ -48,13 +50,19 @@ Gem::Specification.new do |s|
|
|
48
50
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
51
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
50
52
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
53
|
+
s.add_development_dependency(%q<rake>, ["~> 0.9.2"])
|
54
|
+
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
51
55
|
else
|
52
56
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
53
57
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
58
|
+
s.add_dependency(%q<rake>, ["~> 0.9.2"])
|
59
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
54
60
|
end
|
55
61
|
else
|
56
62
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
63
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
64
|
+
s.add_dependency(%q<rake>, ["~> 0.9.2"])
|
65
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
58
66
|
end
|
59
67
|
end
|
60
68
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "coreaudio"
|
4
|
+
|
5
|
+
wav = CoreAudio::AudioFile.new("sample.wav", :read)
|
6
|
+
|
7
|
+
m4a = CoreAudio::AudioFile.new("sample.m4a", :write, :format => :m4a,
|
8
|
+
:rate => wav.rate,
|
9
|
+
:channel => wav.channel)
|
10
|
+
|
11
|
+
loop do
|
12
|
+
buf = wav.read(1024)
|
13
|
+
break if buf.empty?
|
14
|
+
m4a.write(buf)
|
15
|
+
end
|
16
|
+
|
17
|
+
wav.close
|
18
|
+
m4a.close
|
19
|
+
|
data/ext/audiofile.m
CHANGED
@@ -49,7 +49,7 @@ ca_audio_file_free(void *ptr)
|
|
49
49
|
ca_audio_file_t *data = ptr;
|
50
50
|
|
51
51
|
if ( data->file ) {
|
52
|
-
|
52
|
+
ExtAudioFileDispose(data->file);
|
53
53
|
data->file = NULL;
|
54
54
|
}
|
55
55
|
}
|
@@ -77,6 +77,42 @@ ca_audio_file_alloc(VALUE klass)
|
|
77
77
|
return obj;
|
78
78
|
}
|
79
79
|
|
80
|
+
static void
|
81
|
+
parse_audio_file_options(VALUE opt, Boolean for_write,
|
82
|
+
Float64 *rate, Float64 *file_rate,
|
83
|
+
UInt32 *channel, UInt32 *file_channel)
|
84
|
+
{
|
85
|
+
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_rate))) {
|
86
|
+
if (for_write)
|
87
|
+
*rate = 44100.0;
|
88
|
+
else
|
89
|
+
*rate = *file_rate;
|
90
|
+
} else {
|
91
|
+
*rate = NUM2DBL(rb_hash_aref(opt, sym_rate));
|
92
|
+
}
|
93
|
+
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_channel))) {
|
94
|
+
if (for_write)
|
95
|
+
*channel = 2;
|
96
|
+
else
|
97
|
+
*channel = *file_channel;
|
98
|
+
} else {
|
99
|
+
*channel = NUM2UINT(rb_hash_aref(opt, sym_channel));
|
100
|
+
}
|
101
|
+
|
102
|
+
if (for_write) {
|
103
|
+
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_file_rate))) {
|
104
|
+
*file_rate = *rate;
|
105
|
+
} else {
|
106
|
+
*file_rate = NUM2DBL(rb_hash_aref(opt, sym_file_rate));
|
107
|
+
}
|
108
|
+
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_file_channel))) {
|
109
|
+
*file_channel = *channel;
|
110
|
+
} else {
|
111
|
+
*file_channel = NUM2UINT(rb_hash_aref(opt, sym_file_channel));
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
80
116
|
/*
|
81
117
|
* call-seq:
|
82
118
|
* AudioFile.new(filepath, mode, opt)
|
@@ -88,11 +124,11 @@ ca_audio_file_alloc(VALUE klass)
|
|
88
124
|
* 'client data' means audio data pass to AudioFile#write or from
|
89
125
|
* AudioFile#read method.
|
90
126
|
*
|
91
|
-
* :format :: audio file format. currently audio file format and
|
127
|
+
* :format :: audio file format. currently audio file format and
|
92
128
|
* codec type is hardcoded. (:wav, :m4a)
|
93
129
|
* :rate :: sample rate of data pass from AudioFile#read or to AudioFile#write
|
94
130
|
* If not specified, :file_rate value is used. (Float)
|
95
|
-
* :channel :: number of channels
|
131
|
+
* :channel :: number of channels
|
96
132
|
* :file_rate :: file data sample rate. only work when open for output. (Float)
|
97
133
|
* :file_channel :: file data number of channels. only work when open for
|
98
134
|
* output.
|
@@ -104,9 +140,8 @@ ca_audio_file_initialize(int argc, VALUE *argv, VALUE self)
|
|
104
140
|
VALUE path, mode, opt, format;
|
105
141
|
Float64 rate, file_rate;
|
106
142
|
UInt32 channel, file_channel;
|
107
|
-
CFURLRef
|
108
|
-
AudioFileTypeID filetype;
|
109
|
-
UInt32 flags = kAudioFileFlags_EraseFile;
|
143
|
+
CFURLRef url = NULL;
|
144
|
+
AudioFileTypeID filetype = 0;
|
110
145
|
OSStatus err = noErr;
|
111
146
|
|
112
147
|
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, data);
|
@@ -117,65 +152,70 @@ ca_audio_file_initialize(int argc, VALUE *argv, VALUE self)
|
|
117
152
|
if (NIL_P(mode) || mode == sym_read)
|
118
153
|
data->for_write = FALSE;
|
119
154
|
else if (mode == sym_write)
|
120
|
-
|
155
|
+
data->for_write = TRUE;
|
121
156
|
else
|
122
157
|
rb_raise(rb_eArgError, "coreaudio: mode should be :read or :write");
|
123
158
|
|
124
|
-
|
125
|
-
|
126
|
-
rate
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
if (format == sym_wav) {
|
151
|
-
filetype = kAudioFileWAVEType;
|
152
|
-
setASBD(&data->file_desc, file_rate, kAudioFormatLinearPCM,
|
153
|
-
kLinearPCMFormatFlagIsSignedInteger |
|
154
|
-
kAudioFormatFlagIsPacked,
|
155
|
-
file_channel, 16, 1);
|
156
|
-
} else if (format == sym_m4a) {
|
157
|
-
filetype = kAudioFileM4AType;
|
158
|
-
setASBD(&data->file_desc, file_rate, kAudioFormatMPEG4AAC,
|
159
|
-
0, file_channel, 0, 0);
|
160
|
-
} else {
|
161
|
-
volatile VALUE str = rb_inspect(format);
|
162
|
-
RB_GC_GUARD(str);
|
163
|
-
rb_raise(rb_eArgError, "coreaudio: unsupported format (%s)",
|
164
|
-
RSTRING_PTR(str));
|
159
|
+
if (data->for_write) {
|
160
|
+
/* when open for write, parse options before open ExtAudioFile */
|
161
|
+
parse_audio_file_options(opt, data->for_write, &rate, &file_rate,
|
162
|
+
&channel, &file_channel);
|
163
|
+
|
164
|
+
format = rb_hash_aref(opt, sym_format);
|
165
|
+
if (NIL_P(format))
|
166
|
+
rb_raise(rb_eArgError, "coreaudio: :format option must be specified");
|
167
|
+
|
168
|
+
if (format == sym_wav) {
|
169
|
+
filetype = kAudioFileWAVEType;
|
170
|
+
setASBD(&data->file_desc, file_rate, kAudioFormatLinearPCM,
|
171
|
+
kLinearPCMFormatFlagIsSignedInteger |
|
172
|
+
kAudioFormatFlagIsPacked,
|
173
|
+
file_channel, 16, 1);
|
174
|
+
} else if (format == sym_m4a) {
|
175
|
+
filetype = kAudioFileM4AType;
|
176
|
+
setASBD(&data->file_desc, file_rate, kAudioFormatMPEG4AAC,
|
177
|
+
0, file_channel, 0, 0);
|
178
|
+
} else {
|
179
|
+
volatile VALUE str = rb_inspect(format);
|
180
|
+
RB_GC_GUARD(str);
|
181
|
+
rb_raise(rb_eArgError, "coreaudio: unsupported format (%s)",
|
182
|
+
RSTRING_PTR(str));
|
183
|
+
}
|
165
184
|
}
|
166
185
|
|
167
186
|
/* create URL represent the target filepath */
|
168
|
-
|
187
|
+
url = CFURLCreateFromFileSystemRepresentation(
|
169
188
|
NULL, StringValueCStr(path), (CFIndex)RSTRING_LEN(path), FALSE);
|
170
189
|
|
171
190
|
/* open ExtAudioFile */
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
191
|
+
if (data->for_write)
|
192
|
+
err = ExtAudioFileCreateWithURL(url, filetype, &data->file_desc,
|
193
|
+
NULL, kAudioFileFlags_EraseFile,
|
194
|
+
&data->file);
|
195
|
+
else
|
196
|
+
err = ExtAudioFileOpenURL(url, &data->file);
|
197
|
+
CFRelease(url);
|
198
|
+
url = NULL;
|
176
199
|
if (err != noErr) {
|
177
200
|
rb_raise(rb_eArgError,
|
178
|
-
"coreaudio:
|
201
|
+
"coreaudio: fail to open ExtAudioFile: %d", (int)err);
|
202
|
+
}
|
203
|
+
|
204
|
+
/* get Audio Stream Basic Description (ASBD) from input file */
|
205
|
+
if (!data->for_write) {
|
206
|
+
UInt32 size = sizeof(data->file_desc);
|
207
|
+
err = ExtAudioFileGetProperty(data->file,
|
208
|
+
kExtAudioFileProperty_FileDataFormat,
|
209
|
+
&size, &data->file_desc);
|
210
|
+
if (err != noErr)
|
211
|
+
rb_raise(rb_eRuntimeError,
|
212
|
+
"coreaudio: fail to Get ExtAudioFile Property %d", err);
|
213
|
+
|
214
|
+
/* parse options */
|
215
|
+
file_rate = data->file_desc.mSampleRate;
|
216
|
+
file_channel = data->file_desc.mChannelsPerFrame;
|
217
|
+
parse_audio_file_options(opt, data->for_write, &rate, &file_rate,
|
218
|
+
&channel, &file_channel);
|
179
219
|
}
|
180
220
|
|
181
221
|
setASBD(&data->inner_desc, rate, kAudioFormatLinearPCM,
|
@@ -217,6 +257,7 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
217
257
|
AudioBufferList buf_list;
|
218
258
|
UInt32 frames;
|
219
259
|
size_t alloc_size;
|
260
|
+
volatile VALUE tmpstr;
|
220
261
|
OSStatus err = noErr;
|
221
262
|
int i;
|
222
263
|
|
@@ -225,6 +266,12 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
225
266
|
|
226
267
|
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, file);
|
227
268
|
|
269
|
+
if (file->file == NULL)
|
270
|
+
rb_raise(rb_eIOError, "coreaudio: already closend file");
|
271
|
+
|
272
|
+
if (!file->for_write)
|
273
|
+
rb_raise(rb_eRuntimeError, "coreaudio: audio file opened for reading");
|
274
|
+
|
228
275
|
frames = RARRAY_LENINT(data) / file->inner_desc.mChannelsPerFrame;
|
229
276
|
alloc_size = (file->inner_desc.mBitsPerChannel/8) * RARRAY_LEN(data);
|
230
277
|
|
@@ -232,7 +279,7 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
232
279
|
buf_list.mNumberBuffers = 1;
|
233
280
|
buf_list.mBuffers[0].mNumberChannels = file->inner_desc.mChannelsPerFrame;
|
234
281
|
buf_list.mBuffers[0].mDataByteSize = (UInt32)alloc_size;
|
235
|
-
buf_list.mBuffers[0].mData =
|
282
|
+
buf_list.mBuffers[0].mData = rb_alloc_tmp_buffer(&tmpstr, alloc_size);
|
236
283
|
buf = buf_list.mBuffers[0].mData;
|
237
284
|
|
238
285
|
for (i = 0; i < RARRAY_LEN(data); i++) {
|
@@ -241,7 +288,7 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
241
288
|
|
242
289
|
err = ExtAudioFileWrite(file->file, frames, &buf_list);
|
243
290
|
|
244
|
-
|
291
|
+
rb_free_tmp_buffer(&tmpstr);
|
245
292
|
|
246
293
|
if (err != noErr) {
|
247
294
|
rb_raise(rb_eRuntimeError,
|
@@ -251,6 +298,112 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
251
298
|
return self;
|
252
299
|
}
|
253
300
|
|
301
|
+
static VALUE
|
302
|
+
ca_audio_file_read(int argc, VALUE *argv, VALUE self)
|
303
|
+
{
|
304
|
+
ca_audio_file_t *file;
|
305
|
+
VALUE frame_val;
|
306
|
+
UInt32 frames, chunk, total, read_frames;
|
307
|
+
AudioBufferList buf_list;
|
308
|
+
short *buf;
|
309
|
+
size_t alloc_size;
|
310
|
+
volatile VALUE tmpstr;
|
311
|
+
VALUE ary;
|
312
|
+
UInt32 i;
|
313
|
+
OSStatus err = noErr;
|
314
|
+
|
315
|
+
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, file);
|
316
|
+
|
317
|
+
if (file->file == NULL)
|
318
|
+
rb_raise(rb_eIOError, "coreaudio: already closend file");
|
319
|
+
|
320
|
+
if (file->for_write)
|
321
|
+
rb_raise(rb_eRuntimeError, "coreaudio: audio file open for writing");
|
322
|
+
|
323
|
+
rb_scan_args(argc, argv, "01", &frame_val);
|
324
|
+
|
325
|
+
if (NIL_P(frame_val)) {
|
326
|
+
frames = 0;
|
327
|
+
chunk = 1024;
|
328
|
+
} else {
|
329
|
+
frames = chunk = NUM2UINT(frame_val);
|
330
|
+
}
|
331
|
+
|
332
|
+
alloc_size = (file->inner_desc.mBitsPerChannel/8) *
|
333
|
+
file->inner_desc.mChannelsPerFrame * chunk;
|
334
|
+
|
335
|
+
/* prepare interleaved audio buffer */
|
336
|
+
buf_list.mNumberBuffers = 1;
|
337
|
+
buf_list.mBuffers[0].mNumberChannels = file->inner_desc.mChannelsPerFrame;
|
338
|
+
buf_list.mBuffers[0].mDataByteSize = (UInt32)alloc_size;
|
339
|
+
buf_list.mBuffers[0].mData = rb_alloc_tmp_buffer(&tmpstr, alloc_size);
|
340
|
+
buf = buf_list.mBuffers[0].mData;
|
341
|
+
|
342
|
+
ary = rb_ary_new2(chunk*file->inner_desc.mChannelsPerFrame);
|
343
|
+
|
344
|
+
for (total = 0; total < frames || frames == 0; total += read_frames) {
|
345
|
+
read_frames = chunk;
|
346
|
+
err = ExtAudioFileRead(file->file, &read_frames, &buf_list);
|
347
|
+
|
348
|
+
if (err != noErr) {
|
349
|
+
rb_free_tmp_buffer(&tmpstr);
|
350
|
+
rb_raise(rb_eRuntimeError,
|
351
|
+
"coreaudio: ExtAudioFileRead() fails: %d", (int)err);
|
352
|
+
}
|
353
|
+
|
354
|
+
if (read_frames == 0)
|
355
|
+
break;
|
356
|
+
|
357
|
+
for (i = 0; i < read_frames * file->inner_desc.mChannelsPerFrame; i++) {
|
358
|
+
rb_ary_push(ary, INT2NUM((int)buf[i]));
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
rb_free_tmp_buffer(&tmpstr);
|
363
|
+
|
364
|
+
return ary;
|
365
|
+
}
|
366
|
+
|
367
|
+
static VALUE
|
368
|
+
ca_audio_file_rate(VALUE self)
|
369
|
+
{
|
370
|
+
ca_audio_file_t *data;
|
371
|
+
|
372
|
+
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, data);
|
373
|
+
|
374
|
+
return DBL2NUM(data->file_desc.mSampleRate);
|
375
|
+
}
|
376
|
+
|
377
|
+
static VALUE
|
378
|
+
ca_audio_file_channel(VALUE self)
|
379
|
+
{
|
380
|
+
ca_audio_file_t *data;
|
381
|
+
|
382
|
+
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, data);
|
383
|
+
|
384
|
+
return UINT2NUM((unsigned int)data->file_desc.mChannelsPerFrame);
|
385
|
+
}
|
386
|
+
|
387
|
+
static VALUE
|
388
|
+
ca_audio_file_inner_rate(VALUE self)
|
389
|
+
{
|
390
|
+
ca_audio_file_t *data;
|
391
|
+
|
392
|
+
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, data);
|
393
|
+
|
394
|
+
return DBL2NUM(data->inner_desc.mSampleRate);
|
395
|
+
}
|
396
|
+
|
397
|
+
static VALUE
|
398
|
+
ca_audio_file_inner_channel(VALUE self)
|
399
|
+
{
|
400
|
+
ca_audio_file_t *data;
|
401
|
+
|
402
|
+
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, data);
|
403
|
+
|
404
|
+
return UINT2NUM((unsigned int)data->inner_desc.mChannelsPerFrame);
|
405
|
+
}
|
406
|
+
|
254
407
|
void
|
255
408
|
Init_coreaudio_audiofile(void)
|
256
409
|
{
|
@@ -266,10 +419,14 @@ Init_coreaudio_audiofile(void)
|
|
266
419
|
|
267
420
|
rb_cAudioFile = rb_define_class_under(rb_mCoreAudio, "AudioFile",
|
268
421
|
rb_cObject);
|
269
|
-
rb_global_variable(&rb_cAudioFile);
|
270
422
|
|
271
423
|
rb_define_alloc_func(rb_cAudioFile, ca_audio_file_alloc);
|
272
424
|
rb_define_method(rb_cAudioFile, "initialize", ca_audio_file_initialize, -1);
|
273
425
|
rb_define_method(rb_cAudioFile, "close", ca_audio_file_close, 0);
|
274
426
|
rb_define_method(rb_cAudioFile, "write", ca_audio_file_write, 1);
|
427
|
+
rb_define_method(rb_cAudioFile, "read", ca_audio_file_read, -1);
|
428
|
+
rb_define_method(rb_cAudioFile, "rate", ca_audio_file_rate, 0);
|
429
|
+
rb_define_method(rb_cAudioFile, "channel", ca_audio_file_channel, 0);
|
430
|
+
rb_define_method(rb_cAudioFile, "inner_rate", ca_audio_file_inner_rate, 0);
|
431
|
+
rb_define_method(rb_cAudioFile, "inner_channel", ca_audio_file_inner_channel, 0);
|
275
432
|
}
|
data/ext/coreaudio.h
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
#ifndef COREAUDIO_H
|
2
2
|
#define COREAUDIO_H 1
|
3
3
|
|
4
|
+
#include <ruby.h>
|
5
|
+
|
6
|
+
#include "extconf.h"
|
7
|
+
|
4
8
|
extern VALUE rb_mCoreAudio;
|
5
9
|
extern VALUE rb_mAudioFile;
|
6
10
|
|
@@ -9,6 +13,17 @@ extern void Init_coreaudio_audiofile(void);
|
|
9
13
|
/*-- Utility Macros --*/
|
10
14
|
#define CROPF(F) ((F) > 1.0 ? 1.0 : (((F) < -1.0) ? -1.0 : (F)))
|
11
15
|
#define FLOAT2SHORT(F) ((short)(CROPF(F)*0x7FFF))
|
12
|
-
#define SHORT2FLOAT(S) ((
|
16
|
+
#define SHORT2FLOAT(S) ((float)(S) / (float)32767.0)
|
17
|
+
|
18
|
+
/*-- prototypes for missing functions --*/
|
19
|
+
|
20
|
+
#ifndef HAVE_RB_ALLOC_TMP_BUFFER
|
21
|
+
extern void *rb_alloc_tmp_buffer(volatile VALUE *store, long len);
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#ifndef HAVE_RB_FREE_TMP_BUFFER
|
25
|
+
extern void rb_free_tmp_buffer(volatile VALUE *store);
|
26
|
+
#endif
|
27
|
+
|
13
28
|
|
14
29
|
#endif
|
data/ext/coreaudio.m
CHANGED
@@ -422,7 +422,7 @@ ca_out_loop_proc(
|
|
422
422
|
float *ptr = outOutputData->mBuffers[i].mData;
|
423
423
|
UInt32 size = outOutputData->mBuffers[i].mDataByteSize / (UInt32)sizeof(float) / channel;
|
424
424
|
UInt32 offset = (UInt32)inOutputTime->mSampleTime % loop_data->frame;
|
425
|
-
|
425
|
+
UInt32 copied = 0;
|
426
426
|
|
427
427
|
if (outOutputData->mBuffers[i].mNumberChannels != channel) {
|
428
428
|
memset(ptr, 0, size * channel * sizeof(float));
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "coreaudio.h"
|
4
|
+
|
5
|
+
#ifndef HAVE_RB_ALLOC_TMP_BUFFER
|
6
|
+
void *
|
7
|
+
rb_alloc_tmp_buffer(volatile VALUE *store, long len)
|
8
|
+
{
|
9
|
+
VALUE s = rb_str_tmp_new(len);
|
10
|
+
*store = s;
|
11
|
+
return RSTRING_PTR(s);
|
12
|
+
}
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifndef HAVE_RB_FREE_TMP_BUFFER
|
16
|
+
void
|
17
|
+
rb_free_tmp_buffer(volatile VALUE *store)
|
18
|
+
{
|
19
|
+
VALUE s = *store;
|
20
|
+
*store = 0;
|
21
|
+
if (s) rb_str_clear(s);
|
22
|
+
}
|
23
|
+
#endif
|
24
|
+
|
data/ext/extconf.rb
CHANGED
@@ -22,7 +22,16 @@ if have_framework("CoreAudio") and
|
|
22
22
|
have_framework("AudioToolBox") and
|
23
23
|
have_framework("CoreFoundation") and
|
24
24
|
have_framework("Cocoa")
|
25
|
+
|
26
|
+
# check ruby API
|
27
|
+
have_func("rb_alloc_tmp_buffer", "ruby.h")
|
28
|
+
have_func("rb_free_tmp_buffer", "ruby.h")
|
29
|
+
|
30
|
+
create_header
|
31
|
+
|
32
|
+
# create Makefile
|
25
33
|
create_makefile("coreaudio/coreaudio_ext")
|
34
|
+
|
26
35
|
# workaround for mkmf.rb in 1.9.2
|
27
36
|
if RUBY_VERSION < "1.9.3"
|
28
37
|
open("Makefile", "a") do |f|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coreaudio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152377300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.0.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152377300
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: jeweler
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152375220 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,29 @@ dependencies:
|
|
32
32
|
version: 1.6.4
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152375220
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &2152373440 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.2
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2152373440
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rdoc
|
49
|
+
requirement: &2152387460 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152387460
|
36
58
|
description: Mac OS X CoreAudio wrapper library
|
37
59
|
email: nagachika00@gmail.com
|
38
60
|
executables: []
|
@@ -50,16 +72,18 @@ files:
|
|
50
72
|
- Rakefile
|
51
73
|
- VERSION
|
52
74
|
- coreaudio.gemspec
|
75
|
+
- examples/convert_wav_to_m4a.rb
|
53
76
|
- examples/outbuffer_sine.rb
|
54
77
|
- examples/outloop_sine.rb
|
55
78
|
- examples/record_to_wave.rb
|
56
79
|
- ext/audiofile.m
|
57
80
|
- ext/coreaudio.h
|
58
81
|
- ext/coreaudio.m
|
82
|
+
- ext/coreaudio_missing.c
|
59
83
|
- ext/depend
|
60
84
|
- ext/extconf.rb
|
61
85
|
- lib/coreaudio.rb
|
62
|
-
homepage:
|
86
|
+
homepage: https://github.com/nagachika/ruby-coreaudio
|
63
87
|
licenses:
|
64
88
|
- BSDL
|
65
89
|
post_install_message:
|
@@ -74,7 +98,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
98
|
version: '0'
|
75
99
|
segments:
|
76
100
|
- 0
|
77
|
-
hash:
|
101
|
+
hash: -1259507067134800519
|
78
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
103
|
none: false
|
80
104
|
requirements:
|