На главную

Библиотека Интернет Индустрии I2R.ru

Rambler's Top100

Малобюджетные сайты...

Продвижение веб-сайта...

Контент и авторское право...

Забобрить эту страницу! Забобрить! Блог Библиотека Сайтостроительства на toodoo
  Поиск:   
Рассылки для занятых...»
I2R » И2Р Программы » Программирование » Delphi и Pascal

О программировании звуковых плат Sound Blaster 16 в режиме full duplex

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

Но естественно, ЭВМ постоянно совершенствовались, и потому к моменту появления ПК клавиатура и дисплей воспринимались всеми как вполне стандартные устройства ввода-вывода. Не был забыт и звук. В дисплейный блок или клавиатуру, подключаемую к главной ЭВМ, как правило, встраивался маленький динамик, издававший всякие гудки, щелчки, а порой и что-то более сложное. Терминалом большой ЭВМ и руководствовались при создании ПК.

С самого начала IBM PC не повезло со звуком. К сожалению, фирма-разработчик решила, что ее детище будет предназначено исключительно для делового применения. Поэтому при достаточно высокой производительности (16-разрядный процессор) и широких графических возможностях (цветной графический дисплей) этот ПК не только не превосходил, но зачастую и уступал по звучанию своим 8-разрядным собратьям. Его одноразрядный звук использовался в основном лишь для сигнализации о неисправностях аппаратуры или об ошибках оператора.

Однако IBM PC имел открытую архитектуру, и как только звук понадобился (сначала для игр), сразу была создана отдельная аудиоплата, вставляемая в разъем расширения. Такие устройства (Game Blaster фирмы Adlib) умели синтезировать несложный музыкальный звук, но с появлением Sound Blaster стало возможным записывать на IBM-совместимом компьютере и воспроизводить монофонический звук, хотя лишь 8-разрядный. Позднее появились платы, обеспечивающие стереофоническое звучание, а затем и использующиеся для оцифровки 16 разрядов. Правда, если первые звуковые платы старались сделать совместимыми сначала с Creative Sound Blaster, а затем с Creative Sound Blaster Pro (8-разрядные моно- и стереоплаты соответственно), то после перехода на 16-разрядный звук каждый разработчик пошел своим путем.

Что-то похожее происходило позже и с видеоадаптерами. Пока законодателем мод в области ПК считалась IBM, существовали и стандарты де-факто на видеоадаптеры: сначала был CGA, потом EGA, на смену которому пришел VGA... Однако когда IBM уступила лидерство, на рынке ПК появилась масса видеоплат, объединяемых общим названием SuperVGA (SVGA), но совершенно несовместимых друг с другом.

Обратимся снова к аудиоплатам. К тому времени как наметился переход с 8- на 16-разрядный звук, фирма Creative Labs, пионер в области разработки аудиоплат, перестала играть на рынке доминирующую роль. Да и старания производителей защититься от конкурентов путем патентования всех новшеств явно не способствовали формированию нового стандарта де-факто. Но если в области видеоадаптеров благодаря усилиям ассоциации VESA удалось навести хоть какой-то порядок, то с аудиоплатами подобная идея была обречена на провал. Звуковые платы, в отличие от видеоадаптеров, не имеют ПЗУ с драйверами, позволяющими нивелировать особенности аппаратуры и создавать более или менее унифицированный интерфейс с прикладными программами. Да и сама поддержка звука на уровне BIOS не была предусмотрена конструкторами IBM. Все это привело к тому, что до сих пор не появился стандарт на 16-разрядный звук, и послужило, пожалуй, одной из главных причин отказа от DOS в качестве основной платформы для компьютерных игр и перехода на Windows+DirectX.

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

Таблица 1. Регистры микшера
индекс D7 D6 D5 D4 D3 D2 D1 D0
00h Сброс микшера
04h Громкость FM-синтезатора ЛК Громкость FM-синтезатора ПК
0Ah - Громкость микрофона
22h Общий регулятор громкости ЛК Общий регулятор громкости ПК
26h Громкость MIDI ЛК Громкость MIDI ПК
28h Громкость CD ЛК Громкость CD ПК
2Eh Громкость линейного входа ЛК Громкость линейного входа ПК
30h Общий регулятор громкости ЛК -
31h Общий регулятор громкости ПК -
32h Громкость FM-синтезатора ЛК -
33h Громкость FM-синтезатора ПК -
34h Громкость MIDI ЛК -
35h Громкость MIDI ПК -
36h Громкость CD ЛК -
37h Громкость CD ПК -
38h Громкость линейного входа ЛК -
39h Громкость линейного входа ПК -
3Ah Громкость микрофона -
3Bh Громкость динамика -  
3Ch - - - Лин. ЛК (1) Лин. ПК (1) CD ЛК (1) CD ПК (1) Микр. (1)
3Dh - MIDI ЛК (2) MIDI ПК (2) Лин. ЛК (2) Лин. ПК (2) CD ЛК (2) CD ПК (2) Микр.(2)
3Eh - MIDI ЛК (3) MIDI ПК (3) Лин. ЛК (3) Лин. ПК (3) CD ЛК (3) CD ПК (3) Микр.(3)
3Fh Входной аттенюатор ЛК -
40h Входной аттенюатор ПК -
41h Выходной аттенюатор ЛК -
42h Выходной аттенюатор ПК -
43h - АРУ
44h Тембр высоких частот ЛК -
45h Тембр высоких частот ПК -
46h Тембр низких частот ЛК -
47h Тембр низких частот ПК -
Сокращения: ЛК - левый канал, ПК - правый канал, (1) - выходные выключатели микшера, (2) - входные выключатели левого канала микшера, (3) - входные выключатели правого канала микшера, АРУ - включение автоматической регулировки уровня сигнала микрофона.

Таблица 2. Регистры 0Bh и D6h контроллера DMA

Номер бита

Назначение

Значение

D0-D1 Номер канала DMA 0-3 (для 4-7 - два младших бита)
D2-D3 Режим работы 00 - проверка;
01 - запись в память;
10 - чтение из памяти;
11 - недопустимая комбинация
D4 Автоинициализация 0 - нет;
1 - есть
D5 Направление изменения адреса 0 - увеличение;
1 - уменьшение
D6-D7 Тип передачи 00 - по требованию;
01 - одиночная передача;
0 - блочная передача;
11 - каскадный режим

Когда фирма Creative Labs разрабатывала свою первую 16-разрядную плату Sound Blaster 16, она, видимо, и не предполагала, что эту аудиоплату можно будет использовать одновременно и для записи, и для воспроизведения звука (работа в так называемом режиме full duplex). Наверное, именно поэтому данный режим не поддерживается и в драйверах для Windows. Однако его можно запрограммировать в DOS. Правда, передача в таком случае получается несколько несимметричной: в одном направлении звук будет 16-, а в другом - 8-разрядным. Впрочем, вряд ли это серьезно ограничивает реальные применения подобной технологии. При использовании ПК для общения "как по телефону" 8-разрядного звука вполне достаточно, а при записи и сведении фонограммы одновременно с 16-разрядным режимом записи можно обойтись контрольным прослушиванием всего в 8 разрядов. Когда же ПК играет роль измерительного прибора, а звуковая плата - дешевых ЦАП/АЦП, разрядности получаемого сигнала обычно бывает достаточно, по крайней мере в одну сторону. В противном случае следует заменить звуковую плату специализированным прибором. Правда, такая несимметричность затрудняет использование ПК в качестве гитарного процессора, ревербератора или эквалайзера, но вообще-то для концертной деятельности компьютер не слишком подходит.

*   *   *

Программа, иллюстрирующая, каким образом можно применять звуковую плату Creative Labs Sound Blaster 16 или совместимые с ней, например AWE32, приведена в листинге 1. Она реализует простейшее эхо: записанный через микрофон звук спустя некоторое время воспроизводится через громкоговорители, подключенные к выходу аудиоплаты.

Листинг 1. Простейшее цифровое эхо

program echo;

uses dsp_dma,getsbinf;

{Ввод звука - 16 бит со знаком, вывод - 8 бит со знаком.}

const

   BufSize   = 2*1024;              { размер буфера DMA }

   TimeConst = 156;             { 156 - примерно 10 кГц }

   HalfBufToFill  : integer = 0;

                 { которая половина буфера DMA свободна }

   BothBuf        : byte    = 0;

                   { индикатор заполнения обоих буферов }

type

   RecBufType  = array[0..BufSize-1]of integer;

                                { для буфера DMA записи }

   PlayBufType = array[0..BufSize-1]of shortint;

                       { для буфера DMA воспроизведения }

var

   RecBuf  : ^RecBufType;         { буфер DMA для записи}

   PlayBuf : ^PlayBufType;{буфер DMA для воспроизведения}

   inpage,   outpage   : word; {страницы для буферов DMA}

   inoffset, outoffset : word; {смещения для буферов DMA}



procedure SBint;interrupt;

                {обработчик прерывания от звуковой платы}

var

   intstat : integer;

   i : integer;

begin

   Port[base + $04] := $82;

          {проверяем, по какому каналу пришло прерывание}

   intstat := Port[base + $05] and 3;

   BothBuf := BothBuf or intstat;

   if (intstat and 2 <> 0) then begin  {16-битовый канал}

      i := Port[base + $0F];

   end;

   if (intstat and 1 <> 0) then begin {8-битовый канал}

      i := Port[base + $0E];

   end;

   if BothBuf = 3 then begin

                {если прошли прерывания от обоих каналов}

      for i := 0 to BufSize div 2 - 1 do

         PlayBuf^[HalfBufToFill*BufSize div 2 + i] :=

            hi(RecBuf^[HalfBufToFill*BufSize div 2 + i]);

      write(HalfBufToFill,#8);

                {выводим на экран номер половинки буфера}

      HalfBufToFill := HalfBufToFill xor 1;

      BothBuf := 0;

   end;

   if (irq > 8) then

  {для  IRQ 10, посылаем сигнал EOI во второй контроллер}

      Port[$A0] := $20;

   Port[$20] := $20;  { посылаем EOI в первый контроллер}

end;



var

   SkipLength : longint;

           {размер памяти до границы 64-Кбайт страницы}

   SkipBlock  : pointer;

begin

   writeln('               Эхо - Sound Blaster 16 в ',

                                   'режиме full duplex');

   writeln('                   для завершения работы ',

                                        'нажмите Enter');

   GetBlasterInfo;     {определяем характеристики карты}

   if (cardtype <> 6) then begin

            {Проверка, что на плате возможен full duplex}

      writeln(cardtype);

      writeln(

     'Для работы программы необходим Sound Blaster 16.');

      halt;

   end;

   if (dma8 = dma16) then begin

      writeln('Ошибка: совпадение 8-битового и ',

                              '16-битового каналов DMA.');

      halt;

   end;

   SetMixer; {сброс DMAC и установки микшера}

   getmem(SkipBlock,16);

       {проверка, чтобы буферы не пересекали границу 64К}

   SkipLength := $10000 - (seg(SkipBlock^) shl 4)

                                       - ofs(SkipBlock^);

   freemem(SkipBlock,16);

   if SkipLength > 3*BufSize then

      getmem(SkipBlock,SkipLength);

   getmem(RecBuf,2*BufSize);

                     {выделение памяти для буфера записи}

   inpage   := ((longint(seg(RecBuf^)) * 16)

                              + ofs(RecBuf^)) div $10000;

   inoffset := ((longint(seg(RecBuf^)) * 16)

                               + ofs(RecBuf^)) and $FFFF;

   getmem(PlayBuf,BufSize);

            {выделение памяти для буфера воспроизведения}

   outpage   := ((longint(seg(PlayBuf^)) * 16)

                             + ofs(PlayBuf^)) div $10000;

   outoffset := ((longint(seg(PlayBuf^)) * 16)

                              + ofs(PlayBuf^)) and $FFFF;

   fillchar(PlayBuf^,BufSize,0);

                         {очистка буфера воспроизведения}

   EnableInterrupt( @SBint);

   SetupDMA(dma16,inpage,inoffset,BufSize, $54);

                                            {DMA на ввод}

   SetupDSP($BE,$10,BufSize div 2,TimeConst);

                             {16 бит со знаком FIFO моно}

   SetupDMA(dma8,outpage,outoffset,BufSize, $58);

                                           {DMA на вывод}

   SetupDSP($C6,$10,BufSize div 2,TimeConst);

                              {8 бит со знаком FIFO моно}

   readln;

   dspout($D5); {приостанавливаем 16-битовый ввод-вывод}

   dspout($D0); {приостанавливаем 8-битовый ввод-вывод}

   DisableInterrupt;

   freemem(PlayBuf,BufSize);

   freemem(RecBuf,2*BufSize);

   if SkipLength < 3*BufSize then

      freemem(SkipBlock,SkipLength);

end. 

Сначала необходимо убедиться, что звуковая плата способна работать в режиме full duplex. Проще (и безопаснее) всего это сделать с помощью переменной окружения 'BLASTER'. Подобным способом следует определить и базовый адрес порта ввода-вывода, а также номера используемых IRQ и канала DMA. Программа, выполняющая разбор переменной окружения, приведена в листинге 2. Плата должна быть 6-го типа, а номера 8- и 16-разрядного каналов DMA - различаться.

Листинг 2. Извлечение данных из переменной окружения

unit GetSBInf;

interface

var

   base          :integer;  { базовый адрес ввода-вывода}

   irq           :integer;  { номер IRQ                 }

   dma8          :integer;  { 8-битный канал DMA        }

   dma16         :integer;  { 16-битный канал DMA       }

   midi          :integer;  { порт MIDI                 }

   cardtype      :integer;  { номер типа платы          }

procedure GetBlasterInfo; {извлечение информации о плате}

implementation

uses dos;

var

   s : string; {переменная окружения 'BLASTER'}

   e : byte;   {позиция в этой строке}

function str2hex:word;

        {преобразует последовательность hex-цифр в число}

var

   val : word;

begin

   val := 0;

   inc(e);

   while (s[e] <> ' ') and (s[e] <> char(0)) and

                                (e <= length(s)) do begin

      case UpCase(s[e]) of

         '0'..'9' : val := val * 16

                              + (byte(s[e]) - byte('0'));

         'A'..'F' : val := val * 16

                        + (byte(s[e]) - byte('A')  + 10);

         else begin

            writeln(

    'Ошибка в цифровых параметрах переменной окружения');

            halt;

         end;

      end;

      inc(e);

   end;

   str2hex := val;

end;

procedure GetBlasterInfo; {информация о плате}

begin

   s := getenv('BLASTER');

   e := 1;

   if (length(s)>0) then begin

      while (e < length(s)) do begin

         case UpCase(s[e]) of

            'A':base     := str2hex;

            'I':irq      := str2hex;

            'D':dma8     := str2hex;

            'H':dma16    := str2hex;

            'P':midi     := str2hex;

            'T':cardtype := str2hex;

         end; 

         inc(e);

      end; 

   end else begin

      writeln(

             'Отсутствует переменная окружения BLASTER');

      halt;

   end; 

end;

end.

Затем следует проинициализировать DSP (Digital Signal Processor - цифровой процессор сигналов) и установить режим микшера, для управления которым имеются два адреса портов: базовый+4 (для задания номера регистра) и базовый+5 (для записи/чтения нужной величины). Назначение регистров микшера приведено в табл. 1.

Несколько пояснений к табл. 1. Регистры до 2Еh включительно служат для совместимости с предыдущими моделями Sound Blaster, однако, поскольку глубина регулировки уровня в последних моделях возросла, необходимо ввести новые регистры. Старые дублируют старшие биты новых регистров того же назначения. Шаг регулировки громкости у старых регистров - 4 дБ, а у новых - 2 дБ. Появление регистра 3Сh позволяет отключить источники сигнала без изменения положения регуляторов уровня, а добавление регистров 3Dh-3Eh - подключать входные сигналы в любом порядке. Например, можно подсоединить правый канал CD к левому звуковой платы, а правый канал линейного входа смешать с микрофоном и снова послать в правый канал. Кроме того, появились входные и выходные аттенюаторы с шагом 6 дБ и регуляторы тембра с шагом 2 дБ, а также стала возможной автоматическая регулировка уровня микрофонного входа. В случае монофонического сигнала все регулировки осуществляются по левому каналу.

Таблица 3. Формат первого байта команды DSP Bx/Cx

Номер бита

Назначение

Значение

D0 Зарезервирован 0
D1 FIFO 0 - выключен;
1 - включен
D2 Автоинициализация 0 - режим одного цикла;
1 - режим с автоинициализацией
D3 Вид преобразования 0 - цифроаналоговое (воспроизведение);
1 - аналого-цифровое (запись)
D4-D7 Разрядность 1011 (Bh) - 16 разрядов;
1100 (Сh) - 8 разрядов
Примечание: другие комбинации соответствуют остальным командам

Таблица 4. Формат второго байта команды DSP Bx/Cx

Номер бита

Назначение

Значение

D0-D3 Зарезервированы 0000
D4 Представление отсчетов 0 - беззнаковое;
1 - знаковое
D5 Число каналов (-1) 0 - моно;
1 - стерео
D6-D7 Зарезервированы 00

Таблица 5. Регистр статуса прерываний

Номер бита

Источник прерывания

D0 8-разрядный ввод-вывод
D1 16-разрядный ввод-вывод
D2 Внешний MIDI-интерфейс (MPU-401)
D3-D7 Зарезервированы

После сброса DSP и установки режима работы микшера следует создать в оперативной памяти два буфера: для записываемого звука и для воспроизводимого. Поскольку и запись и воспроизведение будут осуществляться через DMAC (Direct Memory Access Controller - контроллер прямого доступа к памяти), к расположению буферов предъявляются некоторые дополнительные требования. Во-первых, они должны находиться в нижнем мегабайте адресного пространства. В реальном режиме работы процессора это выполняется всегда, а о том, как сделать такое в защищенном, рассказано в статье "Программирование Sound Blaster в защищенном режиме процессора" (см. "Мир ПК", № 3/98, с. 48). Во-вторых, буфер не должен пересекать границы 64-Кбайт страниц, поэтому при выделении памяти под него сначала следует проверить, хватит ли места для размещения буферов записи и воспроизведения до конца текущей страницы. Если его окажется недостаточно, то нужно запросить всю память до конца данной страницы, чтобы начало свободной памяти (кучи) совпало с началом следующей, где будут размещены буферы.

Для каждого из буферов определяются номер 64-Кбайт страницы и смещение в ней, которые надо затем сообщить контроллеру прямого доступа к памяти (DMAC). Процедуры работы с DMAC и цифровым сигнальным процессором (DSP) приведены в листинге 3. При инициализации режим работы контроллера необходимо записать в регистр 0Bh для 8-разрядного режима или в регистр D6h - для 16-разрядного. Значения отдельных битов этих регистров приведены в табл. 2.

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

Листинг 3. Работа с DSP и DMA

unit DSP_DMA;

interface

procedure DspOut(val:byte);         {выводит байт на DSP}

procedure SetupDMA(dmach,page,ofs,DMAcount,dmacmd:word);

                                   {установка режима DMA}

procedure SetupDSP(dspcmd, mode, DSPcount, tc:word);

                                   {установка режима DSP}

procedure SetMixer;

                  {сброс платы и выбор источника сигнала}

procedure EnableInterrupt(newvect:pointer);

                          {установка векторов прерываний}

procedure DisableInterrupt;

                     {восстановление векторов прерываний}

implementation

uses getsbinf,crt,dos;

var

   intvecsave      :pointer;  { старый вектор прерывания}

   intrnum         :integer;  { номер прерывания        }

   intrmask        :integer;  { маска прерывания        }

{ структура, содержащая данные контроллера DMA }

type

   DmaPortRec = record

      addr,count,page : byte;

   end;

const

   DmaPorts : array[0..7]of DmaPortRec = (

    (addr:$00; count:$01; page:$87),  

    (addr:$02; count:$03; page:$83),  

    (addr:$04; count:$05; page:$81),  {2 не используется}

    (addr:$06; count:$07; page:$82),  

    (addr:$00; count:$00; page:$00),  {4 не используется}

    (addr:$C4; count:$C6; page:$8B),  

    (addr:$C8; count:$CA; page:$89),  

    (addr:$CC; count:$CE; page:$8A)); 

procedure DspOut(val:byte);{выводит байт в DSP}

begin

   while (Port[base + $0C] and $80) <> 0 do;

   Port[base + $0C] := val;

end;

function DspIn:byte;{читает байт из DSP}

begin

   while (Port[base + $0E] and $80) = 0 do;

   dspin := Port[base + $0A];

end;

procedure SetupDMA(dmach,page,ofs,DMAcount,dmacmd:word);

                          { Программирует контроллер DMA}

                       { для 8- или 16-разрядного канала}

var

   mask,mode,ff : byte;

begin

   if (dmach < 4) then begin

      mask := $0A;

      mode := $0B;

      ff   := $0C;

   end else begin

      mask := $D4;

      mode := $D6;

      ff   := $D8;

      ofs := (ofs shr 1) + ((page and 1) shl 15);

   end;

   Port[mask]  := 4 or dmach;  { маскируем DMA}

   Port[FF]    := 0;        { сбрасываем триггер-защелку}

   Port[mode]  := dmacmd or (dmach and 3);

                                        { уст.режима DMA}

   Port[dmaports[dmach].addr]  := lo(ofs);

                                   { младший байт адреса}

   Port[dmaports[dmach].addr]  := hi(ofs);{ старший байт}

   Port[dmaports[dmach].page]  := page; { номер страницы}

   Port[dmaports[dmach].count] := lo(DMAcount-1);

                                 { младший байт счетчика}

   Port[dmaports[dmach].count] := hi(DMAcount-1);

                                          { старший байт}

   Port[mask]  := (dmach and 3);   { сброс бита маски}

end;

procedure SetupDSP(dspcmd, mode, DSPcount, tc:word);

                      { Программирует DSP звуковой платы}

begin

   DspOut($40);             {установка константы времени}

      DspOut(tc);

   DspOut(dspcmd);                        {команда Bx/Cx}

      DspOut(mode);

      DspOut(lo(DSPcount-1));

      DspOut(hi(DSPcount-1));

end;

procedure SetMixer;{сброс платы и выбор источника сигнала}

var

   val:byte;

begin

   Port[base + $06] := 1; {сброс DSP}

   delay(1);

   Port[base + $06] := 0;

   if (dspin <> $AA) then {проверка готовности}

         writeln('Sound Blaster не готов.');

   Port[base + $04] := $3D;

   Port[base + $05] := 1;

               { левый канал:источник сигнала - микрофон}

{   Port[base + $04] := $3E;  {для моно - не обязательно}

{   Port[base + $05] := 1; }

              { правый канал:источник сигнала - микрофон}

   Port[base + $04] := $3C;

   Port[base + $05] := 0;

                    { на выходе отключаем все, что можно}

end;

procedure EnableInterrupt(newvect:pointer);

                   {установка векторов прерываний}

var intrmask1:word;

begin

   if (irq < 8) then {вычисляем номера прерывания}

      intrnum := irq + 8  { для IRQ 0-7 прерывания 8-15.}

   else

      intrnum := irq - 8 + $70;

                      { для IRQ 8-15 прерывания 70H-78H.}

   intrmask := 1 shl irq; 

   GetIntVec(intrnum,intvecsave);

                               { сохраняем старый вектор}

   SetIntVec(intrnum, newvect);

                            { устанавливаем новый вектор}

   intrmask1 := intrmask;

{разрешаем прерывания}

   Port[$21] := Port[$21] and not intrmask1;

   intrmask1 := intrmask1 shr 8;

   Port[$A1] := Port[$A1] and not intrmask1;

end;

procedure DisableInterrupt;

                     {восстановление векторов прерываний}

var  intrmask1:word;

begin

   intrmask1 := intrmask; {запрещаем прерывания}

   Port[$21] := Port[$21] or intrmask1;

   intrmask1 := intrmask1 shr 8;

   Port[$A1] := Port[$A1] or intrmask1;

   SetIntVec(intrnum,intvecsave);{восстанавливаем вектор}

end;

end. 

После программирования DMAC то же самое проделывается и с DSP звуковой платы. Сначала надо установить частоту дискретизации, сообщив ему константу времени

t = 256 - 1 000 000 / f,
где f - частота дискретизации.

Затем следует задать команду на запись/воспроизведение звука. Для Sound Blaster 16 проще всего выбрать команды Bx/Cx, состоящие из четырех байтов: Command, Mode, LenLo, LenHi.

Формат первого байта Command приведен в табл. 3, а второго байта Mode - в табл. 4.

Байты LenLo и LenHi - младший и старший в соответствии с длиной передаваемого блока, уменьшенной на единицу.

Команды Bx/Cx позволяют задавать как знаковый, так и беззнаковый вид представления отсчетов. При знаковом отсчет представляет собой целое число со знаком, принимающее значение 0 при отсутствии входного сигнала, при беззнаковом - целое число без знака, равное 80h для 8-разрядного режима и 8000h для 16-разрядного при отсутствии входного сигнала.

Стандартом де-факто является представление 8-разрядных отсчетов в беззнаковой форме, а 16-разрядных - в знаковой, однако для упрощения процедуры преобразования в приводимой программе обе величины выбраны знаковыми.

Таблица 6. Команды DSP

Команда

Описание

14h 8-разрядное воспроизведение через DMA без автоинициализации. Команда состоит из 3 байт, за ее кодом следует длина передаваемых данных, уменьшенная на 1
1Ch 8-разрядное воспроизведение с автоинициализацией. Команда состоит из 1 байта, длина воспроизводимого блока задается командой 48h
24h 8-разрядная запись, аналогичная команде 14h
2Ch 8-разрядная запись с автоинициализацией, аналогичная 1Ch
40h Задание константы времени, 2 байта: после кода команды - константа
41h Задание частоты дискретизации вывода, 3 байта: после команды 2 байта частоты дискретизации в диапазоне 5000-45 000 Гц
42h Задание частоты дискретизации ввода, аналогичное 41h
48h Задание длины передаваемых данных, 3 байта, включая 2 байта данных. Определяет, по истечении какого объема переданных данных должно поступить прерывание от звуковой платы
Bxh 16-разрядный ввод-вывод
Cxh 8-разрядный ввод-вывод
D0h Пауза 8-разрядного ввода-вывода
D1h Выключение динамика
D3h Включение динамика
D4h Продолжение 8-разрядного ввода-вывода, приостановленного командой D0h
D5h Пауза 16-разрядного ввода-вывода
D6h Продолжение 16-разрядного ввода-вывода, приостановленного командой D5h
D8h После этой команды чтение из DSP возвращает статус динамика: 0 - выключен; FFh - включен
D9h Выход из 16-разрядного ввода-вывода с автоинициализацией
DAh Выход из 8-разрядного ввода-вывода с автоинициализацией
E1h После этой команды чтение 2 байт из DSP приведет к получению номера версии DSP, причем 1-й байт - старший, а 2-й - младший

После программирования микшера следует установить свои процедуры обработки прерываний от звуковой платы и только потом можно будет задавать режимы DMA и DSP. Затем процессор свободен для выполнения любой другой работы, например с экраном, как это практикуется в компьютерных играх. В данной же программе просто происходит ожидание ввода с клавиатуры. Однако время от времени работу процессора будут приостанавливать прерывания, поступающие со звуковой платы по окончании пересылки очередной порции данных. В задачу обработчика прерываний входит определение номера канала, по которому пришло прерывание. Дело в том, что и 8-разрядный, и 16-разрядный ввод-вывод, и даже внешний MIDI-интерфейс (MPU-401) генерируют одно и то же аппаратное прерывание. Для того чтобы различать их между собой, в адресном пространстве регистров микшера имеется порт номер 82h (регистр статуса прерываний), определяющий источник прерывания (табл. 5).

Обработчик прерывания должен сообщить звуковой плате, что ее прерывание принято и обработано, для чего необходимо осуществить чтение из порта 0Eh или 0Fh для 8- либо 16-разрядного режимов соответственно.

После прихода прерываний от канала записи и от канала воспроизведения можно считать, что соответствующие половины буферов записи и воспроизведения уже обработаны звуковой платой и пора копировать данные из одного буфера в другой. Так как в обоих случаях была выбрана одинаковая (знаковая) форма представления данных, то их преобразование сводится лишь к переписыванию старших байтов значений двухбайтовых звуковых отсчетов из входного буфера в выходной.

По завершении отработки прерывания следует осведомить об этом контроллер прерываний (с учетом каскадирования).

После нажатия на программа приостанавливает и 8-, и 16-разрядные операции ввода-вывода и восстанавливает векторы прерываний.

Выше приведен выборочный список команд DSP, которые

Андрианов С. А.
InfoCity

Другие разделы
C, C++
Java
PHP
VBasic, VBS
Delphi и Pascal
Новое в разделе
Базы данных
Общие вопросы
Теория программирования и алгоритмы
JavaScript и DHTML
Perl
Python
Active Server Pages
Программирование под Windows
I2R-Журналы
I2R Business
I2R Web Creation
I2R Computer
рассылки библиотеки +
И2Р Программы
Всё о Windows
Программирование
Софт
Мир Linux
Галерея Попова
Каталог I2R
Партнеры
Amicus Studio
NunDesign
Горящие путевки, идеи путешествийMegaTIS.Ru

2000-2008 г.   
Все авторские права соблюдены.
Rambler's Top100