{ > Is there a way to play WAV files with TP7.0 for DOS (on SB) ? I once posted my routine in the german PASCALecho. Sblast... UNIT for digital Soundeffects in games by DMA and a complete test of the SB-configs by Dirk Hoeschen (_aptain |-|eadcrash } UNIT SBlast; interface Uses Crt,Dos; Const DMA_ADDX_REG = $02; DMA_COUNT_REG = $03; DMA_MASK_REG = $0A; DMA_MODE_REG = $0B; DMA_FF_REG = $0C; DMA_PAGE_REG = $83; DMA_Mode = $49; DMA_BufSize = $1000-1; DMA_activ : Boolean=false; SbregDetected : Boolean = false; psound : Boolean = true; dsp_adr : word =$0; dsp_irq : byte =$0; DMA_CH : byte =$1; {don't change it if you'r not shure} function Detect_Reg_Sb : Boolean; { Find Sbadress! Adresse nachher in dsp_adr. false if no SBcard availiable} function Reset_Sb : Boolean; Function GetDSPversion: String; { Get Versionsnummer the Yamaha OPL} Procedure Find_DSP_Irq(Mode: Byte; VAR irq : byte); { If IRQ=0 then no interrupt was found. if Mode=1 FIND_IRQ only tests the Interrupt in IRQ} function wr_dsp_adr : String; {writes the address on the screen} procedure wr_dsp(v : byte); function Sbreadbyte : byte; procedure Sb_Befehl110h(v : byte); procedure Set_frequence(freq : Word); Procedure Lautsprecher_Ein; Procedure Lautsprecher_Aus; procedure Play_DMA(count : Word); Procedure Play_Wave(fname : pathstr); Procedure Stop_DMA; Procedure Continue_DMA; Procedure Stop_Playing; implementation Type Page = Array [0..64000] of byte; Page_point = ^Page; Wave_head = ReCord TypeID : Longint; {normally Riff} Length : Longint; {Length of file } WaveID : Array[0..3] of byte;{WAVE} fmtID : Array[0..3] of byte;{fmt} CHlength : Longint;{Laenge des Chunks} Wformat : Word;{0=Left /1=Right /2 Stereo} Wchannels: Word;{# of channels 2=Stereo} Wrate : Longint;{frequence} Wbps : Longint;{Bits per second} BytespSample : Word; BitspSample : Word; DataID : Array[0..3] of byte;{Data} Filler : Longint; end; Var Tbuf, SbintSave : Pointer; Soundbuf : Page_point; Rem_size : Word; ppage, pofs :Word; frate : Word; IRQ_found: Boolean; function Reset_Sb : Boolean; const ready = $AA; var ct,Stat : byte; BEGIN port[dsp_adr+$6]:=1; delay(100); port[dsp_adr+$6]:=0; stat:=0; ct :=0; while (stat <> ready) and (Ct< 100) do begin Stat:=port[dsp_adr+$E]; Stat:=port[dsp_adr+$A]; Inc(ct); end; Reset_Sb := (Stat = ready); END; function wr_dsp_adr : String; BEGIN case dsp_adr of $210 : wr_dsp_adr := '210 Hex'; $220 : wr_dsp_adr := '220 Hex'; $230 : wr_dsp_adr := '230 Hex'; $240 : wr_dsp_adr := '240 Hex'; $250 : wr_dsp_adr := '250 Hex'; $260 : wr_dsp_adr := '260 Hex'; $270 : wr_dsp_adr := '270 Hex'; $280 : wr_dsp_adr := '280 Hex'; end; END; function Detect_Reg_Sb : Boolean; var Port, Lst : Word; BEGIN Detect_Reg_Sb := SBRegDetected; Port := $210; Lst := $280; while (not SBRegDetected) and (Port <= Lst) do begin Dsp_adr:=Port; SbRegDetected:= Reset_Sb; if not SBRegDetected then inc(Port,$10); end; Detect_Reg_Sb := SBRegDetected; END; procedure wr_dsp(v : byte); BEGIN While port[dsp_adr+$c] >= 128 do; port[dsp_adr+$c] := v; END; function SbReadByte: Byte; BEGIN While port[dsp_adr+$a] = $AA do; SbReadByte := port[dsp_adr+$a]; END; procedure Sb_Befehl110h(v : byte); BEGIN wr_dsp($10); wr_dsp(v); END; procedure Set_frequence(freq : Word); var tc: byte; BEGIN tc := trunc(256-(1000000/freq)); {Die samplefrequenz berechnet sich aus 256-10000000/Hz} wr_dsp($40); {40h set frequence} wr_dsp(tc); END; Procedure Lautsprecher_Ein; BEGIN wr_dsp($D1); END; Procedure Lautsprecher_Aus; BEGIN wr_dsp($D3); END; Procedure Stop_DMA; BEGIN wr_dsp($D0); END; Procedure Continue_DMA; BEGIN wr_dsp($D4); END; Function GetDSPversion: String; var s : String[2]; SbVersMaj : byte; SbVersMin : byte; SbVersStr : String[5]; BEGIN GetDSPVersion:=';-)'; wr_dsp($E1); SbVersMaj := SbreadByte; SbVersMin := SbreadByte; Str(SbversMaj , SbVersStr); SbVersStr:= SbVersStr + '.'; Str(SbversMin , s); If Sbversmin > 9 then SbVersStr:= SbVersStr + s else SbVersStr:= SbVersStr + '0' + s; GetDSPVersion:=SBversStr; END; Procedure Start_DMA_transfer(len : word); { Wie gesagt, hier wird der DMA-controller initialisiert und der Befehl $14=Play 8Bit uncompressed via DMA an die SB-karte gesendet. Sobald die laenge und die Adresse uebergeben ist, startet der Transfer. } type pt = record ofs, sgm : Word; end; var L : Longint; pn, ofs :Word; dummy: byte; BEGIN dummy:=Port[DSP_adr+$0E]; l := 16*longint(ppage)+pofs; pn := Pt(l).sgm; {Man beachte die Berechnung der Page} ofs := Pt(l).ofs; Port[DMA_MAsk_Reg]:=DMA_CH+4; Port[DMA_FF_Reg]:=0; Port[DMA_Mode_Reg]:=Dma_Mode; Port[DMA_ADDX_Reg]:=Lo(ofs); Port[DMA_ADDX_Reg]:=hi(ofs); Port[DMA_PAGE_Reg]:=pn; Port[DMA_COUNT_Reg]:=Lo(len); Port[DMA_COUNT_Reg]:=hi(len); Port[DMA_MAsk_Reg]:=DMA_CH; {DMA 1 freigeben}; wr_dsp($14); wr_dsp(Lo(len)); wr_dsp(hi(len)); END; Procedure Stop_Playing; begin if psound then begin Stop_DMA; Port[DMA_MAsk_Reg]:=DMA_CH+4; Port[$21]:=Port[$21] or (1 shl DSP_Irq); Port[$20]:=$20; SetIntVec($8+ DSP_Irq,SBIntSave); end; end; Procedure DummySBint ; Interrupt; Begin IRQ_found:=True; end; Procedure Find_DSP_Irq(Mode: Byte; VAR irq : byte); const possible_IRQs : Array[1..5] Of Byte = ($7,$5,$2,$3,$10); { Das System dieser Routine ist einfach, aber auch nicht ganz ungefaerlich. DummySBint wird nacheinander in die moeglichen Soundblasterinterrupts eingeklinkt. Dannach ein kurzer DMA- transfer gestartet. Wenn der IRQ stimmt, dann setzt der dummy interrupt ein flag.} var c : byte; BEGIN getmem(tbuf,100); Ppage:=seg(tBuf^); Pofs:=Ofs(tBuf^); Lautsprecher_Aus; Set_Frequence(1000); IRQ_found:=false; If mode=1 then Begin GetIntVec($8+Irq,SBIntSave); SetIntVec($8+IRQ,@DummySBInt); Port[$21]:=Port[$21] and not (1 shl IRQ); wr_dsp($D0); Start_DMA_transfer(20); Delay(200); Stop_Playing; Port[$21]:=Port[$21] or (1 shl IRQ); Port[$20]:=$20; SetIntVec($8+Irq,SBIntSave); end else begin c:=1; Repeat IRQ:=Possible_IRQs[c]; GetIntVec($8+Irq,SBIntSave); SetIntVec($8+IRQ,@DummySBInt); Port[$21]:=Port[$21] and not (1 shl IRQ); wr_dsp($D0); Start_DMA_transfer(20); Delay(200); Inc(c); Stop_Playing; Port[$21]:=Port[$21] or (1 shl IRQ); Port[$20]:=$20; SetIntVec($8+Irq,SBIntSave); Until (IRQ_found) or (c=6); end; If not IRQ_found then IRQ:=0; Lautsprecher_Ein; freemem(tbuf,100); END; Procedure SBint ; Interrupt; { Diese procedure wird in den SB-interrupt eingeklinkt und angesprungen, wenn der DMA-Block vollstaendig ausgegeben wurde} Begin If Rem_Size<50 then begin DMA_ACtiv:=False {End of dma_transfer} Dispose(Soundbuff); end else If Rem_size<= DMA_bufsize then begin Pofs:=Pofs+DMA_Bufsize; Start_DMA_transfer(Rem_size); Rem_Size:=0; {nix mehr uebrig} end else begin Pofs:=Pofs+DMA_Bufsize; Start_DMA_transfer(DMA_bufsize); Rem_Size:=Rem_Size-DMA_bufsize; end; Port[$20]:=$20; end; procedure Play_DMA(count : Word); var L : Longint; hbyte : byte; a : word; Oldv, Newv, Hilfe :byte; Begin Ppage:=Seg(Soundbuff^); Pofs:=Ofs(Soundbuff^); a:=Count; If a<= DMA_bufsize then begin Rem_Size:=0; end else begin Rem_Size:=a-DMA_bufsize; a:=DMA_bufsize; end; Lautsprecher_Ein; Set_Frequence(Frate); GetIntVec($8+DSP_Irq,SBIntSave); SetIntVec($8+DSP_Irq,@SBInt); Port[$21]:=Port[$21] and not (1 shl DSP_Irq); wr_dsp($D0); Start_DMA_TRANSFER(a); DMA_activ:=True; end; Procedure Play_Wave(fname :Pathstr); Var size : LongInt; IdStr : String[4]; Header : Wave_Head; F : File; begin if psound then begin size := 0; Assign(f,Fname); reset(f,1); With Header do begin blockread(f,Header,sizeOf(Header)); IdStr:=chr(WaveID[0])+chr(WaveID[1])+chr(WaveID[2])+chr(WaveID[3]); if IdStr = 'WAVE' then begin size := Length-Sizeof(header); If size>50 then begin frate:=Wrate; New(Soundbuff); blockread(f,Soundbuff^,size); {Soundbuff^ is an ARRAY to buffer the WAVe. I know, that the unit is very dirty here, but its only do demonstrate how it works.} Play_DMA(size); end; end; end; close(f); end; end; BEGIN; END.