今天來試試看利用Canvas來做聲音的視覺表現!
搭配Javascript web audio API
(其實是因為找不到好玩的點子)
主要是根據這個影片實作。
老樣子,先看成果!
看成果兩個呈現方式:(請自行搭配音樂XD)
長條型 | 放射狀 |
---|---|
在拆解code前,想先談一下Base 64格式
想看code的請跳過:
影片中有將音樂檔案轉成 Base 64的格式,(利用這個網站)
查了一下Base 64的好處:
- 提升網站速度,不用額外請求圖片/影片資源
- 可以加密,無法一眼看出內容(最常在某些網站看到XD)
壞處:(列舉部分)
- 無法緩存,下次用戶再訪問網站時無法加快載入
- SEO不友善 (無法反連結、或分享)
參見:Why "optimizing" your images with Base64 is almost always a bad idea
轉成base64後我的音樂code變成長長一串,
所以我還是直接引用了!
有其他base 64實作上的心得/建議也請分享~
檔案音樂我是在這邊抓的:https://pixabay.com/music/search/genre/beats/
也很適合拿來當影片用~
來看Code吧!
上JS code:
詳細可看影片!或可以參考中文的[基于Web Audio API实现音频可视化效果的方法](https://www.yisu.com/zixun/151229.html)
const container = document.getElementById('container');
const file = document.getElementById('fileupload'); //去讀取上傳檔案的DOM
//canvas起手式
const canvas = document.getElementById('canvas1');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
//這邊是我上的字
ctx.save();
ctx.font="32px 'Ubuntu', sans-serif";
ctx.fillStyle = 'white';
ctx.fillText('點擊畫面播放音樂', 30, 100);
ctx.fillText('或上傳新的檔案', 30, 150);
ctx.translate(canvas.width/2,canvas.width/2);
ctx.restore();
let audioSource;
let analyser;
//點擊之後開始解析音頻
container.addEventListener('click',function(){
const audio1 = document.getElementById('audio1');
audio1.src = '../../JSSound/club-fashion-house-2887.mp3'
const audioContext = new AudioContext();
audio1.play();
audioSource = audioContext.createMediaElementSource(audio1);//接收元素
analyser = audioContext.createAnalyser();//獲取音頻時間和頻率數據
audioSource.connect(analyser);
analyser.connect(audioContext.destination); //音頻最終輸出目標,通常是指最終端的電腦喇吧,連結才會聽到聲音
//下面三行是計算音頻節點的
//會創造出一個陣列
analyser.fftSize = 64;//快速傅立葉變換,決定音頻譜的密度
const bufferLength = analyser.frequencyBinCount; //fftSize的一半
const dataArray = new Uint8Array(bufferLength); //將每個字節視為0-255單個數字
//https://zh.javascript.info/arraybuffer-binary-arrays
const barWidth = (canvas.width/2) / bufferLength;
let barHeight;
let x;
function animate(){
x=0;
ctx.clearRect(0,0,canvas.width, canvas.height);
analyser.getByteFrequencyData(dataArray);
drawVisualiser(bufferLength,x, barWidth, barHeight, dataArray);
requestAnimationFrame(animate);
}
animate();
});
//這邊是上傳檔案用,跟上面的code差不多
file.addEventListener('change', function(){
const files = this.files;
const audio1 = document.getElementById('audio1');
audio1.src = URL.createObjectURL(files[0]);
audio1.load();
audio1.play();
audioSource = audioContext.createMediaElementSource(audio1);
analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.connect(audioContext.destination);
analyser.fftSize = 64;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const barWidth = canvas.width / bufferLength;
let barHeight;
let x;
function animate(){
x=0;
ctx.clearRect(0,0,canvas.width, canvas.height);
analyser.getByteFrequencyData(dataArray);
drawVisualiser(bufferLength,x, barWidth, barHeight, dataArray);
requestAnimationFrame(animate);
}
animate();
});
//畫圖用
function drawVisualiser(bufferLength,x, barWidth, barHeight, dataArray){
// 1.中心圓的版本
// for(let i = 0; i<bufferLength; i++){
// barHeight = dataArray[i];
// ctx.save(); //將當前狀態保存, 不保存的話下面的圖案都會跟著上一個的參數旋轉
// ctx.translate(canvas.width/2, canvas.height/2);
// ctx.rotate(i * Math.PI * 2 / bufferLength);
// const hue = i * 3 ;
// ctx.fillStyle = 'hsl('+hue+',100%, 50%)';
// ctx.fillRect(0, 0, barWidth, barHeight);
// ctx.restore(); //取出原來所保存狀態
// // save & restore說明:https://blog.csdn.net/tiankongcheng6/article/details/83000247
// }
//2. 柱狀的版本
//左側
for(let i = 0; i<bufferLength; i++){
barHeight = dataArray[i];
const red = i * barHeight/10;
const green = i*4;
const blue = barHeight/10;
ctx.fillStyle = 'rgb('+red+','+green+','+blue+')';
ctx.fillRect(canvas.width /2 - x, canvas.height - barHeight, barWidth, barHeight);
x += barWidth;
}
//右側
for(let i = 0; i<bufferLength; i++){
barHeight = dataArray[i];
const red = i * barHeight/10;
const green = i*20;
const blue = barHeight/10;
ctx.fillStyle = 'rgb('+red+','+green+','+blue+')';
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
x += barWidth;
}
}
Canvas可以玩的東西很多!音樂也是滿有趣的議題,
第一次玩JS audio API,
裡面有很多跟音訊相關的硬知識,
比圖像還複雜,算是初體驗吧!
有錯誤/想法歡迎留言~