diarize-ruby 0.3.3 → 0.3.4

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
  SHA1:
3
- metadata.gz: 24c441a25ed2d6138eb4afe303016301d4abad6e
4
- data.tar.gz: cdb304d830b7e1c1fd1d561b200c3a52177a35e6
3
+ metadata.gz: ccd52691b1b5e219ccea4aaba625f30afc3f16db
4
+ data.tar.gz: d7d61fdae578b67ac0c9d2adec42c70fd51fb64d
5
5
  SHA512:
6
- metadata.gz: 071bff7fbba3e729b3edac28b8ed2a37153d8de4e7ba1f561c60490200b8ad0ae8f00cfca44e40a5adec4c4de19e9344c72358364b0e29475865868c1d5afc47
7
- data.tar.gz: 1398a7144d95c87d9dbbe66318ffe614e6871fd39f94904e1c5cc8bc07948bab170ddbf3881d166a6b6268dd519af6ab0b012ee374ace46e2d0561d6cb16702e
6
+ metadata.gz: af259a8ab28a1b6e0dccd9a0699262dd33032d1f21997f78d0762622ee1c714aa5df4affae9ff942e6a21583f9ef9a8d89f3f9127d1d149fd6d532a5d050a8bf
7
+ data.tar.gz: f688d8d78b3eb163d7a604cdb0dac05202841137d40c65c3ddcc016d8303bcbcd8fa1303eaec8a6459edd2a93fed39874cf73b6b60040f04cfb08786b818afec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [v0.3.4] - 2016-11-16
2
+
3
+ - Add diarize binary
4
+ - DRb server
5
+
1
6
  ## [v0.3.3] - 2016-11-14
2
7
 
3
8
  - Remove require for audio-playback
data/README.md CHANGED
@@ -1,17 +1,8 @@
1
1
  # diarize-ruby
2
2
 
3
- This library provides an easy-to-use toolkit for speaker segmentation (diarization) and identification from audio.
3
+ This library provides an easy-to-use toolkit for speaker segmentation (diarization) and identification from audio. It was adopted from [diarize-jruby](https://github.com/bbc/diarize-jruby), being used within the BBC R&D World Service.
4
4
 
5
- This library was adopted from [diarize-jruby](https://github.com/bbc/diarize-jruby), being used within the BBC R&D World Service.
6
-
7
- The main reason from deviating from the original library is to have a universal gem that works with either Ruby interpreter. It uses [Ruby Java Bridge](http://rjb.rubyforge.org) instead of [JRuby](http://jruby.org).
8
-
9
- Work to be done:
10
-
11
- * Universal gem that works on JRuby and various Ruby implementations (MRI) and versions
12
- * Use performant math packages tuned to either Ruby implementation
13
- * Add support for alternative diarization tools
14
- * Add CI tool
5
+ The main reason from deviating from the original is to provide support for Ruby MRI. It uses [Ruby Java Bridge](http://rjb.rubyforge.org) instead of [JRuby](http://jruby.org).
15
6
 
16
7
  ## Speaker Diarization
17
8
 
@@ -47,21 +38,65 @@ If you are using a different version of LIUM than what is bundled in the `bin` f
47
38
 
48
39
  ## Examples
49
40
 
50
- $ irb -I lib
51
- > require "diarize"
52
- > audio = Diarize::Audio.new URI.join('file:///', File.join(File.expand_path(File.dirname(__FILE__)), "test", "data", "will-and-juergen.wav"))
53
- > audio.analyze!
54
- > audio.segments
55
- > audio.speakers
56
- > audio.to_rdf
57
- > speakers = audio.speakers
58
- > speakers.first.gender
59
- > speakers.first.model.mean_log_likelihood
60
- > speakers.first.model.components.size
61
- > ...
62
- > speakers ||= other_speakers
63
- > Diarize::Speaker.match(speakers)
41
+ ### Get Segments and Speakers
42
+
43
+ From Ruby:
44
+
45
+ $ diarize console
46
+
47
+ ```ruby
48
+ audio = Diarize::Audio.new(URI.join('file:///', File.join(File.expand_path(File.dirname(__FILE__)), "test", "data", "will-and-juergen.wav")))
49
+
50
+ audio.analyze!
51
+ audio.segments
52
+ audio.speakers
53
+ audio.to_rdf
54
+ speakers = audio.speakers
55
+ speakers.first.gender
56
+ speakers.first.model.mean_log_likelihood
57
+ speakers.first.model.components.size
58
+ ...
59
+ speakers ||= other_speakers
60
+ Diarize::Speaker.match(speakers)
61
+ ```
62
+
63
+ From bash:
64
+
65
+ $ diarize audio speaker example.wav
66
+
67
+ ### Start Server
68
+
69
+ Some Java implementations (i.e. OpenJDK on Linux) are causing trouble running [Rjb](http://rjb.rubyforge.org) on threaded environments (e.g. [Celluloid](https://github.com/celluloid/celluloid), [Sidekick](https://github.com/mperham/sidekiq), [Shoryuken](https://github.com/phstc/shoryuken)) leading to instability. One workaround is to start diarize as server [DRb](http://ruby-doc.org/stdlib-2.0.0/libdoc/drb/rdoc/DRb.html) by a client proxy.
64
70
 
71
+ Start the diarizer in a separate process as a server:
72
+
73
+ $ diarize server -P 9999 -H localhost
74
+ Drb server
75
+ diarize-ruby 0.3.4
76
+ Listening on druby://localhost:9999, CTRL+C to stop
77
+
78
+ ### Client
79
+
80
+ From bash:
81
+
82
+ $ diarize remote audio segment example.wav
83
+
84
+ From Ruby:
85
+
86
+ ```ruby
87
+ require "diarize"
88
+ require "drb/drb"
89
+
90
+ server_uri = "druby://localhost:9999"
91
+ DRb.start_service
92
+ client = DRbObject.new_with_uri(server_uri)
93
+
94
+ audio_uri = URI.join('file:///', File.join(File.expand_path(File.dirname(__FILE__)), "test", "data", "will-and-juergen.wav"))
95
+ audio = client.new_audio(audio_uri)
96
+ audio.analyze!
97
+ audio.segments
98
+ ...
99
+ ```
65
100
 
66
101
  ## Running tests
67
102
 
@@ -103,6 +138,13 @@ is licensed under the GNU General Public License version 2. See
103
138
  http://lium3.univ-lemans.fr/diarization/doku.php/licence for more
104
139
  information.
105
140
 
141
+ ## TODOs
142
+
143
+ * Universal gem that works on JRuby and various Ruby implementations (MRI) and versions
144
+ * Use performant math packages tuned to either Ruby implementation
145
+ * Add support for alternative diarization tools
146
+ * Add CI tool
147
+
106
148
  ## Developer Resources
107
149
 
108
150
  * [Connecting Ruby to Java and vice versa](http://nofail.de/2010/04/ruby-in-java-java-in-ruby-jruby-or-ruby-java-bridge/)
data/bin/diarize ADDED
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env ruby
2
+ require "diarize"
3
+ require "gli"
4
+ require "uri"
5
+ require "drb/drb"
6
+ require "byebug"
7
+
8
+ include GLI::App
9
+
10
+ def uri_from_args(args)
11
+ url_or_file_name = args.first
12
+ uri = URI.parse(url_or_file_name)
13
+ if uri.scheme && uri.scheme.match(/^(http|https|file)$/)
14
+ uri = url_or_file_name
15
+ else
16
+ uri = if url_or_file_name[0] == "/"
17
+ URI.join('file:///', url_or_file_name)
18
+ else
19
+ URI.join('file:///', File.join(File.expand_path(Dir.pwd), url_or_file_name))
20
+ end
21
+ end
22
+ uri
23
+ end
24
+
25
+ def build_audio_from_args(args, options = {})
26
+ uri = uri_from_args(args)
27
+ $stdout.puts uri.to_s if options[:verbose]
28
+ audio = Diarize::Audio.new(uri)
29
+ audio.analyze!
30
+ audio
31
+ end
32
+
33
+ def build_remote_audio_from_args(args, options = {})
34
+ remote = client(options)
35
+ audio_uri = uri_from_args(args)
36
+
37
+ $stdout.puts uri.to_s if options[:verbose]
38
+ audio = remote.new_audio(audio_uri)
39
+ audio.analyze!
40
+ audio
41
+ rescue DRb::DRbConnError => ex
42
+ $stdout.puts 'Connection error, start server with "diarize server"'
43
+ end
44
+
45
+ def client(options = {})
46
+ uri = "druby://#{options[:host]}:#{options[:port]}"
47
+ DRb.start_service
48
+ DRbObject.new_with_uri(uri)
49
+ end
50
+
51
+ program_desc 'Diarize is an easy-to-use toolkit for speaker segmentation.'
52
+
53
+ version Diarize::VERSION
54
+
55
+ subcommand_option_handling :normal
56
+ arguments :strict
57
+
58
+ #-v, --verbose
59
+ desc 'Print more verbose output'
60
+ switch [:v, :verbose]
61
+
62
+ #-H, --host HOSTNAME
63
+ desc 'Host, e.g. "www.example.com"'
64
+ default_value 'localhost'
65
+ arg_name 'HOSTNAME'
66
+ flag [:H, :host]
67
+
68
+ #-P, --port PORT
69
+ desc 'Port number'
70
+ default_value 9999
71
+ arg_name 'PORT'
72
+ flag [:P, :port]
73
+
74
+ desc 'start console'
75
+ command [:c, :console] do |console|
76
+ console.action do |global_options, options, args|
77
+ require 'irb'
78
+
79
+ ARGV.clear
80
+ IRB.start
81
+ end
82
+ end
83
+
84
+ command [:r, :remote] do |remote|
85
+ remote.command [:a, :audio] do |audio|
86
+ audio.desc 'diarize remote audio segments FILENAME'
87
+ audio.arg_name 'FILENAME', :multiple
88
+ audio.command [:se, :segment, :segments] do |segments|
89
+ segments.action do |global_options, options, args|
90
+ audio = build_remote_audio_from_args(args, options.merge(global_options))
91
+ audio.segments.each do |segment|
92
+ $stdout.puts segment.uri
93
+ end if audio
94
+ end
95
+ end
96
+
97
+ audio.desc 'diarize remote audio speakers FILENAME'
98
+ audio.arg_name 'FILENAME', :multiple
99
+ audio.command [:sp, :speaker, :speakers] do |speakers|
100
+ speakers.action do |global_options, options, args|
101
+ audio = build_remote_audio_from_args(args, options.merge(global_options))
102
+ audio.speakers.each do |speaker|
103
+ $stdout.puts speaker.uri
104
+ end if audio
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ command [:a, :audio] do |audio|
111
+ audio.desc 'diarize audio segments FILENAME'
112
+ audio.arg_name 'FILENAME', :multiple
113
+ audio.command [:se, :segment, :segments] do |segments|
114
+ segments.action do |global_options, options, args|
115
+ audio = build_audio_from_args(args, global_options)
116
+ audio.segments.each do |segment|
117
+ $stdout.puts segment.uri
118
+ end
119
+ end
120
+ end
121
+
122
+ audio.desc 'diarize audio speakers FILENAME'
123
+ audio.arg_name 'FILENAME', :multiple
124
+ audio.command [:sp, :speaker, :speakers] do |speakers|
125
+ speakers.action do |global_options, options, args|
126
+ audio = build_audio_from_args(args, global_options)
127
+ audio.speakers.each do |speaker|
128
+ $stdout.puts speaker.uri
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ desc 'start server'
135
+ command [:s, :server] do |server|
136
+ server.action do |global_options, options, args|
137
+ merged_options = options.merge(global_options)
138
+ argv = merged_options.reject {|k, v| !k.is_a?(String)}
139
+ argv = argv.inject({}) {|r, h| r[h[0].length > 1 ? "--#{h[0]}" : "-#{h[0]}"] = h.last; r}
140
+ argv = argv.reject {|k, v| !v}
141
+ argv = argv.to_a.flatten
142
+
143
+ uri = "druby://#{merged_options[:host]}:#{merged_options[:port]}"
144
+ $stdout.puts "Drb server"
145
+ $stdout.puts "diarize-ruby #{Diarize::VERSION}"
146
+ $stdout.puts "Arguments: #{argv.inspect}" if global_options[:verbose]
147
+ $stdout.puts "Listening on #{uri}, CTRL+C to stop"
148
+ server = Diarize::Server.new
149
+ DRb.start_service(uri, server)
150
+ DRb.thread.join
151
+ end
152
+
153
+ #-H, --host HOSTNAME
154
+ server.desc 'Host, e.g. "www.example.com"'
155
+ server.default_value 'localhost'
156
+ server.arg_name 'HOSTNAME'
157
+ server.flag [:H, :host]
158
+
159
+ #-P, --port PORT
160
+ server.desc 'Port number'
161
+ server.default_value 9999
162
+ server.arg_name 'PORT'
163
+ server.flag [:P, :port]
164
+ end
165
+
166
+ pre do |global, command, options, args|
167
+ # Pre logic here
168
+ # Return true to proceed; false to abort and not call the
169
+ # chosen command
170
+ # Use skips_pre before a command to skip this block
171
+ # on that command only
172
+ true
173
+ end
174
+
175
+ post do |global,command,options,args|
176
+ # Post logic here
177
+ # Use skips_post before a command to skip this
178
+ # block on that command only
179
+ end
180
+
181
+ on_error do |exception|
182
+ # Error logic here
183
+ # return false to skip default error handling
184
+ true
185
+ end
186
+
187
+ begin
188
+ exit run(ARGV)
189
+ rescue
190
+ $stdout.puts "Bye."
191
+ end
data/diarize-ruby.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
19
  spec.bindir = 'bin'
20
- spec.executables = []
20
+ spec.executables = ["diarize"]
21
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
22
  spec.require_paths = ["lib"]
23
23
 
@@ -29,4 +29,6 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency "rjb", "~> 1.5"
30
30
  spec.add_dependency "to-rdf", "~> 0"
31
31
  spec.add_dependency "jblas-ruby", "~> 1.1"
32
+
33
+ spec.add_runtime_dependency('gli', '~> 2.13.0')
32
34
  end
data/lib/diarize.rb CHANGED
@@ -6,12 +6,19 @@ RJB_OPTIONS = ['-Xms16m', '-Xmx1024m']
6
6
  Rjb::load(RJB_LOAD_PATH, RJB_OPTIONS)
7
7
 
8
8
  require "matrix"
9
+
10
+ require "to_rdf"
11
+ require "uri"
12
+ require "open-uri"
13
+ require "digest/md5"
14
+
9
15
  require "diarize/version"
10
- require "diarize/lium"
11
16
  require "diarize/audio"
12
17
  require "diarize/segment"
18
+ require "diarize/speaker"
13
19
  require "diarize/segmentation"
14
20
  require "diarize/super_vector"
21
+ require "diarize/server"
15
22
 
16
23
  # Extenions to the {Ruby-Java Bridge}[http://rjb.rubyforge.org/] module that
17
24
  # adds a generic Java object wrapper class.
data/lib/diarize/audio.rb CHANGED
@@ -1,17 +1,5 @@
1
- require File.join(File.expand_path(File.dirname(__FILE__)), 'lium')
2
- require File.join(File.expand_path(File.dirname(__FILE__)), 'segmentation')
3
- require File.join(File.expand_path(File.dirname(__FILE__)), 'speaker')
4
-
5
- require 'rubygems'
6
- require 'to_rdf'
7
- require 'uri'
8
- require 'open-uri'
9
- require 'digest/md5'
10
-
11
1
  module Diarize
12
-
13
2
  class Audio
14
-
15
3
  attr_reader :path, :file, :uri
16
4
 
17
5
  def initialize(url_or_uri)
@@ -65,18 +53,18 @@ module Diarize
65
53
 
66
54
  def speakers
67
55
  return @speakers if @speakers
68
- @speakers = segments.map { |segment| segment.speaker }.uniq
56
+ @speakers = segments.map {|segment| segment.speaker}.uniq
69
57
  end
70
58
 
71
59
  def segments_by_speaker(speaker)
72
- segments.select { |segment| segment.speaker == speaker }
60
+ segments.select {|segment| segment.speaker == speaker}
73
61
  end
74
62
 
75
63
  def duration_by_speaker(speaker)
76
64
  return unless speaker
77
65
  segments = segments_by_speaker(speaker)
78
66
  duration = 0.0
79
- segments.each { |segment| duration += segment.duration }
67
+ segments.each {|segment| duration += segment.duration}
80
68
  duration
81
69
  end
82
70
 
@@ -191,6 +179,5 @@ module Diarize
191
179
  Rjb::JavaObjectWrapper.new(clusters)
192
180
  end
193
181
 
194
- end
195
-
182
+ end # Audio
196
183
  end
@@ -1,7 +1,3 @@
1
- require 'rubygems'
2
- require 'to_rdf'
3
- require 'uri'
4
-
5
1
  module Diarize
6
2
  class Segment
7
3
  include ToRdf
@@ -0,0 +1,9 @@
1
+ module Diarize
2
+ class Server
3
+
4
+ def new_audio(url_or_uri)
5
+ Audio.new(url_or_uri)
6
+ end
7
+
8
+ end
9
+ end
@@ -1,15 +1,7 @@
1
- require 'rubygems'
2
- require 'to_rdf'
3
- # require 'jblas'
4
-
5
1
  module Diarize
6
-
7
2
  class Speaker
8
-
9
- # include JBLAS
10
-
11
3
  @@log_likelihood_threshold = -33
12
- @@detection_threshold = 0.2
4
+ @@detection_threshold = 0.2
13
5
 
14
6
  @@speakers = {}
15
7
 
@@ -168,7 +160,5 @@ module Diarize
168
160
  Rjb::import('fr.lium.spkDiarization.libModel.ModelIO').writerGMMContainer(output, gmmlist.java_object)
169
161
  output.close
170
162
  end
171
-
172
- end
173
-
163
+ end # Speaker
174
164
  end
@@ -1,5 +1,4 @@
1
1
  module Diarize
2
-
3
2
  class SuperVector
4
3
  attr_reader :vector
5
4
 
@@ -72,6 +71,5 @@ module Diarize
72
71
  @vector.hash
73
72
  end
74
73
 
75
- end
76
-
74
+ end # SuperVector
77
75
  end
@@ -1,3 +1,3 @@
1
1
  module Diarize
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ class ServerTest < Test::Unit::TestCase
4
+
5
+ def test_new_audio_server_wrapper
6
+ server = Diarize::Server.new
7
+ audio = server.new_audio(URI('file:' + File.join(File.dirname(__FILE__), 'data', 'foo.wav')))
8
+ assert_equal Diarize::Audio, audio.class
9
+ end
10
+
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diarize-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yves Raimond
@@ -109,11 +109,26 @@ dependencies:
109
109
  - - "~>"
110
110
  - !ruby/object:Gem::Version
111
111
  version: '1.1'
112
+ - !ruby/object:Gem::Dependency
113
+ name: gli
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: 2.13.0
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: 2.13.0
112
126
  description: A library for Ruby wrapping the LIUM Speaker Diarization and including
113
127
  a few extra tools
114
128
  email:
115
129
  - jfesslmeier@gmail.com
116
- executables: []
130
+ executables:
131
+ - diarize
117
132
  extensions: []
118
133
  extra_rdoc_files: []
119
134
  files:
@@ -127,12 +142,13 @@ files:
127
142
  - README.md
128
143
  - Rakefile
129
144
  - bin/LIUM_SpkDiarization-4.2.jar
145
+ - bin/diarize
130
146
  - diarize-ruby.gemspec
131
147
  - lib/diarize.rb
132
148
  - lib/diarize/audio.rb
133
- - lib/diarize/lium.rb
134
149
  - lib/diarize/segment.rb
135
150
  - lib/diarize/segmentation.rb
151
+ - lib/diarize/server.rb
136
152
  - lib/diarize/speaker.rb
137
153
  - lib/diarize/super_vector.rb
138
154
  - lib/diarize/ubm.gmm
@@ -143,6 +159,7 @@ files:
143
159
  - test/data/will-and-juergen.wav
144
160
  - test/segment_test.rb
145
161
  - test/segmentation_test.rb
162
+ - test/server_test.rb
146
163
  - test/speaker_test.rb
147
164
  - test/super_vector_test.rb
148
165
  - test/test_helper.rb
@@ -177,6 +194,7 @@ test_files:
177
194
  - test/data/will-and-juergen.wav
178
195
  - test/segment_test.rb
179
196
  - test/segmentation_test.rb
197
+ - test/server_test.rb
180
198
  - test/speaker_test.rb
181
199
  - test/super_vector_test.rb
182
200
  - test/test_helper.rb
data/lib/diarize/lium.rb DELETED
@@ -1,5 +0,0 @@
1
- # require File.join(File.expand_path(File.dirname(__FILE__)), 'LIUM_SpkDiarization-4.2.jar')
2
-
3
- def fr
4
- Java::Fr
5
- end