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>