#include "GlobalFunc.h" #include "T2SoundPlayer.h" #include "T2TowerDoc.h" #include "T2TowerMainView.h" #include "Wave.h" BEGIN_MESSAGE_MAP(T2SoundPlayer, CWnd) ON_MESSAGE(MM_MCINOTIFY, OnMCINotify) END_MESSAGE_MAP() T2SoundPlayer::T2SoundPlayer(CWnd* inParentWnd, IDirectSound* inDirectSound) { mDirectSound = inDirectSound; mItemList = new T2SoundObjItemList; mCurrentCDTrack = 0; MCI_OPEN_PARMS mciParms; memset(&mciParms, 0, sizeof(mciParms)); mciParms.lpstrDeviceType = (LPSTR) MCI_DEVTYPE_CD_AUDIO; CString theName; theName.Format("%s:", GetInstallSourceDrive()); CString theAlias; theAlias = "T2CD"; mciParms.lpstrElementName = theName; mciParms.lpstrAlias = theAlias; mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_SHAREABLE | MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS | MCI_OPEN_TYPE_ID | MCI_OPEN_TYPE, (DWORD) &mciParms); CRect rect(0, 0, 1, 1); CString theClass = AfxRegisterWndClass(CS_NOCLOSE); Create(theClass, "", WS_CHILD, rect, inParentWnd, 9999); mSEMask = 0xFFFFFFFF; mIsSoundOn = true; mIsFadeOut = false; } /*virtual*/ T2SoundPlayer::~T2SoundPlayer() { StopCD(); CString cmd; cmd.Format("close %s", "T2CD"); mciSendString(cmd, NULL, 0, NULL); POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); DeleteSound(item->mName); } delete mItemList; } void T2SoundPlayer::AddSound(const CString& inName, SOUNDPRIORITY inPriority, const CString& inPath) { if (!mDirectSound) return; T2SoundObjItem *item = new T2SoundObjItem; CWave wave(inPath); if (LoadSound(item, inName, wave, false)) { item->mSourceKind = T2SoundObjItem::FileSource; item->mPath = inPath; item->mPriority = inPriority; mItemList->AddTail(item); } else { delete item; } } void T2SoundPlayer::AddSound(const CString& inName, SOUNDPRIORITY inPriority, unsigned int inResID, HINSTANCE inModule) { if (!mDirectSound) return; if (FindResource(inModule, MAKEINTRESOURCE(inResID), "WAVE")) { T2SoundObjItem *item = new T2SoundObjItem; CWave wave(inResID, inModule); if (LoadSound(item, inName, wave, false)) { item->mSourceKind = T2SoundObjItem::ResSource; item->mResID = inResID; item->mModuleHandle = inModule; item->mPriority = inPriority; mItemList->AddTail(item); } else { delete item; } } } BOOL T2SoundPlayer::LoadSound(T2SoundObjItem* inItem, const CString& inName, CWave& inWave, BOOL inReloadFlag) { if (!inReloadFlag) { POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); if (item->mName == inName) return false; } } inItem->mName = inName; BYTE *waveDataPtr; DWORD waveDataLength = inWave.GetDataLen(); WAVEFORMATEX waveFormat; inWave.GetFormat(waveFormat); DSBUFFERDESC desc; memset(&desc, 0, sizeof(DSBUFFERDESC)); desc.dwSize = sizeof(DSBUFFERDESC); desc.dwFlags = DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLDEFAULT; desc.dwBufferBytes = waveDataLength; desc.lpwfxFormat = &waveFormat; mDirectSound->CreateSoundBuffer(&desc, &inItem->mDSBuffers[0], NULL); inItem->mDSBuffers[0]->Lock(0, waveDataLength, &waveDataPtr, &waveDataLength, NULL, NULL, 0); waveDataLength = inWave.GetData(waveDataPtr, waveDataLength); inItem->mDSBuffers[0]->Unlock(waveDataPtr, waveDataLength, NULL, 0); inItem->mPlayedAt[0] = GetTickCount(); for (int i = 1; i < 4; i++) { mDirectSound->DuplicateSoundBuffer(inItem->mDSBuffers[0], &inItem->mDSBuffers[i]); inItem->mPlayedAt[i] = GetTickCount(); } return true; } void T2SoundPlayer::DeleteSound(const CString& inName) { if (!mDirectSound) return; POSITION pos = mItemList->GetHeadPosition(); while (pos) { POSITION prev = pos; T2SoundObjItem *item = mItemList->GetNext(pos); if (item->mName == inName) { mItemList->RemoveAt(prev); for (int i = 3; i >= 0; i--) { if (item->mDSBuffers[i]) item->mDSBuffers[i]->Release(); } delete item; break; } } } void T2SoundPlayer::DeleteSoundAll() { if (!mDirectSound) return; POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); DeleteSound(item->mName); } mItemList->RemoveAll(); } void T2SoundPlayer::Play(const CString& inName, unsigned int inMask, unsigned int inFlags, POINT* inPt, PLAYMODE inPlayMode, int inVolume) { if (!mDirectSound) return; if (!mIsSoundOn || (inMask & mSEMask) == 0) return; POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); if (item->mName == inName) { DWORD currentStatus; int index; if (inPlayMode == PlayMode_0 || inPlayMode == PlayMode_1 || inPlayMode == PlayMode_3) { index = 0; } else if (inPlayMode == PlayMode_2) { for (index = 0; index < 4; index++) { item->mDSBuffers[index]->GetStatus(¤tStatus); if (!(currentStatus & DSBSTATUS_PLAYING)) break; } if (index == 4) { // all slots full, pick the oldest sound to replace DWORD oldest = GetTickCount(); index = 0; for (int i = 0; i < 4; i++) { if (item->mPlayedAt[i] < oldest) { index = i; oldest = item->mPlayedAt[i]; } } } } item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_BUFFERLOST) { for (int i = 3; i >= 0; i--) item->mDSBuffers[i]->Restore(); CWave *wave; if (item->mSourceKind == T2SoundObjItem::FileSource) wave = new CWave(item->mPath); else wave = new CWave(item->mResID, item->mModuleHandle); LoadSound(item, item->mName, *wave, true); } int pan = 0; if (inPt) { CRect rect; GetCurrentT2TowerDoc()->GetMainView()->GetVisibleUnitRect(rect); POINT centerPt = rect.CenterPoint(); float x = ((float) (inPt->x - centerPt.x) / (float) ((rect.right - rect.left) / 2)); x *= 0.5; if (x < 0.0) pan = -10000.0f * -x; else pan = 10000.0f * x; } BOOL play = false; if (inPlayMode == PlayMode_0 || inPlayMode == PlayMode_3) { if (!(currentStatus & DSBSTATUS_PLAYING)) play = true; } else if (inPlayMode == PlayMode_1 || inPlayMode == PlayMode_2) { if (currentStatus & DSBSTATUS_PLAYING) { item->mDSBuffers[index]->Stop(); item->mDSBuffers[index]->SetCurrentPosition(0); } play = true; } if (play) { int volume = ((inVolume * 10000) / 100) - 10000; if (!mIsFadeOut || (inFlags & SoundFlags_10000)) item->mDSBuffers[index]->SetVolume(volume); else item->mDSBuffers[index]->SetVolume(-10000); item->mDSBuffers[index]->SetPan(pan); item->mDSBuffers[index]->Play(0, 0, inPlayMode == PlayMode_3); } item->mPlayedAt[index] = GetTickCount(); break; } } } void T2SoundPlayer::Stop(const CString& inName) { if (!mDirectSound) return; POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); if (item->mName == inName) { for (int index = 0; index < 4; index++) { DWORD currentStatus; item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_PLAYING) { item->mDSBuffers[index]->Stop(); item->mDSBuffers[index]->SetCurrentPosition(0); } } } } } void T2SoundPlayer::StopAll() { if (!mDirectSound) return; POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); for (int index = 0; index < 4; index++) { DWORD currentStatus; item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_PLAYING) { item->mDSBuffers[index]->Stop(); item->mDSBuffers[index]->SetCurrentPosition(0); } } } } void T2SoundPlayer::SetVolume(const CString& inName, int inVolume) { if (!mDirectSound) return; int volume = ((inVolume * 10000) / 100) - 10000; POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); if (item->mName == inName) { for (int index = 0; index < 4; index++) { DWORD currentStatus; item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_PLAYING) item->mDSBuffers[index]->SetVolume(volume); } } } } void T2SoundPlayer::SetSoundOn(BOOL inSoundOn) { mIsSoundOn = inSoundOn; if (!inSoundOn) { POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); DWORD currentStatus; for (int index = 0; index < 4; index++) { item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_PLAYING) { item->mDSBuffers[index]->Stop(); item->mDSBuffers[index]->SetCurrentPosition(0); } } } } } void T2SoundPlayer::FadeOut() { mIsFadeOut = true; DWORD time = GetTickCount(); while (GetTickCount() == time) {} int i = 0; while (i <= 10) { int volume = 0 - ((i * 10000) / 10); POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); DWORD currentStatus; for (int index = 0; index < 4; index++) { item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_PLAYING) item->mDSBuffers[index]->SetVolume(volume); } } time = GetTickCount(); while ((GetTickCount() - time) < 50) { MSG msg; PeekMessage(&msg, NULL, 0, 0, 0); } i++; } } void T2SoundPlayer::FadeIn() { mIsFadeOut = false; DWORD time = GetTickCount(); while (GetTickCount() == time) {} int i = 0; while (i <= 10) { int volume = ((i * 10000) / 10) - 10000; POSITION pos = mItemList->GetHeadPosition(); while (pos) { T2SoundObjItem *item = mItemList->GetNext(pos); DWORD currentStatus; for (int index = 0; index < 4; index++) { item->mDSBuffers[index]->GetStatus(¤tStatus); if (currentStatus & DSBSTATUS_PLAYING) item->mDSBuffers[index]->SetVolume(volume); } } time = GetTickCount(); while ((GetTickCount() - time) < 50) { MSG msg; PeekMessage(&msg, NULL, 0, 0, 0); } i++; } } void T2SoundPlayer::PlayCDTrack(int inTrack, BOOL inFlag) { if (inFlag) mCurrentCDTrack = inTrack; else mCurrentCDTrack = 0; CString cmd; cmd.Format("status %s length track %d", "T2CD", inTrack); char returnString[20]; MCIERROR err = mciSendString(cmd, returnString, 20, NULL); cmd.Format("play %s from %02d:00:00:00 to %02d:%s notify", "T2CD", inTrack, inTrack, returnString); err = mciSendString(cmd, NULL, 0, *this); } void T2SoundPlayer::StopCD() { mCurrentCDTrack = 0; CString cmd; cmd.Format("stop %s", "T2CD"); mciSendString(cmd, NULL, 0, NULL); } LRESULT T2SoundPlayer::OnMCINotify(WPARAM wParam, LPARAM lParam) { if (wParam == MCI_NOTIFY_SUCCESSFUL || wParam == MCI_NOTIFY_ABORTED) { if (mCurrentCDTrack) PlayCDTrack(mCurrentCDTrack, true); } return 0; } T2SoundObjItem::T2SoundObjItem() { mName = ""; for (int i = 0; i < 4; i++) { mDSBuffers[i] = NULL; mPlayedAt[i] = GetTickCount(); } } T2SoundObjItem::~T2SoundObjItem() { } T2SoundObjItemList::T2SoundObjItemList() { } /*virtual*/ T2SoundObjItemList::~T2SoundObjItemList() { }