可以合并两个音频“base64data”字符串来创建一个独特的音频文件吗?

问题描述 投票:0回答:4

可以合并两个音频“base64data”字符串来创建一个独特的音频文件吗?

我在字符串中有两个循环音频 Base64 wav,如下所示:

data:audio/x-wav;base64,UklGRuIfQVZFZm1R7SH$WP90AhICLwKT...

我想我正在做一些非常愚蠢的事情,但我想知道这是否可能。

我正在尝试将两个 wav 合并为一个可以在音频 HTML 元素中播放的 wav。 我想提取第二个的base64数据以合并到第一个,然后播放它,但导航器返回错误。

这是我的JavaScript代码:

var audio_Data1 = base64_audio1;
var audio_Data2 = base64_audio1.split(',')[1];
var audio_final = audio_Data1 + audio_Data2;

audioControl.src = audio_final;
audioControl.play();

感谢您的建议 谢谢你!


编辑:

我正在尝试解码 Base64 块以缓冲数据并连接缓冲区以再次编码为 Base64。

问题:返回的base64是“AA==”

我认为“AA==”是0字节。然后当我连接缓冲区时我做了一些坏事:

var myB64Data  = myB64WavString.split(',');
var myB64Chunk = myB64Data[1];
var myBuffer1 =  base64ToArrayBuffer(myB64Chunk);
var myBuffer2 = ""; //Same process

var myFinalBuffer = [];
myFinalBuffer.push.apply(myFinalBuffer, myBuffer1);
myFinalBuffer.push.apply(myFinalBuffer, myBuffer2); 

var myFinalB64 = 'data:audio/x-wav;base64,' + arrayBufferToBase64(myFinalBuffer); 

console.log( myFinalB64 );

控制台返回下一个:“data:audio/x-wav;base64,AA==”

我的编码/解码的 JavaScript 工作函数:

function base64ToArrayBuffer(base64) {
   var binary_string =  window.atob(base64);
   var len = binary_string.length;
   var bytes = new Uint8Array( len );
   for (var i = 0; i < len; i++)        {
       bytes[i] = binary_string.charCodeAt(i);
   }
   return bytes.buffer;
}

function arrayBufferToBase64( buffer ) {
   var binary = '';
   var bytes = new Uint8Array( buffer );
   var len = bytes.byteLength;
   for (var i = 0; i < len; i++) {
       binary += String.fromCharCode( bytes[ i ] );
   }
   return window.btoa( binary );
}
javascript audio web-audio-api
4个回答
4
投票

我解决了它!(经过艰苦而疯狂的工作两天后,并通过从 Convert AudioBuffer to ArrayBuffer / Blob for WAV Download 复制答案) 我希望它可以帮助您节省我为此开发的所有工作;)

var myB64Data  = myB64WavString.split(',');
var myB64Chunk = myB64Data[1];
var myBuffer1 =  base64ToArrayBuffer(myB64Chunk);
var myBuffer2 = ""; //Same process

var myFinalBuffer = appendBuffer (myBuffer1, myBuffer2);

var myFinalBuffer = getWavBytes( arrBytesFinal, {
  isFloat: false,       // floating point or 16-bit integer
  numChannels: 2,     //1 for mono recordings
  sampleRate: 48000, //Depends on your file audio bitrate !! 32000
})              


var myFinalB64 = 'data:audio/x-wav;base64,' + arrayBufferToBase64(myFinalBuffer); 

console.log( myFinalB64 );

//Then you can asign to an audio HTML control

myAudioControl.src = myFinalB64;

附加功能:

function appendBuffer(buffer1, buffer2) {
  var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
  tmp.set(new Uint8Array(buffer1), 0);
  tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
  return tmp;
};
 

function getWavBytes(buffer, options) {
  const type = options.isFloat ? Float32Array : Uint16Array
  const numFrames = buffer.byteLength / type.BYTES_PER_ELEMENT

  const headerBytes = getWavHeader(Object.assign({}, options, { numFrames }))
  const wavBytes = new Uint8Array(headerBytes.length + buffer.byteLength);

  // prepend header, then add pcmBytes
  wavBytes.set(headerBytes, 0)
  wavBytes.set(new Uint8Array(buffer), headerBytes.length)

  return wavBytes
}

// adapted from https://gist.github.com/also/900023
// returns Uint8Array of WAV header bytes
function getWavHeader(options) {
  const numFrames =      options.numFrames
  const numChannels =    options.numChannels || 2
  const sampleRate =     options.sampleRate || 44100
  const bytesPerSample = options.isFloat? 4 : 2
  const format =         options.isFloat? 3 : 1

  const blockAlign = numChannels * bytesPerSample
  const byteRate = sampleRate * blockAlign
  const dataSize = numFrames * blockAlign

  const buffer = new ArrayBuffer(44)
  const dv = new DataView(buffer)

  let p = 0

  function writeString(s) {
    for (let i = 0; i < s.length; i++) {
      dv.setUint8(p + i, s.charCodeAt(i))
    }
    p += s.length
  }

  function writeUint32(d) {
    dv.setUint32(p, d, true)
    p += 4
  }

  function writeUint16(d) {
    dv.setUint16(p, d, true)
    p += 2
  }

  writeString('RIFF')              // ChunkID
  writeUint32(dataSize + 36)       // ChunkSize
  writeString('WAVE')              // Format
  writeString('fmt ')              // Subchunk1ID
  writeUint32(16)                  // Subchunk1Size
  writeUint16(format)              // AudioFormat
  writeUint16(numChannels)         // NumChannels
  writeUint32(sampleRate)          // SampleRate
  writeUint32(byteRate)            // ByteRate
  writeUint16(blockAlign)          // BlockAlign
  writeUint16(bytesPerSample * 8)  // BitsPerSample
  writeString('data')              // Subchunk2ID
  writeUint32(dataSize)            // Subchunk2Size

  return new Uint8Array(buffer)
}

0
投票

为了扩展上面的答案,这里是如何对一组编码字符串而不是两个字符串进行操作。

function joinBuffers(buffers) {
  const byteLength = buffers
    .map((buffer) => buffer.byteLength)
    .reduce((prev, curr) => prev + curr);
  var tmp = new Uint8Array(byteLength);
  var length = 0;
  for (let i = 0; i < buffers.length; i++) {
    const buffer = buffers[i];
    tmp.set(new Uint8Array(buffer), length);
    length += buffer.byteLength;
  }
  return tmp;
}

0
投票

上面的答案对我不起作用,但这个简单的答案对我有用:

只需解码每个 B64 字符串

// Decode the String
var decodedString0 = atob(encodedString0);
var decodedString1 = atob(encodedString1);

将它们合并在一起,然后编码回来,

var decodedStringMerge = decodedString0 + decodedString1 
var ecodedStringMergeB64 = btoa(decodedStringMerge)

console.log(ecodedStringMergeB64);

播放合并的音频..


0
投票

使用过时的

atob
更新答案:

const decoded1 = Buffer.from(encodedString1, "base64");
const decoded2 = Buffer.from(encodedString2, "base64");
const encodedCombined = Buffer.concat([decoded1, decoded2]).toString("base64");
© www.soinside.com 2019 - 2024. All rights reserved.