Chat Text To Speech

Roblox released their new Text-to-Speech API.

I thought it would be helpful for the community to be able to experience the API in-game.
When you type in chat, the Text-to-Speech API converts what you said into an audio you can hear back.

10 Likes

Could this be used to make NPC have text that is then audio ?

Also in the test place, why do only some words work and also those that do work, do not have audio all the time?

Like I did these words, and sometime Hi would work, and other times it would not.

Also when I play it in studio I get the error on every time I type.

4 Likes

The new Roblox’s TextToSpeech API looks perfect for me!
I just implemented into chat using TextChatService from scratch, but this one might be easier than method i use! :hidere: don’t insult me for using the module or AudioTextToSpeech

1 Like

Hey there!

I just heard about this feature and decided to dive in. While exploring I came across your code and it really helped me out… thank you!

local TextService = game:GetService("TextService")
local Players = game:GetService("Players")

local DEFAULT_VOICE = "British male"

local VOICES = {
	["British male"]      = "1",
	["British female"]    = "2",
	["US male #1"]        = "3",
	["US female #1"]      = "4",
	["US male #2"]        = "5",
	["US female #2"]      = "6",
	["Australian male"]   = "7",
	["Australian female"] = "8",
	["Retro voice #1"]    = "9",
	["Retro voice #2"]    = "10",
}

local CHAT_RANGE = 74

local playerVoice = {}

local function stopExisting(head: Instance)
	for _, obj in ipairs(head:GetChildren()) do
		if obj:IsA("AudioTextToSpeech") and obj.Name == "ChatTTS" then
			obj:Destroy()
		end
		if obj:IsA("AudioEmitter") and obj.Name == "ChatTTSEmitter" then
			obj:Destroy()
		end
		if obj:IsA("Wire") and obj.Name == "ChatTTSWire" then
			obj:Destroy()
		end
	end
end

local function playChatTTS(player: Player, message: string)
	local character = player.Character
	if not character then return end
	local head = character:FindFirstChild("Head")
	if not head then return end

	stopExisting(head)

	local voiceId = playerVoice[player.UserId] or VOICES[DEFAULT_VOICE] or "1"

	local tts = Instance.new("AudioTextToSpeech")
	tts.Name = "ChatTTS"
	tts.Parent = head
	tts.VoiceId = voiceId
	tts.Volume = 3

	local emitter = Instance.new("AudioEmitter")
	emitter.Name = "ChatTTSEmitter"
	emitter.Parent = head

	local ok, err = pcall(function()
		emitter:SetDistanceAttenuation({
			[0] = 1,
			[CHAT_RANGE * 0.5] = 0.6,
			[CHAT_RANGE] = 0,
		})
	end)
	if not ok then
		warn("SetDistanceAttenuation failed:", err)
	end

	local wire = Instance.new("Wire")
	wire.Name = "ChatTTSWire"
	wire.Parent = head
	wire.SourceInstance = tts
	wire.TargetInstance = emitter

	local success, filterResult = pcall(function()
		return TextService:FilterStringAsync(message, player.UserId)
	end)

	if success and filterResult then
		tts.Text = message
		tts:Play()
	else
		tts:Destroy()
		emitter:Destroy()
		wire:Destroy()
		return
	end

	tts.Ended:Once(function()
		if wire.Parent then wire:Destroy() end
		if emitter.Parent then emitter:Destroy() end
		if tts.Parent then tts:Destroy() end
	end)
end

Players.PlayerAdded:Connect(function(player)
	player.Chatted:Connect(function(message)
		if not message or message == "" then return end

		if message:sub(1,7):lower() == "!voice " then
			local param = message:sub(8):gsub("^%s*(.-)%s*$", "%1") -- trim
			if param ~= "" then
				local id = VOICES[param]
				if not id and tonumber(param) then
					id = tostring(tonumber(param))
				end
				if id then
					playerVoice[player.UserId] = id
					player:SendNotification({
						Title = "Voice Changed",
						Text = "Your TTS voice is now: " .. param,
						Duration = 3
					})
				else
					player:SendNotification({
						Title = "Voice Error",
						Text = "Invalid voice name or ID.",
						Duration = 3
					})
				end
			end
			return
		end

		playChatTTS(player, message)
	end)
end)

I made some improvements:

  • added a !voice command that lets you change your voice per id or name
  • implemented a range for the voices

What I couldnt figure out yet (since it got late :sweat_smile:) is how to add reverb from the SoundService. I changed it to “Cave" but didnt notice any difference… maybe its something with the emitter or the wire; ’m not entirely sure. Im gonna look into that tomorrow!!!


I tried my best to build on what you shared and made it for my teast a little “better”. Hope this helps others too!!!

2 Likes