【问题标题】:download result mp3 file after processing in wavesurfer.js and Web Audio API在 wavesurfer.js 和 Web Audio API 处理后下载结果 mp3 文件
【发布时间】:2021-06-26 10:47:50
【问题描述】:

我对这个主题进行了为期 2 天的广泛研究,但没有一个很好解释的文章会起作用。

所以流程如下:

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

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

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

我们的目标是使用来自wavesurfer 的现有参考来生成下载mp3

据我了解,这可以通过 MediaRecorderWebCodecs APIlamejs 等一些库来完成。

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

到目前为止,我只能使用以下脚本下载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, sample, 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, data, true);
        pos += 4;
    }
};

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

有没有办法避免制作wav并立即制作mp3并下载它,或者如果没有从wav制作mp3,如果是这样怎么做?

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

【问题讨论】:

    标签: javascript web-audio-api wavesurfer.js


    【解决方案1】:

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

    1. 从 wavesurfer 播放器获取buffer 数据
    2. 分析buffer 以获得通道数(STEREO 或 MONO)、通道数据和采样率。
    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, btwSample, 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, wavHdr.sampleRate,  data);
        
    
        function setUint16(data) {
            btwView.setUint16(btwPos, data, true);
            btwPos += 2;
        }
    
        function setUint32(data) {
            btwView.setUint32(btwPos, data, true);
            btwPos += 4;
        }
      }
    
      function bufferToMp3(channels, sampleRate, left, right = null) {
        var buffer = [];
        var mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 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;
      
      }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      相关资源
      最近更新 更多