Metropoli BBS
VIEWER: ultradev.pas MODE: TEXT (ASCII)
Unit UltraDev;

(*
UltraDev.Pas
*****************************************************************************
  OS/2 device driver interface to the Gravis Ultrasound family of soundcards
                               10-12-1995
                      Written by Sander van Leeuwen
                   email: s509475@dutiwy.twi.tudelft.nl
              Ported to Pascal (VirtualPascal/2) by Timo Maier
                               13.01.1996
                       email: tam@hqsys.shnet.org
                          fido: 2:2476/830.10
                         gernet: 21:498/100.10
*****************************************************************************
                           Standard Disclaimer
*****************************************************************************
This code is provided as is. The author (Timo Maier) isn't responsible for
any damage that may result from using this code. So don't mail me with claims
about damaged ears/stereo's or crashed computers.
*****************************************************************************
I would like to thank Sander for developing great software for a really great
soundcard. Happy GUSing!
This source isn't still perfect, but it should work nice. I'll do my very
best to keep this unit uptodate. For comments, suggestions ... please contact
me or Sander.
-=> Timo
*****************************************************************************
*)

Interface

Uses Os2Base;

Function UltraSizeDram : LongInt;
Function UltraSetNVoices(NumVoices : Byte) : LongInt;
Function UltraGetAccess : LongInt;
Function UltraReleaseAccess : LongInt;
Function UltraEnableOutput : LongInt;
Function UltraDisableOutput : LongInt;
Function UltraGetDriverVersion : Word;
Function UltraDownload(DataPtr : Pointer; Control : Byte; DRam_Loc,
                       Size : LongInt; Wait : Boolean) : LongInt;
Function UltraMemInit : LongInt;
Function UltraStartVoice(GusVoice : Integer; begin_,start,end_ : LongInt;
                         Mode : Byte) : LongInt;
Function UltraMemAlloc(Size : LongInt; var Location : LongInt) : LongInt;
Function UltiMODMemAlloc(Size : LongInt; var Location : LongInt) : LongInt;
Function UltraStopVoice(Voice : Integer) : LongInt;
Function UltraSetAll(Voice: Integer; Balance : Byte; freq : LongInt;
                     Volume : Word; Rate,Mode : Byte) : LongInt;
Function UltraVoiceStopped(Voice : Integer) : Boolean;
Function UltraSetBalance(Voice: Integer; Data : Byte) : LongInt;
Function UltraSetFrequency(Voice : Integer; Freq : LongInt) : LongInt;
Function UltiMODMemFree : LongInt;
Function UltraSetLoopMode(Voice,Mode : LongInt) : LongInt;
Function GetManleyVersion : String;
Procedure CloseUltraSound;
Function OpenUltraSound : Boolean;

CONST {Balance : use values from 0 to 15 }
      BalanceLeft = 0;
      BalanceCenter = 7;
      BalanceRight = 15;

      { Common frequencies for sounds }
      KHz_11 = 11025;
      KHz_22 = 22050;
      KHz_44 = 44100;

      { Here are the volume ramp control bit definitions: }
      LoopDisable = $00;
      LoopEnable = $08;
      BiDirLoop = $10;
      EnableVolRampIRQ = $20;

      { Here are the voice control bit definitions: }
      Voice8Bit = $00;
      Voice16Bit = $04;
      { LoopEnable = $08; BiDirLoop = $10; see ramp control }
      EnableWavtableIRQ = $20;
      DirectionDec = $40;

      { Here are the dma to/from DRAM control bit definitions: }
      DramRead = $02;
      Dram16Bit = $40;
      Convert = $80;

Implementation

var GusHandle : HFile;

type VolumeStruct = record
                      Voice   : Integer;
                      End_idx : word;
                      Rate    : byte;
                      Mode    : byte;
                    end;

     FreqStruct = record
                    Voice     : Integer;
                    Speed_Khz : LongInt;
                  end;

     BalanceStruct = record
                       Voice : Integer;
                       Data  : Byte;
                     end;
     VoiceStruct  = record
                       Voice : Integer;
                       Begin_,          { voice to start }
                       Start ,          { start loop location in ultra DRAM }
                       End_  : LongInt; { end location in ultra DRAM }
                       Mode  : Byte;    { mode to run the voice (loop etc) }
                     end;
     TimerStruct = record
                       Timer : Integer;
                       Time  : Byte;
                     end;
     AllocStruct = record
                     Size     : LongInt;
                     Location : LongInt;
                   end;
     FreeStruct = record
                    Size     : LongInt;
                    Location : LongInt;
                  end;
     PokeStruct = record
                    Address : LongInt;
                    Data    : Byte;
                  end;
     XferStruct = record
                    Control  : Byte;
                    DRam_Loc : LongInt;
                  end;

     AllStruct = record
                   Freq    : LongInt;
                   Voice   : Integer;
                   Balance : Byte;
                   Volume  : Word;     { Volumerange : 0..511 }
                   Rate,
                   Mode    : Byte;
                 end;

Const  Gus_Commands = $0F;
       UltraDevSetNVoices = $50;
       UltraDevEnableOutput = $51;
       UltraDevDisableOutput = $52;
       UltraDevPokeData = $53;
       UltraDevPeekData = $54;
       UltraDevMemAlloc = $55;
       UltraDevMemFree = $56;
       UltraDevMemInit = $57;
       UltraDevStartTimer = $58;
       UltraDevStopTimer = $59;
       UltraDevBlockTimerHandler1 = $5A;
       UltraDevBlockTimerHandler2 = $5B;
       UltraDevStartVoice = $5C;
       UltraDevStopVoice = $5D;
       UltraDevSetBalance = $5E;
       UltraDevSetFrequency = $5F;
       UltraDevVectorLinearVolume = $60;
       UltraDevPrepare4DMAXfer = $61;
       UltraDevUnblockAll = $62;
       UltraDevSetAll = $63;
       UltraDevGetAccess = $6A;
       UltraDevReleaseAccess = $6B;
       UltraDevSizeDRAM = $6D;
       UltraDevGetDriverVersion = $6E;
       UltraDevMODMemAlloc = $70;
       UltraDevMODMemFree = $71;
       UltraDevMODBigMemAlloc = $72;
       UltraDevSetLoopMode = $73;
       UltraDevVoiceStopped = $74;

Function GetManleyVersion : String;
Var Version : Word;
    s1,s2   : String[3];
begin
  Version := UltraGetDriverVersion;
  Str(Hi(Version),s1);
  Str(Lo(Version),s2);
  GetManleyVersion := s1 + '.' + s2;
end;

Function UltraGetAccess : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  DataLength := 0;
  ParmLength := 0;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevGetAccess,NIL,0,
                    ParmLength,NIL,0,DataLength);
  UltraGetAccess := rc;
end;

Function OpenUltraSound : Boolean;
{ true if successful }
var Status : LongInt;
    Action : LongInt;
begin
  Os2Base.DosError(fErr_DisableHardErr);
  Status := DosOpen('ULTRA1$',GUSHandle,Action,0,FILE_NORMAL,
                     FILE_OPEN,OPEN_ACCESS_READWRITE or
                     OPEN_SHARE_DENYNONE or OPEN_FLAGS_WRITE_THROUGH,
                     NIL );
  if Status <> 0 then
    OpenUltraSound := FALSE
  else begin
    if UltraGetAccess > 0 then begin
      DosClose(GUSHandle);
      OpenUltraSound := FALSE;  { not only owner }
    end
    else
      OpenUltraSound := true;   { GUS access ok }
  end;
  Os2Base.DosError(fErr_EnableHardErr);
end;

Procedure CloseUltraSound;
begin
  UltraDisableOutPut;
  UltraReleaseAccess;
  DosClose(GusHandle);
end;

Function UltraSetNVoices(NumVoices : Byte) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := 4;
  if NumVoices < 14 then       { 14 >= voices <= 32 }
    NumVoices := 14
  else if NumVoices > 32 then
    NumVoices := 32;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevSetNVoices,NIL,0,
                    ParmLength,@NumVoices,DataLength,DataLength);
  UltraSetNVoices := rc;
end;

Function UltraReleaseAccess : LongInt;
var ParmLength,DataLength : LongInt;
    rc                     : LongInt;
begin
  DataLength := 0;
  ParmLength := 0;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevReleaseAccess,NIL,0,
                    ParmLength,NIL,DataLength,DataLength);
  UltraReleaseAccess := rc;
end;

Function UltraEnableOutput : LongInt;
var ParmLength,DataLength : LongInt;
    rc                     : LongInt;
begin
  DataLength := 0;
  ParmLength := 0;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevEnableOutput,NIL,0,
                    ParmLength,NIL,DataLength,DataLength);
  UltraEnableOutput := rc;
end;

Function UltraDisableOutput : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  DataLength := 0;
  ParmLength := 0;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevDisableOutput,NIL,0,
                 ParmLength,NIL,DataLength,DataLength);
  UltraDisableOutput := rc;
end;

Function UltraBlockTimerHandler1 : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  DataLength := 0;
  ParmLength := 0;
  { block until timer interrupt }
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevBlockTimerHandler1,NIL,0,
                    ParmLength,NIL,DataLength,DataLength);
  UltraBlockTimerHandler1 := rc;
end;

Function UltraBlockTimerHandler2 : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  DataLength := 0;
  ParmLength := 0;
  { block until timer interrupt }
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevBlockTimerHandler2,NIL,0,
                    ParmLength,NIL,DataLength,DataLength);
  UltraBlockTimerHandler2 := rc;
end;

Function UltraStartTimer(Timer,Time : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    tBuffer               : TimerStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(TimerStruct);
  tBuffer.Timer := Timer;
  tBuffer.Time := Time;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevStartTimer,NIL,0,
                    ParmLength,@tBuffer,DataLength,DataLength);
  UltraStartTimer := rc;
end;

Function UltraStopTimer(Timer : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := SizeOf(Timer);
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevStopTimer,NIL,0,
                    ParmLength,@Timer,DataLength,DataLength);
  UltraStopTimer := rc;
end;

Function UltraSetBalance(Voice : Integer; Data : Byte) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    bBuffer               : BalanceStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(BalanceStruct);
  bBuffer.Voice := Voice;
  bBuffer.Data := Data;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevSetBalance,NIL,0,
                    ParmLength,@bBuffer,DataLength,DataLength);
  UltraSetBalance := rc;
end;

Function UltraSetFrequency(Voice : Integer; Freq : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    fBuffer               : FreqStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(FreqStruct);
  fBuffer.Voice := Voice;
  fBuffer.Speed_Khz := Freq;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevSetFrequency,NIL,0,
                    ParmLength,@fBuffer,DataLength,DataLength);
  UltraSetFrequency := rc;
end;

Function UltiMODMemFree : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := 0;
  { just Free it all }
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevMODMemFree,NIL,0,
                    ParmLength,NIL,DataLength,DataLength);
  UltiMODMemFree := rc;
end;

Function UltiMODMemAlloc(Size : LongInt; var Location : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    aBuffer               : AllocStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(AllocStruct);
  if (Size MOD 32) <> 0 then
    inc(Size,32 - (Size MOD 32)); { bring Size up TO a 32 BYTE boundary }
  aBuffer.Size := Size;
  aBuffer.Location := Location;
  if Size >= 256*1024 then
  { alloc more than 256 kb (xm) NO 16 BIT SAMPLES!!!! }
    rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevMODBigMemAlloc,NIL,0,
                     ParmLength,@aBuffer,DataLength,DataLength)
  else
    rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevMODMemAlloc,NIL,0,
                     ParmLength,@aBuffer,DataLength,DataLength);
  Location := aBuffer.Location; { location in DRAM GUS }
  UltiMODMemAlloc := rc;
end;

Function UltraMemFree(Size,Location : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    aBuffer               : AllocStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(AllocStruct);
  aBuffer.Size := Size;
  aBuffer.Location := Location;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevMemFree,NIL,0,
                    ParmLength,@aBuffer,DataLength,DataLength);
  UltraMemFree := aBuffer.Size;
end;

Function UltraMemAlloc(Size : LongInt; var Location : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                     : LongInt;
    aBuffer                : AllocStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(AllocStruct);
  if (Size MOD 32) <> 0 then
    inc(Size,32 - (Size MOD 32)); { bring Size up TO a 32 BYTE boundary }
  aBuffer.Size := Size;
  aBuffer.Location := Location;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevMemAlloc,NIL,0,
                    ParmLength,@aBuffer,DataLength,DataLength);
  Location := aBuffer.Location; { location in DRAM GUS }
  UltraMemAlloc := rc;
end;

Function UltraMemInit : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := 0;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevMemInit,NIL,0,
                    ParmLength,NIL,DataLength,DataLength);
  UltraMemInit := rc;
end;

Function UltraDownload(DataPtr : Pointer; Control : Byte; DRam_Loc,Size : LongInt; Wait : Boolean) : LongInt;
Const Max = 64*1000;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    Written               : LongInt;
    xBuffer               : XferStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(XferStruct);
  xBuffer.Control := Control;
  xBuffer.DRam_Loc := DRam_Loc;
  rc := 0;
  While Size > Max do begin { 16 bit segments in a 32 bit world 8( }
    rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevPrepare4DMAXfer,NIL,0,
                      ParmLength,@xBuffer,DataLength,DataLength);
    if rc = 0 then begin
      rc := DosWrite(GUSHandle,DataPtr^,Max,Written);
      if rc = 0 then begin
        inc(xBuffer.DRam_Loc,Max);
        Dec(Size,Max);
        inc(LongInt(DataPtr),Max);
      end;
    end;
  end;
  if (Size > 0) and (rc = 0) then begin
    rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevPrepare4DMAXfer,NIL,0,
                     ParmLength,@xBuffer,DataLength,DataLength);
    if rc = 0 then
       rc := DosWrite(GUSHandle,DataPtr^,Size,Written);  {Last transfer}
  end;
  UltraDownLoad := rc;
end;

Function UltraPokeData(Address : LongInt; Data : Byte) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    pBuffer               : PokeStruct;
begin
  ParmLength := 0;
  pBuffer.Address := Address;
  pBuffer.Data := Data;
  DataLength := SizeOf(pBuffer);
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevPokeData,NIL,0,
                    ParmLength,@pBuffer,DataLength,DataLength);
  UltraPokeData := rc;
end;

Function UltraPeekData(Address : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := SizeOf(Address);
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevPeekData,NIL,0,
                    ParmLength,@Address,DataLength,DataLength);
  UltraPeekData := rc;
end;

Function UltraUnblockAll : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := 0;
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevUnblockAll,NIL,0,
                    ParmLength,NIL,0,DataLength);
  UltraUnblockAll := rc;
end;

Function UltraStopVoice(Voice : Integer) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := SizeOf(Voice);
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevStopVoice,NIL,0,
                    ParmLength,@Voice,DataLength,DataLength);
  UltraStopVoice := rc;
end;

Function UltraVectorLinearVolume(Voice,End_Idx : Word; Rate,
                                 Mode : Byte): LongInt;
(*
End_Idx;   end location in ultra DRAM
Rate;      0 to 63
Mode;      mode to run the volume ramp in ...
*)
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    vBuffer               : VolumeStruct;
begin
  vBuffer.Voice := Voice;
  vBuffer.End_Idx := End_Idx;
  vBuffer.Rate := Rate;
  vBuffer.Mode := Mode;
  DataLength := SizeOf(VolumeStruct);
  ParmLength := 0;
  rc :=  DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevVectorLinearVolume,NIL,0,
                     ParmLength,@vBuffer,DataLength,DataLength);
  UltraVectorLinearVolume := rc;
end;

Function UltraSetAll(Voice: Integer; Balance : Byte; Freq : LongInt;
                     Volume : Word; Rate,Mode : Byte) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    aBuffer               : AllStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(AllStruct);
  aBuffer.Voice := Voice;
  aBuffer.Balance := Balance;
  aBuffer.Freq := Freq;
  aBuffer.Volume := Volume;
  aBuffer.Rate := Rate;
  aBuffer.Mode := Mode;
  rc :=  DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevSetAll,NIL,0,
                     ParmLength,@aBuffer,DataLength,DataLength);
  UltraSetAll := rc;
end;

Function UltraStartVoice(GusVoice : Integer; begin_,start,end_ : LongInt;
                         Mode : Byte) : LongInt;
{
gusvoice  voice to start
begin_    start location in ultra DRAM
start     start loop location in ultra DRAM
end_      end location in ultra DRAM
mode      mode to run the voice (loop etc)
}
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    Voice                 : VoiceStruct;
begin
  ParmLength := 0;
  Voice.Voice := GusVoice;
  Voice.Begin_ := Begin_; { start in DRAM  }
  Voice.Start := Start;   { start loop }
  Voice.End_ := End_;
  Voice.Mode := Mode;
  DataLength := SizeOf(VoiceStruct);
  rc :=  DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevStartVoice,NIL,0,
                    ParmLength,@Voice,DataLength,DataLength);
  UltraStartVoice := rc;
end;

Function UltraSizeDram : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    Size                  : LongInt;
begin
  ParmLength := 0;
  DataLength := SizeOf(LongInt);
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevSizeDRAM,NIL,0,
                    ParmLength,@Size,DataLength,DataLength);
  UltraSizeDram := Size;
end;

Function UltraGetDriverVersion : Word;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    aBuffer               : AllocStruct;
    Version               : Word;
begin
  ParmLength := 0;
  DataLength := SizeOf(Version);
  { High word Contains major version,low word minor version }
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevGetDriverVersion,NIL,0,
                    ParmLength,@Version,DataLength,DataLength);
  UltraGetDriverVersion := Version;
end;

Function UltraSetLoopMode(Voice,Mode : LongInt) : LongInt;
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
    bBuffer               : BalanceStruct;
begin
  ParmLength := 0;
  DataLength := SizeOf(BalanceStruct);
  bBuffer.Voice := Voice;
  bBuffer.Data := Mode;
  rc :=  DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevSetLoopMode,NIL,0,
                     ParmLength,@bBuffer,DataLength,DataLength);
  UltraSetLoopMode := rc;
end;

Function UltraVoiceStopped(Voice : Integer) : Boolean;
{ false while playing Voice }
var ParmLength,DataLength : LongInt;
    rc                    : LongInt;
begin
  ParmLength := 0;
  DataLength := SizeOf(Voice);
  rc := DosDevIOCtl(GUSHandle,Gus_Commands,UltraDevVoiceStopped,NIL,0,
                    ParmLength,@Voice,DataLength,DataLength);
  UltraVoiceStopped := Voice > 0;
end;

{ ... to be continued }
end.

[ RETURN TO DIRECTORY ]