我有一个非常简单的程序,可以播放 4 种不同的音调,具体取决于按下的按钮。我发现如果我快速连续演奏多个音调或相同的音调,会产生令人不快的咔嗒声。我已确保我的音频样本中不存在这些点击;这肯定是由于一个接一个地快速播放剪辑造成的。
在谷歌搜索之后,我相当确定点击是由于剪辑之间音高的快速变化。查看来自违规音频的播放波形,看起来一个剪辑在开始下一个剪辑之前首先被取消了几分之一秒。我已经强调了这似乎特别明显的部分。
展示这些音频点击的剪辑也可以在这里下载。
我的代码非常简单。我正在使用 XInput 从连接的控制器读取输入,这决定了要播放的音调,我正在使用 WinMM 从 wav 文件中输出声音。它是用 D 编程语言编写的,但我已经对其进行了修改,使其不使用特定于 D 的功能,以使其尽可能类似于 C 并避免混淆。
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;
}
假设我对咔哒声的来源是正确的,我认为解决方案是让每个样本淡入下一个样本。但是,我不确定如何执行此操作,因为WinMM 文档似乎相对稀疏,而且我对它缺乏经验。
播放音频样本以使每个样本淡入下一个样本时,是否可以解决我的点击问题?如果是这样,我如何使用 WinMM 完成此操作?如果没有,我可以尝试另一种解决方案吗?