【问题标题】:How to download an array of audio files in one file如何在一个文件中下载一组音频文件
【发布时间】:2022-01-20 16:35:44
【问题描述】:

我正在尝试制作一个音板网络应用程序,您可以在其中将音频文件添加到网站,它们将存储在索引数据库中,然后被提取和播放。

我还在考虑添加一个功能,让您将整个音频文件包下载为单个文件,以便其他人能够导入您的包。 数据看起来像这样:

const data = [
  {
    title: 'audio1',
    description: 'blabla'
    audio: AudioBuffer //or some other buffer
  },{
    title: 'audio2',
    description: 'blablabla'
    audio: AudioBuffer
  }
]

问题是,我将如何将其下载为单个文件?可能有一种方法可以处理 blob 等,但我不知道在哪里寻找。 显然,我还必须将其解码后才能使用

【问题讨论】:

  • 我建议你找到并使用这个库。我以前使用过合并文件来完成类似的任务。 npmjs.com/package/merge-files
  • @Poku 存储多个东西并不是什么大问题,困难的部分是保存包含字符串和音频缓冲区的对象。另外,我需要在客户端进行

标签: javascript blob web-audio-api arraybuffer


【解决方案1】:

避免使用外部库并保持应用程序精简是值得的。考虑构建一个可下载的二进制文件,其结构如下:

*************************************************
|  MARKER  |  META  |  AUDIO  |  AUDIO  |  ...  |  
*************************************************
// Example 32 MiB audio buffers
const audio1 =   new Uint8Array(32 * 1024**2 /   Uint8Array.BYTES_PER_ELEMENT)
const audio2 = new Float32Array(32 * 1024**2 / Float32Array.BYTES_PER_ELEMENT)
​
// Metadata for your file
const meta = new TextEncoder().encode(JSON.stringify([
  { title: 'audio1', length: audio1.byteLength }, 
  { title: 'audio2', length: audio2.byteLength }, 
]))
​
// use 32-bit integer to store byte index where audio begins (metadata ends)
const marker = new Uint32Array([
  meta.byteLength + 4 // include 4 bytes for this 32-bit integer
])
​
function initDownload() {
  const a = document.createElement('a')
  a.href = URL.createObjectURL(new Blob([
    marker,
    meta,
    audio1,
    audio2,
  ], { type: 'application/octet-stream' }))
  a.download = 'saved-audio-project.bin'
  a.click()
}

function parseFile(buffer) {  // ArrayBuffer of file
  const metaLength = new DataView(buffer).getUint32(0, true)
  let readOffset = 4 // 4-byte marker length
  const audioFiles = JSON.parse(
    new TextDecoder().decode(
      buffer.slice(readOffset, readOffset += metaLength)
    )
  )  
  audioFiles.forEach(audio => audio.data = new Float32Array(
    buffer.slice(readOffset, readOffset += audio.length)
  ))
  return audioFiles
}

【讨论】:

  • 这实际上是我想做的一种方式,但并没有想太多。回顾一下,标记表示元数据有多长,所以在解码时我必须按照标记给定的长度拆分数组,第一部分是元数据,然后剩余的数据将是音频文件,我可以根据元数据长度拆分长度。现在有一件事,AudioBuffer 是 Fl​​oat32Array,而不是 UInt8Array,我该如何处理?
  • 不用担心,Blob() 是为您准备的,而底层的ArrayBuffer 仍在使用中。您可以更改类型化的数组,只需保留 Uint32Array 作为填充/可缩放标记。
  • 啊,好吧,所以我猜 .byteLength 也会相应地处理数组的长度,我会尝试这种方式并回到这里以防我无法弄清楚。谢谢!
  • 好的,所以我尝试了这个,我在解码时遇到问题,在运行 const metaLength = new DataView(buffer).getUint32(0) 时,我得到一个数字,这是 waaay off,做了一个包含 3 个音频文件的示例,我得到 2332098560,编码器的代码在这里:github.com/Specy/soundboard/blob/… 解码器在这里:(完成)github.com/Specy/soundboard/blob/main/src/utils/PackImporter.ts 网站在这里:soundboard.specy.app
  • getUint32(0, true) (littleEndian)。看起来字节正在被向后读取,因此是倒置的大数字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-22
  • 2014-07-29
  • 2019-02-24
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
相关资源
最近更新 更多