Проблема при программировании звука

Тема в разделе "WASM.ELECTRONICS", создана пользователем Aids, 20 апр 2008.

  1. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    Мне надо на выходе аудиокарты получить сигнал синусоидильной формы. При передаче блоков данных, мезду ними образуется пауза. Как эту паузу сделать минимальной?
     
  2. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    Вот мой код:
    .....
    hEvent:=CreateEvent(nil,false,false,nil);
    fmt.wFormatTag:=WAVE_FORMAT_PCM;
    fmt.nChannels:=1;
    fmt.nSamplesPerSec:=df;
    fmt.nAvgBytesPerSec:=df;
    fmt.nBlockAlign:=1;
    fmt.wBitsPerSample:=8;
    fmt.cbSize:=0;
    waveOutOpen( @hSound,0,@fmt,hEvent,0,CALLBACK_EVENT);
    p:=pData;
    for i:=0 to dF*MaxTimer-1 do
    begin
    p^:=128+Floor(A*sin(2*pi*Hz/df*i));
    inc(p);
    end;
    ....
    pHeader.lpData:=pData;
    pHeader.dwBufferLength:=MaxTimer*df;
    pHeader.dwFlags := 0;
    pHeader.dwLoops := 0;
    pHeader.dwBytesRecorded:=0;
    pHeader.lpNext:=nil;
    waveOutPrepareHeader( hSound, pHeader,sizeof(WAVEHDR));
    //первый блок данных
    ResetEvent(hEvent);
    waveOutWrite(hSound, pHeader,sizeof(WAVEHDR) );
    WaitForSingleObject(hEvent,Infinite);
    //второй блок данных
    ResetEvent(hEvent);
    waveOutWrite(hSound, pHeader,sizeof(WAVEHDR) );
    WaitForSingleObject(hEvent,Infinite);
     
  3. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    А вообще есть возможность избавиться от паузы в пользоваетильском режиме? Или придётся взаимодействовать напрямую с дровами?
     
  4. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    Кто-нибудь знает как поставить выходные буфферы в очередь? для этого надо правиль сконфигурировать в структуре WAVEHDR параметры dwFlags и
    dwLoops если я правильно понимяю?!
     
  5. VaStaNi

    VaStaNi Member

    Публикаций:
    0
    Регистрация:
    1 июн 2004
    Сообщения:
    203
    Адрес:
    Ukraine
    вообще такую программу встечал готовую и кажется с исходниками... только вот где?...(
    А что если событие твое с большим приоритетом сделать? Ведь паузы - ввиду переключения задач винда дает скорее всего. Т.е. ты real-time хочешь сделать там где его нет, значит надо заствить ее НЕ прерываться на...
     
  6. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Может я чего не понял? Но у МС есть либа такая ДиректСаунд начиная с самых первых директХ. СДК поставляется с доками и примерами, немного перелепив какой попроще вы получите то, что хотели.
     
  7. Novi4ek

    Novi4ek New Member

    Публикаций:
    0
    Регистрация:
    3 авг 2007
    Сообщения:
    317
    Задержка там восновном из-за переписывания данных из буфера в буфер, смешивания, проталкивания по стеку драйверов вниз.

    Еще один момент, я себе плохо представляю вклад в неаккуратность сигнала, но наверно еще стоит согласовывать конец и начало синусоиды, чтобы не было скачка фазы во время подачи нового буфера.
     
  8. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Все это легко решается директСоундом
     
  9. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    все проблему решил. Надо просто сформировать очередь буферов.
    ....
    fmt.wFormatTag:=WAVE_FORMAT_PCM;
    fmt.nChannels:=1;
    fmt.nSamplesPerSec:=df;
    fmt.nAvgBytesPerSec:=dF;
    fmt.nBlockAlign:=1;
    fmt.wBitsPerSample:=8;
    fmt.cbSize:=0;
    waveOutOpen(@hSound,WAVE_MAPPER,@fmt,Form1.Handle,0,CALLBACK_WINDOW);
    //первый буффер
    Header1.lpData:=pData1;
    Header1.dwBufferLength:=BufSize;
    Header1.dwFlags:=WHDR_BEGINLOOP; //флаг начала
    Header1.dwLoops:=0;
    waveOutPrepareHeader(hSound,@Header1,SIZEof(Header1));
    waveOutWrite(hSound,@Header1,sizeof(Header1));
    //второй буффер
    Header2.lpData:=pData2;
    Header2.dwBufferLength:=BufSize;
    Header2.dwFlags:=WHDR_DONE; // флаг продолжения
    Header2.dwLoops:=0;
    waveOutPrepareHeader(hSound,@Header2,SIZEof(Header2));
    waveOutWrite(hSound,@Header2,sizeof(Header2));

    и добавляю вновь и вновь с помощью обработчика события
    ....
    procedure TForm1.MyProc;
    begin
    // ShowMessage('Yes');
    if f then
    begin
    f:=false;
    waveOutUnprepareHeader(hSound,@Header1,sizeof(Header1));
    Header1.lpData:=pData1;
    Header1.dwBufferLength:=BufSize;
    Header1.dwFlags:=WHDR_DONE;
    Header1.dwLoops:=0;
    waveOutPrepareHeader(hSound,@Header1,SIZEof(Header1));
    waveOutWrite(hSound,@Header1,sizeof(Header1));
    end
    else
    begin
    f:=true;
    waveOutUnprepareHeader(hSound,@Header2,sizeof(Header2));
    Header2.lpData:=pData2;
    Header2.dwBufferLength:=BufSize;
    Header2.dwFlags:=WHDR_DONE;
    Header2.dwLoops:=0;
    waveOutPrepareHeader(hSound,@Header2,SIZEof(Header2));
    waveOutWrite(hSound,@Header2,sizeof(Header2));
    end;
    end;

    И ни какой паузы
     
  10. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    По совету Novi4ek пробовал фазу коректировать. На слух ничего не замечаю.
     
  11. Aids

    Aids New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2007
    Сообщения:
    275
    _basmp_
    Ты имеешь в виду работать напрямую со звуковой картой?
     
  12. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Нет. Читайте доку на дирСнд. Впрочем.. С директСоундом дело давно не имел. Потому только шаблон. Дальше книжки, дока, сорцы, эксперименты.
    - получаем первичный звуковой буфер.
    - на каждый отдельный звук выделяем по вторичному буферу.
    - пишем во вторичный буффер выборки.
    - создаем событие по которому дописывать будете
    - запускаем на выполнение, указав событие и указав, чтоб вызывало, когда проиграет пол-буфера
    - ждем событие
    - узнаем какая половина буфера освободилась. Блокируем и переписываем ее. Разблокируем.
    Если быстродействия не хватит (скажем 486 + сложные вычисления/перерисовки), пускаем в отдельном потоке.

    ЗЫ возможно я что-то напутал. Загляните в доку.