audio.c 12 KB

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