DiamondWare's Sound ToolKit for Windows (The WIN-STK) was brought to 
you by DiamondWare, Ltd.

You can contact us via:
    internet email: support@dw.com
    Web Page:	    www.dw.com
    CompuServe:     73704,245
    voice:	    (602) 917-3474
    FAX:	    (602) 917-5973
    snail-mail:	2095 N. Alma School Rd., Suite 12-288, Chandler, AZ 85224

The WIN-STK software was designed and developed by John C. Lundy, Erik 
Lorenzen, and Keith Weiner.

Example source code was developed by John Lundy, with language-specific 
help from Dave Allen (Visual BASIC), and David Bollinger (Delphi).

This document was written and edited by Keith Weiner.  Proofreading was done 
by Joyce Weiner, Angelo Nunes, Erik Lorenzen, John Lundy, Dave Allen and 
David Bollinger.

The Visual BASIC interface was written by Dave Allen.  The Delphi interface 
was written by David Bollinger.

This software and documentation are Copyright c 1994-1996 DiamondWare,
Ltd.  All rights reserved.  DiamondWare's Sound ToolKit, DiamondWare's
STK, The STK, The WIN-STK, DiamondWare, DW, and DW are trademarks of 
DiamondWare, Ltd.

The included sample MIDI song is Copyright c 1994 David Schultz, All Rights 
Reserved.  Used by permission.  May not be used without written permission 
from David Schultz.

DiamondWare also offers a full range of consulting and software development 
services, from device-driver development to turnkey multimedia titles.  Please 
call us for more information.

Borland is a registered trademark, and Delphi is a trademark of Borland
  International Inc.
Microsoft and Win32 are registered trademarks of, and Windows and Visual
  BASIC are trademarks of Microsoft Corporation
Symantec is a trademark of Symantec Corporation.
Watcom is a trademark of Watcom Systems, Inc.

License Agreement: Commercial Version
This document is a legal agreement between you and DiamondWare, Ltd. By using
this software, you agree to be bound by the terms of this Agreement and
Disclaimer of Warranty and Limited Warranty. If you do not agree to the terms
of this Agreement, promptly return the software and all accompanying items for
a full refund.
1. GRANT OF LICENSE. This License Agreement permits you (one person) to use one
copy of the enclosed Sound ToolKit for Windows software and documentation (The
WIN-STK) on a single computer.
2. COPYRIGHT. The WIN-STK is owned by DiamondWare, Ltd., and is protected by
United States copyright law and international treaty provisions. You must treat
the WIN-STK like any other copyrighted work except that you may either (a) make
one copy solely for backup or archival purposes, or (b) transfer the WIN-STK to
your hard disk, provided that you keep the original solely for backup or
archival purposes. You may not copy the written materials accompanying the WIN-
STK. You may be held legally liable for any copyright infringement that is
caused or encouraged by your failure to abide by the terms of this Agreement.
3. OTHER RESTRICTIONS. You may not rent or lease the WIN-STK. It is licensed to
you, the Licensee. The license may not be transferred to any other party
without the prior written consent of DiamondWare, Ltd. You may not reverse
engineer, decompile, or disassemble the WIN-STK.
4. DISTRIBUTION. You are hereby granted a royalty-free non-exclusive right to
reproduce and distribute the WIN-STK DLLs as part of your software, provided
that it does not compete with, or substantially duplicate the functionality of,
the WIN-STK. You must credit the WIN-STK wherever your other credits appear.

License Agreement: Demo Version
This version of the WIN-STK is SHAREWARE.  DiamondWare grants you a personal
license to evaluate the WIN-STK for 30 days.  This license is for evaluation
purposes only.	You may not distribute this SHAREWARE version of the WIN-STK
as part of any other software.	In any event, after 30 days, you must pay the
license fee or stop using the STK.

DiamondWare also grants permission to distribute this SHAREWARE version of the
WIN-STK under the following terms:
1. You must include all of the files listed in PACKING.LST.
2. You must make it clear that the WIN-STK is SHAREWARE.

Disclaimer of Warranty and Limited Warranty
The WIN-STK diskette and accompanying written materials are sold "as is",
without warranty or guarantee as to their performance, merchantability, or
fitness for any particular purpose. The entire risk as to the results and
performance of the WIN-STK is assumed by you. However, the magnetic diskette on
which the software is recorded is warranted to be free from defects in
materials and workmanship under normal use for a period of ninety days from the
date of purchase. If, during this ninety-day period, the diskette should prove
defective, it may be returned for a replacement without charge, provided you
have registered your WIN-STK license via mail.
Your sole and exclusive remedy in the event of a defect is expressly limited to
replacement of the diskette, as provided above.
Any implied warranties relating to the diskette, including any implied
warranties of merchantability and fitness for a particular purpose, are limited
to a period of ninety days from the date of purchase. Neither DiamondWare, nor
its partners, agents, distributors, or contractors, shall be liable for
indirect, special, or consequential damages resulting from the use of this
product.

Free Upgrade Policy for Bug Finders

DiamondWare is committed to the goal of zero-defect software.

Bug-free programs do not happen by accident.  They are the result of a thorough
design, a scientific approach to coding, and extensive testing of the finished
product.  By the time we ship a product, we have more than just a hope that our
products are robust.  We have an expectation, based on evidence.

You shouldn't find any bugs in our code.

But if you do, your foremost concern (and ours) is getting the problem fixed 
properly, verifying the fix, and getting you an update.

For your trouble, we're prepared to offer you a free upgrade to the next major 
version.  This isn't really adequate payment for your time or aggravation.  But
it's our way of showing some appreciation for what is otherwise a grueling and
thankless task.

Conditions
  The defect must be non-trivial.
  You must be the first to report it.
  Upon our request, you must provide us with a test program which 
    demonstrates the bug.
  The bug must be caused by DiamondWare's code.
  Cosmetic problems are excluded from this policy, although we'll try to 
    provide fixes quickly.
  Operating system or driver bugs are also excluded, although we'll try to 
    provide workarounds.
  The final decision, whether or not to award a free upgrade, lies with 
    DiamondWare.

Please help us make the product better by reporting any problem you encounter 
with DiamondWare software.

Introduction

This manual is organized into three major sections.  The first is the Guide.  
Although you can skip the some of its topics, it contains some invaluable 
information about the WIN-STK, including useful hints and troubleshooting 
help.

The second section is the Tutorial.  It will take you step by step through some
code which uses the STK.  If you're familiar with the DOS-STK, or prefer to 
read the files on disk, you might skip this section; it is not essential.

The third section is the Reference.  You might want to skim it before writing 
your code; it's always a good idea to achieve closure with any API you use.

Guide to the WIN-STK

This section gives an overview of the product, but also contains some specific
information, and recommendations.

What Is It?
DiamondWare's Sound ToolKit for Windows (The WIN-STK) is a sound library 
which provides functions to support interactive sound and music.

What does this mean? Windows can play MIDI and WAVE files already.

That's true.  However, Windows cannot play more than one sound at a time, nor 
even reliably tell you when it's done playing.  The rest of this Guide will
discuss the feature set of the WIN-STK, and explain how to use it.

The WIN-STK is supplied as two DLLs: one for 16- and one for 32-bit Windows,
so it can be used from almost any programming or authoring environment.  We
provide all the files you'll need if you're using C/C++ from Microsoft,
Borland, Watcom, or Symantec; or if you're using Visual BASIC, or Delphi.

The WIN-STK implements a superset of our acclaimed API, originally 
introduced for the DOS version.  Its architecture will impact yours minimally
(if at all), so adding the WIN-STK to a mostly-completed program will be easy.

The WIN-STK provides an object-oriented sound-centered API, which is cleaner
and easier to use than a channel-centered system.  With the WIN-STK, you don't
have to allocate or deallocate channels.

The WIN-STK supports (and has been tested under!) Windows 3.1, Windows 95, and
Windows NT.

The WIN-STK requires a minimum platform of a 486.  We recommend a 486-66,
however.

What Does It Do?
It plays up to sixteen digital sounds (WAVEs) at the same time, plus one MIDI
song.  Your program selects the digitized mode (mono or stereo, bits/sample,
and sampling rate) and which MIDI device to use.

The salient features of the WIN-STK are listed below.

Random Access.  You can start or stop any sound at any time.

Low latency.  Latency is the time elapsed between your call to play a sound, 
and when the sound is actually heard.  Typically, for Windows 95 and NT, the 
WIN-STK latency figures are: 100 milliseconds average, 75ms best case, and 
125ms worst case.  For Windows 3.1, they are 200ms average, 150 best, and 
250 worst.  This is good enough to convince users that a sight and sound 
occurred simultaneously.  (Though it's probably not good enough for a 
keyboard synthesizer application.)

DSP.  You can alter the pitch and volume of each sound.

Stereo.  The WIN-STK can play a monophonic (or stereo sound) through both 
stereo output channels, with a different volume in each (panning).

Interactivity.  Even after a sound is playing, you can change its pitch and 
volume, loop count, etc.  The WIN-STK can notify you when a sound is done 
playing, giving you the opportunity to display graphics or execute a handler.

Sequencing.  The WIN-STK allows you to play a sound right after another, 
guaranteeing that the sequenced sound will play exactly when the first is done,
without an overlap, click, or pause.

Music.  The WIN-STK can play a MIDI song.
Where Is It Going in the Future?
This version of the WIN-STK was released because it provides a valuable 
feature set to many programmers, who are trying to mix several channels of 
digital audio.

But it's not the penultimate system.  Here's sneak preview of future WIN-STKs.

Better MIDI support.  This includes volume control, callbacks for SysEx and
other events, multiple songs playing at the same time, segueing, branching,
etc.  In other words, interactive music.

DirectSound and Native Audio support.

Recording.  A future version will support recording, as well as playback.
Added bonus: some boards support simultaneous record/playback, which is
perfect for networked games!

Other features, To Be Determined: If there's something you really want to see,
please let us know!

Development Environments
Before proceeding any further, you should be familiar with such programming 
topics as bitfields and using DLLs.

The WIN-STK will work with any development environment which can load 
and call DLLs, however this document discusses C/C++, Visual BASIC, and 
Pascal specifically.

Language Notes for C/C++
The WIN-STK has been tested with compilers from Microsoft, Borland, 
Watcom, and Symantec.  DWS.H passes through all of them without any 
warnings.  The sample program PLAYSTK also works with all.  However, we 
provide a 16- and 32-bit .LIB file for each compiler.

In some compilers, you may need to add the common dialog library into your 
project in order to build PLAYSTK.EXE.  See your compiler's manual for 
details.

This manual was written using C terminology, so if you're familiar with ANSI 
C, and a modern commercial Windows compiler, you should be able to read this 
manual with 100% comprehension.

As with other libraries, the WIN-STK provides an include file.  Put the line:

  #include "dws.h"

at the top of every source module which uses the WIN-STK.

If you've never written a program using a DLL before, there are two ways to do 
it.  We'll call the first "The Easy Way", and the second "The Hard Way."

In The Easy Way, you link with an import library.  This usually comes with the 
DLL, or most compilers provide a utility called IMPLIB.EXE which can make 
one.  The import library provides a stub for each function in the DLL.	It
takes care of the magic of loading the DLL, determining runtime addresses, etc.

The WIN-STK comes with an import library for the most popular compilers; if 
we didn't provide one for your compiler, look for IMPLIB.EXE in your 
compiler's BIN directory.

In The Hard Way, you do everything yourself.  You manually load the DLL, 
calculate the address of every function you need within it, and call those 
functions through pointers.  The Hard Way is beyond the scope of this 
documentation, but it's mentioned for completeness.

Some programmers use the standard-library function atexit to register 
cleanup functions, which are called before the program terminates.  You must 
not use this facility to call dws_Kill.  This is because Windows 95 and NT 
will wait until all threads except the main thread stop executing.  The WIN-STK
uses a background thread which is terminated during the call to dws_Kill.  
This will lead to an impasse, where the program will not quite terminate.

The atexit problem does not apply to 16-bit programs, but if you think that 
you will ever move to Win32, you should probably avoid it anyway.

Language Notes for Visual BASIC
The WIN-STK supports Visual BASIC 3 and Visual BASIC 4, including the 
new 32-bit mode.

In the reference section, you will find a prototype for each WIN-STK function 
in C, Visual BASIC, and Pascal.  However, this document is somewhat C-
centric.

Read on for some information which will help you comprehend the rest of the 
manual.

In C, all procedures are called "functions", although in Visual BASIC they may 
be "functions" or "subroutines", depending on whether they return a value.

In C, variables are declared type first, and then variable name:

int x;

This declares a variable called x, of type integer.  Pointers are declared with a 
star, like:

  int *y;

Here, y is a pointer to integer.  Some WIN-STK functions take pointer 
parameters, and the sample C code in this document will use this notation.

A C struct, often called a structure, is the equivalent of a Visual BASIC user-
defined Type.

C comments are either a double slash //Comment which is a comment until 
the end of the line, equivalent to Visual BASIC's apostrophe ' or REM; or 
/*Comment*/, which is a comment between the /* and the */.

C expresses bitwise OR as a pipe |, bitwise AND as an ampersand &, boolean 
OR as two pipes ||, and boolean AND as two ampersands &&.

In C, the ampersand & operator can also be used to take the address of a 
variable.  For example:

dws_MSongStatus(&mstat);

This call passes the address of the variable mstat to dws_MSongStatus.  
By default, Visual BASIC passes parameters by reference, so you probably 
won't have to deal with this issue.

In C, the default is to pass a parameter by value, which in VB requires the use of 
the ByVal keyword.

To pass a NULL pointer in Visual BASIC, you need to specify a 32-bit 0:

dws_DGetInfo(dplay, ByVal 0&);

We provide DWS.BAS, which declares all of the constants, data types, and 
routines of the WIN-STK.  Add this file to your project.  You might also want to 
read through it.

The WIN-STK can send your window a message when a digitized sound is done 
playing.  But Visual BASIC alone does not allow you to receive or process 
specific window messages.  You will need a third-party VBX or OCX control to 
use this feature.

Language notes for Pascal
The WIN-STK works with the various Windows Pascal products published by 
Borland.  However, the sample program PLAYSTK, will only compile with 
Delphi.

In the reference section, you will find a prototype for each WIN-STK function 
in C, Visual BASIC, and Pascal.  However, this document is somewhat C-
centric.

Read on for some information which will help you comprehend the rest of the 
manual.

In C, all code routines are called "functions", although in Pascal they may be 
"functions" or "procedures", depending on whether they return a value.

In C, variables are declared type first, and then variable name:

  int x;

This declares a variable called x, of type integer.  Pointers are declared with
a star, like:

  int *y;

Here, y is a pointer to integer.  Some WIN-STK functions take pointer 
parameters, and the sample C code in this document will use this notation.

A C struct, often called a structure, is the equivalent of a Pascal record.

C comments are either a double slash //Comment which is a comment until 
the end of the line or /*Comment*/, which is equivalent to Pascal's 
(*Comment*).

C expresses bitwise OR as a pipe |, bitwise AND as an ampersand &, boolean 
OR as two pipes ||, and boolean AND as two ampersands &&.

In C, the ampersand & operator can also be used to take the address of a 
variable.  For example:

  dws_MSongStatus(&mstat);

This call passes the address of the variable mstat to the function (which puts
the song's status into the variable).  This is equivalent to Pascal's var
calling convention.

We provide DWS.PAS, which declares all of the constants, data types, and 
routines of the WIN-STK.  You will need to insert the line:

uses dws;

into your main program.  You might also want to read the source.

Pascal is not case-sensitive.  This will cause the dws_DPLAY and dws_MPLAY  
record types to conflict with the corresponding function names.  Therefore,
they have a REC at the end (e.g. dws_DPLAYREC and dws_MPLAYREC).

In Pascal, the identifier message is a keyword.  Therefore in Pascal, the 
message field in the dws_DPLAY record is renamed wmessage.

Another problem with Pascal and the WIN-STK is that the functions 
dws_DGetInfo and dws_DSetInfo take two dws_DPLAYREC parameters 
which are passed by reference (declared as var).  To tell these functions to 
ignore a parameter, C and Visual BASIC programmers can pass a NIL.  The 
Pascal compiler will not let you do this directly.  But there is another way
of indicating "ignore this parameter".	The dws_DPLAYREC record has a flags
field which indicates which other fields within the record you are using.  If
you set flags = 0, then the WIN-STK will behave exactly as if you had passed
NIL as the address of the record.  See the Reference section for more details.

The dws_WAV2DWD function also accepts a NIL pointer in certain cases.  
However, the parameter is not a pass-by-reference variable in this function.
It's a PBYTE, so the compiler will let you pass NIL.

This document will not further refer to these differences between Pascal and C.


Installing the WIN-STK
Simply copy (or unzip) the WIN-STK files into their own subdirectory tree on 
your hard drive.  There are different subdirectories for C, Visual BASIC, Pascal, 
the DLLs, etc.  You probably don't need all of them.

Make sure you put the files for your language where your compiler and linker 
can find them.  If you need more information on this and related topics, your 
compiler's manual will be far more detailed than is possible here, and will
cover your specific software environment.

Using the WIN-STK Effectively
The Tutorial and Reference sections describe, in great detail, how to use the 
WIN-STK.  Here, we discuss some of the issues to think about if you want to 
use the WIN-STK effectively.

Stereo or Mono?
The WIN-STK can output stereo or mono sound.  In most cases, you will want 
to use stereo if supported by the hardware.  Elsewhere in this manual, you'll 
find out how to determine if stereo is available.  You might want to use mono, 
however, to save precious CPU cycles on slower machines.  Elsewhere, we
discuss other things to do to maximize performance.

So you've decided to use stereo.  But have you thought about your source 
sounds?  Should you record them in stereo?

The answer depends on what you are trying to do.  If you are playing any kind 
of cinematic sequence, then stereo recording is probably appropriate.

But if you want your sound to be interactive, then mono is probably a better 
choice because the WIN-STK can play the left and right channels at different 
volume levels.  This is called panning, and can be used to communicate a 
sound's location to the user.  In fact, many 3D games use panning to localize 
sound.

Authoring Sound
If you're authoring a long playback sequence, with little or no interactivity
to it, you may author literally anything which the hardware can play back.  The
sampling rate, sample size, and whether to use stereo will be dictated by your
creative designer, and storage considerations.

But if you're producing sound to be played simultaneously with other sounds 
and be manipulated by the program, read on.

The first issue to consider is dynamic range.  In digital sound playback, there
is always a limit to how loud a sample can be.	All overflows must be clipped.
If an occasional sample is clipped, then the user will most likely never notice
it.  However, if you overload the system with many loud sounds, then the output
will sound distorted, which is usually undesirable.

Record your sounds so that they do not use a lot of dynamic range.  The goal is
to minimize the difference between the loud parts and the soft parts, making
the entire sound somewhat quiet.  Good sound editing programs offer a dynamic
range compression feature for just this purpose.

Keep the overall volume level of your sounds commensurate with how many 
you expect to play at the same time.  For example, if you need to play four 
sounds at a time, then each sound should use roughly  of the total dynamic 
range.

If you're going to use volume panning to localize sounds, then you will likely
want distant sounds to be quiet and close sounds to be loud.  In this case,
record your sound at the loudest level you'll need, and use the WIN-STK to make
it softer as it moves into the distance.

This will give you better sound quality (as well as being computationally 
faster-see the next topic for details) than recording soft and raising the
volume at runtime.

WIN-STK Performance
8-bit audio is less CPU intensive than 16-bit.	Using 8-bit also allows the
WIN- STK to perform certain additional optimizations.

So what's the order of fastest to slowest modes?  8-bit mono is fastest,
followed by 16-bit mono, then 8-bit stereo, then 16-bit stereo.  The difference
between 16-bit mono and 8-bit stereo is slight.

There is a tradeoff between latency (the time between when your program calls 
a sound function, and the time when the user hears it) and CPU usage.  A 
smaller internal buffer will allow the WIN-STK to give you lower latency, but
it will need to be updated more often, thus increasing the CPU load.

Sound, unlike video, can't acceptably stall even briefly.  If the buffer is not
updated by the deadline, an audible gap or click will result.  Slower
computers, of course, will take more time before they can get around to
updating the buffer.  Thus, the WIN-STK will use larger buffers on slower
machines, and can get away with smaller buffers on faster machines.

The WIN-STK can play up to 16 digital sounds at the same time.  But you 
should configure the WIN-STK to allow only for the maximum number of 
voices your program will actually use.	Setting this value needlessly high will
impose CPU usage and latency penalties.

It's important to understand that the WIN-STK will convert sounds (if
necessary) to the match the output mode.  Thus, even if the output mode is
8-bit mono, you can still play a 16-bit stereo file.

Obviously, you should author your sounds with the same sample size and 
number of channels as your intended output mode.  You should only rely on the 
WIN-STK's automatic format conversions if a user's sound hardware is less 
capable than your target platform.  But in any event, the WIN-STK can exploit 
the 8-bit optimizations if either the source sound, or the output mode, is
8-bit.

Volume change is always faster than pitch change.  Lowering the pitch is always
faster than raising it.

With 8-bit sound, lowering the volume is faster than raising the volume.  With
16-bit sound, there is no difference in CPU usage.

16-bit vs. 32-bit DLLs
The 16-bit DLL works under Windows 3.1, Windows 95, and Windows NT.
The 32-bit DLL works only under Windows 95, and NT because it makes 
extensive use of multithreading.

16-Bit
The 16-bit DLL is susceptible to all of the problems you normally have in 
Windows 3.1.  If your application hogs the CPU for a while, then the WIN-STK 
might stop playing sound until you yield again.  To get around this problem, we
provide a function (dws_Update) that you can call to keep the sound going, 
even if you don't want to yield to the system.

If another application hogs the CPU (or if your user drags your window around 
by the title bar), then the sound will pause.  There isn't anything that anyone
can do about it.

32-Bit
The 32-bit DLL is immune to the above problems; Win32 is a superior platform 
to Win16!

Be aware, however, that if you really hog the CPU within a very high-priority 
thread, you can cause the sound to pause.  You probably shouldn't be doing
this, but if you must, then you must call dws_Update periodically.  High-
priority threads should only be used for fast, critical actions.

The 32-bit DLL is fully thread-safe.

The WIN-STK kernel thread runs at THREAD_PRIORITY_TIME_CRITICAL 
priority.  This results in a base priority level of 15 for calling processes
with a priority class of IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or
HIGH_PRIORITY_CLASS; and a base priority level of 31 for processes with 
REALTIME_PRIORITY_CLASS.  You should think long and hard before you 
set your priority class to anything above HIGH_PRIORITY_CLASS!

Latency vs. Smooth Playback
There is a tradeoff between minimizing the latency, and playback which never 
skips.	Latency is directly proportional to buffer size.  But larger buffers
offer immunity to skipping.  The WIN-STK autodetect function can do a pretty
good job calculating the buffer size on most machines, but it may not be
perfect.

You might provide a slider bar for the user to make changes to the calculated 
buffer size.

Digitized Sound Theory
This section presents a basic description of digitized sound, and some of the 
theory.  You don't really need to read this, but you may find it interesting
and useful in the future.  Digitized sound on computers will certainly be used
in the future.

Digitized sound is sound that has been sampled, or quantized.  Periodically,
the analog voltage of a sound signal is measured by a special circuit called
an Analog to Digital Converter (ADC), and then stored.

Digitized sounds are discretely quantized.  This means that there is a finite
set of possible values for each sample.  It also means that there are only
samples for a finite number of instants in time.

Let's take the case of 8-bit samples.  Samples range from -128 to +127.  Any 
sound softer than +/-1 is lost.  Any sound louder than +127/-128 will be
clipped, which sounds bad.  This overflow problem is compounded  if you're
mixing several sounds together, or processing the sound digitally.

Just as the range of samples is not infinite, neither is the domain.  Digitized
sounds are not contiguous in the time domain.  They're sampled at T=1 and 
T=2, but not at T=1.5. There's obviously sound at every moment, even during 
those in between the sample points.  But we have no record of it; a graph of 
digitized sound data has a characteristic stair-step shape.  We'll look at the 
problems this can cause below.

Digital signal theory asserts that every possible waveform can be represented
by the sum of a finite series of pure sine waves.  The highest frequency sine
wave in this series is no higher than the highest frequency component present
in the original wave.

The Nyquist theory of digital signal processing states that, in order to
capture a waveform containing frequencies up to F, you need to sample it at a
rate of at least 2F.

Any sampling rate, R, lower than 2F will cause the frequencies above R / 2 to
be aliased as lower frequencies.  This sounds like a metallic overtone on top
of the original sound.

To visualize this better, think of the infamous problem of drawing a diagonal 
line on a low-resolution screen, or of watching a spinning propeller seem to
turn slowly backwards.	The sampling rate (resolution) of the screen is too low
to display the line.  The sampling rate of the human eye is too low to see a
15,000 RPM propeller.

When we convert digital samples back to analog, the result looks quite square 
(the stair-step shape mentioned above), and not at all like the original.  This
is an immutable consequence of the process.

The steep vertical segments in the wave are high frequencies.  Therefore, you 
must send the signal through a low-pass filter to remove the extra garbage.  
Sound boards all contain low-pass filters for this very reason.  In practice, a
cheap set of speakers would probably act as an effective filter for the higher
sampling rates.

Although the following doesn't really relate to computer audio, it's
interesting because it's relevant to every CD player.

Analog filters distort the sound.  The steeper the cutoff, the worse they
sound.	So instead of trying to build a filter which passes everything below
20,000 Hz and cuts everything above 20,001 Hz, CD players use oversampling.
You can think of oversampling as "interpolation".

If you convert the sample data to the frequency domain, add extra zeroes for
all the frequencies above your actual sound data, and convert back to the time
domain, you'll have a smoother interpolation of the original sound.  More 
importantly, the harmonic overtones will be at a higher frequency, and thus 
easier to filter.

So the next time you buy a CD player, don't let the ignorant salesman tell you 
that ".THIS player reads the disc eight times so it doesn't make as many 
errors.".  You know now that oversampling is just a technique to produce 
smoother output.  Even cheap CD players can read a disc without errors, or else
CD-ROM's would never work!

Tutorial

This section will take you through the steps required to add sound to a C 
program, starting with the barest minimum, and leading up to some more 
advanced concepts and features.  Every line of code should easily convert to an
equivalent line in Visual BASIC or Pascal.

The code does not check for errors, or do any of the other things required of 
robust, commercial-quality code.

Caveat: This code has not been tested or compiled!  It's good for reading 
through, and to illustrate key WIN-STK implementation issues.  But, you're 
better off cutting code out of PLAYSTK than attempting to use the code 
presented here.

The Basics
The Variables
void PlaySoundAndSong(void)
{
    FILE *fp;
    BYTE *sfx;
    WORD mstatus;
    WORD dsize;
    dws_DETECTRESULTS dres;
    dws_IDEAL ideal;
    dws_MPLAY mplay;
    dws_DPLAY dplay;

We're going to load one sound effect from disk into memory (MIDI songs are 
played directly from disk file).  sfx, a pointer, holds the address of the
sound effect buffer.  dres, and ideal are structs required for initialization.
dplay, a struct, holds all information needed to play the sound effect; mplay,
another struct, holds information for playing the song.

Loading Songs and Sounds
    /* Allocate memory */
    fp = fopen("sample.dwd", "rb");
    fseek (fp, 0L, SEEK_END);
    sfx = malloc(dsize = ftell(fp));

    /* Load the sound file */
    fseek(fp, 0L, SEEK_SET);
    fread(sound, dsize, 1, fp);
    fclose(fp);

This code allocates a buffer to store the sound, and then reads the sound file into 
it.  SAMPLE.DWD began as SAMPLE.WAV (an 8-bit mono digitized sound, 
sampled at 11kHz), and was converted by WAV2DWD.EXE.

Initializing the STK
    /* Run the WIN-STK's autodetect routine */
    dws_DetectHardWare(&dres);

    /* Init the WIN-STK */
    ideal.mustyp     = dws_muscap_MAPPER;
    ideal.digtyp     = dws_digcap_11025_08_1;
    ideal.dignvoices = 2;
    ideal.flags      = dws_ideal_NONE;
    dws_Init(&dres, &ideal);

The results of the autodetect are returned in the dres struct.

This code fails to check to see whether the WIN-STK even found a MIDI 
mapper, but just assumes that it's there.  The MIDI mapper is installed on most
machines, but you can't make an assumption like that in real code!

We initialized the ideal struct to request the desired STK services.  Note how 
we specified 2 voices.  This allows the WIN-STK to run at its most efficient.  
Don't tell the WIN-STK to use any more voices than you need.

After the call to dws_Init, the sound hardware and the WIN-STK are set up 
for business.
Preparing Songs and Sounds
    /* Prepare to play song */
    mplay.track = "sample.mid";
    mplay.count = 1;

    /* Prepare to play digitized sound */
    dplay.flags = dws_dplay_SND;
    dplay.snd   = sound;

The mplay struct and the dplay struct are set up prior to the calls to play 
them.  The flags field in the dplay struct tells the WIN-STK which fields 
have been initialized.	Since we didn't use most of the fields in the struct,
they'll take on reasonable defaults (see the Reference section for specifics).

Starting Playback
    /* Play song and sound */
    dws_MPlay(&mplay);
    dws_DPlay(&dplay);

A call to dws_MPlay starts the music, and a call to dws_DPlay begins 
playback of the digitized sound effect.

Wait 'Til the Fat Lady Stops Singing
    /* Wait loop */
    do
    {
      dplay.flags = dws_SOUNDNUM;
      dws_DGetInfo(&dplay, NULL);
      dws_MSongStatus(&mstatus);

    } while ((dplay.soundnum) || 
             (mstatus & dws_MSONGSTATUSPLAYING));

To query the sound's status, we call dws_DGetInfo, and look at the 
soundnum field that it sends back to us.  When the sound is done playing, this 
field is returned as 0.

To query the song's status, we call dws_MSongStatus, with the address of a 
bitfield variable.  We're interested in the dws_MSONGSTATUSPLAYING field.

Shutting Down
    /* Free the memory we allocated above */
    free(sound);

    /* We must kill the WIN-STK */
    dws_Kill();
}

Normally, you would call dws_DDiscard before freeing a sound buffer, but 
in this case, we know that the sound is done.

The Fancy Stuff
The WIN-STK does a whole lot more than what we've seen so far.  In this topic, 
we'll show you how to play more than one sound at the same time (which is 
called "polyphony"), how to sequence a sound after another, how to use the 
WIN-STK's built-in volume and pitch control, how to change sounds once 
they're playing, how to get notification that a sound is done playing, how to 
play large files from disk (32-bit DLL only), and how to handle WIN-STK 
errors.

Polyphony
The WIN-STK kernel was designed to be polyphonic from the ground up, so 
you don't need any special tricks.  To play two or more sounds at the same
time, simply call dws_DPlay more than once.

The example code fragment below assumes that the WIN-STK has been 
initialized.  sfx1 and sfx2 are digital sounds in memory.

    dplay.flags    = dws_dplay_SND |
                     dws_dplay_PRIORITY;
    dplay.snd      = sfx1;
    dplay.priority = dws_NORMALPRIORITY;
    dws_DPlay(&dplay);

    dplay.snd      = sfx2;
    dplay.priority = dws_NORMALPRIORITY;
    dws_DPlay(&dplay);

The priority field helps the WIN-STK determine which sound to drop if you 
exceed the maximum number of voices (specified in the dws_IDEAL struct in 
the call to dws_Init).	The issue is moot for this example, but may be a factor
in a real-world application.

Note that you can reuse the dplay struct itself; all WIN-STK functions copy 
what they need from your structs before returning.

Sequencing
Sequencing allows you to play a sound back-to-back with another.  The first 
sample of the sequenced sound plays right after the last sample of the first 
sound.	The effect is that of a single sound playing seamlessly, without a
pause or even a click.

The presnd field of the dws_DPLAY struct is the key to this feature.  To 
sequence sound B after sound A, then set the presnd field of sound B's 
dplay struct to the soundnum of sound A (set by the call to dws_DPlay).

In the example below, assume that dplay1 and dplay2 are both structs of 
type dws_DPLAY.

    dplay1.flags = dws_dplay_SND;
    dplay1.snd   = sfx1;
    dws_DPlay(&dplay1);

    dplay2.flags  = dws_dplay_SND | dws_dplay_PRESND;
    dplay2.snd    = sfx2;
    dplay2.presnd = dplay1.soundnum;
    dws_DPlay(&dplay2);

This example tells the WIN-STK to wait until the first sound is complete, and 
then play the second.

The WIN-STK will set the soundnum field of dplay2 to the same value as its 
presnd; no matter how many sounds you sequence, they will all have the same 
soundnum.

Note: if you have want to play a sequence of more than two sounds, then some 
manual effort is required; the WIN-STK handles only two at a time: the one 
that's playing, and the one sequenced after it.  You must wait until the first 
sound is done (and hence the sequenced sound is playing) before sequencing the 
third.  Use dws_DGetInfo to determine when a sound is done.

Sequencing is useful if you want to break a long sound into several pieces.
Or, if you want to play a sound, and then "branch" to one of several sounds,
depending on some user-interaction after the first part is played (e.g. a gun
fires, continuing with either a scream or a ricochet, depending on whether the
bullet hits).

Pitch and Volume Control
The WIN-STK allows you to specify the left and right volume for any sound, 
plus its pitch.  Actually, the WIN-STK allows you to control the playback
length of the sound, which affects the perceived pitch.  The distinction is
important, because increases in the length decrease the pitch (make it lower).

    dplay.flags = dws_dplay_SND | dws_dplay_LVOL |
                  dws_RVOL | dws_PITCH;
    dplay.snd   = sfx1;
    dplay.lvol  = dws_IDENTITY;
    dplay.rvol  = dws_IDENTITY / 2;
    dplay.pitch = dws_IDENTITY * 2;
    dws_DPlay(&dplay);

This example will play a sound, with the right channel softer than the left.
It will play at a lower pitch than it was recorded at.

In a 3D game, volume control of the left and right channels can be used to 
indicate the direction from which the sound is coming.

Pitch can be used to break up the monotony of a sound that's played many 
times.	Just vary the pitch slightly each time you play it.

Interactive Digitized Audio
Now, let's take a look at what you can do with a sound once it's playing.

You could terminate it.

    dws_DDiscard(dplay.soundnum);

You could terminate it, and all other instances of the same sound file:

    dws_DDiscardAO(sfx1);

The "AO" stands for "All Occurrences".

To do anything sophisticated with a sound, you'll need dws_DGetInfo and 
dws_DSetInfo.

Querying a Sound's Status
dws_DGetInfo can return information about a playing sound, via a 
dws_DPLAY struct. You just set the flags field to indicate the fields for 
which you want information.

The function knows which sound to look up based on its soundnum, so you will 
need to provide that.  Remember to set the dws_dplay_SOUNDNUM bit in 
flags.

    dplay.flags = dws_dplay_SOUNDNUM;
    dplay.soundnum = sndnum_from_prior_call_to_dplay;
    dws_DGetInfo(&dplay, NULL);

In the above example, we're asking for the soundnum field of the currently 
playing sound.  dplay.soundnum will either be unchanged, or hold a 0 if the 
sound is done playing.  There was no sequenced sound, so we pass NULL for 
the second dplay parameter.

Changing a Sound on the Fly
You can change the loop count, priority, left and right volume, pitch, and 
callback of a currently-playing (or sequenced) sound.

This example illustrates changing the left-channel volume of a sound:

    dplay.flags = dws_dplay_SOUNDNUM | dws_dplay_LVOL;
    dplay.soundnum = sndnum_from_prior_call_to_dplay;
    dplay.lvol = dws_IDENTITY / 4;
    dws_DSetInfo(&dplay, NULL);

Callbacks
The WIN-STK can give you notification when a sound is done playing.  This 
feature relies on Windows' message queue system.  If you know your window 
handle, and have a message handler (Window Procedure) installed for the 
window, then this feature will work for you.

The following example illustrates how to play a sound, so that you'll be
notified when it's done.

    dplay.flags = dws_dplay_SND | dws_dplay_CALLBACK;
    dplay.snd     = sfx;
    dplay.hwndmsg = hwnd;
    dplay.message = WM_USER + 1;
    dws_DPlay(&dplay);

The sound will play once.  The window whose handle is specified by hwnd will 
receive the WM_USER + 1 message (you should, of course, create constants for 
any messages you intend to use).

Your message handler can do anything it wants, including make WIN-STK 
function calls.

Note: be very careful about relying on this mechanism, especially if you need a
message to move on to the next phase of execution (i.e. to bring out the boss
monster).  The message is absolutely reliable-if the sound completes.  But, if
a low-priority sound is dropped when another of higher priority is played, then
the message will never be sent.  You could wait forever. . . .

Playing Large Sounds Directly from Disk
If you have a very large sound files (e.g. a 3-minute 16-bit 44kHz music
track), you might want to play it directly from the disk.

Win32
Under Win32 (Windows 95 and NT), you can easily do this.  The operating 
system supports memory-mapped files.  The following code snippet illustrates 
how to do this:

void PlayDWDFile(char *filename)
{
    dws_DPLAY dplay;
    HANDLE hfile;
    HGLOBAL hdwd;
    BYTE *dwd;

    hfile = CreateFile(filename, GENERIC_READ, 0,
                       NULL, OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL, NULL);

    hdwd = CreateFileMapping(hfile, NULL, 
                             PAGE_READONLY, 
                             0L, 0L, "DWD");

    dwd = (BYTE*)MapViewOfFile(hdwd, FILE_MAP_READ,
                               0L, 0L, 0L);

    dPlay.flags = dws_dplay_SND;
    dPlay.snd   = dwd;

    dws_DPlay(&dPlay);

    /* Wait until the file is done playing */

    UnmapViewOfFile(dwd);
    CloseHandle(hdwd);
    CloseHandle(hfile);
}

It's important to clean up by unmapping the file, and closing down the handles!

Win16
You can play large files from disk under Windows 3.1 also, though it's a little
bit more involved.  You read the file one manageable chunk at a time, slap a 
DWD header on each chunk, and sequence the chunk after the previous chunk.

Error Handling
The WIN-STK can often tell you when you're making a mistake.  All functions 
have a boolean return value.  A 1 means success.  A 0 means an error of some 
kind occurred.  In this case, you should call dws_ErrNo to determine which.

    if (dws_DetectHardWare(&dres) == 0)
    {
        err = dws_ErrNo();

        DisplayErr("during dws_DetectHardWare");
    }

We provide the source code to DisplayErr in C, BASIC, and Pascal.  Just 
look inside PLAYSTK.C, PLAYSTK.BAS, or PLAYSTK.PAS, respectively

Reference
This section is broken down into topics for the Functions, the Errors, the Data
Structures, the Utilities, and the File Formats.

Each is the definitive specification on its subject, with a minimum of
verbiage.

The Functions
There are 21 functions in the WIN-STK library.

Unless otherwise noted, you must call dws_Init before calling any other 
WIN-STK function.

For each function, we give the prototypes for C, Visual BASIC, and Pascal.  We
give a description, the parameters, related functions, and the complete list of
errors that the function might generate.  You may assume that the list of
errors is complete; if an error is not listed for a given function, then that
function cannot flag that error.

dws_DClear

Declarations
WORD dws_DClear(void);
Declare Function dws_DClear() As Integer
function dws_DClear : WORDBOOL;

Description
This function stops all digitized sounds.

Parameters
None.

Related Functions
dws_DDiscard, dws_DDiscardAO, dws_DPlay

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

dws_DDiscard
Declarations
WORD dws_DDiscard(WORD soundnum);
Declare Function dws_DDiscard(ByVal soundnum As
  Integer) As Integer
function dws_DDiscard(soundnum: WORD) : WORDBOOL;

Description
This function stops the specified sound.

Parameters
soundnum  number of the sound to be killed

Related Functions
dws_DClear, dws_DDiscardAO, dws_DPlay

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

dws_DDiscardAO
Declarations
WORD dws_DDiscardAO(BYTE *snd);
Declare Function dws_DDiscardAO(snd As Long) As
  Integer
function dws_DDiscardAO(snd: PBYTE) : WORDBOOL;

Description
This function stops all occurrences of a DWD.  It's useful if you have repeatedly 
played the same sound effect, and want to stop all instances.

Parameters
snd  ptr to the DWD to stop

Related Functions
dws_DClear, dws_DDiscard, dws_DPlay

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

dws_DetectHardWare
Declarations
WORD dws_DetectHardWare(dws_DETECTRESULTS *dr);
Declare Function dws_DetectHardWare(dr As
  dws_DETECTRESULTS) as Integer
function dws_DetectHardWare(var dr: dws_DETECTRESULTS)
  : WORDBOOL;

Description
This function determines the capabilities of the hardware and drivers, and also 
calculates the WIN-STK's internal buffer size.

Notes
You may call this function only before dws_Init, or again after dws_Kill.

Parameters
dr  ptr to struct to hold the calculated information

Related Functions
dws_Init

Errors
dws_ALREADYINITTED, dws_INTERNALERROR,
dws_INVALIDPOINTER, dws_MEMORYALLOCFAILED,
dws_RESOURCEINUSE, dws_SETEVENTFAILED

dws_DGetInfo
Declarations
WORD dws_DGetInfo(dws_DPLAY *dp1, dws_DPLAY *dp2);
Declare Function dws_DGetInfo(dp1 As dws_DPLAY,
  dp2 As dws_DPLAY) As Integer
function dws_DGetInfo(var dp1: dws_DPLAYREC; var dp2:
  dws_DPLAYREC) : WORDBOOL;

Description
This function returns information about a playing sound, and the one sequenced 
to play after it.

Parameters
dp1  ptr to struct to hold information on currently-playing sound
dp2  the same, for sequenced sound

The flags field in each struct is used to specify which fields to query.  You
must indicate which sound is of interest, by using the soundnum field in at
least one struct.  If you initialize the soundnum field in both structs, then
both must be the same (e.g. dp1->soundnum = dp2->soundnum).  This is because
a sequenced sound always has the same sound ID number as the playing sound.

You may query these fields: dws_dplay_SND, dws_dplay_COUNT,
dws_dplay_PRIORITY, dws_dplay_PRESND, dws_dplay_LVOL,
dws_dplay_RVOL, dws_dplay_PITCH, or dws_dplay_CALLBACK.

If dws_dplay_CALLBACK is specified, then both the hwndmsg and the 
message fields are returned.

Related Functions
dws_DPlay, dws_DSetInfo

Errors
dws_D_BADDPLAY, dws_INVALIDPOINTER, dws_NOTINITTED,
dws_NOTSUPPORTED

dws_DGetRateFromDWD
Declarations
WORD dws_DGetRateFromDWD(BYTE *snd, WORD *rate);
Declare Function dws_DGetRateFromDWD(snd As Long,
  rate As Integer) As Integer
function dws_DGetRateFromDWD(snd: PBYTE; var rate:
  WORD) : WORDBOOL;

Description
This function returns the sampling rate of the specified DWD.

Notes
You may call this function at any time, even before dws_Init, or after 
dws_Kill.

Parameters
snd   ptr to the DWD of interest
rate  variable which will hold the returned sampling rate, in Hz

Related Functions
dws_Init, dws_WAV2DWD

Errors
dws_D_NOTADWD, dws_D_NOTSUPPORTEDVER,
dws_INVALIDPOINTER

dws_DPause
Declarations
WORD dws_DPause(void);
Declare Function dws_DPause() As Integer
function dws_DPause : WORDBOOL;

Description
This function pauses all digitized playback.

Note: all calls after the first will have no effect until dws_DUnPause is
called.  The WIN-STK does not maintain a "pause count".

Parameters
None.

Related Functions
dws_DUnPause

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

dws_DPlay
Declarations
WORD dws_DPlay(dws_DPLAY *dplay);
Declare Function dws_DPlay(dplay As dws_DPLAY) As
  Integer
function dws_DPlay(var dplay: dws_DPLAYREC) :
  WORDBOOL;

Description
This function can play or sequence a sound.

"Sequencing" a sound causes it to play after another specified sound is done.

Parameters
dplay  ptr to struct specifying the sound

Note
Most of the fields in the dplay struct are optional; you must set the 
corresponding bit in the flags field to indicate which ones you're using.

Each field (except flags and snd) gets a reasonable default if not specified:
count    = 1
priority = dws_NORMALPRIORITY
presnd   = (none)
lvol     = dws_IDENTITY
rvol     = dws_IDENTITY
pitch    = dws_IDENTITY
hwndmsg  = (none)
message  = (none)

Related Functions
dws_DClear, dws_DDiscard, dws_DDiscardAO, dws_DGetInfo, 
dws_DSetInfo

Errors
dws_D_BADDPLAY, dws_D_NOTSUPPORTEDVER,
dws_DPlay_NOSPACEFORSOUND, dws_INVALIDPOINTER,
dws_NOTINITTED, dws_NOTSUPPORTED

dws_DSetInfo
Declarations
WORD dws_DSetInfo(dws_DPLAY *dp1, dws_DPLAY *dp2);
Declare Function dws_DSetInfo(dp1 As dws_DPLAY, dp2 As
  dws_DPLAY) As Integer
function dws_DSetInfo(var dp1: dws_DPLAYREC; var dp2:
  dws_DPLAYREC) : WORDBOOL;

Description
This function can change the parameters of a playing sound, and the one 
sequenced to play after it.

Parameters
dp1  ptr to struct which holds new parameters for currently playing sound
dp2  the same, for sequenced sound

Note
The flags field in each struct is used to specify which fields to modify.  You 
must indicate which sound is of interest, by using the soundnum field in at 
least one struct.  If you initialize the soundnum field in both structs, then both 
must be the same (e.g. dp1->soundnum = dp2->soundnum).  This is 
because a sequenced sound always has the same sound ID number as the 
playing sound.

The following parameters may be changed dws_dplay_COUNT,
dws_dplay_PRIORITY, dws_dplay_LVOL, dws_dplay_RVOL,
dws_dplay_PITCH, and dws_dplay_CALLBACK.

If you specify dws_dplay_CALLBACK then be sure to fill in both the 
hwndmsg and the message field.

Related Functions
dws_DGetInfo, dws_DPlay

Errors
dws_D_BADDPLAY, dws_INVALIDPOINTER, dws_NOTINITTED,
dws_NOTSUPPORTED

dws_DUnPause
Declarations
WORD dws_DUnPause(void);
Declare Function dws_DUnPause() As Integer
function dws_DUnPause : WORDBOOL;

Description
This function resumes digitized playback, if it was previously paused by 
dws_DPause.

All sounds will continue where they left off.

Note: all calls after the first will have no effect until dws_DPause is called 
again.  The WIN-STK does not maintain a "pause count".

Parameters
None.

Related Functions
dws_DPause

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

dws_ErrNo
Declarations
WORD dws_ErrNo(void);
Declare Function dws_ErrNo() As Integer
function dws_ErrNo : WORD;

Description
This function returns the last error triggered by a WIN-STK function.  Call it 
after any WIN-STK function returns failure (0 or FALSE).

Successful WIN-STK calls do not affect the return value of dws_ErrNo.
Notes
You may call this function at any time, even before dws_Init, or after 
dws_Kill.

Parameters
None.

Related Functions
All.

Errors
None.

dws_Init
Declarations
WORD dws_Init(dws_DETECTRESULTS *dr, dws_IDEAL
  *ideal);
Declare Function dws_Init(dr As dws_DETECTRESULTS,
  ideal As dws_IDEAL) As Integer
function dws_Init(var dr: dws_DETECTRESULTS; var
  ideal: dws_IDEAL) : WORDBOOL;

Description
This function configures and initializes the sound device drivers and the WIN-
STK internals.  Most STK calls won't work until after this call.

The exceptions are dws_DetectHardWare,  dws_DGetRateFromDWD,
dws_ErrNo, and dws_WAV2DWD.

Parameters
dr     ptr to struct which holds the output from dws_DetectHardWare
ideal  ptr to struct specifying some WIN-STK mode parameters

Related Functions
dws_DetectHardWare, dws_Kill

Errors
dws_ALREADYINITTED, dws_Init_BUFTOOSMALL,
dws_INTERNALERROR, dws_INVALIDPOINTER,
dws_MEMORYALLOCFAILED, dws_NOTSUPPORTED,
dws_RESOURCEINUSE, dws_SETEVENTFAILED

dws_Kill
Declarations
WORD dws_Kill(void);
Declare Function dws_Kill() As Integer
function dws_Kill : WORDBOOL;

Description
This function kills the WIN-STK.

If you have successfully called dws_Init, then you must call this function 
before your program terminates.

Parameters
None.

Related Functions
dws_Init

Errors
dws_NOTINITTED

dws_MClear
Declarations
WORD dws_MClear(void);
Declare Function dws_MClear() As Integer
function dws_MClear : WORDBOOL;

Description
This function kills the music playback.

Parameters
None.

Related Functions
dws_MPlay

Errors
dws_INTERNALERROR, dws_NOTINITTED, dws_NOTSUPPORTED

dws_MPause
Declarations
WORD dws_MPause(void);
Declare Function dws_MPause() As Integer
function dws_MPause : WORDBOOL;

Description
This function pauses music playback.

Note: all calls after the first will have no effect until dws_MUnPause is called.  
The WIN-STK does not maintain a "pause count".

Parameters
None.

Related Functions
dws_MUnPause

Errors
dws_NOTSUPPORTED, dws_NOTINITTED

dws_MPlay
Declarations
WORD dws_MPlay(dws_MPLAY *mplay);
Declare Function dws_MPlay(mplay As dws_MPlay) As
  Integer
function dws_MPlay(var mplay: dws_MPLAYREC) :
  WORDBOOL;

Description
This function starts playing a MIDI song.  For WIN-STK version 1, the MIDI 
song must be played from disk.  Version 2 will play from a memory buffer.

Notes
When specifying the MIDI filename, be sure to use the full pathname.

Parameters
mplay  ptr to struct specifying the song

Related Functions
dws_MPause, dws_MSongStatus

Errors
dws_INTERNALERROR, dws_INVALIDPOINTER, dws_NOTINITTED,
dws_NOTSUPPORTED

dws_MSongStatus
Declarations
WORD dws_MSongStatus(WORD *result);
Declare Function dws_MSongStatus(result As Integer) As
  Integer
function dws_MSongStatus(var result: WORD) : WORDBOOL;

Description
This function returns the status of the music playback engine.

Parameters
result	ptr to a variable to hold the returned status:

0                         //no song loaded
dws_MSONGSTATUSPLAYING    //song playing
dws_MSONGSTATUSPAUSED     //no song loaded, STK paused
dws_MSONGSTATUSPLAYING | dws_MSONGSTATUSPAUSED //Song loaded but paused

Related Functions
dws_MPause, dws_MPlay, dws_MUnPause

Errors
dws_INVALIDPOINTER, dws_NOTINITTED, dws_NOTSUPPORTED

dws_MUnPause
Declarations
WORD dws_MUnPause(void);
Declare Function dws_MUnPause() As Integer
function dws_MUnPause : WORDBOOL;

Description
This function resumes music playback, if it was previously paused by 
dws_MPause.

The music will continue where it left off.

Note: all calls after the first will have no effect until dws_MPause is called
again.  The WIN-STK does not maintain a "pause count".

Parameters
None.

Related Functions
dws_MPause

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

dws_Update
Declarations
WORD dws_Update(void);
Declare Function dws_Update() As Integer
function dws_Update : WORDBOOL;

Description
This function keeps the digitized sound going, even if your application is 
hogging the CPU.  Under normal circumstances, calling this function shouldn't 
be necessary with the 32-bit WIN-STK DLL.  In a 16-bit program, on the other 
hand, you may need to call dws_Update to prevent sound skipping, unless 
you are scrupulous about yielding time to the system frequently.  We 
recommend an interval of 55ms (18.2 Hz).

Notes
The Windows API timeSetEvent can be used to give you a callback during 
each hardware timer interrupt.  During such callbacks, most Windows API calls 
are off-limits; Windows is not reentrant.  dws_Update makes function calls 
which are in this category.  Calling it from an interrupt-time callback will
crash Windows!

Parameters
None.

Related Functions
None.

Errors
dws_NOTINITTED

dws_WAV2DWD
Declarations
WORD dws_WAV2DWD(BYTE *wave, DWORD *len, BYTE *dwd);
Declare Function dws_WAV2DWD(wave As Long, len As
  Long, dwd As Long) As Integer
function dws_WAV2DWD(wave: PBYTE; var len: DWORD; snd:
  PBYTE) : WORDBOOL;

Description
This function can convert a WAV-format buffer to DWD-format.  DWD is the 
digitized sound format used by DiamondWare's Sound ToolKit.

Notes
There are two usages of this function.  The first returns the buffer length 
required to hold the DWD.  The second converts the WAV to DWD format.
Notes
You may call this function at any time, even before dws_Init, or after 
dws_Kill.

Parameters
Usage 1:
wave  ptr to buffer containing a valid WAV file
len   length of the WAV buffer
dwd   NULL
Usage 2:
wave  ptr to WAV buffer
len   length of the WAV (input), size of DWD (output)
dwd   ptr to a buffer to hold the DWD output

Related Functions
dws_DGetRateFromDWD, dws_DPlay

Errors
dws_INTERNALERROR, dws_INVALIDPOINTER,
dws_WAV2DWD_NOTAWAVE, dws_WAV2DWD_UNSUPPORTEDFORMAT

dws_XDig
Declarations
WORD dws_XDig(WORD lvolume, WORD rvolume);
Declare Function dws_XDig(ByVal lvolume As Integer,
  ByVal rvolume As Integer) As Integer
function dws_XDig(lvolume, rvolume: WORD) : WORDBOOL;

Description
This function allows you to control the overall volume for digitized sound 
output.

Parameters
lvolume	left volume, 0=off, dws_IDENTITY=normal, 65535=MAX
rvolume	same, for right channel

Related Functions
dws_DPlay

Errors
dws_NOTINITTED, dws_NOTSUPPORTED

The Errors
There are 16 errors (plus one non-error) which may be generated by a WIN-STK
function.

0 dws_EZERO
This is a non-error.  dws_ErrNo will return this if you call it before any WIN-
STK function triggers an error.

1 dws_NOTINITTED
The STK was not initialized when you called an STK function.

2 dws_ALREADYINITTED
This call cannot be made after the STK is initialized.

3 dws_NOTSUPPORTED
The installed hardware, or current WIN-STK mode doesn't support the 
requested feature (music or sound).

4 dws_INTERNALERROR
The STK encountered an invalid internal state.  Please report this to  
DiamondWare.

5 dws_INVALIDPOINTER
You passed an invalid pointer to a function.  Under Win32, the WIN-STK can 
sometimes catch this type of problem and trigger an error.

6 dws_RESOURCEINUSE
The WIN-STK tried to open a device driver, but it was already opened by 
another program.

7 dws_MEMORYALLOCFAILED
The WIN-STK tried to allocate some memory, but was denied.

8 dws_SETEVENTFAILED
The WIN-STK tried to set an event semaphore, but was denied.

9 dws_BUSY
The WIN-STK is currently processing something; please try your call again 
later.	This error can only occur in 16-bit programs, and if you're calling the
WIN-STK from an interrupt handler or equivalent.  The error cannot occur in 
32-bit programs, because the WIN-STK is thread-safe.

101 dws_Init_BUFTOOSMALL
You tried to set the buffer size in the dws_IDEAL struct to something which 
was obviously too small.

201 dws_D_NOTADWD
The DWD buffer you passed did not contain a DWD file.

202 dws_D_NOTSUPPORTEDVER
The DWD buffer you passed contained an unknown or unsupported version of 
DWD file.

203 dws_D_BADDPLAY
You set up a dws_DPLAY struct which was not valid for the function called.

Note: dws_DGetInfo and dws_DSetInfo require the soundnum field to 
specify the sound.

251 dws_DPlay_NOSPACEFORSOUND
This is more of a warning than an error.  It's telling you that there are no
sound slots left, and that the priority of your new sound was too low to
displace any playing sound.

301 dws_WAV2DWD_NOTAWAVE
The WAV buffer you passed did not contain a WAV file.

302 dws_WAV2DWD_UNSUPPORTEDFORMAT
The WAV buffer you passed contained an unknown or unsupported version of 
WAV file.

The Data Structures
There are 4 structure types provided by the WIN-STK.  Their formats and 
specifications are detailed here.

dws_DETECTRESULTS
This struct is filled in by dws_DetectHardWare.  The digbfr field is user-
writable, but use caution.

Note: information is stored in the reserved field.  If you're writing this
struct out to a file, make sure to write out the entire contents.  Failure to
do this may result in unpredictable behavior!

Name     Size    Description
muscaps  4      *bitwise OR of available music devices
digcaps  4      +bitwise OR of available WAV modes
digbfr   4       buffer size calculated by autodetect
reserved 20      undocumented

*The music devices are dws_muscap_MIDIPORT (external MIDI port, MPU-401 adapter
or compatible, wavetable board, etc.), dws_muscap_SYNTH (a generic internal
synthesizer), dws_muscap_SQSYNTH (a square-wave synth), dws_muscap_FMSYNTH (FM
synthesizer), and dws_muscap_MAPPER (the MIDI mapper).	If there is no MIDI
capability installed in the machine, then the muscaps field will be set to
dws_muscap_NONE.

+The WAV modes are dws_digcap_11025_08_1,
dws_digcap_11025_08_2, dws_digcap_11025_16_1,
dws_digcap_11025_16_2, dws_digcap_22050_08_1,
dws_digcap_22050_08_2, dws_digcap_22050_16_1,
dws_digcap_22050_16_2, dws_digcap_44100_08_1,
dws_digcap_44100_08_2, dws_digcap_44100_16_1, and
dws_digcap_44100_16_2.	If there is no WAV capability in the machine, then
the digcaps field will be set to dws_digcap_NONE.

The format of each constant is dws_digcap_<sampling rate in Hz>_<bits per 
sample>_<number of channels> (e.g. dws_digcap_22050_08_2 for 22kHz 
8-bit stereo).

dws_IDEAL
This struct allows you to control the mode and features that the WIN-STK will
set up when it initializes.

Name       Size    Description
flags      4      *bitwise OR of options
mustyp     4       preferred MIDI device
digtyp     4       preferred WAV output mode
dignvoices 2       max digitized voices to mix
reserved   18      undocumented

*The possible flags are dws_ideal_SWAPLR (if the left and right channels 
are reversed by the hardware, the WIN-STK can swap them to compensate), 
dws_ideal_DISABLEPITCH (for extra speed, disable pitch changing on slow
machines with one simple flag), dws_ideal_DISABLEVOLUME (for even more speed,
disable volume changing), and dws_ideal_MAXSPEED (a shortcut to disable the
pitch and volume change feature).  Specify dws_ideal_NONE if you don't want
any of these options.

dws_DPLAY
This struct is used for playing or sequencing a digitized sound (the dws_DPlay
function).  It's also used for querying a playing or sequenced sound (the
dws_DGetInfo function) and reprogramming a playing or sequenced sound
(the dws_DSetInfo function).

Name       Size    Description
flags      4      *bitfield specifying fields used
snd        4       pointer to DWD buffer
count      2       number of times to play; 0=infinite
priority   2      +higher numbers = higher priorities
presnd     2       soundnum of sound to sequence after
soundnum   2       number assigned to this sound
lvol       2       left volume, 0-dws_IDENTITY-65535
rvol       2       the same, for the right channel
pitch      2      #playback length
dummy      2       pads next field to dword boundary
hwndmsg   ^4      =handle of window to send msgs to
message   ^4       message ID to send
reserved  ^18      undocumented

*There is a bitfield flag corresponding to each field in this struct, except
that hwndmsg and message must be specified as a pair, and so get only one flag.
The flags are dws_dplay_SND, dws_dplay_COUNT, dws_dplay_PRIORITY,
dws_dplay_PRESND, dws_dplay_SOUNDNUM, dws_dplay_LVOL, dws_dplay_RVOL,
dws_dplay_PITCH, and dws_dplay_CALLBACK.  For each field you use, set the
corresponding bit in flags.

+If the program tries to play more sounds than specified in the dws_IDEAL 
struct passed to dws_Init, then the lowest priority sound will be dropped.

#The pitch field actually controls the playback length.  In other words, lower 
values mean higher frequencies, and higher values mean lower (and slower) 
playback.  As with volume change, dws_IDENTITY means no change in 
volume.

^Sizes are given for the 32-bit DLL.  For the 16-bit DLL, hwndmsg and 
message are both 2 bytes.  reserved is 22 bytes.

=When the WIN-STK send you a window message, the wParam parameter 
holds the soundnum, and lParam holds dws_event_SOUNDCOMPLETE 
(future versions will support more types of events).

dws_MPLAY
This struct is used for playing a MIDI song by the dws_MPlay function.

Name       Size    Description
track      4       0-terminated filename of MIDI song
count      2       number of times to play; 0=infinite
reserved   10      undocumented

The Utilities
We provide two utilities, PLAYSTK (with source in C, Visual BASIC, and 
Pascal) and WAV2DWD.  Both include 16- and 32-bit versions.

PLAYSTK
PLAYSTK is provided mostly as a source-code example of how to use the 
WIN-STK.  It's also useful as a test to see if the machine is working.  It can
play several digitized sounds (.WAV or .DWD format) plus a song (.MID format)
at the same time.

It's implemented as a dialog box.  On the right side are sliders for volume and
pitch control.	These affect all new sounds played, and they'll also change the
most recent currently playing sound.  There is a check box to reverse the left
and right channels.  And there are three radio buttons to control sampling
rate.  The program is hard-wired for 8-bit stereo output.

The New button will bring up a dialog box which allows you to open any 
.WAV, .DWD, or .MID file.

The Play button will start whichever sound or song is selected in the listbox.  
Double-clicking on a listbox item will also play it.

The Stop button will stop all noise.

The Remove button will delete the selected listbox item.

Operation should be straightforward and intuitive.  The source code shows you 
many WIN-STK programming techniques.

WAV2DWD
This program is provided to make batch conversion of a large number of WAV 
files easy.  The WIN-STK can convert WAV buffers to DWD at runtime.  But if 
you know what files you need in advance, then converting them off-line is the
best way to go.

This program is also implemented as a dialog box.

There are three windows on the left side to control the source (WAV) file 
selections.  They are drive, directory, and file listboxes.  The three windows
on the right side control drive and directory for the output (DWD) plus show
(without any user control) the list of DWD files in the output directory.

Once you've set up your source and destination directories, select one or more
WAV files to convert.  Hit the Convert button, and DWD files quickly appear.

8-bit mono WAVs convert to DWDs which are also suitable for use with the 
DOS-STK.

The File Formats
WIN-STK version 1 uses one file format specified by DiamondWare.  It's called
DWD (DiamondWare Digitized).

The specification is provided here in the hope that it may be useful to you.  
Permission is hereby granted to use this specification in the creation of any 
software.  The specification itself is, of course, protected by United States
law and international treaty provisions.

DWD Header
Byte #  Description
00-22   "DiamondWare Digitized\n\0"
23      1A (EOF to abort printing of file)
24      Major version number
25      Minor version number
26-29   Unique sound ID (checksum XOR timestamp)
30      Reserved
31      Compression type (0=none)
32-33   Sampling rate (in Hz)
34      Number of channels (1=mono, 2=stereo)
35      Number of bits per sample (8, 16)
36-37   Absolute value of largest sample in file
38-41   length of data section (in bytes)
42-45   # samples (16-bit stereo is 4 bytes/sample)
46-49   Offset of data from start of file (in bytes)
50-53   Reserved for future expansion (markers)
54-55   Padding
??-?? 	Future expansion (heed the 2 offsets, above!)

About DWD Version Numbers
The DWD specification v1.0, finalized in 1994, did not need modification to 
support the WIN-STK.  However, due to a slight oversight, the DOS-STK does 
not reject DWD files which are stereo and/or 16-bit, even though it cannot 
correctly play them (there was no software which could generate such files back
then).	We can't recall that product, so we are incrementing the version # of
the file.

8-bit mono DWD files with no compression should be marked as version 1.0.  
The DOS- or WIN-STK can correctly play these files.  If a DWD file contains 
two (or more) channels, 16 (or more) bits per sample, or compression, then it 
must be marked as version 1.1, which will be rejected by the DOS-STK.  Our 
WAV2DWD utility generates files according to this version numbering scheme.

The WIN-STK will attempt to play any file of version 1.x (unlike the DOS-
STK).  Any future enhancements to the file format which break backwards 
compatibility will jump to 2.0 or higher for this reason.

Sample Format
Samples are stored as signed data.  That is, each 8-bit sample ranges from -128
to +127.  16-bit samples range from -32768 to +32767.

Monophonic files are stored in order, from sample 0 to sample N.

Stereophonic files are stored in order, with the left channel of each sample 
preceding the right.

Appendix
Changes from the Sound ToolKit for DOS
If you have used DiamondWare's Sound ToolKit for DOS, you may wish to 
skim most of the manual and study this section.

In all cases we have attempted to preserve the same API and behavior as in the
DOS version.  Some changes, many bona fide enhancements, were required or
made possible by the move to Windows.

We'll go over the changes to the data structures, functions, behavior, errors,
samples, and utility software.

Data Structures
Note: we changed all occurrences of  byte, word, and dword to BYTE, 
WORD, and DWORD, to conform to the Windows convention.

Pascal Note
The DOS-STK used explicit pointer syntax.  The WIN-STK now uses the var 
keyword.

dws_DETECTOVERRIDES
In Windows, the sound driver deals with the port, DMA, and IRQ settings, so 
the STK doesn't need to try to autodetect them.  This struct was originally 
provided to override the autodetect, and has been completely eliminated in the 
WIN-STK.

dws_DETECTRESULTS
Forget everything you learned about this structure under DOS.  Its purpose is 
still the same: to store the results of the autodetect.  But under Windows,
we're detecting buffer size, driver and hardware capabilities, not hardware
settings.

You might want to read about this structure in the Reference section.

dws_IDEAL
digrate has been merged into digtyp, which is now a bitfield.  Read the 
section on the dws_IDEAL struct for details on how this works.

In Windows, there is often a choice of music output devices (with different 
levels of sound quality).  The muscaps field in the dws_DETECTRESULTS 
struct tells you which drivers are installed.  The mustyp field in the 
dws_IDEAL struct allows you to specify which one to use.

There is now a flags field, which allows you to disable volume and/or pitch 
changing support (for slower machines).  It also allows you to specify that the
left and right channels should be swapped (to compensate for wiring problems
downstream).

dws_DPLAY
This structure has been greatly expanded, due to the integration of
volume/pitch change functionality into the kernel, and the new support for
stereo.

You should set the first field, flags, to indicate which of the rest of the
fields you're using.  In most cases, unused fields will assume reasonable
defaults--see the complete discussion in the Reference section for details.

snd, count, priority, presnd, and soundnum work as they did in the 
DOS version.

We added lvol and rvol to control the left and right volume of the sound.

Note:  Both mono and stereo source sounds will play in stereo, so long as the
output mode is stereo.

pitch controls the playback rate of the sound.	More specifically, it controls
the length of the sound during playback.  Thus higher numbers correspond to 
slower and lower sounds, and lower numbers correspond to faster and higher 
sounds.

For normal playback, use dws_IDENTITY for lvol, rvol, and pitch.

The WIN-STK can notify you when a sound is done playing.  For this feature,
use the last two fields: hwndmsg and message.  The WIN-STK will send message
ID message to the window whose handle is hwndmsg.  In this message, the wParam
parameter holds the soundnum, and the lParam parameter holds
dws_event_SOUNDCOMPLETE (future versions will support more types of events).

dws_MPLAY
The track field is now a NULL-terminated string holding the filename of the
MIDI song to play (future versions will again play music from memory buffers).

Functions
We removed some functions, added a few new ones, and changed one.

Removed
dws_DGetRate
dws_DSetRate
dws_DSoundStatus
dws_XMaster
dws_XMusic
dwt_*

The playback rate cannot be changed while the STK is running under Windows.
However, the built-in DSP can compensate for the odd sound recorded at a 
different sampling rate (there will be some sound quality loss, however).

dws_DSoundStatus has been replaced with dws_DGetInfo, which is much more
powerful.  This function pairs well with dws_DSetInfo.

In Windows, the user can change the mixer volumes at will using the control 
panel.  Therefore, it's unnecessary (and counter to the Windows paradigm) for 
an application to gratuitously change them.  Thus, we've eliminated
dws_XMaster and dws_XMusic.  Below, read what we've done with dws_XDig.

Because implementing a timer like the DWT is trivial in Windows, and because 
the WIN-STK doesn't require you to call dws_Update frequently and periodically
(see below), we're no longer providing the DWT.

Added
dws_DGetInfo
dws_DSetInfo
dws_WAV2DWD

dws_DGetInfo will return you a full dws_DPLAY structure full of 
information about a playing or sequenced sound.  You can change most of the 
fields, and then call dws_DSetInfo.  See the Reference section for details.

dws_WAV2DWD allows you to convert WAV files to DWD format at runtime.
Changed
dws_Update
dws_XDig

In the DOS-STK, dws_Update kept the music playing; if you didn't call it, 
you didn't get music.  We provided the optional DWT module to take care of 
this, or you could call it from your own hardware time handler.  All of this
stuff is unnecessary in Windows.

But Windows (version 3.x) causes other problems.  Each application runs until
it voluntarily yields time to the system and other applications.  "Normal"
applications are supposed to play nicely, and yield frequently.  If an
application hogs the system, all other apps (and the Windows GUI) freeze until
the hog yields.  This is bad enough (though often tolerated) with productivity
applications.  But it's totally unacceptable for sound to stop and then resume
playing a quarter-second later.  The discontinuity jars the listener.

Games and multimedia applications can generally assume that they're not sharing
the system with email, word processors, spreadsheets, etc.  But they do often
spend significant time in tight loops, and sometimes it's quite inconvenient to
yield time to the system.

If your Windows 3.x application needs to hog the system for a while, call 
dws_Update periodically; we recommend an interval of 55ms (18.2 times per
second).  This will keep the sound rolling under 3.x (the only way to stop it
is to drag your application by the title bar).	Under 95/NT, the 32-bit version
of the WIN-STK is multithreaded, though the function is fully enabled, and
works as it does under 16 bits.

dws_XDig no longer controls the hardware mixer.  Instead, it controls our 
internal software mixer.  Thus, it makes it easy to quickly lower or raise
(subject to clipping distortion) the overall digitized volume level.
dws_XMusic (and dws_XMaster) will return with WIN-STK v2, which will provide
much greater control over MIDI music.

dws_XDig now takes two parameters, to support stereo.  And these parameters 
are 0 to 256 (dws_IDENTITY) to 65535, rather than 0-255 in the DOS version.
The ability to make digitized playback louder via dws_XDig is new for the 
WIN-STK.

Behavior
Some changes in behavior are noted above in the discussions of the various data
structures and functions.  Below, in no particular order, are some other
changes of which you should be aware.

In the DOS-STK, the digitized buffer size was a purely internal issue.	Our
research and testing determined the buffer size.  We compiled it into the STK,
and it just worked.  Unfortunately, under Windows, the buffer size must change
from system to system.	Why?  Because larger buffers are less susceptible to
skipping, but smaller buffers provide lower latency (the time between the call
to dws_DPlay and when the user actually hears the sound).  Slower machines
therefore require larger buffers.  Buffer size determination is a non-trivial
calculation, which is performed during dws_DetectHardWare.  You might provide
your user a slider bar with some amount of control over buffer size, to
optimize on his machine the tradeoff between latency and skipless playback.

After the call to dws_DetectHardWare, you can change digbfr slightly 
(go easy!) according to the user's input.  Of course, most of the time, the
autodetect routine will do its job properly, and you won't need to monkey with
this setting.  Unless there's a problem with skipping, leave it alone.

The DOS version dropped low-priority sounds out when the dynamic range of
the hardware would otherwise be exceeded.  The WIN-STK can clip sounds on
a sample-by-sample basis.  Each sound must still have a priority so that if the
maximum number of sounds is exceeded, the kernel knows in which order to
drop sounds.

The DOS version supported only 8-bit mono sound.  The WIN-STK supports 8- and
16-bit source sounds in both mono and stereo, and can play using drivers in 8-
or 16-bit, mono or stereo modes.  It will perform all necessary conversions.

The DOS version was restricted to sounds smaller than 64K.  Both the 16- and
32-bit WIN-STK DLLs support sounds up to 4G in length.

The 32-bit WIN-STK DLL can trap exceptions caused by invalid user-supplied 
pointers, and flag them with an error return value.

For WIN-STK version 1, music is played directly from .MID files on disk.  
Version 2 will play from memory and provide interactivity and runtime control 
of music.  Therefore, we say a temporary goodbye to the .DWM file (it will 
return!)  There is also no control of FM-instrument patches with the WIN-STK.
Errors
Many errors are unnecessary under Windows, and have been eliminated.  We've 
added some new ones too.  As with the DOS version, the main manual lists all 
possible errors which can be flagged by each routine.

You might want to read the Error listing in the Reference section.

Samples
PLAYSTK.C
PLAYSTK.BAS
PLAYSTK.PAS

The samples all compile into PLAY16.EXE or PLAY32.EXE, which is a single 
sample applet for both music and sound.

Utility Programs
We eliminated VOC2DWD.EXE (VOC files are dying along with DOS) and 
MID2DWM.EXE (this version of the WIN-STK does not use .DWM files).

We now provide WAV2DWD.EXE, which functionality is also available to 
your application on-line via the WIN-STK library.
