我终于找到了解决方案,如果有人遇到同样的问题,我会回答我自己的问题。请记住,我只想从歌曲文件的每一帧中获取频率(然后获取频谱数据)。所以我不得不停止寻找之前获得的样本数据的频率来采取一些步骤返回(请参阅问题以了解最后一部分)。
我找到了AudioContext 的替代品OfflineAudioContext。使用 AudioContext,您需要实时播放音频文件以获取频谱数据(音调),但使用 OfflineAudioContext 您可以节省很多时间,因为它通过渲染音频文件尽可能快地处理所有文件数据。我会说WebAudioAPI真的很混乱,我在得到预期的结果后尝试了几次,但我终于得到了。
您将在下面找到“最终代码”,以获取音频的每一帧(取决于声明的 fps)的频谱数据。此外,您还可以查看下一个数据处理视频结果中获得的数据可以做什么。
Video Result(抱歉,我无法将视频上传到 StackOverflow,因此您需要从 Google Drive 下载结果视频)
Javascript
它将返回每一帧的频谱数据数组。
[警告] 此代码与 Firefox 不兼容,因为它使用 OfflineAudioContext.pause() 和 OfflineAudioContext.resume() 函数 (see more details)。
let $audioCtx = new ( window.AudioContext || window.webkitAudioContext )( ) ;
let $audioOff = null ;
let $analyser = null ;
let FFT_SIZE = 512 ;
fetch( $data.file_url )
.then( response => response.arrayBuffer( ) )
.then( arrayBuffer => $audioCtx.decodeAudioData( arrayBuffer ) )
.then( async ( audioBuffer ) => {
window.$audioBuffer = audioBuffer ;
return new Promise( ( resolve, reject ) => {
$audioOff = new window.OfflineAudioContext( 2, audioBuffer.length, audioBuffer.sampleRate ) ;
$analyser = $audioOff.createAnalyser( ) ;
$analyser . fftSize = FFT_SIZE ;
$analyser . smoothingTimeConstant = $data.fps === 24 ? 0.16 : $data.fps === 29 ? 0.24 : 0.48 ;
$analyser . connect( $audioOff.destination ) ;
var source = $audioOff.createBufferSource( ) ;
source . buffer = audioBuffer ;
source . connect( $analyser ) ;
var __data = [ ] ;
var fps = $data.fps || 24 ;
var index = 0.4 ;
var length = Math.ceil( audioBuffer.duration * fps ) ;
var time = ( ( 1 / fps ) ) ;
var onSuspend = ( ) => {
return new Promise( ( res, rej ) => {
index += 1 ;
var raw = new Uint8Array( $analyser.frequencyBinCount ) ;
$analyser.getByteFrequencyData ( raw ) ;
__data.push( raw ) ;
if( index < length ) {
if( time * ( index + 1 ) < audioBuffer.duration )
{ $audioOff.suspend( time * ( index + 1 ) ).then( onSuspend ) ; }
$audioOff.resume( ) ;
} return res( 'OK' ) ;
} ) ;
} ;
$audioOff.suspend( time * ( index + 1 ) ).then( onSuspend ) ;
source.start( 0 ) ;
console.log( 'Decoding Audio-Spectrum...' ) ;
$audioOff.startRendering( ).then( ( ) => {
console.log( '[✔] Audio-Spectrum Decoded!' ) ;
return resolve( __data ) ;
} ).catch( ( err ) => {
console.log( 'Rendering failed: ' + err ) ;
throw { error : 'Get audio data error', message : err } ;
} ) ;
} ) ;
} )
.then( async ( spectrumData ) => {
/* DO SOMETHING WITH SPECTRUM DATA */
/* spectrumData[ 0 ] is the first frame, depending of established fps */
/* spectrumData[ 1 ] = 2nd frame ... */
} ) ;