voicevox.rb 0.1.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 +7 -0
- data/.rubocop.yml +21 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +19 -0
- data/LICENSE +21 -0
- data/README.md +46 -0
- data/Rakefile +7 -0
- data/Steepfile +29 -0
- data/examples/cli.rb +48 -0
- data/examples/outputs/.gitkeep +0 -0
- data/examples/repl_core.rb +48 -0
- data/examples/repl_wrapper.rb +33 -0
- data/lib/voicevox/core.rb +448 -0
- data/lib/voicevox/error.rb +79 -0
- data/lib/voicevox/version.rb +6 -0
- data/lib/voicevox/wrapper/audio_query.rb +213 -0
- data/lib/voicevox/wrapper/info.rb +113 -0
- data/lib/voicevox/wrapper/manager.rb +137 -0
- data/lib/voicevox/wrapper/utils.rb +45 -0
- data/lib/voicevox.rb +15 -0
- data/rbs_collection.lock.yaml +100 -0
- data/rbs_collection.yaml +15 -0
- data/sig/ffi.rbs +16 -0
- data/sig/voicevox/core.rbs +126 -0
- data/sig/voicevox/error.rbs +53 -0
- data/sig/voicevox/wrapper/info.rbs +26 -0
- data/sig/voicevox/wrapper/manager.rbs +31 -0
- data/sig/voicevox/wrapper/utils.rbs +9 -0
- data/sig/voicevox.rbs +3 -0
- data/voicevox.gemspec +42 -0
- metadata +88 -0
| @@ -0,0 +1,213 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require "json"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class Voicevox
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              # テキストからAudioQueryを生成します。
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # @param [String] text 生成するAudioQueryのテキスト。
         | 
| 9 | 
            +
              # @param [Voicevox::CharacterInfo, Voicevox::StyleInfo, Integer] speaker 話者、または話者のID。
         | 
| 10 | 
            +
              # @param [Boolean] kana textをAquesTalkライクな記法として解釈するかどうか。デフォルトはfalse。
         | 
| 11 | 
            +
              #
         | 
| 12 | 
            +
              # @return [Voicevox::AudioQuery] 生成されたAudioQuery。
         | 
| 13 | 
            +
              #
         | 
| 14 | 
            +
              # @see Voicevox#synthesis
         | 
| 15 | 
            +
              #
         | 
| 16 | 
            +
              def audio_query(text, speaker, kana: false)
         | 
| 17 | 
            +
                options = Voicevox::Core.voicevox_make_default_audio_query_options
         | 
| 18 | 
            +
                options[:kana] = kana
         | 
| 19 | 
            +
                speaker_id = speaker.is_a?(Integer) ? speaker : speaker.id
         | 
| 20 | 
            +
                load_model speaker_id
         | 
| 21 | 
            +
                return_ptr = FFI::MemoryPointer.new(:pointer)
         | 
| 22 | 
            +
                Voicevox.process_result Voicevox::Core.voicevox_audio_query(
         | 
| 23 | 
            +
                                          text,
         | 
| 24 | 
            +
                                          speaker_id,
         | 
| 25 | 
            +
                                          options,
         | 
| 26 | 
            +
                                          return_ptr
         | 
| 27 | 
            +
                                        )
         | 
| 28 | 
            +
                return_str_ptr = return_ptr.read_pointer
         | 
| 29 | 
            +
                json = return_str_ptr.read_string
         | 
| 30 | 
            +
                Voicevox::Core.voicevox_audio_query_json_free return_str_ptr
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                AudioQuery.new JSON.parse(json, symbolize_names: true)
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              #
         | 
| 36 | 
            +
              # AudioQueryから音声を生成します。
         | 
| 37 | 
            +
              #
         | 
| 38 | 
            +
              # @param [AudioQuery] query AudioQuery。
         | 
| 39 | 
            +
              # @param [Voicevox::CharacterInfo, Voicevox::StyleInfo, Integer] speaker 話者、または話者のID。
         | 
| 40 | 
            +
              # @param [Boolran] enable_interrogative_upspeak 疑問文の調整を有効にするかどうか。デフォルトはtrue。
         | 
| 41 | 
            +
              #
         | 
| 42 | 
            +
              # @return [String] 生成された音声のwavデータ。
         | 
| 43 | 
            +
              #
         | 
| 44 | 
            +
              def synthesis(query, speaker, enable_interrogative_upspeak: true)
         | 
| 45 | 
            +
                size_ptr = FFI::MemoryPointer.new(:int)
         | 
| 46 | 
            +
                return_ptr = FFI::MemoryPointer.new(:pointer)
         | 
| 47 | 
            +
                id = speaker.is_a?(Integer) ? speaker : speaker.id
         | 
| 48 | 
            +
                load_model id
         | 
| 49 | 
            +
                options = Voicevox::Core::VoicevoxSynthesisOptions.new
         | 
| 50 | 
            +
                options[:enable_interrogative_upspeak] = enable_interrogative_upspeak
         | 
| 51 | 
            +
                Voicevox.process_result(
         | 
| 52 | 
            +
                  Voicevox::Core.voicevox_synthesis(
         | 
| 53 | 
            +
                    query.to_json,
         | 
| 54 | 
            +
                    id,
         | 
| 55 | 
            +
                    options,
         | 
| 56 | 
            +
                    size_ptr,
         | 
| 57 | 
            +
                    return_ptr
         | 
| 58 | 
            +
                  )
         | 
| 59 | 
            +
                )
         | 
| 60 | 
            +
                data_ptr = return_ptr.read_pointer
         | 
| 61 | 
            +
                size_ptr.free
         | 
| 62 | 
            +
                data = data_ptr.read_string(size_ptr.read_int)
         | 
| 63 | 
            +
                Voicevox::Core.voicevox_wav_free(data_ptr)
         | 
| 64 | 
            +
                data
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              #
         | 
| 68 | 
            +
              # 音声合成用のクエリ。
         | 
| 69 | 
            +
              #
         | 
| 70 | 
            +
              class AudioQuery
         | 
| 71 | 
            +
                # @return [Array<AccentPhrase>] アクセント句のリスト。
         | 
| 72 | 
            +
                attr_accessor :accent_phrases
         | 
| 73 | 
            +
                # @return [Float] 全体の話速。
         | 
| 74 | 
            +
                attr_accessor :speed_scale
         | 
| 75 | 
            +
                # @return [Float] 全体の音高。
         | 
| 76 | 
            +
                attr_accessor :pitch_scale
         | 
| 77 | 
            +
                # @return [Float] 全体の抑揚。
         | 
| 78 | 
            +
                attr_accessor :intonation_scale
         | 
| 79 | 
            +
                # @return [Float] 全体の音量。
         | 
| 80 | 
            +
                attr_accessor :volume_scale
         | 
| 81 | 
            +
                # @return [Float] 音声の前の無音時間。
         | 
| 82 | 
            +
                attr_accessor :pre_phoneme_length
         | 
| 83 | 
            +
                # @return [Float] 音声の後の無音時間。
         | 
| 84 | 
            +
                attr_accessor :post_phoneme_length
         | 
| 85 | 
            +
                # @return [Integer] 音声データの出力サンプリングレート。
         | 
| 86 | 
            +
                attr_accessor :output_sampling_rate
         | 
| 87 | 
            +
                # @return [Boolean] 音声データをステレオ出力するか否か。
         | 
| 88 | 
            +
                attr_accessor :output_stereo
         | 
| 89 | 
            +
                # @return [String] AquesTalkライクな読み仮名。
         | 
| 90 | 
            +
                attr_reader :kana
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                def initialize(query)
         | 
| 93 | 
            +
                  @accent_phrases = query[:accent_phrases].map { |ap| AccentPhrase.new ap }
         | 
| 94 | 
            +
                  @speed_scale = query[:speed_scale]
         | 
| 95 | 
            +
                  @pitch_scale = query[:pitch_scale]
         | 
| 96 | 
            +
                  @intonation_scale = query[:intonation_scale]
         | 
| 97 | 
            +
                  @volume_scale = query[:volume_scale]
         | 
| 98 | 
            +
                  @pre_phoneme_length = query[:pre_phoneme_length]
         | 
| 99 | 
            +
                  @post_phoneme_length = query[:post_phoneme_length]
         | 
| 100 | 
            +
                  @output_sampling_rate = query[:output_sampling_rate]
         | 
| 101 | 
            +
                  @output_stereo = query[:output_stereo]
         | 
| 102 | 
            +
                  @kana = query[:kana]
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                #
         | 
| 106 | 
            +
                # AudioQueryをHashにします。
         | 
| 107 | 
            +
                #
         | 
| 108 | 
            +
                # @return [Hash]
         | 
| 109 | 
            +
                #
         | 
| 110 | 
            +
                def to_hash
         | 
| 111 | 
            +
                  {
         | 
| 112 | 
            +
                    accent_phrases: @accent_phrases.map(&:to_hash),
         | 
| 113 | 
            +
                    pitch_scale: @pitch_scale,
         | 
| 114 | 
            +
                    speed_scale: @speed_scale,
         | 
| 115 | 
            +
                    intonation_scale: @intonation_scale,
         | 
| 116 | 
            +
                    volume_scale: @volume_scale,
         | 
| 117 | 
            +
                    pre_phoneme_length: @pre_phoneme_length,
         | 
| 118 | 
            +
                    post_phoneme_length: @post_phoneme_length,
         | 
| 119 | 
            +
                    output_sampling_rate: @output_sampling_rate,
         | 
| 120 | 
            +
                    output_stereo: @output_stereo,
         | 
| 121 | 
            +
                    kana: @kana
         | 
| 122 | 
            +
                  }
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                #
         | 
| 126 | 
            +
                # AudioQueryをjsonにします。
         | 
| 127 | 
            +
                #
         | 
| 128 | 
            +
                # @return [String]
         | 
| 129 | 
            +
                #
         | 
| 130 | 
            +
                def to_json(...)
         | 
| 131 | 
            +
                  to_hash.to_json(...)
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
              end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              #
         | 
| 136 | 
            +
              # アクセント句ごとの情報。
         | 
| 137 | 
            +
              #
         | 
| 138 | 
            +
              class AccentPhrase
         | 
| 139 | 
            +
                # @return [Array<Mora>] モーラのリスト。
         | 
| 140 | 
            +
                attr_reader :moras
         | 
| 141 | 
            +
                # @return [Integer] アクセント箇所。
         | 
| 142 | 
            +
                attr_reader :accent
         | 
| 143 | 
            +
                # @return [Mora, nil] 後ろに無音を付けるかどうか。
         | 
| 144 | 
            +
                attr_reader :pause_mora
         | 
| 145 | 
            +
                # @return [Boolean] 疑問系かどうか。
         | 
| 146 | 
            +
                attr_reader :is_interrogative
         | 
| 147 | 
            +
                alias interrogative? is_interrogative
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                def initialize(query)
         | 
| 150 | 
            +
                  @moras = query[:moras].map { |ap| Mora.new ap }
         | 
| 151 | 
            +
                  @accent = query[:accent]
         | 
| 152 | 
            +
                  @pause_mora = query[:pause_mora] && Mora.new(query[:pause_mora])
         | 
| 153 | 
            +
                  @is_interrogative = query[:is_interrogative]
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                #
         | 
| 157 | 
            +
                # AccentPhraseをHashにします。
         | 
| 158 | 
            +
                #
         | 
| 159 | 
            +
                # @return [Hash]
         | 
| 160 | 
            +
                #
         | 
| 161 | 
            +
                def to_hash
         | 
| 162 | 
            +
                  {
         | 
| 163 | 
            +
                    moras: @moras.map(&:to_hash),
         | 
| 164 | 
            +
                    accent: @accent,
         | 
| 165 | 
            +
                    pause_mora: @pause_mora&.to_hash,
         | 
| 166 | 
            +
                    is_interrogative: @is_interrogative
         | 
| 167 | 
            +
                  }
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                #
         | 
| 171 | 
            +
                # モーラ(子音+母音)ごとの情報。
         | 
| 172 | 
            +
                #
         | 
| 173 | 
            +
                class Mora
         | 
| 174 | 
            +
                  # @return [String] 文字。
         | 
| 175 | 
            +
                  attr_reader :text
         | 
| 176 | 
            +
                  # @return [String] 子音の音素。
         | 
| 177 | 
            +
                  attr_reader :consonant
         | 
| 178 | 
            +
                  # @return [Float] 子音の音長。
         | 
| 179 | 
            +
                  attr_reader :consonant_length
         | 
| 180 | 
            +
                  # @return [String] 母音の音素。
         | 
| 181 | 
            +
                  attr_reader :vowel
         | 
| 182 | 
            +
                  # @return [Float] 母音の音長。
         | 
| 183 | 
            +
                  attr_reader :vowel_length
         | 
| 184 | 
            +
                  # @return [Float] 音高。
         | 
| 185 | 
            +
                  attr_reader :pitch
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                  def initialize(query)
         | 
| 188 | 
            +
                    @text = query[:text]
         | 
| 189 | 
            +
                    @consonant = query[:consonant]
         | 
| 190 | 
            +
                    @consonant_length = query[:consonant_length]
         | 
| 191 | 
            +
                    @vowel = query[:vowel]
         | 
| 192 | 
            +
                    @vowel_length = query[:vowel_length]
         | 
| 193 | 
            +
                    @pitch = query[:pitch]
         | 
| 194 | 
            +
                  end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                  #
         | 
| 197 | 
            +
                  # MoraをHashにします。
         | 
| 198 | 
            +
                  #
         | 
| 199 | 
            +
                  # @return [Hash]
         | 
| 200 | 
            +
                  #
         | 
| 201 | 
            +
                  def to_hash
         | 
| 202 | 
            +
                    {
         | 
| 203 | 
            +
                      text: @text,
         | 
| 204 | 
            +
                      consonant: @consonant,
         | 
| 205 | 
            +
                      consonant_length: @consonant_length,
         | 
| 206 | 
            +
                      vowel: @vowel,
         | 
| 207 | 
            +
                      vowel_length: @vowel_length,
         | 
| 208 | 
            +
                      pitch: @pitch
         | 
| 209 | 
            +
                    }
         | 
| 210 | 
            +
                  end
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
              end
         | 
| 213 | 
            +
            end
         | 
| @@ -0,0 +1,113 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "json"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class Voicevox
         | 
| 6 | 
            +
              # サポートされているデバイスを表すStruct。
         | 
| 7 | 
            +
              SupportedDevices = Struct.new(:cpu, :cuda, :dml, keyword_init: true)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              # キャラクターの情報を表すStruct。
         | 
| 10 | 
            +
              CharacterInfo =
         | 
| 11 | 
            +
                Struct.new(:name, :styles, :speaker_uuid, :version, keyword_init: true) do
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  # キャラクターの最初のスタイルのIDを返します。
         | 
| 14 | 
            +
                  # @note ほとんどの場合はノーマルになります。
         | 
| 15 | 
            +
                  #
         | 
| 16 | 
            +
                  # @return [Integer] スタイルのID。
         | 
| 17 | 
            +
                  #
         | 
| 18 | 
            +
                  def id
         | 
| 19 | 
            +
                    styles[0].id
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  # キャラクターのスタイルが全てロードされているかを返します。
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # @return [Boolean] 全てロードされている場合はtrue、そうでない場合はfalse。
         | 
| 26 | 
            +
                  #
         | 
| 27 | 
            +
                  def loaded?
         | 
| 28 | 
            +
                    styles.map(&:loaded?).all?
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  # キャラクターのスタイルを全てロードします。
         | 
| 33 | 
            +
                  #
         | 
| 34 | 
            +
                  # @return [void]
         | 
| 35 | 
            +
                  #
         | 
| 36 | 
            +
                  def load
         | 
| 37 | 
            +
                    Voicevox.initialize_required
         | 
| 38 | 
            +
                    styles.map(&:load)
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              StyleInfo =
         | 
| 42 | 
            +
                Struct.new(:name, :id, keyword_init: true) do
         | 
| 43 | 
            +
                  #
         | 
| 44 | 
            +
                  # スタイルがロードされているかを返します。
         | 
| 45 | 
            +
                  #
         | 
| 46 | 
            +
                  # @return [Boolean] ロードされている場合はtrue、そうでない場合はfalse。
         | 
| 47 | 
            +
                  #
         | 
| 48 | 
            +
                  def loaded?
         | 
| 49 | 
            +
                    Voicevox::Core.is_model_loaded(id)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  #
         | 
| 53 | 
            +
                  # スタイルをロードします。
         | 
| 54 | 
            +
                  #
         | 
| 55 | 
            +
                  # @return [void]
         | 
| 56 | 
            +
                  #
         | 
| 57 | 
            +
                  def load
         | 
| 58 | 
            +
                    Voicevox.initialize_required
         | 
| 59 | 
            +
                    Voicevox.process_result Voicevox::Core.voicevox_load_model(id)
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              class << self
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                # サポートしているデバイスを取得します。
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # @return [Voicevox::SupportedDevices] サポートしているデバイス。
         | 
| 68 | 
            +
                #
         | 
| 69 | 
            +
                def supported_devices
         | 
| 70 | 
            +
                  SupportedDevices.new(
         | 
| 71 | 
            +
                    **JSON.parse(Voicevox::Core.voicevox_get_supported_devices_json)
         | 
| 72 | 
            +
                  )
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                #
         | 
| 76 | 
            +
                # キャラクターの一覧を取得します。
         | 
| 77 | 
            +
                #
         | 
| 78 | 
            +
                # @return [Array<CharacterInfo>] キャラクターの一覧。
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                def characters
         | 
| 81 | 
            +
                  JSON
         | 
| 82 | 
            +
                    .parse(Voicevox::Core.voicevox_get_metas_json)
         | 
| 83 | 
            +
                    .map do |meta|
         | 
| 84 | 
            +
                      CharacterInfo.new(
         | 
| 85 | 
            +
                        **{
         | 
| 86 | 
            +
                          **meta,
         | 
| 87 | 
            +
                          "styles" => meta["styles"].map { |style| StyleInfo.new(**style) }
         | 
| 88 | 
            +
                        }
         | 
| 89 | 
            +
                      )
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                #
         | 
| 94 | 
            +
                # GPUをサポートしているかを返します。
         | 
| 95 | 
            +
                #
         | 
| 96 | 
            +
                # @note CUDA、またはDirectMLが使える場合にtrueを返します。
         | 
| 97 | 
            +
                #
         | 
| 98 | 
            +
                # @return [Boolean] GPUをサポートしているかどうか。
         | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                def gpu_supported?
         | 
| 101 | 
            +
                  Voicevox.supported_devices.cuda || Voicevox.supported_devices.dml
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                #
         | 
| 105 | 
            +
                # コアのバージョンを取得します。
         | 
| 106 | 
            +
                #
         | 
| 107 | 
            +
                # @return [String] コアのバージョン。
         | 
| 108 | 
            +
                #
         | 
| 109 | 
            +
                def core_version
         | 
| 110 | 
            +
                  Voicevox::Core.voicevox_get_version
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
            end
         | 
| @@ -0,0 +1,137 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "etc"
         | 
| 4 | 
            +
            require "objspace"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class Voicevox
         | 
| 7 | 
            +
              @initialized = false
         | 
| 8 | 
            +
              # @return [:cpu, :gpu] ハードウェアアクセラレーションモード。
         | 
| 9 | 
            +
              attr_reader :acceleration_mode
         | 
| 10 | 
            +
              # @return [Integer] スレッド数。
         | 
| 11 | 
            +
              attr_reader :cpu_num_threads
         | 
| 12 | 
            +
              # @return [Boolean] 起動時に全てのモデルを読み込むかどうか。
         | 
| 13 | 
            +
              attr_reader :load_all_models
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              #
         | 
| 16 | 
            +
              # GPUモードで動作しているかどうか。
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              # @return [Boolean] GPUモードで動作している場合はtrue、そうでない場合はfalse。
         | 
| 19 | 
            +
              #
         | 
| 20 | 
            +
              def gpu?
         | 
| 21 | 
            +
                @acceleration_mode == :gpu
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              #
         | 
| 25 | 
            +
              # CPUモードで動作しているかどうか。
         | 
| 26 | 
            +
              #
         | 
| 27 | 
            +
              # @return [Boolean] CPUモードで動作している場合はtrue、そうでない場合はfalse。
         | 
| 28 | 
            +
              #
         | 
| 29 | 
            +
              def cpu?
         | 
| 30 | 
            +
                @acceleration_mode == :cpu
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              #
         | 
| 34 | 
            +
              # Voicevoxのコアを初期化します。
         | 
| 35 | 
            +
              #
         | 
| 36 | 
            +
              # @param [String] openjtalk_dict_path OpenJTalkの辞書へのパス。
         | 
| 37 | 
            +
              # @param [:cpu, :gpu, :auto] acceleration_mode ハードウェアアクセラレーションモード。:autoを指定するとコア側で自動的に決定されます。
         | 
| 38 | 
            +
              # @param [Integer] cpu_num_threads スレッド数。省略する、または0を渡すとコア側で自動的に決定されます。
         | 
| 39 | 
            +
              # @param [Boolean] load_all_models 全てのモデルを読み込むかどうか。省略するとfalseになります。
         | 
| 40 | 
            +
              #
         | 
| 41 | 
            +
              def initialize(
         | 
| 42 | 
            +
                openjtalk_dict_path,
         | 
| 43 | 
            +
                acceleration_mode: :auto,
         | 
| 44 | 
            +
                cpu_num_threads: nil,
         | 
| 45 | 
            +
                load_all_models: false
         | 
| 46 | 
            +
              )
         | 
| 47 | 
            +
                acceleration_mode_enum =
         | 
| 48 | 
            +
                  {
         | 
| 49 | 
            +
                    auto: :voicevox_acceleration_mode_auto,
         | 
| 50 | 
            +
                    gpu: :voicevox_acceleration_mode_gpu,
         | 
| 51 | 
            +
                    cpu: :voicevox_acceleration_mode_cpu
         | 
| 52 | 
            +
                  }.fetch(acceleration_mode) do
         | 
| 53 | 
            +
                    raise ArgumentError, "無効なacceleration_mode: #{acceleration_mode}"
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                @cpu_num_threads = cpu_num_threads || 0
         | 
| 56 | 
            +
                @load_all_models = load_all_models
         | 
| 57 | 
            +
                @openjtalk_dict_path = openjtalk_dict_path
         | 
| 58 | 
            +
                options = Voicevox::Core.voicevox_make_default_initialize_options
         | 
| 59 | 
            +
                options[:acceleration_mode] = acceleration_mode_enum
         | 
| 60 | 
            +
                options[:cpu_num_threads] = @cpu_num_threads
         | 
| 61 | 
            +
                options[:load_all_models] = @load_all_models
         | 
| 62 | 
            +
                options[:openjtalk_dict_path] = FFI::MemoryPointer.from_string(
         | 
| 63 | 
            +
                  openjtalk_dict_path
         | 
| 64 | 
            +
                )
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                Voicevox.process_result Voicevox::Core.voicevox_initialize(options)
         | 
| 67 | 
            +
                @acceleration_mode = Voicevox::Core.voicevox_is_gpu_mode ? :gpu : :cpu
         | 
| 68 | 
            +
                at_exit { Voicevox::Core.voicevox_finalize } unless self.class.initialized
         | 
| 69 | 
            +
                self.class.initialized = true
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              #
         | 
| 73 | 
            +
              # Voicevoxのコアをファイナライズします。
         | 
| 74 | 
            +
              #
         | 
| 75 | 
            +
              def finalize
         | 
| 76 | 
            +
                Voicevox::Core.voicevox_finalize
         | 
| 77 | 
            +
                self.class.initialized = false
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              #
         | 
| 81 | 
            +
              # 話者のモデルを読み込みます。
         | 
| 82 | 
            +
              #
         | 
| 83 | 
            +
              # @param [Voicevox::CharacterInfo, Voicevox::StyleInfo, Integer] speaker 話者、または話者のID。
         | 
| 84 | 
            +
              #
         | 
| 85 | 
            +
              def load_model(speaker)
         | 
| 86 | 
            +
                id = speaker.is_a?(Integer) ? speaker : speaker.id
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                Voicevox.process_result Voicevox::Core.voicevox_load_model(id)
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              #
         | 
| 92 | 
            +
              # モデルが読み込まれているかどうかを返します。
         | 
| 93 | 
            +
              #
         | 
| 94 | 
            +
              # @param [Voicevox::CharacterInfo, Voicevox::StyleInfo, Integer] speaker 話者、または話者のID。
         | 
| 95 | 
            +
              #
         | 
| 96 | 
            +
              # @return [Boolean] 読み込まれているかどうか。
         | 
| 97 | 
            +
              #
         | 
| 98 | 
            +
              def model_loaded?(speaker)
         | 
| 99 | 
            +
                id = speaker.is_a?(Integer) ? speaker : speaker.id
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                Voicevox::Core.voicevox_is_model_loaded(id)
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
              #
         | 
| 105 | 
            +
              # voicevox_ttsを使って音声を生成します。
         | 
| 106 | 
            +
              #
         | 
| 107 | 
            +
              # @param [String] text 生成する音声のテキスト。
         | 
| 108 | 
            +
              # @param [Voicevox::CharacterInfo, Voicevox::StyleInfo, Integer] speaker 話者、または話者のID。
         | 
| 109 | 
            +
              # @param [Boolean] kana textをAquesTalkライクな記法として解釈するかどうか。デフォルトはfalse。
         | 
| 110 | 
            +
              # @param [Boolran] enable_interrogative_upspeak 疑問文の調整を有効にするかどうか。デフォルトはtrue。
         | 
| 111 | 
            +
              #
         | 
| 112 | 
            +
              # @return [String] 生成された音声のwavデータ。
         | 
| 113 | 
            +
              #
         | 
| 114 | 
            +
              def tts(text, speaker, kana: false, enable_interrogative_upspeak: true)
         | 
| 115 | 
            +
                size_ptr = FFI::MemoryPointer.new(:int)
         | 
| 116 | 
            +
                return_ptr = FFI::MemoryPointer.new(:pointer)
         | 
| 117 | 
            +
                id = speaker.is_a?(Integer) ? speaker : speaker.id
         | 
| 118 | 
            +
                load_model id
         | 
| 119 | 
            +
                options = Voicevox::Core.voicevox_make_default_tts_options
         | 
| 120 | 
            +
                options[:kana] = kana
         | 
| 121 | 
            +
                options[:enable_interrogative_upspeak] = enable_interrogative_upspeak
         | 
| 122 | 
            +
                Voicevox.process_result(
         | 
| 123 | 
            +
                  Voicevox::Core.voicevox_tts(text, id, options, size_ptr, return_ptr)
         | 
| 124 | 
            +
                )
         | 
| 125 | 
            +
                data_ptr = return_ptr.read_pointer
         | 
| 126 | 
            +
                data = data_ptr.read_string(size_ptr.read_int)
         | 
| 127 | 
            +
                size_ptr.free
         | 
| 128 | 
            +
                Voicevox::Core.voicevox_wav_free(data_ptr)
         | 
| 129 | 
            +
                data
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              class << self
         | 
| 133 | 
            +
                attr_accessor :initialized
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                alias initialized? initialized
         | 
| 136 | 
            +
              end
         | 
| 137 | 
            +
            end
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "etc"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class Voicevox
         | 
| 6 | 
            +
              class << self
         | 
| 7 | 
            +
                #
         | 
| 8 | 
            +
                # Voicevoxが初期化されていなかったらエラーを出す。
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                def initialize_required
         | 
| 11 | 
            +
                  raise Voicevox::Error, "Voicevoxが初期化されていません" unless Voicevox.initialized?
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # voicevox_result_codeに対応するエラーをraiseします。
         | 
| 16 | 
            +
                #
         | 
| 17 | 
            +
                # @param [Symbol] result voicevox_result_code。
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                def process_result(result)
         | 
| 20 | 
            +
                  return if result == :voicevox_result_succeed
         | 
| 21 | 
            +
                  raise "#{result}はSymbolではありません" unless result.is_a?(Symbol)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  raise Voicevox::CoreError.from_code(result)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                #
         | 
| 27 | 
            +
                # 製品版Voicevoxのパスを返します。
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                # @return [String] Voicevoxへの絶対パス。
         | 
| 30 | 
            +
                # @return [nil] Voicevoxが見付からなかった場合。zip版やLinux版ではnilを返します。
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                def voicevox_path
         | 
| 33 | 
            +
                  paths =
         | 
| 34 | 
            +
                    if Gem.win_platform?
         | 
| 35 | 
            +
                      [File.join(ENV.fetch("LOCALAPPDATA", ""), "Programs", "VOICEVOX")]
         | 
| 36 | 
            +
                    else
         | 
| 37 | 
            +
                      [
         | 
| 38 | 
            +
                        "/Applications/VOICEVOX",
         | 
| 39 | 
            +
                        "/Users/#{Etc.getlogin}/Library/Application Support/VOICEVOX"
         | 
| 40 | 
            +
                      ]
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  paths.find { |path| Dir.exist?(path) }
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
    
        data/lib/voicevox.rb
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative "voicevox/core"
         | 
| 4 | 
            +
            require_relative "voicevox/version"
         | 
| 5 | 
            +
            require_relative "voicevox/error"
         | 
| 6 | 
            +
            require_relative "voicevox/wrapper/utils"
         | 
| 7 | 
            +
            require_relative "voicevox/wrapper/info"
         | 
| 8 | 
            +
            require_relative "voicevox/wrapper/manager"
         | 
| 9 | 
            +
            require_relative "voicevox/wrapper/audio_query"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            #
         | 
| 12 | 
            +
            # voicevox_coreのラッパー。
         | 
| 13 | 
            +
            #
         | 
| 14 | 
            +
            class Voicevox # rubocop:disable Lint/EmptyClass
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            sources:
         | 
| 3 | 
            +
            - name: ruby/gem_rbs_collection
         | 
| 4 | 
            +
              remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 5 | 
            +
              revision: main
         | 
| 6 | 
            +
              repo_dir: gems
         | 
| 7 | 
            +
            path: ".gem_rbs_collection"
         | 
| 8 | 
            +
            gems:
         | 
| 9 | 
            +
            - name: activesupport
         | 
| 10 | 
            +
              version: '6.0'
         | 
| 11 | 
            +
              source:
         | 
| 12 | 
            +
                type: git
         | 
| 13 | 
            +
                name: ruby/gem_rbs_collection
         | 
| 14 | 
            +
                revision: e920cbaa517738b75f3b1e70223a0e51da80d5aa
         | 
| 15 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 16 | 
            +
                repo_dir: gems
         | 
| 17 | 
            +
            - name: ast
         | 
| 18 | 
            +
              version: '2.4'
         | 
| 19 | 
            +
              source:
         | 
| 20 | 
            +
                type: git
         | 
| 21 | 
            +
                name: ruby/gem_rbs_collection
         | 
| 22 | 
            +
                revision: e920cbaa517738b75f3b1e70223a0e51da80d5aa
         | 
| 23 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 24 | 
            +
                repo_dir: gems
         | 
| 25 | 
            +
            - name: i18n
         | 
| 26 | 
            +
              version: '1.10'
         | 
| 27 | 
            +
              source:
         | 
| 28 | 
            +
                type: git
         | 
| 29 | 
            +
                name: ruby/gem_rbs_collection
         | 
| 30 | 
            +
                revision: e920cbaa517738b75f3b1e70223a0e51da80d5aa
         | 
| 31 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 32 | 
            +
                repo_dir: gems
         | 
| 33 | 
            +
            - name: io-console
         | 
| 34 | 
            +
              version: '0'
         | 
| 35 | 
            +
              source:
         | 
| 36 | 
            +
                type: stdlib
         | 
| 37 | 
            +
            - name: json
         | 
| 38 | 
            +
              version: '0'
         | 
| 39 | 
            +
              source:
         | 
| 40 | 
            +
                type: stdlib
         | 
| 41 | 
            +
            - name: listen
         | 
| 42 | 
            +
              version: '3.2'
         | 
| 43 | 
            +
              source:
         | 
| 44 | 
            +
                type: git
         | 
| 45 | 
            +
                name: ruby/gem_rbs_collection
         | 
| 46 | 
            +
                revision: e920cbaa517738b75f3b1e70223a0e51da80d5aa
         | 
| 47 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 48 | 
            +
                repo_dir: gems
         | 
| 49 | 
            +
            - name: minitest
         | 
| 50 | 
            +
              version: '0'
         | 
| 51 | 
            +
              source:
         | 
| 52 | 
            +
                type: stdlib
         | 
| 53 | 
            +
            - name: parallel
         | 
| 54 | 
            +
              version: '1.20'
         | 
| 55 | 
            +
              source:
         | 
| 56 | 
            +
                type: git
         | 
| 57 | 
            +
                name: ruby/gem_rbs_collection
         | 
| 58 | 
            +
                revision: e920cbaa517738b75f3b1e70223a0e51da80d5aa
         | 
| 59 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 60 | 
            +
                repo_dir: gems
         | 
| 61 | 
            +
            - name: rainbow
         | 
| 62 | 
            +
              version: '3.0'
         | 
| 63 | 
            +
              source:
         | 
| 64 | 
            +
                type: git
         | 
| 65 | 
            +
                name: ruby/gem_rbs_collection
         | 
| 66 | 
            +
                revision: e920cbaa517738b75f3b1e70223a0e51da80d5aa
         | 
| 67 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 68 | 
            +
                repo_dir: gems
         | 
| 69 | 
            +
            - name: steep
         | 
| 70 | 
            +
              version: 1.1.1
         | 
| 71 | 
            +
              source:
         | 
| 72 | 
            +
                type: rubygems
         | 
| 73 | 
            +
            - name: monitor
         | 
| 74 | 
            +
              version: '0'
         | 
| 75 | 
            +
              source:
         | 
| 76 | 
            +
                type: stdlib
         | 
| 77 | 
            +
            - name: date
         | 
| 78 | 
            +
              version: '0'
         | 
| 79 | 
            +
              source:
         | 
| 80 | 
            +
                type: stdlib
         | 
| 81 | 
            +
            - name: singleton
         | 
| 82 | 
            +
              version: '0'
         | 
| 83 | 
            +
              source:
         | 
| 84 | 
            +
                type: stdlib
         | 
| 85 | 
            +
            - name: logger
         | 
| 86 | 
            +
              version: '0'
         | 
| 87 | 
            +
              source:
         | 
| 88 | 
            +
                type: stdlib
         | 
| 89 | 
            +
            - name: mutex_m
         | 
| 90 | 
            +
              version: '0'
         | 
| 91 | 
            +
              source:
         | 
| 92 | 
            +
                type: stdlib
         | 
| 93 | 
            +
            - name: time
         | 
| 94 | 
            +
              version: '0'
         | 
| 95 | 
            +
              source:
         | 
| 96 | 
            +
                type: stdlib
         | 
| 97 | 
            +
            - name: pathname
         | 
| 98 | 
            +
              version: '0'
         | 
| 99 | 
            +
              source:
         | 
| 100 | 
            +
                type: stdlib
         | 
    
        data/rbs_collection.yaml
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # Download sources
         | 
| 2 | 
            +
            sources:
         | 
| 3 | 
            +
              - name: ruby/gem_rbs_collection
         | 
| 4 | 
            +
                remote: https://github.com/ruby/gem_rbs_collection.git
         | 
| 5 | 
            +
                revision: main
         | 
| 6 | 
            +
                repo_dir: gems
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # A directory to install the downloaded RBSs
         | 
| 9 | 
            +
            path: .gem_rbs_collection
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            gems:
         | 
| 12 | 
            +
              # Skip loading rbs gem's RBS.
         | 
| 13 | 
            +
              # It's unnecessary if you don't use rbs as a library.
         | 
| 14 | 
            +
              - name: rbs
         | 
| 15 | 
            +
                ignore: true
         | 
    
        data/sig/ffi.rbs
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module FFI
         | 
| 2 | 
            +
              module Library
         | 
| 3 | 
            +
                def ffi_lib: (Array[String] | String) -> void
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def enum: (Symbol, Array[Symbol | Integer]) -> void
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def attach_function: (Symbol, Array[Symbol], Symbol) -> void
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              class Pointer
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              class MemoryPointer < Pointer
         | 
| 14 | 
            +
                def initialize: (Symbol `type`) -> void
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         |