1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-07-01 08:58:31 +02:00
Commit Graph

122 Commits

Author SHA1 Message Date
Misa
397d7f21b4 Add length check to OGG check
Dav999 pointed out this potential issue on Discord.

While basically all memcmp implementations will terminate early here if
there's a null byte (because it's mismatched), it doesn't hurt to add
the check here.
2023-03-19 14:05:51 -07:00
Misa
ba7519106f Add support for sound OGG files
This adds support for OGG files as sound effects (via renaming them to
the wrong .wav file extension), because in previous versions of the
game, SDL_mixer didn't care what the file extension was, and so some
people relied on this, as described in #900.

This is accomplished by copy-pasting the OGG loading code for music
tracks. For a bit of cleanliness, I put the WAV and OGG loading code in
separate functions.

This is mostly the same code, except that because sound effects don't
loop and can't be paused or resumed, there's no reserve buffer, and
there's no data for loop points.

Also, for some reason, the music loading code divided by 20 in the
`size` calculation. I found that this prematurely cut off sound effects,
and that it made more sense to just not do the division. I don't know
why it was there, but removing it works.

Also also, some OGG files don't work with this. Namely, ones produced by
FFmpeg. To test this, I just extracted 0levelcomplete.ogg from
vvvvvvmusic.vvv and replaced terminal.wav with it. And it works, so
hopefully I won't have to touch audio code again, although I might if
someone complains about this. But either way, I'm committing this
because it's better than it was before.

Fixes #900.
2023-03-18 18:24:30 -07:00
Misa
05ed7e041c Use VVV_freefunc to call stb_vorbis_close
I noticed that this call wasn't using VVV_freefunc. I missed it earlier
when going through Music.cpp and checking for instances when
VVV_freefunc should have been used
(a926ce9851).
2023-03-18 17:51:55 -07:00
Misa
d6bc319535 Add sample rate mismatch check to sound effects
Sound effects already get recreated if the number of channels
mismatches, but the same could be true if the sample rate mismatches
too, which was the case with music tracks as described in #886.

So, just to be sure - and to be consistent with music tracks - sound
effects now check that the sample rate matches, too, and if not, will be
recreated.
2023-03-18 16:40:24 -07:00
Misa
d54e98200f Fix loading sounds with non-16 bit depths
This fixes an issue where sound effects of bit depths that weren't 16,
such as 8, were being played incorrectly, as described in #886.

The problem is that when loading the sound effect, we would always set
the bit depth to 16 no matter what! Instead, we should set the bit depth
to the actual bit depth of the file.

Fixes #886.
2023-03-18 16:38:28 -07:00
Misa
671c90f7dc Fix music playing wrong if played after track of different format
As described in #886, if a track was played when an existing track was
already playing, and the sample rates of the two tracks differ, then the
second track would play wrong and distorted.

This is because the second track would play with the sample rate of the
first. To fix this, halt the track if the sample rate is mismatched,
which destroys the voice. This results in the voice being recreated
later in the Play() function. The track is also halted if the number of
channels or bit depth is mismatched.

Fixes #886.
2023-03-18 16:30:19 -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
Misa
63bc71b796 Always add null terminator when loading files
This removes the `addnull` argument from `FILESYSTEM_loadFileToMemory`
and `FILESYSTEM_loadAssetToMemory`, and makes it so a null terminator is
always appended no matter what.

This simplifies things and removes the need for callers to make the
decision about null termination and what its implications are. Then you
get cases where null termination might not happen when it should be,
such as the one df577c59ef (#947) fixed.

When FIQ added the `addnull` argument in
5862af4445 (#117), I'm guessing he did it
because he wanted to be cautious about adding the null terminator to
every file, so he only did it for XML files, which was the only case
needed at the time. But really, there's no downsides to always appending
a null terminator. In fact, it's already always done whenever the STDIN
buffer is loaded.
2023-03-18 15:12:24 -07:00
Misa
a926ce9851 Replace all free calls with VVV_free[func]
This replaces all calls to SDL_free with a new macro, VVV_free, that
nulls the pointer afterwards. This mitigates any use-after-frees and
also completely eliminates double-frees. The same is done for any
function to free specific objects such as SDL_FreeSurface, with the
VVV_freefunc macro.

No exceptions for any of these calls, even if the pointer is discarded
or zeroed afterwards anyway. Better safe than sorry.

This is a macro rather than a function that takes in a
pointer-to-pointer because such a function would have type issues that
require casting and that's just not safe.

Even though SDL_free and other SDL functions already check for NULL, the
macro has a NULL check for other functions that don't. For example,
FAudioVoice_DestroyVoice does not check for NULL.

FILESYSTEM_freeMemory has been axed in favor of VVV_free because it
functionally does the same thing except for `unsigned char*` only.
2022-11-30 22:50:08 -08:00
Misa
876362365b Ignore comments of tracks with a negative loop comment
If a music track has a loop comment with a negative value, ignore all
comments of the track. This is just to prevent any weirdness from
happening as it's safer to just let the track loop improperly. Also log
to the console to let users know.

This is the same thing that SDL_mixer does now:
libsdl-org/SDL_mixer@e819489459

This commit happened as a result of discussion on the VVVVVV Discord
server about SDL_mixer 2.0.4 behavior with weird loop comment values
(e.g. octal input with leading zeroes). This is simply updating the code
to be in line with what newer versions of SDL_mixer do.
2022-11-13 19:51:56 -08:00
Misa
fb13e652fa Check for SDL_strdup failure in parseComments
Just in case it happens. Comments aren't really important to the game
(at worst a track will just loop in the wrong place) so it's fine to
carry on here and ignore all comments if this happens.
2022-11-13 19:41:32 -08:00
Misa
27e04e9dbf Fix up style in parseComments
This does the following:

- Wrap lines that are too long (around 80 columns)
- Place the asterisk with the type instead of the variable name
2022-11-13 19:31:01 -08:00
Misa
6dd9200503 Fix up style in _Mix_ParseTime
This does the following:

- Const-qualify variables if they are not modified
- Place each statement onto their own separate lines
- Place the asterisk with the type instead of the variable name
- Combine declarations and initializations where possible
2022-11-13 19:11:50 -08:00
Misa
058fb9fff0 Fix warning: use of non-static data member initialization
This fixes the following warnings:

desktop_version/src/Music.cpp: At global scope:
desktop_version/src/Music.cpp:240:23: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  240 |     Uint8 *wav_buffer = NULL;
      |                       ^
desktop_version/src/Music.cpp:414:32: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  414 |     Uint8* decoded_buf_playing = NULL;
      |                                ^
desktop_version/src/Music.cpp:415:32: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  415 |     Uint8* decoded_buf_reserve = NULL;
      |                                ^
desktop_version/src/Music.cpp:416:21: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  416 |     Uint8* read_buf = NULL;
      |                     ^

These warnings are because the non-static data members (i.e. data
members that will be different for each instance of a class) are being
initialized at the same time as they're being declared, which means
that's what their value will be when the class instance is initialized.

However, this is only a C++11 feature, and we don't use C++11. Luckily,
we don't need to do this, and this is in fact redundant because we
already zero out the class instance in its constructor using
SDL_zerop(). Therefore, we should remove these initializers to fix
compliance with C++03.
2022-07-28 16:48:58 -07:00
Misa
dca3c9600c Explicitly initialize SoundTrack::volume
While this is not needed because it's a static variable, it doesn't hurt
to be explicit, especially if it's going to be refactored in the future.
2022-06-10 11:17:38 -07:00
N00byKing
c077500d16 Fix semi random volume jumps 2022-06-10 11:16:45 -07:00
N00byKing
e16c1557fa Fix music changes between areas 2022-04-10 14:17:46 -07:00
Misa
e47781f92f SoundTrack::Init: Remove unused audio_channels arg
Missed this when reviewing the FAudio PR, so I'll just remove it now.
2022-03-31 11:13:57 -07:00
N00byKing
f877eb3b56 Port to FAudio 2022-03-24 16:19:29 -07:00
Misa
a8feba029f Clean up and harden music loading code
During review of #869, I looked at this part of the codebase again. I
have no idea how or why, but during the course of 2.4 this whole area
just became a mess.

The issues I fixed (in no particular order):
- Copy-pasting the code that loads from the binary blobs
- Making sure SDL_RWFromConstMem is used over SDL_RWFromMem wherever
  possible
- Adding checks to make sure the index from the binary blob is valid
  (it's possible it could not exist)
- Adding checks to make sure we gracefully handle
  SDL_RWFromConstMem/PHYSFSRWOPS_openRead returning NULL
- Moving the pointer asterisk to the type instead of the name :)
2022-03-24 09:38:47 -07:00
Ethan Lee
84f9bb6dd6 Point to SDL_LoadWAV for SoundTrack FAudio suggestion 2022-01-15 01:02:24 -05:00
Ethan Lee
3b18a475dd Move MusicTrack below SoundTrack.
It's very likely that MusicTrack will be pulling from the SoundTrack FAudio
context, so make it so forward declarations are unnecessary.
2022-01-14 17:24:22 -05:00
Ethan Lee
adcabb9483 Add notes for FAudio implementation 2022-01-14 17:11:16 -05:00
Ethan Lee
5202b80a3d Remove unused m_isValid value from MusicTrack 2022-01-14 16:56:00 -05:00
Ethan Lee
d36741fa07 Move the Mix_OpenAudio call to SoundTrack, from MusicTrack.
In hindsight, the FAudio pointer will likely be in SoundTrack since we will
want to keep the mastering voice closer to the sounds and their source voice
arrays, while the MusicTrack will likely just be one source voice that gets
PCM from different streams.
2022-01-14 16:52:52 -05:00
Ethan Lee
df618e6d22 Isolate all SDL_mixer references to SoundTrack/MusicTrack.
This looks redundant but will actually help in the transition to FAudio; we
mostly want to keep the game logic the same while reimplementing the current
mixer, weirdness and all. Once that's done and confirmed to be stable and
consistent we can start cutting out the workarounds and quirks.
2022-01-14 16:46:04 -05: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
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
58ae93c4cc Music: Do not do fades if not playing
This fixes a regression where entering playtesting while a track was
fading out (by exiting out of playtesting with a track playing and then
immediately entering back in with the level start music set) would
result in no music.

The cause is the game doing fades even though nothing is playing, which
puts it in a confusing state.
2021-09-10 19:37:33 -07: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
74b7ce9d80 Reset fade booleans when silencing music
This fixes a bug where the music would keep playing when a collection
prompt appeared if the music was still fading in at that time.
2021-09-10 17:02:24 -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
727400ff27 Only reset fade booleans when music is actually played
Otherwise, the block that fades existing music out if m_doFadeOutVol is
true will never execute, because m_doFadeOutVol would always be false!
2021-09-03 16:38:34 -07:00
Misa
96539f891c Replace all print calls with vlog calls
This is pretty straight-forward to do.
2021-09-01 14:34:55 -07:00
leo60228
f86a67456b Remove data/ from track name list, refactor music loading, and support loose ogg music
(these should be separate commits but they're annoying to split after
the fact, oh well)
2021-08-31 15:30:23 -07:00
Misa
8329afc6df Replace main game music with music area map
The main game used a set of copy-pasted code to set the music of each
area. There WAS some redundancy built-in, but only three rooms in each
direction from the entrance of a zone.

Given this, it's completely possible for players to mismatch the music
of the area and level. In fact, it's easy to do it even on accident,
especially since 2.3 now lets you quicksave and quit during cutscenes.
Just play a cutscene that has Pause music, then quicksave, quit, and
reload. Also some other accidental ways that I've forgotten about.

To fix this, I've done what mapclass has and made an areamap. Except for
music. This map is the map of the track number of every single room,
except for three special cases: -1 for do nothing and don't change music
(usually because multiple different tracks can be played in this room),
-2 for Tower music (needs to be track 2 or 9 depending on Flip Mode),
and -3 for the start of Space Station 2 (track 1 in time trials, track 4
otherwise).

I've thoroughly tested this areamap by playing through the game and
entering every single room. Additionally I've also thoroughly tested all
special cases (entering the Ship through the teleporter or main
entrance, using the Ship's jukebox, the Tower in Flip Mode and regular
mode, and the start of Space Station 2 in time trial and in regular
mode).

Closes #449.
2021-08-22 20:35:06 -07:00
Misa
2af04ad0fa Make fade out duration proportional to volume
This is the same behavior as SDL_mixer. Else, a fadeout would last the
same amount of time no matter the volume, which is a regression.
2021-08-22 16:57:13 -07:00
Misa
ad88939dbb Fix regression with niceplay() moving back and forth between zones
2.3 has a regression where if you move back and forth between a zone,
you can get the wrong music playing in a zone. An example is the
Overworld and Lab. Just walk in to the Lab and immediately walk back
out, and you'll get Potential for Anything playing in the Overworld.

This regression was caused by facb079b35.
That commit removed assigning -1 to currentsong when a fadeout was
called.

Basically, the previous behavior was: currentsong is 4, we enter Lab and
nicechange gets queued to 3 but currentsong gets set to -1, then going
back nicechange gets queued to 4 again.

However, if we don't assign -1, then going back will keep nicechange at
3. Why? Because niceplay() checks for currentsong before assigning
nicechange. If currentsong is still the same then it doesn't assign
nicechange.

To fix this, just always unconditionally assign nicechange.
2021-08-22 16:57:11 -07:00
Misa
1c3274645d Fix up style in musicclass::play()
- Multiline comment instead of single-line.
- Spacing fixes.
- Long line broken up into smaller ones.
2021-08-22 15:27:39 -07:00
Ethan Lee
43e8d31aa9 Music: Enforce the quick fade time as soon as we know it's happening.
Not every music path will trip the quick_fade bool that resets the timer to
500ms, so we need to do this as soon as it's asked of us. This fixes the fade
when quitting to the main menu.

Fixes #764
2021-06-14 15:11:39 -04:00
Ethan Lee
8520533296 Music: Reset step_ms on every fade call.
Without this you end up with two problems:
- Fades will start past their fade time, causing it to just not fade at all
- Fades will start in the middle of their fade time, causing dramatic changes
  in volume that are unintentional

The fade system already preserves the volume that music is playing during a
previous fade, so we can always reset the timer and get a good result.

Part of #764
2021-06-14 15:09:23 -04:00
Misa
6e9fc8e923 Call Mix_VolumeMusic() when playing tracks 0 and 7
This fixes issues where they would be silent for 1 frame due to frame
ordering, resulting in a weird-sounding beginning of these tracks due to
a lack of attack (in the musical sense).

This is similar to the issue where tracks fading in would suddenly be
loud for 1 frame, again due to frame ordering.
2021-04-27 20:33:44 -04:00
Misa
cd38d2ca12 Reset fade booleans when starting music
This fixes issues with music playing, only for it to fade out
afterwards. This happened if tracks 0 or 7 were played after fading out,
because playing other tracks reset the fade booleans (by calling a
fade-in), but not tracks 0 or 7.
2021-04-27 20:33:44 -04: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
be9a6382ea Fix playing same track after it has faded out
If a track was restarted after it faded out, then it wouldn't play. This
is because currentsong wasn't set to -1 after fading out, and that is
because the fade out calls pause() instead of haltdasmusik() when it
finishes.

Unlike f196fcd896, this fixes the time
trial music while keeping it to the same behavior as 2.2, and fixes
every single possible case that this music bug could have happened.
2021-04-14 13:02:00 -04:00
Misa
488916b51c Process queued music after processing fades
While fixing all the other music bugs, I discovered that starting
playtesting in the editor wouldn't play the level music.

The problem is that the editor playtesting start code calls
music.fadeout() before calling music.play(). This queues up the track
from the music.play() call. After that, what should happen is that
processmusic() processes the fade, the fade is then finished, and then
after that it sees that the music is halted so it can play the queued
track.

Instead what happens is that the function first attempts to play the
music before the fade is processed and finished, so play() will re-queue
the music again, but the queue gets cleared right after that (this is a
subtle bit of behavior - it means if the game fails to play a queued
track due to it fading, it's not going to re-queue it again and end up
in some sort of infinite loop).

This is a frame ordering issue - the function is tripping over itself
when it shouldn't be. To fix it, just put the queue processing code
after the fade processing code.
2021-04-12 16:17:31 -04:00
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
Misa
af2e6a2331 Fix 1-frame glitch when fading in from zero
The problem here is that even though we start playing the music when the
volume is set to zero, mixer's state doesn't have volume zero, so
whatever it plays next will be the very first quanta of the track but at
the previous volume (in this case, the maximum volume). To fix this,
just update mixer when we update the volume here - it's okay to not
account for user volume because it ends up being zero anyway.

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