audio.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  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. SDL_mutex *mtx; /* Mutex for preventing using destroyed objects */
  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. #if SDL_VERSION_ATLEAST(2,0,0)
  108. memset(stream, 0, len);
  109. #endif
  110. SDL_mutexP(gAudioDevice.mtx);
  111. gAudioDevice.cvt.buf = stream;
  112. gAudioDevice.cvt.len = len;
  113. //
  114. // Play music
  115. //
  116. if (gAudioDevice.fMusicEnabled && gAudioDevice.iMusicVolume > 0)
  117. {
  118. if (gAudioDevice.pMusPlayer)
  119. {
  120. gAudioDevice.pMusPlayer->FillBuffer(gAudioDevice.pMusPlayer, stream, len);
  121. }
  122. if (gAudioDevice.pCDPlayer)
  123. {
  124. gAudioDevice.pCDPlayer->FillBuffer(gAudioDevice.pCDPlayer, stream, len);
  125. }
  126. //
  127. // Adjust volume for music
  128. //
  129. AUDIO_AdjustVolume((short *)stream, gAudioDevice.iMusicVolume, len >> 1);
  130. }
  131. //
  132. // Play sound
  133. //
  134. if (gAudioDevice.fSoundEnabled && gAudioDevice.pSoundPlayer && gAudioDevice.iSoundVolume > 0)
  135. {
  136. memset(gAudioDevice.pSoundBuffer, 0, len);
  137. gAudioDevice.pSoundPlayer->FillBuffer(gAudioDevice.pSoundPlayer, gAudioDevice.pSoundBuffer, len);
  138. //
  139. // Adjust volume for sound
  140. //
  141. AUDIO_AdjustVolume((short *)gAudioDevice.pSoundBuffer, gAudioDevice.iSoundVolume, len >> 1);
  142. //
  143. // Mix sound & music
  144. //
  145. AUDIO_MixNative((short *)stream, gAudioDevice.pSoundBuffer, len >> 1);
  146. }
  147. //
  148. // Convert audio from native byte-order to actual byte-order
  149. //
  150. SDL_ConvertAudio(&gAudioDevice.cvt);
  151. SDL_mutexV(gAudioDevice.mtx);
  152. }
  153. INT
  154. AUDIO_OpenDevice(
  155. VOID
  156. )
  157. /*++
  158. Purpose:
  159. Initialize the audio subsystem.
  160. Parameters:
  161. None.
  162. Return value:
  163. 0 if succeed, others if failed.
  164. --*/
  165. {
  166. SDL_AudioSpec spec;
  167. if (gAudioDevice.fOpened)
  168. {
  169. //
  170. // Already opened
  171. //
  172. return -1;
  173. }
  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.mtx = SDL_CreateMutex();
  205. gAudioDevice.fOpened = TRUE;
  206. //
  207. // Initialize the sound subsystem.
  208. //
  209. gAudioDevice.pSoundPlayer = SOUND_Init(gAudioDevice.mtx);
  210. //
  211. // Initialize the music subsystem.
  212. //
  213. switch (gConfig.eMusicType)
  214. {
  215. case MUSIC_RIX:
  216. if (!(gAudioDevice.pMusPlayer = RIX_Init(va("%s%s", gConfig.pszGamePath, "mus.mkf"), gAudioDevice.mtx)))
  217. {
  218. gAudioDevice.pMusPlayer = RIX_Init(va("%s%s", gConfig.pszGamePath, "MUS.MKF"), gAudioDevice.mtx);
  219. }
  220. break;
  221. case MUSIC_MP3:
  222. #if PAL_HAS_MP3
  223. gAudioDevice.pMusPlayer = MP3_Init(gAudioDevice.mtx);
  224. #else
  225. gAudioDevice.pMusPlayer = NULL;
  226. #endif
  227. break;
  228. case MUSIC_OGG:
  229. #if PAL_HAS_OGG
  230. gAudioDevice.pMusPlayer = OGG_Init(gAudioDevice.mtx);
  231. #else
  232. gAudioDevice.pMusPlayer = NULL;
  233. #endif
  234. break;
  235. case MUSIC_MIDI:
  236. gAudioDevice.pMusPlayer = NULL;
  237. break;
  238. }
  239. //
  240. // Initialize the CD audio.
  241. //
  242. switch (gConfig.eCDType)
  243. {
  244. case MUSIC_SDLCD:
  245. {
  246. #if PAL_HAS_SDLCD
  247. int i;
  248. gAudioDevice.pCD = NULL;
  249. for (i = 0; i < SDL_CDNumDrives(); i++)
  250. {
  251. gAudioDevice.pCD = SDL_CDOpen(i);
  252. if (gAudioDevice.pCD != NULL)
  253. {
  254. if (!CD_INDRIVE(SDL_CDStatus(gAudioDevice.pCD)))
  255. {
  256. SDL_CDClose(gAudioDevice.pCD);
  257. gAudioDevice.pCD = NULL;
  258. }
  259. else
  260. {
  261. break;
  262. }
  263. }
  264. }
  265. #endif
  266. gAudioDevice.pCDPlayer = NULL;
  267. break;
  268. }
  269. case MUSIC_MP3:
  270. #if PAL_HAS_MP3
  271. gAudioDevice.pCDPlayer = MP3_Init(gAudioDevice.mtx);
  272. #else
  273. gAudioDevice.pCDPlayer = NULL;
  274. #endif
  275. break;
  276. case MUSIC_OGG:
  277. #if PAL_HAS_OGG
  278. gAudioDevice.pCDPlayer = OGG_Init(gAudioDevice.mtx);
  279. #else
  280. gAudioDevice.pCDPlayer = NULL;
  281. #endif
  282. break;
  283. }
  284. //
  285. // Let the callback function run so that musics will be played.
  286. //
  287. SDL_PauseAudio(0);
  288. return 0;
  289. }
  290. VOID
  291. AUDIO_CloseDevice(
  292. VOID
  293. )
  294. /*++
  295. Purpose:
  296. Close the audio subsystem.
  297. Parameters:
  298. None.
  299. Return value:
  300. None.
  301. --*/
  302. {
  303. SDL_CloseAudio();
  304. SDL_mutexP(gAudioDevice.mtx);
  305. if (gAudioDevice.pSoundPlayer != NULL)
  306. {
  307. gAudioDevice.pSoundPlayer->Shutdown(gAudioDevice.pSoundPlayer);
  308. gAudioDevice.pSoundPlayer = NULL;
  309. }
  310. if (gAudioDevice.pMusPlayer)
  311. {
  312. gAudioDevice.pMusPlayer->Shutdown(gAudioDevice.pMusPlayer);
  313. gAudioDevice.pMusPlayer = NULL;
  314. }
  315. if (gAudioDevice.pCDPlayer)
  316. {
  317. gAudioDevice.pCDPlayer->Shutdown(gAudioDevice.pCDPlayer);
  318. gAudioDevice.pCDPlayer = NULL;
  319. }
  320. #if PAL_HAS_SDLCD
  321. if (gAudioDevice.pCD != NULL)
  322. {
  323. AUDIO_PlayCDTrack(-1);
  324. SDL_CDClose(gAudioDevice.pCD);
  325. }
  326. #endif
  327. if (gAudioDevice.pSoundBuffer != NULL)
  328. {
  329. free(gAudioDevice.pSoundBuffer);
  330. gAudioDevice.pSoundBuffer = NULL;
  331. }
  332. #if PAL_HAS_NATIVEMIDI
  333. if (gConfig.eMusicType == MUSIC_MIDI) MIDI_Play(0, FALSE);
  334. #endif
  335. SDL_mutexV(gAudioDevice.mtx);
  336. SDL_DestroyMutex(gAudioDevice.mtx);
  337. gAudioDevice.mtx = NULL;
  338. }
  339. SDL_AudioSpec*
  340. AUDIO_GetDeviceSpec(
  341. VOID
  342. )
  343. {
  344. return &gAudioDevice.spec;
  345. }
  346. static INT
  347. AUDIO_ChangeVolumeByValue(
  348. INT *iVolume,
  349. INT iValue
  350. )
  351. {
  352. *iVolume += iValue;
  353. if (*iVolume > PAL_MAX_VOLUME)
  354. *iVolume = PAL_MAX_VOLUME;
  355. else if (*iVolume < 0)
  356. *iVolume = 0;
  357. return *iVolume;
  358. }
  359. VOID
  360. AUDIO_IncreaseVolume(
  361. VOID
  362. )
  363. /*++
  364. Purpose:
  365. Increase global volume by 3%.
  366. Parameters:
  367. None.
  368. Return value:
  369. None.
  370. --*/
  371. {
  372. AUDIO_ChangeVolumeByValue(&gConfig.iMusicVolume, 3);
  373. AUDIO_ChangeVolumeByValue(&gConfig.iSoundVolume, 3);
  374. gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  375. gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  376. }
  377. VOID
  378. AUDIO_DecreaseVolume(
  379. VOID
  380. )
  381. /*++
  382. Purpose:
  383. Decrease global volume by 3%.
  384. Parameters:
  385. None.
  386. Return value:
  387. None.
  388. --*/
  389. {
  390. AUDIO_ChangeVolumeByValue(&gConfig.iMusicVolume, -3);
  391. AUDIO_ChangeVolumeByValue(&gConfig.iSoundVolume, -3);
  392. gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  393. gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
  394. }
  395. VOID
  396. AUDIO_PlaySound(
  397. INT iSoundNum
  398. )
  399. /*++
  400. Purpose:
  401. Play a sound in voc.mkf/sounds.mkf file.
  402. Parameters:
  403. [IN] iSoundNum - number of the sound; the absolute value is used.
  404. Return value:
  405. None.
  406. --*/
  407. {
  408. // Unlike musics that use the 'load as required' strategy, sound player
  409. // load the entire sound file at once, which may cause about 0.5s or longer
  410. // latency for large sound files. To prevent this latency affects audio playing,
  411. // the mutex lock is obtained inside the SOUND_Play function rather than here.
  412. if (gAudioDevice.pSoundPlayer)
  413. {
  414. gAudioDevice.pSoundPlayer->Play(gAudioDevice.pSoundPlayer, abs(iSoundNum), FALSE, 0.0f);
  415. }
  416. }
  417. VOID
  418. AUDIO_PlayMusic(
  419. INT iNumRIX,
  420. BOOL fLoop,
  421. FLOAT flFadeTime
  422. )
  423. {
  424. #if PAL_HAS_NATIVEMIDI
  425. if (gConfig.eMusicType == MUSIC_MIDI)
  426. {
  427. MIDI_Play(iNumRIX, fLoop);
  428. return;
  429. }
  430. #endif
  431. SDL_mutexP(gAudioDevice.mtx);
  432. if (gAudioDevice.pMusPlayer)
  433. {
  434. gAudioDevice.pMusPlayer->Play(gAudioDevice.pMusPlayer, iNumRIX, fLoop, flFadeTime);
  435. }
  436. SDL_mutexV(gAudioDevice.mtx);
  437. }
  438. BOOL
  439. AUDIO_PlayCDTrack(
  440. INT iNumTrack
  441. )
  442. /*++
  443. Purpose:
  444. Play a CD Audio Track.
  445. Parameters:
  446. [IN] iNumTrack - number of the CD Audio Track.
  447. Return value:
  448. TRUE if the track can be played, FALSE if not.
  449. --*/
  450. {
  451. BOOL ret = FALSE;
  452. #if PAL_HAS_SDLCD
  453. if (gAudioDevice.pCD != NULL)
  454. {
  455. if (CD_INDRIVE(SDL_CDStatus(gAudioDevice.pCD)))
  456. {
  457. SDL_CDStop(gAudioDevice.pCD);
  458. if (iNumTrack != -1)
  459. {
  460. AUDIO_PlayMusic(-1, FALSE, 0);
  461. if (SDL_CDPlayTracks(gAudioDevice.pCD, iNumTrack - 1, 0, 1, 0) == 0)
  462. {
  463. return TRUE;
  464. }
  465. }
  466. }
  467. }
  468. #endif
  469. SDL_mutexP(gAudioDevice.mtx);
  470. if (gAudioDevice.pCDPlayer)
  471. {
  472. if (iNumTrack != -1)
  473. {
  474. AUDIO_PlayMusic(-1, FALSE, 0);
  475. ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, PAL_CDTRACK_BASE + iNumTrack, TRUE, 0);
  476. }
  477. else
  478. {
  479. ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, -1, FALSE, 0);
  480. }
  481. }
  482. SDL_mutexV(gAudioDevice.mtx);
  483. return ret;
  484. }
  485. VOID
  486. AUDIO_EnableMusic(
  487. BOOL fEnable
  488. )
  489. {
  490. gAudioDevice.fMusicEnabled = fEnable;
  491. }
  492. BOOL
  493. AUDIO_MusicEnabled(
  494. VOID
  495. )
  496. {
  497. return gAudioDevice.fMusicEnabled;
  498. }
  499. VOID
  500. AUDIO_EnableSound(
  501. BOOL fEnable
  502. )
  503. {
  504. gAudioDevice.fSoundEnabled = fEnable;
  505. }
  506. BOOL
  507. AUDIO_SoundEnabled(
  508. VOID
  509. )
  510. {
  511. return gAudioDevice.fSoundEnabled;
  512. }