前提
録音した音声の周波数の最高値と最低値を取得して、自分の声の音程を取得したい。
WebAudioAPIの使い方が分からず、録音機能、録音した音声を解析する機能どちらも搭載することができませんでした。
フロントエンドはjavascript、バックエンドRuby on Railsで構成しています。
実現したいこと
- WebAudioAPIを使用して、録音機能を搭載したい。(ボタンを押すと録音を開始させる)
- 録音した音声の周波数の最高値と最低値を取得したい。(もう一度ボタンを押したタイミングで、録音を停止して、録音した音声の周波数の最高値と最低値を取得する)
発生している問題・エラーメッセージ
録音を停止した際にこのエラーが出てしまいます。
GoogleChrome検証画面
1Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
該当のソースコード
html
1<h1 class="heading">音階を測定する</h1> 2<button onclick="startRecording()">解析開始</button> 3<button onclick="endRecording()">解析終了</button>
javascript
1// クロスブラウザ定義 2navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; 3 4// 変数定義 5var localMediaStream = null; 6var localScriptProcessor = null; 7var audioContext = new AudioContext(); 8var bufferSize = 1024; 9var audioData = []; // 録音データ 10var recordingFlg = false; 11 12 13// 音声解析 14var audioAnalyser = null; 15 16 17// 録音バッファ作成(録音中自動で繰り返し呼び出される) 18var onAudioProcess = function(e) { 19 if (!recordingFlg) return; 20 21 // 音声のバッファを作成 22 var input = e.inputBuffer.getChannelData(0); 23 var bufferData = new Float32Array(bufferSize); 24 for (var i = 0; i < bufferSize; i++) { 25 bufferData[i] = input[i]; 26 } 27 audioData.push(bufferData);//録音データに追加 28 29 // オーディオデータ取得 30 var fsDivN = audioContext.sampleRate / audioAnalyser.fftSize; 31 var spectrums = new Uint8Array(audioAnalyser.frequencyBinCount); 32 audioAnalyser.getByteFrequencyData(spectrums); 33 34}; 35 36// 解析開始 37var startRecording = function() { 38 recordingFlg = true; 39 navigator.getUserMedia({audio: true}, function(stream) { 40 // 録音関連 41 localMediaStream = stream; 42 var scriptProcessor = audioContext.createScriptProcessor(bufferSize, 1, 1); 43 localScriptProcessor = scriptProcessor; 44 var mediastreamsource = audioContext.createMediaStreamSource(stream); 45 mediastreamsource.connect(scriptProcessor); 46 scriptProcessor.onaudioprocess = onAudioProcess; 47 scriptProcessor.connect(audioContext.destination); 48 49 // 音声解析関連 50 audioAnalyser = audioContext.createAnalyser(); 51 audioAnalyser.fftSize = 2048; 52 frequencyData = new Uint8Array(audioAnalyser.frequencyBinCount); 53 timeDomainData = new Uint8Array(audioAnalyser.frequencyBinCount); 54 mediastreamsource.connect(audioAnalyser); 55 56 }, 57 function(e) { 58 console.log(e); 59 }); 60}; 61 62// 解析終了 63var endRecording = function() { 64 recordingFlg = false; 65 //audioDataをサーバに送信するなど終了処理 66 // 録音した音声の周波数を取得 67 audioAnalyser.getFloatFrequencyData(); 68 // 録音した音声の周波数の最大値と最小値を出力 69 console.log(audioAnalyser.maxDecibels); 70 console.log(audioAnalyser.minDecibels); 71};
試したこと
録音機能を搭載して、その後の音声解析の際のコードであるaudioAnalyser.getFloatFrequencyData();の位置を変えてみたりしてみましたが、このコードが何を取得しているのいまいち分かっていません。
audioAnalyser.getFloatFrequencyData();の位置を変えたり、audioAnalyser.maxDecibelsの位置を変えたり、オーディオデータを取得する際のコードを変えることで、解決できるのではないかと考えています。
参考にしたwebサイト
getByteFrequencyData メソッド
現在の周波数データを渡されたunsigned byte配列にコピーします。 もし配列の要素数がfrequencyBinCountよりも小さい場合、はみ出した部分は削られます。 もし配列がfrequencyBinCountよりも大きい要素数を持つ場合、余分な要素は無視されます
arrayパラメータは周波数領域の解析結果の格納する場所を示します。
getByteTimeDomainData メソッド
現在の時間領域データ(波形データ)を渡されたunsigned byte配列にコピーします。 もし配列の要素数がfftSizeよりも小さい場合、はみ出た部分は削られます。 もし配列がfftSizeよりも大きな要素数を持つ場合、余分な要素は無視されます。
arrayパラメータは時間領域解析データを格納する場所を示します。
2. https://qiita.com/mhagita/items/6c7d73932d9a207eb94d
getUserMediaで音声を拾いリアルタイムで波形を出力する
3. https://qiita.com/soarflat/items/004cac51b818b9483764
Web Audio APIを利用してオーディオビジュアライザを作成する getByteFrequencyDataで取得する配列のどの要素がどの周波数(Hz)の波形データを格納しているか確認する
4. https://saitodev.co/search?q=web+audio+api
JavaScriptのWeb Audio APIで録音してみる
5. https://developer.mozilla.org/ja/docs/Web/API/AnalyserNode
.maxDecibels
unsigned byte 型値へ変換する FFT 分析データのスケーリング時の最大のパワー値を表す double 型の値である。一般的に、この値は、getByteFrequencyData()の使用時の結果の範囲の最大値として明記される。
.minDecibels
unsigned byte 型値へ変換する FFT 分析データのスケーリング時の最小のパワー値を表す double 型の値である。一般的に、この値は、getByteFrequencyData()の使用時の結果の範囲の最小値として明記される。
補足情報(FW/ツールのバージョンなど)
rails 5.1.6
あなたの回答
tips
プレビュー