using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace ScDriver.VoiceVox : IDisposable { public class VoiceVoxProxy { private static HttpClient client; public VoiceVoxProxy() { try { client = new HttpClient(); } catch (Exception) { client = null; } } public void Dispose() { client?.Dispose(); } private void SettingJsonHeader() { client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("audio/wav")); client.DefaultRequestHeaders.Add("User-Agent", "AssistantSeika Driver"); } private void PostSynthesisQuery(VoiceVoxAudioQuery aq, int speaker, string saveFileName = "") { var json = new DataContractJsonSerializer(typeof(VoiceVoxAudioQuery)); MemoryStream ms = new MemoryStream(); json.WriteObject(ms, aq); var content = new StringContent(Encoding.UTF8.GetString(ms.ToArray()), Encoding.UTF8, "application/json"); Task.Run(async () => { SettingJsonHeader(); try { var response = await client.PostAsync(string.Format(@"http://localhost:50021/synthesis?speaker={0}", speaker), content); if(response.StatusCode== System.Net.HttpStatusCode.OK) { string tempFileName = saveFileName == "" ? Path.GetTempFileName() : saveFileName; using (FileStream tempfile = new FileStream(tempFileName, FileMode.Create, FileAccess.Write, FileShare.None)) { await response.Content.CopyToAsync(tempfile); } if (saveFileName == "") { var player = new System.Media.SoundPlayer(tempFileName); player.PlaySync(); File.Delete(tempFileName); } } } catch (Exception e) { MessageBox.Show(string.Format("** PostSynthesisQuery2 [{0}:{1},{2}]", speaker, saveFileName, e.Message)); } }).Wait(); } private VoiceVoxAudioQuery GetAudioQuery(string text, int speaker) { var content = new StringContent("{}", Encoding.UTF8, @"application/json"); VoiceVoxAudioQuery ans = null; DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings(); settings.UseSimpleDictionaryFormat = true; Task.Run(async () => { SettingJsonHeader(); try { var response = await client.PostAsync(string.Format(@"http://localhost:50021/audio_query?text={0}&speaker={1}", text, speaker), content); if (response.StatusCode == System.Net.HttpStatusCode.OK) { var json = new DataContractJsonSerializer(typeof(VoiceVoxAudioQuery), settings); ans = (VoiceVoxAudioQuery)json.ReadObject(await response.Content.ReadAsStreamAsync()); } } catch (Exception e) { MessageBox.Show(string.Format("** GetAudioQuery {0}:{1},{2}", speaker, text, e.Message)); } }).Wait(); return ans; } /// /// 話者パラメタの取り出し /// /// 話者番号 /// パラメタ情報 public VoiceVoxParams GetAvatorParams(int speaker) { VoiceVoxParams ans = new VoiceVoxParams(); try { VoiceVoxAudioQuery aq = GetAudioQuery("あ", speaker); if (aq!=null) { ans.intonationScale = (double)aq.intonationScale; ans.pitchScale = (double)aq.pitchScale; ans.speedScale = (double)aq.speedScale; ans.volumeScale = (double)aq.volumeScale; } } catch(Exception e) { MessageBox.Show(string.Format("** GetAvatorParams [{0}:{1}]", speaker, e.Message)); } return ans; } /// /// 利用可能な話者の取り出し /// /// 話者番号と名称の組み合わせのリスト public List> AvailableCasts() { DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings(); List speakers = new List(); var ans = new List>(); Task.Run(async () => { SettingJsonHeader(); try { var response = await client.GetAsync("http://localhost:50021/speakers"); if (response.StatusCode == System.Net.HttpStatusCode.OK) { var json = new DataContractJsonSerializer(typeof(List), settings); speakers = (List)json.ReadObject(await response.Content.ReadAsStreamAsync()); ans = speakers.SelectMany(v1 => v1.styles.Select(v2 => new { id = v2.id, name = string.Format("{0}({1})", v1.name, v2.name) })) .OrderBy(v => v.id) .Select(v => new KeyValuePair(v.id, v.name)).ToList(); } } catch (Exception e) { MessageBox.Show(string.Format("** AvailableCasts [{0}]", e.Message)); } }).Wait(); return ans; } /// /// 発声 /// /// 話者番号 /// エフェクト /// 発声させるテキスト public void Speak(int speaker, VoiceVoxParams param, string text) { VoiceVoxAudioQuery aq = GetAudioQuery(text, speaker); if (param != null) { aq.volumeScale = param.volumeScale; aq.speedScale = param.speedScale; aq.pitchScale = param.pitchScale; aq.speedScale = param.speedScale; } PostSynthesisQuery(aq, speaker); } /// /// 音声保存 /// /// 話者番号 /// エフェクト /// 発声させるテキスト /// 保存するファイル名 public void Save(int speaker, VoiceVoxParams param, string text, string WavFilePath) { VoiceVoxAudioQuery aq = GetAudioQuery(text, speaker); if (param != null) { aq.volumeScale = param.volumeScale; aq.speedScale = param.speedScale; aq.pitchScale = param.pitchScale; aq.speedScale = param.speedScale; } PostSynthesisQuery(aq, speaker, WavFilePath); } } public class VoiceVoxParams { public double speedScale; public double pitchScale; public double intonationScale; public double volumeScale; } [DataContract] public class VoiceVoxSpeaker { [DataMember] public string name { get; set; } [DataMember] public string speaker_uuid { get; set; } [DataMember] public VoiceVoxSpeakerStyle[] styles { get; set; } [DataMember] public string version { get; set; } } [DataContract] public class VoiceVoxSpeakerStyle { [DataMember] public string name { get; set; } [DataMember] public int id { get; set; } } [DataContract] public class VoiceVoxAudioQuery { [DataMember] public string name { get; set; } [DataMember] public int? id { get; set; } [DataMember] public VoiceVoxAccentPhrase[] accent_phrases { get; set; } [DataMember] public double? speedScale { get; set; } [DataMember] public double? pitchScale { get; set; } [DataMember] public double? intonationScale { get; set; } [DataMember] public double? volumeScale { get; set; } [DataMember] public double? prePhonemeLength { get; set; } [DataMember] public double? postPhonemeLength { get; set; } [DataMember] public int? outputSamplingRate { get; set; } [DataMember] public bool outputStereo { get; set; } [DataMember] public string kana { get; set; } } [DataContract] public class VoiceVoxAccentPhrase { [DataMember] public VoiceVoxMora[] moras { get; set; } [DataMember] public int accent { get; set; } [DataMember] public VoiceVoxPauseMora pause_mora { get; set; } } [DataContract] public class VoiceVoxMora { [DataMember] public string text { get; set; } [DataMember] public string consonant { get; set; } [DataMember] public double? consonant_length { get; set; } [DataMember] public string vowel { get; set; } [DataMember] public double? vowel_length { get; set; } [DataMember] public double? pitch { get; set; } } [DataContract] public class VoiceVoxPauseMora { [DataMember] public string text { get; set; } [DataMember] public string consonant { get; set; } [DataMember] public double? consonant_length { get; set; } [DataMember] public string vowel { get; set; } [DataMember] public double? vowel_length { get; set; } [DataMember] public double? pitch { get; set; } } }