ref: c151f95b68a8500612a49768cec1648c02562779
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; }