Как проиграть WAV/MP3-файл из памяти?

Тема в разделе "WASM.AUDIO", создана пользователем Mikl___, 2 мар 2022.

  1. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.708
    Привет всем ! :)
    PlaySound с параметром SND_MEMORY не подходит.
    Желательно через какой-нибудь низкоуровневый способ типа mciwioOpen/mciwioPlay
     
  2. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    860
    Почему?
    Можно к примеру через mciSendString с дополнительными манипуляциями.
    Можно через waveOut-функции, но нужно будет вручную многое делать.
     
    Mikl___ нравится это.
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.708
    Thetrik,
    как делать через waveOut примерно представляю, еще можно через DirectSound (IDirectSound8::CreateSoundBuffer и IDirectSoundBuffer8::Play), а вот о "mciSendString с дополнительными манипуляциями" можно более развернуто?
     
  4. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    860
    Накидал небольшой пример:
    Код (C++):
    1.  
    2. #include <Windows.h>
    3. #include <mmreg.h>
    4.  
    5. #pragma comment (linker, "/ENTRY:main")
    6. #pragma comment (lib, "Winmm.lib")
    7.  
    8. static PBYTE m_pbBuffer = NULL;
    9. static SIZE_T m_szBuffer = 0;
    10.  
    11. LRESULT WINAPI MMIOProc(MMIOINFO* lpmmioinfo, UINT uMsg, LONG lParam1, LONG lParam2) {
    12.    
    13.     switch (uMsg) {
    14.         case MMIOM_OPEN:
    15.         case MMIOM_CLOSE:
    16.  
    17.             lpmmioinfo->lDiskOffset = 0;
    18.             return 0;
    19.  
    20.         case MMIOM_READ:
    21.  
    22.             SIZE_T szRead;
    23.  
    24.             if (lpmmioinfo->lDiskOffset + lParam2 > m_szBuffer)
    25.                 szRead = m_szBuffer - lpmmioinfo->lDiskOffset;
    26.             else
    27.                 szRead = lParam2;
    28.  
    29.             memcpy((PVOID)lParam1, m_pbBuffer + lpmmioinfo->lDiskOffset, szRead);
    30.  
    31.             lpmmioinfo->lDiskOffset += szRead;
    32.  
    33.             return szRead;
    34.  
    35.         case MMIOM_SEEK:
    36.  
    37.             switch (lParam2) {
    38.                 case SEEK_SET:
    39.                     lpmmioinfo->lDiskOffset = lParam1;
    40.                     break;
    41.                 case SEEK_CUR:
    42.                     lpmmioinfo->lDiskOffset += lParam1;
    43.                     break;
    44.                 case SEEK_END:
    45.                     lpmmioinfo->lDiskOffset = m_szBuffer - lParam1 - 1;
    46.             }
    47.  
    48.             if (lpmmioinfo->lDiskOffset < 0)
    49.                 lpmmioinfo->lDiskOffset = 0;
    50.             else if (lpmmioinfo->lDiskOffset > m_szBuffer)
    51.                 lpmmioinfo->lDiskOffset = m_szBuffer;
    52.  
    53.             return lpmmioinfo->lDiskOffset;
    54.     }
    55.  
    56.     return -1;
    57.  
    58. }
    59.  
    60.  
    61. void main() {
    62.  
    63.     // Load from resource MPEGLAYER3WAVEFORMAT wave
    64.     HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(101), RT_RCDATA);
    65.     if (!hRes)
    66.         ExitProcess(HRESULT_FROM_WIN32(GetLastError()));
    67.  
    68.     HGLOBAL hMem = LoadResource(NULL, hRes);
    69.     if (!hMem)
    70.         ExitProcess(HRESULT_FROM_WIN32(GetLastError()));
    71.  
    72.     m_pbBuffer = (PBYTE)LockResource(hMem);
    73.     if (!m_pbBuffer)
    74.         ExitProcess(HRESULT_FROM_WIN32(GetLastError()));
    75.  
    76.     m_szBuffer = SizeofResource(NULL, hRes);
    77.     if (!m_szBuffer)
    78.         ExitProcess(HRESULT_FROM_WIN32(GetLastError()));
    79.  
    80.     // Install IO proc
    81.     if (NULL == mmioInstallIOProc(' ZYX', (LPMMIOPROC)MMIOProc, MMIO_INSTALLPROC))
    82.         ExitProcess(E_FAIL);
    83.  
    84.     // Open in-memory file
    85.     MCIERROR merr = mciSendString(L"open x.XYZ+ type waveaudio alias music", NULL, 0, NULL);
    86.     if (merr)
    87.         ExitProcess(merr);
    88.  
    89.     // Play
    90.     merr = mciSendString(L"play music wait", NULL, 0, NULL);
    91.  
    92.     ExitProcess(merr);
    93.  
    94. }
    95.  
    --- Сообщение объединено, 3 мар 2022 ---
    Нужно еще поменять определение MMIOProc для 64 бит если планируется делать. В MSDN бардак, в одном месте такое объявление, в другом другое.
     

    Вложения:

    Mikl___ нравится это.
  5. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    352
    А я у себя на HD нашел вот такой вариант (когда-то эксперементировал). Может тоже пригодится.

    Код (C):
    1. #include <windows.h>
    2. #include <iostream>
    3. #include <string>
    4.  
    5. #pragma comment(lib, "winmm.lib")
    6.  
    7. enum mode {unknown, open, playing, paused, stopped };
    8.  
    9. class MCI
    10. {
    11.  
    12.     private:
    13.         std::string filename;
    14.         unsigned int lenght;
    15.         int volume;
    16.         int balance;
    17.  
    18.     public:
    19.         MCI() : lenght(0),volume(1000),balance(0)
    20.         {
    21.  
    22.         };
    23.  
    24.         MCI(std::string filename): volume(1000),balance(0)
    25.         {
    26.             Open(filename);
    27.         };
    28.  
    29.         ~MCI()
    30.         {
    31.             Close();
    32.         }
    33.  
    34.         void Open(std::string filename)
    35.         {
    36.             Close();
    37.             this->filename = filename;
    38.             std::string msg = "open \"" + filename + "\" type mpegvideo alias " + filename;
    39.             mciSendString(msg.c_str(), NULL, 0, 0);
    40.             lenght = Lenght(true);
    41.         }
    42.  
    43.         void Play(int pos = 0)
    44.         {
    45.             char *buff = new char[10];
    46.             std::string msg = "play " + filename + " from " + itoa(pos,buff,10);
    47.             mciSendString(msg.c_str(), NULL, 0, 0);
    48.             delete [] buff;
    49.         }
    50.  
    51.         void Seek(int pos)
    52.         {
    53.             char *buff = new char[10];
    54.             std::string msg = "seek " + filename + " to " + itoa(pos,buff,10);
    55.             mciSendString(msg.c_str(), NULL, 0, 0);
    56.             delete [] buff;
    57.         }
    58.  
    59.         void Pause()
    60.         {
    61.             std::string msg = "pause " + filename;
    62.             mciSendString(msg.c_str(), NULL, 0, 0);
    63.         }
    64.  
    65.         void Resume()
    66.         {
    67.             std::string msg = "resume " + filename;
    68.             mciSendString(msg.c_str(), NULL, 0, 0);
    69.         }
    70.  
    71.         void Stop()
    72.         {
    73.             std::string msg = "stop " + filename;
    74.             mciSendString(msg.c_str(), NULL, 0, 0);
    75.         }
    76.  
    77.         void Close()
    78.         {
    79.             std::string msg = "close " + filename;
    80.             mciSendString(msg.c_str(), NULL, 0, 0);
    81.         }
    82.  
    83.         int Volume()
    84.         {
    85.             return volume;
    86.         }
    87.  
    88.         void Volume(int vol)
    89.         {
    90.             vol = (vol < 0 ? 0 : (vol > 1000 ? 1000 : vol));
    91.             char *buff = new char[5];
    92.             std::string msg = "setaudio " + filename + " volume to " + itoa(vol,buff,10);
    93.             mciSendString(msg.c_str(), NULL, 0, 0);
    94.             delete [] buff;
    95.         }
    96.  
    97.         int Balance()
    98.         {
    99.             return balance;
    100.         }
    101.  
    102.         void Balance(int bal)
    103.         {
    104.             bal = (bal < -1000 ? -1000 : (bal > 1000 ? 1000 : bal));
    105.             char *buff = new char[5];
    106.             std::string msg = "setaudio " + filename + "left volume to " + itoa((bal<0?1000:1000-bal),buff,10);
    107.             mciSendString(msg.c_str(), NULL, 0, 0);
    108.             msg = "setaudio " + filename + "right volume to " + itoa((bal>0?1000:1000+bal),buff,10);
    109.             mciSendString(msg.c_str(), NULL, 0, 0);
    110.             delete [] buff;
    111.         }
    112.  
    113.         int Lenght(bool refresh = false)
    114.         {
    115.             if (refresh)
    116.             {
    117.                 char *buff = new char[128];
    118.                 std::string msg = "status " + filename + " length";
    119.                 mciSendString(msg.c_str(), buff, 128, 0);
    120.                 int t = atoi(buff);
    121.                 delete [] buff;
    122.                 return t;
    123.             }
    124.             else
    125.             {
    126.                 return lenght;
    127.             }
    128.         }
    129.  
    130.         int Position()
    131.         {
    132.             char *buff = new char[16];
    133.             std::string msg = "status " + filename + " position";
    134.             mciSendString(msg.c_str(), buff, 16, 0);
    135.             int t = atoi(buff);
    136.             delete [] buff;
    137.             return t;
    138.         }
    139.  
    140.         int Position(int ms)
    141.         {
    142.             if (status() == playing || status() == paused)
    143.                 Seek(ms);
    144.             else
    145.                 Play(ms);
    146.         }
    147.  
    148.         mode status()
    149.         {
    150.             char *buff = new char[8];
    151.             std::string msg = "status " + filename + " mode";
    152.             mciSendString(msg.c_str(), buff, 8, 0);
    153.             mode ret;
    154.             if (strncmp(buff,"open",4) == 0) ret = open;
    155.             else if (strncmp(buff,"playing",7) == 0) ret = playing;
    156.             else if (strncmp(buff,"paused",6) == 0) ret = paused;
    157.             else if (strncmp(buff,"stopped",7) == 0) ret = stopped;
    158.             else ret = unknown;
    159.             delete [] buff;
    160.             return ret;
    161.         }
    162. };
    163.  
    164. // Example
    165. int main()
    166. {
    167.     MCI mp3("C:\\1.mp3");
    168.     std::cout << mp3.Lenght()/60000.0 << std::endl; //  1 минута
    169.     mp3.Play();
    170.     std::cout << "Press F8 to exit" << std::endl;
    171.     while (!GetAsyncKeyState(VK_F8))
    172.     {
    173.         std::cout << "\r" << mp3.Position()/60000.0;
    174.         Sleep(500);
    175.     }
    176.     mp3.Stop();
    177.     return 0;
    178. }
    Thetrik, так глядишь и постепенно, полностью перейдете на C/C++ и напишете пару тройку каких-нибудь интересных VST-шек. :)
     
    Mikl___ нравится это.
  6. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    860
    Да уже давно перешел, а VST и на VB писал.
     
  7. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    352
    Ну то, что вы на VB много чего интересного написали я в курсе. В том числе и VST. И даже на FASM'е умудрились VST написать - от чего я, вообще, обалдел, в хорошем смысле слова разумеется. Интересно было бы узнать, кто-нибудь, что-нибудь подобное делал или нет. Мне кажется, что маловероятно. И я всегда, видя ваши интересные посты на VB, которые вы размещали сначала на cyberforum'е ( https://www.cyberforum.ru/blogs/354370/ ), а чуть позже и на WASM'е - страдал от того, что не знаю VB. А так бы, возможно, что было бы что обсудить с интересным и увлеченным человеком. Одно время я даже, вроде как, уже даже настроился изучать VB. Даже самоучитель скачал, но в последний момент схлюздил и подумал, что в наше время Питон чуть поважнее будет, чем VB. Ну и начал изучать Питон, а с VB решил пока повременить. :)
     
    Thetrik нравится это.
  8. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.708
    Воспроизвожу в синхронном режиме wav-файл из буфера в памяти. Используются низкоуровневые функции waveOutPrepareHeader, waveOutUnprepareHeader, waveOutOpen, waveOutClose, waveOutWrite. В аттаче wav-файл, исходник и ехе-файл
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. WAVEHDR struct
    4.    lpData   QWORD ?
    5.    dwBufferLength DWORD ?
    6.    dwBytesRecorded DWORD ?
    7.    dwUser   QWORD ?
    8.    dwFlags    DWORD ?
    9.    dwLoops    DWORD ?
    10.    lpNext   QWORD ?
    11.    reserved qword ?
    12. WAVEHDR ends
    13.  
    14. WHDR_DONE equ 1
    15. .code
    16. WinMain proc
    17. local hGout:qword
    18. local p:qword
    19. local FSize:dword
    20. local hFile:dword
    21. local szReadWrite:qword ;number of bytes actually read or write
    22. local hWaveOut:qword
    23. local lpwiocb:WAVEHDR
    24.  
    25.        mov ecx,offset wav_file
    26.        invoke CreateFile,,GENERIC_READ,0,0,OPEN_EXISTING,\
    27.        FILE_ATTRIBUTE_ARCHIVE,0
    28.        mov hFile,eax
    29.        invoke GetFileSize,eax,0
    30.        mov FSize,eax
    31.        invoke GlobalAlloc,GHND or GMEM_DDESHARE,eax
    32.        mov hGout,rax
    33.        invoke GlobalLock,eax
    34.        mov p,rax
    35.        lea r9d,szReadWrite
    36.        invoke ReadFile,hFile,eax,FSize,,0
    37.        invoke CloseHandle,hFile
    38.        invoke GlobalUnlock,hGout
    39.        lea ecx,hWaveOut; указатель на идентификатор устройства
    40.        xor r9,r9 ; адрес функции обратного вызова или идентификатор окна
    41.        mov [rsp+20h],r9 ; данные для функции обратного вызова
    42.        mov qword ptr[rsp+28h],WAVE_ALLOWSYNC;режим открытия устройства
    43.        mov r8,p
    44.        add r8d,14h; указатель на структуру WAVEFORMAT
    45.        or edx,WAVE_MAPPER; номер открываемого устройства
    46.        invoke waveOutOpen
    47. ; Подготавливаем заголовок для вывода
    48.        lea edx,lpwiocb ; указатель на структуру WAVEHDR
    49.        mov edi,edx
    50.        xor eax,eax
    51.        mov ecx,(sizeof WAVEHDR)/8
    52.        rep stosq
    53.  
    54.        mov rax,p
    55.        add rax,2Ch ; пропускаю "RIFF" и размер (8 байт), "WAVE", "fmt ", размер формата
    56. ; данных, тип формата, количество каналов (моно или стерео), частоту дискретизации,
    57. ; скорость потока данных, выравнивание блока данных
    58. ;заполняем структуру WAVEHDR
    59.        mov [rdx].WAVEHDR.lpData,rax
    60.        mov eax,FSize
    61.        sub eax,2Ch
    62.        mov [rdx].WAVEHDR.dwBufferLength,eax
    63.        invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR
    64. ; Запускаем проигрывание блока
    65.        lea edx,lpwiocb
    66.        invoke waveOutWrite,hWaveOut,,sizeof WAVEHDR
    67. @@:    test lpwiocb.dwFlags,WHDR_DONE
    68.        jz @b; ждем пока музыка доиграет до конца
    69. ; После того как приложение получило сообщение WHDR_DONE, оно должно
    70. ; передать указатель на структуру  WAVEHDR, соответствующей проигранному
    71. ; блоку функции waveOutUnprepareHeader
    72.        lea edx,lpwiocb
    73.        invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR
    74. ; После завершения работы с устройством его необходимо закрыть. Через
    75. ; единственный параметр функции waveOutClose передают идентификатор
    76. ; закрываемого устройства вывода
    77.        invoke waveOutClose,hWaveOut
    78. ; завершаю программу
    79.        invoke RtlExitUserProcess,NULL
    80. WinMain endp
    81. wav_file db 'имя_какого-нибудь_wav-файла',0
    82. end
     

    Вложения:

    • WAV.zip
      Размер файла:
      1,2 МБ
      Просмотров:
      184