Add mu-Law with internal interleave decoder

This is needed for blocked layout, as it can't do normal interleave.
Probably could be fixed in the future to remove several superfluous
_int/block decoders
This commit is contained in:
bnnm 2017-12-24 01:39:24 +01:00
parent 98c5f0a65d
commit 2f9c16ae9b
5 changed files with 77 additions and 51 deletions

View File

@ -65,6 +65,7 @@ void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);

View File

@ -87,69 +87,83 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan
} }
} }
/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */ static int expand_ulaw(uint8_t ulawbyte) {
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int sign, segment, quantization, new_sample;
int i;
int32_t sample_count;
int sign, segment, quantization, sample;
const int bias = 0x84; const int bias = 0x84;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t ulawbyte = read_8bit(stream->offset+i,stream->streamfile);
ulawbyte = ~ulawbyte; /* stored in complement */ ulawbyte = ~ulawbyte; /* stored in complement */
sign = (ulawbyte & 0x80); sign = (ulawbyte & 0x80);
segment = (ulawbyte & 0x70) >> 4; /* exponent */ segment = (ulawbyte & 0x70) >> 4; /* exponent */
quantization = ulawbyte & 0x0F; /* mantissa */ quantization = ulawbyte & 0x0F; /* mantissa */
sample = (quantization << 3) + bias; /* add bias */ new_sample = (quantization << 3) + bias; /* add bias */
sample <<= segment; new_sample <<= segment;
sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */ new_sample = (sign) ? (bias - new_sample) : (new_sample - bias); /* remove bias */
#if 0 // the above follows Sun's implementation, but this works too #if 0 // the above follows Sun's implementation, but this works too
{ {
static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */ static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */
sample = exp_lut[segment] + (quantization << (segment + 3)); new_sample = exp_lut[segment] + (quantization << (segment + 3));
if (sign != 0) sample = -sample; if (sign != 0) new_sample = -new_sample;
} }
#endif #endif
outbuf[sample_count] = sample; return new_sample;
}
} }
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */ /* decodes u-law (ITU G.711 non-linear PCM), from g711.c */
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i; int i, sample_count;
int32_t sample_count;
int sign, segment, quantization, sample;
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) {
uint8_t alawbyte = read_8bit(stream->offset+i,stream->streamfile); uint8_t ulawbyte = read_8bit(stream->offset+i,stream->streamfile);
outbuf[sample_count] = expand_ulaw(ulawbyte);
}
}
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t ulawbyte = read_8bit(stream->offset+i*channelspacing,stream->streamfile);
outbuf[sample_count] = expand_ulaw(ulawbyte);
}
}
static int expand_alaw(uint8_t alawbyte) {
int sign, segment, quantization, new_sample;
alawbyte ^= 0x55; alawbyte ^= 0x55;
sign = (alawbyte & 0x80); sign = (alawbyte & 0x80);
segment = (alawbyte & 0x70) >> 4; /* exponent */ segment = (alawbyte & 0x70) >> 4; /* exponent */
quantization = alawbyte & 0x0F; /* mantissa */ quantization = alawbyte & 0x0F; /* mantissa */
sample = (quantization << 4); new_sample = (quantization << 4);
switch (segment) { switch (segment) {
case 0: case 0:
sample += 8; new_sample += 8;
break; break;
case 1: case 1:
sample += 0x108; new_sample += 0x108;
break; break;
default: default:
sample += 0x108; new_sample += 0x108;
sample <<= segment - 1; new_sample <<= segment - 1;
break; break;
} }
sample = (sign) ? sample : -sample; new_sample = (sign) ? new_sample : -new_sample;
outbuf[sample_count] = sample; return new_sample;
}
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t alawbyte = read_8bit(stream->offset+i,stream->streamfile);
outbuf[sample_count] = expand_alaw(alawbyte);;
} }
} }

View File

@ -423,6 +423,7 @@ static const coding_info coding_info_list[] = {
{coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"}, {coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"},
{coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave (block)"}, {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave (block)"},
{coding_ULAW, "8-bit u-Law"}, {coding_ULAW, "8-bit u-Law"},
{coding_ULAW_int, "8-bit u-Law with 1 byte interleave (block)"},
{coding_ALAW, "8-bit a-Law"}, {coding_ALAW, "8-bit a-Law"},
{coding_PCMFLOAT, "32-bit float PCM"}, {coding_PCMFLOAT, "32-bit float PCM"},

View File

@ -1002,6 +1002,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_PCM8_SB_int: case coding_PCM8_SB_int:
case coding_PCM8_U_int: case coding_PCM8_U_int:
case coding_ULAW: case coding_ULAW:
case coding_ULAW_int:
case coding_ALAW: case coding_ALAW:
case coding_PCMFLOAT: case coding_PCMFLOAT:
return 1; return 1;
@ -1157,6 +1158,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_PCM8_SB_int: case coding_PCM8_SB_int:
case coding_PCM8_U_int: case coding_PCM8_U_int:
case coding_ULAW: case coding_ULAW:
case coding_ULAW_int:
case coding_ALAW: case coding_ALAW:
return 1; return 1;
case coding_PCMFLOAT: case coding_PCMFLOAT:
@ -1405,6 +1407,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do); samples_to_do);
} }
break; break;
case coding_ULAW_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_ulaw_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
case coding_ALAW: case coding_ALAW:
for (chan=0;chan<vgmstream->channels;chan++) { for (chan=0;chan<vgmstream->channels;chan++) {
decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,

View File

@ -80,12 +80,13 @@ typedef enum {
coding_PCM16_int, /* 16-bit PCM with sample-level interleave (for blocks) */ coding_PCM16_int, /* 16-bit PCM with sample-level interleave (for blocks) */
coding_PCM8, /* 8-bit PCM */ coding_PCM8, /* 8-bit PCM */
coding_PCM8_int, /* 8-Bit PCM with sample-level interleave (for blocks) */ coding_PCM8_int, /* 8-bit PCM with sample-level interleave (for blocks) */
coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */ coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */
coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave (for blocks) */ coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave (for blocks) */
coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave (for blocks) */ coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave (for blocks) */
coding_ULAW, /* 8-bit u-Law (non-linear PCM) */ coding_ULAW, /* 8-bit u-Law (non-linear PCM) */
coding_ULAW_int, /* 8-bit u-Law (non-linear PCM) with sample-level interleave (for blocks) */
coding_ALAW, /* 8-bit a-Law (non-linear PCM) */ coding_ALAW, /* 8-bit a-Law (non-linear PCM) */
coding_PCMFLOAT, /* 32 bit float PCM */ coding_PCMFLOAT, /* 32 bit float PCM */