Making a basic GDM player
Not a lot of introduction here, I'm just going to cut to the chase. Writing a program to play
BWSB's GDM format files can be a real pain, so I'm going to keep it simple at first and then
get more detailed and complex as time goes on.
FIRST...load up QB with QB /L MSE_QB (for 4.5) or QBX /L MSE_PDS (for PDS)
This will load the BWSB library. Now, you can start writing your program. The first three major
steps are going to be:
DEFINT A-Z
'$INCLUDE: 'BWSB.BI'
'$INCLUDE: 'GDMTYPE.BI'
BWSB requires integers and those two include files to operate. Failure to follow these first few
steps WILL RESULT IN A CRASH AND POSSIBLE LOSS OF DATA.
So, with that done, you'll want to keep the rest simple as well, and the best way of doing
that is by following pre-built code. Here are a few declarations you'll want to make somewhere
at the start of your module:
TYPE MSEConfigFile
SoundCard AS INTEGER
BaseIO AS INTEGER
IRQ AS INTEGER
DMA AS INTEGER
SoundQuality AS INTEGER
END TYPE
That section makes it easier to load the MSE driver file you choose. BWSB requires a driver
file, called a Music and Sound Engine, or MSE for short. A file called MSE.CFG can be used
to keep this data. However, this is not needed as you can write your own routines, but for
now lets keep it simple.
DIM ModHead AS GDMHeader
ModHead is used for the GDM module. It is used internally by BWSB, so no need to go into
great detail, just make sure that code is added.
DIM SndDevMSE(6) AS STRING
This is another part of the easy MSE load.
DIM MSEConfig AS MSEConfigFile
This is yet another part of the easy MSE load. In fact, this makes setting the device
settings later SO much easier.
Freemem& = FRE(-1) - 80000
A& = SETMEM(-Freemem&)
What this segment does is free up 80K of far heap memory. This is needed for the MSE files,
plus the patterns. Don't worry if this doesn't make sense right now, if you need to know
what this all means, consult the help file in QB.
SndDevMSE(1) = "GUS" 'Gravis Ultrasound
SndDevMSE(2) = "SB1X" 'Sound Blaster 1.xx
SndDevMSE(3) = "SB2X" 'Sound Blaster 2.xx
SndDevMSE(4) = "SBPRO" 'Sound Blaster Pro
SndDevMSE(5) = "SB16" 'Sound Blaster 16
SndDevMSE(6) = "PAS" 'Pro AudioSpectrum 16
The six MSE files, this part is also part of the easy load.
OPEN "MSE.CFG" FOR BINARY AS #1
GET #1, , MSEConfig
CLOSE #1
In this last segment, the MSE.CFG file is opened and read. From here on in, it's smooth
sailing!
IF MSEConfig.SoundCard = 0 THEN
PRINT "No Sound Selected in SETUP. Please run SETUP."
END
END IF
If a soundcard has not been specified, obviously sound will not be available!
MSE$ = SndDevMSE(MSEConfig.SoundCard) + ".MSE"
Easy loading stuff again...
SELECT CASE MSEConfig.SoundQuality
CASE 0: Ov = 16
CASE 1: Ov = 22
CASE 2: Ov = 45
CASE 3: Ov = 8
END SELECT
MSEConfig.SoundQuality sets the variable Ov, which is the Oversampling rate at which sound
plays. The higher the oversampling, the better sounding the music, but in most cases, the
more processor time taken. The exception to this rule is the presence of a GUS card with
1MB or more of DRAM.
ErrorFlag = LoadMSE(MSE$, 0, Ov, 4096, MSEConfig.BaseIO, MSEConfig.IRQ, MSEConfig.DMA)
This last fragment is all it takes to load the MSE. Also, it handles any errors that could occur,
and many are possible!
SELECT CASE ErrorFlag
CASE 0
CASE 1: PRINT "Base I/O address autodetection failure": END
CASE 2: PRINT "IRQ level autodetection failure": END
CASE 3: PRINT "DMA channel autodetection failure": END
CASE 4: PRINT "DMA channel not supported": END
CASE 6: PRINT "Sound device does not respond": END
CASE 7: PRINT "Memory control blocks destroyed": END
CASE 8: PRINT "Insufficient memory for mixing buffers": END
CASE 9: PRINT "Insufficient memory for MSE file": END
CASE 10: PRINT "MSE has invalid identification string (corrupt/non-existant)": END
CASE 11: PRINT "MSE disk read failure": END
CASE 12: PRINT "MVSOUND.SYS not loaded (required for PAS use)": END
CASE ELSE: PRINT "Unknown error on MSE startup" + STR$(ErrorFlag): END
END SELECT
This last section is a monstrous error-notice. If the ErrorFlag is 0, then the operation is a
success. If anything goes wrong, the program will quit with an error. If this is not done, the
computer will lock up. This could be trimmed to just quit if ANY error occurred.
IF LEN(COMMAND$) = 0 THEN INPUT "Module file: ", ModFile$ ELSE ModFile$ = COMMAND$
Here is the example from MMP.BAS about how to specify a filename. All you have to do really
is set ModFile$. This can be done in a number of ways, this is just one of them.
TestMOD:
IF LEN(ModFile$) = 0 THEN END
IF INSTR(ModFile$, ".") = 0 THEN ModFile$ = ModFile$ + ".GDM"
This last fragment of code is MMP.BAS's way of 'testing' the filename.
IF EmsExist THEN ErrorFlag = 1 ELSE ErrorFlag = 0
One of the greatest assets to BWSB is its use of EMS. It can allocate as much EMS as it
needs to play sound files, up to the RAM limit in your computer.
File = FREEFILE
A great way of determining a file handle to open is by using the FREEFILE command. It will
open the next available file handle. Available file handles are set by the FILES line
in CONFIG.SYS.
OPEN ModFile$ FOR BINARY AS File
GDM files are stored in binary format, so open it as such.
LoadGDM FILEATTR(File, 2), 0, ErrorFlag, VARSEG(ModHead), VARPTR(ModHead)
Load that sucker up! And go through extensive error testing...
SELECT CASE ErrorFlag
CASE 0
CASE 1: PRINT "Module is corrupt": END
CASE 2: PRINT "Could not autodetect module type": END
CASE 3: PRINT "Bad format ID": END
CASE 4: PRINT "Out of memory": END
CASE 5: PRINT "Cannot unpack samples": END
CASE 6: PRINT "AdLib samples not supported": END
CASE ELSE: PRINT "Unknown Load Error:" + STR$(ErrorFlag): END
END SELECT
Errors R Us...attempting to play a corrupt GDM file leads to disaster!
MusicChannels = 0
FOR J = 1 TO 32
IF ASC(MID$(ModHead.PanMap, J, 1)) <> &HFF THEN
MusicChannels = MusicChannels + 1
END IF
NEXT
Here, the program uses a sneaky way of detecting how many channels to allocate. BWSB can
allocate up to 32 channels, but unless you're using a GUS card, more channels means more
CPU power.
OverRate& = StartOutput(MusicChannels, 0)
Here, the output is initialized. Only one step left to getting the music going...
StartMusic
How simple! Whew! What a simple final step.
Now, when you wish to cancel the music, you should do this:
StopMusic
StopOutput
UnloadModule
FreeMSE
FreeMSE should only be used when you no longer need sound, like when you are ending the
program. However, one of the nice things about QB is that FreeMSE is called when QB ends
a program, so calling it is not really necessary. How-ever, it is ALWAYS a good idea to
call it anyways...you just never know!
So, if you wish, just cut and paste the code into your program! It's that simple. Oh, and
be sure to use the SETUP.EXE program that comes with the BWSB package to configure your
MSE.CFG file. As it stands, using this code without an MSE.CFG file will make it lock up!
So, use the SETUP.EXE or add error detection in the loading (more on that later...)
Woohoo! This completes the hardest part of using BWSB! If you can master this then the rest
is easy.
This article was written by Nekrophidius
© Copyright 1999-2000 The QB Times.
This tutorial was taken from The QB Times with permission from the webmaster(s)
of the site. You may not take this article and place it on any other website.