[Back to SOUND SWAG index]  [Back to Main SWAG index]  [Original]

{

> 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.

[Back to SOUND SWAG index]  [Back to Main SWAG index]  [Original]