Audio Visualiser
by SQShu
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My_Audio_Visualiser_SSQ</title>
<link href="https://fonts.googleapis.com/css?family=Saira" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<div id="content">
<label for="thefile" class="file"> Choose an audio file
<input type="file" id="thefile" accept="audio/*" />
</label>
<audio id="audio" controls></audio>
<div id="container"></div>
<script id="vertex" type="x-shader/x-vertex">
void main() {
gl_Position = vec4(position, 1.0);
}
</script>
<script id="fragment" type="x-shader/x-vertex">
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_mouse;
#define M_PI 3.14159265358979323846
void main() {
vec2 uv = (gl_FragCoord.xy - u_resolution * 0.5) / u_resolution.yy;
vec2 st = u_mouse.xy/u_resolution.xy;
// Centerings 定位中心點
uv += vec2(1.3, 1.0);
// Create one circle 創建一個圓
float circle = distance(uv, vec2(0.5)) * (abs(sin(u_time))/2.0+0.5); // radius 控制半徑
float dm = abs(sin(u_time * M_PI)); // rate 控制跳動速率
// Create light 創建光效
vec3 light = vec3(0.5-tan(sin(circle*0.5+dm)), 0.5-acos(tan(circle*500.0+dm)), 0.0);
// Mix hue&rgb 混合顏色和色相
vec3 color1 = mix(light, vec3(8.0), 0.5-circle);
vec3 hue = mix(vec3(1.0, 1.0, 1.0), vec3(0.0, 0.0, 0.0), (st.y+abs(sin(u_time)))*0.5);
vec3 color2 = mix(color1, hue, abs(uv.x-0.1));
// Final shader 最後著色器渲染
gl_FragColor = vec4(color1*color2, 0.5);
}
</script>
</div>
<!-- partial -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js'></script>
<script src='https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.3/dat.gui.min.js'></script>
<script...
CSS
:root{
--bgColor : rgba(255,255,255,1);
--bgColorLight : hsla(242, 86%, 24%, 1);
--textColor : hsla(242, 86%, 88%, 1);
--textColorDark : hsla(242, 36%, 0%, 1);
--paperColor: hsla(242, 86%, 44%, 1);
--paperColorDark: hsla(242, 86%, 34%, 1);
--shadowColorFaint: hsla(0, 0%, 0%, 0.2);
}
::selected{
color: var(--textColorDark);
}
html, body{
margin: 0;
padding: 0;
overflow: hidden;
height: 100vh;
width: 100vw;
background: var(--bgColor);
background: linear-gradient(135deg, var(--bgColor), var(--bgColorLight));
color: var(--textColor);
font-family: 'Saira', sans-serif;
position: relative;
}
*{
box-sizing: border-box;
transition: all 0.12s cubic-bezier(0.42, 0.54, 0.22, 1.26);
}
#canvas {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
audio {
position: fixed;
left: 10px;
bottom: -10px;
width: calc(100% - 20px);
}
audio.active{
bottom: 10px;
}
#thefile{
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: 1;
}
label.file{
display: inline-block;
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
padding: 1rem 2rem;
border-radius: 4px;
background: var(--paperColor);
color: var(--textColor);
font-size: 1.25em;
font-weight: 700;
box-shadow: 0 20px 60px var(--shadowColorFaint);
cursor: pointer;
}
label.file:hover{
background: var(--paperColorDark);
transform: translate3d(-50%, -55%, 0);
}
label.file:active{
background: var(--paperColorDark);
transform: translate3d(-50%, -45%, 0);
}
label.file.normal{
transform: translate3d(10%, 50%, 0);
padding: 0.2rem 2rem;
font-size: 1rem;
top: 0;
left: 0;
}
JavaScript
/* 1.13 把著色器顏色寫入了three.js中,留存的問題是:改寫的著色器無法正常顯示
原因1: 著色器中存在沒有uniform的變量
*/
function vertexShader() {
return `
varying vec3 vUv;
void main() {
vUv = position;
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewPosition;
}
`
}
function fragmentShader() {
return `
uniform vec3 colorA;
uniform vec3 colorB;
uniform float u_time;
varying vec3 vUv;
void main() {
gl_FragColor = vec4(mix(colorA, colorB, vUv.x) * sin(u_time), 1.0);
}
`
}
//initialise simplex noise instance 創建一些簡單的噪音實例
var noise = new SimplexNoise();
// the main visualiser function 可視化的主函數
var vizInit = function() {
var file = document.getElementById("thefile"); // 接收上傳文件
var audio = document.getElementById("audio"); // 接收音頻
var fileLabel = document.querySelector("label.file"); // 接收文件標籤
// 加載&播放音頻
document.onload = function(e) {
console.log(e);
audio.play();
play();
} // 文件路徑更改
file.onchange = function() {
fileLabel.classList.add('normal');
audio.classList.add('active');
var files = this.files;
audio.src = URL.createObjectURL(files[0]);
audio.load();
audio.play();
play();
}
// 播放函數,創建analyser
function play() {
var context = new AudioContext(); // 創建新的音頻Context
var src = context.createMediaElementSource(audio); // 在context裡面創建src
var analyser = context.createAnalyser(); // 在context中創建anapyser
src.connect(analyser); // 連結analyser節點到src
analyser.connect(context.destination); // 連結destination節點到analyser
analyser.fftSize = 512; // 設置fftSize,我們會根據這個得到監聽的數據,
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
/* 從下面開始進入webgl three.js的部分 */
//here comes the webgl
var scene = new THREE.Scene(); // 創建場景
var group = new THREE.Group(); // 創建組
var clock = new THREE.Clock();
var camera = new...