	How to use the WMix unit for Delphi (USEWMIX.TXT)

	Welcome to WaveMix, Microsoft's sound-mixing utility for Windows 3.1
and up. Although the other text files describe the WaveMix DLL in some detail,
this text gives the information necessary to use it with Borland's Delphi
language/environment. I originally wrote the WMix import module to support
a sound-playing utility I wrote in May of 1995. This utility, WAVe Blender, is
available in shareware form in Compuserve (WAVBLN.ZIP), and allows the user
to play multiple Wave files simultaneously. Since I found this module useful, I
am making it available to other Delphi programmers to use as they see fit.

I.		INTRODUCTION

1)	What is WMix?

	WMix is a Delphi import module for Microsoft's WaveMix DLL. It provides
access to all of WaveMix's functions, as well as defining the data structures
and flags used by WaveMix in a format usable by Delphi.

2)	What is an 'import module'?

	An import module is a Delphi unit that allows the Delphi compiler to
access an existing executable file or dynamic-link library as a set of function
and procedure calls. It can then be attached to any other Delphi project or
unit through the unit's 'USES' clause.

3)	What does WMix contain?

	WMix implements the twelve WaveMix functions (WMixInit, WMixConfigure,
WMixActivate, WMixWave, WMixPlay, WMixChannel, WMixFlush, WMixClose, WMIxFree,
WMixExit, WMixPump and WMixGetInfo), the data structures (WMixInfo, WMixConfig,
WMixParams and WMixMessage) and the Bit flags used for these routines.

4)	What do I require to use the WMix unit?

	In addition to Delphi, WMix requires a version of WAVEMIX.DLL and the
associated WAVEMIX.INI file. These MUST both be included with the compiled EXE
file for it to operate (WHERE they are included is up to you, as long as the
final program knows where they can be found)

5)	Do I have to pay a licensing fee to distribute a program that uses
	the WMix unit?

	Since WaveMix is distributed license-free by Microsoft, any sort of
formal licensing agreement is out of the question (although you CAN charge for
a complete program which uses WAVEMIX.DLL). I only request that any Delphi code
and the documentation for the final executable program contain a statement like:

	WaveMix DLL Import Module May 1995 by Gavin R. Kujawa


II.		ADDING WMix TO YOUR DELPHI PROJECT

	There are only two steps involved in adding the WMix unit to a Delphi
project:

1)	Copy all necessary files to your system. There are only four files that
need to be properly located; WMIX.PAS (and optionally, WMIX.DCU) should be in
the source directory for your project, while WAVEMIX.DLL and WAVEMIX.INI MUST
be located TOGETHER in any directory. Although the WAVEMIX files can be put in
any directory as long as they are together, it is easiest to locate them in the
same directory as your final executable file (to avoid having to tell the
executable file where they ARE located when you run it).

2)	Add the WMix unit to the 'USES' clause of the units which employ it. The
'USES' clause is at the beginning of each unit. For example:

	unit PlaySound

	interface

	uses
	  SysUtils, WinTypes, ..., ExtCtrls, WMix;

	If WMix is to be used by several units in the same project, it is best
to add it to the 'USES' clause of all those units; it CAN be used by reference
to another unit that utilizes it, but I have found that to cause irregularities
in accessing it.

	Of course, it is one thing to add WMix to a project, and quite another
to actually USE it. Thus, without further delay, ...


III.		HOW TO USE THE WMix UNIT

	The WMix unit allows you to fully utilise the WaveMix DLL in any Delphi
project. All of the functions, data structures and bit flags described in the
WaveMix documentation appear in the WMix unit, although they have slightly
different (and usually shorter) names there. A complete listing of the functions
and procedures in the WMix unit, as well as their associated data structures and
flags, follows. Note that ALL of the functions, procedures, flags and data
structures, although discussed in some detail below, are part of the WMix unit
and are fully accessable by any other unit that includes WMix in its 'USES'
clause (i.e. you do NOT have to define them), although you MUST declare any of
the data structures you need to use within your unit (for example, to use WMix
at all, you need to declare a variable somewhere in your unit as being of type
TWMixParams [var MixParams: TWMixParams;]).

1)	WMixInit: word; {WaveMixInit}

	This function initializes the WaveMix DLL using the data that appears in
the WAVEMIX.INI file. It returns the Windows handle of the WaveMix session; you
MUST record this result, since almost all of the other WMix calls use it. Once
this function (or WMixConfigure) is used, WaveMix is on and ready for use

	Example: MySession := WMixInit; {Start WaveMix & get Session handle}


2)	WMixConfigure(Config: TWMixConfig): word; {WaveMixConfigureInit}

	This function ALSO initializes WaveMix and returns the session handle,
but it also sets the playback format for WaveMix (see ABSTRACT.TXT and
WAVEMIX.TXT for exact details). The WMixConfig data structure is defined in the
WMix unit as follows:

	TWMixConfig = record
		Size: word;	{Size of the WMixConfig record}
		Flags: longint;	{Bit Flags: Must be ORed with both ...}
		Channels: word;	{1(mono) or 2(stereo) AND ...}
		SampRate: word;	{11, 22 or 44 kBd}
	end;

	The Bit flags used by WMixConfigure are:

		WMix_Channels: longint = 1;	{Setting Channels}
		WMix_SamplingRate: longint = 2;	{Setting Sampling Rate}

	Using WMixConfigure allows you to set the exact playback rate and stereo
format you want to use. If you use the WMixInit function, WaveMix will load and
play your wave files REGARDLESS of their format but will CONVERT them to the
format specified in the WAVEMIX.INI file before playing them! You should use
WMixConfigure if you plan to play Stereo or high-resolution (44kBd) Wave files.

	Example: (MixCfg was declared as TWMixConfig)
		with MixCfg do begin
		  Flags := WMix_SamplingRate + WMix_Channels;
		  Channels := (2 or Flags); {Stereo}
		  SampRate := (44 or Flags); {44 kBd playback rate}
		  Size := SizeOf(MixCfg); {Get Record size}
		end;
		MySession := WMixConfigure(MixCfg); {Start WaveMix & get Handle}


3)	WMixActivate(Session: word; Activate: boolean); {WaveMixActivate}

	This procedure activates and deactivates WaveMix playback and gains
control of/releases the Windows Wave player. In addition to starting and
stopping playback, this also allows other programs to access the Wave player but
keeps WaveMix active and ready to regain control of the player upon request. Use
it when you pause your main routine or whenever control of the Wave player must
be transferred to or from another program. 'Session' is the Session handle you
obtained when you started WaveMix (with WMixInit or WMixConfigure), while
'Activate' is true to activate WaveMix, false to deactivate it. You MUST
activate WaveMix to begin playing Waves with it!

	Example: WMixActivate(MySession, true); {Reactivate WaveMix}


4)	WMixWave(Session: word; Wave: PChar; Instance: word; Flags: longint)
		: pointer {WaveMixOpenWave}

	This function opens a Wave file, loads it into memory and returns a
pointer to the memory location of the file. This pointer is used by WMixPlay
and WMixFree to access the Wave files for WaveMix. Session is the WaveMix
Session handle (from WMixInit or WMixConfigure). Wave is (a pointer to) a null-
terminated string that contains the Wave file name/path (use StrPCopy to convert
a Pascal-type file path into null-terminated form: look it up in Delphi Help
for more details). Instance is the instance of an executable file that contains
the Wave file as a resource; use this ONLY if you are using a Wave file that was
compiled into another program, set it to 'zero' for any other use. Flags is one
of the following:

	WMix_File: longint = 1;		{Load Wave from disk}
	WMix_Resource: longint = 2;	{Load Wave from resource}
	WMix_Memory: longint = 4;	{Load Wave from memory}

	Example:(NTString is a character array; i.e. a null-terminated string)
		if OpenDialog1.Execute then begin
		  StrPCopy(NTString, OpenDialog1.FileName); {Convert file path}
		  MyWave := WMixWave(MySession, NTString, 0, WMix_File);{Load}
		end;

	(Note: Delphi allows a null-terminated string to be passed by direct
reference as shown above. This makes this usage MUCH easier)


5)	WMixChannel(Session: word; Channel: integer; Flags: longint);
		{WaveMixOpenChannel}

	This procedure opens one or more of the eight WaveMix playback channels.
You MUST open at least one channel before you can play sounds with WaveMix.
Session is the Session handle you obtained from WMixInit or WMixConfigure.
Channel is (depending on which flags are set) the channel number you wish to
open (0 to 7) or the number of channels you want opened (1 to 8). The following
Bit flags determine how Channel is interpreted:

	WMix_OpenSingle: longint = 0;	{Open channel # 'Channel'}
	WMix_OpenAll: longint = 1;	{Open ALL channels, ignoring 'Channel'}
	WMix_OpenCount: longint = 2;	{Open 'Channel' channels}

	Examples: (to demonstrate the effects of the flags)
		WMixChannel(MySession, 2, WMix_OpenSingle); {Channel 2 open}
		WMixChannel(MySession, 2, WMix_OpenCount); {Channels 0 & 1 open}
		WMixChannel(MySession, 2, WMix_OpenAll); {Channels 0 to 7 open}


6)	WMixPlay(Params: TWMixParams); {WaveMixPlay}

	This is the crucial WMix procedure; the routine that actually plays the
previously-loaded Wave files. Its simplicity conceals a wealth of information
that is necessary to play a Wave file. First, the single parameter is a data
structure that is described below:

	TWMixParams = record
		Size: word;		{Total size of the record}
		Session: word;		{The WaveMix Session handle. See above}
		Channel: integer;	{Play on channel # (0 to 7)}
		Wave: pointer;		{The Memory pointer from WMixWave}
		Notify: word;		{Notify Handle. See below}
		Flags: longint;		{Bit flags. Also see below}
		Loops: word;		{Automatic loop. See below}
	end;

	The first four items are all explained in the preceeding section of this
document. Loops is the number of times you want to repeat the sound (yes, this
is done AUTOMATICALLY by WaveMix); this can be 'zero' (don't repeat) to 65534
times (65535 - FFFF hex - indicates an infinite loop). Notify is the Windows
handle of a program you want to be notified when that sound is finished; you
should use the Handle property of the Form that will respond to the message
(i.e. Params.Notify := Form1.Handle;). The message used by WaveMix to indicate
that a sound is finished is 'MM_WOM_DONE' (03BD hex), while it uses the message
format described below:

	TWMixMessage = record
		Msg: integer;		{MM_WOM_DONE; $03BD}
		Channel: integer;	{Channel just played upon}
		Wave: pointer;		{Wave file pointer from WMixWave}
		Result: longint;	{Apparently not used by WaveMix}
	end;

(See Delphi Help and the Component Writer's Help for details on how to handle
Windows messages.)

	The Bit flags for WMixPlay are as follows:

	WMix_QueueWave: longint = 0;	{Wait until selected Channel is clear
					before playing this sound}
	WMix_ClearQueue: longint = 1;	{Replace whatever sound is currently
					playing on selected Channel}
	WMix_UseLRUChannel: longint = 2;{Ignore Channel; play on next open
					channel or on least recently used
					channel. Produces barrage/echo effect.}
	WMix_HiPriority: longint = 4;	{Remix Play buffer immediately. Playing
					may be delayed by up to 1/2 second if
					not set, depending on computer speed}
	WMix_Wait: longint = 8;		{Puts current sound on a 'waiting list'
					and delays playing until WMixPlay is
					called with this bit clear; will then
					play ALL WAITing sounds at once}

(See WAVEMIX.TXT for more detailed descriptions of the Flags' effects)

	Example: ('Params' previously declared as TWMixParams)
		with Params do begin
		  Session := MySession; {WaveMix Session handle}
		  Channel := 0; {Play on Channel #0}
		  Wave := MyWave; {Wave Memory pointer; see 4) above}
		  Loops := 0; {Don't loop}
		  Notify := MainForm.Handle; {Tell us when it's done}
		  Flags := WMix_ClearQueue + WMix_HiPriority; {Play it NOW!}
		  Size := SizeOf(Params); {Get structure size}
		end;
		WMixPlay(Params); {Finally, play that sound}


7)	WMixFlush(Session: word; Channel: integer; Flags: longint);
		{WaveMixFlushChannel}

	This procedure clears everything that is playing on one or all of the
WaveMix play channels, including looping sounds and ones in the queue for that
channel. This effectively silences that channel; calling WMixFlush with the
WMix_FlushAll flag set will completely stop ALL sound play but leave all of
the play channels open and WaveMix ready to play (compare with WMixClose below).
Session is the WaveMix Session handle, Channel is the channel number to be
flushed, and the Flags are described below:

	WMix_FlushAll: longint = 1;	{Ignore Channel, flush all channels}
	WMix_NoRemix: longint = 2;	{Do not remix the WaveMix buffer; will
					delay the onset of the channel flush}

	Example:WMixFlush(MySession, 4, WMix_NoRemix);{Clear Channel 4,No remix}


8)	WMixClose(Session: word; Channel: integer; Flags: longint);
		{WaveMixCloseChannel}

	This procedure works in the same way as WMixFlush, but it also closes
the selected WaveMix channel, preventing sounds from being played on it until it
is reopened. The only Flag that effects it is WMix_FlushAll, which closes ALL of
the currently open channels.

	Example: WMixClose(MySession, 0, WMix_FlushAll); {Close all channels}


9)	WMixFree(Session: word; Wpointer: pointer); {WaveMixFreeWave}

	This procedure closes a currently loaded Wave file (opened by WMixWave)
and unloads it from memory. Session is the WaveMix Session handle, and Wpointer
is the memory pointer to the Wave data loaded by WMixWave.

	Example: WMixFree(MySession, MyWave); {Close MyWave}


10)	WMixExit(Session: word); {WaveMixCloseSession}

	This procedure shuts down WaveMix, stopping all sound play and ending
the selected WaveMix session. Session is the WaveMix Session handle.

	Example: WMixExit(MySession); {Exit WaveMix}


11)	WMixPump; {WaveMixPump}

	This procedure sends a message that causes the currently running WaveMix
session (regardless of handle) to feed the current buffer to the Wave device and
begin mixing the sound data in the next available buffer. This is used to force
WaveMix to catch up with your program if, for example, the program will handle
some other information and needs to tie up the processor (WaveMix will continue
to play the Wave buffers, but will not mix sounds or release new buffers while
the program is executing). See WAVEMIX.TXT for more information.

	Example: WMixPump; {Clear the WaveMix buffer before we start this}


12)	WMixGetInfo(Info: TWMixInfo): word; {WaveMixGetInfo}

	This function is used to get the version, compilation date and supported
PCM formats from the WaveMix DLL. WMixInfo is a data structure that is defined
as follows:

	TWMixInfo = record
		Size: word;	{Size of record}
		Vmajor: byte;	{'Major' version # (i.e. '#.')}
		Vminor: byte;	{'Minor' version # (i.e. '.#')}
		Date: array[0..11] of char; {Compilation date as Null-t. string
						'mmm dd yyy[null]'}
		Formats: longint;{PCM formats supported as Bit flags}
	end;

(Note that, although the Formats are listed in WAVEMIX.TXT, the exact values of
the Bit flags are NOT. This shouldn't be important for most uses.)

	It is also important to note that WMixGetInfo is a function call that
uses the record it is going to fill as an argument, not as its return value!
What WaveMix does is this; it examines the 'Size' field of the record and checks
that it is the size that it was expecting. If the 'Size' is correct, WaveMix
enters the correct information into the WMixInfo record and returns a value of
'zero'. If the size is different, WaveMix does nothing to the record and returns
the record size that it expected.

	Example: (MixInfo is TWMixInfo; VersNo and CompDate are strings)
		MixInfo.Size := SizeOf(MixInfo); {Get record size}
		Success := WMixGetInfo(MixInfo); {Pass MixInfo to WaveMix}
		if Success = 0 then begin {If successful in getting version ...}
		  VersNo := IntToStr(MixInfo.Vmajor) + '.'; {Major version #}
		  VersNo := VersNo + IntToStr(MixInfo.Vminor); {Minor vers #}
		  CompDate := StrPas(MixInfo.Date); {Convert Date to Pascal}
		  Insert(',', CompDate, 7); {Put comma after 'day'}
		end;


IV)		CONCLUSION

	That is basically it for the WMix unit. You should now be able to use it
in your Delphi projects with little or no difficulty. If you do have problems
with WaveMix or the WMix unit, you can contact me (Gavin R. Kujawa) through
CompuServe at 72070,3217.

	My acknowledgements are to:

	Borland International, for creating Delphi (Hot Stuff!)

	Microsoft, for allowing unlimited free use of WaveMix

	Kevin T. Kujawa, for guiding me through the subtle nuances of Windows'
		API (especially messaging, MM_WOM_DONE in particular)

	Clayton J. Miner, whose decade of working with computer sound provided
		me with my strongest impetus for this work.

	Once again, thank you for your interest in my work.
				Gavin R. Kujawa