Register
Handmade Hero»Forums»Code»WaveOut Sound API
12 posts
WaveOut Sound API
4 months ago Edited by Bits Please on May 23, 2020, 5:41 p.m. Reason: Initial post
Greetings, everyone.

I'm want to write the equivalent code for constructing and playing a sine wave that Casey wrote on episode 9 but using the WaveOut API, and since I'm dealing with a very old API, there's not much information about it. So I was wondering if any of you guys have dealt with this API before and could shed some light as to how exactly it works, its pros and cons over other sound API's and how do I succeed in my mission.

Thanks!
Mārtiņš Možeiko
2126 posts / 1 project
WaveOut Sound API
4 months ago Edited by Mārtiņš Možeiko on May 23, 2020, 8:33 p.m.
MSDN has reasonable documentation about how to use waveOut API: https://docs.microsoft.com/en-us/...s/win32/multimedia/waveform-audio
The older is the API, the better it is documented in MSDN.

There is not really much to do with waveOut functions - first you open device with waveOutOpen, then prepare data blocks to submit with waveOutPrepareHeader, and write them with waveOutWrite, then use waveOutUnprepareHeader to "free" the blocks. That's it. There are different mechanisms to be notified when when block finished playing - callback, event, thread/window messages, polling - all covered in MSDN docs.

Advantages of using waveOut? You can run on Windows 95/98 or XP without installing any redists.
Disadvantages - very large latency compared to other audio API's. If you are playing music or video file - no problem, but for fast games, this can be problematic.
12 posts
WaveOut Sound API
3 months, 4 weeks ago
Thank you, as always, for your useful input!
I actually stumbled upon your guide on how to integrate WASAPI into the handmade hero code and I decided to ditch WaveOut as it is clearly gotten inferior to the Windows Core Audio API in terms of latency. However, I'm now facing a different kind of problem.

I wrote the following code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <mmdeviceapi.h>

#define ASSERT(expression) if (!(expression)) {*(int *) 0 = 0;}

static void InitWASAPI(int sampleRate, int bufferSize) {
    if (CoInitializeEx(0, COINIT_SPEED_OVER_MEMORY) != S_OK) ASSERT(!"Error");
    
    IMMDeviceEnumerator *enumerator;
    if (CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **) &enumerator) != S_OK) ASSERT(!"Error");
}

int main(int argc, char **argv) {
    InitWASAPI(48000, 48000);
    return 0;
}


I'm using pure C here and this complicate things a little for me as there's no such thing as __uuidof() in C. So my first question is, what exactly does this operator do and are there any alternatives which are compatible with C?
And my second question is, why am I getting an undefined reference to CLSID_MMDeviceEnumerator and IID_IMMDeviceEnumerator when trying to compile the aforementioned code?
Mārtiņš Možeiko
2126 posts / 1 project
WaveOut Sound API
3 months, 4 weeks ago Edited by Mārtiņš Možeiko on May 28, 2020, 11:31 a.m.
__uiidof(X) returns GUID from type X.
If you look how MMDeviceEnumerator is defined, you'll see this:
1
2
3
4
5
MIDL_INTERFACE("A95664D2-9614-4F35-A746-DE8DB63617E6")
IMMDeviceEnumerator : public IUnknown
{
...
}

__uiidof(MMDeviceEnumerator) will produce A95664D2-9614-4F35-A746-DE8DB63617E6 as GUID type.

To fix this in C, you should include #include <initguid.h> header first (before all the Windows stuff) or #define INITGUID before all header includes. This will make CLSID/IID guids to be defined. Without it they are only declared extern.
Simon Anciaux
882 posts
WaveOut Sound API
3 months, 4 weeks ago
I had that issue and others a while back. Here is the thread in case it might content useful information.