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.