Remove BMDX decoder and use decryption streamfile instead

The encryption is built on top of PS ADPCM data, so this way mimics the
actual setup and removes a superfluous decoder
This commit is contained in:
bnnm 2018-03-27 22:39:05 +02:00
parent 15206915d1
commit 0f529ea1a7
6 changed files with 88 additions and 127 deletions

View File

@ -76,7 +76,6 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
void decode_hevag(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t ps_bytes_to_samples(size_t bytes, int channels);

View File

@ -110,52 +110,6 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
stream->adpcm_history2_32=hist2;
}
/* encrypted */
void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int predict_nr, shift_factor, sample;
int32_t hist1=stream->adpcm_history1_32;
int32_t hist2=stream->adpcm_history2_32;
short scale;
int i;
int32_t sample_count;
uint8_t flag;
int framesin = first_sample/28;
int head = read_8bit(stream->offset+framesin*16,stream->streamfile) ^ stream->bmdx_xor;
predict_nr = ((head >> 4) & 0xf);
shift_factor = (head & 0xf);
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile);
first_sample = first_sample % 28;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
sample=0;
if(flag<0x07) {
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
if (i/2 == 0)
sample_byte = (short)(int8_t)(sample_byte+stream->bmdx_add);
scale = ((i&1 ?
sample_byte >> 4 :
sample_byte & 0x0f)<<12);
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
}
outbuf[sample_count] = clamp16(sample);
hist2=hist1;
hist1=sample;
}
stream->adpcm_history1_32=hist1;
stream->adpcm_history2_32=hist2;
}
/* some games have garbage (?) in their flags, this decoder just ignores that byte */
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {

View File

@ -465,7 +465,6 @@ static const coding_info coding_info_list[] = {
{coding_XA, "CD-ROM XA 4-bit ADPCM"},
{coding_PSX, "Playstation 4-bit ADPCM"},
{coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"},
{coding_PSX_bmdx, "Playstation 4-bit ADPCM (BMDX encryption)"},
{coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"},
{coding_HEVAG, "Playstation Vita HEVAG 4-bit ADPCM"},

View File

@ -1,92 +1,116 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
static STREAMFILE* setup_bmdx_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size);
/* .bmdx - from Beatmania IIDX (PS2) games */
VGMSTREAM * init_vgmstream_ps2_bmdx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag=0;
int channel_count;
STREAMFILE *temp_streamFile = NULL;
off_t start_offset;
int i;
size_t data_size;
int loop_flag, channel_count, encryption;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("bmdx",filename_extension(filename))) goto fail;
/* check NPSF Header */
/* checks */
if (!check_extensions(streamFile, "bmdx"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x01006408 ||
read_32bitBE(0x04,streamFile) != 0)
read_32bitBE(0x04,streamFile) != 0x00)
goto fail;
/* check loop */
loop_flag = (read_32bitLE(0x10,streamFile)!=0);
channel_count=read_32bitLE(0x1C,streamFile);
start_offset = read_32bitLE(0x08,streamFile);
data_size = read_32bitLE(0x0c,streamFile);
loop_flag = (read_32bitLE(0x10,streamFile) != 0x00);
channel_count = read_32bitLE(0x1C,streamFile);
encryption = (read_32bitLE(0x20,streamFile) == 1);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
/* Check for Compression Scheme */
if (read_32bitLE(0x20,streamFile) == 1)
vgmstream->coding_type = coding_PSX_bmdx;
else
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitLE(0x0c,streamFile)*28/16/channel_count;
/* Get loop point values */
if(vgmstream->loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile)*28/16/channel_count;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
if (channel_count == 1) {
vgmstream->layout_type = layout_none;
} else if (channel_count > 1) {
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
vgmstream->layout_type = layout_interleave;
}
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x10,streamFile), channel_count);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_PS2_BMDX;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
start_offset = read_32bitLE(0x08,streamFile);
if (vgmstream->coding_type == coding_PSX_bmdx)
{
uint8_t xor = read_8bit(start_offset,streamFile);
uint8_t add = (~(uint8_t)read_8bit(start_offset+2,streamFile))+1;
int c;
for (c=0;c<channel_count;c++) {
vgmstream->ch[c].bmdx_xor = xor;
vgmstream->ch[c].bmdx_add = add;
}
/* later games are encrypted [beatmaniaIIDX 14 GOLD (PS2)] */
if (encryption) {
temp_streamFile = setup_bmdx_streamfile(streamFile, start_offset, data_size);
if (!temp_streamFile) goto fail;
}
/* open the file for reading by each channel */
{
for (i=0;i<channel_count;i++) {
if (!vgmstream->ch[0].streamfile) {
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,0x8000);
}
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
if (!vgmstream_open_stream(vgmstream,encryption ? temp_streamFile : streamFile,start_offset))
goto fail;
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
(off_t)(start_offset+vgmstream->interleave_block_size*i);
}
}
close_streamfile(temp_streamFile);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
typedef struct {
uint8_t xor;
uint8_t add;
off_t start_offset;
size_t data_size;
} bmdx_decryption_data;
static size_t bmdx_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, bmdx_decryption_data* data) {
size_t bytes_read;
int i;
bytes_read = streamfile->read(streamfile, dest, offset, length);
/* decrypt data (xor) */
for (i = 0; i < bytes_read; i++) {
if (offset+i >= data->start_offset && offset+i < data->start_offset + data->data_size) {
if (((offset+i) % 0x10) == 0) /* XOR header byte per frame */
dest[i] = dest[i] ^ data->xor;
else if (((offset+i) % 0x10) == 2) /* ADD first data byte per frame */
dest[i] = (uint8_t)(dest[i] + data->add);
}
}
return bytes_read;
}
static STREAMFILE* setup_bmdx_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
bmdx_decryption_data io_data = {0};
size_t io_data_size = sizeof(bmdx_decryption_data);
/* setup decryption (usually xor=0xFF and add=0x02) */
io_data.xor = read_8bit(start_offset,streamFile);
io_data.add = (~(uint8_t)read_8bit(start_offset+2,streamFile)) + 0x01;
io_data.start_offset = start_offset;
io_data.data_size = data_size;
/* setup custom streamfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bmdx_decryption_read);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}

View File

@ -1029,7 +1029,6 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_XA:
case coding_PSX:
case coding_PSX_badflags:
case coding_PSX_bmdx:
case coding_HEVAG:
return 28;
case coding_PSX_cfg:
@ -1192,7 +1191,6 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 0x0e*vgmstream->channels;
case coding_PSX:
case coding_PSX_badflags:
case coding_PSX_bmdx:
case coding_HEVAG:
return 0x10;
case coding_PSX_cfg:
@ -1518,13 +1516,6 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do);
}
break;
case coding_PSX_bmdx:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_psx_bmdx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
case coding_HEVAG:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_hevag(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
@ -1953,7 +1944,6 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
vgmstream->meta_type == meta_DSP_RS03 ||
vgmstream->meta_type == meta_DSP_CSTR ||
vgmstream->coding_type == coding_PSX ||
vgmstream->coding_type == coding_PSX_bmdx ||
vgmstream->coding_type == coding_PSX_badflags) {
int i;
for (i=0;i<vgmstream->channels;i++) {

View File

@ -111,7 +111,6 @@ typedef enum {
coding_XA, /* CD-ROM XA */
coding_PSX, /* Sony PS ADPCM (VAG) */
coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */
coding_PSX_bmdx, /* Sony PS ADPCM with BMDX encryption */
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */
coding_HEVAG, /* Sony PSVita ADPCM */
@ -716,10 +715,6 @@ typedef struct {
uint16_t adx_mult;
uint16_t adx_add;
/* BMDX encryption */
uint8_t bmdx_xor;
uint8_t bmdx_add;
/* generic encryption */
uint16_t key_xor;
} VGMSTREAMCHANNEL;