Refactors sound file checking (#93734)

This commit is contained in:
FalloutFalcon
2025-11-10 09:58:26 -06:00
committed by GitHub
parent c70a1792d0
commit b0ddbf2fb1
9 changed files with 112 additions and 45 deletions

11
code/__DEFINES/files.dm Normal file
View File

@@ -0,0 +1,11 @@
// None of these should be trusted for the purpose of user input
// They do not check the actual type of the file, a user could just rename it
/// File types we can sniff the duration from using rustg.
#define IS_SOUND_FILE_SAFE(file) is_file_type_in_list(##file, SSsounds.safe_formats)
#define IS_SOUND_FILE(file) is_file_type_in_list(##file, SSsounds.byond_sound_formats)
#define IS_OGG_FILE(file) is_file_type(##file, "ogg")
#define IS_WAV_FILE(file) is_file_type(##file, "wav")
#define IS_MP3_FILE(file) is_file_type(##file, "mp3")

View File

@@ -136,3 +136,46 @@ GLOBAL_VAR_INIT(fileaccess_timer, 0)
if(.)
. += delimiter // Add the delimiter before each successive node.
. += SANITIZE_FILENAME(node)
/**
* Verifys wether a string or file ends with a given file type.
*
* this does not at all check the actual type of the file, a user could just rename it
*
* Arguments:
* * file - A string or file. No checks for if this file ACCTALLY exists
* * file_types - A list of strings to check against [e.g. list("ogg" = TRUE, "mp3" = TRUE)]
*/
/proc/is_file_type_in_list(file, file_types = list())
var/extstart = findlasttext("[file]", ".")
if(!extstart)
return FALSE
var/ext = copytext("[file]", extstart + 1)
if(file_types[ext])
return TRUE
/**
* Verifys wether a string or file ends with a given file type
*
* this does not at all check the actual type of the file, a user could just rename it
*
* Arguments:
* * file - A string or file. No checks for if this file ACCTALLY exists
* * file_type - A string to check against [e.g. "ogg"]
*/
/proc/is_file_type(file, file_type)
var/extstart = findlasttext("[file]", ".")
if(!extstart)
return FALSE
var/ext = copytext("[file]", extstart + 1)
if(ext == file_type)
return TRUE
/proc/strip_filepath_extension(file, file_types)
var/extstart = findlasttext("[file]", ".")
if(!extstart)
return "[file]"
var/ext = copytext("[file]", extstart)
if(ext in file_types)
return copytext("[file]", 1, extstart)
return "[file]"

View File

@@ -34,6 +34,50 @@ SUBSYSTEM_DEF(sounds)
/// Any errors from precaching.
VAR_PRIVATE/list/precache_errors = list()
// Comments from https://github.com/DaedalusDock/daedalusdock We love Francinum.
/// A list of sound formats that work in byond. Indexed for direct accesing rather then loop itteration or usage of `in`
var/static/list/byond_sound_formats = list(
"mid" = TRUE, //Midi, 8.3 File Name
"midi" = TRUE, //Midi, Long File Name
"mod" = TRUE, //Module, Original Amiga Tracker format
"it" = TRUE, //Impulse Tracker Module format
"s3m" = TRUE, //ScreamTracker 3 Module
"xm" = TRUE, //FastTracker 2 Module
"oxm" = TRUE, //FastTracker 2 (Vorbis Compressed Samples)
"wav" = TRUE, //Waveform Audio File Format, A (R)IFF-class format, and Microsoft's choice in the 80s sound format pissing match.
"ogg" = TRUE, //OGG Audio Container, Usually contains Vorbis-compressed Audio
//"raw" = TRUE, //On the tin, byond purports to support raw, uncompressed PCM Audio. I actually have no fucking idea how FMOD actually handles these.
//since they completely lack all information. As a confusion based anti-footgun, I'm just going to wire this to FALSE for now. It's here though.
"wma" = TRUE, //Windows Media Audio container
"aiff" = TRUE, //Audio Interchange File Format, Apple's side of the 80s sound format pissing match. It's also (R)IFF in a trenchcoat.
"mp3" = TRUE //MPeg Layer 3 Container (And usually, Codec.)
)
/// File types we can sniff the duration from using rustg.
var/static/list/safe_formats = list(
"ogg" = TRUE,
"mp3" = TRUE
)
// Currently set to private as I would prefer you use byond_sound_formats but you can unprivate it if you have a valid use!
// Put more common extensions first to speed this up a bit (So only ogg and mp3 lol.)
/// Similar to byond_sound_formats, a list of sound formats that work in byond.
VAR_PRIVATE/static/list/byond_sound_extensions = list(
".ogg",
".mp3",
".mid",
".midi",
".mod",
".it",
".s3m",
".xm",
".oxm",
".wav",
//".raw", See byond_sound_formats
".wma",
".aiff"
)
/datum/controller/subsystem/sounds/Initialize()
setup_available_channels()
find_all_available_sounds()
@@ -63,23 +107,7 @@ SUBSYSTEM_DEF(sounds)
/datum/controller/subsystem/sounds/proc/find_all_available_sounds()
all_sounds = list()
// Put more common extensions first to speed this up a bit
var/static/list/valid_file_extensions = list(
".ogg",
".wav",
".mid",
".midi",
".mod",
".it",
".s3m",
".xm",
".oxm",
".raw",
".wma",
".aiff",
)
all_sounds = pathwalk("sound/", valid_file_extensions)
all_sounds = pathwalk("sound/", byond_sound_extensions)
/// Removes a channel from using list.
/datum/controller/subsystem/sounds/proc/free_sound_channel(channel)

View File

@@ -73,21 +73,6 @@ SUBSYSTEM_DEF(ticker)
var/reboot_timer = null
/datum/controller/subsystem/ticker/Initialize()
var/list/byond_sound_formats = list(
"mid" = TRUE,
"midi" = TRUE,
"mod" = TRUE,
"it" = TRUE,
"s3m" = TRUE,
"xm" = TRUE,
"oxm" = TRUE,
"wav" = TRUE,
"ogg" = TRUE,
"raw" = TRUE,
"wma" = TRUE,
"aiff" = TRUE,
)
var/list/provisional_title_music = flist("[global.config.directory]/title_music/sounds/")
var/list/music = list()
var/use_rare_music = prob(1)
@@ -115,11 +100,8 @@ SUBSYSTEM_DEF(ticker)
music -= old_login_music
for(var/S in music)
var/list/L = splittext(S,".")
if(L.len >= 2)
var/ext = LOWER_TEXT(L[L.len]) //pick the real extension, no 'honk.ogg.exe' nonsense here
if(byond_sound_formats[ext])
continue
if(IS_SOUND_FILE(S))
continue
music -= S
if(!length(music))

View File

@@ -100,7 +100,7 @@
var/datum/track/new_track = new()
new_track.song_path = file("[global.config.directory]/jukebox_music/sounds/[track_file]")
var/list/track_data = splittext(track_file, "+")
if(length(track_data) < 3)
if(length(track_data) < 3 || !IS_SOUND_FILE(new_track.song_path))
continue
new_track.song_name = track_data[1]
new_track.song_length = text2num(track_data[2])

View File

@@ -100,13 +100,13 @@ ADMIN_VERB(create_command_report, R_ADMIN, "Create Command Report", "Create a co
if("set_report_sound")
if(params["picked_sound"] == CUSTOM_SOUND_PRESET)
played_sound = DEFAULT_ANNOUNCEMENT_SOUND // fallback by default
var/sound_file = input(ui_user, "Select sound file (OGG, WAV, MP3)", "Upload sound") as file|null
var/sound_file = input(ui_user, "Select sound file", "Upload sound") as sound|null
if(!sound_file)
tgui_alert(ui_user, "The custom sound could not be loaded. The standard sound will be played.", "Loading error", list("Ok"))
return
if(!(copytext("[sound_file]", -4) in list(".ogg", ".wav", ".mp3")))
tgui_alert(ui_user, "Invalid file type. Please select an OGG, WAV, or MP3 file.", "Loading error", list("Ok"))
if(!IS_SOUND_FILE(sound_file))
tgui_alert(ui_user, "Invalid file type. Please select a sound file.", "Loading error", list("Ok"))
return
played_sound = sound_file

View File

@@ -1,4 +1,5 @@
The enclosed /sounds folder holds the sound files used for player selectable songs for an ingame jukebox. OGG and WAV are supported.
The enclosed /sounds folder holds the sound files used for player selectable songs for an ingame jukebox.
OGG is the recommended sound format but see code/controllers/subsystem/sounds.dm for the rest of the supported ones.
Using unnecessarily huge sounds can cause client side lag and should be avoided.
@@ -12,4 +13,4 @@ Every sound you add must have a unique name. Avoid using the plus sign "+" and t
Sound names must be in the format of [song name]+[length in deciseconds]+[beat in deciseconds].ogg
A three minute song title "SS13" that lasted 3 minutes would have a file name SS13+1800+5.ogg
A three minute song title "SS13" that lasted 3 minutes would have a file name SS13+1800+5.ogg

View File

@@ -1,4 +1,5 @@
The enclosed /sounds folder holds the sound files used as the title music for the game. OGG and WAV are supported.
The enclosed /sounds folder holds the sound files used as the title music for the game.
OGG is the recommended sound format but see code/controllers/subsystem/sounds.dm for the rest of the supported ones.
Using unnecessarily huge sounds can cause client side lag and should be avoided.
@@ -23,7 +24,7 @@ Map Title Sounds:
Map sounds are tied to a specific in game map. To make a map title you format the name like this "(name of a map)+(name of your sound)"
The spelling of the map name is important. It must match exactly the define MAP_NAME found in the relevant .DM file in the /_maps folder in
The spelling of the map name is important. It must match exactly the define MAP_NAME found in the relevant .DM file in the /_maps folder in
the root directory. It can also be seen in game in the status menu. Note that there are no spaces between the two names.
It is absolutely fine to have more than one sound tied to the same map. It's also fine to have a rare map sound.

View File

@@ -102,6 +102,7 @@
#include "code\__DEFINES\explosions.dm"
#include "code\__DEFINES\external_organs.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
#include "code\__DEFINES\files.dm"
#include "code\__DEFINES\firealarm.dm"
#include "code\__DEFINES\fish.dm"
#include "code\__DEFINES\font_awesome_icons.dm"