마이크 볼륨 시각화하기 에 이어서, 마이크 변경과 오디오 볼륨을 조절하는 방법을 간단히 살펴봅니다.
바닐라 Javascript로 개발한 예제코드는 아래에서 확인할 수 있습니다.
https://codepen.io/vchgekmq-the-flexboxer/pen/poBWNbE
1. 입력 마이크 변경하기
입력 마이크를 변경하는 기능을 간단히 추가해 보겠습니다.
이전에 만든 볼륨 시각화 코드에서 이어서 개발할 예정이므로, 이전 게시글을 참고해 주시면 감사하겠습니다.
우선 페이지에 간단한 <select> 태그를 추가해 줍니다.
<p>마이크 선택</p>
<select id="microphoneSelect"></select>
이제 아래와 같은 JavaScript코드를 추가해 봅시다.
let selectedMicrophone = null;
document.addEventListener("DOMContentLoaded", () => {
const microphoneSelect = document.getElementById("microphoneSelect");
navigator.mediaDevices
.enumerateDevices()
.then((devices) => {
const microphoneDevices = devices.filter(
(device) => device.kind === "audioinput"
);
microphoneDevices.forEach((device) => {
const option = document.createElement("option");
option.value = device.deviceId;
option.textContent = device.label || `마이크 ${microphoneDevices.indexOf(device) + 1}`;
microphoneSelect.appendChild(option);
});
})
.catch((error) => {
console.error("불러오기 실패", error);
});
microphoneSelect.addEventListener("change", async (e) => {
selectedMicrophone = e.target.value;
if (audioStream) audioStream.getTracks().forEach((track) => track.stop()); // 기존 미디어 트랙 중지
startRecording();
});
});
코드를 차근차근 확인해 보겠습니다.
- document.addEventListener("DOMContentLoaded", () => {
- DOM 트리를 완성하는 즉시 실행합니다.
- const microphoneSelect = document.getElementById("microphoneSelect");
- 앞서 만든 <select> 태그의 참조를 저장합니다.
- navigator.mediaDevices.enumerateDevices()
- 현재 사용 가능한 미디어 입력 및 출력 장치 목록을 불러옵니다.
- const microphoneDevices = devices.filter( (device) => device.kind === "audioinput" );
- 장치 목록에서 오디오 입력 장치인 마이크만 필터링해서 microphoneDevices에 저장합니다.
- microphoneDevices.forEach((device) => { ~ }
- microphoneDevices의 각 마이크를 <option>으로 만들고, <select> 태그에 추가합니다.
- microphoneSelect.addEventListener("change", ~
- <select> 태그에서 선택된 내용이 바뀌면 실행됩니다.
- selectedMicrophone = e.target.value;
- 현재 선택된 마이크의 id를 selectedMicrophone에 저장합니다.
- if (audioStream) audioStream.getTracks().forEach((track) => track.stop());
- 기존의 미디어 트랙 중지합니다.
- startRecording();
- 앞선 게시글에서 구현한 볼륨 시각화를 다시 실행시킵니다.
요약하면, navigator.mediaDevices.enumerateDevices()으로 전체 미디어 장치 목록을 불러오고,
그중에서 오디오 입력장치만 필터링해서 <select> 태그의 option으로 추가해 줍니다.
그런 다음, <select>에서 오디오를 선택하면 해당 오디오의 id를 selectedMicrophone에 저장합니다.
이제 볼륨 시각화 코드를 다음과 같이 수정합니다.
const startRecording = () => {
navigator.mediaDevices
.getUserMedia({ audio: { deviceId: selectedMicrophone } })
.then((stream) => {
// (이전과 동일)
})
.catch((error) => {
console.error("마이크 권한 획득 실패", error);
});
};
여기서 변경된 곳은 getUserMedia()에서 audio의 deviceId를 selectedMicrophone로 지정하는 부분입니다.
이와 같은 방법으로 getUserMedia()에서 특정한 장치에서 입력되는 미디어를 지정해서 가져올 수 있습니다.
2. 입력 오디오 볼륨 조절하기
이제 사용자의 마이크로 입력받은 오디오의 볼륨 크기를 조절해 보겠습니다.
오디오의 크기를 조절하기 위해서는 Web Audio API의 GainNode를 사용합니다.
GainNode는 오디오 신호의 볼륨을 조절하는 데 사용하는 인터페이스로, 자세한 설명은 아래 링크에서 확인할 수 있습니다.
https://developer.mozilla.org/en-US/docs/Web/API/GainNode
먼저 아래처럼 <input> 태그를 이용해서 간단한 슬라이더 바를 만들어 줍니다.
<p>마이크 볼륨</p>
<input id="volumeSlider" class="w-full" type="range" min="0" max="1" step="0.01">
이제 볼륨 값의 가중치를 저장할 micVolume를 선언하고, 아래와 같이 슬라이더 바의 값이 변경되었을 때, micVolume가 갱신되는 코드를 작성해 줍니다.
let micVolume = 0.5;
document.addEventListener("DOMContentLoaded", () => {
const volumeSlider = document.getElementById("volumeSlider");
/*
(앞선 코드와 동일
*/
volumeSlider.addEventListener("change", (e) => {
micVolume = parseFloat(e.target.value);
});
}
이제 본격적으로 GainNode를 이용하여 마이크 볼륨값을 조절해 보겠습니다.
micVolume에 따라 마이크 볼륨이 조절되도록 수정된 startRecording의 코드를 미리 보면 다음과 같습니다.
const startRecording = () => {
navigator.mediaDevices
.getUserMedia({ audio: { deviceId: selectedMicrophone } })
.then((stream) => {
isRecording = true;
audioStream = stream;
// Web Audio API에서 오디오를 다루기 위한 기본 객체 AudioContext 생성
const audioContext = new AudioContext();
// 오디오 신호를 분석하기 위한 AnalyserNode 객체 생성
const analyser = audioContext.createAnalyser();
// 미디어 스트림을 audioContext 내에서 사용할 수 있는 형식으로 변환
const mediaStreamAudioSourceNode =
audioContext.createMediaStreamSource(stream);
// 입력 오디오 신호의 볼륨을 조절하기 위한 GainNode 객체 생성
const gainNode = audioContext.createGain();
// 변환된 미디어 스트림을 GainNode 객체에 연결
mediaStreamAudioSourceNode.connect(gainNode);
// GainNode 객체를 AnalyserNode 객체에 연결
gainNode.connect(analyser);
const pcmData = new Float32Array(analyser.fftSize);
const onFrame = () => {
gainNode.gain.value = micVolume;
// 여기서부터는 기존과 동일 (볼륨 시각화 코드)
analyser.getFloatTimeDomainData(pcmData);
let sum = 0.0;
for (const amplitude of pcmData) {
sum += amplitude * amplitude;
}
const rms = Math.sqrt(sum / pcmData.length);
const normalizedVolume = Math.min(1, rms / 0.5);
colorVolumeMeter(normalizedVolume * 2);
onFrameId = window.requestAnimationFrame(onFrame);
};
onFrameId = window.requestAnimationFrame(onFrame);
})
.catch((error) => {
console.error("마이크 권한 획득 실패", error);
});
};
여기서 GainNode로 변경된 부분만 따로 확인해 보겠습니다.
// 입력 오디오 신호의 볼륨을 조절하기 위한 GainNode 객체 생성
const gainNode = audioContext.createGain();
// 변환된 미디어 스트림을 GainNode 객체에 연결
mediaStreamAudioSourceNode.connect(gainNode);
// GainNode 객체를 AnalyserNode 객체에 연결
gainNode.connect(analyser);
const pcmData = new Float32Array(analyser.fftSize);
const onFrame = () => {
// GainNode의 gain값을 갱신
gainNode.gain.value = micVolume;
// ...
}
우선 GainNode의 주요 속성은 'gain'을 살펴보겠습니다.
gain 속성은 해당 노드를 통과하는 오디오 신호의 볼륨을 제어하는 속성입니다. gain의 value는 0~1 사이의 값을 가지는데, 0은 무음, 1은 오디오 신호가 그대로 전달됨을 의미합니다.
이러한 gain 속성을 가지는 GainNode를 오디오 소스 노드와 출력 노드 사이에 추가해서 볼륨을 조절할 수 있는데, 이를 위해서 위의 코드는 아래와 같이 구현되어 있습니다.
- 1) GainNode를 생성
- 2) 오디오 분석을 위해 변환한 mediaStreamAudioSourceNode를 GainNode에 연결
- 3) GainNode를 AnalyserNode 객체에 연결
이런 과정을 통해 볼륨을 조절할 수 있습니다. 더 이해하기 쉽게 동작 과정을 그림으로 나타내면 다음과 같습니다.
지금까지의 코드를 정리하면 아래와 같습니다.
See the Pen 마이크 변경과 볼륨 조절 예제 by 주완 (@vchgekmq-the-flexboxer) on CodePen.
'WEB > 💡 Javascript' 카테고리의 다른 글
[Javascript] HTML 페이지에 TOC(Table of Content, 목차) 만들기 (0) | 2024.07.12 |
---|---|
자바스크립트가 숫자를 저장하는 방법 (IEEE 754) (0) | 2024.04.28 |
[Javascript] 역따옴표(백틱)을 이용한 템플릿 리터럴(template literal) (0) | 2022.07.27 |
[Javascript] '=='와 '==='의 차이점 (0) | 2022.07.27 |
[Javascript] 아코디언 메뉴 만들기 (접기/펼치기 기능 구현) (0) | 2022.07.20 |