Wave decoder cleanup

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2707 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2007-02-15 20:44:00 +00:00
parent 76c277f01b
commit 4c1de2ed14
+103 -86
View File
@@ -28,33 +28,36 @@
#include "libs/log.h" #include "libs/log.h"
#include "wav.h" #include "wav.h"
#define RIFF 0x46464952 /* "RIFF" */ #define wave_MAKE_ID(x1, x2, x3, x4) \
#define WAVE 0x45564157 /* "WAVE" */ (((x4) << 24) | ((x3) << 16) | ((x2) << 8) | (x1))
#define FMT 0x20746D66 /* "fmt " */
#define DATA 0x61746164 /* "data" */ #define wave_RiffID wave_MAKE_ID('R', 'I', 'F', 'F')
#define wave_WaveID wave_MAKE_ID('W', 'A', 'V', 'E')
#define wave_FmtID wave_MAKE_ID('f', 'm', 't', ' ')
#define wave_DataID wave_MAKE_ID('d', 'a', 't', 'a')
typedef struct typedef struct
{ {
uint32 Id; uint32 id;
sint32 Size; sint32 size;
uint32 Type; uint32 type;
} WAVFileHdr_Struct; } wave_FileHeader;
typedef struct typedef struct
{ {
uint16 Format; uint16 format;
uint16 Channels; uint16 channels;
uint32 SamplesPerSec; uint32 samplesPerSec;
uint32 BytesPerSec; uint32 bytesPerSec;
uint16 BlockAlign; uint16 blockAlign;
uint16 BitsPerSample; uint16 bitsPerSample;
} WAVFmtHdr_Struct; } wave_FormatHeader;
typedef struct typedef struct
{ {
uint32 Id; uint32 id;
uint32 Size; uint32 size;
} WAVChunkHdr_Struct; } wave_ChunkHeader;
#define THIS_PTR TFB_SoundDecoder* This #define THIS_PTR TFB_SoundDecoder* This
@@ -96,7 +99,7 @@ typedef struct tfb_wavesounddecoder
// private // private
sint32 last_error; sint32 last_error;
uio_Stream *fp; uio_Stream *fp;
WAVFmtHdr_Struct FmtHdr; wave_FormatHeader fmtHdr;
uint32 data_ofs; uint32 data_ofs;
uint32 data_size; uint32 data_size;
uint32 max_pcm; uint32 max_pcm;
@@ -159,53 +162,61 @@ wava_Term (THIS_PTR)
} }
static bool static bool
wava_readFileHeader (TFB_WaveSoundDecoder* wava, WAVFileHdr_Struct* hdr) read_le_16 (uio_Stream *fp, uint16 *v)
{ {
if (!uio_fread (&hdr->Id, 4, 1, wava->fp) || if (!uio_fread (v, sizeof(*v), 1, fp))
!uio_fread (&hdr->Size, 4, 1, wava->fp) || return false;
!uio_fread (&hdr->Type, 4, 1, wava->fp)) *v = UQM_SwapLE16 (*v);
return true;
}
static bool
read_le_32 (uio_Stream *fp, uint32 *v)
{
if (!uio_fread (v, sizeof(*v), 1, fp))
return false;
*v = UQM_SwapLE32 (*v);
return true;
}
static bool
wava_readFileHeader (TFB_WaveSoundDecoder* wava, wave_FileHeader* hdr)
{
if (!read_le_32 (wava->fp, &hdr->id) ||
!read_le_32 (wava->fp, &hdr->size) ||
!read_le_32 (wava->fp, &hdr->type))
{ {
wava->last_error = errno; wava->last_error = errno;
return false; return false;
} }
hdr->Id = UQM_SwapLE32 (hdr->Id);
hdr->Size = UQM_SwapLE32 (hdr->Size);
hdr->Type = UQM_SwapLE32 (hdr->Type);
return true; return true;
} }
static bool static bool
wava_readChunkHeader (TFB_WaveSoundDecoder* wava, WAVChunkHdr_Struct* chunk) wava_readChunkHeader (TFB_WaveSoundDecoder* wava, wave_ChunkHeader* chunk)
{ {
if (!uio_fread (&chunk->Id, 4, 1, wava->fp) || if (!read_le_32 (wava->fp, &chunk->id) ||
!uio_fread (&chunk->Size, 4, 1, wava->fp)) !read_le_32 (wava->fp, &chunk->size))
{
wava->last_error = errno;
return false; return false;
}
chunk->Id = UQM_SwapLE32 (chunk->Id);
chunk->Size = UQM_SwapLE32 (chunk->Size);
return true; return true;
} }
static bool static bool
wava_readFormatHeader (TFB_WaveSoundDecoder* wava, WAVFmtHdr_Struct* fmt) wava_readFormatHeader (TFB_WaveSoundDecoder* wava, wave_FormatHeader* fmt)
{ {
if (!uio_fread (&fmt->Format, 2, 1, wava->fp) || if (!read_le_16 (wava->fp, &fmt->format) ||
!uio_fread (&fmt->Channels, 2, 1, wava->fp) || !read_le_16 (wava->fp, &fmt->channels) ||
!uio_fread (&fmt->SamplesPerSec, 4, 1, wava->fp) || !read_le_32 (wava->fp, &fmt->samplesPerSec) ||
!uio_fread (&fmt->BytesPerSec, 4, 1, wava->fp) || !read_le_32 (wava->fp, &fmt->bytesPerSec) ||
!uio_fread (&fmt->BlockAlign, 2, 1, wava->fp) || !read_le_16 (wava->fp, &fmt->blockAlign) ||
!uio_fread (&fmt->BitsPerSample, 2, 1, wava->fp)) !read_le_16 (wava->fp, &fmt->bitsPerSample))
{
wava->last_error = errno;
return false; 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; return true;
} }
@@ -213,8 +224,8 @@ static bool
wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename) wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename)
{ {
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This; TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
WAVFileHdr_Struct FileHdr; wave_FileHeader fileHdr;
WAVChunkHdr_Struct ChunkHdr; wave_ChunkHeader chunkHdr;
wava->fp = uio_fopen (dir, filename, "rb"); wava->fp = uio_fopen (dir, filename, "rb");
if (!wava->fp) if (!wava->fp)
@@ -227,52 +238,53 @@ wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename)
wava->data_ofs = 0; wava->data_ofs = 0;
// read wave header // read wave header
if (!wava_readFileHeader (wava, &FileHdr)) if (!wava_readFileHeader (wava, &fileHdr))
{ {
wava->last_error = errno; wava->last_error = errno;
wava_Close (This); wava_Close (This);
return false; return false;
} }
if (FileHdr.Id != RIFF || FileHdr.Type != WAVE) if (fileHdr.id != wave_RiffID || fileHdr.type != wave_WaveID)
{ {
log_add (log_Warning, "wava_Open(): " log_add (log_Warning, "wava_Open(): "
"not a wave file, ID 0x%08x, Type 0x%08x", "not a wave file, ID 0x%08x, Type 0x%08x",
FileHdr.Id, FileHdr.Type); fileHdr.id, fileHdr.type);
wava_Close (This); wava_Close (This);
return false; return false;
} }
for (FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4; FileHdr.Size != 0; for (fileHdr.size = ((fileHdr.size + 1) & ~1) - 4; fileHdr.size != 0;
FileHdr.Size -= (((ChunkHdr.Size + 1) & ~1) + 8)) fileHdr.size -= (((chunkHdr.size + 1) & ~1) + 8))
{ {
if (!wava_readChunkHeader (wava, &ChunkHdr)) if (!wava_readChunkHeader (wava, &chunkHdr))
{ {
wava->last_error = errno;
wava_Close (This); wava_Close (This);
return false; return false;
} }
if (ChunkHdr.Id == FMT) if (chunkHdr.id == wave_FmtID)
{ {
if (!wava_readFormatHeader (wava, &wava->FmtHdr)) if (!wava_readFormatHeader (wava, &wava->fmtHdr))
{ {
wava->last_error = errno;
wava_Close (This); wava_Close (This);
return false; return false;
} }
uio_fseek (wava->fp, ChunkHdr.Size - 16, SEEK_CUR); uio_fseek (wava->fp, chunkHdr.size - 16, SEEK_CUR);
} }
else else
{ {
if (ChunkHdr.Id == DATA) if (chunkHdr.id == wave_DataID)
{ {
wava->data_size = ChunkHdr.Size; wava->data_size = chunkHdr.size;
wava->data_ofs = uio_ftell (wava->fp); wava->data_ofs = uio_ftell (wava->fp);
} }
uio_fseek (wava->fp, ChunkHdr.Size, SEEK_CUR); uio_fseek (wava->fp, chunkHdr.size, SEEK_CUR);
} }
uio_fseek (wava->fp, ChunkHdr.Size & 1, SEEK_CUR); // 2-align the file ptr
// XXX: I do not think this is necessary in WAVE files;
// possibly a remnant of ported AIFF reader
uio_fseek (wava->fp, chunkHdr.size & 1, SEEK_CUR);
} }
if (!wava->data_size || !wava->data_ofs) if (!wava->data_size || !wava->data_ofs)
@@ -283,29 +295,34 @@ wava_Open (THIS_PTR, uio_DirHandle *dir, const char *filename)
return false; return false;
} }
if (wava->FmtHdr.Format == 0x0001) if (wava->fmtHdr.format != 0x0001)
{ { // not a PCM format
This->format = (wava->FmtHdr.Channels == 1 ?
(wava->FmtHdr.BitsPerSample == 8 ?
wava_formats->mono8 : wava_formats->mono16)
:
(wava->FmtHdr.BitsPerSample == 8 ?
wava_formats->stereo8 : wava_formats->stereo16)
);
This->frequency = wava->FmtHdr.SamplesPerSec;
}
else
{
log_add (log_Warning, "wava_Open(): unsupported format %x", log_add (log_Warning, "wava_Open(): unsupported format %x",
wava->FmtHdr.Format); wava->fmtHdr.format);
wava_Close (This);
return false;
}
if (wava->fmtHdr.channels != 1 && wava->fmtHdr.channels != 2)
{
log_add (log_Warning, "wava_Open(): unsupported number of channels %u",
(unsigned)wava->fmtHdr.channels);
wava_Close (This); wava_Close (This);
return false; return false;
} }
This->format = (wava->fmtHdr.channels == 1 ?
(wava->fmtHdr.bitsPerSample == 8 ?
wava_formats->mono8 : wava_formats->mono16)
:
(wava->fmtHdr.bitsPerSample == 8 ?
wava_formats->stereo8 : wava_formats->stereo16)
);
This->frequency = wava->fmtHdr.samplesPerSec;
uio_fseek (wava->fp, wava->data_ofs, SEEK_SET); uio_fseek (wava->fp, wava->data_ofs, SEEK_SET);
wava->max_pcm = wava->data_size / wava->FmtHdr.BlockAlign; wava->max_pcm = wava->data_size / wava->fmtHdr.blockAlign;
wava->cur_pcm = 0; wava->cur_pcm = 0;
This->length = (float) wava->max_pcm / wava->FmtHdr.SamplesPerSec; This->length = (float) wava->max_pcm / wava->fmtHdr.samplesPerSec;
wava->last_error = 0; wava->last_error = 0;
return true; return true;
@@ -329,14 +346,14 @@ wava_Decode (THIS_PTR, void* buf, sint32 bufsize)
TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This; TFB_WaveSoundDecoder* wava = (TFB_WaveSoundDecoder*) This;
uint32 dec_pcm; uint32 dec_pcm;
dec_pcm = bufsize / wava->FmtHdr.BlockAlign; dec_pcm = bufsize / wava->fmtHdr.blockAlign;
if (dec_pcm > wava->max_pcm - wava->cur_pcm) if (dec_pcm > wava->max_pcm - wava->cur_pcm)
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); dec_pcm = uio_fread (buf, wava->fmtHdr.blockAlign, dec_pcm, wava->fp);
wava->cur_pcm += dec_pcm; wava->cur_pcm += dec_pcm;
return dec_pcm * wava->FmtHdr.BlockAlign; return dec_pcm * wava->fmtHdr.blockAlign;
} }
static uint32 static uint32
@@ -348,7 +365,7 @@ wava_Seek (THIS_PTR, uint32 pcm_pos)
pcm_pos = wava->max_pcm; pcm_pos = wava->max_pcm;
wava->cur_pcm = pcm_pos; wava->cur_pcm = pcm_pos;
uio_fseek (wava->fp, uio_fseek (wava->fp,
wava->data_ofs + pcm_pos * wava->FmtHdr.BlockAlign, wava->data_ofs + pcm_pos * wava->fmtHdr.blockAlign,
SEEK_SET); SEEK_SET);
return pcm_pos; return pcm_pos;