diff --git a/sc2/src/sc2code/libs/sound/decoders/decoder.c b/sc2/src/sc2code/libs/sound/decoders/decoder.c index fc00d1185..9ca018f12 100644 --- a/sc2/src/sc2code/libs/sound/decoders/decoder.c +++ b/sc2/src/sc2code/libs/sound/decoders/decoder.c @@ -36,11 +36,12 @@ extern bool fileExists2(uio_DirHandle *dir, const char *fileName); // Can't '#include "libs/file.h"' due to some type conflicts. +#define MAX_REG_DECODERS 31 #define THIS_PTR TFB_SoundDecoder* static const char* bufa_GetName (void); -static bool bufa_InitModule (int flags); +static bool bufa_InitModule (int flags, const TFB_DecoderFormats*); static void bufa_TermModule (); static uint32 bufa_GetStructSize (void); static int bufa_GetError (THIS_PTR); @@ -83,7 +84,7 @@ typedef struct tfb_bufsounddecoder #define SD_MIN_SIZE (sizeof (TFB_BufSoundDecoder)) static const char* nula_GetName (void); -static bool nula_InitModule (int flags); +static bool nula_InitModule (int flags, const TFB_DecoderFormats*); static void nula_TermModule (); static uint32 nula_GetStructSize (void); static int nula_GetError (THIS_PTR); @@ -124,22 +125,24 @@ typedef struct tfb_nullsounddecoder #undef THIS_PTR -static struct sd_DecoderInfo +struct TFB_RegSoundDecoder { + bool builtin; + bool used; // ever used indicator const char* ext; - TFB_SoundDecoderFuncs* funcs; -} -sd_decoders[] = + const TFB_SoundDecoderFuncs* funcs; +}; +static TFB_RegSoundDecoder sd_decoders[MAX_REG_DECODERS + 1] = { - {"wav", &wava_DecoderVtbl}, - {"mod", &moda_DecoderVtbl}, - {"ogg", &ova_DecoderVtbl}, - {"duk", &duka_DecoderVtbl}, - {NULL, NULL} // null term + {true, true, "wav", &wava_DecoderVtbl}, + {true, true, "mod", &moda_DecoderVtbl}, + {true, true, "ogg", &ova_DecoderVtbl}, + {true, true, "duk", &duka_DecoderVtbl}, + {false, false, NULL, NULL}, // null term }; - -TFB_DecoderFormats decoder_formats; +static TFB_DecoderFormats decoder_formats; +static int sd_flags = 0; /* change endianness of 16bit words * Only works optimal when 'data' is aligned on a 32 bits boundary. @@ -175,7 +178,7 @@ SoundDecoder_GetName (TFB_SoundDecoder *decoder) sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats *formats) { - struct sd_DecoderInfo* info; + TFB_RegSoundDecoder* info; sint32 ret = 0; if (!formats) @@ -185,26 +188,133 @@ SoundDecoder_Init (int flags, TFB_DecoderFormats *formats) } decoder_formats = *formats; + // init built-in decoders for (info = sd_decoders; info->ext; info++) { - if (!info->funcs->InitModule (flags)) + if (!info->funcs->InitModule (flags, &decoder_formats)) { - fprintf (stderr, "SoundDecoder_Init(): %s audio decoder init failed\n", + fprintf (stderr, "SoundDecoder_Init(): " + "%s audio decoder init failed\n", info->funcs->GetName ()); ret = 1; } } - return 0; + sd_flags = flags; + + return ret; } void SoundDecoder_Uninit (void) { - struct sd_DecoderInfo* info; + TFB_RegSoundDecoder* info; - for (info = sd_decoders; info->ext; info++) - info->funcs->TermModule (); + // uninit all decoders + // and unregister loaded decoders + for (info = sd_decoders; info->used; info++) + { + if (info->ext) // check if present + info->funcs->TermModule (); + + if (!info->builtin) + { + info->used = false; + info->ext = NULL; + } + } +} + +TFB_RegSoundDecoder* +SoundDecoder_Register (const char* fileext, TFB_SoundDecoderFuncs* decvtbl) +{ + TFB_RegSoundDecoder* info; + TFB_RegSoundDecoder* newslot = NULL; + + if (!decvtbl) + { + fprintf (stderr, "SoundDecoder_Register(): Null decoder table\n"); + return NULL; + } + if (!fileext) + { + fprintf (stderr, "SoundDecoder_Register(): Bad file type for %s\n", + decvtbl->GetName ()); + return NULL; + } + + // check if extension already registered + for (info = sd_decoders; info->used && + (!info->ext || strcmp (info->ext, fileext) != 0); + ++info) + { + // and pick up an empty slot (where available) + if (!newslot && !info->ext) + newslot = info; + } + + if (info >= sd_decoders + MAX_REG_DECODERS) + { + fprintf (stderr, "SoundDecoder_Register(): Decoders limit reached\n"); + return NULL; + } + else if (info->ext) + { + fprintf (stderr, "SoundDecoder_Register(): " + "'%s' decoder already registered (%s denied)\n", + fileext, decvtbl->GetName ()); + return NULL; + } + + if (!decvtbl->InitModule (sd_flags, &decoder_formats)) + { + fprintf (stderr, "SoundDecoder_Register(): %s decoder init failed\n", + decvtbl->GetName ()); + return NULL; + } + + if (!newslot) + { + newslot = info; + newslot->used = true; + // make next one a term + info[1].builtin = false; + info[1].used = false; + info[1].ext = NULL; + } + + newslot->ext = fileext; + newslot->funcs = decvtbl; + + return newslot; +} + +void +SoundDecoder_Unregister (TFB_RegSoundDecoder* regdec) +{ + if (regdec < sd_decoders || regdec >= sd_decoders + MAX_REG_DECODERS || + !regdec->ext || !regdec->funcs) + { + fprintf (stderr, "SoundDecoder_Unregister(): " + "Invalid or expired decoder passed\n"); + return; + } + + regdec->funcs->TermModule (); + regdec->ext = NULL; + regdec->funcs = NULL; +} + +const TFB_SoundDecoderFuncs* +SoundDecoder_Lookup (const char* fileext) +{ + TFB_RegSoundDecoder* info; + + for (info = sd_decoders; info->used && + (!info->ext || strcmp (info->ext, fileext) != 0); + ++info) + ; + return info->ext ? info->funcs : NULL; } TFB_SoundDecoder* @@ -212,8 +322,8 @@ SoundDecoder_Load (uio_DirHandle *dir, char *filename, uint32 buffer_size, uint32 startTime, sint32 runTime) { const char* pext; - struct sd_DecoderInfo* info; - TFB_SoundDecoderFuncs* funcs; + TFB_RegSoundDecoder* info; + const TFB_SoundDecoderFuncs* funcs; TFB_SoundDecoder* decoder; uint32 struct_size; @@ -226,8 +336,8 @@ SoundDecoder_Load (uio_DirHandle *dir, char *filename, } ++pext; - for (info = sd_decoders; - info->ext && strcmp (info->ext, pext) != 0; + for (info = sd_decoders; info->used && + (!info->ext || strcmp (info->ext, pext) != 0); ++info) ; if (!info->ext) @@ -364,7 +474,8 @@ SoundDecoder_Decode (TFB_SoundDecoder *decoder) if (decoder->error) { fprintf (stderr, "SoundDecoder_Decode(): " - "tried to loop %s but couldn't rewind, error code %d\n", + "tried to loop %s but couldn't rewind, " + "error code %d\n", decoder->filename, decoder->error); } else @@ -571,13 +682,13 @@ bufa_GetName (void) } static bool -bufa_InitModule (int flags) +bufa_InitModule (int flags, const TFB_DecoderFormats* fmts) { // this should never be called fprintf (stderr, "bufa_InitModule(): dead function called\n"); return false; - (void)flags; // laugh at compiler warning + (void)flags; (void)fmts; // laugh at compiler warning } static void @@ -699,13 +810,13 @@ nula_GetName (void) } static bool -nula_InitModule (int flags) +nula_InitModule (int flags, const TFB_DecoderFormats* fmts) { // this should never be called fprintf (stderr, "nula_InitModule(): dead function called\n"); return false; - (void)flags; // laugh at compiler warning + (void)flags; (void)fmts; // laugh at compiler warning } static void diff --git a/sc2/src/sc2code/libs/sound/decoders/decoder.h b/sc2/src/sc2code/libs/sound/decoders/decoder.h index 3be8e86d0..3b60cf741 100644 --- a/sc2/src/sc2code/libs/sound/decoders/decoder.h +++ b/sc2/src/sc2code/libs/sound/decoders/decoder.h @@ -47,7 +47,7 @@ typedef struct tfb_sounddecoder TFB_SoundDecoder; typedef struct tfb_sounddecoderfunc { const char* (* GetName) (void); - bool (* InitModule) (int flags); + bool (* InitModule) (int flags, const TFB_DecoderFormats*); void (* TermModule) (); uint32 (* GetStructSize) (void); int (* GetError) (THIS_PTR); @@ -103,7 +103,13 @@ enum SOUNDDECODER_EOF, }; -extern TFB_DecoderFormats decoder_formats; +typedef struct TFB_RegSoundDecoder TFB_RegSoundDecoder; + +TFB_RegSoundDecoder* SoundDecoder_Register (const char* fileext, + TFB_SoundDecoderFuncs* decvtbl); +void SoundDecoder_Unregister (TFB_RegSoundDecoder* regdec); +const TFB_SoundDecoderFuncs* SoundDecoder_Lookup (const char* fileext); + void SoundDecoder_SwapWords (uint16* data, uint32 size); sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats); void SoundDecoder_Uninit (void); diff --git a/sc2/src/sc2code/libs/sound/decoders/dukaud.c b/sc2/src/sc2code/libs/sound/decoders/dukaud.c index 11c1bbed6..8c501760c 100644 --- a/sc2/src/sc2code/libs/sound/decoders/dukaud.c +++ b/sc2/src/sc2code/libs/sound/decoders/dukaud.c @@ -35,7 +35,7 @@ #define THIS_PTR TFB_SoundDecoder* This static const char* duka_GetName (void); -static bool duka_InitModule (int flags); +static bool duka_InitModule (int flags, const TFB_DecoderFormats*); static void duka_TermModule (); static uint32 duka_GetStructSize (void); static int duka_GetError (THIS_PTR); @@ -103,6 +103,8 @@ typedef struct uint16 indices[2]; // initial indices for channels } DukAud_AudSubframe; +static const TFB_DecoderFormats* duka_formats = NULL; + sint32 duka_readAudFrameHeader (TFB_DuckSoundDecoder* duka, uint32 iframe, DukAud_AudSubframe* aud) @@ -338,9 +340,9 @@ duka_GetName (void) } static bool -duka_InitModule (int flags) +duka_InitModule (int flags, const TFB_DecoderFormats* fmts) { - // no specific module init + duka_formats = fmts; return true; (void)flags; // laugh at compiler warning @@ -372,7 +374,7 @@ duka_Init (THIS_PTR) { //TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This; This->need_swap = - decoder_formats.big_endian != decoder_formats.want_big_endian; + duka_formats->big_endian != duka_formats->want_big_endian; return true; } @@ -449,7 +451,7 @@ duka_Open (THIS_PTR, uio_DirHandle *dir, const char *file) } This->frequency = 22050; - This->format = decoder_formats.stereo16; + This->format = duka_formats->stereo16; duka->channels = 2; duka->pcm_frame = aud.numsamples; duka->data = HMalloc (DATA_BUF_SIZE); diff --git a/sc2/src/sc2code/libs/sound/decoders/modaud.c b/sc2/src/sc2code/libs/sound/decoders/modaud.c index 2f437a236..39823cd4e 100644 --- a/sc2/src/sc2code/libs/sound/decoders/modaud.c +++ b/sc2/src/sc2code/libs/sound/decoders/modaud.c @@ -32,7 +32,7 @@ #define THIS_PTR TFB_SoundDecoder* This static const char* moda_GetName (void); -static bool moda_InitModule (int flags); +static bool moda_InitModule (int flags, const TFB_DecoderFormats*); static void moda_TermModule (); static uint32 moda_GetStructSize (void); static int moda_GetError (THIS_PTR); @@ -72,7 +72,7 @@ typedef struct tfb_modsounddecoder } TFB_ModSoundDecoder; MIKMODAPI extern struct MDRIVER drv_openal; - +static const TFB_DecoderFormats* moda_formats = NULL; static const char* moda_GetName (void) @@ -81,7 +81,7 @@ moda_GetName (void) } static bool -moda_InitModule (int flags) +moda_InitModule (int flags, const TFB_DecoderFormats* fmts) { MikMod_RegisterDriver (&drv_openal); MikMod_RegisterAllLoaders (); @@ -114,6 +114,8 @@ moda_InitModule (int flags) return false; } + moda_formats = fmts; + return true; } @@ -143,7 +145,7 @@ moda_Init (THIS_PTR) { //TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This; This->need_swap = - decoder_formats.big_endian != decoder_formats.want_big_endian; + moda_formats->big_endian != moda_formats->want_big_endian; return true; } @@ -173,7 +175,7 @@ moda_Open (THIS_PTR, uio_DirHandle *dir, const char *filename) mod->wrap = 0; mod->loop = 1; - This->format = decoder_formats.stereo16; + This->format = moda_formats->stereo16; This->frequency = md_mixfreq; This->length = 0; // FIXME way to obtain this from mikmod? diff --git a/sc2/src/sc2code/libs/sound/decoders/oggaud.c b/sc2/src/sc2code/libs/sound/decoders/oggaud.c index 01dfe6018..0d947ece8 100644 --- a/sc2/src/sc2code/libs/sound/decoders/oggaud.c +++ b/sc2/src/sc2code/libs/sound/decoders/oggaud.c @@ -33,7 +33,7 @@ #define THIS_PTR TFB_SoundDecoder* This static const char* ova_GetName (void); -static bool ova_InitModule (int flags); +static bool ova_InitModule (int flags, const TFB_DecoderFormats*); static void ova_TermModule (); static uint32 ova_GetStructSize (void); static int ova_GetError (THIS_PTR); @@ -72,6 +72,8 @@ typedef struct tfb_oggsounddecoder } TFB_OggSoundDecoder; +static const TFB_DecoderFormats* ova_formats = NULL; + static size_t ogg_read (void *ptr, size_t size, size_t nmemb, void *datasource) { @@ -112,9 +114,9 @@ ova_GetName (void) } static bool -ova_InitModule (int flags) +ova_InitModule (int flags, const TFB_DecoderFormats* fmts) { - // no specific module init + ova_formats = fmts; return true; (void)flags; // laugh at compiler warning @@ -195,9 +197,9 @@ ova_Open (THIS_PTR, uio_DirHandle *dir, const char *filename) This->length = (float) ov_time_total (&ova->vf, -1); if (vinfo->channels == 1) - This->format = decoder_formats.mono16; + This->format = ova_formats->mono16; else - This->format = decoder_formats.stereo16; + This->format = ova_formats->stereo16; ova->last_error = 0; @@ -219,7 +221,7 @@ ova_Decode (THIS_PTR, void* buf, sint32 bufsize) long rc; int bitstream; - rc = ov_read (&ova->vf, buf, bufsize, decoder_formats.want_big_endian, + rc = ov_read (&ova->vf, buf, bufsize, ova_formats->want_big_endian, 2, 1, &bitstream); if (rc < 0) diff --git a/sc2/src/sc2code/libs/sound/decoders/wav.c b/sc2/src/sc2code/libs/sound/decoders/wav.c index ece73f6eb..565bf84b8 100644 --- a/sc2/src/sc2code/libs/sound/decoders/wav.c +++ b/sc2/src/sc2code/libs/sound/decoders/wav.c @@ -60,7 +60,7 @@ typedef struct #define THIS_PTR TFB_SoundDecoder* This static const char* wava_GetName (void); -static bool wava_InitModule (int flags); +static bool wava_InitModule (int flags, const TFB_DecoderFormats*); static void wava_TermModule (); static uint32 wava_GetStructSize (void); static int wava_GetError (THIS_PTR); @@ -104,6 +104,8 @@ typedef struct tfb_wavesounddecoder } TFB_WaveSoundDecoder; +static const TFB_DecoderFormats* wava_formats = NULL; + static const char* wava_GetName (void) @@ -112,9 +114,9 @@ wava_GetName (void) } static bool -wava_InitModule (int flags) +wava_InitModule (int flags, const TFB_DecoderFormats* fmts) { - // no specific module init + wava_formats = fmts; return true; (void)flags; // laugh at compiler warning @@ -145,7 +147,7 @@ static bool wava_Init (THIS_PTR) { //TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This; - This->need_swap = decoder_formats.want_big_endian; + This->need_swap = wava_formats->want_big_endian; return true; } @@ -284,10 +286,10 @@ wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename) { This->format = (wava->FmtHdr.Channels == 1 ? (wava->FmtHdr.BitsPerSample == 8 ? - decoder_formats.mono8 : decoder_formats.mono16) + wava_formats->mono8 : wava_formats->mono16) : (wava->FmtHdr.BitsPerSample == 8 ? - decoder_formats.stereo8 : decoder_formats.stereo16) + wava_formats->stereo8 : wava_formats->stereo16) ); This->frequency = wava->FmtHdr.SamplesPerSec; }