首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Timeline Studio 浏览器本地多语言声音克隆技术归档:OpenVoice V2 FP16 ONNX 实现

Timeline Studio 浏览器本地多语言声音克隆技术归档:OpenVoice V2 FP16 ONNX 实现

原创
作者头像
用户5557817
发布2026-08-06 15:58:26
发布2026-08-06 15:58:26
1500
举报

本文记录 Timeline Studio 浏览器本地声音克隆功能的完整技术实现,包括模型组织、音频预处理、ONNX Runtime Web 推理、浏览器缓存、IndexedDB 声音档案、时间线集成以及输出音频处理。

项目仓库:

https://github.com/MartinDelophy/ai-video-editor

一、功能范围

本次实现的目标是在浏览器中完成声音样本录制、音色特征提取、基础语音生成和音色迁移。

完整用户工作流为:

代码语言:plaintext
复制
录制或上传参考声音
        ↓
浏览器本地提取音色特征
        ↓
生成指定语言的基础语音
        ↓
转换为目标音色
        ↓
试听转换结果
        ↓
保存为浏览器声音档案
        ↓
用于后续配音或已有音频片段

参考声音和音色特征不会上传到业务服务器。

二、模型文件

浏览器运行时使用两个 FP16 ONNX 模型:

文件

大小

用途

reference-encoder.onnx

1,637,269 Bytes

提取参考声音的音色特征

converter.onnx

64,314,222 Bytes

执行源音频到目标音色的转换

合计

65,951,491 Bytes

浏览器声音克隆运行包

模型目录:

代码语言:plaintext
复制
openvoice-v2-converter-fp16/
├── LICENSE
├── README.md
├── config.json
├── reference-encoder.onnx
└── converter.onnx

Hugging Face:

https://huggingface.co/haixin/timeline-studio-voice-models/tree/d9e0542e0e4e8fcfb849240f7e8e7fa8147df1a3/openvoice-v2-converter-fp16

ModelScope:

https://www.modelscope.cn/models/martindelophy/timeline-studio-voice-models/files?version=226b24270b69b38781a35566c7d442061f9e3b81&subpath=openvoice-v2-converter-fp16

生产环境固定到不可变 revision,不从 main 分支动态加载模型。

三、浏览器运行架构

声音克隆运行在独立 Web Worker 中。

代码语言:plaintext
复制
React UI
   ↓ postMessage
OpenVoice Worker
   ├── 模型下载与缓存
   ├── Reference Encoder Session
   ├── Converter Session
   ├── FFT 与频谱计算
   ├── 音色特征提取
   ├── 音色迁移
   └── 尾部清理
   ↓ Transferable ArrayBuffer
Main Thread
   ├── WAV 编码
   ├── IndexedDB 保存
   ├── My assets
   └── Timeline Clip

主线程负责界面和项目状态,Worker 负责模型加载和音频计算。

音频数据通过 Transferable ArrayBuffer 传递,避免在主线程与 Worker 之间复制大块 PCM 数据。

取消任务时会直接终止 Worker,并清理所有未完成的 Promise。

四、音频解码与重采样

用户上传的参考音频可能是 WAV、MP3、M4A 或 WebM。

浏览器首先使用 AudioContext.decodeAudioData() 解码,再通过 OfflineAudioContext 统一重采样。

内部音频格式为:

参数

数值

采样率

22,050 Hz

声道

单声道

内部采样

Float32 PCM

最终输出

16-bit PCM WAV

处理过程:

代码语言:plaintext
复制
Audio Blob
   ↓
decodeAudioData
   ↓
OfflineAudioContext
   ↓
22.05 kHz Mono Float32Array

统一音频格式后,模型不需要处理浏览器上传文件之间的采样率和声道差异。

五、频谱计算

OpenVoice Converter 使用频谱作为输入。

浏览器端实现了 Hann 窗、FFT 和 STFT 计算。

参数

数值

FFT Size

1024

Hop Size

256

Frequency Bins

513

Reference Encoder 输入形状:

代码语言:plaintext
复制
spectrogram_frames: [1, FrameCount, 513]

Converter 输入形状:

代码语言:plaintext
复制
spectrogram: [1, 513, FrameCount]
frame_mask:  [1, 1, FrameCount]

频谱计算和维度转换全部在 Worker 中完成。

六、音色特征提取

参考声音经过 reference-encoder.onnx 后生成 256 维音色特征:

代码语言:plaintext
复制
speaker_embedding: [1, 256, 1]

这个 Embedding 是浏览器声音档案的核心数据。

当用户保存克隆声音时,系统同时保存:

代码语言:plaintext
复制
referenceBlob
testBlob
speakerEmbedding
sourceKind
favorite
authorized
createdAt
updatedAt

再次使用已经保存的声音时,可以直接读取 Embedding,不需要重新分析参考音频。

七、多语言处理工作流

语言生成和音色迁移是两个独立阶段。

代码语言:plaintext
复制
文本
  ↓
根据目标语言选择基础 TTS
  ↓
生成目标语言源音频
  ↓
提取源音频的音色特征
  ↓
加载已保存的目标音色特征
  ↓
OpenVoice Converter
  ↓
目标语言 + 目标音色

中文克隆测试使用中文基础语音,英文使用英文基础语音,其他语言按照所选声音模型处理。

OpenVoice 在这个工作流中只负责音色迁移。文本解析、语言发音和说话节奏由基础 TTS 负责。

Converter 的主要输入为:

代码语言:plaintext
复制
spectrogram:       [1, 513, T]
frame_mask:        [1, 1, T]
source_embedding:  [1, 256, 1]
target_embedding:  [1, 256, 1]
noise:             [1, 192, T]

噪声输入使用固定种子生成,保证相同输入具有可复现性。

八、ONNX Runtime Web Session

运行时使用:

代码语言:javascript
复制
import * as ort from "onnxruntime-web/webgpu";

执行策略:

代码语言:plaintext
复制
Reference Encoder
└── WASM Execution Provider

Converter
├── WebGPU Execution Provider
└── WASM Fallback

Converter 首先尝试:

代码语言:javascript
复制
executionProviders: ["webgpu", "wasm"]

如果 WebGPU Session 初始化失败,则重新创建 WASM Session。

所有 Session 使用:

代码语言:javascript
复制
graphOptimizationLevel: "all"

WebGPU 适配器使用:

代码语言:javascript
复制
ort.env.webgpu.powerPreference = "high-performance";

WASM 配置:

代码语言:javascript
复制
ort.env.wasm.simd = true;
ort.env.wasm.numThreads = crossOriginIsolated
  ? Math.min(4, navigator.hardwareConcurrency)
  : 1;

模型文件并行下载,Session 顺序初始化,避免两个模型同时编译造成较高的瞬时内存占用。

九、FP16 与 FP8 技术决策记录

当前生产模型固定使用 FP16。

这里的 FP16 是浮点降精度部署,不等同于传统 INT8 整数量化。

没有发布 FP8 版本的原因是当前浏览器 WebGPU 计算链路缺少通用、稳定的 Float8 原生执行能力。

ONNX 文件格式可以描述 Float8 类型,但模型进入浏览器后仍可能需要:

代码语言:plaintext
复制
FP8 Weight
   ↓
Cast / Dequantize
   ↓
FP16 或 FP32 Tensor
   ↓
WebGPU Kernel

这意味着 FP8 文件可以减少网络传输和磁盘占用,但不一定减少实际计算张量和 GPU Buffer 的体积。

同时还会增加:

  • Cast 或 Dequantize 节点
  • WebGPU 算子覆盖要求
  • WASM 回退概率
  • CPU 与 GPU 之间的数据交换
  • 浏览器和显卡之间的兼容差异
  • 音频生成结果的精度验证成本

因此,当前版本将 FP16 作为浏览器生产格式。FP8 保留为后续实验方向,在浏览器运行时、硬件支持和音频质量验证链路成熟后再重新评估。

十、模型镜像与缓存

模型同时存储在 Hugging Face 和 ModelScope。

路由规则:

代码语言:plaintext
复制
中文界面或国内环境
    → ModelScope
    → Hugging Face fallback

其他环境
    → Hugging Face
    → ModelScope fallback

两个来源使用相同的 provider-independent cache identity。

因此,切换模型源不会在浏览器中保存两份相同模型。

模型加载前会请求:

代码语言:javascript
复制
navigator.storage.persist()

如果浏览器拒绝持久化,功能仍然可以运行。

缓存写入发生 QuotaExceededError 时,处理策略是:

  • 不把缓存失败作为推理失败
  • 跳过本次持久化写入
  • 继续使用已经下载到内存中的模型
  • 不向用户展示原始 Failed to fetch
  • 下次请求重新检查可用模型源和缓存空间

早期预发布缓存会在新运行时初始化时清理,生产环境只保留 Service Worker 管理的统一缓存。

十一、输出尾部处理

模型转换结果曾出现轻微长尾声音。

原因是输出包含频谱补齐区域,随机噪声输入可能在这些无效区域产生低幅值波形。

为此增加了基于源音频 RMS 的结束位置检测。

参数

数值

RMS 窗口

20 ms

滑动步长

10 ms

最低有效峰值

0.0025

活动阈值

max(0.0015, peakRms × 0.035)

尾部保留

160 ms

淡出长度

40 ms

处理流程:

代码语言:plaintext
复制
源音频
  ↓
计算分段 RMS
  ↓
查找最后一个有效语音窗口
  ↓
保留 160 ms 自然尾部
  ↓
裁剪模型填充区域
  ↓
应用 40 ms 余弦淡出

当参考音频整体非常安静时,不执行激进裁剪,防止真实语音尾部被误删。

十二、输出增益与限幅

克隆音频支持 0% 到 400% 输出增益。

为了避免直接放大产生硬削波,增益后使用 tanh 软限幅:

代码语言:javascript
复制
const amplified = sample * gain;
const output =
  Math.tanh(amplified * 1.35) /
  Math.tanh(1.35);

最终重新编码为 22.05 kHz、单声道、16-bit PCM WAV。

十三、IndexedDB 声音档案

已保存声音存储在 IndexedDB,而不是 Local Storage。

数据结构包含:

代码语言:javascript
复制
{
  id,
  name,
  sourceKind,
  referenceBlob,
  testBlob,
  embedding,
  favorite,
  authorized,
  createdAt,
  updatedAt
}

IndexedDB 可以直接保存 Blob 和 TypedArray,适合保存参考音频、试听音频和音色 Embedding。

声音档案支持:

  • 选择
  • 试听
  • 收藏
  • 取消收藏
  • 删除
  • 重新用于多语言语音生成
  • 用于已有音频片段的音色迁移

十四、时间线音频集成

声音克隆不仅存在于语音生成面板,也被接入音频片段属性。

选中配音或其他可转换音频后,可以进入“音色”面板:

代码语言:plaintext
复制
当前源音频
  ↓
选择已保存声音
或上传/录制临时参考声音
  ↓
提取或读取目标 Embedding
  ↓
执行转换
  ↓
试听迁移结果
  ↓
保存到 My assets
  ↓
替换当前片段

片段替换时会保留原始音频信息。

用户可以执行:

代码语言:plaintext
复制
替换当前片段
        ↓
继续编辑
        ↓
恢复原始声音

转换结果不会在生成后自动插入时间线,必须由用户确认替换。

十五、界面与本地化

本次声音克隆工作流覆盖 11 种界面语言:

  • 中文
  • English
  • 日本語
  • 한국어
  • Español
  • Français
  • Deutsch
  • Português
  • ไทย
  • Tiếng Việt
  • Русский

声音克隆相关状态均有独立翻译,包括:

  • 录制与上传
  • 音色提取
  • 克隆试听
  • 模型准备
  • 转换进度
  • 保存成功
  • 转换失败
  • 浏览器本地处理说明
  • 授权确认
  • 片段替换与恢复

不同语言的 Tab 文案按照各自语言习惯处理,没有对所有语言机械使用相同长度。

本文作为 Timeline Studio 浏览器本地声音克隆功能的工程实现归档,后续模型格式、浏览器执行后端、缓存版本和音频处理参数发生变化时,将继续按照版本提交记录更新。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、功能范围
  • 二、模型文件
  • 三、浏览器运行架构
  • 四、音频解码与重采样
  • 五、频谱计算
  • 六、音色特征提取
  • 七、多语言处理工作流
  • 八、ONNX Runtime Web Session
  • 九、FP16 与 FP8 技术决策记录
  • 十、模型镜像与缓存
  • 十一、输出尾部处理
  • 十二、输出增益与限幅
  • 十三、IndexedDB 声音档案
  • 十四、时间线音频集成
  • 十五、界面与本地化
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档