SDL Sound thread delay between samples?

When I use the following handler to handle and mix multiple channels, I get about 1 time unit sound, 5/6 time units silence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//The volume conversion!
#define VOLUME_PER_SOUND(volume) ((SDL_MIX_MAXVOLUME / 2)*volume)
//Ammount of times to multiply the buffer!
#define MULTIPLIER_BUFFER 1

/* This function is called by SDL whenever the sound card
   needs more samples to play. It might be called from a
   separate thread, so we should be careful what we touch. */
void SDLAudioCallback(void *user_data, Uint8 *audio, int length)
{
	//Info: length is in bytes, not in samples!
	int i;
	/* Clear the audio buffer so we can mix samples into it. */
	memset(audio, 0, length);
	length /= sizeof(*soundchannels[0].sound.samples); //Convert length to sample size!

	/* Mix in each sound. */
	for (i = 0; i < NUMITEMS(soundchannels); i++)
	{
		if (soundchannels[i].soundhandler)
		{ //Active?
			if (memprotect(soundchannels[i].sound.samples,soundchannels[i].sound.length*sizeof(*soundchannels[i].sound.samples))) //Valid channel?
			{
				int position = soundchannels[i].sound.position; //The position to use!
				if (soundchannels[i].sound.position >= soundchannels[i].sound.length) { //Expired, we've reached the end of the buffer?
					//dolog("soundservice","Handling sound callback %x...",soundchannels[i].soundhandler);
					soundchannels[i].soundhandler(soundchannels[i].sound.samples,soundchannels[i].sound.length,(void *)&soundchannels[i]); /* Request next sample for this channel, also give our channel pointer! */
					//dolog("soundservice","Sound callback successful.");
					position = soundchannels[i].sound.position = 0; //Reset position in the next frame!
				}
				
				int_32 amount = length; //Default: give length samples!
				if (amount>length) //Over max?
				{
					amount = length; //Use max!
				}
				if (position+amount>soundchannels[i].sound.length) //Overflow?
				{
					amount -= (position+amount)-soundchannels[i].sound.length; //Use rest!
				}
				amount *= sizeof(*soundchannels[i].sound.samples); //Change ammount of samples to ammount of bytes!
				
				int c=0;
				if (amount>0) //Gotten ammount to process?
				{
					for (;c<MULTIPLIER_BUFFER;c++) //How many times to multiply the buffer?
					{
						SDL_MixAudio(audio+(c*amount), (uint8_t *)&soundchannels[i].sound.samples[position], amount, VOLUME_PER_SOUND(soundchannels[i].volume));
						soundchannels[i].sound.position += amount; //Increase the position for the next sample, if any!
					}
				}
			}
		}
	}
}


Anyone knows what I'm doing wrong? What's causing the silence? (I'm working with 44.1kHz stereo PCM streams)

I've multiplied the stream some times, but to no effect (see the c<MULTIPLIER_BUFFER loop arround the mixing)...
Why not use windows.h?
@toad: why would he? o_O What does windows.h have to do with anything?

@OP:

One potential problem I see is that you might not produce enough audio in your audio handler.

Example:

if SoundHandler produces 3000 samples but SDL is requesting 4000 samples, you'll end up with 1/4th silence because you'll only use what's remaining in the buffer.

Also... if SoundHandler produces 6000 samples but SDL is requestion 4000, you'll play all 4000 samples, but then will be left with only 2000 in your sound, which means NEXT time the callback is called, you will only fill the buffer halfway.

So unless SDL is requesting the exact number of samples (or an exact multiple) that SoundHandler is generating... then this code will have periodic gaps of silence.

The best option I can see in this setup is to not double buffer the audio. This is kind of a wasted step anyway. There's no point (I can see) in loading the audio into soundchannels[i].sound.samples only to copy it to the output buffer. Just load it to the output buffer directly. It'll be faster, it'll use less memory, and you can generate, on demand, exactly how much audio you need.

EDIT:

A "quick fix" without changing how your soundchannels work would be to put all this audio generation in a while loop... so it continues until the soundchannel isn't producing any more audio, or until the output buffer has been completely filled. As of right now you're only giving each channel one pass.

IE: you're doing this:

1
2
3
4
if( need_to_output_sound_data )
{
   output_as_much_audio_as_we_have();
}


When you should do something like this:
1
2
3
4
while( audio_is_needed )
{
   output_as_much_audio_as_we_have();
}




On a side note...software audio mixing sucks. This is one of the many reasons I dislike SDL.
Last edited on
Because windows.h has a playsound function. There is also bass.
Because windows.h has a playsound function


I guess.... but PlaySound is pretty limited.

There is also bass.


Yeah, but he's using SDL.
Topic archived. No new replies allowed.