Spaces:
Running
Running
<html> | |
<head> | |
<title>FFT ๋ถ์ ํ ์ฌ์ธํ/์ฝ์ฌ์ธํ ์ฌ์ ์์ </title> | |
<style> | |
body { font-family: sans-serif; text-align: center; margin-top: 50px; } | |
button { padding: 10px 20px; font-size: 16px; cursor: pointer; } | |
#status { margin-top: 20px; color: gray; } | |
</style> | |
</head> | |
<body> | |
<h1>FFT ๋ถ์ ํ ์ฌ์ธํ/์ฝ์ฌ์ธํ ์ฌ์</h1> | |
<p>๋ง์ดํฌ ์ ๋ ฅ์ ๋ฐ์ FFT ๋ถ์ ํ ์ฃผํ์ ์ฑ๋ถ์ผ๋ก ์๋ฆฌ๋ฅผ ์ฌ๊ตฌ์ฑํฉ๋๋ค.</p> | |
<button id="startButton">๋ง์ดํฌ ์ ๋ ฅ ์์ ๋ฐ ์ฌ์</button> | |
<div id="status"></div> | |
<script> | |
let audioContext; | |
let analyser; | |
let source; | |
let oscillatorNode; // ์ฌ์ธ/์ฝ์ฌ์ธ ํํ์ ์์ฑํ ์ค์ค๋ ์ดํฐ ๋ ธ๋ | |
// FFT ๋ถ์ํ ์ฃผํ์ ์ฑ๋ถ์ ๊ฐ์ (2์ ๊ฑฐ๋ญ์ ๊ณฑ) | |
const fftSize = 2048; | |
const bufferLength = fftSize / 2; // ์ฃผํ์ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ํฌ๊ธฐ | |
// FFT ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ๋ฐฐ์ด | |
let dataArray = new Uint8Array(bufferLength); // ์ฃผํ์ ํฌ๊ธฐ (0-255) | |
// ์ฌ์ํ ์ฌ์ธํ/์ฝ์ฌ์ธํ์ ๊ฐ์ (FFT ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ช ๊ฐ์ ํํ์ผ๋ก ์ฌ๊ตฌ์ฑํ ์ง) | |
const numReconstructedOscillators = 50; | |
document.getElementById('startButton').addEventListener('click', async () => { | |
try { | |
// ์ค๋์ค ์ปจํ ์คํธ ์์ฑ (๋ธ๋ผ์ฐ์ ํธํ์ฑ์ ์ํด ์ ๋์ฌ ๊ณ ๋ ค) | |
audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
// ๋ง์ดํฌ ์ ๋ ฅ ์คํธ๋ฆผ ๊ฐ์ ธ์ค๊ธฐ | |
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); | |
// ๋ฏธ๋์ด ์คํธ๋ฆผ ์์ค ๋ ธ๋ ์์ฑ | |
source = audioContext.createMediaStreamSource(stream); | |
// ๋ถ์๊ธฐ ๋ ธ๋ ์์ฑ | |
analyser = audioContext.createAnalyser(); | |
analyser.fftSize = fftSize; // FFT ์ฌ์ด์ฆ ์ค์ | |
// ๋ง์ดํฌ ์์ค๋ฅผ ๋ถ์๊ธฐ ๋ ธ๋์ ์ฐ๊ฒฐ | |
source.connect(analyser); | |
// ------------- FFT ๋ถ์ ๋ฐ ํํ ์ฌ๊ตฌ์ฑ ๋ก์ง ------------- | |
// ์ค์๊ฐ์ผ๋ก FFT ๋ถ์์ ์ํํ๋ ํจ์ | |
const processAudio = () => { | |
// ์ฃผํ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ (ํฌ๊ธฐ) | |
analyser.getByteFrequencyData(dataArray); | |
// ์ด์ ์ค์ค๋ ์ดํฐ ๋ ธ๋๊ฐ ์๋ค๋ฉด ์ฐ๊ฒฐ ํด์ ๋ฐ ์ญ์ | |
if (oscillatorNode) { | |
oscillatorNode.disconnect(); | |
oscillatorNode = null; | |
} | |
// ์๋ก์ด ๊ฒ์ธ ๋ ธ๋ ์์ฑ (๋ณผ๋ฅจ ์กฐ์ ) | |
const gainNode = audioContext.createGain(); | |
gainNode.gain.value = 0.5; // ์ฌ์ ๋ณผ๋ฅจ (์กฐ์ ๊ฐ๋ฅ) | |
// ๊ฒ์ธ ๋ ธ๋๋ฅผ ์ต์ข ์ถ๋ ฅ์ ์ฐ๊ฒฐ | |
gainNode.connect(audioContext.destination); | |
// ์ค์ค๋ ์ดํฐ ๋ ธ๋๋ฅผ ๋ด์ ๋ฐฐ์ด | |
const oscillators = []; | |
// FFT ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ธํ/์ฝ์ฌ์ธํ ์์ฑ (๋จ์ํ๋ ์์ ) | |
for (let i = 0; i < numReconstructedOscillators; i++) { | |
const oscillator = audioContext.createOscillator(); | |
// ์ฃผํ์ ๋ฐ์ดํฐ ๋ฐฐ์ด์์ ํด๋นํ๋ ์ฃผํ์ ์ธ๋ฑ์ค ๊ณ์ฐ | |
const frequencyIndex = Math.min(Math.floor(i * (bufferLength / numReconstructedOscillators)), bufferLength - 1); | |
// ํด๋น ์ฃผํ์ ์ฑ๋ถ์ ํฌ๊ธฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฃผํ์ ์ค์ (๋จ์ํ) | |
// ์ค์ ๋ก๋ analyser.getByteFrequencyData๋ ํฌ๊ธฐ๋ง ์ ๊ณตํ๋ฉฐ, ์ฃผํ์๋ ์ธ๋ฑ์ค์ ์ํ ๋ ์ดํธ๋ก ๊ณ์ฐํด์ผ ํฉ๋๋ค. | |
// ์ฌ๊ธฐ์์ frequency๋ ์์๋ฅผ ์ํด ๊ฐ๋จํ๊ฒ ์ฃผํ์ ์ธ๋ฑ์ค์ ๋น๋กํ๊ฒ ์ค์ ํฉ๋๋ค. | |
const frequency = audioContext.sampleRate / fftSize * frequencyIndex; // ์ค์ ์ฃผํ์ ๊ณ์ฐ | |
// ์ฃผํ์๊ฐ ๋๋ฌด ๋ฎ๊ฑฐ๋ ๋์ผ๋ฉด ์ ์ธ (์กฐ์ ๊ฐ๋ฅ) | |
if (frequency > 50 && frequency < 15000) { | |
oscillator.type = 'sine'; // ๋๋ 'cosine' | |
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime); | |
// ๊ฐ ์ค์ค๋ ์ดํฐ์ ๋ณผ๋ฅจ์ ํด๋น ์ฃผํ์ ์ฑ๋ถ์ ํฌ๊ธฐ์ ๋น๋กํ์ฌ ์ค์ (๋จ์ํ) | |
const oscillatorGain = audioContext.createGain(); | |
oscillatorGain.gain.value = dataArray[frequencyIndex] / 255 * 0.1; // ํฌ๊ธฐ์ ๋น๋กํ์ฌ ๋ณผ๋ฅจ ์กฐ์ | |
// ์ค์ค๋ ์ดํฐ๋ฅผ ๊ฒ์ธ ๋ ธ๋์ ์ฐ๊ฒฐํ๊ณ ๊ฒ์ธ ๋ ธ๋๋ฅผ ๋ฉ์ธ ๊ฒ์ธ ๋ ธ๋์ ์ฐ๊ฒฐ | |
oscillator.connect(oscillatorGain); | |
oscillatorGain.connect(gainNode); | |
// ์ค์ค๋ ์ดํฐ ์์ | |
oscillator.start(); | |
// ์ค์ค๋ ์ดํฐ ๋ฐฐ์ด์ ์ถ๊ฐ | |
oscillators.push(oscillator); | |
} | |
} | |
// ์์ฑ๋ ์ค์ค๋ ์ดํฐ ๋ ธ๋๋ฅผ ์ ์ฅ | |
oscillatorNode = oscillators; | |
// ๋ค์ ํ๋ ์์ ๋ค์ ๋ถ์ ๋ฐ ์ฌ์ ์์ฒญ | |
requestAnimationFrame(processAudio); | |
}; | |
// ๋ถ์ ๋ฐ ์ฌ์ ์์ | |
processAudio(); | |
document.getElementById('status').textContent = '๋ง์ดํฌ ์ ๋ ฅ ๋ฐ ์ฌ์ ์ค...'; | |
} catch (err) { | |
console.error('๋ง์ดํฌ ์ ๊ทผ ์ค๋ฅ:', err); | |
document.getElementById('status').textContent = `์ค๋ฅ ๋ฐ์: ${err.message}`; | |
} | |
}); | |
</script> | |
</body> | |
</html> |