No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

olcPGEX_Sound.cpp 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. #include "olcPGEX_Sound.h"
  2. namespace olc
  3. {
  4. SOUND::AudioSample::AudioSample()
  5. { }
  6. SOUND::AudioSample::AudioSample(std::string sWavFile, olc::ResourcePack *pack)
  7. {
  8. LoadFromFile(sWavFile, pack);
  9. }
  10. olc::rcode SOUND::AudioSample::LoadFromFile(std::string sWavFile, olc::ResourcePack *pack)
  11. {
  12. auto ReadWave = [&](std::istream &is)
  13. {
  14. char dump[4];
  15. is.read(dump, sizeof(char) * 4); // Read "RIFF"
  16. if (strncmp(dump, "RIFF", 4) != 0) return olc::FAIL;
  17. is.read(dump, sizeof(char) * 4); // Not Interested
  18. is.read(dump, sizeof(char) * 4); // Read "WAVE"
  19. if (strncmp(dump, "WAVE", 4) != 0) return olc::FAIL;
  20. // Read Wave description chunk
  21. is.read(dump, sizeof(char) * 4); // Read "fmt "
  22. unsigned int nHeaderSize = 0;
  23. is.read((char*)&nHeaderSize, sizeof(unsigned int)); // Not Interested
  24. is.read((char*)&wavHeader, nHeaderSize);// sizeof(WAVEFORMATEX)); // Read Wave Format Structure chunk
  25. // Note the -2, because the structure has 2 bytes to indicate its own size
  26. // which are not in the wav file
  27. // Just check if wave format is compatible with olcPGE
  28. if (wavHeader.wBitsPerSample != 16 || wavHeader.nSamplesPerSec != 44100)
  29. return olc::FAIL;
  30. // Search for audio data chunk
  31. uint32_t nChunksize = 0;
  32. is.read(dump, sizeof(char) * 4); // Read chunk header
  33. is.read((char*)&nChunksize, sizeof(uint32_t)); // Read chunk size
  34. while (strncmp(dump, "data", 4) != 0)
  35. {
  36. // Not audio data, so just skip it
  37. //std::fseek(f, nChunksize, SEEK_CUR);
  38. is.seekg(nChunksize, std::istream::cur);
  39. is.read(dump, sizeof(char) * 4);
  40. is.read((char*)&nChunksize, sizeof(uint32_t));
  41. }
  42. // Finally got to data, so read it all in and convert to float samples
  43. nSamples = nChunksize / (wavHeader.nChannels * (wavHeader.wBitsPerSample >> 3));
  44. nChannels = wavHeader.nChannels;
  45. // Create floating point buffer to hold audio sample
  46. fSample = new float[nSamples * nChannels];
  47. float *pSample = fSample;
  48. // Read in audio data and normalise
  49. for (long i = 0; i < nSamples; i++)
  50. {
  51. for (int c = 0; c < nChannels; c++)
  52. {
  53. short s = 0;
  54. if (!is.eof())
  55. {
  56. is.read((char*)&s, sizeof(short));
  57. *pSample = (float)s / (float)(SHRT_MAX);
  58. pSample++;
  59. }
  60. }
  61. }
  62. // All done, flag sound as valid
  63. bSampleValid = true;
  64. return olc::OK;
  65. };
  66. if (pack != nullptr)
  67. {
  68. olc::ResourcePack::sEntry entry = pack->GetStreamBuffer(sWavFile);
  69. std::istream is(&entry);
  70. return ReadWave(is);
  71. }
  72. else
  73. {
  74. // Read from file
  75. std::ifstream ifs(sWavFile, std::ifstream::binary);
  76. if (ifs.is_open())
  77. {
  78. return ReadWave(ifs);
  79. }
  80. else
  81. return olc::FAIL;
  82. }
  83. }
  84. // This vector holds all loaded sound samples in memory
  85. std::vector<olc::SOUND::AudioSample> vecAudioSamples;
  86. // This structure represents a sound that is currently playing. It only
  87. // holds the sound ID and where this instance of it is up to for its
  88. // current playback
  89. void SOUND::SetUserSynthFunction(std::function<float(int, float, float)> func)
  90. {
  91. funcUserSynth = func;
  92. }
  93. void SOUND::SetUserFilterFunction(std::function<float(int, float, float)> func)
  94. {
  95. funcUserFilter = func;
  96. }
  97. // Load a 16-bit WAVE file @ 44100Hz ONLY into memory. A sample ID
  98. // number is returned if successful, otherwise -1
  99. int SOUND::LoadAudioSample(std::string sWavFile, olc::ResourcePack *pack)
  100. {
  101. olc::SOUND::AudioSample a(sWavFile, pack);
  102. if (a.bSampleValid)
  103. {
  104. vecAudioSamples.push_back(a);
  105. return (unsigned int)vecAudioSamples.size();
  106. }
  107. else
  108. return -1;
  109. }
  110. // Add sample 'id' to the mixers sounds to play list
  111. void SOUND::PlaySample(int id, bool bLoop)
  112. {
  113. olc::SOUND::sCurrentlyPlayingSample a;
  114. a.nAudioSampleID = id;
  115. a.nSamplePosition = 0;
  116. a.bFinished = false;
  117. a.bFlagForStop = false;
  118. a.bLoop = bLoop;
  119. SOUND::listActiveSamples.push_back(a);
  120. }
  121. void SOUND::StopSample(int id)
  122. {
  123. // Find first occurence of sample id
  124. auto s = std::find_if(listActiveSamples.begin(), listActiveSamples.end(), [&](const olc::SOUND::sCurrentlyPlayingSample &s) { return s.nAudioSampleID == id; });
  125. if (s != listActiveSamples.end())
  126. s->bFlagForStop = true;
  127. }
  128. void SOUND::StopAll()
  129. {
  130. for (auto &s : listActiveSamples)
  131. {
  132. s.bFlagForStop = true;
  133. }
  134. }
  135. float SOUND::GetMixerOutput(int nChannel, float fGlobalTime, float fTimeStep)
  136. {
  137. // Accumulate sample for this channel
  138. float fMixerSample = 0.0f;
  139. for (auto &s : listActiveSamples)
  140. {
  141. if (m_bAudioThreadActive)
  142. {
  143. if (s.bFlagForStop)
  144. {
  145. s.bLoop = false;
  146. s.bFinished = true;
  147. }
  148. else
  149. {
  150. // Calculate sample position
  151. s.nSamplePosition += roundf((float)vecAudioSamples[s.nAudioSampleID - 1].wavHeader.nSamplesPerSec * fTimeStep);
  152. // If sample position is valid add to the mix
  153. if (s.nSamplePosition < vecAudioSamples[s.nAudioSampleID - 1].nSamples)
  154. fMixerSample += vecAudioSamples[s.nAudioSampleID - 1].fSample[(s.nSamplePosition * vecAudioSamples[s.nAudioSampleID - 1].nChannels) + nChannel];
  155. else
  156. {
  157. if (s.bLoop)
  158. {
  159. s.nSamplePosition = 0;
  160. }
  161. else
  162. s.bFinished = true; // Else sound has completed
  163. }
  164. }
  165. }
  166. else
  167. return 0.0f;
  168. }
  169. // If sounds have completed then remove them
  170. listActiveSamples.remove_if([](const sCurrentlyPlayingSample &s) {return s.bFinished; });
  171. // The users application might be generating sound, so grab that if it exists
  172. if (funcUserSynth != nullptr)
  173. fMixerSample += funcUserSynth(nChannel, fGlobalTime, fTimeStep);
  174. // Return the sample via an optional user override to filter the sound
  175. if (funcUserFilter != nullptr)
  176. return funcUserFilter(nChannel, fGlobalTime, fMixerSample);
  177. else
  178. return fMixerSample;
  179. }
  180. std::thread SOUND::m_AudioThread;
  181. std::atomic<bool> SOUND::m_bAudioThreadActive{ false };
  182. std::atomic<float> SOUND::m_fGlobalTime{ 0.0f };
  183. std::list<SOUND::sCurrentlyPlayingSample> SOUND::listActiveSamples;
  184. std::function<float(int, float, float)> SOUND::funcUserSynth = nullptr;
  185. std::function<float(int, float, float)> SOUND::funcUserFilter = nullptr;
  186. }
  187. // Implementation, Windows-specific
  188. #ifdef USE_WINDOWS
  189. #ifndef __MINGW32__
  190. #pragma comment(lib, "winmm.lib")
  191. #endif
  192. namespace olc
  193. {
  194. bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples)
  195. {
  196. // Initialise Sound Engine
  197. m_bAudioThreadActive = false;
  198. m_nSampleRate = nSampleRate;
  199. m_nChannels = nChannels;
  200. m_nBlockCount = nBlocks;
  201. m_nBlockSamples = nBlockSamples;
  202. m_nBlockFree = m_nBlockCount;
  203. m_nBlockCurrent = 0;
  204. m_pBlockMemory = nullptr;
  205. m_pWaveHeaders = nullptr;
  206. // Device is available
  207. WAVEFORMATEX waveFormat;
  208. waveFormat.wFormatTag = WAVE_FORMAT_PCM;
  209. waveFormat.nSamplesPerSec = m_nSampleRate;
  210. waveFormat.wBitsPerSample = sizeof(short) * 8;
  211. waveFormat.nChannels = m_nChannels;
  212. waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
  213. waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
  214. waveFormat.cbSize = 0;
  215. listActiveSamples.clear();
  216. // Open Device if valid
  217. if (waveOutOpen(&m_hwDevice, WAVE_MAPPER, &waveFormat, (DWORD_PTR)SOUND::waveOutProc, (DWORD_PTR)0, CALLBACK_FUNCTION) != S_OK)
  218. return DestroyAudio();
  219. // Allocate Wave|Block Memory
  220. m_pBlockMemory = new short[m_nBlockCount * m_nBlockSamples];
  221. if (m_pBlockMemory == nullptr)
  222. return DestroyAudio();
  223. ZeroMemory(m_pBlockMemory, sizeof(short) * m_nBlockCount * m_nBlockSamples);
  224. m_pWaveHeaders = new WAVEHDR[m_nBlockCount];
  225. if (m_pWaveHeaders == nullptr)
  226. return DestroyAudio();
  227. ZeroMemory(m_pWaveHeaders, sizeof(WAVEHDR) * m_nBlockCount);
  228. // Link headers to block memory
  229. for (unsigned int n = 0; n < m_nBlockCount; n++)
  230. {
  231. m_pWaveHeaders[n].dwBufferLength = m_nBlockSamples * sizeof(short);
  232. m_pWaveHeaders[n].lpData = (LPSTR)(m_pBlockMemory + (n * m_nBlockSamples));
  233. }
  234. m_bAudioThreadActive = true;
  235. m_AudioThread = std::thread(&SOUND::AudioThread);
  236. // Start the ball rolling with the sound delivery thread
  237. std::unique_lock<std::mutex> lm(m_muxBlockNotZero);
  238. m_cvBlockNotZero.notify_one();
  239. return true;
  240. }
  241. // Stop and clean up audio system
  242. bool SOUND::DestroyAudio()
  243. {
  244. m_bAudioThreadActive = false;
  245. m_AudioThread.join();
  246. return false;
  247. }
  248. // Handler for soundcard request for more data
  249. void CALLBACK SOUND::waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD dwParam1, DWORD dwParam2)
  250. {
  251. if (uMsg != WOM_DONE) return;
  252. m_nBlockFree++;
  253. std::unique_lock<std::mutex> lm(m_muxBlockNotZero);
  254. m_cvBlockNotZero.notify_one();
  255. }
  256. // Audio thread. This loop responds to requests from the soundcard to fill 'blocks'
  257. // with audio data. If no requests are available it goes dormant until the sound
  258. // card is ready for more data. The block is fille by the "user" in some manner
  259. // and then issued to the soundcard.
  260. void SOUND::AudioThread()
  261. {
  262. m_fGlobalTime = 0.0f;
  263. static float fTimeStep = 1.0f / (float)m_nSampleRate;
  264. // Goofy hack to get maximum integer for a type at run-time
  265. short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1;
  266. float fMaxSample = (float)nMaxSample;
  267. while (m_bAudioThreadActive)
  268. {
  269. // Wait for block to become available
  270. if (m_nBlockFree == 0)
  271. {
  272. std::unique_lock<std::mutex> lm(m_muxBlockNotZero);
  273. while (m_nBlockFree == 0) // sometimes, Windows signals incorrectly
  274. m_cvBlockNotZero.wait(lm);
  275. }
  276. // Block is here, so use it
  277. m_nBlockFree--;
  278. // Prepare block for processing
  279. if (m_pWaveHeaders[m_nBlockCurrent].dwFlags & WHDR_PREPARED)
  280. waveOutUnprepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
  281. short nNewSample = 0;
  282. int nCurrentBlock = m_nBlockCurrent * m_nBlockSamples;
  283. auto clip = [](float fSample, float fMax)
  284. {
  285. if (fSample >= 0.0)
  286. return fmin(fSample, fMax);
  287. else
  288. return fmax(fSample, -fMax);
  289. };
  290. for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels)
  291. {
  292. // User Process
  293. for (unsigned int c = 0; c < m_nChannels; c++)
  294. {
  295. nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample);
  296. m_pBlockMemory[nCurrentBlock + n + c] = nNewSample;
  297. }
  298. m_fGlobalTime = m_fGlobalTime + fTimeStep;
  299. }
  300. // Send block to sound device
  301. waveOutPrepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
  302. waveOutWrite(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
  303. m_nBlockCurrent++;
  304. m_nBlockCurrent %= m_nBlockCount;
  305. }
  306. }
  307. unsigned int SOUND::m_nSampleRate = 0;
  308. unsigned int SOUND::m_nChannels = 0;
  309. unsigned int SOUND::m_nBlockCount = 0;
  310. unsigned int SOUND::m_nBlockSamples = 0;
  311. unsigned int SOUND::m_nBlockCurrent = 0;
  312. short* SOUND::m_pBlockMemory = nullptr;
  313. WAVEHDR *SOUND::m_pWaveHeaders = nullptr;
  314. HWAVEOUT SOUND::m_hwDevice;
  315. std::atomic<unsigned int> SOUND::m_nBlockFree = 0;
  316. std::condition_variable SOUND::m_cvBlockNotZero;
  317. std::mutex SOUND::m_muxBlockNotZero;
  318. }
  319. #elif defined(USE_ALSA)
  320. namespace olc
  321. {
  322. bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples)
  323. {
  324. // Initialise Sound Engine
  325. m_bAudioThreadActive = false;
  326. m_nSampleRate = nSampleRate;
  327. m_nChannels = nChannels;
  328. m_nBlockSamples = nBlockSamples;
  329. m_pBlockMemory = nullptr;
  330. // Open PCM stream
  331. int rc = snd_pcm_open(&m_pPCM, "default", SND_PCM_STREAM_PLAYBACK, 0);
  332. if (rc < 0)
  333. return DestroyAudio();
  334. // Prepare the parameter structure and set default parameters
  335. snd_pcm_hw_params_t *params;
  336. snd_pcm_hw_params_alloca(&params);
  337. snd_pcm_hw_params_any(m_pPCM, params);
  338. // Set other parameters
  339. snd_pcm_hw_params_set_format(m_pPCM, params, SND_PCM_FORMAT_S16_LE);
  340. snd_pcm_hw_params_set_rate(m_pPCM, params, m_nSampleRate, 0);
  341. snd_pcm_hw_params_set_channels(m_pPCM, params, m_nChannels);
  342. snd_pcm_hw_params_set_period_size(m_pPCM, params, m_nBlockSamples, 0);
  343. snd_pcm_hw_params_set_periods(m_pPCM, params, nBlocks, 0);
  344. // Save these parameters
  345. rc = snd_pcm_hw_params(m_pPCM, params);
  346. if (rc < 0)
  347. return DestroyAudio();
  348. listActiveSamples.clear();
  349. // Allocate Wave|Block Memory
  350. m_pBlockMemory = new short[m_nBlockSamples];
  351. if (m_pBlockMemory == nullptr)
  352. return DestroyAudio();
  353. std::fill(m_pBlockMemory, m_pBlockMemory + m_nBlockSamples, 0);
  354. // Unsure if really needed, helped prevent underrun on my setup
  355. snd_pcm_start(m_pPCM);
  356. for (unsigned int i = 0; i < nBlocks; i++)
  357. rc = snd_pcm_writei(m_pPCM, m_pBlockMemory, 512);
  358. snd_pcm_start(m_pPCM);
  359. m_bAudioThreadActive = true;
  360. m_AudioThread = std::thread(&SOUND::AudioThread);
  361. return true;
  362. }
  363. // Stop and clean up audio system
  364. bool SOUND::DestroyAudio()
  365. {
  366. m_bAudioThreadActive = false;
  367. m_AudioThread.join();
  368. snd_pcm_drain(m_pPCM);
  369. snd_pcm_close(m_pPCM);
  370. return false;
  371. }
  372. // Audio thread. This loop responds to requests from the soundcard to fill 'blocks'
  373. // with audio data. If no requests are available it goes dormant until the sound
  374. // card is ready for more data. The block is fille by the "user" in some manner
  375. // and then issued to the soundcard.
  376. void SOUND::AudioThread()
  377. {
  378. m_fGlobalTime = 0.0f;
  379. static float fTimeStep = 1.0f / (float)m_nSampleRate;
  380. // Goofy hack to get maximum integer for a type at run-time
  381. short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1;
  382. float fMaxSample = (float)nMaxSample;
  383. while (m_bAudioThreadActive)
  384. {
  385. short nNewSample = 0;
  386. auto clip = [](float fSample, float fMax)
  387. {
  388. if (fSample >= 0.0)
  389. return fmin(fSample, fMax);
  390. else
  391. return fmax(fSample, -fMax);
  392. };
  393. for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels)
  394. {
  395. // User Process
  396. for (unsigned int c = 0; c < m_nChannels; c++)
  397. {
  398. nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample);
  399. m_pBlockMemory[n + c] = nNewSample;
  400. }
  401. m_fGlobalTime = m_fGlobalTime + fTimeStep;
  402. }
  403. // Send block to sound device
  404. snd_pcm_uframes_t nLeft = m_nBlockSamples;
  405. short *pBlockPos = m_pBlockMemory;
  406. while (nLeft > 0)
  407. {
  408. int rc = snd_pcm_writei(m_pPCM, pBlockPos, nLeft);
  409. if (rc > 0)
  410. {
  411. pBlockPos += rc * m_nChannels;
  412. nLeft -= rc;
  413. }
  414. if (rc == -EAGAIN) continue;
  415. if (rc == -EPIPE) // an underrun occured, prepare the device for more data
  416. snd_pcm_prepare(m_pPCM);
  417. }
  418. }
  419. }
  420. snd_pcm_t* SOUND::m_pPCM = nullptr;
  421. unsigned int SOUND::m_nSampleRate = 0;
  422. unsigned int SOUND::m_nChannels = 0;
  423. unsigned int SOUND::m_nBlockSamples = 0;
  424. short* SOUND::m_pBlockMemory = nullptr;
  425. }
  426. #elif defined(USE_OPENAL)
  427. namespace olc
  428. {
  429. bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples)
  430. {
  431. // Initialise Sound Engine
  432. m_bAudioThreadActive = false;
  433. m_nSampleRate = nSampleRate;
  434. m_nChannels = nChannels;
  435. m_nBlockCount = nBlocks;
  436. m_nBlockSamples = nBlockSamples;
  437. m_pBlockMemory = nullptr;
  438. // Open the device and create the context
  439. m_pDevice = alcOpenDevice(NULL);
  440. if (m_pDevice)
  441. {
  442. m_pContext = alcCreateContext(m_pDevice, NULL);
  443. alcMakeContextCurrent(m_pContext);
  444. }
  445. else
  446. return DestroyAudio();
  447. // Allocate memory for sound data
  448. alGetError();
  449. m_pBuffers = new ALuint[m_nBlockCount];
  450. alGenBuffers(m_nBlockCount, m_pBuffers);
  451. alGenSources(1, &m_nSource);
  452. for (unsigned int i = 0; i < m_nBlockCount; i++)
  453. m_qAvailableBuffers.push(m_pBuffers[i]);
  454. listActiveSamples.clear();
  455. // Allocate Wave|Block Memory
  456. m_pBlockMemory = new short[m_nBlockSamples];
  457. if (m_pBlockMemory == nullptr)
  458. return DestroyAudio();
  459. std::fill(m_pBlockMemory, m_pBlockMemory + m_nBlockSamples, 0);
  460. m_bAudioThreadActive = true;
  461. m_AudioThread = std::thread(&SOUND::AudioThread);
  462. return true;
  463. }
  464. // Stop and clean up audio system
  465. bool SOUND::DestroyAudio()
  466. {
  467. m_bAudioThreadActive = false;
  468. m_AudioThread.join();
  469. alDeleteBuffers(m_nBlockCount, m_pBuffers);
  470. delete[] m_pBuffers;
  471. alDeleteSources(1, &m_nSource);
  472. alcMakeContextCurrent(NULL);
  473. alcDestroyContext(m_pContext);
  474. alcCloseDevice(m_pDevice);
  475. return false;
  476. }
  477. // Audio thread. This loop responds to requests from the soundcard to fill 'blocks'
  478. // with audio data. If no requests are available it goes dormant until the sound
  479. // card is ready for more data. The block is fille by the "user" in some manner
  480. // and then issued to the soundcard.
  481. void SOUND::AudioThread()
  482. {
  483. m_fGlobalTime = 0.0f;
  484. static float fTimeStep = 1.0f / (float)m_nSampleRate;
  485. // Goofy hack to get maximum integer for a type at run-time
  486. short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1;
  487. float fMaxSample = (float)nMaxSample;
  488. short nPreviousSample = 0;
  489. std::vector<ALuint> vProcessed;
  490. while (m_bAudioThreadActive)
  491. {
  492. ALint nState, nProcessed;
  493. alGetSourcei(m_nSource, AL_SOURCE_STATE, &nState);
  494. alGetSourcei(m_nSource, AL_BUFFERS_PROCESSED, &nProcessed);
  495. // Add processed buffers to our queue
  496. vProcessed.resize(nProcessed);
  497. alSourceUnqueueBuffers(m_nSource, nProcessed, vProcessed.data());
  498. for (ALint nBuf : vProcessed) m_qAvailableBuffers.push(nBuf);
  499. // Wait until there is a free buffer (ewww)
  500. if (m_qAvailableBuffers.empty()) continue;
  501. short nNewSample = 0;
  502. auto clip = [](float fSample, float fMax)
  503. {
  504. if (fSample >= 0.0)
  505. return fmin(fSample, fMax);
  506. else
  507. return fmax(fSample, -fMax);
  508. };
  509. for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels)
  510. {
  511. // User Process
  512. for (unsigned int c = 0; c < m_nChannels; c++)
  513. {
  514. nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample);
  515. m_pBlockMemory[n + c] = nNewSample;
  516. nPreviousSample = nNewSample;
  517. }
  518. m_fGlobalTime = m_fGlobalTime + fTimeStep;
  519. }
  520. // Fill OpenAL data buffer
  521. alBufferData(
  522. m_qAvailableBuffers.front(),
  523. m_nChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
  524. m_pBlockMemory,
  525. 2 * m_nBlockSamples,
  526. m_nSampleRate
  527. );
  528. // Add it to the OpenAL queue
  529. alSourceQueueBuffers(m_nSource, 1, &m_qAvailableBuffers.front());
  530. // Remove it from ours
  531. m_qAvailableBuffers.pop();
  532. // If it's not playing for some reason, change that
  533. if (nState != AL_PLAYING)
  534. alSourcePlay(m_nSource);
  535. }
  536. }
  537. std::queue<ALuint> SOUND::m_qAvailableBuffers;
  538. ALuint *SOUND::m_pBuffers = nullptr;
  539. ALuint SOUND::m_nSource = 0;
  540. ALCdevice *SOUND::m_pDevice = nullptr;
  541. ALCcontext *SOUND::m_pContext = nullptr;
  542. unsigned int SOUND::m_nSampleRate = 0;
  543. unsigned int SOUND::m_nChannels = 0;
  544. unsigned int SOUND::m_nBlockCount = 0;
  545. unsigned int SOUND::m_nBlockSamples = 0;
  546. short* SOUND::m_pBlockMemory = nullptr;
  547. }
  548. #else // Some other platform
  549. namespace olc
  550. {
  551. bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples)
  552. {
  553. return true;
  554. }
  555. // Stop and clean up audio system
  556. bool SOUND::DestroyAudio()
  557. {
  558. return false;
  559. }
  560. // Audio thread. This loop responds to requests from the soundcard to fill 'blocks'
  561. // with audio data. If no requests are available it goes dormant until the sound
  562. // card is ready for more data. The block is fille by the "user" in some manner
  563. // and then issued to the soundcard.
  564. void SOUND::AudioThread()
  565. { }
  566. }
  567. #endif