Sound decoders refactoring;
The decoders are now virtualized, the high-level decoding code is unified and any format is theoretically streamable. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1266 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
uqm_SUBDIRS="mikmod"
|
||||
uqm_CFILES="decoder.c wav.c dukaud.c"
|
||||
uqm_CFILES="decoder.c wav.c dukaud.c modaud.c oggaud.c"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -39,28 +39,61 @@ typedef struct tfb_decoderformats
|
||||
uint32 stereo16;
|
||||
} TFB_DecoderFormats;
|
||||
|
||||
typedef struct tfb_sounddecoder
|
||||
// forward-declare
|
||||
typedef struct tfb_sounddecoder TFB_SoundDecoder;
|
||||
|
||||
#define THIS_PTR TFB_SoundDecoder*
|
||||
|
||||
typedef struct tfb_sounddecoderfunc
|
||||
{
|
||||
// public
|
||||
void *buffer;
|
||||
uint32 buffer_size;
|
||||
const char* (* GetName) (void);
|
||||
bool (* InitModule) (int flags);
|
||||
void (* TermModule) ();
|
||||
uint32 (* GetStructSize) (void);
|
||||
int (* GetError) (THIS_PTR);
|
||||
bool (* Init) (THIS_PTR);
|
||||
void (* Term) (THIS_PTR);
|
||||
bool (* Open) (THIS_PTR, uio_DirHandle *dir, const char *filename);
|
||||
void (* Close) (THIS_PTR);
|
||||
int (* Decode) (THIS_PTR, void* buf, sint32 bufsize);
|
||||
// returns <0 on error, ==0 when no more data, >0 bytes returned
|
||||
uint32 (* Seek) (THIS_PTR, uint32 pcm_pos);
|
||||
// returns the pcm position set
|
||||
uint32 (* GetFrame) (THIS_PTR);
|
||||
|
||||
} TFB_SoundDecoderFuncs;
|
||||
|
||||
#undef THIS_PTR
|
||||
|
||||
struct tfb_sounddecoder
|
||||
{
|
||||
// decoder virtual funcs - R/O
|
||||
const TFB_SoundDecoderFuncs *funcs;
|
||||
|
||||
// public R/O, set by decoder
|
||||
uint32 format;
|
||||
uint32 frequency;
|
||||
bool looping;
|
||||
sint32 error;
|
||||
float length; // total length in seconds
|
||||
char *decoder_info;
|
||||
bool is_null;
|
||||
bool need_swap;
|
||||
|
||||
// public R/O, set by wrapper
|
||||
void *buffer;
|
||||
uint32 buffer_size;
|
||||
sint32 error;
|
||||
uint32 bytes_per_samp;
|
||||
|
||||
// public R/W
|
||||
bool looping;
|
||||
|
||||
// semi-private
|
||||
sint32 type;
|
||||
uio_DirHandle *dir;
|
||||
char *filename;
|
||||
void *data;
|
||||
uint32 pos;
|
||||
uint32 start_sample;
|
||||
uint32 end_sample;
|
||||
|
||||
} TFB_SoundDecoder;
|
||||
};
|
||||
|
||||
// return values
|
||||
enum
|
||||
@@ -70,18 +103,6 @@ enum
|
||||
SOUNDDECODER_EOF,
|
||||
};
|
||||
|
||||
// types
|
||||
enum
|
||||
{
|
||||
SOUNDDECODER_NONE,
|
||||
SOUNDDECODER_WAV,
|
||||
SOUNDDECODER_MOD,
|
||||
SOUNDDECODER_OGG,
|
||||
SOUNDDECODER_NULL,
|
||||
SOUNDDECODER_BUF,
|
||||
SOUNDDECODER_DUK,
|
||||
};
|
||||
|
||||
extern TFB_DecoderFormats decoder_formats;
|
||||
void SoundDecoder_SwapWords (uint16* data, uint32 size);
|
||||
sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats);
|
||||
@@ -92,8 +113,9 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder);
|
||||
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
|
||||
float SoundDecoder_GetTime (TFB_SoundDecoder *decoder);
|
||||
uint32 SoundDecoder_GetFrame (TFB_SoundDecoder *decoder);
|
||||
void SoundDecoder_Seek (TFB_SoundDecoder *decoder, uint32 pcm_pos);
|
||||
void SoundDecoder_Seek (TFB_SoundDecoder *decoder, uint32 msecs);
|
||||
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder);
|
||||
void SoundDecoder_Free (TFB_SoundDecoder *decoder);
|
||||
const char* SoundDecoder_GetName (TFB_SoundDecoder *decoder);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "libs/misc.h"
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
#include "dukaud.h"
|
||||
#include "decoder.h"
|
||||
#include "endian_uqm.h"
|
||||
@@ -28,7 +31,63 @@
|
||||
#define DATA_BUF_SIZE 0x8000
|
||||
#define DUCK_GENERAL_FPS 14.622f
|
||||
|
||||
static sint32 duka_error = 0;
|
||||
|
||||
#define THIS_PTR TFB_SoundDecoder* This
|
||||
|
||||
static const char* duka_GetName (void);
|
||||
static bool duka_InitModule (int flags);
|
||||
static void duka_TermModule ();
|
||||
static uint32 duka_GetStructSize (void);
|
||||
static int duka_GetError (THIS_PTR);
|
||||
static bool duka_Init (THIS_PTR);
|
||||
static void duka_Term (THIS_PTR);
|
||||
static bool duka_Open (THIS_PTR, uio_DirHandle *dir, const char *filename);
|
||||
static void duka_Close (THIS_PTR);
|
||||
static int duka_Decode (THIS_PTR, void* buf, sint32 bufsize);
|
||||
static uint32 duka_Seek (THIS_PTR, uint32 pcm_pos);
|
||||
static uint32 duka_GetFrame (THIS_PTR);
|
||||
|
||||
TFB_SoundDecoderFuncs duka_DecoderVtbl =
|
||||
{
|
||||
duka_GetName,
|
||||
duka_InitModule,
|
||||
duka_TermModule,
|
||||
duka_GetStructSize,
|
||||
duka_GetError,
|
||||
duka_Init,
|
||||
duka_Term,
|
||||
duka_Open,
|
||||
duka_Close,
|
||||
duka_Decode,
|
||||
duka_Seek,
|
||||
duka_GetFrame,
|
||||
};
|
||||
|
||||
typedef struct tfb_ducksounddecoder
|
||||
{
|
||||
// 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* duk;
|
||||
uint32* frames;
|
||||
// buffer
|
||||
void* data;
|
||||
uint32 maxdata;
|
||||
uint32 cbdata;
|
||||
uint32 dataofs;
|
||||
// decoder stuff
|
||||
sint32 predictors[2];
|
||||
|
||||
} TFB_DuckSoundDecoder;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -45,36 +104,28 @@ typedef struct
|
||||
} DukAud_AudSubframe;
|
||||
|
||||
sint32
|
||||
duka_getError ()
|
||||
{
|
||||
sint32 ret = duka_error;
|
||||
duka_error = dukae_None;
|
||||
return ret;
|
||||
}
|
||||
|
||||
sint32
|
||||
duka_readAudFrameHeader (DukAud_Track* track, uint32 iframe,
|
||||
duka_readAudFrameHeader (TFB_DuckSoundDecoder* duka, uint32 iframe,
|
||||
DukAud_AudSubframe* aud)
|
||||
{
|
||||
DukAud_FrameHeader hdr;
|
||||
|
||||
uio_fseek (track->duk, track->frames[iframe], SEEK_SET);
|
||||
if (uio_fread (&hdr, sizeof(hdr), 1, track->duk) != 1)
|
||||
uio_fseek (duka->duk, duka->frames[iframe], SEEK_SET);
|
||||
if (uio_fread (&hdr, sizeof(hdr), 1, duka->duk) != 1)
|
||||
{
|
||||
duka_error = errno;
|
||||
duka->last_error = errno;
|
||||
return dukae_BadFile;
|
||||
}
|
||||
hdr.audsize = UQM_SwapBE32 (hdr.audsize);
|
||||
|
||||
if (uio_fread (aud, sizeof(*aud), 1, track->duk) != 1)
|
||||
if (uio_fread (aud, sizeof(*aud), 1, duka->duk) != 1)
|
||||
{
|
||||
duka_error = errno;
|
||||
duka->last_error = errno;
|
||||
return dukae_BadFile;
|
||||
}
|
||||
|
||||
aud->magic = UQM_SwapBE16 (aud->magic);
|
||||
if (aud->magic != 0xf77f)
|
||||
return duka_error = dukae_BadFile;
|
||||
return duka->last_error = dukae_BadFile;
|
||||
|
||||
aud->numsamples = UQM_SwapBE16 (aud->numsamples);
|
||||
aud->tag = UQM_SwapBE16 (aud->tag);
|
||||
@@ -84,112 +135,6 @@ duka_readAudFrameHeader (DukAud_Track* track, uint32 iframe,
|
||||
return 0;
|
||||
}
|
||||
|
||||
DukAud_Track*
|
||||
duka_openTrack (uio_DirHandle *dir, const char *file)
|
||||
{
|
||||
DukAud_Track* track;
|
||||
uio_Stream* duk;
|
||||
uio_Stream* frm;
|
||||
DukAud_AudSubframe aud;
|
||||
char filename[256];
|
||||
uint32 filelen;
|
||||
size_t cread;
|
||||
uint32 i;
|
||||
|
||||
filelen = strlen (file);
|
||||
if (filelen > sizeof (filename) - 1)
|
||||
return NULL;
|
||||
strcpy (filename, file);
|
||||
|
||||
duk = uio_fopen (dir, filename, "rb");
|
||||
if (!duk)
|
||||
{
|
||||
duka_error = errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy (filename + filelen - 3, "frm");
|
||||
frm = uio_fopen (dir, filename, "rb");
|
||||
if (!frm)
|
||||
{
|
||||
duka_error = errno;
|
||||
uio_fclose (duk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
track = (DukAud_Track *) HCalloc (sizeof (DukAud_Track));
|
||||
track->duk = duk;
|
||||
|
||||
uio_fseek (frm, 0, SEEK_END);
|
||||
track->cframes = uio_ftell (frm) / sizeof (uint32);
|
||||
uio_fseek (frm, 0, SEEK_SET);
|
||||
if (!track->cframes)
|
||||
{
|
||||
duka_error = dukae_BadFile;
|
||||
uio_fclose (frm);
|
||||
duka_closeTrack (track);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
track->frames = (uint32*) HMalloc (track->cframes * sizeof (uint32));
|
||||
cread = uio_fread (track->frames, sizeof (uint32), track->cframes, frm);
|
||||
uio_fclose (frm);
|
||||
if (cread != track->cframes)
|
||||
{
|
||||
duka_error = dukae_BadFile;
|
||||
duka_closeTrack (track);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < track->cframes; ++i)
|
||||
track->frames[i] = UQM_SwapBE32 (track->frames[i]);
|
||||
|
||||
if (duka_readAudFrameHeader (track, 0, &aud) < 0)
|
||||
{
|
||||
duka_closeTrack (track);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
track->rate = 22050;
|
||||
track->channels = 2;
|
||||
track->pcm_frame = aud.numsamples;
|
||||
track->data = HMalloc (DATA_BUF_SIZE);
|
||||
track->maxdata = DATA_BUF_SIZE;
|
||||
|
||||
// estimate
|
||||
track->length = (float) track->cframes / DUCK_GENERAL_FPS;
|
||||
|
||||
duka_error = 0;
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
void
|
||||
duka_closeTrack (DukAud_Track* track)
|
||||
{
|
||||
if (track->data)
|
||||
HFree (track->data);
|
||||
if (track->duk)
|
||||
uio_fclose (track->duk);
|
||||
HFree (track);
|
||||
duka_error = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
duka_seekTrack (DukAud_Track* track, float pos /* in seconds */)
|
||||
{
|
||||
if (pos < 0 || pos > track->length)
|
||||
return false;
|
||||
|
||||
track->iframe = (uint32) (pos * DUCK_GENERAL_FPS);
|
||||
track->cbdata = 0;
|
||||
track->dataofs = 0;
|
||||
track->predictors[0] = 0;
|
||||
track->predictors[1] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This table is from one of the files that came with the original 3do source
|
||||
// It's slightly different from the data used by MPlayer.
|
||||
static int adpcm_step[89] = {
|
||||
@@ -300,7 +245,7 @@ decode_nibbles (sint16 *output, sint32 output_size, sint32 channels,
|
||||
// *** END part copied from MPlayer ***
|
||||
|
||||
sint32
|
||||
duka_decodeFrame (DukAud_Track* track, DukAud_AudSubframe* header,
|
||||
duka_decodeFrame (TFB_DuckSoundDecoder* duka, DukAud_AudSubframe* header,
|
||||
uint8* input)
|
||||
{
|
||||
uint8* inend;
|
||||
@@ -309,7 +254,7 @@ duka_decodeFrame (DukAud_Track* track, DukAud_AudSubframe* header,
|
||||
sint32 outputsize;
|
||||
|
||||
outputsize = header->numsamples * 2 * sizeof (sint16);
|
||||
outptr = output = (sint16*) ((uint8*)track->data + track->cbdata);
|
||||
outptr = output = (sint16*) ((uint8*)duka->data + duka->cbdata);
|
||||
|
||||
for (inend = input + header->numsamples; input < inend; ++input)
|
||||
{
|
||||
@@ -317,35 +262,35 @@ duka_decodeFrame (DukAud_Track* track, DukAud_AudSubframe* header,
|
||||
*(outptr++) = *input & 0x0f;
|
||||
}
|
||||
|
||||
decode_nibbles (output, header->numsamples * 2, track->channels,
|
||||
track->predictors, header->indices);
|
||||
decode_nibbles (output, header->numsamples * 2, duka->channels,
|
||||
duka->predictors, header->indices);
|
||||
|
||||
track->cbdata += outputsize;
|
||||
duka->cbdata += outputsize;
|
||||
|
||||
return outputsize;
|
||||
}
|
||||
|
||||
|
||||
sint32
|
||||
duka_readNextFrame (DukAud_Track* track)
|
||||
duka_readNextFrame (TFB_DuckSoundDecoder* duka)
|
||||
{
|
||||
DukAud_FrameHeader hdr;
|
||||
DukAud_AudSubframe* aud;
|
||||
uint8* p;
|
||||
|
||||
uio_fseek (track->duk, track->frames[track->iframe], SEEK_SET);
|
||||
if (uio_fread (&hdr, sizeof(hdr), 1, track->duk) != 1)
|
||||
uio_fseek (duka->duk, duka->frames[duka->iframe], SEEK_SET);
|
||||
if (uio_fread (&hdr, sizeof(hdr), 1, duka->duk) != 1)
|
||||
{
|
||||
duka_error = errno;
|
||||
duka->last_error = errno;
|
||||
return dukae_BadFile;
|
||||
}
|
||||
hdr.audsize = UQM_SwapBE32 (hdr.audsize);
|
||||
|
||||
// dump encoded data at the end of the buffer aligned on 8-byte
|
||||
p = ((uint8*)track->data + track->maxdata - ((hdr.audsize + 7) & (-8)));
|
||||
if (uio_fread (p, 1, hdr.audsize, track->duk) != hdr.audsize)
|
||||
p = ((uint8*)duka->data + duka->maxdata - ((hdr.audsize + 7) & (-8)));
|
||||
if (uio_fread (p, 1, hdr.audsize, duka->duk) != hdr.audsize)
|
||||
{
|
||||
duka_error = errno;
|
||||
duka->last_error = errno;
|
||||
return dukae_BadFile;
|
||||
}
|
||||
aud = (DukAud_AudSubframe*) p;
|
||||
@@ -353,76 +298,247 @@ duka_readNextFrame (DukAud_Track* track)
|
||||
|
||||
aud->magic = UQM_SwapBE16 (aud->magic);
|
||||
if (aud->magic != 0xf77f)
|
||||
return duka_error = dukae_BadFile;
|
||||
return duka->last_error = dukae_BadFile;
|
||||
|
||||
aud->numsamples = UQM_SwapBE16 (aud->numsamples);
|
||||
aud->tag = UQM_SwapBE16 (aud->tag);
|
||||
aud->indices[0] = UQM_SwapBE16 (aud->indices[0]);
|
||||
aud->indices[1] = UQM_SwapBE16 (aud->indices[1]);
|
||||
|
||||
track->iframe++;
|
||||
duka->iframe++;
|
||||
|
||||
return duka_decodeFrame (track, aud, p);
|
||||
return duka_decodeFrame (duka, aud, p);
|
||||
}
|
||||
|
||||
static sint32
|
||||
duka_stuffBuffer (DukAud_Track* track, void* buf, sint32 bufsize)
|
||||
duka_stuffBuffer (TFB_DuckSoundDecoder* duka, void* buf, sint32 bufsize)
|
||||
{
|
||||
sint32 dataleft;
|
||||
|
||||
dataleft = track->cbdata - track->dataofs;
|
||||
dataleft = duka->cbdata - duka->dataofs;
|
||||
if (dataleft > 0)
|
||||
{
|
||||
if (dataleft > bufsize)
|
||||
dataleft = bufsize & (-4);
|
||||
memcpy (buf, (uint8*)track->data + track->dataofs, dataleft);
|
||||
track->dataofs += dataleft;
|
||||
memcpy (buf, (uint8*)duka->data + duka->dataofs, dataleft);
|
||||
duka->dataofs += dataleft;
|
||||
}
|
||||
|
||||
if (track->cbdata > 0 && track->dataofs >= track->cbdata)
|
||||
track->cbdata = track->dataofs = 0; // reset for new data
|
||||
if (duka->cbdata > 0 && duka->dataofs >= duka->cbdata)
|
||||
duka->cbdata = duka->dataofs = 0; // reset for new data
|
||||
|
||||
return dataleft;
|
||||
}
|
||||
|
||||
sint32
|
||||
duka_readData (DukAud_Track* track, void* buf, sint32 bufsize)
|
||||
|
||||
static const char*
|
||||
duka_GetName (void)
|
||||
{
|
||||
return "DukAud";
|
||||
}
|
||||
|
||||
static bool
|
||||
duka_InitModule (int flags)
|
||||
{
|
||||
// no specific module init
|
||||
return true;
|
||||
|
||||
(void)flags; // laugh at compiler warning
|
||||
}
|
||||
|
||||
static void
|
||||
duka_TermModule ()
|
||||
{
|
||||
// no specific module term
|
||||
}
|
||||
|
||||
static uint32
|
||||
duka_GetStructSize (void)
|
||||
{
|
||||
return sizeof (TFB_DuckSoundDecoder);
|
||||
}
|
||||
|
||||
static int
|
||||
duka_GetError (THIS_PTR)
|
||||
{
|
||||
TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
int ret = duka->last_error;
|
||||
duka->last_error = dukae_None;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
duka_Init (THIS_PTR)
|
||||
{
|
||||
//TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
This->need_swap =
|
||||
decoder_formats.big_endian != decoder_formats.want_big_endian;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
duka_Term (THIS_PTR)
|
||||
{
|
||||
//TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
duka_Close (This); // ensure cleanup
|
||||
}
|
||||
|
||||
static bool
|
||||
duka_Open (THIS_PTR, uio_DirHandle *dir, const char *file)
|
||||
{
|
||||
TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
uio_Stream* duk;
|
||||
uio_Stream* frm;
|
||||
DukAud_AudSubframe aud;
|
||||
char filename[256];
|
||||
uint32 filelen;
|
||||
size_t cread;
|
||||
uint32 i;
|
||||
|
||||
filelen = strlen (file);
|
||||
if (filelen > sizeof (filename) - 1)
|
||||
return false;
|
||||
strcpy (filename, file);
|
||||
|
||||
duk = uio_fopen (dir, filename, "rb");
|
||||
if (!duk)
|
||||
{
|
||||
duka->last_error = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy (filename + filelen - 3, "frm");
|
||||
frm = uio_fopen (dir, filename, "rb");
|
||||
if (!frm)
|
||||
{
|
||||
duka->last_error = errno;
|
||||
uio_fclose (duk);
|
||||
return false;
|
||||
}
|
||||
|
||||
duka->duk = duk;
|
||||
|
||||
uio_fseek (frm, 0, SEEK_END);
|
||||
duka->cframes = uio_ftell (frm) / sizeof (uint32);
|
||||
uio_fseek (frm, 0, SEEK_SET);
|
||||
if (!duka->cframes)
|
||||
{
|
||||
duka->last_error = dukae_BadFile;
|
||||
uio_fclose (frm);
|
||||
duka_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
duka->frames = (uint32*) HMalloc (duka->cframes * sizeof (uint32));
|
||||
cread = uio_fread (duka->frames, sizeof (uint32), duka->cframes, frm);
|
||||
uio_fclose (frm);
|
||||
if (cread != duka->cframes)
|
||||
{
|
||||
duka->last_error = dukae_BadFile;
|
||||
duka_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < duka->cframes; ++i)
|
||||
duka->frames[i] = UQM_SwapBE32 (duka->frames[i]);
|
||||
|
||||
if (duka_readAudFrameHeader (duka, 0, &aud) < 0)
|
||||
{
|
||||
duka_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
This->frequency = 22050;
|
||||
This->format = decoder_formats.stereo16;
|
||||
duka->channels = 2;
|
||||
duka->pcm_frame = aud.numsamples;
|
||||
duka->data = HMalloc (DATA_BUF_SIZE);
|
||||
duka->maxdata = DATA_BUF_SIZE;
|
||||
|
||||
// estimate
|
||||
This->length = (float) duka->cframes / DUCK_GENERAL_FPS;
|
||||
|
||||
duka->last_error = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
duka_Close (THIS_PTR)
|
||||
{
|
||||
TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
|
||||
if (duka->data)
|
||||
{
|
||||
HFree (duka->data);
|
||||
duka->data = NULL;
|
||||
}
|
||||
if (duka->frames)
|
||||
{
|
||||
HFree (duka->frames);
|
||||
duka->frames = NULL;
|
||||
}
|
||||
if (duka->duk)
|
||||
{
|
||||
uio_fclose (duka->duk);
|
||||
duka->duk = NULL;
|
||||
}
|
||||
duka->last_error = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
duka_Decode (THIS_PTR, void* buf, sint32 bufsize)
|
||||
{
|
||||
TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
sint32 stuffed;
|
||||
sint32 total = 0;
|
||||
|
||||
if (bufsize <= 0)
|
||||
return duka_error = dukae_BadArg;
|
||||
return duka->last_error = dukae_BadArg;
|
||||
|
||||
do
|
||||
{
|
||||
stuffed = duka_stuffBuffer (track, buf, bufsize);
|
||||
stuffed = duka_stuffBuffer (duka, buf, bufsize);
|
||||
((uint8*)buf) += stuffed;
|
||||
bufsize -= stuffed;
|
||||
total += stuffed;
|
||||
|
||||
if (bufsize > 0 && track->iframe < track->cframes)
|
||||
if (bufsize > 0 && duka->iframe < duka->cframes)
|
||||
{
|
||||
stuffed = duka_readNextFrame (track);
|
||||
stuffed = duka_readNextFrame (duka);
|
||||
if (stuffed <= 0)
|
||||
return stuffed;
|
||||
}
|
||||
} while (bufsize > 0 && track->iframe < track->cframes);
|
||||
} while (bufsize > 0 && duka->iframe < duka->cframes);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
uint32
|
||||
duka_getFrame (DukAud_Track* track)
|
||||
static uint32
|
||||
duka_Seek (THIS_PTR, uint32 pcm_pos)
|
||||
{
|
||||
// if there is nothing buffered return the actual current frame
|
||||
// otherwise return previous
|
||||
return track->dataofs == track->cbdata ?
|
||||
track->iframe : track->iframe - 1;
|
||||
TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
uint32 iframe;
|
||||
|
||||
iframe = pcm_pos / duka->pcm_frame;
|
||||
if (iframe < duka->cframes)
|
||||
{
|
||||
duka->iframe = iframe;
|
||||
duka->cbdata = 0;
|
||||
duka->dataofs = 0;
|
||||
duka->predictors[0] = 0;
|
||||
duka->predictors[1] = 0;
|
||||
}
|
||||
return duka->iframe * duka->pcm_frame;
|
||||
}
|
||||
|
||||
uint32
|
||||
duka_getFrameSize (DukAud_Track* track)
|
||||
static uint32
|
||||
duka_GetFrame (THIS_PTR)
|
||||
{
|
||||
return track->pcm_frame * track->channels * sizeof (uint16);
|
||||
TFB_DuckSoundDecoder* duka = (TFB_DuckSoundDecoder*) This;
|
||||
|
||||
// if there is nothing buffered return the actual current frame
|
||||
// otherwise return previous
|
||||
return duka->dataofs == duka->cbdata ?
|
||||
duka->iframe : duka->iframe - 1;
|
||||
}
|
||||
|
||||
@@ -19,32 +19,9 @@
|
||||
#ifndef DUKAUD_H
|
||||
#define DUKAUD_H
|
||||
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
#include "decoder.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// public read-only
|
||||
uint32 iframe; // current frame index
|
||||
uint32 cframes; // total count of frames
|
||||
uint32 rate; // frequency
|
||||
uint32 channels; // number of channels
|
||||
uint32 pcm_frame; // samples per frame
|
||||
float length; // length in seconds (estimated)
|
||||
|
||||
// private
|
||||
uio_Stream* duk;
|
||||
uint32* frames;
|
||||
// buffer
|
||||
void* data;
|
||||
uint32 maxdata;
|
||||
uint32 cbdata;
|
||||
uint32 dataofs;
|
||||
// decoder stuff
|
||||
sint32 predictors[2];
|
||||
|
||||
} DukAud_Track;
|
||||
extern TFB_SoundDecoderFuncs duka_DecoderVtbl;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -56,12 +33,4 @@ typedef enum
|
||||
dukae_Other = -1000,
|
||||
} DukAud_Error;
|
||||
|
||||
sint32 duka_getError ();
|
||||
DukAud_Track* duka_openTrack (uio_DirHandle *dir, const char *file);
|
||||
void duka_closeTrack (DukAud_Track* track);
|
||||
bool duka_seekTrack (DukAud_Track* track, float pos /* in seconds */);
|
||||
sint32 duka_readData (DukAud_Track* track, void* buf, sint32 bufsize);
|
||||
uint32 duka_getFrame (DukAud_Track* track);
|
||||
uint32 duka_getFrameSize (DukAud_Track* track);
|
||||
|
||||
#endif // DUKAUD_H
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* MikMod decoder (.mod adapter)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "libs/misc.h"
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
#include "decoder.h"
|
||||
#include "mikmod/mikmod.h"
|
||||
#include "libs/sound/sound_common.h"
|
||||
#include "modaud.h"
|
||||
|
||||
#define THIS_PTR TFB_SoundDecoder* This
|
||||
|
||||
static const char* moda_GetName (void);
|
||||
static bool moda_InitModule (int flags);
|
||||
static void moda_TermModule ();
|
||||
static uint32 moda_GetStructSize (void);
|
||||
static int moda_GetError (THIS_PTR);
|
||||
static bool moda_Init (THIS_PTR);
|
||||
static void moda_Term (THIS_PTR);
|
||||
static bool moda_Open (THIS_PTR, uio_DirHandle *dir, const char *filename);
|
||||
static void moda_Close (THIS_PTR);
|
||||
static int moda_Decode (THIS_PTR, void* buf, sint32 bufsize);
|
||||
static uint32 moda_Seek (THIS_PTR, uint32 pcm_pos);
|
||||
static uint32 moda_GetFrame (THIS_PTR);
|
||||
|
||||
TFB_SoundDecoderFuncs moda_DecoderVtbl =
|
||||
{
|
||||
moda_GetName,
|
||||
moda_InitModule,
|
||||
moda_TermModule,
|
||||
moda_GetStructSize,
|
||||
moda_GetError,
|
||||
moda_Init,
|
||||
moda_Term,
|
||||
moda_Open,
|
||||
moda_Close,
|
||||
moda_Decode,
|
||||
moda_Seek,
|
||||
moda_GetFrame,
|
||||
};
|
||||
|
||||
typedef struct tfb_modsounddecoder
|
||||
{
|
||||
// always the first member
|
||||
TFB_SoundDecoder decoder;
|
||||
|
||||
// private
|
||||
sint32 last_error;
|
||||
MODULE* module;
|
||||
|
||||
} TFB_ModSoundDecoder;
|
||||
|
||||
MIKMODAPI extern struct MDRIVER drv_openal;
|
||||
|
||||
|
||||
static const char*
|
||||
moda_GetName (void)
|
||||
{
|
||||
return "MikMod";
|
||||
}
|
||||
|
||||
static bool
|
||||
moda_InitModule (int flags)
|
||||
{
|
||||
MikMod_RegisterDriver (&drv_openal);
|
||||
MikMod_RegisterAllLoaders ();
|
||||
|
||||
if (flags & TFB_SOUNDFLAGS_HQAUDIO)
|
||||
{
|
||||
md_mode = DMODE_HQMIXER|DMODE_STEREO|DMODE_16BITS|DMODE_INTERP|DMODE_SURROUND;
|
||||
md_mixfreq = 44100;
|
||||
md_reverb = 1;
|
||||
}
|
||||
else if (flags & TFB_SOUNDFLAGS_LQAUDIO)
|
||||
{
|
||||
md_mode = DMODE_SOFT_MUSIC|DMODE_STEREO|DMODE_16BITS;
|
||||
md_mixfreq = 22050;
|
||||
md_reverb = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
md_mode = DMODE_SOFT_MUSIC|DMODE_STEREO|DMODE_16BITS|DMODE_INTERP;
|
||||
md_mixfreq = 44100;
|
||||
md_reverb = 0;
|
||||
}
|
||||
|
||||
md_pansep = 64;
|
||||
|
||||
if (MikMod_Init (""))
|
||||
{
|
||||
fprintf (stderr, "MikMod_Init() failed, %s\n",
|
||||
MikMod_strerror (MikMod_errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
moda_TermModule ()
|
||||
{
|
||||
MikMod_Exit ();
|
||||
}
|
||||
|
||||
static uint32
|
||||
moda_GetStructSize (void)
|
||||
{
|
||||
return sizeof (TFB_ModSoundDecoder);
|
||||
}
|
||||
|
||||
static int
|
||||
moda_GetError (THIS_PTR)
|
||||
{
|
||||
TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
int ret = moda->last_error;
|
||||
moda->last_error = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
moda_Init (THIS_PTR)
|
||||
{
|
||||
//TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
This->need_swap =
|
||||
decoder_formats.big_endian != decoder_formats.want_big_endian;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
moda_Term (THIS_PTR)
|
||||
{
|
||||
//TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
moda_Close (This); // ensure cleanup
|
||||
}
|
||||
|
||||
static bool
|
||||
moda_Open (THIS_PTR, uio_DirHandle *dir, const char *filename)
|
||||
{
|
||||
TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
MODULE* mod;
|
||||
|
||||
mod = Player_Load (dir, (char*) filename, 4, 0);
|
||||
if (!mod)
|
||||
{
|
||||
fprintf (stderr, "moda_Open(): could not load %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
moda->module = mod;
|
||||
mod->extspd = 1;
|
||||
mod->panflag = 1;
|
||||
mod->wrap = 0;
|
||||
mod->loop = 1;
|
||||
|
||||
This->format = decoder_formats.stereo16;
|
||||
This->frequency = md_mixfreq;
|
||||
This->length = 0; // FIXME way to obtain this from mikmod?
|
||||
|
||||
moda->last_error = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
moda_Close (THIS_PTR)
|
||||
{
|
||||
TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
|
||||
if (moda->module)
|
||||
{
|
||||
Player_Free (moda->module);
|
||||
moda->module = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
moda_Decode (THIS_PTR, void* buf, sint32 bufsize)
|
||||
{
|
||||
TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
|
||||
Player_Start (moda->module);
|
||||
if (!Player_Active())
|
||||
return 0;
|
||||
|
||||
return VC_WriteBytes (buf, bufsize);
|
||||
}
|
||||
|
||||
static uint32
|
||||
moda_Seek (THIS_PTR, uint32 pcm_pos)
|
||||
{
|
||||
TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
|
||||
Player_Start (moda->module);
|
||||
if (pcm_pos)
|
||||
fprintf (stderr, "moda_Seek(): "
|
||||
"non-zero seek positions not supported for mod\n");
|
||||
Player_SetPosition (0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32
|
||||
moda_GetFrame (THIS_PTR)
|
||||
{
|
||||
TFB_ModSoundDecoder* moda = (TFB_ModSoundDecoder*) This;
|
||||
return moda->module->sngpos;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* MikMod adapter */
|
||||
|
||||
#ifndef MODAUD_H
|
||||
#define MODAUD_H
|
||||
|
||||
#include "decoder.h"
|
||||
|
||||
extern TFB_SoundDecoderFuncs moda_DecoderVtbl;
|
||||
|
||||
#endif // MODAUD_H
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Ogg Vorbis decoder (.ogg adapter)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "libs/misc.h"
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
#include "decoder.h"
|
||||
#include <vorbis/codec.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include "oggaud.h"
|
||||
|
||||
|
||||
#define THIS_PTR TFB_SoundDecoder* This
|
||||
|
||||
static const char* ova_GetName (void);
|
||||
static bool ova_InitModule (int flags);
|
||||
static void ova_TermModule ();
|
||||
static uint32 ova_GetStructSize (void);
|
||||
static int ova_GetError (THIS_PTR);
|
||||
static bool ova_Init (THIS_PTR);
|
||||
static void ova_Term (THIS_PTR);
|
||||
static bool ova_Open (THIS_PTR, uio_DirHandle *dir, const char *filename);
|
||||
static void ova_Close (THIS_PTR);
|
||||
static int ova_Decode (THIS_PTR, void* buf, sint32 bufsize);
|
||||
static uint32 ova_Seek (THIS_PTR, uint32 pcm_pos);
|
||||
static uint32 ova_GetFrame (THIS_PTR);
|
||||
|
||||
TFB_SoundDecoderFuncs ova_DecoderVtbl =
|
||||
{
|
||||
ova_GetName,
|
||||
ova_InitModule,
|
||||
ova_TermModule,
|
||||
ova_GetStructSize,
|
||||
ova_GetError,
|
||||
ova_Init,
|
||||
ova_Term,
|
||||
ova_Open,
|
||||
ova_Close,
|
||||
ova_Decode,
|
||||
ova_Seek,
|
||||
ova_GetFrame,
|
||||
};
|
||||
|
||||
typedef struct tfb_oggsounddecoder
|
||||
{
|
||||
// always the first member
|
||||
TFB_SoundDecoder decoder;
|
||||
|
||||
// private
|
||||
sint32 last_error;
|
||||
OggVorbis_File vf;
|
||||
|
||||
} TFB_OggSoundDecoder;
|
||||
|
||||
static size_t
|
||||
ogg_read (void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
return uio_fread (ptr, size, nmemb, (uio_Stream *) datasource);
|
||||
}
|
||||
|
||||
static int
|
||||
ogg_seek (void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
long off = (long) offset;
|
||||
return uio_fseek ((uio_Stream *) datasource, off, whence);
|
||||
}
|
||||
|
||||
static int
|
||||
ogg_close (void *datasource)
|
||||
{
|
||||
return uio_fclose ((uio_Stream *) datasource);
|
||||
}
|
||||
|
||||
static long
|
||||
ogg_tell (void *datasource)
|
||||
{
|
||||
return uio_ftell ((uio_Stream *) datasource);
|
||||
}
|
||||
|
||||
static const ov_callbacks ogg_callbacks =
|
||||
{
|
||||
ogg_read,
|
||||
ogg_seek,
|
||||
ogg_close,
|
||||
ogg_tell,
|
||||
};
|
||||
|
||||
static const char*
|
||||
ova_GetName (void)
|
||||
{
|
||||
return "Ogg Vorbis";
|
||||
}
|
||||
|
||||
static bool
|
||||
ova_InitModule (int flags)
|
||||
{
|
||||
// no specific module init
|
||||
return true;
|
||||
|
||||
(void)flags; // laugh at compiler warning
|
||||
}
|
||||
|
||||
static void
|
||||
ova_TermModule ()
|
||||
{
|
||||
// no specific module term
|
||||
}
|
||||
|
||||
static uint32
|
||||
ova_GetStructSize (void)
|
||||
{
|
||||
return sizeof (TFB_OggSoundDecoder);
|
||||
}
|
||||
|
||||
static int
|
||||
ova_GetError (THIS_PTR)
|
||||
{
|
||||
TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
int ret = ova->last_error;
|
||||
ova->last_error = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
ova_Init (THIS_PTR)
|
||||
{
|
||||
//TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
This->need_swap = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ova_Term (THIS_PTR)
|
||||
{
|
||||
//TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
ova_Close (This); // ensure cleanup
|
||||
}
|
||||
|
||||
static bool
|
||||
ova_Open (THIS_PTR, uio_DirHandle *dir, const char *filename)
|
||||
{
|
||||
TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
int rc;
|
||||
uio_Stream *fp;
|
||||
vorbis_info *vinfo;
|
||||
|
||||
fp = uio_fopen (dir, filename, "rb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
fprintf (stderr, "ova_Open(): could not open %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = ov_open_callbacks (fp, &ova->vf, NULL, 0, ogg_callbacks);
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf (stderr, "ova_Open(): "
|
||||
"ov_open_callbacks failed for %s, error code %d\n",
|
||||
filename, rc);
|
||||
uio_fclose (fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
vinfo = ov_info (&ova->vf, -1);
|
||||
if (!vinfo)
|
||||
{
|
||||
fprintf (stderr, "ova_Open(): "
|
||||
"failed to retrieve ogg bitstream info for %s\n",
|
||||
filename);
|
||||
ov_clear (&ova->vf);
|
||||
return false;
|
||||
}
|
||||
|
||||
This->frequency = vinfo->rate;
|
||||
This->length = (float) ov_time_total (&ova->vf, -1);
|
||||
|
||||
if (vinfo->channels == 1)
|
||||
This->format = decoder_formats.mono16;
|
||||
else
|
||||
This->format = decoder_formats.stereo16;
|
||||
|
||||
ova->last_error = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ova_Close (THIS_PTR)
|
||||
{
|
||||
TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
|
||||
ov_clear (&ova->vf);
|
||||
}
|
||||
|
||||
static int
|
||||
ova_Decode (THIS_PTR, void* buf, sint32 bufsize)
|
||||
{
|
||||
TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
long rc;
|
||||
int bitstream;
|
||||
|
||||
rc = ov_read (&ova->vf, buf, bufsize, decoder_formats.want_big_endian,
|
||||
2, 1, &bitstream);
|
||||
|
||||
if (rc < 0)
|
||||
ova->last_error = rc;
|
||||
else
|
||||
ova->last_error = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static uint32
|
||||
ova_Seek (THIS_PTR, uint32 pcm_pos)
|
||||
{
|
||||
TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
int ret;
|
||||
|
||||
ret = ov_pcm_seek (&ova->vf, pcm_pos);
|
||||
if (ret != 0)
|
||||
{
|
||||
ova->last_error = ret;
|
||||
return (uint32) ov_pcm_tell (&ova->vf);
|
||||
}
|
||||
else
|
||||
return pcm_pos;
|
||||
}
|
||||
|
||||
static uint32
|
||||
ova_GetFrame (THIS_PTR)
|
||||
{
|
||||
TFB_OggSoundDecoder* ova = (TFB_OggSoundDecoder*) This;
|
||||
// this is the closest to a frame there is in ogg vorbis stream
|
||||
// doesn't seem to be a func to retrive it
|
||||
return ova->vf.os.pageno;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Ogg Vorbis adapter */
|
||||
|
||||
#ifndef OGGAUD_H
|
||||
#define OGGAUD_H
|
||||
|
||||
#include "decoder.h"
|
||||
|
||||
extern TFB_SoundDecoderFuncs ova_DecoderVtbl;
|
||||
|
||||
#endif // OGGAUD_H
|
||||
@@ -14,17 +14,22 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Loader for .wav files
|
||||
/* Wave decoder (.wav adapter)
|
||||
* Code is based on Creative's Win32 OpenAL implementation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <memory.h>
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
#include "endian_uqm.h"
|
||||
#include "libs/misc.h"
|
||||
#include "wav.h"
|
||||
#include "decoder.h"
|
||||
#include "endian_uqm.h"
|
||||
|
||||
#define RIFF 0x46464952 /* "RIFF" */
|
||||
#define WAVE 0x45564157 /* "WAVE" */
|
||||
#define FMT 0x20746D66 /* "fmt " */
|
||||
#define DATA 0x61746164 /* "data" */
|
||||
|
||||
@@ -52,100 +57,304 @@ typedef struct
|
||||
} WAVChunkHdr_Struct;
|
||||
|
||||
|
||||
void
|
||||
LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format,
|
||||
void **data, uint32 *size, uint32 *freq, bool want_big_endian)
|
||||
#define THIS_PTR TFB_SoundDecoder* This
|
||||
|
||||
static const char* wava_GetName (void);
|
||||
static bool wava_InitModule (int flags);
|
||||
static void wava_TermModule ();
|
||||
static uint32 wava_GetStructSize (void);
|
||||
static int wava_GetError (THIS_PTR);
|
||||
static bool wava_Init (THIS_PTR);
|
||||
static void wava_Term (THIS_PTR);
|
||||
static bool wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename);
|
||||
static void wava_Close (THIS_PTR);
|
||||
static int wava_Decode (THIS_PTR, void* buf, sint32 bufsize);
|
||||
static uint32 wava_Seek (THIS_PTR, uint32 pcm_pos);
|
||||
static uint32 wava_GetFrame (THIS_PTR);
|
||||
|
||||
TFB_SoundDecoderFuncs wava_DecoderVtbl =
|
||||
{
|
||||
WAVChunkHdr_Struct ChunkHdr;
|
||||
WAVFileHdr_Struct FileHdr;
|
||||
WAVFmtHdr_Struct FmtHdr;
|
||||
wava_GetName,
|
||||
wava_InitModule,
|
||||
wava_TermModule,
|
||||
wava_GetStructSize,
|
||||
wava_GetError,
|
||||
wava_Init,
|
||||
wava_Term,
|
||||
wava_Open,
|
||||
wava_Close,
|
||||
wava_Decode,
|
||||
wava_Seek,
|
||||
wava_GetFrame,
|
||||
};
|
||||
|
||||
typedef struct tfb_wavesounddecoder
|
||||
{
|
||||
// always the first member
|
||||
TFB_SoundDecoder decoder;
|
||||
|
||||
// private
|
||||
sint32 last_error;
|
||||
uio_Stream *fp;
|
||||
|
||||
*format = decoder_formats.mono16;
|
||||
*data = NULL;
|
||||
*size = 0;
|
||||
*freq = 22050;
|
||||
|
||||
fp = uio_fopen (dir, file, "rb");
|
||||
if (fp)
|
||||
{
|
||||
uio_fread(&FileHdr.Id, 4, 1, fp);
|
||||
FileHdr.Id = UQM_SwapLE32 (FileHdr.Id);
|
||||
uio_fread(&FileHdr.Size, 4, 1, fp);
|
||||
FileHdr.Size = UQM_SwapLE32 (FileHdr.Size);
|
||||
uio_fread(&FileHdr.Type, 4, 1, fp);
|
||||
FileHdr.Type = UQM_SwapLE32 (FileHdr.Type);
|
||||
WAVFmtHdr_Struct FmtHdr;
|
||||
uint32 data_ofs;
|
||||
uint32 data_size;
|
||||
uint32 max_pcm;
|
||||
uint32 cur_pcm;
|
||||
|
||||
FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4;
|
||||
while (FileHdr.Size != 0)
|
||||
{
|
||||
if (!uio_fread (&ChunkHdr.Id, 4, 1, fp))
|
||||
break;
|
||||
ChunkHdr.Id = UQM_SwapLE32 (ChunkHdr.Id);
|
||||
if (!uio_fread (&ChunkHdr.Size, 4, 1, fp))
|
||||
break;
|
||||
ChunkHdr.Size = UQM_SwapLE32 (ChunkHdr.Size);
|
||||
} TFB_WaveSoundDecoder;
|
||||
|
||||
if (ChunkHdr.Id == FMT)
|
||||
{
|
||||
uio_fread (&FmtHdr.Format, 2, 1, fp);
|
||||
FmtHdr.Format = UQM_SwapLE16 (FmtHdr.Format);
|
||||
uio_fread (&FmtHdr.Channels, 2, 1, fp);
|
||||
FmtHdr.Channels = UQM_SwapLE16 (FmtHdr.Channels);
|
||||
uio_fread (&FmtHdr.SamplesPerSec, 4, 1, fp);
|
||||
FmtHdr.SamplesPerSec = UQM_SwapLE32 (FmtHdr.SamplesPerSec);
|
||||
uio_fread (&FmtHdr.BytesPerSec, 4, 1, fp);
|
||||
FmtHdr.BytesPerSec = UQM_SwapLE32 (FmtHdr.BytesPerSec);
|
||||
uio_fread (&FmtHdr.BlockAlign, 2, 1, fp);
|
||||
FmtHdr.BlockAlign = UQM_SwapLE16 (FmtHdr.BlockAlign);
|
||||
uio_fread (&FmtHdr.BitsPerSample, 2, 1, fp);
|
||||
FmtHdr.BitsPerSample = UQM_SwapLE16 (FmtHdr.BitsPerSample);
|
||||
|
||||
if (FmtHdr.Format == 0x0001)
|
||||
{
|
||||
*format=(FmtHdr.Channels == 1 ?
|
||||
(FmtHdr.BitsPerSample == 8 ?
|
||||
decoder_formats.mono8
|
||||
: decoder_formats.mono16)
|
||||
: (FmtHdr.BitsPerSample == 8 ?
|
||||
decoder_formats.stereo8
|
||||
: decoder_formats.stereo16)
|
||||
);
|
||||
*freq = FmtHdr.SamplesPerSec;
|
||||
uio_fseek (fp, ChunkHdr.Size - 16, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "LoadWAVFile(): unsupported format %x\n", FmtHdr.Format);
|
||||
uio_fclose (fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (ChunkHdr.Id == DATA)
|
||||
{
|
||||
*size = ChunkHdr.Size;
|
||||
if ((*data = HMalloc (ChunkHdr.Size + 31)))
|
||||
uio_fread (*data, FmtHdr.BlockAlign, ChunkHdr.Size / FmtHdr.BlockAlign, fp);
|
||||
memset(((char *)*data) + ChunkHdr.Size, 0, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
uio_fseek(fp, ChunkHdr.Size, SEEK_CUR);
|
||||
}
|
||||
|
||||
uio_fseek (fp, ChunkHdr.Size & 1, SEEK_CUR);
|
||||
FileHdr.Size -= (((ChunkHdr.Size + 1) & ~1) + 8);
|
||||
}
|
||||
uio_fclose(fp);
|
||||
}
|
||||
|
||||
if (want_big_endian &&
|
||||
(*format == decoder_formats.stereo16 || *format == decoder_formats.mono16))
|
||||
{
|
||||
SoundDecoder_SwapWords (*data, *size);
|
||||
}
|
||||
|
||||
if (*size == 0)
|
||||
fprintf (stderr, "LoadWAVFile(): loading %s failed!\n", file);
|
||||
static const char*
|
||||
wava_GetName (void)
|
||||
{
|
||||
return "Wave";
|
||||
}
|
||||
|
||||
static bool
|
||||
wava_InitModule (int flags)
|
||||
{
|
||||
// no specific module init
|
||||
return true;
|
||||
|
||||
(void)flags; // laugh at compiler warning
|
||||
}
|
||||
|
||||
static void
|
||||
wava_TermModule ()
|
||||
{
|
||||
// no specific module term
|
||||
}
|
||||
|
||||
static uint32
|
||||
wava_GetStructSize (void)
|
||||
{
|
||||
return sizeof (TFB_WaveSoundDecoder);
|
||||
}
|
||||
|
||||
static int
|
||||
wava_GetError (THIS_PTR)
|
||||
{
|
||||
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
int ret = wava->last_error;
|
||||
wava->last_error = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
wava_Init (THIS_PTR)
|
||||
{
|
||||
//TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
This->need_swap = decoder_formats.want_big_endian;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
wava_Term (THIS_PTR)
|
||||
{
|
||||
//TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
wava_Close (This); // ensure cleanup
|
||||
}
|
||||
|
||||
static bool
|
||||
wava_readFileHeader (TFB_WaveSoundDecoder* wava, WAVFileHdr_Struct* hdr)
|
||||
{
|
||||
if (!uio_fread (&hdr->Id, 4, 1, wava->fp) ||
|
||||
!uio_fread (&hdr->Size, 4, 1, wava->fp) ||
|
||||
!uio_fread (&hdr->Type, 4, 1, wava->fp))
|
||||
{
|
||||
wava->last_error = errno;
|
||||
return false;
|
||||
}
|
||||
hdr->Id = UQM_SwapLE32 (hdr->Id);
|
||||
hdr->Size = UQM_SwapLE32 (hdr->Size);
|
||||
hdr->Type = UQM_SwapLE32 (hdr->Type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
wava_readChunkHeader (TFB_WaveSoundDecoder* wava, WAVChunkHdr_Struct* chunk)
|
||||
{
|
||||
if (!uio_fread (&chunk->Id, 4, 1, wava->fp) ||
|
||||
!uio_fread (&chunk->Size, 4, 1, wava->fp))
|
||||
return false;
|
||||
|
||||
chunk->Id = UQM_SwapLE32 (chunk->Id);
|
||||
chunk->Size = UQM_SwapLE32 (chunk->Size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
wava_readFormatHeader (TFB_WaveSoundDecoder* wava, WAVFmtHdr_Struct* fmt)
|
||||
{
|
||||
if (!uio_fread (&fmt->Format, 2, 1, wava->fp) ||
|
||||
!uio_fread (&fmt->Channels, 2, 1, wava->fp) ||
|
||||
!uio_fread (&fmt->SamplesPerSec, 4, 1, wava->fp) ||
|
||||
!uio_fread (&fmt->BytesPerSec, 4, 1, wava->fp) ||
|
||||
!uio_fread (&fmt->BlockAlign, 2, 1, wava->fp) ||
|
||||
!uio_fread (&fmt->BitsPerSample, 2, 1, wava->fp))
|
||||
return false;
|
||||
|
||||
fmt->Format = UQM_SwapLE16 (fmt->Format);
|
||||
fmt->Channels = UQM_SwapLE16 (fmt->Channels);
|
||||
fmt->SamplesPerSec = UQM_SwapLE32 (fmt->SamplesPerSec);
|
||||
fmt->BytesPerSec = UQM_SwapLE32 (fmt->BytesPerSec);
|
||||
fmt->BlockAlign = UQM_SwapLE16 (fmt->BlockAlign);
|
||||
fmt->BitsPerSample = UQM_SwapLE16 (fmt->BitsPerSample);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename)
|
||||
{
|
||||
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
WAVFileHdr_Struct FileHdr;
|
||||
WAVChunkHdr_Struct ChunkHdr;
|
||||
|
||||
wava->fp = uio_fopen (dir, filename, "rb");
|
||||
if (!wava->fp)
|
||||
{
|
||||
wava->last_error = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
wava->data_size = 0;
|
||||
wava->data_ofs = 0;
|
||||
|
||||
// read wave header
|
||||
if (!wava_readFileHeader (wava, &FileHdr))
|
||||
{
|
||||
wava->last_error = errno;
|
||||
wava_Close (This);
|
||||
return false;
|
||||
}
|
||||
if (FileHdr.Id != RIFF || FileHdr.Type != WAVE)
|
||||
{
|
||||
fprintf (stderr, "wava_Open(): "
|
||||
"not a wave file, ID 0x%08x, Type 0x%08x\n",
|
||||
FileHdr.Id, FileHdr.Type);
|
||||
wava_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4; FileHdr.Size != 0;
|
||||
FileHdr.Size -= (((ChunkHdr.Size + 1) & ~1) + 8))
|
||||
{
|
||||
if (!wava_readChunkHeader (wava, &ChunkHdr))
|
||||
{
|
||||
wava->last_error = errno;
|
||||
wava_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ChunkHdr.Id == FMT)
|
||||
{
|
||||
if (!wava_readFormatHeader (wava, &wava->FmtHdr))
|
||||
{
|
||||
wava->last_error = errno;
|
||||
wava_Close (This);
|
||||
return false;
|
||||
}
|
||||
uio_fseek (wava->fp, ChunkHdr.Size - 16, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ChunkHdr.Id == DATA)
|
||||
{
|
||||
wava->data_size = ChunkHdr.Size;
|
||||
wava->data_ofs = uio_ftell (wava->fp);
|
||||
}
|
||||
uio_fseek (wava->fp, ChunkHdr.Size, SEEK_CUR);
|
||||
}
|
||||
|
||||
uio_fseek (wava->fp, ChunkHdr.Size & 1, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (!wava->data_size || !wava->data_ofs)
|
||||
{
|
||||
fprintf (stderr, "wava_Open(): bad wave file, no DATA chunk found\n");
|
||||
wava_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wava->FmtHdr.Format == 0x0001)
|
||||
{
|
||||
This->format = (wava->FmtHdr.Channels == 1 ?
|
||||
(wava->FmtHdr.BitsPerSample == 8 ?
|
||||
decoder_formats.mono8 : decoder_formats.mono16)
|
||||
:
|
||||
(wava->FmtHdr.BitsPerSample == 8 ?
|
||||
decoder_formats.stereo8 : decoder_formats.stereo16)
|
||||
);
|
||||
This->frequency = wava->FmtHdr.SamplesPerSec;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "wava_Open(): unsupported format %x\n", wava->FmtHdr.Format);
|
||||
wava_Close (This);
|
||||
return false;
|
||||
}
|
||||
|
||||
uio_fseek (wava->fp, wava->data_ofs, SEEK_SET);
|
||||
wava->max_pcm = wava->data_size / wava->FmtHdr.BlockAlign;
|
||||
wava->cur_pcm = 0;
|
||||
This->length = (float) wava->max_pcm / wava->FmtHdr.SamplesPerSec;
|
||||
wava->last_error = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
wava_Close (THIS_PTR)
|
||||
{
|
||||
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
|
||||
if (wava->fp)
|
||||
{
|
||||
uio_fclose (wava->fp);
|
||||
wava->fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
wava_Decode (THIS_PTR, void* buf, sint32 bufsize)
|
||||
{
|
||||
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
uint32 dec_pcm;
|
||||
|
||||
dec_pcm = bufsize / wava->FmtHdr.BlockAlign;
|
||||
if (dec_pcm > wava->max_pcm - wava->cur_pcm)
|
||||
dec_pcm = wava->max_pcm - wava->cur_pcm;
|
||||
|
||||
dec_pcm = uio_fread (buf, wava->FmtHdr.BlockAlign, dec_pcm, wava->fp);
|
||||
wava->cur_pcm += dec_pcm;
|
||||
|
||||
return dec_pcm * wava->FmtHdr.BlockAlign;
|
||||
}
|
||||
|
||||
static uint32
|
||||
wava_Seek (THIS_PTR, uint32 pcm_pos)
|
||||
{
|
||||
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
|
||||
if (pcm_pos > wava->max_pcm)
|
||||
pcm_pos = wava->max_pcm;
|
||||
wava->cur_pcm = pcm_pos;
|
||||
uio_fseek (wava->fp,
|
||||
wava->data_ofs + pcm_pos * wava->FmtHdr.BlockAlign,
|
||||
SEEK_SET);
|
||||
|
||||
return pcm_pos;
|
||||
}
|
||||
|
||||
static uint32
|
||||
wava_GetFrame (THIS_PTR)
|
||||
{
|
||||
//TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
|
||||
return 0; // only 1 frame for now
|
||||
|
||||
(void)This; // laugh at compiler warning
|
||||
}
|
||||
|
||||
@@ -14,16 +14,13 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Loader for .wav files */
|
||||
/* Wave decoder */
|
||||
|
||||
#ifndef WAV_H
|
||||
#define WAV_H
|
||||
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
#include "decoder.h"
|
||||
|
||||
void LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format,
|
||||
void **data, uint32 *size, uint32 *freq, bool want_big_endian);
|
||||
extern TFB_SoundDecoderFuncs wava_DecoderVtbl;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -164,7 +164,8 @@ _GetMusicData (uio_Stream *fp, DWORD length)
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, " decoder: %s, rate %d format %x\n", (*pmus)->decoder->decoder_info,
|
||||
fprintf (stderr, " decoder: %s, rate %d format %x\n",
|
||||
SoundDecoder_GetName ((*pmus)->decoder),
|
||||
(*pmus)->decoder->frequency, (*pmus)->decoder->format);
|
||||
|
||||
(*pmus)->num_buffers = 64;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
ALCcontext *alcContext = NULL;
|
||||
ALCdevice *alcDevice = NULL;
|
||||
ALfloat listenerPos[] = {0.0f, 0.0f, 0.0f};
|
||||
ALfloat listenerPos[] = {0.0f, 0.0f, 0.2f};
|
||||
ALfloat listenerVel[] = {0.0f, 0.0f, 0.0f};
|
||||
ALfloat listenerOri[] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f};
|
||||
static Task StreamDecoderTask;
|
||||
|
||||
@@ -436,7 +436,7 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
|
||||
{
|
||||
fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n",
|
||||
*TrackNames,
|
||||
track_decs[tracks]->decoder_info,
|
||||
SoundDecoder_GetName (track_decs[tracks]),
|
||||
track_decs[tracks]->frequency,
|
||||
track_decs[tracks]->format);
|
||||
SoundDecoder_DecodeAll (track_decs[tracks]);
|
||||
@@ -614,7 +614,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_Tra
|
||||
if (last_chain->decoder)
|
||||
{
|
||||
static float old_volume = 0.0f;
|
||||
if (last_chain->decoder->type == SOUNDDECODER_NULL)
|
||||
if (last_chain->decoder->is_null)
|
||||
{
|
||||
if (speechVolumeScale != 0.0f)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user