asr_vosk: Allow to handle keyword and command in one sentence
[ros_wild_thumper.git] / scripts / asr_pocketsphinx.rb
1 #!/usr/bin/ruby
2
3 require 'gst'
4 require 'pry'
5 require 'logger'
6 require 'ros'
7 require 'std_msgs/String'
8
9 class Speak
10         def initialize(node)
11                 @logger = Logger.new(STDOUT)
12                 @publisher = node.advertise('asr_result', Std_msgs::String)
13                 @pipeline = Gst.parse_launch('alsasrc device="plughw:1,0" ! audio/x-raw,format=S16LE,channels=1,rate=16000 ! cutter leaky=true name=cutter'\
14                                              ' ! tee name=jsgf ! queue leaky=downstream ! valve name=valve_jsgf drop=true ! pocketsphinx name=asr_jsgf ! fakesink async=false jsgf.'\
15                                              ' ! pocketsphinx name=asr_kws ! fakesink async=false'\
16                                             )
17                 # Ignore everything below the configured volume
18                 cutter = @pipeline.get_by_name('cutter')
19                 cutter.set_property('threshold-dB', -20)
20                 cutter.set_property('pre-length', 100000000) # pocketsphinx needs about 0.1s before start
21                 cutter.set_property('run-length', 1300000000)
22
23                 asr_jsgf = @pipeline.get_by_name('asr_jsgf')
24                 asr_jsgf.set_property('hmm', 'pocketsphinx/adapt/cmusphinx-en-us-5.2')
25                 asr_jsgf.set_property('mllr', 'pocketsphinx/adapt/mllr_matrix')
26                 asr_jsgf.set_property('jsgf', 'data/robot.jsgf')
27
28                 asr_kws = @pipeline.get_by_name('asr_kws')
29                 asr_kws.set_property('hmm', 'pocketsphinx/adapt/cmusphinx-en-us-5.2')
30                 asr_kws.set_property('mllr', 'pocketsphinx/adapt/mllr_matrix')
31                 asr_kws.set_property('kws', 'data/keywords.kws')
32
33                 bus = @pipeline.bus()
34                 bus.add_watch do |bus, message|
35                         case message.type
36                         when Gst::MessageType::EOS
37                                 loop.quit
38                         when Gst::MessageType::ERROR
39                                 p message.parse_error
40                                 binding.pry # open console
41                                 loop.quit
42                         when Gst::MessageType::ELEMENT
43                                 if message.src.name == "asr_kws"
44                                         if message.structure.get_value(:final).value
45                                                 keyword_detect(message.structure.get_value(:hypothesis).value, message.structure.get_value(:confidence).value)
46                                         end
47                                 elsif message.src.name == "asr_jsgf"
48                                         if message.structure.get_value(:final).value
49                                                 final_result(message.structure.get_value(:hypothesis).value, message.structure.get_value(:confidence).value)
50                                         end
51                                 elsif message.src.name == "cutter"
52                                         if message.structure.get_value(:above).value
53                                                 @logger.debug "Start recording.."
54                                         else
55                                                 @logger.debug "Stop recording"
56                                         end
57                                 end
58                         end
59                         true
60                 end
61
62                 @pipeline.play
63         end
64
65         # Enables/Disables the jsgf pipeline branch
66         def enable_jsgf(bEnable)
67                 valve = @pipeline.get_by_name('valve_jsgf')
68                 valve.set_property("drop", !bEnable)
69         end
70
71         # Result of jsgf pipeline branch
72         def final_result(hyp, confidence)
73                 @logger.info "final: " + hyp + " " + confidence.to_s
74                 enable_jsgf(false)
75
76                 # Publish pocketsphinx result as ros message
77                 msg = Std_msgs::String.new
78                 msg.data = hyp
79                 @publisher.publish(msg)
80         end
81
82         def keyword_detect(hyp, confidence)
83                 @logger.debug "Got keyword: " + hyp
84                 enable_jsgf(true)
85         end
86
87         def stop
88                 @pipeline.stop
89         end
90 end
91
92 if __FILE__ == $0
93         node = ROS::Node.new('asr_pocketsphinx')
94         app = Speak.new(node)
95         loop = GLib::MainLoop.new(nil, false)
96         begin
97                 Thread.new {
98                         loop.run
99                 }
100                 node.spin
101         rescue Interrupt
102         ensure
103                 app.stop
104                 node.shutdown
105                 loop.quit
106         end
107 end