[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]
UNIT VOCTOOL;
{* Unit - uses CT-VOICE.DRV. *}
INTERFACE
TYPE
VOCFileTyp = File;
CONST
VOCToolVersion = 'v1.5';
VOCBreakEnd = 0;
VOCBreakNow = 1;
VAR
VOCStatusWord : WORD;
VOCErrStat : WORD;
VOCFileHeader : STRING;
VOCFileHeaderLength : BYTE;
VOCPaused : BOOLEAN;
VOCDriverInstalled : BOOLEAN;
VOCDriverVersion : WORD;
VOCPtrToDriver : Pointer;
OldExitProc : Pointer;
PROCEDURE PrintVOCErrMessage;
FUNCTION VOCGetBuffer(VAR VoiceBuff : Pointer; Voicefile : STRING):BOOLEAN;
FUNCTION VOCFreeBuffer(VAR VoiceBuff : Pointer):BOOLEAN;
FUNCTION VOCGetVersion:WORD;
PROCEDURE VOCSetPort(PortNumber : WORD);
PROCEDURE VOCSetIRQ(IRQNumber : WORD);
FUNCTION VOCInitDriver:BOOLEAN;
PROCEDURE VOCDeInstallDriver;
PROCEDURE VOCSetSpeaker(OnOff:BOOLEAN);
PROCEDURE VOCOutput(BufferAddress : Pointer);
PROCEDURE VOCOutputLoop (BufferAddress : Pointer);
PROCEDURE VOCStop;
PROCEDURE VOCPause;
PROCEDURE VOCContinue;
PROCEDURE VOCBreakLoop(BreakMode : WORD);
IMPLEMENTATION
USES DOS,Crt;
TYPE
TypeCastType = ARRAY [0..6000] of Char;
VAR
Regs : Registers;
PROCEDURE PrintVOCErrMessage;
{* INPUT : None
* OUTPUT : None
* PURPOSE : Displays SB error as text; no change to error status. }
BEGIN
CASE VOCErrStat OF
100 : Write(' Driver file CT-VOICE.DRV not found ');
110 : Write(' No memory available for driver file ');
120 : Write(' False driver file ');
200 : Write(' VOC file not found ');
210 : Write(' No memory available for driver file ');
220 : Write(' File not in VOC format ');
300 : Write(' Memory allocation error occurred ');
400 : Write(' No sound blaster card found ');
410 : Write(' False port address used ');
420 : Write(' False interrupt used ');
500 : Write(' No loop in process ');
510 : Write(' No sample for output ');
520 : Write(' No sample available ');
END;
END;
FUNCTION Exists (Filename : STRING):BOOLEAN;
{* INPUT : Filename as string
* OUTPUT : TRUE if file is available, FALSE if not
* PURPOSE : Checks for availability of file then returns Boolean exp. }
VAR
F : File;
BEGIN
Assign(F,Filename);
{$I-}
Reset(F);
Close(F);
{$I+}
Exists := (IoResult = 0) AND (Filename <> '');
END;
PROCEDURE AllocateMem (VAR Pt : Pointer; Size : LongInt);
{* INPUT : Buffer variable as pointer, buffer size as LongInt
* OUTPUT : Pointer to buffer in variable or NIL
* PURPOSE : Reserves as many bytes as Size allows, then moves pointer in
the Pt variable. If not enough memory is available, Pt = NIL. }
VAR
SizeIntern : WORD;
BEGIN
Inc(Size,15);
SizeIntern := (Size shr 4);
Regs.AH := $48;
Regs.BX := SizeIntern;
MsDos(Regs);
IF (Regs.BX <> SizeIntern) THEN Pt := NIL
ELSE Pt := Ptr(Regs.AX,0);
END;
FUNCTION CheckFreeMem (VAR VoiceBuff : Pointer; VoiceSize : LongInt):BOOLEAN;
{* INPUT : Buffer variable as pointer, size as LongInt
* OUTPUT : Pointer to buffer, TRUE/FALSE, after AllocateMem
* PURPOSE : Checks for sufficient memory to store a VOC file. }
BEGIN
AllocateMem(VoiceBuff,VoiceSize);
CheckFreeMem := VoiceBuff <> NIL;
END;
FUNCTION VOCGetBuffer (VAR VoiceBuff : Pointer; Voicefile : STRING):BOOLEAN;
{* INPUT : Buffer variable as pointer, file name as string
* OUTPUT : Pointer to buffer with VOC data, TRUE/FALSE
* PURPOSE : Loads a file into memory and returns TRUE if file loaded
successfully, and FALSE if not. }
VAR
SampleSize : LongInt;
FPresent : BOOLEAN;
VFile : VOCFileTyp;
Segs : WORD;
Read : WORD;
BEGIN
FPresent := Exists(VoiceFile);
{ VOC file not found }
IF Not(FPresent) THEN BEGIN
VOCGetBuffer := FALSE;
VOCErrStat := 200;
EXIT
END;
Assign(VFile,Voicefile);
Reset(VFile,1);
SampleSize := Filesize(VFile);
AllocateMem(VoiceBuff,SampleSize);
{ Insufficient memory for the VOC file }
IF (VoiceBuff = NIL) THEN BEGIN
Close(VFile);
VOCGetBuffer := FALSE;
VOCErrStat := 210;
EXIT;
END;
Segs := 0;
REPEAT
Blockread(VFile,Ptr(seg(VoiceBuff^)+4096*Segs,Ofs(VoiceBuff^))^,$FFFF,Read
);
Inc(Segs);
UNTIL Read = 0;
Close(VFile);
{ File not in VOC format }
IF (TypeCastType(VoiceBuff^)[0]<>'C') OR
(TypeCastType(VoiceBuff^)[1]<>'r') THEN BEGIN
VOCGetBuffer := FALSE;
VOCErrStat := 220;
EXIT;
END;
{ Load successful }
VOCGetBuffer := TRUE;
VOCErrStat := 0;
{ Read header length from file }
VOCFileHeaderLength := Ord(TypeCastType(VoiceBuff^)[20]);
END;
FUNCTION VOCFreeBuffer (VAR VoiceBuff : Pointer):BOOLEAN;
{* INPUT : Buffer pointer
* OUTPUT : None
* PURPOSE : Frees memory allocated for VOC data. }
BEGIN
Regs.AH := $49;
Regs.ES := seg(VoiceBuff^);
MsDos(Regs);
VOCFreeBuffer := TRUE;
IF (Regs.AX = 7) OR (Regs.AX = 9) THEN BEGIN
VOCFreeBuffer := FALSE;
VOCErrStat := 300
END;
END;
FUNCTION VOCGetVersion:WORD;
{* INPUT : None
* OUTPUT : Driver version number
* PURPOSE : Returns driver version number. }
VAR
VDummy : WORD;
BEGIN
ASM
MOV BX,0
CALL VOCPtrToDriver
MOV VDummy, AX
END;
VOCGetVersion := VDummy;
END;
PROCEDURE VOCSetPort(PortNumber : WORD);
{* INPUT : Port address number
* OUTPUT : None
* PURPOSE : Specifies port address before initialization. }
BEGIN
ASM
MOV BX,1
MOV AX,PortNumber
CALL VOCPtrToDriver
END;
END;
PROCEDURE VOCSetIRQ(IRQNumber : WORD);
{* INPUT : Interrupt number
* OUTPUT : None
* PURPOSE : Specifies interrupt number before initialization.}
BEGIN
ASM
MOV BX,2
MOV AX,IRQNumber
CALL VOCPtrToDriver
END;
END;
FUNCTION VOCInitDriver: BOOLEAN;
{* INPUT : None
* OUTPUT : Error message number, and initialization result
* PURPOSE : Initializes driver software. }
VAR
Out, VSeg, VOfs : WORD;
F : File;
Drivername,
Pdir : DirStr;
Pnam : NameStr;
Pext : ExtStr;
BEGIN
{ Search path for CT-VOICE.DRV driver }
Pdir := ParamStr(0);
Fsplit(ParamStr(0),Pdir,Pnam,Pext);
Drivername := Pdir+'CT-VOICE.DRV';
VOCInitDriver := TRUE;
{ Driver file not found }
IF Not Exists(Drivername) THEN BEGIN
VOCInitDriver := FALSE;
VOCErrStat := 100;
EXIT;
END;
{ Load driver }
Assign(F,Drivername);
Reset(F,1);
AllocateMem(VOCPtrToDriver,Filesize(F));
{ No memory can be allocated for the driver }
IF VOCPtrToDriver = NIL THEN BEGIN
VOCInitDriver := FALSE;
VOCErrStat := 110;
EXIT;
END;
Blockread(F,VOCPtrToDriver^,Filesize(F));
Close(F);
{ Driver file doesn't begin with "CT" - false driver }
IF (TypeCastType(VOCPtrToDriver^)[3]<>'C') OR
(TypeCastType(VOCPtrToDriver^)[4]<>'T') THEN BEGIN
VOCInitDriver := FALSE;
VOCErrStat := 120;
EXIT;
END;
{ Get version number and pass to global variable }
VOCDriverVersion := VOCGetVersion;
{ Start driver }
Vseg := Seg(VOCStatusWord);
VOfs := Ofs(VOCStatusWord);
ASM
MOV BX,3
CALL VOCPtrToDriver
MOV Out,AX
MOV BX,5
MOV ES,VSeg
MOV DI,VOfs
CALL VOCPtrToDriver
END;
{ No Sound Blaster card found }
IF Out = 1 THEN BEGIN
VOCInitDriver := FALSE;
VOCErrStat := 400;
EXIT;
END;
{ False port address used }
IF Out = 2 THEN BEGIN
VOCInitDriver := FALSE;
VOCErrStat := 410;
EXIT;
END;
{ False interrupt used }
IF Out = 3 THEN BEGIN
VOCInitDriver := FALSE;
VOCErrStat := 420;
EXIT;
END;
END;
PROCEDURE VOCDeInstallDriver;
{* INPUT : None
* OUTPUT : None
* PURPOSE : Disables driver and releases memory. }
VAR
Check : BOOLEAN;
BEGIN
IF VOCDriverInstalled THEN
ASM
MOV BX,9
CALL VOCPtrToDriver
END;
Check := VOCFreeBuffer(VOCPtrToDriver);
END;
PROCEDURE VOCSetSpeaker(OnOff:BOOLEAN);
{* INPUT : TRUE=Speaker on, FALSE=Speaker off
* OUTPUT : None
* PURPOSE : Sound Blaster output status. }
VAR
Switch : BYTE;
BEGIN
Switch := Ord(OnOff) AND $01;
ASM
MOV BX,4
MOV AL,Switch
CALL VOCPtrToDriver
END;
END;
PROCEDURE VOCOutput (BufferAddress : Pointer);
{* INPUT : Pointer to sample data
* OUTPUT : None
* PURPOSE : Plays sample. }
VAR
VSeg, VOfs : WORD;
BEGIN
VOCSetSpeaker(TRUE);
VSeg := Seg(BufferAddress^);
VOfs := Ofs(BufferAddress^)+VOCFileHeaderLength;
ASM
MOV BX,6
MOV ES,VSeg
MOV DI,VOfs
CALL VOCPtrToDriver
END;
END;
PROCEDURE VOCOutputLoop (BufferAddress : Pointer);
{* Different from VOCOutput :
* Speaker does not switch on with every sample output, so a
* crackling noise may occur with some Sound Blaster cards. }
VAR
VSeg, VOfs : WORD;
BEGIN
VSeg := Seg(BufferAddress^);
VOfs := Ofs(BufferAddress^)+VOCFileHeaderLength;
ASM
MOV BX,6
MOV ES,VSeg
MOV DI,VOfs
CALL VOCPtrToDriver
END;
END;
PROCEDURE VOCStop;
{* INPUT : None
* OUTPUT : None
* PURPOSE : Stops a sample. }
BEGIN
ASM
MOV BX,8
CALL VOCPtrToDriver
END;
END;
PROCEDURE VOCPause;
{* INPUT : None
* OUTPUT : None
* PURPOSE : Pauses a sample. }
VAR
Switch : WORD;
BEGIN
VOCPaused := TRUE;
ASM
MOV BX,10
CALL VOCPtrToDriver
MOV Switch,AX
END;
IF (Switch = 1) THEN BEGIN
VOCPaused := FALSE;
VOCErrStat := 510;
END;
END;
PROCEDURE VOCContinue;
{* INPUT : None
* OUTPUT : None
* PURPOSE : Continues a paused sample. }
VAR
Switch : WORD;
BEGIN
ASM
MOV BX,11
CALL VOCPtrToDriver
MOV Switch,AX
END;
IF (Switch = 1) THEN BEGIN
VOCPaused := FALSE;
VOCErrStat := 520;
END;
END;
PROCEDURE VOCBreakLoop(BreakMode : WORD);
{* INPUT : Break mode
* OUTPUT : None
* PURPOSE : Breaks a sample loop. }
BEGIN
ASM
MOV BX,12
MOV AX,BreakMode
CALL VOCPtrToDriver
MOV BreakMode,AX
END;
IF (BreakMode = 1) THEN VOCErrStat := 500;
END;
{$F+}
PROCEDURE VoiceToolsExitProc;
{$F-}
{* INPUT : None
* OUTPUT : None
* PURPOSE : De-installs voice driver. }
BEGIN
VOCDeInstallDriver;
ExitProc := OldExitProc;
END;
BEGIN
{* The following statements execute automatically, as soon as the
* unit is linked to a program, and the program starts. }
{ Replaces old ExitProc with new one from Tool unit }
OldExitProc := ExitProc;
ExitProc := @VoiceToolsExitProc;
{ Initialize values }
VOCStatusWord := 0;
VOCErrStat := 0;
VOCPaused := FALSE;
VOCFileHeaderLength := $1A;
VOCFileHeader :=
'Creative Voice File'+#$1A+#$1A+#$00+#$0A+#$01+#$29+#$11+#$01;
{* After installation, VOCDriverInstalled contains either TRUE or FALSE. }
VOCDriverInstalled := VOCInitDriver;
END.
{ ----------------------- DEMO PROGRAM --------------------------}
PROGRAM VToolTest;
{* VTTEST.PAS - uses VOCTOOL.TPU *}
{$M 16000,0,50000}
USES Crt,Voctool;
VAR
Sound : Pointer;
Check : BOOLEAN;
Ch : CHAR;
PROCEDURE TextNumError;
{* INPUT : None; data comes from the VOCErrStat global variable
* OUTPUT : None
* PURPOSE : Displays SB error on the screen as text, including the
error number. Program then ends at the error level
corresponding to the error number. }
BEGIN
Write(' Error #',VOCErrStat:3,' =');
PrintVOCErrMessage;
WriteLn;
HALT(VOCErrStat);
END;
BEGIN
ClrScr;
{ Driver not initialized }
IF Not(VOCDriverInstalled) THEN TextNumError;
{ Loads DEMO.VOC file into memory }
Check := VOCGetBuffer(Sound,'\SBPRO\MMPLAY\SBP.VOC');
{ VOC file could not be loaded }
IF Not(Check) THEN TextNumError;
{ Main loop }
Write('CT-Voice Driver Version : ');
WriteLn(Hi(VOCDriverVersion),'.',Lo(VOCDriverVersion));
WriteLn('(S)ingle play or (M)ultiple play?');
Write('Press a key : '); Ch := ReadKey;WriteLn;WriteLn;
CASE UpCase(Ch) OF
'S' : BEGIN
Write('Press a key to stop the sound...');
VOCOutput(Sound);
REPEAT UNTIL KeyPressed OR (VOCStatusWord = 0);
IF KeyPressed THEN VOCStop;
END;
'M' : BEGIN
Ch := #0;
Write('Press <ESC> to cancel...');
REPEAT
VOCOutputLoop(Sound);
REPEAT UNTIL KeyPressed OR (VOCStatusWord = 0);
IF KeyPressed THEN Ch := ReadKey;
UNTIL Ch = #27;
VOCStop;
END;
END;
{ Free VOC file memory }
Check := VOCFreeBuffer(Sound);
IF Not(Check) THEN TextNumError;
END.
[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]