mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
Improve CD-XA detection and RIFF-less support; minor XA code cleanup
This commit is contained in:
parent
6d7d6dcd54
commit
4dfbc3cf6a
@ -80,7 +80,8 @@ size_t ps_bytes_to_samples(size_t bytes, int channels);
|
|||||||
|
|
||||||
/* xa_decoder */
|
/* xa_decoder */
|
||||||
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
void init_get_high_nibble(VGMSTREAM * vgmstream);
|
void xa_init_get_high_nibble(VGMSTREAM * vgmstream);
|
||||||
|
size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked);
|
||||||
|
|
||||||
/* ea_xa_decoder */
|
/* ea_xa_decoder */
|
||||||
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
|
@ -20,8 +20,8 @@ static int CLAMP(int value, int Minim, int Maxim)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_get_high_nibble(VGMSTREAM *vgmstream) {
|
void xa_init_get_high_nibble(VGMSTREAM *vgmstream) {
|
||||||
vgmstream->get_high_nibble=1;
|
vgmstream->xa_get_high_nibble=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
@ -41,18 +41,18 @@ void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32
|
|||||||
|
|
||||||
first_sample = first_sample % 28;
|
first_sample = first_sample % 28;
|
||||||
|
|
||||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
vgmstream->xa_get_high_nibble=!vgmstream->xa_get_high_nibble;
|
||||||
|
|
||||||
if((first_sample) && (channelspacing==1))
|
if((first_sample) && (channelspacing==1))
|
||||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
vgmstream->xa_get_high_nibble=!vgmstream->xa_get_high_nibble;
|
||||||
|
|
||||||
predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) >> 4;
|
predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->xa_get_high_nibble,stream->streamfile) >> 4;
|
||||||
shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) & 0xf;
|
shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->xa_get_high_nibble,stream->streamfile) & 0xf;
|
||||||
|
|
||||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||||
short sample_byte = (short)read_8bit(stream->offset+16+framesin+(i*4),stream->streamfile);
|
short sample_byte = (short)read_8bit(stream->offset+16+framesin+(i*4),stream->streamfile);
|
||||||
|
|
||||||
scale = ((vgmstream->get_high_nibble ?
|
scale = ((vgmstream->xa_get_high_nibble ?
|
||||||
sample_byte >> 4 :
|
sample_byte >> 4 :
|
||||||
sample_byte & 0x0f)<<12);
|
sample_byte & 0x0f)<<12);
|
||||||
|
|
||||||
@ -70,3 +70,13 @@ void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32
|
|||||||
stream->adpcm_history1_32=hist1;
|
stream->adpcm_history1_32=hist1;
|
||||||
stream->adpcm_history2_32=hist2;
|
stream->adpcm_history2_32=hist2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked) {
|
||||||
|
if (is_blocked) {
|
||||||
|
//todo with -0x10 misses the last sector, not sure if bug or feature
|
||||||
|
return ((bytes - 0x10) / 0x930) * (0x900 - 18*0x10) * 2 / channels;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ((bytes / 0x80)*0xE0) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,48 +4,69 @@
|
|||||||
|
|
||||||
/* set up for the block at the given offset */
|
/* set up for the block at the given offset */
|
||||||
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
int i;
|
||||||
|
int8_t currentChannel=0;
|
||||||
|
int8_t subAudio=0;
|
||||||
|
|
||||||
int i;
|
xa_init_get_high_nibble(vgmstream);
|
||||||
int8_t currentChannel=0;
|
|
||||||
int8_t subAudio=0;
|
|
||||||
|
|
||||||
init_get_high_nibble(vgmstream);
|
|
||||||
|
|
||||||
if(vgmstream->samples_into_block!=0)
|
/* don't change this variable in the init process */
|
||||||
// don't change this variable in the init process
|
if (vgmstream->samples_into_block != 0)
|
||||||
vgmstream->xa_sector_length+=128;
|
vgmstream->xa_sector_length += 0x80;
|
||||||
|
|
||||||
// We get to the end of a sector ?
|
/* XA mode2/form2 sector
|
||||||
if(vgmstream->xa_sector_length==(18*128)) {
|
* 0x00: sync word
|
||||||
vgmstream->xa_sector_length=0;
|
* 0x0c: header = minute, second, sector, mode (always 0x02)
|
||||||
|
* 0x10: subheader = file, channel (marker), submode flags, xa header
|
||||||
|
* 0x14: subheader again
|
||||||
|
* 0x18: data
|
||||||
|
* 0x918: unused
|
||||||
|
* 0x92c: EDC/checksum or null
|
||||||
|
* 0x930: end
|
||||||
|
*/
|
||||||
|
|
||||||
// 0x30 of unused bytes/sector :(
|
/* submode flags (typical audio value = 0x64)
|
||||||
if (!vgmstream->xa_headerless) {
|
* - 7: end of file
|
||||||
block_offset+=0x30;
|
* - 6: real time mode
|
||||||
|
* - 5: sector form (0=form1, 1=form2)
|
||||||
|
* - 4: trigger (for application)
|
||||||
|
* - 3: data sector
|
||||||
|
* - 2: audio sector
|
||||||
|
* - 1: video sector
|
||||||
|
* - 0: end of audio
|
||||||
|
*/
|
||||||
|
|
||||||
|
// We get to the end of a sector ?
|
||||||
|
if (vgmstream->xa_sector_length == (18*0x80)) {
|
||||||
|
vgmstream->xa_sector_length = 0;
|
||||||
|
|
||||||
|
// 0x30 of unused bytes/sector :(
|
||||||
|
if (!vgmstream->xa_headerless) {
|
||||||
|
block_offset += 0x30;
|
||||||
begin:
|
begin:
|
||||||
// Search for selected channel & valid audio
|
// Search for selected channel & valid audio
|
||||||
currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile);
|
currentChannel = read_8bit(block_offset-0x07,vgmstream->ch[0].streamfile);
|
||||||
subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile);
|
subAudio = read_8bit(block_offset-0x06,vgmstream->ch[0].streamfile);
|
||||||
|
|
||||||
// audio is coded as 0x64
|
// audio is coded as 0x64
|
||||||
if(!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) {
|
if (!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) {
|
||||||
// go to next sector
|
// go to next sector
|
||||||
block_offset+=2352;
|
block_offset += 0x930;
|
||||||
if(currentChannel!=-1) goto begin;
|
if (currentChannel!=-1) goto begin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vgmstream->current_block_offset = block_offset;
|
vgmstream->current_block_offset = block_offset;
|
||||||
|
|
||||||
// Quid : how to stop the current channel ???
|
// Quid : how to stop the current channel ???
|
||||||
// i set up 0 to current_block_size to make vgmstream not playing bad samples
|
// i set up 0 to current_block_size to make vgmstream not playing bad samples
|
||||||
// another way to do it ???
|
// another way to do it ???
|
||||||
// (as the number of samples can be false in cd-xa due to multi-channels)
|
// (as the number of samples can be false in cd-xa due to multi-channels)
|
||||||
vgmstream->current_block_size = (currentChannel==-1?0:112);
|
vgmstream->current_block_size = (currentChannel==-1 ? 0 : 0x70);
|
||||||
|
|
||||||
vgmstream->next_block_offset = vgmstream->current_block_offset+128;
|
vgmstream->next_block_offset = vgmstream->current_block_offset + 0x80;
|
||||||
for (i=0;i<vgmstream->channels;i++) {
|
for (i=0;i<vgmstream->channels;i++) {
|
||||||
vgmstream->ch[i].offset = vgmstream->current_block_offset;
|
vgmstream->ch[i].offset = vgmstream->current_block_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,135 +1,118 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../layout/layout.h"
|
#include "../layout/layout.h"
|
||||||
#include "../util.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* Sony PSX CD-XA */
|
|
||||||
/* No looped file ! */
|
|
||||||
|
|
||||||
static off_t init_xa_channel(int *channel,STREAMFILE *streamFile);
|
|
||||||
|
|
||||||
static uint8_t AUDIO_CODING_GET_STEREO(uint8_t value) {
|
|
||||||
return (uint8_t)(value & 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t AUDIO_CODING_GET_FREQ(uint8_t value) {
|
|
||||||
return (uint8_t)((value >> 2) & 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* CD-XA - from Sony PS1 CDs */
|
||||||
VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
off_t start_offset;
|
||||||
|
int loop_flag = 0, channel_count, sample_rate;
|
||||||
|
int xa_channel=0;
|
||||||
|
int is_blocked;
|
||||||
|
size_t file_size = get_streamfile_size(streamFile);
|
||||||
|
|
||||||
int channel_count;
|
/* check extension (.xa: common, .str: sometimes used) */
|
||||||
int headerless=0;
|
if ( !check_extensions(streamFile,"xa,str") )
|
||||||
int xa_channel=0;
|
goto fail;
|
||||||
uint8_t bCoding;
|
|
||||||
off_t start_offset;
|
|
||||||
|
|
||||||
int i;
|
/* Proper XA comes in raw (BIN 2352 mode2/form2) CD sectors, that contain XA subheaders.
|
||||||
|
* This also has minimal support for headerless (ISO 2048 mode1/data) mode. */
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check RIFF header = raw (optional, added when ripping and not part of the CD data) */
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
if (read_32bitBE(0x00,streamFile) == 0x52494646 && /* "RIFF" */
|
||||||
if (strcasecmp("xa",filename_extension(filename))) goto fail;
|
read_32bitBE(0x08,streamFile) == 0x43445841 && /* "CDXA" */
|
||||||
|
read_32bitBE(0x0C,streamFile) == 0x666D7420) { /* "fmt " */
|
||||||
|
is_blocked = 1;
|
||||||
|
start_offset = 0x2c; /* after "data" (chunk size tends to be a bit off) */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* sector sync word = raw */
|
||||||
|
if (read_32bitBE(0x00,streamFile) == 0x00FFFFFF &&
|
||||||
|
read_32bitBE(0x04,streamFile) == 0xFFFFFFFF &&
|
||||||
|
read_32bitBE(0x08,streamFile) == 0xFFFFFF00) {
|
||||||
|
is_blocked = 1;
|
||||||
|
start_offset = 0x00;
|
||||||
|
}
|
||||||
|
else { /* headerless */
|
||||||
|
is_blocked = 0;
|
||||||
|
start_offset = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* check RIFF Header */
|
/* test first block (except when RIFF) */
|
||||||
if (!((read_32bitBE(0x00,streamFile) == 0x52494646) &&
|
if (start_offset == 0) {
|
||||||
(read_32bitBE(0x08,streamFile) == 0x43445841) &&
|
int i, j;
|
||||||
(read_32bitBE(0x0C,streamFile) == 0x666D7420)))
|
|
||||||
headerless=1;
|
|
||||||
|
|
||||||
/* don't misdetect Reflections' XA ("XA30" / "04SW") */
|
/* 0x80 frames for 1 sector (max ~0x800 for ISO mode) */
|
||||||
if (read_32bitBE(0x00,streamFile) == 0x58413330 || read_32bitBE(0x00,streamFile) == 0x30345357) goto fail;
|
for (i = 0; i < (0x800/0x80); i++) {
|
||||||
/* don't misdetect Maxis XA ("XAI\0" / "XAJ\0") */
|
off_t test_offset = start_offset + (is_blocked ? 0x18 : 0x00) + 0x80*i;
|
||||||
if (read_32bitBE(0x00,streamFile) == 0x58414900 || read_32bitBE(0x00,streamFile) == 0x58414A00) goto fail;
|
|
||||||
|
|
||||||
/* First init to have the correct info of the channel */
|
/* ADPCM predictors should be 0..3 index */
|
||||||
if (!headerless) {
|
for (j = 0; j < 16; j++) {
|
||||||
start_offset=init_xa_channel(&xa_channel,streamFile);
|
uint8_t header = read_8bit(test_offset + i, streamFile);
|
||||||
|
if (((header >> 4) & 0xF) > 3)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* No sound ? */
|
|
||||||
if(start_offset==0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
bCoding = read_8bit(start_offset-5,streamFile);
|
/* data is ok: parse header */
|
||||||
|
if (is_blocked) {
|
||||||
|
uint8_t xa_header;
|
||||||
|
|
||||||
switch (AUDIO_CODING_GET_STEREO(bCoding)) {
|
/* parse 0x18 sector header (also see xa_blocked.c) */
|
||||||
case 0: channel_count = 1; break;
|
xa_channel = read_8bit(start_offset + 0x11,streamFile);
|
||||||
case 1: channel_count = 2; break;
|
xa_header = read_8bit(start_offset + 0x13,streamFile);
|
||||||
default: channel_count = 0; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
switch((xa_header >> 0) & 3) { /* 0..1: stereo */
|
||||||
vgmstream = allocate_vgmstream(channel_count,0);
|
case 0: channel_count = 1; break;
|
||||||
if (!vgmstream) goto fail;
|
case 1: channel_count = 2; break;
|
||||||
|
default: goto fail;
|
||||||
|
}
|
||||||
|
switch((xa_header >> 2) & 3) { /* 2..3: sample rate */
|
||||||
|
case 0: sample_rate = 37800; break;
|
||||||
|
case 1: sample_rate = 18900; break;
|
||||||
|
default: goto fail;
|
||||||
|
}
|
||||||
|
VGM_ASSERT(((xa_header >> 4) & 3) == 1, /* 4..5: bits per sample (0=4, 1=8) */
|
||||||
|
"XA: 8 bits per sample mode found\n"); /* spec only? */
|
||||||
|
/* 6: emphasis (applies a filter but apparently not used by games)
|
||||||
|
* XA is also filtered when resampled to 44100 during output, differently from PS-ADPCM */
|
||||||
|
/* 7: reserved */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* headerless, probably will go wrong */
|
||||||
|
channel_count = 2;
|
||||||
|
sample_rate = 44100; /* not 37800? */
|
||||||
|
}
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
vgmstream->channels = channel_count;
|
|
||||||
vgmstream->xa_channel = xa_channel;
|
|
||||||
|
|
||||||
switch (AUDIO_CODING_GET_FREQ(bCoding)) {
|
/* build the VGMSTREAM */
|
||||||
case 0: vgmstream->sample_rate = 37800; break;
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
case 1: vgmstream->sample_rate = 18900; break;
|
if (!vgmstream) goto fail;
|
||||||
default: vgmstream->sample_rate = 0; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for Compression Scheme */
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_samples = (int32_t)((((get_streamfile_size(streamFile) - 0x3C)/2352)*0x1F80)/(2*channel_count));
|
vgmstream->num_samples = xa_bytes_to_samples(file_size - start_offset, channel_count, is_blocked);
|
||||||
} else
|
vgmstream->xa_headerless = !is_blocked;
|
||||||
{
|
vgmstream->xa_channel = xa_channel;
|
||||||
channel_count=2;
|
|
||||||
vgmstream = allocate_vgmstream(2,0);
|
|
||||||
if (!vgmstream) goto fail;
|
|
||||||
|
|
||||||
vgmstream->xa_headerless=1;
|
vgmstream->coding_type = coding_XA;
|
||||||
vgmstream->sample_rate=44100;
|
|
||||||
vgmstream->channels=2;
|
|
||||||
vgmstream->num_samples = (int32_t)(((get_streamfile_size(streamFile)/ 0x80)*0xE0)/2);
|
|
||||||
start_offset=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vgmstream->coding_type = coding_XA;
|
|
||||||
vgmstream->layout_type = layout_xa_blocked;
|
vgmstream->layout_type = layout_xa_blocked;
|
||||||
vgmstream->meta_type = meta_PSX_XA;
|
vgmstream->meta_type = meta_PSX_XA;
|
||||||
|
|
||||||
/* open the file for reading by each channel */
|
if (is_blocked)
|
||||||
{
|
start_offset += 0x18; /* move to first frame (hack for xa_blocked.c) */
|
||||||
STREAMFILE *chstreamfile;
|
|
||||||
chstreamfile = streamFile->open(streamFile,filename,2352);
|
|
||||||
|
|
||||||
if (!chstreamfile) goto fail;
|
/* open the file for reading */
|
||||||
|
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
for (i=0;i<channel_count;i++) {
|
xa_block_update(start_offset,vgmstream);
|
||||||
vgmstream->ch[i].streamfile = chstreamfile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xa_block_update(start_offset,vgmstream);
|
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
fail:
|
||||||
if (vgmstream) close_vgmstream(vgmstream);
|
if (vgmstream) close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t init_xa_channel(int* channel,STREAMFILE* streamFile) {
|
|
||||||
|
|
||||||
off_t block_offset=0x44;
|
|
||||||
size_t filelength=get_streamfile_size(streamFile);
|
|
||||||
|
|
||||||
int8_t currentChannel;
|
|
||||||
|
|
||||||
// 0 can't be a correct value
|
|
||||||
if(block_offset>=(off_t)filelength)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
currentChannel=read_8bit(block_offset-7,streamFile);
|
|
||||||
//subAudio=read_8bit(block_offset-6,streamFile);
|
|
||||||
*channel=currentChannel;
|
|
||||||
//if (!((currentChannel==channel) && (subAudio==0x64))) {
|
|
||||||
// block_offset+=2352;
|
|
||||||
// goto begin;
|
|
||||||
//}
|
|
||||||
return block_offset;
|
|
||||||
}
|
|
||||||
|
@ -715,10 +715,10 @@ typedef struct {
|
|||||||
layout_t layout_type; /* type of layout for data */
|
layout_t layout_type; /* type of layout for data */
|
||||||
meta_t meta_type; /* how we know the metadata */
|
meta_t meta_type; /* how we know the metadata */
|
||||||
|
|
||||||
/* streams (info only) */
|
/* subsongs */
|
||||||
int num_streams; /* for multi-stream formats (0=not set/one, 1=one stream) */
|
int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */
|
||||||
int stream_index; /* current stream */
|
int stream_index; /* selected stream (also 1-based) */
|
||||||
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream, if the file stores it and it's filled */
|
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */
|
||||||
|
|
||||||
/* looping */
|
/* looping */
|
||||||
int loop_flag; /* is this stream looped? */
|
int loop_flag; /* is this stream looped? */
|
||||||
@ -766,12 +766,10 @@ typedef struct {
|
|||||||
|
|
||||||
uint8_t xa_channel; /* XA ADPCM: selected channel */
|
uint8_t xa_channel; /* XA ADPCM: selected channel */
|
||||||
int32_t xa_sector_length; /* XA ADPCM: XA block */
|
int32_t xa_sector_length; /* XA ADPCM: XA block */
|
||||||
uint8_t xa_headerless; /* XA ADPCM: headerless XA block */
|
uint8_t xa_headerless; /* XA ADPCM: headerless XA */
|
||||||
|
int8_t xa_get_high_nibble; /* XA ADPCM: mono/stereo nibble selection (XA state could be simplified) */
|
||||||
|
|
||||||
int8_t get_high_nibble; /* ADPCM: which nibble (XA, IMA, EA) */
|
uint8_t ea_platform; /* EA block */
|
||||||
|
|
||||||
uint8_t ea_big_endian; /* EA ADPCM stuff */
|
|
||||||
uint8_t ea_platform;
|
|
||||||
|
|
||||||
int32_t ws_output_size; /* WS ADPCM: output bytes for this block */
|
int32_t ws_output_size; /* WS ADPCM: output bytes for this block */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user