Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
30
Help us understand the problem. What is going on with this article?
@progfay

webkitSpeechRecgnitionを扱う

More than 1 year has passed since last update.

はじめに

音声認識のためのインターフェイスである webkitSpeechRecognition を扱った際に得た知見をまとめました。本記事では、常にマイクから音声を聞きながら、声が発せられてから無音になるまでの間に話された言葉を文字列として取得する方法について述べていきます。

構造を理解する

まずは以下のコードを実行します。 onなんとか 系が多いので、どのようなタイミングで発火するのかを確認しましょう。

main.js
const rec = new webkitSpeechRecognition()
rec.continuous = false
rec.interimResults = false
rec.lang = 'ja-JP'

rec.onresult = e => {
  console.log('on result')

  for (var i = e.resultIndex; i < e.results.length; i++) {
    if (!e.results[i].isFinal) continue

    const { transcript } = e.results[i][0]
    console.log(`Recognised: ${transcript}`)
  }

  rec.stop()
}

rec.onstart = () => { console.log('on start') }
rec.onend = () => { console.log('on end') }

rec.onspeechstart = () => { console.log('on speech start') }
rec.onspeechend = () => { console.log('on speech end') }

rec.onosundstart = () => { console.log('on sound start') }
rec.onsoundend = () => { console.log('on sound end') }

rec.onaudiostart = () => { console.log('on audio start') }
rec.onaudioend = () => { console.log('on audio end') }

rec.start()

声を発した瞬間に on speech start と表示されましたので、 onspeechstart は声が発せられることがトリガーだと考えられます。その他についてもまとめてみましょう。

  • onstart
    • rec.start() がされた時
  • onend
    • rec.stop() がされた時
  • onspeechstart
    • 発声の始めを声が受け付けた時
  • onsoundstartonaudiostart
    • 不明
  • - onspeechendonsoundendonaudioendonresult
    • 発声が終了した時
    • 判別できなかったが、順序はいつも上記の順番

常に音声を取得し続ける

常に音声を取得し続けるためには発声が終了し、結果が出た後にまた rec.start() をする必要があります。

const rec = new webkitSpeechRecognition()
rec.continuous = false
rec.interimResults = false
rec.lang = 'ja-JP'

rec.onresult = e => {
  rec.stop()

  for (var i = e.resultIndex; i < e.results.length; i++) {
    if (!e.results[i].isFinal) continue

    const { transcript } = e.results[i][0]
    console.log(`Recognised: ${transcript}`)
  }
}

rec.onend = () => { rec.start() }

rec.start()

上記のコードのように、 rec.onendrec.start() することで終了後に開始することができます。 rec.stop() の位置をfor文の下にすると上手く動作しなかったため注意してください。

おまけ - audioデータも取得する

MediaRecorder を使って文字列とaudioデータの両方を取得しましょう。ここではaudioデータはbase64に変換しています。

main.js
const onSuccess = stream => {
  let base64 = ''
  let chunks = []

  const mediaRecorder = new MediaRecorder(stream)
  mediaRecorder.onstop = e => {
    const blob = new Blob(chunks, { type: 'audio/wav' })
    const reader = new window.FileReader()
    reader.readAsDataURL(blob)
    reader.onloadend = () => { base64 = reader.result }
    chunks = []
  }
  mediaRecorder.ondataavailable = e => { chunks.push(e.data) }

  const speechRecognition = new webkitSpeechRecognition()
  speechRecognition.continuous = false
  speechRecognition.interimResults = false
  speechRecognition.lang = 'ja-JP'

  speechRecognition.onresult = function (e) {
    speechRecognition.stop()
    for (let i = e.resultIndex; i < e.results.length; i++) {
      if (!e.results[i].isFinal) continue

      const { transcript } = e.results[i][0]
      console.log(`Recognized: ${transcript}`)
      console.log(`Base64: ${base64}`)
    }
  }

  speechRecognition.onspeechstart = () => { mediaRecorder.start() }
  speechRecognition.onaudioend = () => { mediaRecorder.stop() }
  speechRecognition.onend = () => { speechRecognition.start() }

  speechRecognition.start()
}

navigator.mediaDevices.getUserMedia({ audio: true })
  .then(onSuccess)

ブラウザに getUserMedia() が実装されていないことがあるので注意してください。また途中でエラーを吐くことがたまにあるため、原因がわかった方はコメント等で教えて頂けると幸いです。

おわりに

私はこの知見を初参加のハッカソン中に得ました。開発が始まって1時間しないうちにパソコンに向かって「おにぎり」と連呼してテストを行っていたので、周囲からは変な人と思われていたでしょう...。何はともあれハッカソンは無事終わりました。この記事によって知見が共有され、どこかで使われることがあるならばとても嬉しいです。

30
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
30
Help us understand the problem. What is going on with this article?