181 lines
6.7 KiB
Ruby
181 lines
6.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "ffi"
|
|
|
|
module Vosk
|
|
module C # :nodoc: all
|
|
extend FFI::Library
|
|
|
|
# FIXME: Load same way as in Python, test on Windows
|
|
# This second option, 'vosk', allows system-wide installed library to be loaded.
|
|
# I see you search /usr/share/vosk, so I guess it's supported somehow.
|
|
# It'll allow the gem to be used on systems not supported in pre-compiled releases.
|
|
# (in fact, we only need the first in a pre-compiled release and the second otherwise,
|
|
# but not worth the effort to put more configuration in the build stage - not possible without hacks)
|
|
# But when we load a lib not shipped with the gem itself, we (might) need to ensure it's a compatible version
|
|
# Note: options in the array are alternatives, only the first found is loaded
|
|
# Note: probably needs RubyInstaller::Runtime.add_dll_directory on Windows - if FFI::Platform.windows?
|
|
ffi_lib [File.join(__dir__, FFI.map_library_name("vosk")), "vosk"]
|
|
|
|
class VoskModel < FFI::AutoPointer
|
|
def self.from_native(ptr, _ctx)
|
|
raise Error, "Failed to create a model" if ptr.null?
|
|
|
|
super
|
|
end
|
|
|
|
def self.release(ptr)
|
|
C.vosk_model_free(ptr)
|
|
end
|
|
end
|
|
|
|
class VoskSpkModel < FFI::AutoPointer
|
|
def self.from_native(ptr, _ctx)
|
|
raise Error, "Failed to create a speaker model" if ptr.null?
|
|
|
|
super
|
|
end
|
|
|
|
def self.release(ptr)
|
|
C.vosk_spk_model_free(ptr)
|
|
end
|
|
end
|
|
|
|
VoskEndpointerMode = enum(
|
|
:VoskEndpointerMode,
|
|
[
|
|
:default, 0,
|
|
:short, 1,
|
|
:long, 2,
|
|
:very_long, 3,
|
|
],
|
|
)
|
|
|
|
class VoskRecognizer < FFI::AutoPointer
|
|
def self.from_native(ptr, _ctx)
|
|
raise Error, "Failed to create a recognizer" if ptr.null?
|
|
|
|
super
|
|
end
|
|
|
|
def self.release(ptr)
|
|
C.vosk_recognizer_free(ptr)
|
|
end
|
|
end
|
|
|
|
class VoskBatchModel < FFI::AutoPointer
|
|
def self.from_native(ptr, _ctx)
|
|
raise Error, "Failed to create a model" if ptr.null?
|
|
|
|
super
|
|
end
|
|
|
|
def self.release(ptr)
|
|
C.vosk_batch_model_free(ptr)
|
|
end
|
|
end
|
|
|
|
class VoskBatchRecognizer < FFI::AutoPointer
|
|
def self.from_native(ptr, _ctx)
|
|
raise Error, "Failed to create a recognizer" if ptr.null?
|
|
|
|
super
|
|
end
|
|
|
|
def self.release(ptr)
|
|
C.vosk_batch_recognizer_free(ptr)
|
|
end
|
|
end
|
|
|
|
class VoskTextProcessor < FFI::AutoPointer
|
|
def self.from_native(ptr, _ctx)
|
|
raise Error, "Failed to create processor" if ptr.null?
|
|
|
|
super
|
|
end
|
|
|
|
def self.release(ptr)
|
|
C.vosk_text_processor_free(ptr)
|
|
end
|
|
end
|
|
|
|
attach_function :vosk_model_new, [:string], VoskModel
|
|
attach_function :vosk_model_free, [VoskModel], :void
|
|
attach_function :vosk_model_find_word, [VoskModel, :string], :int
|
|
|
|
attach_function :vosk_spk_model_new, [:string], VoskSpkModel
|
|
attach_function :vosk_spk_model_free, [VoskSpkModel], :void
|
|
|
|
attach_function :vosk_recognizer_new, [VoskModel, :float], VoskRecognizer
|
|
attach_function :vosk_recognizer_new_spk, [VoskModel, :float, VoskSpkModel], VoskRecognizer
|
|
attach_function :vosk_recognizer_new_grm, [VoskModel, :float, :string], VoskRecognizer
|
|
attach_function :vosk_recognizer_set_spk_model, [VoskRecognizer, VoskSpkModel], :void
|
|
attach_function :vosk_recognizer_set_grm, [VoskRecognizer, :string], :void
|
|
attach_function :vosk_recognizer_set_max_alternatives, [VoskRecognizer, :int], :void
|
|
attach_function :vosk_recognizer_set_words, [VoskRecognizer, :int], :void
|
|
attach_function :vosk_recognizer_set_partial_words, [VoskRecognizer, :int], :void
|
|
attach_function :vosk_recognizer_set_nlsml, [VoskRecognizer, :int], :void
|
|
# TODO: remove this, it was needed only because I used libvosk from Python package
|
|
if Gem::Version.new(VERSION) >= Gem::Version.new("0.3.46")
|
|
attach_function :vosk_recognizer_set_endpointer_mode, [VoskRecognizer, VoskEndpointerMode], :void
|
|
attach_function :vosk_recognizer_set_endpointer_delays, [VoskRecognizer, :float, :float, :float], :void
|
|
end
|
|
attach_function :vosk_recognizer_accept_waveform, [VoskRecognizer, :buffer_in, :int], :int
|
|
# vosk_recognizer_accept_waveform_s; vosk_recognizer_accept_waveform_f - skipped
|
|
attach_function :vosk_recognizer_result, [VoskRecognizer], :string
|
|
attach_function :vosk_recognizer_partial_result, [VoskRecognizer], :string
|
|
attach_function :vosk_recognizer_final_result, [VoskRecognizer], :string
|
|
attach_function :vosk_recognizer_reset, [VoskRecognizer], :void
|
|
attach_function :vosk_recognizer_free, [VoskRecognizer], :void
|
|
|
|
attach_function :vosk_set_log_level, [:int], :void
|
|
attach_function :vosk_gpu_init, [], :void
|
|
attach_function :vosk_gpu_thread_init, [], :void
|
|
|
|
attach_function :vosk_batch_model_new, [:string], VoskBatchModel
|
|
attach_function :vosk_batch_model_free, [VoskBatchModel], :void
|
|
attach_function :vosk_batch_model_wait, [VoskBatchModel], :void
|
|
|
|
attach_function :vosk_batch_recognizer_new, [VoskBatchModel, :float], VoskBatchRecognizer
|
|
attach_function :vosk_batch_recognizer_free, [VoskBatchRecognizer], :void
|
|
attach_function :vosk_batch_recognizer_accept_waveform, [VoskBatchRecognizer, :buffer_in, :int], :void
|
|
# vosk_batch_recognizer_set_nlsml - skipped
|
|
attach_function :vosk_batch_recognizer_finish_stream, [VoskBatchRecognizer], :void
|
|
attach_function :vosk_batch_recognizer_front_result, [VoskBatchRecognizer], :string
|
|
attach_function :vosk_batch_recognizer_pop, [VoskBatchRecognizer], :void
|
|
attach_function :vosk_batch_recognizer_get_pending_chunks, [VoskBatchRecognizer], :int
|
|
|
|
# https://github.com/ffi/ffi/issues/467
|
|
class OwnedString
|
|
extend FFI::DataConverter
|
|
|
|
native_type :strptr
|
|
|
|
def self.to_native(_value, _context)
|
|
raise TypeError, "owned_string can't be used for input"
|
|
end
|
|
|
|
def self.from_native((str, ptr), _context)
|
|
C.free(ptr)
|
|
str
|
|
end
|
|
end
|
|
|
|
typedef OwnedString, :owned_string
|
|
attach_function :free, [:pointer], :void
|
|
|
|
# TODO: remove this, it was needed only because I used libvosk from Python package
|
|
if Gem::Version.new(VERSION) >= Gem::Version.new("0.3.48")
|
|
attach_function :vosk_text_processor_new, [:string, :string], VoskTextProcessor
|
|
attach_function :vosk_text_processor_free, [VoskTextProcessor], :void
|
|
# NOTE: you have a memory leak here in your python version, needs to be
|
|
# ptr = _c.vosk_text_processor_itn(self._handle, text.encode('utf-8'))
|
|
# str = _ffi.string(ptr).decode('utf-8')
|
|
# _ffi.gc(ptr, _c.free) # or call libc free directly
|
|
attach_function :vosk_text_processor_itn, [VoskTextProcessor, :string], :owned_string
|
|
end
|
|
end
|
|
|
|
private_constant :C
|
|
end
|