audio.c 12 KB

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