1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-26 14:38:30 +02:00
VVVVVV/desktop_version/src/Music.cpp
Misa 0bde6f1eca Reset fade booleans when halting music
This fixes the 2.2-and-below music blocking workaround not working in
2.3.

The issue was that when the music got halted by the script, the fade
volume would still be processing, silently being decremented in the
background. So the script playing the track afterwards would make the
game queue it (as it was called during the fade), but then the music is
halted so the game would attempt to play it, but the fade is STILL
happening so it wouldn't actually play it and would attempt to queue the
track again.

However, that queue gets discarded immediately afterwards because the
music.play() call happened inside the code responsible for playing the
queued music, and that code unconditionally clears the queue variables
immediately after calling play(). So that's good to know - if the game
queues a song, but fails to play it because of a fade, it's not going to
immediately re-queue it and potentially get stuck in a loop of
infinitely queueing the same song over and over again each frame.

Anyways, the source of the problem is not resetting the fade booleans
when halting music, so I've reset them.

Fixes #701.
2021-04-12 16:17:31 -04:00

437 lines
8.6 KiB
C++

#define MUSIC_DEFINITION
#include "Music.h"
#include <SDL.h>
#include <stdio.h>
#include "BinaryBlob.h"
#include "Game.h"
#include "Map.h"
#include "UtilityClass.h"
musicclass::musicclass(void)
{
safeToProcessMusic= false;
m_doFadeInVol = false;
m_doFadeOutVol = false;
musicVolume = 0;
FadeVolAmountPerFrame = 0;
user_music_volume = USER_VOLUME_MAX;
user_sound_volume = USER_VOLUME_MAX;
currentsong = 0;
nicechange = -1;
nicefade = false;
quick_fade = true;
usingmmmmmm = false;
}
void musicclass::init(void)
{
soundTracks.push_back(SoundTrack( "sounds/jump.wav" ));
soundTracks.push_back(SoundTrack( "sounds/jump2.wav" ));
soundTracks.push_back(SoundTrack( "sounds/hurt.wav" ));
soundTracks.push_back(SoundTrack( "sounds/souleyeminijingle.wav" ));
soundTracks.push_back(SoundTrack( "sounds/coin.wav" ));
soundTracks.push_back(SoundTrack( "sounds/save.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crumble.wav" ));
soundTracks.push_back(SoundTrack( "sounds/vanish.wav" ));
soundTracks.push_back(SoundTrack( "sounds/blip.wav" ));
soundTracks.push_back(SoundTrack( "sounds/preteleport.wav" ));
soundTracks.push_back(SoundTrack( "sounds/teleport.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crew1.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crew2.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crew3.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crew4.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crew5.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crew6.wav" ));
soundTracks.push_back(SoundTrack( "sounds/terminal.wav" ));
soundTracks.push_back(SoundTrack( "sounds/gamesaved.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crashing.wav" ));
soundTracks.push_back(SoundTrack( "sounds/blip2.wav" ));
soundTracks.push_back(SoundTrack( "sounds/countdown.wav" ));
soundTracks.push_back(SoundTrack( "sounds/go.wav" ));
soundTracks.push_back(SoundTrack( "sounds/crash.wav" ));
soundTracks.push_back(SoundTrack( "sounds/combine.wav" ));
soundTracks.push_back(SoundTrack( "sounds/newrecord.wav" ));
soundTracks.push_back(SoundTrack( "sounds/trophy.wav" ));
soundTracks.push_back(SoundTrack( "sounds/rescue.wav" ));
#ifdef VVV_COMPILEMUSIC
binaryBlob musicWriteBlob;
#define FOREACH_TRACK(blob, track_name) blob.AddFileToBinaryBlob(track_name);
TRACK_NAMES(musicWriteBlob)
#undef FOREACH_TRACK
musicWriteBlob.writeBinaryBlob("data/BinaryMusic.vvv");
musicWriteBlob.clear();
#endif
num_mmmmmm_tracks = 0;
num_pppppp_tracks = 0;
if (!mmmmmm_blob.unPackBinary("mmmmmm.vvv"))
{
mmmmmm = false;
usingmmmmmm=false;
bool ohCrap = pppppp_blob.unPackBinary("vvvvvvmusic.vvv");
SDL_assert(ohCrap && "Music not found!");
}
else
{
mmmmmm = true;
int index;
SDL_RWops *rw;
#define FOREACH_TRACK(blob, track_name) \
index = blob.getIndex(track_name); \
if (index >= 0 && index < blob.max_headers) \
{ \
rw = SDL_RWFromConstMem(blob.getAddress(index), blob.getSize(index)); \
if (rw == NULL) \
{ \
printf("Unable to read music file header: %s\n", SDL_GetError()); \
} \
else \
{ \
musicTracks.push_back(MusicTrack( rw )); \
} \
}
TRACK_NAMES(mmmmmm_blob)
num_mmmmmm_tracks += musicTracks.size();
size_t index_ = 0;
while (mmmmmm_blob.nextExtra(&index_))
{
rw = SDL_RWFromConstMem(mmmmmm_blob.getAddress(index_), mmmmmm_blob.getSize(index_));
musicTracks.push_back(MusicTrack( rw ));
num_mmmmmm_tracks++;
index_++;
}
bool ohCrap = pppppp_blob.unPackBinary("vvvvvvmusic.vvv");
SDL_assert(ohCrap && "Music not found!");
}
int index;
SDL_RWops *rw;
TRACK_NAMES(pppppp_blob)
#undef FOREACH_TRACK
num_pppppp_tracks += musicTracks.size() - num_mmmmmm_tracks;
size_t index_ = 0;
while (pppppp_blob.nextExtra(&index_))
{
rw = SDL_RWFromConstMem(pppppp_blob.getAddress(index_), pppppp_blob.getSize(index_));
musicTracks.push_back(MusicTrack( rw ));
num_pppppp_tracks++;
index_++;
}
}
void musicclass::destroy(void)
{
for (size_t i = 0; i < soundTracks.size(); ++i)
{
Mix_FreeChunk(soundTracks[i].sound);
}
soundTracks.clear();
// Before we free all the music: stop playing music, else SDL2_mixer
// will call SDL_Delay() if we are fading, resulting in no-draw frames
Mix_HaltMusic();
for (size_t i = 0; i < musicTracks.size(); ++i)
{
Mix_FreeMusic(musicTracks[i].m_music);
}
musicTracks.clear();
pppppp_blob.clear();
mmmmmm_blob.clear();
}
void musicclass::play(int t)
{
if (mmmmmm && usingmmmmmm)
{
// Don't conjoin this if-statement with the above one...
if (num_mmmmmm_tracks > 0)
{
t %= num_mmmmmm_tracks;
}
}
else if (num_pppppp_tracks > 0)
{
t %= num_pppppp_tracks;
}
if (mmmmmm && !usingmmmmmm)
{
t += num_mmmmmm_tracks;
}
safeToProcessMusic = true;
if (currentsong == t && !m_doFadeOutVol)
{
return;
}
currentsong = t;
if (t == -1)
{
return;
}
if (!INBOUNDS_VEC(t, musicTracks))
{
puts("play() out-of-bounds!");
currentsong = -1;
return;
}
if (currentsong == 0 || currentsong == 7 || (!map.custommode && (currentsong == 0+num_mmmmmm_tracks || currentsong == 7+num_mmmmmm_tracks)))
{
// Level Complete theme, no fade in or repeat
if (Mix_PlayMusic(musicTracks[t].m_music, 0) == -1)
{
printf("Mix_PlayMusic: %s\n", Mix_GetError());
}
else
{
musicVolume = MIX_MAX_VOLUME;
}
}
else
{
if (m_doFadeOutVol)
{
// We're already fading out
nicechange = t;
nicefade = true;
currentsong = -1;
if (quick_fade)
{
fadeMusicVolumeOut(500); // fade out quicker
}
else
{
quick_fade = true;
}
}
else if (Mix_PlayMusic(musicTracks[t].m_music, -1) == -1)
{
printf("Mix_PlayMusic: %s\n", Mix_GetError());
}
else
{
fadeMusicVolumeIn(3000);
}
}
}
void musicclass::resume()
{
Mix_ResumeMusic();
}
void musicclass::resumefade(const int fadein_ms)
{
resume();
fadeMusicVolumeIn(fadein_ms);
}
void musicclass::fadein(void)
{
resumefade(3000); // 3000 ms fadein
}
void musicclass::pause(void)
{
Mix_PauseMusic();
}
void musicclass::haltdasmusik(void)
{
/* Just pauses music. This is intended. */
pause();
currentsong = -1;
m_doFadeInVol = false;
m_doFadeOutVol = false;
}
void musicclass::silencedasmusik(void)
{
musicVolume = 0;
}
void musicclass::setfadeamount(const int fade_ms)
{
if (fade_ms == 0)
{
FadeVolAmountPerFrame = MIX_MAX_VOLUME;
return;
}
FadeVolAmountPerFrame = MIX_MAX_VOLUME / (fade_ms / game.get_timestep());
}
void musicclass::fadeMusicVolumeIn(int ms)
{
m_doFadeInVol = true;
m_doFadeOutVol = false;
/* Ensure it starts at 0 */
musicVolume = 0;
/* Fix 1-frame glitch */
Mix_VolumeMusic(0);
setfadeamount(ms);
}
void musicclass::fadeMusicVolumeOut(const int fadeout_ms)
{
m_doFadeInVol = false;
m_doFadeOutVol = true;
setfadeamount(fadeout_ms);
}
void musicclass::fadeout(const bool quick_fade_ /*= true*/)
{
fadeMusicVolumeOut(2000);
quick_fade = quick_fade_;
}
void musicclass::processmusicfadein(void)
{
musicVolume += FadeVolAmountPerFrame;
if (musicVolume >= MIX_MAX_VOLUME)
{
m_doFadeInVol = false;
}
}
void musicclass::processmusicfadeout(void)
{
musicVolume -= FadeVolAmountPerFrame;
if (musicVolume < 0)
{
musicVolume = 0;
m_doFadeOutVol = false;
pause();
}
}
void musicclass::processmusic(void)
{
if(!safeToProcessMusic)
{
return;
}
if (nicefade && Mix_PausedMusic() == 1)
{
play(nicechange);
nicechange = -1;
nicefade = false;
}
if(m_doFadeInVol)
{
processmusicfadein();
}
if (m_doFadeOutVol)
{
processmusicfadeout();
}
}
void musicclass::niceplay(int t)
{
// important: do nothing if the correct song is playing!
if((!mmmmmm && currentsong!=t) || (mmmmmm && usingmmmmmm && currentsong!=t) || (mmmmmm && !usingmmmmmm && currentsong!=t+num_mmmmmm_tracks))
{
if(currentsong!=-1)
{
fadeout(false);
}
nicefade = true;
nicechange = t;
}
}
void musicclass::changemusicarea(int x, int y)
{
switch(musicroom(x, y))
{
case musicroom(11, 4):
niceplay(2);
break;
case musicroom(2, 4):
case musicroom(7, 15):
niceplay(3);
break;
case musicroom(18, 1):
case musicroom(15, 0):
niceplay(12);
break;
case musicroom(0, 0):
case musicroom(0, 16):
case musicroom(2, 11):
case musicroom(7, 9):
case musicroom(8, 11):
case musicroom(13, 2):
case musicroom(17, 12):
case musicroom(14, 19):
case musicroom(17, 17):
niceplay(4);
break;
default:
niceplay(1);
break;
}
}
void musicclass::playef(int t)
{
if (!INBOUNDS_VEC(t, soundTracks))
{
return;
}
int channel;
channel = Mix_PlayChannel(-1, soundTracks[t].sound, 0);
if(channel == -1)
{
fprintf(stderr, "Unable to play WAV file: %s\n", Mix_GetError());
}
}
void musicclass::pauseef(void)
{
Mix_Pause(-1);
}
void musicclass::resumeef(void)
{
Mix_Resume(-1);
}