vgmstream/src/meta/ktac.c
2022-03-20 13:53:13 +01:00

79 lines
2.7 KiB
C

#include "meta.h"
#include "../coding/coding.h"
typedef struct {
int loop_flag;
int32_t loop_start;
int32_t loop_end;
uint32_t file_size;
#ifdef VGM_USE_FFMPEG
mp4_custom_t mp4;
#endif
int type;
} ktac_header_t;
/* KTAC - Koei Tecmo custom AAC [Kin'iro no Corda 3 (Vita), Shingeki no Kyojin: Shichi kara no Dasshutsu (3DS), Dynasty Warriors (PS4)] */
VGMSTREAM* init_vgmstream_ktac(STREAMFILE* sf) {
#ifdef VGM_USE_FFMPEG
VGMSTREAM* vgmstream = NULL;
ktac_header_t ktac = {0};
/* checks */
/* .ktac: header id */
if (!check_extensions(sf,"ktac"))
goto fail;
if (!is_id32be(0x00,sf, "KTAC"))
goto fail;
/* 0x04: version? (always 1) */
ktac.file_size = read_u32le(0x08,sf);
if (ktac.file_size != get_streamfile_size(sf))
goto fail;
ktac.mp4.stream_offset = read_u32le(0x0c,sf);
ktac.mp4.stream_size = read_u32le(0x10,sf);
ktac.type = read_u32le(0x14,sf);
ktac.mp4.sample_rate = read_u32le(0x18,sf);
ktac.mp4.num_samples = read_u32le(0x1c,sf); /* full samples */
ktac.mp4.channels = read_u16le(0x20,sf);
ktac.mp4.frame_samples = read_u16le(0x22,sf);
ktac.mp4.encoder_delay = read_u16le(0x24,sf);
ktac.mp4.end_padding = read_u16le(0x26,sf);
ktac.loop_start = read_u32le(0x28,sf);
ktac.loop_end = read_u32le(0x2c,sf);
/* 0x30: ? (big, related to loops) */
/* 0x34: ? (always null) */
ktac.mp4.table_offset = read_u32le(0x38,sf);
ktac.mp4.table_entries = read_u32le(0x3c,sf);
ktac.loop_flag = (ktac.loop_end > 0);
/* type 1 files crash during sample_copy, wrong fake header/esds?
* (0=AoT, KnC3 bgm, 1=KnC3 1ch voices, 2=DW4, Atelier Ryza) */
if (ktac.type == 1)
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ktac.mp4.channels, ktac.loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_KTAC;
vgmstream->sample_rate = ktac.mp4.sample_rate;
vgmstream->num_samples = ktac.mp4.num_samples - ktac.mp4.encoder_delay - ktac.mp4.end_padding;
vgmstream->loop_start_sample = ktac.loop_start * ktac.mp4.frame_samples - ktac.mp4.encoder_delay;
vgmstream->loop_end_sample = ktac.loop_end * ktac.mp4.frame_samples - ktac.mp4.encoder_delay;
/* KTAC uses AAC, but not type found in .aac (that has headered frames, like mp3) but raw
* packets + frame size table (similar to .mp4/m4a). We set config for FFmpeg's fake M4A header */
vgmstream->codec_data = init_ffmpeg_mp4_custom_std(sf, &ktac.mp4);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
return vgmstream;
fail:
close_vgmstream(vgmstream);
#endif
return NULL;
}