audio_stream 2.0.0 → 3.0.0
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.
- 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
|