mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-09-28 17:27:23 +02:00
737 lines
17 KiB
C++
737 lines
17 KiB
C++
#define MUSIC_DEFINITION
|
|
#include "Music.h"
|
|
|
|
#include <SDL.h>
|
|
#include <physfsrwops.h>
|
|
|
|
#include "BinaryBlob.h"
|
|
#include "FileSystemUtils.h"
|
|
#include "Game.h"
|
|
#include "Graphics.h"
|
|
#include "Map.h"
|
|
#include "Script.h"
|
|
#include "UtilityClass.h"
|
|
#include "Vlogging.h"
|
|
|
|
/* Begin SDL_mixer wrapper */
|
|
|
|
#include <SDL_mixer.h>
|
|
#include <vector>
|
|
|
|
#define VVV_MAX_VOLUME MIX_MAX_VOLUME
|
|
|
|
class SoundTrack
|
|
{
|
|
public:
|
|
SoundTrack(const char* fileName)
|
|
{
|
|
/* SDL_LoadWAV, convert spec to FAudioBuffer */
|
|
unsigned char *mem;
|
|
size_t length;
|
|
FILESYSTEM_loadAssetToMemory(fileName, &mem, &length, false);
|
|
if (mem == NULL)
|
|
{
|
|
m_sound = NULL;
|
|
vlog_error("Unable to load WAV file %s", fileName);
|
|
SDL_assert(0 && "WAV file missing!");
|
|
return;
|
|
}
|
|
SDL_RWops *fileIn = SDL_RWFromConstMem(mem, length);
|
|
m_sound = Mix_LoadWAV_RW(fileIn, 1);
|
|
FILESYSTEM_freeMemory(&mem);
|
|
|
|
if (m_sound == NULL)
|
|
{
|
|
vlog_error("Unable to load WAV file: %s", Mix_GetError());
|
|
}
|
|
}
|
|
|
|
void Dispose()
|
|
{
|
|
/* Destroy all track voices, SDL_free buffer from LoadWAV */
|
|
Mix_FreeChunk(m_sound);
|
|
}
|
|
|
|
void Play()
|
|
{
|
|
/* Fire-and-forget from a per-track FAudioSourceVoice pool */
|
|
if (Mix_PlayChannel(-1, m_sound, 0) == -1)
|
|
{
|
|
vlog_error("Unable to play WAV file: %s", Mix_GetError());
|
|
}
|
|
}
|
|
|
|
static void Init(int audio_rate, int audio_channels)
|
|
{
|
|
const Uint16 audio_format = AUDIO_S16SYS;
|
|
const int audio_buffers = 1024;
|
|
|
|
/* FAudioCreate, FAudio_CreateMasteringVoice */
|
|
if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0)
|
|
{
|
|
vlog_error("Unable to initialize audio: %s", Mix_GetError());
|
|
SDL_assert(0 && "Unable to initialize audio!");
|
|
}
|
|
}
|
|
|
|
static void Pause()
|
|
{
|
|
/* FAudio_StopEngine */
|
|
Mix_Pause(-1);
|
|
}
|
|
|
|
static void Resume()
|
|
{
|
|
/* FAudio_StartEngine */
|
|
Mix_Resume(-1);
|
|
}
|
|
|
|
static void SetVolume(int soundVolume)
|
|
{
|
|
/* FAudioVoice_SetVolume on all sounds. Yeah, all of them :/
|
|
* If we get desperate we can use a submix and set volume on that, but
|
|
* the submix is an extra mix stage so just loop all sounds manually...
|
|
*/
|
|
Mix_Volume(-1, soundVolume);
|
|
}
|
|
|
|
private:
|
|
Mix_Chunk *m_sound;
|
|
};
|
|
|
|
class MusicTrack
|
|
{
|
|
public:
|
|
MusicTrack(SDL_RWops *rw)
|
|
{
|
|
/* Open an stb_vorbis handle */
|
|
m_music = Mix_LoadMUS_RW(rw, 1);
|
|
if (m_music == NULL)
|
|
{
|
|
vlog_error("Unable to load Magic Binary Music file: %s", Mix_GetError());
|
|
}
|
|
}
|
|
|
|
void Dispose()
|
|
{
|
|
/* Free stb_vorbis */
|
|
Mix_FreeMusic(m_music);
|
|
}
|
|
|
|
bool Play(bool loop)
|
|
{
|
|
/* Create/Validate static FAudioSourceVoice, begin streaming */
|
|
if (Mix_PlayMusic(m_music, loop ? -1 : 0) == -1)
|
|
{
|
|
vlog_error("Mix_PlayMusic: %s", Mix_GetError());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void Halt()
|
|
{
|
|
/* FAudioVoice_Destroy */
|
|
Mix_HaltMusic();
|
|
}
|
|
|
|
static bool IsHalted()
|
|
{
|
|
/* return musicVoice == NULL; */
|
|
return Mix_PausedMusic() == 1;
|
|
}
|
|
|
|
static void Pause()
|
|
{
|
|
/* FAudioSourceVoice_Pause */
|
|
Mix_PauseMusic();
|
|
}
|
|
|
|
static void Resume()
|
|
{
|
|
/* FAudioSourceVoice_Resume */
|
|
Mix_ResumeMusic();
|
|
}
|
|
|
|
static void SetVolume(int musicVolume)
|
|
{
|
|
/* FAudioSourceVoice_SetVolume */
|
|
Mix_VolumeMusic(musicVolume);
|
|
}
|
|
|
|
private:
|
|
Mix_Music *m_music;
|
|
};
|
|
|
|
static std::vector<SoundTrack> soundTracks;
|
|
static std::vector<MusicTrack> musicTracks;
|
|
|
|
/* End SDL_mixer wrapper */
|
|
|
|
musicclass::musicclass(void)
|
|
{
|
|
SoundTrack::Init(44100, 2);
|
|
|
|
safeToProcessMusic= false;
|
|
m_doFadeInVol = false;
|
|
m_doFadeOutVol = false;
|
|
musicVolume = 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("data/" 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"))
|
|
{
|
|
if (pppppp_blob.unPackBinary("vvvvvvmusic.vvv"))
|
|
{
|
|
vlog_info("Loading music from PPPPPP blob...");
|
|
|
|
mmmmmm = false;
|
|
usingmmmmmm=false;
|
|
|
|
int index;
|
|
SDL_RWops* rw;
|
|
|
|
#define FOREACH_TRACK(blob, track_name) \
|
|
index = blob.getIndex("data/" track_name); \
|
|
rw = SDL_RWFromMem(blob.getAddress(index), blob.getSize(index)); \
|
|
musicTracks.push_back(MusicTrack( rw ));
|
|
|
|
TRACK_NAMES(pppppp_blob)
|
|
|
|
#undef FOREACH_TRACK
|
|
}
|
|
else
|
|
{
|
|
vlog_info("Loading music from loose files...");
|
|
|
|
SDL_RWops* rw;
|
|
#define FOREACH_TRACK(_, track_name) \
|
|
rw = PHYSFSRWOPS_openRead(track_name); \
|
|
musicTracks.push_back(MusicTrack( rw ));
|
|
|
|
TRACK_NAMES(_)
|
|
|
|
#undef FOREACH_TRACK
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vlog_info("Loading PPPPPP and MMMMMM blobs...");
|
|
|
|
mmmmmm = true;
|
|
int index;
|
|
SDL_RWops *rw;
|
|
|
|
#define FOREACH_TRACK(blob, track_name) \
|
|
index = blob.getIndex("data/" track_name); \
|
|
if (index >= 0 && index < blob.max_headers) \
|
|
{ \
|
|
rw = SDL_RWFromConstMem(blob.getAddress(index), blob.getSize(index)); \
|
|
if (rw == NULL) \
|
|
{ \
|
|
vlog_error("Unable to read music file header: %s", 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!");
|
|
|
|
TRACK_NAMES(pppppp_blob)
|
|
|
|
#undef FOREACH_TRACK
|
|
}
|
|
|
|
num_pppppp_tracks += musicTracks.size() - num_mmmmmm_tracks;
|
|
|
|
SDL_RWops* rw;
|
|
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)
|
|
{
|
|
soundTracks[i].Dispose();
|
|
}
|
|
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
|
|
MusicTrack::Halt();
|
|
|
|
for (size_t i = 0; i < musicTracks.size(); ++i)
|
|
{
|
|
musicTracks[i].Dispose();
|
|
}
|
|
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))
|
|
{
|
|
vlog_error("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 (musicTracks[t].Play(false))
|
|
{
|
|
m_doFadeInVol = false;
|
|
m_doFadeOutVol = false;
|
|
musicVolume = VVV_MAX_VOLUME;
|
|
MusicTrack::SetVolume(musicVolume);
|
|
}
|
|
}
|
|
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 (musicTracks[t].Play(true))
|
|
{
|
|
m_doFadeInVol = false;
|
|
m_doFadeOutVol = false;
|
|
fadeMusicVolumeIn(3000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void musicclass::resume()
|
|
{
|
|
MusicTrack::Resume();
|
|
}
|
|
|
|
void musicclass::resumefade(const int fadein_ms)
|
|
{
|
|
resume();
|
|
fadeMusicVolumeIn(fadein_ms);
|
|
}
|
|
|
|
void musicclass::fadein(void)
|
|
{
|
|
resumefade(3000); // 3000 ms fadein
|
|
}
|
|
|
|
void musicclass::pause(void)
|
|
{
|
|
MusicTrack::Pause();
|
|
}
|
|
|
|
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;
|
|
m_doFadeInVol = false;
|
|
m_doFadeOutVol = false;
|
|
}
|
|
|
|
struct FadeState
|
|
{
|
|
int start_volume;
|
|
int end_volume;
|
|
int duration_ms;
|
|
int step_ms;
|
|
};
|
|
|
|
static struct FadeState fade;
|
|
|
|
enum FadeCode
|
|
{
|
|
Fade_continue,
|
|
Fade_finished
|
|
};
|
|
|
|
static enum FadeCode processmusicfade(struct FadeState* state, int* volume)
|
|
{
|
|
int range;
|
|
int new_volume;
|
|
|
|
if (state->duration_ms == 0 /* Fast path. */
|
|
|| state->start_volume == state->end_volume /* Fast path. */
|
|
|| state->step_ms >= state->duration_ms /* We're finished. */)
|
|
{
|
|
*volume = state->end_volume;
|
|
state->step_ms = 0;
|
|
return Fade_finished;
|
|
}
|
|
|
|
range = state->end_volume - state->start_volume;
|
|
new_volume = range * state->step_ms / state->duration_ms;
|
|
new_volume += state->start_volume;
|
|
|
|
*volume = new_volume;
|
|
|
|
state->step_ms += game.get_timestep();
|
|
|
|
return Fade_continue;
|
|
}
|
|
|
|
void musicclass::fadeMusicVolumeIn(int ms)
|
|
{
|
|
if (halted())
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_doFadeInVol = true;
|
|
m_doFadeOutVol = false;
|
|
|
|
/* Ensure it starts at 0 */
|
|
musicVolume = 0;
|
|
|
|
/* Fix 1-frame glitch */
|
|
MusicTrack::SetVolume(0);
|
|
|
|
fade.step_ms = 0;
|
|
fade.duration_ms = ms;
|
|
fade.start_volume = 0;
|
|
fade.end_volume = VVV_MAX_VOLUME;
|
|
}
|
|
|
|
void musicclass::fadeMusicVolumeOut(const int fadeout_ms)
|
|
{
|
|
if (halted())
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_doFadeInVol = false;
|
|
m_doFadeOutVol = true;
|
|
|
|
fade.step_ms = 0;
|
|
/* Duration is proportional to current volume. */
|
|
fade.duration_ms = fadeout_ms * musicVolume / VVV_MAX_VOLUME;
|
|
fade.start_volume = musicVolume;
|
|
fade.end_volume = 0;
|
|
}
|
|
|
|
void musicclass::fadeout(const bool quick_fade_ /*= true*/)
|
|
{
|
|
fadeMusicVolumeOut(quick_fade_ ? 500 : 2000);
|
|
quick_fade = quick_fade_;
|
|
}
|
|
|
|
void musicclass::processmusicfadein(void)
|
|
{
|
|
enum FadeCode fade_code = processmusicfade(&fade, &musicVolume);
|
|
if (fade_code == Fade_finished)
|
|
{
|
|
m_doFadeInVol = false;
|
|
}
|
|
}
|
|
|
|
void musicclass::processmusicfadeout(void)
|
|
{
|
|
enum FadeCode fade_code = processmusicfade(&fade, &musicVolume);
|
|
if (fade_code == Fade_finished)
|
|
{
|
|
musicVolume = 0;
|
|
m_doFadeOutVol = false;
|
|
haltdasmusik();
|
|
}
|
|
}
|
|
|
|
void musicclass::processmusic(void)
|
|
{
|
|
if(!safeToProcessMusic)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(m_doFadeInVol)
|
|
{
|
|
processmusicfadein();
|
|
}
|
|
|
|
if (m_doFadeOutVol)
|
|
{
|
|
processmusicfadeout();
|
|
}
|
|
|
|
/* This needs to come after processing fades */
|
|
if (nicefade && halted())
|
|
{
|
|
play(nicechange);
|
|
nicechange = -1;
|
|
nicefade = false;
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
static const int areamap[] = {
|
|
4, 3, 3, 3, 3, 3, 3, 3, 4,-2, 4, 4, 4,12,12,12,12,12,12,12,
|
|
4, 3, 3, 3, 3, 3, 3, 4, 4,-2, 4, 4, 4, 4,12,12,12,12,12,12,
|
|
4, 4, 4, 4, 3, 4, 4, 4, 4,-2, 4, 4, 4, 4,12,12,12,12,12,12,
|
|
4, 4, 4, 4, 3, 4, 4, 4, 4,-2, 4, 4, 1, 1, 1, 1,12,12,12,12,
|
|
4, 4, 3, 3, 3, 4, 4, 4, 4,-2,-2,-2, 1, 1, 1, 1, 4, 4, 4, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 1, 1, 1, 1, 1, 1,11,11,-1, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 1, 1, 1, 1, 1, 1, 1,11,11,11,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1,11,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3,
|
|
4, 4, 4, 4, 4, 4, 4, 4,-2,-2, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4,
|
|
4, 4,-1,-1,-1, 4, 4, 4, 4,-2, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4,
|
|
4, 4,-1,-1,-1, 4, 4, 4, 4,-2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4, 1, 1, 1, 1, 1, 1, 4, 1, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4, 1, 1, 1, 1, 1, 1, 4, 1, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4,-1,-3, 4, 4, 4, 4, 4, 1, 4,
|
|
4, 4, 4, 4, 4, 3, 3, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
4, 4, 3, 3, 3, 3, 3, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
4, 3, 3, 3, 3, 3, 3, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
3, 3, 3, 3, 3, 4, 4, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
3, 3, 3, 3, 3, 4, 4, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
|
};
|
|
|
|
SDL_COMPILE_TIME_ASSERT(areamap, SDL_arraysize(areamap) == 20 * 20);
|
|
|
|
void musicclass::changemusicarea(int x, int y)
|
|
{
|
|
int room;
|
|
int track;
|
|
|
|
if (script.running)
|
|
{
|
|
return;
|
|
}
|
|
|
|
room = musicroom(x, y);
|
|
|
|
if (!INBOUNDS_ARR(room, areamap))
|
|
{
|
|
SDL_assert(0 && "Music map index out-of-bounds!");
|
|
return;
|
|
}
|
|
|
|
track = areamap[room];
|
|
|
|
switch (track)
|
|
{
|
|
case -1:
|
|
/* Don't change music. */
|
|
return;
|
|
case -2:
|
|
/* Special case: Tower music, changes with Flip Mode. */
|
|
if (graphics.setflipmode)
|
|
{
|
|
track = 9; /* ecroF evitisoP */
|
|
}
|
|
else
|
|
{
|
|
track = 2; /* Positive Force */
|
|
}
|
|
break;
|
|
case -3:
|
|
/* Special case: start of Space Station 2. */
|
|
if (game.intimetrial)
|
|
{
|
|
track = 1; /* Pushing Onwards */
|
|
}
|
|
else
|
|
{
|
|
track = 4; /* Passion for Exploring */
|
|
}
|
|
break;
|
|
}
|
|
|
|
niceplay(track);
|
|
}
|
|
|
|
void musicclass::playef(int t)
|
|
{
|
|
if (!INBOUNDS_VEC(t, soundTracks))
|
|
{
|
|
return;
|
|
}
|
|
soundTracks[t].Play();
|
|
}
|
|
|
|
void musicclass::pauseef(void)
|
|
{
|
|
SoundTrack::Pause();
|
|
}
|
|
|
|
void musicclass::resumeef(void)
|
|
{
|
|
SoundTrack::Resume();
|
|
}
|
|
|
|
bool musicclass::halted(void)
|
|
{
|
|
return MusicTrack::IsHalted();
|
|
}
|
|
|
|
void musicclass::updatemutestate(void)
|
|
{
|
|
if (game.muted)
|
|
{
|
|
MusicTrack::SetVolume(0);
|
|
SoundTrack::SetVolume(0);
|
|
}
|
|
else
|
|
{
|
|
SoundTrack::SetVolume(VVV_MAX_VOLUME * user_sound_volume / USER_VOLUME_MAX);
|
|
|
|
if (game.musicmuted)
|
|
{
|
|
MusicTrack::SetVolume(0);
|
|
}
|
|
else
|
|
{
|
|
MusicTrack::SetVolume(musicVolume * user_music_volume / USER_VOLUME_MAX);
|
|
}
|
|
}
|
|
}
|