1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-23 01:59:43 +01:00
Commit graph

40 commits

Author SHA1 Message Date
Misa
dc9c51dbf3 Implement haltedsong
This fixes a bug where if a track was resumed, pausing it by unfocusing
the window (if enabled, of course) would not resume it after refocusing
the window.

This happens because resuming the music doesn't change currentsong back
from -1, and the window refocusing code checks that currentsong isn't -1
before resuming music.

haltedsong is only used when resuming music. It is set back to -1 when
resuming music or when playing a new track.
2023-06-08 15:38:26 -07:00
Misa
4058975ce9 Use enums for sound effects
This adds an anonymous enum for sound effects and replaces all calls to
music.playef that use integer literals.

This is not a named enum (that can be used for strict typechecking)
because sound effect IDs are essentially part of the API of the game -
many custom levels use these numbers. This is just to make the source
code more readable without needing a comment to denote what number is
what sound.
2023-06-05 17:57:23 -07:00
Misa
cdeca65be7 Use enums for music tracks
This adds an anonymous enum for music tracks and replaces all calls to
music.play and music.niceplay that use integer literals. Additionally,
this is also done for integer literals for cl.levmusic (except 0) and
music.currentsong where appropriate, but _not_ the music areamap because
that would not make it look very aesthetically pleasing in the code.

This is not a named enum (that can be used for strict typechecking)
because music track IDs are essentially part of the API of the game -
almost every custom level uses these numbers. This is just to make the
source code more readable without needing a comment to denote what
number is what track.
2023-06-05 17:57:23 -07:00
Misa
5fbdf2b663 Fix regression with music fade transitions not working
Unfortunately, 1de459d9b4 caused a
regression where musicclass::niceplay() didn't work, because fading out
the music would cause haltdasmusik() to be called, which would reset the
fade variables.

To fix this, haltdasmusik() will now only reset the fade variables if
it's not called from a fade, which is signaled with a function
parameter.
2023-04-05 19:32:42 -07:00
Misa
9a87d23719 Style: Fixup instances of void arguments
The style we have here is that functions with no arguments are to have
explicit `void` arguments, even though this doesn't apply in C++,
because it does apply in C.

Unfortunately, some have slipped through the cracks. This commit fixes
them.
2023-03-18 15:28:33 -07:00
Ethan Lee
81aa02e29b SDL_mixer is now entirely contained in Music.cpp.
This meant making the track vectors static, but that's kind of what we do with musicclass anyway?

In any case, this will make the transition to FAudio MUCH less invasive.
2021-12-26 08:57:38 -05:00
Ethan Lee
1eda3647ff Move the mute logic to musicclass.
This moves the last of the SDL_mixer calls to Music.cpp.
2021-12-26 08:48:23 -05:00
Ethan Lee
579f0f763a Update docs for MusicTrack/SoundTrack 2021-12-26 08:41:57 -05:00
Ethan Lee
230859f8f9 Inline SoundSystem into musicclass constructor 2021-12-26 08:41:01 -05:00
Ethan Lee
c87f0e1a0c Consolidate SoundSystem into Music.
It's just some small wrappers, and SoundSystem can be inlined trivially.
2021-12-26 08:38:19 -05:00
Misa
8e02b90b76 Move Mix_PausedMusic() call into wrapper function
This wrapper function is for (a) future-proofing (b) proactive
prevention of future copy-pasting (c) to clarify that we never actually
halt music in the SDL_mixer sense, we only pause it, so to check if the
music is halted we actually check if the music is paused instead. This
is important because Mix_PlayingMusic() does not check if the music is
paused and Mix_PausedMusic() does not check if the music is halted.
2021-09-10 19:37:31 -07:00
Misa
c64fd89325 Untabify every single file
YOLO.

This is a repeat of #642. As before, I just did

    rg -l '\t' | xargs -n 1 sed -i -e 's/\t/    /g'

inside the desktop_version/ folder.
2021-09-06 18:56:39 -07:00
Misa
1f5835c985 Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.

The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.

This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.

What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.

Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-27 20:33:44 -04:00
Misa
e8316c7e9a Implement music and sound volume sliders
This adds music and volume sliders to the audio options. To use the
sliders, you navigate to the given option, then press ACTION, and your
selection will be transferred to the slider. Pressing left or right will
move the slider accordingly. Then you can press ACTION to confirm the
volume is what you want and deselect it, or you can press Esc to cancel
the volume change, and it will revert to the previous volume; both
actions will write your settings to disk.

Most of this commit is just adding infrastructure to support having
sliders in menus (without copy-pasting code), which is a totally
completely new user interface that has never been used before in this
game. If we're going to be adding something new, I want to make sure
that it at least is done the RIGHT way.

Closes #706.
2021-04-11 20:56:16 -04:00
Misa
27874e1dc6 Add music and sound volume config options
This adds <musicvolume> and <soundvolume> tags to unlock.vvv and
settings.vvv, so users' volume preferences will be persistent across
game sessions. This does not add the user interface to change them from
in-game; the next commit will do that.
2021-04-11 20:56:16 -04:00
Misa
510ec07021 Re-fix resumemusic/musicfadein once again
So it looks like facb079b35 (PR #316) had
a few issues.

The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)

Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.

Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).

And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.

There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 16:13:54 -04:00
Misa
6d3a73c540 Add pause(), pauseef(), and resumeef() to musicclass
musicclass already had a resume() function for music.

These are just wrappers around the appropriate SDL_mixer functions, to
avoid direct function calls to the mixer API. So if we ever need to do
something with all callers of pausing and resuming in the future, or we
switch to a different audio backend, the work is already done for us.

Also it just looks cleaner to be calling our musicclass function instead
of doing a direct API call to the mixer.
2021-04-02 16:13:54 -04:00
Misa
92b3c0b413 Factor fade amount calculation to separate function
This makes it so to reuse this code, we don't have to copy-paste it.

Additionally, I added a check for the milliseconds being 0, to avoid a
division by zero. Logically and mathematically, if the fade amount is 0
milliseconds, then that means the fade should happen instantly -
however, dividing by zero is undefined (both in math and in C/C++), so
this check needs to be added.
2021-04-02 16:13:54 -04:00
Misa
6a3a1fe147
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.

This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.

I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 17:23:59 -05:00
Misa
77748f29f9 Separate musicReadBlob into mmmmmm_blob and pppppp_blob
musicReadBlob was used for both MMMMMM and PPPPPP soundtracks. This
causes a memory leak if you have mmmmmm.vvv installed, because the
pointers holding each allocated block of MMMMMM would be lost when
PPPPPP got loaded. Valgrind complains about this memory leak.

This is in contrast to 2.2 and previous behavior, where musicReadBlob
was only a temporary object instead of being held in musicclass.
However, this wasn't really a memory leak (moreso something that just
didn't get cleaned up when closing the game), but it did get turned into
a leak when per-level assets mounting and unmounting got introduced in
2.3 (loading a level with custom assets after starting the game with an
mmmmmm.vvv, or exiting out of a level that had an mmmmmm.vvv, would
cause the game to leak memory). Leo recognized this, and moved
musicReadBlob onto musicclass in a separate 2.3 PR, but either he didn't
think about what was happening here too closely, or he didn't use
Valgrind, because he forgot about the memory leak caused by re-using the
same binaryBlob for PPPPPP and MMMMMM.

So instead, just use two different binaryBlob objects for MMMMMM and
PPPPPP. That way, no memory leaks happen.
2021-02-15 23:07:35 -05:00
Misa
0ea1a0e28e Move musicclass cleanup to separate function musicclass::destroy()
This removes the music cleanup code from musicclass::init(), and
requires that we also call destroy() in Graphics::reloadresources().

This is because we'll need to re-use the musicclass cleanup code
elsewhere, and we don't want to copy-paste the cleanup code. Or at
least, I don't (but I'm not a game dev, game devs copy-paste all the
friggin' time).
2021-02-15 23:07:35 -05:00
Misa
98ef7a8675 Don't reset entire musicclass when mounting and unmounting assets
musicclass::init() re-initializes every attribute of musicclass
unnecessarily, when initialization should be put in a constructor
instead. This is bad, because music.init() gets called whenever we enter
and exit a custom level that has assets.

Otherwise, this would result in a bug where music.usingmmmmmm would be
reset, causing you to revert to PPPPPP on the title screen whenever you
enter a level with MMMMMM selected and exit it.

This also causes a confusing desync between game.usingmmmmmm and
music.usingmmmmmm since the values of the two variables are now
different (these duplicate variables should probably be removed, too,
and a lot of other duplicate variables like these exist, too, which are
a real headache). Which means despite MMMMMM playing on the title
screen, exiting the game and re-launching it will play PPPPPP instead.
What's even more is that going to game options and switching to PPPPPP
will play PPPPPP, but afterwards launching and re-entering will play
MMMMMM. Again, having duplicate variables is very bad, and should
probably be fixed, but that's a separate patch.
2020-11-12 19:11:13 -05:00
Misa
05b7a38f76 Clean up don't-quick-fade signaling
First, the variable has been inverted, because it's bad practice to have
booleans with negative names. Secondly, instead of magically setting a
signaling variable when calling fadeout(), fadeout() now has a parameter
to set the quick_fade attribute, which is much cleaner than doing the
magical assignment that could potentially look unrelated.
2020-11-06 06:09:31 -05:00
Misa
87af9bba04 Merge fadeoutqueuesong into nicechange
fadeoutqueuesong basically does the same thing as nicechange - they both
queue a song to be played when the current track is done fading out.
Except, for some reason, I decided to add fadeoutqueuesong instead of
using the existing nicechange/nicefade system.

This has consequences where fadeoutqueuesong would step on the toes of
nicechange. In the case of #390, nicechange would say "let's play
Potential for Anything" when entering the Super Gravitron, but
fadeoutqueuesong had previously said "let's play Pipe Dream" because of
the player having just exited the Super Gravitron. fadeoutqueuesong took
priority because it came first in musicclass::processfade(), and when it
called play(), the Mix_PlayingMusic() in the nicechange check afterwards
would say music would already be playing at that point, so the
nicechange wouldn't take effect.

In the end, the solution is to just merge the new system into the
already-existing system.

Fixes #390.
2020-11-06 06:09:31 -05:00
Misa
c1ca57e096 Change nicefade to bool instead of int
If it's treated like a bool, why shouldn't it be one?
2020-11-06 06:09:31 -05:00
Misa
cbceeccf78 Clean up and prevent unnecessary qualifiers to self
By "unnecessary qualifiers to self", I mean something like using the
'game.' qualifier for a variable on the Game class when you're inside a
function on the Game class itself. This patch is to enforce consistency
as most of the code doesn't have these unnecessary qualifiers.

To prevent further unnecessary qualifiers to self, I made it so the
extern in each header file can be omitted by using a define. That way,
if someone writes something referring to 'game.' on a Game function,
there will be a compile error.

However, if you really need to have a reference to the global name, and
you're within the same .cpp file as the implementation of that object,
you can just do the extern at the function-level. A good example of this
is editorinput()/editorrender()/editorlogic() in editor.cpp. In my
opinion, they should probably be split off into their own separate file
because editor.cpp is getting way too big, but this will do for now.
2020-09-28 01:34:40 -04:00
Misa
52f7a587fe Separate includes into sections and alphabetize them
Okay, so basically here's the include layout that this game now
consistently uses:

[The "main" header file, if any (e.g. Graphics.h for Graphics.cpp)]
[blank line]
[All system includes, such as tinyxml2/physfs/utfcpp/SDL]
[blank line]
[All project includes, such as Game.h/Entity.h/etc.]

And if applicable, another blank line, and then some special-case
include screwy stuff (take a look at editor.cpp or FileSystemUtils.cpp,
for example, they have ifdefs and defines with their includes).
2020-07-19 21:37:40 -04:00
Misa
7c2b418761 Account for extra tracks in musicclass::play()
Since each soundtrack is no longer guaranteed to be 16, we'll have to
account for their different lengths when playing music.
2020-06-30 21:07:05 -04:00
Misa
22738cdb97 Remove unused/useless vars music.custompd/musicfade(in)/volume
I have no idea why these are here, but it'll simplify readability and
reduce the chance of confusion if I remove them.
2020-06-27 17:23:07 -04:00
Misa
facb079b35 Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.

When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.

I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.

Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.

Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.

Other than that, these commands are now fully functional.
2020-06-27 17:23:07 -04:00
leo60228
f3b26904ec Don't leak binaryBlob 2020-06-07 22:40:03 -04:00
Misa
c278f05397 Remove duplicate function musicclass::stopmusic()
It is an exact duplicate of musicclass::haltdasmusik(), so use that
function instead and update callers. Looks like
musicclass::haltdasmusik() came first, anyway (musicclass::stopmusic()
was only used in editor.cpp).
2020-04-03 19:19:45 -04:00
Misa
34395435f0 Remove unused function musicclass::loopmusic()
Maybe back in the Flash days, you had to loop music manually instead of
having SDL_mixer handle it? Or something?
2020-04-03 19:19:45 -04:00
Misa
d3cdd33605 Remove unused function musicclass::processmusicfade()
It's a function that does nothing, and is also used by nothing.
2020-04-03 10:40:50 -04:00
Misa
eea2232c12 Remove outdated comments from Music.h and Music.cpp
Lots of stuff from the Flash version, especially in Music.h.
2020-04-03 10:40:50 -04:00
Misa
16c3966ace Remove unused argument from musicclass::playef()
Apparently the 'offset' argument did something in the 1.x Flash
versions, but now it does nothing.
2020-04-03 10:40:50 -04:00
Misa
253d44ac0b Remove unused function musicclass::initefchannels()
It's a function that does nothing, used by no one.
2020-04-03 10:40:50 -04:00
Info Teddy
5a316d65e6 Allow using help/graphics/music/game/key/map/obj everywhere
This commit makes `help`, `graphics`, `music`, `game`, `key`, `map`, and
`obj` essentially static global objects that can be used everywhere.
This is useful in case we ever need to add a new function in the future,
so we don't have to bother with passing a new argument in which means we
have to pass a new argument in to the function that calls that function
which means having to pass a new argument into the function that calls
THAT function, etc. which is a real headache when working on fan mods of
the source code.

Note that this changes NONE of the existing function signatures, it
merely just makes those variables accessible everywhere in the same way
`script` and `ed` are.

Also note that some classes had to be initialized after the filesystem
was initialized, but C++ would keep initializing them before the
filesystem got initialized, because I *had* to put them at the top of
`main.cpp`, or else they wouldn't be global variables.

The only way to work around this was to use entityclass's initialization
style (which I'm pretty sure entityclass of all things doesn't need to
be initialized this way), where you actually initialize the class in an
`init()` function, and so then you do `graphics.init()` after the
filesystem initialization, AFTER doing `Graphics graphics` up at the
top.

I've had to do this for `graphics` (but only because its child
GraphicsResources `grphx` needs to be initialized this way), `music`,
and `game`. I don't think this will affect anything. Other than that,
`help`, `key`, and `map` are still using the C++-intended method of
having ClassName::ClassName() functions.
2020-01-29 07:58:23 -05:00
Info Teddy
5419e822d8 Stop the game from freezing if we play a song during a fadeout (#61) 2020-01-12 22:33:58 -05:00
Ethan Lee
f7c0321b71 Hello WWWWWWorld! 2020-01-08 10:37:50 -05:00