audio_stream 3.0.1 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcfa4c84415b2d3fce58e09f86e7f7ed93fc6bf57e302580b8b629fea6b98ed9
4
- data.tar.gz: 5e29c910eddfed09ffe952b6e3ab5cfd75f79dfe1072681bfb10ca3a720195d5
3
+ metadata.gz: e0dd181cb0224f6603451bf72f635deaa9d406ba76f8e587de6b512f1483a1c0
4
+ data.tar.gz: b38c9e486e71646a7db650e1c8731d1cb4d8078f7e788bda1897c3ca89334d2d
5
5
  SHA512:
6
- metadata.gz: 3a812266f92786ab35b68ad6b731020525afda6a0d3dfccda2e47ac466696ec30cdaf82475d0bf0fbda15d7527d9f001ea1d98ef0e6ce8d23769a01f966008c9
7
- data.tar.gz: be4a1e89411f6d0d881119750508d50d7099fe2d8c046fb24f6323520ab065d4469b67a9983460f8138b463fc6f5023a67376cb7a38860fcc849b59e9249353d
6
+ metadata.gz: 8d5a04e5334b1786b16578cdca72bb0f9b296453d7293f61700ebb6447c102d7cbe0509b41505edeaff0bdbcd00382bf2a10e7dcb92bd4033e6df76b48d89e27
7
+ data.tar.gz: f013bc564ea68724eae776ba5c37244d0167617bbd42032cfa0399e3a03e0e6a6c089d41aaf6de42e8d440204cb5bf5b340b6ddba3b4ae0428ea4181371f7d86
@@ -30,7 +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
+ spec.add_dependency "vdsp", ">= 1.10.0"
34
34
  spec.add_dependency "ruby-audio", ">= 1.6.1"
35
35
  spec.add_dependency "coreaudio", ">= 0.0.12"
36
36
  spec.add_dependency "ruby-fftw3", ">= 1.0.2"
@@ -17,6 +17,12 @@ module AudioStream
17
17
  end
18
18
 
19
19
  def on_next(input)
20
+ case @soundinfo.channels
21
+ when 1
22
+ input = input.mono
23
+ when 2
24
+ input = input.stereo
25
+ end
20
26
  @sound.write(input.to_rabuffer)
21
27
  end
22
28
 
@@ -100,7 +100,8 @@ module AudioStream
100
100
  dst = buffers.inject(:+)
101
101
 
102
102
  if average
103
- dst /= buffers.length.to_f
103
+ gain = AGain.new(level: 1.0/buffers.length)
104
+ dst = gain.process(dst)
104
105
  end
105
106
 
106
107
  dst
@@ -174,7 +175,7 @@ module AudioStream
174
175
 
175
176
  case channels
176
177
  when 1
177
- @stream0.each {|v|
178
+ @stream0.each_with_index {|v, i|
178
179
  rabuf[i] = v
179
180
  }
180
181
  when 2
@@ -12,13 +12,17 @@ require 'audio_stream/fx/band_pass_filter'
12
12
  require 'audio_stream/fx/low_shelf_filter'
13
13
  require 'audio_stream/fx/high_shelf_filter'
14
14
  require 'audio_stream/fx/peaking_filter'
15
+ require 'audio_stream/fx/all_pass_filter'
15
16
  require 'audio_stream/fx/equalizer_2band'
16
17
  require 'audio_stream/fx/equalizer_3band'
17
18
  require 'audio_stream/fx/graphic_equalizer'
18
19
  require 'audio_stream/fx/tremolo'
19
20
  require 'audio_stream/fx/delay'
20
21
  require 'audio_stream/fx/chorus'
22
+ require 'audio_stream/fx/phaser'
21
23
  require 'audio_stream/fx/convolution_reverb'
24
+ require 'audio_stream/fx/comb_filter'
25
+ require 'audio_stream/fx/schroeder_reverb'
22
26
  require 'audio_stream/fx/hanning_window'
23
27
 
24
28
  require 'audio_stream/fx/tuner'
@@ -0,0 +1,30 @@
1
+ module AudioStream
2
+ module Fx
3
+ class AllPassFilter < BiquadFilter
4
+
5
+ def update_coef(freq:, q:)
6
+ omega = 2.0 * Math::PI * freq / @samplerate
7
+ alpha = Math.sin(omega) / (2.0 * q)
8
+
9
+ a0 = 1.0 + alpha
10
+ a1 = -2.0 * Math.cos(omega)
11
+ a2 = 1.0 - alpha
12
+ b0 = 1.0 - alpha
13
+ b1 = -2.0 * Math.cos(omega)
14
+ b2 = 1.0 + alpha
15
+
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
+ }
20
+ end
21
+
22
+ def self.create(soundinfo, freq:, q: DEFAULT_Q)
23
+ filter = new(soundinfo)
24
+ filter.update_coef(freq: freq, q: q)
25
+
26
+ filter
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ module AudioStream
2
+ module Fx
3
+ class CombFilter
4
+
5
+ def initialize(soundinfo, freq:, q:)
6
+ @window_size = soundinfo.window_size
7
+ @samplerate = soundinfo.samplerate
8
+ @delaysample = (soundinfo.samplerate.to_f / freq).round
9
+ @q = q
10
+
11
+ @delaybufs = [
12
+ Vdsp::DoubleArray.new(soundinfo.window_size + @delaysample),
13
+ Vdsp::DoubleArray.new(soundinfo.window_size + @delaysample),
14
+ ]
15
+ end
16
+
17
+ def process(input)
18
+ window_size = input.window_size
19
+ if @window_size!=window_size
20
+ raise "window size is not match: impulse.size=#{@window_size} input.size=#{window_size}"
21
+ end
22
+
23
+ streams = input.streams.map.with_index {|src, i|
24
+ buf = @delaybufs[i]
25
+
26
+ Vdsp::UnsafeDouble.copy(buf, window_size, 1, buf, 0, 1, @delaysample)
27
+ if @delaysample<window_size
28
+ Vdsp::UnsafeDouble.vclr(buf, window_size, 1, @delaysample)
29
+ end
30
+ Vdsp::UnsafeDouble.vsmsma(src, 0, 1, 1.0, buf, 0, 1, @q, buf, @delaysample, 1, window_size)
31
+ dst = buf[@delaysample, window_size]
32
+
33
+ dst
34
+ }
35
+
36
+ Buffer.new(*streams)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -9,14 +9,19 @@ module AudioStream
9
9
 
10
10
  def process(input)
11
11
  streams = input.streams.map {|stream|
12
- stream.map {|f|
13
- sign = f.negative? ? -1 : 1
14
- f = f.abs
15
- if @threshold<f
16
- f = (f - @threshold) * @ratio + @threshold
17
- end
18
- @zoom * f * sign
19
- }
12
+ sign = Vdsp::DoubleArray.new(input.window_size)
13
+ Vdsp::UnsafeDouble.vlim(stream, 0, 1, 0.0, @zoom, sign, 0, 1, input.window_size)
14
+
15
+ abs = stream.abs
16
+
17
+ under = Vdsp::DoubleArray.new(input.window_size)
18
+ Vdsp::UnsafeDouble.vclip(abs, 0, 1, 0.0, @threshold, under, 0, 1, input.window_size)
19
+
20
+ over = Vdsp::DoubleArray.new(input.window_size)
21
+ Vdsp::UnsafeDouble.vthr(abs, 0, 1, @threshold, over, 0, 1, input.window_size)
22
+ over = (over - @threshold) * @ratio
23
+
24
+ (under + over) * sign
20
25
  }
21
26
  Buffer.new(*streams)
22
27
  end
@@ -8,15 +8,9 @@ module AudioStream
8
8
 
9
9
  def process(input)
10
10
  streams = input.streams.map {|stream|
11
- stream.map {|f|
12
- val = f * @gain
13
- if 1.0 < val
14
- val = 1.0
15
- elsif val < -1.0
16
- val = -1.0
17
- end
18
- val * @level
19
- }
11
+ dst = Vdsp::DoubleArray.new(input.window_size)
12
+ Vdsp::UnsafeDouble.vclip(stream * @gain, 0, 1, -1.0, 1.0, dst, 0, 1, input.window_size)
13
+ dst * @level
20
14
  }
21
15
  Buffer.new(*streams)
22
16
  end
@@ -4,20 +4,26 @@ module AudioStream
4
4
  include Singleton
5
5
 
6
6
  def process(input)
7
- window_size = input.window_size
8
- window_max = input.window_size - 1
9
- channels = input.channels
7
+ #window_size = input.window_size
8
+ #window_max = input.window_size - 1
9
+ #channels = input.channels
10
10
 
11
- period = 2 * Math::PI / window_max
11
+ #period = 2 * Math::PI / window_max
12
12
 
13
13
  streams = input.streams.map {|stream|
14
- stream.map.with_index {|f, i|
15
- f * (0.5 - 0.5 * Math.cos(i * period))
16
- }
14
+ #stream.map.with_index {|f, i|
15
+ # f * (0.5 - 0.5 * Math.cos(i * period))
16
+ #}
17
+ stream * self.window(input.window_size)
17
18
  }
18
19
 
19
20
  Buffer.new(*streams)
20
21
  end
22
+
23
+ def window(size)
24
+ @window ||= {}
25
+ @window[size] ||= Vdsp::DoubleArray.hann_window(size, Vdsp::FULL_WINDOW)
26
+ end
21
27
  end
22
28
  end
23
29
  end
@@ -0,0 +1,45 @@
1
+ module AudioStream
2
+ module Fx
3
+ class Phaser
4
+
5
+ def initialize(soundinfo, rate:, depth:, freq:, dry: 0.5, wet: 0.5)
6
+ @soundinfo = soundinfo
7
+
8
+ @filters = [
9
+ AllPassFilter.new(soundinfo),
10
+ AllPassFilter.new(soundinfo),
11
+ ]
12
+
13
+ @speed = 2.0 * Math::PI * rate / @soundinfo.samplerate
14
+ @phase = 0
15
+
16
+ @depth = depth
17
+ @freq = freq
18
+
19
+ @dry = dry
20
+ @wet = wet
21
+ end
22
+
23
+ def process(input)
24
+ window_size = input.window_size
25
+ @phase = (@phase + @speed * window_size) % (window_size / @speed)
26
+
27
+ a = Math.sin(@phase) * 0.5 + 0.5
28
+ apf_freq = @freq * (1.0 + a * @depth)
29
+
30
+ wet = input
31
+ @filters.each {|filter|
32
+ filter.update_coef(freq: apf_freq, q: BiquadFilter::DEFAULT_Q)
33
+ wet = filter.process(wet)
34
+ }
35
+
36
+ streams = wet.streams.map.with_index {|wet_stream, i|
37
+ dry_stream = input.streams[i]
38
+ dry_stream * @dry + wet_stream * @wet
39
+ }
40
+
41
+ Buffer.new(*streams)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,52 @@
1
+ module AudioStream
2
+ module Fx
3
+ class SchroederReverb
4
+
5
+ def initialize(soundinfo, time:, dry: 1.0, wet: 0.7)
6
+ @window_size = soundinfo.window_size
7
+ @combs = [
8
+ CombFilter.new(soundinfo, freq: ms2freq(39.85 / 2.0 * time), q: 0.871402),
9
+ CombFilter.new(soundinfo, freq: ms2freq(36.10 / 2.0 * time), q: 0.882762),
10
+ CombFilter.new(soundinfo, freq: ms2freq(33.27 / 2.0 * time), q: 0.891443),
11
+ CombFilter.new(soundinfo, freq: ms2freq(30.15 / 2.0 * time), q: 0.901117),
12
+ ]
13
+ @allpasss = [
14
+ AllPassFilter.create(soundinfo, freq: ms2freq(5.0), q: 0.7),
15
+ AllPassFilter.create(soundinfo, freq: ms2freq(1.7), q: 0.7),
16
+ ]
17
+
18
+ @dry = dry.to_f
19
+ @wet = wet.to_f
20
+ end
21
+
22
+ def process(input)
23
+ window_size = input.window_size
24
+ if @window_size!=window_size
25
+ raise "window size is not match: impulse.size=#{@window_size} input.size=#{window_size}"
26
+ end
27
+
28
+ wets = @combs.map {|comb|
29
+ comb.process(input)
30
+ }
31
+ wet = Buffer.merge(wets, average: true)
32
+
33
+ @allpasss.each {|allpass|
34
+ wet = allpass.process(wet)
35
+ }
36
+
37
+ streams = wet.streams.map.with_index {|wet_stream, i|
38
+ dry_stream = input.streams[i]
39
+ dst = Vdsp::DoubleArray.new(window_size)
40
+ Vdsp::UnsafeDouble.vsmsma(dry_stream, 0, 1, @dry, wet_stream, 0, 1, @wet, dst, 0, 1, window_size)
41
+ dst
42
+ }
43
+
44
+ Buffer.new(*streams)
45
+ end
46
+
47
+ def ms2freq(ms)
48
+ 1.0 / (ms / 1000.0)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module AudioStream
2
- VERSION = "3.0.1"
2
+ VERSION = "3.1.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: 3.0.1
4
+ version: 3.1.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-10-04 00:00:00.000000000 Z
11
+ date: 2019-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 1.6.0
61
+ version: 1.10.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 1.6.0
68
+ version: 1.10.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: ruby-audio
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -168,10 +168,12 @@ files:
168
168
  - lib/audio_stream/error.rb
169
169
  - lib/audio_stream/fx.rb
170
170
  - lib/audio_stream/fx/a_gain.rb
171
+ - lib/audio_stream/fx/all_pass_filter.rb
171
172
  - lib/audio_stream/fx/band_pass_filter.rb
172
173
  - lib/audio_stream/fx/bang_process.rb
173
174
  - lib/audio_stream/fx/biquad_filter.rb
174
175
  - lib/audio_stream/fx/chorus.rb
176
+ - lib/audio_stream/fx/comb_filter.rb
175
177
  - lib/audio_stream/fx/compressor.rb
176
178
  - lib/audio_stream/fx/convolution_reverb.rb
177
179
  - lib/audio_stream/fx/delay.rb
@@ -187,6 +189,8 @@ files:
187
189
  - lib/audio_stream/fx/noise_gate.rb
188
190
  - lib/audio_stream/fx/panning.rb
189
191
  - lib/audio_stream/fx/peaking_filter.rb
192
+ - lib/audio_stream/fx/phaser.rb
193
+ - lib/audio_stream/fx/schroeder_reverb.rb
190
194
  - lib/audio_stream/fx/tremolo.rb
191
195
  - lib/audio_stream/fx/tuner.rb
192
196
  - lib/audio_stream/ring_buffer.rb