Как воспроизвести файл .wav с определенной точки (например, через 30 секунд) - PullRequest
2 голосов
/ 30 июня 2019

Я хочу иметь возможность начать воспроизведение песни в определенное время (например, через 30 секунд после песни) в моей программе, которая копирует радиостанцию, когда вы меняете канал и песня уже воспроизводится или почти завершено.

В настоящее время я использую PlaySound, и мои 26 песен сохраняются в виде файлов WAV и ресурсов в программе. Я видел mciSendString как вариант, однако я не понимаю, как мне удалось заставить его работать при кодировании с Windows API и C ++.

Вот моя текущая функция PlayWavFile (где целое число ресурса - это случайно сгенерированное число от 0 до 25, приведенное к этой функции для воспроизведения случайной песни):

void PlayWavFile(int resource) {
    PlaySound(MAKEINTRESOURCE(resource), hInst, SND_RESOURCE | SND_ASYNC);
}

Я ожидаю, что смогу воспроизвести песню определенным образом, используя целочисленное значение, которое я предопределил (например, длительность).

Ответы [ 3 ]

2 голосов
/ 30 июня 2019

Я видел mciSendString в качестве опции, но я не понимаю, как я мог бы заставить его работать при кодировании с Windows API и C ++.

Вы можете читать документы MSDN, например Командные строки мультимедиа для синтаксиса команд

Базовый пример чтения wav-файла за 1 секунду =>

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
}
2 голосов
/ 01 июля 2019

Чтобы использовать MCI с mciSendCommand, необходимо

  • Откройте устройство и получите идентификатор устройства.
  • Установите поиск.
  • Play.

Или

  • Откройте устройство и получите идентификатор устройства.
  • Воспроизведение с указанной позиции напрямую.

Пример:

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

Обратите внимание, что если вы хотите получить звук, при использовании MCI_PLAY.

необходим флаг MCI_WAIT.

EDIT: Вы не можете услышать звук, потому что у вас мало времени для начала воспроизведения. Он начнет воспроизведение и сразу же закроет его (это можно проверить, добавив Sleep() после начала воспроизведения). См. связанную проблему . Если вы хотите воспроизвести без ожидания, вам нужно обработать MCI_NOTIFY, установить дескриптор окна обратного вызова и обработать 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;
}
0 голосов
/ 30 июня 2019

Есть много библиотек, которые могут воспроизводить звук, но если вы хотите продолжить использовать PlaySound(), вот вам идея:

Так что, хотя это может быть не самый простой способ, вы можете открыть свой оригинальный звук, пропустив первые N секундего (достаточно просто для файлов .wav, поскольку они имеют постоянный битрейт и не имеют ключевых кадров), сохраните его как новый ресурс и, наконец, воспроизведите его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...