微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 wavesurfer.js 和 Web Audio API 中处理后下载结果 mp3 文件

如何解决在 wavesurfer.js 和 Web Audio API 中处理后下载结果 mp3 文件

我对该主题进行了为期 2 天的广泛研究,但没有真正有效的解释作品。

所以流程如下:

  1. mp3(商店购买)cbr 320 加载到 wavesurfer
  2. 应用您需要的所有更改
  3. 将处理后的结果下载回 mp3 文件(不使用服务器)

我见过可以做到这一点的在线应用程序,没有任何东西传输到服务器,一切都发生在浏览器中。

当我们检查 wavesurfer 时,我们可以访问这些:

wavesurfer backend references

目标是使用 wavesurfer 中已有的引用来生成下载 mp3

据我所知,这可以通过 MediaRecorderWebCodecs API 或一些库(例如 lamejs)来完成。

我试图找到如何使用两种第一种方法来做到这一点的工作示例,但没有运气。我还尝试使用 lamejs 使用他们在 git 上提供的示例来执行此操作,但我从库中收到了难以调试的错误,很可能与提供错误输入有关。

到目前为止,我只能使用以下脚本下载 wav 文件

handlecopyRegion = (region,instance) => {
    var segmentDuration = region.end - region.start;

    var originalBuffer = instance.backend.buffer;
    var emptySegment = instance.backend.ac.createBuffer(
        originalBuffer.numberOfChannels,Math.ceil(segmentDuration * originalBuffer.sampleRate),originalBuffer.sampleRate
    );
    for (var i = 0; i < originalBuffer.numberOfChannels; i++) {
        var chanData = originalBuffer.getChannelData(i);
        var emptySegmentData = emptySegment.getChannelData(i);
        var mid_data = chanData.subarray(
            Math.ceil(region.start * originalBuffer.sampleRate),Math.ceil(region.end * originalBuffer.sampleRate)
        );
        emptySegmentData.set(mid_data);
    }

    return emptySegment;
};

bufferToWave = (abuffer,offset,len) => {
    var numOfChan = abuffer.numberOfChannels,length = len * numOfChan * 2 + 44,buffer = new ArrayBuffer(length),view = new DataView(buffer),channels = [],i,sample,pos = 0;

    // write WAVE header
    setUint32(0x46464952); // "RIFF"
    setUint32(length - 8); // file length - 8
    setUint32(0x45564157); // "WAVE"

    setUint32(0x20746d66); // "fmt " chunk
    setUint32(16); // length = 16
    setUint16(1); // PCM (uncompressed)
    setUint16(numOfChan);
    setUint32(abuffer.sampleRate);
    setUint32(abuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
    setUint16(numOfChan * 2); // block-align
    setUint16(16); // 16-bit (hardcoded in this demo)

    setUint32(0x61746164); // "data" - chunk
    setUint32(length - pos - 4); // chunk length

    // write interleaved data
    for (i = 0; i < abuffer.numberOfChannels; i++)
        channels.push(abuffer.getChannelData(i));

    while (pos < length) {
        for (i = 0; i < numOfChan; i++) {
            // interleave channels
            sample = Math.max(-1,Math.min(1,channels[i][offset])); // clamp
            sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767) | 0; // scale to 16-bit signed int
            view.setInt16(pos,true); // update data chunk
            pos += 2;
        }
        offset++; // next source sample
    }

    // create Blob
    return new Blob([buffer],{ type: "audio/wav" });

    function setUint16(data) {
        view.setUint16(pos,data,true);
        pos += 2;
    }

    function setUint32(data) {
        view.setUint32(pos,true);
        pos += 4;
    }
};

const cutSelection = this.handlecopyRegion(
    this.wavesurfer.regions.list.cut,this.wavesurfer
);
const blob = this.bufferToWave(cutSelection,cutSelection.length);
// you can Now download wav from the blob

有没有办法避免制作 wav 并立即制作 mp3 并下载它,或者如果没有制作 mp3 从那个 wav,如果可以,它如何完成了吗?

我主要尝试使用 wavesurfer.backend.buffer 作为输入,因为这个引用是 AudioBuffer 并且访问 .getChannelData(0|1) 会给你 leftright 通道。但是没有完成任何事情,也许我想错了。

解决方法

好的,下面是我们需要做的步骤:

  1. 从 wavesurfer 播放器获取 buffer 数据
  2. 分析 buffer 以获得通道数(立体声或单声道)、通道数据和采样率。
  3. 使用 lamejs 库将缓冲区转换为 MP3 blob 文件
  4. 然后我们可以从 blob 获取下载链接

这是一个快速的DEMO

还有JS代码:

function downloadMp3() {
  var MP3Blob = analyzeAudioBuffer(wavesurfer.backend.buffer);
  console.log('here is your mp3 url:');
  console.log(URL.createObjectURL(MP3Blob));
}

function analyzeAudioBuffer(aBuffer) {
    let numOfChan = aBuffer.numberOfChannels,btwLength = aBuffer.length * numOfChan * 2 + 44,btwArrBuff = new ArrayBuffer(btwLength),btwView = new DataView(btwArrBuff),btwChnls = [],btwIndex,btwSample,btwOffset = 0,btwPos = 0;
    setUint32(0x46464952); // "RIFF"
    setUint32(btwLength - 8); // file length - 8
    setUint32(0x45564157); // "WAVE"
    setUint32(0x20746d66); // "fmt " chunk
    setUint32(16); // length = 16
    setUint16(1); // PCM (uncompressed)
    setUint16(numOfChan);
    setUint32(aBuffer.sampleRate);
    setUint32(aBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
    setUint16(numOfChan * 2); // block-align
    setUint16(16); // 16-bit
    setUint32(0x61746164); // "data" - chunk
    setUint32(btwLength - btwPos - 4); // chunk length

    for (btwIndex = 0; btwIndex < aBuffer.numberOfChannels; btwIndex++)
        btwChnls.push(aBuffer.getChannelData(btwIndex));

    while (btwPos < btwLength) {
        for (btwIndex = 0; btwIndex < numOfChan; btwIndex++) {
            // interleave btwChnls
            btwSample = Math.max(-1,Math.min(1,btwChnls[btwIndex][btwOffset])); // clamp
            btwSample = (0.5 + btwSample < 0 ? btwSample * 32768 : btwSample * 32767) | 0; // scale to 16-bit signed int
            btwView.setInt16(btwPos,true); // write 16-bit sample
            btwPos += 2;
        }
        btwOffset++; // next source sample
    }

    let wavHdr = lamejs.WavHeader.readHeader(new DataView(btwArrBuff));

    //Stereo
    let data = new Int16Array(btwArrBuff,wavHdr.dataOffset,wavHdr.dataLen / 2);
    let leftData = [];
    let rightData = [];
    for (let i = 0; i < data.length; i += 2) {
                 leftData.push(data[i]);
                 rightData.push(data[i + 1]);
    }
    var left = new Int16Array(leftData);
    var right = new Int16Array(rightData);



    //STEREO
    if (wavHdr.channels===2)
        return bufferToMp3(wavHdr.channels,wavHdr.sampleRate,left,right);
    //MONO
    else if (wavHdr.channels===1)
        return bufferToMp3(wavHdr.channels,data);
    

    function setUint16(data) {
        btwView.setUint16(btwPos,data,true);
        btwPos += 2;
    }

    function setUint32(data) {
        btwView.setUint32(btwPos,true);
        btwPos += 4;
    }
  }

  function bufferToMp3(channels,sampleRate,right = null) {
    var buffer = [];
    var mp3enc = new lamejs.Mp3Encoder(channels,128);
    var remaining = left.length;
    var samplesPerFrame = 1152;
  
  
    for (var i = 0; remaining >= samplesPerFrame; i += samplesPerFrame) {
  
        if (!right)
        {
            var mono = left.subarray(i,i + samplesPerFrame);
            var mp3buf = mp3enc.encodeBuffer(mono);
        }
        else {
            var leftChunk = left.subarray(i,i + samplesPerFrame);
            var rightChunk = right.subarray(i,i + samplesPerFrame);
            var mp3buf = mp3enc.encodeBuffer(leftChunk,rightChunk);
        }
            if (mp3buf.length > 0) {
                    buffer.push(mp3buf);//new Int8Array(mp3buf));
            }
            remaining -= samplesPerFrame;
    }
    var d = mp3enc.flush();
    if(d.length > 0){
            buffer.push(new Int8Array(d));
    }
  
    var mp3Blob = new Blob(buffer,{type: 'audio/mpeg'});
    //var bUrl = window.URL.createObjectURL(mp3Blob);
  
    // send the download link to the console
    //console.log('mp3 download:',bUrl);
    return mp3Blob;
  
  }

如果您对代码有任何疑问,请告诉我

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。