refactor : 重构TTS的文字分割方式,队列请求/播放方式, fix : asr录制音频的音量波纹显示

This commit is contained in:
2025-12-29 10:08:20 +08:00
parent f6b7755e32
commit 9769f486f0
4 changed files with 1224 additions and 568 deletions

View File

@@ -95,43 +95,81 @@ export function useRealtimeRecorderOnce() {
// --- 音量计算函数 ---
const calculateVolumeFromFloat32 = (float32Array) => {
if (!float32Array || float32Array.length === 0) return 0;
let sum = 0;
const length = float32Array.length;
// 计算RMS (均方根)
for (let i = 0; i < length; i++) {
sum += float32Array[i] * float32Array[i];
// 绝对值方法更敏感
const absValue = Math.abs(float32Array[i]);
sum += absValue * absValue;
}
const rms = Math.sqrt(sum / length);
// 调试打印原始RMS值
// console.log('Float32 RMS:', rms);
// 转换为0-100的值
// 通常对话语音的RMS在0.01-0.1之间尖叫可达0.3
let volume = Math.min(100, Math.floor(rms * 300));
// 使用对数刻度,使小音量变化更明显
let volume = 0;
if (rms > 0) {
// 使用对数转换:-60dB到0dB映射到0-100
const db = 20 * Math.log10(rms);
// 静音阈值约-60dB
if (db > -60) {
volume = Math.min(100, Math.max(0, (db + 60) / 0.6));
}
}
// 设置最小阈值避免静音时完全为0
if (volume < 5) volume = 0;
// 如果没有计算到值使用旧方法作为fallback
if (volume === 0 && rms > 0) {
volume = Math.min(100, Math.floor(rms * 500));
}
return volume;
// 确保最小值为0
return Math.max(0, volume);
}
const calculateVolumeFromInt16 = (int16Array) => {
if (!int16Array || int16Array.length === 0) return 0;
let sum = 0;
const length = int16Array.length;
// 计算RMS
for (let i = 0; i < length; i++) {
const normalized = int16Array[i] / 32768; // 归一化到[-1, 1]
sum += normalized * normalized;
const absValue = Math.abs(normalized);
sum += absValue * absValue;
}
const rms = Math.sqrt(sum / length);
// 调试打印原始RMS值
// console.log('Int16 RMS:', rms);
// 转换为0-100的值
let volume = Math.min(100, Math.floor(rms * 300));
// 设置最小阈值
if (volume < 5) volume = 0;
return volume;
// 使用对数刻度
let volume = 0;
if (rms > 0) {
const db = 20 * Math.log10(rms);
if (db > -60) {
volume = Math.min(100, Math.max(0, (db + 60) / 0.6));
}
}
// 如果没有计算到值使用旧方法作为fallback
if (volume === 0 && rms > 0) {
volume = Math.min(100, Math.floor(rms * 500));
}
// 确保最小值为0
return Math.max(0, volume);
}
/**
@@ -377,29 +415,67 @@ export function useRealtimeRecorderOnce() {
return;
}
// 生成波形数据,基于当前音量
const baseValue = volumeLevel.value / 100;
// 获取当前音量
const currentVolume = volumeLevel.value;
// 调试:打印音量值
// console.log('Current Volume:', currentVolume);
// 生成适合 WaveDisplay 的数据
const data = [];
// 生成31个数据点
const center = 15; // 中心索引
const timeFactor = Date.now() / 150; // 更快的动画
// 根据音量动态调整波形强度
const volumeFactor = currentVolume / 100;
// 添加基础噪声,使波形在安静时也有轻微活动
const baseNoise = Math.random() * 0.1;
for (let i = 0; i < 31; i++) {
// 使用正弦波生成波形效果,中间高两边低
const position = i / 30;
const centerDistance = Math.abs(position - 0.5);
const waveValue = Math.sin(Date.now() / 200 + i * 0.3) * 0.4 + 0.5;
// 音量因子确保最小显示高度
const volumeFactor = baseValue * 0.7 + 0.3;
// 综合计算最终值
let finalValue = waveValue * (1 - centerDistance) * volumeFactor;
finalValue = Math.max(0.1, Math.min(1, finalValue));
data.push(finalValue);
// 距离中心的位置
const distanceFromCenter = Math.abs(i - center) / center;
// 基础波形模式
const basePattern = 1 - Math.pow(distanceFromCenter, 1.2);
// 动态效果
const dynamicEffect = Math.sin(timeFactor + i * 0.3) * 0.3;
// 计算基础值
let value;
if (volumeFactor > 0.1) {
// 有音量时:音量因子占主导
value = volumeFactor * 0.8 * basePattern +
volumeFactor * 0.4 +
dynamicEffect * volumeFactor * 0.5;
} else {
// 安静时:使用动态效果和基础噪声
value = basePattern * 0.2 +
dynamicEffect * 0.1 +
baseNoise;
}
// 确保值在有效范围内
value = Math.max(0.15, Math.min(1, value));
// 随机微调
const randomVariance = volumeFactor > 0.1 ? 0.15 : 0.05;
value += (Math.random() - 0.5) * randomVariance;
value = Math.max(0.15, Math.min(1, value));
data.push(value);
}
audioDataForDisplay.value = data;
}, 50); // 更快的刷新率,更流畅
// 调试:检查生成的数据范围
// const min = Math.min(...data);
// const max = Math.max(...data);
// console.log(`Data range: ${min.toFixed(3)} - ${max.toFixed(3)}`);
}, 50);
}
/**