audio_stream 1.2.4 → 1.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: '00808bca83da43c81bd03e94f420f7ecce53b9211450c76a09d6d1856edf8be2'
4
- data.tar.gz: 64d161eedf393c991fe2692aa7328afceed56e926fed3101f92dbc862b820446
3
+ metadata.gz: e44fc50ce5993f26948cf0429df83eb1dac15556dbc89f7db605fa398a79f928
4
+ data.tar.gz: 8a4f2bcb04ca5d26b2574ac0b960211769d9d8f1f3474dcfb9823780ec0c90d7
5
5
  SHA512:
6
- metadata.gz: 4665c0f70102e40057ec0f799f21a8d422bd9ce395f74b7075f22cad0d7024ed8701e682cf644df55822055cf6720dacbb499de0766958dfa17bc46d6d0039b3
7
- data.tar.gz: 0be2c27573b1918ac6a01ffaa0b678c44338630415c28a3b13c06b432888c8b467f9443ad26b1e326aab9b4d2277eecb5268b8d541189f5827c35109443a93c9
6
+ metadata.gz: e3e1ac2bde745775aa261b02fa130f98720e3c549ed67d0ff1237e7ca5815a74fb3608f87fb020a03ea8af933bd0c3c78488b5d879310e8cd9d0df845b8fc8d3
7
+ data.tar.gz: 79502696e497e3307f35867cbcc8f585a977530b7f2bf1c2223aed6e84323467ee11e9a9e5cdbe4af7e40cbe77aa3a40a3eccfce1fd20cdb8365145389be5703
data/audio_stream.gemspec CHANGED
@@ -33,6 +33,5 @@ Gem::Specification.new do |spec|
33
33
  spec.add_dependency "ruby-audio", ">= 1.6.1"
34
34
  spec.add_dependency "coreaudio", ">= 0.0.12"
35
35
  spec.add_dependency "ruby-fftw3", ">= 1.0.2"
36
- spec.add_dependency "rx", ">= 0.0.3"
37
36
  spec.add_dependency "rbplotly", ">= 0.1.2"
38
37
  end
@@ -51,7 +51,7 @@
51
51
  ],
52
52
  "source": [
53
53
  "$LOAD_PATH << File.dirname(__FILE__) + \"/../lib\"\n",
54
- "require 'audio_stream/core_ext'\n",
54
+ "require 'audio_stream'\n",
55
55
  "\n",
56
56
  "include AudioStream\n",
57
57
  "include AudioStream::Fx\n",
@@ -118,7 +118,7 @@
118
118
  ],
119
119
  "source": [
120
120
  "$LOAD_PATH << File.dirname(__FILE__) + \"/../lib\"\n",
121
- "require 'audio_stream/core_ext'\n",
121
+ "require 'audio_stream'\n",
122
122
  "\n",
123
123
  "include AudioStream\n",
124
124
  "include AudioStream::Fx\n",
data/examples/chorus.rb CHANGED
@@ -22,8 +22,7 @@ stereo_out = AudioOutput.device(soundinfo: $soundinfo)
22
22
  # Mixer
23
23
 
24
24
  track1
25
- .stream
26
- .fx(MonoToStereo.new)
25
+ .fx(MonoToStereo.instance)
27
26
  .fx(chorus)
28
27
  .send_to(bus1, gain: 1.0, pan: 0.0)
29
28
 
@@ -23,7 +23,6 @@ stereo_out = AudioOutput.device(soundinfo: $soundinfo)
23
23
  # Mixer
24
24
 
25
25
  track1
26
- .stream
27
26
  .fx(noise_gate)
28
27
  .fx(compressor)
29
28
  .fx(distortion)
@@ -1,4 +1,4 @@
1
- require 'audio_stream/core_ext'
1
+ require 'audio_stream'
2
2
  require 'optparse'
3
3
 
4
4
  include AudioStream
@@ -6,7 +6,7 @@ include AudioStream::Fx
6
6
 
7
7
 
8
8
  $soundinfo = SoundInfo.new(
9
- channels: 1,
9
+ channels: 2,
10
10
  samplerate: 44100,
11
11
  window_size: 1024,
12
12
  format: RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
data/examples/lpf.rb CHANGED
@@ -24,8 +24,7 @@ stereo_out = AudioOutput.device(soundinfo: $soundinfo)
24
24
  # Mixer
25
25
 
26
26
  track1
27
- .stream
28
- .fx(StereoToMono.new)
27
+ .fx(StereoToMono.instance)
29
28
  .fx(lpf)
30
29
  .send_to(stereo_out)
31
30
 
data/examples/rec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'audio_stream/core_ext'
1
+ require 'audio_stream'
2
2
 
3
3
  include AudioStream
4
4
  include AudioStream::Fx
@@ -6,7 +6,7 @@ include AudioStream::Fx
6
6
  soundinfo = SoundInfo.new(
7
7
  channels: 2,
8
8
  samplerate: 44100,
9
- window_size: 1024
9
+ window_size: 1024,
10
10
  format: RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
11
11
  )
12
12
 
@@ -31,7 +31,6 @@ stereo_out = AudioOutput.device(soundinfo: soundinfo)
31
31
  # Mixer
32
32
 
33
33
  track1
34
- .stream
35
34
  .send_to(file_out)
36
35
  .send_to(bus1)
37
36
 
@@ -39,7 +38,6 @@ bus1
39
38
  .send_to(stereo_out, gain: 0.5)
40
39
 
41
40
  track2
42
- .stream
43
41
  .send_to(stereo_out)
44
42
 
45
43
 
data/examples/tuner.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'audio_stream/core_ext'
1
+ require 'audio_stream'
2
2
 
3
3
  include AudioStream
4
4
  include AudioStream::Fx
data/lib/audio_stream.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'ruby-audio'
2
2
  require 'coreaudio'
3
3
  require 'numru/fftw3'
4
- require 'rx'
5
4
  require 'rbplotly'
5
+ require 'singleton'
6
6
 
7
7
  require 'audio_stream/version'
8
8
  require 'audio_stream/error'
@@ -11,6 +11,10 @@ require 'audio_stream/buffer'
11
11
  require 'audio_stream/ring_buffer'
12
12
  require 'audio_stream/sync'
13
13
  require 'audio_stream/conductor'
14
+ require 'audio_stream/audio_observer'
15
+ require 'audio_stream/audio_observable'
16
+ require 'audio_stream/audio_observable_fx'
17
+ require 'audio_stream/audio_notification'
14
18
  require 'audio_stream/audio_input'
15
19
  require 'audio_stream/audio_input_file'
16
20
  require 'audio_stream/audio_input_device'
@@ -1,28 +1,68 @@
1
1
  module AudioStream
2
- class AudioBus < Rx::Subject
2
+ class AudioBus
3
+ include AudioObserver
4
+ include AudioObservable
5
+
3
6
  def initialize
4
- super
5
- @observables = []
6
- @zip_observable = nil
7
- @detach = nil
7
+ @mutex = Mutex.new
8
+ @callers = Set[]
9
+ @notifications = {}
8
10
  end
9
11
 
10
12
  def add(observable, gain:, pan:)
11
13
  if gain && gain!=1.0
12
- observable = observable.map(&Fx::AGain.new(level: gain).method(:process))
14
+ observable = observable.fx(Fx::AGain.new(level: gain))
13
15
  end
14
16
 
15
17
  if pan && pan!=0.0
16
- observable = observable.map(&Fx::Panning.new(pan: pan).method(:process))
18
+ observable = observable.fx(Fx::Panning.new(pan: pan))
17
19
  end
18
20
 
19
- @observables << observable
20
- if @detach
21
- @detach.unsubscribe
21
+ @mutex.synchronize {
22
+ @callers << observable
23
+ observable.add_observer(self)
24
+ }
25
+ end
26
+
27
+ def update(notification)
28
+ do_notify = false
29
+ next_notifications = nil
30
+
31
+ @mutex.synchronize {
32
+ @notifications[notification.caller_obj] = notification
33
+
34
+ if @callers.length==@notifications.length
35
+ next_notifications = []
36
+ @notifications.each {|caller_obj, notification|
37
+ case notification.stat
38
+ when AudioNotification::STAT_NEXT
39
+ next_notifications << notification
40
+ when AudioNotification::STAT_COMPLETE
41
+ @callers.delete(caller_obj)
42
+ end
43
+ }
44
+
45
+ do_notify = true
46
+ @notifications.clear
47
+ end
48
+ }
49
+
50
+ if do_notify
51
+ if 0<next_notifications.length
52
+ output = next_notifications.map(&:input).inject(:+)
53
+ on_next(output)
54
+ else
55
+ on_complete
56
+ end
22
57
  end
58
+ end
59
+
60
+ def on_next(input)
61
+ notify_next(input)
62
+ end
23
63
 
24
- @zip_observable = Rx::Observable.zip(*@observables).map{|a| a.inject(:+)}
25
- @detach = @zip_observable.subscribe(self)
64
+ def on_complete
65
+ notify_complete
26
66
  end
27
67
  end
28
68
  end
@@ -2,6 +2,7 @@ module AudioStream
2
2
 
3
3
  module AudioInput
4
4
  include Enumerable
5
+ include AudioObservable
5
6
 
6
7
  attr_reader :connection
7
8
 
@@ -9,13 +10,24 @@ module AudioStream
9
10
  @sync ||= Sync.new
10
11
  end
11
12
 
12
- def connect
13
+ def publish
13
14
  @connection = Thread.start {
14
- stream.connect
15
+ each {|input|
16
+ sync.resume_wait
17
+ notify_next(input)
18
+ sync.yield
19
+ }
20
+ sync.resume_wait
21
+ notify_complete
22
+ sync.finish
15
23
  }
16
24
  self
17
25
  end
18
26
 
27
+ def connect
28
+ nil
29
+ end
30
+
19
31
  def disconnect
20
32
  if @connection
21
33
  @connection.kill
@@ -24,17 +36,12 @@ module AudioStream
24
36
  self
25
37
  end
26
38
 
27
- def stream
28
- @stream ||= Rx::Observable.create do |observer|
29
- each {|buf|
30
- sync.resume_wait
31
- observer.on_next(buf)
32
- sync.yield
33
- }
34
- sync.resume_wait
35
- sync.finish
36
- observer.on_completed
37
- end.publish
39
+ def connected?
40
+ nil
41
+ end
42
+
43
+ def published?
44
+ !!@connection
38
45
  end
39
46
 
40
47
 
@@ -6,6 +6,18 @@ module AudioStream
6
6
  @buffers = [buffers].flatten.compact
7
7
  end
8
8
 
9
+ def connect
10
+ self
11
+ end
12
+
13
+ def disconnect
14
+ self
15
+ end
16
+
17
+ def connected?
18
+ true
19
+ end
20
+
9
21
  def each(&block)
10
22
  Enumerator.new do |y|
11
23
  @buffers.each {|buf|
@@ -14,22 +14,28 @@ module AudioStream
14
14
  end
15
15
 
16
16
  def connect
17
- @inbuf = @dev.input_buffer(@soundinfo.window_size)
18
- @inbuf.start
19
- super
17
+ if !connected?
18
+ @inbuf = @dev.input_buffer(@soundinfo.window_size)
19
+ @inbuf.start
20
+ end
21
+ self
20
22
  end
21
23
 
22
24
  def disconnect
23
- if @inbuf
25
+ if connected?
24
26
  @inbuf.stop
25
27
  @inbuf = nil
26
28
  end
27
29
  super
28
30
  end
29
31
 
32
+ def connected?
33
+ !!@inbuf
34
+ end
35
+
30
36
  def each(&block)
31
37
  Enumerator.new do |y|
32
- if !@inbuf
38
+ if !connected?
33
39
  raise Error, "Device is not connected. You need to exec #{self.class.name}.connect: #{name}"
34
40
  end
35
41
 
@@ -10,25 +10,35 @@ module AudioStream
10
10
  end
11
11
 
12
12
  def connect
13
- @sound = RubyAudio::Sound.open(@path)
14
- super
13
+ if !connected?
14
+ @sound = RubyAudio::Sound.open(@path)
15
+ end
16
+ self
15
17
  end
16
18
 
17
19
  def disconnect
18
- if @sound && !@sound.closed?
20
+ if connected?
19
21
  @sound.close
20
22
  end
21
23
  super
22
24
  end
23
25
 
26
+ def connected?
27
+ @sound && !@sound.closed?
28
+ end
29
+
24
30
  def seek(frames, whence=IO::SEEK_SET)
31
+ if !connected?
32
+ raise Error, "File is not opened. You need to exec #{self.class.name}.connect: #{@path}"
33
+ end
34
+
25
35
  @sound.seek(frames, whence)
26
36
  self
27
37
  end
28
38
 
29
39
  def each(&block)
30
40
  Enumerator.new do |y|
31
- if !@sound || @sound.closed?
41
+ if !connected?
32
42
  raise Error, "File is not opened. You need to exec #{self.class.name}.connect: #{@path}"
33
43
  end
34
44
 
@@ -0,0 +1,17 @@
1
+ module AudioStream
2
+
3
+ class AudioNotification
4
+ STAT_NEXT = :next
5
+ STAT_COMPLETE = :complete
6
+
7
+ attr_reader :stat
8
+ attr_reader :input
9
+ attr_reader :caller_obj
10
+
11
+ def initialize(stat, input, caller_obj)
12
+ @stat = stat
13
+ @input = input
14
+ @caller_obj = caller_obj
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'observer'
2
+
3
+ module AudioStream
4
+
5
+ module AudioObservable
6
+ include Observable
7
+
8
+ def notify_next(input)
9
+ changed
10
+ notify_observers(AudioNotification.new(AudioNotification::STAT_NEXT, input, self))
11
+ end
12
+
13
+ def notify_complete
14
+ changed
15
+ notify_observers(AudioNotification.new(AudioNotification::STAT_COMPLETE, nil, self))
16
+ end
17
+
18
+ def fx(effector)
19
+ observer = AudioObservableFx.new(effector)
20
+ add_observer(observer)
21
+ observer
22
+ end
23
+
24
+ def send_to(bus, gain: nil, pan: nil)
25
+ bus.add(self, gain: gain, pan: pan)
26
+ self
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ module AudioStream
2
+
3
+ class AudioObservableFx
4
+ include AudioObserver
5
+ include AudioObservable
6
+
7
+ def initialize(effector)
8
+ @effector = effector
9
+ end
10
+
11
+ def on_next(input)
12
+ if Fx::BangProcess===input
13
+ @effector.process!(input)
14
+ output = input
15
+ else
16
+ output = @effector.process(input)
17
+ end
18
+ notify_next(output)
19
+ end
20
+
21
+ def on_complete
22
+ notify_complete
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module AudioStream
2
+
3
+ module AudioObserver
4
+ def update(notification)
5
+ case notification.stat
6
+ when AudioNotification::STAT_NEXT
7
+ on_next(notification.input)
8
+ when AudioNotification::STAT_COMPLETE
9
+ on_complete
10
+ end
11
+ end
12
+ end
13
+ end
@@ -23,9 +23,9 @@ module AudioStream
23
23
 
24
24
  case @channels
25
25
  when 1
26
- input = Fx::StereoToMono.new.process(input)
26
+ input = Fx::StereoToMono.instance.process(input)
27
27
  when 2
28
- input = Fx::MonoToStereo.new.process(input)
28
+ input = Fx::MonoToStereo.instance.process(input)
29
29
  end
30
30
 
31
31
  sint_a = input.to_a.flatten.map{|f| (f*0x7FFF).round}
@@ -25,7 +25,7 @@ module AudioStream
25
25
  }
26
26
  }
27
27
  when 2
28
- m2s = Fx::MonoToStereo.new
28
+ m2s = Fx::MonoToStereo.instance
29
29
  a = [
30
30
  m2s.process(self),
31
31
  m2s.process(other),
@@ -8,18 +8,20 @@ module AudioStream
8
8
  def connect
9
9
  @outputs.map(&:connect)
10
10
  @inputs.map(&:connect)
11
+ @inputs.map(&:publish)
11
12
 
12
13
  @sync_thread = Thread.start {
13
14
  catch :break do
14
15
  loop {
15
- @inputs.each {|t|
16
- t.sync.resume
16
+ @inputs.each {|input|
17
+ input.sync.resume
17
18
  }
18
19
 
19
- @inputs.each {|t|
20
- stat = t.sync.yield_wait
20
+ @inputs.each {|input|
21
+ stat = input.sync.yield_wait
21
22
  if stat==Sync::COMPLETED
22
- throw :break
23
+ @inputs.delete(input)
24
+ #throw :break
23
25
  end
24
26
  }
25
27
 
@@ -1,6 +1,7 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class HanningWindow
4
+ include Singleton
4
5
  include BangProcess
5
6
 
6
7
  def process!(input)
@@ -1,6 +1,8 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class MonoToStereo
4
+ include Singleton
5
+
4
6
  def process(input)
5
7
  case input.channels
6
8
  when 1
@@ -5,7 +5,7 @@ module AudioStream
5
5
 
6
6
  def initialize(threshold: 0.01)
7
7
  @threshold = threshold
8
- @window = HanningWindow.new
8
+ @window = HanningWindow.instance
9
9
  end
10
10
 
11
11
  def process!(input)
@@ -1,6 +1,8 @@
1
1
  module AudioStream
2
2
  module Fx
3
3
  class StereoToMono
4
+ include Singleton
5
+
4
6
  def process(input)
5
7
  case input.channels
6
8
  when 1
@@ -15,14 +15,14 @@ module AudioStream
15
15
 
16
16
  def initialize(soundinfo, window: nil)
17
17
  @samplerate = soundinfo.samplerate.to_f
18
- @window = window || HanningWindow.new
18
+ @window = window || HanningWindow.instance
19
19
  end
20
20
 
21
21
  def process(input)
22
22
  window_size = input.size
23
23
 
24
24
  # mono window
25
- input = StereoToMono.new.process(input)
25
+ input = StereoToMono.instance.process(input)
26
26
  @window.process!(input)
27
27
 
28
28
  gain = input.to_a.flatten.max
@@ -12,7 +12,7 @@ module AudioStream
12
12
  end
13
13
 
14
14
  def fft(window=nil)
15
- window ||= HanningWindow.new
15
+ window ||= HanningWindow.instance
16
16
 
17
17
  na = window.process(@input).to_na
18
18
  fft = FFTW3.fft(na, FFTW3::FORWARD) / na.length
@@ -1,3 +1,3 @@
1
1
  module AudioStream
2
- VERSION = "1.2.4"
2
+ VERSION = "1.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: 1.2.4
4
+ version: 1.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-07-22 00:00:00.000000000 Z
11
+ date: 2019-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,20 +94,6 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 1.0.2
97
- - !ruby/object:Gem::Dependency
98
- name: rx
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 0.0.3
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 0.0.3
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: rbplotly
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -152,12 +138,15 @@ files:
152
138
  - lib/audio_stream/audio_input_buffer.rb
153
139
  - lib/audio_stream/audio_input_device.rb
154
140
  - lib/audio_stream/audio_input_file.rb
141
+ - lib/audio_stream/audio_notification.rb
142
+ - lib/audio_stream/audio_observable.rb
143
+ - lib/audio_stream/audio_observable_fx.rb
144
+ - lib/audio_stream/audio_observer.rb
155
145
  - lib/audio_stream/audio_output.rb
156
146
  - lib/audio_stream/audio_output_device.rb
157
147
  - lib/audio_stream/audio_output_file.rb
158
148
  - lib/audio_stream/buffer.rb
159
149
  - lib/audio_stream/conductor.rb
160
- - lib/audio_stream/core_ext.rb
161
150
  - lib/audio_stream/error.rb
162
151
  - lib/audio_stream/fx.rb
163
152
  - lib/audio_stream/fx/a_gain.rb
@@ -1,13 +0,0 @@
1
- require 'audio_stream'
2
-
3
- module Rx::Observable
4
- def fx(effector)
5
- #map(&effector.:process)
6
- map(&effector.method(:process))
7
- end
8
-
9
- def send_to(bus, gain: nil, pan: nil)
10
- bus.add(self, gain: gain, pan: pan)
11
- self
12
- end
13
- end