audio.c 12 KB

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