I am working on an old (1999~) win32 decompiled game codebase.
In it, there is the following sequence of bytes, which were directly taken from the disassembled binary:
static char source_pcm_format[50] =
{
2, 0, 1, 0, 34, 86, 0, 0, 147, 43, 0, 0, 0, 2, 4, 0, 32, 0, 244, 3, 7, 0, 0, 1, 0, 0, 0, 2, 0, 255, 0, 0,
0, 0, 192, 0, 64, 0, 240, 0, 0, 0, 204, 1, 48, 255, 136, 1, 24, 255
};
These bytes are passed into the function acmStreamOpen
, casted to a LPWAVEFORMATEX
:
mmresult = acmStreamOpen(&hACMStream, hACMDriver, (LPWAVEFORMATEX)source_pcm_format, &pcm_format, 0, 0, 0, 0);
this function call works correctly
When interpreting these bytes myself as a WAVEFORMATEX
, the wFormatTag
equals 2, which corresponds to ADPCMWAVEFORMAT
.
When I interpret the bytes as a ADPCMWAVEFORMAT
, things go weird:
The ADPCMWAVEFORAMT
needs wNumCoefs
amount of ADPCMCOEFSET
.
50 bytes however are too few to store 256 coefficients.
When printing the coefficients the following way (I assume its MS-ADPCM):
ADPCMWAVEFORMAT* adpcmfmt = calloc(1, sizeof(ADPCMWAVEFORMAT) + sizeof(ADPCMCOEFSET) * 7); // MS-ADPCM
char source_pcm_format[50] = {
2, 0, 1, 0, 34, 86, 0, 0, 147, 43, 0, 0, 0, 2, 4, 0, 32, 0, 244, 3, 7, 0, 0, 1, 0, 0, 0, 2, 0, 255, 0, 0,
0, 0, 192, 0, 64, 0, 240, 0, 0, 0, 204, 1, 48, 255, 136, 1, 24, 255
};
memcpy(adpcmfmt, source_pcm_format, sizeof(source_pcm_format));
fprintf(stderr, "\n");
for(int i =0; i < 7; ++i) {
fprintf(stderr, "%d %d\n", adpcmfmt->aCoef[i].iCoef1, adpcmfmt->aCoef[i].iCoef2);
}
fflush(stderr);
I receive the following output:
0 512
-256 0
0 192
64 240
0 460
-208 392
-232 0
This seems to be the coefficient list for MS-ADPCM, but shifted by a few bytes:
aCoeff = { {256, 0}, {512, -256}, {0,0}, {192,64}, {240,0}, {460, -208}, {392,-232} }
My goal is to correctly declare and transform the raw bytes into a ADPCMWAVEFORMAT
(or WAVEFORMATEX
).
I don't know why the code with the raw bytes works, when it seemingly contains invalid ADPCMWAVEFORMAT
data.
Edit: sizeof(WAVEFORMATEX) + sizeof(ADPCMCOEFSET * 7)
returns 52.
So the bytes are 2 bytes less than what I would expect.
Did something get added between 1999 and today ?
wSamplesPerBlock
seems to be the wNumCoefs
amount, which is expected to be 7.
user @cremno correctly identified the issue.
windows.h
needs to be the first header to be included to ensure the struct alignment is properly set up for the struct definition of WAVEFORMATEX
.
This is the correct header order:
// header order important here
// clang-format off
#include <windows.h>
#include <mmreg.h>
#include <mmiscapi.h>
#include <MSAcm.h>
// clang-format on
This lets me create a proper ADPCMWAVEFORMAT
variable like so:
ADPCMWAVEFORMAT* adpcmfmt = calloc(1, sizeof(ADPCMWAVEFORMAT) + sizeof(ADPCMCOEFSET) * 7); // MS-ADPCM
adpcmfmt->wfx.nSamplesPerSec = 22050;
adpcmfmt->wfx.nAvgBytesPerSec = 11155;
adpcmfmt->wfx.nBlockAlign = 512;
adpcmfmt->wfx.wBitsPerSample = 4;
adpcmfmt->wfx.cbSize = 32;
adpcmfmt->wfx.wFormatTag = WAVE_FORMAT_ADPCM;
adpcmfmt->wfx.nChannels = 1;
adpcmfmt->wNumCoef = 7;
adpcmfmt->wSamplesPerBlock = adpcmfmt->wfx.nBlockAlign * 2 / adpcmfmt->wfx.nChannels - 12;
adpcmfmt->aCoef[0].iCoef1 = 256;
adpcmfmt->aCoef[0].iCoef2 = 0;
adpcmfmt->aCoef[1].iCoef1 = 512;
adpcmfmt->aCoef[1].iCoef2 = -256;
adpcmfmt->aCoef[2].iCoef1 = 0;
adpcmfmt->aCoef[2].iCoef2 = 0;
adpcmfmt->aCoef[3].iCoef1 = 192;
adpcmfmt->aCoef[3].iCoef2 = 64;
adpcmfmt->aCoef[4].iCoef1 = 240;
adpcmfmt->aCoef[4].iCoef2 = 0;
adpcmfmt->aCoef[5].iCoef1 = 460;
adpcmfmt->aCoef[5].iCoef2 = -208;
adpcmfmt->aCoef[6].iCoef1 = 392;
adpcmfmt->aCoef[6].iCoef2 = -232;
MMRESULT mmresult = acmStreamOpen(&hACMStream, NULL, (LPWAVEFORMATEX)adpcmfmt, &fmt, 0, 0, 0, 0);