From 8527946927875711e3e52a76bca99ea49ffa3a35 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Sun, 23 Jul 2017 07:03:16 -0400 Subject: [PATCH 1/3] Adds 3D Sound System --- code/__DEFINES/misc.dm | 3 +-- code/game/sound.dm | 48 ++++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 1cf9176f0f9..da53445f16b 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -164,8 +164,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define GAME_STATE_FINISHED 4 //SOUND: #define SOUND_MINIMUM_PRESSURE 10 -#define FALLOFF_SOUNDS 1 -#define SURROUND_CAP 7 +#define FALLOFF_SOUNDS 0.5 //FONTS: // Used by Paper and PhotoCopier (and PaperBin once a year). diff --git a/code/game/sound.dm b/code/game/sound.dm index 4b77222f19d..1e75914dffc 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,4 +1,4 @@ -/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, surround = 1, frequency = null, channel = 0, pressure_affected = TRUE) +/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, is_global = FALSE) soundin = get_sfx(soundin) // same sound for everyone @@ -14,25 +14,30 @@ channel = channel || open_sound_channel() // Looping through the player list has the added bonus of working for mobs inside containers - for (var/P in GLOB.player_list) + var/sound/S = sound(soundin) + var/maxdistance = (world.view + extrarange) * 3 + for(var/P in GLOB.player_list) var/mob/M = P if(!M || !M.client) continue - if(get_dist(M, turf_source) <= world.view + extrarange) + var/distance = get_dist(M, turf_source) + + if(distance <= maxdistance) var/turf/T = get_turf(M) if(T && T.z == turf_source.z) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, surround, channel, pressure_affected) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, is_global, S) -/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, surround = 1, channel = 0, pressure_affected = TRUE) +/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, is_global = FALSE, sound/S) if(!client || !can_hear()) return - soundin = get_sfx(soundin) + if(!S) + S = sound(get_sfx(soundin)) - var/sound/S = sound(soundin) S.wait = 0 //No queue S.channel = channel || open_sound_channel() S.volume = vol + S.environment = -1 if (vary) if(frequency) @@ -43,6 +48,11 @@ if(isturf(turf_source)) var/turf/T = get_turf(src) + //sound volume falloff with distance + var/distance = get_dist(T, turf_source) + + S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff. + if(pressure_affected) //Atmosphere affects sound var/pressure_factor = 1 @@ -56,27 +66,25 @@ else //space pressure_factor = 0 - var/distance = get_dist(T, turf_source) if(distance <= 1) pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound S.volume *= pressure_factor //End Atmosphere affecting sound - if(S.volume <= 0) - return //No sound - - // 3D sounds, the technology is here! - if (surround) - var/dx = turf_source.x - T.x // Hearing from the right/left - S.x = round(max(-SURROUND_CAP, min(SURROUND_CAP, dx)), 1) - - var/dz = turf_source.y - T.y // Hearing from infront/behind - S.z = round(max(-SURROUND_CAP, min(SURROUND_CAP, dz)), 1) + if(S.volume <= 0) + return //No sound + var/dx = turf_source.x - T.x // Hearing from the right/left + S.x = dx + var/dz = turf_source.y - T.y // Hearing from infront/behind + S.z = dz // The y value is for above your head, but there is no ceiling in 2d spessmens. S.y = 1 - S.falloff = falloff || FALLOFF_SOUNDS + S.falloff = (falloff ? falloff : FALLOFF_SOUNDS) + + if(!is_global) + S.environment = 2 src << S @@ -85,7 +93,7 @@ for(var/M in GLOB.player_list) if(ismob(M) && !isnewplayer(M)) var/mob/MO = M - MO.playsound_local(get_turf(MO), sound, volume, vary, pressure_affected = FALSE) + MO.playsound_local(get_turf(MO), sound, volume, vary, pressure_affected = FALSE, is_global = TRUE) /proc/open_sound_channel() var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used From c801be68943b30a49f58e241c45ced0e5445d53b Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Tue, 25 Jul 2017 09:36:36 -0400 Subject: [PATCH 2/3] defines and cleanup --- code/__DEFINES/misc.dm | 3 --- code/__DEFINES/sound.dm | 33 +++++++++++++++++++++++++++++++++ code/game/sound.dm | 15 ++++++--------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index da53445f16b..914196ad451 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -162,9 +162,6 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define GAME_STATE_SETTING_UP 2 #define GAME_STATE_PLAYING 3 #define GAME_STATE_FINISHED 4 -//SOUND: -#define SOUND_MINIMUM_PRESSURE 10 -#define FALLOFF_SOUNDS 0.5 //FONTS: // Used by Paper and PhotoCopier (and PaperBin once a year). diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 7b4de823ea4..12e6786ee85 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -11,3 +11,36 @@ #define CHANNEL_HIGHEST_AVAILABLE 1018 + +#define SOUND_MINIMUM_PRESSURE 10 +#define FALLOFF_SOUNDS 0.5 + +//BYOND Sound Environment defines + +#define SOUND_ENV_DEFAULT -1 +#define SOUND_ENV_GENERIC 0 +#define SOUND_ENV_PADDED_CELL 1 +#define SOUND_ENV_ROOM 2 +#define SOUND_ENV_BATHROOM 3 +#define SOUND_ENV_LIVINGROOM 4 +#define SOUND_ENV_STONEROOM 5 +#define SOUND_ENV_AUDITORIUM 6 +#define SOUND_ENV_CONCERT_HALL 7 +#define SOUND_ENV_CAVE 8 +#define SOUND_ENV_ARENA 9 +#define SOUND_ENV_HANGAR 10 +#define SOUND_ENV_CARPETTED_HALLWAY 11 +#define SOUND_ENV_HALLWAY 12 +#define SOUND_ENV_STONE_CORRIDOOR 13 +#define SOUND_ENV_ALLEY 14 +#define SOUND_ENV_FOREST 15 +#define SOUND_ENV_CITY 16 +#define SOUND_ENV_MOUNTAINS 17 +#define SOUND_ENV_QUARRY 18 +#define SOUND_ENV_PLAIN 19 +#define SOUND_ENV_PARKING_LOT 20 +#define SOUND_ENV_SEWER_PIPE 21 +#define SOUND_ENV_UNDERWATER 22 +#define SOUND_ENV_DRUGGED 23 +#define SOUND_ENV_DIZZY 24 +#define SOUND_ENV_PSYCHOTIC 25 \ No newline at end of file diff --git a/code/game/sound.dm b/code/game/sound.dm index 1e75914dffc..a696a8c4dfa 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,13 +1,10 @@ /proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, is_global = FALSE) - - soundin = get_sfx(soundin) // same sound for everyone - if(isarea(source)) throw EXCEPTION("playsound(): source is an area") return - if(isnull(frequency)) - frequency = get_rand_frequency() // Same frequency for everybody + soundin = get_sfx(soundin) // same sound for everyone + var/turf/turf_source = get_turf(source) //allocate a channel if necessary now so its the same for everyone @@ -37,9 +34,9 @@ S.wait = 0 //No queue S.channel = channel || open_sound_channel() S.volume = vol - S.environment = -1 + S.environment = SOUND_ENV_DEFAULT //Always reset the sound environment, or else it'll end up getting applied globally - if (vary) + if(vary) if(frequency) S.frequency = frequency else @@ -84,7 +81,7 @@ S.falloff = (falloff ? falloff : FALLOFF_SOUNDS) if(!is_global) - S.environment = 2 + S.environment = SOUND_ENV_ROOM src << S @@ -154,6 +151,6 @@ soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') return soundin -/proc/playsound_global(file, repeat=0, wait, channel, volume) +/proc/playsound_global(file, repeat = 0, wait, channel, volume) for(var/V in GLOB.clients) V << sound(file, repeat, wait, channel, volume) From 71c7e1fdee7a12360519881e49ddbad14ea13625 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Thu, 27 Jul 2017 17:45:08 -0400 Subject: [PATCH 3/3] last tweaks --- code/__DEFINES/sound.dm | 37 +++------------------- code/game/area/areas.dm | 4 +-- code/game/sound.dm | 19 ++++------- code/modules/client/preferences_toggles.dm | 6 ++-- code/modules/vehicles/bicycle.dm | 4 +-- 5 files changed, 19 insertions(+), 51 deletions(-) diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 12e6786ee85..b58573b27dd 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -5,42 +5,15 @@ #define CHANNEL_JUKEBOX 1021 #define CHANNEL_JUSTICAR_ARK 1020 #define CHANNEL_HEARTBEAT 1019 //sound channel for heartbeats +#define CHANNEL_AMBIENCE 1018 +#define CHANNEL_BUZZ 1017 +#define CHANNEL_BICYCLE 1016 //THIS SHOULD ALWAYS BE THE LOWEST ONE! //KEEP IT UPDATED -#define CHANNEL_HIGHEST_AVAILABLE 1018 +#define CHANNEL_HIGHEST_AVAILABLE 1015 #define SOUND_MINIMUM_PRESSURE 10 -#define FALLOFF_SOUNDS 0.5 - -//BYOND Sound Environment defines - -#define SOUND_ENV_DEFAULT -1 -#define SOUND_ENV_GENERIC 0 -#define SOUND_ENV_PADDED_CELL 1 -#define SOUND_ENV_ROOM 2 -#define SOUND_ENV_BATHROOM 3 -#define SOUND_ENV_LIVINGROOM 4 -#define SOUND_ENV_STONEROOM 5 -#define SOUND_ENV_AUDITORIUM 6 -#define SOUND_ENV_CONCERT_HALL 7 -#define SOUND_ENV_CAVE 8 -#define SOUND_ENV_ARENA 9 -#define SOUND_ENV_HANGAR 10 -#define SOUND_ENV_CARPETTED_HALLWAY 11 -#define SOUND_ENV_HALLWAY 12 -#define SOUND_ENV_STONE_CORRIDOOR 13 -#define SOUND_ENV_ALLEY 14 -#define SOUND_ENV_FOREST 15 -#define SOUND_ENV_CITY 16 -#define SOUND_ENV_MOUNTAINS 17 -#define SOUND_ENV_QUARRY 18 -#define SOUND_ENV_PLAIN 19 -#define SOUND_ENV_PARKING_LOT 20 -#define SOUND_ENV_SEWER_PIPE 21 -#define SOUND_ENV_UNDERWATER 22 -#define SOUND_ENV_DRUGGED 23 -#define SOUND_ENV_DIZZY 24 -#define SOUND_ENV_PSYCHOTIC 25 \ No newline at end of file +#define FALLOFF_SOUNDS 0.5 \ No newline at end of file diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index c71ea6a10fa..a0f268344e4 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -432,7 +432,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) // Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE) L.client.ambience_playing = 1 - L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2) + L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ) if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) return //General ambience check is below the ship ambience so one can play without the other @@ -441,7 +441,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) var/sound = pick(ambientsounds) if(!L.client.played) - L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = 1) + L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE) L.client.played = 1 sleep(600) //ewww - this is very very bad if(L.&& L.client) diff --git a/code/game/sound.dm b/code/game/sound.dm index a696a8c4dfa..e828ede0433 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,17 +1,15 @@ -/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, is_global = FALSE) +/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE) if(isarea(source)) throw EXCEPTION("playsound(): source is an area") return - soundin = get_sfx(soundin) // same sound for everyone - var/turf/turf_source = get_turf(source) //allocate a channel if necessary now so its the same for everyone channel = channel || open_sound_channel() // Looping through the player list has the added bonus of working for mobs inside containers - var/sound/S = sound(soundin) + var/sound/S = sound(get_sfx(soundin)) var/maxdistance = (world.view + extrarange) * 3 for(var/P in GLOB.player_list) var/mob/M = P @@ -21,10 +19,11 @@ if(distance <= maxdistance) var/turf/T = get_turf(M) - if(T && T.z == turf_source.z) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, is_global, S) -/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, is_global = FALSE, sound/S) + if(T && T.z == turf_source.z) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S) + +/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S) if(!client || !can_hear()) return @@ -34,7 +33,6 @@ S.wait = 0 //No queue S.channel = channel || open_sound_channel() S.volume = vol - S.environment = SOUND_ENV_DEFAULT //Always reset the sound environment, or else it'll end up getting applied globally if(vary) if(frequency) @@ -80,9 +78,6 @@ S.y = 1 S.falloff = (falloff ? falloff : FALLOFF_SOUNDS) - if(!is_global) - S.environment = SOUND_ENV_ROOM - src << S /proc/sound_to_playing_players(sound, volume = 100, vary) @@ -90,7 +85,7 @@ for(var/M in GLOB.player_list) if(ismob(M) && !isnewplayer(M)) var/mob/MO = M - MO.playsound_local(get_turf(MO), sound, volume, vary, pressure_affected = FALSE, is_global = TRUE) + MO.playsound_local(get_turf(MO), sound, volume, vary, pressure_affected = FALSE) /proc/open_sound_channel() var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 943999aecc9..d56b6e06199 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -174,8 +174,8 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, Toggle_Soundscape)() to_chat(usr, "You will now hear ambient sounds.") else to_chat(usr, "You will no longer hear ambient sounds.") - usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1) - usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2) + usr.stop_sound_channel(CHANNEL_AMBIENCE) + usr.stop_sound_channel(CHANNEL_BUZZ) SSblackbox.add_details("preferences_verb","Toggle Ambience|[usr.client.prefs.toggles & SOUND_AMBIENCE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/verbs/menu/Settings/Sound/Toggle_Soundscape/Get_checked(client/C) return C.prefs.toggles & SOUND_AMBIENCE @@ -191,7 +191,7 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggle_ship_ambience)() to_chat(usr, "You will now hear ship ambience.") else to_chat(usr, "You will no longer hear ship ambience.") - usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2) + usr.stop_sound_channel(CHANNEL_BUZZ) usr.client.ambience_playing = 0 SSblackbox.add_details("preferences_verb", "Toggle Ship Ambience|[usr.client.prefs.toggles & SOUND_SHIP_AMBIENCE]") //If you are copy-pasting this, I bet you read this comment expecting to see the same thing :^) /datum/verbs/menu/Settings/Sound/toggle_ship_ambience/Get_checked(client/C) diff --git a/code/modules/vehicles/bicycle.dm b/code/modules/vehicles/bicycle.dm index d51de5809c5..2d9b3c82584 100644 --- a/code/modules/vehicles/bicycle.dm +++ b/code/modules/vehicles/bicycle.dm @@ -13,12 +13,12 @@ /obj/vehicle/bicycle/buckle_mob(mob/living/M, force = 0, check_loc = 1) if(prob(easter_egg_chance) || (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) - M << sound(pick(bike_music), repeat = 1, wait = 0, volume = 80, channel = 42) + M << sound(pick(bike_music), repeat = 1, wait = 0, volume = 80, channel = CHANNEL_BICYCLE) . = ..() /obj/vehicle/bicycle/unbuckle_mob(mob/living/buckled_mob,force = 0) if(buckled_mob) - buckled_mob << sound(null, repeat = 0, wait = 0, volume = 80, channel = 42) + buckled_mob.stop_sound_channel(CHANNEL_BICYCLE) . =..() /obj/vehicle/bicycle/tesla_act() // :::^^^)))