using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace ScDriver.CeVio { public class ScDeviceDriver : ScBaseDriver, IScBaseDriver { private const string DrvName = "CeVIO.Driver@echoseika.hgotoh.jp"; private const string DrvVersion = "20210327/c"; private const string DrvProdName = "CeVIO"; private const int DrvTextMaxLength = 100; private const int CidBase = 3000; private const int MaxAvators = 100; private const int SplitLine = 50; public SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); private CeVio.CevioProxy CevioTalkProxy = null; class titles { public int PresetType { get; private set; } public string Avator { get; private set; } public int FixedCid { get; private set; } public int AvatorIndex { get; private set; } public titles(int priset, string avator, int cid) { PresetType = priset; Avator = avator; FixedCid = cid; AvatorIndex = 0; } } private readonly titles[] CeVIO2Names = { new titles(0, "さとうささら", CidBase + 1), new titles(0, "すずきつづみ", CidBase + 2), new titles(0, "タカハシ", CidBase + 3), new titles(0, "ONE", CidBase + 4), new titles(0, "IA", CidBase + 5), }; public ScDeviceDriver() { ScDrvName = DrvName; ScDrvVersion = DrvVersion; ScDrvProdName = DrvProdName; ScDrvTextMaxLength = DrvTextMaxLength; CidBaseIndex = CidBase; AvatorParams = new Dictionary(); IsAlive = false; if(GetCeVIOEditorProcess()) { titles ent = null; // 認識対象外、もしくはユーザ定義プリセットに割り当てるcidのカウンター int cbaseCounter = 1 + CeVIO2Names.Select(v => v.FixedCid).Max(); if (cbaseCounter < (CidBase + SplitLine)) cbaseCounter = CidBase + SplitLine; try { AppDomain appDomain = AppDomain.CreateDomain("SeikaCenterCevioPlugin"); CevioTalkProxy = (CeVio.CevioProxy)appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(CeVio.CevioProxy).FullName); string[] talkers = CevioTalkProxy.AvailableCasts; if (talkers.Length != 0) { for (int avatorIndex = 0; avatorIndex < talkers.Length; avatorIndex++) { if (cbaseCounter >= (CidBase + MaxAvators)) break; CevioTalkProxy.Cast = talkers[avatorIndex]; CeVio.AvatorParam avator = new CeVio.AvatorParam(); avator.AvatorIndex = avatorIndex; avator.AvatorName = talkers[avatorIndex]; // 認識している話者名ならば固定のcidを設定 try { ent = CeVIO2Names.Where(v => v.Avator == avator.AvatorName).First(); avator.FixedCid = ent.FixedCid; } catch (Exception) { avator.FixedCid = cbaseCounter; cbaseCounter++; } // このタイミングで一旦登録する AvatorParams.Add(avator.FixedCid, avator); avator.VoiceEffects_default = new Dictionary { {EnumVoiceEffect.volume, new EffectValueInfo( (decimal)CevioTalkProxy.Volume, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.speed, new EffectValueInfo( (decimal)CevioTalkProxy.Speed, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.pitch, new EffectValueInfo( (decimal)CevioTalkProxy.Tone, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.alpha, new EffectValueInfo( (decimal)CevioTalkProxy.Alpha, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.intonation, new EffectValueInfo( (decimal)CevioTalkProxy.ToneScale, 0.0m, 100.0m, 1.00m)} }; avator.VoiceEffects = new Dictionary { {EnumVoiceEffect.volume, new EffectValueInfo( (decimal)CevioTalkProxy.Volume, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.speed, new EffectValueInfo( (decimal)CevioTalkProxy.Speed, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.pitch, new EffectValueInfo( (decimal)CevioTalkProxy.Tone, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.alpha, new EffectValueInfo( (decimal)CevioTalkProxy.Alpha, 0.0m, 100.0m, 1.00m)}, {EnumVoiceEffect.intonation, new EffectValueInfo( (decimal)CevioTalkProxy.ToneScale, 0.0m, 100.0m, 1.00m)} }; avator.VoiceEmotions_default = new Dictionary(); avator.VoiceEmotions = new Dictionary(); Dictionary emoparams = CevioTalkProxy.Components; if (0 < emoparams.Count) { foreach (KeyValuePair emotion in emoparams) { avator.VoiceEmotions_default.Add(emotion.Key, new EffectValueInfo((decimal)(emotion.Value), 0.00m, 100.0m, 1.00m)); avator.VoiceEmotions.Add(emotion.Key, new EffectValueInfo((decimal)(emotion.Value), 0.00m, 100.0m, 1.00m)); } } } } } catch (Exception) { AvatorParams.Clear(); // ThrowException(string.Format(@"{0} {1}", e.Message, e.StackTrace)); } } else { AvatorParams.Clear(); } IsAlive = AvatorParams.Count != 0; // cidエイリアス用 if (IsAlive) { CeVio.AvatorParam avator = new CeVio.AvatorParam(); int firsFindtCid = AvatorParams.First().Value.FixedCid; avator.FixedCid = CidBase; avator.AvatorIndex = AvatorParams.Count; avator.AvatorName = AvatorParams[firsFindtCid].AvatorName; avator.AliasCode = true; avator.VoiceEffects = (AvatorParams[firsFindtCid] as CeVio.AvatorParam).VoiceEffects; avator.VoiceEmotions = (AvatorParams[firsFindtCid] as CeVio.AvatorParam).VoiceEmotions; avator.VoiceEffects_default = (AvatorParams[firsFindtCid] as CeVio.AvatorParam).VoiceEffects_default; avator.VoiceEmotions_default = (AvatorParams[firsFindtCid] as CeVio.AvatorParam).VoiceEmotions_default; AvatorParams.Add(avator.FixedCid, avator); } } public override void Dispose(bool disposing) { if (Disposed) return; if (disposing) { AvatorParams.Clear(); } Disposed = true; } public void Dispose() { Dispose(true); } /// /// CeVIO起動の確認 /// private bool GetCeVIOEditorProcess() { string winTitle1 = @"^.+ - CeVIO CS6$"; string winTitle2 = @"^.+ - CeVIO CS7$"; string runProcName = @"CeVIO Creative Studio"; int RetryCount = 3; int RetryWaitms = 500; bool p = false; for (int i = 0; i < 3; i++) { Process[] ps = Process.GetProcesses(); foreach (Process pitem in ps) { if ((pitem.MainWindowHandle != IntPtr.Zero) && (pitem.ProcessName == runProcName)) { if (Environment.Is64BitProcess) { if (Regex.IsMatch(pitem.MainWindowTitle, winTitle2)) { p = true; break; } } else { if (Regex.IsMatch(pitem.MainWindowTitle, winTitle1)) { p = true; break; } } } } if (p) break; if (i < (RetryCount - 1)) Thread.Sleep(RetryWaitms); } return p; } /// /// 指定話者で指定テキストで発声 /// /// 話者CID /// 発声させるテキスト /// 発声にかかった時間(ミリ秒) public override double Play(int cid, string talkText) { Semaphore.Wait(); Stopwatch sw = new Stopwatch(); int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); ApplyEffectParameters(avatorIndex); ApplyEmotionParameters(avatorIndex); sw.Start(); try { int len = talkText.Length > ScDriverTextMaxLength ? ScDriverTextMaxLength : talkText.Length; CevioTalkProxy.Speak(talkText.Substring(0, len)); } catch (Exception) { // } sw.Stop(); Semaphore.Release(); return sw.ElapsedMilliseconds; } /// /// 指定話者で指定テキストで発声 /// /// 話者CID /// 発声させるテキスト /// 発声にかかった時間(ミリ秒) public override double Play(int cid, string[] talkTexts) { Semaphore.Wait(); Stopwatch sw = new Stopwatch(); int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); ApplyEffectParameters(avatorIndex); ApplyEmotionParameters(avatorIndex); sw.Start(); try { foreach(string txt in talkTexts) { int len = txt.Length > ScDriverTextMaxLength ? ScDriverTextMaxLength : txt.Length; CevioTalkProxy.Speak(txt.Substring(0, len)); } } catch (Exception) { //MessageBox.Show(String.Format("{0}:{1}", e.Message, e.StackTrace)); } sw.Stop(); Semaphore.Release(); return sw.ElapsedMilliseconds; } /// /// 指定話者で指定テキストで発声 /// /// 話者CID /// 発声させるテキスト public override void PlayAsync(int cid, string talkText) { Task.Run(() => { Semaphore.Wait(); int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); ApplyEffectParameters(avatorIndex); ApplyEmotionParameters(avatorIndex); try { int len = talkText.Length > ScDriverTextMaxLength ? ScDriverTextMaxLength : talkText.Length; CevioTalkProxy.Speak(talkText.Substring(0, len)); } catch (Exception) { // } Semaphore.Release(); }); } /// /// 指定話者で指定テキストで発声 /// /// 話者CID /// 発声させるテキスト public override void PlayAsync(int cid, string[] talkTexts) { Task.Run(() => { Semaphore.Wait(); int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); ApplyEffectParameters(avatorIndex); ApplyEmotionParameters(avatorIndex); try { foreach (string txt in talkTexts) { int len = txt.Length > ScDriverTextMaxLength ? ScDriverTextMaxLength : txt.Length; CevioTalkProxy.Speak(txt.Substring(0, len)); } } catch (Exception) { // } Semaphore.Release(); }); } /// /// 指定話者で指定テキストで発声した結果をファイルに保存 /// /// 話者CID /// 発声させるテキスト /// 保存先ファイル名 /// 0.0ミリ秒固定 public override double Save(int cid, string talkText, string saveFilename) { int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); ApplyEffectParameters(avatorIndex); ApplyEmotionParameters(avatorIndex); try { int len = talkText.Length > ScDriverTextMaxLength ? ScDriverTextMaxLength : talkText.Length; CevioTalkProxy.Save(talkText.Substring(0, len), saveFilename); } catch (Exception) { // } return 0.0; } /// /// 指定話者で指定テキストで発声した結果をファイルに保存 /// /// 話者CID /// 発声させるテキスト /// 保存先ファイル名 /// 0.0ミリ秒固定 public override double Save(int cid, string[] talkTexts, string saveFilename) { int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); ApplyEffectParameters(avatorIndex); ApplyEmotionParameters(avatorIndex); try { string s = String.Join("", talkTexts); int len = s.Length > ScDriverTextMaxLength ? ScDriverTextMaxLength : s.Length; CevioTalkProxy.Save(s.Substring(0, len), saveFilename); } catch (Exception) { // } return 0.0; } public override void ResetVoiceEmotion(int cid) { int avatorIndex = ConvertAvatorIndex(cid); foreach (KeyValuePair item in AvatorParams[avatorIndex].VoiceEmotions_default) { AvatorParams[avatorIndex].VoiceEmotions[item.Key].value = item.Value.value; } ApplyEmotionParameters(avatorIndex); } public override void ResetVoiceEffect(int cid) { int avatorIndex = ConvertAvatorIndex(cid); foreach (var effect in AvatorParams[avatorIndex].VoiceEffects_default) { AvatorParams[avatorIndex].VoiceEffects[effect.Key].value = effect.Value.value; } ApplyEffectParameters(avatorIndex); } public override void SetAvator(int cid) { int avatorIndex = ConvertAvatorIndex(cid); AvatorSelect(avatorIndex); } private void AvatorSelect(int avatorIndex) { CevioTalkProxy.Cast = AvatorParams[avatorIndex].AvatorName; } private void ApplyEmotionParameters(int avatorIndex) { foreach (KeyValuePair item in AvatorParams[avatorIndex].VoiceEmotions) { CevioTalkProxy.SetComponent(item.Key, (uint)(item.Value.value)); } } private void ApplyEffectParameters(int avatorIndex) { foreach (KeyValuePair item in AvatorParams[avatorIndex].VoiceEffects) { switch (item.Key) { case EnumVoiceEffect.volume: CevioTalkProxy.Volume = (uint)(item.Value.value); break; case EnumVoiceEffect.speed: CevioTalkProxy.Speed = (uint)(item.Value.value); break; case EnumVoiceEffect.pitch: CevioTalkProxy.Tone = (uint)(item.Value.value); break; case EnumVoiceEffect.alpha: CevioTalkProxy.Alpha = (uint)(item.Value.value); break; case EnumVoiceEffect.intonation: CevioTalkProxy.ToneScale = (uint)(item.Value.value); break; } } } } }