MDN の AnalyserNode のサンプルコードは入力の部分が省略されていたため、マイクから音を拾うようにして動かしました。
埋め込みだとマイクがうまく動かないので、動作確認は CodePen を開いてください。
【追記1】 同時に getByteFrequencyData
による周波数分析を行うサンプルを作成しました。
【追記2】Chrome の仕様変更に対応しました。
概要
MDN に AnalyserNode のサンプルコードが掲載されています。
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();
...
analyser.fftSize = 2048;
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);
(略)
Voice-change-O-matic デモからの引用だと記載されていますが、残念ながらそのデモは使い方が分かりませんでした。
【追記】 MDN 日本語版の情報が古いようです。英語版からリンクされている https の方は動きました。
そこで ...
の部分を補って動くコードにします。
【追記】 少し違う API ですが、英語版に完全な形でのサンプルがありました。MP3 を読み込む仕様です。
追加箇所
Canvas とボタンとエラーメッセージ用の span を用意します。
<canvas id="canvas" width="500" height="200" style="border:1px solid #000000;"></canvas><br>
<button id="startButton">Start</button>
<span id="errorMessage"></span>
Canvas 関係の変数と、ボタンをクリックするとマイクから入力を開始するコードを補います。
let canvasCtx = canvas.getContext("2d");
let WIDTH = canvas.width;
let HEIGHT = canvas.height;
let stream;
startButton.onclick = async function () {
if (stream) return;
try {
await audioCtx.resume();
stream = await navigator.mediaDevices.getUserMedia({
audio: true
});
audioCtx.createMediaStreamSource(stream).connect(analyser);
} catch (err) {
errorMessage.textContent = err.toString();
}
};
これでとりあえず動くようになりました。
参考
同じ MDN を参照している記事を参考にしました。
API の変更に伴い、以下の個所を修正する必要がありました。
//様々なブラウザでマイクへのアクセス権を取得する
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
【参考】 「MediaDevices.getUserMedia() 」について
以下の個所で別の API を呼んでいるため、表示される波形が別の形になります。
analyser.getByteFrequencyData(data);
描画の度にバッファを確保していたため、メモリ使用量がどんどん増加しました。
var bufLen = analyser.frequencyBinCount;
var data = new Uint8Array(bufLen);
マイクからの入力がそのまま出力に接続されているため、自分の声がそのまま再生されてハウリングの原因になっていました。
analyser.connect(audioCtx.destination);
この部分を外しても動作しました。
1つのAnalyzerNodeは必ず1つの入力と出力を持ちます。出力先がなくてもAnalyzerNodeは問題ありません。
Chrome 71 以降での仕様変更により、事前に作った AudioContext
に対してユーザー操作後に resume()
が必須になりました。
await audioCtx.resume();
色々と書きましたが、まず動くコードが欲しかったので、非常に助かりました。
Python
今回はブラウザで JavaScript を使いましたが、方法を調査しているときに Python を使った記事を見掛けたので、メモしておきます。