diarize-ruby 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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