CD风格音乐播放器 - 带频谱显示
CD风格音乐播放器 - 带频谱显示

<script>
// 获取DOM元素
const audioPlayer = document.getElementById('audioPlayer');
const albumCover = document.getElementById('albumCover');
const needle = document.getElementById('needle');
const playPauseBtn = document.getElementById('playPauseBtn');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const progressBar = document.getElementById('progressBar');
const progress = document.getElementById('progress');
const currentTimeEl = document.getElementById('currentTime');
const totalTimeEl = document.getElementById('totalTime');
const songTitle = document.getElementById('songTitle');
const songArtist = document.getElementById('songArtist');
const loadingText = document.getElementById('loadingText');
const spectrumCanvas = document.getElementById('spectrumCanvas');
const ctx = spectrumCanvas.getContext('2d');
// 设置Canvas尺寸
spectrumCanvas.width = spectrumCanvas.offsetWidth;
spectrumCanvas.height = spectrumCanvas.offsetHeight;
// 模拟音乐数据
const playlist = [
{
title: "Andy-live",
artist: "林小风",
cover: "https://picsum.photos/400/400?random=1",
src: "https://bgm.pw/upfile/mp3/Andy-live.mp3"
},
{
title: "鲁冰花",
artist: "夜光乐队",
cover: "https://picsum.photos/400/400?random=2",
src: "https://bgm.pw/upfile/mp3/lubhua.m4a"
},
{
title: "城市节奏",
artist: "都市行者",
cover: "https://picsum.photos/400/400?random=3",
src: "https://bgm.pw/upfile/mp3/First%20-%20Battle.m4a"
}
];
let currentSongIndex = 0;
let audioContext, analyser, dataArray, bufferLength;
let isPlaying = false;
// 格式化时间(秒 -> 分:秒)[1,5](@ref)
function formatTime(seconds) {
if (isNaN(seconds) || seconds === Infinity) return "0:00";
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
}
// 初始化音频分析器 [6,7](@ref)
function initAudioAnalyzer() {
// 创建音频上下文
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
// 创建音频源节点
const source = audioContext.createMediaElementSource(audioPlayer);
// 连接分析器
source.connect(analyser);
analyser.connect(audioContext.destination);
// 设置FFT大小
analyser.fftSize = 256;
bufferLength = analyser.frequencyBinCount;
dataArray = new Uint8Array(bufferLength);
}
// 绘制频谱 [6,7](@ref)
function drawSpectrum() {
if (!isPlaying || !analyser) return;
requestAnimationFrame(drawSpectrum);
// 获取频率数据
analyser.getByteFrequencyData(dataArray);
// 清除画布
ctx.clearRect(0, 0, spectrumCanvas.width, spectrumCanvas.height);
// 计算条宽和间距
const barWidth = (spectrumCanvas.width / bufferLength) * 2.5;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
// 计算条高
const barHeight = (dataArray[i] / 255) * spectrumCanvas.height;
// 创建渐变颜色
const gradient = ctx.createLinearGradient(0, 0, 0, spectrumCanvas.height);
gradient.addColorStop(0, '#4cc9f0');
gradient.addColorStop(0.5, '#3aa8d0');
gradient.addColorStop(1, '#1a8bb8');
// 绘制频谱条
ctx.fillStyle = gradient;
ctx.fillRect(
x,
spectrumCanvas.height - barHeight,
barWidth - 1,
barHeight
);
x += barWidth + 1;
}
}
// 更新播放器信息
function updatePlayerInfo() {
const song = playlist[currentSongIndex];
songTitle.textContent = song.title;
songArtist.textContent = song.artist;
albumCover.src = song.cover;
audioPlayer.src = song.src;
loadingText.style.display = 'block';
totalTimeEl.textContent = "0:00";
currentTimeEl.textContent = "0:00";
progress.style.width = "0%";
currentTimeEl.style.left = "0px";
totalTimeEl.style.left = "0px";
// 清除Canvas
ctx.clearRect(0, 0, spectrumCanvas.width, spectrumCanvas.height);
// 等待音频加载完成
audioPlayer.load();
// 加载音频元数据 [1](@ref)
audioPlayer.addEventListener('loadedmetadata', function() {
totalTimeEl.textContent = formatTime(audioPlayer.duration);
loadingText.style.display = 'none';
});
}
// 播放/暂停音乐 [2,4](@ref)
function togglePlayPause() {
if (audioPlayer.paused) {
// 初始化音频分析器
if (!audioContext) {
initAudioAnalyzer();
}
// 恢复音频上下文(某些浏览器需要用户交互后)[6](@ref)
if (audioContext.state === 'suspended') {
audioContext.resume();
}
audioPlayer.play().then(() => {
playPauseBtn.innerHTML = '⏸';
albumCover.classList.add('rotating');
needle.classList.add('playing');
isPlaying = true;
// 开始绘制频谱
drawSpectrum();
}).catch(error => {
console.error('播放失败:', error);
loadingText.textContent = '播放失败,请点击重试';
});
} else {
audioPlayer.pause();
playPauseBtn.innerHTML = '▶';
albumCover.classList.remove('rotating');
needle.classList.remove('playing');
isPlaying = false;
}
}
// 点击封面控制播放/暂停
albumCover.addEventListener('click', togglePlayPause);
// 播放/暂停按钮事件
playPauseBtn.addEventListener('click', togglePlayPause);
// 上一首 [4,5](@ref)
prevBtn.addEventListener('click', function() {
currentSongIndex = (currentSongIndex - 1 + playlist.length) % playlist.length;
updatePlayerInfo();
if (!audioPlayer.paused) {
audioPlayer.play();
}
});
// 下一首 [4,5](@ref)
nextBtn.addEventListener('click', function() {
currentSongIndex = (currentSongIndex + 1) % playlist.length;
updatePlayerInfo();
if (!audioPlayer.paused) {
audioPlayer.play();
}
});
// 更新进度条和时间显示 [1,2](@ref)
audioPlayer.addEventListener('timeupdate', function() {
const currentTime = audioPlayer.currentTime;
const duration = audioPlayer.duration;
if (duration && !isNaN(duration) && duration !== Infinity) {
const progressPercent = (currentTime / duration) * 100;
progress.style.width = `${progressPercent}%`;
currentTimeEl.textContent = formatTime(currentTime);
totalTimeEl.textContent = formatTime(duration);
// 更新当前时间和总时间位置
const progressBarWidth = progressBar.offsetWidth;
const timePos = (progressPercent / 100) * progressBarWidth;
currentTimeEl.style.left = `${timePos}px`;
totalTimeEl.style.left = `${timePos}px`;
// 边界检测,确保时间显示不重叠
const minDistance = 30; // 最小间距
if (timePos < progressBarWidth / 2) {
currentTimeEl.style.transform = 'translateX(-50%)';
totalTimeEl.style.transform = 'translateX(-50%)';
currentTimeEl.style.marginTop = '0px';
totalTimeEl.style.marginTop = '20px';
} else {
currentTimeEl.style.transform = 'translateX(-50%)';
totalTimeEl.style.transform = 'translateX(-50%)';
currentTimeEl.style.marginTop = '20px';
totalTimeEl.style.marginTop = '0px';
}
}
});
// 点击进度条跳转 [2](@ref)
progressBar.addEventListener('click', function(e) {
const rect = progressBar.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const width = rect.width;
const duration = audioPlayer.duration;
if (duration && !isNaN(duration) && duration !== Infinity) {
audioPlayer.currentTime = (clickX / width) * duration;
}
});
// 歌曲结束时自动下一首 [4](@ref)
audioPlayer.addEventListener('ended', function() {
currentSongIndex = (currentSongIndex + 1) % playlist.length;
updatePlayerInfo();
audioPlayer.play();
});
// 音频加载错误处理
audioPlayer.addEventListener('error', function() {
loadingText.textContent = '音频加载失败,请检查网络连接';
});
// 窗口大小变化时调整Canvas尺寸 [6](@ref)
window.addEventListener('resize', function() {
spectrumCanvas.width = spectrumCanvas.offsetWidth;
spectrumCanvas.height = spectrumCanvas.offsetHeight;
});
// 初始化播放器
updatePlayerInfo();
</script>2025-12-12 14:47:41 通过 网页 浏览(35)
共有0条评论!