Reputation: 331
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
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