C++ 如何从特定点播放.wav文件(例如30秒)

C++ 如何从特定点播放.wav文件(例如30秒),c++,winapi,C++,Winapi,我希望能够在特定的时间开始播放一首歌,例如,在我的节目中复制一个电台的歌曲30秒后,当你更换频道时,歌曲已经播放或几乎完成 目前我使用PlaySound,并将我的26首歌曲保存为wav文件和程序内的资源。我已经见过MCISESTROSTRING作为一个选项,但是我不知道如何用Windows API和C++来编码它。 这是我当前的PlayWavFile函数,其中资源整数是一个从0到25之间随机生成的数字,用于播放随机歌曲: void PlayWavFile(int resource) {

我希望能够在特定的时间开始播放一首歌,例如,在我的节目中复制一个电台的歌曲30秒后,当你更换频道时,歌曲已经播放或几乎完成

目前我使用PlaySound,并将我的26首歌曲保存为wav文件和程序内的资源。我已经见过MCISESTROSTRING作为一个选项,但是我不知道如何用Windows API和C++来编码它。 这是我当前的PlayWavFile函数,其中资源整数是一个从0到25之间随机生成的数字,用于播放随机歌曲:

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;
}