summaryrefslogtreecommitdiffstats
path: root/OpenAL32/alBuffer.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-03-04 22:44:30 -0800
committerChris Robinson <[email protected]>2014-03-04 22:44:30 -0800
commita1c440bd09d6b0bec36ef84dc474306ce6171b26 (patch)
treeb0666578ef6110d6a956759445654c5adb054af1 /OpenAL32/alBuffer.c
parentf3a87d72b266640a706ddd3234aa4313b53cabce (diff)
Add an extension to support MSADPCM buffer formats
Diffstat (limited to 'OpenAL32/alBuffer.c')
-rw-r--r--OpenAL32/alBuffer.c336
1 files changed, 309 insertions, 27 deletions
diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c
index 058b1f49..8f19ae0a 100644
--- a/OpenAL32/alBuffer.c
+++ b/OpenAL32/alBuffer.c
@@ -81,6 +81,25 @@ static const int IMA4Index_adjust[16] = {
-1,-1,-1,-1, 2, 4, 6, 8
};
+
+/* MSADPCM Adaption table */
+static const int MSADPCMAdaption[16] = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+};
+
+/* MSADPCM Adaption Coefficient tables */
+static const int MSADPCMAdaptionCoeff[7][2] = {
+ { 256, 0 },
+ { 512, -256 },
+ { 0, 0 },
+ { 192, 64 },
+ { 240, 0 },
+ { 460, -208 },
+ { 392, -232 }
+};
+
+
/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
* signed 16-bit sample */
static const ALshort muLawDecompressionTable[256] = {
@@ -409,6 +428,29 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
if(err != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, done);
break;
+
+ case UserFmtMSADPCM:
+ framesize = (align-2)/2 + 7;
+ framesize *= ChannelsFromUserFmt(srcchannels);
+ if((size%framesize) != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ newformat = AL_FORMAT_MONO16;
+ switch(srcchannels)
+ {
+ case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
+ case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
+ case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
+ case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
+ case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
+ case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
+ case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+ }
+ err = LoadData(albuf, freq, newformat, size/framesize*align,
+ srcchannels, srctype, data, align, AL_TRUE);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
+ break;
}
done:
@@ -461,6 +503,11 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons
byte_align = (albuf->OriginalAlign-1)/2 + 4;
byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
}
+ else if(albuf->OriginalType == UserFmtMSADPCM)
+ {
+ byte_align = (albuf->OriginalAlign-2)/2 + 7;
+ byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
+ }
else
{
byte_align = albuf->OriginalAlign;
@@ -1069,6 +1116,7 @@ done:
typedef ALubyte ALmulaw;
typedef ALubyte ALalaw;
typedef ALubyte ALima4;
+typedef ALubyte ALmsadpcm;
typedef struct {
ALbyte b[3];
} ALbyte3;
@@ -1247,6 +1295,118 @@ static void EncodeIMA4Block(ALima4 *dst, const ALshort *src, ALint *sample, ALin
}
+static void DecodeMSADPCMBlock(ALshort *dst, const ALmsadpcm *src, ALint numchans, ALsizei align)
+{
+ ALubyte blockpred[MAX_INPUT_CHANNELS];
+ ALint delta[MAX_INPUT_CHANNELS];
+ ALshort samples[MAX_INPUT_CHANNELS][2];
+ ALint i, j;
+
+ for(i = 0;i < numchans;i++)
+ {
+ blockpred[i] = *(src++);
+ blockpred[i] = minu(blockpred[i], 6);
+ }
+ for(i = 0;i < numchans;i++)
+ {
+ delta[i] = *(src++);
+ delta[i] |= *(src++) << 8;
+ }
+ for(i = 0;i < numchans;i++)
+ {
+ samples[i][0] = *(src++);
+ samples[i][0] |= *(src++) << 8;
+ samples[i][0] = (samples[i][0]^0x8000) - 0x8000;
+ }
+ for(i = 0;i < numchans;i++)
+ {
+ samples[i][1] = *(src++);
+ samples[i][1] |= *(src++) << 8;
+ samples[i][1] = (samples[i][1]^0x8000) - 0x8000;
+ }
+
+ /* Second sample is written first. */
+ for(i = 0;i < numchans;i++)
+ *(dst++) = samples[i][1];
+ for(i = 0;i < numchans;i++)
+ *(dst++) = samples[i][0];
+
+ for(j = 2;j < align;j++)
+ {
+ for(i = 0;i < numchans;i++)
+ {
+ const ALint num = (j*numchans) + i;
+ ALint nibble, pred;
+
+ /* Read the nibble and sign-expand it. */
+ if(!(num&1))
+ nibble = (*src>>4)&0x0f;
+ else
+ nibble = (*(src++))&0x0f;
+ nibble = (nibble^0x08) - 0x08;
+
+ pred = (samples[i][0]*MSADPCMAdaptionCoeff[blockpred[i]][0] +
+ samples[i][1]*MSADPCMAdaptionCoeff[blockpred[i]][1]) / 256;
+ pred += nibble * delta[i];
+ pred = clampi(pred, -32768, 32767);
+
+ samples[i][1] = samples[i][0];
+ samples[i][0] = pred;
+
+ delta[i] = (MSADPCMAdaption[nibble&0x0f] * delta[i]) / 256;
+ delta[i] = maxu(16, delta[i]);
+
+ *(dst++) = pred;
+ }
+ }
+}
+
+/* FIXME: Stubbed. Just inserts silence. */
+static void EncodeMSADPCMBlock(ALmsadpcm *dst, const ALshort* UNUSED(src), ALint* UNUSED(sample), ALint* UNUSED(index), ALint numchans, ALsizei align)
+{
+ ALint i, j;
+
+ /* Block predictor */
+ for(i = 0;i < numchans;i++)
+ *(dst++) = 2;
+ /* Initial delta */
+ for(i = 0;i < numchans;i++)
+ {
+ *(dst++) = 16;
+ *(dst++) = 0;
+ }
+ /* Initial sample 1 */
+ for(i = 0;i < numchans;i++)
+ {
+ *(dst++) = 0;
+ *(dst++) = 0;
+ }
+ /* Initial sample 2 */
+ for(i = 0;i < numchans;i++)
+ {
+ *(dst++) = 0;
+ *(dst++) = 0;
+ }
+
+ for(j = 2;j < align;j++)
+ {
+ for(i = 0;i < numchans;i++)
+ {
+ const ALint num = (j*numchans) + i;
+ ALubyte nibble = 0;
+
+ if(!(num&1))
+ *dst = nibble << 4;
+ else
+ {
+ *dst |= nibble;
+ dst++;
+ }
+ }
+ }
+}
+
+
static inline ALint DecodeByte3(ALbyte3 val)
{
if(IS_LITTLE_ENDIAN)
@@ -1665,7 +1825,7 @@ DECL_TEMPLATE2(ALubyte3)
static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \
ALuint len, ALuint align) \
{ \
- ALsizei byte_align = (align-1)/2 + 4; \
+ ALsizei byte_align = ((align-1)/2 + 4) * numchans; \
ALuint i, j, k; \
ALshort *tmp; \
\
@@ -1673,7 +1833,7 @@ static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \
for(i = 0;i < len;i += align) \
{ \
DecodeIMA4Block(tmp, src, numchans, align); \
- src += byte_align*numchans; \
+ src += byte_align; \
\
for(j = 0;j < align;j++) \
{ \
@@ -1704,7 +1864,7 @@ static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \
{ \
ALint sample[MaxChannels] = {0,0,0,0,0,0,0,0}; \
ALint index[MaxChannels] = {0,0,0,0,0,0,0,0}; \
- ALsizei byte_align = (align-1)/2 + 4; \
+ ALsizei byte_align = ((align-1)/2 + 4) * numchans; \
ALshort *tmp; \
ALuint i, j; \
\
@@ -1714,7 +1874,46 @@ static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \
for(j = 0;j < align*numchans;j++) \
tmp[j] = Conv_ALshort_##T(*(src++)); \
EncodeIMA4Block(dst, tmp, sample, index, numchans, align); \
- dst += byte_align*numchans; \
+ dst += byte_align; \
+ } \
+}
+
+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)
+DECL_TEMPLATE(ALalaw)
+DECL_TEMPLATE(ALbyte3)
+DECL_TEMPLATE(ALubyte3)
+
+#undef DECL_TEMPLATE
+
+
+#define DECL_TEMPLATE(T) \
+static void Convert_##T##_ALmsadpcm(T *dst, const ALmsadpcm *src, \
+ ALuint numchans, ALuint len, \
+ ALuint align) \
+{ \
+ ALsizei byte_align = ((align-2)/2 + 7) * numchans; \
+ ALuint i, j, k; \
+ ALshort *tmp; \
+ \
+ tmp = alloca(align*numchans); \
+ for(i = 0;i < len;i += align) \
+ { \
+ DecodeMSADPCMBlock(tmp, src, numchans, align); \
+ src += byte_align; \
+ \
+ for(j = 0;j < align;j++) \
+ { \
+ for(k = 0;k < numchans;k++) \
+ *(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \
+ } \
} \
}
@@ -1728,18 +1927,78 @@ DECL_TEMPLATE(ALfloat)
DECL_TEMPLATE(ALdouble)
DECL_TEMPLATE(ALmulaw)
DECL_TEMPLATE(ALalaw)
+DECL_TEMPLATE(ALbyte3)
+DECL_TEMPLATE(ALubyte3)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T) \
+static void Convert_ALmsadpcm_##T(ALmsadpcm *dst, const T *src, \
+ ALuint numchans, ALuint len, ALuint align) \
+{ \
+ ALint sample[MaxChannels] = {0,0,0,0,0,0,0,0}; \
+ ALint index[MaxChannels] = {0,0,0,0,0,0,0,0}; \
+ ALsizei byte_align = ((align-2)/2 + 7) * numchans; \
+ ALshort *tmp; \
+ ALuint i, j; \
+ \
+ ERR("MSADPCM encoding not currently supported!\n"); \
+ \
+ tmp = alloca(align*numchans); \
+ for(i = 0;i < len;i += align) \
+ { \
+ for(j = 0;j < align*numchans;j++) \
+ tmp[j] = Conv_ALshort_##T(*(src++)); \
+ EncodeMSADPCMBlock(dst, tmp, sample, index, numchans, align); \
+ dst += byte_align; \
+ } \
+}
+
+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)
+DECL_TEMPLATE(ALalaw)
+DECL_TEMPLATE(ALbyte3)
+DECL_TEMPLATE(ALubyte3)
+
+#undef DECL_TEMPLATE
+
+/* NOTE: We don't store compressed samples internally, so these conversions
+ * should never happen. */
static void Convert_ALima4_ALima4(ALima4* UNUSED(dst), const ALima4* UNUSED(src),
ALuint UNUSED(numchans), ALuint UNUSED(len),
ALuint UNUSED(align))
{
- /* We don't store IMA4 samples internally, so IMA4-to-IMA4 conversions
- * should never happen. */
ERR("Unexpected IMA4-to-IMA4 conversion!\n");
}
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-#undef DECL_TEMPLATE
+static void Convert_ALmsadpcm_ALmsadpcm(ALmsadpcm* UNUSED(dst), const ALmsadpcm* UNUSED(src),
+ ALuint UNUSED(numchans), ALuint UNUSED(len),
+ ALuint UNUSED(align))
+{
+ ERR("Unexpected MSADPCM-to-MSADPCM conversion!\n");
+}
+
+static void Convert_ALmsadpcm_ALima4(ALmsadpcm* UNUSED(dst), const ALima4* UNUSED(src),
+ ALuint UNUSED(numchans), ALuint UNUSED(len),
+ ALuint UNUSED(align))
+{
+ ERR("Unexpected IMA4-to-MSADPCM conversion!\n");
+}
+
+static void Convert_ALima4_ALmsadpcm(ALima4* UNUSED(dst), const ALmsadpcm* UNUSED(src),
+ ALuint UNUSED(numchans), ALuint UNUSED(len),
+ ALuint UNUSED(align))
+{
+ ERR("Unexpected MSADPCM-to-IMA4 conversion!\n");
+}
+
#define DECL_TEMPLATE(T) \
static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \
@@ -1780,6 +2039,9 @@ static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \
case UserFmtIMA4: \
Convert_##T##_ALima4(dst, src, numchans, len, align); \
break; \
+ case UserFmtMSADPCM: \
+ Convert_##T##_ALmsadpcm(dst, src, numchans, len, align); \
+ break; \
case UserFmtByte3: \
Convert_##T##_ALbyte3(dst, src, numchans, len, align); \
break; \
@@ -1800,6 +2062,7 @@ DECL_TEMPLATE(ALdouble)
DECL_TEMPLATE(ALmulaw)
DECL_TEMPLATE(ALalaw)
DECL_TEMPLATE(ALima4)
+DECL_TEMPLATE(ALmsadpcm)
DECL_TEMPLATE(ALbyte3)
DECL_TEMPLATE(ALubyte3)
@@ -1843,6 +2106,9 @@ static void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src
case UserFmtIMA4:
Convert_ALima4(dst, src, srcType, numchans, len, align);
break;
+ case UserFmtMSADPCM:
+ Convert_ALmsadpcm(dst, src, srcType, numchans, len, align);
+ break;
case UserFmtByte3:
Convert_ALbyte3(dst, src, srcType, numchans, len, align);
break;
@@ -1909,6 +2175,12 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
ALBuf->OriginalSize = frames / align * byte_align;
ALBuf->OriginalAlign = align;
}
+ else if(SrcType == UserFmtMSADPCM)
+ {
+ ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
+ ALBuf->OriginalSize = frames / align * byte_align;
+ ALBuf->OriginalAlign = align;
+ }
else
{
ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
@@ -1954,6 +2226,7 @@ ALuint BytesFromUserFmt(enum UserFmtType type)
case UserFmtMulaw: return sizeof(ALubyte);
case UserFmtAlaw: return sizeof(ALubyte);
case UserFmtIMA4: break; /* not handled here */
+ case UserFmtMSADPCM: break; /* not handled here */
}
return 0;
}
@@ -1979,21 +2252,23 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
enum UserFmtChannels channels;
enum UserFmtType type;
} list[] = {
- { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
- { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
- { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
- { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
- { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
- { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
- { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
-
- { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
- { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
- { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
- { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
- { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
- { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
- { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
+ { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
+ { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
+ { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
+ { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
+ { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
+ { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
+ { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
+ { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
+
+ { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
+ { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
+ { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
+ { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
+ { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
+ { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
+ { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
+ { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
{ AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
{ AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
@@ -2130,6 +2405,8 @@ static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
*/
*align = 65;
}
+ else if(type == UserFmtMSADPCM)
+ *align = 64;
else
*align = 1;
return AL_TRUE;
@@ -2138,9 +2415,14 @@ static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
if(type == UserFmtIMA4)
{
/* IMA4 block alignment must be a multiple of 8, plus 1. */
- if(((*align)&7) != 1)
- return AL_FALSE;
- return AL_TRUE;
+ return ((*align)&7) == 1;
+ }
+ if(type == UserFmtMSADPCM)
+ {
+ /* MSADPCM block alignment must be a multiple of 8. */
+ /* FIXME: Too strict? Might only require align*channels to be a
+ * multiple of 2. */
+ return ((*align)&7) == 0;
}
return AL_TRUE;