Add tri-Ace Codec [Star Ocean 3 (PS2), Valkyrie Profile 2 (PS2)]

This commit is contained in:
bnnm 2021-02-16 23:14:07 +01:00
parent da3fdae397
commit 18ae83d656
15 changed files with 3006 additions and 33 deletions

View File

@ -317,6 +317,16 @@ clHCA_stInfo* hca_get_info(hca_codec_data* data);
STREAMFILE* hca_get_streamfile(hca_codec_data* data);
/* tac_decoder */
typedef struct tac_codec_data tac_codec_data;
tac_codec_data* init_tac(STREAMFILE* sf);
void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_tac(tac_codec_data* data);
void seek_tac(tac_codec_data* data, int32_t num_sample);
void free_tac(tac_codec_data* data);
#ifdef VGM_USE_VORBIS
/* ogg_vorbis_decoder */
typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;

185
src/coding/tac_decoder.c Normal file
View File

@ -0,0 +1,185 @@
#include "coding.h"
#include "coding_utils_samples.h"
#include "tac_decoder_lib.h"
/* opaque struct */
struct tac_codec_data {
/* config */
int channels;
int samples_discard;
int encoder_delay;
uint8_t buf[TAC_BLOCK_SIZE];
int read_block;
off_t offset;
int16_t* samples;
int frame_samples;
/* frame state */
s16buf_t sbuf;
void* handle;
};
/* raw SPEEX */
tac_codec_data* init_tac(STREAMFILE* sf) {
tac_codec_data* data = NULL;
int bytes;
data = calloc(1, sizeof(tac_codec_data));
if (!data) goto fail;
bytes = read_streamfile(data->buf, 0x00, sizeof(data->buf), sf);
data->handle = tac_init(data->buf, bytes);
if (!data->handle) goto fail;
data->read_block = 0; /* ok to use current block */
data->offset = bytes;
data->channels = TAC_CHANNELS;
data->frame_samples = TAC_FRAME_SAMPLES;
data->encoder_delay = 0;
data->samples_discard = data->encoder_delay;
data->samples = malloc(data->channels * data->frame_samples * sizeof(int16_t));
if (!data->samples) goto fail;
return data;
fail:
free_tac(data);
return NULL;
}
static int decode_frame(tac_codec_data* data) {
int err;
data->sbuf.samples = data->samples;
data->sbuf.channels = 2;
data->sbuf.filled = 0;
err = tac_decode_frame(data->handle, data->buf);
if (err == TAC_PROCESS_NEXT_BLOCK) {
data->read_block = 1;
return 1;
}
if (err == TAC_PROCESS_DONE) {
goto fail; /* shouldn't reach this */
}
if (err != TAC_PROCESS_OK) {
goto fail;
}
tac_get_samples_pcm16(data->handle, data->sbuf.samples);
data->sbuf.filled = data->frame_samples;
return 1;
fail:
return 0;
}
static int read_frame(tac_codec_data* data, STREAMFILE* sf) {
/* new block must be read only when signaled by lib */
if (data->read_block) {
int bytes = read_streamfile(data->buf, data->offset, sizeof(data->buf), sf);
data->offset += bytes;
data->read_block = 0;
if (bytes <= 0) goto fail; /* can read less that buf near EOF */
}
return 1;
fail:
return 0;
}
void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
tac_codec_data* data = vgmstream->codec_data;
int ok;
while (samples_to_do > 0) {
s16buf_t* sbuf = &data->sbuf;
if (sbuf->filled <= 0) {
ok = read_frame(data, stream->streamfile);
if (!ok) goto fail;
ok = decode_frame(data);
if (!ok) goto fail;
}
if (data->samples_discard)
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
}
return;
fail:
/* on error just put some 0 samples */
VGM_LOG("TAC: decode fail at %x, missing %i samples\n", (uint32_t)data->offset, samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, data->channels);
}
void reset_tac(tac_codec_data* data) {
if (!data) return;
tac_reset(data->handle);
data->read_block = 1;
data->sbuf.filled = 0;
data->samples_discard = data->encoder_delay;
return;
}
void seek_tac(tac_codec_data* data, int32_t num_sample) {
int32_t loop_sample;
const tac_header_t* hdr;
if (!data)
return;
hdr = tac_get_header(data->handle);
loop_sample = hdr->loop_frame * TAC_FRAME_SAMPLES + hdr->loop_discard;
if (loop_sample == num_sample) {
/* simulates original looping (that wouldn't clean codec internals) */
tac_set_loop(data->handle);
data->samples_discard = hdr->loop_discard;
data->offset = hdr->loop_offset;
data->read_block = 1;
data->sbuf.filled = 0;
}
else {
tac_reset(data->handle);
data->samples_discard = num_sample;
data->offset = 0;
data->read_block = 1;
data->sbuf.filled = 0;
}
}
void free_tac(tac_codec_data* data) {
if (!data)
return;
tac_free(data->handle);
free(data->samples);
free(data);
}

1225
src/coding/tac_decoder_lib.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
#ifndef _TAC_DECODER_LIB_H_
#define _TAC_DECODER_LIB_H_
/* tri-Ace Codec (TAC) lib, found in PS2 games */
#include <stdint.h>
#define TAC_SAMPLE_RATE 48000
#define TAC_CHANNELS 2
#define TAC_FRAME_SAMPLES 1024
#define TAC_BLOCK_SIZE 0x4E000 /* size of a single block with N VBR frames */
#define TAC_PROCESS_OK 0 /* frame decoded correctly */
#define TAC_PROCESS_NEXT_BLOCK 1 /* must pass next block (didn't decode) */
#define TAC_PROCESS_DONE 2 /* no more frames to do (didn't decode) */
#define TAC_PROCESS_HEADER_ERROR -1 /* file doesn't match expected header */
#define TAC_PROCESS_ERROR_SIZE -2 /* buffer is smaller than needed */
#define TAC_PROCESS_ERROR_ID -3 /* expected frame id mismatch */
#define TAC_PROCESS_ERROR_CRC -4 /* expected frame crc mismatch */
#define TAC_PROCESS_ERROR_HUFFMAN -5 /* expected huffman count mismatch */
typedef struct tac_handle_t tac_handle_t;
typedef struct {
/* 0x20 header config */
uint32_t huffman_offset; /* setup */
uint32_t unknown1; /* ignored? may be CDVD stuff (divided/multiplied during PS2 process), not file size related */
uint16_t loop_frame; /* aligned to block stard */
uint16_t loop_discard; /* assumed */
uint16_t frame_count; /* number of valid frames ("block end" frame not included) */
uint16_t frame_discard; /* assumed */
uint32_t loop_offset; /* file size if not looped */
uint32_t file_size; /* actual file size can be a bit smaller if last block is truncated */
uint32_t unknown2; /* usually 0 and rarely 1 (R channel has less data, joint stereo mode?) */
uint32_t empty; /* null? */
} tac_header_t;
/* inits codec with data from at least one block */
tac_handle_t* tac_init(const uint8_t* buf, int buf_size);
const tac_header_t* tac_get_header(tac_handle_t* handle);
void tac_reset(tac_handle_t* handle);
void tac_free(tac_handle_t* handle);
/* decodes a frame from current block (of TAC_BLOCK_SIZE), returning TAC_PROCESS_* codes */
int tac_decode_frame(tac_handle_t* handle, const uint8_t* block);
void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst);
void tac_set_loop(tac_handle_t* handle);
#endif /* _TAC_DECODER_LIB_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,377 @@
#ifndef _TAC_DECODER_LIB_OPS_H_
#define _TAC_DECODER_LIB_OPS_H_
#include <math.h>
#include "tac_decoder_lib_ops.h"
/* The following ops are similar to VU1's ops, but not quite the same. For example VU1 has special op
* registers like the ACC, and updates zero/neg/etc flags per op (plus added here a few helper ops).
* Main reason to use them vs doing standard +*-/ in code is allowing to simulate PS2 floats.
* See Nisto's decoder for actual emulation. */
/* PS2 floats are slightly different vs IEEE 754 floats:
* - NaN and Inf (exp 255) don't exist on the PS2, meaning it has a bigger range of floats
* - denormals (exp 0) don't exist either, and ops truncate to 0
* - rounding on PS2 always rounds towards zero
* The code below (partially) simulates this, but for audio it only means +-1 differences,
* plus we can't fully emulate exact behaviour, so it's disabled for performance
* (function call is optimized out by compiler). */
#define TAC_ENABLE_PS2_FLOATS 0
static inline void UPDATE_FLOATS(uint8_t dest, REG_VF *vf) {
#if TAC_ENABLE_PS2_FLOATS
int i;
for (i = 0; i < 4; i++) {
int shift = 3 - i;
if (dest & (1 << shift)) {
if (vf->F[i] == 0.0) {
uint32_t v = vf->UL[i];
int exp = (v >> 23) & 0xff;
uint32_t s = v & 0x80000000;
switch (exp) {
case 0:
vf->UL[i] = s;
break;
case 255:
vf->UL[i] = s|0x7f7fffff; /* max allowed */
break;
default: /* standard */
vf->UL[i] = v;
break;
}
}
}
}
#endif
}
static inline void _DIV_INTERNAL(REG_VF *fd, const REG_VF *fs, const REG_VF *ft, int from) {
float dividend = fs->F[from];
float divisor = ft->F[from];
#if TAC_ENABLE_PS2_FLOATS
if (divisor == 0.0) {
if ((ft->UL[from] & 0x80000000) != (0x80000000 & fs->UL[from])) {
fd->UL[from] = 0xFF7FFFFF;
}
else {
fd->UL[from] = 0x7F7FFFFF;
}
}
else {
fd->F[from] = dividend / divisor;
}
#else
fd->F[from] = dividend / divisor;
#endif
}
///////////////////////////////////////////////////////////////////////////////
static inline void DIV(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) _DIV_INTERNAL(fd, fs, ft, 0);
if (dest & __y__) _DIV_INTERNAL(fd, fs, ft, 1);
if (dest & ___z_) _DIV_INTERNAL(fd, fs, ft, 2);
if (dest & ____w) _DIV_INTERNAL(fd, fs, ft, 3);
UPDATE_FLOATS(dest, fd);
}
///////////////////////////////////////////////////////////////////////////////
static inline void ADD(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x + ft->f.x;
if (dest & __y__) fd->f.y = fs->f.y + ft->f.y;
if (dest & ___z_) fd->f.z = fs->f.z + ft->f.z;
if (dest & ____w) fd->f.w = fs->f.w + ft->f.w;
UPDATE_FLOATS(dest, fd);
}
static inline void ADDx(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x + ft->f.x;
if (dest & __y__) fd->f.y = fs->f.y + ft->f.x;
if (dest & ___z_) fd->f.z = fs->f.z + ft->f.x;
if (dest & ____w) fd->f.w = fs->f.w + ft->f.x;
UPDATE_FLOATS(dest, fd);
}
static inline void ADDy(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x + ft->f.y;
if (dest & __y__) fd->f.y = fs->f.y + ft->f.y;
if (dest & ___z_) fd->f.z = fs->f.z + ft->f.y;
if (dest & ____w) fd->f.w = fs->f.w + ft->f.y;
UPDATE_FLOATS(dest, fd);
}
static inline void ADDz(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x + ft->f.z;
if (dest & __y__) fd->f.y = fs->f.y + ft->f.z;
if (dest & ___z_) fd->f.z = fs->f.z + ft->f.z;
if (dest & ____w) fd->f.w = fs->f.w + ft->f.z;
UPDATE_FLOATS(dest, fd);
}
static inline void ADDw(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x + ft->f.w;
if (dest & __y__) fd->f.y = fs->f.y + ft->f.w;
if (dest & ___z_) fd->f.z = fs->f.z + ft->f.w;
if (dest & ____w) fd->f.w = fs->f.w + ft->f.w;
UPDATE_FLOATS(dest, fd);
}
///////////////////////////////////////////////////////////////////////////////
static inline void SUB(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x - ft->f.x;
if (dest & __y__) fd->f.y = fs->f.y - ft->f.y;
if (dest & ___z_) fd->f.z = fs->f.z - ft->f.z;
if (dest & ____w) fd->f.w = fs->f.w - ft->f.w;
UPDATE_FLOATS(dest, fd);
}
static inline void SUBx(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x - ft->f.x;
if (dest & __y__) fd->f.y = fs->f.y - ft->f.x;
if (dest & ___z_) fd->f.z = fs->f.z - ft->f.x;
if (dest & ____w) fd->f.w = fs->f.w - ft->f.x;
UPDATE_FLOATS(dest, fd);
}
static inline void SUBy(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x - ft->f.y;
if (dest & __y__) fd->f.y = fs->f.y - ft->f.y;
if (dest & ___z_) fd->f.z = fs->f.z - ft->f.y;
if (dest & ____w) fd->f.w = fs->f.w - ft->f.y;
UPDATE_FLOATS(dest, fd);
}
static inline void SUBz(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x - ft->f.z;
if (dest & __y__) fd->f.y = fs->f.y - ft->f.z;
if (dest & ___z_) fd->f.z = fs->f.z - ft->f.z;
if (dest & ____w) fd->f.w = fs->f.w - ft->f.z;
UPDATE_FLOATS(dest, fd);
}
static inline void SUBw(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x - ft->f.w;
if (dest & __y__) fd->f.y = fs->f.y - ft->f.w;
if (dest & ___z_) fd->f.z = fs->f.z - ft->f.w;
if (dest & ____w) fd->f.w = fs->f.w - ft->f.w;
UPDATE_FLOATS(dest, fd);
}
///////////////////////////////////////////////////////////////////////////////
static inline void MUL(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x * ft->f.x;
if (dest & __y__) fd->f.y = fs->f.y * ft->f.y;
if (dest & ___z_) fd->f.z = fs->f.z * ft->f.z;
if (dest & ____w) fd->f.w = fs->f.w * ft->f.w;
UPDATE_FLOATS(dest, fd);
}
static inline void MULx(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x * ft->f.x;
if (dest & __y__) fd->f.y = fs->f.y * ft->f.x;
if (dest & ___z_) fd->f.z = fs->f.z * ft->f.x;
if (dest & ____w) fd->f.w = fs->f.w * ft->f.x;
UPDATE_FLOATS(dest, fd);
}
static inline void MULy(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x * ft->f.y;
if (dest & __y__) fd->f.y = fs->f.y * ft->f.y;
if (dest & ___z_) fd->f.z = fs->f.z * ft->f.y;
if (dest & ____w) fd->f.w = fs->f.w * ft->f.y;
UPDATE_FLOATS(dest, fd);
}
static inline void MULz(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x * ft->f.z;
if (dest & __y__) fd->f.y = fs->f.y * ft->f.z;
if (dest & ___z_) fd->f.z = fs->f.z * ft->f.z;
if (dest & ____w) fd->f.w = fs->f.w * ft->f.z;
UPDATE_FLOATS(dest, fd);
}
static inline void MULw(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fs->f.x * ft->f.w;
if (dest & __y__) fd->f.y = fs->f.y * ft->f.w;
if (dest & ___z_) fd->f.z = fs->f.z * ft->f.w;
if (dest & ____w) fd->f.w = fs->f.w * ft->f.w;
UPDATE_FLOATS(dest, fd);
}
///////////////////////////////////////////////////////////////////////////////
static inline void MADD(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x + (fs->f.x * ft->f.x);
if (dest & __y__) fd->f.y = fd->f.y + (fs->f.y * ft->f.y);
if (dest & ___z_) fd->f.z = fd->f.z + (fs->f.z * ft->f.z);
if (dest & ____w) fd->f.w = fd->f.w + (fs->f.w * ft->f.w);
UPDATE_FLOATS(dest, fd);
}
static inline void MADDx(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x + (fs->f.x * ft->f.x);
if (dest & __y__) fd->f.y = fd->f.y + (fs->f.y * ft->f.x);
if (dest & ___z_) fd->f.z = fd->f.z + (fs->f.z * ft->f.x);
if (dest & ____w) fd->f.w = fd->f.w + (fs->f.w * ft->f.x);
UPDATE_FLOATS(dest, fd);
}
static inline void MADDy(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x + (fs->f.x * ft->f.y);
if (dest & __y__) fd->f.y = fd->f.y + (fs->f.y * ft->f.y);
if (dest & ___z_) fd->f.z = fd->f.z + (fs->f.z * ft->f.y);
if (dest & ____w) fd->f.w = fd->f.w + (fs->f.w * ft->f.y);
UPDATE_FLOATS(dest, fd);
}
static inline void MADDz(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x + (fs->f.x * ft->f.z);
if (dest & __y__) fd->f.y = fd->f.y + (fs->f.y * ft->f.z);
if (dest & ___z_) fd->f.z = fd->f.z + (fs->f.z * ft->f.z);
if (dest & ____w) fd->f.w = fd->f.w + (fs->f.w * ft->f.z);
UPDATE_FLOATS(dest, fd);
}
static inline void MADDw(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x + (fs->f.x * ft->f.w);
if (dest & __y__) fd->f.y = fd->f.y + (fs->f.y * ft->f.w);
if (dest & ___z_) fd->f.z = fd->f.z + (fs->f.z * ft->f.w);
if (dest & ____w) fd->f.w = fd->f.w + (fs->f.w * ft->f.w);
UPDATE_FLOATS(dest, fd);
}
static inline void MSUBx(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x - (fs->f.x * ft->f.x);
if (dest & __y__) fd->f.y = fd->f.y - (fs->f.y * ft->f.x);
if (dest & ___z_) fd->f.z = fd->f.z - (fs->f.z * ft->f.x);
if (dest & ____w) fd->f.w = fd->f.w - (fs->f.w * ft->f.x);
UPDATE_FLOATS(dest, fd);
}
static inline void MSUBy(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x - (fs->f.x * ft->f.y);
if (dest & __y__) fd->f.y = fd->f.y - (fs->f.y * ft->f.y);
if (dest & ___z_) fd->f.z = fd->f.z - (fs->f.z * ft->f.y);
if (dest & ____w) fd->f.w = fd->f.w - (fs->f.w * ft->f.y);
UPDATE_FLOATS(dest, fd);
}
static inline void MSUBz(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x - (fs->f.x * ft->f.z);
if (dest & __y__) fd->f.y = fd->f.y - (fs->f.y * ft->f.z);
if (dest & ___z_) fd->f.z = fd->f.z - (fs->f.z * ft->f.z);
if (dest & ____w) fd->f.w = fd->f.w - (fs->f.w * ft->f.z);
UPDATE_FLOATS(dest, fd);
}
static inline void MSUBw(uint8_t dest, REG_VF *fd, const REG_VF *fs, const REG_VF *ft) {
if (dest & _x___) fd->f.x = fd->f.x - (fs->f.x * ft->f.w);
if (dest & __y__) fd->f.y = fd->f.y - (fs->f.y * ft->f.w);
if (dest & ___z_) fd->f.z = fd->f.z - (fs->f.z * ft->f.w);
if (dest & ____w) fd->f.w = fd->f.w - (fs->f.w * ft->f.w);
UPDATE_FLOATS(dest, fd);
}
///////////////////////////////////////////////////////////////////////////////
static inline void FMUL(uint8_t dest, REG_VF *fd, const REG_VF *fs, const float I_F) {
if (dest & _x___) fd->f.x = fs->f.x * I_F;
if (dest & __y__) fd->f.y = fs->f.y * I_F;
if (dest & ___z_) fd->f.z = fs->f.z * I_F;
if (dest & ____w) fd->f.w = fs->f.w * I_F;
UPDATE_FLOATS(dest, fd);
}
static inline void FMULf(uint8_t dest, REG_VF *fd, const float fs) {
if (dest & _x___) fd->f.x = fd->f.x * fs;
if (dest & __y__) fd->f.y = fd->f.y * fs;
if (dest & ___z_) fd->f.z = fd->f.z * fs;
if (dest & ____w) fd->f.w = fd->f.w * fs;
UPDATE_FLOATS(dest, fd);
}
///////////////////////////////////////////////////////////////////////////////
static inline void ABS(uint8_t dest, REG_VF *ft, const REG_VF *fs) {
if (dest & _x___) ft->f.x = fabsf(fs->f.x);
if (dest & __y__) ft->f.y = fabsf(fs->f.y);
if (dest & ___z_) ft->f.z = fabsf(fs->f.z);
if (dest & ____w) ft->f.w = fabsf(fs->f.w);
}
static inline void FTOI0(uint8_t dest, REG_VF *ft, const REG_VF *fs) {
if (dest & _x___) ft->SL[0] = (int32_t)fs->f.x;
if (dest & __y__) ft->SL[1] = (int32_t)fs->f.y;
if (dest & ___z_) ft->SL[2] = (int32_t)fs->f.z;
if (dest & ____w) ft->SL[3] = (int32_t)fs->f.w;
}
static inline void ITOF0(uint8_t dest, REG_VF *ft, const REG_VF *fs) {
if (dest & _x___) ft->f.x = (float)fs->SL[0];
if (dest & __y__) ft->f.y = (float)fs->SL[1];
if (dest & ___z_) ft->f.z = (float)fs->SL[2];
if (dest & ____w) ft->f.w = (float)fs->SL[3];
}
static inline void MR32(uint8_t dest, REG_VF *ft, const REG_VF *fs) {
float x = fs->f.x;
if (dest & _x___) ft->f.x = fs->f.y;
if (dest & __y__) ft->f.y = fs->f.z;
if (dest & ___z_) ft->f.z = fs->f.w;
if (dest & ____w) ft->f.w = x;
}
///////////////////////////////////////////////////////////////////////////////
static inline void LOAD(uint8_t dest, REG_VF *ft, REG_VF* src, int pos) {
if (dest & _x___) ft->f.x = src[pos].f.x;
if (dest & __y__) ft->f.y = src[pos].f.y;
if (dest & ___z_) ft->f.z = src[pos].f.z;
if (dest & ____w) ft->f.w = src[pos].f.w;
}
static inline void STORE(uint8_t dest, REG_VF* dst, const REG_VF *fs, int pos) {
if (dest & _x___) dst[pos].f.x = fs->f.x;
if (dest & __y__) dst[pos].f.y = fs->f.y;
if (dest & ___z_) dst[pos].f.z = fs->f.z;
if (dest & ____w) dst[pos].f.w = fs->f.w;
}
static inline void MOVE(uint8_t dest, REG_VF *fd, const REG_VF *fs) {
if (dest & _x___) fd->f.x = fs->f.x;
if (dest & __y__) fd->f.y = fs->f.y;
if (dest & ___z_) fd->f.z = fs->f.z;
if (dest & ____w) fd->f.w = fs->f.w;
}
static inline void MOVEx(uint8_t dest, REG_VF *fd, const REG_VF *fs) {
if (dest & _x___) fd->f.x = fs->f.x;
if (dest & __y__) fd->f.y = fs->f.x;
if (dest & ___z_) fd->f.z = fs->f.x;
if (dest & ____w) fd->f.w = fs->f.x;
}
static inline void SIGN(uint8_t dest, REG_VF *fd, const REG_VF *fs) {
if (dest & _x___) if (fs->f.x < 0) fd->f.x = -fd->f.x;
if (dest & __y__) if (fs->f.y < 0) fd->f.y = -fd->f.y;
if (dest & ___z_) if (fs->f.z < 0) fd->f.z = -fd->f.z;
if (dest & ____w) if (fs->f.w < 0) fd->f.w = -fd->f.w;
}
static inline void COPY(uint8_t dest, REG_VF *fd, const int16_t* buf) {
if (dest & _x___) fd->f.x = buf[0];
if (dest & __y__) fd->f.y = buf[1];
if (dest & ___z_) fd->f.z = buf[2];
if (dest & ____w) fd->f.w = buf[3];
}
#endif /* _TAC_DECODER_LIB_OPS_H_ */

View File

@ -32,6 +32,10 @@ void free_codec(VGMSTREAM* vgmstream) {
free_hca(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_TAC) {
free_tac(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_UBI_ADPCM) {
free_ubi_adpcm(vgmstream->codec_data);
}
@ -125,8 +129,8 @@ void seek_codec(VGMSTREAM* vgmstream) {
seek_relic(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_CRI_HCA) {
loop_hca(vgmstream->codec_data, vgmstream->loop_current_sample);
if (vgmstream->coding_type == coding_TAC) {
seek_tac(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_UBI_ADPCM) {
@ -227,8 +231,8 @@ void reset_codec(VGMSTREAM* vgmstream) {
reset_relic(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_CRI_HCA) {
reset_hca(vgmstream->codec_data);
if (vgmstream->coding_type == coding_TAC) {
reset_tac(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_UBI_ADPCM) {
@ -509,6 +513,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
return 0; /* 512 */
case coding_CRI_HCA:
return 0; /* 1024 - delay/padding (which can be bigger than 1024) */
case coding_TAC:
return 0; /* 1024 - delay/padding */
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
case coding_MP4_AAC:
return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame;
@ -705,27 +711,16 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
return vgmstream->interleave_block_size;
case coding_PTADPCM:
return vgmstream->interleave_block_size;
case coding_UBI_ADPCM:
return 0; /* varies per mode? */
case coding_IMUSE:
return 0; /* varies per frame */
case coding_COMPRESSWAVE:
return 0; /* huffman bits */
case coding_EA_MT:
return 0; /* variable (frames of bit counts or PCM frames) */
#ifdef VGM_USE_ATRAC9
case coding_ATRAC9:
return 0; /* varies with config data, usually 0x100-200 */
#endif
#ifdef VGM_USE_CELT
case coding_CELT_FSB:
return 0; /* varies, usually 0x80-100 */
#endif
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
return 0; /* varies, usually 0x40-60 */
#endif
default: /* Vorbis, MPEG, ACM, etc */
/* UBI_ADPCM: varies per mode? */
/* IMUSE: VBR */
/* EA_MT: VBR, frames of bit counts or PCM frames */
/* COMPRESSWAVE: VBR/huffman bits */
/* ATRAC9: CBR around 0x100-200 */
/* CELT FSB: varies, usually 0x80-100 */
/* SPEEX: varies, usually 0x40-60 */
/* TAC: VBR around ~0x200-300 */
/* Vorbis, MPEG, ACM, etc: varies */
default: /* (VBR or managed by decoder) */
return 0;
}
}
@ -1038,6 +1033,9 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_CRI_HCA:
decode_hca(vgmstream->codec_data, buffer, samples_to_do);
break;
case coding_TAC:
decode_tac(vgmstream, buffer, samples_to_do);
break;
#ifdef VGM_USE_FFMPEG
case coding_FFmpeg:
decode_ffmpeg(vgmstream, buffer, samples_to_do, vgmstream->channels);

View File

@ -803,7 +803,8 @@ static const coding_info coding_info_list[] = {
{coding_CIRCUS_VQ, "Circus VQ"},
{coding_RELIC, "Relic Codec"},
{coding_CRI_HCA, "CRI HCA"},
{coding_TAC, "tri-Ace Codec"},
#ifdef VGM_USE_VORBIS
{coding_OGG_VORBIS, "Ogg Vorbis"},
{coding_VORBIS_custom, "Custom Vorbis"},
@ -1338,6 +1339,7 @@ static const meta_info meta_info_list[] = {
{meta_KTAC, "Koei Tecmo KTAC header"},
{meta_MJB_MJH, "Sony MultiStream MJH+MJB header"},
{meta_BSNF, "id Software BSNF header"},
{meta_TAC, "tri-Ace Codec header"},
};
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View File

@ -1741,6 +1741,10 @@
<File
RelativePath=".\meta\ta_aac.c"
>
</File>
<File
RelativePath=".\meta\tac.c"
>
</File>
<File
RelativePath=".\meta\thp.c"
@ -2074,10 +2078,22 @@
RelativePath=".\coding\mpeg_decoder.h"
>
</File>
<File
RelativePath=".\coding\nwa_decoder.h"
>
</File>
<File
RelativePath=".\coding\nwa_decoder.h"
>
</File>
<File
RelativePath=".\coding\tac_decoder_lib.h"
>
</File>
<File
RelativePath=".\coding\tac_decoder_lib_data.h"
>
</File>
<File
RelativePath=".\coding\tac_decoder_lib_ops.h"
>
</File>
<File
RelativePath=".\coding\vorbis_bitreader.h"
>
@ -2326,6 +2342,14 @@
RelativePath=".\coding\speex_decoder.c"
>
</File>
<File
RelativePath=".\coding\tac_decoder.c"
>
</File>
<File
RelativePath=".\coding\tac_decoder_lib.c"
>
</File>
<File
RelativePath=".\coding\ubi_adpcm_decoder.c"
>

View File

@ -163,6 +163,9 @@
<ClInclude Include="coding\fsb_vorbis_data.h" />
<ClInclude Include="coding\g72x_state.h" />
<ClInclude Include="coding\nwa_decoder.h" />
<ClInclude Include="coding\tac_decoder_lib.h" />
<ClInclude Include="coding\tac_decoder_lib_data.h" />
<ClInclude Include="coding\tac_decoder_lib_ops.h" />
<ClInclude Include="layout\layout.h" />
</ItemGroup>
<ItemGroup>
@ -535,6 +538,7 @@
<ClCompile Include="meta\svs.c" />
<ClCompile Include="meta\sxd.c" />
<ClCompile Include="meta\ta_aac.c" />
<ClCompile Include="meta\tac.c" />
<ClCompile Include="meta\thp.c" />
<ClCompile Include="meta\vgs.c" />
<ClCompile Include="meta\ubi_bao.c" />
@ -639,6 +643,8 @@
<ClCompile Include="coding\sassc_decoder.c" />
<ClCompile Include="coding\sdx2_decoder.c" />
<ClCompile Include="coding\speex_decoder.c" />
<ClCompile Include="coding\tac_decoder.c" />
<ClCompile Include="coding\tac_decoder_lib.c" />
<ClCompile Include="coding\ubi_adpcm_decoder.c" />
<ClCompile Include="coding\vadpcm_decoder.c" />
<ClCompile Include="coding\vorbis_custom_decoder.c" />

View File

@ -251,6 +251,15 @@
<ClInclude Include="coding\nwa_decoder.h">
<Filter>coding\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\tac_decoder_lib.h">
<Filter>coding\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\tac_decoder_lib_data.h">
<Filter>coding\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\tac_decoder_lib_ops.h">
<Filter>coding\Header Files</Filter>
</ClInclude>
<ClInclude Include="layout\layout.h">
<Filter>layout\Header Files</Filter>
</ClInclude>
@ -1102,6 +1111,9 @@
<ClCompile Include="meta\ta_aac.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\tac.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\thp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1390,6 +1402,12 @@
<ClCompile Include="coding\speex_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\tac_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\tac_decoder_lib.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ubi_adpcm_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>

View File

@ -944,4 +944,6 @@ VGMSTREAM* init_vgmstream_ktac(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_mjb_mjh(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf);
#endif /*_META_H*/

66
src/meta/tac.c Normal file
View File

@ -0,0 +1,66 @@
#include "meta.h"
#include "../coding/coding.h"
/* tri-Ace codec file [Star Ocean 3 (PS2), Valkyrie Profile 2 (PS2), Radiata Stories (PS2)] */
VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channel_count;
uint16_t loop_frame, frame_count, loop_discard, frame_discard;
uint32_t info_offset, loop_offset, stream_size, file_size;
off_t start_offset;
/* checks */
/* (extensionless): bigfiles have no known names (libs calls mention "St*" and "Sac*" though)
* .aac: fake for convenience given it's a tri-Ace AAC's grandpa (but don't use unless you must)
* .pk3/.20: extremely ugly fake extensions randomly given by an old extractor, *DON'T* */
if (!check_extensions(sf, ",aac,laac"))
goto fail;
/* file is validated on decoder init, early catch of simple errors (see decoder for full header) */
info_offset = read_u32le(0x00,sf);
if (info_offset > 0x4E000 || info_offset < 0x20) /* offset points to value inside first "block" */
goto fail;
loop_frame = read_u16le(0x08,sf);
loop_discard = read_u16le(0x0a,sf);
frame_count = read_u16le(0x0c,sf);
frame_discard = read_u16le(0x0e,sf);
loop_offset = read_u32le(0x10,sf);
stream_size = read_u32le(0x14,sf);
if (stream_size % 0x4E000 != 0) /* multiple of blocks */
goto fail;
/* actual file can truncate last block */
file_size = get_streamfile_size(sf);
if (file_size > stream_size || file_size < stream_size - 0x4E000)
goto fail;
channel_count = 2; /* always stereo */
loop_flag = (loop_offset != stream_size);
start_offset = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_TAC;
vgmstream->sample_rate = 48000;
vgmstream->num_samples = frame_count * 1024 - frame_discard;
vgmstream->loop_start_sample = loop_frame * 1024 + loop_discard;
vgmstream->loop_end_sample = vgmstream->num_samples;
{
vgmstream->codec_data = init_tac(sf);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_TAC;
vgmstream->layout_type = layout_none;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -522,6 +522,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_mjb_mjh,
init_vgmstream_mzrt_v1,
init_vgmstream_bsnf,
init_vgmstream_tac,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */

View File

@ -193,6 +193,7 @@ typedef enum {
coding_CIRCUS_VQ, /* Circus VQ */
coding_RELIC, /* Relic Codec (DCT-based) */
coding_CRI_HCA, /* CRI High Compression Audio (MDCT-based) */
coding_TAC, /* tri-Ace Codec (MDCT-based) */
#ifdef VGM_USE_VORBIS
coding_OGG_VORBIS, /* Xiph Vorbis with Ogg layer (MDCT-based) */
@ -754,6 +755,7 @@ typedef enum {
meta_KTAC,
meta_MJB_MJH,
meta_BSNF,
meta_TAC,
} meta_t;
/* standard WAVEFORMATEXTENSIBLE speaker positions */
@ -1048,7 +1050,7 @@ typedef struct {
uint64_t size; // max size within the streamfile
uint64_t logical_offset; // computed offset FFmpeg sees (including fake header)
uint64_t logical_size; // computed size FFmpeg sees (including fake header)
uint64_t header_size; // fake header (parseable by FFmpeg) prepended on reads
uint8_t* header_block; // fake header data (ie. RIFF)
@ -1061,7 +1063,7 @@ typedef struct {
int64_t totalSamples; // estimated count (may not be accurate for some demuxers)
int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments
int streamCount; // number of FFmpeg audio streams
/*** internal state ***/
// config
int channel_remap_set;
@ -1073,7 +1075,7 @@ typedef struct {
// FFmpeg context used for metadata
AVCodec *codec;
// FFmpeg decoder state
unsigned char *buffer;
AVIOContext *ioCtx;