ref: 60d213d2a215dc1c764507b51a065d81b6a2a8d7
dir: /src/smploaders/ft2_load_brr.c/
/* Super Nintendo BRR sample loader (based on work by _astriid_, but heavily modified)
**
** Note: Vol/loop sanitation is done in the last stage
** of sample loading, so you don't need to do that here.
** Do NOT close the file handle!
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "../ft2_header.h"
#include "../ft2_sample_ed.h"
#include "../ft2_sysreqs.h"
#include "../ft2_sample_loader.h"
#define BRR_RATIO(x) (((x) * 16) / 9)
static int16_t s1, s2;
bool detectBRR(FILE *f)
{
if (f == NULL)
return false;
uint32_t oldPos = (uint32_t)ftell(f);
fseek(f, 0, SEEK_END);
uint32_t filesize = (uint32_t)ftell(f);
const uint32_t filesizeMod9 = filesize % 9;
if (filesize < 11 || filesize > 65536 || (filesizeMod9 != 0 && filesizeMod9 != 2))
goto error; // definitely not a BRR file
rewind(f);
uint32_t blockBytes = filesize;
if (filesizeMod9 == 2) // skip loop block word
{
fseek(f, 2, SEEK_CUR);
blockBytes -= 2;
}
uint32_t numBlocks = blockBytes / 9;
// if the first block is the last, this is very unlikely to be a real BRR sample
uint8_t header = (uint8_t)fgetc(f);
if (header & 1)
goto error;
/* Test the shift range of a few blocks.
** While it's possible to have a shift value above 12 (illegal),
** it's rare in dumped BRR samples. I have personally seen 13,
** but never above, so let's test for >13 then.
*/
uint32_t blocksToTest = 8;
if (blocksToTest > numBlocks)
blocksToTest = numBlocks;
for (uint32_t i = 0; i < blocksToTest; i++)
{
const uint8_t shift = header >> 4;
if (shift > 13)
goto error;
fseek(f, 8, SEEK_CUR);
header = (uint8_t)fgetc(f);
}
fseek(f, oldPos, SEEK_SET);
return true;
error:
fseek(f, oldPos, SEEK_SET);
return false;
}
static int16_t decodeSample(int8_t nybble, int32_t shift, int32_t filter)
{
int32_t smp = (nybble << shift) >> 1;
if (shift >= 13)
smp &= ~2047; // invalid shift clamping
switch (filter)
{
default: break;
case 1:
smp += (s1 * 15) >> 4;
break;
case 2:
smp += (s1 * 61) >> 5;
smp -= (s2 * 15) >> 4;
break;
case 3:
smp += (s1 * 115) >> 6;
smp -= (s2 * 13) >> 4;
break;
}
// clamp as 16-bit, even if we decode into a 15-bit sample
smp = CLAMP(smp, -32768, 32767);
// 15-bit clip
if (smp & 16384)
smp |= ~16383;
else
smp &= 16383;
// shuffle last samples (store as 15-bit sample)
s2 = s1;
s1 = (int16_t)smp;
return (int16_t)(smp << 1); // multiply by two to get 16-bit scale
}
bool loadBRR(FILE *f, uint32_t filesize)
{
sample_t *s = &tmpSmp;
uint32_t blockBytes = filesize, loopStart = 0;
if ((filesize % 9) == 2) // loop header present
{
uint16_t loopStartBlock;
fread(&loopStartBlock, 2, 1, f);
loopStart = BRR_RATIO(loopStartBlock);
blockBytes -= 2;
}
uint32_t sampleLength = BRR_RATIO(blockBytes);
if (!allocateSmpData(s, sampleLength, true))
{
loaderMsgBox("Not enough memory!");
return false;
}
uint32_t shift = 0, filter = 0;
bool loopFlag = false, endFlag = false;
s1 = s2 = 0; // clear last BRR samples (for decoding)
int16_t *ptr16 = (int16_t *)s->dataPtr;
for (uint32_t i = 0; i < blockBytes; i++)
{
const uint32_t blockOffset = i % 9;
const uint8_t byte = (uint8_t)fgetc(f);
if (blockOffset == 0) // this byte is the BRR header
{
shift = byte >> 4;
filter = (byte & 0x0C) >> 2;
loopFlag = !!(byte & 0x02);
endFlag = !!(byte & 0x01);
continue;
}
// decode samples
*ptr16++ = decodeSample((int8_t)byte >> 4, shift, filter);
*ptr16++ = decodeSample((int8_t)(byte << 4) >> 4, shift, filter);
if (endFlag && blockOffset == 8)
{
sampleLength = BRR_RATIO(i+1);
break;
}
}
s->volume = 64;
s->panning = 128;
s->flags |= SAMPLE_16BIT;
s->length = sampleLength;
if (loopFlag) // XXX: Maybe this is not how to do it..?
{
s->flags |= LOOP_FWD;
s->loopStart = loopStart;
s->loopLength = sampleLength - loopStart;
}
return true;
}