1
0
mirror of https://github.com/blupi-games/planetblupi synced 2024-12-30 10:15:36 +01:00
planetblupi/src/sound.cxx
Mathieu Schroeter 5fe231bcc2 Remove buggy suspend stuff
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.
2019-09-06 23:41:12 +02:00

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;
}
}