ブラウザで録音した音源とアップロードした音源を合成する
こんにちわ。kyamashitaです。
前回はブラウザから録音させてみましたので、今回は録音した音源とアップロードした音源を合成させてみます。
アップロードした音源を保持
audioContext.decodeAudioData()
を使ってデコードした音源を保持します。
const audioContext = new (window.AudioContext || window.webkitAudioContext);
let audioBuffer = null;
document.querySelector('#file').addEventListener('change', function () {
const file = this.files[0];
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function () {
audioContext.decodeAudioData(reader.result, function (buffer) {
audioBuffer = buffer;
});
};
});
録音した音源とアップロードした音源を合成
下記にて合成しています。 アップロードした音源の方はループ設定しておきます。 合成したstreamをMediaRecorderに渡します。// record
const deviceSource = audioContext.createMediaStreamSource(stream);
const deviceGain = audioContext.createGain();
deviceGain.gain.value = 0.5;
deviceSource.connect(deviceGain);
// upload file
const audioSource = audioContext.createBufferSource();
audioSource.buffer = audioBuffer;
audioSource.loop = true;
const audioGain = audioContext.createGain();
audioGain.gain.value = 0.5;
audioSource.connect(audioGain);
// mix
const mixedOutput = audioContext.createMediaStreamDestination();
deviceGain.connect(mixedOutput);
audioGain.connect(mixedOutput);
const mediaStream = mixedOutput.stream;
サンプル全文
今回のサンプルはこちら
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>sample</title>
</head>
<body>
<input type="file" id="file">
<hr>
<button id="start">録音</button>
<button id="stop">停止</button>
<hr>
<audio id="player" controls></audio>
<script>
window.onload = function () {
const audioContext = new (window.AudioContext || window.webkitAudioContext);
let audioBuffer = null;
document.querySelector('#file').addEventListener('change', function () {
const file = this.files[0];
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function () {
audioContext.decodeAudioData(reader.result, function (buffer) {
audioBuffer = buffer;
});
};
});
const start = document.querySelector('#start');
const stop = document.querySelector('#stop');
const player = document.querySelector('#player');
let mediaRecorder = null;
let mimeType = '';
let chunks = [];
start.addEventListener('click', function () {
navigator.mediaDevices.getUserMedia({"video": false, "audio": true})
.then(function (stream) {
// record
const deviceSource = audioContext.createMediaStreamSource(stream);
const deviceGain = audioContext.createGain();
deviceGain.gain.value = 0.5;
deviceSource.connect(deviceGain);
// upload file
const audioSource = audioContext.createBufferSource();
audioSource.buffer = audioBuffer;
audioSource.loop = true;
const audioGain = audioContext.createGain();
audioGain.gain.value = 0.5;
audioSource.connect(audioGain);
// mix
const mixedOutput = audioContext.createMediaStreamDestination();
deviceGain.connect(mixedOutput);
audioGain.connect(mixedOutput);
const mediaStream = mixedOutput.stream;
mediaRecorder = new MediaRecorder(mediaStream);
mediaRecorder.ondataavailable = function (e) {
mimeType = e.data.type;
chunks.push(e.data);
};
mediaRecorder.onstop = function () {
const blob = new Blob(chunks, { 'type' : mimeType });
chunks = [];
player.src = window.URL.createObjectURL(blob);
};
audioSource.start(0);
mediaRecorder.start();
})
.catch(function (e) {
alert(e);
});
});
stop.addEventListener('click', function () {
mediaRecorder.stop();
});
};
</script>
</body>
</html>