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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b2b4231db7c1e5aeed85c42c10f9071cbd7bea36a7b286d72c712645a4b4a74
4
- data.tar.gz: 170ebe1b6acef7cd7816dd971a7539cd2a321bdb826ab6455d8764e5127eeb9d
3
+ metadata.gz: b66dd6e651e9b7e179c17382ecfe8a18a1a35181a4df247a1ad960c1314d723b
4
+ data.tar.gz: 49019f9eeb61ab81f10277f931afb6e5f9e2710294dd43d9c20ac1c70d907d60
5
5
  SHA512:
6
- metadata.gz: 2913207ae700123f3fe2ad297894d9167220aac59da9cba1c5086ee3304bd1cc2fa7f5a19ffccdcc8ddd20affd6846955245453502b4f8984444effdd5a5d9de
7
- data.tar.gz: c03e01db92754fd39ad397073641d50519928463a73d0727bd71300075f18eef45dc0d18e068e6135925d6ef7613b8d372ea696fbe432170ff805659995099a7
6
+ metadata.gz: 2e1da05fe284fc2bf71fab340b605ccc7354461497163ec36638304b8602ab431dacab37e2aa6d5184adc1fb28884e5b67a4f989733890aa9ed7e9753bc268d5
7
+ data.tar.gz: 2ac60347cf0f12750be2006fdf91721ea7e4982bfda46096dbf5ef94ddeb64a344a11452814a3645688b3ef3c5af02a08973c67f1196dcb179c3f3b77e6fb454
@@ -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"
@@ -1,5 +1,6 @@
1
1
  require 'ruby-audio'
2
2
  require 'coreaudio'
3
+ require 'vdsp'
3
4
  require 'numru/fftw3'
4
5
  require 'rbplotly'
5
6
  require 'singleton'
@@ -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.class.merge([self, other])
62
- end
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
- def self.merge(buffers, average: false)
65
- if buffers.length==0
66
- raise Error, "argument is empty"
67
- elsif buffers.length==1
68
- return buffers.first.clone
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
- channels = buffers.map(&:channels).max
82
- window_size = buffers[0].window_size
83
- avg = average ? buffers.size.to_f : 1.0
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
- case channels
86
- when 1
87
- result0 = Array.new(window_size, 0.0)
88
- buffers.each {|buf|
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
- window_size.times {|i|
179
- rabuf[i] = @stream0[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] = [@stream0[i], @stream0[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 = Array.new(window_size, 0.0)
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 = Array.new(window_size, 0.0)
206
- stream1 = Array.new(window_size, 0.0)
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 = Array.new(window_size, 0.0)
224
+ stream0 = []
224
225
  window_size.times {|i|
225
- stream0[i] = na[i].real / max
226
+ stream0 << na[i].real / max
226
227
  }
227
228
  self.new(stream0)
228
229
  when 2
229
- stream0 = Array.new(window_size, 0.0)
230
- stream1 = Array.new(window_size, 0.0)
230
+ stream0 = []
231
+ stream1 = []
231
232
  window_size.times {|i|
232
- stream0[i] = na[i*2].real / max
233
- stream1[i] = na[(i*2)+1].real / max
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 = Array.new(window_size, 0.0)
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 = Array.new(window_size, 0.0)
252
- stream1 = Array.new(window_size, 0.0)
249
+ stream0 = []
250
+ stream1 = []
253
251
  rabuf.each_with_index {|fa, i|
254
- stream0[i] = fa[0]
255
- stream1[i] = fa[1]
252
+ stream0 << fa[0]
253
+ stream1 << fa[1]
256
254
  }
257
255
  self.new(stream0, stream1)
258
256
  end
@@ -9,9 +9,7 @@ module AudioStream
9
9
  return input if @level==1.0
10
10
 
11
11
  streams = input.streams.map {|stream|
12
- stream.map {|f|
13
- f * @level
14
- }
12
+ stream * @level
15
13
  }
16
14
  Buffer.new(*streams)
17
15
  end
@@ -13,7 +13,10 @@ module AudioStream
13
13
  b1 = 0.0
14
14
  b2 = -alpha
15
15
 
16
- @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
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
- init_buffer
17
- end
18
-
19
- def init_buffer
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
- streams = input.streams.map.with_index {|stream, i|
32
- b = @filter_bufs[i]
33
- stream.map {|f|
34
- process_one(f, b)
35
- }
36
- }
37
- Buffer.new(*streams)
38
- end
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
- c = @filter_coef
65
-
66
- b0 = c.b0 / c.a0
67
- b1 = c.b1 / c.a0
68
- b2 = c.b2 / c.a0
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
- @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
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
- @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
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
- @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
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
- @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
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
- @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
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
- @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
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
- @normalize = [1.0 - pan, 1.0 + pan].max
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
- input = input.stereo
28
- src = input.streams
32
+ src = input.stereo.streams
29
33
  src0 = src[0]
30
34
  src1 = src[1]
31
35
 
32
- output = Buffer.create_stereo(input.window_size)
33
- dst = output.streams
34
- dst0 = dst[0]
35
- dst1 = dst[1]
36
-
37
- input.window_size.times {|i|
38
- l = (src0[i] * @l_gain + src1[i] * @lr_gain) / @normalize
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
- @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
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)
@@ -1,3 +1,3 @@
1
1
  module AudioStream
2
- VERSION = "2.0.0"
2
+ VERSION = "3.0.0"
3
3
  end
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: 2.0.0
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-08-11 00:00:00.000000000 Z
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