Last active
June 24, 2023 01:25
-
-
Save anon987654321/c538c9ee44469496dd4bef766dbec423 to your computer and use it in GitHub Desktop.
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
var audio, audioContext, audioSrc; | |
var analyser, analyserBufferLength; | |
//--- | |
var w; | |
var h; | |
var btStart; | |
var txtStatus; | |
var canvas; | |
var context; | |
var imageData; | |
var data; | |
var mouseActive = false; | |
var mouseDown = false; | |
var mousePos = { x:0, y:0 }; | |
var mouseFollowSpeed = 0.015; | |
var fov = 250; | |
var speed = 0.75; | |
var particles = []; | |
var particlesCenter = []; | |
var time = 0; | |
var colorInvertValue = 0; | |
//--- | |
function init() { | |
canvas = document.createElement( 'canvas' ); | |
canvas.addEventListener( 'mousedown', mouseDownHandler, false ); | |
canvas.addEventListener( 'mouseup', mouseUpHandler, false ); | |
canvas.addEventListener( 'mousemove', mouseMoveHandler, false ); | |
canvas.addEventListener( 'mouseenter', mouseEnterHandler, false ); | |
canvas.addEventListener( 'mouseleave', mouseLeaveHandler, false ); | |
document.body.appendChild( canvas ); | |
context = canvas.getContext( '2d' ); | |
window.addEventListener( 'resize', onResize, false ); | |
onResize(); | |
addParticles(); | |
render(); | |
clearImageData(); | |
render(); | |
context.putImageData( imageData, 0, 0 ); | |
btStart = document.getElementById( 'btStartAudioVisualization' ); | |
btStart.addEventListener( 'mousedown', userStart, false ); | |
txtStatus = document.getElementById( 'txtStatus' ); | |
txtStatus.innerHTML = 'Waiting Patiently For You... Please Click the Start Button.'; | |
}; | |
//--- | |
function userStart() { | |
btStart.removeEventListener( 'mousedown', userStart ); | |
btStart.addEventListener( 'mousedown', audioBtHandler, false ); | |
btStart.innerHTML = 'Pause Audio'; | |
txtStatus.innerHTML = 'Loading Audio...'; | |
audioSetup(); | |
animate(); | |
}; | |
//--- | |
function audioSetup() { | |
audio = new Audio(); | |
audio.src = 'https://nkunited.de/ExternalImages/jsfiddle/audio/ChillDay_comp.mp3'; | |
audio.controls = false; | |
audio.loop = true; | |
audio.autoplay = true; | |
audio.crossOrigin = 'anonymous'; | |
audio.addEventListener( 'canplaythrough', audioLoaded, false ); | |
audioContext = new ( window.AudioContext || window.webkitAudioContext )(); | |
analyser = audioContext.createAnalyser(); | |
analyser.connect( audioContext.destination ); | |
analyser.smoothingTimeConstant = 0.65; | |
analyser.fftSize = 512 * 32;//circleSegments * 32; | |
analyserBufferLength = analyser.frequencyBinCount; | |
audioSrc = audioContext.createMediaElementSource( audio ); | |
audioSrc.connect( analyser ); | |
}; | |
function audioLoaded( event ) { | |
txtStatus.innerHTML = 'Song: LAKEY INSPIRED - Chill Day'; | |
//txtStatus.style.display = 'none'; | |
}; | |
//--- | |
function clearImageData() { | |
for ( var i = 0, l = data.length; i < l; i += 4 ) { | |
data[ i ] = 0; | |
data[ i + 1 ] = 0; | |
data[ i + 2 ] = 0; | |
data[ i + 3 ] = 255; | |
} | |
}; | |
function setPixel( x, y, r, g, b, a ) { | |
var i = ( x + y * imageData.width ) * 4; | |
data[ i ] = r; | |
data[ i + 1 ] = g; | |
data[ i + 2 ] = b; | |
data[ i + 3 ] = a; | |
}; | |
//--- | |
function drawLine( x1, y1, x2, y2, r, g, b, a ) { | |
var dx = Math.abs( x2 - x1 ); | |
var dy = Math.abs( y2 - y1 ); | |
var sx = ( x1 < x2 ) ? 1 : -1; | |
var sy = ( y1 < y2 ) ? 1 : -1; | |
var err = dx - dy; | |
var lx = x1; | |
var ly = y1; | |
while ( true ) { | |
if ( lx > 0 && lx < w && ly > 0 && ly < h ) { | |
setPixel( lx, ly, r, g, b, a ); | |
} | |
if ( ( lx === x2 ) && ( ly === y2 ) ) | |
break; | |
var e2 = 2 * err; | |
if ( e2 > -dx ) { | |
err -= dy; | |
lx += sx; | |
} | |
if ( e2 < dy ) { | |
err += dx; | |
ly += sy; | |
} | |
} | |
}; | |
//--- | |
function getCirclePosition( centerX, centerY, radius, index, segments ) { | |
var angle = index * ( ( Math.PI * 2 ) / segments ) + time; | |
var x = centerX + Math.cos( angle ) * radius; | |
var y = centerY + Math.sin( angle ) * radius; | |
return { x:x, y:y }; | |
}; | |
function drawCircle( centerPosition, radius, segments ) { | |
var coordinates = []; | |
var radiusSave; | |
var diff = 0;//Math.floor( Math.random() * segments ); | |
for ( var i = 0; i <= segments; i++ ) { | |
//var radiusRandom = radius + Math.random() * ( radius / 8 ); | |
//var radiusRandom = radius + Math.random() * ( radius / 32 ); | |
var radiusRandom = radius;// + ( radius / 8 ); | |
if ( i === 0 ) { | |
radiusSave = radiusRandom; | |
} | |
if ( i === segments ) { | |
radiusRandom = radiusSave; | |
} | |
var centerX = centerPosition.x; | |
var centerY = centerPosition.y; | |
var position = getCirclePosition( centerX, centerY, radiusRandom, i, segments ); | |
coordinates.push( { x:position.x, y:position.y, index:i + diff, radius:radiusRandom, segments:segments, centerX:centerX, centerY:centerY } ); | |
} | |
return coordinates; | |
}; | |
//--- | |
function addParticle( x, y, z, audioBufferIndex ) { | |
var particle = {}; | |
particle.x = x; | |
particle.y = y; | |
particle.z = z; | |
particle.x2d = 0; | |
particle.y2d = 0; | |
particle.audioBufferIndex = audioBufferIndex; | |
return particle; | |
}; | |
function addParticles() { | |
var audioBufferIndexMin = 8; | |
var audioBufferIndexMax = 1024; | |
var audioBufferIndex = audioBufferIndexMin; | |
var centerPosition = { x:0, y:0 }; | |
var center = { x:0, y:0 }; | |
var c = 0; | |
var w1 = Math.random() * ( w / 1 ); | |
var h1 = Math.random() * ( h / 1 ); | |
for ( var z = -fov; z < fov; z += 4 ) { | |
var coordinates = drawCircle( centerPosition, 75, 64 ); | |
var particlesRow = []; | |
center.x = ( ( w / 2 ) - w1 ) * ( c / 15 ) + w / 2; | |
center.y = ( ( h / 2 ) - h1 ) * ( c / 15 ) + w / 2; | |
c++; | |
//var center = { x:w / 2, y:h / 2 }; | |
particlesCenter.push( center ); | |
audioBufferIndex = Math.floor( Math.random() * audioBufferIndexMax ) + audioBufferIndexMin; | |
for ( var i = 0, l = coordinates.length; i < l; i++ ) { | |
var coordinate = coordinates[ i ]; | |
var particle = addParticle( coordinate.x, coordinate.y, z, audioBufferIndex ); | |
particle.index = coordinate.index; | |
particle.radius = coordinate.radius; | |
particle.radiusAudio = particle.radius; | |
particle.segments = coordinate.segments; | |
particle.centerX = coordinate.centerX; | |
particle.centerY = coordinate.centerY; | |
particlesRow.push( particle ); | |
if ( i < coordinates.length / 2 ) { | |
audioBufferIndex++; | |
} else { | |
audioBufferIndex--; | |
} | |
if ( audioBufferIndex > audioBufferIndexMax ) { | |
audioBufferIndex = audioBufferIndexMin; | |
} | |
if ( audioBufferIndex < audioBufferIndexMin ) { | |
audioBufferIndex = audioBufferIndexMax; | |
} | |
/* | |
if ( i < audioBufferIndexMax / 2 ) { | |
//if ( i < Math.random() * audioBufferIndexMax ) { | |
audioBufferIndex++; | |
} else { | |
audioBufferIndex--; | |
} | |
*/ | |
/* | |
audioBufferIndex++; | |
//if ( audioBufferIndex > Math.random() * audioBufferIndexMax ) { | |
if ( audioBufferIndex > audioBufferIndexMax ) { | |
audioBufferIndex = audioBufferIndexMin; | |
} | |
*/ | |
//audioBufferIndex = Math.floor( Math.random() * audioBufferIndexMax ) + audioBufferIndexMin; | |
} | |
particles.push( particlesRow ); | |
} | |
}; | |
//--- | |
function onResize(){ | |
w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; | |
h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; | |
canvas.width = w; | |
canvas.height = h; | |
context.fillStyle = '#000000'; | |
context.fillRect( 0, 0, w, h ); | |
imageData = context.getImageData( 0, 0, w, h ); | |
data = imageData.data; | |
}; | |
//--- | |
function audioBtHandler( event ) { | |
if ( audio.paused ) { | |
audio.play(); | |
btStart.innerHTML = 'Pause Audio'; | |
} else { | |
audio.pause(); | |
btStart.innerHTML = 'Play Audio'; | |
} | |
}; | |
//--- | |
function mouseDownHandler( event ) { | |
mouseDown = true; | |
}; | |
function mouseUpHandler( event ) { | |
mouseDown = false; | |
}; | |
function mouseEnterHandler( event ) { | |
mouseActive = true; | |
}; | |
function mouseLeaveHandler( event ) { | |
mouseActive = false; | |
mousePos.x = w / 2; | |
mousePos.y = h / 2; | |
mouseDown = false; | |
}; | |
function mouseMoveHandler( event ) { | |
mousePos = getMousePos( canvas, event ); | |
}; | |
function getMousePos( canvas, event ) { | |
var rect = canvas.getBoundingClientRect(); | |
return { x:event.clientX - rect.left, y:event.clientY - rect.top }; | |
}; | |
//--- | |
function render() { | |
var frequencySource; | |
if ( analyser ) { | |
frequencySource = new Uint8Array( analyser.frequencyBinCount ); | |
analyser.getByteFrequencyData( frequencySource ); | |
} | |
//--- | |
var sortArray = false; | |
//--- | |
for ( var i = 0, l = particles.length; i < l; i++ ) { | |
var particlesRow = particles[ i ]; | |
var particlesRowBack; | |
if ( i > 0 ) { | |
particlesRowBack = particles[ i - 1 ]; | |
} | |
//--- | |
var center = particlesCenter[ i ]; | |
if ( mouseActive ) { | |
//center.x = ( ( w / 2 ) - mousePos.x ) * ( -i / 150 ) + w / 2; | |
//center.y = ( ( h / 2 ) - mousePos.y ) * ( -i / 150 ) + h / 2; | |
center.x = ( ( w / 2 ) - mousePos.x ) * ( ( particlesRow[ 0 ].z - fov ) / 500 ) + w / 2; | |
center.y = ( ( h / 2 ) - mousePos.y ) * ( ( particlesRow[ 0 ].z - fov ) / 500 ) + h / 2; | |
} else { | |
center.x += ( ( w / 2 ) - center.x ) * mouseFollowSpeed; | |
center.y += ( ( h / 2 ) - center.y ) * mouseFollowSpeed; | |
} | |
//--- | |
for ( var j = 0, k = particlesRow.length; j < k; j++ ) { | |
var particle = particlesRow[ j ]; | |
var scale = fov / ( fov + particle.z ); | |
particle.x2d = ( particle.x * scale ) + center.x; | |
particle.y2d = ( particle.y * scale ) + center.y; | |
//--- | |
if ( analyser ) { | |
var frequency = frequencySource[ particle.audioBufferIndex ]; | |
var frequencyAdd = frequency / 8; | |
particle.radiusAudio = particle.radius + frequencyAdd; | |
} else { | |
particle.radiusAudio = particle.radius;// + Math.random() * 4; | |
} | |
//--- | |
if ( mouseDown ) { | |
particle.z += speed; | |
if ( particle.z > fov ) { | |
particle.z -= ( fov * 2 ); | |
sortArray = true; | |
} | |
} else { | |
particle.z -= speed; | |
if ( particle.z < -fov ) { | |
particle.z += ( fov * 2 ); | |
sortArray = true; | |
} | |
} | |
//--- | |
var lineColorValue = 0; | |
if ( j > 0 ) { | |
var p = particlesRow[ j - 1 ]; | |
//var lineColorValue = Math.round( ( ( i - ( fov / 5 ) ) / l ) * 255 ); | |
lineColorValue = Math.round( i / l * 200 );//255 | |
/* | |
if ( analyser ) { | |
lineColorValue = Math.round( i / l * ( 200 + frequency ));//255 | |
if ( lineColorValue > 255 ) { | |
lineColorValue = 255; | |
} | |
} | |
*/ | |
drawLine( particle.x2d | 0, particle.y2d | 0, p.x2d | 0, p.y2d | 0, 0, Math.round( lineColorValue / 2 ), lineColorValue, 255 ); | |
} | |
var position; | |
if ( j < k - 1 ) { | |
position = getCirclePosition( particle.centerX, particle.centerY, particle.radiusAudio, particle.index, particle.segments ); | |
} else { | |
var p1 = particlesRow[ 0 ]; | |
position = getCirclePosition( p1.centerX, p1.centerY, p1.radiusAudio, p1.index, p1.segments ); | |
} | |
particle.x = position.x; | |
particle.y = position.y; | |
//--- | |
if ( i > 0 && i < l - 1 ) { | |
var pB;// = particlesRowBack[ j ]; | |
if ( j === 0 ) { | |
pB = particlesRowBack[ particlesRowBack.length - 1 ]; | |
} else { | |
pB = particlesRowBack[ j - 1 ]; | |
} | |
drawLine( particle.x2d | 0, particle.y2d | 0, pB.x2d | 0, pB.y2d | 0, 0, Math.round( lineColorValue / 2 ), lineColorValue, 255 ); | |
} | |
} | |
} | |
//--- | |
if ( sortArray ) { | |
particles = particles.sort( function( a, b ) { | |
return ( b[ 0 ].z - a[ 0 ].z ); | |
} ); | |
} | |
//--- | |
if ( mouseDown ) { | |
time -= 0.005; | |
} else { | |
time += 0.005; | |
} | |
//--- | |
//soft invert colors | |
if ( mouseDown ) { | |
if ( colorInvertValue < 255 ) | |
colorInvertValue += 5; | |
else | |
colorInvertValue = 255; | |
softInvert( colorInvertValue ); | |
} else { | |
if ( colorInvertValue > 0 ) | |
colorInvertValue -= 5; | |
else | |
colorInvertValue = 0; | |
if ( colorInvertValue > 0 ) | |
softInvert( colorInvertValue ); | |
} | |
}; | |
//--- | |
function softInvert( value ) { | |
for ( var j = 0, n = data.length; j < n; j += 4 ) { | |
data[ j ] = Math.abs( value - data[ j ] ); // red | |
data[ j + 1 ] = Math.abs( value - data[ j + 1 ] ); // green | |
data[ j + 2 ] = Math.abs( value - data[ j + 2 ] ); // blue | |
data[ j + 3 ] = 255;// - data[ j + 3 ]; // alpha | |
} | |
}; | |
//--- | |
function animate() { | |
clearImageData(); | |
render(); | |
context.putImageData( imageData, 0, 0 ); | |
requestAnimationFrame( animate ); | |
}; | |
window.requestAnimFrame = ( function() { | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
function( callback ) { | |
window.setTimeout( callback, 1000 / 60 ); | |
}; | |
} )(); | |
//--- | |
init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment