summaryrefslogtreecommitdiff
path: root/src/abxadec/abxaud.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/abxadec/abxaud.c')
-rw-r--r--src/abxadec/abxaud.c638
1 files changed, 638 insertions, 0 deletions
diff --git a/src/abxadec/abxaud.c b/src/abxadec/abxaud.c
new file mode 100644
index 0000000..a943f16
--- /dev/null
+++ b/src/abxadec/abxaud.c
@@ -0,0 +1,638 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+//#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;
+}