C++ 如何从特定点播放.wav文件(例如30秒)
我希望能够在特定的时间开始播放一首歌,例如,在我的节目中复制一个电台的歌曲30秒后,当你更换频道时,歌曲已经播放或几乎完成 目前我使用PlaySound,并将我的26首歌曲保存为wav文件和程序内的资源。我已经见过MCISESTROSTRING作为一个选项,但是我不知道如何用Windows API和C++来编码它。 这是我当前的PlayWavFile函数,其中资源整数是一个从0到25之间随机生成的数字,用于播放随机歌曲:C++ 如何从特定点播放.wav文件(例如30秒),c++,winapi,C++,Winapi,我希望能够在特定的时间开始播放一首歌,例如,在我的节目中复制一个电台的歌曲30秒后,当你更换频道时,歌曲已经播放或几乎完成 目前我使用PlaySound,并将我的26首歌曲保存为wav文件和程序内的资源。我已经见过MCISESTROSTRING作为一个选项,但是我不知道如何用Windows API和C++来编码它。 这是我当前的PlayWavFile函数,其中资源整数是一个从0到25之间随机生成的数字,用于播放随机歌曲: void PlayWavFile(int resource) {
void PlayWavFile(int resource) {
PlaySound(MAKEINTRESOURCE(resource), hInst, SND_RESOURCE | SND_ASYNC);
}
我希望能够以某种方式播放歌曲,使用我预先确定的整数值,如持续时间。有很多库可以播放声音,但如果您想继续使用PlaySound,这里有一个想法: 您正在播放来自资源的声音,而不是直接来自文件的声音。 你可以。 因此,虽然这可能不是最简单的方法,但您可以打开原始声音,使用.wav文件轻松跳过前N秒,因为它们是恒定比特率且没有关键帧,将其存储为新资源,最后播放 我已经将mciSendString视为一个选项,但我不明白如何使用它 我可以用Windows API和C++来实现它的工作。 您可以阅读MSDN文档,了解命令的语法 从1秒开始读取wav文件的基本示例=>
int rc = mciSendString(L"open E:\\test.wav alias wav1", NULL, 0, 0);
if (rc == 0)
{
rc = mciSendString(L"set wav1 time format ms", NULL, 0, 0);
rc = mciSendString(L"seek wav1 to 1000", NULL, 0, 0);
if (rc == 0)
{
rc = mciSendString(L"play wav1", NULL, 0, 0);
}
else
{
// handle error (like MCIERR_OUTOFRANGE for example)
}
}
else
{
// handle error
}
要将MCI与mciSendCommand一起使用,您应该
打开设备并获取设备ID。
设置搜索。
玩
或
打开设备并获取设备ID。
直接从指定位置播放。
样本:
#include <windows.h>
#pragma comment(lib, "winmm.lib")
MCIDEVICEID MCIOpen(LPCTSTR strPath)
{
MCI_OPEN_PARMS mciOP;
DWORD opReturn;
mciOP.lpstrDeviceType = NULL;
mciOP.lpstrElementName = strPath; //Set the .wav file name to open
opReturn = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)(LPVOID)&mciOP);
if (!opReturn)
return mciOP.wDeviceID;
return -1;
}
DWORD MCISeek(MCIDEVICEID wDeviceID,int sec)
{
MCI_SEEK_PARMS SeekParms;
SeekParms.dwTo = (sec) * 1000;
return mciSendCommand(wDeviceID, MCI_SEEK, MCI_TO, (DWORD)(LPVOID)&SeekParms);
}
DWORD MCIPlay(MCIDEVICEID wDeviceID)
{
MCI_PLAY_PARMS mciPP;
return mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY| MCI_WAIT, (DWORD)&mciPP);
}
DWORD MCIPlayFrom(MCIDEVICEID wDeviceID,int sec)
{
MCI_PLAY_PARMS play;
play.dwFrom = sec*1000;//Play From sec*1000 ms
return mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM| MCI_WAIT, (DWORD)&play);
}
int main()
{
//open device
MCIDEVICEID wDeviceID = MCIOpen("test.wav"); //Save DeviceID
DWORD opReturn;
if (wDeviceID != -1)
{
//MCI_SET_PARMS mciSet;
//mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;//set time format to milliseconds
//opReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID)&mciSet);
////set the position at 30s.
//opReturn = MCISeek(wDeviceID, 30);
////play
//opReturn = MCIPlay(wDeviceID);
opReturn = MCIPlayFrom(wDeviceID,30);
}
return opReturn;
}
恐怕您必须使用waveOut API,它涉及的内容更多,并且您必须自己处理音频缓冲区。没有像PlaySound这样简单的API可以让你选择位置。使用MCI命令有什么问题?有一个搜索命令可用于音频播放与MCI我只是不知道如何使用它们在所有。尤其是做我想做的事。我对C++比较陌生,这可能是我困惑的一个因素。然后,你需要研究文档,直到你知道为止。我会使用mciSendCommand而不是mciSendString,但是是的,这是最基本的方法。我这样做了,没有出现错误,但仍然没有听到任何声音,相反,我的程序只是继续到下一行。发生了什么事?@EthanSigler尝试mciSendStringLplay wav1等待,NULL,0,0@DrakeWu MSFT Ok这使它发挥作用,但我需要它与其他功能一起工作,否则窗口将不会响应,例如,我需要使它异步。有没有办法用mciSendString做到这一点?@EthanSigler首先,你听不到声音,因为你开始播放后几乎没有时间跑。它将启动播放并立即关闭播放。可以通过在播放开始后添加睡眠来验证。看。如果希望播放无等待,则需要处理MCI_通知,设置回调窗口句柄,并在播放结束时处理MM_MCINOTIFY。请看我答案中的示例。
#include <windows.h>
#pragma comment(lib, "winmm.lib")
HWND hwnd;
MCIDEVICEID MCIOpen(LPCTSTR strPath)
{
MCI_OPEN_PARMS mciOP;
DWORD opReturn;
mciOP.lpstrDeviceType = NULL;
mciOP.lpstrElementName = strPath; //Set the .wav file name to open
opReturn = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)(LPVOID)&mciOP);
if (!opReturn)
return mciOP.wDeviceID;
return -1;
}
DWORD MCISeek(MCIDEVICEID wDeviceID,int sec)
{
MCI_SEEK_PARMS SeekParms;
SeekParms.dwTo = (sec) * 1000;
return mciSendCommand(wDeviceID, MCI_SEEK, MCI_TO, (DWORD)(LPVOID)&SeekParms);
}
DWORD MCIPlay(MCIDEVICEID wDeviceID)
{
MCI_PLAY_PARMS mciPP;
mciPP.dwCallback = (DWORD_PTR)hwnd;
return mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mciPP);
}
DWORD MCIPlayFrom(MCIDEVICEID wDeviceID,int sec)
{
MCI_PLAY_PARMS play;
play.dwFrom = sec*1000;//Play From sec*1000 ms
return mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM, (DWORD)&play);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case MM_MCINOTIFY:
{
if (MCI_NOTIFY_SUCCESSFUL == wParam) //MCI_NOTIFY_SUCCESSFUL means that the song has been played successfully.
{
//To Do
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int main()
{
static const char* class_name = "DUMMY_CLASS";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WndProc; // function which will handle messages
wx.hInstance = GetModuleHandleA(NULL);
wx.lpszClassName = class_name;
if (RegisterClassEx(&wx)) {
hwnd = CreateWindowEx(0, class_name, "dummy_name", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
}
//open device
MCIDEVICEID wDeviceID = MCIOpen("test.wav"); //Save DeviceID
DWORD opReturn;
if (wDeviceID != -1)
{
//MCI_SET_PARMS mciSet;
//mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;//set time format to milliseconds
//opReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID)&mciSet);
////set the position at 30s.
//opReturn = MCISeek(wDeviceID, 30);
////play
//opReturn = MCIPlay(wDeviceID);
opReturn = MCIPlayFrom(wDeviceID,30);
}
HACCEL hAccelTable = LoadAccelerators(wx.hInstance, class_name);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}