简体   繁体   English

擦洗音频时如何听到声音播放<audio>标签?

[英]How can I hear sound playing while scrubbing the audio from an <audio> tag?

In my example, I have a mp3 that a user has uploaded to a webpage.在我的示例中,我有一个用户已上传到网页的 mp3。 I create a visual waveform on the page and have all the default controls coded and working (play, pause, stop, scrubbing, etc...)我在页面上创建了一个可视波形,并编码了所有默认控件并使其正常工作(播放、暂停、停止、擦除等...)

What I'm trying to accomplish is the scrubbing effect that you hear in After Effects or Animate.我想要实现的是您在 After Effects 或 Animate 中听到的擦洗效果。 When I scrub the audio, I want to hear the tones of the audio at the exact place where the scrubber is.当我擦洗音频时,我想在擦洗器所在的确切位置听到音频的音调。

I don't even know where to begin on this?我什至不知道从哪里开始? I looked into AudioContext and I think my answer is in there somewhere but I'm not sure.我查看了AudioContext ,我认为我的答案就在某个地方,但我不确定。 I've thought about having a "shadow audio tag" that I set the same src to and then calling play() and pausing it pretty soon after but that seems like a mess;我想过有一个“影子音频标签”,我将相同的 src 设置为,然后调用play()并在不久之后暂停它,但这似乎是一团糟; especially with an aggressive scrubber.尤其是使用激进的洗涤器。 Any direction would be appreciated!任何方向将不胜感激!

Yes your answer is in the AudioContext API (all async and slow MediaElements are not made for this).是的,您的答案在 AudioContext API 中(所有异步和慢速 MediaElements 都不是为此制作的)。 Specifically, what you want is the AudioBufferSourceNode interface, which is able to play audio instantly.具体来说,你想要的是AudioBufferSourceNode接口,它能够立即播放音频。

All you need to do is to fetch your audio file as an ArrayBuffer, ask an AudioContext to decode the audio PCM data from this buffer and create an AudioBuffer from it.您需要做的就是将您的音频文件作为 ArrayBuffer 获取,请求 AudioContext 解码来自该缓冲区的音频 PCM 数据并从中创建一个 AudioBuffer。

That was the heavy part, but it's done only once.这是最重要的部分,但它只完成了一次。

Then you just need to create a very-light AudioBufferSourceNode for each "scrub" event.然后你只需要为每个“scrub”事件创建一个非常轻的AudioBufferSourceNode
To do so, you can use the three arguments version of its start(when, offset, duration) method.为此,您可以使用其start(when, offset, duration)方法的三个参数版本。

 const slider = document.getElementById('slider'); const ctx = new AudioContext(); fetch("https://upload.wikimedia.org/wikipedia/en/d/dc/Strawberry_Fields_Forever_(Beatles_song_-_sample).ogg") .then( resp => resp.arrayBuffer() ) .then( buf => ctx.decodeAudioData(buf) ) .then( prepareUI ) .catch( console.error ); function prepareUI( audioBuf ) { let source; slider.oninput = e => { if( source ) { source.stop(0); } source = ctx.createBufferSource(); source.buffer = audioBuf; source.connect(ctx.destination); const offset = slider.value * audioBuf.duration; const duration = 0.1; source.start(0, offset, duration); }; slider.disabled = false; }
 input { width: 350px }
 <input type="range" id="slider" min="0" max="1" step="0.005" disabled>

And of-course you can also reuse this AudioBuffer for your whole player.当然,您也可以为整个播放器重复使用此 AudioBuffer。

I think you're on the right track.我认为你在正确的轨道上。 Your scrubber UI could interact with an Audio element that is not attached to the DOM/page and could directly set audio.currentTime , play for a few milliseconds, and then stop.您的 Scrubber UI 可以与未附加到 DOM/页面的Audio元素进行交互,并且可以直接设置audio.currentTime ,播放几毫秒,然后停止。 You can leverage cancellation of setTimeout() queues to create short scrubbing playbacks and then play continuously when the scrubbing stops.您可以利用setTimeout()队列的取消来创建短暂的清理播放,然后在清理停止时继续播放。 I assume this all depends on the complete file being downloaded to avoid network latency during scrubbing.我认为这一切都取决于正在下载的完整文件,以避免在清理过程中出现网络延迟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM