Sound pops and clicks - XAudio2

Started by
8 comments, last by Prads 12 years, 7 months ago
I have to play different quadrangular waves of 12.5%, 25%, 50% and 75% duty cycle to create melodies. So far I have been able to get melodies right but one problem exist and that is when I try to start and stop the sound, it gives me nasty pops and clicks sound. The program has to start and stop the sound quite a lot so there is lot of pops and clicks. One way I have found to get rids of these pops and clicks is by instead of starting and stopping the sound, I just start it once and then change the volume, if I am starting the sound I change the volume to 1 and if I am stopping the sound I change the volume to 0. This method works but I am not sure if this is a good or the right method to stop sound. So, can anyone tell me how I can get rid of pops and clicks when I am starting and stopping sound?

Thanks!!!


My first 3D game: Click Here
Advertisement
I'm no expert on XAudio2 but one option you could possibly try is to call[font="Segoe UI"] IXAudio2SourceVoice::FlushSourceBuffers() before you [/font]ultimately [font="Segoe UI"]stop playing your sound. What this does is it discards all of the queued audio buffers for that source voice and only maintains the currently playing buffer, which (depending on your implementation) could only be a second or so of audio.[/font]
[font="Segoe UI"][color="#1C2837"][font="arial, verdana, tahoma, sans-serif"]
[/font][/font]
[font="Segoe UI"][color="#1C2837"][font="arial, verdana, tahoma, sans-serif"]
One way I have found to get rids of these pops and clicks is by instead of starting and stopping the sound, I just start it once and then change the volume, if I am starting the sound I change the volume to 1 and if I am stopping the sound I change the volume to 0.[/quote][/font][/font]
[color="#1c2837"]If this works for you, you can still Start() and Stop() your source voice's normally, but just add a call to SetVolume(1.0f) and [color="#1C2837"]SetVolume(0.0f)[color="#1C2837"] before you actually call Start() and Stop() respectively. I don't believe there is that much overhead with SetVolume() that it would cause much of a problem, but again I'm no expert.
[font="Segoe UI"] [/font]
[font="Segoe UI"]However I think it would be best if you posted some of your code for everyone to look at. The most important things would be your start, stop, initialization and update functions[/font]
Thank you for your reply. Flushing off the buffer is not a bad idea but it wouldn't work for me because the source voice only has one buffer that is looped again and again. Also setting the volume to zero and starting and stopping didn't work.

Here are some codes, first this is how I have setup my WAVEFORMATEX:


WAVEFORMATEX wFormat;

wFormat.wFormatTag = WAVE_FORMAT_PCM;
wFormat.wBitsPerSample = 8;
wFormat.nBlockAlign = 1;
wFormat.nAvgBytesPerSec = 8000;
wFormat.nSamplesPerSec = 8000;
wFormat.nChannels = 1;
wFormat.cbSize = 0;

ZeroMemory(&xABufferInfo, sizeof(xABufferInfo));
xABufferInfo.AudioBytes = 8;
xABufferInfo.pAudioData = xABuffer;
xABufferInfo.LoopCount = XAUDIO2_LOOP_INFINITE;

if (xASourceChTwo->SubmitSourceBuffer(&xABufferInfo) != S_OK) return false;


So the sample depth is 8 bits and sample rate is 8 kHz.

Now I have 5 buffers, 1st buffer that source voice reads and loops again and again and 4 others are wave patterns of different duty cycle. All of them are 8 bytes long:


unsigned char xABuffer[8], wDTwelve[8], wDTwenty[8], wDFifty[8], wDSeventyFive[8];

//12.5% duty cycle
wDTwelve[0] = 0; wDTwelve[1] = 64; wDTwelve[2] = 64; wDTwelve[3] = 64;
wDTwelve[4] = 64; wDTwelve[5] = 64; wDTwelve[6] = 64; wDTwelve[7] = 64;

//25% duty cycle
wDTwentyFive[0] = 0; wDTwentyFive[1] = 0; wDTwentyFive[2] = 64; wDTwentyFive[3] = 64;
wDTwentyFive[4] = 64; wDTwentyFive[5] = 64; wDTwentyFive[6] = 64; wDTwentyFive[7] = 64;

//50% duty cycle
wDFifty[0] = 0; wDFifty[1] = 0; wDFifty[2] = 0; wDFifty[3] = 0;
wDFifty[4] = 64; wDFifty[5] = 64; wDFifty[6] = 64; wDFifty[7] = 64;

//75% duty cycle
wDSeventyFive[0] = 0; wDSeventyFive[1] = 0; wDSeventyFive[2] = 0; wDSeventyFive[3] = 0;
wDSeventyFive[4] = 0; wDSeventyFive[5] = 0; wDSeventyFive[6] = 64; wDSeventyFive[7] = 64;

//Default wave duty cycle is 50%
memcpy(xABuffer, wDFifty, 8);


Now before playing and updating the sound, program checks duty cycle flag and just copies the data to xABuffer like this:


switch (dutyFlag) {
case DUTY_TWELVE:
memcpy(xABuffer, wDTwelve, 8;
break;
case DUTY_TWENTYFIVE:
memcpy(xABuffer, wDTwentyFive, 8);
break;
case DUTY_FIFTY:
memcpy(xABuffer, wDFifty, 8);
break;
case DUTY_SEVENTYFIVE:
memcpy(xABuffer, wDSeventyFive, 8);
}


Then some flags are checked, frequency is set and the sound is played like this:


if (!channelTwo) {
channelTwo = true;
xASourceChTwo->Start()
}


And at last when sound is suppose to stop, it stops like this:


if (channelTwo) {
channelTwo = false;
xASourceChTwo->Stop();
}
My first 3D game: Click Here
When starting and stopping the sound, you should fade it in and out over a few milliseconds. Clicks and pops are caused by very sudden changes in amplitude.

When starting and stopping the sound, you should fade it in and out over a few milliseconds. Clicks and pops are caused by very sudden changes in amplitude.


This. And you can do a simple test:

Play a 0% duty cycle with full volume. Now you should not hear any clicks and pops at all when you start and stop the audio. If you do, the problem lies elsewhere.
Yeah sudden change of amplitude seems to be the cause. I want to ask something else, performance wise, if sound has to stop and start many times (once a second an average) is it better to leave the sound open with volume down when not playing or is it better to completely stop the sound and restart the sound.

EDIT:
@aregee: Uh oh, I just did that test with 0% duty cycle and I still got clicks and pops. :(
My first 3D game: Click Here

Yeah sudden change of amplitude seems to be the cause. I want to ask something else, performance wise, if sound has to stop and start many times (once a second an average) is it better to leave the sound open with volume down when not playing or is it better to completely stop the sound and restart the sound.

EDIT:
@aregee: Uh oh, I just did that test with 0% duty cycle and I still got clicks and pops. :(


So even if you have perfect silence, you get those clicks and pops?

It is hard to tell what the problem is then. Might be hardware, might be software or something I haven't thought of.

There is an easy fix whatever the reason is: If you can come up with a way to render the sound and also control the volume, perhaps with a multiplication of a value between 0.0f and 1.0f, then you can make a very short transition (fade-in and fade-out) of a very few milliseconds as Adam_42 suggests. I am pretty sure that would work.

Why I suggest you render the volume changes is because I don't know if the volume change you are talking about is the global volume or just for the audio channel you are using. It is not a good solution to alter the global volume to stop the sound from one channel for obvious reasons. What about the other channels then? What about that Spotify song in the background? Yes, users do weird things! ;)

I am also confused how you manage to render different frequencies as you seem to use a fixed number of samples for your sounds. I guess there is something that I don't see. :)

@aregee: Uh oh, I just did that test with 0% duty cycle and I still got clicks and pops. :(

I have read about XAudio2 and its capabilities. Unless XAudio2 is broken, I can not see that it should behave this way and I don't think XAudio2 is broken like that.

I have one suggestion to what may be the fault. You are probably feeding signed data where unsigned is expected or the oposite. This would create cracks and pops where there should be silence when you start and stop the sample.

So if you are feeding all zeroes when each sample is 16 bit, you may actually be feeding DC at max amplitude instead of DC at 0 amplitude. Try the 0% duty cycle again, but this time use the value in the middle of an unsigned word or an unsigned byte depending on 8 bits or 16 bits sample size. 32768 dec (8000 hex) for 16 bits and 128 dec (80 hex) for 8 bits.
Thank you very much. You were right, 0 amplitude is 128 for 8 bits. Cracks are far less frequent now in my program. But can you please answer my this question:

performance wise, if sound has to stop and start many times (once a second an average) is it better to leave the sound open with volume down when not playing or is it better to completely stop the sound and restart the sound.[/quote]
Thank you...
My first 3D game: Click Here

Thank you very much. You were right, 0 amplitude is 128 for 8 bits. Cracks are far less frequent now in my program. But can you please answer my this question:

performance wise, if sound has to stop and start many times (once a second an average) is it better to leave the sound open with volume down when not playing or is it better to completely stop the sound and restart the sound.

Thank you...
[/quote]
Glad that it helped! :)

Regarding your question, I am not sure really. It depends on a lot of factors. My initial thought is that this is what XAudio2 is made to do. Starting, stopping and mixing sounds through a convenient interface. I believe there is very little overhead in starting and stopping sounds since you are not deallocating or reallocating resources for each time you do. That would probably be a bit of a overhead and not a good idea anyway.

I suggest you just postpone any premature optimizations till you actually stumble upon a problem regarding performance since any optimization I can think of is a lot of work that is better spent on the progress of your work. :)

This topic is closed to new replies.

Advertisement