audio_stream 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/audio_stream.gemspec +1 -0
- data/lib/audio_stream.rb +1 -0
- data/lib/audio_stream/buffer.rb +57 -59
- data/lib/audio_stream/fx/a_gain.rb +1 -3
- data/lib/audio_stream/fx/band_pass_filter.rb +4 -1
- data/lib/audio_stream/fx/biquad_filter.rb +18 -51
- data/lib/audio_stream/fx/high_pass_filter.rb +4 -1
- data/lib/audio_stream/fx/high_shelf_filter.rb +4 -1
- data/lib/audio_stream/fx/low_pass_filter.rb +4 -1
- data/lib/audio_stream/fx/low_shelf_filter.rb +4 -1
- data/lib/audio_stream/fx/panning.rb +24 -25
- data/lib/audio_stream/fx/peaking_filter.rb +4 -1
- data/lib/audio_stream/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b66dd6e651e9b7e179c17382ecfe8a18a1a35181a4df247a1ad960c1314d723b
|
4
|
+
data.tar.gz: 49019f9eeb61ab81f10277f931afb6e5f9e2710294dd43d9c20ac1c70d907d60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e1da05fe284fc2bf71fab340b605ccc7354461497163ec36638304b8602ab431dacab37e2aa6d5184adc1fb28884e5b67a4f989733890aa9ed7e9753bc268d5
|
7
|
+
data.tar.gz: 2ac60347cf0f12750be2006fdf91721ea7e4982bfda46096dbf5ef94ddeb64a344a11452814a3645688b3ef3c5af02a08973c67f1196dcb179c3f3b77e6fb454
|
data/audio_stream.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "rake", "~> 12.0"
|
31
31
|
spec.add_development_dependency "minitest", "~> 5.0"
|
32
32
|
|
33
|
+
spec.add_dependency "vdsp", ">= 1.6.0"
|
33
34
|
spec.add_dependency "ruby-audio", ">= 1.6.1"
|
34
35
|
spec.add_dependency "coreaudio", ">= 0.0.12"
|
35
36
|
spec.add_dependency "ruby-fftw3", ">= 1.0.2"
|
data/lib/audio_stream.rb
CHANGED
data/lib/audio_stream/buffer.rb
CHANGED
@@ -6,6 +6,13 @@ module AudioStream
|
|
6
6
|
attr_reader :window_size
|
7
7
|
|
8
8
|
def initialize(stream0, stream1=nil)
|
9
|
+
if Array===stream0
|
10
|
+
stream0 = Vdsp::DoubleArray.create(stream0)
|
11
|
+
end
|
12
|
+
if Array===stream1
|
13
|
+
stream1 = Vdsp::DoubleArray.create(stream1)
|
14
|
+
end
|
15
|
+
|
9
16
|
@stream0 = stream0
|
10
17
|
@stream1 = stream1
|
11
18
|
|
@@ -58,53 +65,45 @@ module AudioStream
|
|
58
65
|
end
|
59
66
|
|
60
67
|
def +(other)
|
61
|
-
self.
|
62
|
-
|
68
|
+
if self.window_size!=other.window_size
|
69
|
+
raise Error, "Buffer.window_size is not match: self.window_size=#{self.window_size} other.window_size=#{other.window_size}"
|
70
|
+
end
|
63
71
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
72
|
+
channels = [self.channels, other.channels].max
|
73
|
+
case channels
|
74
|
+
when 1
|
75
|
+
stream0 = self.streams[0] + other.streams[0]
|
76
|
+
self.class.new(stream0)
|
77
|
+
when 2
|
78
|
+
st_self = self.stereo
|
79
|
+
st_other = other.stereo
|
80
|
+
|
81
|
+
stream0 = st_self.streams[0] + st_other.streams[0]
|
82
|
+
stream1 = st_self.streams[1] + st_other.streams[1]
|
83
|
+
self.class.new(stream0, stream1)
|
69
84
|
end
|
85
|
+
end
|
70
86
|
|
87
|
+
def self.merge(buffers, average: false)
|
71
88
|
buffers.each {|buf|
|
72
89
|
unless Buffer===buf
|
73
90
|
raise Error, "argument is not Buffer: #{buf}"
|
74
91
|
end
|
75
|
-
if buffers[0].window_size!=buf.window_size
|
76
|
-
i = buffers.index(buf)
|
77
|
-
raise Error, "Buffer.window_size is not match: buffers[0].window_size=#{buffers[0].window_size} buffers[#{i}].window_size=#{buf.window_size}"
|
78
|
-
end
|
79
92
|
}
|
80
93
|
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
if buffers.length==0
|
95
|
+
raise Error, "argument is empty"
|
96
|
+
elsif buffers.length==1
|
97
|
+
return buffers[0]
|
98
|
+
end
|
84
99
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
buffers.
|
89
|
-
buf.streams[0].each_with_index {|f, i|
|
90
|
-
result0[i] += f / avg
|
91
|
-
}
|
92
|
-
}
|
93
|
-
self.class.new(result0)
|
94
|
-
when 2
|
95
|
-
result0 = Array.new(window_size, 0.0)
|
96
|
-
result1 = Array.new(window_size, 0.0)
|
97
|
-
buffers.each {|buf|
|
98
|
-
buf = buf.stereo
|
99
|
-
src0 = buf.streams[0]
|
100
|
-
src1 = buf.streams[1]
|
101
|
-
window_size.times {|i|
|
102
|
-
result0[i] += src0[i] / avg
|
103
|
-
result1[i] += src1[i] / avg
|
104
|
-
}
|
105
|
-
}
|
106
|
-
self.new(result0, result1)
|
100
|
+
dst = buffers.inject(:+)
|
101
|
+
|
102
|
+
if average
|
103
|
+
dst /= buffers.length.to_f
|
107
104
|
end
|
105
|
+
|
106
|
+
dst
|
108
107
|
end
|
109
108
|
|
110
109
|
def plot
|
@@ -147,10 +146,10 @@ module AudioStream
|
|
147
146
|
|
148
147
|
case channels
|
149
148
|
when 1
|
150
|
-
na[(0+offset)...(window_size+offset)] = @stream0
|
149
|
+
na[(0+offset)...(window_size+offset)] = @stream0.to_a
|
151
150
|
when 2
|
152
|
-
na[window_size.times.map{|i| i*2+offset}] = @stream0
|
153
|
-
na[window_size.times.map{|i| i*2+1+offset}] = @stream1
|
151
|
+
na[window_size.times.map{|i| i*2+offset}] = @stream0.to_a
|
152
|
+
na[window_size.times.map{|i| i*2+1+offset}] = @stream1.to_a
|
154
153
|
end
|
155
154
|
|
156
155
|
na
|
@@ -175,12 +174,14 @@ module AudioStream
|
|
175
174
|
|
176
175
|
case channels
|
177
176
|
when 1
|
178
|
-
|
179
|
-
rabuf[i] =
|
177
|
+
@stream0.each {|v|
|
178
|
+
rabuf[i] = v
|
180
179
|
}
|
181
180
|
when 2
|
181
|
+
stream0 = @stream0.to_a
|
182
|
+
stream1 = @stream1.to_a
|
182
183
|
window_size.times {|i|
|
183
|
-
rabuf[i] = [
|
184
|
+
rabuf[i] = [stream0[i], stream1[i]]
|
184
185
|
}
|
185
186
|
end
|
186
187
|
|
@@ -197,13 +198,13 @@ module AudioStream
|
|
197
198
|
end
|
198
199
|
|
199
200
|
def self.create_mono(window_size)
|
200
|
-
stream0 =
|
201
|
+
stream0 = Vdsp::DoubleArray.new(window_size)
|
201
202
|
new(stream0)
|
202
203
|
end
|
203
204
|
|
204
205
|
def self.create_stereo(window_size)
|
205
|
-
stream0 =
|
206
|
-
stream1 =
|
206
|
+
stream0 = Vdsp::DoubleArray.new(window_size)
|
207
|
+
stream1 = Vdsp::DoubleArray.new(window_size)
|
207
208
|
new(stream0, stream1)
|
208
209
|
end
|
209
210
|
|
@@ -220,17 +221,17 @@ module AudioStream
|
|
220
221
|
|
221
222
|
case channels
|
222
223
|
when 1
|
223
|
-
stream0 =
|
224
|
+
stream0 = []
|
224
225
|
window_size.times {|i|
|
225
|
-
stream0
|
226
|
+
stream0 << na[i].real / max
|
226
227
|
}
|
227
228
|
self.new(stream0)
|
228
229
|
when 2
|
229
|
-
stream0 =
|
230
|
-
stream1 =
|
230
|
+
stream0 = []
|
231
|
+
stream1 = []
|
231
232
|
window_size.times {|i|
|
232
|
-
stream0
|
233
|
-
stream1
|
233
|
+
stream0 << na[i*2].real / max
|
234
|
+
stream1 << na[(i*2)+1].real / max
|
234
235
|
}
|
235
236
|
self.new(stream0, stream1)
|
236
237
|
end
|
@@ -242,17 +243,14 @@ module AudioStream
|
|
242
243
|
|
243
244
|
case channels
|
244
245
|
when 1
|
245
|
-
stream0 =
|
246
|
-
rabuf.each_with_index {|f, i|
|
247
|
-
stream0[i] = f
|
248
|
-
}
|
246
|
+
stream0 = rabuf.to_a
|
249
247
|
self.new(stream0)
|
250
248
|
when 2
|
251
|
-
stream0 =
|
252
|
-
stream1 =
|
249
|
+
stream0 = []
|
250
|
+
stream1 = []
|
253
251
|
rabuf.each_with_index {|fa, i|
|
254
|
-
stream0
|
255
|
-
stream1
|
252
|
+
stream0 << fa[0]
|
253
|
+
stream1 << fa[1]
|
256
254
|
}
|
257
255
|
self.new(stream0, stream1)
|
258
256
|
end
|
@@ -13,7 +13,10 @@ module AudioStream
|
|
13
13
|
b1 = 0.0
|
14
14
|
b2 = -alpha
|
15
15
|
|
16
|
-
@
|
16
|
+
@coef = Vdsp::Biquad::Coefficient.new(b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)
|
17
|
+
@biquads.each {|biquad|
|
18
|
+
biquad.coefficients = @coef
|
19
|
+
}
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.create(soundinfo, freq:, bandwidth: 1.0)
|
@@ -1,23 +1,14 @@
|
|
1
1
|
module AudioStream
|
2
2
|
module Fx
|
3
3
|
class BiquadFilter
|
4
|
-
FilterBuffer = Struct.new("FilterBuffer", :in1, :in2, :out1, :out2) do
|
5
|
-
def self.create
|
6
|
-
new(0.0, 0.0, 0.0, 0.0)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
FilterCoef = Struct.new("FilterCoef", :a0, :a1, :a2, :b0, :b1, :b2)
|
11
|
-
|
12
4
|
DEFAULT_Q = 1.0 / Math.sqrt(2.0)
|
13
5
|
|
14
6
|
def initialize(soundinfo)
|
15
7
|
@samplerate = soundinfo.samplerate.to_f
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@filter_bufs = [FilterBuffer.create, FilterBuffer.create]
|
8
|
+
@biquads = [
|
9
|
+
Vdsp::DoubleBiquad.new(1),
|
10
|
+
Vdsp::DoubleBiquad.new(1),
|
11
|
+
]
|
21
12
|
end
|
22
13
|
|
23
14
|
def update_coef(*args, **kwargs)
|
@@ -25,49 +16,25 @@ module AudioStream
|
|
25
16
|
end
|
26
17
|
|
27
18
|
def process(input)
|
28
|
-
window_size = input.window_size
|
29
19
|
channels = input.channels
|
30
20
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def process_mono(in0)
|
41
|
-
process_one(in0, @filter_bufs[0])
|
42
|
-
end
|
43
|
-
|
44
|
-
def process_stereo(in0, in1)
|
45
|
-
[
|
46
|
-
process_one(in0, @filter_bufs[0]),
|
47
|
-
process_one(in1, @filter_bufs[1])
|
48
|
-
]
|
49
|
-
end
|
50
|
-
|
51
|
-
def process_one(in0, b)
|
52
|
-
c = @filter_coef
|
53
|
-
out0 = c.b0/c.a0 * in0 + c.b1/c.a0 * b.in1 + c.b2/c.a0 * b.in2 - c.a1/c.a0 * b.out1 - c.a2/c.a0 * b.out2
|
54
|
-
|
55
|
-
b.in2 = b.in1
|
56
|
-
b.in1 = in0
|
57
|
-
b.out2 = b.out1
|
58
|
-
b.out1 = out0
|
59
|
-
|
60
|
-
out0
|
21
|
+
case channels
|
22
|
+
when 1
|
23
|
+
dst0 = @biquads[0].apply(input.streams[0])
|
24
|
+
Buffer.new(dst0)
|
25
|
+
when 2
|
26
|
+
dst0 = @biquads[0].apply(input.streams[0])
|
27
|
+
dst1 = @biquads[1].apply(input.streams[1])
|
28
|
+
Buffer.new(dst0, dst1)
|
29
|
+
end
|
61
30
|
end
|
62
31
|
|
63
32
|
def plot_data(width=500)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
a1 = c.a1 / c.a0
|
70
|
-
a2 = c.a2 / c.a0
|
33
|
+
b0 = @coef.b0
|
34
|
+
b1 = @coef.b1
|
35
|
+
b2 = @coef.b2
|
36
|
+
a1 = @coef.a1
|
37
|
+
a2 = @coef.a2
|
71
38
|
|
72
39
|
noctaves = 10
|
73
40
|
nyquist = @samplerate * 0.5
|
@@ -13,7 +13,10 @@ module AudioStream
|
|
13
13
|
b1 = -(1.0 + Math.cos(omega))
|
14
14
|
b2 = (1.0 + Math.cos(omega)) / 2.0
|
15
15
|
|
16
|
-
@
|
16
|
+
@coef = Vdsp::Biquad::Coefficient.new(b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)
|
17
|
+
@biquads.each {|biquad|
|
18
|
+
biquad.coefficients = @coef
|
19
|
+
}
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.create(soundinfo, freq:, q: DEFAULT_Q)
|
@@ -15,7 +15,10 @@ module AudioStream
|
|
15
15
|
b1 = -2.0 * a * ((a-1) + (a+1) * Math.cos(omega))
|
16
16
|
b2 = a * ((a+1) + (a-1) * Math.cos(omega) - beta * Math.sin(omega))
|
17
17
|
|
18
|
-
@
|
18
|
+
@coef = Vdsp::Biquad::Coefficient.new(b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)
|
19
|
+
@biquads.each {|biquad|
|
20
|
+
biquad.coefficients = @coef
|
21
|
+
}
|
19
22
|
end
|
20
23
|
|
21
24
|
def self.create(soundinfo, freq:, q: DEFAULT_Q, gain: 1.0)
|
@@ -13,7 +13,10 @@ module AudioStream
|
|
13
13
|
b1 = 1.0 - Math.cos(omega)
|
14
14
|
b2 = (1.0 - Math.cos(omega)) / 2.0
|
15
15
|
|
16
|
-
@
|
16
|
+
@coef = Vdsp::Biquad::Coefficient.new(b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)
|
17
|
+
@biquads.each {|biquad|
|
18
|
+
biquad.coefficients = @coef
|
19
|
+
}
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.create(soundinfo, freq:, q: DEFAULT_Q)
|
@@ -15,7 +15,10 @@ module AudioStream
|
|
15
15
|
b1 = 2.0 * a * ((a-1) - (a+1) * Math.cos(omega))
|
16
16
|
b2 = a * ((a+1) - (a-1) * Math.cos(omega) - beta * Math.sin(omega))
|
17
17
|
|
18
|
-
@
|
18
|
+
@coef = Vdsp::Biquad::Coefficient.new(b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)
|
19
|
+
@biquads.each {|biquad|
|
20
|
+
biquad.coefficients = @coef
|
21
|
+
}
|
19
22
|
end
|
20
23
|
|
21
24
|
def self.create(soundinfo, freq:, q: DEFAULT_Q, gain: 1.0)
|
@@ -4,43 +4,42 @@ module AudioStream
|
|
4
4
|
def initialize(pan: 0.0)
|
5
5
|
@pan = pan
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
if 1.0
|
10
|
-
|
11
|
-
|
7
|
+
l_gain = 1.0 - pan
|
8
|
+
lr_gain = 0.0
|
9
|
+
if 1.0<l_gain
|
10
|
+
lr_gain = l_gain - 1.0
|
11
|
+
l_gain = 1.0
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
if 1.0
|
17
|
-
|
18
|
-
|
14
|
+
r_gain = 1.0 + pan
|
15
|
+
rl_gain = 0.0
|
16
|
+
if 1.0<r_gain
|
17
|
+
rl_gain = r_gain - 1.0
|
18
|
+
r_gain = 1.0
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
normalize = [1.0 - pan, 1.0 + pan].max
|
22
|
+
|
23
|
+
@r_gain = r_gain / normalize
|
24
|
+
@rl_gain = rl_gain / normalize
|
25
|
+
@l_gain = l_gain / normalize
|
26
|
+
@lr_gain = lr_gain / normalize
|
22
27
|
end
|
23
28
|
|
24
29
|
def process(input)
|
25
30
|
return input if @pan==0.0
|
26
31
|
|
27
|
-
|
28
|
-
src = input.streams
|
32
|
+
src = input.stereo.streams
|
29
33
|
src0 = src[0]
|
30
34
|
src1 = src[1]
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
dst1 =
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
r = (src1[i] * @r_gain + src0[i] * @rl_gain) / @normalize
|
40
|
-
dst0[i] = l
|
41
|
-
dst1[i] = r
|
42
|
-
}
|
43
|
-
output
|
36
|
+
dst0 = Vdsp::DoubleArray.new(src0.length)
|
37
|
+
Vdsp::UnsafeDouble.vsmsma(src0, 0, 1, @l_gain, src1, 0, 1, @lr_gain, dst0, 0, 1, src0.length)
|
38
|
+
|
39
|
+
dst1 = Vdsp::DoubleArray.new(src1.length)
|
40
|
+
Vdsp::UnsafeDouble.vsmsma(src0, 0, 1, @rl_gain, src1, 0, 1, @r_gain, dst1, 0, 1, src1.length)
|
41
|
+
|
42
|
+
Buffer.new(dst0, dst1)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
@@ -14,7 +14,10 @@ module AudioStream
|
|
14
14
|
b1 = -2.0 * Math.cos(omega)
|
15
15
|
b2 = 1.0 - alpha * a
|
16
16
|
|
17
|
-
@
|
17
|
+
@coef = Vdsp::Biquad::Coefficient.new(b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)
|
18
|
+
@biquads.each {|biquad|
|
19
|
+
biquad.coefficients = @coef
|
20
|
+
}
|
18
21
|
end
|
19
22
|
|
20
23
|
def self.create(soundinfo, freq:, bandwidth: 1.0, gain: 40.0)
|
data/lib/audio_stream/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: audio_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yoshida Tetsuya
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: vdsp
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.6.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.6.0
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: ruby-audio
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|