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
218 lines
7.6 KiB
using Apewer.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
// using System.Threading.Tasks;
|
|
using System.IO;
|
|
using Apewer.Internals.Interop;
|
|
|
|
#if NET40_OR_GREATER
|
|
using System.Speech.Synthesis;
|
|
#endif
|
|
|
|
namespace Apewer
|
|
{
|
|
|
|
/// <summary>音频实用工具。</summary>
|
|
public sealed class AudioUtility
|
|
{
|
|
|
|
private AudioUtility() { }
|
|
|
|
#region WAVE 校验。
|
|
|
|
private static int mmioFOURCC(char ch0, char ch1, char ch2, char ch3)
|
|
{
|
|
int num = 0;
|
|
num |= ch0;
|
|
num |= (int)((uint)ch1 << 8);
|
|
num |= (int)((uint)ch2 << 16);
|
|
return num | (int)((uint)ch3 << 24);
|
|
}
|
|
|
|
private static int BytesToInt(byte ch0, byte ch1, byte ch2, byte ch3)
|
|
{
|
|
return mmioFOURCC((char)ch3, (char)ch2, (char)ch1, (char)ch0);
|
|
}
|
|
|
|
private static short BytesToInt16(byte ch0, byte ch1)
|
|
{
|
|
int num = ch1 | ch0 << 8;
|
|
return (short)num;
|
|
}
|
|
|
|
/// <summary>检查字节数组是 WAVE。</summary>
|
|
public static bool IsWave(params byte[] data)
|
|
{
|
|
if (data == null || data.LongLength < 1L) return false;
|
|
|
|
int num = 0;
|
|
short num2 = -1;
|
|
bool flag = false;
|
|
if (data.Length < 12) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
if (data[0] == 82 && data[1] == 73 && data[2] == 70 && data[3] == 70)
|
|
{
|
|
if (data[8] == 87 && data[9] == 65 && data[10] == 86 && data[11] == 69)
|
|
{
|
|
num = 12;
|
|
int num3 = data.Length;
|
|
while (!flag && num < num3 - 8)
|
|
{
|
|
if (data[num] == 102 && data[num + 1] == 109 && data[num + 2] == 116 && data[num + 3] == 32)
|
|
{
|
|
flag = true;
|
|
int num4 = BytesToInt(data[num + 7], data[num + 6], data[num + 5], data[num + 4]);
|
|
int num5 = 16;
|
|
if (num4 != num5)
|
|
{
|
|
int num6 = 18;
|
|
if (num3 < num + 8 + num6 - 1) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
short num7 = BytesToInt16(data[num + 8 + num6 - 1], data[num + 8 + num6 - 2]);
|
|
if (num7 + num6 != num4) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
}
|
|
if (num3 < num + 9) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
num2 = BytesToInt16(data[num + 9], data[num + 8]);
|
|
num += num4 + 8;
|
|
}
|
|
else
|
|
{
|
|
num += 8 + BytesToInt(data[num + 7], data[num + 6], data[num + 5], data[num + 4]);
|
|
}
|
|
}
|
|
if (!flag) return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
if (num2 == 1) return true;
|
|
if (num2 == 2) return true;
|
|
if (num2 == 3) return true;
|
|
return false; // throw new InvalidOperationException(SR.GetString("SoundAPIFormatNotSupported"));
|
|
}
|
|
return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
}
|
|
return false; // throw new InvalidOperationException(SR.GetString("SoundAPIInvalidWaveHeader"));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region WinMM 控制。
|
|
|
|
/// <summary>WinMM:播放音频。</summary>
|
|
/// <param name="wave">波形数据。</param>
|
|
/// <param name="loop">循环播放。</param>
|
|
public static void Play(byte[] wave, bool loop = false)
|
|
{
|
|
if (wave == null || wave.LongLength == 0) return;
|
|
|
|
int flag = loop ? 9 : 1;
|
|
try { WinMM.PlaySound(wave, IntPtr.Zero, 6 | flag); } catch { }
|
|
}
|
|
|
|
/// <summary>WinMM:停止播放。</summary>
|
|
public static void Stop()
|
|
{
|
|
try { WinMM.PlaySound(null as string, IntPtr.Zero, 64); } catch { }
|
|
}
|
|
|
|
private static void MessageBeep(int type)
|
|
{
|
|
try { User32.MessageBeep(type); } catch { }
|
|
}
|
|
|
|
/// <summary>播放系统声音。</summary>
|
|
public static void Asterisk() => MessageBeep(64);
|
|
|
|
/// <summary>播放系统声音。</summary>
|
|
public static void Beep() => MessageBeep(0);
|
|
|
|
/// <summary>播放系统声音。</summary>
|
|
public static void Exclamation() => MessageBeep(48);
|
|
|
|
/// <summary>播放系统声音。</summary>
|
|
public static void Hand() => MessageBeep(16);
|
|
|
|
/// <summary>播放系统声音。</summary>
|
|
public static void Question() => MessageBeep(32);
|
|
|
|
#endregion
|
|
|
|
#if NET40_OR_GREATER
|
|
|
|
/// <summary>列举所有 Speech Voices 的 Name。 </summary>
|
|
public static List<string> ListVoices()
|
|
{
|
|
var list = new List<string>();
|
|
using (var synthesizer = new SpeechSynthesizer())
|
|
{
|
|
var installed = synthesizer.GetInstalledVoices();
|
|
foreach (var voice in installed)
|
|
{
|
|
list.Add(voice.VoiceInfo.Name);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/// <summary>获取 Voice 信息。</summary>
|
|
public static VoiceInfo GetVoice(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name)) return null;
|
|
using (var synthesizer = new SpeechSynthesizer())
|
|
{
|
|
var installed = synthesizer.GetInstalledVoices();
|
|
foreach (var voice in installed)
|
|
{
|
|
if (voice.VoiceInfo.Name == name) return voice.VoiceInfo;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>讲述文本,默认为异步执行。</summary>
|
|
public static void Speak(string text, string voice = null, bool async = true)
|
|
{
|
|
if (string.IsNullOrEmpty(text)) return;
|
|
|
|
if (async)
|
|
{
|
|
var wave = Render(text, voice);
|
|
Play(wave);
|
|
}
|
|
else
|
|
{
|
|
using (var synthesizer = new SpeechSynthesizer())
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(voice)) synthesizer.SelectVoice(voice);
|
|
synthesizer.Speak(text);
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>渲染为音频数据。</summary>
|
|
public static byte[] Render(string text, string voice = null)
|
|
{
|
|
if (string.IsNullOrEmpty(text)) return null;
|
|
using (var memory = new MemoryStream())
|
|
{
|
|
using (var synthesizer = new SpeechSynthesizer())
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(voice)) synthesizer.SelectVoice(voice);
|
|
synthesizer.SetOutputToWaveStream(memory);
|
|
synthesizer.Speak(text);
|
|
}
|
|
catch { }
|
|
}
|
|
var bytes = memory.ToArray();
|
|
return bytes;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|