coreaudio 0.0.3 → 0.0.4
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 +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:
|