coreaudio 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.rdoc +0 -1
- data/VERSION +1 -1
- data/coreaudio.gemspec +10 -3
- data/examples/convert_wav_to_m4a.rb +2 -2
- data/examples/fft_shift_pitch.rb +47 -0
- data/examples/loopback_delay.rb +30 -0
- data/examples/outbuffer_sine.rb +3 -2
- data/examples/record_to_wave.rb +1 -1
- data/examples/ring_modulator.rb +42 -0
- data/ext/audiofile.m +88 -80
- data/ext/coreaudio.h +1 -0
- data/ext/coreaudio.m +74 -58
- data/ext/extconf.rb +27 -1
- data/lib/coreaudio.rb +2 -0
- data/lib/coreaudio/audiofile.rb +38 -0
- metadata +26 -11
data/Gemfile
CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
|
|
2
2
|
# Add dependencies required to use your gem here.
|
3
3
|
# Example:
|
4
4
|
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem "narray", "~> 0.6.0.0"
|
5
6
|
|
6
7
|
# Add dependencies to develop your gem here.
|
7
8
|
# Include everything needed to run rake, tests, features, etc.
|
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -12,7 +12,6 @@ CoreAudio (Audio Framework of Mac OS X) wrapper library for ruby 1.9
|
|
12
12
|
* Ream audio file (WAV/M4A)
|
13
13
|
|
14
14
|
== ToDo
|
15
|
-
* Switch input/output audio sample type (signed 16bit integer, packed String)
|
16
15
|
* Wrapper for AudioUnit/AudioGraph
|
17
16
|
|
18
17
|
== Contributing to coreaudio
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.4
|
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.4"
|
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-28"
|
13
13
|
s.description = "Mac OS X CoreAudio wrapper library"
|
14
14
|
s.email = "nagachika00@gmail.com"
|
15
15
|
s.extensions = ["ext/extconf.rb"]
|
@@ -27,16 +27,20 @@ Gem::Specification.new do |s|
|
|
27
27
|
"VERSION",
|
28
28
|
"coreaudio.gemspec",
|
29
29
|
"examples/convert_wav_to_m4a.rb",
|
30
|
+
"examples/fft_shift_pitch.rb",
|
31
|
+
"examples/loopback_delay.rb",
|
30
32
|
"examples/outbuffer_sine.rb",
|
31
33
|
"examples/outloop_sine.rb",
|
32
34
|
"examples/record_to_wave.rb",
|
35
|
+
"examples/ring_modulator.rb",
|
33
36
|
"ext/audiofile.m",
|
34
37
|
"ext/coreaudio.h",
|
35
38
|
"ext/coreaudio.m",
|
36
39
|
"ext/coreaudio_missing.c",
|
37
40
|
"ext/depend",
|
38
41
|
"ext/extconf.rb",
|
39
|
-
"lib/coreaudio.rb"
|
42
|
+
"lib/coreaudio.rb",
|
43
|
+
"lib/coreaudio/audiofile.rb"
|
40
44
|
]
|
41
45
|
s.homepage = "https://github.com/nagachika/ruby-coreaudio"
|
42
46
|
s.licenses = ["BSDL"]
|
@@ -48,17 +52,20 @@ Gem::Specification.new do |s|
|
|
48
52
|
s.specification_version = 3
|
49
53
|
|
50
54
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
|
+
s.add_runtime_dependency(%q<narray>, ["~> 0.6.0.0"])
|
51
56
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
52
57
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
53
58
|
s.add_development_dependency(%q<rake>, ["~> 0.9.2"])
|
54
59
|
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
55
60
|
else
|
61
|
+
s.add_dependency(%q<narray>, ["~> 0.6.0.0"])
|
56
62
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
63
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
58
64
|
s.add_dependency(%q<rake>, ["~> 0.9.2"])
|
59
65
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
60
66
|
end
|
61
67
|
else
|
68
|
+
s.add_dependency(%q<narray>, ["~> 0.6.0.0"])
|
62
69
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
63
70
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
64
71
|
s.add_dependency(%q<rake>, ["~> 0.9.2"])
|
@@ -6,11 +6,11 @@ wav = CoreAudio::AudioFile.new("sample.wav", :read)
|
|
6
6
|
|
7
7
|
m4a = CoreAudio::AudioFile.new("sample.m4a", :write, :format => :m4a,
|
8
8
|
:rate => wav.rate,
|
9
|
-
:
|
9
|
+
:channels => wav.channels)
|
10
10
|
|
11
11
|
loop do
|
12
12
|
buf = wav.read(1024)
|
13
|
-
break if buf.
|
13
|
+
break if buf.nil?
|
14
14
|
m4a.write(buf)
|
15
15
|
end
|
16
16
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
require "thread"
|
3
|
+
require "fftw3"
|
4
|
+
require "coreaudio"
|
5
|
+
|
6
|
+
Thread.abort_on_exception = true
|
7
|
+
|
8
|
+
inbuf = CoreAudio.default_input_device.input_buffer(1024)
|
9
|
+
outbuf = CoreAudio.default_output_device.output_buffer(1024)
|
10
|
+
|
11
|
+
queue = Queue.new
|
12
|
+
pitch_shift_th = Thread.start do
|
13
|
+
while w = queue.pop
|
14
|
+
half = w.shape[1] / 2
|
15
|
+
f = FFTW3.fft(w, 1)
|
16
|
+
shift = 12
|
17
|
+
f.shape[0].times do |ch|
|
18
|
+
f[ch, shift...half] = f[ch, 0...(half-shift)]
|
19
|
+
f[ch, 0...shift] = 0
|
20
|
+
f[ch, half...(w.shape[1]-shift)] = f[ch, (half+shift)..-1]
|
21
|
+
f[ch, -shift..-1] = 0
|
22
|
+
end
|
23
|
+
outbuf << FFTW3.ifft(f, 1) / w.shape[1]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
th = Thread.start do
|
28
|
+
loop do
|
29
|
+
wav = inbuf.read(1024)
|
30
|
+
queue.push(wav)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
inbuf.start
|
35
|
+
outbuf.start
|
36
|
+
$stdout.print "loopback..."
|
37
|
+
$stdout.flush
|
38
|
+
sleep 10;
|
39
|
+
queue.push(nil)
|
40
|
+
inbuf.stop
|
41
|
+
outbuf.stop
|
42
|
+
$stdout.puts "done."
|
43
|
+
th.kill.join
|
44
|
+
pitch_shift_th.kill.join
|
45
|
+
|
46
|
+
puts "#{inbuf.dropped_frame} frame dropped at input buffer."
|
47
|
+
puts "#{outbuf.dropped_frame} frame dropped at output buffer."
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
require "coreaudio"
|
3
|
+
|
4
|
+
inbuf = CoreAudio.default_input_device.input_buffer(1024)
|
5
|
+
outbuf = CoreAudio.default_output_device.output_buffer(1024)
|
6
|
+
|
7
|
+
th = Thread.start do
|
8
|
+
ary = []
|
9
|
+
loop do
|
10
|
+
wav = inbuf.read(1024)
|
11
|
+
ary.push(wav)
|
12
|
+
# 1024*43 frames delayed. about 1 sec when sample rate = 44100Hz
|
13
|
+
if ary.size > 43
|
14
|
+
outbuf << ary.shift
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
inbuf.start
|
20
|
+
outbuf.start
|
21
|
+
$stdout.print "loopback..."
|
22
|
+
$stdout.flush
|
23
|
+
sleep 10;
|
24
|
+
inbuf.stop
|
25
|
+
outbuf.stop
|
26
|
+
$stdout.puts "done."
|
27
|
+
th.kill.join
|
28
|
+
|
29
|
+
puts "#{inbuf.dropped_frame} frame dropped at input buffer."
|
30
|
+
puts "#{outbuf.dropped_frame} frame dropped at output buffer."
|
data/examples/outbuffer_sine.rb
CHANGED
@@ -6,8 +6,9 @@ buf = dev.output_buffer(1024)
|
|
6
6
|
phase = Math::PI * 2.0 * 440.0 / dev.nominal_rate
|
7
7
|
th = Thread.start do
|
8
8
|
i = 0
|
9
|
+
wav = NArray.sint(1024)
|
9
10
|
loop do
|
10
|
-
|
11
|
+
1024.times {|j| wav[j] = (0.4 * Math.sin(phase*(i+j)) * 0x7FFF).round }
|
11
12
|
i += 1024
|
12
13
|
buf << wav
|
13
14
|
end
|
@@ -19,4 +20,4 @@ buf.stop
|
|
19
20
|
|
20
21
|
puts "#{buf.dropped_frame} frame dropped."
|
21
22
|
|
22
|
-
th.kill
|
23
|
+
th.kill.join
|
data/examples/record_to_wave.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require "thread"
|
3
|
+
require "coreaudio"
|
4
|
+
|
5
|
+
Thread.abort_on_exception = true
|
6
|
+
|
7
|
+
inbuf = CoreAudio.default_input_device.input_buffer(1024)
|
8
|
+
outbuf = CoreAudio.default_output_device.output_buffer(1024)
|
9
|
+
|
10
|
+
queue = Queue.new
|
11
|
+
output_th = Thread.start do
|
12
|
+
filter = NArray.float(2, 1024)
|
13
|
+
filter.shape[1].times do |i|
|
14
|
+
filter[true, i] = (i % 256 - 128) / 128.0
|
15
|
+
end
|
16
|
+
|
17
|
+
while w = queue.pop
|
18
|
+
outbuf << w * filter
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
input_th = Thread.start do
|
23
|
+
loop do
|
24
|
+
wav = inbuf.read(1024)
|
25
|
+
queue.push(wav)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
inbuf.start
|
30
|
+
outbuf.start
|
31
|
+
$stdout.print "loopback..."
|
32
|
+
$stdout.flush
|
33
|
+
sleep 10;
|
34
|
+
queue.push(nil)
|
35
|
+
inbuf.stop
|
36
|
+
outbuf.stop
|
37
|
+
$stdout.puts "done."
|
38
|
+
input_th.kill.join
|
39
|
+
output_th.kill.join
|
40
|
+
|
41
|
+
puts "#{inbuf.dropped_frame} frame dropped at input buffer."
|
42
|
+
puts "#{outbuf.dropped_frame} frame dropped at output buffer."
|
data/ext/audiofile.m
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
VALUE rb_cAudioFile;
|
15
15
|
|
16
16
|
static VALUE sym_read, sym_write, sym_format;
|
17
|
-
static VALUE sym_rate, sym_file_rate,
|
17
|
+
static VALUE sym_rate, sym_file_rate, sym_channels, sym_file_channels;
|
18
18
|
static VALUE sym_wav, sym_m4a;
|
19
19
|
|
20
20
|
static void
|
@@ -22,7 +22,7 @@ setASBD(AudioStreamBasicDescription *asbd,
|
|
22
22
|
Float64 rate,
|
23
23
|
UInt32 format,
|
24
24
|
UInt32 flags,
|
25
|
-
UInt32
|
25
|
+
UInt32 channels,
|
26
26
|
UInt32 bitsPerChannel,
|
27
27
|
UInt32 framePerPacket)
|
28
28
|
{
|
@@ -30,10 +30,10 @@ setASBD(AudioStreamBasicDescription *asbd,
|
|
30
30
|
asbd->mFormatID = format;
|
31
31
|
asbd->mFormatFlags = flags;
|
32
32
|
asbd->mBitsPerChannel = bitsPerChannel;
|
33
|
-
asbd->mChannelsPerFrame =
|
33
|
+
asbd->mChannelsPerFrame = channels;
|
34
34
|
asbd->mFramesPerPacket = framePerPacket;
|
35
|
-
asbd->mBytesPerFrame = bitsPerChannel/8*
|
36
|
-
asbd->mBytesPerPacket = bitsPerChannel/8*
|
35
|
+
asbd->mBytesPerFrame = bitsPerChannel/8*channels;
|
36
|
+
asbd->mBytesPerPacket = bitsPerChannel/8*channels*framePerPacket;
|
37
37
|
}
|
38
38
|
|
39
39
|
typedef struct {
|
@@ -80,7 +80,7 @@ ca_audio_file_alloc(VALUE klass)
|
|
80
80
|
static void
|
81
81
|
parse_audio_file_options(VALUE opt, Boolean for_write,
|
82
82
|
Float64 *rate, Float64 *file_rate,
|
83
|
-
UInt32 *
|
83
|
+
UInt32 *channels, UInt32 *file_channels)
|
84
84
|
{
|
85
85
|
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_rate))) {
|
86
86
|
if (for_write)
|
@@ -90,13 +90,13 @@ parse_audio_file_options(VALUE opt, Boolean for_write,
|
|
90
90
|
} else {
|
91
91
|
*rate = NUM2DBL(rb_hash_aref(opt, sym_rate));
|
92
92
|
}
|
93
|
-
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt,
|
93
|
+
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_channels))) {
|
94
94
|
if (for_write)
|
95
|
-
*
|
95
|
+
*channels = 2;
|
96
96
|
else
|
97
|
-
*
|
97
|
+
*channels = *file_channels;
|
98
98
|
} else {
|
99
|
-
*
|
99
|
+
*channels = NUM2UINT(rb_hash_aref(opt, sym_channels));
|
100
100
|
}
|
101
101
|
|
102
102
|
if (for_write) {
|
@@ -105,10 +105,10 @@ parse_audio_file_options(VALUE opt, Boolean for_write,
|
|
105
105
|
} else {
|
106
106
|
*file_rate = NUM2DBL(rb_hash_aref(opt, sym_file_rate));
|
107
107
|
}
|
108
|
-
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt,
|
109
|
-
*
|
108
|
+
if (NIL_P(opt) || NIL_P(rb_hash_aref(opt, sym_file_channels))) {
|
109
|
+
*file_channels = *channels;
|
110
110
|
} else {
|
111
|
-
*
|
111
|
+
*file_channels = NUM2UINT(rb_hash_aref(opt, sym_file_channels));
|
112
112
|
}
|
113
113
|
}
|
114
114
|
}
|
@@ -128,9 +128,9 @@ parse_audio_file_options(VALUE opt, Boolean for_write,
|
|
128
128
|
* codec type is hardcoded. (:wav, :m4a)
|
129
129
|
* :rate :: sample rate of data pass from AudioFile#read or to AudioFile#write
|
130
130
|
* If not specified, :file_rate value is used. (Float)
|
131
|
-
* :
|
131
|
+
* :channels :: number of channels
|
132
132
|
* :file_rate :: file data sample rate. only work when open for output. (Float)
|
133
|
-
* :
|
133
|
+
* :file_channels :: file data number of channels. only work when open for
|
134
134
|
* output.
|
135
135
|
*/
|
136
136
|
static VALUE
|
@@ -139,7 +139,7 @@ ca_audio_file_initialize(int argc, VALUE *argv, VALUE self)
|
|
139
139
|
ca_audio_file_t *data;
|
140
140
|
VALUE path, mode, opt, format;
|
141
141
|
Float64 rate, file_rate;
|
142
|
-
UInt32
|
142
|
+
UInt32 channels, file_channels;
|
143
143
|
CFURLRef url = NULL;
|
144
144
|
AudioFileTypeID filetype = 0;
|
145
145
|
OSStatus err = noErr;
|
@@ -159,7 +159,7 @@ ca_audio_file_initialize(int argc, VALUE *argv, VALUE self)
|
|
159
159
|
if (data->for_write) {
|
160
160
|
/* when open for write, parse options before open ExtAudioFile */
|
161
161
|
parse_audio_file_options(opt, data->for_write, &rate, &file_rate,
|
162
|
-
&
|
162
|
+
&channels, &file_channels);
|
163
163
|
|
164
164
|
format = rb_hash_aref(opt, sym_format);
|
165
165
|
if (NIL_P(format))
|
@@ -170,11 +170,11 @@ ca_audio_file_initialize(int argc, VALUE *argv, VALUE self)
|
|
170
170
|
setASBD(&data->file_desc, file_rate, kAudioFormatLinearPCM,
|
171
171
|
kLinearPCMFormatFlagIsSignedInteger |
|
172
172
|
kAudioFormatFlagIsPacked,
|
173
|
-
|
173
|
+
file_channels, 16, 1);
|
174
174
|
} else if (format == sym_m4a) {
|
175
175
|
filetype = kAudioFileM4AType;
|
176
176
|
setASBD(&data->file_desc, file_rate, kAudioFormatMPEG4AAC,
|
177
|
-
0,
|
177
|
+
0, file_channels, 0, 0);
|
178
178
|
} else {
|
179
179
|
volatile VALUE str = rb_inspect(format);
|
180
180
|
RB_GC_GUARD(str);
|
@@ -213,14 +213,14 @@ ca_audio_file_initialize(int argc, VALUE *argv, VALUE self)
|
|
213
213
|
|
214
214
|
/* parse options */
|
215
215
|
file_rate = data->file_desc.mSampleRate;
|
216
|
-
|
216
|
+
file_channels = data->file_desc.mChannelsPerFrame;
|
217
217
|
parse_audio_file_options(opt, data->for_write, &rate, &file_rate,
|
218
|
-
&
|
218
|
+
&channels, &file_channels);
|
219
219
|
}
|
220
220
|
|
221
221
|
setASBD(&data->inner_desc, rate, kAudioFormatLinearPCM,
|
222
222
|
kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
|
223
|
-
|
223
|
+
channels, 16, 1);
|
224
224
|
|
225
225
|
err = ExtAudioFileSetProperty(
|
226
226
|
data->file, kExtAudioFileProperty_ClientDataFormat,
|
@@ -253,16 +253,20 @@ static VALUE
|
|
253
253
|
ca_audio_file_write(VALUE self, VALUE data)
|
254
254
|
{
|
255
255
|
ca_audio_file_t *file;
|
256
|
-
|
256
|
+
UInt32 n_ch;
|
257
|
+
int rank;
|
258
|
+
short *buf = NULL;
|
257
259
|
AudioBufferList buf_list;
|
258
260
|
UInt32 frames;
|
259
261
|
size_t alloc_size;
|
260
|
-
volatile VALUE tmpstr;
|
262
|
+
volatile VALUE tmpstr = Qundef;
|
261
263
|
OSStatus err = noErr;
|
262
|
-
int i;
|
263
264
|
|
264
|
-
|
265
|
-
|
265
|
+
/* cast to NArray of SINT and check rank of NArray */
|
266
|
+
data = na_cast_object(data, NA_SINT);
|
267
|
+
rank = NA_RANK(data);
|
268
|
+
if (rank > 3)
|
269
|
+
rb_raise(rb_eArgError, "coreaudio: audio buffer rank must be 1 or 2.");
|
266
270
|
|
267
271
|
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, file);
|
268
272
|
|
@@ -272,23 +276,42 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
272
276
|
if (!file->for_write)
|
273
277
|
rb_raise(rb_eRuntimeError, "coreaudio: audio file opened for reading");
|
274
278
|
|
275
|
-
|
276
|
-
|
279
|
+
n_ch = file->inner_desc.mChannelsPerFrame;
|
280
|
+
|
281
|
+
if (rank == 2 && NA_SHAPE0(data) != (int)n_ch)
|
282
|
+
rb_raise(rb_eArgError,
|
283
|
+
"coreaudio: audio buffer size of first dimension must be "
|
284
|
+
"equal to number of channels");
|
285
|
+
|
286
|
+
frames = rank == 1 ? NA_SHAPE0(data) : NA_SHAPE1(data);
|
287
|
+
alloc_size = (file->inner_desc.mBitsPerChannel/8) * frames * n_ch;
|
277
288
|
|
278
289
|
/* prepare interleaved audio buffer */
|
279
290
|
buf_list.mNumberBuffers = 1;
|
280
|
-
buf_list.mBuffers[0].mNumberChannels =
|
291
|
+
buf_list.mBuffers[0].mNumberChannels = n_ch;
|
281
292
|
buf_list.mBuffers[0].mDataByteSize = (UInt32)alloc_size;
|
282
|
-
buf_list.mBuffers[0].mData = rb_alloc_tmp_buffer(&tmpstr, alloc_size);
|
283
|
-
buf = buf_list.mBuffers[0].mData;
|
284
293
|
|
285
|
-
|
286
|
-
|
294
|
+
if ((rank == 1 && n_ch == 1) || rank == 2) {
|
295
|
+
/* no need to allocate buffer. NArray buffer can be used as mData */
|
296
|
+
buf_list.mBuffers[0].mData = NA_PTR_TYPE(data, void *);
|
297
|
+
} else {
|
298
|
+
UInt32 i, j;
|
299
|
+
short *na_buf = NA_PTR_TYPE(data, short *);
|
300
|
+
|
301
|
+
buf_list.mBuffers[0].mData = rb_alloc_tmp_buffer(&tmpstr, alloc_size);
|
302
|
+
buf = buf_list.mBuffers[0].mData;
|
303
|
+
|
304
|
+
for (i = 0; i < frames; i++) {
|
305
|
+
for (j = 0; j < n_ch; j++) {
|
306
|
+
buf[i*n_ch+j] = na_buf[i];
|
307
|
+
}
|
308
|
+
}
|
287
309
|
}
|
288
310
|
|
289
311
|
err = ExtAudioFileWrite(file->file, frames, &buf_list);
|
290
312
|
|
291
|
-
|
313
|
+
if (tmpstr != Qundef)
|
314
|
+
rb_free_tmp_buffer(&tmpstr);
|
292
315
|
|
293
316
|
if (err != noErr) {
|
294
317
|
rb_raise(rb_eRuntimeError,
|
@@ -299,19 +322,18 @@ ca_audio_file_write(VALUE self, VALUE data)
|
|
299
322
|
}
|
300
323
|
|
301
324
|
static VALUE
|
302
|
-
|
325
|
+
ca_audio_file_read_frames(VALUE self, VALUE frame_val)
|
303
326
|
{
|
304
327
|
ca_audio_file_t *file;
|
305
|
-
|
306
|
-
UInt32 frames, chunk, total, read_frames;
|
328
|
+
UInt32 channels, frames, read_frames;
|
307
329
|
AudioBufferList buf_list;
|
308
|
-
short *buf;
|
309
330
|
size_t alloc_size;
|
310
|
-
|
311
|
-
|
312
|
-
UInt32 i;
|
331
|
+
VALUE nary;
|
332
|
+
int shape[2];
|
313
333
|
OSStatus err = noErr;
|
314
334
|
|
335
|
+
frames = NUM2UINT(frame_val);
|
336
|
+
|
315
337
|
TypedData_Get_Struct(self, ca_audio_file_t, &ca_audio_file_type, file);
|
316
338
|
|
317
339
|
if (file->file == NULL)
|
@@ -320,48 +342,34 @@ ca_audio_file_read(int argc, VALUE *argv, VALUE self)
|
|
320
342
|
if (file->for_write)
|
321
343
|
rb_raise(rb_eRuntimeError, "coreaudio: audio file open for writing");
|
322
344
|
|
323
|
-
|
345
|
+
channels = file->inner_desc.mChannelsPerFrame;
|
324
346
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
} else {
|
329
|
-
frames = chunk = NUM2UINT(frame_val);
|
330
|
-
}
|
347
|
+
shape[0] = channels;
|
348
|
+
shape[1] = frames;
|
349
|
+
nary = na_make_object(NA_SINT, 2, shape, cNArray);
|
331
350
|
|
332
|
-
alloc_size = (file->inner_desc.mBitsPerChannel/8) *
|
333
|
-
file->inner_desc.mChannelsPerFrame * chunk;
|
351
|
+
alloc_size = (file->inner_desc.mBitsPerChannel/8) * channels * frames;
|
334
352
|
|
335
353
|
/* prepare interleaved audio buffer */
|
336
354
|
buf_list.mNumberBuffers = 1;
|
337
|
-
buf_list.mBuffers[0].mNumberChannels =
|
355
|
+
buf_list.mBuffers[0].mNumberChannels = channels;
|
338
356
|
buf_list.mBuffers[0].mDataByteSize = (UInt32)alloc_size;
|
339
|
-
buf_list.mBuffers[0].mData =
|
340
|
-
buf = buf_list.mBuffers[0].mData;
|
357
|
+
buf_list.mBuffers[0].mData = NA_PTR_TYPE(nary, void *);
|
341
358
|
|
342
|
-
|
359
|
+
read_frames = frames;
|
360
|
+
err = ExtAudioFileRead(file->file, &read_frames, &buf_list);
|
343
361
|
|
344
|
-
|
345
|
-
|
346
|
-
|
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
|
-
}
|
362
|
+
if (err != noErr) {
|
363
|
+
rb_raise(rb_eRuntimeError,
|
364
|
+
"coreaudio: ExtAudioFileRead() fails: %d", (int)err);
|
360
365
|
}
|
361
366
|
|
362
|
-
|
367
|
+
if (read_frames == 0)
|
368
|
+
return Qnil;
|
369
|
+
|
370
|
+
NA_SHAPE1(nary) = read_frames;
|
363
371
|
|
364
|
-
return
|
372
|
+
return nary;
|
365
373
|
}
|
366
374
|
|
367
375
|
static VALUE
|
@@ -375,7 +383,7 @@ ca_audio_file_rate(VALUE self)
|
|
375
383
|
}
|
376
384
|
|
377
385
|
static VALUE
|
378
|
-
|
386
|
+
ca_audio_file_channels(VALUE self)
|
379
387
|
{
|
380
388
|
ca_audio_file_t *data;
|
381
389
|
|
@@ -395,7 +403,7 @@ ca_audio_file_inner_rate(VALUE self)
|
|
395
403
|
}
|
396
404
|
|
397
405
|
static VALUE
|
398
|
-
|
406
|
+
ca_audio_file_inner_channels(VALUE self)
|
399
407
|
{
|
400
408
|
ca_audio_file_t *data;
|
401
409
|
|
@@ -412,8 +420,8 @@ Init_coreaudio_audiofile(void)
|
|
412
420
|
sym_format = ID2SYM(rb_intern("format"));
|
413
421
|
sym_rate = ID2SYM(rb_intern("rate"));
|
414
422
|
sym_file_rate = ID2SYM(rb_intern("file_rate"));
|
415
|
-
|
416
|
-
|
423
|
+
sym_channels = ID2SYM(rb_intern("channels"));
|
424
|
+
sym_file_channels = ID2SYM(rb_intern("file_channels"));
|
417
425
|
sym_wav = ID2SYM(rb_intern("wav"));
|
418
426
|
sym_m4a = ID2SYM(rb_intern("m4a"));
|
419
427
|
|
@@ -424,9 +432,9 @@ Init_coreaudio_audiofile(void)
|
|
424
432
|
rb_define_method(rb_cAudioFile, "initialize", ca_audio_file_initialize, -1);
|
425
433
|
rb_define_method(rb_cAudioFile, "close", ca_audio_file_close, 0);
|
426
434
|
rb_define_method(rb_cAudioFile, "write", ca_audio_file_write, 1);
|
427
|
-
rb_define_method(rb_cAudioFile, "
|
435
|
+
rb_define_method(rb_cAudioFile, "read_frames", ca_audio_file_read_frames, 1);
|
428
436
|
rb_define_method(rb_cAudioFile, "rate", ca_audio_file_rate, 0);
|
429
|
-
rb_define_method(rb_cAudioFile, "
|
437
|
+
rb_define_method(rb_cAudioFile, "channels", ca_audio_file_channels, 0);
|
430
438
|
rb_define_method(rb_cAudioFile, "inner_rate", ca_audio_file_inner_rate, 0);
|
431
|
-
rb_define_method(rb_cAudioFile, "
|
439
|
+
rb_define_method(rb_cAudioFile, "inner_channels", ca_audio_file_inner_channels, 0);
|
432
440
|
}
|
data/ext/coreaudio.h
CHANGED
data/ext/coreaudio.m
CHANGED
@@ -374,7 +374,7 @@ typedef struct {
|
|
374
374
|
AudioDeviceID devID;
|
375
375
|
AudioDeviceIOProcID procID;
|
376
376
|
UInt32 frame;
|
377
|
-
UInt32
|
377
|
+
UInt32 channels;
|
378
378
|
short *buf;
|
379
379
|
} ca_out_loop_data;
|
380
380
|
|
@@ -395,7 +395,7 @@ static size_t
|
|
395
395
|
ca_out_loop_data_memsize(const void *ptr)
|
396
396
|
{
|
397
397
|
const ca_out_loop_data *data = ptr;
|
398
|
-
return sizeof(ca_out_loop_data) + data->
|
398
|
+
return sizeof(ca_out_loop_data) + data->channels * data->frame * sizeof(short);
|
399
399
|
}
|
400
400
|
|
401
401
|
static const rb_data_type_t ca_out_loop_data_type = {
|
@@ -416,16 +416,16 @@ ca_out_loop_proc(
|
|
416
416
|
NSUInteger i;
|
417
417
|
UInt32 buffers = outOutputData->mNumberBuffers;
|
418
418
|
ca_out_loop_data *loop_data = inClientData;
|
419
|
-
UInt32
|
419
|
+
UInt32 channels = loop_data->channels;
|
420
420
|
|
421
421
|
for (i = 0; i < buffers; i++) {
|
422
422
|
float *ptr = outOutputData->mBuffers[i].mData;
|
423
|
-
UInt32 size = outOutputData->mBuffers[i].mDataByteSize / (UInt32)sizeof(float) /
|
423
|
+
UInt32 size = outOutputData->mBuffers[i].mDataByteSize / (UInt32)sizeof(float) / channels;
|
424
424
|
UInt32 offset = (UInt32)inOutputTime->mSampleTime % loop_data->frame;
|
425
425
|
UInt32 copied = 0;
|
426
426
|
|
427
|
-
if (outOutputData->mBuffers[i].mNumberChannels !=
|
428
|
-
memset(ptr, 0, size *
|
427
|
+
if (outOutputData->mBuffers[i].mNumberChannels != channels) {
|
428
|
+
memset(ptr, 0, size * channels * sizeof(float));
|
429
429
|
continue;
|
430
430
|
}
|
431
431
|
|
@@ -434,8 +434,8 @@ ca_out_loop_proc(
|
|
434
434
|
UInt32 j;
|
435
435
|
if ( len > size - copied )
|
436
436
|
len = size - copied;
|
437
|
-
for (j = 0; j < len*
|
438
|
-
ptr[copied*
|
437
|
+
for (j = 0; j < len*channels; j++) {
|
438
|
+
ptr[copied*channels+j] = SHORT2FLOAT(loop_data->buf[offset*channels+j]);
|
439
439
|
}
|
440
440
|
offset = (offset + len) % loop_data->frame;
|
441
441
|
copied += len;
|
@@ -456,7 +456,7 @@ ca_out_loop_data_alloc(VALUE klass)
|
|
456
456
|
}
|
457
457
|
|
458
458
|
static VALUE
|
459
|
-
ca_out_loop_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE
|
459
|
+
ca_out_loop_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE channels)
|
460
460
|
{
|
461
461
|
ca_out_loop_data *data;
|
462
462
|
OSStatus status;
|
@@ -469,8 +469,8 @@ ca_out_loop_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE channel)
|
|
469
469
|
rb_raise(rb_eRuntimeError, "coreaudio: create proc ID fail: %d", status);
|
470
470
|
}
|
471
471
|
data->frame = NUM2UINT(frame);
|
472
|
-
data->
|
473
|
-
data->buf = malloc(sizeof(short)*data->frame*data->
|
472
|
+
data->channels = NUM2UINT(channels);
|
473
|
+
data->buf = malloc(sizeof(short)*data->frame*data->channels);
|
474
474
|
if (data->buf == NULL)
|
475
475
|
rb_raise(rb_eNoMemError, "coreaudio: fail to alloc out loop data buffer");
|
476
476
|
return self;
|
@@ -550,7 +550,7 @@ ca_out_loop_data_stop(VALUE self)
|
|
550
550
|
*
|
551
551
|
* Assign audio loop buffer frame value.
|
552
552
|
* If assigned value is an Fixnum (-32767..32767, signed 16bit),
|
553
|
-
* the value is stored to all
|
553
|
+
* the value is stored to all channels.
|
554
554
|
* The +sample+ should be normalize to -32767 <= sample <= 32767 range.
|
555
555
|
* If assigned value is an Array of Fixnum, each value is stored to each
|
556
556
|
* correponding channel. If size of array is not equal to the AudioDevice's
|
@@ -567,15 +567,15 @@ ca_out_loop_data_assign(VALUE self, VALUE index, VALUE val)
|
|
567
567
|
|
568
568
|
idx = NUM2UINT(index) % data->frame;
|
569
569
|
if (TYPE(val) == T_ARRAY) {
|
570
|
-
if (RARRAY_LEN(val) != data->
|
570
|
+
if (RARRAY_LEN(val) != data->channels) {
|
571
571
|
rb_raise(rb_eArgError, "size of array and channel size mismatch");
|
572
572
|
}
|
573
|
-
for (i = 0; i < data->
|
574
|
-
data->buf[idx*data->
|
573
|
+
for (i = 0; i < data->channels; i++) {
|
574
|
+
data->buf[idx*data->channels+i] = (short)NUM2INT(RARRAY_PTR(val)[i]);
|
575
575
|
}
|
576
576
|
} else {
|
577
|
-
for (i = 0; i < data->
|
578
|
-
data->buf[idx*data->
|
577
|
+
for (i = 0; i < data->channels; i++) {
|
578
|
+
data->buf[idx*data->channels+i] = (short)NUM2INT(val);
|
579
579
|
}
|
580
580
|
}
|
581
581
|
return val;
|
@@ -585,7 +585,7 @@ typedef struct {
|
|
585
585
|
AudioDeviceID devID;
|
586
586
|
AudioDeviceIOProcID procID;
|
587
587
|
UInt32 frame;
|
588
|
-
UInt32
|
588
|
+
UInt32 channels;
|
589
589
|
short *buf;
|
590
590
|
UInt32 start;
|
591
591
|
UInt32 end;
|
@@ -613,7 +613,7 @@ static size_t
|
|
613
613
|
ca_buffer_data_memsize(const void *ptr)
|
614
614
|
{
|
615
615
|
const ca_buffer_data *data = ptr;
|
616
|
-
return sizeof(ca_buffer_data) + data->
|
616
|
+
return sizeof(ca_buffer_data) + data->channels * data->frame * sizeof(short);
|
617
617
|
}
|
618
618
|
|
619
619
|
static const rb_data_type_t ca_buffer_data_type = {
|
@@ -754,31 +754,31 @@ ca_out_buffer_proc(
|
|
754
754
|
NSUInteger n_buf;
|
755
755
|
UInt32 buffers = outOutputData->mNumberBuffers;
|
756
756
|
ca_buffer_data *buffer_data = inClientData;
|
757
|
-
UInt32
|
757
|
+
UInt32 channels = buffer_data->channels;
|
758
758
|
|
759
759
|
for (n_buf = 0; n_buf < buffers; n_buf++) {
|
760
760
|
float *ptr = outOutputData->mBuffers[n_buf].mData;
|
761
|
-
UInt32 size = outOutputData->mBuffers[n_buf].mDataByteSize / (UInt32)sizeof(float) /
|
761
|
+
UInt32 size = outOutputData->mBuffers[n_buf].mDataByteSize / (UInt32)sizeof(float) / channels;
|
762
762
|
UInt32 copied = 0;
|
763
763
|
UInt32 i;
|
764
764
|
|
765
|
-
if (outOutputData->mBuffers[n_buf].mNumberChannels !=
|
766
|
-
memset(ptr, 0, size *
|
765
|
+
if (outOutputData->mBuffers[n_buf].mNumberChannels != channels) {
|
766
|
+
memset(ptr, 0, size * channels * sizeof(float));
|
767
767
|
continue;
|
768
768
|
}
|
769
769
|
|
770
770
|
pthread_mutex_lock(&buffer_data->mutex);
|
771
771
|
for ( copied = 0, i = buffer_data->start; copied < size && i != buffer_data->end; copied++, i = (i+1) % buffer_data->frame ) {
|
772
772
|
UInt32 ch;
|
773
|
-
for (ch = 0; ch <
|
774
|
-
ptr[copied*
|
773
|
+
for (ch = 0; ch < channels; ch++) {
|
774
|
+
ptr[copied*channels+ch] = SHORT2FLOAT(buffer_data->buf[i*channels+ch]);
|
775
775
|
}
|
776
776
|
}
|
777
777
|
buffer_data->start = i;
|
778
778
|
pthread_cond_broadcast(&buffer_data->cond);
|
779
779
|
pthread_mutex_unlock(&buffer_data->mutex);
|
780
780
|
if ( copied < size ) {
|
781
|
-
memset(ptr+(copied*
|
781
|
+
memset(ptr+(copied*channels), 0, sizeof(float)*channels*(size-copied));
|
782
782
|
buffer_data->dropped_frame += size - copied;
|
783
783
|
}
|
784
784
|
}
|
@@ -787,7 +787,7 @@ ca_out_buffer_proc(
|
|
787
787
|
}
|
788
788
|
|
789
789
|
static VALUE
|
790
|
-
ca_out_buffer_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE
|
790
|
+
ca_out_buffer_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE channels)
|
791
791
|
{
|
792
792
|
ca_buffer_data *data;
|
793
793
|
OSStatus status;
|
@@ -800,8 +800,8 @@ ca_out_buffer_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE channe
|
|
800
800
|
rb_raise(rb_eRuntimeError, "coreaudio: create proc ID fail: %d", status);
|
801
801
|
}
|
802
802
|
data->frame = NUM2UINT(frame);
|
803
|
-
data->
|
804
|
-
data->buf = malloc(sizeof(short)*data->frame*data->
|
803
|
+
data->channels = NUM2UINT(channels);
|
804
|
+
data->buf = malloc(sizeof(short)*data->frame*data->channels);
|
805
805
|
if (data->buf == NULL)
|
806
806
|
rb_raise(rb_eNoMemError, "coreaudio: fail to alloc out buffer data buffer");
|
807
807
|
return self;
|
@@ -820,19 +820,37 @@ ca_device_create_out_buffer_proc(VALUE self, VALUE frame)
|
|
820
820
|
}
|
821
821
|
|
822
822
|
static VALUE
|
823
|
-
ca_out_buffer_data_append(VALUE self, VALUE
|
823
|
+
ca_out_buffer_data_append(VALUE self, VALUE nary)
|
824
824
|
{
|
825
825
|
ca_buffer_data *data;
|
826
|
+
int rank;
|
827
|
+
short *buf;
|
828
|
+
UInt32 frames;
|
826
829
|
UInt32 idx;
|
827
|
-
VALUE val;
|
828
830
|
long i;
|
829
831
|
UInt32 j;
|
830
832
|
|
831
833
|
TypedData_Get_Struct(self, ca_buffer_data, &ca_buffer_data_type, data);
|
832
834
|
|
835
|
+
nary = na_cast_object(nary, NA_SINT);
|
836
|
+
rank = NA_RANK(nary);
|
837
|
+
if (rank == 1) {
|
838
|
+
frames = NA_SHAPE0(nary);
|
839
|
+
} else if (rank == 2) {
|
840
|
+
frames = NA_SHAPE1(nary);
|
841
|
+
if (NA_SHAPE0(nary) != (int)data->channels)
|
842
|
+
rb_raise(rb_eArgError,
|
843
|
+
"coreaudio: audio buffer NArray size of first dim. must be "
|
844
|
+
"number of channels");
|
845
|
+
} else {
|
846
|
+
rb_raise(rb_eArgError,
|
847
|
+
"coreaudio: audio buffer NArray rank must be 1 or 2");
|
848
|
+
}
|
849
|
+
buf = NA_PTR_TYPE(nary, short *);
|
850
|
+
|
833
851
|
pthread_mutex_lock(&data->mutex);
|
834
852
|
idx = data->end;
|
835
|
-
for ( i = 0; i <
|
853
|
+
for ( i = 0; i < frames; i++, idx = (idx+1)%data->frame) {
|
836
854
|
while ( (idx+1) % data->frame == data->start ) {
|
837
855
|
int ret, state;
|
838
856
|
data->end = idx;
|
@@ -852,19 +870,14 @@ ca_out_buffer_data_append(VALUE self, VALUE ary)
|
|
852
870
|
break;
|
853
871
|
}
|
854
872
|
}
|
855
|
-
val = RARRAY_PTR(ary)[i];
|
856
873
|
|
857
|
-
if (
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
}
|
862
|
-
for (j = 0; j < data->channel; j++) {
|
863
|
-
data->buf[idx*data->channel+j] = (short)NUM2INT(RARRAY_PTR(val)[j]);
|
864
|
-
}
|
874
|
+
if (rank == 2) {
|
875
|
+
memcpy(data->buf + idx * data->channels,
|
876
|
+
buf + i * data->channels,
|
877
|
+
sizeof(short) * data->channels);
|
865
878
|
} else {
|
866
|
-
for (j = 0; j < data->
|
867
|
-
data->buf[idx*data->
|
879
|
+
for (j = 0; j < data->channels; j++) {
|
880
|
+
data->buf[idx*data->channels+j] = buf[i];
|
868
881
|
}
|
869
882
|
}
|
870
883
|
data->end = idx;
|
@@ -891,14 +904,14 @@ ca_in_buffer_proc(
|
|
891
904
|
NSUInteger n_buf;
|
892
905
|
UInt32 buffers = inInputData->mNumberBuffers;
|
893
906
|
ca_buffer_data *buffer_data = inClientData;
|
894
|
-
UInt32
|
907
|
+
UInt32 channels = buffer_data->channels;
|
895
908
|
|
896
909
|
for (n_buf = 0; n_buf < buffers; n_buf++) {
|
897
910
|
float *ptr = inInputData->mBuffers[n_buf].mData;
|
898
|
-
UInt32 size = inInputData->mBuffers[n_buf].mDataByteSize / (UInt32)sizeof(float) /
|
911
|
+
UInt32 size = inInputData->mBuffers[n_buf].mDataByteSize / (UInt32)sizeof(float) / channels;
|
899
912
|
UInt32 copied, idx;
|
900
913
|
|
901
|
-
if (inInputData->mBuffers[n_buf].mNumberChannels !=
|
914
|
+
if (inInputData->mBuffers[n_buf].mNumberChannels != channels) {
|
902
915
|
continue;
|
903
916
|
}
|
904
917
|
|
@@ -909,8 +922,8 @@ ca_in_buffer_proc(
|
|
909
922
|
copied < size && (idx+1) % buffer_data->frame != buffer_data->start;
|
910
923
|
copied++, idx = (idx+1) % buffer_data->frame) {
|
911
924
|
UInt32 ch;
|
912
|
-
for (ch = 0; ch <
|
913
|
-
buffer_data->buf[idx*
|
925
|
+
for (ch = 0; ch < channels; ch++) {
|
926
|
+
buffer_data->buf[idx*channels+ch] = FLOAT2SHORT(ptr[copied*channels+ch]);
|
914
927
|
}
|
915
928
|
}
|
916
929
|
buffer_data->end = idx;
|
@@ -924,7 +937,7 @@ ca_in_buffer_proc(
|
|
924
937
|
}
|
925
938
|
|
926
939
|
static VALUE
|
927
|
-
ca_in_buffer_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE
|
940
|
+
ca_in_buffer_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE channels)
|
928
941
|
{
|
929
942
|
ca_buffer_data *data;
|
930
943
|
OSStatus status;
|
@@ -937,8 +950,8 @@ ca_in_buffer_data_initialize(VALUE self, VALUE devID, VALUE frame, VALUE channel
|
|
937
950
|
rb_raise(rb_eRuntimeError, "coreaudio: create proc ID fail: %d", status);
|
938
951
|
}
|
939
952
|
data->frame = NUM2UINT(frame);
|
940
|
-
data->
|
941
|
-
data->buf = malloc(sizeof(short)*data->frame*data->
|
953
|
+
data->channels = NUM2UINT(channels);
|
954
|
+
data->buf = malloc(sizeof(short)*data->frame*data->channels);
|
942
955
|
if (data->buf == NULL)
|
943
956
|
rb_raise(rb_eNoMemError, "coreaudio: fail to alloc input buffer data buffer");
|
944
957
|
return self;
|
@@ -961,13 +974,17 @@ ca_in_buffer_data_read(VALUE self, VALUE num)
|
|
961
974
|
{
|
962
975
|
ca_buffer_data *data;
|
963
976
|
UInt32 frame = NUM2UINT(num);
|
964
|
-
VALUE
|
977
|
+
VALUE nary;
|
978
|
+
int shape[2];
|
979
|
+
short *buf;
|
965
980
|
UInt32 i;
|
966
|
-
UInt32 j;
|
967
981
|
|
968
982
|
TypedData_Get_Struct(self, ca_buffer_data, &ca_buffer_data_type, data);
|
969
983
|
|
970
|
-
|
984
|
+
shape[0] = data->channels;
|
985
|
+
shape[1] = frame;
|
986
|
+
nary = na_make_object(NA_SINT, 2, shape, cNArray);
|
987
|
+
buf = NA_PTR_TYPE(nary, short *);
|
971
988
|
|
972
989
|
pthread_mutex_lock(&data->mutex);
|
973
990
|
for ( i = 0; i < frame; i++, data->start = (data->start+1)%data->frame) {
|
@@ -989,12 +1006,11 @@ ca_in_buffer_data_read(VALUE self, VALUE num)
|
|
989
1006
|
break;
|
990
1007
|
}
|
991
1008
|
}
|
992
|
-
|
993
|
-
|
994
|
-
}
|
1009
|
+
memcpy(buf + i * data->channels, data->buf + data->start*data->channels,
|
1010
|
+
sizeof(short) * data->channels);
|
995
1011
|
}
|
996
1012
|
pthread_mutex_unlock(&data->mutex);
|
997
|
-
return
|
1013
|
+
return nary;
|
998
1014
|
}
|
999
1015
|
|
1000
1016
|
void
|
data/ext/extconf.rb
CHANGED
@@ -17,7 +17,33 @@ unless defined?(have_framework)
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
begin
|
21
|
+
files = Gem.find_files("narray.h")
|
22
|
+
if files.empty?
|
23
|
+
narray_dir = $sitearchdir
|
24
|
+
else
|
25
|
+
narray_dir = File.dirname(files.first)
|
26
|
+
end
|
27
|
+
rescue
|
28
|
+
narray_dir = $sitearchdir
|
29
|
+
end
|
30
|
+
dir_config("narray", narray_dir, narray_dir)
|
31
|
+
|
32
|
+
if not(have_header("narray.h") and have_header("narray_config.h"))
|
33
|
+
print <<-EOS
|
34
|
+
** configure error **
|
35
|
+
narray.h or narray_config.h is not found.
|
36
|
+
If you have installed narray to /path/to/narray, try the following:
|
37
|
+
|
38
|
+
% ruby extconf.rb --with-narray-dir=/path/to/narray
|
39
|
+
|
40
|
+
or
|
41
|
+
% gem install coreaudio -- --with-narray-dir=/path/to/narray
|
42
|
+
|
43
|
+
EOS
|
44
|
+
exit false
|
45
|
+
end
|
46
|
+
|
21
47
|
if have_framework("CoreAudio") and
|
22
48
|
have_framework("AudioToolBox") and
|
23
49
|
have_framework("CoreFoundation") and
|
data/lib/coreaudio.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
module CoreAudio
|
3
|
+
class AudioFile
|
4
|
+
def read(frames=nil)
|
5
|
+
if frames
|
6
|
+
frames = Integer(frames)
|
7
|
+
if frames and frames > 0
|
8
|
+
return read_frames(frames)
|
9
|
+
elsif frames == 0
|
10
|
+
return NArray.sint(0)
|
11
|
+
else
|
12
|
+
raise ArgumentError,
|
13
|
+
"coreaudio: read frame number must be zero or positive"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# read all frames
|
18
|
+
chunk = self.inner_rate.to_i * 10
|
19
|
+
total = nil
|
20
|
+
loop do
|
21
|
+
tmp = read_frames(chunk)
|
22
|
+
if tmp.nil?
|
23
|
+
break
|
24
|
+
end
|
25
|
+
if total.nil?
|
26
|
+
total = tmp
|
27
|
+
else
|
28
|
+
new_na = NArray.sint(total.shape[0], tmp.shape[1] + total.shape[1])
|
29
|
+
new_na[false, 0...total.shape[1]] = total
|
30
|
+
new_na[false, total.shape[1]..-1] = tmp
|
31
|
+
total = new_na
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
total
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
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.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: narray
|
16
|
+
requirement: &2156227560 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.6.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156227560
|
14
25
|
- !ruby/object:Gem::Dependency
|
15
26
|
name: bundler
|
16
|
-
requirement: &
|
27
|
+
requirement: &2156239180 !ruby/object:Gem::Requirement
|
17
28
|
none: false
|
18
29
|
requirements:
|
19
30
|
- - ~>
|
@@ -21,10 +32,10 @@ dependencies:
|
|
21
32
|
version: 1.0.0
|
22
33
|
type: :development
|
23
34
|
prerelease: false
|
24
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156239180
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: jeweler
|
27
|
-
requirement: &
|
38
|
+
requirement: &2156238240 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
40
|
requirements:
|
30
41
|
- - ~>
|
@@ -32,10 +43,10 @@ dependencies:
|
|
32
43
|
version: 1.6.4
|
33
44
|
type: :development
|
34
45
|
prerelease: false
|
35
|
-
version_requirements: *
|
46
|
+
version_requirements: *2156238240
|
36
47
|
- !ruby/object:Gem::Dependency
|
37
48
|
name: rake
|
38
|
-
requirement: &
|
49
|
+
requirement: &2156237000 !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
51
|
requirements:
|
41
52
|
- - ~>
|
@@ -43,10 +54,10 @@ dependencies:
|
|
43
54
|
version: 0.9.2
|
44
55
|
type: :development
|
45
56
|
prerelease: false
|
46
|
-
version_requirements: *
|
57
|
+
version_requirements: *2156237000
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: rdoc
|
49
|
-
requirement: &
|
60
|
+
requirement: &2156235680 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,7 +65,7 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *2156235680
|
58
69
|
description: Mac OS X CoreAudio wrapper library
|
59
70
|
email: nagachika00@gmail.com
|
60
71
|
executables: []
|
@@ -73,9 +84,12 @@ files:
|
|
73
84
|
- VERSION
|
74
85
|
- coreaudio.gemspec
|
75
86
|
- examples/convert_wav_to_m4a.rb
|
87
|
+
- examples/fft_shift_pitch.rb
|
88
|
+
- examples/loopback_delay.rb
|
76
89
|
- examples/outbuffer_sine.rb
|
77
90
|
- examples/outloop_sine.rb
|
78
91
|
- examples/record_to_wave.rb
|
92
|
+
- examples/ring_modulator.rb
|
79
93
|
- ext/audiofile.m
|
80
94
|
- ext/coreaudio.h
|
81
95
|
- ext/coreaudio.m
|
@@ -83,6 +97,7 @@ files:
|
|
83
97
|
- ext/depend
|
84
98
|
- ext/extconf.rb
|
85
99
|
- lib/coreaudio.rb
|
100
|
+
- lib/coreaudio/audiofile.rb
|
86
101
|
homepage: https://github.com/nagachika/ruby-coreaudio
|
87
102
|
licenses:
|
88
103
|
- BSDL
|
@@ -98,7 +113,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
113
|
version: '0'
|
99
114
|
segments:
|
100
115
|
- 0
|
101
|
-
hash: -
|
116
|
+
hash: -1205790832167491304
|
102
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
118
|
none: false
|
104
119
|
requirements:
|