/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "system.hpp" #include "classes.hpp" #pragma hdrstop #define STRICT #include "Sound.h" #include "Usefull.h" #include "Globals.h" //#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_RELEASE(p) \ { \ if (p) \ { \ (p)->Release(); \ (p) = NULL; \ } \ } char Directory[] = "sounds\\"; LPDIRECTSOUND TSoundsManager::pDS; LPDIRECTSOUNDNOTIFY TSoundsManager::pDSNotify; int TSoundsManager::Count = 0; TSoundContainer *TSoundsManager::First = NULL; TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, char *Directory, char *strFileName, int NConcurrent) { // wczytanie pliku dźwiękowego int hr = 111; DSBuffer = NULL; // na początek, gdyby uruchomić dźwięków się nie udało Concurrent = NConcurrent; Oldest = 0; // strcpy(Name, strFileName); strcpy(Name, Directory); strcat(Name, strFileName); CWaveSoundRead *pWaveSoundRead; // Create a new wave file class pWaveSoundRead = new CWaveSoundRead(); // Load the wave file if (FAILED(pWaveSoundRead->Open(Name))) if (FAILED(pWaveSoundRead->Open(strFileName))) { // SetFileUI( hDlg, TEXT("Bad wave file.") ); return; ErrorLog("Missed sound: " + AnsiString(strFileName)); } strcpy(Name, AnsiString(strFileName).LowerCase().c_str()); // Set up the direct sound buffer, and only request the flags needed // since each requires some overhead and limits if the buffer can // be hardware accelerated DSBUFFERDESC dsbd; ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; if (!Global::bInactivePause) // jeśli przełączony w tło ma nadal działać dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS; // to dźwięki mają być również słyszalne dsbd.dwBufferBytes = pWaveSoundRead->m_ckIn.cksize; dsbd.lpwfxFormat = pWaveSoundRead->m_pwfx; fSamplingRate = pWaveSoundRead->m_pwfx->nSamplesPerSec; iBitsPerSample = pWaveSoundRead->m_pwfx->wBitsPerSample; // pDSBuffer= (LPDIRECTSOUNDBUFFER*) malloc(Concurrent*sizeof(LPDIRECTSOUNDBUFFER)); // for (int i=0; iCreateSoundBuffer(&dsbd, &(DSBuffer), NULL))) // if (FAILED(pDS->CreateSoundBuffer(&dsbd,&(DSBuffer),NULL))) return; // Remember how big the buffer is DWORD dwBufferBytes; dwBufferBytes = dsbd.dwBufferBytes; //---------------------------------------------------------- BYTE *pbWavData; // Pointer to actual wav data UINT cbWavSize; // Size of data VOID *pbData = NULL; VOID *pbData2 = NULL; DWORD dwLength; DWORD dwLength2; // The size of wave data is in pWaveFileSound->m_ckIn INT nWaveFileSize = pWaveSoundRead->m_ckIn.cksize; // Allocate that buffer. pbWavData = new BYTE[nWaveFileSize]; if (NULL == pbWavData) return; // E_OUTOFMEMORY; // if (FAILED(hr=pWaveSoundRead->Read( nWaveFileSize,pbWavData,&cbWavSize))) if (FAILED(hr = pWaveSoundRead->Read(nWaveFileSize, pbWavData, &cbWavSize))) return; // Reset the file to the beginning pWaveSoundRead->Reset(); // Lock the buffer down // if (FAILED(hr=DSBuffer->Lock(0,dwBufferBytes,&pbData,&dwLength,&pbData2,&dwLength2,0))) if (FAILED(hr = DSBuffer->Lock(0, dwBufferBytes, &pbData, &dwLength, &pbData2, &dwLength2, 0L))) return; // Copy the memory to it. memcpy(pbData, pbWavData, dwBufferBytes); // Unlock the buffer, we don't need it anymore. DSBuffer->Unlock(pbData, dwBufferBytes, NULL, 0); pbData = NULL; // We dont need the wav file data buffer anymore, so delete it delete[] pbWavData; delete pWaveSoundRead; DSBuffers.push(DSBuffer); /* for (int i=1; iDuplicateSoundBuffer(pDSBuffer[0],&(pDSBuffer[i])))) { Concurrent= i; break; }; };*/ }; TSoundContainer::~TSoundContainer() { // for (int i=Concurrent-1; i>=0; i--) // SAFE_RELEASE( pDSBuffer[i] ); // free(pDSBuffer); while (!DSBuffers.empty()) { SAFE_RELEASE(DSBuffers.top()); DSBuffers.pop(); } SafeDelete(Next); }; LPDIRECTSOUNDBUFFER TSoundContainer::GetUnique(LPDIRECTSOUND pDS) { if (!DSBuffer) return NULL; // jeśli się dobrze zainicjowało LPDIRECTSOUNDBUFFER buff; pDS->DuplicateSoundBuffer(DSBuffer, &buff); if (buff) DSBuffers.push(buff); return DSBuffers.top(); }; TSoundsManager::~TSoundsManager() { Free(); }; void TSoundsManager::Free() { SafeDelete(First); SAFE_RELEASE(pDS); }; TSoundContainer * TSoundsManager::LoadFromFile(char *Dir, char *Name, int Concurrent) { TSoundContainer *Tmp = First; First = new TSoundContainer(pDS, Dir, Name, Concurrent); First->Next = Tmp; Count++; return First; // albo NULL, jak nie wyjdzie (na razie zawsze wychodzi) }; void TSoundsManager::LoadSounds(char *Directory) { // wczytanie wszystkich plików z katalogu - mało elastyczne WIN32_FIND_DATA FindFileData; HANDLE handle = FindFirstFile("sounds\\*.wav", &FindFileData); if (handle != INVALID_HANDLE_VALUE) do { LoadFromFile(Directory, FindFileData.cFileName, 1); } while (FindNextFile(handle, &FindFileData)); FindClose(handle); }; LPDIRECTSOUNDBUFFER TSoundsManager::GetFromName(char *Name, bool Dynamic, float *fSamplingRate) { // wyszukanie dźwięku w pamięci albo wczytanie z pliku AnsiString file; if (Dynamic) { // próba wczytania z katalogu pojazdu file = Global::asCurrentDynamicPath + AnsiString(Name); if (FileExists(file)) Name = file.c_str(); // nowa nazwa else Dynamic = false; // wczytanie z "sounds/" } TSoundContainer *Next = First; DWORD dwStatus; for (int i = 0; i < Count; i++) { if (strcmp(Name, Next->Name) == 0) { if (fSamplingRate) *fSamplingRate = Next->fSamplingRate; // częstotliwość return (Next->GetUnique(pDS)); // DSBuffers. /* Next->pDSBuffer[Next->Oldest]->Stop(); Next->pDSBuffer[Next->Oldest]->SetCurrentPosition(0); if (Next->OldestConcurrent-1) { Next->Oldest++; return (Next->pDSBuffer[Next->Oldest-1]); } else { Next->Oldest= 0; return (Next->pDSBuffer[Next->Concurrent-1]); }; /* for (int j=0; jConcurrent; j++) { Next->pDSBuffer[j]->GetStatus(&dwStatus); if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING) return (Next->pDSBuffer[j]); } */ } else Next = Next->Next; }; if (Dynamic) // wczytanie z katalogu pojazdu Next = LoadFromFile("", Name, 1); else Next = LoadFromFile(Directory, Name, 1); if (Next) { // if (fSamplingRate) *fSamplingRate = Next->fSamplingRate; // częstotliwość return Next->GetUnique(pDS); } ErrorLog("Missed sound: " + AnsiString(Name)); return (NULL); }; void TSoundsManager::RestoreAll() { TSoundContainer *Next = First; HRESULT hr; DWORD dwStatus; for (int i = 0; i < Count; i++) { if (FAILED(hr = Next->DSBuffer->GetStatus(&dwStatus))) ; // return hr; if (dwStatus & DSBSTATUS_BUFFERLOST) { // Since the app could have just been activated, then // DirectSound may not be giving us control yet, so // the restoring the buffer may fail. // If it does, sleep until DirectSound gives us control. do { hr = Next->DSBuffer->Restore(); if (hr == DSERR_BUFFERLOST) Sleep(10); } while ((hr = Next->DSBuffer->Restore()) != NULL); // char *Name= Next->Name; // int cc= Next->Concurrent; // delete Next; // Next= new TSoundContainer(pDS, Directory, Name, cc); // if( FAILED( hr = FillBuffer() ) ); // return hr; }; Next = Next->Next; }; }; // void TSoundsManager::Init(char *Name, int Concurrent) // TSoundsManager::TSoundsManager(HWND hWnd) // void TSoundsManager::Init(HWND hWnd, char *NDirectory) void TSoundsManager::Init(HWND hWnd) { First = NULL; Count = 0; pDS = NULL; pDSNotify = NULL; HRESULT hr; //=222; LPDIRECTSOUNDBUFFER pDSBPrimary = NULL; // strcpy(Directory, NDirectory); // Create IDirectSound using the primary sound device hr = DirectSoundCreate(NULL, &pDS, NULL); if (hr != DS_OK) { if (hr == DSERR_ALLOCATED) return; if (hr == DSERR_INVALIDPARAM) return; if (hr == DSERR_NOAGGREGATION) return; if (hr == DSERR_NODRIVER) return; if (hr == DSERR_OUTOFMEMORY) return; // hr=0; }; // return ; // Set coop level to DSSCL_PRIORITY // if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ); // return ; pDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY); // Get the primary buffer DSBUFFERDESC dsbd; ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; if (!Global::bInactivePause) // jeśli przełączony w tło ma nadal działać dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS; // to dźwięki mają być również słyszalne dsbd.dwBufferBytes = 0; dsbd.lpwfxFormat = NULL; if (FAILED(hr = pDS->CreateSoundBuffer(&dsbd, &pDSBPrimary, NULL))) return; // Set primary buffer format to 22kHz and 16-bit output. WAVEFORMATEX wfx; ZeroMemory(&wfx, sizeof(WAVEFORMATEX)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; wfx.nSamplesPerSec = 44100; wfx.wBitsPerSample = 16; wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; if (FAILED(hr = pDSBPrimary->SetFormat(&wfx))) return; SAFE_RELEASE(pDSBPrimary); }; //--------------------------------------------------------------------------- #pragma package(smart_init)