На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania 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  все  ( Перейти к последнему сообщению )  
> Непрерывный поток звука
    Изучаю возможности программного вывода звука.
    С получением звука с микрофона вроде всё нормально, а вот вывод ни к чёрту.)
    Маленький кусок кода:

    ExpandedWrap disabled
      unit U4_1;
      interface
      uses
        Windows, Math, Messages, Classes, Forms, MMSystem;
      const
          discret = 8000;
          SizeBufOut = 400;
      type
        TForm1 = class(TForm)
          procedure FormCreate(Sender: TObject);
        public
          procedure WCard;
        end;
      var
         hMapFile:THandle;
         lpBaseAddress:PChar;
         Vdata: array [0..SizeBufOut-1] of integer;
          Form1: TForm1;
          WaveFormatEx: TWaveFormatEx;
          WaveOut:HWAVEOUT;
          hEvent: THandle;
          woh: WAVEHDR;
          Bits16: boolean;
          hBuf: THandle;
          BufHead: TWaveHdr;
      implementation
      {$R *.dfm}
       
      procedure TForm1.FormCreate(Sender: TObject);
      begin
          WCard;
      end;
       
      procedure TForm1.WCard;
      var
        BufLen: word;
        buf: pointer;
        n: word;
        begin
          bits16 := True;
          with WaveFormatEx do
          begin
            wFormatTag := WAVE_FORMAT_PCM;
            nChannels := 1;
            nSamplesPerSec := discret;
            wBitsPerSample := integer(Bits16) * 8 + 8;
            nBlockAlign := nChannels * (wBitsPerSample div 8);
            nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
          end;
          hEvent := CreateEvent(nil, false, false, nil);
          WaveOutOpen(Addr(WaveOut), 0, addr(WaveFormatEx), hEvent, 0,CALLBACK_EVENT);
          for n:=0 to SizeBufOut-1 do Vdata[n]:=RandomRange(1,1000);
          BufLen := WaveFormatEx.nBlockAlign * SizeBufOut;
          with BufHead do
          begin
            woh.lpData := addr(Vdata);
            woh.dwBufferLength := BufLen;
          end;
            waveOutPrepareHeader(WaveOut, addr(woh), sizeof(woh));
            waveOutWrite(WaveOut, addr(woh), sizeof(woh));
        end;
       
      end.

    Вроде звук одного блока получил, а вот как его зациклить (для начала), чтобы это был единый поток не получается.
      Цитата Ivan123 @
      чтобы это был единый поток не получается.

      Вопрос решён
        Вот что получилось кому интересно

        ExpandedWrap disabled
          unit U7_1;
           
          interface
           
          uses
            Windows, Math, Messages, Classes, Forms, MMSystem;
          procedure Execute;
          const
              discret = 8000;
              SizeBufOut = 400;
              MMFName: pAnsiChar = 'MP';
              a=0;
           
          type
            TForm1 = class(TForm)
              procedure FormCreate(Sender: TObject);
            public
              procedure WCard;
            end;
           
          var
              hMapFile:THandle;
              lpBaseAddress:PChar;
              Vdata: array [0..SizeBufOut-1] of smallint;
           
              Form1: TForm1;
              WaveFormatEx: TWaveFormatEx;
              WaveOut:HWAVEOUT;
              hEvent: THandle;
              woh: WAVEHDR;
              BufHead: TWaveHdr;
              n: word;
           
          implementation
           
          {$R *.dfm}
           
          procedure TForm1.FormCreate(Sender: TObject);
          begin
              WCard;
              Execute;
          end;
           
          procedure TForm1.WCard;
          var
            BufLen: word;
            n: word;
           
            begin
              with WaveFormatEx do
              begin
                wFormatTag := WAVE_FORMAT_PCM;
                nChannels := 1;
                nSamplesPerSec := discret;
                wBitsPerSample := 16;
                nBlockAlign := nChannels * (wBitsPerSample div 8);
              end;
           
              hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS,False,MMFName);
              lpBaseAddress := MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1);
           
              hEvent := CreateEvent(nil, false, false, nil);
              WaveOutOpen(Addr(WaveOut), 0, addr(WaveFormatEx), hEvent, 0,CALLBACK_EVENT);
              waveOutPrepareHeader(WaveOut, addr(woh),SizeOf(woh));
              BufLen := WaveFormatEx.nBlockAlign * SizeBufOut;
              with BufHead do
                begin
                  woh.lpData := addr(Vdata);
                  woh.dwBufferLength := BufLen;
                end;
            end;
           
          procedure Execute;
            begin
              while a<1 do
                begin;
                  //CopyMemory(addr(Vdata), lpBaseAddress, SizeBufOut*2);
                  for n:=0 to SizeBufOut-1 do Vdata[n]:=RandomRange(1,32000);
                  waveOutWrite(WaveOut, addr(woh), SizeOf(woh));
                  waveOutReset(WaveOut);
                end;
            end;
           
          end.

        Прикреплённый файлПрикреплённый файлDF9.rar (171,62 Кбайт, скачиваний: 10)
          ExpandedWrap disabled
            type
              TForm1 = class(TForm)
                procedure FormCreate(Sender: TObject);
                procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
              private
                { Private declarations }
              public
                { Public declarations }
              end;
             
              const
                discret     = 8000;
                SizeBufOut  = 400;
                bufcount    = 3;
                play        = 1;
                stop        = 0;
             
            var
               Form1        : TForm1;
               WaveOut      : HWAVEOUT;
               mode         : integer;
               actbufcount  : cardinal;
             
            implementation
             
            {$R *.dfm}
             
            Procedure FillBuf(var buf);
              var
                ps  : psmallint;
                i   : cardinal;
             
            begin
              ps:=pointer(buf);
              for i:=0 to sizebufout-1 do
                begin
                  ps^:=Random(32000)-16000;
                  inc(ps);
                end;
             
            end;
             
            procedure waveOutProc( hwo:HWAVEOUT; uMsg,dwinstance,dwParam1,dwParam2:dword);stdcall;
            Begin
              case umsg of
                WOM_OPEN:;
                WOM_CLOSE:;
                WOM_DONE:
                    if mode<>stop
                           then
                            begin
                              fillbuf(PWaveHdr(dwParam1)^.lpData);
                              waveoutwrite(waveout,PWaveHdr(dwParam1),sizeof(TwaveHdr));
                            end
                            else
                            begin
                              waveoutunprepareheader(waveout,PWaveHdr(dwParam1),sizeof(TwaveHdr));
                              freemem(PWaveHdr(dwParam1)^.lpData);
                              freemem(PWaveHdr(dwParam1));
                              dec(actbufcount);
                            end;
              end;
            End;
             
            procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
            begin
            mode:=stop;
               repeat
                until actbufcount=0;
              waveoutclose(waveout);
              canclose:=true;
            end;
             
            procedure TForm1.FormCreate(Sender: TObject);
             
              var
                  fmt   : TWaveFormatEx;
                  pwhdr : PWaveHdr;
                  i     : cardinal;
             
            begin
              mode:=stop;
              actbufcount:=0;
                with fmt do
                begin
                  wFormatTag      := WAVE_FORMAT_PCM;
                  nChannels       := 1;
                  nSamplesPerSec  := discret;
                  wBitsPerSample  := 16;
                  nBlockAlign     := nChannels * (wBitsPerSample div 8);
                  nAvgBytesPerSec :=nBlockAlign*nSamplesPerSec;
                  cbsize          :=0;
                end;
             
                WaveOutOpen(@WaveOut, 0, @fmt, dword(@waveoutproc), 0,CALLBACK_FUNCTION);
                WaveOutPause(WaveOut);
             
             for i:=0 to bufcount-1 do
              begin
                pwhdr:=allocmem(sizeof(TWaveHdr));
                pwhdr.lpData:=allocmem(SizeBufOut*fmt.nBlockAlign);
                pwhdr.dwBufferLength:= SizeBufOut*fmt.nBlockAlign;
                waveOutPrepareHeader(WaveOut, pwhdr,SizeOf(TWaveHdr));
                fillbuf(pwhdr.lpData);
                waveoutwrite(waveout,pwhdr,sizeof(TwaveHdr));
                inc(actbufcount);
              end;
              mode:=play;
              waveoutrestart(waveout);
             
              //
            end;
          Человек человека понять не может.
            Спасибо за пример, наверно так профессионально.
            Я писал просто чтобы получить хоть какой положительный результат) у вас это произведение, учиться никогда не поздно.
              Пример самый обычный, для песочницы, для теста, для проверки идеи. Как один из возможных вариантов. Ваш пример совсем нехорош. Он не решает задачу, не обеспечивает непрерывность звукового потока.
              Человек человека понять не может.
                Цитата Ivan123 @
                не обеспечивает непрерывность звукового потока

                Согласен, но на тот момент задача стояла услышать программно любой звук, да и функции мультимедия я видел впервые, так что я только учусь и спасибо за помощь)
                  Цитата Prince @
                  Как один из возможных вариантов

                  Ещё один вопрос про ещё один вариант.
                  А как этот кусок будет выглядеть для консоли? К сожалению из консоли у меня никак не получается добраться до аудио буфера.
                  Или может какую литературу подскажите по теме?
                    Литература в FAQ раздела. Рекомендую книги Секунова и Кинтцеля.
                    Консольный вариант будет аналогичным. В консольном приложении сначала выполните код из метода create, потом будет пустой цикл, с выходом по нажатию клавиши, а за ним то, что в closequery.
                    Сообщение отредактировано: Prince -
                    Человек человека понять не может.
                      Цитата Prince @
                      bufcount = 3;

                      1. Можете пояснить зачем нужен этот цикл, и почему 3, не 1, не 4 и тд?

                      Если я правильно понимаю, чтобы просто разделить процесс записи в буфер и процесс воспроизведения из буфера, но тогда почему 3, а не 2?

                      2. И каков максимальный размер блока аудиоданных? Или для каждого устройства он разный и его надо предварительно определять? и сколько таких блоков (вернее какой суммарный объём байтов) можно запихнуть в этот буфер?
                      Сообщение отредактировано: Ivan123 -
                        1. Минимум необходимы 2 буфера, для обеспечения непрерывности звука. Они же могут быть и достаточны. Я выбрал 3, мне так больше нравится. Максимум...любое вменяемое количество, но ограниченное объемом памяти. 100500 - бессмысленно.

                        2. Максимальный размер блока [может быть] ограничен объемом памяти, организацией памяти, драйвером, разрядностью DWORD(?)... не проверял, потому как смысла нет.

                        Буфер - он же и есть блок данных. Размер выбираете сами. Снизу размер/длительность ограничены быстродействием железа и многопоточностью винды(разрешением системного таймера, например), сверху - объемом памяти.
                        На практике примерно 20 мс минимум, если повезет. Надежней 50 мс. Совсем хорошо - 100 мс. Зависит от задачи. Верхний предел 200-1000 мс. Можно больше, зависит от задачи.

                        Читайте литературу. Когда поймете принцип работы с блоками, размеры и количества встанут на свои места. Для них нет однозначных жестких ограничений. За исключением, пожалуй, минимального количества блоков. Хотя и это ограничение можно обойти. Но тогда потеряется простота работы с ними. Точнее, один буфер противоречит самой логике работы интерфейса.
                        Сообщение отредактировано: Prince -
                        Человек человека понять не может.
                          Я бы поставил штуки 4 общим объёмом в секунду, чтоб не париться, что называется (для надёжности).
                          По 50 мс как-то маловато (по мне), мало ли подвиснет система на десятые доли секунды.
                          Хотя вон ASIO работает по 32 семпла (1.5 мсек) и ничего, не глючит, а 64 – вообще огонь (хотя, там технология другая, тут буферы по 64 семпла вряд ли будут нормально звучать) :)
                          Тут действительно кто во что горазд и какие задачи. Может, у вас там целая эпопея делается длительностью в полсекунды перед чтением очередного блока :rolleyes:
                          vpmultishiftqb vscatterpf0dps vfmsubadd132pd vgatherpf1dps vpclmulhqlqdq vcmptrue_ussd vaeskeygenassist
                            Цитата Prince @
                            Минимум необходимы 2 буфера

                            Переписал свой код для захвата звука под консоль и с учётом ваших рекомендаций по структуре вывода белого шума (расположен выше)

                            ExpandedWrap disabled
                              procedure FillBuf(var buf);
                              var
                                ps      : psmallint;
                                i       : cardinal;
                              begin
                                ps:=pointer(buf);
                                for i:=0 to SizeBufIn-1 do
                                  begin
                                    ps^:=PData16(pwhdr.lpData)^[i];
                                    Vdata[i]:=ps^;
                                    inc(ps);
                                  end;
                              end;
                               
                               
                              procedure waveInProc( hwo:HWAVEIN; uMsg, dwinstance, dwParam1, dwParam2:dword); stdcall;
                              begin
                                if uMsg = WIM_DATA then
                                  begin
                                    fillbuf(PWaveHdr(dwParam1)^.lpData);
                                    WaveInAddBuffer(waveIn,PWaveHdr(dwParam1),sizeof(TwaveHdr));
                                  end;
                              end;
                               
                              procedure Create;
                              var
                                fmt   : TWaveFormatEx;
                                a,i   : cardinal;
                                buf   : psmallint;
                               
                              begin
                                  with fmt do
                                    begin
                                      wFormatTag      := WAVE_FORMAT_PCM;
                                      nChannels       := 1;
                                      nSamplesPerSec  := discret;
                                      wBitsPerSample  := 16;
                                      nBlockAlign     := nChannels * (wBitsPerSample div 8);
                                      nAvgBytesPerSec :=nBlockAlign * nSamplesPerSec;
                                    end;
                               
                               
                                  WaveInOpen(@WaveIn, WAVE_MAPPER, @fmt, dword(@waveInProc), 0, CALLBACK_FUNCTION);
                               
                                  for i:=0 to bufcount-1 do
                                    begin
                                      pwhdr:=allocmem(sizeof(TWaveHdr));
                                      pwhdr.lpData:=allocmem(SizeBufIn * fmt.nBlockAlign);
                                      pwhdr.dwBufferLength:= SizeBufIn * fmt.nBlockAlign;
                                      pwhdr.dwBytesRecorded:=0;
                                      pwhdr.dwFlags:= 0;
                                      WaveInPrepareHeader(WaveIn, pwhdr, SizeOf(TWaveHdr));
                                      fillbuf(pwhdr.lpData);
                                      WaveInAddBuffer(waveIn, pwhdr, sizeof(TwaveHdr));
                                    end;
                                  WaveInStart(WaveIn);
                                  a:=0;
                                  Repeat
                                    FillBuf(buf);
                                  until
                                    a > 0;
                              end;


                            И здесь у меня возникло два вопроса:
                            1. почему то у меня не получается организовать 2 буфера, вернее получается , но при первом цикле первый заполняется не полностью, а в последующем данные дублируются и во второй буфер. При bufcount=1 всё получается красиво с данными, но скорее всего это будет не непрерывный сигнал.
                            2. Вопрос касается другой темы, где я решал вопрос с микшером. Можно ли убить отправку данных на драйвер в этом коде каким нибудь хитрым способом, например заполнив перед WaveInAddBuffer буфер нулями.
                            Сообщение отредактировано: Ivan123 -
                              Цитата Ivan123 @
                              Переписал свой код для захвата звука под консоль и с учётом ваших рекомендаций по структуре вывода белого шума

                              Белый шум по определению так устроен, что на нём не будут заметны никакие сбои, он плохо подходит для тестирования непрерывного воспроизведения.
                                Что вы хотите получить в итоге. Куда сливается аудиопоток? В vdata...а дальше?
                                ExpandedWrap disabled
                                  procedure FillBuf(var buf);
                                  var
                                    ps      : psmallint;
                                    i       : cardinal;
                                  begin
                                    ps:=pointer(buf);
                                    for i:=0 to SizeBufIn-1 do
                                      begin
                                        ps^:=PData16(pwhdr.lpData)^[i]; //что оно должно делать??????
                                        Vdata[i]:=ps^;
                                        inc(ps);

                                Если вам нужно (для чего-то) переписать буфер в другой массив, используйте функцию Move;


                                ExpandedWrap disabled
                                   WaveInPrepareHeader(WaveIn, pwhdr, SizeOf(TWaveHdr));
                                          fillbuf(pwhdr.lpData);
                                          WaveInAddBuffer(waveIn, pwhdr, sizeof(TwaveHdr));

                                fillbuf здесь не к месту. Буфер ещё не заполнен данными аудио. Там пока нули, поскольку память выделялась через allocmem. Если бы память выделялась как-то иначе, возможно, был бы мусор. Но там еще нет аудио. Аудио ловится только в waveinproc по WIM_DATA и нигде больше.

                                Цитата
                                a:=0;
                                Repeat
                                FillBuf(buf);
                                until
                                a > 0;

                                Это вообще ерунда какая-то.
                                ExpandedWrap disabled
                                  readln;

                                заменит эту конструкцию. fillbuf снова не в тему, на выходе приложения черте-что окажется вместо непрерывного аудио потока.

                                Код неполный, но и так видно, что он работает неправильно.
                                Сообщение отредактировано: Prince -
                                Человек человека понять не может.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) [1] 2 3  все


                                Рейтинг@Mail.ru
                                [ Script Execution time: 0,1524 ]   [ 16 queries used ]   [ Generated: 21.03.19, 06:15 GMT ]