Add HALPST (.hps), unify blocked layouts.

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@38 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2008-03-04 07:15:25 +00:00
parent 147cba7952
commit f2a9f60807
14 changed files with 277 additions and 47 deletions

View File

@ -22,10 +22,11 @@ Formats supported by this version of vgmstream ($Revision$):
- .brstm (RSTM: GC/Wii DSP ADPCM, 8/16 bit PCM)
- .strm (STRM: NDS IMA ADPCM, 8/16 bit PCM)
- .adp (GC DTK ADPCM)
- .agsc (GC ADPCM)
- .agsc (GC DSP ADPCM)
- .rsf (CCITT G.721 ADPCM)
- .afc (GC AFC ADPCM)
- .ast (GC/Wii AFC ADPCM, 16 bit PCM)
- .hps (GC DSP ADPCM)
Enjoy!
-hcs

View File

@ -35,3 +35,19 @@ void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
stream->adpcm_history1_16 = hist1;
stream->adpcm_history2_16 = hist2;
}
/*
* The original DSP spec uses nibble counts for loop points, and some
* variants don't have a proper sample count, so all we (who are interested
* in sample counts) need to do this conversion occasionally.
*/
int32_t dsp_nibbles_to_samples(int32_t nibbles) {
int32_t whole_frames = nibbles/16;
int32_t remainder = nibbles%16;
if (remainder > 0 && remainder < 14)
return whole_frames*14 + remainder;
else if (remainder >= 14)
fprintf(stderr,"last frame %d leftover nibbles makes no sense\n",remainder);
return whole_frames*14;
}

View File

@ -5,4 +5,6 @@
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
int32_t dsp_nibbles_to_samples(int32_t nibbles);
#endif

View File

@ -16,41 +16,3 @@ void ast_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
0x20 + vgmstream->current_block_size*i;
}
}
void render_vgmstream_ast_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
int frame_size = get_vgmstream_frame_size(vgmstream);
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
int samples_this_block;
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
while (samples_written<sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
if (vgmstream->samples_into_block==samples_this_block) {
ast_block_update(vgmstream->next_block_offset,vgmstream);
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
vgmstream->samples_into_block=0;
}
}
}

View File

@ -7,8 +7,6 @@
#ifndef _AST_BLOCKED_H
#define _AST_BLOCKED_H
void render_vgmstream_ast_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
#endif

61
src/layout/blocked.c Normal file
View File

@ -0,0 +1,61 @@
#include "ast_blocked.h"
#include "halpst_blocked.h"
#include "../vgmstream.h"
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
int frame_size = get_vgmstream_frame_size(vgmstream);
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
int samples_this_block;
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
while (samples_written<sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
if (vgmstream->current_block_offset>=0)
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
else {
int i;
/* we've run off the end! */
for (i=samples_written*vgmstream->channels;
i<(samples_written+samples_to_do)*vgmstream->channels;i++)
buffer[i]=0;
}
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
if (vgmstream->samples_into_block==samples_this_block) {
switch (vgmstream->layout_type) {
case layout_ast_blocked:
ast_block_update(vgmstream->next_block_offset,vgmstream);
break;
case layout_halpst_blocked:
if (vgmstream->next_block_offset>=0)
halpst_block_update(vgmstream->next_block_offset,vgmstream);
else
vgmstream->current_block_offset=-1;
break;
default:
break;
}
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
vgmstream->samples_into_block=0;
}
}
}

12
src/layout/blocked.h Normal file
View File

@ -0,0 +1,12 @@
/*
* blocked.h - blocking
*/
#include "../streamtypes.h"
#include "../vgmstream.h"
#ifndef _BLOCKED_H
#define _BLOCKED_H
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
#endif

View File

@ -0,0 +1,19 @@
#include "halpst_blocked.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void halpst_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitBE(
vgmstream->current_block_offset,
vgmstream->ch[0].streamfile)/vgmstream->channels;
vgmstream->next_block_offset = read_32bitBE(
vgmstream->current_block_offset+8,
vgmstream->ch[0].streamfile);
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset +
0x20 + vgmstream->current_block_size*i;
}
}

View File

@ -0,0 +1,12 @@
/*
* halpst_blocked.h - HALPST blocking
*/
#include "../streamtypes.h"
#include "../vgmstream.h"
#ifndef _HALPST_BLOCKED_H
#define _HALPST_BLOCKED_H
void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
#endif

130
src/meta/halpst.c Normal file
View File

@ -0,0 +1,130 @@
#include "halpst.h"
#include "../coding/ngc_dsp_decoder.h"
#include "../layout/halpst_blocked.h"
#include "../util.h"
VGMSTREAM * init_vgmstream_halpst(const char * const filename) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * infile = NULL;
int channel_count;
int loop_flag = 0;
int32_t samples_l,samples_r;
int32_t start_sample = 0;
size_t max_block;
/* check extension, case insensitive */
if (strcasecmp("hps",filename_extension(filename))) goto fail;
/* try to open the file for header reading */
infile = open_streamfile_buffer(filename,0x20);
if (!infile) goto fail;
/* check header */
if ((uint32_t)read_32bitBE(0,infile)!=0x2048414C || /* " HAL" */
read_32bitBE(4,infile)!=0x50535400) /* "PST\0" */
goto fail;
/* details */
channel_count = read_32bitBE(0xc,infile);
max_block = read_32bitBE(0x10,infile);
/* have I ever seen a mono .hps? */
if (channel_count!=2) goto fail;
/* yay for redundancy, gives us something to test */
samples_l = dsp_nibbles_to_samples(read_32bitBE(0x18,infile));
samples_r = dsp_nibbles_to_samples(read_32bitBE(0x50,infile));
if (samples_l != samples_r) goto fail;
/*
* looping info is implicit in the "next block" field of the final
* block, so we have to find that
*/
{
off_t offset = 0x80, last_offset = 0;
off_t loop_offset;
/* determine if there is a loop */
while (offset > last_offset) {
last_offset = offset;
offset = read_32bitBE(offset+8,infile);
}
if (offset < 0) loop_flag = 0;
else {
/* one more pass to determine start sample */
int32_t start_nibble = 0;
loop_flag = 1;
loop_offset = offset;
offset = 0x80;
while (offset != loop_offset) {
start_nibble += read_32bitBE(offset,infile);
offset = read_32bitBE(offset+8,infile);
}
start_sample = dsp_nibbles_to_samples(start_nibble);
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = samples_l;
vgmstream->sample_rate = read_32bitBE(8,infile);
/* channels and loop flag are set by allocate_vgmstream */
if (loop_flag) {
vgmstream->loop_start_sample = start_sample;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_halpst_blocked;
vgmstream->meta_type = meta_HALPST;
/* load decode coefs */
{
int i;
for (i=0;i<16;i++)
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,infile);
for (i=0;i<16;i++)
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x58+i*2,infile);
}
close_streamfile(infile); infile=NULL;
/* open the file for reading by each channel */
{
int i;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = open_streamfile_buffer(filename,
(i==0?
max_block+0x20: /* first buffer a bit bigger to
read block header without
inefficiency */
max_block
)
);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}
/* start me up */
halpst_block_update(0x80,vgmstream);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (infile) close_streamfile(infile);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

8
src/meta/halpst.h Normal file
View File

@ -0,0 +1,8 @@
#include "../vgmstream.h"
#ifndef _HALPST_H
#define _HALPST_H
VGMSTREAM * init_vgmstream_halpst(const char * const filename);
#endif

View File

@ -7,9 +7,10 @@
#include "meta/rsf.h"
#include "meta/afc_header.h"
#include "meta/ast.h"
#include "meta/halpst.h"
#include "layout/interleave.h"
#include "layout/nolayout.h"
#include "layout/ast_blocked.h"
#include "layout/blocked.h"
#include "coding/adx_decoder.h"
#include "coding/ngc_dsp_decoder.h"
#include "coding/pcm_decoder.h"
@ -22,7 +23,7 @@
* List of functions that will recognize files. These should correspond pretty
* directly to the metadata types
*/
#define INIT_VGMSTREAM_FCNS 8
#define INIT_VGMSTREAM_FCNS 9
VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_adx,
init_vgmstream_brstm,
@ -32,6 +33,7 @@ VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_rsf,
init_vgmstream_afc,
init_vgmstream_ast,
init_vgmstream_halpst,
};
/* format detection and VGMSTREAM setup */
@ -131,7 +133,8 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
render_vgmstream_nolayout(buffer,sample_count,vgmstream);
break;
case layout_ast_blocked:
render_vgmstream_ast_blocked(buffer,sample_count,vgmstream);
case layout_halpst_blocked:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
}
}
@ -406,6 +409,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream) {
case layout_ast_blocked:
printf("AST blocked");
break;
case layout_halpst_blocked:
printf("HALPST blocked");
break;
default:
printf("INCONCEIVABLE");
}
@ -447,6 +453,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream) {
case meta_AST:
printf("AST header");
break;
case meta_HALPST:
printf("HALPST header");
break;
default:
printf("THEY SHOULD HAVE SENT A POET");
}

View File

@ -37,8 +37,8 @@ typedef enum {
#endif
/* headered blocks */
layout_ast_blocked, /* .ast STRM with BLCK blocks*/
layout_halpst_blocked, /* blocks with HALPST-format header */
#if 0
layout_halp_blocked, /* blocks with HALP-format header */
layout_strm_blocked, /* */
#endif
/* otherwise odd */
@ -66,7 +66,7 @@ typedef enum {
meta_NGC_ADPDTK, /* NGC DTK/ADP, no header (.adp) */
meta_kRAW, /* almost headerless PCM */
meta_RSF, /* Retro Studios RSF, no header (.rsf) */
meta_HALPST, /* HAL Labs HALPST */
} meta_t;
typedef struct {

View File

@ -1,7 +1,7 @@
SHELL = /bin/sh
CFLAGS=-lm -Wall -O3
VGMSTREAMFILES = ../src/streamfile.c ../src/vgmstream.c ../src/util.c ../src/meta/adx_header.c ../src/coding/adx_decoder.c ../src/coding/ngc_dsp_decoder.c ../src/meta/brstm.c ../src/layout/interleave.c ../src/layout/nolayout.c ../src/coding/pcm_decoder.c ../src/meta/nds_strm.c ../src/coding/ima_decoder.c ../src/meta/agsc.c ../src/meta/ngc_adpdtk.c ../src/coding/ngc_dtk_decoder.c ../src/coding/g721_decoder.c ../src/meta/rsf.c ../src/meta/afc_header.c ../src/coding/ngc_afc_decoder.c ../src/meta/ast.c ../src/layout/ast_blocked.c
VGMSTREAMFILES = ../src/streamfile.c ../src/vgmstream.c ../src/util.c ../src/meta/adx_header.c ../src/coding/adx_decoder.c ../src/coding/ngc_dsp_decoder.c ../src/meta/brstm.c ../src/layout/interleave.c ../src/layout/nolayout.c ../src/coding/pcm_decoder.c ../src/meta/nds_strm.c ../src/coding/ima_decoder.c ../src/meta/agsc.c ../src/meta/ngc_adpdtk.c ../src/coding/ngc_dtk_decoder.c ../src/coding/g721_decoder.c ../src/meta/rsf.c ../src/meta/afc_header.c ../src/coding/ngc_afc_decoder.c ../src/meta/ast.c ../src/layout/ast_blocked.c ../src/layout/halpst_blocked.c ../src/layout/blocked.c ../src/meta/halpst.c
test: test.c $(VGMSTREAMFILES)
gcc $(CFLAGS) test.c $(VGMSTREAMFILES) -o test