dsp: add MS ADPCM codec.
This commit is contained in:
parent
052f841d7f
commit
e50983fdff
@ -138,6 +138,7 @@ static void rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, rdpsndFormat* for
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 2: /* MS ADPCM */
|
||||||
case 0x11: /* IMA ADPCM */
|
case 0x11: /* IMA ADPCM */
|
||||||
alsa->format = SND_PCM_FORMAT_S16_LE;
|
alsa->format = SND_PCM_FORMAT_S16_LE;
|
||||||
alsa->bytes_per_channel = 2;
|
alsa->bytes_per_channel = 2;
|
||||||
@ -212,6 +213,7 @@ static boolean rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, rdpsndFo
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 2: /* MS ADPCM */
|
||||||
case 0x11: /* IMA ADPCM */
|
case 0x11: /* IMA ADPCM */
|
||||||
if (format->nSamplesPerSec <= 48000 &&
|
if (format->nSamplesPerSec <= 48000 &&
|
||||||
format->wBitsPerSample == 4 &&
|
format->wBitsPerSample == 4 &&
|
||||||
@ -243,7 +245,14 @@ static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, uint8* data, int size)
|
|||||||
if (alsa->out_handle == 0)
|
if (alsa->out_handle == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (alsa->wformat == 0x11)
|
if (alsa->wformat == 2)
|
||||||
|
{
|
||||||
|
alsa->dsp_context->decode_ms_adpcm(alsa->dsp_context,
|
||||||
|
data, size, alsa->source_channels, alsa->block_size);
|
||||||
|
size = alsa->dsp_context->adpcm_size;
|
||||||
|
src = alsa->dsp_context->adpcm_buffer;
|
||||||
|
}
|
||||||
|
else if (alsa->wformat == 0x11)
|
||||||
{
|
{
|
||||||
alsa->dsp_context->decode_ima_adpcm(alsa->dsp_context,
|
alsa->dsp_context->decode_ima_adpcm(alsa->dsp_context,
|
||||||
data, size, alsa->source_channels, alsa->block_size);
|
data, size, alsa->source_channels, alsa->block_size);
|
||||||
|
@ -212,6 +212,7 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, rdpsndFormat*
|
|||||||
sample_spec.format = PA_SAMPLE_ULAW;
|
sample_spec.format = PA_SAMPLE_ULAW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 2: /* MS ADPCM */
|
||||||
case 0x11: /* IMA ADPCM */
|
case 0x11: /* IMA ADPCM */
|
||||||
sample_spec.format = PA_SAMPLE_S16LE;
|
sample_spec.format = PA_SAMPLE_S16LE;
|
||||||
break;
|
break;
|
||||||
@ -364,6 +365,7 @@ static boolean rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, rdpsndF
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 2: /* MS ADPCM */
|
||||||
case 0x11: /* IMA ADPCM */
|
case 0x11: /* IMA ADPCM */
|
||||||
if ((format->nSamplesPerSec <= PA_RATE_MAX) &&
|
if ((format->nSamplesPerSec <= PA_RATE_MAX) &&
|
||||||
(format->wBitsPerSample == 4) &&
|
(format->wBitsPerSample == 4) &&
|
||||||
@ -405,7 +407,14 @@ static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, uint8* data, int size)
|
|||||||
if (!pulse->stream)
|
if (!pulse->stream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pulse->format == 0x11)
|
if (pulse->format == 2)
|
||||||
|
{
|
||||||
|
pulse->dsp_context->decode_ms_adpcm(pulse->dsp_context,
|
||||||
|
data, size, pulse->sample_spec.channels, pulse->block_size);
|
||||||
|
size = pulse->dsp_context->adpcm_size;
|
||||||
|
src = pulse->dsp_context->adpcm_buffer;
|
||||||
|
}
|
||||||
|
else if (pulse->format == 0x11)
|
||||||
{
|
{
|
||||||
pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context,
|
pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context,
|
||||||
data, size, pulse->sample_spec.channels, pulse->block_size);
|
data, size, pulse->sample_spec.channels, pulse->block_size);
|
||||||
|
@ -22,12 +22,22 @@
|
|||||||
|
|
||||||
#include <freerdp/api.h>
|
#include <freerdp/api.h>
|
||||||
|
|
||||||
struct _ADPCM
|
union _ADPCM
|
||||||
{
|
{
|
||||||
sint16 last_sample[2];
|
struct
|
||||||
sint16 last_step[2];
|
{
|
||||||
|
sint16 last_sample[2];
|
||||||
|
sint16 last_step[2];
|
||||||
|
} ima;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8 predictor[2];
|
||||||
|
sint32 delta[2];
|
||||||
|
sint32 sample1[2];
|
||||||
|
sint32 sample2[2];
|
||||||
|
} ms;
|
||||||
};
|
};
|
||||||
typedef struct _ADPCM ADPCM;
|
typedef union _ADPCM ADPCM;
|
||||||
|
|
||||||
typedef struct _FREERDP_DSP_CONTEXT FREERDP_DSP_CONTEXT;
|
typedef struct _FREERDP_DSP_CONTEXT FREERDP_DSP_CONTEXT;
|
||||||
struct _FREERDP_DSP_CONTEXT
|
struct _FREERDP_DSP_CONTEXT
|
||||||
@ -52,6 +62,11 @@ struct _FREERDP_DSP_CONTEXT
|
|||||||
const uint8* src, int size, int channels, int block_size);
|
const uint8* src, int size, int channels, int block_size);
|
||||||
void (*encode_ima_adpcm)(FREERDP_DSP_CONTEXT* context,
|
void (*encode_ima_adpcm)(FREERDP_DSP_CONTEXT* context,
|
||||||
const uint8* src, int size, int channels, int block_size);
|
const uint8* src, int size, int channels, int block_size);
|
||||||
|
|
||||||
|
void (*decode_ms_adpcm)(FREERDP_DSP_CONTEXT* context,
|
||||||
|
const uint8* src, int size, int channels, int block_size);
|
||||||
|
void (*encode_ms_adpcm)(FREERDP_DSP_CONTEXT* context,
|
||||||
|
const uint8* src, int size, int channels, int block_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
FREERDP_API FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void);
|
FREERDP_API FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void);
|
||||||
|
@ -100,7 +100,7 @@ static uint16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm,
|
|||||||
sint32 ss;
|
sint32 ss;
|
||||||
sint32 d;
|
sint32 d;
|
||||||
|
|
||||||
ss = ima_step_size_table[adpcm->last_step[channel]];
|
ss = ima_step_size_table[adpcm->ima.last_step[channel]];
|
||||||
d = (ss >> 3);
|
d = (ss >> 3);
|
||||||
if (sample & 1)
|
if (sample & 1)
|
||||||
d += (ss >> 2);
|
d += (ss >> 2);
|
||||||
@ -110,20 +110,20 @@ static uint16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm,
|
|||||||
d += ss;
|
d += ss;
|
||||||
if (sample & 8)
|
if (sample & 8)
|
||||||
d = -d;
|
d = -d;
|
||||||
d += adpcm->last_sample[channel];
|
d += adpcm->ima.last_sample[channel];
|
||||||
|
|
||||||
if (d < -32768)
|
if (d < -32768)
|
||||||
d = -32768;
|
d = -32768;
|
||||||
else if (d > 32767)
|
else if (d > 32767)
|
||||||
d = 32767;
|
d = 32767;
|
||||||
|
|
||||||
adpcm->last_sample[channel] = (sint16) d;
|
adpcm->ima.last_sample[channel] = (sint16) d;
|
||||||
|
|
||||||
adpcm->last_step[channel] += ima_step_index_table[sample];
|
adpcm->ima.last_step[channel] += ima_step_index_table[sample];
|
||||||
if (adpcm->last_step[channel] < 0)
|
if (adpcm->ima.last_step[channel] < 0)
|
||||||
adpcm->last_step[channel] = 0;
|
adpcm->ima.last_step[channel] = 0;
|
||||||
else if (adpcm->last_step[channel] > 88)
|
else if (adpcm->ima.last_step[channel] > 88)
|
||||||
adpcm->last_step[channel] = 88;
|
adpcm->ima.last_step[channel] = 88;
|
||||||
|
|
||||||
return (uint16) d;
|
return (uint16) d;
|
||||||
}
|
}
|
||||||
@ -149,15 +149,15 @@ static void freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context,
|
|||||||
{
|
{
|
||||||
if (size % block_size == 0)
|
if (size % block_size == 0)
|
||||||
{
|
{
|
||||||
context->adpcm.last_sample[0] = (sint16) (((uint16)(*src)) | (((uint16)(*(src + 1))) << 8));
|
context->adpcm.ima.last_sample[0] = (sint16) (((uint16)(*src)) | (((uint16)(*(src + 1))) << 8));
|
||||||
context->adpcm.last_step[0] = (sint16) (*(src + 2));
|
context->adpcm.ima.last_step[0] = (sint16) (*(src + 2));
|
||||||
src += 4;
|
src += 4;
|
||||||
size -= 4;
|
size -= 4;
|
||||||
out_size -= 16;
|
out_size -= 16;
|
||||||
if (channels > 1)
|
if (channels > 1)
|
||||||
{
|
{
|
||||||
context->adpcm.last_sample[1] = (sint16) (((uint16)(*src)) | (((uint16)(*(src + 1))) << 8));
|
context->adpcm.ima.last_sample[1] = (sint16) (((uint16)(*src)) | (((uint16)(*(src + 1))) << 8));
|
||||||
context->adpcm.last_step[1] = (sint16) (*(src + 2));
|
context->adpcm.ima.last_step[1] = (sint16) (*(src + 2));
|
||||||
src += 4;
|
src += 4;
|
||||||
size -= 4;
|
size -= 4;
|
||||||
out_size -= 16;
|
out_size -= 16;
|
||||||
@ -197,7 +197,7 @@ static void freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context->adpcm_size = out_size;
|
context->adpcm_size = dst - context->adpcm_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,8 +240,8 @@ static uint8 dsp_encode_ima_adpcm_sample(ADPCM* adpcm,
|
|||||||
uint8 enc;
|
uint8 enc;
|
||||||
sint32 diff;
|
sint32 diff;
|
||||||
|
|
||||||
ss = ima_step_size_table[adpcm->last_step[channel]];
|
ss = ima_step_size_table[adpcm->ima.last_step[channel]];
|
||||||
d = e = sample - adpcm->last_sample[channel];
|
d = e = sample - adpcm->ima.last_sample[channel];
|
||||||
diff = ss >> 3;
|
diff = ss >> 3;
|
||||||
enc = 0;
|
enc = 0;
|
||||||
if (e < 0)
|
if (e < 0)
|
||||||
@ -272,18 +272,18 @@ static uint8 dsp_encode_ima_adpcm_sample(ADPCM* adpcm,
|
|||||||
else
|
else
|
||||||
diff = d - e + diff;
|
diff = d - e + diff;
|
||||||
|
|
||||||
diff += adpcm->last_sample[channel];
|
diff += adpcm->ima.last_sample[channel];
|
||||||
if (diff < -32768)
|
if (diff < -32768)
|
||||||
diff = -32768;
|
diff = -32768;
|
||||||
else if (diff > 32767)
|
else if (diff > 32767)
|
||||||
diff = 32767;
|
diff = 32767;
|
||||||
adpcm->last_sample[channel] = (sint16) diff;
|
adpcm->ima.last_sample[channel] = (sint16) diff;
|
||||||
|
|
||||||
adpcm->last_step[channel] += ima_step_index_table[enc];
|
adpcm->ima.last_step[channel] += ima_step_index_table[enc];
|
||||||
if (adpcm->last_step[channel] < 0)
|
if (adpcm->ima.last_step[channel] < 0)
|
||||||
adpcm->last_step[channel] = 0;
|
adpcm->ima.last_step[channel] = 0;
|
||||||
else if (adpcm->last_step[channel] > 88)
|
else if (adpcm->ima.last_step[channel] > 88)
|
||||||
adpcm->last_step[channel] = 88;
|
adpcm->ima.last_step[channel] = 88;
|
||||||
|
|
||||||
return enc;
|
return enc;
|
||||||
}
|
}
|
||||||
@ -308,15 +308,15 @@ static void freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context,
|
|||||||
{
|
{
|
||||||
if ((dst - context->adpcm_buffer) % block_size == 0)
|
if ((dst - context->adpcm_buffer) % block_size == 0)
|
||||||
{
|
{
|
||||||
*dst++ = context->adpcm.last_sample[0] & 0xff;
|
*dst++ = context->adpcm.ima.last_sample[0] & 0xff;
|
||||||
*dst++ = (context->adpcm.last_sample[0] >> 8) & 0xff;
|
*dst++ = (context->adpcm.ima.last_sample[0] >> 8) & 0xff;
|
||||||
*dst++ = (uint8) context->adpcm.last_step[0];
|
*dst++ = (uint8) context->adpcm.ima.last_step[0];
|
||||||
*dst++ = 0;
|
*dst++ = 0;
|
||||||
if (channels > 1)
|
if (channels > 1)
|
||||||
{
|
{
|
||||||
*dst++ = context->adpcm.last_sample[1] & 0xff;
|
*dst++ = context->adpcm.ima.last_sample[1] & 0xff;
|
||||||
*dst++ = (context->adpcm.last_sample[1] >> 8) & 0xff;
|
*dst++ = (context->adpcm.ima.last_sample[1] >> 8) & 0xff;
|
||||||
*dst++ = (uint8) context->adpcm.last_step[1];
|
*dst++ = (uint8) context->adpcm.ima.last_step[1];
|
||||||
*dst++ = 0;
|
*dst++ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,6 +350,241 @@ static void freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context,
|
|||||||
context->adpcm_size = dst - context->adpcm_buffer;
|
context->adpcm_size = dst - context->adpcm_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microsoft ADPCM Specification:
|
||||||
|
*
|
||||||
|
* http://wiki.multimedia.cx/index.php?title=Microsoft_ADPCM
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const sint16 ms_adpcm_adaptation_table[] =
|
||||||
|
{
|
||||||
|
230, 230, 230, 230, 307, 409, 512, 614,
|
||||||
|
768, 614, 512, 409, 307, 230, 230, 230
|
||||||
|
};
|
||||||
|
|
||||||
|
static const sint16 ms_adpcm_coeff1_table[] =
|
||||||
|
{
|
||||||
|
256, 512, 0, 192, 240, 460, 392
|
||||||
|
};
|
||||||
|
|
||||||
|
static const sint16 ms_adpcm_coeff2_table[] =
|
||||||
|
{
|
||||||
|
0, -256, 0, 64, 0, -208, -232
|
||||||
|
};
|
||||||
|
|
||||||
|
static sint16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, uint8 sample, int channel)
|
||||||
|
{
|
||||||
|
sint8 nibble;
|
||||||
|
sint32 presample;
|
||||||
|
|
||||||
|
nibble = (sample & 0x08 ? (sint8)sample - 16 : sample);
|
||||||
|
presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeff1_table[adpcm->ms.predictor[channel]]) +
|
||||||
|
(adpcm->ms.sample2[channel] * ms_adpcm_coeff2_table[adpcm->ms.predictor[channel]])) / 256;
|
||||||
|
presample += nibble * adpcm->ms.delta[channel];
|
||||||
|
if (presample > 32767)
|
||||||
|
presample = 32767;
|
||||||
|
else if (presample < -32768)
|
||||||
|
presample = -32768;
|
||||||
|
adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel];
|
||||||
|
adpcm->ms.sample1[channel] = presample;
|
||||||
|
adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[sample] / 256;
|
||||||
|
if (adpcm->ms.delta[channel] < 16)
|
||||||
|
adpcm->ms.delta[channel] = 16;
|
||||||
|
return (sint16) presample;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context,
|
||||||
|
const uint8* src, int size, int channels, int block_size)
|
||||||
|
{
|
||||||
|
uint8* dst;
|
||||||
|
uint8 sample;
|
||||||
|
uint32 out_size;
|
||||||
|
|
||||||
|
out_size = size * 4;
|
||||||
|
if (out_size > context->adpcm_maxlength)
|
||||||
|
{
|
||||||
|
context->adpcm_maxlength = out_size + 1024;
|
||||||
|
context->adpcm_buffer = xrealloc(context->adpcm_buffer, context->adpcm_maxlength);
|
||||||
|
}
|
||||||
|
dst = context->adpcm_buffer;
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
if (size % block_size == 0)
|
||||||
|
{
|
||||||
|
if (channels > 1)
|
||||||
|
{
|
||||||
|
context->adpcm.ms.predictor[0] = *src++;
|
||||||
|
context->adpcm.ms.predictor[1] = *src++;
|
||||||
|
context->adpcm.ms.delta[0] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.delta[1] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.sample1[0] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.sample1[1] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.sample2[0] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.sample2[1] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
size -= 14;
|
||||||
|
|
||||||
|
*((sint16*)dst) = context->adpcm.ms.sample2[0];
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = context->adpcm.ms.sample2[1];
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = context->adpcm.ms.sample1[0];
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = context->adpcm.ms.sample1[1];
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context->adpcm.ms.predictor[0] = *src++;
|
||||||
|
context->adpcm.ms.delta[0] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.sample1[0] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
context->adpcm.ms.sample2[0] = *((sint16*)src);
|
||||||
|
src += 2;
|
||||||
|
size -= 7;
|
||||||
|
|
||||||
|
*((sint16*)dst) = context->adpcm.ms.sample2[0];
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = context->adpcm.ms.sample1[0];
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels > 1)
|
||||||
|
{
|
||||||
|
sample = *src++;
|
||||||
|
size--;
|
||||||
|
*((sint16*)dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0);
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1);
|
||||||
|
dst += 2;
|
||||||
|
|
||||||
|
sample = *src++;
|
||||||
|
size--;
|
||||||
|
*((sint16*)dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0);
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1);
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sample = *src++;
|
||||||
|
size--;
|
||||||
|
*((sint16*)dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0);
|
||||||
|
dst += 2;
|
||||||
|
*((sint16*)dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 0);
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context->adpcm_size = dst - context->adpcm_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8 freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, sint32 sample, int channel)
|
||||||
|
{
|
||||||
|
sint32 presample;
|
||||||
|
sint32 errordelta;
|
||||||
|
|
||||||
|
presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeff1_table[adpcm->ms.predictor[channel]]) +
|
||||||
|
(adpcm->ms.sample2[channel] * ms_adpcm_coeff2_table[adpcm->ms.predictor[channel]])) / 256;
|
||||||
|
errordelta = (sample - presample) / adpcm->ms.delta[channel];
|
||||||
|
if ((sample - presample) % adpcm->ms.delta[channel] > adpcm->ms.delta[channel] / 2)
|
||||||
|
errordelta++;
|
||||||
|
if (errordelta > 7)
|
||||||
|
errordelta = 7;
|
||||||
|
else if (errordelta < -8)
|
||||||
|
errordelta = -8;
|
||||||
|
presample += adpcm->ms.delta[channel] * errordelta;
|
||||||
|
if (presample > 32767)
|
||||||
|
presample = 32767;
|
||||||
|
else if (presample < -32768)
|
||||||
|
presample = -32768;
|
||||||
|
adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel];
|
||||||
|
adpcm->ms.sample1[channel] = presample;
|
||||||
|
adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[(((uint8)errordelta) & 0x0F)] / 256;
|
||||||
|
if (adpcm->ms.delta[channel] < 16)
|
||||||
|
adpcm->ms.delta[channel] = 16;
|
||||||
|
return ((uint8)errordelta) & 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context,
|
||||||
|
const uint8* src, int size, int channels, int block_size)
|
||||||
|
{
|
||||||
|
uint8* dst;
|
||||||
|
sint32 sample;
|
||||||
|
uint32 out_size;
|
||||||
|
|
||||||
|
out_size = size / 2;
|
||||||
|
if (out_size > context->adpcm_maxlength)
|
||||||
|
{
|
||||||
|
context->adpcm_maxlength = out_size + 1024;
|
||||||
|
context->adpcm_buffer = xrealloc(context->adpcm_buffer, context->adpcm_maxlength);
|
||||||
|
}
|
||||||
|
dst = context->adpcm_buffer;
|
||||||
|
|
||||||
|
if (context->adpcm.ms.delta[0] < 16)
|
||||||
|
context->adpcm.ms.delta[0] = 16;
|
||||||
|
if (context->adpcm.ms.delta[1] < 16)
|
||||||
|
context->adpcm.ms.delta[1] = 16;
|
||||||
|
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
if ((dst - context->adpcm_buffer) % block_size == 0)
|
||||||
|
{
|
||||||
|
if (channels > 1)
|
||||||
|
{
|
||||||
|
*dst++ = context->adpcm.ms.predictor[0];
|
||||||
|
*dst++ = context->adpcm.ms.predictor[1];
|
||||||
|
*dst++ = (uint8) (context->adpcm.ms.delta[0] & 0xff);
|
||||||
|
*dst++ = (uint8) ((context->adpcm.ms.delta[0] >> 8) & 0xff);
|
||||||
|
*dst++ = (uint8) (context->adpcm.ms.delta[1] & 0xff);
|
||||||
|
*dst++ = (uint8) ((context->adpcm.ms.delta[1] >> 8) & 0xff);
|
||||||
|
context->adpcm.ms.sample1[0] = *((sint16*) (src + 4));
|
||||||
|
context->adpcm.ms.sample1[1] = *((sint16*) (src + 6));
|
||||||
|
context->adpcm.ms.sample2[0] = *((sint16*) (src + 0));
|
||||||
|
context->adpcm.ms.sample2[1] = *((sint16*) (src + 2));
|
||||||
|
*((sint16*) (dst + 0)) = (sint16) context->adpcm.ms.sample1[0];
|
||||||
|
*((sint16*) (dst + 2)) = (sint16) context->adpcm.ms.sample1[1];
|
||||||
|
*((sint16*) (dst + 4)) = (sint16) context->adpcm.ms.sample2[0];
|
||||||
|
*((sint16*) (dst + 6)) = (sint16) context->adpcm.ms.sample2[1];
|
||||||
|
dst += 8;
|
||||||
|
src += 8;
|
||||||
|
size -= 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dst++ = context->adpcm.ms.predictor[0];
|
||||||
|
*dst++ = (uint8) (context->adpcm.ms.delta[0] & 0xff);
|
||||||
|
*dst++ = (uint8) ((context->adpcm.ms.delta[0] >> 8) & 0xff);
|
||||||
|
context->adpcm.ms.sample1[0] = *((sint16*) (src + 2));
|
||||||
|
context->adpcm.ms.sample2[0] = *((sint16*) (src + 0));
|
||||||
|
*((sint16*) (dst + 0)) = (sint16) context->adpcm.ms.sample1[0];
|
||||||
|
*((sint16*) (dst + 2)) = (sint16) context->adpcm.ms.sample2[0];
|
||||||
|
dst += 4;
|
||||||
|
src += 4;
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sample = *((sint16*) src);
|
||||||
|
src += 2;
|
||||||
|
*dst = freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, 0) << 4;
|
||||||
|
sample = *((sint16*) src);
|
||||||
|
src += 2;
|
||||||
|
*dst += freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, channels > 1 ? 1 : 0);
|
||||||
|
dst++;
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->adpcm_size = dst - context->adpcm_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void)
|
FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void)
|
||||||
{
|
{
|
||||||
FREERDP_DSP_CONTEXT* context;
|
FREERDP_DSP_CONTEXT* context;
|
||||||
@ -359,6 +594,8 @@ FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void)
|
|||||||
context->resample = freerdp_dsp_resample;
|
context->resample = freerdp_dsp_resample;
|
||||||
context->decode_ima_adpcm = freerdp_dsp_decode_ima_adpcm;
|
context->decode_ima_adpcm = freerdp_dsp_decode_ima_adpcm;
|
||||||
context->encode_ima_adpcm = freerdp_dsp_encode_ima_adpcm;
|
context->encode_ima_adpcm = freerdp_dsp_encode_ima_adpcm;
|
||||||
|
context->decode_ms_adpcm = freerdp_dsp_decode_ms_adpcm;
|
||||||
|
context->encode_ms_adpcm = freerdp_dsp_encode_ms_adpcm;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -255,6 +255,11 @@ static void rdpsnd_server_select_format(rdpsnd_server_context* context, int clie
|
|||||||
bs = (format->nBlockAlign - 4 * format->nChannels) * 4;
|
bs = (format->nBlockAlign - 4 * format->nChannels) * 4;
|
||||||
rdpsnd->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2);
|
rdpsnd->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2);
|
||||||
}
|
}
|
||||||
|
else if (format->wFormatTag == 0x02)
|
||||||
|
{
|
||||||
|
bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
|
||||||
|
rdpsnd->out_frames = bs * 4;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rdpsnd->out_frames = 0x4000 / rdpsnd->src_bytes_per_frame;
|
rdpsnd->out_frames = 0x4000 / rdpsnd->src_bytes_per_frame;
|
||||||
@ -311,11 +316,19 @@ static boolean rdpsnd_server_send_audio_pdu(rdpsnd_server* rdpsnd)
|
|||||||
src = rdpsnd->dsp_context->adpcm_buffer;
|
src = rdpsnd->dsp_context->adpcm_buffer;
|
||||||
size = rdpsnd->dsp_context->adpcm_size;
|
size = rdpsnd->dsp_context->adpcm_size;
|
||||||
}
|
}
|
||||||
|
else if (format->wFormatTag == 0x02)
|
||||||
|
{
|
||||||
|
rdpsnd->dsp_context->encode_ms_adpcm(rdpsnd->dsp_context,
|
||||||
|
src, size, format->nChannels, format->nBlockAlign);
|
||||||
|
src = rdpsnd->dsp_context->adpcm_buffer;
|
||||||
|
size = rdpsnd->dsp_context->adpcm_size;
|
||||||
|
}
|
||||||
|
|
||||||
rdpsnd->context.block_no = (rdpsnd->context.block_no + 1) % 256;
|
rdpsnd->context.block_no = (rdpsnd->context.block_no + 1) % 256;
|
||||||
|
|
||||||
/* Fill to nBlockAlign for the last audio packet */
|
/* Fill to nBlockAlign for the last audio packet */
|
||||||
if (format->wFormatTag == 0x11 && rdpsnd->out_pending_frames < rdpsnd->out_frames && (size % format->nBlockAlign) != 0)
|
if ((format->wFormatTag == 0x11 || format->wFormatTag == 0x02) &&
|
||||||
|
rdpsnd->out_pending_frames < rdpsnd->out_frames && (size % format->nBlockAlign) != 0)
|
||||||
fill_size = format->nBlockAlign - (size % format->nBlockAlign);
|
fill_size = format->nBlockAlign - (size % format->nBlockAlign);
|
||||||
else
|
else
|
||||||
fill_size = 0;
|
fill_size = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user