На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела "Программирование звука"
0) Данный раздел предназначен для обсуждения проблем, возникающих при программировании задач, связанных с записью, обработкой, воспроизведением звука. Перед созданием темы подумайте, не будет ли она уместнее в разделах Разработка и тестирование программ, Наши исходники, а особенно Разовые заказы и подработки
1) На Раздел распространяются все Правила форума.Огромная просьба с ними внимательно ознакомиться.
2) Запрещается давать бессмысленные ответы вроде: "Снеси Мастдай", "ХП рулит", "Поставь Линукс" и т.д.
3) Запрещается создавать темы, в которых Вы намереваетесь получить ссылку на кряки, серийники и т.п. Также запрещено любое обсуждение p2p (peer-to-peer) сетей (BitTorrent, eDonkey и т.д.).
4) Реклама всякого рода пресекается беспощадно.
5) Используйте тэг [CODE] для выделения кода программы (непременно с указанием языка программирования - выбрать из списка. В противном случае бессмысленно!). Уважайте тех, кто будет читать ваш код!
6) Если решение вашей проблемы найдено, то не забываем помечать тему специальной функцией "Вопрос решён". Вам всего лишь требуется при написании последнего ответа поставить одну единственную галочку прямо над формой ответа.
7) Если вы хотите получить совет для конкретной платформы/языка программирования, обязательно укажите их в вопросе

8) Если не прикрепляются/не скачиваются файлы, читаем Не прикрепляется / не скачивается файл. Любые обсуждения в данном разделе проблем с приложением файлов считаются оффтопиком! Со всеми вытекающими.

9) NEW! Уважаемые новички! Мы приветствуем Ваше желание научить всех посетителей раздела правильному программированию. Но огромная просьба, перед тем, как писать поучения в старых (последний ответ - "старее" месяца, а особенно, если вопрошавший не появляется на форуме уже не первый месяц, в чем можно убедиться в его профиле) темах, хорошо подумать, будет ли кому-нибудь, кроме Вас cамих, это интересно. Попытки накрутки количества тематических сообщений за счёт поднятия древних неактуальных тем ("некрофилия") будут наказываться по велению левой пятки модераторского состава (см. пп.12, 13 Правил)



Нарушение Правил может повлечь наказание со стороны модераторов.



user posted imageFAQ Раздела user posted imageПоиск в Разделе user posted imageMSDN Library Online | Ваше мнение о модераторах: user posted imageBarazuk user posted imageRikkie
  
> Как программа записи звука с микрофона прерывает запись?
    Нашел на каком-то из форумов пример программы записи с микрофона, немного ее изменил:
    ExpandedWrap disabled
      #include <windows.h>
      #include <conio.h>
      #include <locale>
      #include <string.h>
      #include <vector>
      #include <iostream>
      #include <MMSystem.h>
       
      #pragma comment(lib,"winmm.lib")
       
      using namespace std;
       
      #define stop 1
       
      int mode = 0;
       
      int numBufCyr = 0;
       
      FILE *pf = fopen("test.pcm", "wb");
       
      HWAVEIN      hwvInDev;
       
      void wvErrorMes(string mes, MMRESULT wvRes)
      {
        char strError[128];
        if(wvRes != MMSYSERR_NOERROR)
        {
          cout << mes << endl;
          wvRes = waveInGetErrorText(wvRes, strError, 128);
          cout << "\nОшибка: " << strError << endl;
          cout << "\nПрограмма завершила работу. Для продолжения нажмите любую клавишу";
          _getch();
          exit(EXIT_FAILURE); // EXIT_SUCCESS, EXIT_FAILURE
        }
      }
       
      void GetAudioInfo()
      {
        UINT numInDev  = waveInGetNumDevs();
        MMRESULT wvRes;
        cout << "------------------ Входные устройства ---------------" << endl << endl;
        WAVEINCAPS wvInfoIn;
        for(UINT i = 0; i < numInDev; i++)
        {
          wvRes = waveInGetDevCaps(i, &wvInfoIn, sizeof(wvInfoIn));
          if(wvRes != MMSYSERR_NOERROR)
          {
            cout << "\nОшибка определения параметров входного устройства № " << i << endl;
          }  
          cout << i << "\t" << wvInfoIn.szPname << endl;
        }
      }
       
      inline void CALLBACK wvRecCallBack(HWAVEIN hwvInDev, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
      {
        WAVEHDR *wvBuf = (WAVEHDR*) dwParam1;  
        MMRESULT wvRes = 0;
        switch(uMsg)
        {
          case WIM_OPEN:
            printf("\nЗапись началась\n");
            break;
          case WIM_DATA:
            if(!mode)
              printf("Операции с буфером\n");
            fwrite(wvBuf -> lpData, wvBuf -> dwBytesRecorded, 1, pf);
            if(mode == stop)
            {
              cout << "Операции завершения записи" << endl;
              numBufCyr--;
              wvRes = waveInUnprepareHeader(hwvInDev, wvBuf, sizeof(*wvBuf));
              wvErrorMes("\nНе удалось освободить буфер!\n", wvRes);          
              free(wvBuf -> lpData);
              free((WAVEHDR*)dwParam1);
            }  
            else
            {  
            wvRes =  waveInAddBuffer(hwvInDev, wvBuf, sizeof(*wvBuf));
            wvErrorMes("\nНе удалось добавить буфер для записи!\n", wvRes);          
            }
            break;
          case WIM_CLOSE:
            printf("\nЗапись закончилась\n");
            break;
        }
      }                            
       
      void tryrec(UINT numIn, UINT numBlock, UINT numBuf)
      {
        MMRESULT     wvRes;
        WAVEFORMATEX wvFormat;
        wvFormat.wFormatTag      = WAVE_FORMAT_PCM;
        wvFormat.nChannels       = 1;
        wvFormat.nSamplesPerSec  = 44100;
        wvFormat.wBitsPerSample  = 16;
        wvFormat.nBlockAlign     = (wvFormat.nChannels*wvFormat.wBitsPerSample + 7)/8;
        wvFormat.nAvgBytesPerSec = wvFormat.nSamplesPerSec*wvFormat.nBlockAlign;
        wvFormat.cbSize          = sizeof(wvFormat);
        wvRes = waveInOpen(&hwvInDev, numIn, &wvFormat, (DWORD)wvRecCallBack, 0L, CALLBACK_FUNCTION);
        wvErrorMes("\nУстройство для записи открыть не удалось!\n", wvRes);
        int numBufSize = numBlock*wvFormat.nBlockAlign;
        numBufCyr  = numBuf;
        for(UINT i = 0; i < numBuf; i++)
        {
          char    *sbuf            = (char*)    malloc(numBufSize);
          WAVEHDR *wvBuf           = (WAVEHDR *)malloc(sizeof(*wvBuf));
          wvBuf -> lpData          = sbuf;
          wvBuf -> dwFlags         = 0;
          wvBuf -> dwLoops         = 0;
          wvBuf -> dwUser          = 0;
          wvBuf -> dwBufferLength  = numBufSize;
          wvRes =  waveInPrepareHeader(hwvInDev, wvBuf, sizeof(*wvBuf));
          wvErrorMes("\nНе удалось подготовить буфер для записи!\n", wvRes);
          wvRes =  waveInAddBuffer(hwvInDev, wvBuf, sizeof(*wvBuf));
          wvErrorMes("\nНе удалось добавить буфер для записи!\n", wvRes);
        }
        wvRes = waveInStart(hwvInDev);  
        wvErrorMes("\nНе удалось начать запись!\n", wvRes);
        _getch();
        mode = stop;
        do
        {
       
        } while(numBufCyr != 0);
        wvRes = waveInReset(hwvInDev);   wvErrorMes("\nНе удалось сбросить поток!\n", wvRes);
        wvRes = waveInStop(hwvInDev);    wvErrorMes("\nНе удалось остановить запись!\n", wvRes);
        wvRes = waveInClose(hwvInDev);   wvErrorMes("\nНе удалось закрыть устройство!\n", wvRes);
        fclose(pf);
      }
       
      void main(int argc, char* argv[])
      {
        setlocale(LC_ALL, "");
        GetAudioInfo();
        int numIn;
        cout << "\nВведите номер используемого для записи устройства и нажмите Enter: ";
        cin >> numIn;
        tryrec(numIn, 128, 16);
        cout << "\nПрограмма завершила работу. Для выхода нажмите любую клавишу" << endl;
        _getch();
      }
    Программа записывает звук с микрофона, но я не понимаю, как происходит отслеживание нажатия клавиши во время записи:
    1. Строка
    ExpandedWrap disabled
      wvRes = waveInOpen(&hwvInDev, numIn, &wvFormat, (DWORD)wvRecCallBack, 0L, CALLBACK_FUNCTION);
    привязывает открытое устройство к колбек функции.
    2. Строка
    ExpandedWrap disabled
      wvRes = waveInStart(hwvInDev);
    запускает запись, которая осуществляется с помощью колбек-функции.
    3. Не понятно, как отслеживается нажатие клавиши. Ведь запись еще не окончена, как же от строки старта записи происходит переход к _getch()? Или в теле tryrec происходят циклический проход по операторам вследствие неизвестного мне механизма? Помогите, пожалуйста, разобраться. на всякий случай прикрепляю проект.
    Прикреплённый файлПрикреплённый файл02_SoundStudy.zip (5,04 Кбайт, скачиваний: 181)
      Цитата
      но я не понимаю, как происходит отслеживание нажатия клавиши во время записи:

      wvRecCallBack, при поступлении wim_data, выполняется в отдельном потоке, который добавляется к процессу после wavеinaddbuffer.
      Цитата
      как же от строки старта записи происходит переход к _getch()?

      Функция WaveInStart быстро "что-то делает" и возращает результат(MMSYSERR_NOERROR - "запись пошла", или возращает ошибку - "что-то пошло не так"). Она не блокирует основной поток.
      После выполнения waveinstart, основной поток "зависает" на _getch(), пока не будет нажата клавиша, а wvRecCallBack и обработка wim_data, как я уже сказал, выполняется в другом потоке.
      Поставьте брэкпоинты в обработчиках wim_open, wim_close, wim_data, проверьте в отладчике, в каких потоках выполняется wvRecCallBack во всех случаях.
      Цитата
      Или в теле tryrec происходят циклический проход по операторам вследствие неизвестного мне механизма?

      См. выше. Приложение автоматически становится многопоточным при обращении к функциям аудио из winmm. "Кто" конкретно делает его многопоточным, не могу сказать. Один поток добавляется после waveinopen. Ещё один, где происходит обработка wim_data - после waveinaddbuffer.
      Механизм зарыт где-то тут:
      Прикреплённый файлПрикреплённый файлwdm_audio_XP.JPG (102,09 Кбайт, скачиваний: 635)
      Прикреплённый файлПрикреплённый файлWASAPI_Vista_7.JPG (93,83 Кбайт, скачиваний: 638)
      Сообщение отредактировано: Prince -
        Цитата
        Как программа записи звука с микрофона прерывает запись?

        Основной поток устанавливает mode=stop и ждёт, когда счётчик буферов обнулится(когда все буферы "ликвидируются" в сallback):
        ExpandedWrap disabled
            _getch();
            mode = stop;
            do
            {
           
            } while(numBufCyr != 0);
            wvRes = waveInReset(hwvInDev);   wvErrorMes("\nНе удалось сбросить поток!\n", wvRes);
            wvRes = waveInStop(hwvInDev);    wvErrorMes("\nНе удалось остановить запись!\n", wvRes);
            wvRes = waveInClose(hwvInDev);   wvErrorMes("\nНе удалось закрыть устройство!\n", wvRes);
            fclose(pf);


        Скрытый текст
        Возможно, стоит предусмотреть дополнительную возможность прерывания цикла while(numBufCyr != 0), на всякий пожарный случай.

        Нет смысла вызывать waveInStop после waveInReset.
        waveInReset выбрасывает все буферы из очереди записи и сбрасывает позицию записи в 0. После waveInReset процесс записи уже остановлен. Майкрософт сообщает следующее про Waveinstop:
        Calling this function when input is not started has no effect, and the function returns zero.
        Если процесс записи не запущен, вызов функции не будет иметь никакого эффекта, при этом функция вернёт ноль(нет ошибок).
        C учётом того, что ко времени вызова функций в очереди нет ни одного буфера и устройство просто нужно закрыть, возможно, можно обойтись без вызова этих функций вообще и достаточно будет waveinclose. :scratch:


        В callback, в другом потоке, при поступлении очередного сообщения wim_data, производится проверка переменной mode. Если mode=stop - выполняется освобождение памяти, выделенной под буфер и заголовок, на который ссылается текущее сообщение wim_data, и уменьшается значение счётчика буферов numBufCyr:
        ExpandedWrap disabled
          if(mode == stop)
                {
                  cout << "Операции завершения записи" << endl;
                  numBufCyr--;
                  wvRes = waveInUnprepareHeader(hwvInDev, wvBuf, sizeof(*wvBuf));
                  wvErrorMes("\nНе удалось освободить буфер!\n", wvRes);          
                  free(wvBuf -> lpData);
                  free((WAVEHDR*)dwParam1);
                }

        Скрытый текст
        numBufCyr-- , имхо, будет более безопасным в конце блока. Только после того, как память свободна, уменьшается значение счётчика. :-?


        Когда сallback "обнулит" numBufCyr - это будет означать, что память, выделенная под буферы и заголовки, освобождена. Основной поток завершит цикл while(numBufCyr != 0) и закроет устройство.
        Сообщение отредактировано: Prince -
          Цитата
          пример программы записи с микрофона

          С любого входа звукового адаптера. Функции wavein не выбирают вход для записи.
            Спасибо большое за подробные объяснения!
              У меня возникли проблемы в релиз-версии приведенной выше программы. После нажатия клавиши появляются надписи "Операции завершения" и программа зависает. В дебуг-версии такого эффекта нет. Я вставил в цикл do строку
              ExpandedWrap disabled
                cout << "";
              программа зависать перестала. Хотелось бы разобраться, почему происходит зависание в релиз-версии и как с этим бороться.
                Я тоже попробовал сделать релиз, программа зависает после нажатия клавиши, причем вход в колбек не происходит. В чем тут дело, я не понимаю.
                  Уберите из callback вывод в консоль.

                  Закоментируйте waveinreset и waveinstop в main.

                  numBufCyr-- в callback при завершении записи перенесите в конец блока.

                  Кстати, по поводу callback function майкрософт говорит следующее:
                  Цитата
                  Applications should not call any system-defined functions from inside a callback function, except for EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, and timeSetEvent. Calling other wave functions will cause deadlock.

                  https://msdn.microsoft.com/en-us/library/wi...9(v=vs.85).aspx

                  Если понимать буквально, то и wavein функции в callback function юзать нельзя. А где можно, майкрософт молчит.

                  Там же, в конце страницы камент от одного из участников форума тамошнего(?):
                  Цитата
                  Re: Applications should not call any system-defined functions from inside a callback
                  SDK sample Metronome calls waveInAddBuffer from WAVEIN Callback (file Microsoft SDKs\Windows\v6.1\Samples\Multimedia\DirectShow\Filters \Metronome\Metronom.cpp).
                  Also according to this sample dwParam1 contains pointer to the WAVEHDR of the completed buffer when uMsg == WIM_DATA.

                  VictorZaslavsky
                  12/29/2009

                  Т.е., майкрософт в примере из SDK вызывает waveInAddBuffer из Callback, хотя другим запрещает.

                  Причины и механизм deadlock-а майрософт не раскрывает. Но понятно, что callback function должна выполняться как можно быстрее, очень-очень быстро.

                  Добавлено
                  Вспомнил ещё.
                  В delphi экспериментировал с консольным приложением и столкнулся с проблемой: после waveinreset, попытка выполнить waveinunprepareheader в callback function вызывала исключение. Причина осталась неизвестной. В оконном приложении всё было ок.
                  Сообщение отредактировано: Prince -
                    Цитата Prince @
                    Если понимать буквально, то и wavein функции в callback function юзать нельзя. А где можно, майкрософт молчит.

                    Не берусь всё детально рассказать.

                    В любом процессе есть очередь сообщений. И её внутренний механизм обработчик сообщений. Обработчик сообщений представляет собой бесконечный цикл с функцией GetMessage.
                    Что-бы процессор не тратил в пустое время GetMessage основан на обработки событий. Он ждёт события прихода сообщения.

                    Так вот что-бы callback функции не влияли на остальной код, они должны вызываться в основном потоке. А чтобы основной код не влиял на callback функции, надо что-бы состояния переменные были в определённом состоянии. Добивается это тем что callback функции вызываются синхронно с основным потоком. Если бы они вызывались не синхронно, а в побочном потоке, то тогда была бы переменные могли бы находиться в не определённом состоянии. Грубо говоря в переменную типа DWord мог бы записаться 1 байт, а 3 других не успеть. А в это время бы вызвалась callback.

                    Поэтому МС и сделал callback синхронным с основным потоком. Но как этого добиться? Для этих целий МС использует Хак подругому не скажешь. Они вызывают callback функции внутри GetMessage. Это гарантирует что все переменные будут определённом, а не промежуточном состоянии.

                    Отсюда следует, что разрешено использовать системные фукции с событийной(Event) структурой такие как
                    Цитата
                    PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, and timeSetEvent.

                    А вот те функции которые ждут прихода сообщения вот их нельзя. Так как это приведёт к зависанию. Они будут ждать обработки GetMessage, а GetMessage будет ждать завершения CallBack функции. От куда имеем замкнутый круг защелки, который называется deadlock.

                    Как определить, какие функции можно какие нет? Большинство функций вызывать можно. Кроме медленных, которые предполагают что реакция на них будет не скорой и поэтому их реализовали через сообщения. Часто МС прописывает в своей документации что данную функцию нельзя вызывать внутри CallBack.
                    Сообщение отредактировано: Pavia -
                      Цитата
                      callback - функции работают в основном потоке.

                      При обрабтке wim_data, callback выполняется как раз в побочном потоке. :-?
                      Могу предположить, что и цикл c getmessage там свой, а сообщения wim_data могут прилетать через PostThreadMessage. :scratch: Но это так, догадка, предположение.
                      Сообщение отредактировано: Prince -
                        Цитата Prince @
                        При обрабтке wim_data, callback выполняется как раз в побочном потоке.

                        С чего вы взяли, что в побочном? Просто это дюже не удобно. Тогда надо блокировать все структуры от изменения. В каждой структуре тогда надо делать поле Lock для спиновой блокировки. И заниматься проблемами синхронизации на каждом шагу. А если сделали изначально синхронно с основным потоком, то нет проблем.
                        Сообщение отредактировано: Pavia -
                          Цитата
                          С чего вы взяли, что в побочном?

                          Так отладчик говорит. :ph34r: Когда прилетают wim_open/close - вызов сallback происходит в основном потоке. А когда wim_data - в побочном, который добавляется к процессу, когда создаётся очередь буферов(после первого waveinaddbuffer).

                          Добавлено
                          Да и читал, помню, об этом. А где читал - не помню.

                          Добавлено
                          Цитата
                          Функция может вызываться в контексте обработчика прерывания, поэтому безопасно может использовать лишь ограниченный набор функций Windows: EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, timeSetEvent. Обращение к другим системным функциям, как и к функциям звуковой подсистемы, может вызвать непредсказуемые последствия.

                          Для вызова функции звуковая подсистема создает отдельную задачу (thread) с повышенным (ABOVE_NORMAL) приоритетом. В отличие от передачи сообщений, которые обрабатываются в порядке очереди, вызов функции происходит параллельно с работой остальных задач процесса, поэтому необходимо заботиться о синхронизации доступа функции и других задач к общим переменным и структурам данных.

                          Вспомогательная задача создается один раз и существует до полного завершения процесса. Звуковая подсистема вызывает из этой задачи функции уведомления для всех устройств, которые будут открыты за время жизни процесса.

                          https://rsdn.ru/article/multimedia/winsnd.xml
                          Сообщение отредактировано: Prince -
                            Prince
                            Вполне очевидно, я когда то об этом слышал, но подтверждения не находил. Для реального масштаба времени wim_data должен быть не завязан на систему сообщений. И реализован на системном таймере. Есть у МС недокументированный таймер используемый для указателя и каретки.

                            Тогда получается пока окромя как опытным путем выяснить что можно, а что нельзя не получится.
                            Предположу, что МС сделал синхронизацию, и вызов WIM_DATA и wim_open - обоих идёт внутри GetMessage.
                              Я ничего не понял. Как это - вызов wim_data внутри GetMessage? Цикла getmessage? Всё-таки какого потока? :wacko:

                              Цитата
                              Тогда получается пока окромя как опытным путем выяснить что можно, а что нельзя не получится.

                              Ну да, если функция как-то завязана на обработчик прерывания(пред. сообщение), то я тут уже потерялся.
                              На а что касается вызова функций wavein из callback, если майкрософт так делает, значит - можно. Да по другому я и не представляю, как и зачем, в таком случае, использовать callback_function. :scratch:
                              Сообщение отредактировано: Prince -
                                Prince
                                Вот про CallBack
                                https://msdn.microsoft.com/ru-ru/library/wi...1(v=vs.85).aspx

                                Добавлено
                                Prince
                                Цитата
                                Remarks

                                Applications should not call any system-defined functions from inside a callback function, except for EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, and timeSetEvent. Calling other wave functions will cause deadlock.

                                Я склонен читать это сообщение так. Что это просто отписка, автора. Что-бы пройти нормо контроль документации. Я не представляю как можно описать что можно вызывать, а что нельзя. Но алгоритм могу сказать если внутри есть ожидание сообщения, то будет дедлок. Если нет можете вызывать. Так как внутренее устройства функций нам не известно. То воспользоваться этим алгоритмом не представляется возможным. А перечислять все 10 000 функций которые можно вызывать и которые нельзя тоже не целесообразно. Отсюда автор просто упомянул то что считает наиболее важным.
                                OutputDebugString - была упомянута как альтернатива выводу на консоль. Так как последняя очевидно что приведёт к зависанию. Вернее это мне очевидно, так как на 70% представляю её внутренние устройство.
                                PostMessage - разрешено, так как она работает в не блокируещем режиме(т.е. без гарантии доставки) в отличии от SendMessages которую очевидно что нельзя вызывать.
                                EnterCriticalSection, LeaveCriticalSection - тоже не завязаны на сообщения. И нужны для синхронизации. А есть механизмы синхронизации которые построены на очереди сообщений на память Semaphore functions их использовать нельзя .
                                Сообщение отредактировано: Pavia -
                                  Простая проверка показывает, что если в обработчик wim_open/сlose воткнуть sleep(10000), основной поток зависает на заданные 10 с. В то время как обработчик wim_data основной поток не блокирует. Отладчик показывает выполнение callback, в случае wim_data, в побочном потоке.
                                  Механизм мне неизвестен. :-?

                                  Добавлено
                                  Цитата
                                  А перечислять все 10 000 функций которые можно вызывать и которые нельзя тоже не целесообразно. Отсюда автор просто упомянул то что считает наиболее важным.

                                  Логично. Но всё-таки в callback-е возвращается заголовок буфера, и майкрософт мог бы сообщить, что с ним, на их взгляд, можно делать.
                                  Перечислить waveinaddbuffer и пр. было бы несложно. midiOutLongMsg они же в описание впихнули, хотя необходимость его использования в callback менее очевидна, чем waveinaddbuffer. Мне так кажется.
                                  Цитата
                                  Просто это дюже не удобно.

                                  Как раз очень удобно. Основной поток не блокируется, и есть куча времени на обработку буферов, при вменяемой их длительности.
                                  Сообщение отредактировано: Prince -
                                    Цитата Prince @
                                    Уберите из callback вывод в консоль.

                                    Закоментируйте waveinreset и waveinstop в main.

                                    numBufCyr-- в callback при завершении записи перенесите в конец блока.

                                    Все сделал, не помогло. Видимо, причина в чем-то другом
                                      У меня тоже не получилось. Проект прикрепил.
                                      Прикреплённый файлПрикреплённый файлMySound.zip (5,16 Кбайт, скачиваний: 170)
                                        Если сделать volatile для numBufCyr, то работает и с циклом do. Программа зависает при включении waveInReset, почему - не понятно.
                                          Все заработало, видимо, был сбой
                                            Цитата
                                            Программа зависает при включении waveInReset, почему - не понятно.

                                            Ещё раз проверил. После waveinreset виснет waveinunprepareheader в сallback.
                                            Варианты:
                                            1. не использовать waveinreset, подождать, пока все буферы будут заполнены и уничтожены в callback.
                                            2. при использовании waveinreset, вынести waveinunprepareheader из callback в основной поток.
                                            Во втором случае могут быть тоже несколько вариантов. Самый простой, наверное - это хранить массив headers. И после того, как цикл по numBufCyr завершится, выполнить в цикле unpreapre/free/free для всех элементов headers.

                                            После waveinreset, дополнительный поток, в котором обрабатывается очередь сообщений wim_data - уничтожается. Получается, дедлок наступает...когда waveinreset("кто-то" другой после выполнения waveinreset) собирается уничтожить поток, ожидая, когда очистится очередь сообщений потока (?), в то время как в нём происходит вызов waveinunprepare...в общем, нельзя вызывать waveinunprepareheader внутри callback после waveinreset.
                                            Сообщение отредактировано: Prince -
                                              А вы проверяли c volatile numBufCyr?
                                                Я проверял код из первого поста, компилил в wxDev-C++. Также повторил в delphi.
                                                Работает без нареканий.
                                                Уже говорил, waveinreset и waveinstop в таком контексте лишние. Поскольку все буферы ко времени вызова фунций уже уничтожены, функции фактически ничего не делают(полезного). Работает и с waveinreset/stop и без.
                                                В общем, программа не виснет. Как исходный вариант, так и допиленый.

                                                Если поставить waveinreset перед циклом while(numBufCyr != 0)(там вызов waveinreset имеет смысл: не нужно ожидать, пока будут записаны все буферы в очереди) - см. выше, сообщение #21.

                                                Цитата
                                                А вы проверяли c volatile numBufCyr?

                                                Работает и так и эдак.

                                                А, да, winXP.
                                                Сообщение отредактировано: Prince -
                                                  Спасибо за объяснения, очень полезно.
                                                    Так у вас программа виснет или нет? :unsure:
                                                    Win7/8/.. ?
                                                    Сообщение отредактировано: Prince -
                                                      В Windows 7 и 8 я по сравнению с исходным текстом (в 1 сообщении) сделал volatile для nunBufCyr, больше ничего не менял. Программа не виснет. Посоветовали это решение в теме Почему в релиз-версии программа зависает?
                                                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                      0 пользователей:


                                                      Рейтинг@Mail.ru
                                                      [ Script execution time: 0,0684 ]   [ 22 queries used ]   [ Generated: 19.03.24, 11:16 GMT ]