Я работаю над старой (1999~) декомпилированной кодовой базой игры Win32.
В нем есть следующая последовательность байтов, взятых непосредственно из дизассемблированного бинарника:
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
};
Эти байты передаются в функцию acmStreamOpen
и преобразуются в LPWAVEFORMATEX
:
mmresult = acmStreamOpen(&hACMStream, hACMDriver, (LPWAVEFORMATEX)source_pcm_format, &pcm_format, 0, 0, 0, 0);
этот вызов функции работает правильно
Когда я сам интерпретирую эти байты как WAVEFORMATEX
, wFormatTag
равен 2, что соответствует ADPCMWAVEFORMAT
.
Когда я интерпретирую байты как ADPCMWAVEFORMAT
, дела идут странно:
ADPCMWAVEFORAMT
необходимо wNumCoefs
количество ADPCMCOEFSET
.
Однако 50 байт слишком мало для хранения 256 коэффициентов.
При печати коэффициентов следующим образом (я предполагаю, что это 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);
Я получаю следующий вывод:
0 512
-256 0
0 192
64 240
0 460
-208 392
-232 0
Кажется, это список коэффициентов для MS-ADPCM, но сдвинутый на несколько байт:
aCoeff = { {256, 0}, {512, -256}, {0,0}, {192,64}, {240,0}, {460, -208}, {392, -232} }
Моя цель — правильно объявить и преобразовать необработанные байты в ADPCMWAVEFORMAT
(или WAVEFORMATEX
).
Я не знаю, почему код с необработанными байтами работает, если он, казалось бы, содержит неверные ADPCMWAVEFORMAT
данные.
Обновлено: sizeof(WAVEFORMATEX) + sizeof(ADPCMCOEFSET * 7)
возвращает 52.
Таким образом, байты на 2 байта меньше, чем я ожидал.
Было ли что-то добавлено между 1999 годом и сегодняшним днем?
wSamplesPerBlock
кажется суммой wNumCoefs
, которая, как ожидается, будет равна 7.
Я использую флаги компилятора x86 по умолчанию (/Zp не указан)
Что, по мнению вашего компилятора, представляют собой sizeof(WAVEFORMATEX)
и sizeof(ADPCMWAVEFORMAT)
? Это должны быть 18
и 22
соответственно.
@Люк, ты, кажется, прав. с моей стороны sizeof(WAVEFORMATEX)
возвращается 20
. Но как именно мне убедиться, что размер правильный? Это структура Win32, поэтому я не могу добавить #pragma pack
пользователь @cremno правильно определил проблему .
windows.h
должен быть первым включенным заголовком, чтобы обеспечить правильную настройку выравнивания структуры для определения структуры WAVEFORMATEX
.
Это правильный порядок заголовков:
// header order important here
// clang-format off
#include <windows.h>
#include <mmreg.h>
#include <mmiscapi.h>
#include <MSAcm.h>
// clang-format on
Это позволяет мне создать правильную переменную ADPCMWAVEFORMAT
, например:
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);
Какой бы компилятор/редактор вы ни использовали, он неправильно интерпретирует структуру. Похоже, что используется 16-битная упаковка, тогда как фактическое определение структуры — 8-битная упаковка.