getUserMedia와 canvas를 사용하여 브라우저를 통해 마이크 입력의 시간 영역 파형과 주파수 영역 파형 표시
15263 단어 HTML5자바스크립트캔버스getUserMedia
소개
브라우저에서, 마이크 입력의 음성의 해석이라든지, 소리의 재생이라든지, 이펙터적인 것을 만들어 보고 싶다고 생각해 여러가지 조사해 시험해 보았다. getUserMedia 사용하면 마이크 사용할 수 있고, audioContext라든지 사용하면 해석할 수 있는 것을 알았다. 자바스크립트 왠지 알 정도로 했지만, 콜백이나 Promise라든지 조금 알았다. 공부가 되었다.
조사
우선은 비슷한 일을 하고 있는 사람 찾았다.
마이크에서 음성 캡처하고 FFT하고 표시하는 사람을 발견했다. getUserMedia를 사용하면 좋은 것 같습니다. 코드 봐도, 너무 잘 모르기 때문에, 좀 더 조사하기로 했다.
getUserMedia로 오디오를 픽업하고 실시간으로 파형 출력하기 - Qiita
getUserMedia를 살펴보면 이 사람의 기사가 간단하고 이해하기 쉬웠다.
navigator.mediaDevices.getUserMedia()라는 것이 새로운 것 같다. Promise는 콜백이 아닌 하고 싶다. 왠지, 이쪽이 지금 바람같다.
브라우저에서 미디어 장치 조작 - getUserMedia()의 기본 | CodeGrid
Promise는 여기에 불렀다.
Promise 사용 - JavaScript | MDN
JavaScript 입문자 필견! Promise의 기초의 기초를 해설! (then, all, get) | 사무라이 엔지니어 학원 블로그 | 프로그래밍 입문자를위한 학습 정보 사이트
좀 더 살펴보면 navigator.mediaDevices.getUserMedia() 사용하여 파형 표시하고 있는 사람도 발견했다. FFT는 하지 않았지만. 이대로 움직이지 않았기 때문에 조금 수정이 필요했다.
브라우저에서 음성 입력 시각화 및 녹음 - EagleLand
시도한 것
우선은 비슷한 일을 하고 있는 사람 찾았다.
마이크에서 음성 캡처하고 FFT하고 표시하는 사람을 발견했다. getUserMedia를 사용하면 좋은 것 같습니다. 코드 봐도, 너무 잘 모르기 때문에, 좀 더 조사하기로 했다.
getUserMedia로 오디오를 픽업하고 실시간으로 파형 출력하기 - Qiita
getUserMedia를 살펴보면 이 사람의 기사가 간단하고 이해하기 쉬웠다.
navigator.mediaDevices.getUserMedia()라는 것이 새로운 것 같다. Promise는 콜백이 아닌 하고 싶다. 왠지, 이쪽이 지금 바람같다.
브라우저에서 미디어 장치 조작 - getUserMedia()의 기본 | CodeGrid
Promise는 여기에 불렀다.
Promise 사용 - JavaScript | MDN
JavaScript 입문자 필견! Promise의 기초의 기초를 해설! (then, all, get) | 사무라이 엔지니어 학원 블로그 | 프로그래밍 입문자를위한 학습 정보 사이트
좀 더 살펴보면 navigator.mediaDevices.getUserMedia() 사용하여 파형 표시하고 있는 사람도 발견했다. FFT는 하지 않았지만. 이대로 움직이지 않았기 때문에 조금 수정이 필요했다.
브라우저에서 음성 입력 시각화 및 녹음 - EagleLand
시도한 것
우선은, 이런 느낌으로 시험해 보았다.
코드
이런 느낌으로 써 보았다.
주로 아래 URL의 코드를 참고로 했다.
브라우저에서 음성 입력 시각화 및 녹음 - EagleLand
FFT할 때는 FFT 포인트 수의 절반만 표시했다. 나이퀴스트 주파수적으로. 표본화 정리로 나오는 녀석.
창함수를 걸고 있니? 아래 사이트를 보면 아무래도 데시벨로 나오는 것 같다.
AnalyserNode.maxDecibels - Web APIs | MDN
querySelector는 여기를 확인했습니다.
Document.querySelector() - Web API | MDN
샘플 레이트는 console.log(audioContext.sampleRate);
로 확인. 48kHz했다.
mic_test2.html<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>microphone</title>
</head>
<body>
<canvas id="canvas1" width="400" height="300"></canvas>
<canvas id="canvas2" width="400" height="300"></canvas>
<script src="mic_test2.js"></script>
</body>
</html>
mic_test2.jsconst canvas1 = document.querySelector('#canvas1');
const drawContext1 = canvas1.getContext('2d');
const canvas2 = document.querySelector('#canvas2');
const drawContext2 = canvas2.getContext('2d');
navigator.mediaDevices.getUserMedia({
audio: true,
video: false
}).then(stream => {
const audioContext = new AudioContext();
const sourceNode = audioContext.createMediaStreamSource(stream);
const analyserNode = audioContext.createAnalyser();
console.log(audioContext.sampleRate);
analyserNode.fftSize = 1024*2;
sourceNode.connect(analyserNode);
function draw1() {
const barWidth = canvas1.width / analyserNode.fftSize;
const time_array = new Uint8Array(analyserNode.fftSize);
analyserNode.getByteTimeDomainData(time_array);
drawContext1.fillStyle = 'rgba(0, 0, 0, 1)';
drawContext1.fillRect(0, 0, canvas1.width, canvas1.height);
for (let i = 0; i < analyserNode.fftSize; ++i) {
const value = time_array[i];
const percent = value / 255;
const height = canvas1.height * percent;
const offset = canvas1.height - height;
drawContext1.fillStyle = 'lime';
drawContext1.fillRect(i * barWidth, offset, 4*barWidth, 4);
}
requestAnimationFrame(draw1);
}
draw1();
function draw2() {
const barWidth = canvas2.width / (analyserNode.fftSize/2);
const freq_array = new Uint8Array(analyserNode.fftSize);
analyserNode.getByteFrequencyData(freq_array);
drawContext2.fillStyle = 'rgba(0, 0, 0, 1)';
drawContext2.fillRect(0, 0, canvas2.width, canvas2.height);
for (let i = 0; i < analyserNode.fftSize; ++i) {
const value = freq_array[i];
const percent = value / 255;
const height = canvas2.height * percent;
const offset = canvas2.height - height;
drawContext2.fillStyle = 'lime';
drawContext2.fillRect(i * barWidth, offset, 4*barWidth, 4);
}
requestAnimationFrame(draw2);
}
draw2();
});
결과
이런 느낌으로 표시된다. 그리기를 Line으로 하지 않고 Rectangle로 하고 있기 때문에, 흩날리면 보기 어려운 생각도 한다. 덧붙여서 거기 귀찮게 보자. 어쨌든 모든 데이터를 그려주고 그런 느낌은 들지만 잘 모르겠습니다.
결론
지금 자바스크립트의 Promise를 알지 못했기 때문에, 조사하면서 하고 시간이 걸렸다. 결국 심플한 느낌으로 할 수 있는 것을 알았기 때문에 좋았다. 다음은, 이펙터 같은 것 만들어 보고 싶다.
Reference
이 문제에 관하여(getUserMedia와 canvas를 사용하여 브라우저를 통해 마이크 입력의 시간 영역 파형과 주파수 영역 파형 표시), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/optimisuke/items/6dd8a58586ee5a56cf50
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>microphone</title>
</head>
<body>
<canvas id="canvas1" width="400" height="300"></canvas>
<canvas id="canvas2" width="400" height="300"></canvas>
<script src="mic_test2.js"></script>
</body>
</html>
const canvas1 = document.querySelector('#canvas1');
const drawContext1 = canvas1.getContext('2d');
const canvas2 = document.querySelector('#canvas2');
const drawContext2 = canvas2.getContext('2d');
navigator.mediaDevices.getUserMedia({
audio: true,
video: false
}).then(stream => {
const audioContext = new AudioContext();
const sourceNode = audioContext.createMediaStreamSource(stream);
const analyserNode = audioContext.createAnalyser();
console.log(audioContext.sampleRate);
analyserNode.fftSize = 1024*2;
sourceNode.connect(analyserNode);
function draw1() {
const barWidth = canvas1.width / analyserNode.fftSize;
const time_array = new Uint8Array(analyserNode.fftSize);
analyserNode.getByteTimeDomainData(time_array);
drawContext1.fillStyle = 'rgba(0, 0, 0, 1)';
drawContext1.fillRect(0, 0, canvas1.width, canvas1.height);
for (let i = 0; i < analyserNode.fftSize; ++i) {
const value = time_array[i];
const percent = value / 255;
const height = canvas1.height * percent;
const offset = canvas1.height - height;
drawContext1.fillStyle = 'lime';
drawContext1.fillRect(i * barWidth, offset, 4*barWidth, 4);
}
requestAnimationFrame(draw1);
}
draw1();
function draw2() {
const barWidth = canvas2.width / (analyserNode.fftSize/2);
const freq_array = new Uint8Array(analyserNode.fftSize);
analyserNode.getByteFrequencyData(freq_array);
drawContext2.fillStyle = 'rgba(0, 0, 0, 1)';
drawContext2.fillRect(0, 0, canvas2.width, canvas2.height);
for (let i = 0; i < analyserNode.fftSize; ++i) {
const value = freq_array[i];
const percent = value / 255;
const height = canvas2.height * percent;
const offset = canvas2.height - height;
drawContext2.fillStyle = 'lime';
drawContext2.fillRect(i * barWidth, offset, 4*barWidth, 4);
}
requestAnimationFrame(draw2);
}
draw2();
});
이런 느낌으로 표시된다. 그리기를 Line으로 하지 않고 Rectangle로 하고 있기 때문에, 흩날리면 보기 어려운 생각도 한다. 덧붙여서 거기 귀찮게 보자. 어쨌든 모든 데이터를 그려주고 그런 느낌은 들지만 잘 모르겠습니다.
결론
지금 자바스크립트의 Promise를 알지 못했기 때문에, 조사하면서 하고 시간이 걸렸다. 결국 심플한 느낌으로 할 수 있는 것을 알았기 때문에 좋았다. 다음은, 이펙터 같은 것 만들어 보고 싶다.
Reference
이 문제에 관하여(getUserMedia와 canvas를 사용하여 브라우저를 통해 마이크 입력의 시간 영역 파형과 주파수 영역 파형 표시), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/optimisuke/items/6dd8a58586ee5a56cf50
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(getUserMedia와 canvas를 사용하여 브라우저를 통해 마이크 입력의 시간 영역 파형과 주파수 영역 파형 표시), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/optimisuke/items/6dd8a58586ee5a56cf50텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)