-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #550 from AnubhabMukherjee2003/web-dev-mini
Audio Visualization with three.js
- Loading branch information
Showing
7 changed files
with
343 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!DOCTYPE html> | ||
<html lang="en" > | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Audio Visualizer based on Three.js</title> | ||
<link href="https://fonts.googleapis.com/css?family=Saira" rel="stylesheet"><link rel="stylesheet" href="./style.css"> | ||
|
||
</head> | ||
<body> | ||
<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="out"></div> | ||
</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 src='https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.3.0/simplex-noise.min.js'></script> | ||
<script src="./script.js"></script> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Audio Visualization with three.js | ||
|
||
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. | ||
|
||
![Audio Visualization](a.png) | ||
Here is the look! | ||
## Table of Contents | ||
- [Introduction](#introduction) | ||
- [Features](#features) | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Files](#files) | ||
|
||
|
||
## Introduction | ||
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. | ||
|
||
## Features | ||
- Real-time audio analysis | ||
- Dynamic 3D visualizations | ||
- Interactive controls | ||
|
||
## Installation | ||
To get started, clone the repository and open the `index.html` file in your browser. | ||
|
||
```bash | ||
git clone https://github.com/Ayushparikh-code/Web-dev-mini-projects.git | ||
cd Web-dev-mini-projects/audio-visualization-threejs | ||
``` | ||
|
||
## Usage | ||
1. Open `index.html` in your preferred web browser. | ||
2. Play an audio file to see the visualization in action. | ||
![Another Visualization](b.png) | ||
## Files | ||
- `index.html`: The main HTML file. | ||
- `style.css`: The CSS file for styling. | ||
- `script.js`: The JavaScript file containing the three.js logic. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
var noise = new SimplexNoise(); | ||
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(); | ||
} | ||
|
||
function play() { | ||
var context = new AudioContext(); | ||
var src = context.createMediaElementSource(audio); | ||
var analyser = context.createAnalyser(); | ||
src.connect(analyser); | ||
analyser.connect(context.destination); | ||
analyser.fftSize = 512; | ||
var bufferLength = analyser.frequencyBinCount; | ||
var dataArray = new Uint8Array(bufferLength); | ||
var scene = new THREE.Scene(); | ||
var group = new THREE.Group(); | ||
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); | ||
camera.position.set(0,0,100); | ||
camera.lookAt(scene.position); | ||
scene.add(camera); | ||
|
||
var renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); | ||
renderer.setSize(window.innerWidth, window.innerHeight); | ||
|
||
var planeGeometry = new THREE.PlaneGeometry(800, 800, 20, 20); | ||
var planeMaterial = new THREE.MeshLambertMaterial({ | ||
color: 0x6904ce, | ||
side: THREE.DoubleSide, | ||
wireframe: true | ||
}); | ||
|
||
var plane = new THREE.Mesh(planeGeometry, planeMaterial); | ||
plane.rotation.x = -0.5 * Math.PI; | ||
plane.position.set(0, 30, 0); | ||
group.add(plane); | ||
|
||
var plane2 = new THREE.Mesh(planeGeometry, planeMaterial); | ||
plane2.rotation.x = -0.5 * Math.PI; | ||
plane2.position.set(0, -30, 0); | ||
group.add(plane2); | ||
|
||
var icosahedronGeometry = new THREE.IcosahedronGeometry(10, 4); | ||
var lambertMaterial = new THREE.MeshLambertMaterial({ | ||
color: 0xff00ee, | ||
wireframe: true | ||
}); | ||
|
||
var ball = new THREE.Mesh(icosahedronGeometry, lambertMaterial); | ||
ball.position.set(0, 0, 0); | ||
group.add(ball); | ||
|
||
var ambientLight = new THREE.AmbientLight(0xaaaaaa); | ||
scene.add(ambientLight); | ||
|
||
var spotLight = new THREE.SpotLight(0xffffff); | ||
spotLight.intensity = 0.9; | ||
spotLight.position.set(-10, 40, 20); | ||
spotLight.lookAt(ball); | ||
spotLight.castShadow = true; | ||
scene.add(spotLight); | ||
|
||
scene.add(group); | ||
|
||
document.getElementById('out').appendChild(renderer.domElement); | ||
|
||
window.addEventListener('resize', onWindowResize, false); | ||
|
||
render(); | ||
|
||
function render() { | ||
analyser.getByteFrequencyData(dataArray); | ||
|
||
var lowerHalfArray = dataArray.slice(0, (dataArray.length/2) - 1); | ||
var upperHalfArray = dataArray.slice((dataArray.length/2) - 1, dataArray.length - 1); | ||
|
||
var overallAvg = avg(dataArray); | ||
var lowerMax = max(lowerHalfArray); | ||
var lowerAvg = avg(lowerHalfArray); | ||
var upperMax = max(upperHalfArray); | ||
var upperAvg = avg(upperHalfArray); | ||
|
||
var lowerMaxFr = lowerMax / lowerHalfArray.length; | ||
var lowerAvgFr = lowerAvg / lowerHalfArray.length; | ||
var upperMaxFr = upperMax / upperHalfArray.length; | ||
var upperAvgFr = upperAvg / upperHalfArray.length; | ||
|
||
makeRoughGround(plane, modulate(upperAvgFr, 0, 1, 0.5, 4)); | ||
makeRoughGround(plane2, modulate(lowerMaxFr, 0, 1, 0.5, 4)); | ||
|
||
makeRoughBall(ball, modulate(Math.pow(lowerMaxFr, 0.8), 0, 1, 0, 8), modulate(upperAvgFr, 0, 1, 0, 4)); | ||
|
||
group.rotation.y += 0.005; | ||
renderer.render(scene, camera); | ||
requestAnimationFrame(render); | ||
} | ||
|
||
function onWindowResize() { | ||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
renderer.setSize(window.innerWidth, window.innerHeight); | ||
} | ||
|
||
function makeRoughBall(mesh, bassFr, treFr) { | ||
mesh.geometry.vertices.forEach(function (vertex) { | ||
var offset = mesh.geometry.parameters.radius; | ||
var amp = 7; | ||
var time = window.performance.now(); | ||
vertex.normalize(); | ||
var rf = 0.00001; | ||
var distance = (offset + bassFr ) + noise.noise3D(vertex.x + time *rf*7, vertex.y + time*rf*8, vertex.z + time*rf*9) * amp * treFr; | ||
vertex.multiplyScalar(distance); | ||
}); | ||
mesh.geometry.verticesNeedUpdate = true; | ||
mesh.geometry.normalsNeedUpdate = true; | ||
mesh.geometry.computeVertexNormals(); | ||
mesh.geometry.computeFaceNormals(); | ||
} | ||
|
||
function makeRoughGround(mesh, distortionFr) { | ||
mesh.geometry.vertices.forEach(function (vertex) { | ||
var amp = 2; | ||
var time = Date.now(); | ||
var distance = (noise.noise2D(vertex.x + time * 0.0003, vertex.y + time * 0.0001) + 0) * distortionFr * amp; | ||
vertex.z = distance; | ||
}); | ||
mesh.geometry.verticesNeedUpdate = true; | ||
mesh.geometry.normalsNeedUpdate = true; | ||
mesh.geometry.computeVertexNormals(); | ||
mesh.geometry.computeFaceNormals(); | ||
} | ||
|
||
audio.play(); | ||
} | ||
} | ||
|
||
window.onload = vizInit(); | ||
|
||
document.body.addEventListener('touchend', function() { context.resume(); }); | ||
|
||
|
||
|
||
|
||
|
||
function fractionate(val, minVal, maxVal) { | ||
return (val - minVal)/(maxVal - minVal); | ||
} | ||
|
||
function modulate(val, minVal, maxVal, outMin, outMax) { | ||
var fr = fractionate(val, minVal, maxVal); | ||
var delta = outMax - outMin; | ||
return outMin + (fr * delta); | ||
} | ||
|
||
function avg(arr){ | ||
var total = arr.reduce(function(sum, b) { return sum + b; }); | ||
return (total / arr.length); | ||
} | ||
|
||
function max(arr){ | ||
return arr.reduce(function(a, b){ return Math.max(a, b); }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
:root{ | ||
--bgColor : hsla(242, 86%, 6%, 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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters