How to use Microsoft voices combined with Sonos speakers Options: voice, speaking speed, pitch, langauge.
I made a combination of advanced flow and Homey script. Azure account with a Speech services key needed.
There are multiple alternatives, but this is mine:
- step 1: Homey script (see below) creates a mp3 variabele
- step 2: app “FTP client” creates with Micro web server app a mp3 file for the Homey device
- step 3: Micro web server creates an url for this mp3 file (see app setup here)
- step 4: play this Cloud url with Sonos (local api) app.
Create in Microsoft Azure a key for speech services. Use this TTS key in Homey script below. Try different Microsoft voices and languages here.
This is the Homey script based on my use case (I’m not a developer and it works for me):
//read a flow variable (text type), here the variabele is
//called TTSAfTeSpelen.
//This variabele contains the text to play on Sonos
let Variabelen = await Homey.logic.getVariables();
let sNieuwsVariabele = _.find(Variabelen, (object) => object.name === "TTSAfTeSpelen");
// Fallback for empty or not existing variable
let mijnTekst = sNieuwsVariabele ? sNieuwsVariabele.value : "Geen nieuws gevonden";
//SSML commands can't escape texts:
//replace ampersand (&) with "and" (in my case "en")
mijnTekst = mijnTekst.replaceAll("&", " en ");
//Call TTS (Text To Speech) in Azure Cognitive Services
//mp3 format audio-48khz-96kbitrate-mono-mp3: nice sound on Sonos speakers
//and small size
//NL language: lang='nl-NL'
//voice: en-US-JennyMultilingualNeural (see Microsoft TTS setting).
//this is a US base voice,
//but can be used in multiple languages without accents.
//narration-professional: speaking style (for news messages)
//prosody rate='-10%': speed, in my case 10% less than standard speed
//pitch='0%': default voice pitch
const antwoord = await fetch(
'https://northeurope.tts.speech.microsoft.com/cognitiveservices/v1',
{
method: "POST",
headers: {
"Ocp-Apim-Subscription-Key": 'fill here your Azure tts key',
"Content-Type": "application/ssml+xml",
"X-Microsoft-OutputFormat": "audio-48khz-96kbitrate-mono-mp3"
},
body:
"<speak xmlns='http://www.w3.org/2001/10/synthesis' " +
"xmlns:mstts='http://www.w3.org/2001/mstts' version='1.0' xml:lang='nl-NL'>" +
"<voice name='en-US-JennyMultilingualNeural'>" +
"<lang xml:lang='nl-NL'>" +
"<mstts:express-as style='narration-professional' styledegree='3'>" +
"<prosody rate='-10%' pitch='0%'>" +
mijnTekst +
"</prosody>" +
"</mstts:express-as>" +
"</lang>" +
"</voice>" +
"</speak>"
}
);
// check TTS call
if (!antwoord.ok) {
throw new Error("TTS-aanroep mislukt met status: " + antwoord.status + " " + antwoord.statusText);
}
// Get TTS buffer (this is raw data, not yet base64 format needed for Sonos)
const ttsBuffer = await antwoord.buffer();
// announcement sound (Base64 string), created after convert mp3 to base64
const aankondigingsgeluidBase64 = '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';
//cancatenate announcement and TTS variabele to flow.
//This variabele can be used in the next flow step
return aankondigingsgeluidBase64 + ttsBuffer.toString('base64');
