Files
Xenia-Canary/src/xenia/apu/xaudio2/xaudio2_audio_system.cc

175 lines
4.9 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/apu/xaudio2/xaudio2_audio_system.h>
#include <xenia/apu/apu-private.h>
#include <xenia/emulator.h>
using namespace xe;
using namespace xe::apu;
using namespace xe::apu::xaudio2;
class XAudio2AudioSystem::VoiceCallback : public IXAudio2VoiceCallback {
public:
VoiceCallback(HANDLE wait_handle) : wait_handle_(wait_handle) {}
~VoiceCallback() {}
void OnStreamEnd() {}
void OnVoiceProcessingPassEnd() {}
void OnVoiceProcessingPassStart(UINT32 SamplesRequired) {}
void OnBufferEnd(void * pBufferContext) {
SetEvent(wait_handle_);
}
void OnBufferStart(void * pBufferContext) {}
void OnLoopEnd(void * pBufferContext) {}
void OnVoiceError(void * pBufferContext, HRESULT Error) {}
private:
HANDLE wait_handle_;
};
XAudio2AudioSystem::XAudio2AudioSystem(Emulator* emulator) :
audio_(0), mastering_voice_(0), pcm_voice_(0),
wait_handle_(NULL), voice_callback_(0),
AudioSystem(emulator) {
}
XAudio2AudioSystem::~XAudio2AudioSystem() {
}
void XAudio2AudioSystem::Initialize() {
AudioSystem::Initialize();
HRESULT hr;
wait_handle_ = CreateEvent(NULL, TRUE, TRUE, NULL);
voice_callback_ = new VoiceCallback(wait_handle_);
hr = XAudio2Create(&audio_, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr)) {
XELOGE("XAudio2Create failed with %.8X", hr);
XEASSERTALWAYS();
return;
}
XAUDIO2_DEBUG_CONFIGURATION config;
config.TraceMask = XAUDIO2_LOG_ERRORS;
config.BreakMask = 0;
config.LogThreadID = FALSE;
config.LogTiming = TRUE;
config.LogFunctionName = TRUE;
config.LogFileline = TRUE;
audio_->SetDebugConfiguration(&config);
hr = audio_->CreateMasteringVoice(&mastering_voice_);
if (FAILED(hr)) {
XELOGE("CreateMasteringVoice failed with %.8X", hr);
XEASSERTALWAYS();
return;
}
WAVEFORMATIEEEFLOATEX waveformat;
waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
waveformat.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
waveformat.Format.nChannels = 6;
waveformat.Format.nSamplesPerSec = 44100;
waveformat.Format.wBitsPerSample = 32;
waveformat.Format.nBlockAlign = (waveformat.Format.nChannels * waveformat.Format.wBitsPerSample) / 8; // 4
waveformat.Format.nAvgBytesPerSec = waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign; // 44100 * 4
waveformat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample;
waveformat.dwChannelMask =
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
hr = audio_->CreateSourceVoice(
&pcm_voice_, (WAVEFORMATEX*)&waveformat, 0, XAUDIO2_DEFAULT_FREQ_RATIO,
voice_callback_);
if (FAILED(hr)) {
XELOGE("CreateSourceVoice failed with %.8X", hr);
XEASSERTALWAYS();
return;
}
//
pcm_voice_->Start();
}
void XAudio2AudioSystem::Pump() {
XAUDIO2_VOICE_STATE state;
pcm_voice_->GetState(&state);
auto n = state.BuffersQueued;
if (n > 30) {
// A lot of buffers are queued up, and until we use them block.
ResetEvent(wait_handle_);
}
WaitForSingleObject(wait_handle_, INFINITE);
}
void XAudio2AudioSystem::SubmitFrame(uint32_t samples_ptr) {
// Process samples! They are big-endian floats.
HRESULT hr;
int sample_count = 6 * 256;
auto samples = reinterpret_cast<float*>(
emulator_->memory()->membase() + samples_ptr);
for (int i = 0; i < sample_count; ++i) {
samples_[i] = XESWAPF32BE(*(samples + i));
}
// this is dumb and not right.
XAUDIO2_BUFFER buffer;
buffer.Flags = 0;
buffer.AudioBytes = sample_count * sizeof(float);
buffer.pAudioData = reinterpret_cast<BYTE*>(samples_);
buffer.PlayBegin = 0;
buffer.PlayLength = 0;
buffer.LoopBegin = 0;
buffer.LoopLength = 0;
buffer.LoopCount = 0;
buffer.pContext = 0;
hr = pcm_voice_->SubmitSourceBuffer(&buffer);
if (FAILED(hr)) {
XELOGE("SubmitSourceBuffer failed with %.8X", hr);
XEASSERTALWAYS();
return;
}
hr = pcm_voice_->Start(0);
if (FAILED(hr)) {
XELOGE("Start failed with %.8X", hr);
XEASSERTALWAYS();
return;
}
}
void XAudio2AudioSystem::Shutdown() {
pcm_voice_->Stop();
pcm_voice_->DestroyVoice();
pcm_voice_ = NULL;
mastering_voice_->DestroyVoice();
mastering_voice_ = NULL;
audio_->StopEngine();
XESAFERELEASE(audio_);
delete voice_callback_;
CloseHandle(wait_handle_);
AudioSystem::Shutdown();
}