#include "Macromedia.h" #include "FSound.h" // // The Low Level sound object // const S32 FSound::kRateTable[4] = {sndRate5K, sndRate11K, sndRate22K, sndRate44K}; const int FSound::kRateShiftTable[4] = {3, 2, 1, 0}; void FSound::Init() { format = 0; nSamples = 0; samples = 0; dataLen = 0; delay = 0; } void FSound::Set(WaveFormat *wfmt) { wfmt->wFormatTag = 1; //WAVE_FORMAT_PCM; wfmt->nSamplesPerSec = Rate(); wfmt->nChannels = NChannels(); wfmt->wBitsPerSample = BitsPerSample(); wfmt->nBlockAlign = (wfmt->wBitsPerSample * wfmt->nChannels) / 8; wfmt->nAvgBytesPerSec = wfmt->nBlockAlign * wfmt->nSamplesPerSec; //wfmt->cbSize = 0; } // // ADPCM tables // static const int indexTable2[2] = { -1, 2, }; // Is this ok? static const int indexTable3[4] = { -1, -1, 2, 4, }; static const int indexTable4[8] = { -1, -1, -1, -1, 2, 4, 6, 8, }; static const int indexTable5[16] = { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16, }; static const int *indexTables[] = { indexTable2, indexTable3, indexTable4, indexTable5}; static const int stepsizeTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767}; // // The Compressor // FSoundComp::FSoundComp(FSound *snd, S32 nb) { // assert(snd->CompressFormat() == sndCompressADPCM); isStereo = snd->Stereo(); is8Bit = snd->Is8Bit(); nBits = nb; nSamples = 0; len = 0; bitBuf = 0; bitPos = 0; } void FSoundComp::WriteBits(std::vector *stream) { if (stream) { // Actually write the bits... while (bitPos >= 8) { // May need to rewrite this line // recorder->PutByte((U8)(bitBuf >> (bitPos-8))); stream->push_back((U8)(bitBuf >> (bitPos - 8))); bitPos -= 8; len++; } } else { // Just counting... len += bitPos / 8; bitPos &= 0x7; } } void FSoundComp::Flush(std::vector *stream) { WriteBits(stream); if (bitPos > 0) { PutBits(0, 8 - bitPos, stream); WriteBits(stream); } } void FSoundComp::Compress16(S16 *src, S32 n, std::vector *stream) { if (nSamples == 0) { // Emit the compression settings PutBits(nBits - 2, 2, stream); } int sn = isStereo ? 2 : 1; const int *indexTable = indexTables[nBits - 2]; while (n-- > 0) { nSamples++; if ((nSamples & 0xfff) == 1) { // We emit a header every 4096 samples so we can seek quickly for (int i = 0; i < sn; i++) { // Pick an initial index value S32 d = abs(src[sn] - src[0]); int k = 0; while (k < 63 && stepsizeTable[k] < d) k++; PutBits(valpred[i] = *src++, 16, stream); PutBits(index[i] = k, 6, stream); } } else { // Generate a delta value for (int i = 0; i < sn; i++) { /* Step 1 - compute difference with previous value */ S32 diff = *src++ - valpred[i]; /* Difference between val and valprev */ int sign; if (diff < 0) { sign = 1 << (nBits - 1); diff = -diff; } else { sign = 0; } /* Step 2 - Divide and clamp */ /* Note: ** This code *approximately* computes: ** delta = diff*4/step; ** vpdiff = (delta+0.5)*step/4; ** but in shift step bits are dropped. The net result of this is ** that even if you have fast mul/div hardware you cannot put it to ** good use since the fixup would be too expensive. */ int step = stepsizeTable[index[i]]; /* Stepsize */ S32 delta = 0; /* Current adpcm output value */ S32 vpdiff = 0; /* Current change to valpred */ int k = 1 << (nBits - 2); do { if (diff >= step) { delta |= k; diff -= step; vpdiff += step; } step >>= 1; k >>= 1; } while (k); vpdiff += step; // add the 0.5 /* Step 3 - Update previous value */ if (sign) valpred[i] -= vpdiff; else valpred[i] += vpdiff; /* Step 4 - Clamp previous value to 16 bits */ if (valpred[i] != (S16)valpred[i]) valpred[i] = valpred[i] < 0 ? -32768 : 32767; assert(valpred[i] <= 32767 && valpred[i] >= -32768); /* Step 5 - Assemble value, update index and step values */ index[i] += indexTable[delta]; if (index[i] < 0) index[i] = 0; else if (index[i] > 88) index[i] = 88; delta |= sign; /* Step 6 - Output value */ PutBits(delta, nBits, stream); } } } } inline void Filter8to16(U8 *src, S16 *dst, S32 n) // Can work in place { src += n; dst += n; while (n--) *(--dst) = ((S16) * (--src) - 128) << 8; } void FSoundComp::Compress(void *src, S32 n, std::vector *stream) { if (is8Bit) { S16 buf[4096]; U8 *s = (U8 *)src; while (n > 0) { // Expand to 16 bit and compress S32 nb = std::min((S32)4096, n); Filter8to16(s, buf, nb); Compress16(buf, nb, stream); n -= nb; s += nb; } } else { Compress16((S16 *)src, n, stream); } }