[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]
{ SBLASTER.PAS }
{ A small unit demonstrating DMA transfers to and from the Sound Blaster }
{ as well as simple double buffering techniques. }
{ Programmed by Ian Ash of Arcturus. }
Unit SBlaster;
interface
uses Crt, Dos;
Procedure InitSB(rate : Word);
Procedure SBPlay(segm, ofst, lgth : Word);
Procedure SBRecord(segm, ofst, Lgth : Word);
Procedure SetInterrupt(Intrrpt : Pointer);
Procedure Record2Disk(var buf; name : String);
type
InfoType = Array[1..1] Of Byte;
var
samplerate : Byte;
CurrentInterrupt : Pointer;
FileIDByte : Array[1..2] Of Char;
EndOfTransfer : Boolean;
const
BasePort = $220;
DSPReset = BasePort + $06;
DSPRead = BasePort + $0A;
DSPWrite = BasePort + $0C;
DSPDataAvail = BasePort + $0E;
IRQ2 = $0A;
IRQ3 = $0B;
IRQ5 = $0D;
IRQ7 = $0F;
implementation
{ Simple interrupt handler for use. It acknowledges the end of transfer }
{ and then sets a flag EndOfTransfer to indicate the transfer end. }
Procedure HandleInterrupt; interrupt;
var
Info : Byte;
begin
Info := Port[DSPDataAvail];
Port[$21] := Port[$21] XOR 129;
EndOfTransfer := True;
Port[$20] := $20;
end;
Procedure InitSB(rate : Word); { Initializes SoundBlaster And Sets The }
var { Sampling Rate To rate Which Is Given In }
ActRate : LongInt; { Hertz. }
Count : Byte;
InitComplete : Byte;
begin
CurrentInterrupt := @HandleInterrupt;
sampleRate := 256 - (1000000 div rate);
Port[DSPReset] := 1;
Delay(5);
Port[DSPReset] := 0;
Count := 0;
If (Port[DSPDataAvail] And 128) = 128 Then
repeat
InitComplete := Port[DSPRead];
Count := Count + 1;
until (InitComplete = $AA) Or (Count > 150);
FileIDByte[1] := 'I'; FileIDByte[2] := 'A';
end;
{ Plays a digitised sound clip. 'segm' and 'ofst' is the segment and }
{ offset where the data is stored and Lgth is the length in bytes of }
{ the sound clip. Note that this routine can only play a sound clip }
{ of maximum size 64K. }
Procedure SBPlay(segm, ofst, Lgth : Word);
var
page : Byte;
offset : Word;
count : word;
InitComplete : Byte;
OldInt : Pointer;
begin
SetIntVec(IRQ5, @HandleInterrupt);
Port[$21] := Port[$21] XOR 129;
page := Hi(segm) div $10;
offset := (segm shl 4) + ofst;
Port[$0A] := $05;
Port[$0C] := $00;
Port[$0B] := $49;
Port[$02] := Lo(offset);
Port[$02] := Hi(offset);
Port[$83] := page;
Port[$03] := lo(lgth);
Port[$03] := hi(lgth);
Port[$0A] := 1;
Port[DSPWrite] := $D1;
Port[DSPWrite] := $40;
Port[DSPWrite] := samplerate;
repeat until (Port[DSPWrite] And 128) = 0;
Port[DSPWrite] := $14;
Delay(1);
Port[DSPWrite] := lo(lgth);
repeat until (Port[DSPWrite] And 128) = 0;
Port[DSPWrite] := hi(lgth);
end;
{ Records a sound clip to data location whose segment:offset is specified }
{ in 'segm' and 'ofst' respectively. 'lgth' is the number of bytes to be }
{ recorded. }
Procedure SBRecord(segm, ofst, lgth : Word);
var
page : Byte;
offset : Word;
OldInt : Pointer;
begin
SetIntVec(IRQ5, @HandleInterrupt);
Port[$21] := Port[$21] XOR 129;
page := Hi(segm) div $10;
offset := (segm shl 4) + ofst;
Port[$0A] := $05;
Port[$0C] := $00;
Port[$0B] := $45;
Port[$02] := Lo(offset);
Port[$02] := Hi(offset);
Port[$83] := page;
Port[$03] := lo(lgth);
Port[$03] := hi(lgth);
Port[$0A] := 1;
Delay(10);
Port[DSPWrite] := $40;
repeat until (Port[DSPWrite] And 128) = 0;
Port[DSPWrite] := samplerate;
repeat until (Port[DSPWrite] And 128) = 0;
Port[DSPWrite] := $24;
Delay(1);
Port[DSPWrite] := lo(lgth);
Delay(1);
Port[DSPWrite] := hi(lgth);
end;
Procedure SetInterrupt(Intrrpt : Pointer);
begin
CurrentInterrupt := Intrrpt;
end;
{ Records a digital sound to disk. buf is a data area to be used as a }
{ buffer and must be 64K in size (a whole segment!!). name is the name }
{ of the DOS file to store the info in. }
Procedure Record2Disk(var buf; name : String);
type
DataType = Array[1..1] Of Byte;
var
f : File;
Data : DataType absolute buf;
WorkArea : Word;
ch : Char;
begin
Assign(f, name);
Rewrite(f, 1);
BlockWrite(f, FileIDByte, 2);
FileIDByte[1] := Chr(samplerate);
BlockWrite(f, FileIDByte, 1);
FileIDByte[1] := 'I';
ch := ReadKey;
SetInterrupt(@handleInterrupt);
EndOfTransfer := False;
WorkArea := 1;
SBRecord(Seg(Data[WorkArea]), Ofs(Data[WorkArea]), 30000);
repeat
repeat until EndOfTransfer;
WorkArea := 30500;
EndOfTransfer := False;
SBRecord(Seg(Data[WorkArea]), Ofs(Data[WorkArea]), 30000);
BlockWrite(f, Data[1], 30000);
repeat until EndOfTransfer;
WorkArea := 1;
EndOfTransfer := False;
SBRecord(Seg(Data[WorkArea]), Ofs(Data[WorkArea]), 30000);
BlockWrite(f, Data[WorkArea + 30499], 30000);
until KeyPressed;
Close(f);
end;
end.
[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]