CXAudio2::IntCacheIterator CXAudio2::_PreCacheResource(int ID) { // File already in cache IntCacheIterator i = resourceCache.find(ID); if (i != resourceCache.end()) return i; // Load WAV (PCM, ADPCM, xWMA). OGG not supported via resources. // Wave file reading class; from the SDK samples CWaveFile wav; hr = wav.Open(MAKEINTRESOURCE(ID), 0, WAVEFILE_READ, true); if (FAILED(hr)) throw CXAudio2Error(hr, "Failed to load file from disk. Check the filename exists and that the file is of a supported format."); DWORD size = wav.GetSize(); BYTE* pBuffer = new BYTE[size]; // Read WAV data hr = wav.Read(pBuffer, size, &size); if (FAILED(hr)) { delete[] pBuffer; throw CXAudio2Error(hr, "Failed to read WAV data. Check the WAV file encoding is supported."); } // Make a cache entry of the WAV data now // Avoid invocation of CacheEntry copy constructor which copies pBuffer's memory //fileCache[filename] = CacheEntry(pwfx, pBuffer, size); resourceCache[ID] = CacheEntry(this); i = resourceCache.find(ID); CacheEntry& ce = i->second; // xWMA if (wav.m_bIsXWMA) { ce.SetWma((GENERICWAVEFILE*)wav.GetFormat(), pBuffer, size, wav.m_nPacketCount, wav.m_aDecodedPacketCumulativeBytes); } // PCM or ADPCM else { // Cache entry now has reference count 1 and responsibility for deleting pBuffer ce.Set((GENERICWAVEFILE*)wav.GetFormat(), pBuffer, size); } ce.refCount = 0; // Just precached, nothing referencing yet totalCacheSize += size; return i; }
void GameAudio::registerMusic(MusicTypes muType, LPWSTR wavFilePath) { CWaveFile wav; /// wav file will be destroyed at the end of this function //// All the file references are rooted at the directory "Apps/Rebelle/data" bool wavOpenSuccess = SUCCEEDED(wav.Open(wavFilePath, 0, WAVEFILE_READ)); WAVEFORMATEX *format = wav.GetFormat(); unsigned long wavSize = wav.GetSize(); unsigned char *wavData = new unsigned char[wavSize]; bool wavReadSuccess = SUCCEEDED(wav.Read(wavData, wavSize, &wavSize)); IXAudio2SourceVoice* srcVoice; /// this will be stored in the map of this class bool csvSuccess = SUCCEEDED(xAudio2Engine->CreateSourceVoice(&srcVoice, format, 0, XAUDIO2_DEFAULT_FREQ_RATIO, 0, 0, 0)); XAUDIO2_BUFFER *bufferPrototype = new XAUDIO2_BUFFER(); bufferPrototype->pAudioData = wavData; bufferPrototype->Flags = XAUDIO2_END_OF_STREAM; bufferPrototype->AudioBytes = wavSize; //// register sound buffer prototype musicBufferPrototypeMap[muType] = bufferPrototype; //// mark this sourceVoice as registered musicRegistrationMap[muType] = true; //// store the source voice musicMap[muType] = srcVoice; }
//计算WAV文件播放时间,这个时间由数据大小和格式共同决定 DWORD GetSoundLength(LPSTR strFileName){ CWaveFile* pWav; DWORD dwLen = 0; DWORD dwSize; WAVEFORMATEX* pwfx; pWav = new CWaveFile(); if (SUCCEEDED(pWav->Open(strFileName, NULL, WAVEFILE_READ)))){ pwfx = pWav->GetFormat(); dwSize = pWav->GetSize(); dwLen = (DWORD)(1000 * dwSize / pwfx->nAvgBytesPerSec); pWav->Close(); } if (pWav) delete pWav; return dwLen; }
//----------------------------------------------------------------------------- // Name: ValidateWaveFile() // Desc: Open the wave file with the helper // class CWaveFile to make sure it is valid //----------------------------------------------------------------------------- HRESULT ValidateWaveFile( HWND hDlg, TCHAR* strFileName ) { HRESULT hr; CWaveFile waveFile; if( -1 == GetFileAttributes(strFileName) ) return E_FAIL; // Load the wave file if( FAILED( hr = waveFile.Open( strFileName, NULL, WAVEFILE_READ ) ) ) { waveFile.Close(); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Bad wave file.") ); return DXTRACE_ERR( TEXT("Open"), hr ); } else // The load call succeeded { WAVEFORMATEX* pwfx = waveFile.GetFormat(); if( pwfx->wFormatTag != WAVE_FORMAT_PCM ) { // Sound must be PCM when using DSBCAPS_CTRLFX SAFE_RELEASE( g_pIGargle ); SAFE_DELETE( g_pSound ); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be PCM for effects control.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return S_FALSE; } // Update the UI controls to show the sound as the file is loaded waveFile.Close(); EnablePlayUI( hDlg, TRUE ); SetDlgItemText( hDlg, IDC_FILENAME, strFileName ); SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded.") ); strcpy( g_strWaveFileName, strFileName ); // Get the samples per sec from the wave file DWORD dwSamplesPerSec = waveFile.m_pwfx->nSamplesPerSec; return S_OK; } }
/* ================= - Play sound. ================= */ void cXAudio::playSound(LPWSTR theFilename, bool pLoop ) // Play sound { HRESULT hResult; CWaveFile wavFile; wavFile.Open( theFilename, NULL, WAVEFILE_READ ); // Get format of wave file WAVEFORMATEX* pwfx = wavFile.GetFormat(); // Calculate how many bytes and samples are in the wave DWORD cbWaveSize = wavFile.GetSize(); // Read the sample data into memory BYTE* pbWaveData = new BYTE[ cbWaveSize ]; wavFile.Read( pbWaveData, cbWaveSize, &cbWaveSize ); // Submit the wave sample data using an XAUDIO2_BUFFER structure XAUDIO2_BUFFER buffer = {0}; buffer.pAudioData = pbWaveData; buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer buffer.AudioBytes = cbWaveSize; if (pLoop) { buffer.LoopLength = 0; buffer.LoopCount = XAUDIO2_LOOP_INFINITE; } // Create the source voice if( FAILED( hResult = mXAudio2->CreateSourceVoice( &mSourceVoice, pwfx ) ) ) { OutputDebugString("Error creating source voice\n"); delete pbWaveData; } else { mSourceVoice->SubmitSourceBuffer(&buffer); mSourceVoice->Start(0, XAUDIO2_COMMIT_NOW ); } }
/* Loads a sound with the specified id and path */ void XAudioSoundSystem::OnLoadSound(uint32 soundID, const char* szSoundPath) { if(mSounds[soundID] != NULL) return; HRESULT hr = S_OK; char szFullPath[1024]; sprintf_s(szFullPath, 1024, "Data/Win32/%s", szSoundPath); size_t convertedChars = 0; wchar_t wpath[1024]; mbstowcs_s(&convertedChars, wpath, strlen(szFullPath) + 1, szFullPath, _TRUNCATE); // // Read in the wave file // CWaveFile wav; if( FAILED( hr = wav.Open( wpath, NULL, WAVEFILE_READ ) ) ) { wprintf( L"Failed reading WAV file: %#X (%s)\n", hr, wpath ); return; } // Get format of wave file WAVEFORMATEX* pwfx = wav.GetFormat(); // Calculate how many bytes and samples are in the wave DWORD cbWaveSize = wav.GetSize(); // Read the sample data into memory BYTE* pbWaveData = new BYTE[ cbWaveSize ]; if( FAILED( hr = wav.Read( pbWaveData, cbWaveSize, &cbWaveSize ) ) ) { wprintf( L"Failed to read WAV data: %#X\n", hr ); SAFE_DELETE_ARRAY( pbWaveData ); return; } // // Play the wave using a XAudio2SourceVoice // // Create the source voice IXAudio2SourceVoice* pSourceVoice; if( FAILED( hr = mXAudio2->CreateSourceVoice( &pSourceVoice, pwfx ) ) ) { wprintf( L"Error %#X creating source voice\n", hr ); SAFE_DELETE_ARRAY( pbWaveData ); return; } // Submit the wave sample data using an XAUDIO2_BUFFER structure XAUDIO2_BUFFER buffer = {0}; buffer.pAudioData = pbWaveData; buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer buffer.AudioBytes = cbWaveSize; if( FAILED( hr = pSourceVoice->SubmitSourceBuffer( &buffer ) ) ) { wprintf( L"Error %#X submitting source buffer\n", hr ); pSourceVoice->DestroyVoice(); SAFE_DELETE_ARRAY( pbWaveData ); return; } Sound* pSound = new Sound(); pSound->mVoice = pSourceVoice; pSound->mAudioBuffer = buffer; pSound->mData = pbWaveData; pSound->mStarted = false; mSounds[soundID] = pSound; }
CXAudio2::StringCacheIterator CXAudio2::_PreCacheFile(std::string filename) { // File already in cache StringCacheIterator i = fileCache.find(filename); if (i != fileCache.end()) return i; // Check for OGG file std::string ext = filename; ext.erase(0, ext.length() - 4); // Load OGG file if (_stricmp(ext.c_str(), ".ogg") == 0 || _stricmp(ext.c_str(), ".oga") == 0) { #ifdef XAUDIO2_OGGVORBIS FILE* f = fopen(filename.c_str(), "rb"); if (f == NULL) throw CXAudio2Error(E_FAIL, std::string("Error loading file '") + filename + "'. Check the file exists and is valid."); OggVorbis_File oggFile; ov_open(f, &oggFile, NULL, 0); // Takes control of f; no need to call fclose() vorbis_info* pInfo = ov_info(&oggFile, -1); int endian = 0; // 0 for Little-Endian, 1 for Big-Endian int bytesRead = 0; int bitStream; // Read the file data vector<char> oggData; char readbuffer[XAUDIO2_OGGVORBIS_BUFFERSIZE]; do { // Read up to a buffer's worth of decoded sound data bytesRead = ov_read(&oggFile, readbuffer, XAUDIO2_OGGVORBIS_BUFFERSIZE, endian, 2, 1, &bitStream); // Append to end of buffer oggData.insert(oggData.end(), readbuffer, readbuffer + bytesRead); } while (bytesRead > 0); // Fill out a WAVEFORMATEX for the decompressed OGG WAVEFORMATEX wfx; memset(&wfx, 0, sizeof(WAVEFORMATEX)); wfx.cbSize = sizeof(WAVEFORMATEX); wfx.nChannels = pInfo->channels; wfx.nSamplesPerSec = pInfo->rate; wfx.wBitsPerSample = 16; // OGG is always 16 bit wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nChannels * 2; wfx.nBlockAlign = 2 * wfx.nChannels; wfx.wFormatTag = WAVE_FORMAT_PCM; ov_clear(&oggFile); // Copy the vector which is local scope and will deallocate: the cache takes responsibility for deleting BYTE* pBuffer = new BYTE[oggData.size()]; memcpy(pBuffer, &(oggData.front()), oggData.size()); // Make a cache entry of the WAV data now // Avoid invocation of CacheEntry copy constructor which copies pBuffer's memory //fileCache[filename] = CacheEntry(pwfx, pBuffer, size); fileCache[filename] = CacheEntry(this); i = fileCache.find(filename); CacheEntry& ce = i->second; ce.Set((GENERICWAVEFILE*)&wfx, pBuffer, oggData.size()); ce.refCount = 0; // Just precached, nothing referencing yet ce.isOgg = true; totalCacheSize += oggData.size(); return i; #else // Not built with OGG Vorbis support; throw an error throw CXAudio2Error(E_FAIL, "OGG Vorbis is not supported by this version of XAudio2."); #endif } else { // Load WAV (PCM, ADPCM, xWMA) // Wave file reading class; from the SDK samples CWaveFile wav; // Dumb function definition needs an LPSTR, not an LPCSTR TCHAR* fileNameStr = new TCHAR[filename.size() + 1]; memcpy(fileNameStr, filename.c_str(), filename.size() + 1); // copy null terminator in hr = wav.Open(fileNameStr, 0, WAVEFILE_READ); delete[] fileNameStr; if (FAILED(hr)) throw CXAudio2Error(hr, "Failed to load file from disk. Check the filename exists and that the file is of a supported format."); DWORD size = wav.GetSize(); BYTE* pBuffer = new BYTE[size]; // Read WAV data hr = wav.Read(pBuffer, size, &size); if (FAILED(hr)) { delete[] pBuffer; throw CXAudio2Error(hr, "Failed to read WAV data. Check the WAV file encoding is supported."); } // Make a cache entry of the WAV data now // Avoid invocation of CacheEntry copy constructor which copies pBuffer's memory //fileCache[filename] = CacheEntry(pwfx, pBuffer, size); fileCache[filename] = CacheEntry(this); i = fileCache.find(filename); CacheEntry& ce = i->second; // xWMA if (wav.m_bIsXWMA) { ce.SetWma((GENERICWAVEFILE*)wav.GetFormat(), pBuffer, size, wav.m_nPacketCount, wav.m_aDecodedPacketCumulativeBytes); } // PCM or ADPCM else { // Cache entry now has reference count 1 and responsibility for deleting pBuffer ce.Set((GENERICWAVEFILE*)wav.GetFormat(), pBuffer, size); } ce.refCount = 0; // Just precached, nothing referencing yet totalCacheSize += size; return i; } }
//----------------------------------------------------------------------------- // Name: OnOpenSoundFile() // Desc: Called when the user requests to open a sound file //----------------------------------------------------------------------------- VOID OnOpenSoundFile( HWND hDlg ) { GUID guid3DAlgorithm = GUID_NULL; int nResult; HRESULT hr; static TCHAR strFileName[MAX_PATH] = TEXT(""); static TCHAR strPath[MAX_PATH] = TEXT(""); // Setup the OPENFILENAME structure OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL, TEXT("Wave Files\0*.wav\0All Files\0*.*\0\0"), NULL, 0, 1, strFileName, MAX_PATH, NULL, 0, strPath, TEXT("Open Sound File"), OFN_FILEMUSTEXIST|OFN_HIDEREADONLY, 0, 0, TEXT(".wav"), 0, NULL, NULL }; // Get the default media path (something like C:\WINDOWS\MEDIA) if( '\0' == strPath[0] ) { GetWindowsDirectory( strPath, MAX_PATH ); if( strcmp( &strPath[strlen(strPath)], TEXT("\\") ) ) strcat( strPath, TEXT("\\") ); strcat( strPath, TEXT("MEDIA") ); } if( g_pSound ) { g_pSound->Stop(); g_pSound->Reset(); } // Update the UI controls to show the sound as loading a file EnableWindow( GetDlgItem( hDlg, IDC_PLAY ), FALSE); EnableWindow( GetDlgItem( hDlg, IDC_STOP ), FALSE); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Loading file...") ); // Stop the timer while dialogs are displayed g_bAllowMovementTimer = FALSE; // Display the OpenFileName dialog. Then, try to load the specified file if( TRUE != GetOpenFileName( &ofn ) ) { SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") ); g_bAllowMovementTimer = TRUE; return; } SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); // Free any previous sound, and make a new one SAFE_DELETE( g_pSound ); CWaveFile waveFile; waveFile.Open( strFileName, NULL, WAVEFILE_READ ); WAVEFORMATEX* pwfx = waveFile.GetFormat(); if( pwfx == NULL ) { SetDlgItemText( hDlg, IDC_STATUS, TEXT("Invalid wave file format.") ); return; } if( pwfx->nChannels > 1 ) { // Too many channels in wave. Sound must be mono when using DSBCAPS_CTRL3D SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be mono for 3D control.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; } if( pwfx->wFormatTag != WAVE_FORMAT_PCM ) { // Sound must be PCM when using DSBCAPS_CTRL3D SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be PCM for 3D control.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; } // Get the software DirectSound3D emulation algorithm to use // Ask the user for this sample, so display the algorithm dialog box. nResult = (int)DialogBox( NULL, MAKEINTRESOURCE(IDD_3D_ALGORITHM), NULL, AlgorithmDlgProc ); switch( nResult ) { case -1: // User canceled dialog box SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; case 0: // User selected DS3DALG_NO_VIRTUALIZATION guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION; break; case 1: // User selected DS3DALG_HRTF_FULL guid3DAlgorithm = DS3DALG_HRTF_FULL; break; case 2: // User selected DS3DALG_HRTF_LIGHT guid3DAlgorithm = DS3DALG_HRTF_LIGHT; break; } // Load the wave file into a DirectSound buffer hr = g_pSoundManager->Create( &g_pSound, strFileName, DSBCAPS_CTRL3D, guid3DAlgorithm ); if( FAILED( hr ) || hr == DS_NO_VIRTUALIZATION ) { DXTRACE_ERR_NOMSGBOX( TEXT("Create"), hr ); if( DS_NO_VIRTUALIZATION == hr ) { MessageBox( hDlg, "The 3D virtualization algorithm requested is not supported under this " "operating system. It is available only on Windows 2000, Windows ME, and Windows 98 with WDM " "drivers and beyond. Creating buffer with no virtualization.", "DirectSound Sample", MB_OK ); } // Unknown error, but not a critical failure, so just update the status SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Could not create sound buffer.") ); return; } // Get the 3D buffer from the secondary buffer if( FAILED( hr = g_pSound->Get3DBufferInterface( 0, &g_pDS3DBuffer ) ) ) { DXTRACE_ERR( TEXT("Get3DBufferInterface"), hr ); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Could not get 3D buffer.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; } // Get the 3D buffer parameters g_dsBufferParams.dwSize = sizeof(DS3DBUFFER); g_pDS3DBuffer->GetAllParameters( &g_dsBufferParams ); // Set new 3D buffer parameters g_dsBufferParams.dwMode = DS3DMODE_HEADRELATIVE; g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE ); DSBCAPS dsbcaps; ZeroMemory( &dsbcaps, sizeof(DSBCAPS) ); dsbcaps.dwSize = sizeof(DSBCAPS); LPDIRECTSOUNDBUFFER pDSB = g_pSound->GetBuffer( 0 ); pDSB->GetCaps( &dsbcaps ); if( ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) != 0 ) SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using hardware mixing.") ); else SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using software mixing.") ); // Update the UI controls to show the sound as the file is loaded SetDlgItemText( hDlg, IDC_FILENAME, strFileName ); EnablePlayUI( hDlg, TRUE ); g_bAllowMovementTimer = TRUE; // Remember the path for next time strcpy( strPath, strFileName ); char* strLastSlash = strrchr( strPath, '\\' ); strLastSlash[0] = '\0'; // Set the slider positions SetSlidersPos( hDlg, 0.0f, 0.0f, ORBIT_MAX_RADIUS, ORBIT_MAX_RADIUS*2.0f ); OnSliderChanged( hDlg ); }