Decompiled source of Babbler v0.9.6
plugins\System.Speech.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
#define TRACE using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Speech.AudioFormat; using System.Speech.Internal; using System.Speech.Internal.GrammarBuilding; using System.Speech.Internal.ObjectTokens; using System.Speech.Internal.SapiInterop; using System.Speech.Internal.SrgsCompiler; using System.Speech.Internal.SrgsParser; using System.Speech.Internal.Synthesis; using System.Speech.Recognition; using System.Speech.Recognition.SrgsGrammar; using System.Speech.Synthesis; using System.Speech.Synthesis.TtsEngine; using System.Text; using System.Threading; using System.Xml; using System.Xml.XPath; using Microsoft.CodeAnalysis; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyDefaultAlias("System.Speech")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: CLSCompliant(true)] [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyDescription("Provides types to perform speech synthesis and speech recognition.\r\n\r\nCommonly Used Types\r\nSystem.Speech.Synthesis.SpeechSynthesizer\r\nSystem.Speech.Recognition.SpeechRecognizer")] [assembly: AssemblyFileVersion("8.0.23.53103")] [assembly: AssemblyInformationalVersion("8.0.0+5535e31a712343a63f5d7d796cd874e563e5ac14")] [assembly: AssemblyProduct("Microsoft® .NET")] [assembly: AssemblyTitle("System.Speech")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")] [assembly: SupportedOSPlatform("Windows")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("8.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NativeIntegerAttribute : Attribute { public readonly bool[] TransformFlags; public NativeIntegerAttribute() { TransformFlags = new bool[1] { true }; } public NativeIntegerAttribute(bool[] P_0) { TransformFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class Interop { internal static class Libraries { internal const string Activeds = "activeds.dll"; internal const string Advapi32 = "advapi32.dll"; internal const string Authz = "authz.dll"; internal const string BCrypt = "BCrypt.dll"; internal const string Credui = "credui.dll"; internal const string Crypt32 = "crypt32.dll"; internal const string CryptUI = "cryptui.dll"; internal const string Dnsapi = "dnsapi.dll"; internal const string Dsrole = "dsrole.dll"; internal const string Gdi32 = "gdi32.dll"; internal const string HttpApi = "httpapi.dll"; internal const string IpHlpApi = "iphlpapi.dll"; internal const string Kernel32 = "kernel32.dll"; internal const string Logoncli = "logoncli.dll"; internal const string Mswsock = "mswsock.dll"; internal const string NCrypt = "ncrypt.dll"; internal const string Netapi32 = "netapi32.dll"; internal const string Netutils = "netutils.dll"; internal const string NtDll = "ntdll.dll"; internal const string Odbc32 = "odbc32.dll"; internal const string Ole32 = "ole32.dll"; internal const string OleAut32 = "oleaut32.dll"; internal const string Pdh = "pdh.dll"; internal const string Secur32 = "secur32.dll"; internal const string Shell32 = "shell32.dll"; internal const string SspiCli = "sspicli.dll"; internal const string User32 = "user32.dll"; internal const string Version = "version.dll"; internal const string WebSocket = "websocket.dll"; internal const string Wevtapi = "wevtapi.dll"; internal const string WinHttp = "winhttp.dll"; internal const string WinMM = "winmm.dll"; internal const string Wkscli = "wkscli.dll"; internal const string Wldap32 = "wldap32.dll"; internal const string Ws2_32 = "ws2_32.dll"; internal const string Wtsapi32 = "wtsapi32.dll"; internal const string CompressionNative = "System.IO.Compression.Native"; internal const string GlobalizationNative = "System.Globalization.Native"; internal const string MsQuic = "msquic.dll"; internal const string HostPolicy = "hostpolicy"; internal const string Ucrtbase = "ucrtbase.dll"; internal const string Xolehlp = "xolehlp.dll"; internal const string Comdlg32 = "comdlg32.dll"; internal const string Gdiplus = "gdiplus.dll"; internal const string Oleaut32 = "oleaut32.dll"; internal const string Winspool = "winspool.drv"; } internal static class WinMM { internal enum MMSYSERR { NOERROR = 0, ERROR = 1, BADDEVICEID = 2, NOTENABLED = 3, ALLOCATED = 4, INVALHANDLE = 5, NODRIVER = 6, NOMEM = 7, NOTSUPPORTED = 8, BADERRNUM = 9, INVALFLAG = 10, INVALPARAM = 11, HANDLEBUSY = 12, INVALIDALIAS = 13, BADDB = 14, KEYNOTFOUND = 15, READERROR = 16, WRITEERROR = 17, DELETEERROR = 18, VALNOTFOUND = 19, NODRIVERCB = 20, LASTERROR = 20 } internal struct WAVEOUTCAPS { private const int szPnameLength = 32; private ushort wMid; private ushort wPid; private uint vDriverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] internal string szPname; private uint dwFormats; private ushort wChannels; private ushort wReserved1; private ushort dwSupport; } internal enum MM_MSG { MM_WOM_OPEN = 955, MM_WOM_CLOSE, MM_WOM_DONE } internal delegate void WaveOutProc(IntPtr hwo, MM_MSG uMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2); internal struct WAVEHDR { internal IntPtr lpData; internal uint dwBufferLength; internal uint dwBytesRecorded; internal uint dwUser; internal uint dwFlags; internal uint dwLoops; internal IntPtr lpNext; internal uint reserved; } internal const uint CALLBACK_WINDOW = 65536u; internal const uint CALLBACK_NULL = 0u; internal const uint CALLBACK_FUNCTION = 196608u; [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutClose(IntPtr hwo); [DllImport("winmm.dll", EntryPoint = "waveOutGetDevCapsW", ExactSpelling = true)] [LibraryImport("winmm.dll", EntryPoint = "waveOutGetDevCapsW")] internal static extern MMSYSERR waveOutGetDevCaps(IntPtr uDeviceID, ref WAVEOUTCAPS caps, int cbwoc); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern int waveOutGetNumDevs(); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutOpen(ref IntPtr phwo, int uDeviceID, byte[] pwfx, WaveOutProc dwCallback, IntPtr dwInstance, uint fdwOpen); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutPause(IntPtr hwo); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutPrepareHeader(IntPtr hwo, IntPtr pwh, int cbwh); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutUnprepareHeader(IntPtr hwo, IntPtr pwh, int cbwh); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutReset(IntPtr hwo); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutRestart(IntPtr hwo); [DllImport("winmm.dll", ExactSpelling = true)] [LibraryImport("winmm.dll")] internal static extern MMSYSERR waveOutWrite(IntPtr hwo, IntPtr pwh, int cbwh); } } namespace System { internal static class Obsoletions { internal const string SharedUrlFormat = "https://aka.ms/dotnet-warnings/{0}"; internal const string SystemTextEncodingUTF7Message = "The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead."; internal const string SystemTextEncodingUTF7DiagId = "SYSLIB0001"; internal const string PrincipalPermissionAttributeMessage = "PrincipalPermissionAttribute is not honored by the runtime and must not be used."; internal const string PrincipalPermissionAttributeDiagId = "SYSLIB0002"; internal const string CodeAccessSecurityMessage = "Code Access Security is not supported or honored by the runtime."; internal const string CodeAccessSecurityDiagId = "SYSLIB0003"; internal const string ConstrainedExecutionRegionMessage = "The Constrained Execution Region (CER) feature is not supported."; internal const string ConstrainedExecutionRegionDiagId = "SYSLIB0004"; internal const string GlobalAssemblyCacheMessage = "The Global Assembly Cache is not supported."; internal const string GlobalAssemblyCacheDiagId = "SYSLIB0005"; internal const string ThreadAbortMessage = "Thread.Abort is not supported and throws PlatformNotSupportedException."; internal const string ThreadResetAbortMessage = "Thread.ResetAbort is not supported and throws PlatformNotSupportedException."; internal const string ThreadAbortDiagId = "SYSLIB0006"; internal const string DefaultCryptoAlgorithmsMessage = "The default implementation of this cryptography algorithm is not supported."; internal const string DefaultCryptoAlgorithmsDiagId = "SYSLIB0007"; internal const string CreatePdbGeneratorMessage = "The CreatePdbGenerator API is not supported and throws PlatformNotSupportedException."; internal const string CreatePdbGeneratorDiagId = "SYSLIB0008"; internal const string AuthenticationManagerMessage = "The AuthenticationManager Authenticate and PreAuthenticate methods are not supported and throw PlatformNotSupportedException."; internal const string AuthenticationManagerDiagId = "SYSLIB0009"; internal const string RemotingApisMessage = "This Remoting API is not supported and throws PlatformNotSupportedException."; internal const string RemotingApisDiagId = "SYSLIB0010"; internal const string BinaryFormatterMessage = "BinaryFormatter serialization is obsolete and should not be used. See https://aka.ms/binaryformatter for more information."; internal const string BinaryFormatterDiagId = "SYSLIB0011"; internal const string CodeBaseMessage = "Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead."; internal const string CodeBaseDiagId = "SYSLIB0012"; internal const string EscapeUriStringMessage = "Uri.EscapeUriString can corrupt the Uri string in some cases. Consider using Uri.EscapeDataString for query string components instead."; internal const string EscapeUriStringDiagId = "SYSLIB0013"; internal const string WebRequestMessage = "WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead."; internal const string WebRequestDiagId = "SYSLIB0014"; internal const string DisablePrivateReflectionAttributeMessage = "DisablePrivateReflectionAttribute has no effect in .NET 6.0+."; internal const string DisablePrivateReflectionAttributeDiagId = "SYSLIB0015"; internal const string GetContextInfoMessage = "Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations."; internal const string GetContextInfoDiagId = "SYSLIB0016"; internal const string StrongNameKeyPairMessage = "Strong name signing is not supported and throws PlatformNotSupportedException."; internal const string StrongNameKeyPairDiagId = "SYSLIB0017"; internal const string ReflectionOnlyLoadingMessage = "ReflectionOnly loading is not supported and throws PlatformNotSupportedException."; internal const string ReflectionOnlyLoadingDiagId = "SYSLIB0018"; internal const string RuntimeEnvironmentMessage = "RuntimeEnvironment members SystemConfigurationFile, GetRuntimeInterfaceAsIntPtr, and GetRuntimeInterfaceAsObject are not supported and throw PlatformNotSupportedException."; internal const string RuntimeEnvironmentDiagId = "SYSLIB0019"; internal const string JsonSerializerOptionsIgnoreNullValuesMessage = "JsonSerializerOptions.IgnoreNullValues is obsolete. To ignore null values when serializing, set DefaultIgnoreCondition to JsonIgnoreCondition.WhenWritingNull."; internal const string JsonSerializerOptionsIgnoreNullValuesDiagId = "SYSLIB0020"; internal const string DerivedCryptographicTypesMessage = "Derived cryptographic types are obsolete. Use the Create method on the base type instead."; internal const string DerivedCryptographicTypesDiagId = "SYSLIB0021"; internal const string RijndaelMessage = "The Rijndael and RijndaelManaged types are obsolete. Use Aes instead."; internal const string RijndaelDiagId = "SYSLIB0022"; internal const string RNGCryptoServiceProviderMessage = "RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead."; internal const string RNGCryptoServiceProviderDiagId = "SYSLIB0023"; internal const string AppDomainCreateUnloadMessage = "Creating and unloading AppDomains is not supported and throws an exception."; internal const string AppDomainCreateUnloadDiagId = "SYSLIB0024"; internal const string SuppressIldasmAttributeMessage = "SuppressIldasmAttribute has no effect in .NET 6.0+."; internal const string SuppressIldasmAttributeDiagId = "SYSLIB0025"; internal const string X509CertificateImmutableMessage = "X509Certificate and X509Certificate2 are immutable. Use the appropriate constructor to create a new certificate."; internal const string X509CertificateImmutableDiagId = "SYSLIB0026"; internal const string PublicKeyPropertyMessage = "PublicKey.Key is obsolete. Use the appropriate method to get the public key, such as GetRSAPublicKey."; internal const string PublicKeyPropertyDiagId = "SYSLIB0027"; internal const string X509CertificatePrivateKeyMessage = "X509Certificate2.PrivateKey is obsolete. Use the appropriate method to get the private key, such as GetRSAPrivateKey, or use the CopyWithPrivateKey method to create a new instance with a private key."; internal const string X509CertificatePrivateKeyDiagId = "SYSLIB0028"; internal const string ProduceLegacyHmacValuesMessage = "ProduceLegacyHmacValues is obsolete. Producing legacy HMAC values is not supported."; internal const string ProduceLegacyHmacValuesDiagId = "SYSLIB0029"; internal const string UseManagedSha1Message = "HMACSHA1 always uses the algorithm implementation provided by the platform. Use a constructor without the useManagedSha1 parameter."; internal const string UseManagedSha1DiagId = "SYSLIB0030"; internal const string CryptoConfigEncodeOIDMessage = "EncodeOID is obsolete. Use the ASN.1 functionality provided in System.Formats.Asn1."; internal const string CryptoConfigEncodeOIDDiagId = "SYSLIB0031"; internal const string CorruptedStateRecoveryMessage = "Recovery from corrupted process state exceptions is not supported; HandleProcessCorruptedStateExceptionsAttribute is ignored."; internal const string CorruptedStateRecoveryDiagId = "SYSLIB0032"; internal const string Rfc2898CryptDeriveKeyMessage = "Rfc2898DeriveBytes.CryptDeriveKey is obsolete and is not supported. Use PasswordDeriveBytes.CryptDeriveKey instead."; internal const string Rfc2898CryptDeriveKeyDiagId = "SYSLIB0033"; internal const string CmsSignerCspParamsCtorMessage = "CmsSigner(CspParameters) is obsolete and is not supported. Use an alternative constructor instead."; internal const string CmsSignerCspParamsCtorDiagId = "SYSLIB0034"; internal const string SignerInfoCounterSigMessage = "ComputeCounterSignature without specifying a CmsSigner is obsolete and is not supported. Use the overload that accepts a CmsSigner."; internal const string SignerInfoCounterSigDiagId = "SYSLIB0035"; internal const string RegexCompileToAssemblyMessage = "Regex.CompileToAssembly is obsolete and not supported. Use the GeneratedRegexAttribute with the regular expression source generator instead."; internal const string RegexCompileToAssemblyDiagId = "SYSLIB0036"; internal const string AssemblyNameMembersMessage = "AssemblyName members HashAlgorithm, ProcessorArchitecture, and VersionCompatibility are obsolete and not supported."; internal const string AssemblyNameMembersDiagId = "SYSLIB0037"; internal const string SystemDataSerializationFormatBinaryMessage = "SerializationFormat.Binary is obsolete and should not be used. See https://aka.ms/serializationformat-binary-obsolete for more information."; internal const string SystemDataSerializationFormatBinaryDiagId = "SYSLIB0038"; internal const string TlsVersion10and11Message = "TLS versions 1.0 and 1.1 have known vulnerabilities and are not recommended. Use a newer TLS version instead, or use SslProtocols.None to defer to OS defaults."; internal const string TlsVersion10and11DiagId = "SYSLIB0039"; internal const string EncryptionPolicyMessage = "EncryptionPolicy.NoEncryption and AllowEncryption significantly reduce security and should not be used in production code."; internal const string EncryptionPolicyDiagId = "SYSLIB0040"; internal const string Rfc2898OutdatedCtorMessage = "The default hash algorithm and iteration counts in Rfc2898DeriveBytes constructors are outdated and insecure. Use a constructor that accepts the hash algorithm and the number of iterations."; internal const string Rfc2898OutdatedCtorDiagId = "SYSLIB0041"; internal const string EccXmlExportImportMessage = "ToXmlString and FromXmlString have no implementation for ECC types, and are obsolete. Use a standard import and export format such as ExportSubjectPublicKeyInfo or ImportSubjectPublicKeyInfo for public keys and ExportPkcs8PrivateKey or ImportPkcs8PrivateKey for private keys."; internal const string EccXmlExportImportDiagId = "SYSLIB0042"; internal const string EcDhPublicKeyBlobMessage = "ECDiffieHellmanPublicKey.ToByteArray() and the associated constructor do not have a consistent and interoperable implementation on all platforms. Use ECDiffieHellmanPublicKey.ExportSubjectPublicKeyInfo() instead."; internal const string EcDhPublicKeyBlobDiagId = "SYSLIB0043"; internal const string AssemblyNameCodeBaseMessage = "AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported."; internal const string AssemblyNameCodeBaseDiagId = "SYSLIB0044"; internal const string CryptoStringFactoryMessage = "Cryptographic factory methods accepting an algorithm name are obsolete. Use the parameterless Create factory method on the algorithm type instead."; internal const string CryptoStringFactoryDiagId = "SYSLIB0045"; internal const string ControlledExecutionRunMessage = "ControlledExecution.Run method may corrupt the process and should not be used in production code."; internal const string ControlledExecutionRunDiagId = "SYSLIB0046"; internal const string XmlSecureResolverMessage = "XmlSecureResolver is obsolete. Use XmlResolver.ThrowingResolver instead when attempting to forbid XML external entity resolution."; internal const string XmlSecureResolverDiagId = "SYSLIB0047"; internal const string RsaEncryptDecryptValueMessage = "RSA.EncryptValue and DecryptValue are not supported and throw NotSupportedException. Use RSA.Encrypt and RSA.Decrypt instead."; internal const string RsaEncryptDecryptDiagId = "SYSLIB0048"; internal const string JsonSerializerOptionsAddContextMessage = "JsonSerializerOptions.AddContext is obsolete. To register a JsonSerializerContext, use either the TypeInfoResolver or TypeInfoResolverChain properties."; internal const string JsonSerializerOptionsAddContextDiagId = "SYSLIB0049"; internal const string LegacyFormatterMessage = "Formatter-based serialization is obsolete and should not be used."; internal const string LegacyFormatterDiagId = "SYSLIB0050"; internal const string LegacyFormatterImplMessage = "This API supports obsolete formatter-based serialization. It should not be called or extended by application code."; internal const string LegacyFormatterImplDiagId = "SYSLIB0051"; internal const string RegexExtensibilityImplMessage = "This API supports obsolete mechanisms for Regex extensibility. It is not supported."; internal const string RegexExtensibilityDiagId = "SYSLIB0052"; internal const string AesGcmTagConstructorMessage = "AesGcm should indicate the required tag size for encryption and decryption. Use a constructor that accepts the tag size."; internal const string AesGcmTagConstructorDiagId = "SYSLIB0053"; } } namespace System.Runtime.InteropServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] internal sealed class LibraryImportAttribute : Attribute { public string LibraryName { get; } public string EntryPoint { get; set; } public StringMarshalling StringMarshalling { get; set; } public Type StringMarshallingCustomType { get; set; } public bool SetLastError { get; set; } public LibraryImportAttribute(string libraryName) { LibraryName = libraryName; } } internal enum StringMarshalling { Custom, Utf8, Utf16 } } namespace System.Speech { internal static class SR { private static ResourceManager s_resourceManager = new ResourceManager("ExceptionStringTable", typeof(SR).Assembly); internal static string Get(SRID id, params object[] args) { string text = s_resourceManager.GetString(id.ToString()); if (string.IsNullOrEmpty(text)) { text = s_resourceManager.GetString("Unavailable"); } else if (args != null && args.Length != 0) { text = string.Format(text, args); } return text; } } internal enum SRID { NullParamIllegal, ArrayOfNullIllegal, ParamsEntryNullIllegal, Unavailable, UnexpectedError, CollectionReadOnly, StringCanNotBeEmpty, EnumInvalid, NotSupportedWithThisVersionOfSAPI, NotSupportedWithThisVersionOfSAPI2, NotSupportedWithThisVersionOfSAPIBaseUri, NotSupportedWithThisVersionOfSAPITagFormat, NotSupportedWithThisVersionOfSAPICompareOption, MustBeGreaterThanZero, InvalidXml, OperationAborted, InvariantCultureInfo, DuplicatedEntry, StreamMustBeReadable, StreamMustBeWriteable, StreamMustBeSeekable, StreamEndedUnexpectedly, CannotReadFromDirectory, UnknownMimeFormat, CannotLoadResourceFromManifest, TokenInUse, TokenDeleted, TokenUninitialized, InvalidTokenId, NotFound, NoBackSlash, InvalidRegistryEntry, TokenCannotCreateInstance, InvalidXmlFormat, IncorrectAttributeValue, MissingRequiredAttribute, InvalidRuleRefSelf, InvalidDynamicExport, InvalidToken, MetaNameHTTPEquiv, EmptyRule, InvalidTokenString, InvalidQuotedString, ExportDynamicRule, EmptyDisplayString, EmptyPronunciationString, InvalidPhoneme, MuliplePronunciationString, MultipleDisplayString, RuleRedefinition, EmptyOneOf, InvalidGrammarOrdering, MinMaxOutOfRange, InvalidExampleOrdering, GrammarDefTwice, UnsupportedFormat, InvalidImport, DuplicatedRuleName, RootRuleAlreadyDefined, RuleNameIdConflict, RuleNotDynamic, StateWithNoArcs, NoTerminatingRulePath, RuleRefNoUri, UnavailableProperty, MinGreaterThanMax, ReqConfidenceNotSupported, SapiPropertiesAndSemantics, InvalidAttributeDefinedTwice, GrammarCompilerError, RuleScriptNotFound, DynamicRuleNotFound, RuleScriptInvalidParameters, RuleScriptInvalidReturnType, NoClassname, EmbeddedClassLibraryFailed, CannotFindClass, StrongTypedGrammarNotAGrammar, NoScriptsForRules, ClassNotPublic, MethodNotPublic, IncompatibleLanguageProperties, IncompatibleNamespaceProperties, IncompatibleDebugProperties, CannotLoadDotNetSemanticCode, InvalidSemanticProcessingType, InvalidScriptDefinition, InvalidMethodName, ConstructorNotAllowed, OverloadNotAllowed, OnInitOnPublicRule, ArgumentMismatch, CantGetPropertyFromSerializedInfo, CantFindAConstructor, TooManyArcs, TooManyRulesWithSemanticsGlobals, MaxTransitionsCount, UnknownElement, CircularRuleRef, InvalidFlagsSet, RuleDefinedMultipleTimes, RuleDefinedMultipleTimes2, RuleNotDefined, RootNotDefined, InvalidLanguage, InvalidRuleId, InvalidRepeatProbability, InvalidConfidence, InvalidMinRepeat, InvalidMaxRepeat, InvalidWeight, InvalidName, InvalidValueType, TagFormatNotSet, NoName, NoName1, InvalidSpecialRuleRef, InvalidRuleRef, InvalidNotEmptyElement, InvalidEmptyElement, InvalidEmptyRule, UndefRuleRef, UnsupportedLanguage, UnsupportedPhoneticAlphabet, UnsupportedLexicon, InvalidScriptAttribute, NoLanguageSet, MethodAttributeDefinedMultipleTimes, RuleAttributeDefinedMultipleTimes, InvalidAssemblyReferenceAttribute, InvalidImportNamespaceAttribute, NoUriForSpecialRuleRef, NoAliasForSpecialRuleRef, NoSmlData, InvalidNameValueProperty, InvalidTagInAnEmptyItem, InvalidSrgs, InvalidSrgsNamespace, Line, Position, InvalidVersion, InvalidTagFormat, MissingTagFormat, InvalidGrammarMode, InvalidGrammarAttribute, InvalidRuleAttribute, InvalidRulerefAttribute, InvalidOneOfAttribute, InvalidItemAttribute, InvalidTokenAttribute, InvalidItemRepeatAttribute, InvalidReqConfAttribute, InvalidTagAttribute, InvalidLexiconAttribute, InvalidMetaAttribute, InvalidItemAttribute2, InvalidElement, InvalidRuleScope, InvalidDynamicSetting, InvalidSubsetAttribute, InvalidVoiceElementInPromptOutput, NoRuleId, PromptBuilderInvalideState, PromptBuilderStateEnded, PromptBuilderStateSentence, PromptBuilderStateParagraph, PromptBuilderStateVoice, PromptBuilderStateStyle, PromptBuilderAgeOutOfRange, PromptBuilderMismatchStyle, PromptBuilderMismatchVoice, PromptBuilderMismatchParagraph, PromptBuilderMismatchSentence, PromptBuilderNestedParagraph, PromptBuilderNestedSentence, PromptBuilderInvalidAttribute, PromptBuilderInvalidElement, PromptBuilderInvalidVariant, PromptBuilderDatabaseName, PromptAsyncOperationCancelled, SynthesizerPauseResumeMismatched, SynthesizerInvalidMediaType, SynthesizerUnknownMediaType, SynthesizerSpeakError, SynthesizerInvalidWaveFile, SynthesizerPromptInUse, SynthesizerUnknownPriority, SynthesizerUnknownEvent, SynthesizerVoiceFailed, SynthesizerSetVoiceNoMatch, SynthesizerNoCulture, SynthesizerSyncSpeakWhilePaused, SynthesizerSyncSetOutputWhilePaused, SynthesizerNoCulture2, SynthesizerNoSpeak, SynthesizerSetOutputSpeaking, InvalidSpeakAttribute, UnsupportedAlphabet, GrammarInvalidWeight, GrammarInvalidPriority, DictationInvalidTopic, DictationTopicNotFound, RecognizerGrammarNotFound, RecognizerRuleNotFound, RecognizerInvalidBinaryGrammar, RecognizerRuleNotFoundStream, RecognizerNoRootRuleToActivate, RecognizerNoRootRuleToActivate1, RecognizerRuleActivationFailed, RecognizerAlreadyRecognizing, RecognizerHasNoGrammar, NegativeTimesNotSupported, AudioDeviceFormatError, AudioDeviceError, AudioDeviceInternalError, RecognizerNotFound, RecognizerNotEnabled, RecognitionNotSupported, RecognitionNotSupportedOn64bit, GrammarAlreadyLoaded, RecognizerNoInputSource, GrammarNotLoaded, GrammarLoadingInProgress, GrammarLoadFailed, GrammarWrongRecognizer, NotSupportedOnDictationGrammars, LocalFilesOnly, NotValidAudioFile, NotValidAudioStream, FileNotFound, CannotSetPriorityOnDictation, RecognizerUpdateTableTooLarge, MaxAlternatesInvalid, RecognizerSettingGetError, RecognizerSettingUpdateError, RecognizerSettingNotSupported, ResourceUsageOutOfRange, RateOutOfRange, EndSilenceOutOfRange, RejectionThresholdOutOfRange, ReferencedGrammarNotFound, SapiErrorRuleNotFound2, NoAudioAvailable, ResultNotGrammarAvailable, ResultInvalidFormat, UnhandledVariant, DupSemanticKey, DupSemanticValue, CannotUseCustomFormat, NoPromptEngine, NoPromptEngineInterface, SeekNotSupported, ExtraDataNotPresent, BitsPerSampleInvalid, DataBlockSizeInvalid, NotWholeNumberBlocks, BlockSignatureInvalid, NumberOfSamplesInvalid, SapiErrorUninitialized, SapiErrorAlreadyInitialized, SapiErrorNotSupportedFormat, SapiErrorInvalidFlags, SapiErrorEndOfStream, SapiErrorDeviceBusy, SapiErrorDeviceNotSupported, SapiErrorDeviceNotEnabled, SapiErrorNoDriver, SapiErrorFileMustBeUnicode, InsufficientData, SapiErrorInvalidPhraseID, SapiErrorBufferTooSmall, SapiErrorFormatNotSpecified, SapiErrorAudioStopped0, AudioPaused, SapiErrorRuleNotFound, SapiErrorTTSEngineException, SapiErrorTTSNLPException, SapiErrorEngineBUSY, AudioConversionEnabled, NoHypothesisAvailable, SapiErrorCantCreate, AlreadyInLex, SapiErrorNotInLex, LexNothingToSync, SapiErrorLexVeryOutOfSync, SapiErrorUndefinedForwardRuleRef, SapiErrorEmptyRule, SapiErrorGrammarCompilerInternalError, SapiErrorRuleNotDynamic, SapiErrorDuplicateRuleName, SapiErrorDuplicateResourceName, SapiErrorTooManyGrammars, SapiErrorCircularReference, SapiErrorInvalidImport, SapiErrorInvalidWAVFile, RequestPending, SapiErrorAllWordsOptional, SapiErrorInstanceChangeInvalid, SapiErrorRuleNameIdConflict, SapiErrorNoRules, SapiErrorCircularRuleRef, NoParseFound, SapiErrorInvalidHandle, SapiErrorRemoteCallTimedout, SapiErrorAudioBufferOverflow, SapiErrorNoAudioData, SapiErrorDeadAlternate, SapiErrorHighLowConfidence, SapiErrorInvalidFormatString, SPNotSupportedOnStreamInput, SapiErrorAppLexReadOnly, SapiErrorNoTerminatingRulePath, WordExistsWithoutPronunciation, SapiErrorStreamClosed, SapiErrorNoMoreItems, SapiErrorNotFound, SapiErrorInvalidAudioState, SapiErrorGenericMMSYS, SapiErrorMarshalerException, SapiErrorNotDynamicGrammar, SapiErrorAmbiguousProperty, SapiErrorInvalidRegistrykey, SapiErrorInvalidTokenId, SapiErrorXMLBadSyntax, SapiErrorXMLResourceNotFound, SapiErrorTokenInUse, SapiErrorTokenDeleted, SapiErrorMultilingualNotSupported, SapiErrorExportDynamicRule, SapiErrorSTGF, SapiErrorWordFormat, SapiErrorStreamNotActive, SapiErrorEngineResponseInvalid, SapiErrorSREngineException, SapiErrorStreamPosInvalid, SapiErrorRecognizerInactive, SapiErrorRemoteCallOnWrongThread, SapiErrorRemoteProcessTerminated, SapiErrorRemoteProcessAlreadyRunning, SapiErrorLangIdMismatch, SapiErrorPartialParseFound, SapiErrorNotTopLevelRule, SapiErrorNoRuleActive, SapiErrorLexRequiresCookie, SapiErrorStreamUninitialized, SapiErrorUnused0, SapiErrorNotSupportedLang, SapiErrorVoicePaused, SapiErrorAudioBufferUnderflow, SapiErrorAudioStoppedUnexpectedly, SapiErrorNoWordPronunciation, SapiErrorAlternatesWouldBeInconsistent, SapiErrorNotSupportedForSharedRecognizer, SapiErrorTimeOut, SapiErrorReenterSynchronize, SapiErrorStateWithNoArcs, SapiErrorNotActiveSession, SapiErrorAlreadyDeleted, SapiErrorAudioStopped, SapiErrorRecoXMLGenerationFail, SapiErrorSMLGenerationFail, SapiErrorNotPromptVoice, SapiErrorRootRuleAlreadyDefined, SapiErrorUnused1, SapiErrorUnused2, SapiErrorUnused3, SapiErrorUnused4, SapiErrorUnused5, SapiErrorUnused6, SapiErrorScriptDisallowed, SapiErrorRemoteCallTimedOutStart, SapiErrorRemoteCallTimedOutConnect, SapiErrorSecMgrChangeNotAllowed, SapiErrorCompleteButExtendable, SapiErrorFailedToDeleteFile, SapiErrorSharedEngineDisabled, SapiErrorRecognizerNotFound, SapiErrorAudioNotFound, SapiErrorNoVowel, SapiErrorNotSupportedPhoneme, SapiErrorNoRulesToActivate, SapiErrorNoWordEntryNotification, SapiErrorWordNeedsNormalization, SapiErrorCannotNormalize, LimitReached, NotSupported, SapiErrorTopicNotAdaptable, SapiErrorPhonemeConversion, SapiErrorNotSupportedForInprocRecognizer, SapiErrorOverload, SapiLexInvalidData, SapiConfigInvalidData, SapiLexUnexpectedFormat, SapiStringTooLong, SapiStringEmpty, SapiErrorUnused7, SapiErrorUnused8, SapiErrorUnused9, SapiErrorUnused10, SapiErrorUnused11, SapiErrorUnused12, SapiNonWordTransition, SapiSisrAttributesNotAllowed, SapiSisrMixedNotAllowed, SapiVoiceNotFound } } namespace System.Speech.Synthesis { public class BookmarkReachedEventArgs : PromptEventArgs { private string _bookmark; private TimeSpan _audioPosition; public string Bookmark => _bookmark; public TimeSpan AudioPosition => _audioPosition; internal BookmarkReachedEventArgs(Prompt prompt, string bookmark, TimeSpan audioPosition) : base(prompt) { _bookmark = bookmark; _audioPosition = audioPosition; } } [DebuggerDisplay("{_text}")] public class FilePrompt : Prompt { public FilePrompt(string path, SynthesisMediaType media) : this(new Uri(path, UriKind.Relative), media) { } public FilePrompt(Uri promptFile, SynthesisMediaType media) : base(promptFile, media) { } } [DebuggerDisplay("{VoiceInfo.Name} = [{Enabled ? \"Enabled\" : \"Disabled\"}]")] public class InstalledVoice { private VoiceInfo _voice; private bool _enabled; private VoiceSynthesis _voiceSynthesizer; public VoiceInfo VoiceInfo => _voice; public bool Enabled { get { return _enabled; } set { SetEnabledFlag(value, switchContext: true); } } internal InstalledVoice(VoiceSynthesis voiceSynthesizer, VoiceInfo voice) { _voiceSynthesizer = voiceSynthesizer; _voice = voice; _enabled = true; } public override bool Equals(object obj) { if (!(obj is InstalledVoice installedVoice)) { return false; } if (VoiceInfo.Name == installedVoice.VoiceInfo.Name && VoiceInfo.Age == installedVoice.VoiceInfo.Age && VoiceInfo.Gender == installedVoice.VoiceInfo.Gender) { return VoiceInfo.Culture.Equals(installedVoice.VoiceInfo.Culture); } return false; } public override int GetHashCode() { return VoiceInfo.Name.GetHashCode(); } internal static InstalledVoice Find(List<InstalledVoice> list, VoiceInfo voiceId) { foreach (InstalledVoice item in list) { if (item.Enabled && item.VoiceInfo.Equals(voiceId)) { return item; } } return null; } internal static InstalledVoice FirstEnabled(List<InstalledVoice> list, CultureInfo culture) { InstalledVoice installedVoice = null; foreach (InstalledVoice item in list) { if (item.Enabled) { if (Helpers.CompareInvariantCulture(item.VoiceInfo.Culture, culture)) { return item; } if (installedVoice == null) { installedVoice = item; } } } return installedVoice; } internal void SetEnabledFlag(bool value, bool switchContext) { try { if (_enabled == value) { return; } _enabled = value; if (!_enabled) { if (_voice.Equals(_voiceSynthesizer.CurrentVoice(switchContext).VoiceInfo)) { _voiceSynthesizer.Voice = null; } } else { _voiceSynthesizer.Voice = null; } } catch (InvalidOperationException) { _voiceSynthesizer.Voice = null; } } } public class PhonemeReachedEventArgs : PromptEventArgs { private string _currentPhoneme; private TimeSpan _audioPosition; private TimeSpan _duration; private SynthesizerEmphasis _emphasis; private string _nextPhoneme; public string Phoneme => _currentPhoneme; public TimeSpan AudioPosition => _audioPosition; public TimeSpan Duration => _duration; public SynthesizerEmphasis Emphasis => _emphasis; public string NextPhoneme => _nextPhoneme; internal PhonemeReachedEventArgs(Prompt prompt, string currentPhoneme, TimeSpan audioPosition, TimeSpan duration, SynthesizerEmphasis emphasis, string nextPhoneme) : base(prompt) { _currentPhoneme = currentPhoneme; _audioPosition = audioPosition; _duration = duration; _emphasis = emphasis; _nextPhoneme = nextPhoneme; } } [DebuggerDisplay("{_text}")] public class Prompt { internal string _text; internal Uri _audio; internal SynthesisMediaType _media; internal bool _syncSpeak; private bool _completed; private object _synthesizer; private static ResourceLoader s_resourceLoader = new ResourceLoader(); public bool IsCompleted { get { return _completed; } internal set { _completed = value; } } internal object Synthesizer { set { if (value != null && (_synthesizer != null || _completed)) { throw new ArgumentException(SR.Get(SRID.SynthesizerPromptInUse), "value"); } _synthesizer = value; } } internal Exception Exception { get; set; } public Prompt(string textToSpeak) : this(textToSpeak, SynthesisTextFormat.Text) { } public Prompt(PromptBuilder promptBuilder) { Helpers.ThrowIfNull(promptBuilder, "promptBuilder"); _text = promptBuilder.ToXml(); _media = SynthesisMediaType.Ssml; } public Prompt(string textToSpeak, SynthesisTextFormat media) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); if ((uint)(_media = (SynthesisMediaType)media) <= 1u) { _text = textToSpeak; return; } throw new ArgumentException(SR.Get(SRID.SynthesizerUnknownMediaType), "media"); } internal Prompt(Uri promptFile, SynthesisMediaType media) { Helpers.ThrowIfNull(promptFile, "promptFile"); switch (_media = media) { case SynthesisMediaType.Text: case SynthesisMediaType.Ssml: { string mimeType; Uri baseUri; string localPath; using Stream stream = s_resourceLoader.LoadFile(promptFile, out mimeType, out baseUri, out localPath); try { using StreamReader streamReader = new StreamReader(stream); _text = streamReader.ReadToEnd(); break; } finally { s_resourceLoader.UnloadFile(localPath); } } case SynthesisMediaType.WaveAudio: _text = promptFile.ToString(); _audio = promptFile; break; default: throw new ArgumentException(SR.Get(SRID.SynthesizerUnknownMediaType), "media"); } } } public enum SynthesisMediaType { Text, Ssml, WaveAudio } public enum SynthesisTextFormat { Text, Ssml } [Serializable] public class PromptBuilder { internal enum SsmlState { Header = 1, Paragraph = 2, Sentence = 4, StyleEmphasis = 8, StyleProsody = 0x10, Voice = 0x20, Ended = 0x40 } [Serializable] private struct StackElement { internal SsmlElement _possibleChildren; internal SsmlState _state; internal CultureInfo _culture; internal StackElement(SsmlElement possibleChildren, SsmlState state, CultureInfo culture) { _possibleChildren = possibleChildren; _state = state; _culture = culture; } } private enum ElementType { Prosody, Emphasis, SayAs, Phoneme, Sub, Break, Audio, Bookmark, StartVoice, StartParagraph, StartSentence, EndSentence, EndParagraph, StartStyle, EndStyle, EndVoice, Text, SsmlMarkup } [Serializable] private struct AttributeItem { internal string _key; internal string _value; internal string _namespace; internal AttributeItem(string key, string value) { _key = key; _value = value; _namespace = null; } internal AttributeItem(string ns, string key, string value) : this(key, value) { _namespace = ns; } } [Serializable] private sealed class Element { internal ElementType _type; internal string _text; internal Collection<AttributeItem> _attributes; internal Element(ElementType type) { _type = type; } internal Element(ElementType type, string text) : this(type) { _text = text; } } private Stack<StackElement> _elementStack = new Stack<StackElement>(); private CultureInfo _culture; private List<Element> _elements = new List<Element>(); private static ResourceLoader s_resourceLoader = new ResourceLoader(); private const string _xmlnsDefault = "http://www.w3.org/2001/10/synthesis"; private static readonly string[] s_promptBuilderElementName = new string[11] { "prosody", "emphasis", "say-as", "phoneme", "sub", "break", "audio", "mark", "voice", "p", "s" }; public bool IsEmpty => _elements.Count == 0; public CultureInfo Culture { get { return _culture; } set { if (value == null) { throw new ArgumentNullException("value"); } _culture = value; } } public PromptBuilder() : this(CultureInfo.CurrentUICulture) { } public PromptBuilder(CultureInfo culture) { Helpers.ThrowIfNull(culture, "culture"); if (culture.Equals(CultureInfo.InvariantCulture)) { throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture"); } _culture = culture; ClearContent(); } public void ClearContent() { _elements.Clear(); _elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle | SsmlElement.ParagraphOrSentence | SsmlElement.Lexicon | SsmlElement.Meta | SsmlElement.MetaData, SsmlState.Header, _culture)); } public void AppendText(string textToSpeak) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); ValidateElement(_elementStack.Peek(), SsmlElement.Text); _elements.Add(new Element(ElementType.Text, textToSpeak)); } public void AppendText(string textToSpeak, PromptRate rate) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); if (rate < PromptRate.NotSet || rate > PromptRate.ExtraSlow) { throw new ArgumentOutOfRangeException("rate"); } ValidateElement(_elementStack.Peek(), SsmlElement.Text); Element element = new Element(ElementType.Prosody, textToSpeak); _elements.Add(element); string value = null; switch (rate) { case PromptRate.ExtraFast: value = "x-fast"; break; case PromptRate.ExtraSlow: value = "x-slow"; break; default: value = rate.ToString().ToLowerInvariant(); break; case PromptRate.NotSet: break; } if (!string.IsNullOrEmpty(value)) { element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("rate", value)); } } public void AppendText(string textToSpeak, PromptVolume volume) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); if (volume < PromptVolume.NotSet || volume > PromptVolume.Default) { throw new ArgumentOutOfRangeException("volume"); } ValidateElement(_elementStack.Peek(), SsmlElement.Text); Element element = new Element(ElementType.Prosody, textToSpeak); _elements.Add(element); string value = null; switch (volume) { case PromptVolume.ExtraSoft: value = "x-soft"; break; case PromptVolume.ExtraLoud: value = "x-loud"; break; default: value = volume.ToString().ToLowerInvariant(); break; case PromptVolume.NotSet: break; } if (!string.IsNullOrEmpty(value)) { element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("volume", value)); } } public void AppendText(string textToSpeak, PromptEmphasis emphasis) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); if (emphasis < PromptEmphasis.NotSet || emphasis > PromptEmphasis.Reduced) { throw new ArgumentOutOfRangeException("emphasis"); } ValidateElement(_elementStack.Peek(), SsmlElement.Text); Element element = new Element(ElementType.Emphasis, textToSpeak); _elements.Add(element); if (emphasis != 0) { element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("level", emphasis.ToString().ToLowerInvariant())); } } public void StartStyle(PromptStyle style) { Helpers.ThrowIfNull(style, "style"); StackElement stackElement = _elementStack.Peek(); ValidateElement(stackElement, SsmlElement.Prosody); SsmlState ssmlState = (SsmlState)0; SsmlElement possibleChildren = stackElement._possibleChildren; _elements.Add(new Element(ElementType.StartStyle)); if (style.Emphasis != 0) { Element element = new Element(ElementType.Emphasis); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("level", style.Emphasis.ToString().ToLowerInvariant())); possibleChildren = SsmlElement.AudioMarkTextWithStyle; ssmlState = SsmlState.StyleEmphasis; } if (style.Rate != 0 || style.Volume != 0) { if (ssmlState != 0) { _elements.Add(new Element(ElementType.StartStyle)); } Element element2 = new Element(ElementType.Prosody); _elements.Add(element2); if (style.Rate != 0) { string value = style.Rate switch { PromptRate.ExtraFast => "x-fast", PromptRate.ExtraSlow => "x-slow", _ => style.Rate.ToString().ToLowerInvariant(), }; element2._attributes = new Collection<AttributeItem>(); element2._attributes.Add(new AttributeItem("rate", value)); } if (style.Volume != 0) { string value2 = style.Volume switch { PromptVolume.ExtraSoft => "x-soft", PromptVolume.ExtraLoud => "x-loud", _ => style.Volume.ToString().ToLowerInvariant(), }; Element element3 = element2; if (element3._attributes == null) { element3._attributes = new Collection<AttributeItem>(); } element2._attributes.Add(new AttributeItem("volume", value2)); } possibleChildren = SsmlElement.AudioMarkTextWithStyle | SsmlElement.ParagraphOrSentence; ssmlState |= SsmlState.StyleProsody; } _elementStack.Push(new StackElement(possibleChildren, ssmlState, stackElement._culture)); } public void EndStyle() { StackElement stackElement = _elementStack.Pop(); if (stackElement._state != 0) { if ((stackElement._state & (SsmlState)24) == 0) { throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchStyle)); } _elements.Add(new Element(ElementType.EndStyle)); if (stackElement._state == (SsmlState)24) { _elements.Add(new Element(ElementType.EndStyle)); } } } public void StartVoice(VoiceInfo voice) { Helpers.ThrowIfNull(voice, "voice"); if (!VoiceInfo.ValidateGender(voice.Gender)) { throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceGender"), "voice"); } if (!VoiceInfo.ValidateAge(voice.Age)) { throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceAge"), "voice"); } StackElement stackElement = _elementStack.Peek(); ValidateElement(stackElement, SsmlElement.Voice); CultureInfo culture = voice.Culture ?? stackElement._culture; Element element = new Element(ElementType.StartVoice); element._attributes = new Collection<AttributeItem>(); _elements.Add(element); if (!string.IsNullOrEmpty(voice.Name)) { element._attributes.Add(new AttributeItem("name", voice.Name)); } if (voice.Culture != null) { element._attributes.Add(new AttributeItem("xml", "lang", voice.Culture.Name)); } if (voice.Gender != 0) { element._attributes.Add(new AttributeItem("gender", voice.Gender.ToString().ToLowerInvariant())); } if (voice.Age != 0) { element._attributes.Add(new AttributeItem("age", ((int)voice.Age).ToString(CultureInfo.InvariantCulture))); } if (voice.Variant >= 0) { element._attributes.Add(new AttributeItem("variant", voice.Variant.ToString(CultureInfo.InvariantCulture))); } _elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle | SsmlElement.Sentence, SsmlState.Voice, culture)); } public void StartVoice(string name) { Helpers.ThrowIfEmptyOrNull(name, "name"); StartVoice(new VoiceInfo(name)); } public void StartVoice(VoiceGender gender) { StartVoice(new VoiceInfo(gender)); } public void StartVoice(VoiceGender gender, VoiceAge age) { StartVoice(new VoiceInfo(gender, age)); } public void StartVoice(VoiceGender gender, VoiceAge age, int voiceAlternate) { StartVoice(new VoiceInfo(gender, age, voiceAlternate)); } public void StartVoice(CultureInfo culture) { StartVoice(new VoiceInfo(culture)); } public void EndVoice() { if (_elementStack.Pop()._state != SsmlState.Voice) { throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchVoice)); } _elements.Add(new Element(ElementType.EndVoice)); } public void StartParagraph() { StartParagraph(null); } public void StartParagraph(CultureInfo culture) { StackElement stackElement = _elementStack.Peek(); ValidateElement(stackElement, SsmlElement.Paragraph); Element element = new Element(ElementType.StartParagraph); _elements.Add(element); if (culture != null) { if (culture.Equals(CultureInfo.InvariantCulture)) { throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture"); } element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("xml", "lang", culture.Name)); } else { culture = stackElement._culture; } _elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle | SsmlElement.Sentence, SsmlState.Paragraph, culture)); } public void EndParagraph() { if (_elementStack.Pop()._state != SsmlState.Paragraph) { throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchParagraph)); } _elements.Add(new Element(ElementType.EndParagraph)); } public void StartSentence() { StartSentence(null); } public void StartSentence(CultureInfo culture) { StackElement stackElement = _elementStack.Peek(); ValidateElement(stackElement, SsmlElement.Sentence); Element element = new Element(ElementType.StartSentence); _elements.Add(element); if (culture != null) { if (culture.Equals(CultureInfo.InvariantCulture)) { throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture"); } element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("xml", "lang", culture.Name)); } else { culture = stackElement._culture; } _elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle, SsmlState.Sentence, culture)); } public void EndSentence() { if (_elementStack.Pop()._state != SsmlState.Sentence) { throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchSentence)); } _elements.Add(new Element(ElementType.EndSentence)); } public void AppendTextWithHint(string textToSpeak, SayAs sayAs) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); if (sayAs < SayAs.SpellOut || sayAs > SayAs.Text) { throw new ArgumentOutOfRangeException("sayAs"); } ValidateElement(_elementStack.Peek(), SsmlElement.Text); if (sayAs != SayAs.Text) { Element element = new Element(ElementType.SayAs, textToSpeak); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); string value = null; string value2 = null; switch (sayAs) { case SayAs.SpellOut: value = "characters"; break; case SayAs.NumberOrdinal: value = "ordinal"; break; case SayAs.NumberCardinal: value = "cardinal"; break; case SayAs.Date: value = "date"; break; case SayAs.DayMonthYear: value = "date"; value2 = "dmy"; break; case SayAs.MonthDayYear: value = "date"; value2 = "mdy"; break; case SayAs.YearMonthDay: value = "date"; value2 = "ymd"; break; case SayAs.YearMonth: value = "date"; value2 = "ym"; break; case SayAs.MonthYear: value = "date"; value2 = "my"; break; case SayAs.MonthDay: value = "date"; value2 = "md"; break; case SayAs.DayMonth: value = "date"; value2 = "dm"; break; case SayAs.Year: value = "date"; value2 = "y"; break; case SayAs.Month: value = "date"; value2 = "m"; break; case SayAs.Day: value = "date"; value2 = "d"; break; case SayAs.Time: value = "time"; break; case SayAs.Time24: value = "time"; value2 = "hms24"; break; case SayAs.Time12: value = "time"; value2 = "hms12"; break; case SayAs.Telephone: value = "telephone"; break; } element._attributes.Add(new AttributeItem("interpret-as", value)); if (!string.IsNullOrEmpty(value2)) { element._attributes.Add(new AttributeItem("format", value2)); } } else { AppendText(textToSpeak); } } public void AppendTextWithHint(string textToSpeak, string sayAs) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); Helpers.ThrowIfEmptyOrNull(sayAs, "sayAs"); ValidateElement(_elementStack.Peek(), SsmlElement.Text); Element element = new Element(ElementType.SayAs, textToSpeak); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("interpret-as", sayAs)); } public void AppendTextWithPronunciation(string textToSpeak, string pronunciation) { Helpers.ThrowIfEmptyOrNull(textToSpeak, "textToSpeak"); Helpers.ThrowIfEmptyOrNull(pronunciation, "pronunciation"); ValidateElement(_elementStack.Peek(), SsmlElement.Text); PhonemeConverter.ValidateUpsIds(pronunciation); Element element = new Element(ElementType.Phoneme, textToSpeak); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("ph", pronunciation)); } public void AppendTextWithAlias(string textToSpeak, string substitute) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); Helpers.ThrowIfNull(substitute, "substitute"); ValidateElement(_elementStack.Peek(), SsmlElement.Text); Element element = new Element(ElementType.Sub, textToSpeak); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("alias", substitute)); } public void AppendBreak() { ValidateElement(_elementStack.Peek(), SsmlElement.Break); _elements.Add(new Element(ElementType.Break)); } public void AppendBreak(PromptBreak strength) { ValidateElement(_elementStack.Peek(), SsmlElement.Break); Element element = new Element(ElementType.Break); _elements.Add(element); string text = null; text = strength switch { PromptBreak.None => "none", PromptBreak.ExtraSmall => "x-weak", PromptBreak.Small => "weak", PromptBreak.Medium => "medium", PromptBreak.Large => "strong", PromptBreak.ExtraLarge => "x-strong", _ => throw new ArgumentNullException("strength"), }; element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("strength", text)); } public void AppendBreak(TimeSpan duration) { ValidateElement(_elementStack.Peek(), SsmlElement.Break); if (duration.Ticks < 0) { throw new ArgumentOutOfRangeException("duration"); } Element element = new Element(ElementType.Break); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("time", duration.TotalMilliseconds + "ms")); } public void AppendAudio(string path) { Helpers.ThrowIfEmptyOrNull(path, "path"); Uri audioFile; try { audioFile = new Uri(path, UriKind.RelativeOrAbsolute); } catch (UriFormatException ex) { throw new ArgumentException(ex.Message, path, ex); } ValidateElement(_elementStack.Peek(), SsmlElement.Audio); AppendAudio(audioFile); } public void AppendAudio(Uri audioFile) { Helpers.ThrowIfNull(audioFile, "audioFile"); ValidateElement(_elementStack.Peek(), SsmlElement.Audio); Element element = new Element(ElementType.Audio); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("src", audioFile.ToString())); } public void AppendAudio(Uri audioFile, string alternateText) { Helpers.ThrowIfNull(audioFile, "audioFile"); Helpers.ThrowIfNull(alternateText, "alternateText"); ValidateElement(_elementStack.Peek(), SsmlElement.Audio); Element element = new Element(ElementType.Audio, alternateText); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("src", audioFile.ToString())); } public void AppendBookmark(string bookmarkName) { Helpers.ThrowIfEmptyOrNull(bookmarkName, "bookmarkName"); ValidateElement(_elementStack.Peek(), SsmlElement.Mark); Element element = new Element(ElementType.Bookmark); _elements.Add(element); element._attributes = new Collection<AttributeItem>(); element._attributes.Add(new AttributeItem("name", bookmarkName)); } public void AppendPromptBuilder(PromptBuilder promptBuilder) { Helpers.ThrowIfNull(promptBuilder, "promptBuilder"); StringReader stringReader = new StringReader(promptBuilder.ToXml()); XmlTextReader xmlTextReader = new XmlTextReader(stringReader); AppendSsml(xmlTextReader); xmlTextReader.Close(); stringReader.Close(); } public void AppendSsml(string path) { Helpers.ThrowIfEmptyOrNull(path, "path"); AppendSsml(new Uri(path, UriKind.Relative)); } public void AppendSsml(Uri ssmlFile) { Helpers.ThrowIfNull(ssmlFile, "ssmlFile"); string localPath; Uri redirectedUri; using Stream input = s_resourceLoader.LoadFile(ssmlFile, out localPath, out redirectedUri); try { AppendSsml(new XmlTextReader(input)); } finally { s_resourceLoader.UnloadFile(localPath); } } public void AppendSsml(XmlReader ssmlFile) { Helpers.ThrowIfNull(ssmlFile, "ssmlFile"); AppendSsmlInternal(ssmlFile); } [EditorBrowsable(EditorBrowsableState.Never)] public void AppendSsmlMarkup(string ssmlMarkup) { Helpers.ThrowIfEmptyOrNull(ssmlMarkup, "ssmlMarkup"); _elements.Add(new Element(ElementType.SsmlMarkup, ssmlMarkup)); } public string ToXml() { using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); using XmlTextWriter writer = new XmlTextWriter(stringWriter); WriteXml(writer); SsmlState state = _elementStack.Peek()._state; if (state != SsmlState.Header) { string text = SR.Get(SRID.PromptBuilderInvalideState); switch (state) { case SsmlState.Ended: text += SR.Get(SRID.PromptBuilderStateEnded); break; case SsmlState.Sentence: text += SR.Get(SRID.PromptBuilderStateSentence); break; case SsmlState.Paragraph: text += SR.Get(SRID.PromptBuilderStateParagraph); break; case SsmlState.StyleEmphasis: case SsmlState.StyleProsody: case (SsmlState)24: text += SR.Get(SRID.PromptBuilderStateStyle); break; case SsmlState.Voice: text += SR.Get(SRID.PromptBuilderStateVoice); break; default: throw new NotSupportedException(); } throw new InvalidOperationException(text); } return stringWriter.ToString(); } private void WriteXml(XmlTextWriter writer) { writer.WriteStartElement("speak"); writer.WriteAttributeString("version", "1.0"); writer.WriteAttributeString("xmlns", "http://www.w3.org/2001/10/synthesis"); writer.WriteAttributeString("xml", "lang", null, _culture.Name); bool flag = false; foreach (Element element in _elements) { flag = flag || element._type == ElementType.StartSentence || element._type == ElementType.StartParagraph || element._type == ElementType.StartStyle || element._type == ElementType.StartVoice; switch (element._type) { case ElementType.Text: writer.WriteString(element._text); break; case ElementType.SsmlMarkup: writer.WriteRaw(element._text); break; case ElementType.Prosody: case ElementType.Emphasis: case ElementType.SayAs: case ElementType.Phoneme: case ElementType.Sub: case ElementType.Break: case ElementType.Audio: case ElementType.Bookmark: case ElementType.StartVoice: case ElementType.StartParagraph: case ElementType.StartSentence: writer.WriteStartElement(s_promptBuilderElementName[(int)element._type]); if (element._attributes != null) { foreach (AttributeItem attribute in element._attributes) { if (attribute._namespace == null) { writer.WriteAttributeString(attribute._key, attribute._value); } else { writer.WriteAttributeString(attribute._namespace, attribute._key, null, attribute._value); } } } if (element._text != null) { writer.WriteString(element._text); } if (!flag) { writer.WriteEndElement(); } flag = false; break; case ElementType.EndSentence: case ElementType.EndParagraph: case ElementType.EndStyle: case ElementType.EndVoice: writer.WriteEndElement(); break; default: throw new NotSupportedException(); case ElementType.StartStyle: break; } } writer.WriteEndElement(); } private static void ValidateElement(StackElement stackElement, SsmlElement currentElement) { if ((stackElement._possibleChildren & currentElement) == 0) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, SR.Get(SRID.PromptBuilderInvalidElement), currentElement.ToString(), stackElement._state.ToString())); } } private void AppendSsmlInternal(XmlReader ssmlFile) { StackElement stackElement = _elementStack.Peek(); ValidateElement(_elementStack.Peek(), SsmlElement.Voice); using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); using (XmlTextWriter writer = new XmlTextWriter(stringWriter)) { TextWriterEngine engine = new TextWriterEngine(writer, stackElement._culture); SsmlParser.Parse(ssmlFile, engine, null); } _elements.Add(new Element(ElementType.SsmlMarkup, stringWriter.ToString())); } } public abstract class PromptEventArgs : AsyncCompletedEventArgs { private Prompt _prompt; public Prompt Prompt => _prompt; internal PromptEventArgs(Prompt prompt) : base(prompt.Exception, prompt.Exception != null, prompt) { _prompt = prompt; } } public class SpeakStartedEventArgs : PromptEventArgs { internal SpeakStartedEventArgs(Prompt prompt) : base(prompt) { } } [Serializable] public class PromptStyle { private PromptRate _rate; private PromptVolume _volume; private PromptEmphasis _emphasis; public PromptRate Rate { get { return _rate; } set { _rate = value; } } public PromptVolume Volume { get { return _volume; } set { _volume = value; } } public PromptEmphasis Emphasis { get { return _emphasis; } set { _emphasis = value; } } public PromptStyle() { } public PromptStyle(PromptRate rate) { Rate = rate; } public PromptStyle(PromptVolume volume) { Volume = volume; } public PromptStyle(PromptEmphasis emphasis) { Emphasis = emphasis; } } public enum SayAs { SpellOut, NumberOrdinal, NumberCardinal, Date, DayMonthYear, MonthDayYear, YearMonthDay, YearMonth, MonthYear, MonthDay, DayMonth, Year, Month, Day, Time, Time24, Time12, Telephone, Text } public enum VoiceGender { NotSet, Male, Female, Neutral } public enum VoiceAge { NotSet = 0, Child = 10, Teen = 15, Adult = 30, Senior = 65 } public enum PromptRate { NotSet, ExtraFast, Fast, Medium, Slow, ExtraSlow } public enum PromptVolume { NotSet, Silent, ExtraSoft, Soft, Medium, Loud, ExtraLoud, Default } public enum PromptEmphasis { NotSet, Strong, Moderate, None, Reduced } public enum PromptBreak { None, ExtraSmall, Small, Medium, Large, ExtraLarge } public class SpeakCompletedEventArgs : PromptEventArgs { internal SpeakCompletedEventArgs(Prompt prompt) : base(prompt) { } } public class SpeakProgressEventArgs : PromptEventArgs { private TimeSpan _audioPosition; private int _iWordPos; private int _cWordLen; private string _word; public TimeSpan AudioPosition => _audioPosition; public int CharacterPosition => _iWordPos; public int CharacterCount { get { return _cWordLen; } internal set { _cWordLen = value; } } public string Text { get { return _word; } internal set { _word = value; } } internal SpeakProgressEventArgs(Prompt prompt, TimeSpan audioPosition, int iWordPos, int cWordLen) : base(prompt) { _audioPosition = audioPosition; _iWordPos = iWordPos; _cWordLen = cWordLen; } } public sealed class SpeechSynthesizer : IDisposable { private VoiceSynthesis _voiceSynthesis; private bool _isDisposed; private bool _paused; private Stream _outputStream; private bool _closeStreamOnExit; public SynthesizerState State => VoiceSynthesizer.State; public int Rate { get { return VoiceSynthesizer.Rate; } set { if (value < -10 || value > 10) { throw new ArgumentOutOfRangeException("value", SR.Get(SRID.RateOutOfRange)); } VoiceSynthesizer.Rate = value; } } public int Volume { get { return VoiceSynthesizer.Volume; } set { if (value < 0 || value > 100) { throw new ArgumentOutOfRangeException("value", SR.Get(SRID.ResourceUsageOutOfRange)); } VoiceSynthesizer.Volume = value; } } public VoiceInfo Voice => VoiceSynthesizer.CurrentVoice(switchContext: true).VoiceInfo; private VoiceSynthesis VoiceSynthesizer { get { if (_voiceSynthesis == null && _isDisposed) { throw new ObjectDisposedException("SpeechSynthesizer"); } if (_voiceSynthesis == null) { WeakReference speechSynthesizer = new WeakReference(this); _voiceSynthesis = new VoiceSynthesis(speechSynthesizer); } return _voiceSynthesis; } } public event EventHandler<SpeakStartedEventArgs> SpeakStarted { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesis voiceSynthesizer = VoiceSynthesizer; voiceSynthesizer._speakStarted = (EventHandler<SpeakStartedEventArgs>)Delegate.Combine(voiceSynthesizer._speakStarted, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesis voiceSynthesizer = VoiceSynthesizer; voiceSynthesizer._speakStarted = (EventHandler<SpeakStartedEventArgs>)Delegate.Remove(voiceSynthesizer._speakStarted, value); } } public event EventHandler<SpeakCompletedEventArgs> SpeakCompleted { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesis voiceSynthesizer = VoiceSynthesizer; voiceSynthesizer._speakCompleted = (EventHandler<SpeakCompletedEventArgs>)Delegate.Combine(voiceSynthesizer._speakCompleted, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesis voiceSynthesizer = VoiceSynthesizer; voiceSynthesizer._speakCompleted = (EventHandler<SpeakCompletedEventArgs>)Delegate.Remove(voiceSynthesizer._speakCompleted, value); } } public event EventHandler<SpeakProgressEventArgs> SpeakProgress { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.AddEvent(TtsEventId.WordBoundary, ref VoiceSynthesizer._speakProgress, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.RemoveEvent(TtsEventId.WordBoundary, ref VoiceSynthesizer._speakProgress, value); } } public event EventHandler<BookmarkReachedEventArgs> BookmarkReached { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.AddEvent(TtsEventId.Bookmark, ref VoiceSynthesizer._bookmarkReached, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.RemoveEvent(TtsEventId.Bookmark, ref VoiceSynthesizer._bookmarkReached, value); } } public event EventHandler<VoiceChangeEventArgs> VoiceChange { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.AddEvent(TtsEventId.VoiceChange, ref VoiceSynthesizer._voiceChange, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.RemoveEvent(TtsEventId.VoiceChange, ref VoiceSynthesizer._voiceChange, value); } } public event EventHandler<PhonemeReachedEventArgs> PhonemeReached { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.AddEvent(TtsEventId.Phoneme, ref VoiceSynthesizer._phonemeReached, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.RemoveEvent(TtsEventId.Phoneme, ref VoiceSynthesizer._phonemeReached, value); } } public event EventHandler<VisemeReachedEventArgs> VisemeReached { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.AddEvent(TtsEventId.Viseme, ref VoiceSynthesizer._visemeReached, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesizer.RemoveEvent(TtsEventId.Viseme, ref VoiceSynthesizer._visemeReached, value); } } public event EventHandler<StateChangedEventArgs> StateChanged { [MethodImpl(MethodImplOptions.Synchronized)] add { Helpers.ThrowIfNull(value, "value"); VoiceSynthesis voiceSynthesizer = VoiceSynthesizer; voiceSynthesizer._stateChanged = (EventHandler<StateChangedEventArgs>)Delegate.Combine(voiceSynthesizer._stateChanged, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { Helpers.ThrowIfNull(value, "value"); VoiceSynthesis voiceSynthesizer = VoiceSynthesizer; voiceSynthesizer._stateChanged = (EventHandler<StateChangedEventArgs>)Delegate.Remove(voiceSynthesizer._stateChanged, value); } } ~SpeechSynthesizer() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } public void SelectVoice(string name) { Helpers.ThrowIfEmptyOrNull(name, "name"); TTSVoice engine = VoiceSynthesizer.GetEngine(name, CultureInfo.CurrentUICulture, VoiceGender.NotSet, VoiceAge.NotSet, 1, switchContext: true); if (engine == null || name != engine.VoiceInfo.Name) { throw new ArgumentException(SR.Get(SRID.SynthesizerSetVoiceNoMatch)); } VoiceSynthesizer.Voice = engine; } public void SelectVoiceByHints(VoiceGender gender) { SelectVoiceByHints(gender, VoiceAge.NotSet, 1, CultureInfo.CurrentUICulture); } public void SelectVoiceByHints(VoiceGender gender, VoiceAge age) { SelectVoiceByHints(gender, age, 1, CultureInfo.CurrentUICulture); } public void SelectVoiceByHints(VoiceGender gender, VoiceAge age, int voiceAlternate) { SelectVoiceByHints(gender, age, voiceAlternate, CultureInfo.CurrentUICulture); } public void SelectVoiceByHints(VoiceGender gender, VoiceAge age, int voiceAlternate, CultureInfo culture) { Helpers.ThrowIfNull(culture, "culture"); if (voiceAlternate < 0) { throw new ArgumentOutOfRangeException("voiceAlternate", SR.Get(SRID.PromptBuilderInvalidVariant)); } if (!VoiceInfo.ValidateGender(gender)) { throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceGender"), "gender"); } if (!VoiceInfo.ValidateAge(age)) { throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceAge"), "age"); } TTSVoice engine = VoiceSynthesizer.GetEngine(null, culture, gender, age, voiceAlternate, switchContext: true); if (engine == null) { throw new InvalidOperationException(SR.Get(SRID.SynthesizerSetVoiceNoMatch)); } VoiceSynthesizer.Voice = engine; } public Prompt SpeakAsync(string textToSpeak) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); Prompt prompt = new Prompt(textToSpeak, SynthesisTextFormat.Text); SpeakAsync(prompt); return prompt; } public void SpeakAsync(Prompt prompt) { Helpers.ThrowIfNull(prompt, "prompt"); prompt.Synthesizer = this; VoiceSynthesizer.SpeakAsync(prompt); } public Prompt SpeakSsmlAsync(string textToSpeak) { Helpers.ThrowIfNull(textToSpeak, "textToSpeak"); Prompt prompt = new Prompt(textToSpeak, SynthesisTextFormat.Ssml); SpeakAsync(prompt); return prompt; } public Prompt SpeakAsync(PromptBuilder promptBuilder) { Helpers.ThrowIfNull(promptBuilder, "promptBuilder"); Prompt prompt = new Prompt(promptBuilder); SpeakAsync(prompt); return prompt; } public void Speak(string textToSpeak) { Speak(new Prompt(textToSpeak, SynthesisTextFormat.Text)); } public void Speak(Prompt prompt) { Helpers.ThrowIfNull(prompt, "prompt"); if (State == SynthesizerState.Paused) { throw new InvalidOperationException(SR.Get(SRID.SynthesizerSyncSpeakWhilePaused)); } prompt.Synthesizer = this; prompt._syncSpeak = true; VoiceSynthesizer.Speak(prompt); } public void Speak(PromptBuilder promptBuilder) { Speak(new Prompt(promptBuilder)); } public void SpeakSsml(string textToSpeak) { Speak(new Prompt(textToSpeak, SynthesisTextFormat.Ssml)); } public void Pause() { if (!_paused) { VoiceSynthesizer.Pause(); _paused = true; } } public void Resume() { if (_paused) { VoiceSynthesizer.Resume(); _paused = false; } } public void SpeakAsyncCancel(Prompt prompt) { Helpers.ThrowIfNull(prompt, "prompt"); VoiceSynthesizer.Abort(prompt); } public void SpeakAsyncCancelAll() { VoiceSynthesizer.Abort(); } public void SetOutputToWaveFile(string path) { Helpers.ThrowIfEmptyOrNull(path, "path"); SetOutputToNull(); SetOutputStream(new FileStream(path, FileMode.Create, FileAccess.Write), null, headerInfo: true, closeStreamOnExit: true); } public void SetOutputToWaveFile(string path, SpeechAudioFormatInfo formatInfo) { Helpers.ThrowIfEmptyOrNull(path, "path"); Helpers.ThrowIfNull(formatInfo, "formatInfo"); SetOutputToNull(); SetOutputStream(new FileStream(path, FileMode.Create, FileAccess.Write), formatInfo, headerInfo: true, closeStreamOnExit: true); } public void SetOutputToWaveStream(Stream audioDestination) { Helpers.ThrowIfNull(audioDestination, "audioDestination"); SetOutputStream(audioDestination, null, headerInfo: true, closeStreamOnExit: false); } public void SetOutputToAudioStream(Stream audioDestination, SpeechAudioFormatInfo formatInfo) { Helpers.ThrowIfNull(audioDestination, "audioDestination"); Helpers.ThrowIfNull(formatInfo, "formatInfo"); SetOutputStream(audioDestination, formatInfo, headerInfo: false, closeStreamOnExit: false); } public void SetOutputToDefaultAudioDevice() { SetOutputStream(null, null, headerInfo: true, closeStreamOnExit: false); } public void SetOutputToNull() { if (_outputStream != Stream.Null) { VoiceSynthesizer.SetOutput(Stream.Null, null, headerInfo: true); } if (_outputStream != null && _closeStreamOnExit) { _outputStream.Close(); } _outputStream = Stream.Null; } public Prompt GetCurrentlySpokenPrompt() { return VoiceSynthesizer.Prompt; } public ReadOnlyCollection<InstalledVoice> GetInstalledVoices() { return VoiceSynthesizer.GetInstalledVoices(null); } public ReadOnlyCollection<InstalledVoice> GetInstalledVoices(CultureInfo culture) { Helpers.ThrowIfNull(culture, "culture"); if (culture.Equals(CultureInfo.InvariantCulture)) { throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture"); } return VoiceSynthesizer.GetInstalledVoices(culture); } public void AddLexicon(Uri uri, string mediaType) { Helpers.ThrowIfNull(uri, "uri"); VoiceSynthesizer.AddLexicon(uri, mediaType); } public void RemoveLexicon(Uri uri) { Helpers.ThrowIfNull(uri, "uri"); VoiceSynthesizer.RemoveLexicon(uri); } private void SetOutputStream(Stream stream, SpeechAudioFormatInfo formatInfo, bool headerInfo, bool closeStreamOnExit) { SetOutputToNull(); _outputStream = stream; _closeStreamOnExit = closeStreamOnExit; VoiceSynthesizer.SetOutput(stream, formatInfo, headerInfo); } private void Dispose(bool disposing) { if (!_isDisposed && disposing && _voiceSynthesis != null) { _isDisposed = true; SpeakAsyncCancelAll(); if (_outputStream != null) { if (_closeStreamOnExit) { _outputStream.Close(); } else { _outputStream.Flush(); } _outputStream = null; } } if (_voiceSynthesis != null) { _voiceSynthesis.Dispose(); _voiceSynthesis = null; } _isDisposed = true; } } public enum SynthesizerState { Ready, Speaking, Paused } [Flags] public enum SynthesizerEmphasis { Stressed = 1, Emphasized = 2 } public class StateChangedEventArgs : EventArgs { private SynthesizerState _state; private SynthesizerState _previousState; public SynthesizerState State => _state; public SynthesizerState PreviousState => _previousState; internal StateChangedEventArgs(SynthesizerState state, SynthesizerState previousState) { _state = state; _previousState = previousState; } } public class VisemeReachedEventArgs : PromptEventArgs { private int _currentViseme; private TimeSpan _audioPosition; private TimeSpan _duration; private SynthesizerEmphasis _emphasis; private int _nextViseme; public int Viseme => _currentViseme; public TimeSpan AudioPosition => _audioPosition; public TimeSpan Duration => _duration; public SynthesizerEmphasis Emphasis => _emphasis; public int NextViseme => _nextViseme; internal VisemeReachedEventArgs(Prompt speakPrompt, int currentViseme, TimeSpan audioPosition, TimeSpan duration, SynthesizerEmphasis emphasis, int nextViseme) : base(speakPrompt) { _currentViseme = currentViseme; _audioPosition = audioPosition; _duration = duration; _emphasis = emphasis; _nextViseme = nextViseme; } } public class VoiceChangeEventArgs : PromptEventArgs { private VoiceInfo _voice; public VoiceInfo Voice => _voice; internal VoiceChangeEventArgs(Prompt prompt, VoiceInfo voice) : base(prompt) { _voice = voice; } } [Serializable] [DebuggerDisplay("{(_name != null ? \"'\" + _name + \"' \" : \"\") + (_culture != null ? \" '\" + _culture.ToString () + \"' \" : \"\") + (_gender != VoiceGender.NotSet ? \" '\" + _gender.ToString () + \"' \" : \"\") + (_age != VoiceAge.NotSet ? \" '\" + _age.ToString () + \"' \" : \"\") + (_variant > 0 ? \" \" + _variant.ToString () : \"\")}")] public class VoiceInfo { private string _name; private CultureInfo _culture; private VoiceGender _gender; private VoiceAge _age; private int _variant = -1; [NonSerialized] private string _id; [NonSerialized] private string _registryKeyPath; [NonSerialized] private string _assemblyName; [NonSerialized] private string _clsid; [NonSerialized] private string _description; [NonSerialized] private ReadOnlyDictionary<string, string> _attributes; [NonSerialized] private ReadOnlyCollection<SpeechAudioFormatInfo> _audioFormats; public VoiceGender Gender => _gender; public VoiceAge Age => _age; public string Name => _name; public CultureInfo Culture => _culture; public string Id => _id; public string Description => _description ?? string.Empty; [EditorBrowsable(EditorBrowsableState.Advanced)] public ReadOnlyCollection<SpeechAudioFormatInfo> SupportedAudioFormats => _audioFormats; [EditorBrowsable(EditorBrowsableState.Advanced)] public IDictionary<string, string> AdditionalInfo => _attributes ?? (_attributes = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>(0))); internal int Variant => _variant; internal string AssemblyName => _assemblyName; internal string Clsid => _clsid; internal string RegistryKeyPath => _registryKeyPath; internal VoiceInfo(string name) { Helpers.ThrowIfEmptyOrNull(name, "name"); _name = name; } internal VoiceInfo(CultureInfo culture) { Helpers.ThrowIfNull(culture, "culture"); if (culture.Equals(CultureInfo.InvariantCulture)) { throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture"); } _culture = culture; } internal VoiceInfo(ObjectToken token) { _registryKeyPath = token._sKeyId; _id = token.Name; _description = token.Description; _name = token.TokenName(); SsmlParserHelpers.TryConvertAge(token.Age.ToLowerInvariant(), out _age); SsmlParserHelpers.TryConvertGender(token.Gender.ToLowerInvariant(), out _gender); if (token.Attributes.TryGetString("Language", out var value)) { _culture = SapiAttributeParser.GetCultureInfoFromLanguageString(value); } if (token.TryGetString("Assembly", out var value2)) { _assemblyName = value2; } if (token.TryGetString("CLSID", out var value3)) { _clsid = value3; } if (token.Attributes != null) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); string[] valueNames = token.Attributes.GetValueNames(); foreach (string text in valueNames) { if (token.Attributes.TryGetString(text, out var value4)) { dictionary.Add(text, value4); } } _attributes = new ReadOnlyDictionary<string, string>(dictionary); } if (token.Attributes != null && token.Attributes.TryGetString("AudioFormats", out var value5)) { _audioFormats = new ReadOnlyCollection<SpeechAudioFormatInfo>(SapiAttributeParser.GetAudioFormatsFromString(value5)); } else { _audioFormats = new ReadOnlyCollection<SpeechAudioFormatInfo>(new List<SpeechAudioFormatInfo>()); } } internal VoiceInfo(VoiceGender gender) { _gender = gender; } internal VoiceInfo(VoiceGender gender, VoiceAge age) { _gender = gender; _age = age; } internal VoiceInfo(VoiceGender gender, VoiceAge age, int voiceAlternate) { if (voiceAlternate < 0) { throw new ArgumentOutOfRangeException("voiceAlternate", SR.Get(SRID.PromptBuilderInvalidVariant)); } _gender = gender; _age = age; _variant = voiceAlternate + 1; } public override bool Equals(object obj) { if (obj is VoiceInfo voiceInfo && _name == voiceInfo._name && (_age == voiceInfo._age || _age == VoiceAge.NotSet || voiceInfo._age == VoiceAge.NotSet) && (_gender == voiceInfo._gender || _gender == VoiceGender.NotSet || voiceInfo._gender == VoiceGender.NotSet)) { if (_culture != null && voiceInfo._culture != null) { return _culture.Equals(voiceInfo._culture); } return true; } return false; } public override int GetHashCode() { return _name.GetHashCode(); } internal static bool ValidateGender(VoiceGender gender) { if (gender != VoiceGender.Female && gender != VoiceGender.Male && gender != VoiceGender.Neutral) { return gender == VoiceGender.NotSet; } return true; } internal static bool ValidateAge(VoiceAge age) { if (age != VoiceAge.Adult && age != VoiceAge.Child && age != 0 && age != VoiceAge.Senior) { return age == VoiceAge.Teen; } return true; } } } namespace System.Speech.Synthesis.TtsEngine { [ComImport] [Guid("A74D7C8E-4CC5-4F2F-A6EB-804DEE18500E")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ITtsEngine { [PreserveSig] void Speak(SPEAKFLAGS dwSpeakFlags, ref Guid rguidFormatId, IntPtr pWaveFormatEx, IntPtr pTextFragList, IntPtr pOutputSite); [PreserveSig] void GetOutputFormat(ref Guid pTargetFmtId, IntPtr pTargetWaveFormatEx, out Guid pOutputFormatId, out IntPtr ppCoMemOutputWaveFormatEx); } [StructLayout(LayoutKind.Sequential)] internal class SPVTEXTFRAG { public IntPtr pNext; public SPVSTATE State; public IntPtr pTextStart; public int ulTextLen; public int ulTextSrcOffset; public GCHandle gcText; public GCHandle gcNext; public GCHandle gcPhoneme; public GCHandle gcSayAsCategory; } [ComConversionLoss] [TypeLibType(16)] internal struct SPVSTATE { public SPVACTIONS eAction; public short LangID; public short wReserved; public int EmphAdj; public int RateAdj; public int Volume; public SPVPITCH PitchAdj; public int SilenceMSecs; public IntPtr pPhoneIds; public SPPARTOFSPEECH ePartOfSpeech; public SPVCONTEXT Context; } [TypeLibType(16)] internal struct SPVCONTEXT { public IntPtr pCategory; public IntPtr pBefore; public IntPtr pAfter; } [TypeLibType(16)] internal struct SPVPITCH { public int MiddleAdj; public int RangeAdj; } internal static class SAPIGuids { internal static readonly Guid SPDFID_WaveFormatEx = new Guid("C31ADBAE-527F-4ff5-A230-F62BB61FF70C"); } [Flags] internal enum SPEAKFLAGS { SPF_DEFAULT = 0, SPF_ASYNC = 1, SPF_PURGEBEFORESPEAK = 2, SPF_IS_FILENAME = 4, SPF_IS_XML = 8, SPF_IS_NOT_XML = 0x10, SPF_PERSIST_XML = 0x20, SPF_NLP_SPEAK_PUNC = 0x40, SPF_PARSE_SAPI = 0x80, SPF_PARSE_SSML = 0x100 } [Flags] internal enum SPVESACTIONS { SPVES_CONTINUE = 0, SPVES_ABORT = 1, SPVES_SKIP = 2, SPVES_RATE = 4, SPVES_VOLUME = 8 } [TypeLibType(16)] internal enum SPVACTIONS { SPVA_Speak, SPVA_Silence, SPVA_Pronounce, SPVA_Bookmark, SPVA_SpellOut, SPVA_Section, SPVA_ParseUnknownTag } [TypeLibType(16)] internal enum SPPARTOFSPEECH { SPPS_NotOverridden = -1, SPPS_Unknown = 0, SPPS_Noun = 4096, SPPS_Verb = 8192, SPPS_Modifier = 12288, SPPS_Function = 16384, SPPS_Interjection = 20480, SPPS_SuppressWord = 61440 } public abstract class TtsEngineSsml { protected TtsEngineSsml(string registryKey) { } public abstract IntPtr GetOutputFormat(SpeakOutputFormat speakOutputFormat, IntPtr targetWaveFormat); public abstract void AddLexicon(Uri uri, string mediaType, ITtsEngineSite site); public abstract void RemoveLexicon(Uri uri, ITtsEngineSite site); public abstract void Speak(TextFragment[] fragment, IntPtr waveHeader, ITtsEngineSite site); } [ImmutableObject(true)] public struct SpeechEventInfo : IEquatable<SpeechEventInfo> { private short _eventId; private short _parameterType; private int _param1; private IntPtr _param2; public short EventId { get { return _eventId; } internal set { _eventId = value; } } public short ParameterType { get { return _parameterType; } internal set { _parameterType = value; } } public int Param1 { get { return _param1; } internal set { _param1 = value; } } public IntPtr Param2 { get { return _param2; } internal set { _param2 = value; } } public SpeechEventInfo(short eventId, short parameterType, int param1, IntPtr param2) { _eventId = eventId; _parameterType = parameterType; _param1 = param1; _param2 = param2; } public static bool operator ==(SpeechEventInfo event1, SpeechEventInfo event2) { if (event1.EventId == event2.EventId && event1.ParameterType == event2.ParameterType && event1.Param1 == event2.Param1) { return event1.Param2 == event2.Param2; } return false; } public static bool operator !=(SpeechEventInfo event1, SpeechEventInfo event2) { return !(event1 == event2); } public bool Equals(SpeechEventInfo other) { return this == other; } public override bool Equals(object obj) { if (!(obj is SpeechEventInfo)) { return false; } return Equals((SpeechEventInfo)obj); } public override int GetHashCode() { return base.GetHashCode(); } } public interface ITtsEngineSite { int EventInterest { get; } int Actions { get; } int Rate { get; } int Volume { get; } void AddEvents(SpeechEventInfo[] events, int count); int Write(IntPtr data, int count); SkipInfo GetSkipInfo(); void CompleteSkip(int skipped); Stream LoadResource(Uri uri, string mediaType); } public class SkipInfo { private int _type; private int _count; public int Type { get { return _type; } set { _type = value; } } public int Count { get { return _count; } set { _count = value; } } internal SkipInfo(int type, int count) { _type = type; _count = count; } public SkipInfo() { } } [StructLayout(LayoutKind.Sequential)] [DebuggerDisplay("{State.Action} = {TextToSpeak!=null?TextToSpeak:\"\"}")] public class TextFragment { private FragmentState _state; [MarshalAs(UnmanagedType.LPWStr)] private string _textToSpeak = string.Empty; private int _textOffset; private int _textLength; public FragmentState State { get { return _state; } set { _state = value; } } public string TextToSpeak { get { return _textToSpeak; } set { Helpers.ThrowIfEmptyOrNull(value, "value"); _textToSpeak = value; } } public int TextOffset { get { return _textOffset; } set { _textOffset = value; } } public int TextLength { get { return _textLength; } set { _textLength = value; } } public TextFragment() { } internal TextFragment(FragmentState fragState) : this(fragState, null, null, 0, 0) { } internal TextFragment(FragmentState fragState, string textToSpeak) : this(fragState, textToSpeak, textToSpeak, 0, textToSpeak.Length) { } internal TextFragment(FragmentState fragState, string textToSpeak, string textFrag, int offset, int length) { if (fragState.Action == TtsEngineAction.Speak || fragState.Action == TtsEngineAction.Pronounce) { textFrag = textToSpeak; } if (!string.IsNullOrEmpty(textFrag)) { TextToSpeak = textFrag; } State = fragState; TextOffset = offset; TextLength = length; } } [ImmutableObject(true)] public struct FragmentState : IEquatable<FragmentState> { private TtsEngineAction _action; private int _langId; private int _emphasis; private int _duration; private SayAs _sayAs; private Prosody _prosody; private char[] _phoneme; public TtsEngineAction Action { get { return _action; } internal set { _action = value; } } public int LangId { get { return _langId; } internal set { _langId = value; } } public int Emphasis { get { return _emphasis; } internal set { _emphasis = value; } } public int Duration { get { return _duration; } internal set { _duration = value; } } public SayAs SayAs { get { return _sayAs; } internal set { Helpers.ThrowIfNull(value, "value"); _sayAs = value; } } public Prosody Prosody { get { return _prosody; } internal set { Helpers.ThrowIfNull(value, "value"); _prosody = value; } } public char[] Phoneme { get { return _phoneme; } internal set { Helpers.ThrowIfNull(value, "value"); _phoneme = value; } } public FragmentState(TtsEngineAction action, int langId, int emphasis, int duration, SayAs sayAs, Prosody prosody, char[] phonemes) { _action = action; _langId = langId; _emphasis = emphasis; _duration = duration; _sayAs = sayAs; _prosody = prosody; _phoneme = phonemes; } public static bool operator ==(FragmentState state1, FragmentState state2) { if (state1.Action == state2.Action && state1.LangId == state2.LangId && state1.Emphasis == state2.Emphasis && state1.Duration == state2.Duration && state1.SayAs == state2.SayAs && state1.Prosody == state2.Prosody) { return object.Equals(state1.Phoneme, state2.Phoneme); } return false; } public static bool operator !=(FragmentState state1, FragmentState state2) { return !(state1 == state2); } public bool Equals(FragmentState other) { return this == other; } public override bool Equals(object obj) { if (!(obj is FragmentState)) { return false; } return Equals((FragmentState)obj); } public override int GetHashCode() { return base.GetHashCode(); } } [StructLayout(LayoutKind.Sequential)] public class Prosody { internal ProsodyNumber _pitch; internal ProsodyNumber _range; internal ProsodyNumber _rate; internal int _duration; internal ProsodyNumber _volume; internal ContourPoint[] _contourPoints; public ProsodyNumber Pitch { get { return _pitch; } set { _pitch = value; } } public ProsodyNumber Range { get { return _range; } set { _range = value; } } public ProsodyNumber Rate { get { return _rate; } set { _rate = value; } } public int Duration { get { return _duration; } set { _duration = value; } } public ProsodyNumber Volume { get { return _volume; } set { _volume = value; } } public ContourPoint[] GetContourPoints() { return _contourPoints; } public void SetContourPoints(ContourPoint[] points) { Helpers.ThrowIfNull(points, "points"); _contourPoints = (ContourPoint[])points.Clone(); } public Prosody() { Pitch = new ProsodyNumber(0); Range = new ProsodyNumber(0); Rate = new ProsodyNumber(0); Volume = new ProsodyNumber(-1); } internal Prosody Clone() { Prosody prosody = new Prosody(); prosody._pitch = _pitch; prosody._range = _range; prosody._rate = _rate; prosody._duration = _duration; prosody._volume = _volume; return prosody; } } [ImmutableObject(true)] public struct ContourPoint : IEquatable<ContourPoint> { private float _start; private float _change; private ContourPointChangeType _changeType; public float Start => _start; public float Change => _change; public ContourPointChangeType ChangeType => _changeType; public ContourPoint(float start, float change, ContourPointChangeType changeType) { _start = start; _change = change; _changeType = changeType; } public static bool operator ==(ContourPoint point1, ContourPoint point2) { if (point1.Start.Equals(point2.Start) && point1.Change.Equals(point2.Change)) { return point1.ChangeType.Equals(point2.ChangeType); } return false; } public static bool operator !=(ContourPoint point1, ContourPoint point2) { return !(point1 == point2); } public bool Equals(ContourPoint other) { return this == other; } public override bool Equals(object obj) { if (!(obj is ContourPoint)) { return false; } return Equals((ContourPoint)obj); } public override int GetHashCode() { return base.GetHashCode(); } } [ImmutableObject(true)] public struct ProsodyNumber : IEquatable<ProsodyNumber> { public const int AbsoluteNumber = int.MaxValue; private int _ssmlAttributeId; private bool _isPercent; private float _number; private ProsodyUnit _unit; public int SsmlAttributeId { get { return _ssmlAttributeId; } internal set { _ssmlAttributeId = value; } } public bool IsNumberPercent { get { return _isPercent; } internal set { _isPercent = value; } } public float Number { get { return _number; } internal set { _number = value; } } public ProsodyUnit Unit { get { return _unit; } internal set { _unit = value; } } public ProsodyNumber(int ssmlAttributeId) { _ssmlAttributeId = ssmlAttributeId; _number = 1f; _isPercent = true; _unit = ProsodyUnit.Default; } public ProsodyNumber(float number) { _ssmlAttributeId = int.MaxValue; _number = number; _isPercent = false; _unit = ProsodyUnit.Default; } public static bool operator ==(ProsodyNumber prosodyNumber1, ProsodyNumber prosodyNumber2) { if (prosodyNumber1._ssmlAttributeId == prosodyNumber2._ssmlAttributeId && prosodyNumber1.Number.Equals(prosodyNumber2.Number) && prosodyNumber1.IsNumberPercent == prosodyNumber2.IsNumberPercent) { return prosodyNumber1.Unit == prosodyNumber2.Unit; } return false; } public static bool operator !=(ProsodyNumber prosodyNumber1, ProsodyNumber prosodyNumber2) { return !(prosodyNumber1 == prosodyNumber2); } public bool Equals(ProsodyNumber other) { return this == other; } public override bool Equals(object obj) { if (!(obj is ProsodyNumber)) { return false; } return Equals((ProsodyNumber)obj); } public override int GetHashCode() { return base.GetHashCode(); } } [StructLayout(LayoutKind.Sequential)] public class SayAs { [MarshalAs(UnmanagedType.LPWStr)] private string _interpretAs; [MarshalAs(UnmanagedType.LPWStr)] private string _format; [MarshalAs(UnmanagedType.LPWStr)] private string _detail; public string InterpretAs { get { return _interpretAs; } set { Helpers.ThrowIfEmptyOrNull(value, "value"); _interpretAs = value; } } public string Format { get { return _format; } set { Helpers.ThrowIfEmptyOrNull(value, "value"); _format = value; } } public string Detail { get { return _detail; } set { Helpers.ThrowIfEmptyOrNull(value, "value"); _detail = value; } } } public enum TtsEngineAction { Speak, Silence, Pronounce, Bookmark, SpellOut, StartSentence, StartParagraph, ParseUnknownTag } public enum EmphasisWord { Default, Strong, Moderate, None, Reduced } public enum EmphasisBreak { None = -1, ExtraWeak = -2, Weak = -3, Medium = -4, Strong = -5, ExtraStrong = -6, Default = -7 } public enum ProsodyPitch { Default, ExtraLow, Low, Medium, High, ExtraHigh } public enum ProsodyRange { Default, ExtraLow, Low, Medium, High, ExtraHigh } public enum ProsodyRate { Default, ExtraSlow, Slow, Medium, Fast, ExtraFast } public enum ProsodyVolume { Default = -1, Silent = -2, ExtraSoft = -3, Soft = -4, Medium = -5, Loud = -6, ExtraLoud = -7 } public enum ProsodyUnit { Default, Hz, Semitone } public enum TtsEventId { StartInputStream = 1, EndInputStream, VoiceChange, Bookmark, WordBoundary, Phoneme, SentenceBoundary, Viseme, AudioLevel } public enum EventParameterType { Undefined, Token, Object, Pointer, String } public enum SpeakOutputFormat { WaveFormat, Text } public enum ContourPointChangeType { Hz, Percentage } } namespace System.Speech.Recognition { public class AudioLevelUpdatedEventArgs : EventArgs { private int _audioLevel; public int AudioLevel => _audioLevel; internal AudioLevelUpdatedEventArgs(int audioLevel) { _audioLevel = audioLevel; } } public enum AudioSignalProblem { None, TooNoisy, NoSignal, TooLoud, TooSoft, TooFast, TooSlow } public class AudioSignalProblemOccurredEventArgs : EventArgs { private AudioSignalProblem _audioSignalProblem; private TimeSpan _recognizerPosition; private TimeSpan _audioPosition; private int _audioLevel; public AudioSignalProblem AudioSignalProblem => _audioSignalProblem; public int AudioLevel => _audioLevel; public TimeSpan AudioPosition => _audioPosition; public TimeSpan RecognizerAudioPosition => _recognizerPosition; internal AudioSignalProblemOccurredEventArgs(AudioSignalProblem audioSignalProblem, int audioLevel, TimeSpan audioPosition, TimeSpan recognizerPosition) { _audioSignalProblem = audioSignalProblem;
Babbler.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Speech.AudioFormat; using System.Speech.Synthesis; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Babbler.Hooks; using Babbler.Implementation.Characteristics; using Babbler.Implementation.Common; using Babbler.Implementation.Config; using Babbler.Implementation.Emotes; using Babbler.Implementation.Hosts; using Babbler.Implementation.Occlusion; using Babbler.Implementation.Occlusion.Vents; using Babbler.Implementation.Occlusion.Vents.Explorer; using Babbler.Implementation.Phonetic; using Babbler.Implementation.Speakers; using Babbler.Implementation.Synthesis; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FMOD; using FMODUnity; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; using Il2CppSystem.IO; using Microsoft.CodeAnalysis; using SOD.Common; using SOD.Common.BepInEx; using SOD.Common.Helpers; using UnityEngine; using UniverseLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Arsonide")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyCopyright("Arsonide")] [assembly: AssemblyDescription("Plugin that makes citizens audibly speak in Shadows of Doubt.")] [assembly: AssemblyFileVersion("0.9.6")] [assembly: AssemblyInformationalVersion("0.9.6")] [assembly: AssemblyProduct("Babbler")] [assembly: AssemblyTitle("Babbler")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Arsonide/Babbler")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.6.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Babbler { [BepInPlugin("AAAA_Babbler", "Babbler", "0.9.6")] public class BabblerPlugin : PluginController<BabblerPlugin> { private bool _hasInitializedImmediate; private bool _hasInitializedDeferred; public override void Load() { ((PluginController<BabblerPlugin, IEmptyBindings>)(object)this).Load(); _hasInitializedImmediate = false; _hasInitializedDeferred = false; BabblerConfig.Initialize(base.Config); if (!BabblerConfig.Enabled.Value) { Utilities.Log("Plugin Babbler is disabled.", (LogLevel)16); return; } Utilities.Log("Plugin Babbler is loaded!", (LogLevel)16); ((PluginController<BabblerPlugin, IEmptyBindings>)(object)this).Harmony.PatchAll(); Utilities.Log("Plugin Babbler is patched!", (LogLevel)16); ClassInjector.RegisterTypeInIl2Cpp<SpeakerHost>(); ClassInjector.RegisterTypeInIl2Cpp<VentTagPeekable>(); ClassInjector.RegisterTypeInIl2Cpp<VentTagInteractable>(); Utilities.Log("Plugin Babbler has added custom types!", (LogLevel)16); InitializeImmediate(); } public override bool Unload() { UninitializeImmediate(); UninitializeDeferred(); return ((PluginController<BabblerPlugin, IEmptyBindings>)(object)this).Unload(); } private void InitializeImmediate() { if (!_hasInitializedImmediate) { _hasInitializedImmediate = true; Utilities.Log("Plugin is running immediate initialization.", (LogLevel)32); SpeakerHostPool.InitializePools(); ReplacementRegistry.Initialize(); if (BabblerConfig.Mode.Value == SpeechMode.Synthesis) { SynthesisVoiceRegistry.Initialize(); } } } public void InitializeDeferred() { if (!_hasInitializedDeferred) { _hasInitializedDeferred = true; Utilities.Log("Plugin is running deferred initialization.", (LogLevel)32); FMODRegistry.Initialize(); SpeechMode value = BabblerConfig.Mode.Value; SpeechMode speechMode = value; if (speechMode == SpeechMode.Phonetic || speechMode == SpeechMode.Droning) { PhoneticVoiceRegistry.Initialize(); } VolumeCacheHook.Initialize(); EmoteSoundRegistry.Initialize(); VentRegistry.Initialize(); TVWatcher.Initialize(); } } private void UninitializeImmediate() { if (_hasInitializedImmediate) { Utilities.Log("Plugin is running immediate uninitialization.", (LogLevel)32); SpeakerHostPool.UninitializePools(); } } private void UninitializeDeferred() { if (_hasInitializedDeferred) { Utilities.Log("Plugin is running deferred uninitialization.", (LogLevel)32); SpeechMode value = BabblerConfig.Mode.Value; SpeechMode speechMode = value; if (speechMode == SpeechMode.Phonetic || speechMode == SpeechMode.Droning) { PhoneticVoiceRegistry.Uninitialize(); } EmoteSoundRegistry.Uninitialize(); VentRegistry.Uninitialize(); TVWatcher.Uninitialize(); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Babbler"; public const string PLUGIN_NAME = "Babbler"; public const string PLUGIN_VERSION = "0.9.6"; } } namespace Babbler.Implementation.Synthesis { public static class SynthesisExtensions { public static List<InstalledVoice> GetOneCoreVoices(this SpeechSynthesizer synthesizer) { List<InstalledVoice> list = new List<InstalledVoice>(); Type typeFromHandle = typeof(SpeechSynthesizer); object obj = typeFromHandle.GetProperty("VoiceSynthesizer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(synthesizer); if (obj == null) { return list; } Assembly assembly = typeFromHandle.Assembly; Type type = assembly.GetType("System.Speech.Internal.ObjectTokens.ObjectTokenCategory"); if (type == null) { return list; } Type typeFromHandle2 = typeof(VoiceInfo); Type typeFromHandle3 = typeof(InstalledVoice); string fullName = typeFromHandle2.FullName; string fullName2 = typeFromHandle3.FullName; if (string.IsNullOrEmpty(fullName) || string.IsNullOrEmpty(fullName2)) { return list; } if (!(type.GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic)?.Invoke(null, new object[1] { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices" }) is IDisposable disposable)) { return list; } using (disposable) { if (!(type.GetMethod("FindMatchingTokens", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(disposable, new object[2]) is IList list2)) { return list; } foreach (object item in list2) { if (item == null || item.GetType().GetProperty("Attributes", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(item) == null) { continue; } object obj2 = assembly.CreateInstance(fullName, ignoreCase: true, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[1] { item }, null, null); if (obj2 != null) { object obj3 = assembly.CreateInstance(fullName2, ignoreCase: true, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[2] { obj, obj2 }, null, null); InstalledVoice val = (InstalledVoice)((obj3 is InstalledVoice) ? obj3 : null); if (val != null) { list.Add(val); } } } } return list; } public static void AddVoices(this SpeechSynthesizer synthesizer, List<InstalledVoice> voices) { Type type = ((object)synthesizer).GetType(); object obj = type.GetProperty("VoiceSynthesizer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(synthesizer); if (obj == null) { return; } Type type2 = obj.GetType(); if (!(type2.GetField("_installedVoices", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj) is IList list)) { return; } foreach (InstalledVoice voice in voices) { list.Add(voice); } } } public enum SynthesisVoiceFilterType { Everything, Blacklist, Whitelist } public static class SynthesisVoiceRegistry { public static List<InstalledVoice> OneCoreVoices = null; private const int PRIME_VOICE = 37; private static List<string> MaleVoices = new List<string>(); private static List<string> FemaleVoices = new List<string>(); private static List<string> NonBinaryVoices = new List<string>(); private static List<string> AllVoices = new List<string>(); private static List<string> VoiceFilterInput = new List<string>(); private static readonly List<string>[] VoicePriorities = new List<string>[4]; private static bool HasMaleVoices; private static bool HasFemaleVoices; private static bool HasNonBinaryVoices; private static bool HasAnyVoices; public static void Initialize() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected I4, but got Unknown MaleVoices.Clear(); FemaleVoices.Clear(); NonBinaryVoices.Clear(); AllVoices.Clear(); SetupVoiceFilterInput(); SpeechSynthesizer val = new SpeechSynthesizer(); try { OneCoreVoices = val.GetOneCoreVoices(); if (OneCoreVoices != null) { val.AddVoices(OneCoreVoices); } } catch (Exception ex) { Utilities.Log("Exception encountered while SynthesisVoiceRegistry tried to get OneCore voices: " + ex.Message, (LogLevel)32); } foreach (InstalledVoice installedVoice in val.GetInstalledVoices()) { if (PassesVoiceFilterInput(installedVoice)) { VoiceInfo voiceInfo = installedVoice.VoiceInfo; string name = voiceInfo.Name; VoiceGender gender = voiceInfo.Gender; AllVoices.Add(name); VoiceGender val2 = gender; VoiceGender val3 = val2; switch ((int)val3) { case 1: MaleVoices.Add(name); break; case 2: FemaleVoices.Add(name); break; default: NonBinaryVoices.Add(name); break; } } } HasMaleVoices = MaleVoices.Count > 0; HasFemaleVoices = FemaleVoices.Count > 0; HasNonBinaryVoices = NonBinaryVoices.Count > 0; HasAnyVoices = AllVoices.Count > 0; val.SpeakCompleted -= OnSpeakCompleted; val.SpeakCompleted += OnSpeakCompleted; val.SetOutputToNull(); val.SpeakAsync("Initialize"); Utilities.Log($"SynthesisVoiceRegistry has initialized! Male Voices: {MaleVoices.Count}, Female Voices: {FemaleVoices.Count}, Non-Binary Voices: {NonBinaryVoices.Count}", (LogLevel)32); if (AllVoices.Count <= 0 && BabblerConfig.Mode.Value == SpeechMode.Synthesis) { BabblerConfig.Mode.Value = SpeechMode.Phonetic; Utilities.Log("The plugin is configured for Synthesis but no voices are installed, reverting to Phonetic mode!", (LogLevel)2); } } private static void OnSpeakCompleted(object sender, SpeakCompletedEventArgs e) { SpeechSynthesizer val = (SpeechSynthesizer)((sender is SpeechSynthesizer) ? sender : null); if (val != null) { val.SpeakCompleted -= OnSpeakCompleted; val.Dispose(); } } public static string GetVoice(Human human, out VoiceCharacteristics characteristics) { characteristics = VoiceCharacteristics.Create(human, HasMaleVoices, HasFemaleVoices, HasNonBinaryVoices); return characteristics.SelectDeterministicGenderedListElement(VoicePriorities, AllVoices, MaleVoices, FemaleVoices, NonBinaryVoices, 37); } private static void SetupVoiceFilterInput() { VoiceFilterInput.Clear(); string text = BabblerConfig.SynthesisVoiceFilterInput.Value.ToLowerInvariant(); VoiceFilterInput.AddRange(text.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)); } private static bool PassesVoiceFilterInput(InstalledVoice voice) { switch (BabblerConfig.SynthesisVoiceFilter.Value) { case SynthesisVoiceFilterType.Blacklist: foreach (string item in VoiceFilterInput) { if (voice.VoiceInfo.Name.ToLowerInvariant().Contains(item)) { return false; } } return true; case SynthesisVoiceFilterType.Whitelist: foreach (string item2 in VoiceFilterInput) { if (voice.VoiceInfo.Name.ToLowerInvariant().Contains(item2)) { return true; } } return false; default: return true; } } } } namespace Babbler.Implementation.Speakers { public abstract class BaseSpeaker { public Action OnFinishedSpeaking; protected readonly List<Channel> ActiveChannels = new List<Channel>(); protected SoundContext SoundContext { get; private set; } protected Human SpeechPerson { get; private set; } protected Transform SpeechSource { get; private set; } protected float SpeechPitch { get; private set; } public virtual void InitializeSpeaker() { } public virtual void UninitializeSpeaker() { } public virtual void StopSpeaker() { ActiveChannels.Clear(); } public virtual void StartSpeaker(string speechInput, SoundContext soundContext, Human speechPerson) { StopSpeaker(); SoundContext = soundContext; SpeechPerson = speechPerson; SpeechSource = CacheSpeechSource(soundContext, speechPerson); SpeechPitch = CacheSpeechPitch(speechPerson, speechInput); } public virtual void UpdateSpeaker() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) Vector3 position = Vector3.zero; OcclusionResult occlusionResult = OcclusionChecker.CheckOcclusion(SpeechPerson, (Human)(object)Player.Instance, SoundContext); if (!occlusionResult.AlternativePosition) { if ((Object)(object)SpeechSource != (Object)null) { position = SpeechSource.position; } else { Utilities.Log("Babbler speaker had a null SpeechSource, which should not happen!", (LogLevel)32); } } else { position = occlusionResult.Position; } bool flag = false; bool flag2 = default(bool); for (int num = ActiveChannels.Count - 1; num >= 0; num--) { Channel channel = ActiveChannels[num]; if ((int)((Channel)(ref channel)).isPlaying(ref flag2) == 0 && flag2) { SetChannelPosition(position, channel); SetChannelVolume(occlusionResult.State, channel); flag = true; } else { ActiveChannels.RemoveAt(num); if (ActiveChannels.Count <= 0) { OnLastChannelFinished(); } } } if (flag) { FMODRegistry.TryUpdate(); } } protected virtual float CacheSpeechPitch(Human speechPerson, string speechInput) { return 1f; } private Transform CacheSpeechSource(SoundContext soundContext, Human speechPerson) { Transform val2; if (soundContext == SoundContext.PhoneSpeech || soundContext == SoundContext.PhoneShout) { Interactable interactingWith = ((Actor)Player.Instance).interactingWith; object obj; if (interactingWith == null) { obj = null; } else { InteractableController controller = interactingWith.controller; obj = ((controller != null) ? controller.phoneReciever : null); } if (obj == null) { Interactable phoneInteractable = Player.Instance.phoneInteractable; if (phoneInteractable == null) { obj = null; } else { InteractableController controller2 = phoneInteractable.controller; obj = ((controller2 != null) ? controller2.phoneReciever : null); } if (obj == null) { Telephone answeringPhone = Player.Instance.answeringPhone; if (answeringPhone == null) { obj = null; } else { Interactable interactable = answeringPhone.interactable; if (interactable == null) { obj = null; } else { InteractableController controller3 = interactable.controller; obj = ((controller3 != null) ? controller3.phoneReciever : null); } } } } GameObject val = (GameObject)obj; val2 = ((val != null) ? val.transform : null); } else { val2 = ((speechPerson != null) ? ((Actor)speechPerson).lookAtThisTransform : null); } if ((Object)(object)val2 == (Object)null) { Player instance = Player.Instance; val2 = ((instance != null) ? ((Component)instance).transform : null); } return val2; } protected void SetChannelPosition(Vector3 position, Channel channel) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) VECTOR val = default(VECTOR); val.x = position.x; val.y = position.y; val.z = position.z; VECTOR val2 = val; val = default(VECTOR); val.x = 0f; val.y = 0f; val.z = 0f; VECTOR val3 = val; ((Channel)(ref channel)).set3DAttributes(ref val2, ref val3); } protected void SetChannelVolume(OcclusionState occlusionState, Channel channel) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) ((Channel)(ref channel)).setVolume(FMODRegistry.GetVolume(SoundContext, occlusionState)); } protected virtual void OnLastChannelFinished() { } } public class DroningSpeaker : PhoneticSpeaker { private const int PRIME_PHONEME = 97; protected override void ProcessSpeechInput(Human speechPerson, ref string speechInput) { base.ProcessSpeechInput(speechPerson, ref speechInput); char c = PickPhoneme(speechPerson); Utilities.GlobalStringBuilder.Clear(); string text = speechInput; foreach (char c2 in text) { Utilities.GlobalStringBuilder.Append((c2 != ' ') ? c : c2); } speechInput = Utilities.GlobalStringBuilder.ToString(); } private char PickPhoneme(Human human) { return BabblerConfig.DroningValidPhonemes.Value[Utilities.GetDeterministicInteger(CurrentHash, 97, 0, BabblerConfig.DroningValidPhonemes.Value.Length)]; } protected override void CacheSpeechVarianceFactors() { if (Utilities.GetDeterministicFloat(CurrentHash, 401, 0f, 1f) <= BabblerConfig.DroningChanceDelayVariance.Value) { CurrentDelayVarianceFactor = Utilities.GetDeterministicFloat(CurrentHash, 419, 0f, 1f); } else { CurrentDelayVarianceFactor = -1f; } if (Utilities.GetDeterministicFloat(CurrentHash, 409, 0f, 1f) <= BabblerConfig.DroningChancePitchVariance.Value) { CurrentPitchVarianceFactor = Utilities.GetDeterministicFloat(CurrentHash, 421, 0f, 1f); } else { CurrentPitchVarianceFactor = -1f; } } protected override float GetPhonemeDelay() { float value = BabblerConfig.DroningSpeechDelay.Value; if (CurrentDelayVarianceFactor < 0f) { return value; } float num = BabblerConfig.DroningSpeechDelay.Value + Utilities.GetRandomFloat(BabblerConfig.DroningMinDelayVariance.Value, BabblerConfig.DroningMaxDelayVariance.Value); return Mathf.Lerp(value, num, CurrentDelayVarianceFactor); } protected override float GetPhonemePitch() { float speechPitch = base.SpeechPitch; if (CurrentPitchVarianceFactor < 0f) { return speechPitch; } float num = speechPitch * Utilities.GetRandomFloat(BabblerConfig.DroningMinPitchVariance.Value, BabblerConfig.DroningMaxPitchVariance.Value); return Mathf.Lerp(speechPitch, num, CurrentPitchVarianceFactor); } } public class EmoteSpeaker : BaseSpeaker, IDelayableSpeaker { private static float _emotesAllowedTimestamp = -1f; private EmoteSound _emoteToPlay; private Coroutine _emotePlayCoroutine; private float _delay; public override void StopSpeaker() { base.StopSpeaker(); if (_emotePlayCoroutine != null) { RuntimeHelper.StopCoroutine(_emotePlayCoroutine); _emotePlayCoroutine = null; } _delay = 0f; } public override void StartSpeaker(string speechInput, SoundContext soundContext, Human speechPerson) { base.StartSpeaker(speechInput, soundContext, speechPerson); if (_emoteToPlay == null) { OnFinishedSpeaking?.Invoke(); } else { _emotePlayCoroutine = RuntimeHelper.StartCoroutine(EmotePlayRoutine()); } } private IEnumerator EmotePlayRoutine() { while (_delay > 0f) { yield return null; _delay -= Time.deltaTime; } while (Time.realtimeSinceStartup < _emotesAllowedTimestamp) { yield return null; } if (!FMODRegistry.TryPlaySound(_emoteToPlay.Sound, FMODRegistry.GetChannelGroup(base.SoundContext), out var channel)) { OnFinishedSpeaking?.Invoke(); yield break; } float minStagger = BabblerConfig.EmotesMinStagger.Value; float maxStagger = BabblerConfig.EmotesMaxStagger.Value; float staggerDuration = Utilities.GlobalRandom.NextSingle() * (maxStagger - minStagger) + minStagger; _emotesAllowedTimestamp = Time.realtimeSinceStartup + staggerDuration; bool pitchShiftsAllowed = BabblerConfig.EmotesUsePitchShifts.Value && _emoteToPlay.CanPitchShift; ((Channel)(ref channel)).setPitch(pitchShiftsAllowed ? base.SpeechPitch : 1f); SetChannelPosition(base.SpeechSource.position, channel); SetChannelVolume(OcclusionState.NoOcclusion, channel); FMODRegistry.TryUpdate(); ActiveChannels.Add(channel); float expiration = Time.realtimeSinceStartup + _emoteToPlay.Length + 0.2f; while (Time.realtimeSinceStartup < expiration) { yield return null; } OnFinishedSpeaking?.Invoke(); } protected override float CacheSpeechPitch(Human speechPerson, string speechInput) { if (!EmoteSoundRegistry.TryGetEmote(speechInput, speechPerson, out var characteristics, out _emoteToPlay)) { return 1f; } float value; float value2; switch (characteristics.Category) { case VoiceCategory.Male: value = BabblerConfig.EmotesMinFrequencyMale.Value; value2 = BabblerConfig.EmotesMaxFrequencyMale.Value; break; case VoiceCategory.Female: value = BabblerConfig.EmotesMinFrequencyFemale.Value; value2 = BabblerConfig.EmotesMaxFrequencyFemale.Value; break; default: value = BabblerConfig.EmotesMinFrequencyNonBinary.Value; value2 = BabblerConfig.EmotesMaxFrequencyNonBinary.Value; break; } float num = value + characteristics.Pitch * (value2 - value); return num / _emoteToPlay.Frequency; } public void InitializeDelay(float delay) { _delay = delay; } } public interface IDelayableSpeaker { void InitializeDelay(float delay); } public class PhoneticSpeaker : BaseSpeaker { protected const int PRIME_DELAY_CHANCE = 401; protected const int PRIME_PITCH_CHANCE = 409; protected const int PRIME_DELAY_FACTOR = 419; protected const int PRIME_PITCH_FACTOR = 421; private readonly List<PhoneticSound> _phoneticsToSpeak = new List<PhoneticSound>(); private Coroutine _phoneticCoroutine; private PhoneticVoice _currentVoice; protected int CurrentHash; protected float CurrentDelayVarianceFactor; protected float CurrentPitchVarianceFactor; public override void StopSpeaker() { base.StopSpeaker(); if (_phoneticCoroutine != null) { RuntimeHelper.StopCoroutine(_phoneticCoroutine); _phoneticCoroutine = null; } } public override void StartSpeaker(string speechInput, SoundContext soundContext, Human speechPerson) { base.StartSpeaker(speechInput, soundContext, speechPerson); CurrentHash = Utilities.GetDeterministicStringHash(speechPerson.seed); CacheSpeechVarianceFactors(); ProcessSpeechInput(speechPerson, ref speechInput); PopulatePhoneticSounds(speechInput); _phoneticCoroutine = RuntimeHelper.StartCoroutine(PhoneticRoutine()); } private IEnumerator PhoneticRoutine() { foreach (PhoneticSound phoneme in _phoneticsToSpeak) { if (FMODRegistry.TryPlaySound(phoneme.Sound, FMODRegistry.GetChannelGroup(base.SoundContext), out var channel)) { ((Channel)(ref channel)).setPitch(GetPhonemePitch()); SetChannelPosition(base.SpeechSource.position, channel); SetChannelVolume(OcclusionState.NoOcclusion, channel); FMODRegistry.TryUpdate(); ActiveChannels.Add(channel); float delay = GetPhonemeDelay(); float syllableExpiration = Time.realtimeSinceStartup + phoneme.Length + delay; while (Time.realtimeSinceStartup < syllableExpiration) { yield return null; } channel = default(Channel); } } OnFinishedSpeaking?.Invoke(); } protected virtual void ProcessSpeechInput(Human speechPerson, ref string speechInput) { } private void PopulatePhoneticSounds(string speechInput) { _phoneticsToSpeak.Clear(); ReadOnlySpan<char> readOnlySpan = speechInput.ToLowerInvariant().AsSpan(); for (int i = 0; i < readOnlySpan.Length; i++) { ReadOnlySpan<char> readOnlySpan2 = readOnlySpan.Slice(i, Math.Min(2, readOnlySpan.Length - i)); string text = readOnlySpan2.ToString(); if (readOnlySpan2.Length > 1 && _currentVoice.TryGetPhoneticSound(text, out var result)) { _phoneticsToSpeak.Add(result); i++; } else if (_currentVoice.TryGetPhoneticSound(text[0].ToString(), out result)) { _phoneticsToSpeak.Add(result); } } } protected override float CacheSpeechPitch(Human speechPerson, string speechInput) { _currentVoice = PhoneticVoiceRegistry.GetVoice(speechPerson, out var characteristics); float value; float value2; switch (characteristics.Category) { case VoiceCategory.Male: value = BabblerConfig.PhoneticMinFrequencyMale.Value; value2 = BabblerConfig.PhoneticMaxFrequencyMale.Value; break; case VoiceCategory.Female: value = BabblerConfig.PhoneticMinFrequencyFemale.Value; value2 = BabblerConfig.PhoneticMaxFrequencyFemale.Value; break; default: value = BabblerConfig.PhoneticMinFrequencyNonBinary.Value; value2 = BabblerConfig.PhoneticMaxFrequencyNonBinary.Value; break; } float num = value + characteristics.Pitch * (value2 - value); return num / _currentVoice.Frequency; } protected virtual void CacheSpeechVarianceFactors() { if (Utilities.GetDeterministicFloat(CurrentHash, 401, 0f, 1f) <= BabblerConfig.PhoneticChanceDelayVariance.Value) { CurrentDelayVarianceFactor = Utilities.GetDeterministicFloat(CurrentHash, 419, 0f, 1f); } else { CurrentDelayVarianceFactor = -1f; } if (Utilities.GetDeterministicFloat(CurrentHash, 409, 0f, 1f) <= BabblerConfig.PhoneticChancePitchVariance.Value) { CurrentPitchVarianceFactor = Utilities.GetDeterministicFloat(CurrentHash, 421, 0f, 1f); } else { CurrentPitchVarianceFactor = -1f; } } protected virtual float GetPhonemeDelay() { float value = BabblerConfig.PhoneticSpeechDelay.Value; if (CurrentDelayVarianceFactor < 0f) { return value; } float num = BabblerConfig.PhoneticSpeechDelay.Value + Utilities.GetRandomFloat(BabblerConfig.PhoneticMinDelayVariance.Value, BabblerConfig.PhoneticMaxDelayVariance.Value); return Mathf.Lerp(value, num, CurrentDelayVarianceFactor); } protected virtual float GetPhonemePitch() { float speechPitch = base.SpeechPitch; if (CurrentPitchVarianceFactor < 0f) { return speechPitch; } float num = speechPitch * Utilities.GetRandomFloat(BabblerConfig.PhoneticMinPitchVariance.Value, BabblerConfig.PhoneticMaxPitchVariance.Value); return Mathf.Lerp(speechPitch, num, CurrentPitchVarianceFactor); } } public class SynthesisSpeaker : BaseSpeaker { private SpeechSynthesizer _synthesizer; private MemoryStream _memoryStream; public override void InitializeSpeaker() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown base.InitializeSpeaker(); _synthesizer = new SpeechSynthesizer(); try { if (SynthesisVoiceRegistry.OneCoreVoices != null) { _synthesizer.AddVoices(SynthesisVoiceRegistry.OneCoreVoices); } } catch (Exception ex) { Utilities.Log("Exception encountered while SynthesisSpeaker tried to add OneCore voices: " + ex.Message, (LogLevel)32); } _memoryStream = new MemoryStream(); _synthesizer.SetOutputToAudioStream((Stream)_memoryStream, new SpeechAudioFormatInfo(44100, (AudioBitsPerSample)16, (AudioChannel)1)); } public override void UninitializeSpeaker() { base.UninitializeSpeaker(); _synthesizer.Dispose(); _memoryStream.Dispose(); } public override void StopSpeaker() { base.StopSpeaker(); _synthesizer.SpeakCompleted -= OnSpeakCompleted; _synthesizer.SpeakAsyncCancelAll(); } public override void StartSpeaker(string speechInput, SoundContext soundContext, Human speechPerson) { base.StartSpeaker(speechInput, soundContext, speechPerson); _synthesizer.SpeakCompleted -= OnSpeakCompleted; _synthesizer.SpeakCompleted += OnSpeakCompleted; _synthesizer.SpeakAsync(speechInput); } private void OnSpeakCompleted(object sender, SpeakCompletedEventArgs args) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) SpeechSynthesizer val = (SpeechSynthesizer)((sender is SpeechSynthesizer) ? sender : null); if (val != null) { val.SpeakCompleted -= OnSpeakCompleted; _memoryStream.Position = 0L; CREATESOUNDEXINFO val2 = default(CREATESOUNDEXINFO); val2.cbsize = Marshal.SizeOf(typeof(CREATESOUNDEXINFO)); val2.length = (uint)_memoryStream.Length; val2.format = (SOUND_FORMAT)2; val2.defaultfrequency = 44100; val2.numchannels = 1; CREATESOUNDEXINFO extraInfo = val2; if (FMODRegistry.TryCreateSound(_memoryStream.ToArray(), (MODE)6160, ref extraInfo, out var sound) && FMODRegistry.TryPlaySound(sound, FMODRegistry.GetChannelGroup(base.SoundContext), out var channel)) { ((Channel)(ref channel)).setPitch(base.SpeechPitch); SetChannelPosition(base.SpeechSource.position, channel); SetChannelVolume(OcclusionState.NoOcclusion, channel); FMODRegistry.TryUpdate(); ActiveChannels.Add(channel); } } } protected override float CacheSpeechPitch(Human speechPerson, string speechInput) { VoiceCharacteristics characteristics; string voice = SynthesisVoiceRegistry.GetVoice(speechPerson, out characteristics); _synthesizer.SelectVoice(voice); _synthesizer.Rate = Mathf.RoundToInt(Mathf.Lerp((float)BabblerConfig.SynthesisMinSpeed.Value, (float)BabblerConfig.SynthesisMaxSpeed.Value, characteristics.Rate)); return characteristics.Category switch { VoiceCategory.Male => Mathf.Lerp(BabblerConfig.SynthesisMinPitchMale.Value, BabblerConfig.SynthesisMaxPitchMale.Value, characteristics.Pitch), VoiceCategory.Female => Mathf.Lerp(BabblerConfig.SynthesisMinPitchFemale.Value, BabblerConfig.SynthesisMaxPitchFemale.Value, characteristics.Pitch), _ => Mathf.Lerp(BabblerConfig.SynthesisMinPitchNonBinary.Value, BabblerConfig.SynthesisMaxPitchNonBinary.Value, characteristics.Pitch), }; } protected override void OnLastChannelFinished() { base.OnLastChannelFinished(); _memoryStream.Seek(0L, SeekOrigin.Begin); _memoryStream.SetLength(0L); OnFinishedSpeaking?.Invoke(); } } } namespace Babbler.Implementation.Phonetic { public class PhoneticSound { public string Phonetic; public string FilePath; public Sound Sound; public float Length; public bool Released; } public class PhoneticVoice { private readonly Dictionary<string, PhoneticSound> _phonemes = new Dictionary<string, PhoneticSound>(); public string Name { get; private set; } public float Frequency { get; private set; } public void Initialize(string directory) { _phonemes.Clear(); if (!Directory.Exists(directory)) { return; } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(directory); string[] array = fileNameWithoutExtension.Split('_', StringSplitOptions.RemoveEmptyEntries); if (array.Length != 2 || !float.TryParse(array[1], out var result)) { return; } Frequency = result; Name = array[0]; string[] files = Directory.GetFiles(directory, "*.wav"); foreach (string text in files) { string fileNameWithoutExtension2 = Path.GetFileNameWithoutExtension(text); string[] array2 = fileNameWithoutExtension2.Split('_'); if (array2.Length != 2) { continue; } string text2 = array2[1].ToLowerInvariant(); PhoneticSound value = CreatePhoneticSound(text, text2); if (fileNameWithoutExtension2.StartsWith("symbol")) { if (text2.Contains("space")) { _phonemes[" "] = value; _phonemes[","] = value; } else if (text2.Contains("exclamation")) { _phonemes["!"] = value; } else if (text2.Contains("question")) { _phonemes["?"] = value; } else if (text2.Contains("period")) { _phonemes["."] = value; } } else { _phonemes[text2] = value; } } } public void Uninitialize() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<string, PhoneticSound> phoneme in _phonemes) { if (!phoneme.Value.Released) { ((Sound)(ref phoneme.Value.Sound)).release(); phoneme.Value.Released = true; } } } private PhoneticSound CreatePhoneticSound(string filePath, string phonetic) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!FMODRegistry.TryCreateSound(filePath, (MODE)16, out var sound)) { return null; } uint num = default(uint); ((Sound)(ref sound)).getLength(ref num, (TIMEUNIT)1); float length = (float)num / 1000f; return new PhoneticSound { Phonetic = phonetic, FilePath = filePath, Sound = sound, Length = length, Released = false }; } public bool TryGetPhoneticSound(string phonetic, out PhoneticSound result) { return _phonemes.TryGetValue(phonetic, out result); } } public static class PhoneticVoiceRegistry { private const int PRIME_VOICE = 211; private static readonly List<PhoneticVoice> Voices = new List<PhoneticVoice>(); public static void Initialize() { Voices.Clear(); string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException(), "Phonemes"); string[] directories = Directory.GetDirectories(path); foreach (string directory in directories) { PhoneticVoice phoneticVoice = new PhoneticVoice(); phoneticVoice.Initialize(directory); Voices.Add(phoneticVoice); } Utilities.Log($"SynthesisVoiceRegistry has initialized! Voices: {Voices.Count}", (LogLevel)32); } public static void Uninitialize() { foreach (PhoneticVoice voice in Voices) { voice.Uninitialize(); } } public static PhoneticVoice GetVoice(Human human, out VoiceCharacteristics characteristics) { characteristics = VoiceCharacteristics.Create(human, maleVoiceAvailable: true, femaleVoiceAvailable: true, nonBinaryVoiceAvailable: true); return Voices[Utilities.GetDeterministicInteger(characteristics.Hash, 211, 0, Voices.Count)]; } } } namespace Babbler.Implementation.Occlusion { public static class OcclusionChecker { private static Vector3Int _occlusionBoundsMin; private static Vector3Int _occlusionBoundsMax; public static OcclusionResult CheckOcclusion(Human speaker, Human listener, SoundContext context) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (context == SoundContext.PhoneSpeech || context == SoundContext.PhoneShout || context == SoundContext.PhoneEmote) { return OcclusionResult.CreateNoOcclusion(); } if (!BabblerConfig.OcclusionEnabled.Value) { return OcclusionResult.CreateNoOcclusion(); } if (!((Actor)speaker).currentCityTile.isInPlayerVicinity) { return OcclusionResult.CreateFullOcclusion(); } bool flag = Utilities.IsHumanOutside(speaker); bool flag2 = Utilities.IsHumanOutside(listener); if (flag && flag2) { return IsHumanInOcclusionBounds(speaker) ? OcclusionResult.CreateNoOcclusion() : OcclusionResult.CreateFullOcclusion(); } if (flag ^ flag2) { return IsHumanInOcclusionBounds(listener) ? CalculateOcclusionDoorMuffleResult(speaker, listener, crossThreshold: true) : OcclusionResult.CreateFullOcclusion(); } if ((Object)(object)((Actor)speaker).currentBuilding == (Object)null || ((Actor)speaker).currentBuilding.buildingID != ((Actor)listener).currentBuilding.buildingID) { return OcclusionResult.CreateFullOcclusion(); } Vector3Int currentNodeCoord = ((Actor)speaker).currentNodeCoord; int z = ((Vector3Int)(ref currentNodeCoord)).z; currentNodeCoord = ((Actor)listener).currentNodeCoord; if (Mathf.Abs(z - ((Vector3Int)(ref currentNodeCoord)).z) > 3 || !IsHumanInOcclusionBounds(speaker)) { return OcclusionResult.CreateFullOcclusion(); } if (((Actor)listener).inAirVent) { return CalculateOcclusionVentResult(speaker, listener); } if (((Actor)speaker).currentGameLocation.isLobby && ((Actor)listener).currentGameLocation.isLobby) { return OcclusionResult.CreateNoOcclusion(); } bool flag3 = ((Actor)listener).currentGameLocation.isLobby || ((Actor)speaker).currentGameLocation.isLobby; if (!flag3 && ((Actor)speaker).currentGameLocation.thisAsAddress.id != ((Actor)listener).currentGameLocation.thisAsAddress.id) { return OcclusionResult.CreateFullOcclusion(); } return CalculateOcclusionDoorMuffleResult(speaker, listener, flag3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static OcclusionResult CalculateOcclusionDoorMuffleResult(Human speaker, Human listener, bool crossThreshold) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) NewRoom currentRoom = ((Actor)speaker).currentRoom; NewRoom currentRoom2 = ((Actor)listener).currentRoom; if (currentRoom.roomID == currentRoom2.roomID) { return OcclusionResult.CreateNoOcclusion(); } int num = 0; int num2 = 0; Vector3 val = Vector3.zero; Vector3 val2 = Vector3.zero; Enumerator<NodeAccess> enumerator = currentRoom.entrances.GetEnumerator(); while (enumerator.MoveNext()) { NodeAccess current = enumerator.Current; if ((int)current.accessType != 5 && current.GetOtherRoom(currentRoom).roomID == currentRoom2.roomID) { if ((Object)(object)current.door == (Object)null || !current.door.isClosed) { num++; val += current.worldAccessPoint; } else { num2++; val2 += current.worldAccessPoint; } } } if (num + num2 > 0) { OcclusionState state; Vector3 val3; if (num > 0) { state = OcclusionState.MuffleOpenDoor; val3 = val / (float)num; } else { state = OcclusionState.MuffleClosedDoor; val3 = val2 / (float)num2; } Vector3 val4 = val3 - ((Actor)listener).aimTransform.position; float num3 = Vector3.Distance(((Actor)speaker).aimTransform.position, val3); Vector3 position = val3 + ((Vector3)(ref val4)).normalized * num3; OcclusionResult result = default(OcclusionResult); result.State = state; result.AlternativePosition = true; result.Position = position; return result; } return crossThreshold ? OcclusionResult.CreateFullOcclusion() : OcclusionResult.CreateDistantOcclusion(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static OcclusionResult CalculateOcclusionVentResult(Human speaker, Human listener) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) if (!VentRegistry.TryGetVents(((Actor)speaker).currentRoom, out var vents) || vents.Count <= 0) { return OcclusionResult.CreateFullOcclusion(); } VentRegistry.CacheNearbyVentCoordinates(Player.Instance.currentDuctSection); int num = 0; Vector3 val = Vector3.zero; foreach (VentTagCache item in vents) { if (VentRegistry.IsVentNearby(item)) { num++; val += item.AudioPosition; } } if (num <= 0) { return OcclusionResult.CreateFullOcclusion(); } Vector3 val2 = val / (float)num; Vector3 val3 = val2 - ((Actor)listener).aimTransform.position; float num2 = Vector3.Distance(((Actor)speaker).aimTransform.position, val2); Vector3 position = val2 + ((Vector3)(ref val3)).normalized * num2; OcclusionResult result = default(OcclusionResult); result.State = OcclusionState.MuffleVent; result.AlternativePosition = true; result.Position = position; return result; } public static void CachePlayerBounds() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Vector3Int currentNodeCoord = ((Actor)Player.Instance).currentNodeCoord; int value = BabblerConfig.OcclusionNodeRange.Value; _occlusionBoundsMin = currentNodeCoord - new Vector3Int(value, value, value); _occlusionBoundsMax = currentNodeCoord + new Vector3Int(value, value, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsHumanInOcclusionBounds(Human speaker) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) Vector3Int currentNodeCoord = ((Actor)speaker).currentNodeCoord; int result; if (((Vector3Int)(ref currentNodeCoord)).x >= ((Vector3Int)(ref _occlusionBoundsMin)).x) { currentNodeCoord = ((Actor)speaker).currentNodeCoord; if (((Vector3Int)(ref currentNodeCoord)).x <= ((Vector3Int)(ref _occlusionBoundsMax)).x) { currentNodeCoord = ((Actor)speaker).currentNodeCoord; if (((Vector3Int)(ref currentNodeCoord)).y >= ((Vector3Int)(ref _occlusionBoundsMin)).y) { currentNodeCoord = ((Actor)speaker).currentNodeCoord; if (((Vector3Int)(ref currentNodeCoord)).y <= ((Vector3Int)(ref _occlusionBoundsMax)).y) { currentNodeCoord = ((Actor)speaker).currentNodeCoord; if (((Vector3Int)(ref currentNodeCoord)).z >= ((Vector3Int)(ref _occlusionBoundsMin)).z) { currentNodeCoord = ((Actor)speaker).currentNodeCoord; result = ((((Vector3Int)(ref currentNodeCoord)).z <= ((Vector3Int)(ref _occlusionBoundsMax)).z) ? 1 : 0); goto IL_00a6; } } } } } result = 0; goto IL_00a6; IL_00a6: return (byte)result != 0; } } public struct OcclusionResult { public OcclusionState State; public bool AlternativePosition; public Vector3 Position; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OcclusionResult CreateFullOcclusion() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) OcclusionResult result = default(OcclusionResult); result.State = OcclusionState.FullOcclusion; result.AlternativePosition = false; result.Position = Vector3.zero; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OcclusionResult CreateNoOcclusion() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) OcclusionResult result = default(OcclusionResult); result.State = OcclusionState.NoOcclusion; result.AlternativePosition = false; result.Position = Vector3.zero; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OcclusionResult CreateDistantOcclusion() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) OcclusionResult result = default(OcclusionResult); result.State = OcclusionState.DistantOcclusion; result.AlternativePosition = false; result.Position = Vector3.zero; return result; } } public enum OcclusionState { NoOcclusion, MuffleOpenDoor, MuffleClosedDoor, MuffleVent, DistantOcclusion, FullOcclusion } } namespace Babbler.Implementation.Occlusion.Vents { public static class VentRegistry { private const int REGISTRATION_BATCH_COUNT = 5; private static bool _occlusionEnabled; private static readonly Queue<VentTagCache> _unregisteredTags = new Queue<VentTagCache>(); private static readonly Dictionary<int, List<VentTagCache>> _registeredTags = new Dictionary<int, List<VentTagCache>>(); private static readonly List<int> _registeredRooms = new List<int>(); private static readonly List<List<VentTagCache>> _registrationPool = new List<List<VentTagCache>>(); private static readonly HashSet<Vector3Int> _nearbyVentCoordinates = new HashSet<Vector3Int>(); private static Vector3Int _lastNearbyCheck = Vector3Int.zero; private static readonly DuctExplorer _explorer = new DuctExplorer(); public static void Initialize() { _occlusionEnabled = BabblerConfig.OcclusionEnabled.Value; if (_occlusionEnabled) { InteriorControls.Instance.ductStraightWithPeekVent.AddComponent<VentTagPeekable>(); PrefabControls.Instance.airVent.prefab.AddComponent<VentTagInteractable>(); Lib.SaveGame.OnBeforeLoad -= OnBeforeEnterGame; Lib.SaveGame.OnBeforeLoad += OnBeforeEnterGame; Lib.SaveGame.OnBeforeNewGame -= OnBeforeEnterGame; Lib.SaveGame.OnBeforeNewGame += OnBeforeEnterGame; } } public static void Uninitialize() { if (_occlusionEnabled) { Lib.SaveGame.OnBeforeLoad -= OnBeforeEnterGame; Lib.SaveGame.OnBeforeNewGame -= OnBeforeEnterGame; } } private static void OnBeforeEnterGame(object sender, EventArgs eventArgs) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) ClearRegistrations(); _unregisteredTags.Clear(); _nearbyVentCoordinates.Clear(); _lastNearbyCheck = Vector3Int.zero; } public static void Tick() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!_occlusionEnabled || (Object)(object)PathFinder.Instance == (Object)null) { return; } int num = 5; NewNode val = default(NewNode); while (_unregisteredTags.Count > 0 && num > 0) { VentTagCache tag = _unregisteredTags.Dequeue(); if (PathFinder.Instance.nodeMap.TryGetValue(Vector3Int.op_Implicit(CityData.Instance.RealPosToNodeInt(tag.TransformPosition)), ref val) && (Object)(object)((val != null) ? val.room : null) != (Object)null) { tag.Node = val; tag.Room = val.room; RegisterVent(tag.Room.roomID, tag); } num--; } } public static bool TryGetVents(NewRoom room, out List<VentTagCache> vents) { return _registeredTags.TryGetValue(room.roomID, out vents); } public static void CacheNearbyVentCoordinates(AirDuctSection playerDuct) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) NewNode val = ((playerDuct != null) ? playerDuct.node : null); if (val == null) { return; } Vector3Int nodeCoord = val.nodeCoord; if (nodeCoord == _lastNearbyCheck) { return; } _lastNearbyCheck = nodeCoord; _explorer.Reset(); _explorer.StartExploration(playerDuct); _nearbyVentCoordinates.Clear(); int i = 0; for (int value = BabblerConfig.OcclusionVentRange.Value; i < value; i++) { List<Vector3Int> list = _explorer.TickExploration(playerDuct); foreach (Vector3Int item in list) { _nearbyVentCoordinates.Add(item); } } } public static bool IsVentNearby(VentTagCache tag) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return _nearbyVentCoordinates.Contains(tag.Node.nodeCoord); } public static void QueueVentTagRegistration(VentTagCache tag) { _unregisteredTags.Enqueue(tag); } private static void RegisterVent(int roomId, VentTagCache tag) { if (!_registeredTags.TryGetValue(roomId, out var value)) { value = GetPooledList(); value.Add(tag); _registeredTags.Add(roomId, value); _registeredRooms.Add(roomId); } else { value.Add(tag); } } private static void ClearRegistrations() { for (int num = _registeredRooms.Count - 1; num >= 0; num--) { int key = _registeredRooms[num]; ReturnPooledList(_registeredTags[key]); _registeredTags.Remove(key); _registeredRooms.RemoveAt(num); } } private static List<VentTagCache> GetPooledList() { List<VentTagCache> result; if (_registrationPool.Count > 0) { int index = _registrationPool.Count - 1; result = _registrationPool[index]; _registrationPool.RemoveAt(index); } else { result = new List<VentTagCache>(); } return result; } private static void ReturnPooledList(List<VentTagCache> list) { list.Clear(); _registrationPool.Add(list); } } public struct VentTagCache { public Vector3 TransformPosition; public Vector3 CenterPosition; public Vector3 AudioPosition; public NewNode Node; public NewRoom Room; } public class VentTagInteractable : MonoBehaviour { private void Start() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)this).transform; Vector3 position = transform.position; Vector3 centerPosition = position; Vector3 audioPosition = position + transform.forward * 0.425f - transform.up * 0.375f; VentTagCache tag = default(VentTagCache); tag.TransformPosition = position; tag.CenterPosition = centerPosition; tag.AudioPosition = audioPosition; VentRegistry.QueueVentTagRegistration(tag); } } public class VentTagPeekable : MonoBehaviour { private void OnDestroy() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)this).transform; Vector3 position = transform.position; Vector3 val = position + transform.forward * 0.425f; Vector3 audioPosition = val - transform.up * 0.375f; VentTagCache tag = default(VentTagCache); tag.TransformPosition = position; tag.CenterPosition = val; tag.AudioPosition = audioPosition; VentRegistry.QueueVentTagRegistration(tag); } } } namespace Babbler.Implementation.Occlusion.Vents.Explorer { public class DuctExplorer { private readonly Queue<AirDuctSection> _queue = new Queue<AirDuctSection>(); private readonly HashSet<Vector3Int> _visited = new HashSet<Vector3Int>(); private readonly List<Vector3Int> _results = new List<Vector3Int>(); private List<AirDuctSection> _neighbors = new List<AirDuctSection>(); private List<Vector3Int> _neighborOffsets = new List<Vector3Int>(); private List<AirVent> _vents = new List<AirVent>(); public void Reset() { _queue.Clear(); _visited.Clear(); _results.Clear(); _neighbors.Clear(); _vents.Clear(); } public void StartExploration(AirDuctSection startSection) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) _queue.Enqueue(startSection); _visited.Add(startSection.duct); } public List<Vector3Int> TickExploration(AirDuctSection duct) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Invalid comparison between Unknown and I4 //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) _results.Clear(); if (_queue.Count <= 0) { return _results; } int count = _queue.Count; for (int i = 0; i < count; i++) { AirDuctSection val = _queue.Dequeue(); GetVentInformation(val, ref _neighbors, ref _neighborOffsets, ref _vents); for (int j = 0; j < _neighbors.Count; j++) { AirDuctSection val2 = _neighbors[j]; if (!_visited.Contains(val2.duct)) { _queue.Enqueue(val2); _visited.Add(val2.duct); } } bool flag = false; foreach (AirVent vent in _vents) { if ((int)vent.ventType == 0) { _results.Add(val.node.nodeCoord); flag = true; } else { _results.Add(vent.roomNode.nodeCoord); } } if (val.peekSection && !flag) { _results.Add(val.node.nodeCoord); } } return _results; } private void GetVentInformation(AirDuctSection thisDuct, ref List<AirDuctSection> neighbors, ref List<Vector3Int> neighborOffsets, ref List<AirVent> vents) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Invalid comparison between Unknown and I4 //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Invalid comparison between Unknown and I4 neighbors.Clear(); neighborOffsets.Clear(); vents.Clear(); AirDuctSection val2 = default(AirDuctSection); foreach (Vector3Int item in (Il2CppArrayBase<Vector3Int>)(object)CityData.Instance.offsetArrayX6) { Vector3Int val = thisDuct.duct + item; if (thisDuct.node.building.ductMap.TryGetValue(val, ref val2) && (item == thisDuct.next || item == thisDuct.previous || val2.next == -item || val2.previous == -item) && !neighbors.Contains(val2)) { neighbors.Add(val2); neighborOffsets.Add(item); } } if (thisDuct.level == 2) { AirVent val3 = FindCeilingVent(thisDuct.node); if (val3 != null && !vents.Contains(val3)) { vents.Add(val3); } return; } Vector3Int val4 = default(Vector3Int); NewNode foundNode = default(NewNode); foreach (Vector2Int item2 in (Il2CppArrayBase<Vector2Int>)(object)CityData.Instance.offsetArrayX4) { Vector2Int current2 = item2; ((Vector3Int)(ref val4))..ctor(((Vector2Int)(ref current2)).x, ((Vector2Int)(ref current2)).y, 0); Vector3Int val5 = thisDuct.node.nodeCoord + val4; if (!PathFinder.Instance.nodeMap.TryGetValue(Vector3Int.op_Implicit(val5), ref foundNode)) { continue; } AirVent val6 = FindWallVent(foundNode, thisDuct.node); if (val6 == null) { continue; } if ((int)val6.ventType == 1 && thisDuct.level == 1) { if (!vents.Contains(val6)) { vents.Add(val6); } } else if ((int)val6.ventType == 2 && thisDuct.level == 0 && !vents.Contains(val6)) { vents.Add(val6); } } } private AirVent FindCeilingVent(NewNode ductNode) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 Enumerator<AirVent> enumerator = ductNode.room.airVents.GetEnumerator(); while (enumerator.MoveNext()) { AirVent current = enumerator.Current; if (current.node.nodeCoord == ductNode.nodeCoord && (int)current.ventType == 0) { return current; } } return null; } private AirVent FindWallVent(NewNode foundNode, NewNode ductNode) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Enumerator<AirVent> enumerator = foundNode.room.airVents.GetEnumerator(); while (enumerator.MoveNext()) { AirVent current = enumerator.Current; if (current.node.nodeCoord == ductNode.nodeCoord && current.roomNode.nodeCoord == foundNode.nodeCoord) { return current; } } return null; } } } namespace Babbler.Implementation.Hosts { public class SpeakerHost : MonoBehaviour { public SpeakerHostPool Pool; public BaseSpeaker Speaker; private bool _initialized; private void OnDestroy() { Uninitialize(); } public void Initialize() { if (_initialized) { return; } _initialized = true; if (Pool.SpeakerType == SpeakerType.Speech) { switch (Pool.SpeechMode) { case SpeechMode.Synthesis: Speaker = new SynthesisSpeaker(); break; case SpeechMode.Phonetic: Speaker = new PhoneticSpeaker(); break; case SpeechMode.Droning: Speaker = new DroningSpeaker(); break; default: Speaker = new PhoneticSpeaker(); break; } } else { Speaker = new EmoteSpeaker(); } BaseSpeaker speaker = Speaker; speaker.OnFinishedSpeaking = (Action)Delegate.Remove(speaker.OnFinishedSpeaking, new Action(OnFinishedSpeaking)); BaseSpeaker speaker2 = Speaker; speaker2.OnFinishedSpeaking = (Action)Delegate.Combine(speaker2.OnFinishedSpeaking, new Action(OnFinishedSpeaking)); Speaker.InitializeSpeaker(); } private void Uninitialize() { if (_initialized) { BaseSpeaker speaker = Speaker; speaker.OnFinishedSpeaking = (Action)Delegate.Remove(speaker.OnFinishedSpeaking, new Action(OnFinishedSpeaking)); Speaker.UninitializeSpeaker(); _initialized = false; } } private void OnEnable() { if (Speaker != null) { Speaker.StopSpeaker(); } } private void OnDisable() { if (Speaker != null) { Speaker.StopSpeaker(); } } private void Update() { Speaker.UpdateSpeaker(); } private void OnFinishedSpeaking() { Pool.ReleaseSpeakerHost(this); } } public class SpeakerHostPool { public static SpeakerHostPool Speech; public static SpeakerHostPool Emotes; private List<SpeakerHost> AvailableHosts = new List<SpeakerHost>(); private List<SpeakerHost> AllHosts = new List<SpeakerHost>(); public SpeakerType SpeakerType { get; private set; } public SpeechMode SpeechMode { get; private set; } public static void InitializePools() { Speech = new SpeakerHostPool(SpeakerType.Speech, BabblerConfig.Mode.Value); Emotes = new SpeakerHostPool(SpeakerType.Emote, SpeechMode.Phonetic); } public static void UninitializePools() { Speech.CleanupSpeakerHosts(); Emotes.CleanupSpeakerHosts(); } private SpeakerHostPool(SpeakerType speakerType, SpeechMode speechMode) { SpeakerType = speakerType; SpeechMode = speechMode; } public void Play(string speechInput, SoundContext soundContext, Human speechPerson, float delay = 0f) { SpeakerHost speakerHost = GetSpeakerHost(); if (delay > 0f && speakerHost.Speaker is IDelayableSpeaker delayableSpeaker) { delayableSpeaker.InitializeDelay(delay); } speakerHost.Speaker.StartSpeaker(speechInput, soundContext, speechPerson); } private SpeakerHost GetSpeakerHost() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) int num = AvailableHosts.Count - 1; SpeakerHost speakerHost; if (num >= 0) { speakerHost = AvailableHosts[num]; AvailableHosts.RemoveAt(num); ((Component)speakerHost).gameObject.SetActive(true); } else { GameObject val = new GameObject("BabblerSpeakerHost"); val.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); speakerHost = val.AddComponent<SpeakerHost>(); Object.DontDestroyOnLoad((Object)(object)val); AllHosts.Add(speakerHost); speakerHost.Pool = this; speakerHost.Initialize(); Log($"Created speaker host, current count is {AllHosts.Count}."); } return speakerHost; } public void ReleaseSpeakerHost(SpeakerHost speakerHost) { ((Component)speakerHost).gameObject.SetActive(false); AvailableHosts.Add(speakerHost); } private void CleanupSpeakerHosts() { for (int num = AllHosts.Count - 1; num >= 0; num--) { SpeakerHost speakerHost = AllHosts[num]; if (((Component)speakerHost).gameObject.activeSelf) { ((Component)speakerHost).gameObject.SetActive(false); } Object.DestroyImmediate((Object)(object)((Component)speakerHost).gameObject); } Log("Cleaned up all speaker hosts."); } private void Log(string log) { bool flag = true; } } } namespace Babbler.Implementation.Emotes { public class EmoteSound { public string Key; public string FilePath; public VoiceCategory Category; public float Frequency; public bool CanPitchShift; public Sound Sound; public float Length; public bool Released; } public class EmoteSoundFamily { private readonly List<EmoteSound> _allSounds = new List<EmoteSound>(); private readonly List<EmoteSound> _maleSounds = new List<EmoteSound>(); private readonly List<EmoteSound> _femaleSounds = new List<EmoteSound>(); private readonly List<EmoteSound> _nonBinarySounds = new List<EmoteSound>(); private static readonly List<EmoteSound>[] EmotePriorities = new List<EmoteSound>[4]; public string Key { get; private set; } public bool HasMaleEmotes => _maleSounds.Count > 0; public bool HasFemaleEmotes => _femaleSounds.Count > 0; public bool HasNonBinaryEmotes => _nonBinarySounds.Count > 0; public void Initialize(string directory) { _allSounds.Clear(); _maleSounds.Clear(); _femaleSounds.Clear(); _nonBinarySounds.Clear(); if (!Directory.Exists(directory)) { return; } Key = Path.GetFileNameWithoutExtension(directory).ToLowerInvariant(); string[] files = Directory.GetFiles(directory, "*.wav"); foreach (string filePath in files) { EmoteSound emoteSound = CreateEmoteSound(filePath, Key); if (emoteSound != null) { switch (emoteSound.Category) { case VoiceCategory.Male: _maleSounds.Add(emoteSound); break; case VoiceCategory.Female: _femaleSounds.Add(emoteSound); break; default: _nonBinarySounds.Add(emoteSound); break; } _allSounds.Add(emoteSound); } } } public void Uninitialize() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) foreach (EmoteSound allSound in _allSounds) { if (!allSound.Released) { ((Sound)(ref allSound.Sound)).release(); allSound.Released = true; } } } private EmoteSound CreateEmoteSound(string filePath, string key) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (!FMODRegistry.TryCreateSound(filePath, (MODE)16, out var sound)) { return null; } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); string[] array = fileNameWithoutExtension.Split('_'); if (array.Length != 3) { return null; } string text = array[1].ToLowerInvariant(); string s = array[2].ToLowerInvariant(); VoiceCategory category = VoiceCategory.NonBinary; bool canPitchShift = true; string text2 = text; string text3 = text2; if (!(text3 == "male")) { if (text3 == "female") { category = VoiceCategory.Female; } } else { category = VoiceCategory.Male; } if (!float.TryParse(s, out var result)) { result = 178f; canPitchShift = false; } uint num = default(uint); ((Sound)(ref sound)).getLength(ref num, (TIMEUNIT)1); float length = (float)num / 1000f; return new EmoteSound { Key = key, Category = category, Frequency = result, CanPitchShift = canPitchShift, FilePath = filePath, Sound = sound, Length = length, Released = false }; } public EmoteSound GetRandomSound(VoiceCharacteristics characteristics) { return characteristics.SelectRandomGenderedListElement(EmotePriorities, _allSounds, _maleSounds, _femaleSounds, _nonBinarySounds); } } public static class EmoteSoundRegistry { private static readonly Dictionary<string, EmoteSoundFamily> Groups = new Dictionary<string, EmoteSoundFamily>(); public static void Initialize() { Groups.Clear(); if (BabblerConfig.EmotesEnabled.Value) { string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException(), "Emotes", BabblerConfig.EmotesTheme.Value); if (Directory.Exists(path)) { string[] directories = Directory.GetDirectories(path); foreach (string directory in directories) { EmoteSoundFamily emoteSoundFamily = new EmoteSoundFamily(); emoteSoundFamily.Initialize(directory); Groups.Add(emoteSoundFamily.Key, emoteSoundFamily); } } } Utilities.Log($"EmoteSoundRegistry has initialized! Sounds: {Groups.Count}", (LogLevel)32); } public static void Uninitialize() { foreach (EmoteSoundFamily value in Groups.Values) { value.Uninitialize(); } } public static bool HasEmote(string key) { return Groups.ContainsKey(key); } public static bool TryGetEmote(string key, Human human, out VoiceCharacteristics characteristics, out EmoteSound sound) { if (!Groups.TryGetValue(key, out var value)) { characteristics = default(VoiceCharacteristics); sound = null; return false; } characteristics = VoiceCharacteristics.Create(human, value.HasMaleEmotes, value.HasFemaleEmotes, value.HasNonBinaryEmotes); sound = value.GetRandomSound(characteristics); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsEmoteRelevantBroadphase(Human human) { if (!BabblerConfig.EmotesEnabled.Value) { return false; } return OcclusionChecker.CheckOcclusion(human, (Human)(object)Player.Instance, SoundContext.OverheardEmote).State != OcclusionState.FullOcclusion; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool CanPlayIncidentals(Human human, bool mouthVocalization) { if (!BabblerConfig.IncidentalsEnabled.Value) { return false; } if (mouthVocalization && ((Actor)human).isSpeaking) { return false; } return !((Actor)human).isPlayer && !((Actor)human).isAsleep && !((Actor)human).isDead && !((Actor)human).isStunned; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ShouldPlayUncouthEmote(Human human, float minThreshold, float maxThreshold) { float num = human.conscientiousness; float drunk = human.drunk; if (((Actor)human).isHome) { num /= 2f; } float num2 = 1f - Mathf.Min(num, 1f - drunk); float num3 = Mathf.Lerp(minThreshold, maxThreshold, num2); return Utilities.GlobalRandom.NextSingle() <= num3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ShouldPlayExpressiveEmote(Human human, float minThreshold, float maxThreshold) { float num = (human.extraversion + human.creativity) / 2f; float num2 = Mathf.Lerp(minThreshold, maxThreshold, num); return Utilities.GlobalRandom.NextSingle() <= num2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ShouldPlayExtravertedEmote(Human human, float minThreshold, float maxThreshold) { float num = Mathf.Lerp(minThreshold, maxThreshold, human.extraversion); return Utilities.GlobalRandom.NextSingle() <= num; } } public static class TVWatcher { private static AIActionPreset _turnOnTVPreset; public static void Initialize() { if (BabblerConfig.IncidentalsEnabled.Value) { Lib.Time.OnMinuteChanged -= Tick; Lib.Time.OnMinuteChanged += Tick; } } public static void Uninitialize() { if (BabblerConfig.IncidentalsEnabled.Value) { Lib.Time.OnMinuteChanged -= Tick; } } private static void Tick(object sender, TimeChangedArgs args) { if (Utilities.IsHumanOutside((Human)(object)Player.Instance)) { return; } NewBuilding currentBuilding = ((Actor)Player.Instance).currentBuilding; if ((Object)(object)currentBuilding == (Object)null) { return; } NewRoom currentRoom = ((Actor)Player.Instance).currentRoom; if ((Object)(object)currentRoom == (Object)null) { return; } int floor = currentRoom.floor.floor; NewFloor val = default(NewFloor); for (int i = floor - 3; i <= floor + 3; i++) { if (!currentBuilding.floors.TryGetValue(i, ref val)) { continue; } Enumerator<NewAddress> enumerator = val.addresses.GetEnumerator(); while (enumerator.MoveNext()) { NewAddress current = enumerator.Current; Enumerator<Actor> enumerator2 = ((NewGameLocation)current).currentOccupants.GetEnumerator(); while (enumerator2.MoveNext()) { Actor current2 = enumerator2.Current; TickOccupant((Human)(object)((current2 is Human) ? current2 : null)); } } } } private static void TickOccupant(Human occupant) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 if (!((Object)(object)occupant == (Object)null) && !((Actor)occupant).isPlayer && ((Actor)occupant).isHome && (int)((Actor)occupant).animationController.idleAnimationState == 1 && EmoteSoundRegistry.CanPlayIncidentals(occupant, mouthVocalization: true) && IsTelevisionOn(((Actor)occupant).currentRoom) && EmoteSoundRegistry.IsEmoteRelevantBroadphase(occupant) && EmoteSoundRegistry.ShouldPlayExtravertedEmote(occupant, BabblerConfig.IncidentalsMinTVChance.Value, BabblerConfig.IncidentalsMaxTVChance.Value)) { switch (Utilities.GlobalRandom.Next(0, 2)) { case 0: SpeakerHostPool.Emotes.Play("chuckle", SoundContext.OverheardEmote, occupant); break; case 1: SpeakerHostPool.Emotes.Play("gasp", SoundContext.OverheardEmote, occupant); break; } } } private static bool IsTelevisionOn(NewRoom room) { if ((SoCustomComparison)(object)_turnOnTVPreset == (SoCustomComparison)null) { Enumerator<AIActionPreset, List<Interactable>> enumerator = room.actionReference.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair<AIActionPreset, List<Interactable>> current = enumerator.Current; if (((SoCustomComparison)current.Key).presetName != "TurnOnTV") { continue; } _turnOnTVPreset = current.Key; break; } if ((SoCustomComparison)(object)_turnOnTVPreset == (SoCustomComparison)null) { return false; } } List<Interactable> val = default(List<Interactable>); if (!room.actionReference.TryGetValue(_turnOnTVPreset, ref val)) { return false; } Enumerator<Interactable> enumerator2 = val.GetEnumerator(); while (enumerator2.MoveNext()) { Interactable current2 = enumerator2.Current; if (current2.sw0) { return true; } } return false; } } } namespace Babbler.Implementation.Config { public static class BabblerConfig { public static ConfigEntry<string> DroningValidPhonemes; public static ConfigEntry<float> DroningSpeechDelay; public static ConfigEntry<float> DroningChanceDelayVariance; public static ConfigEntry<float> DroningMinDelayVariance; public static ConfigEntry<float> DroningMaxDelayVariance; public static ConfigEntry<float> DroningChancePitchVariance; public static ConfigEntry<float> DroningMinPitchVariance; public static ConfigEntry<float> DroningMaxPitchVariance; public static ConfigEntry<float> DroningMinFrequencyMale; public static ConfigEntry<float> DroningMaxFrequencyMale; public static ConfigEntry<float> DroningMinFrequencyFemale; public static ConfigEntry<float> DroningMaxFrequencyFemale; public static ConfigEntry<float> DroningMinFrequencyNonBinary; public static ConfigEntry<float> DroningMaxFrequencyNonBinary; public static ConfigEntry<bool> EmotesEnabled; public static ConfigEntry<string> EmotesTheme; public static ConfigEntry<float> EmotesMinStagger; public static ConfigEntry<float> EmotesMaxStagger; public static ConfigEntry<bool> EmotesUsePitchShifts; public static ConfigEntry<float> EmotesMinFrequencyMale; public static ConfigEntry<float> EmotesMaxFrequencyMale; public static ConfigEntry<float> EmotesMinFrequencyFemale; public static ConfigEntry<float> EmotesMaxFrequencyFemale; public static ConfigEntry<float> EmotesMinFrequencyNonBinary; public static ConfigEntry<float> EmotesMaxFrequencyNonBinary; private const string ExpectedVersion = "c30388124ff54e8b8c917064b221c11d"; public static ConfigEntry<string> Version; public static ConfigEntry<bool> Enabled; public static ConfigEntry<SpeechMode> Mode; public static ConfigEntry<ConfigTemplate> Template; public static ConfigEntry<bool> DistortPhoneSpeech; public static ConfigEntry<float> FemaleThreshold; public static ConfigEntry<float> MaleThreshold; public static ConfigEntry<float> GenderDiversity; public static ConfigEntry<bool> IncidentalsEnabled; public static ConfigEntry<float> IncidentalsRange; public static ConfigEntry<float> IncidentalsMinDrunkForHiccups; public static ConfigEntry<float> IncidentalsMinBurpChance; public static ConfigEntry<float> IncidentalsMaxBurpChance; public static ConfigEntry<float> IncidentalsMinFartChance; public static ConfigEntry<float> IncidentalsMaxFartChance; public static ConfigEntry<float> IncidentalsMinHiccupChance; public static ConfigEntry<float> IncidentalsMaxHiccupChance; public static ConfigEntry<float> IncidentalsMinWhistleChance; public static ConfigEntry<float> IncidentalsMaxWhistleChance; public static ConfigEntry<float> IncidentalsMinTVChance; public static ConfigEntry<float> IncidentalsMaxTVChance; public static ConfigEntry<float> PhoneticSpeechDelay; public static ConfigEntry<float> PhoneticChanceDelayVariance; public static ConfigEntry<float> PhoneticMinDelayVariance; public static ConfigEntry<float> PhoneticMaxDelayVariance; public static ConfigEntry<float> PhoneticChancePitchVariance; public static ConfigEntry<float> PhoneticMinPitchVariance; public static ConfigEntry<float> PhoneticMaxPitchVariance; public static ConfigEntry<float> PhoneticMinFrequencyMale; public static ConfigEntry<float> PhoneticMaxFrequencyMale; public static ConfigEntry<float> PhoneticMinFrequencyFemale; public static ConfigEntry<float> PhoneticMaxFrequencyFemale; public static ConfigEntry<float> PhoneticMinFrequencyNonBinary; public static ConfigEntry<float> PhoneticMaxFrequencyNonBinary; public static ConfigEntry<SynthesisVoiceFilterType> SynthesisVoiceFilter; public static ConfigEntry<string> SynthesisVoiceFilterInput; public static ConfigEntry<int> SynthesisMinSpeed; public static ConfigEntry<int> SynthesisMaxSpeed; public static ConfigEntry<float> SynthesisMinPitchMale; public static ConfigEntry<float> SynthesisMaxPitchMale; public static ConfigEntry<float> SynthesisMinPitchFemale; public static ConfigEntry<float> SynthesisMaxPitchFemale; public static ConfigEntry<float> SynthesisMinPitchNonBinary; public static ConfigEntry<float> SynthesisMaxPitchNonBinary; public static ConfigEntry<float> ConversationalVolume; public static ConfigEntry<float> ConversationalShoutVolume; public static ConfigEntry<float> ConversationalEmoteVolume; public static ConfigEntry<float> OverheardVolume; public static ConfigEntry<float> OverheardShoutVolume; public static ConfigEntry<float> OverheardEmoteVolume; public static ConfigEntry<float> PhoneVolume; public static ConfigEntry<float> PhoneShoutVolume; public static ConfigEntry<float> PhoneEmoteVolume; public static ConfigEntry<float> OpenDoorOcclusionMultiplier; public static ConfigEntry<float> ClosedDoorOcclusionMultiplier; public static ConfigEntry<float> VentOcclusionMultiplier; public static ConfigEntry<float> DistantOcclusionMultiplier; public static ConfigEntry<bool> OcclusionEnabled; public static ConfigEntry<int> OcclusionNodeRange; public static ConfigEntry<int> OcclusionVentRange; private static void InitializeDroning(ConfigFile config) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Expected O, but got Unknown //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown DroningValidPhonemes = config.Bind<string>("6. Droning", "Valid Phonemes", "aeiouybdglmptvw", new ConfigDescription("Citizens pick one phoneme to repeat, that is chosen from these phonemes.", (AcceptableValueBase)null, Array.Empty<object>())); DroningSpeechDelay = config.Bind<float>("6. Droning", "Speech Delay", -0.175f, new ConfigDescription("The delay of each phoneme is its length plus this. Negative numbers cause overlapping phonemes.", (AcceptableValueBase)null, Array.Empty<object>())); DroningChanceDelayVariance = config.Bind<float>("6. Droning", "Chance Delay Variance", 0.4f, new ConfigDescription("This is the chance for any citizen to speak with variations in their phoneme delay.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); DroningMinDelayVariance = config.Bind<float>("6. Droning", "Min Delay Variance", 0f, new ConfigDescription("A value between the min and max delay variance is chosen to add to the speech delay to create variations in it.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMaxDelayVariance = config.Bind<float>("6. Droning", "Max Delay Variance", 0.3f, new ConfigDescription("A value between the min and max delay variance is chosen to add to the speech delay to create variations in it.", (AcceptableValueBase)null, Array.Empty<object>())); DroningChancePitchVariance = config.Bind<float>("6. Droning", "Chance Pitch Variance", 0.2f, new ConfigDescription("This is the chance for any citizen to speak with variations in their phoneme pitch.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); DroningMinPitchVariance = config.Bind<float>("6. Droning", "Min Pitch Variance", 0.8f, new ConfigDescription("A value between the min and max pitch variance is chosen to multiply with the phoneme pitch to create variations of it.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMaxPitchVariance = config.Bind<float>("6. Droning", "Max Pitch Variance", 1.2f, new ConfigDescription("A value between the min and max pitch variance is chosen to multiply with the phoneme pitch to create variations of it.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMinFrequencyMale = config.Bind<float>("6. Droning", "Min Frequency Male", 100f, new ConfigDescription("Lowest possible frequency (in hertz) for male voices.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMaxFrequencyMale = config.Bind<float>("6. Droning", "Max Frequency Male", 180f, new ConfigDescription("Highest possible frequency (in hertz) for male voices.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMinFrequencyFemale = config.Bind<float>("6. Droning", "Min Frequency Female", 165f, new ConfigDescription("Lowest possible frequency (in hertz) for female voices.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMaxFrequencyFemale = config.Bind<float>("6. Droning", "Max Frequency Female", 255f, new ConfigDescription("Highest possible frequency (in hertz) for female voices.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMinFrequencyNonBinary = config.Bind<float>("6. Droning", "Min Frequency Non-Binary", 100f, new ConfigDescription("Lowest possible frequency (in hertz) for non-binary voices.", (AcceptableValueBase)null, Array.Empty<object>())); DroningMaxFrequencyNonBinary = config.Bind<float>("6. Droning", "Max Frequency Non-Binary", 255f, new ConfigDescription("Highest possible frequency (in hertz) for non-binary voices.", (AcceptableValueBase)null, Array.Empty<object>())); Utilities.EnforceMinMax(ref DroningMinDelayVariance, ref DroningMaxDelayVariance); Utilities.EnforceMinMax(ref DroningMinPitchVariance, ref DroningMaxPitchVariance); Utilities.EnforceMinMax(ref DroningMinFrequencyMale, ref DroningMaxFrequencyMale); Utilities.EnforceMinMax(ref DroningMinFrequencyFemale, ref DroningMaxFrequencyFemale); Utilities.EnforceMinMax(ref DroningMinFrequencyNonBinary, ref DroningMaxFrequencyNonBinary); } private static void ResetDroning() { DroningValidPhonemes.Value = (string)((ConfigEntryBase)DroningValidPhonemes).DefaultValue; DroningSpeechDelay.Value = (float)((ConfigEntryBase)DroningSpeechDelay).DefaultValue; DroningChanceDelayVariance.Value = (float)((ConfigEntryBase)DroningChanceDelayVariance).DefaultValue; DroningMinDelayVariance.Value = (float)((ConfigEntryBase)DroningMinDelayVariance).DefaultValue; DroningMaxDelayVariance.Value = (float)((ConfigEntryBase)DroningMaxDelayVariance).DefaultValue; DroningChancePitchVariance.Value = (float)((ConfigEntryBase)DroningChancePitchVariance).DefaultValue; DroningMinPitchVariance.Value = (float)((ConfigEntryBase)DroningMinPitchVariance).DefaultValue; DroningMaxPitchVariance.Value = (float)((ConfigEntryBase)DroningMaxPitchVariance).DefaultValue; DroningMinFrequencyMale.Value = (float)((ConfigEntryBase)DroningMinFrequencyMale).DefaultValue; DroningMaxFrequencyMale.Value = (float)((ConfigEntryBase)DroningMaxFrequencyMale).DefaultValue; DroningMinFrequencyFemale.Value = (float)((ConfigEntryBase)DroningMinFrequencyFemale).DefaultValue; DroningMaxFrequencyFemale.Value = (float)((ConfigEntryBase)DroningMaxFrequencyFemale).DefaultValue; DroningMinFrequencyNonBinary.Value = (float)((ConfigEntryBase)DroningMinFrequencyNonBinary).DefaultValue; DroningMaxFrequencyNonBinary.Value = (float)((ConfigEntryBase)DroningMaxFrequencyNonBinary).DefaultValue; } private static void InitializeEmotes(ConfigFile config) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown EmotesEnabled = config.Bind<bool>("7. Emotes", "Enabled", true, new ConfigDescription("Whether emote sound effects (like sneezing, sighing, or coughing) are enabled.", (AcceptableValueBase)null, Array.Empty<object>())); EmotesTheme = config.Bind<string>("7. Emotes", "Theme", "Realistic", new ConfigDescription("Which theme to load and play for emote sound effects. Babbler comes with \"Realistic\" and \"Abstract\" but you can