mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
commit
b1bc14d033
13
README.md
13
README.md
@ -220,6 +220,7 @@ a companion file:
|
|||||||
- .hca: .hcakey (8 byte decryption key, a 64-bit number)
|
- .hca: .hcakey (8 byte decryption key, a 64-bit number)
|
||||||
- May be followed by 2 byte AWB scramble key for newer HCA
|
- May be followed by 2 byte AWB scramble key for newer HCA
|
||||||
- .fsb: .fsbkey (decryption key, in hex)
|
- .fsb: .fsbkey (decryption key, in hex)
|
||||||
|
- .bnsf: .bnsfkey (decryption key, a string up to 24 chars)
|
||||||
|
|
||||||
The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key"
|
The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key"
|
||||||
(for a single file). The format is made up to suit vgmstream.
|
(for a single file). The format is made up to suit vgmstream.
|
||||||
@ -286,6 +287,9 @@ can reduce the number of channels to a playable amount. Note that this type
|
|||||||
of downmixing is very generic, not meant to be used when converting to other
|
of downmixing is very generic, not meant to be used when converting to other
|
||||||
formats.
|
formats.
|
||||||
|
|
||||||
|
You can also choose which channels to play using *TXTP*. For example, create
|
||||||
|
a file named `song.adx#C1,2.txtp` to play only channels 1 and 2 from `song.adx`.
|
||||||
|
|
||||||
## Tagging
|
## Tagging
|
||||||
Some of vgmstream's plugins support simple read-only tagging via external files.
|
Some of vgmstream's plugins support simple read-only tagging via external files.
|
||||||
|
|
||||||
@ -702,10 +706,11 @@ This list is not complete and many other files are supported.
|
|||||||
- .sfl (loop info for .ogg)
|
- .sfl (loop info for .ogg)
|
||||||
- .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
|
- .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
|
||||||
- other:
|
- other:
|
||||||
- .adxkey (decryption key for .adx, in start/mult/add format)
|
- .adxkey (decryption key for .adx)
|
||||||
- .ahxkey (decryption key for .ahx, in start/mult/add format)
|
- .ahxkey (decryption key for .ahx)
|
||||||
- .hcakey (decryption key for .hca, in HCA Decoder format)
|
- .hcakey (decryption key for .hca)
|
||||||
- .fsbkey (decryption key for .fsb, in hex)
|
- .fsbkey (decryption key for .fsb)
|
||||||
|
- .bnsfkey (decryption key for .bnsf)
|
||||||
- .txtp (per song segment/layer handler and player configurator)
|
- .txtp (per song segment/layer handler and player configurator)
|
||||||
|
|
||||||
Enjoy! *hcs*
|
Enjoy! *hcs*
|
||||||
|
@ -260,9 +260,11 @@ long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data);
|
|||||||
#ifdef VGM_USE_G7221
|
#ifdef VGM_USE_G7221
|
||||||
/* g7221_decoder */
|
/* g7221_decoder */
|
||||||
g7221_codec_data* init_g7221(int channel_count, int frame_size);
|
g7221_codec_data* init_g7221(int channel_count, int frame_size);
|
||||||
void decode_g7221(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
void decode_g7221(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
||||||
void reset_g7221(VGMSTREAM *vgmstream);
|
void reset_g7221(g7221_codec_data* data);
|
||||||
void free_g7221(VGMSTREAM *vgmstream);
|
void free_g7221(g7221_codec_data* data);
|
||||||
|
void set_key_g7221(g7221_codec_data* data, const uint8_t* key);
|
||||||
|
int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VGM_USE_G719
|
#ifdef VGM_USE_G719
|
||||||
|
@ -2,54 +2,59 @@
|
|||||||
#include "g7221_decoder_lib.h"
|
#include "g7221_decoder_lib.h"
|
||||||
|
|
||||||
#ifdef VGM_USE_G7221
|
#ifdef VGM_USE_G7221
|
||||||
#define G7221_MAX_FRAME_SIZE 0x78 /* max frame 0x78 uint8s = 960/8 */
|
#define G7221_MAX_FRAME_SIZE 0x78 /* 960/8 */
|
||||||
|
#define G7221_MAX_FRAME_SAMPLES 640 /* 32000/50 */
|
||||||
|
|
||||||
struct g7221_codec_data {
|
struct g7221_codec_data {
|
||||||
sample_t buffer[640];
|
int channels;
|
||||||
|
int frame_size;
|
||||||
|
struct g7221_channel_data {
|
||||||
|
sample_t buffer[G7221_MAX_FRAME_SAMPLES];
|
||||||
g7221_handle* handle;
|
g7221_handle* handle;
|
||||||
|
} *ch;
|
||||||
};
|
};
|
||||||
|
|
||||||
g7221_codec_data* init_g7221(int channel_count, int frame_size) {
|
g7221_codec_data* init_g7221(int channels, int frame_size) {
|
||||||
int i;
|
int i;
|
||||||
g7221_codec_data* data = NULL;
|
g7221_codec_data* data = NULL;
|
||||||
|
|
||||||
if (frame_size > G7221_MAX_FRAME_SIZE)
|
if (frame_size > G7221_MAX_FRAME_SIZE)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
data = calloc(channel_count, sizeof(g7221_codec_data)); /* one decoder per channel */
|
data = calloc(1, sizeof(g7221_codec_data));
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
|
|
||||||
for (i = 0; i < channel_count; i++) {
|
data->channels = channels;
|
||||||
data[i].handle = g7221_init(frame_size, 14000); /* Siren 14 == 14khz bandwidth */
|
data->frame_size = frame_size;
|
||||||
if (!data[i].handle) goto fail;
|
|
||||||
|
data->ch = calloc(channels, sizeof(struct g7221_channel_data));
|
||||||
|
if (!data->ch) goto fail;
|
||||||
|
|
||||||
|
for (i = 0; i < data->channels; i++) {
|
||||||
|
data->ch[i].handle = g7221_init(frame_size);
|
||||||
|
if (!data->ch[i].handle) goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (data) {
|
free_g7221(data);
|
||||||
for (i = 0; i < channel_count; i++) {
|
|
||||||
g7221_free(data[i].handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(data);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
void decode_g7221(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
||||||
VGMSTREAMCHANNEL* ch = &vgmstream->ch[channel];
|
VGMSTREAMCHANNEL* ch = &vgmstream->ch[channel];
|
||||||
g7221_codec_data* data = vgmstream->codec_data;
|
g7221_codec_data* data = vgmstream->codec_data;
|
||||||
g7221_codec_data *ch_data = &data[channel];
|
struct g7221_channel_data* ch_data = &data->ch[channel];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (0 == vgmstream->samples_into_block) {
|
if (0 == vgmstream->samples_into_block) {
|
||||||
uint8_t buf[G7221_MAX_FRAME_SIZE];
|
uint8_t buf[G7221_MAX_FRAME_SIZE];
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
size_t read = vgmstream->interleave_block_size;
|
size_t read = data->frame_size;
|
||||||
|
|
||||||
bytes = vgmstream->ch[channel].streamfile->read(ch->streamfile, buf, ch->offset, read);
|
bytes = read_streamfile(buf, ch->offset, read, ch->streamfile);
|
||||||
if (bytes != read) {
|
if (bytes != read) {
|
||||||
//g7221_decode_empty(ch_data->handle, ch_data->buffer);
|
//g7221_decode_empty(ch_data->handle, ch_data->buffer);
|
||||||
memset(ch_data->buffer, 0, sizeof(ch_data->buffer));
|
memset(ch_data->buffer, 0, sizeof(ch_data->buffer));
|
||||||
@ -66,25 +71,89 @@ void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void reset_g7221(VGMSTREAM *vgmstream) {
|
void reset_g7221(g7221_codec_data* data) {
|
||||||
g7221_codec_data *data = vgmstream->codec_data;
|
|
||||||
int i;
|
int i;
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
for (i = 0; i < vgmstream->channels; i++) {
|
for (i = 0; i < data->channels; i++) {
|
||||||
g7221_reset(data[i].handle);
|
g7221_reset(data->ch[i].handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_g7221(VGMSTREAM *vgmstream) {
|
void free_g7221(g7221_codec_data* data) {
|
||||||
g7221_codec_data *data = (g7221_codec_data *) vgmstream->codec_data;
|
|
||||||
int i;
|
int i;
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
for (i = 0; i < vgmstream->channels; i++) {
|
for (i = 0; i < data->channels; i++) {
|
||||||
g7221_free(data[i].handle);
|
g7221_free(data->ch[i].handle);
|
||||||
}
|
}
|
||||||
|
free(data->ch);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_key_g7221(g7221_codec_data* data, const uint8_t* key) {
|
||||||
|
int i;
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
for (i = 0; i < data->channels; i++) {
|
||||||
|
g7221_set_key(data->ch[i].handle, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* just in case but very few should be enough */
|
||||||
|
#define S14_KEY_MIN_TEST_FRAMES 3
|
||||||
|
#define S14_KEY_MAX_TEST_FRAMES 5
|
||||||
|
|
||||||
|
/* Test a number of frames to check if current key decrypts correctly.
|
||||||
|
* Returns score: <0: error/wrong, 0: unknown/silent, >0: good (closer to 1 is better). */
|
||||||
|
int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf) {
|
||||||
|
size_t test_frames = 0, current_frame = 0;
|
||||||
|
int total_score = 0;
|
||||||
|
int max_frames = (get_streamfile_size(sf) - start) / data->frame_size;
|
||||||
|
int cur_ch = 0;
|
||||||
|
|
||||||
|
/* assumes key was set before this call */
|
||||||
|
|
||||||
|
while (test_frames < S14_KEY_MAX_TEST_FRAMES && current_frame < max_frames) {
|
||||||
|
int score, ok;
|
||||||
|
size_t bytes;
|
||||||
|
uint8_t buf[G7221_MAX_FRAME_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
bytes = read_streamfile(buf, start, data->frame_size, sf);
|
||||||
|
if (bytes != data->frame_size) {
|
||||||
|
total_score = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = g7221_decode_frame(data->ch[cur_ch].handle, buf, data->ch[cur_ch].buffer);
|
||||||
|
if (!ok) {
|
||||||
|
total_score = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* alternate channels (decode may affect scores otherwise) */
|
||||||
|
cur_ch = (cur_ch + 1) % data->channels;
|
||||||
|
|
||||||
|
/* good key if it decodes without error, encryption is easily detectable */
|
||||||
|
score = 1;
|
||||||
|
|
||||||
|
test_frames++;
|
||||||
|
|
||||||
|
total_score += score;
|
||||||
|
|
||||||
|
start += data->frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* signal best possible score (many perfect frames and few blank frames) */
|
||||||
|
if (test_frames > S14_KEY_MIN_TEST_FRAMES && total_score > 0 && total_score <= test_frames) {
|
||||||
|
total_score = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up decoders */
|
||||||
|
reset_g7221(data);
|
||||||
|
|
||||||
|
return total_score;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
326
src/coding/g7221_decoder_aes.c
Normal file
326
src/coding/g7221_decoder_aes.c
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "g7221_decoder_aes.h"
|
||||||
|
|
||||||
|
/* Namco's NUS AES is just standard AES-192 in ECB mode, so this can be swapped with another lib,
|
||||||
|
* if more code needs AES. Most implementations out there either use pre-calculated look-up tables,
|
||||||
|
* or calculate manually every AES op. Namco's code calculates tables first in a slightly different
|
||||||
|
* layout, so it may be interesting as a sort of doc piece. */
|
||||||
|
|
||||||
|
|
||||||
|
struct s14aes_handle {
|
||||||
|
/* substitution box look-up table and the inverse */
|
||||||
|
uint8_t sbox[256];
|
||||||
|
uint8_t ibox[256];
|
||||||
|
/* helper for various tables, not too sure about it */
|
||||||
|
uint8_t xors[256];
|
||||||
|
/* round constant, though only sets up to 8 */
|
||||||
|
uint8_t rcon[16];
|
||||||
|
/* MixColumn(?) LUTs, unlike normal Rijndael which uses 4 tables: Td0a Td0b..., Td1a Td1b..., ...
|
||||||
|
* layout is: Td0a Td1a Td2a Td3a, Td0b Td0b Td1b Td2b, ... (better for CPU cache?) */
|
||||||
|
uint32_t tds[256*4];
|
||||||
|
/* expanded roundkey, actual final key */
|
||||||
|
uint32_t rk[52];
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_U32LE(p) (((p)[0] << 0 ) | ((p)[1] << 8 ) | ((p)[2] << 16) | ((p)[3] << 24))
|
||||||
|
#define GET_U32BE(p) (((p)[3] << 0 ) | ((p)[2] << 8 ) | ((p)[1] << 16) | ((p)[0] << 24))
|
||||||
|
#define GET_B0(x) (((x) >> 0 ) & 0xFF)
|
||||||
|
#define GET_B1(x) (((x) >> 8 ) & 0xFF)
|
||||||
|
#define GET_B2(x) (((x) >> 16) & 0xFF)
|
||||||
|
#define GET_B3(x) (((x) >> 24) & 0xFF)
|
||||||
|
|
||||||
|
|
||||||
|
static void aes_key_expand(s14aes_handle* ctx, const uint8_t* key, uint32_t* rk) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rk[0] = GET_U32LE(key + 0);
|
||||||
|
rk[1] = GET_U32LE(key + 4);
|
||||||
|
rk[2] = GET_U32LE(key + 8);
|
||||||
|
rk[3] = GET_U32LE(key + 12);
|
||||||
|
rk[4] = GET_U32LE(key + 16);
|
||||||
|
rk[5] = GET_U32LE(key + 20);
|
||||||
|
|
||||||
|
for (i = 6; i < 52; i++) {
|
||||||
|
uint8_t temp0 = (rk[5] >> 0 ) & 0xFF;
|
||||||
|
uint8_t temp1 = (rk[5] >> 8 ) & 0xFF;
|
||||||
|
uint8_t temp2 = (rk[5] >> 16) & 0xFF;
|
||||||
|
uint8_t temp3 = (rk[5] >> 24) & 0xFF;
|
||||||
|
if (i == 6 * (i / 6)) {
|
||||||
|
uint8_t sv = ctx->sbox[temp1];
|
||||||
|
temp1 = ctx->sbox[temp2];
|
||||||
|
temp2 = ctx->sbox[temp3];
|
||||||
|
temp3 = ctx->sbox[temp0];
|
||||||
|
temp0 = ctx->rcon[i / 6u - 1] ^ sv;
|
||||||
|
}
|
||||||
|
rk[6] = ((temp0 ^ ((rk[0] >> 0 ) & 0xFF)) << 0 ) |
|
||||||
|
((temp1 ^ ((rk[0] >> 8 ) & 0xFF)) << 8 ) |
|
||||||
|
((temp2 ^ ((rk[0] >> 16) & 0xFF)) << 16) |
|
||||||
|
((temp3 ^ ((rk[0] >> 24) & 0xFF)) << 24);
|
||||||
|
rk++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aes_init_key(s14aes_handle* ctx, const uint8_t* key) {
|
||||||
|
const uint8_t invcols[4][4] = {
|
||||||
|
{0x0E,0x0B,0x0D,0x09},
|
||||||
|
{0x09,0x0E,0x0B,0x0D},
|
||||||
|
{0x0D,0x09,0x0E,0x0B},
|
||||||
|
{0x0B,0x0D,0x09,0x0E}
|
||||||
|
};
|
||||||
|
unsigned int roundkey[52];
|
||||||
|
int i, j, row, col, b;
|
||||||
|
|
||||||
|
aes_key_expand(ctx, key, roundkey);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
ctx->rk[i] = ((roundkey[i] << 24) & 0xFF000000) |
|
||||||
|
((roundkey[i] << 8 ) & 0x00FF0000) |
|
||||||
|
((roundkey[i] >> 8 ) & 0x0000FF00) |
|
||||||
|
((roundkey[i] >> 24) & 0x000000FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 4; i < 48; i += 4) {
|
||||||
|
for (j = i; j < i + 4; j++) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
|
||||||
|
for (row = 0; row < 4; row++) {
|
||||||
|
uint8_t xv = 0;
|
||||||
|
|
||||||
|
for (col = 0; col < 4; col++) {
|
||||||
|
uint16_t rv1 = 0;
|
||||||
|
uint16_t rv2 = (roundkey[j] >> (col * 8)) & 0xFF;
|
||||||
|
uint8_t ic = invcols[row][col];
|
||||||
|
|
||||||
|
for (b = 0; b < 8; b++) {
|
||||||
|
if (ic & (1 << b))
|
||||||
|
rv1 ^= rv2;
|
||||||
|
rv2 *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
xv ^= rv1 ^ ctx->xors[rv1 >> 8];
|
||||||
|
}
|
||||||
|
|
||||||
|
val = (val << 8) | xv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->rk[j] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 48; i < 52; i++) {
|
||||||
|
ctx->rk[i] = ((roundkey[i] << 24) & 0xFF000000) |
|
||||||
|
((roundkey[i] << 8 ) & 0x00FF0000) |
|
||||||
|
((roundkey[i] >> 8 ) & 0x0000FF00) |
|
||||||
|
((roundkey[i] >> 24) & 0x000000FF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aes_init_state(s14aes_handle* ctx) {
|
||||||
|
const uint8_t invcol[4] = {
|
||||||
|
0x0E, 0x0B, 0x0D, 0x09
|
||||||
|
};
|
||||||
|
unsigned int *tds_ptr;
|
||||||
|
uint8_t rcon[32];
|
||||||
|
uint8_t box[256];
|
||||||
|
int i, j, k, b;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
uint16_t rv;
|
||||||
|
if (i >= 8) {
|
||||||
|
rv = 128;
|
||||||
|
for (j = 0; j < i - 7; j++) {
|
||||||
|
rv *= 2;
|
||||||
|
if (rv & 256)
|
||||||
|
rv ^= 0x11Bu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rv = 1 << i;
|
||||||
|
}
|
||||||
|
rcon[i] = rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
uint8_t xv = 0;
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
if (i & (1 << j))
|
||||||
|
xv ^= rcon[j + 8];
|
||||||
|
}
|
||||||
|
ctx->xors[i] = xv;
|
||||||
|
}
|
||||||
|
|
||||||
|
tds_ptr = ctx->tds;
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
uint16_t tv1 = 0;
|
||||||
|
uint16_t tv2 = invcol[j];
|
||||||
|
for (b = 0; b < 8; b++) {
|
||||||
|
if (i & (1 << b))
|
||||||
|
tv1 ^= tv2;
|
||||||
|
tv2 *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = ((val >> 8u) & 0x00FFFFFF) | ((val << 24u) & 0xFF000000);
|
||||||
|
val = ((uint8_t)tv1 ^ ctx->xors[tv1 >> 8]) | val;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = ((val >> 16u) & 0x0000FFFF) | ((val << 16u) & 0xFFFF0000);
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
*tds_ptr++ = val;
|
||||||
|
val = ((val >> 8u) & 0x00FFFFFF) | ((val << 24u) & 0xFF000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
box[0] = 0;
|
||||||
|
for (i = 1; i < 256; i++) {
|
||||||
|
for (j = 1; j < 256; j++) {
|
||||||
|
uint16_t bv1 = 0;
|
||||||
|
uint16_t bv2 = j;
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
if (i & (1 << k))
|
||||||
|
bv1 ^= bv2;
|
||||||
|
bv2 *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((uint8_t)bv1 ^ ctx->xors[bv1 >> 8]) == 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
box[i] = j;
|
||||||
|
|
||||||
|
if (j == 256) /* ??? */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i += 16) {
|
||||||
|
for (j = 0; j < 16; j++) {
|
||||||
|
uint8_t val = 0;
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
val |= box[i | j] & (1 << k);
|
||||||
|
for (b = 0; b < 4; b++) {
|
||||||
|
uint8_t bv = box[i | j];
|
||||||
|
if (bv & (1 << ((b + k - 4) & 7)))
|
||||||
|
val ^= 1 << k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->sbox[i + j] = val ^ 0x63;
|
||||||
|
ctx->ibox[val ^ 0x63] = i + j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* originally recalculated in Namco's code (inlined?) */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
ctx->rcon[i] = rcon[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aes_decrypt_block(s14aes_handle* ctx, uint8_t* buf) {
|
||||||
|
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
|
||||||
|
uint8_t* ibox = ctx->ibox;
|
||||||
|
uint32_t* tds = ctx->tds;
|
||||||
|
uint32_t* rk = ctx->rk;
|
||||||
|
|
||||||
|
s0 = rk[48] ^ GET_U32BE(buf + 0);
|
||||||
|
s1 = rk[49] ^ GET_U32BE(buf + 4);
|
||||||
|
s2 = rk[50] ^ GET_U32BE(buf + 8);
|
||||||
|
s3 = rk[51] ^ GET_U32BE(buf + 12);
|
||||||
|
|
||||||
|
t0 = rk[44] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
|
||||||
|
t1 = rk[45] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
|
||||||
|
t2 = rk[46] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
|
||||||
|
t3 = rk[47] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
|
||||||
|
|
||||||
|
s0 = rk[40] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
|
||||||
|
s1 = rk[41] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
|
||||||
|
s2 = rk[42] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
|
||||||
|
s3 = rk[43] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
|
||||||
|
|
||||||
|
t0 = rk[36] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
|
||||||
|
t1 = rk[37] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
|
||||||
|
t2 = rk[38] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
|
||||||
|
t3 = rk[39] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
|
||||||
|
|
||||||
|
s0 = rk[32] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
|
||||||
|
s1 = rk[33] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
|
||||||
|
s2 = rk[34] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
|
||||||
|
s3 = rk[35] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
|
||||||
|
|
||||||
|
t0 = rk[28] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
|
||||||
|
t1 = rk[29] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
|
||||||
|
t2 = rk[30] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
|
||||||
|
t3 = rk[31] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
|
||||||
|
|
||||||
|
s0 = rk[24] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
|
||||||
|
s1 = rk[25] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
|
||||||
|
s2 = rk[26] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
|
||||||
|
s3 = rk[27] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
|
||||||
|
|
||||||
|
t0 = rk[20] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
|
||||||
|
t1 = rk[21] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
|
||||||
|
t2 = rk[22] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
|
||||||
|
t3 = rk[23] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
|
||||||
|
|
||||||
|
s0 = rk[16] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
|
||||||
|
s1 = rk[17] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
|
||||||
|
s2 = rk[18] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
|
||||||
|
s3 = rk[19] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
|
||||||
|
|
||||||
|
t0 = rk[12] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
|
||||||
|
t1 = rk[13] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
|
||||||
|
t2 = rk[14] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
|
||||||
|
t3 = rk[15] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
|
||||||
|
|
||||||
|
s0 = rk[8 ] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
|
||||||
|
s1 = rk[9 ] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
|
||||||
|
s2 = rk[10] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
|
||||||
|
s3 = rk[11] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
|
||||||
|
|
||||||
|
t0 = rk[4 ] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
|
||||||
|
t1 = rk[5 ] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
|
||||||
|
t2 = rk[6 ] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
|
||||||
|
t3 = rk[7 ] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
|
||||||
|
|
||||||
|
buf[0 ] = GET_B3(rk[0]) ^ ibox[GET_B3(t0)];
|
||||||
|
buf[1 ] = GET_B2(rk[0]) ^ ibox[GET_B2(t3)];
|
||||||
|
buf[2 ] = GET_B1(rk[0]) ^ ibox[GET_B1(t2)];
|
||||||
|
buf[3 ] = GET_B0(rk[0]) ^ ibox[GET_B0(t1)];
|
||||||
|
buf[4 ] = GET_B3(rk[1]) ^ ibox[GET_B3(t1)];
|
||||||
|
buf[5 ] = GET_B2(rk[1]) ^ ibox[GET_B2(t0)];
|
||||||
|
buf[6 ] = GET_B1(rk[1]) ^ ibox[GET_B1(t3)];
|
||||||
|
buf[7 ] = GET_B0(rk[1]) ^ ibox[GET_B0(t2)];
|
||||||
|
buf[8 ] = GET_B3(rk[2]) ^ ibox[GET_B3(t2)];
|
||||||
|
buf[9 ] = GET_B2(rk[2]) ^ ibox[GET_B2(t1)];
|
||||||
|
buf[10] = GET_B1(rk[2]) ^ ibox[GET_B1(t0)];
|
||||||
|
buf[11] = GET_B0(rk[2]) ^ ibox[GET_B0(t3)];
|
||||||
|
buf[12] = GET_B3(rk[3]) ^ ibox[GET_B3(t3)];
|
||||||
|
buf[13] = GET_B2(rk[3]) ^ ibox[GET_B2(t2)];
|
||||||
|
buf[14] = GET_B1(rk[3]) ^ ibox[GET_B1(t1)];
|
||||||
|
buf[15] = GET_B0(rk[3]) ^ ibox[GET_B0(t0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************** */
|
||||||
|
|
||||||
|
s14aes_handle* s14aes_init() {
|
||||||
|
s14aes_handle* ctx = malloc(sizeof(s14aes_handle));
|
||||||
|
if (!ctx) goto fail;
|
||||||
|
|
||||||
|
aes_init_state(ctx);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
fail:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void s14aes_close(s14aes_handle* ctx) {
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s14aes_set_key(s14aes_handle* ctx, const uint8_t* key) {
|
||||||
|
aes_init_key(ctx, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s14aes_decrypt(s14aes_handle* ctx, uint8_t* buf) {
|
||||||
|
aes_decrypt_block(ctx, buf);
|
||||||
|
}
|
19
src/coding/g7221_decoder_aes.h
Normal file
19
src/coding/g7221_decoder_aes.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _G7221_DECODER_AES_H
|
||||||
|
#define _G7221_DECODER_AES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct s14aes_handle s14aes_handle;
|
||||||
|
|
||||||
|
/* init/close handle (AES-192 in ECB mode) */
|
||||||
|
s14aes_handle* s14aes_init();
|
||||||
|
|
||||||
|
void s14aes_close(s14aes_handle* ctx);
|
||||||
|
|
||||||
|
/* set new key (can be called multiple times) */
|
||||||
|
void s14aes_set_key(s14aes_handle* ctx, const uint8_t* key);
|
||||||
|
|
||||||
|
/* decrypt a single 0x10 block */
|
||||||
|
void s14aes_decrypt(s14aes_handle* ctx, uint8_t* buf);
|
||||||
|
|
||||||
|
#endif
|
@ -3,6 +3,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "g7221_decoder_lib.h"
|
#include "g7221_decoder_lib.h"
|
||||||
|
#include "g7221_decoder_aes.h"
|
||||||
|
|
||||||
|
|
||||||
/* Decodes Siren14 from Namco's BNSF, a mono MLT/DCT-based codec for speech/sound (low bandwidth).
|
/* Decodes Siren14 from Namco's BNSF, a mono MLT/DCT-based codec for speech/sound (low bandwidth).
|
||||||
@ -35,7 +36,7 @@
|
|||||||
* - very minor change in bit unpacking (minor output diffs)
|
* - very minor change in bit unpacking (minor output diffs)
|
||||||
* - modified DCT-IV optimizations, scaling and window functions (minor output diffs)
|
* - modified DCT-IV optimizations, scaling and window functions (minor output diffs)
|
||||||
* - internally PCM16 bufs, but converts to float (sample/32768.0) afterwards if the platform needs it
|
* - internally PCM16 bufs, but converts to float (sample/32768.0) afterwards if the platform needs it
|
||||||
* - less error control
|
* - less error control (on error decoder is supposed to repeat last coefs)
|
||||||
* - can't decode Siren7, and given output diffs it's not actually ITU-compliant
|
* - can't decode Siren7, and given output diffs it's not actually ITU-compliant
|
||||||
* - minor optimizations here and there but otherwise very similar
|
* - minor optimizations here and there but otherwise very similar
|
||||||
* This decoder generally uses Polycom's terminology, and while some parts like the bitreader could be
|
* This decoder generally uses Polycom's terminology, and while some parts like the bitreader could be
|
||||||
@ -93,13 +94,14 @@ static int imlt_window(int16_t* new_samples, int16_t* old_samples, int16_t* out_
|
|||||||
old_ptr = old_samples + 0;
|
old_ptr = old_samples + 0;
|
||||||
new_ptr = new_samples + 320;
|
new_ptr = new_samples + 320;
|
||||||
|
|
||||||
for (i = 320; i > 0; --i) {
|
for (i = 0; i < 320; i++) {
|
||||||
*old_ptr++ = *new_ptr++;
|
old_ptr[i] = new_ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* "dct4_x640_int" */
|
||||||
static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
|
static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
|
||||||
int i, j, k, n;
|
int i, j, k, n;
|
||||||
const uint8_t *set1_ptr;
|
const uint8_t *set1_ptr;
|
||||||
@ -186,55 +188,55 @@ static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
|
|||||||
{
|
{
|
||||||
int cos_val, sin_val;
|
int cos_val, sin_val;
|
||||||
const uint16_t *cos_ptr, *sin_ptr, *cos_ptr_lo, *sin_ptr_lo;
|
const uint16_t *cos_ptr, *sin_ptr, *cos_ptr_lo, *sin_ptr_lo;
|
||||||
int16_t C_in_val_lo, C_in_val_hi, C_in_val_mlo, C_in_val_mhi;
|
int16_t mlt_val_lo, mlt_val_hi, mlt_val_mlo, mlt_val_mhi;
|
||||||
int16_t *C_in_ptr, *C_in_ptr_lo, *C_in_ptr_hi, *C_in_ptr_mlo, *C_in_ptr_mhi;
|
int16_t *mlt_ptr, *mlt_ptr_lo, *mlt_ptr_hi, *mlt_ptr_mlo, *mlt_ptr_mhi;
|
||||||
|
|
||||||
cos_ptr = &imlt_cos_tables[320+160]; /* cos_table_16 > 8 > 4 > 2 */
|
cos_ptr = &imlt_cos_tables[320+160]; /* cos_table_16 > 8 > 4 > 2 */
|
||||||
sin_ptr = &imlt_sin_tables[320+160]; /* sin_table_16 > 8 > 4 > 2 */
|
sin_ptr = &imlt_sin_tables[320+160]; /* sin_table_16 > 8 > 4 > 2 */
|
||||||
|
|
||||||
for (n = 160; n >= 20; n /= 2) {
|
for (n = 160; n >= 20; n /= 2) {
|
||||||
C_in_ptr = mlt_coefs + 0;
|
mlt_ptr = mlt_coefs + 0;
|
||||||
while (C_in_ptr < mlt_coefs + 640) {
|
while (mlt_ptr < mlt_coefs + 640) {
|
||||||
for (j = *set1_ptr; j > 0; --j) {
|
for (j = *set1_ptr; j > 0; --j) {
|
||||||
C_in_ptr_lo = C_in_ptr + 0;
|
mlt_ptr_lo = mlt_ptr + 0;
|
||||||
C_in_ptr_hi = C_in_ptr + n;
|
mlt_ptr_hi = mlt_ptr + n;
|
||||||
C_in_ptr_mlo = C_in_ptr + (n / 2);
|
mlt_ptr_mlo = mlt_ptr + (n / 2);
|
||||||
C_in_ptr_mhi = C_in_ptr + (n / 2);
|
mlt_ptr_mhi = mlt_ptr + (n / 2);
|
||||||
for (k = n / 4; k > 0; --k) {
|
for (k = n / 4; k > 0; --k) {
|
||||||
C_in_val_lo = *C_in_ptr_lo;
|
mlt_val_lo = *mlt_ptr_lo;
|
||||||
C_in_val_hi = *--C_in_ptr_hi;
|
mlt_val_hi = *--mlt_ptr_hi;
|
||||||
C_in_val_mhi = *--C_in_ptr_mhi;
|
mlt_val_mhi = *--mlt_ptr_mhi;
|
||||||
C_in_val_mlo = *C_in_ptr_mlo;
|
mlt_val_mlo = *mlt_ptr_mlo;
|
||||||
*C_in_ptr_lo++ = C_in_val_lo + C_in_val_hi;
|
*mlt_ptr_lo++ = mlt_val_lo + mlt_val_hi;
|
||||||
*C_in_ptr_mlo++ = C_in_val_lo - C_in_val_hi;
|
*mlt_ptr_mlo++ = mlt_val_lo - mlt_val_hi;
|
||||||
*C_in_ptr_mhi = C_in_val_mlo + C_in_val_mhi;
|
*mlt_ptr_mhi = mlt_val_mlo + mlt_val_mhi;
|
||||||
*C_in_ptr_hi = C_in_val_mhi - C_in_val_mlo;
|
*mlt_ptr_hi = mlt_val_mhi - mlt_val_mlo;
|
||||||
}
|
}
|
||||||
C_in_ptr += n;
|
mlt_ptr += n;
|
||||||
}
|
}
|
||||||
set1_ptr++;
|
set1_ptr++;
|
||||||
|
|
||||||
for (j = *set1_ptr; j > 0; --j) {
|
for (j = *set1_ptr; j > 0; --j) {
|
||||||
C_in_ptr_lo = C_in_ptr + 0;
|
mlt_ptr_lo = mlt_ptr + 0;
|
||||||
C_in_ptr_hi = C_in_ptr + n;
|
mlt_ptr_hi = mlt_ptr + n;
|
||||||
cos_ptr_lo = cos_ptr + 0;
|
cos_ptr_lo = cos_ptr + 0;
|
||||||
sin_ptr_lo = sin_ptr + 0;
|
sin_ptr_lo = sin_ptr + 0;
|
||||||
for (k = n / 4; k > 0; --k) {
|
for (k = n / 4; k > 0; --k) {
|
||||||
cos_val = *cos_ptr_lo++;
|
cos_val = *cos_ptr_lo++;
|
||||||
sin_val = *sin_ptr_lo++;
|
sin_val = *sin_ptr_lo++;
|
||||||
C_in_val_lo = *C_in_ptr_lo;
|
mlt_val_lo = *mlt_ptr_lo;
|
||||||
C_in_val_hi = *--C_in_ptr_hi;
|
mlt_val_hi = *--mlt_ptr_hi;
|
||||||
*C_in_ptr_lo++ = (cos_val * C_in_val_lo + sin_val * C_in_val_hi + 32768) >> 16;
|
*mlt_ptr_lo++ = (cos_val * mlt_val_lo + sin_val * mlt_val_hi + 32768) >> 16;
|
||||||
*C_in_ptr_hi = (sin_val * -C_in_val_lo + cos_val * C_in_val_hi + 32768) >> 16;
|
*mlt_ptr_hi = (sin_val * -mlt_val_lo + cos_val * mlt_val_hi + 32768) >> 16;
|
||||||
|
|
||||||
cos_val = *cos_ptr_lo++;
|
cos_val = *cos_ptr_lo++;
|
||||||
sin_val = *sin_ptr_lo++;
|
sin_val = *sin_ptr_lo++;
|
||||||
C_in_val_lo = *C_in_ptr_lo;
|
mlt_val_lo = *mlt_ptr_lo;
|
||||||
C_in_val_hi = *--C_in_ptr_hi;
|
mlt_val_hi = *--mlt_ptr_hi;
|
||||||
*C_in_ptr_lo++ = (cos_val * C_in_val_lo + sin_val * C_in_val_hi + 32768) >> 16;
|
*mlt_ptr_lo++ = (cos_val * mlt_val_lo + sin_val * mlt_val_hi + 32768) >> 16;
|
||||||
*C_in_ptr_hi = (sin_val * C_in_val_lo - cos_val * C_in_val_hi + 32768) >> 16;
|
*mlt_ptr_hi = (sin_val * mlt_val_lo - cos_val * mlt_val_hi + 32768) >> 16;
|
||||||
}
|
}
|
||||||
C_in_ptr += n;
|
mlt_ptr += n;
|
||||||
}
|
}
|
||||||
set1_ptr++;
|
set1_ptr++;
|
||||||
}
|
}
|
||||||
@ -408,7 +410,7 @@ static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
|
|||||||
new_ptr += 10;
|
new_ptr += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* below is some three way swapping tmp ptrs change between mlt<>new */
|
/* below is some three way swapping, tmp ptrs change between mlt<>new */
|
||||||
tmp0_ptr = mlt_coefs + 640;
|
tmp0_ptr = mlt_coefs + 640;
|
||||||
tmp1_ptr = new_samples + 640;
|
tmp1_ptr = new_samples + 640;
|
||||||
for (n = 20; n <= 160; n *= 2) {
|
for (n = 20; n <= 160; n *= 2) {
|
||||||
@ -532,18 +534,18 @@ static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* transform frequency domain MLT spectrum coefs to time domain PCM samples with reverse/inverse MLT */
|
/* "inverse_MLT" */
|
||||||
static int rmlt_coefs_to_samples(int mag_shift, int16_t* mlt_coefs, int16_t* old_samples, int16_t* out_samples /*, int p_samples_done*/) {
|
static int rmlt_coefs_to_samples(int mag_shift, int16_t* mlt_coefs, int16_t* old_samples, int16_t* out_samples /*, int p_samples_done*/) {
|
||||||
int res;
|
int res;
|
||||||
int16_t new_samples[640];
|
int16_t new_samples[640];
|
||||||
|
|
||||||
/* block transform coefs-to-samples using DCT-IV (inverse) */
|
/* block transform MLT spectrum coefs to time domain PCM samples using DCT-IV (inverse) */
|
||||||
res = imlt_dct4(mlt_coefs, new_samples, mag_shift);
|
res = imlt_dct4(mlt_coefs, new_samples, mag_shift);
|
||||||
if (res) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
/* apply IMLT overlapped window filter function (640 samples) */
|
/* apply IMLT overlapped window filter function (640 samples) */
|
||||||
res = imlt_window(new_samples, old_samples, out_samples);
|
res = imlt_window(new_samples, old_samples, out_samples);
|
||||||
if (res) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
//*p_samples_done = 640; /* in Namco's code but actually ignored */
|
//*p_samples_done = 640; /* in Namco's code but actually ignored */
|
||||||
|
|
||||||
@ -802,7 +804,7 @@ static inline void index_to_array(int index, int* array_cv, int category) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, int bit_count, uint32_t* p_random_value, int* decoder_region_standard_deviation, int* power_categories, int16_t* mlt_coefs) {
|
static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int* p_bitpos, int bit_count, uint32_t* p_random_value, int* decoder_region_standard_deviation, int* power_categories, int16_t* mlt_coefs) {
|
||||||
int16_t standard_deviation;
|
int16_t standard_deviation;
|
||||||
int array_cv[MAX_VECTOR_DIMENSION];
|
int array_cv[MAX_VECTOR_DIMENSION];
|
||||||
int i, v, region, category, index;
|
int i, v, region, category, index;
|
||||||
@ -810,8 +812,8 @@ static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, i
|
|||||||
uint32_t* ptr_u32;
|
uint32_t* ptr_u32;
|
||||||
|
|
||||||
/* bitreading setup */
|
/* bitreading setup */
|
||||||
ptr_u32 = &data_u32[(bitpos >> 5)];
|
ptr_u32 = &data_u32[(*p_bitpos >> 5)];
|
||||||
bitmask = 1 << (31 - (bitpos & 0x1F));
|
bitmask = 1 << (31 - (*p_bitpos & 0x1F));
|
||||||
cur_u32 = *ptr_u32;
|
cur_u32 = *ptr_u32;
|
||||||
ptr_u32++;
|
ptr_u32++;
|
||||||
|
|
||||||
@ -832,6 +834,7 @@ static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, i
|
|||||||
do {
|
do {
|
||||||
int bit = (bitmask & cur_u32) != 0;
|
int bit = (bitmask & cur_u32) != 0;
|
||||||
bitmask >>= 1;
|
bitmask >>= 1;
|
||||||
|
(*p_bitpos)++;
|
||||||
if (bitmask == 0) {
|
if (bitmask == 0) {
|
||||||
bitmask = 0x80000000;
|
bitmask = 0x80000000;
|
||||||
cur_u32 = *ptr_u32;
|
cur_u32 = *ptr_u32;
|
||||||
@ -872,6 +875,7 @@ static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, i
|
|||||||
|
|
||||||
negative = (bitmask & cur_u32) != 0;
|
negative = (bitmask & cur_u32) != 0;
|
||||||
bitmask >>= 1;
|
bitmask >>= 1;
|
||||||
|
(*p_bitpos)++;
|
||||||
if (bitmask == 0) {
|
if (bitmask == 0) {
|
||||||
bitmask = 0x80000000;
|
bitmask = 0x80000000;
|
||||||
cur_u32 = *ptr_u32;
|
cur_u32 = *ptr_u32;
|
||||||
@ -1015,7 +1019,7 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
|
|||||||
res = categorize(
|
res = categorize(
|
||||||
8 * expected_frame_size - bitpos,
|
8 * expected_frame_size - bitpos,
|
||||||
absolute_region_power_index, power_categories, category_balances);
|
absolute_region_power_index, power_categories, category_balances);
|
||||||
if (res) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
/* adjust power categories (rate_adjust_categories) */
|
/* adjust power categories (rate_adjust_categories) */
|
||||||
{
|
{
|
||||||
@ -1060,16 +1064,44 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
|
|||||||
|
|
||||||
/* decode the quantized bits into MLT coefs */
|
/* decode the quantized bits into MLT coefs */
|
||||||
res = decode_vector_quantized_mlt_indices(
|
res = decode_vector_quantized_mlt_indices(
|
||||||
data_u32, bitpos, 8 * expected_frame_size,
|
data_u32, &bitpos, 8 * expected_frame_size,
|
||||||
p_random_value,
|
p_random_value,
|
||||||
decoder_region_standard_deviation, power_categories, mlt_coefs);
|
decoder_region_standard_deviation, power_categories, mlt_coefs);
|
||||||
if (res) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
|
|
||||||
|
/* test for errors (in refdec but not Namco's, useful to detect decryption) */
|
||||||
|
{
|
||||||
|
int bits_left = 8 * expected_frame_size - bitpos;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (bits_left > 0) {
|
||||||
|
/* frame must be padded with 1s */
|
||||||
|
for (i = 0; i < bits_left; i++) {
|
||||||
|
int bit = (data_u32[bitpos >> 5] >> (31 - (bitpos & 0x1F))) & 1;
|
||||||
|
bitpos++;
|
||||||
|
|
||||||
|
if (bit == 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* ? */
|
||||||
|
if (categorization_control < NUM_CATEGORIZATION_CONTROL_BITS - 1 && bits_left < 0)
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUMBER_OF_REGIONS; i++) {
|
||||||
|
if ((absolute_region_power_index[i] + ESF_ADJUSTMENT_TO_RMS_INDEX > 31) ||
|
||||||
|
(absolute_region_power_index[i] + ESF_ADJUSTMENT_TO_RMS_INDEX < -8))
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* API
|
* API
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@ -1078,13 +1110,15 @@ struct g7221_handle {
|
|||||||
/* control */
|
/* control */
|
||||||
int bit_rate;
|
int bit_rate;
|
||||||
int frame_size;
|
int frame_size;
|
||||||
|
/* AES setup/state */
|
||||||
|
s14aes_handle* aes;
|
||||||
/* state */
|
/* state */
|
||||||
int16_t mlt_coefs[MAX_DCT_LENGTH];
|
int16_t mlt_coefs[MAX_DCT_LENGTH];
|
||||||
int16_t old_samples[MAX_DCT_LENGTH >> 1];
|
int16_t old_samples[MAX_DCT_LENGTH >> 1];
|
||||||
uint32_t random_value;
|
uint32_t random_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
g7221_handle* g7221_init(int bytes_per_frame, int flags) {
|
g7221_handle* g7221_init(int bytes_per_frame) {
|
||||||
g7221_handle* handle = NULL;
|
g7221_handle* handle = NULL;
|
||||||
int bit_rate;
|
int bit_rate;
|
||||||
|
|
||||||
@ -1093,9 +1127,6 @@ g7221_handle* g7221_init(int bytes_per_frame, int flags) {
|
|||||||
if (bit_rate != 24000 && bit_rate != 32000 && bit_rate != 48000)
|
if (bit_rate != 24000 && bit_rate != 32000 && bit_rate != 48000)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
//if (flags != 0)
|
|
||||||
// goto fail;
|
|
||||||
|
|
||||||
handle = calloc(1, sizeof(g7221_handle));
|
handle = calloc(1, sizeof(g7221_handle));
|
||||||
if (!handle) goto fail;
|
if (!handle) goto fail;
|
||||||
|
|
||||||
@ -1111,41 +1142,38 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples) {
|
int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples) {
|
||||||
int res;
|
int res;
|
||||||
int mag_shift;
|
int mag_shift;
|
||||||
|
|
||||||
#if 0
|
/* first 0x10 bytes may be encrypted with AES. Original code also saves encrypted bytes,
|
||||||
/* first 0x10 bytes are encrypted with an unknown substitution key and a complex
|
* then re-crypts after unpacking, presumably to guard against memdumps. */
|
||||||
* unXOR function. Original code also saves encrypted bytes, then re-crypts after
|
if (handle->aes != NULL) {
|
||||||
* unpacking, presumably to guard against memdumps. */
|
s14aes_decrypt(handle->aes, data);
|
||||||
if (handle->flags & 0x02) {
|
|
||||||
decrypt_frame(data, key);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Namco's decoder is designed so that out_samples can be used in place of mlt_coefs,
|
/* Namco's decoder is designed so that out_samples can be set in place of mlt_coefs,
|
||||||
* so we could avoid one extra buffer, but for clarity we'll leave as is */
|
* so we could avoid one extra buffer, but for clarity we'll leave as is */
|
||||||
|
|
||||||
/* unpack data into MLT spectrum coefs */
|
/* unpack data into MLT spectrum coefs */
|
||||||
res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value);
|
res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value);
|
||||||
if (res) goto fail;
|
if (res < 0) goto fail;
|
||||||
|
|
||||||
/* convert coefs to samples using reverse (inverse) MLT */
|
/* convert coefs to samples using reverse (inverse) MLT */
|
||||||
res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples);
|
res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples);
|
||||||
if (res) goto fail;
|
if (res < 0) goto fail;
|
||||||
|
|
||||||
/* Namco also gets number of codes/samples done from unpack_frame/rmlt (ptr arg),
|
/* Namco also sets number of codes/samples done from unpack_frame/rmlt (ptr arg),
|
||||||
* but they seem unused */
|
* but they seem unused */
|
||||||
|
|
||||||
//todo return values
|
return 1;
|
||||||
return;
|
|
||||||
fail:
|
fail:
|
||||||
return;
|
//;printf("S14: fail %i\n", res);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
|
int g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
|
||||||
static const uint8_t empty_frame[0x3c] = {
|
static const uint8_t empty_frame[0x3c] = {
|
||||||
0x1E,0x0B,0x89,0x40,0x02,0x4F,0x51,0x35, 0x10,0xA1,0xFE,0xDF,0x52,0x51,0x10,0x0B,
|
0x1E,0x0B,0x89,0x40,0x02,0x4F,0x51,0x35, 0x10,0xA1,0xFE,0xDF,0x52,0x51,0x10,0x0B,
|
||||||
0xF0,0x69,0x7B,0xAE,0x18,0x17,0x00,0x52, 0x07,0x74,0xF4,0x65,0xA2,0x58,0xD8,0x3F,
|
0xF0,0x69,0x7B,0xAE,0x18,0x17,0x00,0x52, 0x07,0x74,0xF4,0x65,0xA2,0x58,0xD8,0x3F,
|
||||||
@ -1155,8 +1183,8 @@ void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
|
|||||||
int res;
|
int res;
|
||||||
int mag_shift;
|
int mag_shift;
|
||||||
|
|
||||||
/* This only seems to exist in older exes. Namco's samples don't seem to reach EOF,
|
/* This only seems to exist in older exes. Namco's samples don't reach EOF, so this
|
||||||
* so this wouldn't need to be called. Doesn't seem to use encoder delay either. */
|
* wouldn't need to be called. Doesn't seem to use encoder delay either. */
|
||||||
|
|
||||||
res = unpack_frame(24000, empty_frame, 0x3c, &mag_shift, handle->mlt_coefs, &handle->random_value);
|
res = unpack_frame(24000, empty_frame, 0x3c, &mag_shift, handle->mlt_coefs, &handle->random_value);
|
||||||
if (res) goto fail;
|
if (res) goto fail;
|
||||||
@ -1165,9 +1193,9 @@ void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
|
|||||||
res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples);
|
res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples);
|
||||||
if (res) goto fail;
|
if (res) goto fail;
|
||||||
|
|
||||||
return;
|
return 1;
|
||||||
fail:
|
fail:
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1184,5 +1212,46 @@ void g7221_reset(g7221_handle* handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void g7221_free(g7221_handle* handle) {
|
void g7221_free(g7221_handle* handle) {
|
||||||
|
if (!handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s14aes_close(handle->aes);
|
||||||
free(handle);
|
free(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int g7221_set_key(g7221_handle* handle, const uint8_t* key) {
|
||||||
|
const int key_size = 192 / 8; /* only 192 bit mode */
|
||||||
|
uint8_t temp_key[192 / 8];
|
||||||
|
const char* mod_key = "Ua#oK3P94vdxX,ft*k-mnjoO"; /* constant for all platform/games */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!handle)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* disable, useful for testing? */
|
||||||
|
if (key == NULL) {
|
||||||
|
s14aes_close(handle->aes);
|
||||||
|
handle->aes = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init AES state (tables) or reuse if already exists */
|
||||||
|
if (handle->aes == NULL) {
|
||||||
|
handle->aes = s14aes_init();
|
||||||
|
if (!handle->aes) goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base key is XORed probably against memdumps, as plain key would be part of the final AES key. However
|
||||||
|
* roundkey is still in memdumps near AES state (~0x1310 from sbox table, that starts with 0x63,0x7c,0x77,0x7b...)
|
||||||
|
* so it isn't too effective. XORing was originally done inside aes_expand_key during S14/S22 init. */
|
||||||
|
for (i = 0; i < key_size; i++) {
|
||||||
|
temp_key[i] = key[i] ^ mod_key[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset new key */
|
||||||
|
s14aes_set_key(handle->aes, temp_key);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Interface to Namco G.722.1 decoder
|
Interface to Namco G.722.1 decoder
|
||||||
*/
|
*/
|
||||||
#ifndef G7221_H
|
#ifndef _G7221_DECODER_LIB_H
|
||||||
#define G7221_H
|
#define _G7221_DECODER_LIB_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -10,14 +10,14 @@
|
|||||||
typedef struct g7221_handle g7221_handle;
|
typedef struct g7221_handle g7221_handle;
|
||||||
|
|
||||||
/* return a handle for decoding on successful init, NULL on failure */
|
/* return a handle for decoding on successful init, NULL on failure */
|
||||||
g7221_handle* g7221_init(int bytes_per_frame, int flags);
|
g7221_handle* g7221_init(int bytes_per_frame);
|
||||||
|
|
||||||
/* decode a frame, at code_words, into 16-bit PCM in sample_buffer */
|
/* decode a frame, at code_words, into 16-bit PCM in sample_buffer */
|
||||||
void g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples);
|
int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* decodes an empty frame after no more data is found (may be used to "drain" window samples */
|
/* decodes an empty frame after no more data is found (may be used to "drain" window samples */
|
||||||
void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples);
|
int g7221_decode_empty(g7221_handle* handle, int16_t* out_samples);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* reset the decoder to its initial state */
|
/* reset the decoder to its initial state */
|
||||||
@ -26,4 +26,7 @@ void g7221_reset(g7221_handle* handle);
|
|||||||
/* free resources */
|
/* free resources */
|
||||||
void g7221_free(g7221_handle* handle);
|
void g7221_free(g7221_handle* handle);
|
||||||
|
|
||||||
|
/* set new key (ignores key on failure) */
|
||||||
|
int g7221_set_key(g7221_handle* handle, const uint8_t* key);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
* for (i = 0; i < 640; i++)
|
* for (i = 0; i < 640; i++)
|
||||||
* window[i] = floor(sin((PI/2.0) * (i + 0.5) / 640) * 32767.0)
|
* window[i] = floor(sin((PI/2.0) * (i + 0.5) / 640) * 32767.0)
|
||||||
* while the original int refdec table uses an altered formula? (smaller values) */
|
* while the original int refdec table uses an altered formula? (smaller values) */
|
||||||
static const int16_t imlt_samples_window[MAX_DCT_LENGTH] = {
|
static const int16_t imlt_samples_window[MAX_DCT_LENGTH] = { /* "Out_Window"? */
|
||||||
40, 120, 201, 281, 361, 442, 522, 603, 683, 763,
|
40, 120, 201, 281, 361, 442, 522, 603, 683, 763,
|
||||||
844, 924, 1005, 1085, 1165, 1246, 1326, 1406, 1487, 1567,
|
844, 924, 1005, 1085, 1165, 1246, 1326, 1406, 1487, 1567,
|
||||||
1647, 1728, 1808, 1888, 1969, 2049, 2129, 2209, 2290, 2370,
|
1647, 1728, 1808, 1888, 1969, 2049, 2129, 2209, 2290, 2370,
|
||||||
@ -204,7 +204,7 @@ static const uint16_t imlt_cos_tables[636] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* see cos table info */
|
/* see cos table info */
|
||||||
static const uint16_t imlt_sin_tables[636] = {
|
static const uint16_t imlt_sin_tables[636] = { /* "sin_table" */
|
||||||
/* imlt_sin_table_64[320] (640/2) */
|
/* imlt_sin_table_64[320] (640/2) */
|
||||||
80, 241, 402, 562, 723, 884, 1045, 1206,
|
80, 241, 402, 562, 723, 884, 1045, 1206,
|
||||||
1367, 1527, 1688, 1849, 2010, 2171, 2331, 2492,
|
1367, 1527, 1688, 1849, 2010, 2171, 2331, 2492,
|
||||||
@ -326,7 +326,7 @@ static const uint16_t imlt_sin_tables[636] = {
|
|||||||
|
|
||||||
/* vs refdec: has region 0 (unused, all 0s) and regions>13 (repeats of region 13) so they were removed.
|
/* vs refdec: has region 0 (unused, all 0s) and regions>13 (repeats of region 13) so they were removed.
|
||||||
* 2nd index only went to DIFF_REGION_POWER_LEVELS-1 and last was added (all 0s though so probably unused). */
|
* 2nd index only went to DIFF_REGION_POWER_LEVELS-1 and last was added (all 0s though so probably unused). */
|
||||||
static const int16_t differential_region_power_decoder_tree[NUMBER_OF_REGIONS][DIFF_REGION_POWER_LEVELS][2] = {
|
static const int16_t differential_region_power_decoder_tree[NUMBER_OF_REGIONS][DIFF_REGION_POWER_LEVELS][2] = { /* "rms_table"? */
|
||||||
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{ 11,-12},{-11,-10},{ -8, -9},{ -7, -6},{-13, 12},{ -5, -4},{ 0, 13},{ -3,-14},{ -2, 14},{ -1, 15},{-15, 16},{-16, 17},{-17, 18},{ 19, 20},{ 21, 22},{-18,-19},{-20,-21},{-22,-23},{ 0, 0}},
|
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{ 11,-12},{-11,-10},{ -8, -9},{ -7, -6},{-13, 12},{ -5, -4},{ 0, 13},{ -3,-14},{ -2, 14},{ -1, 15},{-15, 16},{-16, 17},{-17, 18},{ 19, 20},{ 21, 22},{-18,-19},{-20,-21},{-22,-23},{ 0, 0}},
|
||||||
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{-10, -9},{ -8,-11},{ -7, -6},{ 9, -5},{ 10,-12},{ -4, 11},{-13, -3},{ 12, -2},{ 13,-14},{ -1, 14},{ 15,-15},{ 0, 16},{-16, 17},{-17, 18},{-18, 19},{ 20, 21},{ 22,-19},{-20,-21},{-22,-23},{ 0, 0}},
|
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{-10, -9},{ -8,-11},{ -7, -6},{ 9, -5},{ 10,-12},{ -4, 11},{-13, -3},{ 12, -2},{ 13,-14},{ -1, 14},{ 15,-15},{ 0, 16},{-16, 17},{-17, 18},{-18, 19},{ 20, 21},{ 22,-19},{-20,-21},{-22,-23},{ 0, 0}},
|
||||||
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{-12, 11},{-11,-13},{-10, -9},{ 12,-14},{ -8, -7},{-15, -6},{ 13, -5},{-16, -4},{ 14,-17},{ 15, -3},{ 16,-18},{ -2, 17},{ 18,-19},{ -1, 19},{-20, 20},{ 0, 21},{ 22,-21},{-22,-23},{ 0, 0}},
|
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{-12, 11},{-11,-13},{-10, -9},{ 12,-14},{ -8, -7},{-15, -6},{ 13, -5},{-16, -4},{ 14,-17},{ 15, -3},{ 16,-18},{ -2, 17},{ 18,-19},{ -1, 19},{-20, 20},{ 0, 21},{ 22,-21},{-22,-23},{ 0, 0}},
|
||||||
@ -343,7 +343,7 @@ static const int16_t differential_region_power_decoder_tree[NUMBER_OF_REGIONS][D
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* vs refdec: same table */
|
/* vs refdec: same table */
|
||||||
static const int16_t mlt_quant_centroid[NUM_CATEGORIES][NUM_BINS] = {
|
static const int16_t mlt_quant_centroid[NUM_CATEGORIES][NUM_BINS] = { /* "mlt_q" */
|
||||||
{ 0, 1606, 3119, 4586, 6049, 7502, 8941,10406,11851,13292,14736,16146,17566,19351, 0, 0},
|
{ 0, 1606, 3119, 4586, 6049, 7502, 8941,10406,11851,13292,14736,16146,17566,19351, 0, 0},
|
||||||
{ 0, 2229, 4341, 6401, 8471,10531,12583,14588,16673,18924, 0, 0, 0, 0, 0, 0},
|
{ 0, 2229, 4341, 6401, 8471,10531,12583,14588,16673,18924, 0, 0, 0, 0, 0, 0},
|
||||||
{ 0, 3055, 5998, 8929,11806,14680,17680, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
{ 0, 3055, 5998, 8929,11806,14680,17680, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
@ -361,7 +361,7 @@ static const int16_t expected_bits_table[NUM_CATEGORIES] = {
|
|||||||
|
|
||||||
/* vs refdec: Namco uses positive values *2 but I'm not sure what they are for (some index access)
|
/* vs refdec: Namco uses positive values *2 but I'm not sure what they are for (some index access)
|
||||||
* so these are the refdec values */
|
* so these are the refdec values */
|
||||||
static const int16_t mlt_decoder_tree_category_0[180][2] = {
|
static const int16_t mlt_decoder_tree_category_0[180][2] = { /* "reasion_huffman_table"? */
|
||||||
{ 1, 0},{ 2, 3},{ 4, 5},{ 6, 7},{ 8, 9},{ -1, -14},{ 10, 11},{ 12, 13},
|
{ 1, 0},{ 2, 3},{ 4, 5},{ 6, 7},{ 8, 9},{ -1, -14},{ 10, 11},{ 12, 13},
|
||||||
{ 14, 15},{ 16, 17},{ 18, 19},{ -15, 20},{ 21, 22},{ 23, -28},{ 24, -2},{ 25, 26},
|
{ 14, 15},{ 16, 17},{ 18, 19},{ -15, 20},{ 21, 22},{ 23, -28},{ 24, -2},{ 25, 26},
|
||||||
{ 27, 28},{ 29, 30},{ 31, 32},{ -29, 33},{ -16, 34},{ -3, 35},{ 36, 37},{ -42, 38},
|
{ 27, 28},{ 29, 30},{ 31, 32},{ -29, 33},{ -16, 34},{ -3, 35},{ 36, 37},{ -42, 38},
|
||||||
@ -541,7 +541,7 @@ static const int16_t *table_of_decoder_tables[NUM_CATEGORIES-1] = {
|
|||||||
|
|
||||||
|
|
||||||
/* vs refdec: same table */
|
/* vs refdec: same table */
|
||||||
static const int16_t region_standard_deviation_table[REGION_POWER_TABLE_SIZE] = {
|
static const int16_t region_standard_deviation_table[REGION_POWER_TABLE_SIZE] = { /* "rnd_reg"? */
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 1, 1,
|
0, 0, 0, 0, 0, 0, 1, 1,
|
||||||
@ -559,17 +559,17 @@ static const int16_t number_of_vectors[NUM_CATEGORIES] = {
|
|||||||
10, 10, 10, 5, 5, 4, 4, 0,
|
10, 10, 10, 5, 5, 4, 4, 0,
|
||||||
};
|
};
|
||||||
/* vs refdec: same table but last index is 1 */
|
/* vs refdec: same table but last index is 1 */
|
||||||
static const int16_t vector_dimension[NUM_CATEGORIES] = {
|
static const int16_t vector_dimension[NUM_CATEGORIES] = { /* "vd_inv"? */
|
||||||
2, 2, 2, 4, 4, 5, 5, 0,
|
2, 2, 2, 4, 4, 5, 5, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* vs refdec: pre-adds one instead of in runtime and last index is 1 */
|
/* vs refdec: pre-adds one instead of in runtime and last index is 1 */
|
||||||
static const int16_t max_bin_plus1[NUM_CATEGORIES] = {
|
static const int16_t max_bin_plus1[NUM_CATEGORIES] = { /* "kmax_p1" */
|
||||||
14, 10, 7, 5, 4, 3, 2, 0,
|
14, 10, 7, 5, 4, 3, 2, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* vs refdec: pre-scaled x2 (cat3 subs -1 and cat5/7 -2 too) */
|
/* vs refdec: pre-scaled x2 (cat3 subs -1 and cat5/7 -2 too) */
|
||||||
static const uint16_t max_bin_plus_one_inverse_scaled[8] = {
|
static const uint16_t max_bin_plus_one_inverse_scaled[8] = { /* "kmax_p1_inv" */
|
||||||
4682, 6554, 9363, 13108, 16384, 21846, 32768, 0,
|
4682, 6554, 9363, 13108, 16384, 21846, 32768, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -252,6 +252,10 @@
|
|||||||
RelativePath=".\meta\bgw_streamfile.h"
|
RelativePath=".\meta\bgw_streamfile.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\meta\bnsf_keys.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\meta\cri_utf.h"
|
RelativePath=".\meta\cri_utf.h"
|
||||||
>
|
>
|
||||||
@ -1894,6 +1898,10 @@
|
|||||||
RelativePath=".\coding\ea_mt_decoder_utk.h"
|
RelativePath=".\coding\ea_mt_decoder_utk.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\coding\g7221_decoder_aes.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\coding\g7221_decoder_lib.h"
|
RelativePath=".\coding\g7221_decoder_lib.h"
|
||||||
>
|
>
|
||||||
@ -2010,6 +2018,10 @@
|
|||||||
RelativePath=".\coding\g7221_decoder.c"
|
RelativePath=".\coding\g7221_decoder.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\coding\g7221_decoder_aes.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\coding\g7221_decoder_lib.c"
|
RelativePath=".\coding\g7221_decoder_lib.c"
|
||||||
>
|
>
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
<ClInclude Include="meta\awc_xma_streamfile.h" />
|
<ClInclude Include="meta\awc_xma_streamfile.h" />
|
||||||
<ClInclude Include="meta\bar_streamfile.h" />
|
<ClInclude Include="meta\bar_streamfile.h" />
|
||||||
<ClInclude Include="meta\bgw_streamfile.h" />
|
<ClInclude Include="meta\bgw_streamfile.h" />
|
||||||
|
<ClInclude Include="meta\bnsf_keys.h" />
|
||||||
<ClInclude Include="meta\cri_utf.h" />
|
<ClInclude Include="meta\cri_utf.h" />
|
||||||
<ClInclude Include="meta\deblock_streamfile.h" />
|
<ClInclude Include="meta\deblock_streamfile.h" />
|
||||||
<ClInclude Include="meta\ea_eaac_streamfile.h" />
|
<ClInclude Include="meta\ea_eaac_streamfile.h" />
|
||||||
@ -138,6 +139,7 @@
|
|||||||
<ClInclude Include="coding\acm_decoder_libacm.h" />
|
<ClInclude Include="coding\acm_decoder_libacm.h" />
|
||||||
<ClInclude Include="coding\coding.h" />
|
<ClInclude Include="coding\coding.h" />
|
||||||
<ClInclude Include="coding\ea_mt_decoder_utk.h" />
|
<ClInclude Include="coding\ea_mt_decoder_utk.h" />
|
||||||
|
<ClInclude Include="coding\g7221_decoder_aes.h" />
|
||||||
<ClInclude Include="coding\g7221_decoder_lib.h" />
|
<ClInclude Include="coding\g7221_decoder_lib.h" />
|
||||||
<ClInclude Include="coding\g7221_decoder_lib_data.h" />
|
<ClInclude Include="coding\g7221_decoder_lib_data.h" />
|
||||||
<ClInclude Include="coding\fsb_vorbis_data.h" />
|
<ClInclude Include="coding\fsb_vorbis_data.h" />
|
||||||
@ -559,6 +561,7 @@
|
|||||||
<ClCompile Include="coding\g719_decoder.c" />
|
<ClCompile Include="coding\g719_decoder.c" />
|
||||||
<ClCompile Include="coding\g721_decoder.c" />
|
<ClCompile Include="coding\g721_decoder.c" />
|
||||||
<ClCompile Include="coding\g7221_decoder.c" />
|
<ClCompile Include="coding\g7221_decoder.c" />
|
||||||
|
<ClCompile Include="coding\g7221_decoder_aes.c" />
|
||||||
<ClCompile Include="coding\g7221_decoder_lib.c" />
|
<ClCompile Include="coding\g7221_decoder_lib.c" />
|
||||||
<ClCompile Include="coding\hca_decoder.c" />
|
<ClCompile Include="coding\hca_decoder.c" />
|
||||||
<ClCompile Include="coding\ima_decoder.c" />
|
<ClCompile Include="coding\ima_decoder.c" />
|
||||||
|
@ -86,6 +86,9 @@
|
|||||||
<ClInclude Include="meta\bgw_streamfile.h">
|
<ClInclude Include="meta\bgw_streamfile.h">
|
||||||
<Filter>meta\Header Files</Filter>
|
<Filter>meta\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="meta\bnsf_keys.h">
|
||||||
|
<Filter>meta\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="meta\cri_utf.h">
|
<ClInclude Include="meta\cri_utf.h">
|
||||||
<Filter>meta\Header Files</Filter>
|
<Filter>meta\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -185,7 +188,7 @@
|
|||||||
<ClInclude Include="coding\ea_mt_decoder_utk.h">
|
<ClInclude Include="coding\ea_mt_decoder_utk.h">
|
||||||
<Filter>coding\Header Files</Filter>
|
<Filter>coding\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="coding\g7221_decoder_lib.h">
|
<ClInclude Include="coding\g7221_decoder_aes.h">
|
||||||
<Filter>coding\Header Files</Filter>
|
<Filter>coding\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="coding\g7221_decoder_lib_data.h">
|
<ClInclude Include="coding\g7221_decoder_lib_data.h">
|
||||||
@ -1192,6 +1195,9 @@
|
|||||||
<ClCompile Include="coding\g7221_decoder.c">
|
<ClCompile Include="coding\g7221_decoder.c">
|
||||||
<Filter>coding\Source Files</Filter>
|
<Filter>coding\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="coding\g7221_decoder_aes.c">
|
||||||
|
<Filter>coding\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="coding\g7221_decoder_lib.c">
|
<ClCompile Include="coding\g7221_decoder_lib.c">
|
||||||
<Filter>coding\Source Files</Filter>
|
<Filter>coding\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
#include "bnsf_keys.h"
|
||||||
|
|
||||||
/* BNSF - Namco Bandai's Bandai Namco Sound Format/File [Tales of Graces (Wii), Tales of Berseria (PS4)] */
|
|
||||||
|
static void find_bnsf_key(g7221_codec_data *data, off_t start, STREAMFILE *sf, uint8_t *best_key);
|
||||||
|
|
||||||
|
/* BNSF - Bandai Namco Sound Format/File [Tales of Graces (Wii), Tales of Berseria (PS4)] */
|
||||||
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
off_t start_offset = 0, first_offset = 0x0C;
|
off_t start_offset = 0, first_offset = 0x0C;
|
||||||
@ -19,11 +23,10 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
|||||||
if (read_32bitBE(0,streamFile) != 0x424E5346) /* "BNSF" */
|
if (read_32bitBE(0,streamFile) != 0x424E5346) /* "BNSF" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
bnsf_size = read_32bitBE(0x04,streamFile);
|
||||||
codec = read_32bitBE(0x08,streamFile);
|
codec = read_32bitBE(0x08,streamFile);
|
||||||
|
|
||||||
/* check file size (siren22 uses full size) */
|
if (bnsf_size + (codec == 0x49533232 ? 0x00 : 0x08) != get_streamfile_size(streamFile)) /* IS22 uses full size */
|
||||||
bnsf_size = read_32bitBE(0x04,streamFile);
|
|
||||||
if (bnsf_size + (codec == 0x49533232 ? 0x00 : 0x08) != get_streamfile_size(streamFile))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!find_chunk_be(streamFile, 0x73666d74,first_offset,0, &sfmt_chunk,NULL)) /* "sfmt" */
|
if (!find_chunk_be(streamFile, 0x73666d74,first_offset,0, &sfmt_chunk,NULL)) /* "sfmt" */
|
||||||
@ -40,15 +43,14 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
|||||||
channel_count = read_16bitBE(sfmt_chunk+0x02,streamFile);
|
channel_count = read_16bitBE(sfmt_chunk+0x02,streamFile);
|
||||||
sample_rate = read_32bitBE(sfmt_chunk+0x04,streamFile);
|
sample_rate = read_32bitBE(sfmt_chunk+0x04,streamFile);
|
||||||
num_samples = read_32bitBE(sfmt_chunk+0x08,streamFile);
|
num_samples = read_32bitBE(sfmt_chunk+0x08,streamFile);
|
||||||
loop_adjust = read_32bitBE(sfmt_chunk+0x0c,streamFile); /* 0 if no looping */
|
loop_adjust = read_32bitBE(sfmt_chunk+0x0c,streamFile); /* 0 when no loop */
|
||||||
block_size = read_16bitBE(sfmt_chunk+0x10,streamFile);
|
block_size = read_16bitBE(sfmt_chunk+0x10,streamFile);
|
||||||
block_samples = read_16bitBE(sfmt_chunk+0x12,streamFile);
|
block_samples = read_16bitBE(sfmt_chunk+0x12,streamFile);
|
||||||
//max_samples = sdat_size / block_size * block_samples /* num_samples is smaller */
|
//max_samples = sdat_size / block_size * block_samples;
|
||||||
|
|
||||||
start_offset = sdat_chunk;
|
start_offset = sdat_chunk;
|
||||||
|
|
||||||
/* shouldn't happen, plus decoder can't handle it */
|
if (loop_adjust >= block_samples) /* decoder can't handle this */
|
||||||
if (loop_adjust >= block_samples)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
@ -65,10 +67,6 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
|||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = block_size / channel_count;
|
vgmstream->interleave_block_size = block_size / channel_count;
|
||||||
|
|
||||||
/* Late IS14 set flag 0x02 = encrypted [Tales of Zestiria (PS3/PC) voices, The Idolm@ster 2 (PS3) voices] */
|
|
||||||
if (flags != 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
#ifdef VGM_USE_G7221
|
#ifdef VGM_USE_G7221
|
||||||
case 0x49533134: /* "IS14" (interleaved Siren14) */
|
case 0x49533134: /* "IS14" (interleaved Siren14) */
|
||||||
@ -76,10 +74,29 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
|||||||
vgmstream->codec_data = init_g7221(vgmstream->channels, vgmstream->interleave_block_size);
|
vgmstream->codec_data = init_g7221(vgmstream->channels, vgmstream->interleave_block_size);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
|
||||||
|
/* get decryption key in .bnsfkey file or list, for later games' voices
|
||||||
|
* [The Idolm@ster 2 (PS3/X360), Tales of Zestiria (PS3/PC)] */
|
||||||
|
if (flags != 0) { /* only known value is 0x02 though */
|
||||||
|
size_t keysize;
|
||||||
|
uint8_t key[24] = {0}; /* keystring 0-padded to 192-bit */
|
||||||
|
|
||||||
|
keysize = read_key_file(key, sizeof(key), streamFile);
|
||||||
|
if (keysize <= 0 || keysize > sizeof(key)) {
|
||||||
|
find_bnsf_key(vgmstream->codec_data, start_offset, streamFile, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_key_g7221(vgmstream->codec_data, key);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef VGM_USE_G719
|
#ifdef VGM_USE_G719
|
||||||
case 0x49533232: /* "IS22" (interleaved Siren22) */
|
case 0x49533232: /* "IS22" (interleaved Siren22) */
|
||||||
|
|
||||||
|
/* same encryption as IS14 but not seen */
|
||||||
|
if (flags != 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
vgmstream->coding_type = coding_G719;
|
vgmstream->coding_type = coding_G719;
|
||||||
vgmstream->codec_data = init_g719(vgmstream->channels, vgmstream->interleave_block_size);
|
vgmstream->codec_data = init_g719(vgmstream->channels, vgmstream->interleave_block_size);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
@ -99,3 +116,41 @@ fail:
|
|||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void find_bnsf_key(g7221_codec_data* data, off_t start, STREAMFILE* sf, uint8_t* best_key) {
|
||||||
|
const size_t keys_length = sizeof(s14key_list) / sizeof(bnsfkey_info);
|
||||||
|
int score, best_score = -1;
|
||||||
|
int i;
|
||||||
|
uint8_t tmpkey[24];
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < keys_length; i++) {
|
||||||
|
const char* key = s14key_list[i].key;
|
||||||
|
int keylen = strlen(key);
|
||||||
|
|
||||||
|
if (keylen > sizeof(tmpkey))
|
||||||
|
continue;
|
||||||
|
memcpy(tmpkey, key, keylen);
|
||||||
|
memset(tmpkey + keylen, 0, sizeof(tmpkey) - keylen);
|
||||||
|
|
||||||
|
//;VGM_LOG("BNSF: test key=%.24s\n", tmpkey);
|
||||||
|
set_key_g7221(data, tmpkey);
|
||||||
|
|
||||||
|
score = test_key_g7221(data, start, sf);
|
||||||
|
if (score < 0) continue;
|
||||||
|
|
||||||
|
if (best_score <= 0 || (score < best_score && score > 0)) {
|
||||||
|
best_score = score;
|
||||||
|
memcpy(best_key, key, keylen);
|
||||||
|
memset(best_key + keylen, 0, sizeof(tmpkey) - keylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_score == 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
|
||||||
|
VGM_ASSERT(best_score < 0, "BNSF: key not found\n"); /* defaults to all 0s */
|
||||||
|
}
|
||||||
|
16
src/meta/bnsf_keys.h
Normal file
16
src/meta/bnsf_keys.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _BNSF_KEYS_H_
|
||||||
|
#define _BNSF_KEYS_H_
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* key;
|
||||||
|
} bnsfkey_info;
|
||||||
|
|
||||||
|
/* Known keys, extracted from games' exe */
|
||||||
|
static const bnsfkey_info s14key_list[] = {
|
||||||
|
|
||||||
|
/* THE iDOLM@STER 2 (PS3/X360) */
|
||||||
|
{"haruka17imas"},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif/*_BNSF_KEYS_H_*/
|
@ -695,7 +695,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
|
|||||||
|
|
||||||
#ifdef VGM_USE_G7221
|
#ifdef VGM_USE_G7221
|
||||||
if (vgmstream->coding_type == coding_G7221C) {
|
if (vgmstream->coding_type == coding_G7221C) {
|
||||||
reset_g7221(vgmstream);
|
reset_g7221(vgmstream->codec_data);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -879,7 +879,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
|||||||
|
|
||||||
#ifdef VGM_USE_G7221
|
#ifdef VGM_USE_G7221
|
||||||
if (vgmstream->coding_type == coding_G7221C) {
|
if (vgmstream->coding_type == coding_G7221C) {
|
||||||
free_g7221(vgmstream);
|
free_g7221(vgmstream->codec_data);
|
||||||
vgmstream->codec_data = NULL;
|
vgmstream->codec_data = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user