如何在特定时间对音频斑点进行切片?



我有一个音频斑点,我想在特定时间将其切碎。我应该如何在Javascript中做到这一点?

例:

sliceAudioBlob( audio_blob, 0, 10000 ); // Time in milliseconds [ start = 0, end = 10000 ]

注意:我不知道该怎么做,所以一点提示真的会 赞赏。

更新:

我正在尝试构建一个简单的录音机,但问题是每个浏览器的持续时间存在差异,其中一些会增加几秒钟( 火狐 )而另一些则不会( Chrome )。因此,我想出了编写一个仅返回所需切片的方法的想法。

完整的网页代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Audio Recorder</title>
<style>
audio{
display: block;
}
</style>
</head>
<body>
<button type="button" onclick="mediaRecorder.start(1000)">Start</button>
<button type="button" onclick="mediaRecorder.stop()">Stop</button>

<script type="text/javascript">
var mediaRecorder = null,
chunks = [],
max_duration = 10000;// in milliseconds.
function onSuccess( stream ) {
mediaRecorder = new MediaRecorder( stream );

mediaRecorder.ondataavailable = function( event ) {
// chunks.length is the number of recorded seconds
// since every chunk is 1 second duration.
if ( chunks.length < max_duration / 1000 ) {
chunks.push( event.data );
} else {
if (mediaRecorder.state === 'recording') {
mediaRecorder.stop();
}
}
}
mediaRecorder.onstop = function() {
var audio = document.createElement('audio'),
audio_blob = new Blob(chunks, {
'type' : 'audio/mpeg'
});
audio.controls = 'controls';
audio.autoplay = 'autoplay';
audio.src = window.URL.createObjectURL( audio_blob );
document.body.appendChild(audio);
};
}
var onError = function(err) {
console.log('Error: ' + err);
}
navigator.mediaDevices.getUserMedia({ audio: true }).then(onSuccess, onError);
</script>
</body>
</html>

没有直接的方法可以像这样对音频媒体进行切片,这是因为您的文件不仅仅是由声音信号组成的:其中有多个段,带有一些标头等,其位置不能仅由字节长度确定。这就像你不能仅仅通过获取它的x个字节来裁剪jpeg图像。

可能有一些方法使用 Web 音频 API 将您的媒体文件转换为 AudioBuffer,然后根据需要对此 AudioBuffer 的原始 PCM 数据进行切片,然后再将其打包回具有正确新描述符的媒体文件中,但我认为您正面临 X-Y 问题,如果我正确理解, 有一种简单的方法可以解决此X问题。

事实上,你描述的问题是Chrome或Firefox不会从你的代码中产生10s的媒体。
但那是因为你依赖于MediaRecorder.start(timeslice)的时间参数来给你完美的时间块。
不会的。这个论点应该只理解为你给浏览器的线索,但他们很可能会强加自己的最小时间片,从而不尊重你的论点。(2.3[方法].5.4).

相反,当您需要时,最好使用简单的setTimeout来触发记录器的stop()方法:

start_btn.onclick = function() {
mediaRecorder.start(); // we don't even need timeslice
// now we'll get similar max duration in every browsers
setTimeout(stopRecording, max_duration);
};
stop_btn.onclick = stopRecording;
function stopRecording() {
if (mediaRecorder.state === "recording")
mediaRecorder.stop();
};

下面是一个使用 gUM 托管在 jsfiddle 上的实时示例。

还有一个使用来自 Web Audio API 的静默流的实时片段,因为 StackSnippet 的保护在 gUM 中运行不佳......

var start_btn = document.getElementById('start'),
stop_btn = document.getElementById('stop');
var mediaRecorder = null,
chunks = [],
max_duration = 10000; // in milliseconds.
start_btn.onclick = function() {
mediaRecorder.start(); // we don't even need timeslice
// now we'll get similar max duration in every browsers
setTimeout(stopRecording, max_duration);
this.disabled = !(stop_btn.disabled = false);
};
stop_btn.onclick = stopRecording;
function stopRecording() {
if (mediaRecorder.state === "recording")
mediaRecorder.stop();
stop_btn.disabled = true;
};
function onSuccess(stream) {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = function(event) {
// simply always push here, the stop will be controlled by setTimeout
chunks.push(event.data);
}
mediaRecorder.onstop = function() {
var audio_blob = new Blob(chunks);
var audio = new Audio(URL.createObjectURL(audio_blob));
audio.controls = 'controls';
document.body.appendChild(audio);
// workaround https://crbug.com/642012
audio.currentTime = 1e12;
audio.onseeked = function() {
audio.onseeked = null;
console.log(audio.duration);
audio.currentTime = 0;
audio.play();
}
};
start_btn.disabled = false;
}
var onError = function(err) {
console.log('Error: ' + err);
}
onSuccess(SilentStream());
function SilentStream() {
var ctx = new(window.AudioContext || window.webkitAudioContext),
gain = ctx.createGain(),
dest = ctx.createMediaStreamDestination();
gain.connect(dest);
return dest.stream;
}
<button id="start" disabled>start</button>
<button id="stop" disabled>stop</button>

在你的行中:

<button type="button" onclick="mediaRecorder.start(1000)">Start</button>

mediaRecorder.start 接收时间片作为参数。时间片指定区块的大小(以毫秒为单位)。因此,为了剪切音频,您应该修改在mediaRecorder.ondataavailable上创建的块数组

例如: 您传递 1000 作为时间片,这意味着您有 1 秒的切片,并且您想要剪切录制的前 2 秒。

你只需要做这样的事情:

mediaRecorder.onstop = function() {
//Remove first 2 seconds of the audio
var chunksSliced = chunks.slice(2);
var audio = document.createElement('audio'),
// create the audio from the sliced chunk
audio_blob = new Blob(chunksSliced, {
'type' : 'audio/mpeg'
});
audio.controls = 'controls';
audio.autoplay = 'autoplay';
audio.src = window.URL.createObjectURL( audio_blob );
document.body.appendChild(audio);
};
}

如果需要,您可以以毫秒为单位减小块的大小。只需传递不同的数字start并将数组切到所需的位置即可。

要获得更具体的答案,您可以对 audioSlice 执行此操作:

const TIMESLICE = 1000;
// @param chunks Array with the audio chunks
// @param start where to start cutting in seconds
// @param end where to stop cutting in seconds
function audioSlice(chunks, start, end) {
const timeSliceToSeconds = TIMESLICE/1000;
const startIndex = Math.round(start / timeSliceToSeconds);
const endIndex = Math.round(end / timeSliceToSeconds);
if (startIndex < chunks.length && endIndex < chunks.length) {
return chunks.slice(startIndex, endIndex)
}
throw Error('You cannot cut this at those points');
}

如果您修改值的 TIMESLICE,它将计算在以秒为单位传递时要剪切的位置

尝试在暂停时收集 timeSliced 块,然后过滤掉这些块:

if(this.isPaused){
this.deleteChunks.push(...audioChunks)
}
const pushChunks = _.filter(audioChunks, chunk=> _.indexOf(this.deleteChunks, chunk) > -1 ? false : true)
console.log("audioChunks::", this.deleteChunks, pushChunks.length, audioChunks.length)

最新更新