audio.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 4; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009-2011, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // Copyright (c) 2011-2017, SDLPAL development team.
  5. // All rights reserved.
  6. //
  7. // This file is part of SDLPAL.
  8. //
  9. // SDLPAL is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU General Public License as published by
  11. // the Free Software Foundation, either version 3 of the License, or
  12. // (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. //
  22. #include "palcommon.h"
  23. #include "global.h"
  24. #include "palcfg.h"
  25. #include "audio.h"
  26. #include "players.h"
  27. #include "util.h"
  28. #include "resampler.h"
  29. #include "midi.h"
  30. #include <math.h>
  31. #if PAL_HAS_OGG
  32. #include <vorbis/codec.h>
  33. #endif
  34. #define PAL_CDTRACK_BASE 10000
  35. typedef void(*ResampleMixFunction)(void *, const void *, int, void *, int, int, uint8_t);
  36. typedef struct tagAUDIODEVICE
  37. {
  38. SDL_AudioSpec spec; /* Actual-used sound specification */
  39. SDL_AudioCVT cvt; /* Audio format conversion parameter */
  40. AUDIOPLAYER *pMusPlayer;
  41. AUDIOPLAYER *pCDPlayer;
  42. #if PAL_HAS_SDLCD
  43. SDL_CD *pCD;
  44. #endif
  45. AUDIOPLAYER *pSoundPlayer;
  46. void *pSoundBuffer; /* The output buffer for sound */
  47. INT iMusicVolume; /* The BGM volume ranged in [0, 128] for better performance */
  48. INT iSoundVolume; /* The sound effect volume ranged in [0, 128] for better performance */
  49. BOOL fMusicEnabled; /* Is BGM enabled? */
  50. BOOL fSoundEnabled; /* Is sound effect enabled? */
  51. BOOL fOpened; /* Is the audio device opened? */
  52. } AUDIODEVICE;
  53. static AUDIODEVICE gAudioDevice;
  54. PAL_FORCE_INLINE
  55. void
  56. AUDIO_MixNative(
  57. short *dst,
  58. short *src,
  59. int samples
  60. )
  61. {
  62. while (samples > 0)
  63. {
  64. int val = *src++ + *dst;
  65. if (val > SHRT_MAX)
  66. *dst++ = SHRT_MAX;
  67. else if (val < SHRT_MIN)
  68. *dst++ = SHRT_MIN;
  69. else
  70. *dst++ = (short)val;
  71. samples--;
  72. }
  73. }
  74. PAL_FORCE_INLINE
  75. void
  76. AUDIO_AdjustVolume(
  77. short *srcdst,
  78. int iVolume,
  79. int samples
  80. )
  81. {
  82. if (iVolume == SDL_MIX_MAXVOLUME) return;
  83. if (iVolume == 0) { memset(srcdst, 0, samples << 1); return; }
  84. while (samples > 0)
  85. {
  86. *srcdst = *srcdst * iVolume / SDL_MIX_MAXVOLUME;
  87. samples--; srcdst++;
  88. }
  89. }
  90. static VOID SDLCALL
  91. AUDIO_FillBuffer(
  92. LPVOID udata,
  93. LPBYTE stream,
  94. INT len
  95. )
  96. /*++
  97. Purpose:
  98. SDL sound callback function.
  99. Parameters:
  100. [IN] udata - pointer to user-defined parameters (Not used).
  101. [OUT] stream - pointer to the stream buffer.
  102. [IN] len - Length of the buffer.
  103. Return value:
  104. None.
  105. --*/
  106. {
  107. memset(stream, 0, len);
  108. gAudioDevice.cvt.buf = stream;
  109. gAudioDevice.cvt.len = len;
  110. //
  111. // Play music
  112. //
  113. if (gAudioDevice.fMusicEnabled && gAudioDevice.iMusicVolume > 0)
  114. {
  115. if (gAudioDevice.pMusPlayer)
  116. {
  117. gAudioDevice.pMusPlayer->FillBuffer(gAudioDevice.pMusPlayer, stream, len);
  118. }
  119. if (gAudioDevice.pCDPlayer)
  120. {
  121. gAudioDevice.pCDPlayer->FillBuffer(gAudioDevice.pCDPlayer, stream, len);
  122. }
  123. //
  124. // Adjust volume for music
  125. //
  126. AUDIO_AdjustVolume((short *)stream, gAudioDevice.iMusicVolume, len >> 1);
  127. }
  128. //
  129. // Play sound
  130. //
  131. if (gAudioDevice.fSoundEnabled && gAudioDevice.pSoundPlayer && gAudioDevice.iSoundVolume > 0)
  132. {
  133. memset(gAudioDevice.pSoundBuffer, 0, len);
  134. gAudioDevice.pSoundPlayer->FillBuffer(gAudioDevice.pSoundPlayer, gAudioDevice.pSoundBuffer, len);
  135. //
  136. // Adjust volume for sound
  137. //
  138. AUDIO_AdjustVolume((short *)gAudioDevice.pSoundBuffer, gAudioDevice.iSoundVolume, len >> 1);
  139. //
  140. // Mix sound & music
  141. //
  142. AUDIO_MixNative((short *)stream, gAudioDevice.pSoundBuffer, len >> 1);
  143. }
  144. //
  145. // Convert audio from native byte-order to actual byte-order
  146. //
  147. SDL_ConvertAudio(&gAudioDevice.cvt);
  148. }
  149. INT
  150. AUDIO_OpenDevice(
  151. VOID
  152. )
  153. /*++
  154. Purpose:
  155. Initialize the audio subsystem.
  156. Parameters:
  157. None.
  158. Return value:
  159. 0 if succeed, others if failed.
  160. --*/
  161. {
  162. SDL_AudioSpec spec;
  163. if (gAudioDevice.fOpened)
  164. {
  165. //
  166. // Already opened
  167. //
  168. return -1;
  169. }
  170. #ifdef __EMSCRIPTEN__ // Now either music/sound enabled will makes whole app crash in emscripten. Disabled until a solution is found.
  171. return -1;
  172. #endif
  173. gAudioDevice.fOpened = FALSE;
  174. gAudioDevice.fMusicEnabled = TRUE;
  175. gAudioDevice.fSoundEnabled = TRUE;
  176. gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  177. gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  178. //
  179. // Initialize the resampler module
  180. //
  181. resampler_init();
  182. //
  183. // Open the audio device.
  184. //
  185. gAudioDevice.spec.freq = gConfig.iSampleRate;
  186. gAudioDevice.spec.format = AUDIO_S16;
  187. gAudioDevice.spec.channels = gConfig.iAudioChannels;
  188. gAudioDevice.spec.samples = gConfig.wAudioBufferSize;
  189. gAudioDevice.spec.callback = AUDIO_FillBuffer;
  190. if (SDL_OpenAudio(&gAudioDevice.spec, &spec) < 0)
  191. {
  192. //
  193. // Failed
  194. //
  195. return -3;
  196. }
  197. else
  198. {
  199. gAudioDevice.spec = spec;
  200. gAudioDevice.pSoundBuffer = malloc(spec.size);
  201. }
  202. SDL_BuildAudioCVT(&gAudioDevice.cvt, AUDIO_S16SYS, spec.channels, spec.freq, spec.format, spec.channels, spec.freq);
  203. gAudioDevice.fOpened = TRUE;
  204. //
  205. // Initialize the sound subsystem.
  206. //
  207. gAudioDevice.pSoundPlayer = SOUND_Init();
  208. //
  209. // Initialize the music subsystem.
  210. //
  211. switch (gConfig.eMusicType)
  212. {
  213. case MUSIC_RIX:
  214. if (!(gAudioDevice.pMusPlayer = RIX_Init(va("%s%s", gConfig.pszGamePath, "mus.mkf"))))
  215. {
  216. gAudioDevice.pMusPlayer = RIX_Init(va("%s%s", gConfig.pszGamePath, "MUS.MKF"));
  217. }
  218. break;
  219. case MUSIC_MP3:
  220. #if PAL_HAS_MP3
  221. gAudioDevice.pMusPlayer = MP3_Init();
  222. #else
  223. gAudioDevice.pMusPlayer = NULL;
  224. #endif
  225. break;
  226. case MUSIC_OGG:
  227. #if PAL_HAS_OGG
  228. gAudioDevice.pMusPlayer = OGG_Init();
  229. #else
  230. gAudioDevice.pMusPlayer = NULL;
  231. #endif
  232. break;
  233. case MUSIC_MIDI:
  234. gAudioDevice.pMusPlayer = NULL;
  235. break;
  236. }
  237. //
  238. // Initialize the CD audio.
  239. //
  240. switch (gConfig.eCDType)
  241. {
  242. case MUSIC_SDLCD:
  243. {
  244. #if PAL_HAS_SDLCD
  245. int i;
  246. gAudioDevice.pCD = NULL;
  247. for (i = 0; i < SDL_CDNumDrives(); i++)
  248. {
  249. gAudioDevice.pCD = SDL_CDOpen(i);
  250. if (gAudioDevice.pCD != NULL)
  251. {
  252. if (!CD_INDRIVE(SDL_CDStatus(gAudioDevice.pCD)))
  253. {
  254. SDL_CDClose(gAudioDevice.pCD);
  255. gAudioDevice.pCD = NULL;
  256. }
  257. else
  258. {
  259. break;
  260. }
  261. }
  262. }
  263. #endif
  264. gAudioDevice.pCDPlayer = NULL;
  265. break;
  266. }
  267. case MUSIC_MP3:
  268. #if PAL_HAS_MP3
  269. gAudioDevice.pCDPlayer = MP3_Init();
  270. #else
  271. gAudioDevice.pCDPlayer = NULL;
  272. #endif
  273. break;
  274. case MUSIC_OGG:
  275. #if PAL_HAS_OGG
  276. gAudioDevice.pCDPlayer = OGG_Init();
  277. #else
  278. gAudioDevice.pCDPlayer = NULL;
  279. #endif
  280. break;
  281. }
  282. //
  283. // Let the callback function run so that musics will be played.
  284. //
  285. SDL_PauseAudio(0);
  286. return 0;
  287. }
  288. VOID
  289. AUDIO_CloseDevice(
  290. VOID
  291. )
  292. /*++
  293. Purpose:
  294. Close the audio subsystem.
  295. Parameters:
  296. None.
  297. Return value:
  298. None.
  299. --*/
  300. {
  301. SDL_CloseAudio();
  302. if (gAudioDevice.pSoundPlayer != NULL)
  303. {
  304. gAudioDevice.pSoundPlayer->Shutdown(gAudioDevice.pSoundPlayer);
  305. gAudioDevice.pSoundPlayer = NULL;
  306. }
  307. if (gAudioDevice.pMusPlayer)
  308. {
  309. gAudioDevice.pMusPlayer->Shutdown(gAudioDevice.pMusPlayer);
  310. gAudioDevice.pMusPlayer = NULL;
  311. }
  312. if (gAudioDevice.pCDPlayer)
  313. {
  314. gAudioDevice.pCDPlayer->Shutdown(gAudioDevice.pCDPlayer);
  315. gAudioDevice.pCDPlayer = NULL;
  316. }
  317. #if PAL_HAS_SDLCD
  318. if (gAudioDevice.pCD != NULL)
  319. {
  320. AUDIO_PlayCDTrack(-1);
  321. SDL_CDClose(gAudioDevice.pCD);
  322. }
  323. #endif
  324. if (gAudioDevice.pSoundBuffer != NULL)
  325. {
  326. free(gAudioDevice.pSoundBuffer);
  327. gAudioDevice.pSoundBuffer = NULL;
  328. }
  329. #if PAL_HAS_NATIVEMIDI
  330. if (gConfig.eMusicType == MUSIC_MIDI) MIDI_Play(0, FALSE);
  331. #endif
  332. }
  333. SDL_AudioSpec*
  334. AUDIO_GetDeviceSpec(
  335. VOID
  336. )
  337. {
  338. return &gAudioDevice.spec;
  339. }
  340. static INT
  341. AUDIO_ChangeVolumeByValue(
  342. INT *iVolume,
  343. INT iValue
  344. )
  345. {
  346. *iVolume += iValue;
  347. if (*iVolume > PAL_MAX_VOLUME)
  348. *iVolume = PAL_MAX_VOLUME;
  349. else if (*iVolume < 0)
  350. *iVolume = 0;
  351. return *iVolume;
  352. }
  353. VOID
  354. AUDIO_IncreaseVolume(
  355. VOID
  356. )
  357. /*++
  358. Purpose:
  359. Increase global volume by 3%.
  360. Parameters:
  361. None.
  362. Return value:
  363. None.
  364. --*/
  365. {
  366. AUDIO_ChangeVolumeByValue(&gConfig.iMusicVolume, 3);
  367. AUDIO_ChangeVolumeByValue(&gConfig.iSoundVolume, 3);
  368. gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  369. gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  370. }
  371. VOID
  372. AUDIO_DecreaseVolume(
  373. VOID
  374. )
  375. /*++
  376. Purpose:
  377. Decrease global volume by 3%.
  378. Parameters:
  379. None.
  380. Return value:
  381. None.
  382. --*/
  383. {
  384. AUDIO_ChangeVolumeByValue(&gConfig.iMusicVolume, -3);
  385. AUDIO_ChangeVolumeByValue(&gConfig.iSoundVolume, -3);
  386. gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  387. gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  388. }
  389. VOID
  390. AUDIO_PlaySound(
  391. INT iSoundNum
  392. )
  393. /*++
  394. Purpose:
  395. Play a sound in voc.mkf/sounds.mkf file.
  396. Parameters:
  397. [IN] iSoundNum - number of the sound; the absolute value is used.
  398. Return value:
  399. None.
  400. --*/
  401. {
  402. // Unlike musics that use the 'load as required' strategy, sound player
  403. // load the entire sound file at once, which may cause about 0.5s or longer
  404. // latency for large sound files. To prevent this latency affects audio playing,
  405. // the mutex lock is obtained inside the SOUND_Play function rather than here.
  406. if (gAudioDevice.pSoundPlayer)
  407. {
  408. gAudioDevice.pSoundPlayer->Play(gAudioDevice.pSoundPlayer, abs(iSoundNum), FALSE, 0.0f);
  409. }
  410. }
  411. VOID
  412. AUDIO_PlayMusic(
  413. INT iNumRIX,
  414. BOOL fLoop,
  415. FLOAT flFadeTime
  416. )
  417. {
  418. #if PAL_HAS_NATIVEMIDI
  419. if (gConfig.eMusicType == MUSIC_MIDI)
  420. {
  421. MIDI_Play(iNumRIX, fLoop);
  422. return;
  423. }
  424. #endif
  425. SDL_LockAudio();
  426. if (gAudioDevice.pMusPlayer)
  427. {
  428. gAudioDevice.pMusPlayer->Play(gAudioDevice.pMusPlayer, iNumRIX, fLoop, flFadeTime);
  429. }
  430. SDL_UnlockAudio();
  431. }
  432. BOOL
  433. AUDIO_PlayCDTrack(
  434. INT iNumTrack
  435. )
  436. /*++
  437. Purpose:
  438. Play a CD Audio Track.
  439. Parameters:
  440. [IN] iNumTrack - number of the CD Audio Track.
  441. Return value:
  442. TRUE if the track can be played, FALSE if not.
  443. --*/
  444. {
  445. BOOL ret = FALSE;
  446. #if PAL_HAS_SDLCD
  447. if (gAudioDevice.pCD != NULL)
  448. {
  449. if (CD_INDRIVE(SDL_CDStatus(gAudioDevice.pCD)))
  450. {
  451. SDL_CDStop(gAudioDevice.pCD);
  452. if (iNumTrack != -1)
  453. {
  454. AUDIO_PlayMusic(-1, FALSE, 0);
  455. if (SDL_CDPlayTracks(gAudioDevice.pCD, iNumTrack - 1, 0, 1, 0) == 0)
  456. {
  457. return TRUE;
  458. }
  459. }
  460. }
  461. }
  462. #endif
  463. SDL_LockAudio();
  464. if (gAudioDevice.pCDPlayer)
  465. {
  466. if (iNumTrack != -1)
  467. {
  468. AUDIO_PlayMusic(-1, FALSE, 0);
  469. ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, PAL_CDTRACK_BASE + iNumTrack, TRUE, 0);
  470. }
  471. else
  472. {
  473. ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, -1, FALSE, 0);
  474. }
  475. }
  476. SDL_UnlockAudio();
  477. return ret;
  478. }
  479. VOID
  480. AUDIO_EnableMusic(
  481. BOOL fEnable
  482. )
  483. {
  484. gAudioDevice.fMusicEnabled = fEnable;
  485. }
  486. BOOL
  487. AUDIO_MusicEnabled(
  488. VOID
  489. )
  490. {
  491. return gAudioDevice.fMusicEnabled;
  492. }
  493. VOID
  494. AUDIO_EnableSound(
  495. BOOL fEnable
  496. )
  497. {
  498. gAudioDevice.fSoundEnabled = fEnable;
  499. }
  500. BOOL
  501. AUDIO_SoundEnabled(
  502. VOID
  503. )
  504. {
  505. return gAudioDevice.fSoundEnabled;
  506. }