Skip to content

Instantly share code, notes, and snippets.

@mrpippy
Created November 13, 2020 00:32
Show Gist options
  • Save mrpippy/f2ddbf57bed572c0f056612dbdf8f98f to your computer and use it in GitHub Desktop.
Save mrpippy/f2ddbf57bed572c0f056612dbdf8f98f to your computer and use it in GitHub Desktop.
// build with: x86_64-w64-mingw32-gcc -o rez_xaudio_test.exe rez_xaudio_test.c -lole32
#include <stdio.h>
#define COBJMACROS
#include <initguid.h>
#include <windows.h>
#include <xaudio2.h>
#include <xaudio2fx.h>
#include <xapofx.h>
void printf_guid(GUID *guid) {
printf("Guid = {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
static void WINAPI ECB_OnProcessingPassStart(IXAudio2EngineCallback *This)
{
printf("callback: OnProcessingPassStart\n");
}
static void WINAPI ECB_OnProcessingPassEnd(IXAudio2EngineCallback *This)
{
printf("callback: OnProcessingPassEnd\n");
}
static void WINAPI ECB_OnCriticalError(IXAudio2EngineCallback *This, HRESULT Error)
{
printf("callback: OnCriticalError err %lx\n", Error);
}
static IXAudio2EngineCallbackVtbl ecb_vtbl = {
ECB_OnProcessingPassStart,
ECB_OnProcessingPassEnd,
ECB_OnCriticalError
};
static IXAudio2EngineCallback ecb = { &ecb_vtbl };
int main()
{
HRESULT hr;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HANDLE hXAudio2_7 = LoadLibraryA("XAudio2_7.dll");
IXAudio27 *xa27;
CoCreateInstance(&CLSID_XAudio27, NULL, 1, &IID_IXAudio27, (void **)&xa27);
hr = IXAudio27_Initialize(xa27, 0, XAUDIO2_ANY_PROCESSOR);
UINT32 deviceCount;
hr = IXAudio27_GetDeviceCount(xa27, &deviceCount);
printf("device count: %u\n", deviceCount);
for (UINT32 i = 0; i < deviceCount; i++)
{
XAUDIO2_DEVICE_DETAILS details;
hr = IXAudio27_GetDeviceDetails(xa27, i, &details);
printf("device %u:\n", i);
printf("\tID: %ls\n", details.DeviceID);
printf("\tname: %ls\n", details.DisplayName);
printf("\trole: %d\n", details.Role);
{
printf("\tmixformat: tag %x channels %d samplespersec %ld avgbytespersec %ld blockalign %d bitspersample %d cbsize %d\n",
details.OutputFormat.Format.wFormatTag, details.OutputFormat.Format.nChannels, details.OutputFormat.Format.nSamplesPerSec, details.OutputFormat.Format.nAvgBytesPerSec, details.OutputFormat.Format.nBlockAlign, details.OutputFormat.Format.wBitsPerSample, details.OutputFormat.Format.cbSize
);
printf("\twfx samples %x channelmask %lx subformat ", details.OutputFormat.Samples.wValidBitsPerSample, details.OutputFormat.dwChannelMask);
printf_guid(&details.OutputFormat.SubFormat);
printf("\n");
}
}
IXAudio2MasteringVoice *masteringvoice;
hr = IXAudio27_CreateMasteringVoice(xa27, &masteringvoice, 2, 44100, 0, 0, NULL);
IXAudio2SubmixVoice *submixvoice;
hr = IXAudio27_CreateSubmixVoice(xa27, &submixvoice, 6, 44100, 0, 20, NULL, NULL);
const float matrix[6*2] = {1.0};
hr = IXAudio27SubmixVoice_SetOutputMatrix(submixvoice, (IXAudio2Voice*)masteringvoice, 6, 2, matrix, 0);
hr = IXAudio27MasteringVoice_SetVolume(masteringvoice, 1.0, 0);
hr = IXAudio27_RegisterForCallbacks(xa27, &ecb);
IXAudio2SubmixVoice *submixvoice2;
XAUDIO2_VOICE_SENDS sends;
XAUDIO2_SEND_DESCRIPTOR send_desc;
sends.SendCount = 1;
sends.pSends = &send_desc;
sends.pSends[0].Flags = 0;
sends.pSends[0].pOutputVoice = (IXAudio2Voice*)submixvoice;
hr = IXAudio27_CreateSubmixVoice(xa27, &submixvoice2, 6, 48000, 0, 2, &sends, NULL);
hr = IXAudio27SubmixVoice_SetOutputMatrix(submixvoice2, (IXAudio2Voice*)submixvoice, 6, 6, matrix, 0);
IXAudio2SubmixVoice *submixvoice3;
hr = IXAudio27_CreateSubmixVoice(xa27, &submixvoice3, 6, 48000, XAUDIO2_VOICE_USEFILTER, 1, &sends, NULL);
hr = IXAudio27SubmixVoice_SetOutputMatrix(submixvoice3, (IXAudio2Voice*)submixvoice, 6, 6, matrix, 0);
IXAudio2SubmixVoice *submixvoice4;
hr = IXAudio27_CreateSubmixVoice(xa27, &submixvoice4, 6, 48000, XAUDIO2_VOICE_USEFILTER, 1, &sends, NULL);
hr = IXAudio27SubmixVoice_SetOutputMatrix(submixvoice4, (IXAudio2Voice*)submixvoice, 6, 6, matrix, 0);
IUnknown *reverb_apo;
CoCreateInstance(&CLSID_AudioReverb27, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&reverb_apo);
XAUDIO2_EFFECT_CHAIN effects;
XAUDIO2_EFFECT_DESCRIPTOR eff_desc[2];
effects.pEffectDescriptors = eff_desc;
effects.EffectCount = 1;
effects.pEffectDescriptors[0].pEffect = reverb_apo;
effects.pEffectDescriptors[0].InitialState = TRUE;
effects.pEffectDescriptors[0].OutputChannels = 6;
/* this succeeds on Windows but fails with Wine/FAudio */
hr = IXAudio27SubmixVoice_SetEffectChain(submixvoice4, &effects);
printf("SetEffectChain hr 0x%lx\n", hr);
#if 0
HRESULT (CDECL *pCreateFX)(REFCLSID,IUnknown**) = NULL;
IUnknown *echo1, *echo2;
HANDLE pXAPOFX1_5 = LoadLibraryA("xapofx1_5.dll");
pCreateFX = (void*)GetProcAddress(pXAPOFX1_5, "CreateFX");
pCreateFX(&CLSID_FXEcho27, &echo1);
pCreateFX(&CLSID_FXEcho27, &echo2);
effects.EffectCount = 2;
effects.pEffectDescriptors[0].pEffect = echo1;
effects.pEffectDescriptors[0].InitialState = TRUE;
effects.pEffectDescriptors[0].OutputChannels = 6;
effects.pEffectDescriptors[1].pEffect = echo2;
effects.pEffectDescriptors[1].InitialState = TRUE;
effects.pEffectDescriptors[1].OutputChannels = 6;
hr = IXAudio27SubmixVoice_SetEffectChain(submixvoice3, &effects);
printf("SetEffectChain hr %lx\n", hr);
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment