// 确保在用户交互后初始化音频
document.addEventListener('click', () => {
if (this.audioContext && this.audioContext.state === 'suspended') {
this.audioContext.resume();
}
});
}
// 切换播放状态
async togglePlay() {
if (this.isPlaying) {
this.pause();
} else {
await this.play();
}
}
// 播放功能
async play() {
if (this.isPlaying) return;
this.isPlaying = true;
const playBtn = document.getElementById('play-btn');
playBtn.innerHTML = '<span>⏸️</span><span>暂停</span>';
const lyrics = document.getElementById('lyrics-editor').value;
this.sections = this.parseLyrics(lyrics);
if (this.sections.length === 0) {
this.showMessage('没有检测到有效的歌曲段落', 'warning');
this.stop();
return;
}
// 计算总时长
this.totalTime = this.calculateTotalDuration();
document.getElementById('total-time').textContent = this.formatTime(this.totalTime);
// 开始播放
this.currentSectionIndex = 0;
this.startTime = Date.now();
this.animationFrame = requestAnimationFrame(() => this.updatePlayback());
await this.playSection(0);
}
// 暂停播放
pause() {
this.isPlaying = false;
const playBtn = document.getElementById('play-btn');
playBtn.innerHTML = '<span>▶️</span><span>播放</span>';
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
}
// 停止播放
stop() {
this.isPlaying = false;
this.currentTime = 0;
this.currentSectionIndex = 0;
const playBtn = document.getElementById('play-btn');
playBtn.innerHTML = '<span>▶️</span><span>播放</span>';
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
document.getElementById('progress').style.width = '0%';
document.getElementById('current-time').textContent = '00:00';
document.getElementById('current-section').textContent = '[已停止]';
// 停止所有音频
if (this.audioContext) {
this.audioContext.suspend();
}
this.showMessage('播放已停止', 'info');
}
// 更新播放进度
updatePlayback() {
if (!this.isPlaying) return;
const elapsed = (Date.now() - this.startTime) / 1000;
this.currentTime = Math.min(elapsed, this.totalTime);
this.updateProgress();
this.updateVisualization();
if (this.currentTime >= this.totalTime) {
if (this.isLooping) {
this.currentTime = 0;
this.startTime = Date.now();
this.currentSectionIndex = 0;
this.playSection(0);
} else {
this.stop();
}
}
this.animationFrame = requestAnimationFrame(() => this.updatePlayback());
}
// 播放指定段落
async playSection(sectionIndex) {
if (!this.isPlaying || sectionIndex >= this.sections.length) {
if (this.isLooping && this.isPlaying) {
// 循环播放
this.currentSectionIndex = 0;
await this.playSection(0);
}
return;
}
const section = this.sections[sectionIndex];
this.currentSectionIndex = sectionIndex;
// 更新UI
document.getElementById('current-section').textContent = `[${section.name}]`;
this.updateSectionMarkers();
if (section.type === 'interlude') {
// 间奏处理 - 播放纯音乐
await this.playInterlude(section);
} else {
// 演唱段落 - 合成语音和音乐
await this.playSingingSection(section);
}
// 播放下一个段落
if (this.isPlaying) {
await this.playSection(sectionIndex + 1);
}
}
// 播放间奏
async playInterlude(section) {
const duration = this.calculateInterludeDuration(section);
// 生成间奏音乐
await this.generateInstrumentalMusic(this.currentInstrument, duration, 'interlude');
// 等待间奏结束
await new Promise(resolve => {
setTimeout(() => {
if (this.isPlaying) {
resolve();
}
}, duration * 1000);
});
}
// 播放演唱段落
async playSingingSection(section) {
for (const line of section.lyrics) {
if (!this.isPlaying) break;
// 计算行的情感权重
const lineEmotion = this.analyzeLineEmotion(line);
// 合成语音
await this.synthesizeSpeech(line, this.currentVoice, lineEmotion);
// 添加背景音乐和和声
await this.addBackgroundMusic(line, section.type);
// 短暂停顿
await new Promise(resolve => setTimeout(resolve, 200));
}
}
// 分析行的情感
analyzeLineEmotion(line) {
// 简单的情感分析基于关键词
const emotionScores = { ...this.emotionProfile };
const emotionKeywords = {
happiness: ['开心', '快乐', '喜悦', '幸福', '笑'],
sadness: ['悲伤', '伤心', '哭泣', '眼泪', '离别'],
anger: ['愤怒', '生气', '怒吼', '爆发', '恨'],
calmness: ['平静', '安静', '温柔', '轻轻', '慢慢']
};
Object.entries(emotionKeywords).forEach(([emotion, keywords]) => {
keywords.forEach(keyword => {
if (line.includes(keyword)) {
emotionScores[emotion] = Math.min(100, emotionScores[emotion] + 20);
}
});
});
return emotionScores;
}
// 高级语音合成
async synthesizeSpeech(text, voiceType, emotionScores) {
return new Promise((resolve) => {
try {
if ('speechSynthesis' in window) {
const utterance = new SpeechSynthesisUtterance(text);
Back to home |
File page
Subscribe |
Register |
Login
| N