梦中想着你【视频频谱】
本帖最后由 亚伦影音工作室 于 2025-9-19 09:37 编辑 <br /><br /><style>#bj {position: relative;
width: 1286px;
height: 720px;
margin-left: -300px;
margin-top: 120px;
overflow: hidden;z-index:12345;
background: ;
}
.intro {margin: 0px0px;z-index:1;
width: 100%;
height:100%;
position: absolute;
background:radial-gradient(ellipse farthest-corner at center center, transparent 38%,#000 80%),url(https://pic1.imgdb.cn/item/68caa2c9c5157e1a8812b7bd.webp),linear-gradient(135deg, #e56420, #c22525, #3d9c31, #000078);
background-size: cover;
animation: hue-rotate 1s linear infinite;
}
.stop.intro{animation-play-state: paused;}
@keyframes hue-rotate {
from {
filter: hue-rotate(0);
}
to {
filter: hue-rotate(360deg);
}
}
video::-webkit-media-controls-enclosure{ display: none;}
.lyrics{margin: 0;z-index: 6;
top: 86%;
left: 50%;
transform: translate(-50%, -50%);
height: 100px; /* 调整高度,只容纳当前歌词 */
text-align: center;
position: absolute;
}
.lyric-line{
width: 100%;
position: relative;
height: 60px;
overflow: visible;
font: 300 45px '华文隶书', sans-serif;
line-height: 60px;
text-align: left;
white-space: nowrap; /* 禁止换行 */
filter: drop-shadow(#fff 1px 0 0) drop-shadow(#fff 0 1px 0) drop-shadow(#fff -1px 0 0) drop-shadow(#fff 0 -1px 0);
}
.lyric-mask {
position: absolute;
top: 0;
left: 0;
width: 0;
overflow: hidden;
color: #8B4513;
height: 100%;
white-space: nowrap;
}
.lyric-original {
color: #ag0000;
white-space: nowrap;
}
#bfqbnt{ width: 300px;height: 160px;position: absolute; top:99%; overflow: hidden;z-index: 13; left: 55%;transform: translate(-50%, -50%);}
.start{color: #fff;position: absolute; top:14px; left: 22px;z-index: 3;}
.end{color: #fff;position: absolute;top:14px; left: 154px;z-index: 3;}
#btn{background: url(https://pic.imgdb.cn/item/675813f6d0e0a243d4e14a48.png) no-repeat 0px 0px/cover;width:50px;height: 50px;left: 80px; top: 2px;position: absolute;z-index: 20;}
#prog {position: absolute;z-index: 20;
width: 100%;
height: 20px;background:#555;
cursor: pointer;
top:98%;
left:0%;
border-radius: 1px;}
#prog-bar {
height: 100%;
background: #880000;
width: 0%;
}
#world,#fullscreen {border-radius: 4px;position: relative;background:#0000 ;
color:#fff;box-shadow:0px 0px 0px 1px #fff;z-index: 23;
padding: 4px 10px;
font-size: 12px;
border: none;
cursor: pointer;margin: 8px 5px;left: 75%;top: 30px;
}
</style>
<divid="bj">
<video id="audio" src="https://file.uhsea.com/2509/bafaf55550b99904d29922459795e401LW.mp4" autoplay loop controls style="max-width: 60%; height: auto;z-index:23;position: absolute;left: 40%;top:16%;object-fit: cover; pointer-events: none;mix-blend-mode:lighten;display: block;"></video>
<div class='intro'></div>
<div id='bfqbnt'>
<span class="start">00:00</span><p id="btn"></p><span class="end">00:00</span>
</div>
<div id="prog" title="播放进度条"><div id="prog-bar"></div></div>
<span id="world" onclick="btncd()"title="频谱隐藏">频谱隐藏</span>
<span id="fullscreen" title="屏展模式">全屏欣赏</span>
<div class="lyrics" >
<div class="lyric-line">
<div class="lyric-mask"></div>
<div class="lyric-original"></div>
</div>
</div>
</div>
<script>
// 歌词解析ksc歌词或lrc歌词
const lrc = `一个人在梦里总是难以入睡
刚要闭上眼仿佛你就在眼前
其实那并不是你只是想你的感觉
我也要与你梦中相约
一个人在梦里与你依依相偎
刚要睁开眼你却消失在眼前
望着慢慢离去的你那种忧伤的感觉
只好让眼泪留在眼里面
我在梦中想着你
我在梦中念着你
可是现在的你却究竟去了哪里
我愿永远陪着你
我愿永远伴着你
就算只是在梦中相遇我也会愿意
我会天天都想你
把你放在我心里
就当梦中的你是你
一个人在梦里与你依依相偎
刚要睁开眼你却消失在眼前
望着慢慢离去的你那种忧伤的感觉
只好让眼泪留在眼里面
我在梦中想着你
我在梦中念着你
可是现在的你却究竟去了哪里
我愿永远陪着你
我愿永远伴着你
就算只是在梦中相遇我也会愿意
我会天天都想你
把你放在我心里
就当梦中的你是你
就当梦中的你是你
一个人在梦里总是难以入睡
刚要闭上眼仿佛你就在眼前
其实那并不是你只是想你的感觉
我也要与你梦中相约
一个人在梦里与你依依相偎
刚要睁开眼你却消失在眼前
望着慢慢离去的你那种忧伤的感觉
只好让眼泪留在眼里面
我在梦中想着你
我在梦中念着你
可是现在的你却究竟去了哪里
我愿永远陪着你
我愿永远伴着你
就算只是在梦中相遇我也会愿意
我会天天都想你
把你放在我心里
就当梦中的你是你
一个人在梦里与你依依相偎
刚要睁开眼你却消失在眼前
望着慢慢离去的你那种忧伤的感觉
只好让眼泪留在眼里面
我在梦中想着你
我在梦中念着你
可是现在的你却究竟去了哪里
我愿永远陪着你
我愿永远伴着你
就算只是在梦中相遇我也会愿意
我会天天都想你
把你放在我心里
就当梦中的你是你
就当梦中的你是你
`;
const audio = document.getElementById('audio');
const lyrics = parseLyrics(lrc);
const lyricMask = document.querySelector('.lyric-mask');
const lyricOriginal = document.querySelector('.lyric-original');
let currentIndex = -1;
let currentLyric = null;
// 解析歌词(支持两种格式)
function parseLyrics(lrcText) {
const lyrics = [];
if (lrcText.includes('karaoke.add')) {
const lineRegex = /karaoke\.add\('([^']+)', '([^']+)', '([^']+)', '([^']+)'\);/g;
let match;
while ((match = lineRegex.exec(lrcText)) !== null) {
const startTime = timeToMs(match);
const endTime = timeToMs(match);
const text = match.replace(/\[|\]/g, '').trim();
const durations = match.split(',').map(Number);
if (text) {
lyrics.push({startTime, endTime, text, durations});
}
}
}
else if (lrcText.includes('[')) {
const lines = lrcText.split('\n').filter(line => line.trim());
lines.forEach((line, index) => {
const timeMatch = line.match(/\[(\d+:\d+\.\d+)\]/);
if (timeMatch) {
const timeStr = timeMatch;
const text = line.replace(/\[.*?\]/, '').trim();
if (text) {
const startTime = timeToMs(timeStr);
const nextLine = lines;
const nextTimeMatch = nextLine ? nextLine.match(/\[(\d+:\d+\.\d+)\]/) : null;
const endTime = nextTimeMatch ? timeToMs(nextTimeMatch) : startTime + 5000;
lyrics.push({
startTime,
endTime,
text,
durations: calculateCharDurations(text, startTime, endTime)
});
}
}
});
}
return lyrics;
}
function calculateCharDurations(text, startTime, endTime) {
const totalDuration = endTime - startTime;
const charCount = text.length;
const baseDur = Math.floor(totalDuration / charCount);
const durations = new Array(charCount).fill(baseDur);
const remainder = totalDuration % charCount;
for (let i = 0; i < remainder; i++) {
durations++;
}
return durations;
}
function timeToMs(timeStr) {
const parts = timeStr.split(':');
const minutes = parseInt(parts, 10);
const secondsAndMs = parts.split('.');
const seconds = parseInt(secondsAndMs, 10);
const ms = parseInt(secondsAndMs || 0, 10);
return minutes * 60 * 1000 + seconds * 1000 + ms;
}
function getCurrentLyricIndex(lyrics, currentTimeMs) {
for (let i = 0; i < lyrics.length; i++) {
if (currentTimeMs >= lyrics.startTime && currentTimeMs <= lyrics.endTime) {
return i;
}
}
return -1;
}
function updateLyricDisplay(index) {
if (index < 0 || index >= lyrics.length) return;
currentIndex = index;
currentLyric = lyrics;
lyricOriginal.textContent = currentLyric.text;
lyricMask.textContent = currentLyric.text;
lyricMask.style.width = '0%';
}
function updateLyricMask(currentTimeMs) {
if (!currentLyric) return;
const lyricStartTime = currentLyric.startTime;
const elapsed = currentTimeMs - lyricStartTime;
const totalDuration = currentLyric.durations.reduce((sum, d) => sum + d, 0);
let charIndex = 0;
let accumulatedTime = 0;
for (let i = 0; i < currentLyric.durations.length; i++) {
accumulatedTime += currentLyric.durations;
if (elapsed <= accumulatedTime) {
charIndex = i + 1;
break;
}
}
if (elapsed >= totalDuration) {
charIndex = currentLyric.text.length;
}
charIndex = Math.min(charIndex, currentLyric.text.length);
const tempSpan = document.createElement('span');
tempSpan.style.visibility = 'hidden';
tempSpan.style.position = 'absolute';
tempSpan.style.fontSize = '50px';
tempSpan.style.fontWeight = '800';
document.body.appendChild(tempSpan);
const visibleText = currentLyric.text.substring(0, charIndex);
tempSpan.textContent = visibleText;
const width = tempSpan.offsetWidth;
document.body.removeChild(tempSpan);
lyricMask.style.width = `${width}px`;
}
// 监听更新歌词
audio.addEventListener('timeupdate', () => {
const currentTimeMs = audio.currentTime * 1000;
const index = getCurrentLyricIndex(lyrics, currentTimeMs);
if (index !== currentIndex) {
updateLyricDisplay(index);
}
updateLyricMask(currentTimeMs);
});
updateLyricDisplay(0);
</script>
<script>
const intro= document.querySelector('.intro');
let mState = () => audio.paused ? (intro.classList.add('stop')):(intro.classList.remove('stop'));
audio.addEventListener('play', () => mState());
audio.addEventListener('pause', () => mState());
btn.onclick = () => audio.paused ? (audio.play(), btn.style.background = 'url(https://pic.imgdb.cn/item/675813f6d0e0a243d4e14a48.png) no-repeat 0px 0px/cover') : (audio.pause(), btn.style.background = 'url(https://pic.imgdb.cn/item/675813e7d0e0a243d4e14a18.png) no-repeat 0px 0px/cover');
const start = document.querySelector('.start')
const end= document.querySelector('.end')
function conversion (value) {
let minute = Math.floor(value / 60)
minute = minute.toString().length === 1 ? ('0' + minute) : minute
let second = Math.round(value % 60)
second = second.toString().length === 1 ? ('0' + second) : second
return `${minute}:${second}`
}
audio.onloadedmetadata = function () {
end.innerHTML = conversion(audio.duration)
start.innerHTML = conversion(audio.currentTime)
}
setInterval(() => {
start.innerHTML = conversion(audio.currentTime)
}, 1000)
prog.onclick = (e) => { audio.currentTime = audio.duration * e.offsetX / prog.offsetWidth; }
var progBar = document.getElementById('prog-bar');
audio.addEventListener('timeupdate', () => {
const percent = (audio.currentTime / audio.duration) * 100;
progBar.style.width = percent + '%';
});
function btncd() {
var img = document.getElementById("audio");
if (document.getElementById("world").innerHTML == "频谱显示") {
img.style.display = 'block';
document.getElementById("world").innerHTML = "频谱隐藏";
} else {
img.style.display = 'none';
document.getElementById("world").innerHTML = "频谱显示";
}
};
let fs = true;
fullscreen.onclick = () => {
if (fs) {
fullscreen.innerText = '退出全屏';
bj.requestFullscreen();
} else {
fullscreen.innerText = '全屏欣赏';
document.exitFullscreen();
}
fs = !fs;
};
</script> 在线音频可视化制作地址:https://tuneonmusic.com/zh/music-tools/music-visualizer/ 谢谢老师的新代码,请问老师视频频谱做完后下载无法播放,不知怎么办?
老谟深虑 发表于 2025-9-19 15:22
谢谢老师的新代码,请问老师视频频谱做完后下载无法播放,不知怎么办?
视频的容积太大需要压缩,然后上传网盘得到地址就可用了! 亚伦影音工作室 发表于 2025-9-19 15:30
视频的容积太大需要压缩,然后上传网盘得到地址就可用了!
谢谢老师!晚上好!
页:
[1]