Editor bridge for audio tools, auto-generated MCP wrappers that call McpGate to run editor tool actions for TTS speaker generation, assigning sounds, creating .sound events, listing sounds, and previewing audio.
// AUTO-GENERATED by scripts/emit-mcp-wrappers.mjs — DO NOT EDIT.
// Regenerate: node scripts/extract-manifest.mjs && node scripts/emit-mcp-wrappers.mjs
// Source of truth: sbox-mcp-server/src/tools/ (zod schemas) → scripts/tools-manifest.json
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Editor.Mcp;
/// <summary>
/// List sounds, author .sound events, attach sound components, and preview audio in the editor.
/// </summary>
[McpToolset( "bridge_audio", "List sounds, author .sound events, attach sound components, and preview audio in the editor." )]
public static class BridgeAudioTools
{
/// <summary>
/// Generate a text-to-speech speaker component over Sandbox.Speech.Synthesizer (the OS speech
/// engine — dynamic NPC dialog with zero recorded VO): call <class>.Say("text") from game
/// code and it builds a Synthesizer (TrySetVoice by exact VoiceName, else gender/age hint, else OS
/// default) -> WithText -> WithRate -> Play(), returning a tracked SoundHandle —
/// positional 3D parented to the speaker (default) or flat 2D, with stop-previous-on-say
/// interruption, IsSpeaking, StopSpeaking(), and LogVoices() to enumerate installed OS voices.
/// Returns {created, path, className, propertyNames[], note}. Next: trigger_hotload +
/// get_compile_errors, attach (targetId or add_component_with_properties), then Say from game code
/// — LOCAL audio only, wrap the Say call in an [Rpc.Broadcast] handler for everyone to hear. Limits
/// & honesty: the editor cannot playtest audio, so RUNTIME speech is UNVERIFIED (the API
/// surface compiles — verify with your ears in play mode); voices are machine/OS-specific and
/// TrySetVoice is best-effort; LIPSYNC IS NOT AUTO-WIRED — s&box's Sandbox.LipSync component
/// consumes a BaseSoundComponent, not the raw SoundHandle TTS produces, and
/// Synthesizer.OnVisemeReached's delegate arg types can't be confirmed via reflection;
/// enableVisemeData:true enables Handle.LipSync.Visemes for your own mouth-drive code
/// (runtime-unverified). Refuses to overwrite an existing file; refused during play mode.
/// </summary>
/// <param name="name">Class/file name. Defaults to 'TtsSpeaker'. Sanitized to a valid C# identifier.</param>
/// <param name="directory">Subdirectory under the project root for the .cs file. Defaults to 'Code'.</param>
/// <param name="voiceName">Exact installed OS voice name (machine-specific — the generated LogVoices() lists them at runtime). Empty = use voiceGender/voiceAge, or the OS default.</param>
/// <param name="voiceGender">Voice gender hint used only when voiceName is empty (e.g. 'Female', 'Male'). Must be paired with voiceAge. Passed through unvalidated.</param>
/// <param name="voiceAge">Voice age hint paired with voiceGender (e.g. 'Adult', 'Child', 'Senior'). Passed through unvalidated.</param>
/// <param name="rate">Speaking rate offset (integer): negative = slower, positive = faster. Defaults to 0 (normal).</param>
/// <param name="volume">Playback volume for spoken lines. Defaults to 1.</param>
/// <param name="positional">true (default): 3D sound parented to the speaker GameObject (follows it). false: flat 2D voice on the listener (narrator/UI style).</param>
/// <param name="stopPreviousOnSay">true (default): a new Say() fades out the still-playing previous line. false: lines overlap.</param>
/// <param name="stopFadeSeconds">Fade-out duration used when interrupting/stopping a line. Defaults to 0.1.</param>
/// <param name="enableVisemeData">true: sets Handle.LipSync.Enabled on each played line so custom mouth-drive code can read Handle.LipSync.Visemes. Runtime behavior unverified (editor can't playtest audio). Defaults to false.</param>
/// <param name="targetId">GUID of the speaker GameObject to attach to (only attaches if the type is already in the TypeLibrary — hotload first).</param>
[McpTool( "add_tts_voice" )]
public static Task<object> AddTtsVoice( string name = null, string directory = null, string voiceName = null, string voiceGender = null, string voiceAge = null, double? rate = null, double? volume = null, bool? positional = null, bool? stopPreviousOnSay = null, double? stopFadeSeconds = null, bool? enableVisemeData = null, string targetId = null )
=> McpGate.Run( "add_tts_voice", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "voiceName", voiceName ), ( "voiceGender", voiceGender ), ( "voiceAge", voiceAge ), ( "rate", rate ), ( "volume", volume ), ( "positional", positional ), ( "stopPreviousOnSay", stopPreviousOnSay ), ( "stopFadeSeconds", stopFadeSeconds ), ( "enableVisemeData", enableVisemeData ), ( "targetId", targetId ) ) );
/// <summary>
/// Attach a sound event to a GameObject via SoundPointComponent. Creates the component if needed.
/// Returns { assigned, id, sound, soundLoaded, playOnStart } — soundLoaded:false means the .sound
/// path did not resolve (the component is still added with no event; verify the path with
/// list_sounds).
/// </summary>
/// <param name="id">GUID of the GameObject.</param>
/// <param name="sound">Sound event path (e.g. 'sounds/ambient_wind.sound').</param>
/// <param name="playOnStart">If true, the handler calls StartSound() immediately, so the sound starts playing right away (audible in the editor).</param>
[McpTool( "assign_sound" )]
public static Task<object> AssignSound( string id, string sound, bool? playOnStart = null )
=> McpGate.Run( "assign_sound", McpGate.Args( ( "id", id ), ( "sound", sound ), ( "playOnStart", playOnStart ) ) );
/// <summary>
/// Create a .sound event file wired to a source .vsnd. Returns { created, path, soundReferenced,
/// note } (path is project-relative); errors if the file already exists. Preview the result with
/// play_sound_preview or attach it to an object with assign_sound. Note: .sound events have no loop
/// flag — looping lives on the SoundPointComponent that plays the event.
/// </summary>
/// <param name="path">Project-relative path for the sound event file (e.g. 'sounds/footstep.sound'; '.sound' appended if missing).</param>
/// <param name="sound">Path to the source sound asset (.vsnd) the event plays. Omit to create an empty event and wire it later.</param>
/// <param name="volume">Volume multiplier (0-1). Defaults to 1.0.</param>
/// <param name="pitch">Pitch multiplier. Defaults to 1.0.</param>
/// <param name="maxDistance">Maximum audible distance in units (sets Distance + enables DistanceAttenuation). Omit for the engine default.</param>
[McpTool( "create_sound_event" )]
public static Task<object> CreateSoundEvent( string path, string sound = null, double? volume = null, double? pitch = null, double? maxDistance = null )
=> McpGate.Run( "create_sound_event", McpGate.Args( ( "path", path ), ( "sound", sound ), ( "volume", volume ), ( "pitch", pitch ), ( "maxDistance", maxDistance ) ) );
/// <summary>
/// List the project's .sound event files (recursive scan of the project root for *.sound). Returns
/// { count, sounds } — project-relative paths ready to pass to assign_sound, play_sound_preview, or
/// add_lipsync. NOTE: the current handler returns every match (filter/maxResults are not applied)
/// and only covers .sound files in the project tree — use search_assets type='sound' for other
/// sound assets.
/// </summary>
/// <param name="filter">Search filter for sound name or path (currently not applied by the handler — all .sound files are returned).</param>
/// <param name="maxResults">Maximum results. Defaults to 50 (currently not applied by the handler).</param>
[McpTool.ReadOnly( "list_sounds" )]
public static Task<object> ListSounds( string filter = null, double? maxResults = null )
=> McpGate.Run( "list_sounds", McpGate.Args( ( "filter", filter ), ( "maxResults", maxResults ) ) );
/// <summary>
/// Play a sound in the editor for testing without entering play mode. Returns { playing, sound,
/// volume }. Fire-and-forget via Sound.Play — there is no stop control, and the volume param is
/// echoed back but not currently applied to playback.
/// </summary>
/// <param name="sound">Sound event or asset path to preview.</param>
/// <param name="volume">Preview volume (0-1). Defaults to 1.0 (echoed in the response but not currently applied to playback).</param>
[McpTool( "play_sound_preview" )]
public static Task<object> PlaySoundPreview( string sound, double? volume = null )
=> McpGate.Run( "play_sound_preview", McpGate.Args( ( "sound", sound ), ( "volume", volume ) ) );
}