mirror of
https://github.com/blupi-games/planetblupi
synced 2024-12-30 10:15:36 +01:00
It doesn't make sense here. Not sure why the old code needs that. Anyway, it's just wrong because. Maybe the old code needs that because the sound was played independently of the video. This commit prevents that the music to continue on the win or lost screen when the video has been skipped by space or esc.
447 lines
8.5 KiB
C++
447 lines
8.5 KiB
C++
/*
|
|
* This file is part of the planetblupi source code
|
|
* Copyright (C) 1997, Daniel Roux & EPSITEC SA
|
|
* Copyright (C) 2017-2018, Mathieu Schroeter
|
|
* http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games
|
|
*
|
|
* This program 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://gnu.org/licenses
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "def.h"
|
|
#include "event.h"
|
|
#include "misc.h"
|
|
#include "platform.h"
|
|
#include "sound.h"
|
|
|
|
void
|
|
CSound::StopSound (bool immediat, Sint32 rank)
|
|
{
|
|
Sounds stopCh;
|
|
|
|
if (rank >= 0 && rank < MAXBLUPI)
|
|
{
|
|
stopCh = m_channelBlupi[rank];
|
|
if (stopCh >= 0 && m_lpSDL[stopCh] != nullptr)
|
|
{
|
|
/* FIXME: add support of fade out with emscripten */
|
|
if (immediat || Platform::getType () == Platform::Type::JS)
|
|
Mix_HaltChannel (stopCh + 1);
|
|
else
|
|
Mix_FadeOutChannel (stopCh + 1, 500);
|
|
}
|
|
|
|
m_channelBlupi[rank] = SOUND_NONE;
|
|
}
|
|
}
|
|
|
|
// Stops all sounds.
|
|
|
|
bool
|
|
CSound::StopAllSounds (bool immediat, const std::set<Sint32> * except)
|
|
{
|
|
for (Sint32 i = 0; i < MAXSOUND; i++)
|
|
{
|
|
if (!m_lpSDL[i])
|
|
continue;
|
|
|
|
if (except && except->find (i) != except->end ())
|
|
continue;
|
|
|
|
if (Mix_Playing (i + 1) == SDL_TRUE)
|
|
{
|
|
/* FIXME: add support of fade out with emscripten */
|
|
if (immediat || Platform::getType () == Platform::Type::JS)
|
|
Mix_HaltChannel (i + 1);
|
|
else
|
|
Mix_FadeOutChannel (i + 1, 500);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
CSound::CSound ()
|
|
: m_sndFiles (MAXSOUND)
|
|
{
|
|
Sint32 i;
|
|
|
|
m_bState = false;
|
|
m_MIDIFilename[0] = 0;
|
|
m_audioVolume = 20;
|
|
m_midiVolume = 15;
|
|
m_lastMidiVolume = 0;
|
|
m_pMusic = nullptr;
|
|
m_bStopped = false;
|
|
|
|
for (i = 0; i < MAXBLUPI; i++)
|
|
m_channelBlupi[i] = SOUND_NONE;
|
|
|
|
memset (m_lpSDL, 0, sizeof (m_lpSDL));
|
|
}
|
|
|
|
// Destructeur.
|
|
|
|
CSound::~CSound ()
|
|
{
|
|
Sint32 i;
|
|
|
|
for (i = 0; i < MAXSOUND; i++)
|
|
{
|
|
if (!m_lpSDL[i])
|
|
continue;
|
|
|
|
Mix_FreeChunk (m_lpSDL[i]);
|
|
m_lpSDL[i] = nullptr;
|
|
}
|
|
|
|
if (m_pMusic)
|
|
{
|
|
Mix_FreeMusic (m_pMusic);
|
|
m_pMusic = nullptr;
|
|
}
|
|
|
|
Mix_CloseAudio ();
|
|
}
|
|
|
|
// Initialisation de DirectSound.
|
|
|
|
bool
|
|
CSound::Create ()
|
|
{
|
|
if (
|
|
Mix_OpenAudio (44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 1024) == -1)
|
|
return false;
|
|
|
|
Mix_AllocateChannels (MAXSOUND);
|
|
|
|
Mix_HookMusicFinished ([]() { CEvent::PushUserEvent (EV_MUSIC_STOP); });
|
|
|
|
return true;
|
|
}
|
|
|
|
// Enclenche ou d�clenche le son.
|
|
|
|
void
|
|
CSound::SetState (bool bState)
|
|
{
|
|
m_bState = bState;
|
|
}
|
|
|
|
// Gestion des volumes audio (.wav) et midi (.mid).
|
|
|
|
void
|
|
CSound::SetAudioVolume (Sint32 volume)
|
|
{
|
|
m_audioVolume = volume;
|
|
}
|
|
|
|
Sint32
|
|
CSound::GetAudioVolume ()
|
|
{
|
|
return m_audioVolume;
|
|
}
|
|
|
|
void
|
|
CSound::SetMidiVolume (Sint32 volume)
|
|
{
|
|
m_midiVolume = volume;
|
|
}
|
|
|
|
Sint32
|
|
CSound::GetMidiVolume ()
|
|
{
|
|
return m_midiVolume;
|
|
}
|
|
|
|
// Cache tous les ficheirs son (.wav).
|
|
|
|
void
|
|
CSound::CacheAll ()
|
|
{
|
|
Sint32 i;
|
|
char name[50];
|
|
|
|
this->StopAllSounds (true);
|
|
|
|
for (i = 0; i < MAXSOUND; i++)
|
|
{
|
|
snprintf (name, sizeof (name), "sound%.3d.wav", i);
|
|
if (!Cache (i, name))
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Charge un fichier son (.wav).
|
|
|
|
bool
|
|
CSound::Cache (Sint32 channel, const std::string & pFilename)
|
|
{
|
|
if (channel < 0 || channel >= MAXSOUND)
|
|
return false;
|
|
|
|
auto sound = "sound/" + GetLocale () + "/" + pFilename;
|
|
auto file = GetBaseDir () + sound;
|
|
|
|
if (m_lpSDL[channel] && m_sndFiles[channel] == sound)
|
|
return true;
|
|
|
|
Mix_Chunk * chunk = nullptr;
|
|
std::string absolute;
|
|
|
|
if (FileExists (file, absolute, Location::LOCATION_ABSOLUTE))
|
|
chunk = Mix_LoadWAV (file.c_str ());
|
|
|
|
if (!chunk)
|
|
{
|
|
if (GetLocale () != "en")
|
|
{
|
|
/* Try with the fallback locale */
|
|
sound = "sound/en/" + pFilename;
|
|
file = GetBaseDir () + sound;
|
|
|
|
if (m_lpSDL[channel] && m_sndFiles[channel] == sound)
|
|
return true;
|
|
|
|
chunk = Mix_LoadWAV (file.c_str ());
|
|
if (!chunk)
|
|
goto err;
|
|
}
|
|
else
|
|
goto err;
|
|
}
|
|
|
|
if (m_lpSDL[channel])
|
|
Flush (channel);
|
|
|
|
m_lpSDL[channel] = chunk;
|
|
m_sndFiles[channel] = sound;
|
|
|
|
SDL_Log ("Load sound: %s\n", sound.c_str ());
|
|
return true;
|
|
|
|
err:
|
|
SDL_Log ("Mix_LoadWAV: %s\n", Mix_GetError ());
|
|
return false;
|
|
}
|
|
|
|
void
|
|
CSound::FlushAll ()
|
|
{
|
|
for (size_t ch = 0; ch < sizeof (m_lpSDL); ++ch)
|
|
Flush (ch);
|
|
}
|
|
|
|
// D�charge un son.
|
|
|
|
void
|
|
CSound::Flush (Sint32 channel)
|
|
{
|
|
if (channel < 0 || channel >= MAXSOUND)
|
|
return;
|
|
|
|
if (m_lpSDL[channel])
|
|
{
|
|
Mix_FreeChunk (m_lpSDL[channel]);
|
|
m_lpSDL[channel] = nullptr;
|
|
}
|
|
}
|
|
|
|
// Fait entendre un son.
|
|
// Le volume est compris entre 128 (max) et 0 (silence).
|
|
// Le panoramique est compris entre 255,0 (gauche), 127,128 (centre)
|
|
// et 0,255 (droite).
|
|
|
|
bool
|
|
CSound::Play (Sint32 channel, Sint32 volume, Uint8 panLeft, Uint8 panRight)
|
|
{
|
|
if (!m_bState || !m_audioVolume)
|
|
return true;
|
|
|
|
if (channel < 0 || channel >= MAXSOUND)
|
|
return false;
|
|
|
|
Mix_SetPanning (channel + 1, panLeft, panRight);
|
|
|
|
volume = volume * 100 * m_audioVolume / 20 / 100;
|
|
Mix_Volume (channel + 1, volume);
|
|
|
|
if (Mix_Playing (channel + 1) == SDL_FALSE)
|
|
Mix_PlayChannel (channel + 1, m_lpSDL[channel], 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Fait entendre un son dans une image.
|
|
// Si rank != -1, il indique le rang du blupi dont il faudra
|
|
// �ventuellement stopper le dernier son en cours !
|
|
|
|
bool
|
|
CSound::PlayImage (Sounds channel, Point pos, Sint32 rank, bool stop)
|
|
{
|
|
Sint32 volumex, volumey, volume;
|
|
|
|
if (rank >= 0 && rank < MAXBLUPI)
|
|
{
|
|
bool immediat = channel == SOUND_DYNAMITE;
|
|
|
|
if (stop || immediat)
|
|
this->StopSound (immediat, rank);
|
|
else
|
|
m_channelBlupi[rank] = channel;
|
|
}
|
|
|
|
Uint8 panRight, panLeft;
|
|
volumex = MIX_MAX_VOLUME;
|
|
volumey = MIX_MAX_VOLUME;
|
|
|
|
if (pos.x < 0)
|
|
{
|
|
panRight = 0;
|
|
panLeft = 255;
|
|
volumex += pos.x;
|
|
if (volumex < 0)
|
|
volumex = 0;
|
|
}
|
|
else if (pos.x > LXIMAGE ())
|
|
{
|
|
panRight = 255;
|
|
panLeft = 0;
|
|
volumex -= pos.x - LXIMAGE ();
|
|
if (volumex < 0)
|
|
volumex = 0;
|
|
}
|
|
else
|
|
{
|
|
panRight = 255 * static_cast<Uint16> (pos.x) / LXIMAGE ();
|
|
panLeft = 255 - panRight;
|
|
}
|
|
|
|
if (pos.y < 0)
|
|
{
|
|
volumey += pos.y;
|
|
if (volumey < 0)
|
|
volumey = 0;
|
|
}
|
|
else if (pos.y > LYIMAGE ())
|
|
{
|
|
volumey -= pos.y - LYIMAGE ();
|
|
if (volumey < 0)
|
|
volumey = 0;
|
|
}
|
|
|
|
volume = volumex < volumey ? volumex : volumey;
|
|
|
|
return Play (channel, volume, panLeft, panRight);
|
|
}
|
|
|
|
// Uses MCI to play a MIDI file. The window procedure
|
|
// is notified when playback is complete.
|
|
|
|
bool
|
|
CSound::PlayMusic (const std::string & lpszMIDIFilename)
|
|
{
|
|
if (m_midiVolume == 0)
|
|
return true;
|
|
|
|
if (lpszMIDIFilename.empty ())
|
|
return false;
|
|
|
|
Mix_VolumeMusic (MIX_MAX_VOLUME * 100 * m_midiVolume / 20 / 100);
|
|
m_lastMidiVolume = m_midiVolume;
|
|
|
|
if (m_pMusic)
|
|
Mix_FreeMusic (m_pMusic);
|
|
|
|
std::string absolute;
|
|
if (FileExists (lpszMIDIFilename, absolute, Location::LOCATION_ABSOLUTE))
|
|
m_pMusic = Mix_LoadMUS (lpszMIDIFilename.c_str ());
|
|
|
|
if (!m_pMusic)
|
|
{
|
|
printf ("%s\n", Mix_GetError ());
|
|
return false;
|
|
}
|
|
|
|
if (Mix_PlayMusic (m_pMusic, 0) == -1)
|
|
{
|
|
printf ("%s\n", Mix_GetError ());
|
|
return false;
|
|
}
|
|
|
|
m_bStopped = false;
|
|
m_MIDIFilename = lpszMIDIFilename;
|
|
return true;
|
|
}
|
|
|
|
// Restart the MIDI player.
|
|
|
|
bool
|
|
CSound::RestartMusic ()
|
|
{
|
|
OutputDebug ("RestartMusic\n");
|
|
|
|
if (m_midiVolume == 0)
|
|
return true;
|
|
if (m_MIDIFilename[0] == 0)
|
|
return false;
|
|
|
|
return PlayMusic (m_MIDIFilename);
|
|
}
|
|
|
|
// Shuts down the MIDI player.
|
|
|
|
void
|
|
CSound::SuspendMusic ()
|
|
{
|
|
m_bStopped = true;
|
|
Mix_HaltMusic ();
|
|
}
|
|
|
|
// Shuts down the MIDI player.
|
|
|
|
void
|
|
CSound::StopMusic ()
|
|
{
|
|
SuspendMusic ();
|
|
m_MIDIFilename[0] = 0;
|
|
}
|
|
|
|
// Retourne true si une musique est en cours.
|
|
|
|
bool
|
|
CSound::IsPlayingMusic ()
|
|
{
|
|
return (m_MIDIFilename[0] != 0);
|
|
}
|
|
|
|
bool
|
|
CSound::IsStoppedOnDemand ()
|
|
{
|
|
return m_bStopped;
|
|
}
|
|
|
|
// Adapte le volume de la musique en cours, si n�cessaire.
|
|
|
|
void
|
|
CSound::AdaptVolumeMusic ()
|
|
{
|
|
if (m_midiVolume != m_lastMidiVolume)
|
|
{
|
|
Mix_VolumeMusic (MIX_MAX_VOLUME * 100 * m_midiVolume / 20 / 100);
|
|
m_lastMidiVolume = m_midiVolume;
|
|
}
|
|
}
|