Exemple #1
0
// Submits any buffers that have currently been queued,
// assuming they are needed based on current queue depth
void sound_xaudio2::submit_needed()
{
	XAUDIO2_VOICE_STATE state;
	m_sourceVoice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);

	std::lock_guard<std::mutex> lock(m_buffer_lock);

	// If we have buffers queued into XAudio and our current in-memory buffer
	// isn't yet full, there's no need to submit it
	if (state.BuffersQueued >= 1 && m_queue.empty())
		return;

	// We do however want to achieve some kind of minimal latency, so if the queued buffers
	// are greater than 2, flush them to re-sync the audio
	if (state.BuffersQueued > 2)
	{
		m_sourceVoice->FlushSourceBuffers();
		m_overflows++;
	}

	// Roll the buffer
	roll_buffer();

	// Submit the next buffer
	submit_next_queued();
}
Exemple #2
0
int sound_xaudio2::init(osd_options const &options)
{
	HRESULT result;
	WAVEFORMATEX format = {0};
	auto init_start = std::chrono::system_clock::now();
	std::chrono::milliseconds init_time;

	CoInitializeEx(nullptr, COINIT_MULTITHREADED);

	// Make sure our XAudio2Create entrypoint is bound
	if (!XAudio2Create)
	{
		osd_printf_error("Could not find XAudio2. Please try to reinstall DirectX runtime package.\n");
		return 1;
	}

	// Create the IXAudio2 object
	HR_GOERR(this->XAudio2Create(m_xAudio2.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR));

	// make a format description for what we want
	format.wBitsPerSample = 16;
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nChannels = 2;
	format.nSamplesPerSec = sample_rate();
	format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8;
	format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;

	m_sample_bytes = format.nBlockAlign;

	// Create the buffers
	create_buffers(format);

	// Initialize our events
	m_hEventBufferCompleted = CreateEvent(nullptr, FALSE, FALSE, nullptr);
	m_hEventDataAvailable = CreateEvent(nullptr, FALSE, FALSE, nullptr);
	m_hEventExiting = CreateEvent(nullptr, FALSE, FALSE, nullptr);

	// create the voices and start them
	HR_GOERR(create_voices(format));
	HR_GOERR(m_sourceVoice->Start());

	// Start the thread listening
	m_audioThread = std::thread([](sound_xaudio2* self) { self->process_audio(); }, this);

	init_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - init_start);
	osd_printf_verbose("Sound: XAudio2 initialized. %d ms.\n", static_cast<int>(init_time.count()));

	m_initialized = TRUE;
	return 0;

Error:
	this->exit();
	return 1;
}
Exemple #3
0
int sound_xaudio2::init(osd_options const &options)
{
	HRESULT result;

	// Make sure our XAudio2Create entrypoint is bound
	int status = XAudio2Create.initialize();
	if (status != 0)
	{
		osd_printf_error("Could not find XAudio2 library\n");
		return 1;
	}

	// Create the IXAudio2 object
	IXAudio2 *temp_xaudio2 = nullptr;
	HR_RET1(this->XAudio2Create(&temp_xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR));
	m_xAudio2 = xaudio2_ptr(temp_xaudio2);

	// make a format description for what we want
	WAVEFORMATEX format = { 0 };
	format.wBitsPerSample = 16;
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nChannels = 2;
	format.nSamplesPerSec = sample_rate();
	format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8;
	format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;

	m_sample_bytes = format.nBlockAlign;

	// Create the buffers
	create_buffers(format);

	// Initialize our events
	m_hEventBufferCompleted = CreateEvent(nullptr, FALSE, FALSE, nullptr);
	m_hEventDataAvailable = CreateEvent(nullptr, FALSE, FALSE, nullptr);
	m_hEventExiting = CreateEvent(nullptr, FALSE, FALSE, nullptr);

	// create the voices and start them
	HR_RET1(create_voices(format));
	HR_RET1(m_sourceVoice->Start());

	// Start the thread listening
	m_audioThread = std::thread([](sound_xaudio2* self) { self->process_audio(); }, this);

	osd_printf_verbose("Sound: XAudio2 initialized\n");

	return 0;
}
Exemple #4
0
// Submits any buffers that have currently been queued,
// assuming they are needed based on current queue depth
void sound_xaudio2::submit_needed()
{
	XAUDIO2_VOICE_STATE state;
	m_sourceVoice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);

	// If we have a buffer on the queue, no reason to submit
	if (state.BuffersQueued >= 1)
		return;

	std::lock_guard<std::mutex> lock(m_buffer_lock);

	// Roll the buffer
	roll_buffer();

	// Submit the next buffer
	submit_next_queued();
}
Exemple #5
0
void sound_xaudio2::set_mastervolume(int attenuation)
{
	assert(m_sourceVoice);

	HRESULT result;

	// clamp the attenuation to 0-32 range
	attenuation = MAX(MIN(attenuation, 0), -32);

	// Ranges from 1.0 to XAUDIO2_MAX_VOLUME_LEVEL indicate additional gain
	// Ranges from 0 to 1.0 indicate a reduced volume level
	// 0 indicates silence
	// We only support a reduction from 1.0, so we generate values in the range 0.0 to 1.0
	float scaledVolume = (32.0f + attenuation) / 32.0f;

	// set the master volume
	HR_RETV(m_sourceVoice->SetVolume(scaledVolume));
}
Exemple #6
0
void sound_xaudio2::exit()
{
	// Wait on processing thread to end
	SetEvent(m_hEventExiting);
	m_audioThread.join();

	CloseHandle(m_hEventBufferCompleted);
	CloseHandle(m_hEventDataAvailable);
	CloseHandle(m_hEventExiting);

	m_sourceVoice.reset();
	m_masterVoice.reset();
	m_xAudio2.reset();
	m_buffer.reset();
	m_buffer_pool.reset();

	if (m_overflows != 0 || m_underflows != 0)
		osd_printf_verbose("Sound: overflows=%u, underflows=%u\n", m_overflows, m_underflows);

	osd_printf_verbose("Sound: XAudio2 deinitialized\n");
}
Exemple #7
0
void sound_xaudio2::submit_buffer(std::unique_ptr<BYTE[]> audioData, DWORD audioLength) const
{
	assert(audioLength != 0);

	XAUDIO2_BUFFER buf = { 0 };
	buf.AudioBytes = audioLength;
	buf.pAudioData = audioData.get();
	buf.PlayBegin = 0;
	buf.PlayLength = audioLength / m_sample_bytes;
	buf.Flags = XAUDIO2_END_OF_STREAM;
	buf.pContext = audioData.get();

	HRESULT result;
	if (FAILED(result = m_sourceVoice->SubmitSourceBuffer(&buf)))
	{
		osd_printf_verbose("Sound: XAudio2 failed to submit source buffer (non-fatal). Error: 0x%X\n", static_cast<unsigned int>(result));
		m_buffer_pool->return_to_pool(audioData.release());
		return;
	}

	// If we succeeded, relinquish the buffer allocation to the XAudio2 runtime
	// The buffer will be freed on the OnBufferCompleted callback
	audioData.release();
}