3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Javascriptでマイクから生データを取り出す

Last updated at Posted at 2021-04-03

はじめに

マイクで取得したデータを、数値の配列にしたいだけなのに、苦労した話です。

調べるとScriptProcessorNodeを使ったものがいくつか出てきますが、非推奨っぽい。
AudioWorkletで代用してね、という話もあるが、これは扱いにくそう。
MediaRecorderからWav形式に変換できる方法もあるようだが、そこからうまいこと取り出すのも大変。
もっと簡単にできる方法があると思う。

結論

  1. MediaRecorderでMediaStreamからデータを取得し適当な音声ファイル形式に出力
  2. FileReaderにより音声ファイルをArrayBuffer形式に変換
  3. AudioContext.decodeAudioDataによりArrayBufferをAudioBuffer形式に変換
  4. AudioBufferからgetChannelDataなどにより生データの取得

※取得される値の詳細はAudioBufferを参照してください。WAV形式で保管される数値とは異なります。
※コードは後述

調べたこと

ScriptProcessorNode

次の方の記事に書いてあるような方法になります。

ただmozillaによると、本機能は廃止対象とのことです。なので長期使用を考える場合は、これを使わない方法が必要となります。

AudioWorklet

ScriptProcessorNodeの代替を調べると、AudioWorkletが出てきます。

次の方の記事が詳しいです。

む、難しいです。また、ファイル数が増えることや、実装行数が増えることもちょっといただけません。
私はただ、音声データの配列が欲しいだけなのです。

MediaRecorder

やはりこれで何とかしないと、とは思うのですが、うまく検索できませんでした。

Audio要素

Audio要素で再生するのは簡単ですね。
ふむ、ではここに格納されたデータを取得してうまいことできる方法は、と思ったのですが、見つけられませんでした。

decodeAudioData

音声ファイルをAudioBufferに変換するものだそうです。
音声ファイルはMediaRecorderで生成できるので、あとはAudioBufferから生データを取り出せれば、できます。

まとめ

手順は以下の通りです。

まず、MediaDevicesからMediaStreamを取得します。

let audioStream = null
navigator.mediaDevices.getUserMedia({audio: true}).then(stream => {
    audioStream = stream
})

次に、MediaRecorderを作成します。
そしてEventListenerでデータの取得・変換を行うようにします。

chunks = []

const mediaRecorder = new MediaRecorder(audioStream, {
    mimeType: 'audio/webm'
})
mediaRecorder.addEventListener('dataavailable', e => {
    if (e.data.size > 0) {
        chunks.push(e.data);
    }
})
mediaRecorder.addEventListener('stop', e => {
    const blob = new Blob(chunks)
    const reader = new FileReader()
    reader.readAsArrayBuffer(blob)
    reader.onload = () => {
        audioCtx.decodeAudioData(reader.result).then(buf => {
            const b = buf.getChannelData(0)
            console.log(b)
        })
    }
})

あとは適切なタイミングでMediaRecorderを開始・停止するだけでになります。

mediaRecorder.start()
// some process
mediaRecorder.stop()

完成コード

おまけ

そもそもなぜ必要だったかというと、

でマイクからの音声をデータとして扱えるようにするためです。
よかったら見てもらえると嬉しいです。

3
5
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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?