#c #winapi #playsound
#c #winapi #воспроизведение звука
Вопрос:
Я создал программу, которая выдает звук щелчка при каждом нажатии клавиши на клавиатуре. Когда я попробовал программу на своем ПК (с Ryzen 3900x) и на одном из моих ноутбуков (с i7 8850h), она воспроизводила звук безупречно, без каких-либо задержек, даже при быстром наборе текста.
Но на более медленном ноутбуке, который я использую для учебы, он неправильно воспроизводит звук, особенно при быстром наборе текста. (Звук либо задерживается, либо воспроизводится только небольшая часть перед остановкой)
Я не могу найти проблему, кроме того, что воспроизведение звука может быть слишком медленным или что-то в этом роде. Это не имеет никакого отношения к загрузке звукового файла, потому что я воспроизводю звук из памяти. Это также не распознавание нажатия клавиши, потому что вывод на консоль (какая клавиша нажата) происходит почти мгновенно.
Вот мой код:
#ifndef UNICODE
#define UNICODE
#endif // UNICODE
#include <stdio.h>
#include <stdlib.h>
#include <w32api.h>
#define WINVER WindowsXP
#include <windows.h>
#include <winuser.h>
BYTE* byteAudio = NULL;
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_INPUT)
{
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
RAWINPUT input = { 0 };
UINT size = sizeof(input);
GetRawInputData(hRawInput, RID_INPUT,amp;input,amp;size,sizeof(RAWINPUTHEADER));
if(input.data.keyboard.Flags == 0)
{
//PlaySoundW(TEXT("res/click.wav"), NULL, SND_ASYNC | SND_FILENAME);
PlaySound(byteAudio, SND_MEMORY, SND_ASYNC | SND_MEMORY);
printf("vkey: %x, flag: %dn",input.data.keyboard.VKey, input.data.keyboard.Flags);
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpComLine, int iShowCmd)
{
const char* CLASS_NAME = "RawInputClass";
FILE* fPtr;
long lFileSize;
//Gets file size
fPtr = fopen("res/click.wav", "rb");
if(!fPtr)
{
printf("Error while opening file!");
return -1;
}
fseek(fPtr, 0, SEEK_END);
lFileSize = ftell(fPtr);
rewind(fPtr);
//Reads file into byte-Array
byteAudio = (BYTE*)malloc(lFileSize * sizeof(BYTE));
if(!byteAudio)
{
printf("byteAudio; OUT_OF_MEMORY"); //If that happens, it is probably time for an upgrade
return -1;
}
fread(byteAudio, lFileSize, 1, fPtr);
fclose(fPtr);
//Create Message-Only window
WNDCLASS wnd = { 0 };
wnd.hInstance = GetModuleHandle(NULL);
wnd.lpfnWndProc = WinProc;
wnd.lpszClassName = CLASS_NAME;
RegisterClass(amp;wnd);
HWND hWnd = CreateWindowExW(0, CLASS_NAME, TEXT("THE WINDOW IS INVISIBLE SO WHO CARES!"),
0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
RAWINPUTDEVICE rid = { 0 };
rid.usUsagePage = 0x01;
rid.usUsage = 0x06; //keyboard
rid.dwFlags = RIDEV_INPUTSINK | RIDEV_NOLEGACY;
rid.hwndTarget = hWnd;
RegisterRawInputDevices(amp;rid, 1, sizeof(RAWINPUTDEVICE));
MSG msg;
while(GetMessage(amp;msg, NULL, 0, 0))
{
TranslateMessage(amp;msg);
DispatchMessage(amp;msg);
}
}
Комментарии:
1. Я не знаю, почему мой пост получает downvoted. Пожалуйста, скажите мне, что не так в моем вопросе, чтобы я мог соответствующим образом его отредактировать
2. SND_MEMORY для 2-го аргумента (hMod) неверно. Воспроизведение звука не может перекрывать звуки волн, вызов его во время воспроизведения SND_ASYNC приводит к остановке текущего воспроизведения, а затем к повторному запуску, что, вероятно, и происходит.
3. Я не могу воспроизвести вашу проблему. Согласно вашему описанию, это может быть связано только с самим компьютером. Может быть, вы можете предоставить нам больше информации, чтобы воспроизвести вашу проблему.
4. @Ascendise Я думаю, что это не имеет никакого отношения к используемому звуковому файлу, возможно, вам нужно выяснить другие возможные повторяющиеся причины, помимо компьютера.
5. Да, у меня все работает нормально. Я использую i7-7700CPU и наушники. Я некоторое время пытался вводить данные, и все работает нормально.
Ответ №1:
Вы используете метод опроса, который является медленным.
while(GetMessage(amp;msg, NULL, 0, 0))
{
/* stuff */
}
Прочитайте о том, что такое прерывания и для чего они используются. Это решит вашу проблему.
Комментарии:
1. Не так. Это стандартный цикл сообщений Win32.
GetMessage
блокируется до тех пор, пока сообщение не будет добавлено в очередь.2. Это именно то, что делает метод опроса . Может быть, я слепой, но я не вижу никакой процедуры прерывания .
3. Введение в устройства с человеческим интерфейсом (HID): learn.microsoft.com/en-us/windows-hardware/drivers/hid PS в разделе legacy также есть полезная информация
4. Нет. Этот код ожидает, пока сообщения не будут добавлены в очередь. Затем он обрабатывает их. Базовый тариф для программистов пользовательского интерфейса Windows.
5. «Прерывание» скрыто в реализации
GetMessage
. Запуск вызывающего потока не запланирован до тех пор, пока сообщение не станет доступным. Это часть управляемого событиями API Windows и полная противоположность «опросу» .