<canvas></canvas>
<button id="toggle" style="display: block" disabled="true">
<i class="fa fa-spinner fa-pulse fa-fw"></i>
</button>
body {
overflow: hidden;
margin: 0px;
padding: 0px;
width:100%;
height:100vh;
background-color: #000;
}
.transculent {
opacity: 0;
}
button{
position: absolute;
overflow: hidden;
font-size:7rem;
top: 0px;
left: 0px;
width:100%;
height: 100%;
background-color: rgba( 255, 255, 255, 0);
color: rgba(255, 255, 255, 0.5);
border:0px;
}
let context = new (window.AudioContext || window.webkitAudioContext)();
if (!context.createGain)
context.createGain = context.createGainNode;
if (!context.createDelay)
context.createDelay = context.createDelayNode;
if (!context.createScriptProcessor)
context.createScriptProcessor = context.createJavaScriptNode;
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function playSound(buffer, time) {
let source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source[source.start ? 'start' : 'noteOn'](time);
}
function loadSounds(obj, soundMap, callback) {
const names = [];
const paths = [];
for (const name in soundMap) {
const path = soundMap[name];
names.push(name);
paths.push(path);
}
const bufferLoader = new BufferLoader(context, paths, function (bufferList) {
for (let i = 0; i < bufferList.length; i++) {
const buffer = bufferList[i];
const name = names[i];
obj[name] = buffer;
}
if (callback) {
callback();
}
});
bufferLoader.load();
}
function BufferLoader(context, urlList, callback) {
this.context = context;
this.urlList = urlList;
this.onload = callback;
this.bufferList = new Array();
this.loadCount = 0;
}
const song = "https://res.cloudinary.com/dlszhsahq/video/upload/v1696907055/pop/16_Roby_Benvenuto_Gringo_iu0if7.mp3";
BufferLoader.prototype.loadBuffer = function (url, index) {
const request = new XMLHttpRequest();
request.open('GET', song, true);
request.responseType = "arraybuffer";
const loader = this;
request.onload = function () {
loader.context.decodeAudioData(
request.response,
function (buffer) {
if (!buffer) {
alert('error decoding file data');
return;
}
loader.bufferList[index] = buffer;
if (++loader.loadCount == loader.urlList.length)
loader.onload(loader.bufferList);
},
function (error) {
console.error('decodeAudioData error', error);
}
);
}
request.onerror = function () {
alert('BufferLoader: XHR error');
}
request.send();
};
BufferLoader.prototype.load = function () {
for (let i = 0; i < this.urlList.length; ++i)
this.loadBuffer(this.urlList[i], i);
};
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const source = audioContext.createBufferSource();
const request = new XMLHttpRequest();
request.open('GET', song, true);
request.responseType = 'arraybuffer';
request.onload = function () {
audioContext.decodeAudioData(request.response, function (buffer) {
source.buffer = buffer;
source.loop = true;
source.start(0);
}, function (e) {
console.log('Audio error! ', e);
});
}
request.send();
const WIDTH = window.innerWidth; // 현재 창의 너비를 WIDTH로 설정
const HEIGHT = window.innerHeight; // 현재 창의 높이를 HEIGHT로 설정
const SMOOTHING = 0.8;
const FFT_SIZE = 2048;
function VisualizerSample() {
this.analyser = context.createAnalyser();
this.analyser.connect(context.destination);
this.analyser.minDecibels = -240;
this.analyser.maxDecibels = 0;
loadSounds(this, {
buffer: source.buffer
}, onLoaded);
this.freqs = new Uint8Array(this.analyser.frequencyBinCount);
this.times = new Uint8Array(this.analyser.frequencyBinCount);
function onLoaded() {
const button = document.querySelector('button');
button.removeAttribute('disabled');
button.innerHTML = '<i class="fa fa-play" aria-hidden="true"></i>';
};
this.isPlaying = false;
this.startTime = 0;
this.startOffset = 0;
}
VisualizerSample.prototype.togglePlayback = function () {
if (this.isPlaying) {
this.source[this.source.stop ? 'stop' : 'noteOff'](0);
this.startOffset += context.currentTime - this.startTime;
console.log('paused at', this.startOffset);
} else {
this.startTime = context.currentTime;
console.log('started at', this.startOffset);
this.source = context.createBufferSource();
this.source.connect(this.analyser);
this.source.buffer = this.buffer;
this.source.loop = true;
this.source[this.source.start ? 'start' : 'noteOn'](0, this.startOffset % this.buffer.duration);
requestAnimFrame(this.draw.bind(this));
}
this.isPlaying = !this.isPlaying;
}
VisualizerSample.prototype.draw = function () {
this.analyser.smoothingTimeConstant = SMOOTHING;
this.analyser.fftSize = FFT_SIZE;
this.analyser.getByteFrequencyData(this.freqs);
this.analyser.getByteTimeDomainData(this.times);
const width = Math.floor(1 / this.freqs.length, 10);
const canvas = document.querySelector('canvas');
const drawContext = canvas.getContext('2d');
canvas.width = WIDTH;
canvas.height = HEIGHT;
for (let i = 0; i < this.analyser.frequencyBinCount; i++) {
const value = this.freqs[i];
const percent = value / 256;
const height = HEIGHT * percent;
const offset = HEIGHT - height - 1;
const barWidth = WIDTH / this.analyser.frequencyBinCount;
const hue = i / this.analyser.frequencyBinCount * 360;
drawContext.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
drawContext.fillRect(i * barWidth, offset, barWidth, height);
}
for (let i = 0; i < this.analyser.frequencyBinCount; i++) {
const value = this.times[i];
const percent = value / 256;
const height = HEIGHT * percent * 2;
const offset = HEIGHT - height / 2 - 1;
const barWidth = WIDTH / this.analyser.frequencyBinCount;
drawContext.fillStyle = 'white';
drawContext.fillRect(i * barWidth, offset, 1, 1);
}
if (this.isPlaying) {
requestAnimFrame(this.draw.bind(this));
}
}
const sample = new VisualizerSample();
document.querySelector('button').addEventListener('click', function () {
sample.togglePlayback();
console.log(this.className);
if (this.className === '') {
this.className += 'transculent';
} else {
this.className = '';
}
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.