| File: Internal\Synthesis\SpeakInfo.cs | Web Access |
| Project: src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Speech.Synthesis; using System.Speech.Synthesis.TtsEngine; #pragma warning disable 56524 // The _voiceSynthesis member is not created in this module and should not be disposed namespace System.Speech.Internal.Synthesis { internal sealed class SpeakInfo { #region Constructors /// <param name="voiceSynthesis">Voice synthesizer used</param> /// <param name="ttsVoice">Default engine to use</param> internal SpeakInfo(VoiceSynthesis voiceSynthesis, TTSVoice ttsVoice) { _voiceSynthesis = voiceSynthesis; _ttsVoice = ttsVoice; } #endregion #region Internal Properties internal TTSVoice Voice { get { return _ttsVoice; } } #endregion #region Internal Methods internal void SetVoice(string? name, CultureInfo? culture, VoiceGender gender, VoiceAge age, int variant) { TTSVoice ttsVoice = _voiceSynthesis.GetEngine(name, culture, gender, age, variant, false); if (!ttsVoice.Equals(_ttsVoice)) { _ttsVoice = ttsVoice; NotInTextSeg = true; } } internal void AddAudio(AudioData audio) { AddNewSeg(new SpeechSeg(audio)); NotInTextSeg = true; } internal void AddText(TTSVoice ttsVoice, TextFragment textFragment) { if (NotInTextSeg || ttsVoice != _ttsVoice) { AddNewSeg(new SpeechSeg(ttsVoice)); NotInTextSeg = false; } _lastSeg.AddFrag(textFragment); } internal SpeechSeg? RemoveFirst() { SpeechSeg? speechSeg = null; if (_listSeg.Count > 0) { speechSeg = _listSeg[0]; _listSeg.RemoveAt(0); } return speechSeg; } #endregion #region Private Method [MemberNotNull(nameof(_lastSeg))] private void AddNewSeg(SpeechSeg pNew) { _listSeg.Add(pNew); _lastSeg = pNew; } #endregion #region private Fields // default TTS voice private TTSVoice _ttsVoice; // If true then a new segment is required for the next Add Text [MemberNotNullWhen(false, nameof(_lastSeg))] private bool NotInTextSeg { get; set; } = true; // list of segments (text or audio) private List<SpeechSeg> _listSeg = new(); // current segment private SpeechSeg? _lastSeg; // Reference to the VoiceSynthesizer that created it private VoiceSynthesis _voiceSynthesis; #endregion } #region Private Types internal class AudioData : IDisposable { internal AudioData(Uri uri, ResourceLoader resourceLoader) { _uri = uri; _resourceLoader = resourceLoader; Uri? baseAudio; _stream = _resourceLoader.LoadFile(uri, out _mimeType, out baseAudio, out _localFile); } /// <summary> /// Needed by IEnumerable!!! /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~AudioData() { Dispose(false); } internal Uri _uri; internal string? _mimeType; internal Stream _stream; protected virtual void Dispose(bool disposing) { if (disposing) { // unload the file from the cache if (_localFile != null) { _resourceLoader.UnloadFile(_localFile); } if (_stream != null) { _stream.Dispose(); _stream = null!; _localFile = null!; _uri = null!; } } } private string? _localFile; private ResourceLoader _resourceLoader; } #endregion }