audio_stream 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -36,11 +36,11 @@ module AudioStream
36
36
  }
37
37
  when 2
38
38
  window_size.times {|i|
39
- input[i] = channels.times.map {|j|
40
- b = @filter_bufs[j]
41
- in0 = input[i][j]
42
- process_one(in0, b)
43
- }
39
+ input_i = input[i]
40
+ input[i] = [
41
+ process_one(input_i[0], @filter_bufs[0]),
42
+ process_one(input_i[1], @filter_bufs[1]),
43
+ ]
44
44
  }
45
45
  end
46
46
 
@@ -69,6 +69,57 @@ module AudioStream
69
69
 
70
70
  out0
71
71
  end
72
+
73
+ def plot_data(width=1000)
74
+ c = @filter_coef
75
+
76
+ b0 = c.b0 / c.a0
77
+ b1 = c.b1 / c.a0
78
+ b2 = c.b2 / c.a0
79
+ a1 = c.a1 / c.a0
80
+ a2 = c.a2 / c.a0
81
+
82
+ noctaves = 10
83
+ nyquist = @samplerate * 0.5
84
+
85
+ freq = []
86
+ x = []
87
+ width.times {|i|
88
+ f = i.to_f / width
89
+ f = 2.0 ** (noctaves * (f - 1.0))
90
+ freq << f
91
+ x << (f * nyquist)
92
+ }
93
+
94
+ mag_res = []
95
+ phase_res = []
96
+ width.times {|i|
97
+ omega = -Math::PI * freq[i]
98
+ z = Complex(Math.cos(omega), Math.sin(omega))
99
+ num = b0 + (b1 + b2 * z) * z
100
+ den = 1 + (a1 + a2 * z) * z
101
+ res = num / den
102
+
103
+ mag_res << Decibel.mag(res.abs).db
104
+ phase_res << 180 / Math::PI * Math.atan2(res.imag, res.real)
105
+ }
106
+
107
+ {x: x, magnitude: mag_res, phase: phase_res}
108
+ end
109
+
110
+ def plot(width=1000)
111
+ data = plot_data(width)
112
+
113
+ Plotly::Plot.new(
114
+ data: [{x: data[:x], y: data[:magnitude], name: 'Magnitude', yaxis: 'y1'}, {x: data[:x], y: data[:phase], name: 'Phase', yaxis: 'y2'}],
115
+ layout: {
116
+ xaxis: {title: 'Frequency (Hz)', type: 'log'},
117
+ yaxis: {side: 'left', title: 'Magnitude (dB)', showgrid: false},
118
+ yaxis2: {side: 'right', title: 'Phase (deg)', showgrid: false, overlaying: 'y'}
119
+ }
120
+ )
121
+ end
122
+
72
123
  end
73
124
  end
74
125
  end
@@ -10,7 +10,7 @@ module AudioStream
10
10
  @window_size = impulse_bufs[0].size
11
11
  @dry_gain = dry
12
12
  @wet_gain = wet
13
- @window = window || HanningWindow.new
13
+ @window = window || HanningWindow.instance
14
14
 
15
15
  zero_buf = Buffer.float(@window_size, @channels)
16
16
  if @channels==1
@@ -3,21 +3,35 @@ module AudioStream
3
3
  class Equalizer2band
4
4
  include BangProcess
5
5
 
6
- def initialize(soundinfo, lowgain:, highgain:)
7
- @lowfreq = 400.0
8
- @lowgain = lowgain
9
-
10
- @highfreq = 4000.0
11
- @highgain = highgain
12
-
13
- @low_filter = LowShelfFilter.create(soundinfo, freq: @lowfreq, q: 1.0/Math.sqrt(2.0), gain: @lowgain)
14
- @high_filter = HighShelfFilter.create(soundinfo, freq: @highfreq, q: 1.0/Math.sqrt(2.0), gain: @highgain)
6
+ def initialize(soundinfo, lowfreq: 400.0, lowgain:, highfreq: 4000.0, highgain:)
7
+ @low_filter = LowShelfFilter.create(soundinfo, freq: lowfreq, q: 1.0/Math.sqrt(2.0), gain: lowgain)
8
+ @high_filter = HighShelfFilter.create(soundinfo, freq: highfreq, q: 1.0/Math.sqrt(2.0), gain: highgain)
15
9
  end
16
10
 
17
11
  def process!(input)
18
12
  @low_filter.process!(input)
19
13
  @high_filter.process!(input)
20
14
  end
15
+
16
+ def plot(width=1000)
17
+ data1 = @low_filter.plot_data(width)
18
+ data2 = @high_filter.plot_data(width)
19
+
20
+ data = {
21
+ x: data1[:x],
22
+ magnitude: [data1[:magnitude], data2[:magnitude]].transpose.map {|a| a[0] + a[1]},
23
+ phase: [data1[:phase], data2[:phase]].transpose.map {|a| a[0] + a[1]},
24
+ }
25
+
26
+ Plotly::Plot.new(
27
+ data: [{x: data[:x], y: data[:magnitude], name: 'Magnitude', yaxis: 'y1'}, {x: data[:x], y: data[:phase], name: 'Phase', yaxis: 'y2'}],
28
+ layout: {
29
+ xaxis: {title: 'Frequency (Hz)', type: 'log'},
30
+ yaxis: {side: 'left', title: 'Magnitude (dB)', showgrid: false},
31
+ yaxis2: {side: 'right', title: 'Phase (deg)', showgrid: false, overlaying: 'y'}
32
+ }
33
+ )
34
+ end
21
35
  end
22
36
  end
23
37
  end
@@ -3,19 +3,10 @@ module AudioStream
3
3
  class Equalizer3band
4
4
  include BangProcess
5
5
 
6
- def initialize(soundinfo, lowgain:, midgain:, highgain:)
7
- @lowfreq = 400.0
8
- @lowgain = lowgain
9
-
10
- @midfreq = 1000.0
11
- @midgain = midgain
12
-
13
- @highfreq = 4000.0
14
- @highgain = highgain
15
-
16
- @low_filter = LowShelfFilter.create(soundinfo, freq: @lowfreq, q: 1.0/Math.sqrt(2.0), gain: @lowgain)
17
- @mid_filter = PeakingFilter.create(soundinfo, freq: @midfreq, bandwidth: 1.0/Math.sqrt(2.0), gain: @midgain)
18
- @high_filter = HighShelfFilter.create(soundinfo, freq: @highfreq, q: 1.0/Math.sqrt(2.0), gain: @highgain)
6
+ def initialize(soundinfo, lowfreq: 400.0, lowgain:, midfreq: 1000.0, midgain:, highfreq: 4000.0, highgain:)
7
+ @low_filter = LowShelfFilter.create(soundinfo, freq: lowfreq, q: 1.0/Math.sqrt(2.0), gain: lowgain)
8
+ @mid_filter = PeakingFilter.create(soundinfo, freq: midfreq, bandwidth: 1.0/Math.sqrt(2.0), gain: midgain)
9
+ @high_filter = HighShelfFilter.create(soundinfo, freq: highfreq, q: 1.0/Math.sqrt(2.0), gain: highgain)
19
10
  end
20
11
 
21
12
  def process!(input)
@@ -23,6 +14,27 @@ module AudioStream
23
14
  @mid_filter.process!(input)
24
15
  @high_filter.process!(input)
25
16
  end
17
+
18
+ def plot(width=1000)
19
+ data1 = @low_filter.plot_data(width)
20
+ data2 = @mid_filter.plot_data(width)
21
+ data3 = @high_filter.plot_data(width)
22
+
23
+ data = {
24
+ x: data1[:x],
25
+ magnitude: [data1[:magnitude], data2[:magnitude], data3[:magnitude]].transpose.map {|a| a[0] + a[1] + a[2]},
26
+ phase: [data1[:phase], data2[:phase], data3[:phase]].transpose.map {|a| a[0] + a[1] + a[2]},
27
+ }
28
+
29
+ Plotly::Plot.new(
30
+ data: [{x: data[:x], y: data[:magnitude], name: 'Magnitude', yaxis: 'y1'}, {x: data[:x], y: data[:phase], name: 'Phase', yaxis: 'y2'}],
31
+ layout: {
32
+ xaxis: {title: 'Frequency (Hz)', type: 'log'},
33
+ yaxis: {side: 'left', title: 'Magnitude (dB)', showgrid: false},
34
+ yaxis2: {side: 'right', title: 'Phase (deg)', showgrid: false, overlaying: 'y'}
35
+ }
36
+ )
37
+ end
26
38
  end
27
39
  end
28
40
  end
@@ -12,7 +12,7 @@ module AudioStream
12
12
  a2 = 1.0 - alpha / a
13
13
  b0 = 1.0 + alpha * a
14
14
  b1 = -2.0 * Math.cos(omega)
15
- b2 = 1.0 + alpha * a
15
+ b2 = 1.0 - alpha * a
16
16
 
17
17
  @filter_coef = FilterCoef.new(a0, a1, a2, b0, b1, b2)
18
18
  end
@@ -1,3 +1,3 @@
1
1
  module AudioStream
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
data/lib/audio_stream.rb CHANGED
@@ -7,6 +7,7 @@ require 'singleton'
7
7
  require 'audio_stream/version'
8
8
  require 'audio_stream/error'
9
9
  require 'audio_stream/sound_info'
10
+ require 'audio_stream/decibel'
10
11
  require 'audio_stream/buffer'
11
12
  require 'audio_stream/ring_buffer'
12
13
  require 'audio_stream/sync'
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: 1.3.0
4
+ version: 1.4.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-07-27 00:00:00.000000000 Z
11
+ date: 2019-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -124,9 +124,10 @@ files:
124
124
  - audio_stream.gemspec
125
125
  - bin/console
126
126
  - bin/setup
127
- - examples/buffer.ipynb
127
+ - examples/biquad.ipynb
128
128
  - examples/chorus.rb
129
129
  - examples/distortion.rb
130
+ - examples/equalizer.ipynb
130
131
  - examples/example_options.rb
131
132
  - examples/lpf.rb
132
133
  - examples/rec.rb
@@ -147,6 +148,7 @@ files:
147
148
  - lib/audio_stream/audio_output_file.rb
148
149
  - lib/audio_stream/buffer.rb
149
150
  - lib/audio_stream/conductor.rb
151
+ - lib/audio_stream/decibel.rb
150
152
  - lib/audio_stream/error.rb
151
153
  - lib/audio_stream/fx.rb
152
154
  - lib/audio_stream/fx/a_gain.rb