'****************************************************** '* * '* File Name: CMSMOD.BAS * '* * '* Description: Contains all the source code * '* necessary to play Creative Music * '* System (CMS) files using a CMS * '* compatable card (GameBlaster or * '* SoundBlaster) and CMS driver * '* (CMSDRV.COM). This file may be * '* loaded as a program or a module. * '* * '* Requirements: CMSDRV resident in memory. * '* Interruptx in QuickLib * '* (i.e. QW.QLB). * '* * '****************************************************** DEFINT A-Z TYPE RegTypeX ax AS INTEGER bx AS INTEGER cx AS INTEGER dx AS INTEGER bp AS INTEGER si AS INTEGER di AS INTEGER flags AS INTEGER ds AS INTEGER es AS INTEGER END TYPE DECLARE SUB CmsPlayMusic (Repeats%) DECLARE SUB CmsVersion (version$) DECLARE SUB CmsFindDriver (IntNum%, version$) DECLARE SUB CmsPauseMusic () DECLARE SUB CmsContinueMusic () DECLARE SUB CmsStopMusic () DECLARE SUB WaitForKey (Key$) DECLARE SUB GetFileName (FileSpec$) DECLARE SUB GetCmsFile (FileSpec$) DECLARE SUB OpenCmsFile (FileSpec$) CONST False = 0, True = NOT False DIM SHARED Reg88X AS RegTypeX ' Make all arrays DYNAMIC so the .CMS file won't get relocated ' and cause CMSDRV to lose track of it. '$DYNAMIC ' The PlayFlag is used to synchronize the user program with the music. DIM PlayFlag AS INTEGER ' CmsSong array is the .CMS file loaded from disc. DIM CmsSong(0) AS STRING * 32767 CLS ' Set the default number of plays to 1. Repeats = 1 ' Call the routine that finds the driver interrupt number and version. CmsFindDriver IntNum, version$ SELECT CASE IntNum CASE IS = False PRINT "CMSDRV is not installed." END CASE ELSE ' Users should modify these 2 lines to do what ever they want with ' the version number (i.e. check to see if it is 3.00 or greater) ' and interrupt number. PRINT "CMSDRV Version "; version$ PRINT "CMSDRV is using interrupt &H"; HEX$(IntNum) END SELECT ' Go get the name of the .CMS file to be played... GetFileName FileSpec$ ' ...and load it into memory. GetCmsFile FileSpec$ ' This is the main part of the program. The one shown is a mini program ' just to demonstrate how the routines are used. DO WaitForKey Key$ SELECT CASE Key$ CASE "T" CmsStopMusic CASE "P" CmsPauseMusic CASE "C" CmsContinueMusic CASE "S" CmsPlayMusic Repeats CASE "Q" CmsStopMusic END CASE "N" GetFileName FileSpec$ CmsStopMusic GetCmsFile FileSpec$ END SELECT LOOP REM $STATIC 'This sub continues music play after a pause. 'Entry conditions: ' AH = 3 'Exit conditions: ' AX = 0 successful ' AX = 1 no song had been paused ' SUB CmsContinueMusic Reg88X.ax = &H300 CALL Interruptx(&H80, Reg88X, Reg88X) END SUB 'This sub disables the CMS break function (CTRL-Keypad5) 'Entry conditions: ' AH = 5 'Exit conditions: ' None ' SUB CmsDisableBreak Reg88X.ax = &H500 CALL Interruptx(&H80, Reg88X, Reg88X) END SUB 'This sub searches for the CMS driver CMSDRV.COM beginning at the INT 80h 'jump address thru INT 0BFh. When the SUB finds the string "CMSDRV" at 'offset 104h of the interrupt, the interrupt number used by CMSDRV.COM is 'returned to the main program. ' SUB CmsFindDriver (Inter, Ver$) CONST CMSDRV$ = "CMSDRV" CONST MaxInter = &HBF, StartInter = &H80 RightString = False Inter = StartInter DO DEF SEG = 0 SegmentLo = PEEK((Inter * 4) + 2) SegmentHi = PEEK((Inter * 4) + 3) Segment = SegmentHi * 256 + SegmentLo DEF SEG = Segment Offset = &H104 i = 1 DO x$ = CHR$(PEEK(Offset)) IF x$ = MID$(CMSDRV$, i, 1) THEN RightString = True Offset = Offset + 1 i = i + 1 ELSE RightString = False END IF LOOP WHILE (RightString = True) AND (i <= LEN(CMSDRV$)) IF RightString = True THEN CmsVersion Ver$ EXIT DO END IF Inter = Inter + 1 LOOP WHILE (Inter <= MaxInter) DEF SEG IF Inter > MaxInter THEN Inter = False END SUB 'This sub pauses the music currently playing. 'Entry conditions: ' AH = 2 'Exit conditions: ' AX = 0 successful ' AX = 1 no music was being played ' SUB CmsPauseMusic Reg88X.ax = &H200 CALL Interruptx(&H80, Reg88X, Reg88X) END SUB 'This sub plays music from a .CMS music file. 'Entry conditions: ' AH = 1 ' AL = number of times to play (1-255; 0 for non-play) ' ES = segment address of PLAY-FLAG ' BX = offset address of PLAY-FLAG ' CX = segment of music score (.CMS file in memory) 'Exit conditions: ' AX = 0 successful ' AX = 1 non-CMS file structure ' AX = 2 wrong COMPOSEr version ' SUB CmsPlayMusic (Rpts) SHARED PlayFlag AS INTEGER SHARED CmsSong() AS STRING * 32767 Dummy& = FRE("") PfSeg = VARSEG(PlayFlag) PfOff = VARPTR(PlayFlag) MSeg = VARSEG(CmsSong(0)) Reg88X.ax = &H100 + Rpts Reg88X.es = PfSeg Reg88X.bx = PfOff Reg88X.cx = MSeg CALL Interruptx(&H80, Reg88X, Reg88X) END SUB 'This sub stops playing the current music. 'Entry conditions: ' AH = 4 'Exit conditions: ' None ' SUB CmsStopMusic Reg88X.ax = &H400 CALL Interruptx(&H80, Reg88X, Reg88X) END SUB ' This sub gets the the version number of the .CMS driver and returns ' it as Ver$. ' SUB CmsVersion (Ver$) Reg88X.ax = 0 CALL Interruptx(&H80, Reg88X, Reg88X) SELECT CASE LEN(HEX$(Reg88X.ax)) CASE IS = 3 Ver$ = LEFT$(HEX$(Reg88X.ax), 1) + "." + RIGHT$(HEX$(Reg88X.ax), 2) CASE IS = 4 Ver$ = LEFT$(HEX$(Reg88X.ax), 2) + "." + RIGHT$(HEX$(Reg88X.ax), 2) END SELECT END SUB ' This routine loads a .CMS file (FSpec$) from disc ' into CmsSong array. ' SUB GetCmsFile (FSpec$) SHARED CmsSong() AS STRING * 32767 OPEN FSpec$ FOR BINARY AS #1 GET #1, , CmsSong(0) CLOSE #1 END SUB SUB GetFileName (FileSpec$) GoodFile = True LOCATE 3, 1 PRINT SPACE$(79) LOCATE 10, 1 INPUT "Which drive and path"; Drive$ FILES Drive$ + "*.cms" DO LOCATE 3, 1 LINE INPUT "Enter CMS file name: "; FileSpec$ LOOP WHILE GoodFile = False FileSpec$ = Drive$ + FileSpec$ END SUB SUB WaitForKey (K$) LOCATE 5, 1 PRINT "N)ew file, S)tart, C)ontinue, P)ause, T)erminate, Q)uit: "; DO K$ = INKEY$ LOOP WHILE K$ = "" K$ = UCASE$(K$) PRINT K$; END SUB