Skip to content

Commit 6a4654e

Browse files
authoredOct 29, 2024··
Merge pull request #550 from AnubhabMukherjee2003/web-dev-mini
Audio Visualization with three.js
2 parents 5914d03 + 7dab069 commit 6a4654e

File tree

7 files changed

+343
-0
lines changed

7 files changed

+343
-0
lines changed
 
1.15 MB
Loading
339 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE html>
2+
<html lang="en" >
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Audio Visualizer based on Three.js</title>
6+
<link href="https://fonts.googleapis.com/css?family=Saira" rel="stylesheet"><link rel="stylesheet" href="./style.css">
7+
8+
</head>
9+
<body>
10+
<div id="content">
11+
12+
<label for="thefile" class="file"> Choose an audio file
13+
<input type="file" id="thefile" accept="audio/*" />
14+
</label>
15+
16+
<audio id="audio" controls></audio>
17+
<div id="out"></div>
18+
</div>
19+
<!-- partial -->
20+
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js'></script>
21+
<script src='https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js'></script>
22+
<script src='https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.3/dat.gui.min.js'></script>
23+
<script src='https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.3.0/simplex-noise.min.js'></script>
24+
<script src="./script.js"></script>
25+
26+
</body>
27+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Audio Visualization with three.js
2+
3+
This project demonstrates audio visualization using the powerful 3D graphics library, three.js. The visualization reacts to audio input, creating a dynamic and engaging visual experience.
4+
5+
![Audio Visualization](a.png)
6+
Here is the look!
7+
## Table of Contents
8+
- [Introduction](#introduction)
9+
- [Features](#features)
10+
- [Installation](#installation)
11+
- [Usage](#usage)
12+
- [Files](#files)
13+
14+
15+
## Introduction
16+
Audio Visualization with three.js is a mini-project aimed at showcasing the capabilities of three.js in creating interactive and visually appealing audio visualizations.
17+
18+
## Features
19+
- Real-time audio analysis
20+
- Dynamic 3D visualizations
21+
- Interactive controls
22+
23+
## Installation
24+
To get started, clone the repository and open the `index.html` file in your browser.
25+
26+
```bash
27+
git clone https://github.com/Ayushparikh-code/Web-dev-mini-projects.git
28+
cd Web-dev-mini-projects/audio-visualization-threejs
29+
```
30+
31+
## Usage
32+
1. Open `index.html` in your preferred web browser.
33+
2. Play an audio file to see the visualization in action.
34+
![Another Visualization](b.png)
35+
## Files
36+
- `index.html`: The main HTML file.
37+
- `style.css`: The CSS file for styling.
38+
- `script.js`: The JavaScript file containing the three.js logic.
39+
40+
+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
var noise = new SimplexNoise();
2+
var vizInit = function (){
3+
4+
var file = document.getElementById("thefile");
5+
var audio = document.getElementById("audio");
6+
var fileLabel = document.querySelector("label.file");
7+
8+
document.onload = function(e){
9+
console.log(e);
10+
audio.play();
11+
play();
12+
}
13+
file.onchange = function(){
14+
fileLabel.classList.add('normal');
15+
audio.classList.add('active');
16+
var files = this.files;
17+
18+
audio.src = URL.createObjectURL(files[0]);
19+
audio.load();
20+
audio.play();
21+
play();
22+
}
23+
24+
function play() {
25+
var context = new AudioContext();
26+
var src = context.createMediaElementSource(audio);
27+
var analyser = context.createAnalyser();
28+
src.connect(analyser);
29+
analyser.connect(context.destination);
30+
analyser.fftSize = 512;
31+
var bufferLength = analyser.frequencyBinCount;
32+
var dataArray = new Uint8Array(bufferLength);
33+
var scene = new THREE.Scene();
34+
var group = new THREE.Group();
35+
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
36+
camera.position.set(0,0,100);
37+
camera.lookAt(scene.position);
38+
scene.add(camera);
39+
40+
var renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
41+
renderer.setSize(window.innerWidth, window.innerHeight);
42+
43+
var planeGeometry = new THREE.PlaneGeometry(800, 800, 20, 20);
44+
var planeMaterial = new THREE.MeshLambertMaterial({
45+
color: 0x6904ce,
46+
side: THREE.DoubleSide,
47+
wireframe: true
48+
});
49+
50+
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
51+
plane.rotation.x = -0.5 * Math.PI;
52+
plane.position.set(0, 30, 0);
53+
group.add(plane);
54+
55+
var plane2 = new THREE.Mesh(planeGeometry, planeMaterial);
56+
plane2.rotation.x = -0.5 * Math.PI;
57+
plane2.position.set(0, -30, 0);
58+
group.add(plane2);
59+
60+
var icosahedronGeometry = new THREE.IcosahedronGeometry(10, 4);
61+
var lambertMaterial = new THREE.MeshLambertMaterial({
62+
color: 0xff00ee,
63+
wireframe: true
64+
});
65+
66+
var ball = new THREE.Mesh(icosahedronGeometry, lambertMaterial);
67+
ball.position.set(0, 0, 0);
68+
group.add(ball);
69+
70+
var ambientLight = new THREE.AmbientLight(0xaaaaaa);
71+
scene.add(ambientLight);
72+
73+
var spotLight = new THREE.SpotLight(0xffffff);
74+
spotLight.intensity = 0.9;
75+
spotLight.position.set(-10, 40, 20);
76+
spotLight.lookAt(ball);
77+
spotLight.castShadow = true;
78+
scene.add(spotLight);
79+
80+
scene.add(group);
81+
82+
document.getElementById('out').appendChild(renderer.domElement);
83+
84+
window.addEventListener('resize', onWindowResize, false);
85+
86+
render();
87+
88+
function render() {
89+
analyser.getByteFrequencyData(dataArray);
90+
91+
var lowerHalfArray = dataArray.slice(0, (dataArray.length/2) - 1);
92+
var upperHalfArray = dataArray.slice((dataArray.length/2) - 1, dataArray.length - 1);
93+
94+
var overallAvg = avg(dataArray);
95+
var lowerMax = max(lowerHalfArray);
96+
var lowerAvg = avg(lowerHalfArray);
97+
var upperMax = max(upperHalfArray);
98+
var upperAvg = avg(upperHalfArray);
99+
100+
var lowerMaxFr = lowerMax / lowerHalfArray.length;
101+
var lowerAvgFr = lowerAvg / lowerHalfArray.length;
102+
var upperMaxFr = upperMax / upperHalfArray.length;
103+
var upperAvgFr = upperAvg / upperHalfArray.length;
104+
105+
makeRoughGround(plane, modulate(upperAvgFr, 0, 1, 0.5, 4));
106+
makeRoughGround(plane2, modulate(lowerMaxFr, 0, 1, 0.5, 4));
107+
108+
makeRoughBall(ball, modulate(Math.pow(lowerMaxFr, 0.8), 0, 1, 0, 8), modulate(upperAvgFr, 0, 1, 0, 4));
109+
110+
group.rotation.y += 0.005;
111+
renderer.render(scene, camera);
112+
requestAnimationFrame(render);
113+
}
114+
115+
function onWindowResize() {
116+
camera.aspect = window.innerWidth / window.innerHeight;
117+
camera.updateProjectionMatrix();
118+
renderer.setSize(window.innerWidth, window.innerHeight);
119+
}
120+
121+
function makeRoughBall(mesh, bassFr, treFr) {
122+
mesh.geometry.vertices.forEach(function (vertex) {
123+
var offset = mesh.geometry.parameters.radius;
124+
var amp = 7;
125+
var time = window.performance.now();
126+
vertex.normalize();
127+
var rf = 0.00001;
128+
var distance = (offset + bassFr ) + noise.noise3D(vertex.x + time *rf*7, vertex.y + time*rf*8, vertex.z + time*rf*9) * amp * treFr;
129+
vertex.multiplyScalar(distance);
130+
});
131+
mesh.geometry.verticesNeedUpdate = true;
132+
mesh.geometry.normalsNeedUpdate = true;
133+
mesh.geometry.computeVertexNormals();
134+
mesh.geometry.computeFaceNormals();
135+
}
136+
137+
function makeRoughGround(mesh, distortionFr) {
138+
mesh.geometry.vertices.forEach(function (vertex) {
139+
var amp = 2;
140+
var time = Date.now();
141+
var distance = (noise.noise2D(vertex.x + time * 0.0003, vertex.y + time * 0.0001) + 0) * distortionFr * amp;
142+
vertex.z = distance;
143+
});
144+
mesh.geometry.verticesNeedUpdate = true;
145+
mesh.geometry.normalsNeedUpdate = true;
146+
mesh.geometry.computeVertexNormals();
147+
mesh.geometry.computeFaceNormals();
148+
}
149+
150+
audio.play();
151+
}
152+
}
153+
154+
window.onload = vizInit();
155+
156+
document.body.addEventListener('touchend', function() { context.resume(); });
157+
158+
159+
160+
161+
162+
function fractionate(val, minVal, maxVal) {
163+
return (val - minVal)/(maxVal - minVal);
164+
}
165+
166+
function modulate(val, minVal, maxVal, outMin, outMax) {
167+
var fr = fractionate(val, minVal, maxVal);
168+
var delta = outMax - outMin;
169+
return outMin + (fr * delta);
170+
}
171+
172+
function avg(arr){
173+
var total = arr.reduce(function(sum, b) { return sum + b; });
174+
return (total / arr.length);
175+
}
176+
177+
function max(arr){
178+
return arr.reduce(function(a, b){ return Math.max(a, b); })
179+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
:root{
2+
--bgColor : hsla(242, 86%, 6%, 1);
3+
--bgColorLight : hsla(242, 86%, 24%, 1);
4+
--textColor : hsla(242, 86%, 88%, 1);
5+
--textColorDark : hsla(242, 36%, 0%, 1);
6+
--paperColor: hsla(242, 86%, 44%, 1);
7+
--paperColorDark: hsla(242, 86%, 34%, 1);
8+
--shadowColorFaint: hsla(0, 0%, 0%, 0.2);
9+
}
10+
11+
::selected{
12+
color: var(--textColorDark);
13+
}
14+
15+
html, body{
16+
margin: 0;
17+
padding: 0;
18+
overflow: hidden;
19+
height: 100vh;
20+
width: 100vw;
21+
background: var(--bgColor);
22+
background: linear-gradient(135deg, var(--bgColor), var(--bgColorLight));
23+
color: var(--textColor);
24+
font-family: 'Saira', sans-serif;
25+
position: relative;
26+
}
27+
28+
*{
29+
box-sizing: border-box;
30+
transition: all 0.12s cubic-bezier(0.42, 0.54, 0.22, 1.26);
31+
}
32+
33+
#canvas {
34+
position: fixed;
35+
left: 0;
36+
top: 0;
37+
width: 100%;
38+
height: 100%;
39+
}
40+
41+
audio {
42+
position: fixed;
43+
left: 10px;
44+
bottom: -10px;
45+
width: calc(100% - 20px);
46+
}
47+
48+
audio.active{
49+
bottom: 10px;
50+
}
51+
52+
#thefile{
53+
width: 0.1px;
54+
height: 0.1px;
55+
opacity: 0;
56+
overflow: hidden;
57+
position: absolute;
58+
z-index: 1;
59+
}
60+
61+
label.file{
62+
display: inline-block;
63+
position: absolute;
64+
left: 50%;
65+
top: 50%;
66+
transform: translate3d(-50%, -50%, 0);
67+
padding: 1rem 2rem;
68+
border-radius: 4px;
69+
70+
background: var(--paperColor);
71+
color: var(--textColor);
72+
font-size: 1.25em;
73+
font-weight: 700;
74+
box-shadow: 0 20px 60px var(--shadowColorFaint);
75+
76+
cursor: pointer;
77+
}
78+
79+
80+
label.file:hover{
81+
background: var(--paperColorDark);
82+
transform: translate3d(-50%, -55%, 0);
83+
}
84+
85+
label.file:active{
86+
background: var(--paperColorDark);
87+
transform: translate3d(-50%, -45%, 0);
88+
}
89+
90+
label.file.normal{
91+
transform: translate3d(10%, 50%, 0);
92+
padding: 0.2rem 2rem;
93+
font-size: 1rem;
94+
top: 0;
95+
left: 0;
96+
}

‎Index.md

+1
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,4 @@
110110
| [Restaurant Website](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/Restaurant%20Website) | A simple and responsive Restaurant website template. |
111111
| [Pomodoro Timer](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/Pomodoro-Timer) | A simple Pomodoro Timer using React.js, where you can track the time spent on work and break. |
112112

113+
|[Audio Visualization with three.js](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/Audio%20Visualization%20with%20three.js) | audio visualization using the powerful 3D graphics library, three.js |

0 commit comments

Comments
 (0)
Please sign in to comment.