/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* CDP module sample * .abx speech track decoder */ /* * Derived from decoder by Serge van den Boom (svdb@stack.nl), * The actual conversion code (somewhat moded) is from Toys for Bob. * So far, it ignores sample rates, so it will work ok as long as all * the frames have the same frequency. This is probably * enough for our purposes. */ #include #include #include //#include "port.h" #include "types.h" #include "port.h" #include "libs/cdp/cdp_imem.h" #include "libs/cdp/cdp_iio.h" #include "libs/cdp/cdp_isnd.h" #include "libs/cdp/cdpmod.h" #include "abxaud.h" #include "endian_uqm.h" #define DATA_BUF_SIZE 0x8000 #define DUCK_GENERAL_FPS 14.622f #define THIS_PTR TFB_SoundDecoder* This static const char* abxa_GetName (void); static bool abxa_InitModule (int flags, const TFB_DecoderFormats*); static void abxa_TermModule (); static uint32 abxa_GetStructSize (void); static int abxa_GetError (THIS_PTR); static bool abxa_Init (THIS_PTR); static void abxa_Term (THIS_PTR); static bool abxa_Open (THIS_PTR, uio_DirHandle *dir, const char *filename); static void abxa_Close (THIS_PTR); static int abxa_Decode (THIS_PTR, void* buf, sint32 bufsize); static uint32 abxa_Seek (THIS_PTR, uint32 pcm_pos); static uint32 abxa_GetFrame (THIS_PTR); static TFB_SoundDecoderFuncs abxa_DecoderVtbl = { abxa_GetName, abxa_InitModule, abxa_TermModule, abxa_GetStructSize, abxa_GetError, abxa_Init, abxa_Term, abxa_Open, abxa_Close, abxa_Decode, abxa_Seek, abxa_GetFrame, }; static bool abxa_module_init (cdp_Module* module, cdp_Itf_Host* hostitf); static void abxa_module_term (); // The one and only "cdpmodinfo" symbol // on win32, it does not have to be named like so // the exported name can be overridden with .def file cdp_ModuleInfo CDPEXPORT CDP_INFO_SYM = { sizeof (cdp_ModuleInfo), // size of struct for version control CDPAPI_VERSION, // API version we are using 1, 0, 2, // our module version 0, 3, 0, // host version required, purely informational CDP_MODINFO_RESERVED1, // reserved "UQM", // CDP context name (we can use UQM) "Abx Decoder", // CDP mod name "1.0", // CDP mod version "Alex Volkov", // CDP mod author "http://sc2.sf.net", // CDP mod URL (do not have any yet) "Sample CDP-based decoder", // CDP mod comment CDP_MODINFO_RESERVED2, // reserved abxa_module_init, // init entrypoint abxa_module_term, // term entrypoint }; typedef struct { uint16 num_frames; // total number of frame uint32 tot_size; // total size of decoded stream uint16 frame_samps; // samples per frame uint16 freq; // general sampling frequency } abxa_Header; typedef struct { uint32 ofs; // file offset of frame uint16 fsize; // compressed file size uint16 usize; // uncompressed file size } abxa_FrameInfo; #define SQLCH 0x40 // Squelch byte flag #define RESYNC 0x80 // Resync byte flag. #define DELTAMOD 0x30 // Delta modulation bits. #define ONEBIT 0x10 // One bit delta modulate #define TWOBIT 0x20 // Two bit delta modulate #define FOURBIT 0x30 // four bit delta modulate #define MULTIPLIER 0x0F // Bottom nibble contains multiplier value. #define SQUELCHCNT 0x3F // Bits for squelching. typedef struct { uint16 usize; uint16 freq; uint8 frame_size; uint8 sqelch; uint16 max_error; } abxa_FrameHeader; typedef struct { // always the first member TFB_SoundDecoder decoder; // public read-only uint32 iframe; // current frame index uint32 cframes; // total count of frames uint32 channels; // number of channels uint32 pcm_frame; // samples per frame // private sint32 last_error; uio_Stream* abx; abxa_FrameInfo* frames; // buffer void* data; uint32 maxdata; uint32 cbdata; uint32 dataofs; } abxa_SoundDecoder; // interfaces our decoder needs cdp_ItfDef game_itfs[] = { {CDPITF_KIND_MEMORY}, {CDPITF_KIND_IO}, {CDPITF_KIND_SOUND}, {CDPITF_KIND_INVALID} // term }; static cdp_Module* abxa_mod = NULL; // our module handle static cdp_Itf_Host* abxa_ihost = NULL; // HOST interface ptr static cdp_Itf_Memory* abxa_imem = NULL; // MEMORY interface ptr static cdp_Itf_Io* abxa_iio = NULL; // IO interface ptr static cdp_Itf_Sound* abxa_isnd = NULL; // SOUND interface ptr static const TFB_DecoderFormats* abxa_formats = NULL; static TFB_RegSoundDecoder* abxa_regdec = NULL; // registered decoder static bool abxa_module_init (cdp_Module* module, cdp_Itf_Host* hostitf) { abxa_mod = module; abxa_ihost = hostitf; if (!hostitf->GetItfs (game_itfs)) return false; abxa_imem = game_itfs[0].itf; abxa_iio = game_itfs[1].itf; abxa_isnd = game_itfs[2].itf; abxa_regdec = abxa_isnd->RegisterDecoder ("abx", &abxa_DecoderVtbl); if (!abxa_regdec) { fprintf (stderr, "abxa_module_init(): " "Could not register audio decoder\n"); return false; } return true; } static void abxa_module_term () { if (abxa_regdec) abxa_isnd->UnregisterDecoder (abxa_regdec); // do nothing loop for 1 trillion iterations } static sint32 abxa_readHeader (abxa_SoundDecoder* abxa, abxa_Header* hdr) { if (1 != abxa_iio->fread (&hdr->num_frames, sizeof (hdr->num_frames), 1, abxa->abx) || 1 != abxa_iio->fread (&hdr->tot_size, sizeof (hdr->tot_size), 1, abxa->abx) || 1 != abxa_iio->fread (&hdr->frame_samps, sizeof (hdr->frame_samps), 1, abxa->abx) || 1 != abxa_iio->fread (&hdr->freq, sizeof (hdr->freq), 1, abxa->abx)) { abxa->last_error = errno; return abxa_ErrBadFile; } // byte swap when necessary hdr->num_frames = UQM_SwapLE16 (hdr->num_frames); hdr->tot_size = UQM_SwapLE32 (hdr->tot_size); hdr->frame_samps = UQM_SwapLE16 (hdr->frame_samps); hdr->freq = UQM_SwapLE16 (hdr->freq); return 0; } static signed char abxa_trans[16 * 16] = { -8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8, // Multiplier of 1 -16,-14,-12,-10,-8,-6,-4,-2,2,4,6,8,10,12,14,16, // Multiplier of 2 -24,-21,-18,-15,-12,-9,-6,-3,3,6,9,12,15,18,21,24, // Multiplier of 3 -32,-28,-24,-20,-16,-12,-8,-4,4,8,12,16,20,24,28,32, // Multiplier of 4 -40,-35,-30,-25,-20,-15,-10,-5,5,10,15,20,25,30,35,40, // Multiplier of 5 -48,-42,-36,-30,-24,-18,-12,-6,6,12,18,24,30,36,42,48, // Multiplier of 6 -56,-49,-42,-35,-28,-21,-14,-7,7,14,21,28,35,42,49,56, // Multiplier of 7 -64,-56,-48,-40,-32,-24,-16,-8,8,16,24,32,40,48,56,64, // Multiplier of 8 -72,-63,-54,-45,-36,-27,-18,-9,9,18,27,36,45,54,63,72, // Multiplier of 9 -80,-70,-60,-50,-40,-30,-20,-10,10,20,30,40,50,60,70,80, // Multiplier of 10 -88,-77,-66,-55,-44,-33,-22,-11,11,22,33,44,55,66,77,88, // Multiplier of 11 -96,-84,-72,-60,-48,-36,-24,-12,12,24,36,48,60,72,84,96, // Multiplier of 12 -104,-91,-78,-65,-52,-39,-26,-13,13,26,39,52,65,78,91,104, // Multiplier of 13 -112,-98,-84,-70,-56,-42,-28,-14,14,28,42,56,70,84,98,112, // Multiplier of 14 -120,-105,-90,-75,-60,-45,-30,-15,15,30,45,60,75,90,105,120,// Multiplier of 15 -128,-112,-96,-80,-64,-48,-32,-16,16,32,48,64,80,96,112,127,// Multiplier of 16 }; static sint32 abxa_decodeFrame (abxa_SoundDecoder* abxa, abxa_FrameHeader* hdr, uint8* input, uint32 inputsize) { uint8* inend; uint8* output; uint8* outptr; sint16 prev; sint32 outputsize; output = outptr = abxa->data; inend = input + inputsize; prev = *input++; // Get initial previous data point. *output++ = prev; while (input < inend) { uint16 bytes; uint8 sample; sample = *input++; // Get sample. if (sample & RESYNC) // Is it a resync byte? { //--slen; // Decrement output sample length. prev = (sample & 0x7F) << 1; // Store resync byte. *output++ = prev; } else if (sample & SQLCH) // Is it a squelch byte? { bytes = sample & SQUELCHCNT; // And off the number of squelch bytes // ?? the following makes no sense, should be --slen; //slen -= bytes; // Decrement total samples remaining count. memset (output, prev, bytes); output += bytes; } else // Must be a delta modulate byte!! { sint8 *base; //slen -= hdr->frame_size; // Pulling one frame out. // Compute base address to multiplier table. base = abxa_trans + (sample & MULTIPLIER) * 16; switch (sample & DELTAMOD) // Delta mod resolution. { case ONEBIT: { sint16 up; up = base[8]; // Go up 1 bit. for (bytes = hdr->frame_size / 8; bytes; bytes--) { uint8 mask; sample = *input++; for (mask = 0x80; mask; mask >>= 1) { if ( sample & mask ) prev += up; else prev -= up; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; } } break; } case TWOBIT: base += 6; // Base address of two bit delta's. for (bytes = hdr->frame_size / 4; bytes; bytes--) { sample = *input++; prev += base[sample>>6]; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; prev += base[(sample>>4)&0x3]; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; prev += base[(sample>>2)&0x3]; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; prev += base[sample&0x3]; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; } break; case FOURBIT: for (bytes = hdr->frame_size / 2; bytes; bytes--) { sample = *input++; prev += base[sample>>4]; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; prev += base[sample&0x0F]; if ( prev < 0 ) prev = 0; else if ( prev > 255 ) prev = 255; *output++ = prev; } break; } } // While still audio data to decompress.... } outputsize = output - outptr; abxa->cbdata += outputsize; return outputsize; } static sint32 abxa_readNextFrame (abxa_SoundDecoder* abxa) { abxa_FrameHeader* hdr; uint8* p; uint32 fsize; sint32 ret; fsize = abxa->frames[abxa->iframe].fsize; abxa_iio->fseek (abxa->abx, abxa->frames[abxa->iframe].ofs, SEEK_SET); // dump encoded data at the end of the buffer aligned on 8-byte p = ((uint8*)abxa->data + abxa->maxdata - ((fsize + 7) & (-8))); if (abxa_iio->fread (p, 1, fsize, abxa->abx) != fsize) { abxa->last_error = errno; return abxa_ErrBadFile; } hdr = (abxa_FrameHeader*) p; p += sizeof (abxa_FrameHeader); fsize -= sizeof (abxa_FrameHeader); hdr->usize = UQM_SwapLE16 (hdr->usize); hdr->freq = UQM_SwapLE16 (hdr->freq); hdr->max_error = UQM_SwapLE16 (hdr->max_error); if (hdr->freq == 0) { hdr->freq = abxa->decoder.frequency; } else if (hdr->freq != abxa->decoder.frequency) { fprintf (stderr, "abxa_readNextFrame(): " "WARNING: Frame frequency (%u) != global frequency (%u) " "for frame %u\n", hdr->freq, abxa->decoder.frequency, abxa->iframe); //abxa->decoder.frequency = hdr->freq; } abxa->iframe++; ret = abxa_decodeFrame (abxa, hdr, p, fsize); if (ret > 0 && ret != hdr->usize) { fprintf (stderr, "abxa_readNextFrame(): " "WARNING: decompressed frame size (%d) != specified size (%u) " "for frame %u\n", ret, hdr->usize, abxa->iframe); } return ret; } static sint32 abxa_stuffBuffer (abxa_SoundDecoder* abxa, void* buf, sint32 bufsize) { sint32 dataleft; dataleft = abxa->cbdata - abxa->dataofs; if (dataleft > 0) { if (dataleft > bufsize) dataleft = bufsize & (-4); memcpy (buf, (uint8*)abxa->data + abxa->dataofs, dataleft); abxa->dataofs += dataleft; } if (abxa->cbdata > 0 && abxa->dataofs >= abxa->cbdata) abxa->cbdata = abxa->dataofs = 0; // reset for new data return dataleft; } static const char* abxa_GetName (void) { return "Abx"; } static bool abxa_InitModule (int flags, const TFB_DecoderFormats* fmts) { abxa_formats = fmts; return true; (void)flags; // laugh at compiler warning } static void abxa_TermModule () { // no specific module term } static uint32 abxa_GetStructSize (void) { return sizeof (abxa_SoundDecoder); } static int abxa_GetError (THIS_PTR) { abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; int ret = abxa->last_error; abxa->last_error = abxa_ErrNone; return ret; } static bool abxa_Init (THIS_PTR) { //abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; /* enable if 16bit PCM abx exist This->need_swap = abxa_formats->big_endian != abxa_formats->want_big_endian; */ This->need_swap = false; return true; } static void abxa_Term (THIS_PTR) { //abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; abxa_Close (This); // ensure cleanup } static bool abxa_Open (THIS_PTR, uio_DirHandle *dir, const char *file) { abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; abxa_Header hdr; abxa_FrameInfo* info; size_t cread; uint32 i; abxa->abx = abxa_iio->fopen (dir, file, "rb"); if (!abxa->abx) { abxa->last_error = errno; return false; } if (abxa_readHeader (abxa, &hdr)) { abxa_Close (This); return false; } abxa->cframes = hdr.num_frames; abxa->frames = abxa_imem->malloc (abxa->cframes * sizeof (abxa_FrameInfo)); cread = abxa_iio->fread (abxa->frames, sizeof (abxa_FrameInfo), abxa->cframes, abxa->abx); if (cread != abxa->cframes) { abxa->last_error = abxa_ErrBadFile; abxa_Close (This); return false; } // byte swap when necessary for (i = 0, info = abxa->frames; i < abxa->cframes; ++i, ++info) { info->ofs = UQM_SwapLE32 (info->ofs); info->fsize = UQM_SwapLE16 (info->fsize); info->usize = UQM_SwapLE16 (info->usize); } This->frequency = hdr.freq; This->format = abxa_formats->mono8; abxa->channels = 1; abxa->pcm_frame = hdr.frame_samps; abxa->data = abxa_imem->malloc (hdr.frame_samps * 2); abxa->maxdata = hdr.frame_samps * 2; // estimate This->length = (float) hdr.tot_size / hdr.freq; abxa->last_error = 0; return true; } static void abxa_Close (THIS_PTR) { abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; if (abxa->data) { abxa_imem->free (abxa->data); abxa->data = NULL; } if (abxa->frames) { abxa_imem->free (abxa->frames); abxa->frames = NULL; } if (abxa->abx) { abxa_iio->fclose (abxa->abx); abxa->abx = NULL; } abxa->last_error = 0; } static int abxa_Decode (THIS_PTR, void* buf, sint32 bufsize) { abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; sint32 stuffed; sint32 total = 0; if (bufsize <= 0) return abxa->last_error = abxa_ErrBadArg; do { stuffed = abxa_stuffBuffer (abxa, buf, bufsize); ((uint8*)buf) += stuffed; bufsize -= stuffed; total += stuffed; if (bufsize > 0 && abxa->iframe < abxa->cframes) { stuffed = abxa_readNextFrame (abxa); if (stuffed <= 0) return stuffed; } } while (bufsize > 0 && abxa->iframe < abxa->cframes); return total; } static uint32 abxa_Seek (THIS_PTR, uint32 pcm_pos) { abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; uint32 iframe; iframe = pcm_pos / abxa->pcm_frame; if (iframe < abxa->cframes) { abxa->iframe = iframe; abxa->cbdata = 0; abxa->dataofs = 0; } return abxa->iframe * abxa->pcm_frame; } static uint32 abxa_GetFrame (THIS_PTR) { abxa_SoundDecoder* abxa = (abxa_SoundDecoder*) This; // if there is nothing buffered return the actual current frame // otherwise return previous return abxa->dataofs == abxa->cbdata ? abxa->iframe : abxa->iframe - 1; }