| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 | 
							- /* -*- mode: c; tab-width: 4; c-basic-offset: 4; c-file-style: "linux" -*- */
 
- //
 
- // Copyright (c) 2009-2011, Wei Mingzhi <whistler_wmz@users.sf.net>.
 
- // Copyright (c) 2011-2017, SDLPAL development team.
 
- // All rights reserved.
 
- //
 
- // This file is part of SDLPAL.
 
- //
 
- // SDLPAL is free software: you can redistribute it and/or modify
 
- // it under the terms of the GNU General Public License as published by
 
- // the Free Software Foundation, either version 3 of the License, or
 
- // (at your option) any later version.
 
- //
 
- // This program is distributed in the hope that it will be useful,
 
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
 
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
- // GNU General Public License for more details.
 
- //
 
- // You should have received a copy of the GNU General Public License
 
- // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- //
 
- #include "palcommon.h"
 
- #include "global.h"
 
- #include "palcfg.h"
 
- #include "audio.h"
 
- #include "players.h"
 
- #include "util.h"
 
- #include "resampler.h"
 
- #include "midi.h"
 
- #include <math.h>
 
- #if PAL_HAS_OGG
 
- #include <vorbis/codec.h>
 
- #endif
 
- #define PAL_CDTRACK_BASE    10000
 
- typedef void(*ResampleMixFunction)(void *, const void *, int, void *, int, int, uint8_t);
 
- typedef struct tagAUDIODEVICE
 
- {
 
-    SDL_AudioSpec             spec;		/* Actual-used sound specification */
 
-    SDL_AudioCVT              cvt;		/* Audio format conversion parameter */
 
-    AUDIOPLAYER              *pMusPlayer;
 
-    AUDIOPLAYER              *pCDPlayer;
 
- #if PAL_HAS_SDLCD
 
-    SDL_CD                   *pCD;
 
- #endif
 
-    AUDIOPLAYER              *pSoundPlayer;
 
-    void                     *pSoundBuffer;	/* The output buffer for sound */
 
-    INT                       iMusicVolume;	/* The BGM volume ranged in [0, 128] for better performance */
 
-    INT                       iSoundVolume;	/* The sound effect volume ranged in [0, 128] for better performance */
 
-    BOOL                      fMusicEnabled; /* Is BGM enabled? */
 
-    BOOL                      fSoundEnabled; /* Is sound effect enabled? */
 
-    BOOL                      fOpened;       /* Is the audio device opened? */
 
- } AUDIODEVICE;
 
- static AUDIODEVICE gAudioDevice;
 
- PAL_FORCE_INLINE
 
- void
 
- AUDIO_MixNative(
 
- 	short     *dst,
 
- 	short     *src,
 
- 	int        samples
 
- )
 
- {
 
- 	while (samples > 0)
 
- 	{
 
- 		int val = *src++ + *dst;
 
- 		if (val > SHRT_MAX)
 
- 			*dst++ = SHRT_MAX;
 
- 		else if (val < SHRT_MIN)
 
- 			*dst++ = SHRT_MIN;
 
- 		else
 
- 			*dst++ = (short)val;
 
- 		samples--;
 
- 	}
 
- }
 
- PAL_FORCE_INLINE
 
- void
 
- AUDIO_AdjustVolume(
 
- 	short     *srcdst,
 
- 	int        iVolume,
 
- 	int        samples
 
- )
 
- {
 
- 	if (iVolume == SDL_MIX_MAXVOLUME) return;
 
- 	if (iVolume == 0) { memset(srcdst, 0, samples << 1); return; }
 
- 	while (samples > 0)
 
- 	{
 
- 		*srcdst = *srcdst * iVolume / SDL_MIX_MAXVOLUME;
 
- 		samples--; srcdst++;
 
- 	}
 
- }
 
- static VOID SDLCALL
 
- AUDIO_FillBuffer(
 
-    LPVOID          udata,
 
-    LPBYTE          stream,
 
-    INT             len
 
- )
 
- /*++
 
-   Purpose:
 
-     SDL sound callback function.
 
-   Parameters:
 
-     [IN]  udata - pointer to user-defined parameters (Not used).
 
-     [OUT] stream - pointer to the stream buffer.
 
-     [IN]  len - Length of the buffer.
 
-   Return value:
 
-     None.
 
- --*/
 
- {
 
-    memset(stream, 0, len);
 
-    gAudioDevice.cvt.buf = stream;
 
-    gAudioDevice.cvt.len = len;
 
-    //
 
-    // Play music
 
-    //
 
-    if (gAudioDevice.fMusicEnabled && gAudioDevice.iMusicVolume > 0)
 
-    {
 
-       if (gAudioDevice.pMusPlayer)
 
-       {
 
-          gAudioDevice.pMusPlayer->FillBuffer(gAudioDevice.pMusPlayer, stream, len);
 
-       }
 
-       if (gAudioDevice.pCDPlayer)
 
-       {
 
-          gAudioDevice.pCDPlayer->FillBuffer(gAudioDevice.pCDPlayer, stream, len);
 
-       }
 
-       //
 
-       // Adjust volume for music
 
-       //
 
-       AUDIO_AdjustVolume((short *)stream, gAudioDevice.iMusicVolume, len >> 1);
 
-    }
 
-    //
 
-    // Play sound
 
-    //
 
-    if (gAudioDevice.fSoundEnabled && gAudioDevice.pSoundPlayer && gAudioDevice.iSoundVolume > 0)
 
-    {
 
- 	   memset(gAudioDevice.pSoundBuffer, 0, len);
 
- 	   gAudioDevice.pSoundPlayer->FillBuffer(gAudioDevice.pSoundPlayer, gAudioDevice.pSoundBuffer, len);
 
- 	   //
 
- 	   // Adjust volume for sound
 
- 	   //
 
- 	   AUDIO_AdjustVolume((short *)gAudioDevice.pSoundBuffer, gAudioDevice.iSoundVolume, len >> 1);
 
- 	   //
 
- 	   // Mix sound & music
 
- 	   //
 
- 	   AUDIO_MixNative((short *)stream, gAudioDevice.pSoundBuffer, len >> 1);
 
-    }
 
-    //
 
-    // Convert audio from native byte-order to actual byte-order
 
-    //
 
-    SDL_ConvertAudio(&gAudioDevice.cvt);
 
- }
 
- INT
 
- AUDIO_OpenDevice(
 
-    VOID
 
- )
 
- /*++
 
-   Purpose:
 
-     Initialize the audio subsystem.
 
-   Parameters:
 
-     None.
 
-   Return value:
 
-     0 if succeed, others if failed.
 
- --*/
 
- {
 
-    SDL_AudioSpec spec;
 
-    if (gAudioDevice.fOpened)
 
-    {
 
-       //
 
-       // Already opened
 
-       //
 
-       return -1;
 
-    }
 
- #ifdef __EMSCRIPTEN__ // Now either music/sound enabled will makes whole app crash in emscripten. Disabled until a solution is found.
 
-    return -1;
 
- #endif
 
-    gAudioDevice.fOpened = FALSE;
 
-    gAudioDevice.fMusicEnabled = TRUE;
 
-    gAudioDevice.fSoundEnabled = TRUE;
 
-    gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
 
-    gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
 
-    //
 
-    // Initialize the resampler module
 
-    //
 
-    resampler_init();
 
-    //
 
-    // Open the audio device.
 
-    //
 
-    gAudioDevice.spec.freq = gConfig.iSampleRate;
 
-    gAudioDevice.spec.format = AUDIO_S16;
 
-    gAudioDevice.spec.channels = gConfig.iAudioChannels;
 
-    gAudioDevice.spec.samples = gConfig.wAudioBufferSize;
 
-    gAudioDevice.spec.callback = AUDIO_FillBuffer;
 
-    if (SDL_OpenAudio(&gAudioDevice.spec, &spec) < 0)
 
-    {
 
-       //
 
-       // Failed
 
-       //
 
-       return -3;
 
-    }
 
-    else
 
-    {
 
-       gAudioDevice.spec = spec;
 
-       gAudioDevice.pSoundBuffer = malloc(spec.size);
 
-    }
 
-    SDL_BuildAudioCVT(&gAudioDevice.cvt, AUDIO_S16SYS, spec.channels, spec.freq, spec.format, spec.channels, spec.freq);
 
-    gAudioDevice.fOpened = TRUE;
 
-    //
 
-    // Initialize the sound subsystem.
 
-    //
 
-    gAudioDevice.pSoundPlayer = SOUND_Init();
 
-    //
 
-    // Initialize the music subsystem.
 
-    //
 
-    switch (gConfig.eMusicType)
 
-    {
 
-    case MUSIC_RIX:
 
- 	   if (!(gAudioDevice.pMusPlayer = RIX_Init(va("%s%s", gConfig.pszGamePath, "mus.mkf"))))
 
- 	   {
 
- 		   gAudioDevice.pMusPlayer = RIX_Init(va("%s%s", gConfig.pszGamePath, "MUS.MKF"));
 
- 	   }
 
- 	   break;
 
-    case MUSIC_MP3:
 
- #if PAL_HAS_MP3
 
- 	   gAudioDevice.pMusPlayer = MP3_Init();
 
- #else
 
- 	   gAudioDevice.pMusPlayer = NULL;
 
- #endif
 
- 	   break;
 
-    case MUSIC_OGG:
 
- #if PAL_HAS_OGG
 
- 	   gAudioDevice.pMusPlayer = OGG_Init();
 
- #else
 
- 	   gAudioDevice.pMusPlayer = NULL;
 
- #endif
 
- 	   break;
 
-    case MUSIC_MIDI:
 
- 	   gAudioDevice.pMusPlayer = NULL;
 
- 	   break;
 
-    }
 
-    //
 
-    // Initialize the CD audio.
 
-    //
 
-    switch (gConfig.eCDType)
 
-    {
 
-    case MUSIC_SDLCD:
 
-    {
 
- #if PAL_HAS_SDLCD
 
- 	   int i;
 
- 	   gAudioDevice.pCD = NULL;
 
- 	   for (i = 0; i < SDL_CDNumDrives(); i++)
 
- 	   {
 
- 		   gAudioDevice.pCD = SDL_CDOpen(i);
 
- 		   if (gAudioDevice.pCD != NULL)
 
- 		   {
 
- 			   if (!CD_INDRIVE(SDL_CDStatus(gAudioDevice.pCD)))
 
- 			   {
 
- 				   SDL_CDClose(gAudioDevice.pCD);
 
- 				   gAudioDevice.pCD = NULL;
 
- 			   }
 
- 			   else
 
- 			   {
 
- 				   break;
 
- 			   }
 
- 		   }
 
- 	   }
 
- #endif
 
- 	   gAudioDevice.pCDPlayer = NULL;
 
- 	   break;
 
-    }
 
-    case MUSIC_MP3:
 
- #if PAL_HAS_MP3
 
- 	   gAudioDevice.pCDPlayer = MP3_Init();
 
- #else
 
- 	   gAudioDevice.pCDPlayer = NULL;
 
- #endif
 
- 	   break;
 
-    case MUSIC_OGG:
 
- #if PAL_HAS_OGG
 
- 	   gAudioDevice.pCDPlayer = OGG_Init();
 
- #else
 
- 	   gAudioDevice.pCDPlayer = NULL;
 
- #endif
 
- 	   break;
 
-    }
 
-    //
 
-    // Let the callback function run so that musics will be played.
 
-    //
 
-    SDL_PauseAudio(0);
 
-    return 0;
 
- }
 
- VOID
 
- AUDIO_CloseDevice(
 
-    VOID
 
- )
 
- /*++
 
-   Purpose:
 
-     Close the audio subsystem.
 
-   Parameters:
 
-     None.
 
-   Return value:
 
-     None.
 
- --*/
 
- {
 
-    SDL_CloseAudio();
 
-    if (gAudioDevice.pSoundPlayer != NULL)
 
-    {
 
-       gAudioDevice.pSoundPlayer->Shutdown(gAudioDevice.pSoundPlayer);
 
-       gAudioDevice.pSoundPlayer = NULL;
 
-    }
 
-    if (gAudioDevice.pMusPlayer)
 
-    {
 
- 	   gAudioDevice.pMusPlayer->Shutdown(gAudioDevice.pMusPlayer);
 
- 	   gAudioDevice.pMusPlayer = NULL;
 
-    }
 
-    if (gAudioDevice.pCDPlayer)
 
-    {
 
- 	   gAudioDevice.pCDPlayer->Shutdown(gAudioDevice.pCDPlayer);
 
- 	   gAudioDevice.pCDPlayer = NULL;
 
-    }
 
- #if PAL_HAS_SDLCD
 
-    if (gAudioDevice.pCD != NULL)
 
-    {
 
-       AUDIO_PlayCDTrack(-1);
 
-       SDL_CDClose(gAudioDevice.pCD);
 
-    }
 
- #endif
 
-    if (gAudioDevice.pSoundBuffer != NULL)
 
-    {
 
-       free(gAudioDevice.pSoundBuffer);
 
- 	  gAudioDevice.pSoundBuffer = NULL;
 
-    }
 
- #if PAL_HAS_NATIVEMIDI
 
-    if (gConfig.eMusicType == MUSIC_MIDI) MIDI_Play(0, FALSE);
 
- #endif
 
- }
 
- SDL_AudioSpec*
 
- AUDIO_GetDeviceSpec(
 
- 	VOID
 
- )
 
- {
 
- 	return &gAudioDevice.spec;
 
- }
 
- static INT
 
- AUDIO_ChangeVolumeByValue(
 
-    INT   *iVolume,
 
-    INT    iValue
 
- )
 
- {
 
-    *iVolume += iValue;
 
-    if (*iVolume > PAL_MAX_VOLUME)
 
-       *iVolume = PAL_MAX_VOLUME;
 
-    else if (*iVolume < 0)
 
-       *iVolume = 0;
 
-    return *iVolume;
 
- }
 
- VOID
 
- AUDIO_IncreaseVolume(
 
-    VOID
 
- )
 
- /*++
 
-   Purpose:
 
-     Increase global volume by 3%.
 
-   Parameters:
 
-     None.
 
-   Return value:
 
-     None.
 
- --*/
 
- {
 
-    AUDIO_ChangeVolumeByValue(&gConfig.iMusicVolume, 3);
 
-    AUDIO_ChangeVolumeByValue(&gConfig.iSoundVolume, 3);
 
-    gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
 
-    gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
 
- }
 
- VOID
 
- AUDIO_DecreaseVolume(
 
-    VOID
 
- )
 
- /*++
 
-   Purpose:
 
-     Decrease global volume by 3%.
 
-   Parameters:
 
-     None.
 
-   Return value:
 
-     None.
 
- --*/
 
- {
 
-    AUDIO_ChangeVolumeByValue(&gConfig.iMusicVolume, -3);
 
-    AUDIO_ChangeVolumeByValue(&gConfig.iSoundVolume, -3);
 
-    gAudioDevice.iMusicVolume = gConfig.iMusicVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
 
-    gAudioDevice.iSoundVolume = gConfig.iSoundVolume * SDL_MIX_MAXVOLUME / PAL_MAX_VOLUME;
 
- }
 
- VOID
 
- AUDIO_PlaySound(
 
-    INT    iSoundNum
 
- )
 
- /*++
 
-   Purpose:
 
-     Play a sound in voc.mkf/sounds.mkf file.
 
-   Parameters:
 
-     [IN]  iSoundNum - number of the sound; the absolute value is used.
 
-   Return value:
 
-     None.
 
- --*/
 
- {
 
-    // Unlike musics that use the 'load as required' strategy, sound player
 
-    // load the entire sound file at once, which may cause about 0.5s or longer
 
-    // latency for large sound files. To prevent this latency affects audio playing,
 
-    // the mutex lock is obtained inside the SOUND_Play function rather than here.
 
-    if (gAudioDevice.pSoundPlayer)
 
-    {
 
-       gAudioDevice.pSoundPlayer->Play(gAudioDevice.pSoundPlayer, abs(iSoundNum), FALSE, 0.0f);
 
-    }
 
- }
 
- VOID
 
- AUDIO_PlayMusic(
 
-    INT       iNumRIX,
 
-    BOOL      fLoop,
 
-    FLOAT     flFadeTime
 
- )
 
- {
 
- #if PAL_HAS_NATIVEMIDI
 
-    if (gConfig.eMusicType == MUSIC_MIDI)
 
-    {
 
-       MIDI_Play(iNumRIX, fLoop);
 
-       return;
 
-    }
 
- #endif
 
-    SDL_LockAudio();
 
-    if (gAudioDevice.pMusPlayer)
 
-    {
 
-       gAudioDevice.pMusPlayer->Play(gAudioDevice.pMusPlayer, iNumRIX, fLoop, flFadeTime);
 
-    }
 
-    SDL_UnlockAudio();
 
- }
 
- BOOL
 
- AUDIO_PlayCDTrack(
 
-    INT    iNumTrack
 
- )
 
- /*++
 
-   Purpose:
 
-     Play a CD Audio Track.
 
-   Parameters:
 
-     [IN]  iNumTrack - number of the CD Audio Track.
 
-   Return value:
 
-     TRUE if the track can be played, FALSE if not.
 
- --*/
 
- {
 
- 	BOOL ret = FALSE;
 
- #if PAL_HAS_SDLCD
 
-    if (gAudioDevice.pCD != NULL)
 
-    {
 
-       if (CD_INDRIVE(SDL_CDStatus(gAudioDevice.pCD)))
 
-       {
 
-          SDL_CDStop(gAudioDevice.pCD);
 
-          if (iNumTrack != -1)
 
-          {
 
-             AUDIO_PlayMusic(-1, FALSE, 0);
 
-             if (SDL_CDPlayTracks(gAudioDevice.pCD, iNumTrack - 1, 0, 1, 0) == 0)
 
-             {
 
-                return TRUE;
 
-             }
 
-          }
 
-       }
 
-    }
 
- #endif
 
-    SDL_LockAudio();
 
-    if (gAudioDevice.pCDPlayer)
 
-    {
 
- 	   if (iNumTrack != -1)
 
- 	   {
 
- 		   AUDIO_PlayMusic(-1, FALSE, 0);
 
- 		   ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, PAL_CDTRACK_BASE + iNumTrack, TRUE, 0);
 
- 	   }
 
- 	   else
 
- 	   {
 
- 		   ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, -1, FALSE, 0);
 
- 	   }
 
-    }
 
-    SDL_UnlockAudio();
 
-    return ret;
 
- }
 
- VOID
 
- AUDIO_EnableMusic(
 
-    BOOL   fEnable
 
- )
 
- {
 
-    gAudioDevice.fMusicEnabled = fEnable;
 
- }
 
- BOOL
 
- AUDIO_MusicEnabled(
 
-    VOID
 
- )
 
- {
 
-    return gAudioDevice.fMusicEnabled;
 
- }
 
- VOID
 
- AUDIO_EnableSound(
 
-    BOOL   fEnable
 
- )
 
- {
 
- 	gAudioDevice.fSoundEnabled = fEnable;
 
- }
 
- BOOL
 
- AUDIO_SoundEnabled(
 
-    VOID
 
- )
 
- {
 
-    return gAudioDevice.fSoundEnabled;
 
- }
 
 
  |