jQueryとhowler.jsを使ったサウンドビジュアライザーのサンプルコードの備忘録です。
音のスピードや音量調整も簡易的に付けています。
BGM
rate
1
2
3
volume
1
2
3
howler.jsを読み込みます。
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.1/howler.min.js" crossorigin="anonymous"></script>
JS
window.onload = () => {
this.drawTimer = null;
this.playButton = document.getElementById('js-play');
this.svg = document.getElementById('js-svg');
this.svgPath = this.svg.querySelector('path');
$(".btn_base").on("click",function(){
if($(this).attr("data")==="off"){
if(typeof bgm !== 'undefined'){
bgm.stop();
}
bgm = new Howl({
src: [$(this).attr("data-base")],
autoplay: false,
loop: true,
volume: 0.5
});
initAudioVisualizer();
bgm.load();
bgm.play();
drawAudioVisualizer();
$(".btn_base").attr("data","off");
$(this).attr("data","on");
}else if($(this).attr("data")==="on"){
bgm.stop();
$(this).attr("data","off");
}
});
$(".btn_tempo").on("click",function(){
//速度を変更する 0.5 〜 4.0
if(typeof bgm !== 'undefined'){
bgm.rate($(this).attr("data"));
}
});
$(".btn_vol").on("click",function(){
// ボリュームは 0.0 〜 1.0 の間で設定できる
if(typeof bgm !== 'undefined'){
bgm.volume($(this).attr("data"));
}
});
//Web Audio APIの設定 各ノードをつなぐ
function initAudioVisualizer(){
//音源を視覚化するために波形データの配列を取得する
this.analyserNode = Howler.ctx.createAnalyser();
this.freqs = new Uint8Array(this.analyserNode.frequencyBinCount);
//ボリュームコントローラ
Howler.ctx.createGain = Howler.ctx.createGain || Howler.ctx.createGainNode;
this.gainNode = Howler.ctx.createGain();
this.gainNode.gain.setValueAtTime(1, Howler.ctx.currentTime);
//各ノードをつなぐ
Howler.masterGain.connect(this.analyserNode);
this.analyserNode.connect(this.gainNode);
this.gainNode.connect(Howler.ctx.destination);
}
//オーディオビジュアライザーのSVGを描画
function drawAudioVisualizer(){
// 0~1 0に近い方が描画がスムーズになる
this.analyserNode.smoothingTimeConstant = 0.1;
// FFTサイズ
this.analyserNode.fftSize = 1024;
// 周波数領域の波形データを引数の配列に格納する
this.analyserNode.getByteFrequencyData(this.freqs);
//SVG横幅が波形データに対してどのくらいの長さになるか
const barWidth = this.svg.width.baseVal.value * 1.5 / this.analyserNode.frequencyBinCount;
//SVGのpathに適用
drawSvgPath(barWidth);
//毎フレームごとに描画
this.drawTimer = window.requestAnimationFrame(drawAudioVisualizer.bind(this));
}
//SVGパスを描画
function drawSvgPath(barWidth){
let d = 'M';
this.freqs.forEach((y, i) => {
const x = i * barWidth;
const value = this.freqs[i];
const percent = value / 255;
const yBase = i % 2 === 0 ? 1 : -1
const height = this.svg.height.baseVal.value/2 + (this.svg.height.baseVal.value/2 * percent * -1) * yBase * this.gainNode.gain.value;
d += `${x} ${height},`;
});
this.svgPath.setAttribute('d', d);
}
};
HTML
<div class="flex">
<div class="btn_base btn" data="off" data-base="/sound/demo/base/d001.wav">BGM</div>
<div class="t">rate</div>
<div class="btn_tempo demo_btn m" data="1">1</div>
<div class="btn_tempo demo_btn m" data="1.5">2</div>
<div class="btn_tempo demo_btn m" data="2">3</div>
<div class="t">volume</div>
<div class="btn_vol demo_btn m" data="0.1">1</div>
<div class="btn_vol demo_btn m" data="0.5">2</div>
<div class="btn_vol demo_btn m" data="1.0">3</div>
</div>
<div class="p-view">
<div class="p-view__box">
<svg class="p-view__svg" id="js-svg" xmlns="http://www.w3.org/2000/svg" width="600" height="400" viewBox="0 0 600 400" preserveAspectRatio="none">
<path d="M0,200 L600,200" stroke="#430" stroke-width="0.5" fill="none" />
</svg>
</div>
</div>