audio_stream 3.2.0 → 3.3.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: e1bdc59349cd6ef2c49c5cbc140c15037225f32f852a32ca6e951041b7a30711
4
- data.tar.gz: 31694954a02b8920b3da085cba2ac5dfa46c851e44d44f5cf0cefa871b76e1ce
3
+ metadata.gz: 0011df46c8c5a4ca83fac3301ca638940087710da3dd996382a354d9aa19596f
4
+ data.tar.gz: d88cb6715119d98bd02ee980be8cf9446b3a729a8de5003cf77a0dc0f958501a
5
5
  SHA512:
6
- metadata.gz: f88c300ac5d2e45e2c7b8b9d4de0aba54a49b22542478c7ba0ae7408140df727cc6ffb66b68f8d6a1353cea462a678ec2bcd6ed4681684ec2c87cfa71d2404a5
7
- data.tar.gz: b5281f647673f887c4e001e72c29e678614a064be79fc199156774dfeba2a9c9a51da49f4a58fdbd14a05fa339ced998186b54146f1a7d7c26f134c676d2a9a5
6
+ metadata.gz: 7059283b291c17fec85bcd40f194d8312a0f2539fe093a31268c5361f6a00517390a5d5c56df72cedb9dcc8432100a066834dee1fde4872039cf5adc2524c58c
7
+ data.tar.gz: 55340551e2da2ce9dcd87c89261b71868687d30ab65167f05552402c10d2e227337ccc7bba0c5ae9c7ebc737e779fa85952fb3056db3a7b5a1a65423fcffeed2
data/lib/audio_stream.rb CHANGED
@@ -9,6 +9,7 @@ require 'audio_stream/version'
9
9
  require 'audio_stream/error'
10
10
  require 'audio_stream/sound_info'
11
11
  require 'audio_stream/decibel'
12
+ require 'audio_stream/rate'
12
13
  require 'audio_stream/buffer'
13
14
  require 'audio_stream/ring_buffer'
14
15
  require 'audio_stream/sync'
@@ -10,7 +10,7 @@ module AudioStream
10
10
  end
11
11
 
12
12
  def add(observable, gain:, pan:)
13
- if gain && gain!=1.0
13
+ if gain && gain!=0.0
14
14
  observable = observable.fx(Fx::AGain.new(level: gain))
15
15
  end
16
16
 
@@ -100,7 +100,7 @@ module AudioStream
100
100
  dst = buffers.inject(:+)
101
101
 
102
102
  if average
103
- gain = AGain.new(level: 1.0/buffers.length)
103
+ gain = AGain.new(level: Decibel.mag(1.0/buffers.length))
104
104
  dst = gain.process(dst)
105
105
  end
106
106
 
@@ -20,5 +20,13 @@ module AudioStream
20
20
  def self.mag(mag)
21
21
  new(mag: mag)
22
22
  end
23
+
24
+ def self.create(val)
25
+ if self===val
26
+ val
27
+ else
28
+ new(db: val.to_f)
29
+ end
30
+ end
23
31
  end
24
32
  end
@@ -1,8 +1,13 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class AGain
4
- def initialize(level: 1.0)
5
- @level = level
4
+ # @param level [AudioStream::Decibel] Amplification level
5
+ def initialize(level:)
6
+ if Decibel===level
7
+ @level = level.mag
8
+ else
9
+ @level = Decibel.db(level).mag
10
+ end
6
11
  end
7
12
 
8
13
  def process(input)
@@ -19,6 +19,9 @@ module AudioStream
19
19
  }
20
20
  end
21
21
 
22
+ # @param soundinfo [AudioStream::SoundInfo]
23
+ # @param freq [Float] Cutoff frequency
24
+ # @param q [Float] Quality factor
22
25
  def self.create(soundinfo, freq:, q: DEFAULT_Q)
23
26
  filter = new(soundinfo)
24
27
  filter.update_coef(freq: freq, q: q)
@@ -19,6 +19,9 @@ module AudioStream
19
19
  }
20
20
  end
21
21
 
22
+ # @param soundinfo [AudioStream::SoundInfo]
23
+ # @param freq [Float] Center frequency
24
+ # @param bandwidth [Float] bandwidth (octave)
22
25
  def self.create(soundinfo, freq:, bandwidth: 1.0)
23
26
  filter = new(soundinfo)
24
27
  filter.update_coef(freq: freq, bandwidth: bandwidth)
@@ -2,10 +2,12 @@ module AudioStream
2
2
  module Fx
3
3
  class CombFilter
4
4
 
5
+ # @param soundinfo [AudioStream::SoundInfo]
6
+ # @param freq [AudioStream::Rate] frequency
7
+ # @param q [Float] Quality factor
5
8
  def initialize(soundinfo, freq:, q:)
6
9
  @window_size = soundinfo.window_size
7
- @samplerate = soundinfo.samplerate
8
- @delaysample = (soundinfo.samplerate.to_f / freq).round
10
+ @delaysample = freq.sample(soundinfo).round
9
11
  @q = q
10
12
 
11
13
  @delaybufs = [
@@ -1,12 +1,15 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class Delay
4
+ # @param soundinfo [AudioStream::SoundInfo]
5
+ # @param time [AudioStream::Rate] delay time
6
+ # @param level [AudioStream::Decibel] wet gain
7
+ # @param feedback [AudioStream::Decibel] feedback level
4
8
  def initialize(soundinfo, time:, level:, feedback:)
5
- @time = time
6
- @level = level
7
- @feedback = feedback
9
+ @level = Decibel.create(level).mag
10
+ @feedback = Decibel.create(feedback).mag
8
11
 
9
- @delaysample = (soundinfo.samplerate * time).round
12
+ @delaysample = time.sample(soundinfo).round
10
13
  @delaybuf0 = Array.new(@delaysample, 0.0)
11
14
  @delaybuf1 = Array.new(@delaysample, 0.0)
12
15
  @seek = 0
@@ -1,9 +1,11 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class Distortion
4
- def initialize(gain: 100, level: 0.1)
5
- @gain = gain
6
- @level = level
4
+ # @param gain [AudioStream::Decibel] input gain
5
+ # @param level [AudioStream::Decibel] output level
6
+ def initialize(gain: 40.0, level: -20.0)
7
+ @gain = Decibel.create(gain).mag
8
+ @level = Decibel.create(level).mag
7
9
  end
8
10
 
9
11
  def process(input)
@@ -1,6 +1,9 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class Equalizer2band
4
+ # @param freq [Float] Cutoff frequency
5
+ # @param q [Float] Quality factor
6
+ # @param gain [AudioStream::Decibel] Amplification level at cutoff frequency
4
7
  def initialize(soundinfo, lowfreq: 400.0, lowgain:, highfreq: 4000.0, highgain:)
5
8
  @low_filter = LowShelfFilter.create(soundinfo, freq: lowfreq, q: BiquadFilter::DEFAULT_Q, gain: lowgain)
6
9
  @high_filter = HighShelfFilter.create(soundinfo, freq: highfreq, q: BiquadFilter::DEFAULT_Q, gain: highgain)
@@ -19,6 +19,9 @@ module AudioStream
19
19
  }
20
20
  end
21
21
 
22
+ # @param soundinfo [AudioStream::SoundInfo]
23
+ # @param freq [Float] Cutoff frequency
24
+ # @param q [Float] Quality factor
22
25
  def self.create(soundinfo, freq:, q: DEFAULT_Q)
23
26
  filter = new(soundinfo)
24
27
  filter.update_coef(freq: freq, q: q)
@@ -3,6 +3,10 @@ module AudioStream
3
3
  class HighShelfFilter < BiquadFilter
4
4
 
5
5
  def update_coef(freq:, q:, gain:)
6
+ if Decibel===gain
7
+ gain = gain.db
8
+ end
9
+
6
10
  omega = 2.0 * Math::PI * freq / @samplerate
7
11
  alpha = Math.sin(omega) / (2.0 * q)
8
12
  a = 10.0 ** (gain / 40.0)
@@ -21,6 +25,10 @@ module AudioStream
21
25
  }
22
26
  end
23
27
 
28
+ # @param soundinfo [AudioStream::SoundInfo]
29
+ # @param freq [Float] Cutoff frequency
30
+ # @param q [Float] Quality factor
31
+ # @param gain [AudioStream::Decibel] Amplification level at cutoff frequency
24
32
  def self.create(soundinfo, freq:, q: DEFAULT_Q, gain: 1.0)
25
33
  filter = new(soundinfo)
26
34
  filter.update_coef(freq: freq, q: q, gain: gain)
@@ -19,6 +19,9 @@ module AudioStream
19
19
  }
20
20
  end
21
21
 
22
+ # @param soundinfo [AudioStream::SoundInfo]
23
+ # @param freq [Float] Cutoff frequency
24
+ # @param q [Float] Quality factor
22
25
  def self.create(soundinfo, freq:, q: DEFAULT_Q)
23
26
  filter = new(soundinfo)
24
27
  filter.update_coef(freq: freq, q: q)
@@ -3,6 +3,10 @@ module AudioStream
3
3
  class LowShelfFilter < BiquadFilter
4
4
 
5
5
  def update_coef(freq:, q:, gain:)
6
+ if Decibel===gain
7
+ gain = gain.db
8
+ end
9
+
6
10
  omega = 2.0 * Math::PI * freq / @samplerate
7
11
  alpha = Math.sin(omega) / (2.0 * q)
8
12
  a = 10.0 ** (gain / 40.0)
@@ -21,6 +25,10 @@ module AudioStream
21
25
  }
22
26
  end
23
27
 
28
+ # @param soundinfo [AudioStream::SoundInfo]
29
+ # @param freq [Float] Cutoff frequency
30
+ # @param q [Float] Quality factor
31
+ # @param gain [AudioStream::Decibel] Amplification level at cutoff frequency
24
32
  def self.create(soundinfo, freq:, q: DEFAULT_Q, gain: 1.0)
25
33
  filter = new(soundinfo)
26
34
  filter.update_coef(freq: freq, q: q, gain: gain)
@@ -3,6 +3,10 @@ module AudioStream
3
3
  class PeakingFilter < BiquadFilter
4
4
 
5
5
  def update_coef(freq:, bandwidth:, gain:)
6
+ if Decibel===gain
7
+ gain = gain.db
8
+ end
9
+
6
10
  omega = 2.0 * Math::PI * freq / @samplerate
7
11
  alpha = Math.sin(omega) * Math.sinh(Math.log(2.0) / 2.0 * bandwidth * omega / Math.sin(omega))
8
12
  a = 10.0 ** (gain / 40.0)
@@ -20,6 +24,10 @@ module AudioStream
20
24
  }
21
25
  end
22
26
 
27
+ # @param soundinfo [AudioStream::SoundInfo]
28
+ # @param freq [Float] Cutoff frequency
29
+ # @param bandwidth [Float] bandwidth (octave)
30
+ # @param gain [AudioStream::Decibel] Amplification level at cutoff frequency
23
31
  def self.create(soundinfo, freq:, bandwidth: 1.0, gain: 40.0)
24
32
  filter = new(soundinfo)
25
33
  filter.update_coef(freq: freq, bandwidth: bandwidth, gain: gain)
@@ -2,7 +2,13 @@ module AudioStream
2
2
  module Fx
3
3
  class Phaser
4
4
 
5
- def initialize(soundinfo, rate:, depth:, freq:, dry: 0.5, wet: 0.5)
5
+ # @param soundinfo [AudioStream::SoundInfo]
6
+ # @param rate [AudioStream::Rate] modulation speed
7
+ # @param depth [Float] frequency modulation depth
8
+ # @param freq [Float] Base cutoff frequency
9
+ # @param dry [AudioStream::Decibel] dry gain
10
+ # @param wet [AudioStream::Decibel] wet gain
11
+ def initialize(soundinfo, rate:, depth:, freq:, dry: -6.0, wet: -6.0)
6
12
  @soundinfo = soundinfo
7
13
 
8
14
  @filters = [
@@ -10,19 +16,19 @@ module AudioStream
10
16
  AllPassFilter.new(soundinfo),
11
17
  ]
12
18
 
13
- @speed = 2.0 * Math::PI * rate / @soundinfo.samplerate
19
+ @speed = rate.frame_phase(soundinfo)
14
20
  @phase = 0
15
21
 
16
22
  @depth = depth
17
23
  @freq = freq
18
24
 
19
- @dry = dry
20
- @wet = wet
25
+ @dry = Decibel.create(dry).mag
26
+ @wet = Decibel.create(wet).mag
21
27
  end
22
28
 
23
29
  def process(input)
24
30
  window_size = input.window_size
25
- @phase = (@phase + @speed * window_size) % (window_size / @speed)
31
+ @phase = (@phase + @speed) % (2.0 * Math::PI)
26
32
 
27
33
  a = Math.sin(@phase) * 0.5 + 0.5
28
34
  apf_freq = @freq * (1.0 + a * @depth)
@@ -3,6 +3,9 @@ module AudioStream
3
3
  class Vocoder
4
4
  include MultiAudioInputtable
5
5
 
6
+ # @param soundinfo [AudioStream::SoundInfo]
7
+ # @param shift [Float] modulator pitch shift. 1.0=1semitone
8
+ # @param bandwidth [Float] bandwidth (octave)
6
9
  def initialize(soundinfo, shift: 0, bandwidth: 0.2)
7
10
  regist_audio_input(:main)
8
11
  regist_audio_input(:side)
@@ -0,0 +1,98 @@
1
+ module AudioStream
2
+ class Rate
3
+ def initialize(sec: nil, sample: nil, freq: nil, sync: nil)
4
+ @sec = sec
5
+ @sample = sample
6
+ @freq = freq
7
+ @sync = sync
8
+ end
9
+
10
+ def sec(soundinfo)
11
+ sample(soundinfo).to_f / soundinfo.samplerate
12
+ end
13
+
14
+ def frame(soundinfo)
15
+ sample(soundinfo).to_f / soundinfo.window_size
16
+ end
17
+
18
+ def sample(soundinfo)
19
+ if @sample
20
+ return @sample
21
+ end
22
+
23
+ if @sec
24
+ return @sec.to_f * soundinfo.samplerate
25
+ end
26
+
27
+ if @freq
28
+ return soundinfo.samplerate.to_f / @freq
29
+ end
30
+
31
+ if @sync
32
+ return @sync / 480.0 * soundinfo.sync_rate
33
+ end
34
+ end
35
+
36
+ def frame_phase(soundinfo)
37
+ sample_phase(soundinfo) * soundinfo.window_size
38
+ end
39
+
40
+ def sample_phase(soundinfo)
41
+ 2.0 * Math::PI / sample(soundinfo)
42
+ end
43
+
44
+ def self.sec(v)
45
+ new(sec: v)
46
+ end
47
+
48
+ def self.millisec(v)
49
+ new(sec: v*0.001)
50
+ end
51
+
52
+ def self.sample(v)
53
+ new(sample: v)
54
+ end
55
+
56
+ def self.freq(v)
57
+ new(freq: v)
58
+ end
59
+
60
+ def self.sync(v)
61
+ new(sync: v)
62
+ end
63
+
64
+
65
+ SYNC_64 = sync(480 * 64)
66
+ SYNC_32 = sync(480 * 32)
67
+ SYNC_16 = sync(480 * 16)
68
+ SYNC_8 = sync(480 * 8)
69
+ SYNC_6 = sync(480 * 6)
70
+ SYNC_4 = sync(480 * 4)
71
+ SYNC_3 = sync(480 * 3)
72
+ SYNC_2 = sync(480 * 2)
73
+ SYNC_7_4 = sync(480 * 7 / 4)
74
+ SYNC_6_4 = sync(480 * 6 / 4)
75
+ SYNC_5_4 = sync(480 * 5 / 4)
76
+ SYNC_1 = sync(480 * 1)
77
+ SYNC_3_4 = sync(480 * 3 / 4)
78
+ SYNC_1_2 = sync(480 * 1 / 2)
79
+ SYNC_1_4D = sync(480 * 1 / 4 * 3 / 2)
80
+ SYNC_1_4 = sync(480 * 1 / 4)
81
+ SYNC_1_4T = sync(480 * 1 / 4 * 2 / 3)
82
+ SYNC_1_8D = sync(480 * 1 / 8 * 3 / 2)
83
+ SYNC_1_8 = sync(480 * 1 / 8)
84
+ SYNC_1_8T = sync(480 * 1 / 8 * 2 / 3)
85
+ SYNC_1_16D = sync(480 * 1 / 16 * 3 / 2)
86
+ SYNC_1_16 = sync(480 * 1 / 16)
87
+ SYNC_1_16T = sync(480 * 1 / 16 * 2 / 3)
88
+ SYNC_1_32D = sync(480 * 1 / 32 * 3 / 2)
89
+ SYNC_1_32 = sync(480 * 1 / 32)
90
+ SYNC_1_32T = sync(480 * 1 / 32 * 2 / 3)
91
+ SYNC_1_64D = sync(480 * 1 / 64 * 3 / 2)
92
+ SYNC_1_64 = sync(480 * 1 / 64)
93
+ SYNC_1_64T = sync(480 * 1 / 64 * 2 / 3)
94
+ SYNC_1_128D = sync(480 * 1 / 128 * 3 / 2)
95
+ SYNC_1_128 = sync(480 * 1 / 128)
96
+ SYNC_1_128T = sync(480 * 1 / 128 * 2 / 3)
97
+ end
98
+ end
@@ -1,13 +1,24 @@
1
1
  module AudioStream
2
2
  class SoundInfo < RubyAudio::SoundInfo
3
3
  attr_accessor :window_size
4
+ attr_reader :bpm
5
+ attr_reader :bps
4
6
 
5
7
  def framerate
6
8
  self.samplerate.to_f / self.window_size
7
9
  end
8
10
 
11
+ def bpm=(bpm)
12
+ @bpm = bpm.to_f
13
+ @bps = @bpm / 60.0
14
+ end
15
+
16
+ def sync_rate
17
+ self.samplerate.to_f / self.bps
18
+ end
19
+
9
20
  def clone
10
- SoundInfo.new(channels: channels, samplerate: samplerate, format: format, window_size: window_size)
21
+ SoundInfo.new(channels: channels, samplerate: samplerate, format: format, window_size: window_size, bpm: bpm)
11
22
  end
12
23
  end
13
24
  end
@@ -1,3 +1,3 @@
1
1
  module AudioStream
2
- VERSION = "3.2.0"
2
+ VERSION = "3.3.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.2.0
4
+ version: 3.3.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-17 00:00:00.000000000 Z
11
+ date: 2019-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -196,6 +196,7 @@ files:
196
196
  - lib/audio_stream/fx/tremolo.rb
197
197
  - lib/audio_stream/fx/tuner.rb
198
198
  - lib/audio_stream/fx/vocoder.rb
199
+ - lib/audio_stream/rate.rb
199
200
  - lib/audio_stream/ring_buffer.rb
200
201
  - lib/audio_stream/sound_info.rb
201
202
  - lib/audio_stream/sync.rb