На главную Наши проекты:
Журнал   ·   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
  
> Работа со звуком с помощью 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 Кбайт, скачиваний: 367)
                                  Привет, всем!
                                  Решил не создавать новой темы, надеюсь, пишу в нужную ветку.
                                  На работе попросили разобраться с интерфейсом в mmystem. Вроде всё просто и понятно, но тут возникла сложность с регулировкой уровня звука и баланса:
                                  -используя самый простой метод, получаю доступ к первому попавшемуся destination, имеющий опцию контроля над уровнем громкости ("Общей громкости", в данном случае):

                                  ...
                                  if (mixerGetNumDevs() < 1)
                                  {
                                  return;
                                  }

                                  unsigned int rc;

                                  HMIXER hMix;
                                  if (mixerOpen(&hMix, 0, 0, 0, 0) != MMSYSERR_NOERROR) {
                                  return;
                                  }

                                  MIXERLINE ml = {0};
                                  ml.cbStruct = sizeof(MIXERLINE);
                                  ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
                                  if( (rc=mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(hMix), &ml, MIXER_GETLINEINFOF_DESTINATION)) != MMSYSERR_NOERROR)
                                  return;

                                  MIXERLINECONTROLS mlc = {0};

                                  MIXERCONTROL mc = {0};

                                  mlc.cbStruct = sizeof(MIXERLINECONTROLS);
                                  mlc.dwLineID = ml.dwLineID;
                                  mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
                                  mlc.cControls = 1;
                                  mlc.pamxctrl = &mc;
                                  mlc.cbmxctrl = sizeof(MIXERCONTROL);

                                  if( (rc=mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(hMix), &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE)) != MMSYSERR_NOERROR)
                                  return;

                                  - дальше начинаются непонимания: в инициализации структуры MIXERCONTROLDETAILS для получения данных я не могу понять, какой флаг указать, чтобы мне выдали информацию в структуре MIXERCONTROLDETAILS_UNSIGNED о уровне баланса? Хорошо, решил проэкспериментировать, заполнил объект MIXERCONTROLDETAILS следующим образом:

                                  ...
                                  MIXERCONTROLDETAILS_UNSIGNED* mxBalControlData = new MIXERCONTROLDETAILS_UNSIGNED[ml.cChannels*2];

                                  MIXERCONTROLDETAILS mcd = {0};
                                  mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
                                  mcd.hwndOwner = 0;
                                  mcd.cMultipleItems = 0;
                                  mcd.dwControlID = mc.dwControlID;
                                  mcd.paDetails = mxBalControlData;
                                  mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
                                  mcd.cChannels = ml.cChannels;

                                  if((rc=mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(hMix), &mcd, MIXER_GETCONTROLDETAILSF_VALUE)) != MMSYSERR_NOERROR)
                                  return;
                                  ...

                                  Конечно, я проверил в отладчике, что ml.cChannels равна 2, а значит, как я понимаю, имеется доступ к управлению громкости и баланса, ок. Но никак не пойму до конца, что за значения мне приходят в mxBalControlData: должны прийти показатели или уровня громкости, или баланса, - поэкперементировав чуток, пришёл к выводу, что приходят данные с того ползунка, показатели которого последний раз изменяли. И как же мне указать, что в данный момент мне нужен control показателя баланса или показателя громкости?
                                    Размер данных контрола должен быть 8 байт: 4 байта на канал(?);
                                    Я сделал так:

                                    ExpandedWrap disabled
                                      // volume:array[0..1] of integer;
                                      // volume[0] - левый канал
                                      // volume[1] - правый канал
                                      mxcdetail.cbDetails:=sizeof(MIXERCONTROLDETAILS_UNSIGNED)*Length(volume);
                                      mxcdetail.paDetails:=@volume;
                                       
                                      mixerGetControlDetails(mixercombobox.ItemIndex,@mxcdetail,
                                      MIXER_OBJECTF_MIXER or MIXER_GETCONTROLDETAILSF_VALUE);


                                    Как вариант, если не нужен именно master volume, достаточно waveoutsetvolume c предварительной проверкой флага WAVECAPS_LRVOLUME в waveoutgetdevcaps. .


                                    Контрол MIXERCONTROL_CONTROLTYPE_PAN пока не встречался.
                                    Сообщение отредактировано: Prince -
                                      ту Prince
                                      А кто из них кто? Левый канал, правый канал? Где будут показатели с уровня громкости, а где с уровня баланса?
                                        Цитата
                                        А кто из них кто? Левый канал, правый канал?

                                        Ну, чисто интутивно, первое 4-байтовое - левый канал, второе - правый. Но а кто мешает проверить? :rolleyes:
                                        Цитата
                                        где будут показатели с уровня громкости, а где с уровня баланса?

                                        У вас в наличии два регулятора громкости, раздельно по левому и правому каналам, с пределами регулировки от 0 до 65535.
                                        А вам очень хочется общий регулятор громкости и баланса.
                                        Можно поступить так.
                                        Пределы регулировки громкости общего регулятора оставляете от 0 до 65535.
                                        А баланса от -100 до +100.
                                        -100 соотвествует левому крайнему положению слайдера баланса, +100 - крайнему правому.
                                        И считаете громкость в каналах при изменении положения регуляторов vol или bal(надеюсь, не напутал):
                                        ExpandedWrap disabled
                                          case bal of
                                          -100..-1:Begin
                                                   volume[0]:=vol;
                                                   volume[1]:=trunc(vol*((100-abs(bal))/100);
                                                   end;
                                          0:       Begin
                                                   volume[0]:=vol;
                                                   volume[1]:=vol;
                                                   end;
                                          1..100:  Begin
                                                   volume[0]:=trunc(vol*(100-bal)/100);
                                                   volume[1]:=vol;
                                                   end;
                                          end;

                                        Дальше передаете расчитанные значения в mixerSetControlDetails. Зависимость громкость/баланс можно придумать и другую, например, такую, чтобы при изменении баланса громкость изменялась синхронно в обоих каналах, все в ваших руках. А если вдруг в каком-нибудь из кодеков обнаружите контрол типа MIXERCONTROL_CONTROLTYPE_PAN, дайте знать, интересно.

                                        Все сказанное относится не только к линии master volume, но и к прочим.
                                        Сообщение отредактировано: Prince -
                                          Цитата Prince @
                                          Цитата
                                          А кто из них кто? Левый канал, правый канал?

                                          Ну, чисто интутивно, первое 4-байтовое - левый канал, второе - правый. Но а кто мешает проверить? :rolleyes:
                                          Цитата
                                          где будут показатели с уровня громкости, а где с уровня баланса?

                                          У вас в наличии два регулятора громкости, раздельно по левому и правому каналам, с пределами регулировки от 0 до 65535.
                                          А вам очень хочется общий регулятор громкости и баланса.
                                          Можно поступить так.
                                          Пределы регулировки громкости общего регулятора оставляете от 0 до 65535.
                                          А баланса от -100 до +100.
                                          -100 соотвествует левому крайнему положению слайдера баланса, +100 - крайнему правому.
                                          И считаете громкость в каналах при изменении положения регуляторов vol или bal(надеюсь, не напутал):
                                          ExpandedWrap disabled
                                            case bal of
                                            -100..1: Begin
                                                     volume[0]:=vol;
                                                     volume[1]:=trunc(vol*((100-abs(bal))/100);
                                                     end;
                                            0:       Begin
                                                     volume[0]:=vol;
                                                     volume[1]:=vol;
                                                     end;
                                            1..100:  Begin
                                                     volume[0]:=trunc(vol*(100-bal)/100);
                                                     volume[1]:=vol;
                                                     end;
                                            end;

                                          Дальше передаете расчитанные значения в mixerSetControlDetails. Зависимость громкость/баланс можно придумать и другую, например, такую, чтобы при изменении баланса громкость изменялась синхронно в обоих каналах, все в ваших руках. А если вдруг в каком-нибудь из кодеков обнаружите контрол типа MIXERCONTROL_CONTROLTYPE_PAN, дайте знать, интересно.

                                          Все сказанное относится не только к линии master volume, но и к прочим.

                                          Ту Prince
                                          Т.е. если в массиве из двух элементов левому каналу соответсвует нулевой элемент, а правому - первый. То при заполнении данного массива функцией mixerGetControlDetails, как отличить какой элемент массива указывает на показания громкости, а какой на показания баланса? Будет ли нулевой элемент - уровнем громкости, а первый - уровнем баланса, как определяется порядок заполнения?
                                            Нету баланса, не-ту. Есть два канала громкости, левый/правый, каждому из них где-то во внутренностях аудиокодека(микросхема такая) соотвествуют некие регистры. А "баланс" вы высчитываете самоятоятельно из значений громкости каналов, возвращаемых драйвером. И наоборот, управляя балансом из своей программы, вы по значению "громкости" и "баланса" высчитываете значения громкости для каждого канала и передаете драйверу.

                                            Посмотрите, сколько контролов имеет линия MIXERLINE_COMPONENTTYPE_DST_SPEAKERS и проверьте тип каждого контрола. С какой вы звуковушкой работаете?
                                            Сообщение отредактировано: Prince -
                                              Цитата Prince @
                                              Нету баланса, не-ту. Есть два канала громкости, левый/правый, каждому из них где-то во внутренностях аудиокодека(микросхема такая) соотвествуют некие регистры. А "баланс" вы высчитываете самоятоятельно из значений громкости каналов, возвращаемых драйвером. И наоборот, управляя балансом из своей программы, вы по значению "громкости" и "баланса" высчитываете значения громкости для каждого канала и передаете драйверу.

                                              Посмотрите, сколько контролов имеет линия MIXERLINE_COMPONENTTYPE_DST_SPEAKERS и проверьте тип каждого контрола. С какой вы звуковушкой работаете?

                                              Ааа) Понятно. А я всё думал :wall: , что они отдельно нам выдают уже суммарные данные по балансу, и по уровню громкости для двух каналов, а оно вон оно как. Ясно.
                                              А MIXERCONTROL_CONTROLTYPE_PAN у меня тоже не нашёл.
                                              Спасибо.
                                                Здравствуйте.
                                                Пишу программу обработки сигналов, сигналы поступают на вход звуковой карты. Исходный код взят на просторах инета, думаю все кто начинал пользовать MMSystem его видели. Возникла следующая проблема: при получении уведомления запускается процедура обработки сигнала (начинаем анализировать данные буфера). Но в большинстве случаев начало буфера уже затерто новой порцией данных. Т.е. я полагаю что по достижении конца буфера драйвер (или что там пишет в него) посылает процедуре TForm1.OnWaveIn сообщение о заполнености буфера, переводит указатель на начало буфера и начинает писать свежие данные поверх старых.
                                                Скрин прилагаю. "Стык" может быть в любом месте, но обычно это происходит в начале буфера.
                                                Прикреплённый файлПрикреплённый файлrewrite.jpg (44,91 Кбайт, скачиваний: 868)

                                                код Дельфи:
                                                ExpandedWrap disabled
                                                  procedure TForm1.StartButtonClick(Sender: TObject);
                                                  var header: TWaveFormatEx;
                                                      BufLen: integer;
                                                      buf: pointer;
                                                  begin
                                                    with header do begin
                                                                    wFormatTag := WAVE_FORMAT_PCM;
                                                                    nChannels := 2;          
                                                                    nSamplesPerSec := 22050;
                                                                    wBitsPerSample := 16;
                                                                    nBlockAlign := nChannels * (wBitsPerSample div 8);
                                                                    nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
                                                                    cbSize := 0;
                                                                   end;
                                                   
                                                    WaveInOpen(Addr(WaveIn), WAVE_MAPPER, addr(header),Form1.Handle, 0, CALLBACK_WINDOW);
                                                    BufLen := header.nBlockAlign * BufSize;
                                                    hBuf := GlobalAlloc(GMEM_MOVEABLE and GMEM_SHARE, BufLen);
                                                    Buf := GlobalLock(hBuf);
                                                    with BufHead do begin
                                                                     lpData := Buf;
                                                                     dwBufferLength := BufLen;
                                                                     dwFlags := WHDR_DONE;// изначально было WHDR_BEGINLOOP;
                                                                     dwLoops:=0;
                                                                    end;
                                                    WaveInPrepareHeader(WaveIn, Addr(BufHead), sizeof(BufHead));
                                                    WaveInAddBuffer(WaveIn, addr(BufHead), sizeof(BufHead));
                                                    GetMem(pRight,BufSize * sizeof(TPoint));
                                                    GetMem(pLeft, BufSize * sizeof(TPoint));
                                                    Work := true;
                                                    WaveInStart(WaveIn);
                                                  end;


                                                сама процедура, которую вызываем
                                                ExpandedWrap disabled
                                                  procedure TForm1.OnWaveIn;
                                                  var
                                                    dSync,dBal,i,n: integer;
                                                    data16: PData16;
                                                    begin
                                                    data16 := PData16(PWaveHdr(Msg.lParam)^.lpData);
                                                    //всякие преобразования сигнала
                                                    //If mono.Checked    then for i:=0 to BufSize_1 do data16^[i*2+1]:=data16^[i*2];
                                                    //If Invert1.Checked then for i:=0 to BufSize_1 do data16^[i*2]:=-data16^[i*2];    //round(data16^[i*2]*(0.54-0.46*cos(2*Pi*I/BufSize)));
                                                    //If Invert2.Checked then for i:=0 to BufSize_1 do data16^[i*2+1]:=-data16^[i*2+1];
                                                    //..
                                                    with PaintBox1.Canvas do
                                                   begin
                                                      Brush.Color := clWhite;
                                                      FillRect(ClipRect);
                                                      n:=(PaintBox1.Height div 2)+OffsetRCh.Position*2;
                                                      
                                                      for i:=0 to BufSize_1 do pRight^[i]:=Point(round(i*XScale),round(n-data16^[i*2+1]*YScale/YRCh.Position));
                                                      Polyline(Slice(pRight^, BufSize);
                                                      
                                                      n:=(PaintBox1.Height div 2)+OffsetLCh.Position*2;
                                                      for i:=0 to BufSize_1 do pLeft^[i-StartN]:=Point(round(i*XScale),round(n-data16^[i*2]*YScale));
                                                      Polyline(Slice(pLeft^, BufSize);
                                                   end;
                                                   if Work then WaveInAddBuffer(WaveIn, PWaveHdr(Msg.lParam),SizeOf(TWaveHdr))
                                                           else Work := true;
                                                  end;


                                                Вопрос - как запретить драйверу перезапись данных в буфере? Флаг dwLoops установил в 0 dwLoops:=0

                                                Cпасибо.
                                                  И да, ответ на возможный вопрос об изменении сигнала внутри процедуры TForm1.OnWaveIn - убирал все действия, кроме вывода на экран. Не помогает, стык все равно где-нибудь да есть.
                                                    Для обеспечения непрерывности потока данных необходимо использовать как минимум 2 буфера. Концепция waveform-audio предполагает очередь буферов. Почитайте темы пользователя tumanovalex, касающиеся работы с функциями mmsystem, в этом же разделе(а-а, эта одна из них :lol: ).
                                                    Цитата
                                                    Т.е. я полагаю что по достижении конца буфера драйвер (или что там пишет в него) посылает процедуре TForm1.OnWaveIn сообщение о заполнености буфера, переводит указатель на начало буфера и начинает писать свежие данные поверх старых.

                                                    "Виноват" не драйвер . Это Вы передаёте драйверу, в TForm1.OnWaveIn, только что заполненный буфер, а драйвер, естественно, снова начинает его заполнять, так как в очереди других буферов нет.
                                                    А кроме того, что данные перезаписываются, они ещё и теряются, поскольку обработка сообщения системой, и собственно выполнение содержимого TForm1.OnWaveIn (до WaveInAddBuffer) занимают какое-то время.

                                                    Добавлено
                                                    dwLoops - для зацикливания буфера при воспроизведении. При записи, если не ошибаюсь, содержимое dwLoops не обрабатывается вообще.

                                                    Обрабатывать буфер в оконной процедуре не совсем хорошо, лучше использовать механизмы уведомления CALLBACK_EVENT (в отдельном потоке), CALLBACK_FUNCTION, или CALLBACK_THREAD.
                                                    Сообщение отредактировано: Prince -
                                                      Ок. Это сигнал с балансировочного станка, в одном канале датчики баланса, в другом - датчик синхронизации (фотодатчик). В непрерывности потока данных нужды нет никакой, потому использую один буфер. Требуется получить массив с неискаженными данными (т.е. наложение сигнала внутри буфера недопустимо), обработать его (вычислить сдвиг фазы), и только после этого получить следующий кусок данных.

                                                      Цитата
                                                      "Виноват" не драйвер . Это Вы передаёте драйверу, в TForm1.OnWaveIn, только что заполненный буфер, а драйвер, естественно, снова начинает его заполнять, так как в очереди других буферов нет.

                                                      Так буфер передается драйверу после процедуры рисования (которая выводит УЖЕ искаженный буфер). Или это не так?

                                                      Цитата
                                                      Обрабатывать буфер в оконной процедуре не совсем хорошо, лучше использовать механизмы уведомления CALLBACK_EVENT (в отдельном потоке), CALLBACK_FUNCTION, или CALLBACK_THREAD.

                                                      к сожалению с потоками вообще не знаком :whistle: Программирую на уровне "Хэллоу ворлд!" Можно ли в этом варианте написания программы "попросить" драйвер остановить запись в буфер при вызове OnWaveIn?
                                                      Спасибо.
                                                        Ок. Это сигнал с балансировочного станка, в одном канале датчики баланса, в другом - датчик синхронизации (фотодатчик). В непрерывности потока данных нужды нет никакой, потому использую один буфер. Требуется получить массив с неискаженными данными (т.е. наложение сигнала внутри буфера недопустимо), обработать его (вычислить сдвиг фазы), и только после этого получить следующий кусок данных.

                                                        Цитата
                                                        "Виноват" не драйвер . Это Вы передаёте драйверу, в TForm1.OnWaveIn, только что заполненный буфер, а драйвер, естественно, снова начинает его заполнять, так как в очереди других буферов нет. А кроме того, что данные перезаписываются, они ещё и теряются, поскольку обработка сообщения системой, и собственно выполнение содержимого TForm1.OnWaveIn (до WaveInAddBuffer) занимают какое-то время.

                                                        Так буфер передается драйверу после процедуры рисования (которая выводит УЖЕ искаженный буфер). Или это не так? Только что пробовал в самом начале OnWaveIn вставить WaveInStop(WaveIn). Теперь стык появляется вообще в любом месте.

                                                        Цитата
                                                        Обрабатывать буфер в оконной процедуре не совсем хорошо, лучше использовать механизмы уведомления CALLBACK_EVENT (в отдельном потоке), CALLBACK_FUNCTION, или CALLBACK_THREAD.

                                                        к сожалению с потоками вообще не знаком :whistle: Программирую на уровне "Хэллоу ворлд!" Можно ли в этом варианте написания программы "попросить" драйвер остановить запись в буфер при вызове OnWaveIn? Или сделать хоть что-нибудь, чтоб получить массив из 1024-16000 неискаженных точек.
                                                        Спасибо.
                                                          Цитата
                                                          Для обеспечения непрерывности потока данных необходимо использовать как минимум 2 буфера. Концепция waveform-audio предполагает очередь буферов.

                                                          нашел в сети вариант работы с 2мя буферами. Программа пишет данные со звуковой карты в файл.
                                                          @wh1 и @wh2 - ссылки на буфера, при каждом вызове функции меняются между собой. Вроде красиво. Переделал под себя - не работает как надо. Видимо мой обработчик довольно долгий (выполняется преобразование Фурье, поиск в каждом канале сигнала "пиков", расчет фаз и вывод на экран) и буфер все равно успевает переполняться.
                                                          ExpandedWrap disabled
                                                            // обработчик "данные готовы"
                                                            procedure TformMain.MMProcData(var Message: TMessage);
                                                            var
                                                               temp: pWaveHdr;
                                                               recorded: integer;
                                                            begin
                                                               temp:=address;
                                                               if address=@wh1 then address:=@wh2 else address:=@wh1;
                                                            // если не остановлено, ставим в очередь
                                                               if not stop then
                                                                    waveInAddBuffer(hwi,address,sizeof(TWaveHdr));
                                                               recorded:=address.dwBytesRecorded;
                                                            // записываем блок
                                                               BlockWrite(fOut,(temp.lpData)^,recorded);
                                                               n:=n+recorded;
                                                               formMain.Label1.Caption:=IntToStr(n);
                                                            end;
                                                            Цитата
                                                            Или это не так?

                                                            В принципе, так.
                                                            Причину "затирания" можно искать и найти, например, в отладчике.
                                                            Или, сделайте копию буфера в начале OnWaveIn и сравните оригинал и копию перед вызовом waveinaddbuffer.
                                                            Цитата
                                                            Можно ли в этом варианте написания программы "попросить" драйвер остановить запись в буфер при вызове OnWaveIn? Или сделать хоть что-нибудь, чтоб получить массив из 1024-16000 неискаженных точек.
                                                            Спасибо.

                                                            Драйвер невиновен. Он выбрасывает из очереди заполненный буфер, уведомляет вас о том, что вот этот конкретный буфер уже заполнен, и вычёркивает его "из своей памяти".
                                                            Хоть что-нибудь можно. Найти ошибку, и исправить.
                                                            Цитата
                                                            dwFlags := WHDR_DONE

                                                            Флаги должны быть "по нулям". Флагами, как правило, распоряжается драйвер.

                                                            Добавлено
                                                            Цитата
                                                            нашел в сети вариант работы с 2мя буферами.

                                                            Да зачем вам вариант? В StartButtonClick добавьте ещё один буфер в очередь и всё.
                                                            Цитата
                                                            Видимо мой обработчик довольно долгий

                                                            Видимо, где-то ошибка.
                                                              Цитата
                                                              Или, сделайте копию буфера в начале OnWaveIn и сравните оригинал и копию перед вызовом waveinaddbuffer.

                                                              сделал и сравнил. Буфер в это время не меняется, даже sleep(100) вставлял в процедуру.
                                                                Вывод: в буфере ничего не "затирается".
                                                                Сообщение отредактировано: Prince -
                                                                  Переделал свою прг как вы советуете (добавил 2й буфер). Теперь стыков гораздо меньше, но они все равно проскакивают. Пока эту проблему решу анализом массива. Если стык есть - просто выюрасываем этот буфер и ждем следующего.
                                                                  Спасибо!
                                                                    Цитата
                                                                    Теперь стыков гораздо меньше, но они все равно проскакивают.

                                                                    Запишите сигнал в звуковом редакторе. Если в нём присуствуют "стыки", значит, на входе звуковой карты такой сигнал.
                                                                    Вставьте в OnwaveIn запись буферов в файл, и таким способом запишите звук из своей программы. Проанализируйте запись в том же редакторе, сравните.
                                                                    Лучше найти причину глюка, и если она програмная, переписать программу по-человечески, чем костыли для игнорирования глюка изобретать. Имхо.
                                                                      Длительность буфера какая?
                                                                        Ок. Сигнал был записан с помощью стандартной программы виндов "звукозапись", воспроизводилась через Винамп. Чтоб исключить возможную порчу звука Винампом сделано как вы советуете.
                                                                        Из OnWaveIn выброшено все, добавлена только запись в файл. Используем 2 буфера, звук подаем на вход микрофона, я в него дышал, чтоб низкую частоту получить)
                                                                        После быстренько накалякал программу чтения из ВАВа.
                                                                        Читаем то, что записали в файл - Оппа, стыки идут!
                                                                        Прикреплённый файлПрикреплённый файлtest.jpg (26 Кбайт, скачиваний: 691)
                                                                          Длительность (длина буфера) - 1024точки. Пробовал 2048 и т.д. до 16000 - не меняется ничего. Стык то есть, то нет. И если есть - то он обычно в начале буфера, со смещением 50-200 точек.
                                                                          Частоту дискретизации ставил от 4000 до 44100.
                                                                            Из опыта, длительность буфера должна быть не менее 100 - 200 мс, иначе будут потери в данных.
                                                                            Прикреплённый файлПрикреплённый файлwavein.rar (12,04 Кбайт, скачиваний: 324)
                                                                            Сообщение отредактировано: Prince -
                                                                              Цитата IvanB @
                                                                              Переделал под себя - не работает как надо. Видимо мой обработчик довольно долгий (выполняется преобразование Фурье, поиск в каждом канале сигнала "пиков", расчет фаз и вывод на экран) и буфер все равно успевает переполняться.

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

                                                                              А программа обработки, соответственно, должна либо искать последний готовый буфер в очереди, освобождая все прочие в первом варианте, либо по завершении обработки выставлять флаг готовности и ждать, пока обработчик выплюнет очередной буфер.
                                                                                Цитата
                                                                                Обработчик должен схватить буфер и либо скопировать его, скажем, в закольцованную очередь, либо выяснить, готов ли его кто обрабатывать, и если не готов - игнорировать.

                                                                                Зачем ещё одна очередь, если она уже есть.
                                                                                  andriano, так буфер в обработчике изначально находится в непотребном состоянии, с искажениями.
                                                                                  Только что проверил свою программу дома, на стационарном компе. Все работает как надо! Нет никаких наложений даже с одним буфером, при любой его длине (выставлял даже 256точек, 44100 дискретность).
                                                                                  Но не работает нормально на ноутбуке на работе и на ноутбуке в гараже (в гараже старенький Тошиба, на работе свежий Асер). Такие вот пироги :blink:
                                                                                    IvanB, вопрос, вероятно, не в том, стационарный комп или ноутбук, а в том, какой стоит звуковой чип и, соответственно, его возможности - что он делает аппаратно, а что перекладывает на процессор для программной обработки.

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

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

                                                                                    Добавлено
                                                                                    Цитата Prince @
                                                                                    Зачем ещё одна очередь, если она уже есть.

                                                                                    Затем, что вторая очередь не будет совпадать с первой.
                                                                                    Они будут по-разному обрабатываться и их элементы будут по-разному освобождаться.
                                                                                      Цитата
                                                                                      Затем, что вторая очередь не будет совпадать с первой.
                                                                                      Они будут по-разному обрабатываться и их элементы будут по-разному освобождаться.

                                                                                      Так зачем это нужно? Чем не устривает та очередь, что уже есть?
                                                                                        Цитата
                                                                                        выставлял даже 256точек, 44100 дискретность

                                                                                        Выставьте 256 точек(6 мс), 1024(23 мс), 2048(46 мс) и 4096(92 мс) и сравните загрузку процессора. Допустите, что ваша программа выполняется на старенькой машине, параллельно с другими задачами, тоже требующими процессорного времени.
                                                                                          Prince, исправил в своей программе "инициализацию" буферов, что-то связанное с выделением памяти. Сделал как у вас в WaveIn.
                                                                                          До этого было так
                                                                                          ExpandedWrap disabled
                                                                                            type BufHead1,BufHead2: TWaveHdr;
                                                                                                 adress:PWaveHdr;
                                                                                                 header: TWaveFormatEx;
                                                                                                 buf: pointer;
                                                                                             
                                                                                            СтартБаттонКлик
                                                                                            begin
                                                                                             with header do begin
                                                                                                              wFormatTag := WAVE_FORMAT_PCM;
                                                                                                              nChannels := 2;  { количество каналов }
                                                                                                              nSamplesPerSec := SpS; { частота }
                                                                                                              wBitsPerSample := 16; { 8 / 16 бит }
                                                                                                              nBlockAlign := nChannels * (wBitsPerSample div 8);
                                                                                                              nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
                                                                                                              cbSize := 0;
                                                                                                             end;
                                                                                             
                                                                                              WaveInOpen(Addr(WaveIn), WAVE_MAPPER, addr(header),Form1.Handle, 0, CALLBACK_WINDOW);
                                                                                              BufLen := header.nBlockAlign * BufSize;
                                                                                              hBuf := GlobalAlloc(GMEM_MOVEABLE and GMEM_SHARE, BufLen);
                                                                                              Buf := GlobalLock(hBuf);
                                                                                              with BufHead1 do begin
                                                                                                                lpData := Buf;
                                                                                                                dwBufferLength := BufLen;
                                                                                                                dwFlags := 0;//WHDR_DONE;//BEGINLOOP;
                                                                                                                dwLoops:=0;
                                                                                                              end;
                                                                                              adress:=@BufHead1;
                                                                                              with BufHead2 do begin
                                                                                                                lpData := Buf;
                                                                                                                dwBufferLength := BufLen;
                                                                                                                dwFlags := 0;//WHDR_DONE;//BEGINLOOP;
                                                                                                                dwLoops:=0;
                                                                                                              end;
                                                                                              WaveInPrepareHeader(WaveIn, Addr(BufHead1), sizeof(TWaveHdr));
                                                                                              WaveInPrepareHeader(WaveIn, Addr(BufHead2), sizeof(TWaveHdr));
                                                                                              WaveInAddBuffer(WaveIn, adress, sizeof(BufHead1));
                                                                                              WaveInStart(WaveIn);


                                                                                          Переделал в такое
                                                                                          ExpandedWrap disabled
                                                                                            with header do begin
                                                                                                              wFormatTag := WAVE_FORMAT_PCM;
                                                                                                              nChannels := 2;
                                                                                                              nSamplesPerSec := SpS;      
                                                                                                              wBitsPerSample := 16;                
                                                                                                              nBlockAlign := nChannels * (wBitsPerSample div 8);
                                                                                                              nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
                                                                                                              cbSize := 0;
                                                                                                             end;
                                                                                             
                                                                                            WaveInOpen(Addr(WaveIn), WAVE_MAPPER, addr(header),Form1.Handle, 0, CALLBACK_WINDOW);
                                                                                            BufLen := header.nBlockAlign * BufSize;
                                                                                             
                                                                                            adress:=allocmem(sizeof(TWAVEHDR));
                                                                                            adress.lpData := allocmem(BufLen);
                                                                                            adress.dwBufferLength := BufLen;
                                                                                            WaveInPrepareHeader(WaveIn, adress, sizeof(TWaveHdr));
                                                                                            WaveInAddBuffer(WaveIn, adress, sizeof(TWaveHdr));
                                                                                             
                                                                                            adress:=allocmem(sizeof(TWAVEHDR));
                                                                                            adress.lpData := allocmem(BufLen);
                                                                                            adress.dwBufferLength := BufLen;
                                                                                            WaveInPrepareHeader(WaveIn, adress, sizeof(TWaveHdr));
                                                                                            WaveInAddBuffer(WaveIn, adress, sizeof(TWaveHdr));
                                                                                             
                                                                                            WaveInStart(WaveIn);


                                                                                          Стало работать без ошибок! :good: Вечером еще на старом буке надо проверить.
                                                                                          Выделение буферов сейчас сделано как у вас в программе, здесь просто приведен пример того, что исправлено.

                                                                                          Спасибо!
                                                                                          зы: пока писал ответ, помоему понял ошибку. В первом случае я 1 раз выделил память (строки 21-22) и дальше писал по одному и тому же адресу 2 буфера.
                                                                                            Доброго!
                                                                                            Писать звук с 2х каналов научили :good: . Теперь хотелки выросли и нужно записать 4 канала на том же железе.
                                                                                            Имеем встроенную звуковую систему АС97 на чипе Alc201, т.е. 2х канальное стерео. АЦП имеет частоту дискретизации 48кГц и 4 пары каналов записи. Задача - получить 4х канальный сигнал с полезной частотой не превышающей 3кГц, синхронизированный во времени.
                                                                                            Идея следующая. Запрограммировать длину буфера весьма короткой (1, 2 или 4 отсчета). Получить от АЦП выборку 1й пары каналов, скинуть ее в буфер1. Потом переключить запись на другую пару каналов и получить выборку с нее, сбросить ее в буфер2. Получится ли таким образом записать "одновременно" 4 канала? Или потрачу много времени на переключение каналов?
                                                                                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                            0 пользователей:


                                                                                            Рейтинг@Mail.ru
                                                                                            [ Script execution time: 0,1271 ]   [ 24 queries used ]   [ Generated: 29.03.24, 13:46 GMT ]