通过MSDN的文档可以知道,XAuido2出了最新的再发行版本,可以兼容win7。而DirectX SDK的XAudio2.7版本已经是2010年的产物了。需要下载库的我有上传资源在CSDN~

封装之后,不仅可播放wav文件,也可以播放ogg文件。不过解析ogg格式需要配置libogg、libvorbis、libvorbisfile三个库,在ogg的官网下载配置即可。

https://xiph.org/downloads/

并且我分为音乐和音效两个混音,可以分别控制音量大小,符合一般游戏的需求。

并且我还是用X3DAudio实现了简单的3D音效封装,代码如下:

标头DNDSound:

//
//name:     DNDSound
//author:   Lveyou
//date:     17-11-11//other:
//17-11-11: 简单封装zplaylib库 - Lveyou
//18-08-09: 改为 XAudio2 播放 wav文件 - Lveyou
//#ifndef _DND_SOUND_H_
#define _DND_SOUND_H_#include "DNDDLL.h"
#include "DNDTypedef.h"
#include "DNDString.h"
#include "DNDGame.h"
#include "DNDDebug.h"namespace DND
{class DLL_API Voice{friend class Voice_imp;public:virtual void Play() = 0;//传入256无限循环virtual void PlayLoop(UINT32 num = 256) = 0;virtual void Pause() = 0;virtual void SetVolume(float volume) = 0;virtual void SetFrequencyRatio(float ratio) = 0;//是否没有播放virtual bool IsEnd() = 0;//设置是否播放完成后再删除,默认为truevirtual void SetDeleteWaitEnd(bool delete_wait_end) = 0;private:virtual ~Voice() {}};class DLL_API Sound{public:virtual void SetOpen(bool open = true) = 0;virtual bool IsOpen() = 0;virtual void Load(const String& name, const String& path) = 0;//0为音效、1为音乐(group id)virtual Voice* Create(const String& name,UINT32 group_id = 0, bool dsp = false, float scaler = 64.0f) = 0;//删除音效virtual void Delete(Voice* voice) = 0;//传入-1代表总音量,0为音效、1为音乐(group id)virtual void SetVolume(float v, UINT32 group_id = -1) = 0;virtual float GetVolume(UINT32 group_id = -1) = 0;//此方法返//virtual Voice* GetVoice(const String& name) = 0;//请判断是播放状态再调用virtual void UpdateDSP(Voice* voice,Vector3 voice_pos, Vector3 listener_pos,Vector3 voice_v = Vector3(), Vector3 listener_v = Vector3()) = 0;};inline void snd_play(const String& name, UINT32 group_id = 0, float volume = 1.0f){if (name.IsEmpty())return;//auto* voice = Game::Get()->sound->Create(name, group_id);if (voice){if (volume != 1.0f)voice->SetVolume(volume);voice->Play();}else{debug_err(String(L"DND: 音效获取失败") + name);return;}Game::Get()->sound->Delete(voice);}
}#endif

实现标头:

//
//name:     DNDSound imp
//author:   Lveyou
//date:     18-08-09//other:
//18-08-09: 实现 - Lveyou
//20-12-28: 使用XAuido2.9再发行版本,兼容win7 - Lveyou
//#ifndef _DND_SOUND_IMP_H_
#define _DND_SOUND_IMP_H_//#ifdef USE_DX_SDK
//#include <..\dx11_sdk\include\XAudio2.h>
//#include <..\dx11_sdk\include\X3DAudio.h>
//#else
//#include <XAudio2.h>
//#include <X3DAudio.h>
//#endif
#include <..\XAudio2.9Redist\include\XAudio2.h>
#include <..\XAudio2.9Redist\include\X3DAudio.h>#include <map>
#include <list>
using namespace std;#include "DNDSound.h"
#include "DNDThread.h"namespace DND
{class VoiceData{public:    WAVEFORMATEXTENSIBLE _wfx;XAUDIO2_BUFFER _buffer;VoiceData(){ZeroMemory(&_wfx, sizeof(_wfx));ZeroMemory(&_buffer, sizeof(_buffer));}};class VoiceCallback;class Voice_imp : public Voice//, public Thread{public:virtual void Play() override;virtual void PlayLoop(UINT32 num) override;virtual void Pause() override;virtual void SetVolume(float volume) override;virtual void SetFrequencyRatio(float ratio) override;virtual bool IsEnd() override;virtual void SetDeleteWaitEnd(bool delete_wait_end) override;//virtual void _run() override;bool _is_valid(){return _sourceVoice;}IXAudio2SourceVoice* _sourceVoice;VoiceCallback* _voiceCallBack;bool _end;//为true代表需要提交bool _deleteWaitEnd;//等待结束再删除UINT32 _groupID;//XAUDIO2_BUFFER* _bufferRef;//X3DAUDIO_EMITTER* _emitter;Voice_imp();~Voice_imp();};//回调class VoiceCallback : public IXAudio2VoiceCallback{public:Voice_imp* _voice;HANDLE hBufferEndEvent;VoiceCallback() : hBufferEndEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) {}~VoiceCallback() { CloseHandle(hBufferEndEvent); }//Called when the voice has just finished playing a contiguous audio stream.void STDMETHODCALLTYPE OnStreamEnd(){SetEvent(hBufferEndEvent);}//Unused methods are stubsvoid STDMETHODCALLTYPE OnVoiceProcessingPassEnd() { }void STDMETHODCALLTYPE OnVoiceProcessingPassStart(UINT32 SamplesRequired) {    }void STDMETHODCALLTYPE OnBufferEnd(void * pBufferContext) { //debug_err(L"DND: VoiceCallback: OnBufferEnd "); /*_voice->_sourceVoice->Stop(0);if (FAILED(_voice->_sourceVoice->SubmitSourceBuffer(_voice->_bufferRef))){debug_err(L"DND: VoiceCallback: 提交SourceBuffer失败: ");}else*///直接标记为播放结束_voice->_end = true;}void STDMETHODCALLTYPE OnBufferStart(void * pBufferContext) {    }void STDMETHODCALLTYPE OnLoopEnd(void * pBufferContext) {    停止循环//_voice->_sourceVoice->Stop(XAUDIO2_PLAY_TAILS);指明它已经播放结束了//_voice->_ready = true;//debug_err(L"DND: VoiceCallback: OnLoopEnd ");}void STDMETHODCALLTYPE OnVoiceError(void * pBufferContext, HRESULT Error) { }};class Sound_imp : public Sound{public:virtual void SetOpen(bool open = true) override;virtual bool IsOpen() override;virtual void Load(const String& name, const String& path) override;virtual Voice* Create(const String& name, UINT32 group_id = 0, bool dsp = false, float scaler = 64.0f) override;virtual void Delete(Voice* voice) override;virtual void SetVolume(float v, UINT32 group_id = -1) override;virtual float GetVolume(UINT32 group_id = -1) override;//virtual Voice* GetVoice(const String& name) override;virtual void UpdateDSP(Voice* voice,Vector3 voice_pos, Vector3 listener_pos, Vector3 voice_v = Vector3(), Vector3 listener_v = Vector3()) override;void _init();//失败返回一个空Voice,防止指针操作崩溃Voice* _get_voice_invalid();bool _is_voice_valid(Voice* v);Sound_imp(){_xaudio2 = NULL;_masterVoice = NULL;_open = false;_inited = false;}public:IXAudio2* _xaudio2;IXAudio2MasteringVoice* _masterVoice;//子混音IXAudio2SubmixVoice * _submixVoice[2];//0为音效、1为音乐(group id)XAUDIO2_SEND_DESCRIPTOR _sendArray0[1];XAUDIO2_SEND_DESCRIPTOR _sendArray1[1];XAUDIO2_VOICE_SENDS _voiceSends[2];//设备信息//UINT32 _cannelMask;//主混音X3DAUDIO_HANDLE _x3dInstance;XAUDIO2_VOICE_DETAILS _voiceDetails;//name -> datamap<String, VoiceData*> _mapVoiceData;//所有音频//map<String, list<Voice_imp*>> _mapAllVoice;//删除列表list<Voice_imp*> _listDelete;//听者信息X3DAUDIO_LISTENER _listener;X3DAUDIO_DSP_SETTINGS _dsp;bool _open;bool _inited;};
}#endif

源:

#include "DNDSound_imp.h"
#include "DNDDebug.h"
#include "DNDStreamOutput.h"
#include "DNDSystem.h"#include "vorbis\codec.h"
#include "vorbis\vorbisfile.h"//#ifdef _WIN32
//#include <io.h>
//#include <fcntl.h>
//#endif//#include <fstream>
#include <io.h>namespace DND
{
#ifdef _XBOX //Big-Endian
#define fourccRIFF 'RIFF'
#define fourccDATA 'data'
#define fourccFMT 'fmt '
#define fourccWAVE 'WAVE'
#define fourccXWMA 'XWMA'
#define fourccDPDS 'dpds'
#endif#ifndef _XBOX //Little-Endian
#define fourccRIFF 'FFIR'
#define fourccDATA 'atad'
#define fourccFMT ' tmf'
#define fourccWAVE 'EVAW'
#define fourccXWMA 'AMWX'
#define fourccDPDS 'sdpd'
#endifHRESULT FindChunk(FILE* fp, DWORD fourcc, DWORD & dwChunkSize, DWORD & dwChunkDataPosition){HRESULT hr = S_OK;/*if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))return HRESULT_FROM_WIN32(GetLastError());*/if (0 != fseek(fp, 0, SEEK_SET))return S_FALSE;DWORD dwChunkType;DWORD dwChunkDataSize;DWORD dwRIFFDataSize = 0;DWORD dwFileType;DWORD bytesRead = 0;DWORD dwOffset = 0;while (hr == S_OK){DWORD dwRead;/*if (0 == ReadFile(hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL))hr = HRESULT_FROM_WIN32(GetLastError());if (0 == ReadFile(hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL))hr = HRESULT_FROM_WIN32(GetLastError());*/dwRead = fread(&dwChunkType, sizeof(DWORD), 1, fp);dwRead = fread(&dwChunkDataSize, sizeof(DWORD), 1, fp);switch (dwChunkType){case fourccRIFF:dwRIFFDataSize = dwChunkDataSize;dwChunkDataSize = 4;/*if (0 == ReadFile(hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL))hr = HRESULT_FROM_WIN32(GetLastError());*/dwRead = fread(&dwFileType, sizeof(DWORD), 1, fp);break;default:/*if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, dwChunkDataSize, NULL, FILE_CURRENT))return HRESULT_FROM_WIN32(GetLastError());*/if (0 != fseek(fp, dwChunkDataSize, SEEK_CUR))return S_FALSE;break;}dwOffset += sizeof(DWORD) * 2;if (dwChunkType == fourcc){dwChunkSize = dwChunkDataSize;dwChunkDataPosition = dwOffset;return S_OK;}dwOffset += dwChunkDataSize;if (bytesRead >= dwRIFFDataSize) return S_FALSE;}return S_OK;}HRESULT ReadChunkData(FILE* fp, void * buffer, DWORD buffersize, DWORD bufferoffset){HRESULT hr = S_OK;/*   if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, bufferoffset, NULL, FILE_BEGIN))return HRESULT_FROM_WIN32(GetLastError());*/if (0 != fseek(fp, bufferoffset, SEEK_SET))return S_FALSE;//DWORD dwRead;/*if (0 == ReadFile(hFile, buffer, buffersize, &dwRead, NULL))hr = HRESULT_FROM_WIN32(GetLastError());*/fread(buffer, buffersize, 1, fp);return hr;}void Sound_imp::SetOpen(bool open /*= true*/){_open = open;if(_open)_init();}bool Sound_imp::IsOpen(){return _open;}////以上代码copy自dx sdk文档void Sound_imp::Load(const String& name, const String& path){if (!_open)return;String name_format = path;int index = name_format.FindEnd(L'.');if(index != -1)name_format.CutHead(index);int file_type = 0;if (name_format == L".wav")file_type = 1;else if (name_format == L".ogg")file_type = 2;if (file_type == 1){FILE* file = NULL;if (Game::Get()->sys->GetFile(path, file) == -1){debug_err(String(L"DND: wav文件加载失败: ") + path);return;}//HANDLE hFile = (HANDLE)_get_osfhandle((int)file);/*HANDLE hFile = CreateFile(file,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);*//*if (INVALID_HANDLE_VALUE == hFile){debug_err(String(L"DND: wav文件获取文件句柄失败: ") + path);return;}*/if (0 != fseek(file, 0, SEEK_SET))//INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)){debug_err(String(L"DND: wav文件加载失败2: ") + path);fclose(file);return;}DWORD dwChunkSize;DWORD dwChunkPosition;//check the file type, should be fourccWAVE or 'XWMA'FindChunk(file, fourccRIFF, dwChunkSize, dwChunkPosition);DWORD filetype;ReadChunkData(file, &filetype, sizeof(DWORD), dwChunkPosition);if (filetype != fourccWAVE){debug_err(String(L"DND: 音效文件加载失败,不是wav文件: ") + path);fclose(file);return;}VoiceData* ret = new VoiceData;if (S_OK != FindChunk(file, fourccFMT, dwChunkSize, dwChunkPosition)){debug_err(String(L"DND: 加载wav文件fourccFMT失败: ") + path);fclose(file);return;}if (S_OK != ReadChunkData(file, &(ret->_wfx), dwChunkSize, dwChunkPosition)){debug_err(String(L"DND: 加载wav文件_wfx失败: ") + path);fclose(file);return;};//fill out the audio data buffer with the contents of the fourccDATA chunkif (S_OK != FindChunk(file, fourccDATA, dwChunkSize, dwChunkPosition)){debug_err(String(L"DND: 加载wav文件fourccDATA失败: ") + path);fclose(file);return;};BYTE * pDataBuffer = new BYTE[dwChunkSize];if (S_OK != ReadChunkData(file, pDataBuffer, dwChunkSize, dwChunkPosition)){debug_err(String(L"DND: 加载wav文件pDataBuffer失败: ") + path);fclose(file);return;};(ret->_buffer).AudioBytes = dwChunkSize;  //buffer containing audio data(ret->_buffer).pAudioData = pDataBuffer;  //size of the audio buffer in bytes(ret->_buffer).Flags = 0;// XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer(ret->_buffer).LoopCount = 0;// XAUDIO2_LOOP_INFINITE_mapVoiceData[name] = ret;//至少一个准备播放//_mapAllVoice[name].push_back((Voice_imp*)Create(name));//CloseHandle(hFile);fclose(file);}else if(file_type == 2){FILE* file = NULL;if(Game::Get()->sys->GetFile(path, file) == -1){debug_err(String(L"DND: ogg文件加载失败: ") + path);return;}/*char temp[1024] = {0};name.GetMultiByteStr(temp, 1024);if (fopen_s(&file, temp, "rb") == NULL){debug_err(String(L"DND: ogg文件加载失败: ") + path);return;}*/OggVorbis_File vf;int eof = 0;int current_section;//#ifdef _WIN32
//          _setmode(_fileno(stdin), _O_BINARY);
//          _setmode(_fileno(stdout), _O_BINARY);
//#endifint ov_ret = ov_open_callbacks(file, &vf, NULL, 0, OV_CALLBACKS_NOCLOSE);if (ov_ret < 0){debug_err(String(L"DND: 音效文件加载失败,不是ogg文件: ") + path);fclose(file);return;}VoiceData* ret = new VoiceData;//写入wfx{vorbis_info *vi = ov_info(&vf, -1);//只需要填充Foramt这一个结构,其他被截断了ret->_wfx.Format.cbSize = 0;ret->_wfx.Format.wFormatTag = WAVE_FORMAT_PCM;ret->_wfx.Format.nChannels = vi->channels;//声道数ret->_wfx.Format.nSamplesPerSec = vi->rate;//采样率ret->_wfx.Format.wBitsPerSample = 16; //msdn: 如果wFormatTag是WAVE_FORMAT_PCM,则wBitsPerSample应该等于8或16ret->_wfx.Format.nBlockAlign = ret->_wfx.Format.nChannels * ret->_wfx.Format.wBitsPerSample / 8;//msdn: 如果wFormatTag是WAVE_FORMAT_PCM或WAVE_FORMAT_EXTENSIBLE,则nBlockAlign必须等于nChannels和wBitsPerSample的乘积除以8(每字节位数)ret->_wfx.Format.nAvgBytesPerSec = ret->_wfx.Format.nSamplesPerSec * ret->_wfx.Format.nBlockAlign;//msdn: 如果wFormatTag是WAVE_FORMAT_PCM,则nAvgBytesPerSec应该等于nSamplesPerSec和nBlockAlign的乘积}//写入bufferchar pcmout[4096];StreamOutput o;o.SetDelete(false);while (!eof) {long ret = ov_read(&vf, pcmout, sizeof(pcmout), 0, 2, 1, &current_section);if (ret == 0) {/* EOF */eof = 1;}else if (ret < 0) {/* error in the stream.  Not a problem, just reporting it incase we (the app) cares.  In this case, we don't. */}else {/* we don't bother dealing with sample rate changes, etc, butyou'll have to*/o.Write(pcmout, ret);//fwrite(pcmout, 1, ret, stdout);}}(ret->_buffer).AudioBytes = o.GetLength();  //buffer containing audio data(ret->_buffer).pAudioData = o.GetBuffer();  //size of the audio buffer in bytes(ret->_buffer).Flags = 0;// XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer(ret->_buffer).LoopCount = 0;_mapVoiceData[name] = ret;//至少一个准备播放//_mapAllVoice[name].push_back((Voice_imp*)Create(name));ov_clear(&vf);fclose(file);}else{debug_err(String(L"DND: 音效文件加载失败,不支持的格式: ") + name_format);return;}}DND::Voice* Sound_imp::Create(const String& name, UINT32 group_id, bool dsp, float scaler){if (!_open)return _get_voice_invalid();Voice_imp* ret = new Voice_imp;ret->_voiceCallBack = new VoiceCallback; ret->_voiceCallBack->_voice = ret;ret->_groupID = group_id;auto& iter = _mapVoiceData.find(name);if (iter == _mapVoiceData.end()){debug_err(String(L"DND: Sound::Create: 音频没有加载: ") + name);delete ret;return _get_voice_invalid();}if (FAILED(_xaudio2->CreateSourceVoice(&(ret->_sourceVoice), (WAVEFORMATEX*)&(iter->second->_wfx),0, XAUDIO2_DEFAULT_FREQ_RATIO, ret->_voiceCallBack, &_voiceSends[group_id], NULL))){debug_err(String(L"DND: Sound::Create: 创建SourceVoice失败: ") + name);delete ret;return _get_voice_invalid();}ret->_bufferRef = &(iter->second->_buffer);/*if (FAILED(ret->_sourceVoice->SubmitSourceBuffer(ret->_bufferRef))){debug_err(String(L"DND: Sound::Create: 提交SourceBuffer失败: ") + name);delete ret;return NULL;}*///dspif (dsp){XAUDIO2_VOICE_DETAILS voice_detail;ret->_sourceVoice->GetVoiceDetails(&voice_detail);if (voice_detail.InputChannels != 2){debug_err(String(L"DND: Sound::Create: 音频文件通道数不为2,不能创建DSP效果: ") + name);return ret;}ret->_emitter = new X3DAUDIO_EMITTER;ZeroMemory(ret->_emitter, sizeof(X3DAUDIO_EMITTER));ret->_emitter->ChannelCount = 2;ret->_emitter->CurveDistanceScaler = scaler;FLOAT32* p_cas = new FLOAT32[2];for (UINT32 i = 0; i != 2; ++i)p_cas[i] = 0;ret->_emitter->pChannelAzimuths = p_cas;ret->_emitter->OrientFront = {0.0f, 0.0f, 1.0f};ret->_emitter->OrientTop = { 0.0f, -1.0f, 0.0f };}return ret;}void Sound_imp::SetVolume(float v, UINT32 group_id){if (!_open)return;//_masterVoice->SetVolume(v);if (group_id == -1)_masterVoice->SetVolume(v);else_submixVoice[group_id]->SetVolume(v);}float Sound_imp::GetVolume(UINT32 group_id){if (!_open)return 0;float ret;if(group_id == -1)_masterVoice->GetVolume(&ret);else_submixVoice[group_id]->GetVolume(&ret);//_masterVoice->GetVolume(&ret);return ret;}//DND::Voice* Sound_imp::GetVoice(const String& name)//{//    auto& iter = _mapAllVoice.find(name);//    if (iter == _mapAllVoice.end())//     return NULL;//  for (auto& iter2 : iter->second)//   {//     if (iter2->_ready)//         return iter2;// }// Voice* ret = Create(name);//   iter->second.push_back((Voice_imp*)ret);//   return ret;//}void Sound_imp::UpdateDSP(Voice* voice, Vector3 voice_pos, Vector3 listener_pos, Vector3 voice_v /*= Vector3()*/, Vector3 listener_v /*= Vector3()*/){if (!_is_voice_valid(voice))return;Voice_imp* p = (Voice_imp*)voice;if (p && p->_emitter){//设置速度与位置p->_emitter->Position.x = voice_pos.a;p->_emitter->Position.y = voice_pos.b;p->_emitter->Position.z = voice_pos.c;p->_emitter->Velocity.x = voice_v.a;p->_emitter->Velocity.y = voice_v.b;p->_emitter->Velocity.z = voice_v.c;_listener.Position.x = listener_pos.a;_listener.Position.y = listener_pos.b;_listener.Position.z = listener_pos.c;_listener.Velocity.x = listener_v.a;_listener.Velocity.y = listener_v.b;_listener.Velocity.z = listener_v.c;//计算X3DAudioCalculate(_x3dInstance, &_listener, p->_emitter,X3DAUDIO_CALCULATE_MATRIX//| X3DAUDIO_CALCULATE_DOPPLER/*| X3DAUDIO_CALCULATE_LPF_DIRECT| X3DAUDIO_CALCULATE_REVERB*/,&_dsp);//应用效果p->_sourceVoice->SetOutputMatrix(_submixVoice[p->_groupID], 2, _voiceDetails.InputChannels, _dsp.pMatrixCoefficients);//p->_sourceVoice->SetFrequencyRatio(_dsp.DopplerFactor);/*p->_sourceVoice->SetOutputMatrix(_submixVoice[p->_groupID], 2, _voiceDetails.InputChannels, &_dsp.ReverbLevel);*//*XAUDIO2_FILTER_PARAMETERS FilterParameters = { LowPassFilter, 2.0f * sinf(X3DAUDIO_PI / 6.0f * _dsp.LPFDirectCoefficient), 1.0f };p->_sourceVoice->SetFilterParameters(&FilterParameters);*/}}void Sound_imp::_init(){if (_inited)return;_inited = true;#ifndef _XBOXCoInitializeEx(NULL, COINIT_MULTITHREADED);
#endifHRESULT hr;if (FAILED(hr = XAudio2Create(&_xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR))){dnd_assert(L"DND: XAudio2 初始化失败!");return;}//#define USE_DX_SDK_SND#ifdef USE_DX_SDK_SND//获取设备详情XAUDIO2_DEVICE_DETAILS device_details;_xaudio2->GetDeviceDetails(0, &device_details);debug_msg(String::Format(L"DND: 音频设备: %ws-%ws", device_details.DisplayName, device_details.DeviceID));
#endif//直接使用0,全局音频设备if (FAILED(hr = _xaudio2->CreateMasteringVoice(&_masterVoice, XAUDIO2_DEFAULT_CHANNELS,XAUDIO2_DEFAULT_SAMPLERATE, 0, 0, NULL))){dnd_assert(L"DND: XAudio2 创建 MasterVoice 失败!");return;}//获取主控详情_masterVoice->GetVoiceDetails(&_voiceDetails);//子混音(应和主混音通道数一致)if (FAILED(hr = _xaudio2->CreateSubmixVoice(&(_submixVoice[0]),_voiceDetails.InputChannels,_voiceDetails.InputSampleRate, 0, 0, 0))){dnd_assert(L"DND: XAudio2 创建 SubmixVoice0 失败!");return;}if (FAILED(hr = _xaudio2->CreateSubmixVoice(&(_submixVoice[1]), _voiceDetails.InputChannels,_voiceDetails.InputSampleRate, 0, 0, 0))){dnd_assert(L"DND: XAudio2 创建 SubmixVoice1 失败!");return;}_sendArray0[0] = { 0, _submixVoice[0] };_sendArray1[0] = { 0, _submixVoice[1] };_voiceSends[0] = { 1, _sendArray0 };_voiceSends[1] = { 1, _sendArray1 };//初始化X3DAudioDWORD dwChannelMask;
#ifdef USE_DX_SDK_SNDdwChannelMask = device_details.OutputFormat.dwChannelMask;
#else_masterVoice->GetChannelMask(&dwChannelMask);
#endifX3DAudioInitialize(dwChannelMask, X3DAUDIO_SPEED_OF_SOUND, _x3dInstance);//听者只有一个ZeroMemory(&_listener, sizeof(X3DAUDIO_LISTENER));_listener.OrientFront = { 0.0f,0.0f,-1.0f };_listener.OrientTop = { 0.0f,-1.0f,0.0f };//dspZeroMemory(&_dsp, sizeof(X3DAUDIO_DSP_SETTINGS));FLOAT32 * matrix = new FLOAT32[2 * _voiceDetails.InputChannels];FLOAT32* dtimes = new FLOAT32[_voiceDetails.InputChannels];_dsp.SrcChannelCount = 2;_dsp.DstChannelCount = _voiceDetails.InputChannels;_dsp.pMatrixCoefficients = matrix;_dsp.pDelayTimes = dtimes;/*_dsp.EmitterToListenerDistance = 1.0f / 64.0f;_dsp.EmitterVelocityComponent = 1.0f / 64.0f;_dsp.ListenerVelocityComponent = 1.0f / 64.0f;*/}void Sound_imp::Delete(Voice* voice){if (!voice)return;Voice_imp* p = (Voice_imp*)voice;if (p->_sourceVoice == NULL){delete p;return;}if (!p->_deleteWaitEnd || p->_end){p->_sourceVoice->Stop();delete p;}else{_listDelete.push_back(p);}}DND::Voice* Sound_imp::_get_voice_invalid(){Voice_imp* ret = new Voice_imp();return ret;}bool Sound_imp::_is_voice_valid(Voice* v){return v && ((Voice_imp*)v)->_sourceVoice;}void Voice_imp::Play(){if (!_is_valid())return;if (_end){_bufferRef->LoopCount = 0;if (FAILED(_sourceVoice->SubmitSourceBuffer(_bufferRef))){debug_err(String(L"DND: Voice::Play: 提交SourceBuffer失败: "));return;}_sourceVoice->Start(0, XAUDIO2_COMMIT_NOW);_end = false;}/*WaitForSingleObject(_voiceCallBack->hBufferEndEvent, INFINITE);Thread::Start();*///_sourceVoice->SetChannelVolumes(,)}void Voice_imp::PlayLoop(UINT32 num){if (!_is_valid())return;if (_end){//结束了则重新提交_bufferRef->LoopCount = num - 1;if (FAILED(_sourceVoice->SubmitSourceBuffer(_bufferRef))){debug_err(String(L"DND: Voice::PlayLoop: 提交SourceBuffer失败: "));return;}_sourceVoice->Start(0, XAUDIO2_COMMIT_NOW);_end = false;}}void Voice_imp::Pause(){if (!_is_valid())return;_sourceVoice->Stop(0, XAUDIO2_COMMIT_NOW);}void Voice_imp::SetVolume(float volume){if (!_is_valid())return;_sourceVoice->SetVolume(volume);}bool Voice_imp::IsEnd(){return _end;}void Voice_imp::SetDeleteWaitEnd(bool delete_wait_end){_deleteWaitEnd = delete_wait_end;}Voice_imp::Voice_imp(){_sourceVoice = NULL;_voiceCallBack = NULL;_end = true;_deleteWaitEnd = true;_groupID = 0;_emitter = NULL;_bufferRef = NULL;}Voice_imp::~Voice_imp(){if (_sourceVoice)_sourceVoice->DestroyVoice();//先于_sourceVoice释放会导致深不可测的bugdelete _voiceCallBack;if (_emitter)delete[] _emitter->pChannelAzimuths;delete _emitter;}void Voice_imp::SetFrequencyRatio(float ratio){if (!_is_valid())return;_sourceVoice->SetFrequencyRatio(ratio);//_sourceVoice->}/*void Voice_imp::_run(){}*/}

【XAuido2】播放wav和ogg格式音频文件相关推荐

  1. ubuntu下播放wav视频和mp3音频文件

    sudo apt-get install sox play xx.wav 支持播放wav和mp3文件的package是sox,所以sudo apt-get install sox即可使用play命令来 ...

  2. Python之ffmpeg:利用python编程基于ffmpeg将m4a格式音频文件转为mp3格式文件

    Python之ffmpeg:利用python编程基于ffmpeg将m4a格式音频文件转为mp3格式文件 目录 利用python编程基于ffmpeg将m4a格式音频文件转为mp3格式文件 1.先下载ff ...

  3. (原创)speex与wav格式音频文件的互相转换

    我们的司信项目又有了新的需求,就是要做会议室.然而需求却很纠结,要继续按照原来发语音消息那样的形式来实现这个会议的功能,还要实现语音播放的计时,暂停,语音的拼接,还要绘制频谱图等等. 如果是wav,m ...

  4. 关于微信录音的坑 amr格式音频文件HTML无法播放

    之前开发一个微信公众好实时聊天的时候,由于项目需要,要求支持文字,文字+表情,图片,语音实时聊天,除了语音其他的还好说,可能第一次搞网页版语音聊天所以觉得麻烦吧,其实做完之后才发现并没有那么难,下面我 ...

  5. window API播放pcm格式音频文件,函数waveOutOpen等

    之前在我的博客中有一篇关于编写录音器的代码,可保存为pcm和wav格式,说白了其实两者是一个东西,只不过wav比pcm多了一个文件头,这个文件头一共占了44个字节.此处这个不是重点,重点是如何编写程序 ...

  6. Java如何播放MP3格式音频文件,以及如何循环播放音频?

    首选,感谢你能在百忙之中阅读我的博客,在这里我告诉大家2中播放MP3格式音频的方法.第一种,使用自带的JavaFX技术来播放(现再最新的JDK版本中已被移除).第二种我们使用第三方库来进行播放. 点击 ...

  7. Android 手机录制wav格式音频文件实现

    上一篇文章已经实现了在Android手机上使用MediaRecorder录音,但是后期在处理这些音频文件的时候发现3gp格式的音频不大方便处理,使用wav格式的音频处理起来更方便一些! 这里需要用到A ...

  8. java播放mp3格式音频文件

    下载第三方jar包,网址:http://www.javazoom.net/javalayer/javalayer.html 下载完成之后解压提取jl1.0.0.1.jar 将jl1.0.0.1.jar ...

  9. STM32F767 音乐播放器 SAI DMA双缓冲 可播放WAV、MP3、FLAC文件

    以下为在单缓冲程序基础上修改 /*** Enable DMA controller clock*/ static void MX_DMA_Init(void) {/* DMA controller c ...

最新文章

  1. (转)Javascript标准DOM Range操作(1)
  2. android 工作 绝望,我的人生绝望手游
  3. 命令行 sc delete 的使用(删除服务项)
  4. 一致性 Hash 在负载均衡中的应用
  5. pyqt打包成linux可执行程序,PyQtopencv图像处理(5):python程序打包成可执行文件...
  6. js-this作用域
  7. OpenJudge 2972(确定进制)
  8. bzoj 1193: [HNOI2006]马步距离(贪心+BFS)
  9. VMware 虚拟机安装
  10. 字符串常量池、堆、栈
  11. DVBS卫星识别流程
  12. ipad版实现横屏竖屏 详解iPad横竖屏切换解决方案
  13. 关于Chrome浏览器升级到80版本后受影响的场景以及解决方案
  14. 计算机网络IP地址分配
  15. 数据库中存储用户名、密码时如何处理?
  16. 千兆PHY与RJ45接口线序
  17. HelloWord代码
  18. 视觉问答学习(一)——视觉问答的动态记忆网络DMN+(tensorflow实现)
  19. 原生小程序 申请小程序 - 发布流程
  20. Linux7.0下UNbound搭建DNS服务器

热门文章

  1. 八十九、动态规划系列背包问题之完全背包
  2. 三十三、深入Vue.js语法(上篇)
  3. 黑马Go语言与区块链学习笔记
  4. @即将开学的你,请收好这份必读论文清单
  5. Face++ 论文解读:一种新的行人重识别度量学习方法 | PaperDaily #20
  6. 深度学习入门之PyTorch学习笔记:卷积神经网络
  7. Markdown简明教程
  8. 启动mysql提1067_win7系统启动mysql服务提升错误1067进程意外终止的解决方法
  9. 快速判断list是否为空
  10. Illegal access: this web application instance has been stopped already