{──────────────────────────────────────────────────────────────────────────}
{ Bells, Whistles, and Sound Boards. Version 1.02 }
{ Copyright (C) 1993-94, Edward Schlunder. All Rights Reserved. }
{══════════════════════════════════════════════════════════════════════════}
{ TP_MSE.PAS - Turbo Pascal <-> MSE Interface Unit file. }
{ Requires TPX_MSE.OBJ to compile. }
{ Written by Alex Chalfin (1994) }
{ }
{──────────────────────────────────────────────────────────────────────────}
Unit MSE_TP;
{$G+} { Enable 286 Instructions }
Interface
Type
{ GDM file header Type definition. See DOCs for more details}
GDMHeaderType = Record
IDString : Longint; { 'GDM■' = $FE4D4447 }
SongTitle : Array[0..31] of Char;
SongMusician : Array[0..31] of Char;
EOF : Array[0..2] of Char; { DOS EOF marker, 13,10,26 }
IDString2 : Longint; { 'GMFS' = $53464D47 }
FormatMajor : Byte;
FormatMinor : Byte;
TrackerID : Word;
TrackerMajor : Byte;
TrackerMinor : Byte;
PanMap : Array[0..31] of Byte;
InitVol : Byte;
InitTempo : Byte;
InitBPM : Byte;
MusicFlags : Word;
OrderOffset : Longint;
NumOrders : Byte;
PatternOffset: Longint;
NumPatterns : Byte;
OffsetSamHead: Longint;
OffsetSamData: Longint;
NumSamples : Byte;
OffsetMessage: Longint;
MessageLen : Longint;
OffsetScrolly: Longint;
ScrollyLen : Word;
OffsetGraph : Longint;
GraphLen : Word;
End;
Function LoadMSEASM(MSESeg, Ovr, BfSz : Word; Var Base : Word; Var IRQ, DMA : Byte) : Word;
Function LoadMSE(FileName : String; Ovr, BufferSize : Word; Var BaseIO : Word; Var IRQ, DMA : Byte) : Word;
Function StartOutput(Channels, Amp : ShortInt) : Word;
Function MixStatus : Word;
Function MusicStatus : Word;
Function MusicBPM(BPM : Byte) : Byte;
Function MusicTempo(Tempo : Byte) : Byte;
Function MusicOrder(Order : Byte) : Byte;
Function MusicPattern(Pat : Byte) : Byte;
Function MusicRow : Byte;
Function MusicLoop(LoopStatus : Byte) : Byte;
Function MusicVolume(Vol : Byte) : Byte;
Function ChannelPan(Chan, Pan : Byte) : Byte;
Function ChannelVU(Chan, Vu : Byte) : Byte;
Function ChannelVol(Chan, Volume : Byte) : Word;
Function LoadGDM(Handle : Word; FileOfs : Longint; Var Flags : Word; Var GHead) : Word;
Function EmsExist : Boolean;
Function OpenFile(Filename : String) : Word;
Procedure GetChannelTable(Chan : Byte; TSeg, TOff : Word);
Procedure FreeMSE;
Procedure StopOutput;
Procedure MixForground;
Procedure SetAutoMix(Mix : Byte);
Procedure StartMusic;
Procedure StopMusic;
Procedure GetSampleTable(Samp : Byte; TSeg, TOff : Word);
Procedure GetMainScope(Var Left, Right : Word);
Procedure UnloadModule;
Procedure CloseFile(Handle : Word);
Procedure PlaySample(Channel, Sample : Byte; Rate : Word; Volume, Pan : Byte);
Procedure AmigaHertz(Hertz : Longint);
Implementation
Const
EmmIdCode : Array[0..7] of Char = ('E','M','M','X','X','X','X','0');
{$F+}
{$L TPX_MSE.OBJ}
Function LoadMSEASM(MSESeg, Ovr, BfSz : Word; Var Base : Word; Var IRQ, DMA : Byte) : Word; External;
Function StartOutput(Channels, Amp : ShortInt) : Word; External;
Function MixStatus : Word; External;
Function MusicStatus : Word; External;
Function MusicBPM(BPM : Byte) : Byte; External;
Function MusicTempo(Tempo : Byte) : Byte; External;
Function MusicOrder(Order : Byte) : Byte; External;
Function MusicPattern(Pat : Byte) : Byte; External;
Function MusicRow : Byte; External;
Function MusicLoop(LoopStatus : Byte) : Byte; External;
Function MusicVolume(Vol : Byte) : Byte; External;
Function ChannelPan(Chan, Pan : Byte) : Byte; External;
Function ChannelVU(Chan, Vu : Byte) : Byte; External;
Function ChannelVol(Chan, Volume : Byte) : Word; External;
Function LoadGDM(Handle : Word; FileOfs : Longint; Var Flags : Word; Var GHead) : Word; External;
Procedure FreeMSE; External;
Procedure StopOutput; External;
Procedure MixForground; External;
Procedure SetAutoMix(Mix : Byte); External;
Procedure StartMusic; External;
Procedure StopMusic; External;
Procedure GetChannelTable(Chan : Byte; TSeg, TOff : Word); External;
Procedure GetSampleTable(Samp : Byte; TSeg, TOff : Word); External;
Procedure GetMainScope(Var Left, Right : Word); External;
Procedure UnloadModule; External;
Procedure AmigaHertz(Hertz : Longint); External;
Procedure PlaySample(Channel, Sample : Byte; Rate : Word; Volume, Pan : Byte); External;
{$F-}
Function LoadMSE(FileName : String; Ovr, BufferSize : Word; Var BaseIO : Word; Var IRQ, DMA : Byte) : Word;
Var
Diskfile : File; { Binary file }
Size : Word; { Size of file }
MSESeg : Word; { Segment pointer to MSE memory location }
P : Pointer;
ReadIn : Word; { Number of bytes read in }
Begin
Assign(Diskfile, FileName);
{$I-}
Reset(Diskfile, 1);
{$I+}
If IOResult <> 0
Then Begin
LoadMSE := 11; { MSE diskread error, file not found }
Exit;
End;
Size := FileSize(Diskfile); { Get size of MSE file }
Asm
Mov ah,48h { Allocate memory for MSE using DOS to }
Mov bx,Size { ensure a segment boundary }
Shr bx,4
Inc bx
Int 21h
Jnc @AllocOK
Mov ax,$FFFF { An error has occured }
@AllocOK:
Mov MSESeg,ax
End;
If MSESeg = $FFFF
Then Begin
LoadMSE := 9; { Couldn't allocate memory }
Exit;
End;
P := Ptr(MSESeg, 0); { Create a temporary FAR pointer to allocated memory }
BlockRead(Diskfile, P^, Size, Readin);
If Readin <> Size
Then Begin
LoadMSE := 11; { MSE read error }
Exit;
End;
Close(Diskfile);
LoadMSE := LoadMSEASM(MSESeg, Ovr, BufferSize, BaseIO, IRQ, DMA);
End;
Function OpenFile(Filename : String) : Word;
{ Bypasses TP's file handling routines. }
{ Uses handles instead of file control blocks. }
{ in : Filename - Name of file to open }
{ out: $FFFF - Error opening file or file not }
{ found. }
{ Anything else - File handle }
Var
TempP : Pointer;
Handle : Word;
Begin
Filename := FileName + #0; { Make an ASCIIZ string }
TempP := @Filename; { Get a pointer to filename }
Asm
Push ds
Lds dx,TempP
Inc dx { Get past length byte }
Mov ax,$3D02
Int 21h { Get a file handle using DOS }
Jnc @OpenOK
Mov ax,$FFFF { An error has occured }
@OpenOK:
Pop ds
Mov Handle,ax
End;
OpenFile := Handle;
End;
Procedure CloseFile(Handle : Word); Assembler;
{ Closes a file via handle }
{ in: Handle - filehandle of file to close }
{ out : nothing }
Asm
Mov ah,$3E
Mov bx,Handle
Int 21h
End;
Function EmsExist : Boolean; Assembler;
{ Checks to see if EMS memory exists }
{ Returns TRUE/FALSE }
Asm
Xor ax, ax
Mov es, ax
Mov bx, 19Eh
Mov ax, es:[bx]
Mov es, ax
Mov cl, 8
Mov si, 10
Xor bx, bx
@CmpLoop:
Mov al, es:[si]
Cmp al, Byte Ptr ds:[EmmIdCode+bx]
Jne @EmsNoExist
Inc si
Inc bx
Dec cl
Jnz @CmpLoop
@EmsYesExist:
Mov ax, 0FFFFh
Ret
@EmsNoExist:
Xor ax, ax
End;
End.