Skip to content

Commit

Permalink
add tts to hologram and modlink. Refactor tts related code a bit (ss2…
Browse files Browse the repository at this point in the history
…20club#997)

## Что этот PR делает

ТТС для голограмм и модлинков

## Summary by Sourcery

Add TTS support for holograms and modlinks.

New Features:
- Holograms and modlinks now have text-to-speech (TTS) capabilities.

Tests:
- Added tests for the new TTS features.
  • Loading branch information
Gaxeer authored Jan 16, 2025
1 parent 33ca834 commit e14c3b0
Show file tree
Hide file tree
Showing 20 changed files with 206 additions and 127 deletions.
4 changes: 2 additions & 2 deletions code/__DEFINES/bandastation/defines.dm
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//from base of datum/component/tts_component/cast_tts(): (atom/speaker, mob/listener, message, atom/location, is_local, effect, traits, preSFX, postSFX)
//from base of datum/component/tts_component/cast_tts(): (atom/speaker, mob/listener, message, atom/location, is_local, is_radio, list/effects, traits, preSFX, postSFX)
#define COMSIG_TTS_COMPONENT_PRE_CAST_TTS "tts_component_pre_cast_tts"
#define TTS_CAST_SPEAKER "tts_speaker"
#define TTS_CAST_LISTENER "tts_listener"
#define TTS_CAST_MESSAGE "tts_message"
#define TTS_CAST_LOCATION "tts_location"
#define TTS_CAST_LOCAL "tts_local"
#define TTS_CAST_EFFECT "tts_effect"
#define TTS_CAST_EFFECTS "tts_effect"
#define TTS_CAST_TRAITS "tts_traits"
#define TTS_CAST_PRE_SFX "tts_preSFX"
#define TTS_CAST_POST_SFX "tts_postSFX"
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/say.dm
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#define MODE_CUSTOM_SAY_ERASE_INPUT "erase_input"
/// Message is being relayed through another object
#define MODE_RELAY "relayed"
#define MODE_TTS_FILTERS "tts_filters" // Bandastation Addition

//Spans. Robot speech, italics, etc. Applied in compose_message().
#define SPAN_ROBOT "robot"
Expand Down
20 changes: 13 additions & 7 deletions code/__HELPERS/priority_announce.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* * encode_title - if TRUE, the title will be HTML encoded
* * encode_text - if TRUE, the text will be HTML encoded
*/
/proc/priority_announce(text, title = "", sound, type, sender_override, has_important_message = FALSE, list/mob/players = GLOB.player_list, encode_title = TRUE, encode_text = TRUE, color_override)
/proc/priority_announce(text, title = "", sound, type, sender_override, has_important_message = FALSE, list/mob/players = GLOB.player_list, encode_title = TRUE, encode_text = TRUE, color_override, datum/component/tts_component/tts_override = null) // Bandastation Addition: "datum/component/tts_component/tts_override = null"
if(!text)
return

Expand Down Expand Up @@ -83,7 +83,7 @@
else
finalized_announcement = CHAT_ALERT_DEFAULT_SPAN(jointext(announcement_strings, ""))

dispatch_announcement_to_players(finalized_announcement, players, sound)
dispatch_announcement_to_players(finalized_announcement, players, sound, tts_override = tts_override) // Bandastation Addition: "tts_override = tts_override"

if(isnull(sender_override) && players == GLOB.player_list)
if(length(title) > 0)
Expand Down Expand Up @@ -186,7 +186,7 @@

/// Proc that just dispatches the announcement to our applicable audience. Only the announcement is a mandatory arg.
/// `should_play_sound` can also be a callback, if you want to only play the sound to specific players.
/proc/dispatch_announcement_to_players(announcement, list/players = GLOB.player_list, sound_override = null, should_play_sound = TRUE)
/proc/dispatch_announcement_to_players(announcement, list/players = GLOB.player_list, sound_override = null, should_play_sound = TRUE, datum/component/tts_component/tts_override = null) // Bandastation Addition: "datum/component/tts_component/tts_override = null"
var/sound_to_play = !isnull(sound_override) ? sound_override : 'sound/announcer/notice/notice2.ogg'

// note for later: low-hanging fruit to convert to astype() behind an experiment define whenever the 516 beta releases
Expand All @@ -204,11 +204,14 @@
continue

if(target.client?.prefs.read_preference(/datum/preference/toggle/sound_announcements))
SEND_SOUND(target, sound(sound_to_play))

// SEND_SOUND(target, sound(sound_to_play)) // Bandastion Removal
/// SS220 TTS START
var/mob/living/silicon/ai/active_ai = DEFAULTPICK(active_ais(TRUE, null), null)
var/datum/tts_seed/announcement_tts_seed = active_ai ? active_ai.get_tts_seed() : /datum/tts_seed/silero/glados
var/datum/tts_seed/announcement_tts_seed = tts_override?.tts_seed
var/list/tts_effects = tts_override?.get_effects()
if(isnull(announcement_tts_seed))
var/mob/living/silicon/ai/active_ai = DEFAULTPICK(active_ais(TRUE, null), null)
announcement_tts_seed = active_ai ? active_ai.get_tts_seed() : /datum/tts_seed/silero/glados

INVOKE_ASYNC(
SStts220, \
TYPE_PROC_REF(/datum/controller/subsystem/tts220, get_tts), \
Expand All @@ -217,6 +220,9 @@
announcement, \
announcement_tts_seed, \
FALSE, \
tts_effects, \
null, \
sound_to_play \
)
/// SS220 TTS END

Expand Down
4 changes: 2 additions & 2 deletions code/datums/communications.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ GLOBAL_DATUM_INIT(communications_controller, /datum/communciations_controller, n
else
var/list/message_data = user.treat_message(input)
if(syndicate)
priority_announce(html_decode(message_data["message"]), null, 'sound/announcer/announcement/announce_syndi.ogg', ANNOUNCEMENT_TYPE_SYNDICATE, has_important_message = TRUE, players = players, color_override = "red")
priority_announce(html_decode(message_data["message"]), null, 'sound/announcer/announcement/announce_syndi.ogg', ANNOUNCEMENT_TYPE_SYNDICATE, has_important_message = TRUE, players = players, color_override = "red", tts_override = user.GetComponent(/datum/component/tts_component)) // Bandastation Addition: "tts_override = user.GetComponent(/datum/component/tts_component)"
else
priority_announce(html_decode(message_data["message"]), null, 'sound/announcer/announcement/announce.ogg', ANNOUNCEMENT_TYPE_CAPTAIN, has_important_message = TRUE, players = players)
priority_announce(html_decode(message_data["message"]), null, 'sound/announcer/announcement/announce.ogg', ANNOUNCEMENT_TYPE_CAPTAIN, has_important_message = TRUE, players = players, tts_override = user.GetComponent(/datum/component/tts_component)) // Bandastation Addition: "tts_override = user.GetComponent(/datum/component/tts_component)"
COOLDOWN_START(src, nonsilicon_message_cooldown, COMMUNICATION_COOLDOWN)
user.log_talk(input, LOG_SAY, tag="priority announcement")
message_admins("[ADMIN_LOOKUPFLW(user)] has made a priority announcement.")
Expand Down
1 change: 1 addition & 0 deletions code/game/machinery/hologram.dm
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ Possible to do for anyone motivated enough:
var/obj/effect/overlay/holo_pad_hologram/hologram = new(loc)//Spawn a blank effect at the location.
var/atom/work_off = AI?.hologram_appearance || user

hologram.AddComponent(/datum/component/tts_component, user.get_tts_seed(), user.get_tts_effects(list(/datum/singleton/sound_effect/radio))) // Bandastation Addition
hologram.icon = work_off.icon
hologram.icon_state = work_off.icon_state
hologram.copy_overlays(work_off, TRUE)
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/items/devices/megaphone.dm
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
else
playsound(loc, 'sound/items/megaphone.ogg', 100, FALSE, TRUE)
speech_args[SPEECH_SPANS] |= voicespan
LAZYADD(speech_args[SPEECH_MODS][MODE_TTS_FILTERS], /datum/singleton/sound_effect/megaphone) // Bandastation Addition

/obj/item/megaphone/proc/add_tts_filter(mob/living/carbon/user, list/message_args)
SIGNAL_HANDLER
Expand Down
1 change: 1 addition & 0 deletions code/modules/mod/mod_link.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
link_visual.makeHologram(0.75)
mod_link.visual_overlays = user.overlays - user.active_thinking_indicator
link_visual.add_overlay(mod_link.visual_overlays)
link_visual.AddComponent(/datum/component/tts_component, user.get_tts_seed(), user.get_tts_effects(list(/datum/singleton/sound_effect/radio))) // Bandastation Addition
mod_link.visual = link_visual
mod_link.holder.become_hearing_sensitive(REF(mod_link))
mod_link.holder.RegisterSignals(user, list(COMSIG_CARBON_APPLY_OVERLAY, COMSIG_CARBON_REMOVE_OVERLAY), proc_path)
Expand Down
1 change: 1 addition & 0 deletions code/modules/mod/modules/modules_security.dm
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
SIGNAL_HANDLER

speech_args[SPEECH_SPANS] |= voicespan
LAZYADD(speech_args[SPEECH_MODS][MODE_TTS_FILTERS], /datum/singleton/sound_effect/megaphone) // Bandastation Addition
drain_power(use_energy_cost)

///Criminal Capture - Generates hardlight bags you can put people in and sinch.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
#define TTS_TRAIT_RATE_FASTER (1<<2)
#define TTS_TRAIT_RATE_MEDIUM (1<<3)

#define TTS_TRAIT_ROBOTIZE "tts_trait_robotize"

#define TTS_CATEGORY_OTHER "Другое"
#define TTS_CATEGORY_WARCRAFT3 "WarCraft 3"
#define TTS_CATEGORY_HALFLIFE2 "Half-Life 2"
Expand Down
12 changes: 6 additions & 6 deletions modular_bandastation/_defines220/code/signals_atom.dm
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
///from base of atom/change_tts_seed(): (mob/chooser, override, new_traits)
///from base of atom/change_tts_seed(): (mob/chooser, override, list/new_sound_effects)
#define COMSIG_ATOM_TTS_SEED_CHANGE "atom_tts_seed_change"
///from base of atom/cast_tts(): (mob/listener, message, atom/location, is_local, effect, traits, preSFX, postSFX)
///from base of atom/cast_tts(): (mob/listener, message, atom/location, is_local, is_radio, list/effects, traits, preSFX, postSFX)
#define COMSIG_ATOM_TTS_CAST "atom_tts_cast"
///from base of atom/tts_trait_add(): (trait)
#define COMSIG_ATOM_TTS_TRAIT_ADD "atom_tts_trait_add"
///from base of atom/tts_trait_remove(): (trait)
#define COMSIG_ATOM_TTS_TRAIT_REMOVE "atom_tts_trait_remove"
///from base of atom/tts_effects_add(): (trait)
#define COMSIG_ATOM_TTS_EFFECTS_ADD "atom_tts_trait_add"
///from base of atom/tts_effects_remove(): (trait)
#define COMSIG_ATOM_TTS_EFFECTS_REMOVE "atom_tts_trait_remove"
8 changes: 4 additions & 4 deletions modular_bandastation/tts/code/actions/change_tts_actions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
overlay_icon_state = "bg_revenant_border"
button_icon_state = "voice_changer"
var/overrides
var/list/traits = list()
var/list/sound_effects = list()

/datum/action/innate/voice_change/Activate()
owner.change_tts_seed(owner, overrides, traits)
owner.change_tts_seed(owner, overrides, sound_effects)

/datum/action/innate/voice_change/robotic
traits = list(TTS_TRAIT_ROBOTIZE)
sound_effects = list(/datum/singleton/sound_effect/robot)

/datum/action/innate/voice_change/genderless
desc = "Изменяет TTS вне зависимости от пола и с учетом уровня подписки."
overrides = TTS_OVERRIDE_GENDER

/datum/action/innate/voice_change/genderless/robotic
traits = list(TTS_TRAIT_ROBOTIZE)
sound_effects = list(/datum/singleton/sound_effect/robot)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/mob/eye/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
. = ..()
speaker.cast_tts(src, raw_message, effect = radio_freq ? /datum/singleton/sound_effect/radio : null)
speaker.cast_tts(src, raw_message, is_radio = !!radio_freq)

/mob/eye/imaginary_friend/setup_friend_from_prefs(datum/preferences/appearance_from_prefs)
. = ..()
Expand Down
2 changes: 1 addition & 1 deletion modular_bandastation/tts/code/base_seeds/mobs/_base.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/angel)

/mob/living/silicon/add_tts_component()
AddComponent(/datum/component/tts_component, null, TTS_TRAIT_ROBOTIZE)
AddComponent(/datum/component/tts_component, null, list(/datum/singleton/sound_effect/robot))

/mob/living/carbon/add_tts_component()
var/random_tts_seed_key = SStts220.pick_tts_seed_by_gender(gender)
Expand Down
2 changes: 1 addition & 1 deletion modular_bandastation/tts/code/base_seeds/mobs/other.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//Uncategorized mobs

/mob/living/silicon/ai/add_tts_component()
AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/glados, TTS_TRAIT_ROBOTIZE)
AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/glados, list(/datum/singleton/sound_effect/robot))

/obj/item/nullrod/scythe/talking/add_tts_component()
AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/sylvanas)
Expand Down
29 changes: 11 additions & 18 deletions modular_bandastation/tts/code/shell.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@
#define SHELLEO_ERR ".err"
#define SHELLEO_OUT ".out"

/proc/apply_sound_effect(datum/singleton/sound_effect/effect, filename_input, filename_output)
if(!effect)
/proc/apply_sound_effects(list/effects, filename_input, filename_output)
if(!length(effects))
CRASH("Invalid sound effect chosen.")

var/taskset
CONFIG_GET(string/ffmpeg_cpuaffinity)
if(CONFIG_GET(string/ffmpeg_cpuaffinity))
taskset = "taskset -ac [CONFIG_GET(string/ffmpeg_cpuaffinity)]"
var/list/ffmpeg_arguments = list()
for(var/datum/singleton/sound_effect/effect as anything in effects)
ffmpeg_arguments |= effect.ffmpeg_arguments

var/command = {"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "[effect.ffmpeg_arguments]" [filename_output]"}
var/taskset = CONFIG_GET(string/ffmpeg_cpuaffinity) ? "taskset -ac [CONFIG_GET(string/ffmpeg_cpuaffinity)]" : ""
var/command = {"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "[ffmpeg_arguments.Join(", ")]" [filename_output]"}
var/list/output = world.shelleo(command)

var/errorlevel = output[SHELLEO_ERRORLEVEL]
var/stdout = output[SHELLEO_STDOUT]
var/stderr = output[SHELLEO_STDERR]
if(errorlevel)
log_runtime("Error: apply_sound_effect([effect.suffix], [filename_input], [filename_output]) - See debug logs.")
logger.Log(LOG_CATEGORY_DEBUG, "apply_sound_effect([effect.suffix], [filename_input], [filename_output]) STDOUT: [stdout]")
logger.Log(LOG_CATEGORY_DEBUG, "apply_sound_effect([effect.suffix], [filename_input], [filename_output]) STDERR: [stderr]")
var/effect_types = effects.Join("; ")
log_runtime("Error: apply_sound_effects([effect_types], [filename_input], [filename_output]) - See debug logs.")
logger.Log(LOG_CATEGORY_DEBUG, "apply_sound_effects([effect_types], [filename_input], [filename_output]) STDOUT: [stdout]")
logger.Log(LOG_CATEGORY_DEBUG, "apply_sound_effects([effect_types], [filename_input], [filename_output]) STDERR: [stderr]")
return FALSE
return TRUE

Expand All @@ -40,18 +41,10 @@
suffix = "_robot"
ffmpeg_arguments = "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=1024:overlap=0.5, deesser=i=0.4, volume=volume=1.5"

/datum/singleton/sound_effect/radio_robot
suffix = "_radio_robot"
ffmpeg_arguments = "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=1024:overlap=0.5, deesser=i=0.4, volume=volume=1.5, highpass=f=1000, lowpass=f=3000, acrusher=1:1:50:0:log"

/datum/singleton/sound_effect/megaphone
suffix = "_megaphone"
ffmpeg_arguments = "highpass=f=500, lowpass=f=4000, volume=volume=10, acrusher=1:1:45:0:log"

/datum/singleton/sound_effect/megaphone_robot
suffix = "_megaphone_robot"
ffmpeg_arguments = "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=1024:overlap=0.5, deesser=i=0.4, highpass=f=500, lowpass=f=4000, volume=volume=10, acrusher=1:1:45:0:log"

#undef SHELLEO_ERRORLEVEL
#undef SHELLEO_STDOUT
#undef SHELLEO_STDERR
Expand Down
Loading

0 comments on commit e14c3b0

Please sign in to comment.