Spaces:
Running
Running
Update index.html
Browse files- index.html +128 -18
index.html
CHANGED
@@ -1,19 +1,129 @@
|
|
1 |
-
<!
|
2 |
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
<html>
|
3 |
+
<head>
|
4 |
+
<title>FFT ๋ถ์ ํ ์ฌ์ธํ/์ฝ์ฌ์ธํ ์ฌ์ ์์ </title>
|
5 |
+
<style>
|
6 |
+
body { font-family: sans-serif; text-align: center; margin-top: 50px; }
|
7 |
+
button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
|
8 |
+
#status { margin-top: 20px; color: gray; }
|
9 |
+
</style>
|
10 |
+
</head>
|
11 |
+
<body>
|
12 |
+
|
13 |
+
<h1>FFT ๋ถ์ ํ ์ฌ์ธํ/์ฝ์ฌ์ธํ ์ฌ์</h1>
|
14 |
+
<p>๋ง์ดํฌ ์
๋ ฅ์ ๋ฐ์ FFT ๋ถ์ ํ ์ฃผํ์ ์ฑ๋ถ์ผ๋ก ์๋ฆฌ๋ฅผ ์ฌ๊ตฌ์ฑํฉ๋๋ค.</p>
|
15 |
+
|
16 |
+
<button id="startButton">๋ง์ดํฌ ์
๋ ฅ ์์ ๋ฐ ์ฌ์</button>
|
17 |
+
<div id="status"></div>
|
18 |
+
|
19 |
+
<script>
|
20 |
+
let audioContext;
|
21 |
+
let analyser;
|
22 |
+
let source;
|
23 |
+
let oscillatorNode; // ์ฌ์ธ/์ฝ์ฌ์ธ ํํ์ ์์ฑํ ์ค์ค๋ ์ดํฐ ๋
ธ๋
|
24 |
+
|
25 |
+
// FFT ๋ถ์ํ ์ฃผํ์ ์ฑ๋ถ์ ๊ฐ์ (2์ ๊ฑฐ๋ญ์ ๊ณฑ)
|
26 |
+
const fftSize = 2048;
|
27 |
+
const bufferLength = fftSize / 2; // ์ฃผํ์ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ํฌ๊ธฐ
|
28 |
+
|
29 |
+
// FFT ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ๋ฐฐ์ด
|
30 |
+
let dataArray = new Uint8Array(bufferLength); // ์ฃผํ์ ํฌ๊ธฐ (0-255)
|
31 |
+
|
32 |
+
// ์ฌ์ํ ์ฌ์ธํ/์ฝ์ฌ์ธํ์ ๊ฐ์ (FFT ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ช ๊ฐ์ ํํ์ผ๋ก ์ฌ๊ตฌ์ฑํ ์ง)
|
33 |
+
const numReconstructedOscillators = 50;
|
34 |
+
|
35 |
+
document.getElementById('startButton').addEventListener('click', async () => {
|
36 |
+
try {
|
37 |
+
// ์ค๋์ค ์ปจํ
์คํธ ์์ฑ (๋ธ๋ผ์ฐ์ ํธํ์ฑ์ ์ํด ์ ๋์ฌ ๊ณ ๋ ค)
|
38 |
+
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
39 |
+
|
40 |
+
// ๋ง์ดํฌ ์
๋ ฅ ์คํธ๋ฆผ ๊ฐ์ ธ์ค๊ธฐ
|
41 |
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
42 |
+
|
43 |
+
// ๋ฏธ๋์ด ์คํธ๋ฆผ ์์ค ๋
ธ๋ ์์ฑ
|
44 |
+
source = audioContext.createMediaStreamSource(stream);
|
45 |
+
|
46 |
+
// ๋ถ์๊ธฐ ๋
ธ๋ ์์ฑ
|
47 |
+
analyser = audioContext.createAnalyser();
|
48 |
+
analyser.fftSize = fftSize; // FFT ์ฌ์ด์ฆ ์ค์
|
49 |
+
|
50 |
+
// ๋ง์ดํฌ ์์ค๋ฅผ ๋ถ์๊ธฐ ๋
ธ๋์ ์ฐ๊ฒฐ
|
51 |
+
source.connect(analyser);
|
52 |
+
|
53 |
+
// ------------- FFT ๋ถ์ ๋ฐ ํํ ์ฌ๊ตฌ์ฑ ๋ก์ง -------------
|
54 |
+
|
55 |
+
// ์ค์๊ฐ์ผ๋ก FFT ๋ถ์์ ์ํํ๋ ํจ์
|
56 |
+
const processAudio = () => {
|
57 |
+
// ์ฃผํ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ (ํฌ๊ธฐ)
|
58 |
+
analyser.getByteFrequencyData(dataArray);
|
59 |
+
|
60 |
+
// ์ด์ ์ค์ค๋ ์ดํฐ ๋
ธ๋๊ฐ ์๋ค๋ฉด ์ฐ๊ฒฐ ํด์ ๋ฐ ์ญ์
|
61 |
+
if (oscillatorNode) {
|
62 |
+
oscillatorNode.disconnect();
|
63 |
+
oscillatorNode = null;
|
64 |
+
}
|
65 |
+
|
66 |
+
// ์๋ก์ด ๊ฒ์ธ ๋
ธ๋ ์์ฑ (๋ณผ๋ฅจ ์กฐ์ )
|
67 |
+
const gainNode = audioContext.createGain();
|
68 |
+
gainNode.gain.value = 0.5; // ์ฌ์ ๋ณผ๋ฅจ (์กฐ์ ๊ฐ๋ฅ)
|
69 |
+
|
70 |
+
// ๊ฒ์ธ ๋
ธ๋๋ฅผ ์ต์ข
์ถ๋ ฅ์ ์ฐ๊ฒฐ
|
71 |
+
gainNode.connect(audioContext.destination);
|
72 |
+
|
73 |
+
// ์ค์ค๋ ์ดํฐ ๋
ธ๋๋ฅผ ๋ด์ ๋ฐฐ์ด
|
74 |
+
const oscillators = [];
|
75 |
+
|
76 |
+
// FFT ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ธํ/์ฝ์ฌ์ธํ ์์ฑ (๋จ์ํ๋ ์์ )
|
77 |
+
for (let i = 0; i < numReconstructedOscillators; i++) {
|
78 |
+
const oscillator = audioContext.createOscillator();
|
79 |
+
|
80 |
+
// ์ฃผํ์ ๋ฐ์ดํฐ ๋ฐฐ์ด์์ ํด๋นํ๋ ์ฃผํ์ ์ธ๋ฑ์ค ๊ณ์ฐ
|
81 |
+
const frequencyIndex = Math.min(Math.floor(i * (bufferLength / numReconstructedOscillators)), bufferLength - 1);
|
82 |
+
|
83 |
+
// ํด๋น ์ฃผํ์ ์ฑ๋ถ์ ํฌ๊ธฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฃผํ์ ์ค์ (๋จ์ํ)
|
84 |
+
// ์ค์ ๋ก๋ analyser.getByteFrequencyData๋ ํฌ๊ธฐ๋ง ์ ๊ณตํ๋ฉฐ, ์ฃผํ์๋ ์ธ๋ฑ์ค์ ์ํ ๋ ์ดํธ๋ก ๊ณ์ฐํด์ผ ํฉ๋๋ค.
|
85 |
+
// ์ฌ๊ธฐ์์ frequency๋ ์์๋ฅผ ์ํด ๊ฐ๋จํ๊ฒ ์ฃผํ์ ์ธ๋ฑ์ค์ ๋น๋กํ๊ฒ ์ค์ ํฉ๋๋ค.
|
86 |
+
const frequency = audioContext.sampleRate / fftSize * frequencyIndex; // ์ค์ ์ฃผํ์ ๊ณ์ฐ
|
87 |
+
|
88 |
+
// ์ฃผํ์๊ฐ ๋๋ฌด ๋ฎ๊ฑฐ๋ ๋์ผ๋ฉด ์ ์ธ (์กฐ์ ๊ฐ๋ฅ)
|
89 |
+
if (frequency > 50 && frequency < 15000) {
|
90 |
+
oscillator.type = 'sine'; // ๋๋ 'cosine'
|
91 |
+
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
|
92 |
+
|
93 |
+
// ๊ฐ ์ค์ค๋ ์ดํฐ์ ๋ณผ๋ฅจ์ ํด๋น ์ฃผํ์ ์ฑ๋ถ์ ํฌ๊ธฐ์ ๋น๋กํ์ฌ ์ค์ (๋จ์ํ)
|
94 |
+
const oscillatorGain = audioContext.createGain();
|
95 |
+
oscillatorGain.gain.value = dataArray[frequencyIndex] / 255 * 0.1; // ํฌ๊ธฐ์ ๋น๋กํ์ฌ ๋ณผ๋ฅจ ์กฐ์
|
96 |
+
|
97 |
+
// ์ค์ค๋ ์ดํฐ๋ฅผ ๊ฒ์ธ ๋
ธ๋์ ์ฐ๊ฒฐํ๊ณ ๊ฒ์ธ ๋
ธ๋๋ฅผ ๋ฉ์ธ ๊ฒ์ธ ๋
ธ๋์ ์ฐ๊ฒฐ
|
98 |
+
oscillator.connect(oscillatorGain);
|
99 |
+
oscillatorGain.connect(gainNode);
|
100 |
+
|
101 |
+
// ์ค์ค๋ ์ดํฐ ์์
|
102 |
+
oscillator.start();
|
103 |
+
|
104 |
+
// ์ค์ค๋ ์ดํฐ ๋ฐฐ์ด์ ์ถ๊ฐ
|
105 |
+
oscillators.push(oscillator);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
// ์์ฑ๋ ์ค์ค๋ ์ดํฐ ๋
ธ๋๋ฅผ ์ ์ฅ
|
110 |
+
oscillatorNode = oscillators;
|
111 |
+
|
112 |
+
// ๋ค์ ํ๋ ์์ ๋ค์ ๋ถ์ ๋ฐ ์ฌ์ ์์ฒญ
|
113 |
+
requestAnimationFrame(processAudio);
|
114 |
+
};
|
115 |
+
|
116 |
+
// ๋ถ์ ๋ฐ ์ฌ์ ์์
|
117 |
+
processAudio();
|
118 |
+
|
119 |
+
document.getElementById('status').textContent = '๋ง์ดํฌ ์
๋ ฅ ๋ฐ ์ฌ์ ์ค...';
|
120 |
+
} catch (err) {
|
121 |
+
console.error('๋ง์ดํฌ ์ ๊ทผ ์ค๋ฅ:', err);
|
122 |
+
document.getElementById('status').textContent = `์ค๋ฅ ๋ฐ์: ${err.message}`;
|
123 |
+
}
|
124 |
+
});
|
125 |
+
|
126 |
+
</script>
|
127 |
+
|
128 |
+
</body>
|
129 |
+
</html>
|