ç½é¡µé³é¢æ¥å£ææè¶£çç¹æ§ä¹ä¸å®å°±æ¯å¯ä»¥è·åé¢çãæ³¢å½¢åå ¶ä»æ¥èªå£°æºçæ°æ®ï¼è¿äºæ°æ®å¯ä»¥è¢«ç¨ä½é³é¢å¯è§åãè¿ç¯æç« å°è§£éå¦ä½åå°å¯è§åï¼å¹¶æä¾äºä¸äºåºç¡ä½¿ç¨æ¡ä¾ã
夿³¨ï¼ ä½ å¯ä»¥å¨Voice-change-O-maticæ¼ç¤ºéæ¾å°æ¬æåºç°çææä»£ç çæ®µã
åºæ¬æ¦å¿µè¦ä»ä½ çé³é¢æºè·åæ°æ®ï¼ä½ éè¦ä¸ä¸ª AnalyserNode
èç¹ï¼å®å¯ä»¥ç¨ AudioContext.createAnalyser()
æ¹æ³åå»ºï¼æ¯å¦ï¼
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();
ç¶åæè¿ä¸ªèç¹ï¼nodeï¼è¿æ¥å°ä½ ç声æºï¼
source = audioCtx.createMediaStreamSource(stream);
source.connect(analyser);
analyser.connect(distortion);
// etc.
夿³¨ï¼ åæå¨èç¹ (Analyser Node) ä¸ä¸å®è¾åºå°å¦ä¸ä¸ªèç¹ï¼ä¸è¾åºæ¶ä¹å¯ä»¥æ£å¸¸ä½¿ç¨ãä½åææ¯å®å¿ é¡»ä¸ä¸ä¸ªå£°æºç¸è¿ï¼ç´æ¥æè éè¿å ¶ä»èç¹é´æ¥ç¸è¿é½å¯ä»¥ï¼ã
åæå¨èç¹ (Analyser Node) å°å¨ä¸ä¸ªç¹å®çé¢çåé使ç¨å¿«éå
ç«å¶åæ¢(Fast Fourier Transform (FFT) ) æ¥æè·é³é¢æ°æ®ï¼è¿åå³äºä½ ç» AnalyserNode.fftSize
屿§èµçå¼ï¼å¦ææ²¡æèµå¼ï¼é»è®¤å¼ä¸º 2048ï¼ã
夿³¨ï¼ ä½ ä¹å¯ä»¥ä¸º FFT æ°æ®ç¼©æ¾èå´æå®ä¸ä¸ªæå°å¼åæå¤§å¼ï¼ä½¿ç¨AnalyserNode.minDecibels
åAnalyserNode.maxDecibels
è¿è¡è®¾ç½®ï¼è¦è·å¾ä¸åæ°æ®çå¹³å常éï¼ä½¿ç¨ AnalyserNode.smoothingTimeConstant
ãé
读è¿äºé¡µé¢ä»¥è·å¾æ´å¤å¦ä½ä½¿ç¨å®ä»¬çä¿¡æ¯ã
è¦æè·æ°æ®ï¼ä½ éè¦ä½¿ç¨ AnalyserNode.getFloatFrequencyData()
æ AnalyserNode.getByteFrequencyData()
æ¹æ³æ¥è·åé¢çæ°æ®ï¼ç¨ AnalyserNode.getByteTimeDomainData()
æ AnalyserNode.getFloatTimeDomainData()
æ¥è·åæ³¢å½¢æ°æ®ã
è¿äºæ¹æ³ææ°æ®å¤å¶è¿äºä¸ä¸ªç¹å®çæ°ç»å½ä¸ï¼æä»¥ä½ å¨è°ç¨å®ä»¬ä¹åè¦å
å建ä¸ä¸ªæ°æ°ç»ã第ä¸ä¸ªæ¹æ³ä¼äº§çä¸ä¸ª 32 使µ®ç¹æ°ç»ï¼ç¬¬äºä¸ªå第ä¸ä¸ªæ¹æ³ä¼äº§ç 8 使 ç¬¦å·æ´åæ°ç»ï¼å æ¤ä¸ä¸ªæ åç JavaScript æ°ç»å°±ä¸è½ä½¿ç¨ââä½ éè¦ç¨ä¸ä¸ª Float32Array
æè
Uint8Array
æ°ç»ï¼å
·ä½éè¦åªä¸ªè§æ
åµèå®ã
é£ä¹è®©æä»¬æ¥ççä¾åï¼æ¯å¦æä»¬æ£å¨å¤çä¸ä¸ª 2048 尺寸ç FFTãæä»¬è¿å AnalyserNode.frequencyBinCount
å¼ï¼å®æ¯ FFT çä¸åï¼ç¶åè°ç¨ Uint8Array()ï¼æ frequencyBinCount ä½ä¸ºå®çé¿åº¦åæ°ââè¿ä»£è¡¨æä»¬å°å¯¹è¿ä¸ªå°ºå¯¸ç FFT æ¶éå¤å°æ°æ®ç¹ã
analyser.fftSize = 2048;
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
è¦æ£ç¡®æ£ç´¢æ°æ®å¹¶æå®å¤å¶å°æä»¬çæ°ç»éï¼å°±è¦è°ç¨æä»¬æ³è¦çæ°æ®æ¶éæ¹æ³ï¼ææ°ç»ä½ä¸ºåæ°ä¼ éç»å®ï¼ä¾å¦ï¼
analyser.getByteTimeDomainData(dataArray);
ç°å¨æä»¬å°±è·åäºé£æ¶çé³é¢æ°æ®ï¼å¹¶åå°äºæä»¬çæ°ç»éï¼èä¸å¯ä»¥æå®åææä»¬å欢çå¯è§åææäºï¼æ¯å¦æå®ç»å¨ä¸ä¸ª HTML5 <canvas>
ç»å¸ä¸ã
ä¸é¢è®©æä»¬æ¥çä¸äºå ·ä½çä¾åã
å建ä¸ä¸ªæ³¢å½¢/示波å¨è¦å建ä¸ä¸ªç¤ºæ³¢å¨è§è§ææï¼æè°¢ Soledad Penadés å¨ Voice-change-O-matic 䏿ä¾çæºç ï¼ï¼æä»¬é¦å ç¨ä¸é¢ä»£ç æ¡ä¸ç代ç 为æ å设置ä¸ä¸ª bufferï¼
analyser.fftSize = 2048;
var bufferLength = analyser.fftSize;
var dataArray = new Uint8Array(bufferLength);
æ¥ä¸æ¥ï¼æä»¬æ¸ 空ç»å¸ä¸ºç»å¶æ°çå¯è§åææååå¤ï¼
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
ç°å¨æä»¬æ¥å®ä¹ draw()
彿°ï¼
è¿éæä»¬ç¨ requestAnimationFrame()
æ¥ä¿æç»å¾æç»æ´æ°ï¼
drawVisual = requestAnimationFrame(draw);
æ¥ä¸æ¥æä»¬è·åæ¶é´åä¸çæ°æ®å¹¶å°å®å¤å¶å°æ°ç»å½ä¸ï¼
analyser.getByteTimeDomainData(dataArray);
æ¥ä¸æ¥æ canvas ç¨çº¯è²å¡«æ»¡ä½ä¸ºèæ¯ï¼
canvasCtx.fillStyle = "rgb(200, 200, 200)";
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
为æä»¬è¦ç»ç波形设置好线宽å线çé¢è²ï¼ç¶åå¼å§ç»å¶è·¯å¾ï¼
canvasCtx.lineWidth = 2;
canvasCtx.strokeStyle = "rgb(0, 0, 0)";
canvasCtx.beginPath();
ç¨ canvas ç»å¸çæ»å®½åº¦é¤ä»¥æ°ç»çé¿åº¦ï¼ä¸ä¹åå®ä¹ç FrequencyBinCount ç¸çï¼æ¥å³å®è¦è±ä¸çæ¯æ®µçº¿æ¡ç宽度ï¼ä¹åè®¾ç½®æ¨ªåæ (x) 为 0ï¼å°ç»ç¬ç§»å¨å°èµ·å§ä½ç½®ï¼
var sliceWidth = (WIDTH * 1.0) / bufferLength;
var x = 0;
æ¥ä¸æ¥æä»¬è¿å ¥å¾ªç¯ï¼éåæ°ç»ï¼éè¿å ¶ä¸çæ°æ®æ¥ç¡®å®æ¯æ®µçº¿æ¡çé«åº¦ï¼ä¹åæ¹åæ¨ªåæ å°ç»ç¬ç§»å¨å°ä¸ä¸æ®µçº¿æ¡å¼å§çå°æ¹ï¼
for (var i = 0; i < bufferLength; i++) {
var v = dataArray[i] / 128.0;
var y = (v * HEIGHT) / 2;
if (i === 0) {
canvasCtx.moveTo(x, y);
} else {
canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
æåï¼æä»¬æçº¿è¿å°å³è¾¹çä¸å¤®ï¼ç¶åç»åºæ¥ï¼
canvasCtx.lineTo(canvas.width, canvas.height/2);
canvasCtx.stroke();
};
å¨è¿åä»£ç æåï¼æä»¬è°ç¨ draw()
彿°æ¥å¼å§æ´ä¸ªè¿ç¨ï¼
è¿ä¸ªæ¼ç¤ºç»åºäºä¸ä¸ªæ¯ç§ä¼å·æ°å 次并ä¸çèµ·æ¥è¿ä¸éçæ³¢å½¢å¾ï¼
å建ä¸ä¸ªé¢çæ¡å½¢å¾å¦ä¸ç§å°å·§çå¯è§åæ¹æ³æ¯å建é¢çæ¡å½¢å¾ï¼å¨ Voice-change-O-matic ä¸å·²ç»æä¸ä¸ªå好çï¼ç°å¨è®©æä»¬æ¥çç宿¯å¦ä½å®ç°çã
é¦å ï¼æä»¬è®¾ç½®å¥½è§£æå¨å空æ°ç»ï¼ä¹åç¨ clearRect() æ¸ ç©ºç»å¸ãä¸ä¹åçå¯ä¸åºå«æ¯æä»¬è¿æ¬¡å¤§å¤§åå°äº FFT ç大å°ï¼è¿æ ·åçåå æ¯ä¸ºäºä½¿å¾æ¯ä¸ªé¢çæ¡è¶³å¤å®½ï¼è®©å®ä»¬ççåâæ¡âè䏿¯âç»æâã
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
æ¥ä¸æ¥æä»¬å好 draw()
彿°ï¼å䏿¬¡ç¨ requestAnimationFrame()
设置ä¸ä¸ªå¾ªç¯ï¼è¿æ ·æ¾ç¤ºçæ°æ®å°±å¯ä»¥ä¿æå·æ°ï¼å¹¶ä¸æ¯ä¸å¸§é½æ¸
ç©ºä¸æ¬¡ç»å¸ã
function draw() {
drawVisual = requestAnimationFrame(draw);
analyser.getByteFrequencyData(dataArray);
canvasCtx.fillStyle = 'rgb(0, 0, 0)';
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
ç°å¨æä»¬æ¥è®¾ç½®ä¸ä¸ª barWidth
åéï¼å®çäºæ¯ä¸ä¸ªæ¡å½¢ç宽度ãç论ä¸ç¨è±å¸å®½åº¦é¤ä»¥æ¡ç个æ°å°±å¯ä»¥å¾å°å®ï¼ä½æ¯å¨è¿éæä»¬è¿è¦ä¹ä»¥ 2.5ãè¿æ¯å 为æå¾å¤è¿åçé¢çåºå䏿¯æ²¡æå£°é³çï¼æä»¬æ¯å¤©å¬å°ç大夿°å£°é³ä¹åªæ¯å¨ä¸ä¸ªå¾å°çé¢çåºåå½ä¸ã卿¡å½¢å¾ä¸æä»¬è¯å®ä¸æ³çå°å¤§ççç©ºç½æ¡ï¼æä»¥æä»¬å°±æä¸äºè½æ£å¸¸æ¾ç¤ºçæ¡å½¢æå®½æ¥å¡«å
è¿äºç©ºç½åºåã
æä»¬è¿è¦è®¾ç½®ä¸ä¸ªæ¡é«åº¦åé barHeight
ï¼è¿æä¸ä¸ª x
åéæ¥è®°å½å½åæ¡å½¢çä½ç½®ã
var barWidth = (WIDTH / bufferLength) * 2.5;
var barHeight;
var x = 0;
åä¹å䏿 ·ï¼æä»¬è¿å
¥å¾ªç¯æ¥éå dataArray
æ°ç»ä¸çæ°æ®ã卿¯ä¸æ¬¡å¾ªç¯è¿ç¨ä¸ï¼æä»¬è®©æ¡å½¢çé«åº¦ barHeight
çäºæ°ç»çæ°å¼ï¼ä¹åæ ¹æ®é«åº¦è®¾ç½®æ¡å½¢çå¡«å
è²ï¼æ¡å½¢è¶é«ï¼å¡«å
è²è¶äº®ï¼ï¼ç¶å卿¨ªåæ x
夿ç
§è®¾ç½®ç宽度åé«åº¦çä¸åææ¡å½¢ç»åºæ¥ï¼æä»¬æåå³å®åªç»é«åº¦çä¸åå ä¸ºè¿æ ·æ¡å½¢çèµ·æ¥æ´ç¾è§ï¼ã
éè¦å¤å è§£éçä¸ç¹æ¯æ¯ä¸ªæ¡å½¢ç«ç´æ¹åçä½ç½®ï¼æä»¬å¨ HEIGHT-barHeight/2
çä½ç½®ç»æ¯ä¸æ¡ï¼è¿æ¯å ä¸ºææ³è®©æ¯ä¸ªæ¡å½¢ä»åºé¨åä¸ä¼¸åºï¼è䏿¯ä»é¡¶é¨åä¸ï¼å¦ææä»¬æç«ç´ä½ç½®è®¾ç½®ä¸º 0 å®å°±ä¼è¿æ ·ç»ï¼ãæä»¥ï¼æä»¬æç«ç´ä½ç½®è®¾ç½®ä¸ºç»å¸é«åº¦å廿¡å½¢é«åº¦çä¸åï¼è¿æ ·æ¯ä¸ªæ¡å½¢å°±ä¼ä»ä¸é´åä¸ç»ï¼ç´å°ç»å¸æåºé¨ã
for(var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i]/2;
canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight);
x += barWidth + 1;
}
};
ååæä¸æ ·ï¼æä»¬å¨æåè°ç¨ draw() 彿°æ¥å¼å¯æ´ä¸ªå¯è§åè¿ç¨ã
è¿äºä»£ç ä¼å¸¦æ¥ä¸é¢çææï¼
夿³¨ï¼ æ¬æä¸çæ¡ä¾å±ç°äº AnalyserNode.getByteFrequencyData()
å AnalyserNode.getByteTimeDomainData()
çç¨æ³ã妿æ³è¦æ¥ç AnalyserNode.getFloatFrequencyData()
å AnalyserNode.getFloatTimeDomainData()
çç¨æ³ï¼è¯·åèæä»¬ç Voice-change-O-matic-float-data æ¼ç¤ºï¼ä¹è½çå° æºä»£ç ï¼ââå®åæ¬æä¸åºç°ç Voice-change-O-matic åè½å®å
¨ç¸åï¼å¯ä¸åºå«å°±æ¯å®ä½¿ç¨çæ¯æµ®ç¹æ°ä½æ°æ®ï¼è䏿¯æ¬æä¸çæ ç¬¦å·æ´åæ°ã
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4