#176495 - Ruben - Sun Aug 07, 2011 6:05 pm
Hi all.
Just thought I'd post this as it's quite nifty.
Just today, I finished perfecting a new delta format that stores its samples as 4-bit data with indices.
The whole idea of the format is that the entire file is split into seven-sample 'blocks'. Each block contains a 4-bit index followed by 7x 4-bit samples. The index is a reference to a set of 16 delta tables and the four bit 'samples' are a reference to the table data.
Decoding (C/C++):
Decoding (ARM ASM):
What you may have noticed is that samples are loaded when the packed data = 0. You may be asking, "What if the final sample's index is zero?" Well, that's the thing: the final sample index *CAN'T* be zero. The conversion program should take care of that.
Another nifty thing about this format is that since it's differential PCM, linear interpolation is a LOT easier as you have to read the delta anyway so you can pre-load it (it's what I do).
Sound demo (NOTE: taken from my FFII-DS port, so there may be extra baggage and will NOT work on a real DS as it's using ROM/FS. You may also have to set DeSmuME to synchronous sound mode): MediaFire
Conversion program source (NOTE: made for my own DS library, so you'll have to make changes to use it): MediaFire
Just thought I'd post this as it's quite nifty.
Just today, I finished perfecting a new delta format that stores its samples as 4-bit data with indices.
The whole idea of the format is that the entire file is split into seven-sample 'blocks'. Each block contains a 4-bit index followed by 7x 4-bit samples. The index is a reference to a set of 16 delta tables and the four bit 'samples' are a reference to the table data.
Decoding (C/C++):
Code: |
//! read packed data [7 samples + index]
u32 pckDat = *src++; //! since data is packed as I1234567, //! find the index u32 tabIndex = pckDat>>28; //! since the whole point of this format //! is speed, the index is shifted off pckDat = pckDat << 4; //! now decode the seven samples for(i=0;i<7;i++) { //! find the delta //! NOTE: highest nibble first u32 ti = pckDat>>28; s32 delta = stepTab[tabIndex][ti]; //! add to original sample to find //! final data. //! since the data is 15-bit, there's //! no need to clip and overflow is ok smpDat += delta; //! skip to next sample. //! again, since the point of this //! format is speed, the data is //! shifted off pckDat = pckDat<<4; //! out of samples? if(!pckDat) pckDat = *src++; } |
Decoding (ARM ASM):
Code: |
@ r0: sample
@ r1: source data @ r2: step tables @ r3: packed data @ r4: current step table @ r5: mask @ r6: count prepare: ldd r0, =0 ldr r1, =sourceData ldr r2, =stepTab ldr r3, [r1], #0x04 @ load samples + index mov r4, r3, lsr #0x1C @ find index... add r4, r2, r4, lsl #0x01+4 @ find table source @ [SHL 1 for 16-bit data, @ SHL 4 as 16 entries] mov r3, r3, lsl #0x04 @ shift off index mvn r5, #0x01 @ mask = 0xFFFE mov r6, #0x07 @ count = 7 decode: and r7, r5, r3, lsr #0x1C-1 @ find table offset ldrsh r7, [r4, r7] @ find delta add r0, r0, r7 @ find final sample movs r3, r3, lsl #0x04 @ shift out data... ldreq r3, [r1], #0x04 @ load new data when out of data subs r6, r6, #0x01 @ more samples? bne decode @ yes, keep decoding |
What you may have noticed is that samples are loaded when the packed data = 0. You may be asking, "What if the final sample's index is zero?" Well, that's the thing: the final sample index *CAN'T* be zero. The conversion program should take care of that.
Another nifty thing about this format is that since it's differential PCM, linear interpolation is a LOT easier as you have to read the delta anyway so you can pre-load it (it's what I do).
Sound demo (NOTE: taken from my FFII-DS port, so there may be extra baggage and will NOT work on a real DS as it's using ROM/FS. You may also have to set DeSmuME to synchronous sound mode): MediaFire
Conversion program source (NOTE: made for my own DS library, so you'll have to make changes to use it): MediaFire