{┌───────────────────────────────────────────────────────────────────────────┐
┌┘ GusPlay v1.5 and UltraDox v1.? interface for B/TPascal! │
│ (C) Copyright, 1993 by Bjarni R. Einarsson (Juggler) │
│ │
│ With added bonuses by Juggler/BTL. :-) Thats me. OK, here it is, all │
│ you Pascal proggin GUS owners: a unit that lets you do your (my) most │
│ favorite GUS thingz! This (cute) little unit plays back 4/6/8 channel │
│ .MODs in the background and lets you play up to 12 other samples at a │
│ time as well. (GUS initialized with 20 active voices..) │
│ │
│ Full source code of course, and all the important stuff is in the .ASM │
│ file. So you should be able to hack this into a C/C++ program without │
│ too much trouble, if ya get the urge. │
│ │
│ Thanx go to Robert Adolfsson/Cascada and CyberStrike/Renaissance for │
│ writing the important bits of code. │
│ │
│ Now go read the dox. :-) │
│ │
│ P.S. The tabs should be set to 4 spaces for all this to look right. ┌┘
└───────────────────────────────────────────────────────────────────────────┘}
{$F+,A+,G+,S+}
unit GP15 ;
interface
const GP_RampNoFlags = $000 ; (* Ramp Control bits.. *)
GP_RampLoopOn = $008 ; (* on=enable *)
GP_RampBiDirLoop = $010 ; (* on=enable *)
GP_RampIRQEnable = $020 ; (* Not properly supported.. *)
GP_VocNoFlags = $000 ; (* Voice control. (loopmode) *)
GP_VocLoopOn = $008 ; (* on=enable *)
GP_VocBiDirLoop = $010 ; (* on=enable *)
GP_VocIs16Bit = $004 ; (* Not properly supported.. *)
GP_VocIRQEnable = $020 ; (* Not properly supported.. *)
GP_FarLeft = 0 ; (* Some balance values.. *)
GP_Middle = 7 ;
GP_FarRight = 15 ;
GP_MaxVolume = 64 ; (* Some voice/mod volume values *)
GP_MidVolume = 32 ;
GP_MinVolume = 0 ;
GP_MixMyDefault = $01 ; (* Mixer Control values *)
GP_MixNoLineIn = $01 ; (* on=disable *)
GP_MixNoLineOut = $02 ; (* on=disable *)
GP_MixMicInOn = $04 ; (* on=enable *)
type GP_Var_Types = (MainVolume, PlayingPattern, RealPPattern,
PatternRow, RealRow, ChanOn, NumChans, ProtSampNum,
ProtMainVolume, NextVoice) ;
GP_Array_Typ = array[GP_Var_Types] of word ;
GP_LArr32 = array[0..31] of longint ;
GP_WArr32 = array[0..31] of word ;
GP_LArr64 = array[0..63] of longint ;
GP_WArr64 = array[0..63] of word ;
GP_Data = record (* All this stuff is *)
BasePort : ^Word ; (* in the assembler *)
ErrorCode : ^Word ; (* file! These *)
Vars : ^GP_Array_Typ ; (* are merely *)
Timer, (* pointers! *)
GUSMem, (* GetVariables must be *)
GUSMemProt : ^Longint ; (* called before *)
SampChans : ^Word ; (* using this stuff.*)
GusVolTable : ^GP_WArr64 ; (* I've got it set *)
MSOffset : ^GP_LArr32 ; (* up to do this *)
MSLen, (* automatically. *)
MSVol,
MSRep,
MSRepLen : ^GP_WArr32 ;
PSOffset : ^GP_LArr64 ;
PSLen,
PSVol,
PSRep,
PSRepLen : ^GP_WArr64 ;
end ;
const GP_MixerVal : word = GP_MixMyDefault ; (* Mixer settings, on reset.*)
GP_PlayOK : boolean = false ; (* Is a module in memory? *)
GP_Playing : boolean = false ; (* Is a module being played?*)
var GP : GP_Data ; (* Pointers to data. *)
(* GUS reset (init) routine. Call this first and last in your program. *)
procedure GP_ResetGUS ;
(* Module stuff..
(*
(* LoadModule - allocs memory and dumps into GUS DRAM,
(* KillModule - frees up all .MOD memory..
(* SlideModVolTo- Just to save time.. (when coding, time = change*0.01 secs)
(* Start/StopPlaying - do just that. Neither resets the playback postition.
(* ResetPlaying - Resets playback position to beginning of song.
(*)
procedure GP_LoadModule (FileName : string) ;
procedure GP_KillModule ;
procedure GP_SlideModVolTo (NewVolume : word) ;
procedure GP_StartPlaying ;
procedure GP_StopPlaying ;
procedure GP_ResetPlaying ;
(* Protected samples. Load these before you load your modules!
(*
(* ProtSampAdd - dumps whatever DATA is the first element of into GUS DRAM
(* and sets up tables containing info about the sample
(* (length, loops and so on). Returns the sample's handle.
(* Rep and RepLen are OFFSETs, not calculated GUS addresses.
(* ProtSampPlay - plays a sample previously loaded by PSAdd.
(* ProtSampPop - pops the most recently loaded sample off the sample stack.
(*)
function GP_ProtSampAdd (var Data; DLen,Vol,Rep,RepLen : word;
Signed : boolean) : word;
procedure GP_ProtSampPlay (Handle,Freq,Balance,LoopMode : word) ;
procedure GP_ProtSampPop ;
(* Low level stuff.
(*
(* Copied (almost) straight from Ultradox 1.? by Renaissance.
(*)
function GP_Peek (MemPos : longint) : byte ;
procedure GP_Poke (MemPos : longint; PokeByte : word) ;
procedure GP_SetFreq (Voice, Freq : word) ;
procedure GP_SetBalance (Voice, Balance : word) ;
procedure GP_SetLogVolume (Voice, LogVolume : word) ;
procedure GP_SetLoopMode (Voice, LoopMode : word) ;
procedure GP_StopVoice (Voice : word) ;
procedure GP_StartVoice (Voice, LoopMode : word;
StartP, BeginP, EndP : longint);
function GP_ReadPos (Voice : word) : longint ;
procedure GP_SetMixer (MixValue : word) ;
procedure GP_DumpSampleToDRAM
(var Data; DLen : word; GusMemPos : longint;
XORval : byte) ;
procedure GP_DumpDRAMToMemory
(GusMemPos : longint; DLen : word; var Data) ;
implementation
{$F+}
uses dos ;
const GP_DEBUG = FALSE ; (* Toggles irritating messages on/off :*)
{$L pasgplay.obj}
(* GUSPlay v1.5 code *)
procedure Init ; external ;
procedure InitDevice ; external ;
procedure ClearMem ; external ;
procedure StartPlaying ; external ;
procedure StopPlaying ; external ;
(* Renaissance code *)
procedure U_Peek ; external ;
procedure U_Poke ; external ;
procedure U_SetFreq ; external ;
procedure U_SetBalance ; external ;
procedure U_SetVolume ; external ;
procedure U_SetLoopMode ; external ;
procedure U_StopVoice ; external ;
procedure U_StartVoice(voice,loopmode : word; startp,beginp,endp : longint) ;
external ;
procedure U_ReadPos ; external ;
procedure U_ChangeInOut ; external ;
procedure U_DumpSampleToDRAM ; external ;
procedure U_DumpDRAMToMemory ; external ;
(* My code! Hmm.. not very much of it, is there? :*)
procedure GetVariables (var ProgData : GP_Data) ; external;
function LoadModule (nseg, nofs : word) : word ; external;
function ProtSampAdd (var data; dlen,vol,rep,replen : word;
XORval : byte) : word; external;
procedure ProtSampPlay (snum,freq,balance,loopmode : word) ; external;
procedure ProtSampPop ; external;
procedure GP_ResetGUS ;
begin
if (GP_Playing) then GP_KillModule ;
InitDevice ;
GP_SetMixer(GP_MixerVal) ;
end ;
procedure GP_KillModule ;
begin
if (GP_Playing) then StopPlaying ;
if (GP_PlayOK) then ClearMem ;
GP_Playing := false ;
GP_PlayOK := false ;
end ;
procedure GP_LoadModule(FileName : string) ;
var sn,on : word ;
begin
GP_KillModule ;
GP_PlayOK := False ;
if (length(FileName) > 254) then Exit ; (* Range checking sux.. *)
FileName[length(FileName)+1] := #0 ;
sn := seg(FileName[1]) ;
on := ofs(FileName[1]) ;
GP_PlayOK := (LoadModule(sn,on) = 0) ;
end ;
procedure GP_SlideModVolTo(newvolume : word) ;
var i : integer ;
j : longint ;
begin
if (newvolume > 64) then newvolume := 64 ;
if (newvolume = GP.Vars^[MainVolume]) or
(not GP_Playing) then exit
;
if (newvolume > GP.Vars^[MainVolume]) then
for i := GP.Vars^[MainVolume]+1 to newvolume do begin
j := GP.Timer^ ;
repeat until (GP.Timer^ >= j+10) ;
GP.Vars^[MainVolume] := i ;
end ;
if (newvolume < GP.Vars^[MainVolume]) then
for i := GP.Vars^[MainVolume]+1 downto newvolume do begin
j := GP.Timer^ ;
repeat until (GP.Timer^ >= j+10) ;
GP.Vars^[MainVolume] := i ;
end ;
end ;
procedure GP_StartPlaying ;
begin
if (not GP_PlayOK) or (GP_Playing) then exit ;
StartPlaying ;
GP_Playing := true ;
end ;
procedure GP_StopPlaying ;
begin
if (GP_Playing) then StopPlaying ;
GP_Playing := false ;
end ;
procedure GP_ResetPlaying ;
begin
if (GP_Playing) then StopPlaying ;
Init ;
if (GP_Playing) then StartPlaying ;
end ;
function GP_ProtSampAdd
(var data; dlen,vol,rep,replen : word; Signed : boolean) : word ;
begin
if Signed then
GP_ProtSampAdd := ProtSampAdd(data, dlen,vol,rep,replen, $00)
else GP_ProtSampAdd := ProtSampAdd(data, dlen,vol,rep,replen, $80) ;
end ;
procedure GP_ProtSampPlay(handle,freq,Balance,LoopMode : word) ;
begin
ProtSampPlay(handle, freq, Balance, LoopMode) ;
end ;
procedure GP_ProtSampPop ;
begin
ProtSampPop ;
end ;
function GP_Peek(mempos : longint) : byte ;
var retv : byte ;
begin
asm
mov cx,Word Ptr [mempos]
mov bx,Word Ptr [mempos+2]
call U_Peek
mov retv, ah
end ;
GP_Peek := retv ;
end ;
procedure GP_Poke(mempos : longint; pokebyte : word) ; assembler ;
asm
mov cx,Word Ptr [mempos]
mov bx,Word Ptr [mempos+2]
mov ax,pokebyte
call U_Poke
end ;
procedure GP_SetFreq(voice, freq : word) ; assembler ;
asm
mov bx,voice
mov ax,freq
call U_SetFreq
end ;
procedure GP_SetBalance(voice, balance : word) ; assembler ;
asm
mov ax,voice
mov bx,balance
call U_SetBalance
end ;
procedure GP_SetLogVolume(voice, logVolume : word) ; assembler ;
asm
mov ax,voice
mov bx,logVolume
call U_SetVolume
end ;
procedure GP_SetLoopMode(voice, loopMode : word) ; assembler ;
asm
mov ax,voice
mov bx,loopMode
call U_SetLoopMode
end ;
procedure GP_StopVoice(voice : word) ; assembler ;
asm
mov ax,voice
call U_StopVoice
end ;
procedure GP_StartVoice(voice,loopmode : word; startP,beginP,endP : longint);
begin
U_StartVoice(voice,loopmode, startP,beginP,endP) ;
end ;
function GP_ReadPos(voice : word) : longint ;
var retv : longint ;
begin
asm
mov ax,voice
call U_ReadPos
mov Word Ptr [retv ], ax
mov Word Ptr [retv+2], dx
end ;
GP_ReadPos := retv ;
end ;
procedure GP_SetMixer(mixValue : word) ; assembler ;
asm
mov ax, mixValue
mov GP_MixerVal, ax
call U_ChangeInOut
end ;
procedure GP_DumpSampleToDRAM
(var data; dlen : word; gusMemPos : longint; xorval : byte) ; assembler;
asm
les bx,data
mov ax,Word Ptr [gusMemPos]
mov di,ax
mov ax,Word Ptr [gusMemPos+2]
mov si,ax
mov cx,dlen
mov ah,xorval
call U_DumpSampleToDRAM
end ;
procedure GP_DumpDRAMToMemory
(gusMemPos : longint; dlen : word; var data) ; assembler ;
asm
les bx,data
mov ax,Word Ptr [gusMemPos]
mov di,ax
mov ax,Word Ptr [gusMemPos+2]
mov si,ax
mov cx,dlen
call U_DumpDRAMToMemory
end ;
procedure CheckULTRASND ;
var s : string ;
a,x : integer ;
begin
s := getenv('ULTRASND') ;
if (s <> '') and (s[4] = ',') then begin
a := ord(s[2])-ord('0') ;
GP.BasePort^ := $200+(a*$10) ;
if GP_DEBUG then writeln(
'Using UltraSound at base address 2',
chr(a+ord('0')),'0h') ;
(* GP_ResetGUS ;*)
end ;
end ;
begin
GetVariables(GP) ; (* VERY IMPORTANT!!! *)
CheckULTRASND ; (* Not nearly as important :*)
end.