LoginSignup
6
6

More than 5 years have passed since last update.

テキスト読み上げサービスのAmazon Pollyをつかってテキストの音声ファイルをコマンドラインで入手し正規化する

Last updated at Posted at 2017-02-27

作っているアプリで多言語で、単語の音声読み上げが必要だったのでPollyを使うことにしました。
Pollyはテキストを指定すると多言語でテキストを読み上げたり、その音声ファイルを取得できたりします。

今回は以下の手順で最終的に音声ファイルを作成します。

  1. MacOSでの環境構築
  2. 1ファイルの変換
  3. 多数のファイルを同時に変換

MacOSでの環境構築

awscliなど各種導入します

brew install awscli
brew install sox  # 音声の正規化用
brew install vorbis-tools  # wavからoggに変換

1ファイルの変換

例えばHelloという単語を発音させたファイルをPollyから取得し、変換するには以下のようにします。

# PollyからHelloをPCMでローカルに出力
aws polly synthesize-speech \
  --output-format pcm --voice-id Salli --sample-rate 16000 \
  --text "Hello" \
  --region us-west-2 \
  Hello.raw

# Wavに変換。Pollyは音声が小さいので正規化もしています。
sox -r 16k -e signed -b 16 -c 1 Hello.raw Hello.wav norm

# Oggに変換
oggenc Hello.wav -o Hello.ogg

複数言語、複数テキストを効率的に変換

text.csvを作ってそれを、convert.rbで変換します。convert.rbの$awscli_profileは各自適切なものにします。

filename,jajp,enus,engb
Dog,いぬ,Dog,Dog
Cat,ねこ,Cat,Cat
require 'csv'
require 'fileutils'
require 'parallel'

$language_voice = {
    jajp: 'Mizuki',
    enus: 'Salli',
    engb: 'Emma',
}
$tmp_dir = 'tmp'
$out_dir = 'out'
$input_file = 'text.csv'
$awscli_profile = 'profile'

def convert(file, lang, text)
  tmp_dir_path = "#{$tmp_dir}/#{lang.to_s}"
  out_dir_path = "#{$out_dir}/#{lang.to_s}"
  [tmp_dir_path, out_dir_path].each do |dir|
    FileUtils::mkdir_p dir
  end

  voice = $language_voice[lang]
  command = "aws polly synthesize-speech \\
    --output-format pcm --voice-id #{voice}  --sample-rate 16000 \\
    --text '#{text}' \\
    --profile #{$awscli_profile} \\
    --region us-west-2 \\
    #{tmp_dir_path}/#{file}.raw"
  system(command)

  command = "sox -r 16k -e signed -b 16 -c 1 #{tmp_dir_path}/#{file}.raw #{tmp_dir_path}/#{file}.wav norm"
  system(command)

  command = "oggenc #{tmp_dir_path}/#{file}.wav -o #{out_dir_path}/#{file}.ogg"
  system(command)
end

csv = CSV.table($input_file)

[$tmp_dir, $out_dir].each do |dir|
  FileUtils.rm_rf dir
  FileUtils::mkdir_p dir
end

Parallel.each(csv.each_entry, in_processes: 20) do |row|
  filename = row[0]
  1.upto(row.size) do |i|
    next if row[i].nil?
    p "#{filename} #{row[i]} #{csv.headers[i]}"
    convert(filename, csv.headers[i], row[i])
  end
end

parallelは標準では、入っていないのでbundle installなどでいれておきます。
bundlerの場合は、bundle exec ruby convert.rbで実行するとout以下にファイルができます。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6