Open spessasus opened 3 hours ago
The problem
Currently, SF2 is limited to 4GB of data. This is a problem for larger soundfonts.
Problems with the SFe approach
SFe approaches this problem by creating a second version called SFe64. I think it's unnecessary to create two versions. Also, if we want to DLSify the specification (wrap everything in LIST chunks), 64 bits would waste a ton of space for storing small numbers for small chunks.
Proposed solution
I propose a new type of a RIFF chunk with dynamic and virtually unlimited size. Here's how it would work:
typedef struct { CHAR[4] fourCC; // the regular FourCC code BYTE ckSizeLength; // the length of the size field in bytes CHAR[4] ckSize; // the RIFF chunk size BYTE[ckSize] data; // the RIFF chunk data } RiffDynamic;
Or
RIFD
if we want to fit in the 4 character name.This adds a new byte called
ckSizeLength
. As the name suggests, this describes the length in bytes of theckSize
field, rather than being fixed at 4 bytes. Everything else is still the same.For example, a chunk that will contain 100 bytes will look like this:
0x72 // "R" 0x69 // "I" 0x66 // "F" 0x66 // "F" 0x01 // ckSizeLength: 1 byte 0x64 // ckSize: 100 bytes // the chunk data here: 100 bytes with something
This saves 2 bytes already. Regular RIFF would use a total of 8 bytes for header (fourCC + ckSize), while this approach only uses 6.
What about 32-bit systems?
I'm glad you asked. This approach would work with these just fine.
A 32-bit device would simply reject a file which has
ckSizeLength
set above 4 bytes, since that's the maximum number. There's no advantage of using a different 32-bit version of the format instead of this as it wouldn't be able to store that sizes anyways. And shrinking the file (by deleting instruments or samples for example) could shrink the size enough to be able to be read by a 32-bit device, without the need of converting SFe64 to SFe32.Advantages of this approach
Virtually unlimited chunk size
This approach easily allows us to use 64-bit chunks and more! If 128-bit would ever become the standard, no problem!
ckSizeLength
would simply grow to 16 or up if needed.File size savings
Why store a small number as a 32-bit integer? This approach allows us to use only the minimum amount of bytes needed to store the size. For example, an INAM chunk wouldn't probably be longer than around 60 bytes. Therefore only one byte is needed to store the size + one byte for
ckSizeLength
. That's two bytes less than the regular 32-bit RIFF.Dynamic bitness
File too large to be read by a 32-bit system? No problem! Simply shrink the soundfont's size down to 4GB or less, and the
ckSizeLength
will reach 4 or lower, allowing the 32-bit device to read the soundfont without issues or needing to convert to SFe32.Drop-in replacement
The only thing that would need to be changed is the writing/reading function for RIFF chunks. Everything else stays the same, so there's no need for a rewrite. In fact, here's SpessaSynth's RIFF reading function adjusted for this proposal:
export function readRIFFChunk(dataArray, readData = true, forceShift = false) { let header = readBytesAsString(dataArray, 4); let sizeByteLength = dataArray[dataArray.currentIndex++]; // this line is new let size = readLittleEndian(dataArray, sizeByteLength); // this line is changed let chunkData = undefined; if (readData) { chunkData = new IndexedByteArray(dataArray.buffer.slice(dataArray.currentIndex, dataArray.currentIndex + size)); } if (readData || forceShift) { dataArray.currentIndex += size; } if (size % 2 !== 0) { if (dataArray[dataArray.currentIndex] === 0) { dataArray.currentIndex++; } } return new RiffChunk(header, size, chunkData); }
What do you think about this idea?
I find it ingenious. One reason why Saga Musix did not like TSC was because it didn't apparently fall back gracefully.
If we're changing the fabric of RIFF, then let's find out a way to create banks that use samples with mixed bitdepths.
While it may not be a complete rewrite for something like Spessasynth, it may be a complete rewrite for other programs. This is something to consider for a version of SFe in the far future, when the RIFF-based format that SFe is currently built on is completely tapped out.
If we're changing the fabric of RIFF, then let's find out a way to create banks that use samples with mixed bitdepths.
that's exactly what DLS does. Its sdta
equivalent is just a RIFF LIST of WAVE files. They can have whatever bit depth you want them to be. And they can use compression too!
The problem
Currently, SF2 is limited to 4GB of data. This is a problem for larger soundfonts.
Problems with the SFe approach
SFe approaches this problem by creating a second version called SFe64. I think it's unnecessary to create two versions. Also, if we want to DLSify the specification (wrap everything in LIST chunks), 64 bits would waste a ton of space for storing small numbers for small chunks.
Proposed solution
I propose a new type of a RIFF chunk with dynamic and virtually unlimited size. Here's how it would work:
Or
RIFD
if we want to fit in the 4 character name.This adds a new byte called
ckSizeLength
. As the name suggests, this describes the length in bytes of theckSize
field, rather than being fixed at 4 bytes. Everything else is still the same.For example, a chunk that will contain 100 bytes will look like this:
This saves 2 bytes already. Regular RIFF would use a total of 8 bytes for header (fourCC + ckSize), while this approach only uses 6.
What about 32-bit systems?
I'm glad you asked. This approach would work with these just fine.
A 32-bit device would simply reject a file which has
ckSizeLength
set above 4 bytes, since that's the maximum number. There's no advantage of using a different 32-bit version of the format instead of this as it wouldn't be able to store that sizes anyways. And shrinking the file (by deleting instruments or samples for example) could shrink the size enough to be able to be read by a 32-bit device, without the need of converting SFe64 to SFe32.Advantages of this approach
Virtually unlimited chunk size
This approach easily allows us to use 64-bit chunks and more! If 128-bit would ever become the standard, no problem!
ckSizeLength
would simply grow to 16 or up if needed.File size savings
Why store a small number as a 32-bit integer? This approach allows us to use only the minimum amount of bytes needed to store the size. For example, an INAM chunk wouldn't probably be longer than around 60 bytes. Therefore only one byte is needed to store the size + one byte for
ckSizeLength
. That's two bytes less than the regular 32-bit RIFF.Dynamic bitness
File too large to be read by a 32-bit system? No problem! Simply shrink the soundfont's size down to 4GB or less, and the
ckSizeLength
will reach 4 or lower, allowing the 32-bit device to read the soundfont without issues or needing to convert to SFe32.Drop-in replacement
The only thing that would need to be changed is the writing/reading function for RIFF chunks. Everything else stays the same, so there's no need for a rewrite. In fact, here's SpessaSynth's RIFF reading function adjusted for this proposal:
What do you think about this idea?