「waveaudio」設備(由PlaySound使用)不支持同時播放多個文件。嘗試使用.mp3文件。下面的例子。
#include <Windows.h>
#include <stdio.h>
#include <stdexcept>
#ifdef _UNICODE
#define stprintf_s swprintf_s
#else
#define stprintf_s sprintf_s
#endif
class Player {
public:
Player(LPCTSTR lpFileName) {
MCI_OPEN_PARMS openp;
MCI_SET_PARMS setp;
openp.dwCallback = NULL;
openp.lpstrDeviceType = reinterpret_cast<LPCTSTR>(MCI_ALL_DEVICE_ID);
openp.lpstrElementName = lpFileName;
TCHAR name[32];
static int alias = 0;
stprintf_s(name, TEXT("alias%08d"), alias++);
openp.lpstrAlias = name;
checkerror(mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE | MCI_OPEN_ALIAS, reinterpret_cast<DWORD_PTR>(&openp)));
_device = openp.wDeviceID;
setp.dwCallback = NULL;
setp.dwTimeFormat = 0;
if (mciSendCommand(openp.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, reinterpret_cast<DWORD_PTR>(&setp)) == DWORD(-1)) {
close();
throw std::runtime_error("Can't open MCI device");
}
}
Player(Player const&) = delete;
Player(Player&& other) {
_device = other._device;
other._device = 0;
}
~Player() {
if (_device != 0) {
close();
}
}
void play(HWND hWndNotify) {
MCI_PLAY_PARMS params;
params.dwCallback = reinterpret_cast<DWORD_PTR>(hWndNotify);
params.dwFrom = NULL;
params.dwTo = NULL;
checkerror(mciSendCommand(_device, MCI_PLAY, (hWndNotify != 0) ? MCI_NOTIFY : 0, reinterpret_cast<DWORD_PTR>(¶ms)));
}
void rewind() {
MCI_SEEK_PARMS params;
checkerror(mciSendCommand(_device, MCI_SEEK, MCI_WAIT | MCI_SEEK_TO_START, reinterpret_cast<DWORD_PTR>(¶ms)));
}
void pause() {
MCI_GENERIC_PARMS params;
params.dwCallback = NULL;
checkerror(mciSendCommand(_device, MCI_PAUSE, MCI_WAIT, reinterpret_cast<DWORD_PTR>(¶ms)));
}
void stop() {
MCI_GENERIC_PARMS params;
params.dwCallback = NULL;
checkerror(mciSendCommand(_device, MCI_STOP, MCI_WAIT, reinterpret_cast<DWORD_PTR>(¶ms)));
}
MCIDEVICEID device() const { return _device; }
private:
MCIDEVICEID _device;
static void checkerror(MCIERROR code) {
if (code != 0) {
char buffer[260];
mciGetErrorStringA(code, buffer, sizeof(buffer) - 1);
throw std::runtime_error(buffer);
}
}
void close() {
MCI_GENERIC_PARMS params;
params.dwCallback = NULL;
checkerror(mciSendCommand(_device, MCI_CLOSE, MCI_WAIT, reinterpret_cast<DWORD_PTR>(¶ms)));
}
};
#include <map>
#include <string>
#include <mutex>
#ifdef _UNICODE
typedef std::wstring tstring;
#else
typedef std::string tstring;
#endif
class Repeater {
public:
Repeater(LPCTSTR fn) : fn(fn) {
hWnd = CreateWindowEx(0, TEXT("STATIC"), NULL, 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, GetModuleHandle(NULL), 0);
if (hWnd == NULL)
throw std::runtime_error("Can't create window");
oldproc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(this));
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG>(&myproc));
}
~Repeater() {
DestroyWindow(hWnd);
}
void play() {
Player player(fn.c_str());
std::lock_guard<std::recursive_mutex> lock(devmap_mutex);
player.play(hWnd);
devmap.insert(decltype(devmap)::value_type(player.device(), std::move(player)));
}
HWND wnd() const { return hWnd; }
void stop() {
std::lock_guard<std::recursive_mutex> lock(devmap_mutex);
devmap.clear();
}
private:
HWND hWnd;
tstring fn;
std::recursive_mutex devmap_mutex;
std::map<MCIDEVICEID, Player> devmap;
WNDPROC oldproc;
static LRESULT CALLBACK myproc(_In_ HWND hWnd, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam) {
auto self = reinterpret_cast<Repeater*>(GetWindowLong(hWnd, GWLP_USERDATA));
switch (Msg) {
case MM_MCINOTIFY: {
// see https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd757358(v=vs.85).aspx
std::lock_guard<std::recursive_mutex> lock(self->devmap_mutex);
self->devmap.erase(static_cast<MCIDEVICEID>(lParam));
return 0;
}
case WM_DESTROY: {
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG>(self->oldproc));
}
default:
break;
}
return CallWindowProc(self->oldproc, hWnd, Msg, wParam, lParam);
}
};
int main() {
// USE MP3. Forget about WAV.
LPCTSTR filename = TEXT("c:\\Users\\Vyacheslav\\Music\\Ori\\soundtrack\\Racing the Lava.mp3");
#if 0
// without notifications
Player dev1(filename), dev2(filename);
dev1.play();
Sleep(1000);
dev2.play();
Sleep(10000);
#else
// with notifications
{
Repeater rep(filename);
std::thread thread([&rep] {
for (int i = 0; i < 5; ++i) {
rep.play();
Sleep(1000);
}
Sleep(1000);
rep.stop(); // .stop() MUST be called from the same thread as ALL .play() !!!
PostMessage(rep.wnd(), WM_QUIT, 0, 0); // interrupt message processing queue
});
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
thread.join();
}
Sleep(10000); // silence
#endif
return 0;
}
現在它的行爲就好像我沒有'SND_ASYNC'(它以同步方式播放)。 –
@ coder108解決方案已更新。 PlaySound不允許這樣做。 MCI不支持同時播放多個.wav文件。上述解決方案之後的下一步是使用DirectShow。 – slavanap
謝謝你的迴應。在運行更新的代碼(我只替換了文件名)後,我收到錯誤「您正在使用的MCI設備不支持指定的命令」。我嘗試了使用MP3而不是WAV來調用mciSendString,並且仍然存在與之前相同的問題(我用代碼更新了原始問題) –