Added .duk audio decoder
(video playback support phase 2) git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1247 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
uqm_SUBDIRS="mikmod"
|
uqm_SUBDIRS="mikmod"
|
||||||
uqm_CFILES="decoder.c wav.c"
|
uqm_CFILES="decoder.c wav.c dukaud.c"
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "wav.h"
|
#include "wav.h"
|
||||||
#include "libs/sound/sound_common.h"
|
#include "libs/sound/sound_common.h"
|
||||||
#include "mikmod/mikmod.h"
|
#include "mikmod/mikmod.h"
|
||||||
|
#include "dukaud.h"
|
||||||
|
|
||||||
extern bool fileExists2(uio_DirHandle *dir, const char *fileName);
|
extern bool fileExists2(uio_DirHandle *dir, const char *fileName);
|
||||||
// Can't '#include "libs/file.h"' due to some type conflicts.
|
// Can't '#include "libs/file.h"' due to some type conflicts.
|
||||||
@@ -44,6 +45,7 @@ static char *decoder_info_wav = "Wav";
|
|||||||
static char *decoder_info_mod = "MikMod";
|
static char *decoder_info_mod = "MikMod";
|
||||||
static char *decoder_info_ogg = "Ogg Vorbis";
|
static char *decoder_info_ogg = "Ogg Vorbis";
|
||||||
static char *decoder_info_nul = "None";
|
static char *decoder_info_nul = "None";
|
||||||
|
static char *decoder_info_duk = "DukAud";
|
||||||
|
|
||||||
TFB_DecoderFormats decoder_formats;
|
TFB_DecoderFormats decoder_formats;
|
||||||
|
|
||||||
@@ -333,6 +335,43 @@ TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir, char *filename,
|
|||||||
|
|
||||||
return decoder;
|
return decoder;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (&filename[i], "duk"))
|
||||||
|
{
|
||||||
|
TFB_SoundDecoder *decoder;
|
||||||
|
DukAud_Track* track;
|
||||||
|
|
||||||
|
track = duka_openTrack (dir, filename);
|
||||||
|
if (!track)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "SoundDecoder_Load(): couldn't load %s\n", filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder));
|
||||||
|
decoder->buffer = HMalloc (buffer_size);
|
||||||
|
decoder->buffer_size = buffer_size;
|
||||||
|
decoder->frequency = track->rate;
|
||||||
|
decoder->looping = false;
|
||||||
|
decoder->error = SOUNDDECODER_OK;
|
||||||
|
decoder->length = track->length - (startTime / 1000.0f);
|
||||||
|
decoder->start_sample = 0;
|
||||||
|
decoder->end_sample = 0;
|
||||||
|
decoder->pos = 0;
|
||||||
|
|
||||||
|
if (track->channels == 1)
|
||||||
|
decoder->format = decoder_formats.mono16;
|
||||||
|
else
|
||||||
|
decoder->format = decoder_formats.stereo16;
|
||||||
|
|
||||||
|
decoder->decoder_info = decoder_info_duk;
|
||||||
|
decoder->type = SOUNDDECODER_DUK;
|
||||||
|
decoder->dir = dir;
|
||||||
|
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
|
||||||
|
strcpy (decoder->filename, filename);
|
||||||
|
decoder->data = track;
|
||||||
|
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, "SoundDecoder_Load(): %s file format is unsupported\n", filename);
|
fprintf (stderr, "SoundDecoder_Load(): %s file format is unsupported\n", filename);
|
||||||
@@ -470,6 +509,37 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
|
|||||||
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
|
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
|
||||||
return decoded_bytes;
|
return decoded_bytes;
|
||||||
}
|
}
|
||||||
|
case SOUNDDECODER_DUK:
|
||||||
|
{
|
||||||
|
DukAud_Track *track = (DukAud_Track *) decoder->data;
|
||||||
|
uint32 decoded_bytes = 0;
|
||||||
|
sint32 rc;
|
||||||
|
|
||||||
|
rc = duka_readData (track, decoder->buffer, decoder->buffer_size);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
decoder->error = SOUNDDECODER_ERROR;
|
||||||
|
fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc);
|
||||||
|
return decoded_bytes;
|
||||||
|
}
|
||||||
|
decoded_bytes = rc;
|
||||||
|
decoder->pos += decoded_bytes;
|
||||||
|
decoder->error = rc > 0 ? SOUNDDECODER_OK : SOUNDDECODER_EOF;
|
||||||
|
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
|
||||||
|
|
||||||
|
/* DukAud produces output in machine byte-order
|
||||||
|
* may need to do a word-swap
|
||||||
|
*/
|
||||||
|
if (decoded_bytes > 0 &&
|
||||||
|
decoder_formats.big_endian != decoder_formats.want_big_endian &&
|
||||||
|
(decoder->format == decoder_formats.stereo16 ||
|
||||||
|
decoder->format == decoder_formats.mono16))
|
||||||
|
{
|
||||||
|
SoundDecoder_SwapWords (
|
||||||
|
decoder->buffer, decoded_bytes);
|
||||||
|
}
|
||||||
|
return decoded_bytes;
|
||||||
|
}
|
||||||
case SOUNDDECODER_NULL:
|
case SOUNDDECODER_NULL:
|
||||||
{
|
{
|
||||||
uint32 max_bytes;
|
uint32 max_bytes;
|
||||||
@@ -591,6 +661,11 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
|
|||||||
return decoded_bytes;
|
return decoded_bytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SOUNDDECODER_DUK:
|
||||||
|
{
|
||||||
|
fprintf (stderr, "SoundDecoder_DecodeAll(): unimplemented for duk\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SOUNDDECODER_NULL:
|
case SOUNDDECODER_NULL:
|
||||||
{
|
{
|
||||||
decoder->error = SOUNDDECODER_OK;
|
decoder->error = SOUNDDECODER_OK;
|
||||||
@@ -656,6 +731,24 @@ void SoundDecoder_Seek (TFB_SoundDecoder *decoder, uint32 seekTime)
|
|||||||
decoder->error = SOUNDDECODER_OK;
|
decoder->error = SOUNDDECODER_OK;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case SOUNDDECODER_DUK:
|
||||||
|
{
|
||||||
|
DukAud_Track* track = (DukAud_Track*) decoder->data;
|
||||||
|
|
||||||
|
if (duka_seekTrack (track, (float)seekTime / 1000.0f))
|
||||||
|
{
|
||||||
|
decoder->pos = seekTime * decoder->frequency * 2 / 1000;
|
||||||
|
if (decoder->format == decoder_formats.stereo16)
|
||||||
|
decoder->pos *= 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "SoundDecoder_Seek(): couldn't seek %s to %u\n", decoder->filename, seekTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
decoder->error = SOUNDDECODER_OK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
case SOUNDDECODER_BUF:
|
case SOUNDDECODER_BUF:
|
||||||
{
|
{
|
||||||
uint32 pcm_pos = seekTime * decoder->frequency / 1000;
|
uint32 pcm_pos = seekTime * decoder->frequency / 1000;
|
||||||
@@ -714,6 +807,13 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder)
|
|||||||
HFree (vf);
|
HFree (vf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SOUNDDECODER_DUK:
|
||||||
|
{
|
||||||
|
DukAud_Track* track = (DukAud_Track*) decoder->data;
|
||||||
|
//fprintf (stderr, "SoundDecoder_Free(): freeing %s\n", decoder->filename);
|
||||||
|
duka_closeTrack (track);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SOUNDDECODER_BUF:
|
case SOUNDDECODER_BUF:
|
||||||
break;
|
break;
|
||||||
case SOUNDDECODER_NULL:
|
case SOUNDDECODER_NULL:
|
||||||
@@ -750,6 +850,7 @@ float SoundDecoder_GetTime (TFB_SoundDecoder *decoder)
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
case SOUNDDECODER_OGG:
|
case SOUNDDECODER_OGG:
|
||||||
|
case SOUNDDECODER_DUK:
|
||||||
case SOUNDDECODER_BUF:
|
case SOUNDDECODER_BUF:
|
||||||
case SOUNDDECODER_NULL:
|
case SOUNDDECODER_NULL:
|
||||||
{
|
{
|
||||||
@@ -767,3 +868,47 @@ float SoundDecoder_GetTime (TFB_SoundDecoder *decoder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
SoundDecoder_GetFrame (TFB_SoundDecoder *decoder)
|
||||||
|
{
|
||||||
|
uint32 frame = 0;
|
||||||
|
|
||||||
|
if (!decoder)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (decoder->type)
|
||||||
|
{
|
||||||
|
case SOUNDDECODER_MOD:
|
||||||
|
{
|
||||||
|
MODULE *mod = (MODULE *) decoder->data;
|
||||||
|
frame = mod->sngpos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SOUNDDECODER_OGG:
|
||||||
|
{
|
||||||
|
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
|
||||||
|
// this is the closest to a frame there is in ogg vorbis stream
|
||||||
|
// doesn't seem to be a func to retrive it
|
||||||
|
frame = vf->os.pageno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SOUNDDECODER_DUK:
|
||||||
|
{
|
||||||
|
DukAud_Track* track = (DukAud_Track*) decoder->data;
|
||||||
|
frame = duka_getFrame (track);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SOUNDDECODER_WAV:
|
||||||
|
case SOUNDDECODER_BUF:
|
||||||
|
case SOUNDDECODER_NULL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
fprintf (stderr, "SoundDecoder_GetFrame(): unknown type %d\n", decoder->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ enum
|
|||||||
SOUNDDECODER_OGG,
|
SOUNDDECODER_OGG,
|
||||||
SOUNDDECODER_NULL,
|
SOUNDDECODER_NULL,
|
||||||
SOUNDDECODER_BUF,
|
SOUNDDECODER_BUF,
|
||||||
|
SOUNDDECODER_DUK,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TFB_DecoderFormats decoder_formats;
|
extern TFB_DecoderFormats decoder_formats;
|
||||||
@@ -90,6 +91,7 @@ TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir,
|
|||||||
uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder);
|
uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder);
|
||||||
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
|
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
|
||||||
float SoundDecoder_GetTime (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 pcm_pos);
|
||||||
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder);
|
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder);
|
||||||
void SoundDecoder_Free (TFB_SoundDecoder *decoder);
|
void SoundDecoder_Free (TFB_SoundDecoder *decoder);
|
||||||
|
|||||||
@@ -0,0 +1,428 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* .duk sound track decoder
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "libs/misc.h"
|
||||||
|
#include "dukaud.h"
|
||||||
|
#include "decoder.h"
|
||||||
|
#include "endian_uqm.h"
|
||||||
|
|
||||||
|
#define DATA_BUF_SIZE 0x8000
|
||||||
|
#define DUCK_GENERAL_FPS 14.622f
|
||||||
|
|
||||||
|
static sint32 duka_error = 0;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32 audsize;
|
||||||
|
uint32 vidsize;
|
||||||
|
} DukAud_FrameHeader;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16 magic; // always 0xf77f
|
||||||
|
uint16 numsamples;
|
||||||
|
uint16 tag;
|
||||||
|
uint16 indices[2]; // initial indices for channels
|
||||||
|
} DukAud_AudSubframe;
|
||||||
|
|
||||||
|
sint32
|
||||||
|
duka_getError ()
|
||||||
|
{
|
||||||
|
sint32 ret = duka_error;
|
||||||
|
duka_error = dukae_None;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sint32
|
||||||
|
duka_readAudFrameHeader (DukAud_Track* track, 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)
|
||||||
|
{
|
||||||
|
duka_error = errno;
|
||||||
|
return dukae_BadFile;
|
||||||
|
}
|
||||||
|
hdr.audsize = UQM_SwapBE32 (hdr.audsize);
|
||||||
|
|
||||||
|
if (uio_fread (aud, sizeof(*aud), 1, track->duk) != 1)
|
||||||
|
{
|
||||||
|
duka_error = errno;
|
||||||
|
return dukae_BadFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
aud->magic = UQM_SwapBE16 (aud->magic);
|
||||||
|
if (aud->magic != 0xf77f)
|
||||||
|
return duka_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]);
|
||||||
|
|
||||||
|
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] = {
|
||||||
|
0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xF,
|
||||||
|
0x10, 0x12, 0x13, 0x15, 0x17, 0x1A, 0x1C, 0x1F,
|
||||||
|
0x22, 0x26, 0x29, 0x2E, 0x32, 0x37, 0x3D, 0x43,
|
||||||
|
0x4A, 0x51, 0x59, 0x62, 0x6C, 0x76, 0x82, 0x8F,
|
||||||
|
0x9E, 0xAD, 0xBF, 0xD2, 0xE7, 0xFE, 0x117, 0x133,
|
||||||
|
0x152, 0x174, 0x199, 0x1C2, 0x1EF, 0x220, 0x256, 0x292,
|
||||||
|
0x2D4, 0x31D, 0x36C, 0x3C4, 0x424, 0x48E, 0x503, 0x583,
|
||||||
|
0x610, 0x6AC, 0x756, 0x812, 0x8E1, 0x9C4, 0xABE, 0xBD1,
|
||||||
|
0xCFF, 0xE4C, 0xFBA, 0x114D, 0x1308, 0x14EF, 0x1707, 0x1954,
|
||||||
|
0x1BDD, 0x1EA6, 0x21B7, 0x2516,
|
||||||
|
0x28CB, 0x2CDF, 0x315C, 0x364C,
|
||||||
|
0x3BBA, 0x41B2, 0x4844, 0x4F7E,
|
||||||
|
0x5771, 0x6030, 0x69CE, 0x7463,
|
||||||
|
0x7FFF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// *** BEGIN part copied from MPlayer ***
|
||||||
|
// (some little changes)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// pertinent tables for IMA ADPCM
|
||||||
|
static int adpcm_step[89] = {
|
||||||
|
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||||
|
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||||
|
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||||
|
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||||
|
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||||
|
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||||
|
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||||
|
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||||
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int adpcm_index[16] = {
|
||||||
|
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||||
|
-1, -1, -1, -1, 2, 4, 6, 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// clamp a number between 0 and 88
|
||||||
|
#define CLAMP_0_TO_88(x) \
|
||||||
|
if ((x) < 0) (x) = 0; else if ((x) > 88) (x) = 88;
|
||||||
|
|
||||||
|
// clamp a number within a signed 16-bit range
|
||||||
|
#define CLAMP_S16(x) \
|
||||||
|
if ((x) < -32768) \
|
||||||
|
(x) = -32768; \
|
||||||
|
else if ((x) > 32767) \
|
||||||
|
(x) = 32767;
|
||||||
|
|
||||||
|
static void
|
||||||
|
decode_nibbles (sint16 *output, sint32 output_size, sint32 channels,
|
||||||
|
sint32* predictors, uint16* indices)
|
||||||
|
{
|
||||||
|
sint32 step[2];
|
||||||
|
sint32 index[2];
|
||||||
|
sint32 diff;
|
||||||
|
sint32 i;
|
||||||
|
int sign;
|
||||||
|
sint32 delta;
|
||||||
|
int channel_number = 0;
|
||||||
|
|
||||||
|
channels -= 1;
|
||||||
|
index[0] = indices[0];
|
||||||
|
index[1] = indices[1];
|
||||||
|
step[0] = adpcm_step[index[0]];
|
||||||
|
step[1] = adpcm_step[index[1]];
|
||||||
|
|
||||||
|
for (i = 0; i < output_size; i++)
|
||||||
|
{
|
||||||
|
delta = output[i];
|
||||||
|
|
||||||
|
index[channel_number] += adpcm_index[delta];
|
||||||
|
CLAMP_0_TO_88(index[channel_number]);
|
||||||
|
|
||||||
|
sign = delta & 8;
|
||||||
|
delta = delta & 7;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// fast approximation, used in most decoders
|
||||||
|
diff = step[channel_number] >> 3;
|
||||||
|
if (delta & 4) diff += step[channel_number];
|
||||||
|
if (delta & 2) diff += step[channel_number] >> 1;
|
||||||
|
if (delta & 1) diff += step[channel_number] >> 2;
|
||||||
|
#else
|
||||||
|
// real thing
|
||||||
|
// diff = ((signed)delta + 0.5) * step[channel_number] / 4;
|
||||||
|
diff = (((delta << 1) + 1) * step[channel_number]) >> 3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
predictors[channel_number] -= diff;
|
||||||
|
else
|
||||||
|
predictors[channel_number] += diff;
|
||||||
|
|
||||||
|
CLAMP_S16(predictors[channel_number]);
|
||||||
|
output[i] = predictors[channel_number];
|
||||||
|
step[channel_number] = adpcm_step[index[channel_number]];
|
||||||
|
|
||||||
|
// toggle channel
|
||||||
|
channel_number ^= channels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// *** END part copied from MPlayer ***
|
||||||
|
|
||||||
|
sint32
|
||||||
|
duka_decodeFrame (DukAud_Track* track, DukAud_AudSubframe* header,
|
||||||
|
uint8* input)
|
||||||
|
{
|
||||||
|
uint8* inend;
|
||||||
|
sint16* output;
|
||||||
|
sint16* outptr;
|
||||||
|
sint32 outputsize;
|
||||||
|
|
||||||
|
outputsize = header->numsamples * 2 * sizeof (sint16);
|
||||||
|
outptr = output = (sint16*) ((uint8*)track->data + track->cbdata);
|
||||||
|
|
||||||
|
for (inend = input + header->numsamples; input < inend; ++input)
|
||||||
|
{
|
||||||
|
*(outptr++) = *input >> 4;
|
||||||
|
*(outptr++) = *input & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_nibbles (output, header->numsamples * 2, track->channels,
|
||||||
|
track->predictors, header->indices);
|
||||||
|
|
||||||
|
track->cbdata += outputsize;
|
||||||
|
|
||||||
|
return outputsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sint32
|
||||||
|
duka_readNextFrame (DukAud_Track* track)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
duka_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)
|
||||||
|
{
|
||||||
|
duka_error = errno;
|
||||||
|
return dukae_BadFile;
|
||||||
|
}
|
||||||
|
aud = (DukAud_AudSubframe*) p;
|
||||||
|
p += sizeof(DukAud_AudSubframe);
|
||||||
|
|
||||||
|
aud->magic = UQM_SwapBE16 (aud->magic);
|
||||||
|
if (aud->magic != 0xf77f)
|
||||||
|
return duka_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++;
|
||||||
|
|
||||||
|
return duka_decodeFrame (track, aud, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sint32
|
||||||
|
duka_stuffBuffer (DukAud_Track* track, void* buf, sint32 bufsize)
|
||||||
|
{
|
||||||
|
sint32 dataleft;
|
||||||
|
|
||||||
|
dataleft = track->cbdata - track->dataofs;
|
||||||
|
if (dataleft > 0)
|
||||||
|
{
|
||||||
|
if (dataleft > bufsize)
|
||||||
|
dataleft = bufsize & (-4);
|
||||||
|
memcpy (buf, (uint8*)track->data + track->dataofs, dataleft);
|
||||||
|
track->dataofs += dataleft;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track->cbdata > 0 && track->dataofs >= track->cbdata)
|
||||||
|
track->cbdata = track->dataofs = 0; // reset for new data
|
||||||
|
|
||||||
|
return dataleft;
|
||||||
|
}
|
||||||
|
|
||||||
|
sint32
|
||||||
|
duka_readData (DukAud_Track* track, void* buf, sint32 bufsize)
|
||||||
|
{
|
||||||
|
sint32 stuffed;
|
||||||
|
sint32 total = 0;
|
||||||
|
|
||||||
|
if (bufsize <= 0)
|
||||||
|
return duka_error = dukae_BadArg;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
stuffed = duka_stuffBuffer (track, buf, bufsize);
|
||||||
|
((uint8*)buf) += stuffed;
|
||||||
|
bufsize -= stuffed;
|
||||||
|
total += stuffed;
|
||||||
|
|
||||||
|
if (bufsize > 0 && track->iframe < track->cframes)
|
||||||
|
{
|
||||||
|
stuffed = duka_readNextFrame (track);
|
||||||
|
if (stuffed <= 0)
|
||||||
|
return stuffed;
|
||||||
|
}
|
||||||
|
} while (bufsize > 0 && track->iframe < track->cframes);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
duka_getFrame (DukAud_Track* track)
|
||||||
|
{
|
||||||
|
// if there is nothing buffered return the actual current frame
|
||||||
|
// otherwise return previous
|
||||||
|
return track->dataofs == track->cbdata ?
|
||||||
|
track->iframe : track->iframe - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
duka_getFrameSize (DukAud_Track* track)
|
||||||
|
{
|
||||||
|
return track->pcm_frame * track->channels * sizeof (uint16);
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* .duk sound track decoder */
|
||||||
|
|
||||||
|
#ifndef DUKAUD_H
|
||||||
|
#define DUKAUD_H
|
||||||
|
|
||||||
|
#include "port.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "uio.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;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
// positive values are the same as in errno
|
||||||
|
dukae_None = 0,
|
||||||
|
dukae_Unknown = -1,
|
||||||
|
dukae_BadFile = -2,
|
||||||
|
dukae_BadArg = -3,
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user