Add an IMA4 encoder

This commit is contained in:
Chris Robinson
2010-12-05 03:34:19 -08:00
parent c4adf541c1
commit cd65ab7dfa
+139
View File
@@ -909,6 +909,77 @@ static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans)
}
}
static void EncodeIMA4Block(ALubyte *dst, const ALshort *src, ALint *sample, ALint *index, ALint numchans)
{
ALsizei j,k,c;
for(c = 0;c < numchans;c++)
{
int diff = src[c] - sample[c];
int step = IMAStep_size[index[c]];
int nibble;
nibble = 0;
if(diff < 0)
{
nibble = 0x8;
diff = -diff;
}
diff = min(step*2, diff);
nibble |= (diff*8/step - 1) / 2;
sample[c] += IMA4Codeword[nibble] * step / 8;
sample[c] = max(-32768, sample[c]);
sample[c] = min(sample[c], 32767);
index[c] += IMA4Index_adjust[nibble];
index[c] = max(0, index[c]);
index[c] = min(index[c], 88);
*(dst++) = sample[c] & 0xff;
*(dst++) = (sample[c]>>8) & 0xff;
*(dst++) = index[c] & 0xff;
*(dst++) = (index[c]>>8) & 0xff;
}
j = 1;
while(j < 65)
{
for(c = 0;c < numchans;c++)
{
for(k = 0;k < 8;k++)
{
int diff = src[(j+k)*numchans + c] - sample[c];
int step = IMAStep_size[index[c]];
int nibble;
nibble = 0;
if(diff < 0)
{
nibble = 0x8;
diff = -diff;
}
diff = min(step*2, diff);
nibble |= (diff*8/step - 1) / 2;
sample[c] += IMA4Codeword[nibble] * step / 8;
sample[c] = max(-32768, sample[c]);
sample[c] = min(sample[c], 32767);
index[c] += IMA4Index_adjust[nibble];
index[c] = max(0, index[c]);
index[c] = min(index[c], 88);
if(!(k&1)) *dst = nibble;
else *(dst++) |= nibble<<4;
}
}
j += 8;
}
}
static __inline ALbyte Conv_ALbyte_ALbyte(ALbyte val)
{ return val; }
@@ -1253,6 +1324,35 @@ DECL_TEMPLATE(ALmulaw)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T) \
static void Convert_IMA4_##T(ALubyte *dst, const T *src, ALuint numchans, \
ALuint numblocks) \
{ \
ALuint i, j; \
ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */ \
ALint sample[MAXCHANNELS] = {0,0,0,0,0,0,0,0}; \
ALint index[MAXCHANNELS] = {0,0,0,0,0,0,0,0}; \
for(i = 0;i < numblocks;i++) \
{ \
for(j = 0;j < 65*numchans;j++) \
tmp[j] = Conv_ALshort_##T(*(src++)); \
EncodeIMA4Block(dst, tmp, sample, index, numchans); \
dst += 36*numchans; \
} \
}
DECL_TEMPLATE(ALbyte)
DECL_TEMPLATE(ALubyte)
DECL_TEMPLATE(ALshort)
DECL_TEMPLATE(ALushort)
DECL_TEMPLATE(ALint)
DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALfloat)
DECL_TEMPLATE(ALdouble)
DECL_TEMPLATE(ALmulaw)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T) \
static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \
ALsizei len) \
@@ -1303,6 +1403,44 @@ DECL_TEMPLATE(ALmulaw)
#undef DECL_TEMPLATE
static void Convert_IMA4(ALubyte *dst, const ALvoid *src, enum UserFmtType srcType,
ALint chans, ALsizei len)
{
switch(srcType)
{
case UserFmtByte:
Convert_IMA4_ALbyte(dst, src, chans, len);
break;
case UserFmtUByte:
Convert_IMA4_ALubyte(dst, src, chans, len);
break;
case UserFmtShort:
Convert_IMA4_ALshort(dst, src, chans, len);
break;
case UserFmtUShort:
Convert_IMA4_ALushort(dst, src, chans, len);
break;
case UserFmtInt:
Convert_IMA4_ALint(dst, src, chans, len);
break;
case UserFmtUInt:
Convert_IMA4_ALuint(dst, src, chans, len);
break;
case UserFmtFloat:
Convert_IMA4_ALfloat(dst, src, chans, len);
break;
case UserFmtDouble:
Convert_IMA4_ALdouble(dst, src, chans, len);
break;
case UserFmtMulaw:
Convert_IMA4_ALmulaw(dst, src, chans, len);
break;
case UserFmtIMA4:
memcpy(dst, src, len*36*chans);
break;
}
}
static void ConvertData(ALvoid *dst, enum FmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei len)
{
@@ -1323,6 +1461,7 @@ static void ConvertData(ALvoid *dst, enum FmtType dstType, const ALvoid *src, en
break;
(void)Convert_ALdouble;
(void)Convert_ALmulaw;
(void)Convert_IMA4;
}
}