winmm.dll mciSendString - How to loop from specific song point?

David G 1 Reputation point
2021-02-11T21:20:05.433+00:00

Hi,

I'm using a background program and playing MP3 with mciSendString with commands like "play Mediafile Repeat".

However, my songs usually have an Introduction and then the looping part (as videogames). So I want that the song start playing normally, but the looping point been at some point.

Thanks!!

Windows development | Windows API - Win32
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. Castorix31 90,686 Reputation points
    2021-02-11T22:48:39.61+00:00

    You can do :

    "set your_mp3 time format ms"
    then
    "play your_mp3 notify" (with window handle to receive MM_MCINOTIFY

    then in MM_MCINOTIFY :
    "seek your_mp3 to n" (where n = nb of milliseconds, for example 2000 for 2 seconds)
    then again
    "play your_mp3 notify"

    (tested on Windows 10)

    0 comments No comments

  2. Drake Wu - MSFT 996 Reputation points
    2021-02-12T02:41:46.167+00:00

    Hi, DavidG-0663 I assume that the file you want to play is 20 seconds long, and want to loop from10s to 15s, you can use the following steps:

    1. Create a window, which can be a message-only window (invisible)
    2. Set the time format to ms.
    3. Play to 15s and notify the window.
    4. Play from 10s-15s and set notify again.
    5. Play to the end.

    Try the following sample:

    #include <windows.h>  
    #pragma comment(lib, "winmm.lib")  
      
    MCIDEVICEID wDeviceID;  
    static int loop_count = 3;  
      
    MCIDEVICEID MCIOpen(LPCTSTR strPath)  
    {  
        MCI_OPEN_PARMS mciOP = {0};  
        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 MCISetTimeFormat(MCIDEVICEID wDeviceID, DWORD timeformat)  
    {  
        MCI_SET_PARMS mciSet = {0};  
        mciSet.dwTimeFormat = timeformat;//set time format to milliseconds  
      
        return mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID)&mciSet);  
    }  
      
    DWORD MCIPlayTo(HWND hwnd, MCIDEVICEID wDeviceID, int sec)  
    {  
        MCI_PLAY_PARMS mciPP;  
        mciPP.dwCallback = (DWORD_PTR)hwnd;  
        mciPP.dwTo = sec * 1000;  
        return mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_TO, (DWORD)&mciPP);  
    }  
    DWORD MCIPlayFromTo(HWND hwnd, MCIDEVICEID wDeviceID, int secFrom, int secTo)  
    {  
        MCI_PLAY_PARMS play = {0};  
        play.dwFrom = secFrom * 1000;   //Looping From sec*1000 ms  
        play.dwTo = secTo * 1000;   //Looping To sec*1000 ms  
        play.dwCallback = (DWORD_PTR)hwnd;  
        DWORD_PTR dwParam1;  
        if (secTo == 0)  
            dwParam1 = MCI_NOTIFY | MCI_FROM;  
        else  
            dwParam1 = MCI_NOTIFY | MCI_FROM | MCI_TO;  
        return mciSendCommand(wDeviceID, MCI_PLAY, dwParam1, (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  
                if (--loop_count > 0)  
                    MCIPlayFromTo(hWnd, wDeviceID, 10, 15);  
                else  
                    MCIPlayFromTo(hWnd, wDeviceID, 15, 0); //to the end;  
            }  
        }  
        break;  
        default:  
            return DefWindowProc(hWnd, message, wParam, lParam);  
        }  
        return 0;  
    }  
      
    int main()  
    {  
        DWORD opReturn;  
        static const WCHAR* class_name = L"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)) {  
            return 0;  
        }  
        HWND hwnd = CreateWindowEx(0, class_name, L"dummy_name", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);  
        //open device  
        wDeviceID = MCIOpen(L"test.wav");  //Save DeviceID  
        opReturn = MCISetTimeFormat(wDeviceID, MCI_FORMAT_MILLISECONDS);  
          
        if (wDeviceID != -1)  
        {  
            opReturn = MCIPlayTo(hwnd, wDeviceID, 15);  
        }  
        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;  
    }  
    

    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

  3. David G 1 Reputation point
    2021-02-12T13:49:09.13+00:00

    Thanks for the answers.

    I have to check the "notify" as Im using Lua on CheatEngine and importing the DLL there, so I don't really know how to handle that kind of messages right now as I have just started to use this DLL.

    I will take a look during the weekend.

    If you have any tip about doing it on Lua CE, it will be appreciated. Thanks in advance!

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.