Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

473 lines
14 KiB

//*********************************************************************
//* Microsoft Windows **
//* Copyright(c) Microsoft Corp., 1995 **
//*********************************************************************
//
// MIDI.C - Code to play MIDI files
//
// HISTORY:
//
// 7/21/95 jeremys Created.
//
#include "all.h"
#include "midi.h"
#include "blob.h"
const CHAR c_szSequencer[] = "sequencer";
const CHAR c_szWaveAudio[] = "waveaudio";
DWORD PlayAudio_w(struct Mwin * tw,LPSTR lpszFileName,BOOL fMIDI);
DWORD PlayMIDIFile(struct Mwin * tw,LPSTR lpszMIDIFileName)
{
return PlayAudio_w(tw,lpszMIDIFileName,TRUE);
}
DWORD PlayWaveFile(struct Mwin * tw,LPSTR lpszWaveFileName)
{
return PlayAudio_w(tw,lpszWaveFileName,FALSE);
}
VOID HandleBGSoundRequest(struct Mwin * tw,PLAYSOUNDREQ * pPlaySoundReq)
{
if (pPlaySoundReq->dwFileType == BA_TYPE_MIDI) {
// stop any MIDI playing we are currently doing
StopBackgroundAudio(tw,SBA_STOP_MIDI);
if (tw->w3doc && tw->w3doc->pBGSoundInfo) {
// free memory in tw for filename of previous MIDI file, if any
if (tw->w3doc->pBGSoundInfo->pszMidiFileName)
GTR_FREE(tw->w3doc->pBGSoundInfo->pszMidiFileName);
// remember the filename of the current MIDI file
tw->w3doc->pBGSoundInfo->pszMidiFileName =
pPlaySoundReq->pszFileName;
tw->w3doc->pBGSoundInfo->nMidiFileLoopsRemaining =
pPlaySoundReq->nLoops;
}
PlayMIDIFile(tw,pPlaySoundReq->pszFileName);
} else {
// stop any waveform audio playing we are currently doing
StopBackgroundAudio(tw,SBA_STOP_WAVEFORM);
if (tw->w3doc && tw->w3doc->pBGSoundInfo) {
// free memory in tw for filename of previous sound file, if any
if (tw->w3doc->pBGSoundInfo->pszSoundFileName)
GTR_FREE(tw->w3doc->pBGSoundInfo->pszSoundFileName);
// remember the filename of the current sound file
tw->w3doc->pBGSoundInfo->pszSoundFileName =
pPlaySoundReq->pszFileName;
tw->w3doc->pBGSoundInfo->nSoundFileLoopsRemaining =
pPlaySoundReq->nLoops;
tw->w3doc->pBGSoundInfo->dwWaveType = pPlaySoundReq->dwFileType;
}
PlaySoundFile(tw,pPlaySoundReq->pszFileName,pPlaySoundReq->dwFileType);
}
// free the sound req structure. Note that we don't have to free
// pPlaySoundReq->pszFileName... that buffer is now pointed to by tw
// and will get freed when tw is freed.
GTR_FREE(pPlaySoundReq);
}
DWORD PlayAudio_w(struct Mwin * tw,LPSTR lpszFileName,BOOL fMIDI)
{
UINT wDeviceID;
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;
MCI_PLAY_PARMS mciPlayParms;
/*
* Open the device by specifying the
* device name and device element.
* MCI will attempt to choose the
* MIDI Mapper as the output port.
*/
mciOpenParms.lpstrDeviceType = (fMIDI ? c_szSequencer : c_szWaveAudio);
mciOpenParms.lpstrElementName = lpszFileName;
if (dwReturn = (DWORD) mciSendCommand((MCIDEVICEID) NULL, MCI_OPEN,
MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
(DWORD)(LPVOID) &mciOpenParms)) {
/*
* Failed to open device;
* don't close it, just return error.
*/
return dwReturn;
}
/* Device opened successfully. Get the device ID. */
wDeviceID = mciOpenParms.wDeviceID;
/*
* Begin playback. The window procedure function
* for the parent window is notified with an
* MM_MCINOTIFY message when playback is complete.
* The window procedure then closes the device.
*/
mciPlayParms.dwCallback = (DWORD) tw->hWndFrame;
if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,
MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms)) {
mciSendCommand(wDeviceID, MCI_CLOSE, 0, 0);
return dwReturn;
}
// remember the device ID so we can close it later if need be
// (if we change the page or exit the app while still playing)
if (fMIDI) {
tw->w3doc->pBGSoundInfo->dwMidiDeviceID = wDeviceID;
} else {
tw->w3doc->pBGSoundInfo->dwWaveDeviceID = wDeviceID;
}
return 0;
}
VOID HandleMciNotify(struct Mwin * tw,DWORD dwFlags,DWORD dwDeviceID)
{
// if this is "success" notification, that means a wave or
// MIDI file has finished playing. We need to close the device
// in this case.
if (dwFlags & MCI_NOTIFY_SUCCESSFUL) {
BGSOUNDINFO * pBGSoundInfo;
BOOL fPlayAgain=FALSE;
if (tw && tw->w3doc && tw->w3doc->pBGSoundInfo) {
pBGSoundInfo = tw->w3doc->pBGSoundInfo;
// figure out if this was a wave or MIDI device, update the
// status in our structure.
if (dwDeviceID == pBGSoundInfo->dwMidiDeviceID) {
// if loop counter is > 1, decrement loop counter and
// repeat. If loop counter is -1 (infinite), repeat
// without decrementing loop counter. Otherwise
// don't repeat the sound.
if (pBGSoundInfo->nMidiFileLoopsRemaining > 1) {
pBGSoundInfo->nMidiFileLoopsRemaining --;
fPlayAgain = TRUE;
} else if (pBGSoundInfo->nMidiFileLoopsRemaining == -1) {
fPlayAgain = TRUE;
} else {
pBGSoundInfo->dwMidiDeviceID = 0;
}
} else if (dwDeviceID == pBGSoundInfo->dwWaveDeviceID) {
// if loop counter is > 1, decrement loop counter and
// repeat. If loop counter is -1 (infinite), repeat
// without decrementing loop counter. Otherwise
// don't repeat the sound.
if (pBGSoundInfo->nSoundFileLoopsRemaining > 1) {
pBGSoundInfo->nSoundFileLoopsRemaining --;
fPlayAgain = TRUE;
} else if (pBGSoundInfo->nSoundFileLoopsRemaining == -1) {
fPlayAgain = TRUE;
} else {
pBGSoundInfo->dwWaveDeviceID = 0;
}
}
}
if (fPlayAgain) {
// play the sound/midi file again from the beginning
MCI_PLAY_PARMS mciPlayParms;
DWORD dwReturn;
mciPlayParms.dwCallback = (DWORD) tw->hWndFrame;
mciPlayParms.dwFrom = 0;
if (dwReturn = mciSendCommand(dwDeviceID, MCI_PLAY,
MCI_FROM | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms)) {
mciSendCommand(dwDeviceID, MCI_CLOSE, 0, 0);
}
} else {
// close the device (stop playing)
mciSendCommand(dwDeviceID, MCI_CLOSE, 0, 0);
}
}
}
/*******************************************************************
NAME: StopBackgroundAudio
SYNOPSIS: Stops any playing background audio of the specified type
ENTRY: tw - browser window
dwFlags - a combination of SBA_* flags specifying that
wave audio, MIDI playback, or both should be
stopped.
********************************************************************/
VOID StopBackgroundAudio(struct Mwin * tw,DWORD dwFlags)
{
BGSOUNDINFO * pBGSoundInfo;
if (!tw || !tw->w3doc || !tw->w3doc->pBGSoundInfo)
return;
pBGSoundInfo = tw->w3doc->pBGSoundInfo;
// if "stop MIDI" flags specified and we are playing MIDI, stop now.
// Do this by closing the open MCI device.
if ((dwFlags & SBA_STOP_MIDI) && pBGSoundInfo->dwMidiDeviceID) {
mciSendCommand(pBGSoundInfo->dwMidiDeviceID,MCI_CLOSE,0,0);
pBGSoundInfo->dwMidiDeviceID = 0;
}
// if "stop wave audio" flags specified and we are playing a
// sound file, stop now.
if (dwFlags & SBA_STOP_WAVEFORM) {
// if we are playing .WAV file, an MCI device will be open, close it
if (pBGSoundInfo->dwWaveDeviceID) {
mciSendCommand(pBGSoundInfo->dwWaveDeviceID,MCI_CLOSE,0,0);
pBGSoundInfo->dwWaveDeviceID = 0;
}
// if we are playing .AU or .AIFF, send message to window to stop it
if (pBGSoundInfo->hwndAuAiffPlayer) {
if (IsWindow(pBGSoundInfo->hwndAuAiffPlayer)) {
SendMessage(pBGSoundInfo->hwndAuAiffPlayer, WM_COMMAND,
MAKEWPARAM(IDCANCEL,BN_CLICKED), (LPARAM) 0 );
}
pBGSoundInfo->hwndAuAiffPlayer = NULL;
}
}
}
/*******************************************************************
NAME: RestartBackgroundAudio
SYNOPSIS: Called when revisiting a page. Background sounds
that were played on that page are started again.
NOTE: Note that all sounds (waveform and MIDI) are restarted
from the beginning, not where they may have left off.
********************************************************************/
VOID RestartBackgroundAudio(struct Mwin * tw)
{
if (!tw || !tw->w3doc || !tw->w3doc->pBGSoundInfo) {
// nothing to do... bogus page or no background audio for this
// page.
return;
}
// restart MIDI sequence if there is one for page
if (tw->w3doc->pBGSoundInfo->pszMidiFileName) {
PlayMIDIFile(tw,tw->w3doc->pBGSoundInfo->pszMidiFileName);
}
// restart sound file if there is one for page
if (tw->w3doc->pBGSoundInfo->pszSoundFileName) {
PlaySoundFile(tw,tw->w3doc->pBGSoundInfo->pszSoundFileName,
tw->w3doc->pBGSoundInfo->dwWaveType);
}
}
/*******************************************************************
NAME: PlaySoundFile
SYNOPSIS: Plays a .wav, .au, or .aiff sound file in the background
with no UI.
ENTRY: tw - browser window
lpszFileName - local file name of file to play
dwSoundFileType - a BA_* define indicating the type of file
NOTE: .wav is processed differently from .au and .aiff, this
function abstracts that.
********************************************************************/
VOID PlaySoundFile(struct Mwin * tw,LPSTR lpszFileName,DWORD dwSoundFileType)
{
struct SoundInfo *si;
// .WAV files are handled by the brief .WAV playing code above. .AU
// and .AIFF files are more complicated and will be handled by our
// normal internal player with the UI hidden.
// for .WAV files, just call our .WAV playing code and get out
if (dwSoundFileType == BA_TYPE_WAV) {
PlayWaveFile(tw,lpszFileName);
return;
}
// for .AU and .AIFF files, we need to set up a structure to pass to the
// processing code.
if (!(si = GTR_MALLOC(sizeof(struct SoundInfo))))
goto LError;
memset(si, 0, sizeof(struct SoundInfo));
si->tw_refer = tw;
si->bNoDeleteFile = TRUE;
// hide the player dialog
si->fHidden = TRUE;
// set the number of loops
if (tw->w3doc && tw->w3doc->pBGSoundInfo) {
si->nLoopsRemaining = tw->w3doc->pBGSoundInfo->nSoundFileLoopsRemaining;
}
if (!(si->fsOrig = GTR_MALLOC(_MAX_PATH + 1)))
goto LError;
strcpy(si->fsOrig,lpszFileName);
// call the appropriate procedure to process and play the sound file
switch (dwSoundFileType) {
case BA_TYPE_AU:
si->type = SOUND_AU;
AuProcess(si,"");
break;
case BA_TYPE_AIFF:
si->type = SOUND_AIFF;
AiffProcess(si,"");
break;
}
if (tw->w3doc && tw->w3doc->pBGSoundInfo) {
// remember the window handle of sound player so we can kill it
// later if necessary
tw->w3doc->pBGSoundInfo->hwndAuAiffPlayer = si->hwnd;
}
// note that si struct will be freed by sound player once the sound
// completes. (We are, however, guaranteed that si will be valid when we
// deference it above.)
return;
LError:
// free the structure we allocated to set up AuProcess/AiffProcess
// parameters
if (si) {
if (si->fsOrig)
GTR_FREE(si->fsOrig);
GTR_FREE(si);
}
}
/*******************************************************************
NAME: HandleBG_AUSoundComplete
SYNOPSIS: Called when AU/AIFF sound player window (which is hidden)
sends message to main window to indicate it's done
NOTE: We keep window handle of the player tucked away so we
can terminate it if user changes pages or such, now
we need to know it stoped so we don't try to notify a
non-existent (or totally incorrect!) window to stop later.
********************************************************************/
VOID HandleBGSound_AUComplete(struct Mwin * tw,HWND hwndPlayer)
{
// look in our sound info structure for the window handle of sound
// player
if (tw && tw->w3doc && tw->w3doc->pBGSoundInfo) {
// sound player passes in its window handle with the message.
// sanity-check that the window handle is the one we expect...
if (tw->w3doc->pBGSoundInfo->hwndAuAiffPlayer ==
hwndPlayer) {
// yes, all is kosher. Set our copy of the window handle
// to NULL so we know there's no background sound playing now.
tw->w3doc->pBGSoundInfo->hwndAuAiffPlayer = NULL;
}
}
}
/*******************************************************************
NAME: BackgroundSoundFile_Callback
SYNOPSIS: Called when we are done downloading a file as a result
of a background sound tag
NOTES: param is a pointer to a BGBLOBPARAMS struct we previously
allocated and must be freed.
********************************************************************/
/*Evil Tables that should be replaced with mime stuff-----------------------*/
static STI rgSoundExtensions[] = {
{"WAV", BA_TYPE_WAV},
{"AU", BA_TYPE_AU},
{"AIF", BA_TYPE_AIFF},
{"AIFF", BA_TYPE_AIFF},
{"MID", BA_TYPE_MIDI}
};
#define nSoundExtensions (sizeof(rgSoundExtensions)/sizeof(STI))
DWORD DwValidSoundFile(PCSTR pcszFileName)
{
char * pszExt;
pszExt = strrchr(pcszFileName,'.');
if (pszExt)
{
pszExt++; // point after the '.'
return StringTableToIndex(pszExt, rgSoundExtensions, nSoundExtensions, 0);
}
return 0;
}
void BackgroundSoundFile_Callback(struct Mwin* tw, ELEMENT* pel)
{
DWORD dwSoundFileType;
PLAYSOUNDREQ * pPlaySoundReq;
// allocate a struct to keep info on player state and name of
// file, if not already allocated
if (!tw->w3doc->pBGSoundInfo)
{
tw->w3doc->pBGSoundInfo = (BGSOUNDINFO *) GTR_MALLOC(sizeof(BGSOUNDINFO));
if (!tw->w3doc->pBGSoundInfo)
return;
memset(tw->w3doc->pBGSoundInfo,0,sizeof(BGSOUNDINFO));
}
// find the file extension
if(dwSoundFileType = DwValidSoundFile(pel->pblob->szFileName))
{
// we can't start playing right this second, because
// playing through MCI takes a second or two to start up
// before the audio starts. We can't block that long in a light-
// weight thread, so send a message to the main window proc
// to start sound in the context of a real thread
// set up a PLAYSOUNDREQ struct to tell the main thread
// the file name, file type, etc.
pPlaySoundReq = GTR_MALLOC(sizeof(*pPlaySoundReq));
memset(pPlaySoundReq,0,sizeof(*pPlaySoundReq));
if (!pPlaySoundReq)
return;
pPlaySoundReq->pszFileName = GTR_strdup(pel->pblob->szFileName);
if (!pPlaySoundReq->pszFileName)
return;
pPlaySoundReq->dwFileType=dwSoundFileType;
pPlaySoundReq->nLoops = (DWORD) pel->pblob->vp;
PostMessage(tw->hWndFrame,WM_START_BGSOUND,0,(LPARAM) pPlaySoundReq);
}
}