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

Cry*_*ird 2 javascript audio blob

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

例子:

sliceAudioBlob( audio_blob, 0, 10000 ); // Time in milliseconds [ start = 0, end = 10000 ]
Run Code Online (Sandbox Code Playgroud)

注意:我不知道如何做到这一点,所以一点提示将非常感激。

更新 :

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

完整的 HTML 代码:

<!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>
Run Code Online (Sandbox Code Playgroud)

Kai*_*ido 5

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

可能有一些方法使用 Web Audio API 将您的媒体文件转换为AudioBuffer,然后按照您的意愿切片此 AudioBuffer 的原始 PCM 数据,然后再使用正确的新描述符将其打包回媒体文件中,但我认为您面临着XY 问题,如果我正确理解,有一个简单的方法可以解决这个 X 问题。

事实上,您描述的问题是 Chrome 或 Firefox 都不会从您的代码中生成 10 秒的媒体。
但这是因为您依赖MediaRecorder.start(timeslice)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();
};
Run Code Online (Sandbox Code Playgroud)

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

以及使用来自 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;
}
Run Code Online (Sandbox Code Playgroud)
<button id="start" disabled>start</button>
<button id="stop" disabled>stop</button>
Run Code Online (Sandbox Code Playgroud)