mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
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:
parent
15206915d1
commit
0f529ea1a7
@ -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);
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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"},
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user