Specy
Specy

Reputation: 331

How to download an array of audio files in one file

I'm trying to make a soundboard webapp where you can add audio files to the website and they will be stored inside of the indexed db to be then fetched and played.

I was thinking of also adding a feature that would let you download the whole pack of audio files as a single file so that other people would be able to import your pack. The data would look something like this:

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

The question is, how would i go at downloading this as a single file? There is probably a way with blobs etc but i have no idea where to look for. Obviously i would also have to decode this back to be used

Upvotes: 1

Views: 557

Answers (1)

anthumchris
anthumchris

Reputation: 9072

It's worth avoiding external libraries and keeping your application lean. Consider building a downloadable binary file structured like:

*************************************************
|  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
}

Upvotes: 1

Related Questions