|
|
|
@ -1,6 +1,6 @@ |
|
|
|
|
/*
|
|
|
|
|
+-------------------------------------------------------------+ |
|
|
|
|
| OneLoneCoder Sound Wave Engine v0.01 | |
|
|
|
|
| OneLoneCoder Sound Wave Engine v0.02 | |
|
|
|
|
| "You wanted noise? Well is this loud enough?" - javidx9 | |
|
|
|
|
+-------------------------------------------------------------+ |
|
|
|
|
|
|
|
|
@ -64,39 +64,73 @@ |
|
|
|
|
Homepage: https://www.onelonecoder.com
|
|
|
|
|
Patreon: https://www.patreon.com/javidx9
|
|
|
|
|
|
|
|
|
|
Compiling in Linux |
|
|
|
|
~~~~~~~~~~~~~~~~~~ |
|
|
|
|
When compiling, you will need to include ALSA to your list of library flags. |
|
|
|
|
Add: -lasound |
|
|
|
|
Thanks |
|
|
|
|
~~~~~~ |
|
|
|
|
Gorbit99, Dragoneye, Puol |
|
|
|
|
|
|
|
|
|
Your command should look something like: |
|
|
|
|
Authors |
|
|
|
|
~~~~~~~ |
|
|
|
|
slavka, MaGetzUb, cstd, Moros1138 & javidx9 |
|
|
|
|
|
|
|
|
|
g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng -lstdc++fs -lasound -std=c++17 |
|
|
|
|
(c)OneLoneCoder 2019, 2020, 2021, 2022 |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Compiling with Emscripten |
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
|
When compiling with Emscripten, you will include SDL mixer in your setting flags: |
|
|
|
|
Add: -s USE_SDL_MIXER=2
|
|
|
|
|
/*
|
|
|
|
|
Using & Installing On Microsoft Windows |
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
|
|
|
|
|
|
Microsoft Visual Studio |
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
|
1) Include the header file "olcSoundWaveEngine.h" from a .cpp file in your project. |
|
|
|
|
2) That's it! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Code::Blocks |
|
|
|
|
~~~~~~~~~~~~ |
|
|
|
|
1) Make sure your compiler toolchain is NOT the default one installed with Code::Blocks. That |
|
|
|
|
one is old, out of date, and a general mess. Instead, use MSYS2 to install a recent and |
|
|
|
|
decent GCC toolchain, then configure Code::Blocks to use it |
|
|
|
|
|
|
|
|
|
Guide for installing recent GCC for Windows: |
|
|
|
|
https://www.msys2.org/
|
|
|
|
|
Guide for configuring code::blocks: |
|
|
|
|
https://solarianprogrammer.com/2019/11/05/install-gcc-windows/
|
|
|
|
|
https://solarianprogrammer.com/2019/11/16/install-codeblocks-gcc-windows-build-c-cpp-fortran-programs/
|
|
|
|
|
|
|
|
|
|
2) Include the header file "olcSoundWaveEngine.h" from a .cpp file in your project. |
|
|
|
|
3) Add these libraries to "Linker Options": user32 winmm |
|
|
|
|
4) Set this "Compiler Option": -std=c++17 |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
Your command should look something like: |
|
|
|
|
/*
|
|
|
|
|
Using & Installing On Linux |
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
|
|
|
|
|
|
em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 ./YourSource.cpp -o pge.html |
|
|
|
|
GNU Compiler Collection (GCC) |
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
|
1) Include the header file "olcSoundWaveEngine.h" from a .cpp file in your project. |
|
|
|
|
2) Build with the following command: |
|
|
|
|
|
|
|
|
|
Thanks |
|
|
|
|
~~~~~~ |
|
|
|
|
Slavka - OpenAL and ALSA |
|
|
|
|
MaGetzUb - XAudio |
|
|
|
|
Gorbit99 - Testing, Bug Fixes |
|
|
|
|
Cyberdroid - Testing, Bug Fixes |
|
|
|
|
Dragoneye - Testing |
|
|
|
|
Puol - Testing |
|
|
|
|
|
|
|
|
|
Author |
|
|
|
|
~~~~~~ |
|
|
|
|
David Barr, aka javidx9, <EFBFBD>OneLoneCoder 2019, 2020, 2021, 2022 |
|
|
|
|
g++ olcSoundWaveEngineExample.cpp -o olcSoundWaveEngineExample -lpulse -lpulse-simple -std=c++17 |
|
|
|
|
|
|
|
|
|
3) That's it! |
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Using in multiple-file projects |
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
|
If you intend to use olcSoundWaveEngine across multiple files, it's important to only have one |
|
|
|
|
instance of the implementation. This is done using the compiler preprocessor definition: OLC_SOUNDWAVE |
|
|
|
|
|
|
|
|
|
This is defined typically before the header is included in teh translation unit you wish the implementation |
|
|
|
|
to be associated with. To avoid things getting messy I recommend you create a file "olcSoundWaveEngine.cpp"
|
|
|
|
|
and that file includes ONLY the following code: |
|
|
|
|
|
|
|
|
|
#define OLC_SOUNDWAVE |
|
|
|
|
#include "olcSoundWaveEngine.h" |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
0.01: olcPGEX_Sound.h reworked |
|
|
|
@ -107,6 +141,15 @@ |
|
|
|
|
+Loading form WAV files |
|
|
|
|
+LERPed sampling from all buffers |
|
|
|
|
+Multi-channel audio support |
|
|
|
|
0.02: +Support multi-channel wave files |
|
|
|
|
+Support for 24-bit wave files |
|
|
|
|
+Wave files are now sample rate invariant |
|
|
|
|
+Linux PulseAudio Updated |
|
|
|
|
+Linux ALSA Updated |
|
|
|
|
+WinMM Updated |
|
|
|
|
+CMake Compatibility |
|
|
|
|
=Fix wave format durations preventing playback |
|
|
|
|
=Various bug fixes |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
@ -131,13 +174,14 @@ |
|
|
|
|
// Compiler/System Sensitivity
|
|
|
|
|
#if !defined(SOUNDWAVE_USING_WINMM) && !defined(SOUNDWAVE_USING_WASAPI) && \ |
|
|
|
|
!defined(SOUNDWAVE_USING_XAUDIO) && !defined(SOUNDWAVE_USING_OPENAL) && \
|
|
|
|
|
!defined(SOUNDWAVE_USING_ALSA) && !defined(SOUNDWAVE_USING_SDLMIXER) \
|
|
|
|
|
!defined(SOUNDWAVE_USING_ALSA) && !defined(SOUNDWAVE_USING_SDLMIXER) && \
|
|
|
|
|
!defined(SOUNDWAVE_USING_PULSE) \
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32) |
|
|
|
|
#define SOUNDWAVE_USING_WINMM |
|
|
|
|
#endif |
|
|
|
|
#if defined(__linux__) |
|
|
|
|
#define SOUNDWAVE_USING_ALSA |
|
|
|
|
#define SOUNDWAVE_USING_PULSE |
|
|
|
|
#endif |
|
|
|
|
#if defined(__APPLE__) |
|
|
|
|
#define SOUNDWAVE_USING_SDLMIXER |
|
|
|
@ -167,6 +211,8 @@ namespace olc::sound |
|
|
|
|
m_nSampleSize = nSampleSize; |
|
|
|
|
m_nSamples = nSamples; |
|
|
|
|
m_nSampleRate = nSampleRate; |
|
|
|
|
m_dDuration = double(m_nSamples) / double(m_nSampleRate); |
|
|
|
|
m_dDurationInSamples = double(m_nSamples); |
|
|
|
|
|
|
|
|
|
m_pRawData = std::make_unique<T[]>(m_nSamples * m_nChannels); |
|
|
|
|
} |
|
|
|
@ -287,6 +333,15 @@ namespace olc::sound |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 3: // 24-bit
|
|
|
|
|
{ |
|
|
|
|
int32_t s = 0; |
|
|
|
|
ifs.read((char*)&s, 3); |
|
|
|
|
if (s & (1 << 23)) s |= 0xFF000000; |
|
|
|
|
*pSample = T(s) / T(std::pow(2, 23)-1); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 4: |
|
|
|
|
{ |
|
|
|
|
int32_t s = 0; |
|
|
|
@ -722,7 +777,11 @@ namespace olc::sound::driver |
|
|
|
|
|
|
|
|
|
#if defined(SOUNDWAVE_USING_SDLMIXER) |
|
|
|
|
|
|
|
|
|
#if defined(__EMSCRIPTEN__) |
|
|
|
|
#include <SDL2/SDL_mixer.h> |
|
|
|
|
#else |
|
|
|
|
#include <SDL_mixer.h> |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
namespace olc::sound::driver |
|
|
|
|
{ |
|
|
|
@ -767,8 +826,12 @@ namespace olc::sound::driver |
|
|
|
|
class RingBuffer |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
RingBuffer(unsigned int bufnum, unsigned int buflen): m_vBuffers(bufnum) |
|
|
|
|
RingBuffer() |
|
|
|
|
{ } |
|
|
|
|
|
|
|
|
|
void Resize(unsigned int bufnum = 0, unsigned int buflen = 0) |
|
|
|
|
{ |
|
|
|
|
m_vBuffers.resize(bufnum); |
|
|
|
|
for (auto &vBuffer : m_vBuffers) |
|
|
|
|
vBuffer.resize(buflen); |
|
|
|
|
} |
|
|
|
@ -835,6 +898,33 @@ namespace olc::sound::driver |
|
|
|
|
} |
|
|
|
|
#endif // SOUNDWAVE_USING_ALSA
|
|
|
|
|
|
|
|
|
|
#if defined(SOUNDWAVE_USING_PULSE) |
|
|
|
|
#include <pulse/simple.h> |
|
|
|
|
|
|
|
|
|
namespace olc::sound::driver |
|
|
|
|
{ |
|
|
|
|
class PulseAudio : public Base |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
PulseAudio(WaveEngine* pHost); |
|
|
|
|
~PulseAudio(); |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
bool Open(const std::string& sOutputDevice, const std::string& sInputDevice) override; |
|
|
|
|
bool Start() override; |
|
|
|
|
void Stop() override; |
|
|
|
|
void Close() override; |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
void DriverLoop(); |
|
|
|
|
|
|
|
|
|
pa_simple *m_pPA; |
|
|
|
|
std::atomic<bool> m_bDriverLoopActive{ false }; |
|
|
|
|
std::thread m_thDriverLoop; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
#endif // SOUNDWAVE_USING_PULSE
|
|
|
|
|
|
|
|
|
|
#ifdef OLC_SOUNDWAVE |
|
|
|
|
#undef OLC_SOUNDWAVE |
|
|
|
|
|
|
|
|
@ -868,6 +958,10 @@ namespace olc::sound |
|
|
|
|
#if defined(SOUNDWAVE_USING_SDLMIXER) |
|
|
|
|
m_driver = std::make_unique<driver::SDLMixer>(this); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if defined(SOUNDWAVE_USING_PULSE) |
|
|
|
|
m_driver = std::make_unique<driver::PulseAudio>(this); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
WaveEngine::~WaveEngine() |
|
|
|
@ -938,8 +1032,8 @@ namespace olc::sound |
|
|
|
|
WaveInstance wi; |
|
|
|
|
wi.bLoop = bLoop; |
|
|
|
|
wi.pWave = pWave; |
|
|
|
|
wi.dSpeedModifier = dSpeed; |
|
|
|
|
wi.dDuration = double(pWave->file.samples()) / double(pWave->file.samplerate()) / wi.dSpeedModifier; |
|
|
|
|
wi.dSpeedModifier = dSpeed * double(pWave->file.samplerate()) / m_dSamplePerTime; |
|
|
|
|
wi.dDuration = pWave->file.duration() / dSpeed; |
|
|
|
|
wi.dInstanceTime = m_dGlobalTime; |
|
|
|
|
m_listWaves.push_back(wi); |
|
|
|
|
return std::prev(m_listWaves.end()); |
|
|
|
@ -1006,8 +1100,8 @@ namespace olc::sound |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// OR, sample the waveform form the correct channel
|
|
|
|
|
fSample += float(wave.pWave->vChannelView[nChannel].GetSample(dTimeOffset * m_dSamplePerTime * wave.dSpeedModifier)); |
|
|
|
|
// OR, sample the waveform from the correct channel
|
|
|
|
|
fSample += float(wave.pWave->vChannelView[nChannel % wave.pWave->file.channels()].GetSample(dTimeOffset * m_dSamplePerTime * wave.dSpeedModifier)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1288,9 +1382,9 @@ namespace olc::sound |
|
|
|
|
random_seed += 0xe120fc15; |
|
|
|
|
uint64_t tmp; |
|
|
|
|
tmp = (uint64_t)random_seed * 0x4a39b70d; |
|
|
|
|
uint32_t m1 = (tmp >> 32) ^ tmp; |
|
|
|
|
uint32_t m1 = uint32_t(((tmp >> 32) ^ tmp) & 0xFFFFFFFF); |
|
|
|
|
tmp = (uint64_t)m1 * 0x12fad5c9; |
|
|
|
|
uint32_t m2 = (tmp >> 32) ^ tmp; |
|
|
|
|
uint32_t m2 = uint32_t(((tmp >> 32) ^ tmp) & 0xFFFFFFFF); |
|
|
|
|
return m2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1490,15 +1584,15 @@ bool SDLMixer::Open(const std::string& sOutputDevice, const std::string& sInputD |
|
|
|
|
{ |
|
|
|
|
case AUDIO_F32: |
|
|
|
|
case AUDIO_S32: |
|
|
|
|
bufferSize = m_pHost->GetBlockSampleCount() * 4; |
|
|
|
|
bufferSize = m_pHost->GetBlockSampleCount() * m_pHost->GetChannels() * 4; |
|
|
|
|
break; |
|
|
|
|
case AUDIO_S16: |
|
|
|
|
case AUDIO_U16: |
|
|
|
|
bufferSize = m_pHost->GetBlockSampleCount() * 2; |
|
|
|
|
bufferSize = m_pHost->GetBlockSampleCount() * m_pHost->GetChannels() * 2; |
|
|
|
|
break; |
|
|
|
|
case AUDIO_S8: |
|
|
|
|
case AUDIO_U8: |
|
|
|
|
bufferSize = m_pHost->GetBlockSampleCount() * 1; |
|
|
|
|
bufferSize = m_pHost->GetBlockSampleCount() * m_pHost->GetChannels() * 1; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
std::cerr << "Audio format of device '" << sOutputDevice << "' is not supported" << std::endl; |
|
|
|
@ -1557,7 +1651,12 @@ void SDLMixer::FillChunkBuffer(const std::vector<float>& userData) const |
|
|
|
|
|
|
|
|
|
void SDLMixer::SDLMixerCallback(int channel) |
|
|
|
|
{ |
|
|
|
|
static std::vector<float> userData(instance->m_pHost->GetBlockSampleCount()); |
|
|
|
|
static std::vector<float> userData(instance->m_pHost->GetBlockSampleCount() * instance->m_pHost->GetChannels()); |
|
|
|
|
|
|
|
|
|
if (channel != 0) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "Unexpected channel number" << std::endl; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Don't add another chunk if we should not keep running
|
|
|
|
|
if (!instance->m_keepRunning) |
|
|
|
@ -1566,7 +1665,7 @@ void SDLMixer::SDLMixerCallback(int channel) |
|
|
|
|
instance->GetFullOutputBlock(userData); |
|
|
|
|
instance->FillChunkBuffer(userData); |
|
|
|
|
|
|
|
|
|
if (Mix_PlayChannel(channel, &instance->audioChunk, 0) == -1) |
|
|
|
|
if (Mix_PlayChannel(0, &instance->audioChunk, 0) == -1) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "Error while playing Chunk" << std::endl; |
|
|
|
|
} |
|
|
|
@ -1610,7 +1709,7 @@ void SDLMixer::Close() |
|
|
|
|
// ALSA Driver Implementation
|
|
|
|
|
namespace olc::sound::driver |
|
|
|
|
{ |
|
|
|
|
ALSA::ALSA(WaveEngine* pHost) : Base(pHost), m_rBuffers(pHost->GetBlocks(), pHost->GetBlockSampleCount()) |
|
|
|
|
ALSA::ALSA(WaveEngine* pHost) : Base(pHost) |
|
|
|
|
{ } |
|
|
|
|
|
|
|
|
|
ALSA::~ALSA() |
|
|
|
@ -1644,7 +1743,7 @@ namespace olc::sound::driver |
|
|
|
|
snd_pcm_hw_params_set_format(m_pPCM, params, SND_PCM_FORMAT_FLOAT); |
|
|
|
|
snd_pcm_hw_params_set_rate(m_pPCM, params, m_pHost->GetSampleRate(), 0); |
|
|
|
|
snd_pcm_hw_params_set_channels(m_pPCM, params, m_pHost->GetChannels()); |
|
|
|
|
snd_pcm_hw_params_set_period_size(m_pPCM, params, m_pHost->GetBlockSampleCount() / m_pHost->GetChannels(), 0); |
|
|
|
|
snd_pcm_hw_params_set_period_size(m_pPCM, params, m_pHost->GetBlockSampleCount(), 0); |
|
|
|
|
snd_pcm_hw_params_set_periods(m_pPCM, params, m_pHost->GetBlocks(), 0); |
|
|
|
|
|
|
|
|
|
// Save these parameters
|
|
|
|
@ -1658,10 +1757,12 @@ namespace olc::sound::driver |
|
|
|
|
bool ALSA::Start() |
|
|
|
|
{ |
|
|
|
|
// Unsure if really needed, helped prevent underrun on my setup
|
|
|
|
|
std::vector<float> vSilence(m_pHost->GetBlockSampleCount(), 0.0f); |
|
|
|
|
std::vector<float> vSilence(m_pHost->GetBlockSampleCount() * m_pHost->GetChannels(), 0.0f); |
|
|
|
|
snd_pcm_start(m_pPCM); |
|
|
|
|
for (unsigned int i = 0; i < m_pHost->GetBlocks(); i++) |
|
|
|
|
snd_pcm_writei(m_pPCM, vSilence.data(), m_pHost->GetBlockSampleCount() / m_pHost->GetChannels()); |
|
|
|
|
snd_pcm_writei(m_pPCM, vSilence.data(), m_pHost->GetBlockSampleCount()); |
|
|
|
|
|
|
|
|
|
m_rBuffers.Resize(m_pHost->GetBlocks(), m_pHost->GetBlockSampleCount() * m_pHost->GetChannels()); |
|
|
|
|
|
|
|
|
|
snd_pcm_start(m_pPCM); |
|
|
|
|
m_bDriverLoopActive = true; |
|
|
|
@ -1679,7 +1780,8 @@ namespace olc::sound::driver |
|
|
|
|
if (m_thDriverLoop.joinable()) |
|
|
|
|
m_thDriverLoop.join(); |
|
|
|
|
|
|
|
|
|
snd_pcm_drop(m_pPCM); |
|
|
|
|
if (m_pPCM != nullptr) |
|
|
|
|
snd_pcm_drop(m_pPCM); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ALSA::Close() |
|
|
|
@ -1695,7 +1797,7 @@ namespace olc::sound::driver |
|
|
|
|
|
|
|
|
|
void ALSA::DriverLoop() |
|
|
|
|
{ |
|
|
|
|
const uint32_t nFrames = m_pHost->GetBlockSampleCount() / m_pHost->GetChannels(); |
|
|
|
|
const uint32_t nFrames = m_pHost->GetBlockSampleCount(); |
|
|
|
|
|
|
|
|
|
int err; |
|
|
|
|
std::vector<pollfd> vFDs; |
|
|
|
@ -1774,6 +1876,87 @@ namespace olc::sound::driver |
|
|
|
|
} |
|
|
|
|
} // ALSA Driver Implementation
|
|
|
|
|
#endif |
|
|
|
|
#if defined(SOUNDWAVE_USING_PULSE) |
|
|
|
|
// PULSE Driver Implementation
|
|
|
|
|
#include <pulse/error.h> |
|
|
|
|
#include <iostream> |
|
|
|
|
|
|
|
|
|
namespace olc::sound::driver |
|
|
|
|
{ |
|
|
|
|
PulseAudio::PulseAudio(WaveEngine* pHost) : Base(pHost) |
|
|
|
|
{ } |
|
|
|
|
|
|
|
|
|
PulseAudio::~PulseAudio() |
|
|
|
|
{ |
|
|
|
|
Stop(); |
|
|
|
|
Close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool PulseAudio::Open(const std::string& sOutputDevice, const std::string& sInputDevice) |
|
|
|
|
{ |
|
|
|
|
pa_sample_spec ss { |
|
|
|
|
PA_SAMPLE_FLOAT32, m_pHost->GetSampleRate(), (uint8_t)m_pHost->GetChannels() |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
m_pPA = pa_simple_new(NULL, "olcSoundWaveEngine", PA_STREAM_PLAYBACK, NULL, |
|
|
|
|
"Output Stream", &ss, NULL, NULL, NULL); |
|
|
|
|
|
|
|
|
|
if (m_pPA == NULL) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool PulseAudio::Start() |
|
|
|
|
{ |
|
|
|
|
m_bDriverLoopActive = true; |
|
|
|
|
m_thDriverLoop = std::thread(&PulseAudio::DriverLoop, this); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PulseAudio::Stop() |
|
|
|
|
{ |
|
|
|
|
// Signal the driver loop to exit
|
|
|
|
|
m_bDriverLoopActive = false; |
|
|
|
|
|
|
|
|
|
// Wait for driver thread to exit gracefully
|
|
|
|
|
if (m_thDriverLoop.joinable()) |
|
|
|
|
m_thDriverLoop.join(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PulseAudio::Close() |
|
|
|
|
{ |
|
|
|
|
if (m_pPA != nullptr) |
|
|
|
|
{ |
|
|
|
|
pa_simple_free(m_pPA); |
|
|
|
|
m_pPA = nullptr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PulseAudio::DriverLoop() |
|
|
|
|
{ |
|
|
|
|
// We will be using this vector to transfer to the host for filling, with
|
|
|
|
|
// user sound data (float32, -1.0 --> +1.0)
|
|
|
|
|
std::vector<float> vFloatBuffer(m_pHost->GetBlockSampleCount() * m_pHost->GetChannels(), 0.0f); |
|
|
|
|
|
|
|
|
|
// While the system is active, start requesting audio data
|
|
|
|
|
while (m_bDriverLoopActive) |
|
|
|
|
{ |
|
|
|
|
// Grab audio data from user
|
|
|
|
|
GetFullOutputBlock(vFloatBuffer); |
|
|
|
|
|
|
|
|
|
// Fill PulseAudio data buffer
|
|
|
|
|
int error; |
|
|
|
|
if (pa_simple_write(m_pPA, vFloatBuffer.data(), |
|
|
|
|
vFloatBuffer.size() * sizeof(float), &error) < 0) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "Failed to feed data to PulseAudio: " << pa_strerror(error) << "\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} // PulseAudio Driver Implementation
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#endif // OLC_SOUNDWAVE IMPLEMENTATION
|
|
|
|
|
#endif // OLC_SOUNDWAVE_H
|
|
|
|
|