Javascript 从url提取音频片段并使用纯Web音频API播放

Javascript 从url提取音频片段并使用纯Web音频API播放,javascript,html,xmlhttprequest,web-audio-api,audiocontext,Javascript,Html,Xmlhttprequest,Web Audio Api,Audiocontext,在以下url上: 我想在以下范围内使用纯网络音频API播放一个音频: range from: second: 306.6 range to: second: 311.8 total: 5.2 seconds 我将该文件下载到我的桌面上(我使用的是windows10),然后用VLC打开它,得到了以下文件信息: 在这里,您可以了解有关此概念的信息: 从那里我得到了以下摘录: 我想播放上面评论的范围(也粘贴在这里): 通过从支持请求头的服务器下载该片段:Range 然后我尝试了

在以下url上:

我想在
以下范围内使用纯
网络音频API
播放一个音频:

range from: second: 306.6
  range to: second: 311.8
     total: 5.2 seconds
我将该文件下载到我的桌面上(我使用的是
windows10
),然后用
VLC
打开它,得到了以下文件信息:

在这里,您可以了解有关此概念的信息:

从那里我得到了以下摘录:

我想播放上面评论的
范围
(也粘贴在这里):

通过从支持请求头的服务器下载该片段:
Range

然后我尝试了以下代码:

...
let num_channels    = 2;
let sample_rate     = 44100;
let range_from      = 0;                                    // Goal: 306.6 seconds
let range_length    = (sample_rate / num_channels) * 5.2;   // Goal:   5.2 seconds
let range_to        = range_from + (range_length - 1);      // "range_to" is inclusive (confirmed)
request.setRequestHeader("Range", "bytes=" + range_from + "-" + range_to);
...
我的问题是:

  • 我需要为变量找到正确的值:
    range\u from
    ,以便它从第二个开始播放:
    306.6

  • 我想知道上面为:
    range\u length
    指定的值是否正确,因为可能有字节用于标题等,我的意思是:
    标题
    +
    数据

  • 这是我到目前为止的代码:

    window.AudioContext=window.AudioContext | | window.webkitadiocontext;//对于iPhone来说是必要的(可能是其他的)。可能在不久的将来改变。
    常量URL=https://www.tophtml.com/snl/15.mp3';
    const context=新的AudioContext();
    addEventListener('load',function()){
    const button_option_1=document.querySelector('.button_option_1');
    const button_option_1_play=document.querySelector('.button_option_1_play');
    按钮\u选项\u 1\u播放。禁用=真;
    按钮选项1.addEventListener('click',异步函数(){
    让时间开始,持续时间;
    让缓冲;
    日志(“…”,false);
    按钮\u选项\u 1\u play.disabled=true;
    按钮_选项_1 _play.onclick=()=>playBuffer(缓冲区);
    //---
    time_start=new Date().getTime();
    让arrayBuffer=等待获取(URL);
    //下载完整
    持续时间=sprintf('%.2fs',(新日期().getTime()-time\u开始)/1000);
    日志(sprintf('P2.Delay:+%s用于下载。等待…',持续时间));
    //---
    time_start=new Date().getTime();
    let audioBuffer=等待解码音频数据(上下文,arrayBuffer);
    //解码完成
    持续时间=sprintf('%.2fs',(新日期().getTime()-time\u开始)/1000);
    日志(sprintf('P3.延迟:+%s用于解码',持续时间));
    //---
    按钮\u选项\u 1\u play.disabled=false;
    缓冲区=音频缓冲区;
    按钮选项1播放。单击();
    });
    });
    功能播放缓冲区(缓冲区、起始区、持续时间){
    const source=context.createBufferSource();//源的类型:“AudioBufferSourceNode”
    source.buffer=缓冲区;
    source.connect(context.destination);
    source.start(context.currentTime、from、duration);
    }
    函数日志(text,append=true){
    让log=document.querySelector('.log');
    如果(!追加)
    log.innerHTML='';
    让entry=document.createElement('div');
    entry.innerHTML=文本;
    log.appendChild(条目);
    }
    函数解码音频数据(上下文,arrayBuffer){
    返回新承诺(异步(解析、拒绝)=>{
    if(false){}
    else if(context.decodeAudioData.length==1){
    //console.log(“解码音频数据/方式1”);
    让audioBuffer=等待上下文。解码AudioData(arrayBuffer);
    解析(音频缓冲);
    }
    else if(context.decodeAudioData.length==2){
    //iPhone(Safari,Chrome)和Mac(Safari)所必需的。可能在不久的将来改变。
    //console.log(“解码音频数据/方式2”);
    解码音频数据(arrayBuffer,函数onSuccess(audioBuffer){
    解析(音频缓冲);
    });
    }
    });
    }
    函数获取(url){
    返回新承诺((解决、拒绝)=>{
    var request=new XMLHttpRequest();
    打开('GET',url,true);
    request.responseType='arraybuffer';
    设num_通道=2;
    样本率=44100;
    让范围_from=0;//目标:306.6秒
    让范围长度=(采样率/通道数)*5.2;//目标:5.2秒
    让range_to=range_from+(range_length-1);/“range_to”包含在内(已确认)
    setRequestHeader(“Range”,“bytes=“+Range\u from+”-“+Range\u to”);
    request.onload=函数(){
    让arrayBuffer=request.response;
    let byteArray=新的UINT8阵列(arrayBuffer);
    //console.log(Array.from(byteArray));//只记录信息
    解决(arrayBuffer);
    }
    request.send();
    });
    }
    .log{
    显示:内联块;
    字体系列:“Courier New”,Courier,monospace;
    字体大小:13px;
    边缘顶部:10px;
    填充:4px;
    背景色:#d4e4ff;
    }
    .分隔器{
    边框顶部:1px实心#ccc;
    利润率:10px0;
    }
    
    选择1
    播放
    [空]
    帧长度(秒)=帧采样数/采样率,即38.28帧/秒

    帧长度(字节)=144*比特率/采样率

    因此,fetch()现在应该可以工作了(我也更改了范围长度):

    函数获取(url){
    返回新承诺((解决、拒绝)=>{
    var request=new XMLHttpRequest();
    打开('GET',url,true);
    request.responseType='arraybuffer';
    设num_通道=2;
    比特率=192000;
    样本率=44100;
    设字节/秒=144*(比特率/采样率)*38.28;
    let range_from=数学地板(字节/u秒*306.6);
    let range_length=数学地板(字节/秒*5.2);
    让range_to=range_from+(range_length-1);
    setRequestHeader(“Range”,“bytes=“+Range\u from+”-“+Range\u to”);
    request.onload=函数(){
    让arrayBuffer=request.response;
    let byteArray=新的UINT8阵列(arrayBuffer);
    //******************
    for(设i=0;irange from: second: 306.6
      range to: second: 311.8
         total: 5.2 seconds
    
    ...
    let num_channels    = 2;
    let sample_rate     = 44100;
    let range_from      = 0;                                    // Goal: 306.6 seconds
    let range_length    = (sample_rate / num_channels) * 5.2;   // Goal:   5.2 seconds
    let range_to        = range_from + (range_length - 1);      // "range_to" is inclusive (confirmed)
    request.setRequestHeader("Range", "bytes=" + range_from + "-" + range_to);
    ...
    
    function fetch(url) {
      return new Promise((resolve, reject) => {
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.responseType = 'arraybuffer';
        let num_channels    = 2;
        let bitrate         = 192000;
        let sample_rate     = 44100;
        let byte_per_sec    = 144 * (bitrate/sample_rate) * 38.28;
        let range_from      = Math.floor(byte_per_sec * 306.6);
        let range_length    = Math.floor(byte_per_sec * 5.2);
        let range_to        = range_from + (range_length - 1);
        request.setRequestHeader("Range", "bytes=" + range_from + "-" + range_to);
        request.onload = function() {
            let arrayBuffer = request.response;
            let byteArray = new Uint8Array(arrayBuffer);
            //******************
                for ( let i = 0; i < byteArray.length; i += 1 ) {
                    if (( byteArray[i] === 0b11111111 ) && ( byteArray[ i + 1 ] & 0b11110000 ) === 0b11110000 ){
                        log('we have a winner! Frame header at:'+i, true);
                        console.log((parseInt(byteArray[i], 10)).toString(2)); //frame header 4 bytes
                        console.log((parseInt(byteArray[i+1], 10)).toString(2));
                        console.log((parseInt(byteArray[i+2], 10)).toString(2));
                        console.log((parseInt(byteArray[i+3], 10)).toString(2));
                        resolve(arrayBuffer.slice(i));
                        break;
                    }
                }
            //******************
        }
        request.send();
      });
    }