На главную Наши проекты:
Журнал   ·   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
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
> Работа со звуком с помощью MMSystem
    Начал с самого начала, попробовал вывести параметры устройств ввода своей звуковой карты. Код:
    ExpandedWrap disabled
      void getnumdevaudio(UINT &nin, UINT &nout)
      {
        nin  = waveInGetNumDevs();
        nout = waveOutGetNumDevs();
      }  
       
      void getinaudioinfo(UINT nin)
      {
        WAVEINCAPS wvinfo;
        for(UINT i = 0; i < nin; i++)
        {
          MMRESULT wvres = waveInGetDevCaps(i, &wvinfo, sizeof(wvinfo));
          if(wvres != MMSYSERR_NOERROR)
          {
            std::cout << "Ошибка определения параметров устройства № "  << i << std::endl;
          } // if(wvres
            _tprintf(TEXT("%s\t%i\t%i\n"), wvinfo.szPname, wvinfo.dwFormats, wvinfo.wChannels);
        } // for(UINT
        std::cin.get();
      } // fun
       
      #include <windows.h>
      #include <iostream>
      #include <stdio.h>
      #include <string.h>
      #include <tchar.h>
      #include "mysound.h"
       
      void main(int argc, char* argv[])
      {
        setlocale(LC_ALL, "");
        UINT nin, nout;
        getnumdevaudio(nin, nout);
        getinaudioinfo(nin);
      }

    В результате получил:
    ExpandedWrap disabled
      IA HD Audio CD In   786431  65535
      VIA HD Audio Front Microphone   786431  65535
      VIA HD Audio Line In    786431  65535
      VIA HD Audio Microphone 786431  65535
      VIA HD Audio Stereo Mixer   786431  65535
    Возникли следующие вопросы:
    1. Почему wvinfo.wChannels дает большое целое значение, а не значение 1 или 2, как указано в MSDN?
    2. Как из цифры, которые дает wvinfo.dwFormats, получить все возможные параметры устрройства ввода, например WAVE_FORMAT_1M08 и др., которые устройство ввода поддерживает?
      1. Потому что такое значение возвращает драйвер устройства. Почему производители посчитали, что он должен возвращать именно такое значение...да кто бы знал бы.
      2. Проверять, установлен ли соотвествующий флаг в dwFormats.
      Цитата
      #DEFINE WAVE_FORMAT_1M08 0x00000001
      #DEFINE WAVE_FORMAT_1S08 0x00000002
      #DEFINE WAVE_FORMAT_1M16 0x00000004
      #DEFINE WAVE_FORMAT_1S16 0x00000008
      ...


      Имхо, не стоит dwFormats воспринимать слишком серьезно. "Стандартные комбинации" параметров давно стали общепринятыми, и современными картами(драйверами) поддерживаются. Кроме того, константы для форматов 96/192 кГц 24/32 бита и многоканальных, вряд ли существуют, судя по "конструкции" 32-х битного слова dwFormats. На мой взгляд, надежней проверять поддержку формата, открывая устройство с параметрами, валидность которых под вопросом.

      Цитата
      IA HD Audio CD In 786431 65535
      VIA HD Audio Front Microphone 786431 65535
      VIA HD Audio Line In 786431 65535
      VIA HD Audio Microphone 786431 65535
      VIA HD Audio Stereo Mixer 786431 65535

      :wacko: семерка?
        Нет, у меня Windows XP. Компьютер с какой-то навороченной мультимедийной звуковой картой. У меня возникли следующие вопросы:
        1. Начинаю пробовать записать звук:
        ExpandedWrap disabled
          int tryrec(UINT nin, DWORD nbuf) // nin = 0 (домашний компьтер с одним устройством ввода - микрофоном), nbuf = 1024 - размер буфера для записи звука
          {
            TCHAR serror[128];
            serror[0] = 0;
            MMRESULT wvres;
            HWAVEIN hwvindev;
            WAVEFORMATEX wvformat;
            wvformat.wFormatTag = WAVE_FORMAT_PCM;
            wvformat.nChannels = 1;
            wvformat.nSamplesPerSec = 44100;
            wvformat.wBitsPerSample = 16;
            wvformat.nBlockAlign = wvformat.nChannels*wvformat.wBitsPerSample/8;
            wvformat.nAvgBytesPerSec = wvformat.nSamplesPerSec*wvformat.nBlockAlign;
            wvformat.cbSize = sizeof(wvformat);
            wvres = waveInOpen( &hwvindev, nin, &wvformat, 0, 0, WAVE_FORMAT_DIRECT);
            if(wvres != MMSYSERR_NOERROR)
            {
              printf("Устройство %i открыть не удалось!\n", nin);
              return 1;
            } // if(wvres
            char *swvbuf  = (char*)malloc((size_t) nbuf);
            swvbuf[0] = 0;
            WAVEHDR wvbuf;
            wvbuf.lpData          = swvbuf;
            wvbuf.dwBufferLength  = nbuf;
            wvres =  waveInPrepareHeader(hwvindev, &wvbuf, sizeof(wvbuf));
            if(wvres != MMSYSERR_NOERROR)
            {
              printf("Не удалось подготовить буфер для записи!\n");
              wvres = waveInGetErrorText(wvres, serror, 128);
              _tprintf(TEXT("Ошибка: %s\n"), serror);
              return 2;
            } // if(wvres
            return 0;  
          }
        Получаю ошибку в waveInPrepareHeader "Системной функции передан неправильный параметр". Подскажите, пожалуйста, что я делаю неправильно.
        2. Не очень понимаю механизм записи звука. Подготавливаю буфер, делаю waveInAddBuffer, тем самым уведомляю драйвер, что туда можно записывать данные. После заполнения буфера как мне в программе узнать, что он заполнился и надо его очистить и снова подготовить для новой записи?
        3. Сколько может быть буферов и можно ли их записывать последовательно, а очищать и подготавливать за один прием после заполнения последнего? Или так не делается и нужно в процессе записи в следующий буфер готовить предыдущий?
        4. Есть ли функция API для записи данных из буфера в файл? Или для записи нужно использовать обычные функции записи буфера swvbuf в файл?
        5. Исходя из каких соображений нужно выбирать размер буфера?
          1. Скорее всего, ошибка в sizeof(wvbuf). Нужен размер заголовка sizeof(WAVEHDR), а не размер переменной.
          2. Вы не указали механизм уведомления в waveinopen, что равносильно callback_null. В таком варианте вы никак не узнаете. Читайте про механизмы уведомлений звуковой подсистемы.
          3. Сколько может быть буферов, я не знаю, много может быть. Когда буфер заполнен, вы получаете уведомление(в это время записывается следующий в очереди буфер). В зависимости от механизма уведомления, в оконной процедуре или в специальной функции, или в потоке, вы обрабатываете буфер, вернувшийся из очереди, и снова ставите в очередь при помощи waveinaddbuffer( или уничтожаете, если он вам уже не нужен).
          4. Буфер - кусок памяти, начинающийся с адреса wvbuf.lpData. Для записи в файл можно использовать все доступные функции для работы с файлами. Для записи RIFF wave файла существуют специализированные функции mmio...
          5. Исходя из потребностей. Маленький буфер обеспечит меньшую задержку и более быструю реакцию вашей программы, если ваша программа должна каким-то образом реагировать на параметры звука. Но, ваша программа не сможет реагировать на события происходящие в системе чаще, чем получает управление ваш процесс. Поэтому размер буфера снизу ограничен как минимум квантом времени виндовс. Если буфер оооочень большой, а ваш компьютер ооочень медленный, в этом случае комп может не успеть сделать с буфером все что необходимо до того, как из очереди вернется следующий буфер. Хоть и гипотетически, но такая ситуация возможна, в принципе. Сверху размер буфера ограничен объемом оперативной памяти и быстродействием компа.
          Если без "воды", размер 0.1 с - 1.0 с вполне нормально, имхо.
          Сообщение отредактировано: Prince -
            Добавил в код
            ExpandedWrap disabled
                wvbuf.dwFlags         = WHDR_PREPARED;
            сообщение об ошибке исчезло, видимо из-за неопределения флага оно появлялось. Однако остальные вопросы остаются актуальными.
              Цитата
              wvbuf.dwFlags = WHDR_PREPARED;

              Неверно. Это флаг пользователь не устанавливает. Флаги можно просто обнулять.
              Сравните значения sizeof(wvbuf) и sizeof(WAVEHDR).
              Сообщение отредактировано: Prince -
                Проверил размеры:
                ExpandedWrap disabled
                  printf("%i\t%i\n", sizeof(WAVEHDR), sizeof(wvbuf));
                Получилось, что они одинаковые (32). Попробовал убрать
                ExpandedWrap disabled
                  wvbuf.dwFlags = WHDR_PREPARED;
                опять появилась ошибка. В MSDN
                ExpandedWrap disabled
                  The lpData, dwBufferLength, and dwFlags members must be set before calling the waveInPrepareHeader or waveOutPrepareHeader function.
                Вроде бы получается, что в программе нужно устанавливать этот флаг.

                Добавлено
                Мне не очень понятно по поводу буфера. Я задаю один буфер, его размеры и другие параметры. Достаточно указать только один буфер, а драйвер сам создаст нужное количество буферов? Или мне нужно завать количество буферов самому? Например, так:
                ExpandedWrap disabled
                  WAVEHDR wvbuf1, wvbuf2, wvbuf3
                Сообщение отредактировано: tumanovalex -
                  Цитата
                  The lpData, dwBufferLength, and dwFlags members must be set before calling the waveInPrepareHeader or waveOutPrepareHeader function.

                  The lpData, dwBufferLength, and dwFlags members of the WAVEHDR structure must be set before calling this function (dwFlags must be zero).

                  Цитата
                  Получилось, что они одинаковые (32)

                  Значит, мое предположение было ошибочным. А если обнулить флаги?

                  Цитата
                  Мне не очень понятно по поводу буфера. Я задаю один буфер, его размеры и другие параметры. Достаточно указать только один буфер, а драйвер сам создаст нужное количество буферов? Или мне нужно завать количество буферов самому?

                  Вы описываете все буферы. Не количество, а ВСЕ буферы. Как минимум необходимы два буфера.
                  Сообщение отредактировано: Prince -
                    Спасибо за помощь. С обнуленным флагом все работает. Опять возникли вопросы (вызваны они наверное тем, что раньше с CALLBACK функциями в явном виде не приходилось работать):
                    1. У меня консольное приложение. В каком месте функции tryrec нужно описывать функцию уведомления? Непосредственно вместо нуля в определении функции waveInOpen или в виде отдельной фунции в заголовочном файле? В последнем случае в waveInOpen нужно указывать указатель на функцию уведомления?
                    2. Как организовать в консольном приложении оповещение о заполненности буферов?
                      Цитата tumanovalex @
                      Как организовать в консольном приложении оповещение о заполненности буферов?

                      Добавить в приложение функцию:
                      ExpandedWrap disabled
                        //Процедура CallBack
                        procedure CallBackZvyk(HWAVEx:THandle;UINT:Cardinal;Instance:DWORD;
                                      Param1:DWORD;Param2:DWORD);stdcall;
                        var
                          Hdr:PWaveHdr;I: Integer;
                        begin
                          if UINT = WOM_DONE then
                      При открытии устройства:
                      ExpandedWrap disabled
                          Err := WaveOutOpen(WaveOut, 0, @WaveFormat,
                            Cardinal(@CallBackZvyk), 0, CALLBACK_FUNCTION);
                      Система сама вызовет твою функцию и ты сможешь проверить, с каким флагом вызвана данная функция и предпринять необходимые действия по изъятию данных из буфера (при записи) или заливке данных в буфер (при воспроизведении). :D
                        Видимо, я опять что-то не понял. Попытка использования функции окончилась неудачей. Сделал пустую функцию:
                        ExpandedWrap disabled
                          void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
                          {
                            switch(uMsg)
                            {
                              case WIM_OPEN:
                                break;
                              case WIM_DATA:
                                break;
                              case WIM_CLOSE:
                                break;
                            }
                          }
                        Вызов функции
                        ExpandedWrap disabled
                          wvres = waveInOpen( &hwvindev, nin, &wvformat, (DWORD_PTR) (*waveInProc), 0, WAVE_FORMAT_DIRECT | СALLBACK_FUNCTION);
                        окончился необработанным исключением. Подскажите, пожалуйста, как правильно вызывать CALLBACK функцию в моем случае.
                          Я не сишник. Возможно, проблема в dword_ptr вместо dword. Или в (DWORD_PTR) (*waveInProc). Без понятия.
                          Кстати, флаг WAVE_FORMAT_DIRECT не нужен, поскольку вы запрашиваете данные непосредственно от устройства (nin=0) и в формате WAVE_FORMAT_PCM. АСМ при любом раскладе задействован не будет. Если запрошенный формат не подерживается, устройство просто не удастся открыть. WaveInOpen завершится с ошибкой WAVERR_BADFORMAT.
                            Цитата tumanovalex @
                            Подскажите, пожалуйста, как правильно вызывать CALLBACK функцию в моем случае.

                            Цитата tumanovalex @
                            Видимо, я опять что-то не понял.

                            Видимо.... Ты не будешь вызывать эту функцию. Ее будет вызывать СИСТЕМА. А для этого необходимо (в первую очередь) соблюсти СОГЛАШЕНИЕ О ВЫЗОВАХ данной функции. Это выполнено? :)

                            Добавлено
                            Цитата tumanovalex @
                            Вызов функции

                            Это не ВЫЗОВ функции. Это всего лишь попытка ОТКРЫТЬ устройство с определенными параметрами. И судя по:
                            Цитата tumanovalex @
                            окончился необработанным исключением

                            параметры не соответствуют заявленным системой. :D
                            Сообщение отредактировано: medved_68 -
                              Я неправильно сформулировал, имел в виду, как правильно записать свою функцию и сделать на нее ссылку в waveInOpen.
                                Как оказалось, ошибка возникает в строке
                                ExpandedWrap disabled
                                    wvres = waveInStart(hwvindev);

                                До начала записи я делаю следующее:
                                ExpandedWrap disabled
                                    char *swvbuf[16];
                                    for(UINT i = 0; i < nbuf; i++)
                                    {
                                      swvbuf[i]    = (char*)malloc((size_t) nbufsize);
                                      swvbuf[i][0] = 0;
                                      wvbuf.lpData          = swvbuf[i];
                                      wvbuf.dwFlags         = 0;
                                      wvbuf.dwLoops         = 0;
                                      wvbuf.dwUser          = 0;
                                      wvbuf.dwBufferLength  = nbufsize;
                                      wvres =  waveInPrepareHeader(hwvindev, &wvbuf, sizeof(wvbuf)); errormes("Не удалось подготовить буфер для записи!\n", wvres);
                                      wvres =  waveInAddBuffer(hwvindev, &wvbuf, sizeof(wvbuf));     errormes("Не удалось добавить буфер для записи!\n", wvres);
                                    } // for(UINT i = 0; i < nbuf; i++)
                                Помогите, пожалуйста, исправить ошибку. Прикрепляю проект.

                                Прикреплённый файлПрикреплённый файлMySound.zip (9,77 Кбайт, скачиваний: 369)
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) [1] 2 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0494 ]   [ 18 queries used ]   [ Generated: 16.04.24, 12:00 GMT ]