SDL isn't working correctly

My code isn’t working. I think I’ve done everything correctly according to the official SDL2 documentation. It should play a sinewave for just under 1 second, but instead I hear nothing. The strange thing is that I have error checks at a couple places and it should pop up an error message box if anything is going wrong. But I don’t get any error messages. It’s like it’s failing in a way that it shouldn’t, and so isn’t actually triggering the official error catching routines that enable the operation of the SDL_GetError function.

I’ve completely documented my code so you can see what each piece of code is supposed to be doing. Below is the complete code for my program. Please tell me what’s wrong with my program.
#include <smallcrt.h>
#include <stdlib.h>
#include <SDL.h>
#include <windows.h>

void _start(){
	SDL_AudioSpec as;
	SDL_AudioSpec as2;
	SDL_AudioDeviceID ad;
	short buff[4096];
	int n;

	
	//configure desired audio output spec
	as.freq = 48000;
	as.format = AUDIO_S16LSB;
	as.channels = 1;
	as.samples = 4096;
	as.callback = 0; //no callback
	as.silence = 0; //field will be initialized by SDL_OpenAudioDevice, but must be set to 0 now
	as.size = 0; //field will be initialized by SDL_OpenAudioDevice, but must be set to 0 now
	as.userdata = 0; //set this to zero as no callback will be used so user defined data for callback is unneeded
	
	//zero all fields for actual audio output spec struct in preparation for SDL_OpenAudioDevice to fill it with meaningful data
	as2.freq = 0;
	as2.format = 0;
	as2.channels = 0;
	as2.samples = 0;
	as2.callback = 0;
	as2.silence = 0;
	as2.size = 0;
	as2.userdata = 0;

	
	for (n=0;n<4096;n++){
		buff[n] = sin(3.14159*2*n*1000/48000)*0x7FFF; //create a 1khz sinewave at max amplitude to put into the buffer
	}
	
	
	SDL_Init(SDL_INIT_AUDIO); //initialize SDL audio sysetm
	
	ad = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(1,0),0,&as,&as2,0); //open Headphones audio device
	if (ad==0){
		MessageBoxA(0,SDL_GetError(),"Error",0); //display error message if device doesn't open
	} 
	
	
	SDL_PauseAudioDevice(ad,0); //activate device, so that it plays silence until audio data is queued later
	
	//queue the 1khz sinewave audio data 10 times, which should play for just under 1 second
	if (SDL_QueueAudio(ad,&buff,4096*2)){
		MessageBoxA(0,SDL_GetError(),"Error",0); //first time check if it actually queued it without error, and display error message if it failed
	}
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	SDL_QueueAudio(ad,&buff,4096*2);
	
	
	SDL_Delay(2000); //delay closing of main thread, so that program won't end before SDL audio thread finishes playing queued sinewave
	
	SDL_CloseAudioDevice(ad); //close the Headphones audio device
	
	
	SDL_Quit(); //close SDL systems
	ExitProcess(0); //quit program
}

Not sure why you use _start instead of main() - id reccomend to go with main (and link against SDLmain) instead.

Aside from that i think you will have to do SDL_QueueAudio(ad,buff,4096*2) instead of SDL_QueueAudio(ad,&buff,4096*2), as buff is already a pointer.

Also, buff is to small. If you want 4096 stero samples witch each 16 bit, youd need twice the size. (and you need to fill both channels at once in the loop.

So I’m basically giving it a pointer to a pointer? Is that what I’m doing wrong?
Also, where do I get a copy of SDLmain? Is that the name of an .h header file? I didn’t get a copy of that when I downloaded SDL2.

Ok, I just tried what you suggested with removing the & from the QueueAudio function and it didn’t fix anything. I ended up loading my program into the debugger OllyDbg and I see where the problem is. It is crashing during the call to OpenAudioDevice. Something is happening within SDL itself leads to a call to Kernel32, but an invalid location in Kernel32 (in other words, not the start of a function) so it ends up executing invalid bytes as if they were opcodes, somewhere in Kernel32.dll.

If the buffer is too small and/or you’re passing in the address of a pointer instead of the pointer itself I’d expect it to crash. If you fix those and still hear silence, you might troubleshoot by opening all audio devices in a loop and push the audio buffer into each one, to rule out wrong device as the problem.

I created a somewhat working example from your code.

Note that i renamed some variables.

Doing stuff like this will have several issues. The biggest, if playback is working, will be that your buffer probably wont end up on a 0-value, so each time a queued buffer finished (wich takes about 0.1 seconds), you will here a noisy clipping sound.

Try working with an audio callback instead, as described in the documentation.

If you just want audio playback, consider using SDL_mixer.

I finally got mine working too, but it required me to not use _start as the entry point. It required me to use main instead. I tend to not like to use main, becauese of the simple fact that when main is used as the entry point, it forces the C compiler (I’m using TinyCC) to insert its own _start function which contains nothing but a bunch of initialization code that does a number of things (including getting command-line arguments that I don’t even plan to use). So to keep my compiled code small, I always use _start as my entry point and -nostdlib command line switch. This allows me to keep the code very small, and basically the C compiler then only compiles code that I ask it to, instead of inserting a bunch of code that I didn’t ask it to.

It’s a good way to write small/efficient/optimized code, but for some reason is not compatible with SDL2 (or at least with SDL’s audio functions). Any tips on making it compatible with SDL2?

Here is a bit of a rant about why you should just use main like everyone else does:

main is the standard, and everything is built around it. Sure, it’s good to be efficiency-minded but don’t get too concerned about such things as the expense of using main and receiving command line arguments. Anything the compiler puts before main is probably both very important (why else would it put it?) and very inexpensive. You’re probably going to see a hundred billion times more startup cost from the OS simply loading your executable image into RAM to run it, than you are going to see from some very small initialization code. The time it takes to call SDL_Init(SDL_INIT_AUDIO) is itself probably many orders of magnitude longer, too. Further, even if it did add some noticeable few tens of milliseconds, it is a one-time expense. Focus on the functionality of your application first. Then improve high-level inefficiencies with the way your design works. Only after you have a working system that cannot be logically optimized any further should you ever resort to exotic tricks like this (but I would suggest even then you don’t, since you risk breaking things, especially when you go from one compiler to another or even between different versions of the same compiler - your compiler hack might not break everything in one environment, but then you go to compile for another platform and everything explodes… and I would expect the very reason you’re using SDL is because it’s meant to be cross-platform and reliable, right?).