Merge pull request #2387 from lioncash/atomic
AudioCommon: Remove usages of volatile variables.
This commit is contained in:
commit
e35148fe15
|
@ -32,7 +32,7 @@ void AOSound::SoundLoop()
|
||||||
|
|
||||||
buf_size = format.bits/8 * format.channels * format.rate;
|
buf_size = format.bits/8 * format.channels * format.rate;
|
||||||
|
|
||||||
while (!threadData)
|
while (m_run_thread.load())
|
||||||
{
|
{
|
||||||
m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
|
m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ void AOSound::SoundLoop()
|
||||||
|
|
||||||
bool AOSound::Start()
|
bool AOSound::Start()
|
||||||
{
|
{
|
||||||
|
m_run_thread.store(true);
|
||||||
memset(realtimeBuffer, 0, sizeof(realtimeBuffer));
|
memset(realtimeBuffer, 0, sizeof(realtimeBuffer));
|
||||||
|
|
||||||
thread = std::thread(&AOSound::SoundLoop, this);
|
thread = std::thread(&AOSound::SoundLoop, this);
|
||||||
|
@ -60,7 +61,7 @@ void AOSound::Update()
|
||||||
|
|
||||||
void AOSound::Stop()
|
void AOSound::Stop()
|
||||||
{
|
{
|
||||||
threadData = 1;
|
m_run_thread.store(false);
|
||||||
soundSyncEvent.Set();
|
soundSyncEvent.Set();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ class AOSound final : public SoundStream
|
||||||
{
|
{
|
||||||
#if defined(HAVE_AO) && HAVE_AO
|
#if defined(HAVE_AO) && HAVE_AO
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
|
std::atomic<bool> m_run_thread;
|
||||||
std::mutex soundCriticalSection;
|
std::mutex soundCriticalSection;
|
||||||
Common::Event soundSyncEvent;
|
Common::Event soundSyncEvent;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,11 @@
|
||||||
#define BUFFER_SIZE_MAX 8192
|
#define BUFFER_SIZE_MAX 8192
|
||||||
#define BUFFER_SIZE_BYTES (BUFFER_SIZE_MAX*2*2)
|
#define BUFFER_SIZE_BYTES (BUFFER_SIZE_MAX*2*2)
|
||||||
|
|
||||||
AlsaSound::AlsaSound(CMixer *mixer) : SoundStream(mixer), thread_data(0), handle(nullptr), frames_to_deliver(FRAME_COUNT_MIN)
|
AlsaSound::AlsaSound(CMixer *mixer)
|
||||||
|
: SoundStream(mixer)
|
||||||
|
, m_thread_status(ALSAThreadStatus::STOPPED)
|
||||||
|
, handle(nullptr)
|
||||||
|
, frames_to_deliver(FRAME_COUNT_MIN)
|
||||||
{
|
{
|
||||||
mix_buffer = new u8[BUFFER_SIZE_BYTES];
|
mix_buffer = new u8[BUFFER_SIZE_BYTES];
|
||||||
}
|
}
|
||||||
|
@ -22,14 +26,14 @@ AlsaSound::~AlsaSound()
|
||||||
|
|
||||||
bool AlsaSound::Start()
|
bool AlsaSound::Start()
|
||||||
{
|
{
|
||||||
|
m_thread_status.store(ALSAThreadStatus::RUNNING);
|
||||||
thread = std::thread(&AlsaSound::SoundLoop, this);
|
thread = std::thread(&AlsaSound::SoundLoop, this);
|
||||||
thread_data = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlsaSound::Stop()
|
void AlsaSound::Stop()
|
||||||
{
|
{
|
||||||
thread_data = 1;
|
m_thread_status.store(ALSAThreadStatus::STOPPING);
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,11 +46,11 @@ void AlsaSound::Update()
|
||||||
void AlsaSound::SoundLoop()
|
void AlsaSound::SoundLoop()
|
||||||
{
|
{
|
||||||
if (!AlsaInit()) {
|
if (!AlsaInit()) {
|
||||||
thread_data = 2;
|
m_thread_status.store(ALSAThreadStatus::STOPPED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Common::SetCurrentThreadName("Audio thread - alsa");
|
Common::SetCurrentThreadName("Audio thread - alsa");
|
||||||
while (!thread_data)
|
while (m_thread_status.load() == ALSAThreadStatus::RUNNING)
|
||||||
{
|
{
|
||||||
m_mixer->Mix(reinterpret_cast<short *>(mix_buffer), frames_to_deliver);
|
m_mixer->Mix(reinterpret_cast<short *>(mix_buffer), frames_to_deliver);
|
||||||
int rc = m_muted ? 1337 : snd_pcm_writei(handle, mix_buffer, frames_to_deliver);
|
int rc = m_muted ? 1337 : snd_pcm_writei(handle, mix_buffer, frames_to_deliver);
|
||||||
|
@ -61,7 +65,7 @@ void AlsaSound::SoundLoop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AlsaShutdown();
|
AlsaShutdown();
|
||||||
thread_data = 2;
|
m_thread_status.store(ALSAThreadStatus::STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AlsaSound::AlsaInit()
|
bool AlsaSound::AlsaInit()
|
||||||
|
|
|
@ -4,13 +4,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#if defined(HAVE_ALSA) && HAVE_ALSA
|
#if defined(HAVE_ALSA) && HAVE_ALSA
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "AudioCommon/SoundStream.h"
|
#include "AudioCommon/SoundStream.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Thread.h"
|
|
||||||
|
|
||||||
class AlsaSound final : public SoundStream
|
class AlsaSound final : public SoundStream
|
||||||
{
|
{
|
||||||
|
@ -31,15 +33,19 @@ public:
|
||||||
virtual void Update() override;
|
virtual void Update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class ALSAThreadStatus
|
||||||
|
{
|
||||||
|
RUNNING,
|
||||||
|
STOPPING,
|
||||||
|
STOPPED,
|
||||||
|
};
|
||||||
|
|
||||||
bool AlsaInit();
|
bool AlsaInit();
|
||||||
void AlsaShutdown();
|
void AlsaShutdown();
|
||||||
|
|
||||||
u8 *mix_buffer;
|
u8 *mix_buffer;
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
// 0 = continue
|
std::atomic<ALSAThreadStatus> m_thread_status;
|
||||||
// 1 = shutdown
|
|
||||||
// 2 = done shutting down.
|
|
||||||
volatile int thread_data;
|
|
||||||
|
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
int frames_to_deliver;
|
int frames_to_deliver;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "AudioCommon/AudioCommon.h"
|
#include "AudioCommon/AudioCommon.h"
|
||||||
#include "AudioCommon/Mixer.h"
|
#include "AudioCommon/Mixer.h"
|
||||||
#include "Common/Atomic.h"
|
|
||||||
#include "Common/CPUDetect.h"
|
#include "Common/CPUDetect.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
@ -31,8 +30,8 @@ unsigned int CMixer::MixerFifo::Mix(short* samples, unsigned int numSamples, boo
|
||||||
// so we will just ignore new written data while interpolating.
|
// so we will just ignore new written data while interpolating.
|
||||||
// Without this cache, the compiler wouldn't be allowed to optimize the
|
// Without this cache, the compiler wouldn't be allowed to optimize the
|
||||||
// interpolation loop.
|
// interpolation loop.
|
||||||
u32 indexR = Common::AtomicLoad(m_indexR);
|
u32 indexR = m_indexR.load();
|
||||||
u32 indexW = Common::AtomicLoad(m_indexW);
|
u32 indexW = m_indexW.load();
|
||||||
|
|
||||||
float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2);
|
float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2);
|
||||||
m_numLeftI = (numLeft + m_numLeftI*(CONTROL_AVG-1)) / CONTROL_AVG;
|
m_numLeftI = (numLeft + m_numLeftI*(CONTROL_AVG-1)) / CONTROL_AVG;
|
||||||
|
@ -53,8 +52,8 @@ unsigned int CMixer::MixerFifo::Mix(short* samples, unsigned int numSamples, boo
|
||||||
|
|
||||||
const u32 ratio = (u32)(65536.0f * aid_sample_rate / (float)m_mixer->m_sampleRate);
|
const u32 ratio = (u32)(65536.0f * aid_sample_rate / (float)m_mixer->m_sampleRate);
|
||||||
|
|
||||||
s32 lvolume = m_LVolume;
|
s32 lvolume = m_LVolume.load();
|
||||||
s32 rvolume = m_RVolume;
|
s32 rvolume = m_RVolume.load();
|
||||||
|
|
||||||
// TODO: consider a higher-quality resampling algorithm.
|
// TODO: consider a higher-quality resampling algorithm.
|
||||||
for (; currentSample < numSamples * 2 && ((indexW-indexR) & INDEX_MASK) > 2; currentSample += 2)
|
for (; currentSample < numSamples * 2 && ((indexW-indexR) & INDEX_MASK) > 2; currentSample += 2)
|
||||||
|
@ -99,7 +98,7 @@ unsigned int CMixer::MixerFifo::Mix(short* samples, unsigned int numSamples, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush cached variable
|
// Flush cached variable
|
||||||
Common::AtomicStore(m_indexR, indexR);
|
m_indexR.store(indexR);
|
||||||
|
|
||||||
return numSamples;
|
return numSamples;
|
||||||
}
|
}
|
||||||
|
@ -130,11 +129,11 @@ void CMixer::MixerFifo::PushSamples(const short *samples, unsigned int num_sampl
|
||||||
// Cache access in non-volatile variable
|
// Cache access in non-volatile variable
|
||||||
// indexR isn't allowed to cache in the audio throttling loop as it
|
// indexR isn't allowed to cache in the audio throttling loop as it
|
||||||
// needs to get updates to not deadlock.
|
// needs to get updates to not deadlock.
|
||||||
u32 indexW = Common::AtomicLoad(m_indexW);
|
u32 indexW = m_indexW.load();
|
||||||
|
|
||||||
// Check if we have enough free space
|
// Check if we have enough free space
|
||||||
// indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW
|
// indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW
|
||||||
if (num_samples * 2 + ((indexW - Common::AtomicLoad(m_indexR)) & INDEX_MASK) >= MAX_SAMPLES * 2)
|
if (num_samples * 2 + ((indexW - m_indexR.load()) & INDEX_MASK) >= MAX_SAMPLES * 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// AyuanX: Actual re-sampling work has been moved to sound thread
|
// AyuanX: Actual re-sampling work has been moved to sound thread
|
||||||
|
@ -151,9 +150,7 @@ void CMixer::MixerFifo::PushSamples(const short *samples, unsigned int num_sampl
|
||||||
memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4);
|
memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::AtomicAdd(m_indexW, num_samples * 2);
|
m_indexW.fetch_add(num_samples * 2);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMixer::PushSamples(const short *samples, unsigned int num_samples)
|
void CMixer::PushSamples(const short *samples, unsigned int num_samples)
|
||||||
|
@ -215,6 +212,6 @@ void CMixer::MixerFifo::SetInputSampleRate(unsigned int rate)
|
||||||
|
|
||||||
void CMixer::MixerFifo::SetVolume(unsigned int lvolume, unsigned int rvolume)
|
void CMixer::MixerFifo::SetVolume(unsigned int lvolume, unsigned int rvolume)
|
||||||
{
|
{
|
||||||
m_LVolume = lvolume + (lvolume >> 7);
|
m_LVolume.store(lvolume + (lvolume >> 7));
|
||||||
m_RVolume = rvolume + (rvolume >> 7);
|
m_RVolume.store(rvolume + (rvolume >> 7));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -109,8 +110,8 @@ public:
|
||||||
|
|
||||||
std::mutex& MixerCritical() { return m_csMixing; }
|
std::mutex& MixerCritical() { return m_csMixing; }
|
||||||
|
|
||||||
float GetCurrentSpeed() const { return m_speed; }
|
float GetCurrentSpeed() const { return m_speed.load(); }
|
||||||
void UpdateSpeed(volatile float val) { m_speed = val; }
|
void UpdateSpeed(float val) { m_speed.store(val); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class MixerFifo {
|
class MixerFifo {
|
||||||
|
@ -135,11 +136,11 @@ protected:
|
||||||
CMixer *m_mixer;
|
CMixer *m_mixer;
|
||||||
unsigned m_input_sample_rate;
|
unsigned m_input_sample_rate;
|
||||||
short m_buffer[MAX_SAMPLES * 2];
|
short m_buffer[MAX_SAMPLES * 2];
|
||||||
volatile u32 m_indexW;
|
std::atomic<u32> m_indexW;
|
||||||
volatile u32 m_indexR;
|
std::atomic<u32> m_indexR;
|
||||||
// Volume ranges from 0-256
|
// Volume ranges from 0-256
|
||||||
volatile s32 m_LVolume;
|
std::atomic<s32> m_LVolume;
|
||||||
volatile s32 m_RVolume;
|
std::atomic<s32> m_RVolume;
|
||||||
float m_numLeftI;
|
float m_numLeftI;
|
||||||
u32 m_frac;
|
u32 m_frac;
|
||||||
};
|
};
|
||||||
|
@ -156,5 +157,5 @@ protected:
|
||||||
|
|
||||||
std::mutex m_csMixing;
|
std::mutex m_csMixing;
|
||||||
|
|
||||||
volatile float m_speed; // Current rate of the emulation (1.0 = 100% speed)
|
std::atomic<float> m_speed; // Current rate of the emulation (1.0 = 100% speed)
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ static soundtouch::SoundTouch soundTouch;
|
||||||
//
|
//
|
||||||
bool OpenALStream::Start()
|
bool OpenALStream::Start()
|
||||||
{
|
{
|
||||||
|
m_run_thread.store(true);
|
||||||
bool bReturn = false;
|
bool bReturn = false;
|
||||||
|
|
||||||
ALDeviceList pDeviceList;
|
ALDeviceList pDeviceList;
|
||||||
|
@ -72,7 +73,7 @@ bool OpenALStream::Start()
|
||||||
|
|
||||||
void OpenALStream::Stop()
|
void OpenALStream::Stop()
|
||||||
{
|
{
|
||||||
threadData = 1;
|
m_run_thread.store(false);
|
||||||
// kick the thread if it's waiting
|
// kick the thread if it's waiting
|
||||||
soundSyncEvent.Set();
|
soundSyncEvent.Set();
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ void OpenALStream::SoundLoop()
|
||||||
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28);
|
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28);
|
||||||
soundTouch.setSetting(SETTING_OVERLAP_MS, 12);
|
soundTouch.setSetting(SETTING_OVERLAP_MS, 12);
|
||||||
|
|
||||||
while (!threadData)
|
while (m_run_thread.load())
|
||||||
{
|
{
|
||||||
// num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD.
|
// num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD.
|
||||||
const u32 stereo_16_bit_size = 4;
|
const u32 stereo_16_bit_size = 4;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "AudioCommon/SoundStream.h"
|
#include "AudioCommon/SoundStream.h"
|
||||||
|
@ -72,6 +73,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
|
std::atomic<bool> m_run_thread;
|
||||||
|
|
||||||
Common::Event soundSyncEvent;
|
Common::Event soundSyncEvent;
|
||||||
|
|
||||||
short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS];
|
short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS];
|
||||||
|
|
|
@ -11,17 +11,13 @@
|
||||||
class SoundStream
|
class SoundStream
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
CMixer* m_mixer;
|
CMixer* m_mixer;
|
||||||
// We set this to shut down the sound thread.
|
|
||||||
// 0=keep playing, 1=stop playing NOW.
|
|
||||||
volatile int threadData;
|
|
||||||
bool m_logAudio;
|
bool m_logAudio;
|
||||||
WaveFileWriter g_wave_writer;
|
WaveFileWriter g_wave_writer;
|
||||||
bool m_muted;
|
bool m_muted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SoundStream(CMixer* mixer) : m_mixer(mixer), threadData(0), m_logAudio(false), m_muted(false) {}
|
SoundStream(CMixer* mixer) : m_mixer(mixer), m_logAudio(false), m_muted(false) {}
|
||||||
virtual ~SoundStream() { delete m_mixer; }
|
virtual ~SoundStream() { delete m_mixer; }
|
||||||
|
|
||||||
static bool isValid() { return false; }
|
static bool isValid() { return false; }
|
||||||
|
|
Loading…
Reference in New Issue