当前位置:   article > 正文

Unity C# 之 Azure 微软SSML语音合成TTS流式获取音频数据以及表情嘴型 Animation 的简单整理_unity azure 口唇驱动

unity azure 口唇驱动

Unity C# 之 Azure 微软SSML语音合成TTS流式获取音频数据以及表情嘴型 Animation 的简单整理

目录

Unity C# 之 Azure 微软SSML语音合成TTS流式获取音频数据以及表情嘴型 Animation 的简单整理

一、简单介绍

二、实现原理

三、注意事项

四、实现步骤

五、关键代码


一、简单介绍

Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。

本节介绍,这里在使用微软的Azure 使用SSML进行SS语音合成的音频,并且获取表情嘴型Animation 数据,并且保存到本地,在特定的情况下,用于本地读取音频和表情嘴型Animation 数据,直接使用,避免可能网络访问造成的延迟问题,这里简单说明,如果你有更好的方法,欢迎留言交流。

语音合成标记语言 (SSML) 是一种基于 XML 的标记语言,可用于微调文本转语音输出属性,例如音调、发音、语速、音量等。 与纯文本输入相比,你拥有更大的控制权和灵活性。

可以使用 SSML 来执行以下操作:

  •     定义输入文本结构,用于确定文本转语音输出的结构、内容和其他特征。 例如,可以使用 SSML 来定义段落、句子、中断/暂停或静音。 可以使用事件标记(例如书签或视素)来包装文本,这些标记可以稍后由应用程序处理。
  •     选择语音、语言、名称、样式和角色。 可以在单个 SSML 文档中使用多个语音。 调整重音、语速、音调和音量。 还可以使用 SSML 插入预先录制的音频,例如音效或音符。
  •     控制输出音频的发音。 例如,可以将 SSML 与音素和自定义词典配合使用来改进发音。 还可以使用 SSML 定义单词或数学表达式的具体发音。
     

下面是 SSML 文档的基本结构和语法的子集:

  1. <speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="string">
  2. <mstts:backgroundaudio src="string" volume="string" fadein="string" fadeout="string"/>
  3. <voice name="string" effect="string">
  4. <audio src="string"></audio>
  5. <bookmark mark="string"/>
  6. <break strength="string" time="string" />
  7. <emphasis level="value"></emphasis>
  8. <lang xml:lang="string"></lang>
  9. <lexicon uri="string"/>
  10. <math xmlns="http://www.w3.org/1998/Math/MathML"></math>
  11. <mstts:audioduration value="string"/>
  12. <mstts:express-as style="string" styledegree="value" role="string"></mstts:express-as>
  13. <mstts:silence type="string" value="string"/>
  14. <mstts:viseme type="string"/>
  15. <p></p>
  16. <phoneme alphabet="string" ph="string"></phoneme>
  17. <prosody pitch="value" contour="value" range="value" rate="value" volume="value"></prosody>
  18. <s></s>
  19. <say-as interpret-as="string" format="string" detail="string"></say-as>
  20. <sub alias="string"></sub>
  21. </voice>
  22. </speak>

 SSML 语音和声音
语音合成标记语言 (SSML) 的语音和声音 - 语音服务 - Azure AI services | Microsoft Learn

官网注册:

面向学生的 Azure - 免费帐户额度 | Microsoft Azure

官网技术文档网址:

技术文档 | Microsoft Learn

官网的TTS:

文本转语音快速入门 - 语音服务 - Azure Cognitive Services | Microsoft Learn

Azure Unity SDK  包官网:

安装语音 SDK - Azure Cognitive Services | Microsoft Learn

SDK具体链接:

https://aka.ms/csspeech/unitypackage

 

二、实现原理

1、官网申请得到语音合成对应的 SPEECH_KEY 和 SPEECH_REGION

2、然后对应设置 语言 和需要的声音 配置

3、使用 SSML 带有流式获取得到音频数据,在声源中播放或者保存即可,样例如下

  1. public static async Task SynthesizeAudioAsync()
  2. {
  3. var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
  4. using var speechSynthesizer = new SpeechSynthesizer(speechConfig, null);
  5. var ssml = File.ReadAllText("./ssml.xml");
  6. var result = await speechSynthesizer.SpeakSsmlAsync(ssml);
  7. using var stream = AudioDataStream.FromResult(result);
  8. await stream.SaveToWaveFileAsync("path/to/write/file.wav");
  9. }

4、本地保存音频,以及表情嘴型 Animation 数据

  1. // 获取到视频的数据,保存为 .wav
  2. using var stream = AudioDataStream.FromResult(speechSynthesisResult);
  3. await stream.SaveToWaveFileAsync($"./{fileName}.wav");
  4. /// <summary>
  5. /// 嘴型 animation 数据,本地保存为 json 数据
  6. /// </summary>
  7. /// <param name="fileName">保存文件名</param>
  8. /// <param name="content">保存内容</param>
  9. /// <returns></returns>
  10. static async Task CommitAsync(string fileName,string content)
  11. {
  12. var bits = Encoding.UTF8.GetBytes(content);
  13. using (var fs = new FileStream(
  14. path: @$"d:\temp\{fileName}.json",
  15. mode: FileMode.Create,
  16. access: FileAccess.Write,
  17. share: FileShare.None,
  18. bufferSize: 4096,
  19. useAsync: true))
  20. {
  21. await fs.WriteAsync(bits, 0, bits.Length);
  22. }
  23. }

三、注意事项

1、不是所有的 speechSynthesisVoiceName 都能生成对应的 表情嘴型 Animation 数据

四、实现步骤

这里是直接使用 .Net VS 中进行代码测试

1、在 NuGet 中安装 微软的 Speech 包

 2、代码编写实现 SSML 合成语音,并且本地保存对应的 音频文件和表情嘴型 Animation json 数据

3、运行代码,运行完后,就会本地保存对应的 音频文件和表情嘴型 Animation json 数据

 

 4、本地查看保存的数据

 

五、关键代码

  1. using Microsoft.CognitiveServices.Speech;
  2. using System.Text;
  3. class Program
  4. {
  5. // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
  6. static string speechKey = "YOUR_SPEECH_KEY";
  7. static string speechRegion = "YOUR_SPEECH_REGION";
  8. static string speechSynthesisVoiceName = "zh-CN-XiaoxiaoNeural";
  9. static string fileName = "Test" + "Hello";
  10. static string InputAudioContent = "黄河之水天上来,奔流到海不复回"; // 生成的
  11. static int index = 0; // 记录合成的表情口型动画的数据数组个数
  12. static string content="["; // [ 是为了组成 json 数组
  13. async static Task Main(string[] args)
  14. {
  15. var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);
  16. // 根据需要可以使用更多 xml 配置,让合成的声音更加生动立体
  17. var ssml = @$"<speak version='1.0' xml:lang='zh-CN' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'>
  18. <voice name='{speechSynthesisVoiceName}'>
  19. <mstts:viseme type='FacialExpression'/>
  20. <mstts:express-as style='friendly'>{InputAudioContent}</mstts:express-as>
  21. </voice>
  22. </speak>";
  23. // Required for sentence-level WordBoundary events
  24. speechConfig.SetProperty(PropertyId.SpeechServiceResponse_RequestSentenceBoundary, "true");
  25. using (var speechSynthesizer = new SpeechSynthesizer(speechConfig))
  26. {
  27. // Subscribe to events
  28. // 注册表情嘴型数据
  29. speechSynthesizer.VisemeReceived += async (s, e) =>
  30. {
  31. Console.WriteLine($"VisemeReceived event:" +
  32. $"\r\n\tAudioOffset: {(e.AudioOffset + 5000) / 10000}ms"
  33. + $"\r\n\tVisemeId: {e.VisemeId}"
  34. // + $"\r\n\tAnimation: {e.Animation}"
  35. );
  36. if (string.IsNullOrEmpty( e.Animation)==false)
  37. {
  38. // \r\n, 是为了组合 json 格式
  39. content += e.Animation + "\r\n,";
  40. index++;
  41. }
  42. };
  43. // 注册合成完毕的事件
  44. speechSynthesizer.SynthesisCompleted += async (s, e) =>
  45. {
  46. Console.WriteLine($"SynthesisCompleted event:" +
  47. $"\r\n\tAudioData: {e.Result.AudioData.Length} bytes" +
  48. $"\r\n\tindex: {index} " +
  49. $"\r\n\tAudioDuration: {e.Result.AudioDuration}");
  50. content = content.Substring(0, content.Length-1);
  51. content += "]";
  52. await CommitAsync(fileName, content);
  53. };
  54. // Synthesize the SSML
  55. Console.WriteLine($"SSML to synthesize: \r\n{ssml}");
  56. var speechSynthesisResult = await speechSynthesizer.SpeakSsmlAsync(ssml);
  57. // 获取到视频的数据,保存为 .wav
  58. using var stream = AudioDataStream.FromResult(speechSynthesisResult);
  59. await stream.SaveToWaveFileAsync(@$"d:\temp\{fileName}.wav");
  60. // Output the results
  61. switch (speechSynthesisResult.Reason)
  62. {
  63. case ResultReason.SynthesizingAudioCompleted:
  64. Console.WriteLine("SynthesizingAudioCompleted result");
  65. break;
  66. case ResultReason.Canceled:
  67. var cancellation = SpeechSynthesisCancellationDetails.FromResult(speechSynthesisResult);
  68. Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");
  69. if (cancellation.Reason == CancellationReason.Error)
  70. {
  71. Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
  72. Console.WriteLine($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
  73. Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
  74. }
  75. break;
  76. default:
  77. break;
  78. }
  79. }
  80. Console.WriteLine("Press any key to exit...");
  81. Console.ReadKey();
  82. }
  83. /// <summary>
  84. /// 嘴型 animation 数据,本地保存为 json 数据
  85. /// </summary>
  86. /// <param name="fileName">保存文件名</param>
  87. /// <param name="content">保存内容</param>
  88. /// <returns></returns>
  89. static async Task CommitAsync(string fileName,string content)
  90. {
  91. var bits = Encoding.UTF8.GetBytes(content);
  92. using (var fs = new FileStream(
  93. path: @$"d:\temp\{fileName}.json",
  94. mode: FileMode.Create,
  95. access: FileAccess.Write,
  96. share: FileShare.None,
  97. bufferSize: 4096,
  98. useAsync: true))
  99. {
  100. await fs.WriteAsync(bits, 0, bits.Length);
  101. }
  102. }
  103. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/523125
推荐阅读
相关标签
  

闽ICP备14008679号