#include "amuse/N64MusyXCodec.hpp" #include #include #include /* Acknowledgements: * SubDrag for N64 Sound Tool (http://www.goldeneyevault.com/viewfile.php?id=212) * Bobby Smiles for MusyX codec research */ static int rdot(unsigned n, const int16_t* x, const int16_t* y) { int accu = 0; y += n; while (n != 0) { accu += ((int)*(x++) * (int)*(--y)); --n; } return accu; } static int16_t adpcm_get_predicted_sample(unsigned char byte, unsigned char mask, unsigned lshift, unsigned rshift) { int16_t sample = ((int16_t)byte & (int16_t)mask) << lshift; sample >>= rshift; /* signed */ return sample; } static void adpcm_get_predicted_frame(int16_t* dst, const unsigned char* src, const unsigned char* nibbles, unsigned rshift) { *(dst++) = (src[0] << 8) | src[1]; *(dst++) = (src[2] << 8) | src[3]; for (unsigned i = 1; i < 16; ++i) { unsigned char byteData = nibbles[i]; *(dst++) = adpcm_get_predicted_sample(byteData, 0xf0, 8, rshift); *(dst++) = adpcm_get_predicted_sample(byteData, 0x0f, 12, rshift); } } static unsigned adpcm_decode_upto_8_samples(int16_t* dst, const int16_t* src, const int16_t* cb_entry, const int16_t* last_samples, unsigned size) { if (size == 0) return 0; const int16_t* book1 = cb_entry; const int16_t* book2 = cb_entry + 8; int16_t l1 = last_samples[0]; int16_t l2 = last_samples[1]; int accu; for (unsigned i = 0; i < size; ++i) { accu = (int)src[i] << 11; accu += book1[i] * l1 + book2[i] * l2 + rdot(i, book2, src); dst[i] = N64MusyXSampClamp(accu >> 11); } return size; } unsigned N64MusyXDecompressFrame(int16_t* out, const uint8_t* in, const int16_t coefs[8][2][8], unsigned lastSample) { int16_t frame[32]; unsigned remSamples = lastSample; unsigned samples = 0; unsigned procSamples, procRes; unsigned char c2 = in[0x8]; c2 = c2 % 0x80; const int16_t* bookPredictors = coefs[(c2 & 0xf0) >> 4][0]; unsigned int rshift = (c2 & 0x0f); adpcm_get_predicted_frame(frame, &in[0x0], &in[0x8], rshift); procSamples = (remSamples < 2) ? remSamples : 2; memmove(out, frame, 2 * procSamples); samples += procSamples; remSamples -= procSamples; if (samples == lastSample) return samples; #define adpcm_decode_upto_end_samples(inOffset, outOffset, size) \ procSamples = (remSamples < size) ? remSamples : size; \ procRes = \ adpcm_decode_upto_8_samples(out + inOffset, frame + inOffset, bookPredictors, out + outOffset, procSamples); \ samples += procRes; \ remSamples -= procRes; \ if (samples == lastSample) \ return samples; adpcm_decode_upto_end_samples(2, 0, 6); adpcm_decode_upto_end_samples(8, 6, 8); adpcm_decode_upto_end_samples(16, 14, 8); adpcm_decode_upto_end_samples(24, 22, 8); out += 32; c2 = in[0x18]; c2 = c2 % 0x80; bookPredictors = coefs[(c2 & 0xf0) >> 4][0]; rshift = (c2 & 0x0f); adpcm_get_predicted_frame(frame, &in[0x4], &in[0x18], rshift); procSamples = (remSamples < 2) ? remSamples : 2; memmove(out, frame, 2 * procSamples); samples += procSamples; remSamples -= procSamples; if (samples == lastSample) return samples; adpcm_decode_upto_end_samples(2, 0, 6); adpcm_decode_upto_end_samples(8, 6, 8); adpcm_decode_upto_end_samples(16, 14, 8); adpcm_decode_upto_end_samples(24, 22, 8); return samples; } unsigned N64MusyXDecompressFrameRanged(int16_t* out, const uint8_t* in, const int16_t coefs[8][2][8], unsigned firstSample, unsigned lastSample) { int16_t final[64]; unsigned procSamples = N64MusyXDecompressFrame(final, in, coefs, firstSample + lastSample); unsigned samples = procSamples - firstSample; memmove(out, final + firstSample, samples * 2); return samples; }