You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
7.6 KiB

4 years ago
4 years ago
  1. using Apewer.Models;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. // using System.Threading.Tasks;
  6. using System.IO;
  7. using Apewer.Internals.Interop;
  8. #if NET40_OR_GREATER
  9. using System.Speech.Synthesis;
  10. #endif
  11. namespace Apewer
  12. {
  13. /// <summary>音频实用工具。</summary>
  14. public sealed class AudioUtility
  15. {
  16. private AudioUtility() { }
  17. #region WAVE 校验。
  18. private static int mmioFOURCC(char ch0, char ch1, char ch2, char ch3)
  19. {
  20. int num = 0;
  21. num |= ch0;
  22. num |= (int)((uint)ch1 << 8);
  23. num |= (int)((uint)ch2 << 16);
  24. return num | (int)((uint)ch3 << 24);
  25. }
  26. private static int BytesToInt(byte ch0, byte ch1, byte ch2, byte ch3)
  27. {
  28. return mmioFOURCC((char)ch3, (char)ch2, (char)ch1, (char)ch0);
  29. }
  30. private static short BytesToInt16(byte ch0, byte ch1)
  31. {
  32. int num = ch1 | ch0 << 8;
  33. return (short)num;
  34. }
  35. /// <summary>检查字节数组是 WAVE。</summary>
  36. public static bool IsWave(params byte[] data)
  37. {
  38. if (data == null || data.LongLength < 1L) return false;
  39. int num = 0;
  40. short num2 = -1;
  41. bool flag = false;
  42. if (data.Length < 12) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  43. if (data[0] == 82 && data[1] == 73 && data[2] == 70 && data[3] == 70)
  44. {
  45. if (data[8] == 87 && data[9] == 65 && data[10] == 86 && data[11] == 69)
  46. {
  47. num = 12;
  48. int num3 = data.Length;
  49. while (!flag && num < num3 - 8)
  50. {
  51. if (data[num] == 102 && data[num + 1] == 109 && data[num + 2] == 116 && data[num + 3] == 32)
  52. {
  53. flag = true;
  54. int num4 = BytesToInt(data[num + 7], data[num + 6], data[num + 5], data[num + 4]);
  55. int num5 = 16;
  56. if (num4 != num5)
  57. {
  58. int num6 = 18;
  59. if (num3 < num + 8 + num6 - 1) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  60. short num7 = BytesToInt16(data[num + 8 + num6 - 1], data[num + 8 + num6 - 2]);
  61. if (num7 + num6 != num4) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  62. }
  63. if (num3 < num + 9) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  64. num2 = BytesToInt16(data[num + 9], data[num + 8]);
  65. num += num4 + 8;
  66. }
  67. else
  68. {
  69. num += 8 + BytesToInt(data[num + 7], data[num + 6], data[num + 5], data[num + 4]);
  70. }
  71. }
  72. if (!flag) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  73. if (num2 == 1) return true;
  74. if (num2 == 2) return true;
  75. if (num2 == 3) return true;
  76. return false; // throw new InvalidOperationException(SR.GetString("SoundAPIFormatNotSupported"));
  77. }
  78. return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  79. }
  80. return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
  81. }
  82. #endregion
  83. #region WinMM 控制。
  84. /// <summary>WinMM:播放音频。</summary>
  85. /// <param name="wave">波形数据。</param>
  86. /// <param name="loop">循环播放。</param>
  87. public static void Play(byte[] wave, bool loop = false)
  88. {
  89. if (wave == null || wave.LongLength == 0) return;
  90. int flag = loop ? 9 : 1;
  91. try { WinMM.PlaySound(wave, IntPtr.Zero, 6 | flag); } catch { }
  92. }
  93. /// <summary>WinMM:停止播放。</summary>
  94. public static void Stop()
  95. {
  96. try { WinMM.PlaySound(null as string, IntPtr.Zero, 64); } catch { }
  97. }
  98. private static void MessageBeep(int type)
  99. {
  100. try { User32.MessageBeep(type); } catch { }
  101. }
  102. /// <summary>播放系统声音。</summary>
  103. public static void Asterisk() => MessageBeep(64);
  104. /// <summary>播放系统声音。</summary>
  105. public static void Beep() => MessageBeep(0);
  106. /// <summary>播放系统声音。</summary>
  107. public static void Exclamation() => MessageBeep(48);
  108. /// <summary>播放系统声音。</summary>
  109. public static void Hand() => MessageBeep(16);
  110. /// <summary>播放系统声音。</summary>
  111. public static void Question() => MessageBeep(32);
  112. #endregion
  113. #if NET40_OR_GREATER
  114. /// <summary>列举所有 Speech Voices 的 Name。 </summary>
  115. public static List<string> ListVoices()
  116. {
  117. var list = new List<string>();
  118. using (var synthesizer = new SpeechSynthesizer())
  119. {
  120. var installed = synthesizer.GetInstalledVoices();
  121. foreach (var voice in installed)
  122. {
  123. list.Add(voice.VoiceInfo.Name);
  124. }
  125. }
  126. return list;
  127. }
  128. /// <summary>获取 Voice 信息。</summary>
  129. public static VoiceInfo GetVoice(string name)
  130. {
  131. if (string.IsNullOrEmpty(name)) return null;
  132. using (var synthesizer = new SpeechSynthesizer())
  133. {
  134. var installed = synthesizer.GetInstalledVoices();
  135. foreach (var voice in installed)
  136. {
  137. if (voice.VoiceInfo.Name == name) return voice.VoiceInfo;
  138. }
  139. }
  140. return null;
  141. }
  142. /// <summary>讲述文本,默认为异步执行。</summary>
  143. public static void Speak(string text, string voice = null, bool async = true)
  144. {
  145. if (string.IsNullOrEmpty(text)) return;
  146. if (async)
  147. {
  148. var wave = Render(text, voice);
  149. Play(wave);
  150. }
  151. else
  152. {
  153. using (var synthesizer = new SpeechSynthesizer())
  154. {
  155. try
  156. {
  157. if (!string.IsNullOrEmpty(voice)) synthesizer.SelectVoice(voice);
  158. synthesizer.Speak(text);
  159. }
  160. catch { }
  161. }
  162. }
  163. }
  164. /// <summary>渲染为音频数据。</summary>
  165. public static byte[] Render(string text, string voice = null)
  166. {
  167. if (string.IsNullOrEmpty(text)) return null;
  168. using (var memory = new MemoryStream())
  169. {
  170. using (var synthesizer = new SpeechSynthesizer())
  171. {
  172. try
  173. {
  174. if (!string.IsNullOrEmpty(voice)) synthesizer.SelectVoice(voice);
  175. synthesizer.SetOutputToWaveStream(memory);
  176. synthesizer.Speak(text);
  177. }
  178. catch { }
  179. }
  180. var bytes = memory.ToArray();
  181. return bytes;
  182. }
  183. }
  184. #endif
  185. }
  186. }