Простейшее цифровое эхо
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} {$F+} 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; {$F-} 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 - различаться.