Unit DWaveMix

Classes

TfChannels - Renamed from WaveMix.
TWaveMix -
TWaveMixChannelsProperty -

Functions

InitLibrary - get the system directory don't bother checking path, because will fail when I do cmp anyway
MixerPlay - This is the main mixing function, it gets called often and so is a good candidate for assembly optimization.
MyWaveOutGetPosition -
MyWaveOutReset - bugbug: if stereo gets screwed up may need to force dwBaseTime to be block aligned
Register - ********************************* TWaveMix
WaveMixActivate - error msg already displayed in AllocWaveBlocks */
WaveMixCloseChannel - don't remix if that channel didn't have data on it.
WaveMixCloseSession -
WaveMixConfigureInit - * if we are running on NT don't want to use our technique of flooding the wave output to ** try to figure out the DMA size since the way NT protects the hardware makes this inaccurate
WaveMixFlushChannel - * if we are not already playing we should pause before submitting data or we ** may not be able to do it fast enough and will cause a hicup
WaveMixFreeWave - * flush the channel and let WaveMixFlushChannel do all the ** error checking for us
WaveMixInit - function prototypes

adjust the wave format if the sampling rate is no longer set to the default */
WaveMixOpenChannel - return same errors as waveOutOpen, waveOutWrite, and waveOutClose */
WaveMixOpenWave - SamplesPerSec align the data, e.
WaveMixPlay - if the playqueue is empty we want to reset our global waveoutposition back to 0 so we don't have to worry about the waveout position wrapping back to zero and messing up all sounds still playing (this would take 13.

Types

CHANNELNODE
fnRemix
fnSampleAdjust
GLOBALS
HPINT
PCHANNELNODE
PDWord
PGLOBALS
PLAYQUEUE
PMixConfig
PMixPlayParams
PMixWave
PPCMWaveFormat
PPLAYQUEUE
PSAMPLE
PSAMPLE16
PWaveFormat
PXWAVEHDR
TMixConfig
TMixPlayParams
TMixWave
TPCMWaveFormat
TWaveFormat
TWaveMixChannels
XWAVEHDR

Constants

BITSPERBYTE
BITSPERSAMPLE
BYTESPERSAMPLE
COUNTNODES
DEBUGOUTPUT
DEFAULT_GOODWAVPOS
DEFAULT_NTWAVEBLOCKLEN
DEFAULT_REMIXALGORITHM
DEFAULT_SAMPLESPERSEC
DEFAULT_WAVEBLOCKLEN
DEFAULT_WAVEBLOCKS
gpFormat
gszAppName
gszDefault
gszIniFile
gszMemError
MAGICNO
MAJORVERSION
MAXCHANNELS
MAXFILENAME
MAXQUEUEDWAVES
MAXWAVEBLOCKLEN
MAXWAVEBLOCKS
MINORVERSION
MINWAVEBLOCKLEN
MINWAVEBLOCKS
MONO
NUMHDRS
SAMPLESPERSEC
SILENCE
WAVEBUFSIZE
WF_WINNT
WMIX_ALL
WMIX_CHANNELS
WMIX_CLEARQUEUE
WMIX_CONFIG_CHANNELS
WMIX_CONFIG_SAMPLINGRATE
WMIX_FILE
WMIX_HIGHPRIORITY
WMIX_MEMORY
WMIX_NOREMIX
WMIX_OPENALL
WMIX_OPENCOUNT
WMIX_OPENSINGLE
WMiX_QUEUEWAVE
WMIX_RESOURCE
WMIX_SAMPLINGRATE
WMIX_USELRUCHANNEL
WMIX_WAIT
_MAX_PATH

Variables

fChannels


Functions


procedure InitLibrary;

get the system directory don't bother checking path, because will fail when I do cmp anyway

function MixerPlay(lpXWH: PXWAVEHDR; fWriteBlocks: Boolean): Boolean;

This is the main mixing function, it gets called often and so is a good candidate for assembly optimization. Not sure how much benefit I could get from it. return TRUE if a block was submitted for playing */

function MyWaveOutGetPosition(hWaveOut: HWAVEOUT; fGoodGetPos: Boolean): DWord;


procedure MyWaveOutReset(hWaveOut: HWAVEOUT);

bugbug: if stereo gets screwed up may need to force dwBaseTime to be block aligned

Procedure Register;

********************************* TWaveMix

procedure WaveMixActivate(hMixSession: THandle; fActivate: Boolean);

error msg already displayed in AllocWaveBlocks */

procedure WaveMixCloseChannel(hMixSession: THandle; iChannel: Integer; dwFlags: DWord);

don't remix if that channel didn't have data on it. */

procedure WaveMixCloseSession(hMixSession: THandle);


function WaveMixConfigureInit(lpConfig: PMIXCONFIG): THandle;

* if we are running on NT don't want to use our technique of flooding the wave output to ** try to figure out the DMA size since the way NT protects the hardware makes this inaccurate

procedure WaveMixFlushChannel(hMixSession: THandle; iChannel: Integer; dwFlags: DWord);

* if we are not already playing we should pause before submitting data or we ** may not be able to do it fast enough and will cause a hicup

procedure WaveMixFreeWave(hMixSession: THandle; lpMixWave: PMIXWAVE);

* flush the channel and let WaveMixFlushChannel do all the ** error checking for us

function WaveMixInit: THandle;

function prototypes

adjust the wave format if the sampling rate is no longer set to the default */


procedure WaveMixOpenChannel(hMixSession: THandle; iChannel: Integer; dwFlags: DWord);

return same errors as waveOutOpen, waveOutWrite, and waveOutClose */

function WaveMixOpenWave(hMixSession: THandle; szWaveFilename: PChar; hInst: THandle; dwFlags: DWord): PMixWave;

SamplesPerSec align the data, e.g. convert from 44.1kHz to 11.025 kHz or vice versa*/

procedure WaveMixPlay(lpMixPlayParams: PMIXPLAYPARAMS);

if the playqueue is empty we want to reset our global waveoutposition back to 0 so we don't have to worry about the waveout position wrapping back to zero and messing up all sounds still playing (this would take 13.5 hours of playing at 44.1khz to happen, but we want to be as robust as possible. However, we need to verify that all the channels are empty too. Otherwise resetting the waveoutpostion will cause these sounds to stay on the channel and play again sometime in the future.

Types


CHANNELNODE = record
next : PCHANNELNODE;
PlayParams : TMIXPLAYPARAMS;
lpMixWave : PMIXWAVE;
dwNumSamples : DWord;
dwStartPos : DWord;
dwEndPos : DWord;
lpPos : PSAMPLE;
lpEnd : PSAMPLE;
end;

fnRemix = procedure (dwRemixSamplePos: DWord; pCD: PCHANNELNODE)
this is pointer to last sample of actual wave data
fnSampleAdjust = function (dwSamplePos: DWord; dwAdjustAmt: DWord): DWord

GLOBALS = record
wMagic1 : Word;
hWndApp : HWND;
fShow : Boolean;
hWaveOut : HWAVEOUT;
fActive : Boolean;
wDeviceID : UINT;
szDevicePName : array [0..MAXPNAMELEN] of char;
aChannel : array [0..MAXCHANNELS-1] of PCHANNELNODE;
iChannels : Integer;
MRUChannel : array [0..MAXCHANNELS-1] of DWord;
dwMRU : DWord;
pcm : TPCMWAVEFORMAT;
dwWaveBlockLen : DWord;
iNumWaveBlocks : Integer;
dwCurrentSample : DWord;
dwBaseTime : DWord;
fGoodGetPos : Boolean;
dwWaveOutPos : DWord;
pfnRemix : fnRemix;
pfnSampleAdjust : fnSampleAdjust;
pWaitList : PCHANNELNODE;
wMagic2 : Word;
end;

HPINT = ^Word

PCHANNELNODE = ^CHANNELNODE

PDWord = ^DWord

PGLOBALS = ^GLOBALS

PLAYQUEUE = record
first : PXWAVEHDR;
last : PXWAVEHDR;
end;

PMixConfig = ^TMixConfig
11, 22, or 44 kHz
PMixPlayParams = ^TMixPlayParams
# of times to loop ($FFFF = indefinite
PMixWave = ^TMixWave

PPCMWaveFormat = ^TPCMWaveFormat

PPLAYQUEUE = ^PLAYQUEUE

PSAMPLE = PCHAR

PSAMPLE16 = ^Smallint

PWaveFormat = ^TWaveFormat

PXWAVEHDR = ^XWAVEHDR

TMixConfig = record
wSize : word;
dwFlags : longint;
wChannels : word;
wSamplingRate : word;
end;
block size of data
TMixPlayParams = record
Size : Word;
hMixSession : THandle;
iChannel : Integer;
lpMixWave : PMixWave;
hWndNotify : HWND;
dwFlags : Longint;
wLoops : Word;
end;

TMixWave = record
pcm : TPCMWAVEFORMAT;
wh : TWAVEHDR;
szWaveFilename : array [0..MAXFILENAME] of char;
end;

TPCMWaveFormat = record
wf : TWaveFormat;
wBitsPerSample : Word;
end;

TWaveFormat = record
wFormatTag : Word;
nChannels : Word;
nSamplesPerSec : DWord;
nAvgBytesPerSec : DWord;
nBlockAlign : Word;
end;

TWaveMixChannels = Byte
**************************************** ***** TWaveMix Component *****************
XWAVEHDR = record
wh : TWAVEHDR;
fAvailable : Boolean;
dwWavePos : DWord;
g : PGLOBALS;
QNext : PXWAVEHDR;
end;

Constants

BITSPERBYTE = 8

BITSPERSAMPLE = 8

BYTESPERSAMPLE = 1

COUNTNODES = 0

DEBUGOUTPUT = 0

DEFAULT_GOODWAVPOS = 0

ResetRemix() */

DEFAULT_NTWAVEBLOCKLEN = 2048

DEFAULT_REMIXALGORITHM = 1

DEFAULT_SAMPLESPERSEC = 11

0 forces code to figure DMA size */

DEFAULT_WAVEBLOCKLEN = 0

number of ping-pong buffers */

DEFAULT_WAVEBLOCKS = 3

use timeGetTime() */

gpFormat = ( wf: (wFormatTag: WAVE_FORMAT_PCM; nChannels: MONO; nSamplesPerSec: SAMPLESPERSEC; nAvgBytesPerSec: SAMPLESPERSEC * BYTESPERSAMPLE * MONO; nBlockAlign: BYTESPERSAMPLE ); wBitsPerSample: BITSPERSAMPLE )

gszAppName = 'WavMix32'

11025 hz */

gszDefault = 'default'

gszIniFile = 'WAVEMIX.INI'

gszMemError = 'Unable to allocate memory for waveform data. '+ 'Try making more memory available by closing other applications.'

MAGICNO = $5432

MAJORVERSION = $02

MAXCHANNELS = 8

MAXFILENAME = 15

WMixPlay: hold until next 'Play'

MAXQUEUEDWAVES = 100

MAXWAVEBLOCKLEN = 4096

MAXWAVEBLOCKS = 6

MINORVERSION = $00

MINWAVEBLOCKLEN = 512

MINWAVEBLOCKS = 2

MONO = 1

NUMHDRS = 512

SAMPLESPERSEC = 11025

SILENCE = $80

WAVEBUFSIZE = 16

WF_WINNT = $4000

if the buffer is bigger than this don't worry about it

WMIX_ALL = $0001

WMixChannel: open # channels

WMIX_CHANNELS = $0001

WMixFlush: don't remix sound data

WMIX_CLEARQUEUE = $0001

WMixPlay: play when previous finishes

WMIX_CONFIG_CHANNELS = 1

WMIX_CONFIG_SAMPLINGRATE = 2

WMIX_FILE = $0001

WMIX_HIGHPRIORITY = $0004

WMixPlay: play on next available chan

WMIX_MEMORY = $0004

WMixOpen: from system resource file

WMIX_NOREMIX = $0002

WMixFlush & Close: do ALL channels

WMIX_OPENALL = $0001

WMixChannel: open one Play channel

WMIX_OPENCOUNT = $0002

WMixChannel: open ALL eight channels

WMIX_OPENSINGLE = $0000

WMixOpen: from memory

WMiX_QUEUEWAVE = $0000

WMixConfigure: set playback rate

WMIX_RESOURCE = $0002

WMixOpen: from disk file

WMIX_SAMPLINGRATE = $0002

WMixConfigure: set channels

WMIX_USELRUCHANNEL = $0002

WMixPlay: play sound immediately

WMIX_WAIT = $0008

WMixPlay: remix play buffer immediately

_MAX_PATH = 200


Variables

fChannels : TfChannels