mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-14 23:52:53 +01:00
106 lines
3.7 KiB
C
106 lines
3.7 KiB
C
|
#include "meta.h"
|
||
|
#include "../layout/layout.h"
|
||
|
#include "../coding/coding.h"
|
||
|
|
||
|
/* H4M - from Hudson HVQM4 videos [Resident Evil 0 (GC), Tales of Symphonia (GC)]
|
||
|
* (info from hcs/Nisto's h4m_audio_decode) */
|
||
|
VGMSTREAM * init_vgmstream_h4m(STREAMFILE *streamFile) {
|
||
|
VGMSTREAM * vgmstream = NULL;
|
||
|
off_t start_offset;
|
||
|
int loop_flag, channel_count;
|
||
|
int format, extra_tracks, sample_rate;
|
||
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||
|
|
||
|
|
||
|
/* checks */
|
||
|
if (!check_extensions(streamFile, "h4m"))
|
||
|
goto fail;
|
||
|
|
||
|
if (read_32bitBE(0x00,streamFile) != 0x4856514D && /* "HVQM" */
|
||
|
read_32bitBE(0x04,streamFile) != 0x3420312E) /* "4 1." */
|
||
|
goto fail;
|
||
|
if (read_32bitBE(0x08,streamFile) != 0x33000000 && /* "3\0\0\0" */
|
||
|
read_32bitBE(0x08,streamFile) != 0x35000000) /* "5\0\0\0" */
|
||
|
goto fail;
|
||
|
|
||
|
/* header */
|
||
|
start_offset = read_32bitBE(0x10, streamFile); /* header_size */
|
||
|
if (start_offset != 0x44) /* known size */
|
||
|
goto fail;
|
||
|
if (read_32bitBE(0x14, streamFile) != get_streamfile_size(streamFile) - start_offset) /* body_size */
|
||
|
goto fail;
|
||
|
if (read_32bitBE(0x18, streamFile) == 0) /* blocks */
|
||
|
goto fail;
|
||
|
/* 0x1c: video_frames */
|
||
|
if (read_32bitBE(0x20, streamFile) == 0) /* audio_frames */
|
||
|
goto fail;
|
||
|
/* 0x24: frame interval */
|
||
|
/* 0x28: max_video_frame_size */
|
||
|
/* 0x2c: unk2C (0) */
|
||
|
if (read_32bitBE(0x30, streamFile) == 0) /* max_audio_frame_size */
|
||
|
goto fail;
|
||
|
/* 0x34: hres */
|
||
|
/* 0x36: vres */
|
||
|
/* 0x38: h_srate */
|
||
|
/* 0x39: v_srate */
|
||
|
/* 0x3a: unk3A (0 or 0x12) */
|
||
|
/* 0x3b: unk3B (0) */
|
||
|
channel_count = read_8bit(0x3c,streamFile);
|
||
|
if (read_8bit(0x3d,streamFile) != 16) /* bitdepth */ //todo Pikmin not working
|
||
|
goto fail;
|
||
|
format = read_8bit(0x3e,streamFile); /* flags? */
|
||
|
extra_tracks = read_8bit(0x3f,streamFile);
|
||
|
sample_rate = read_32bitBE(0x40,streamFile);
|
||
|
|
||
|
loop_flag = 0;
|
||
|
|
||
|
total_subsongs = extra_tracks + 1; /* tracks for languages [Pokemon Channel], or sometimes used to fake multichannel [Tales of Symphonia] */
|
||
|
if (target_subsong == 0) target_subsong = 1;
|
||
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||
|
|
||
|
|
||
|
/* build the VGMSTREAM */
|
||
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||
|
if (!vgmstream) goto fail;
|
||
|
|
||
|
vgmstream->sample_rate = sample_rate;
|
||
|
vgmstream->num_streams = total_subsongs;
|
||
|
vgmstream->stream_size = get_streamfile_size(streamFile) / total_subsongs; /* approx... */
|
||
|
vgmstream->codec_version = format; /* for blocks */
|
||
|
vgmstream->meta_type = meta_H4M;
|
||
|
vgmstream->layout_type = layout_blocked_h4m;
|
||
|
|
||
|
switch(format & 0x7F) {
|
||
|
case 0x00:
|
||
|
vgmstream->coding_type = coding_DVI_IMA; //todo H4M_IMA
|
||
|
break;
|
||
|
/* no games known to use this, h4m_audio_decode may decode them */
|
||
|
case 0x01: /* Uncompressed PCM */
|
||
|
case 0x04: /* 8-bit (A)DPCM */
|
||
|
default:
|
||
|
VGM_LOG("H4M: unknown codec %x\n", format);
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||
|
goto fail;
|
||
|
|
||
|
/* calc num_samples manually */
|
||
|
{
|
||
|
vgmstream->next_block_offset = start_offset;
|
||
|
do {
|
||
|
block_update_h4m(vgmstream->next_block_offset,vgmstream);
|
||
|
vgmstream->num_samples += vgmstream->current_block_samples;
|
||
|
}
|
||
|
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||
|
}
|
||
|
|
||
|
block_update_h4m(start_offset, vgmstream);
|
||
|
|
||
|
return vgmstream;
|
||
|
|
||
|
fail:
|
||
|
close_vgmstream(vgmstream);
|
||
|
return NULL;
|
||
|
}
|