mercredi 24 décembre 2014

Clicking Sounds When Playing Clips in Rapid Succession

I have a very simple program that plays 4 different tones, depending on what button is pressed. I have found that if I play multiple tones or the same tone in rapid succession, there are unpleasant clicking noises produced. I have made sure that these clicks are not present in my audio samples; it is definitely caused by playing the clips quickly one after another.


After googling around, I'm fairly sure that the clicks are due to the rapid change in pitch between clips. Looking at the waveform of the playback from the offending audio, it looks like a clip is first cancelled for a fraction of a second before starting the next clip. I have highlighted the section where this seems particularly obvious.


Waveform of the clip that exhibits clicking between tones


The clip that showcases these audio clicks can also be downloaded here.


My code is very simple. I am using XInput to read input from a connected controller, which determines the tone to play, and I am using WinMM to output sound from wav files. It is written in the D programming language, but I have modified it to use no D-specific features to make it as C-like as possible and to avoid confusion.



SHORT keyPressed(int vkey)
{
enum highBit { val = 0x8000 }

return cast(SHORT)(GetKeyState(vkey) & highBit.val);
}

enum Button
{
DPAD_UP = 0x0001,
DPAD_DOWN = 0x0002,
DPAD_LEFT = 0x0004,
DPAD_RIGHT = 0x0008,

START = 0x0010,
BACK = 0x0020,

LEFT_THUMB = 0x0040,
RIGHT_THUMB = 0x0080,

LEFT_SHOULDER = 0x0100,
RIGHT_SHOULDER = 0x0200,

A = 0x1000,
B = 0x2000,
X = 0x4000,
Y = 0x8000,
}

struct XINPUT_GAMEPAD
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
}

struct XINPUT_STATE
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;

bool isPressed(int button)
{
return cast(bool)(Gamepad.wButtons & button);
}
}

int main()
{
HANDLE xinputDLL = initXinput();

XINPUT_STATE oldState;
XINPUT_STATE newState;

while (!keyPressed(VK_ESCAPE))
{
oldState = newState;
XInputGetState(0, &newState);

enum flags { val = SND_ASYNC | SND_FILENAME | SND_NODEFAULT }

if (newState.isPressed(Button.A) && !oldState.isPressed(Button.A))
{
PlaySoundA(toStringz("Piano.ff.A4.wav"), null, flags.val);
}

if (newState.isPressed(Button.B) && !oldState.isPressed(Button.B))
{
PlaySoundA(toStringz("Piano.ff.B4.wav"), null, flags.val);
}

if (newState.isPressed(Button.X) && !oldState.isPressed(Button.X))
{
PlaySoundA(toStringz("Piano.ff.C5.wav"), null, flags.val);
}

if (newState.isPressed(Button.Y) && !oldState.isPressed(Button.Y))
{
PlaySoundA(toStringz("Piano.ff.F4.wav"), null, flags.val);
}
}

denitXinput(xinputDLL);

return 0;
}


Assuming that I'm correct in regards to the source of the clicking sounds, I think the solution is to have each sample fade into the next one. However, I am not sure how to do this as the WinMM documentation seems relatively sparse, and I am inexperienced with it.


Is the solution to my problem of clicks when playing audio samples to have each sample fade into the next one? If so, how can I accomplish this using WinMM? If not, is there another solution that I can try?


Aucun commentaire:

Enregistrer un commentaire