js -音频变音(听不出说话的人是谁)

学习参考来源:

https://zhuanlan.zhihu.com/p/634848804

https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API
实际效果:

http://www.qingkong.zone/laboratory?type=audio-confusion

前言

本文内容可结合上面学习参考来源,结合学习。

之前我遇到的需求主要是对人声进行变音处理,以确保无法通过声音识别出是谁说的这个话,保护隐私。通过Web Audio API即可实现该变声效果。

1. 获取Audio上下文

javascript 复制代码
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

2. 用 audioCtx 与音频源做关联

各个音频源关联方法:

(1) 与audio,vidio标签 或 Audio实例

javascript 复制代码
const audio = new Audio()
const sourceNode = audioCtx.createMediaElementSource(audio)

(2) 获取麦克风

javascript 复制代码
const stream = await navigator.mediaDevices
  .getUserMedia({ audio: true})
  .catch(function (error) {
    console.log(error);
  });
const sourceNode = audioCtx.createMediaStreamSource(stream)

(3) 使用 缓冲器

javascript 复制代码
const loadAudioBuffer = async (url) => {
  const response = await fetch(url);
  const arrayBuffer = await response.arrayBuffer();
  return await audioCtx.decodeAudioData(arrayBuffer);
}
// 获取 audioBuffer
loadAudioBuffer(props.url).then((audioBuffer) => {
  audioCtx.audioBuffer = audioBuffer;
}).catch((error) => {
  console.error("Failed to load audio buffer:", error);
});

// 创建缓冲区
const bufferNode = audioCtx.createBufferSource()

需要注意:缓冲区只能播放一次,所以创建缓冲区逻辑要与播放逻辑放在一起

3. 使用缓冲区后,改写原有音频播放、暂停

声音流添加处理效果就像穿项链一样,一个接一个(引自学习参考来源1)

javascript 复制代码
// 创建多个不同作用功能的node节点
var analyser = audioCtx.createAnalyser();
var distortion = audioCtx.createWaveShaper();
var gainNode = audioCtx.createGain();
var biquadFilter = audioCtx.createBiquadFilter();
var convolver = audioCtx.createConvolver();

// 将所有节点连接在一起

source = audioCtx.createMediaStreamSource(stream);
source.connect(analyser);
analyser.connect(distortion);
distortion.connect(biquadFilter);
biquadFilter.connect(convolver);
convolver.connect(gainNode);
gainNode.connect(audioCtx.destination);

上述代码是帮助你理解 AudioContext 的处理节点如何添加,不是实现代码。

audioCtx.destination 是 AudioContext 的输出源

播放

javascript 复制代码
  if (flag) {
    // 创建缓冲区
    bufferNode = audioCtx.createBufferSource()
    bufferNode.buffer = audioCtx.audioBuffer;
    bufferNode.playbackRate.value = umlautValue;
    
    // 用于修改音量
    gainNode = audioCtx.createGain();
    bufferNode.connect(gainNode);
    gainNode.connect(audioCtx.destination);
    gainNode.gain.value = audioData.volume / 100;
    
    bufferNode.startTime = audioCtx.currentTime - audioData.currentTime;
    bufferNode.start(0, audioData.currentTime);
    bufferNode.onended = () => {
      audioData.status = "play";
      cancelAnimationFrame(animationFrameId);
    };
  } else {
    audio.play()
  }

暂停

javascript 复制代码
  if (flag) {
    bufferNode.stop();
    audioData.currentTime = audioCtx.currentTime - bufferNode.startTime;
    cancelAnimationFrame(animationFrameId);
  } else {
    audio.pause()
  }

4. 使用 requestAnimationFrame 代替 timeupdate 获取实时信息

javascript 复制代码
const updateCurrentTime = () => {
  if (bufferNode && bufferNode.playbackState === bufferNode.PLAYING_STATE) {
    audioData.currentTime = audioCtx.currentTime - bufferNode.startTime;
    audioData.currentValue = audioData.currentTime / audioData.duration * 100 * umlautValue;
    audioData.currentFormat = `${moment.utc(audioData.currentTime * 1000 * umlautValue).format("mm:ss")} / ${moment.utc(audioData.duration * 1000).format("mm:ss")}`;
  }
  animationFrameId = requestAnimationFrame(updateCurrentTime);
}

在需要关闭的地方

javascript 复制代码
cancelAnimationFrame(animationFrameId);

5. 音频变音核心逻辑

本文走的是 变速变调 的路子,改变声音播放速率情况下,音调音色也会随着改变,例如玩过磁带的都知道,按快进功能会使声音变尖提高音调,慢放功能使声音变粗,降低音调。

为了让音频进度条与 加速或减速 的速率保持一致,需创建个变量做统一管理

javascript 复制代码
const umlautValue = 1.5

6. 结尾

在销毁前记得销毁这些节点

javascript 复制代码
  if (bufferNode) {
    bufferNode.stop();
  }
  if (gainNode) {
    gainNode.disconnect();
  }
  cancelAnimationFrame(animationFrameId);

喜欢的话不妨点个小小的赞与关注,您的赞与关注将是我源源不断的前进动力。

相关推荐
RobinDevNotes2 小时前
从 Electron 到 GPUI,9 个跨平台桌面方案该怎么选
前端·javascript·rust·electron·openresty·前端开发工具
程序员大阳3 小时前
HTML+CSS+JS对话式实战(6)-学生端查看活动功能开发
javascript·css·html·模块·查看学生
噢,我明白了4 小时前
JAVA中的一些基础应用知识点
java·开发语言
时间的拾荒人5 小时前
Redis 入门详解:核心特性、重要文件与全局命令实战
开发语言·redis·面试
敲上瘾5 小时前
Qt Widgets入门:项目模板解析与Hello World
开发语言·数据库·c++·qt·ui·qt6.3
码途行者6 小时前
网站的SQL 注入:从攻击原理到防御措施
开发语言·sql·php
旖旎夜光7 小时前
【C++ 基础入门】C++ 多态(中):虚函数表、多态原理与动静绑定
开发语言·c++·笔记·学习
你看我名字7 小时前
产品参数昨天还对,今天已过期:数眼智能与大模型应用如何做资料版本校验
开发语言·架构
老秦包你会8 小时前
计算机网络第二课 ----Socket(套接字)编程预备
开发语言·计算机网络·php
旖旎夜光8 小时前
【C++ 基础入门】C++多态(下):单/多继承虚表、多态补充与 21 道高频题
开发语言·c++·笔记·学习