根据上面这张图,我们写好了以下的程序码,就成功得到经由傅立叶转换的音频讯号了,取得了名为dataArray音频阵列,耶比~~可以开始图像化了!
// 创建音讯物件
let AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx = new AudioContext();
// 创建节点
let audio = document.querySelector("#Music");
let source = audioCtx.createMediaElementSource(audio);
let gainNode = audioCtx.createGain();
let analyserNode = audioCtx.createAnalyser();
// 连接节点
source.connect(gainNode);
gainNode.connect(analyserNode);
analyserNode.connect(audioCtx.destination);
// 对每个节点进行设定
gainNode.gain.value = 1;
analyserNode.fftSize = 2048;
// 利用analyserNode取得当下的音频讯号
let bufferLength = analyserNode.frequencyBinCount;
let dataArray = new Uint8Array(bufferLength);
analyserNode.getByteFrequencyData(dataArray);
咦? 你说这样有点跳太快了吗
开玩笑的啦,待会就一步一步拆解给大家看呗,今天有不少知识点,先让大家熟悉今天的六个名词
名词有点多对吧!没关系我们慢慢来,先从最简单的开始:「如果我今天要在底层实作一个音乐播放器,可以怎麽做?」
// 步骤 1
let audio = document.querySelector("#Music");
// 步骤 2
let AudioContext = window.AudioContext || window.webkitAudioContext; // 跨浏览器写法
let audioCtx = new AudioContext();
let source = audioCtx.createMediaElementSource(audio);
// 步骤 3
source.connect(audioCtx.destination);
如果少了步骤3,你会发现这个ID为#Music的audio元件不能播放了!因为在步骤2的时候,我们已经把它音讯放到了audio当中做处理,必须主动执行步骤3接到音讯出口,才能让它有音源可以播放。也就是说,你现在是DJ了!可以决定任何一个混音源(节点),最後要不要接上去。
以下是用来制作昨天的Demo时,用到的5个步骤:
// 步骤 1
let AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx = new AudioContext();
// 步骤 2
let audio = document.querySelector("#Music");
let source = audioCtx.createMediaElementSource(audio);
let gainNode = audioCtx.createGain();
let analyserNode = audioCtx.createAnalyser();
// 步骤 3
source.connect(gainNode);
gainNode.connect(analyserNode);
analyserNode.connect(audioCtx.destination);
// 步骤 4
gainNode.gain.value = 1;
analyserNode.fftSize = 2048;
// 步骤 5
let bufferLength = analyserNode.frequencyBinCount;
let dataArray = new Uint8Array(bufferLength);
analyserNode.getByteFrequencyData(dataArray);
这样是不是清楚多了呢?
这个步骤5是相当关键的一环,允许你取得音频并进行分析,先来解释出现的新东西:
关於傅立叶(微积分),简单来说,就是你做越多次,效果越好,花的时间越多;做越少次,效果越差(失真),花的时间越少。还是不太理解的朋友没关系,你就把fftSize设个256也很够用了!那麽你只需要准备长度为analyserNode.frequencyBinCount(刚好会是128)的阵列去装讯号就好。若是上面的例子来说,长度会刚好是1024。
讲到这聪明的你也应该明白了吧,如果不担心取得的音讯失真的话,fftSize简直是越小越好,阵列越短,对於效能的优化当然是越好!而dataArray代表了每个频段的信号大小,fftSize越小,显然频宽越大,也因此才会失真。
这边还有几个知识点要补充:
而总频率又被记录在一开始的音源audioContext中,预设为48000。这边就先爆个雷,明天会用到以下程序码:
let bands = audioCtx.sampleRate / (analyserNode.fftSize / 2); // 每个区段的频宽
let highestBands = 16000; // 16kHz高音频以下的音乐
let index = highestBands / bands;
假如我想绘制的频率信号,最多只到高音频16kHz,那就用这个去除以阵列每个间隔的频率宽度bands,就可以得到16kHz对应於dataArray的索引位置index了!
那麽明天我们就可以把拿到手的dataArray图像化罗!
整理文章真的是一门大学问...光是懂还不行,要讲得清楚,安排前後上下文,本来以为分享技术这件事很简单,没想到这麽花时间!再次赞叹网路上,有这麽多无私分享的大神。
该系列文章内文和程序码皆出自本人撰写,名词解释参考MDN Web Docs文件。
<<: Day 11-假物件 (Fake) - 虚设常式 (Stub)-3 (核心技术-3)
前言 今天要来介绍一下用於数学运算的函式,sqrt 开根号,以及 square 平方 NumPy n...
大家好~ 我是五岁~ 今天要来画可爱的殭屍女孩~ 风格类似是中国殭屍,她外观上有两个巨大的手手可以跟...
不怎麽重要的前言 上一篇介绍了for loop的概念,让大家面对在有重复性、明确次数的处理时,可以使...
大家好,我是阿飞,今天的题目是演算法初阶题目 Two Sum,让我们一起来看看: 题目来源 Code...
工欲善其事,必先利其器,好的开始是成功的一半~ 今天来把要使用的环境建立好 这次我选用的是线上编辑器...