Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DIO OH v1.0.2
plugins/DIOOH.dll
Decompiled a day 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DIOOH.Modules; using DIOOH.Modules.Characters; using DIOOH.Survivors.DIO; using DIOOH.Survivors.DIO.Components; using DIOOH.Survivors.DIO.SkillStates; using EntityStates; using EntityStates.AI.Walker; using EntityStates.ClayBruiser.Weapon; using EntityStates.GolemMonster; using EntityStates.GreaterWispMonster; using EntityStates.TitanMonster; using EntityStates.Wisp1Monster; using HG; using HG.BlendableTypes; using NAudio.Wave; using On.EntityStates.ClayBruiser.Weapon; using On.EntityStates.GolemMonster; using On.EntityStates.GreaterWispMonster; using On.EntityStates.TitanMonster; using On.EntityStates.Wisp1Monster; using On.RoR2; using On.RoR2.Orbs; using On.RoR2.Projectile; using R2API; using R2API.Utils; using RoR2; using RoR2.Achievements; using RoR2.Audio; using RoR2.CharacterAI; using RoR2.ContentManagement; using RoR2.Orbs; using RoR2.Projectile; using RoR2.Skills; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.Rendering.PostProcessing; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DIOOH")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DIOOH")] [assembly: AssemblyTitle("DIOOH")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace DIOOH { [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.ES15.DIOOH", "DIOOH", "1.0.2")] public class DIOOHPlugin : BaseUnityPlugin { public const string MODUID = "com.ES15.DIOOH"; public const string MODNAME = "DIOOH"; public const string MODVERSION = "1.0.2"; public const string DEVELOPER_PREFIX = "ES15"; public static DIOOHPlugin instance; private void Awake() { instance = this; Log.Init(((BaseUnityPlugin)this).Logger); Language.Init(); new DIOSurvivor().Initialize(); new ContentPacks().Initialize(); } } internal static class Log { internal static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void ErrorAssetBundle(string assetName, string bundleName) { Error("failed to load asset, " + assetName + ", because it does not exist in asset bundle, " + bundleName); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } } } namespace DIOOH.Modules { internal static class Asset { internal static Dictionary<string, AssetBundle> loadedBundles = new Dictionary<string, AssetBundle>(); internal static AssetBundle LoadAssetBundle(string bundleName) { if (bundleName == "myassetbundle") { Log.Error("AssetBundle name hasn't been changed. not loading any assets to avoid conflicts.\nMake sure to rename your assetbundle filename and rename the AssetBundleName field in your character setup code "); return null; } if (loadedBundles.ContainsKey(bundleName)) { return loadedBundles[bundleName]; } AssetBundle val = null; try { val = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)DIOOHPlugin.instance).Info.Location), "AssetBundles", bundleName)); } catch (Exception arg) { Log.Error($"Error loading asset bundle, {bundleName}. Your asset bundle must be in a folder next to your mod dll called 'AssetBundles'. Follow the guide to build and install your mod correctly!\n{arg}"); } loadedBundles[bundleName] = val; return val; } internal static GameObject CloneTracer(string originalTracerName, string newTracerName) { if ((Object)(object)LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/Tracers/" + originalTracerName) == (Object)null) { return null; } GameObject val = PrefabAPI.InstantiateClone(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/Tracers/" + originalTracerName), newTracerName, true); if (!Object.op_Implicit((Object)(object)val.GetComponent<EffectComponent>())) { val.AddComponent<EffectComponent>(); } if (!Object.op_Implicit((Object)(object)val.GetComponent<VFXAttributes>())) { val.AddComponent<VFXAttributes>(); } if (!Object.op_Implicit((Object)(object)val.GetComponent<NetworkIdentity>())) { val.AddComponent<NetworkIdentity>(); } val.GetComponent<Tracer>().speed = 250f; val.GetComponent<Tracer>().length = 50f; Content.CreateAndAddEffectDef(val); return val; } internal static void ConvertAllRenderersToHopooShader(GameObject objectToConvert) { if (!Object.op_Implicit((Object)(object)objectToConvert)) { return; } MeshRenderer[] componentsInChildren = objectToConvert.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Renderer)val).sharedMaterial)) { ((Renderer)val).sharedMaterial.ConvertDefaultShaderToHopoo(); } } SkinnedMeshRenderer[] componentsInChildren2 = objectToConvert.GetComponentsInChildren<SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)((Renderer)val2).sharedMaterial)) { ((Renderer)val2).sharedMaterial.ConvertDefaultShaderToHopoo(); } } } internal static GameObject LoadCrosshair(string crosshairName) { GameObject val = LegacyResourcesAPI.Load<GameObject>("Prefabs/Crosshair/" + crosshairName + "Crosshair"); if ((Object)(object)val == (Object)null) { Log.Error("could not load crosshair with the name " + crosshairName + ". defaulting to Standard"); return LegacyResourcesAPI.Load<GameObject>("Prefabs/Crosshair/StandardCrosshair"); } return val; } internal static GameObject LoadEffect(this AssetBundle assetBundle, string resourceName, bool parentToTransform) { return assetBundle.LoadEffect(resourceName, "", parentToTransform); } internal static GameObject LoadEffect(this AssetBundle assetBundle, string resourceName, string soundName = "", bool parentToTransform = false) { //IL_003c: 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) GameObject val = assetBundle.LoadAsset<GameObject>(resourceName); if (!Object.op_Implicit((Object)(object)val)) { Log.ErrorAssetBundle(resourceName, ((Object)assetBundle).name); return null; } val.AddComponent<DestroyOnTimer>().duration = 12f; val.AddComponent<NetworkIdentity>(); val.AddComponent<VFXAttributes>().vfxPriority = (VFXPriority)2; EffectComponent obj = val.AddComponent<EffectComponent>(); obj.applyScale = false; obj.effectIndex = (EffectIndex)(-1); obj.parentToReferencedTransform = parentToTransform; obj.positionAtReferencedTransform = true; obj.soundName = soundName; Content.CreateAndAddEffectDef(val); return val; } internal static GameObject CreateProjectileGhostPrefab(this AssetBundle assetBundle, string ghostName) { GameObject val = assetBundle.LoadAsset<GameObject>(ghostName); if ((Object)(object)val == (Object)null) { Log.Error("Failed to load ghost prefab " + ghostName); } if (!Object.op_Implicit((Object)(object)val.GetComponent<NetworkIdentity>())) { val.AddComponent<NetworkIdentity>(); } if (!Object.op_Implicit((Object)(object)val.GetComponent<ProjectileGhostController>())) { val.AddComponent<ProjectileGhostController>(); } ConvertAllRenderersToHopooShader(val); return val; } internal static GameObject CloneProjectilePrefab(string prefabName, string newPrefabName) { return PrefabAPI.InstantiateClone(LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/" + prefabName), newPrefabName); } internal static GameObject LoadAndAddProjectilePrefab(this AssetBundle assetBundle, string newPrefabName) { GameObject val = assetBundle.LoadAsset<GameObject>(newPrefabName); if ((Object)(object)val == (Object)null) { Log.ErrorAssetBundle(newPrefabName, ((Object)assetBundle).name); return null; } Content.AddProjectilePrefab(val); return val; } } public static class Config { public static ConfigFile MyConfig = ((BaseUnityPlugin)DIOOHPlugin.instance).Config; public static ConfigEntry<bool> CharacterEnableConfig(string section, string characterName, string description = "", bool enabledByDefault = true) { if (string.IsNullOrEmpty(description)) { description = "Set to false to disable this character and as much of its code and content as possible"; } return BindAndOptions(section, "Enable " + characterName, enabledByDefault, description, restartRequired: true); } public static ConfigEntry<T> BindAndOptions<T>(string section, string name, T defaultValue, string description = "", bool restartRequired = false) { return BindAndOptions(section, name, defaultValue, 0f, 20f, description, restartRequired); } public static ConfigEntry<T> BindAndOptions<T>(string section, string name, T defaultValue, float min, float max, string description = "", bool restartRequired = false) { if (string.IsNullOrEmpty(description)) { description = name; } if (restartRequired) { description += " (restart required)"; } ConfigEntry<T> result = MyConfig.Bind<T>(section, name, defaultValue, description); Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); return result; } public static ConfigEntry<float> BindAndOptionsSlider(string section, string name, float defaultValue, string description, float min = 0f, float max = 20f, bool restartRequired = false) { return BindAndOptions(section, name, defaultValue, min, max, description, restartRequired); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static void TryRegisterOption<T>(ConfigEntry<T> entry, float min, float max, bool restartRequired) { } public static bool GetKeyPressed(KeyboardShortcut entry) { //IL_0010: 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) foreach (KeyCode modifier in ((KeyboardShortcut)(ref entry)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } return Input.GetKeyDown(((KeyboardShortcut)(ref entry)).MainKey); } } internal class Content { internal static void AddCharacterBodyPrefab(GameObject bprefab) { ContentPacks.bodyPrefabs.Add(bprefab); } internal static void AddMasterPrefab(GameObject prefab) { ContentPacks.masterPrefabs.Add(prefab); } internal static void AddProjectilePrefab(GameObject prefab) { ContentPacks.projectilePrefabs.Add(prefab); } internal static void AddSurvivorDef(SurvivorDef survivorDef) { ContentPacks.survivorDefs.Add(survivorDef); } internal static void CreateSurvivor(GameObject bodyPrefab, GameObject displayPrefab, Color charColor, string tokenPrefix) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) CreateSurvivor(bodyPrefab, displayPrefab, charColor, tokenPrefix, null, 100f); } internal static void CreateSurvivor(GameObject bodyPrefab, GameObject displayPrefab, Color charColor, string tokenPrefix, float sortPosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) CreateSurvivor(bodyPrefab, displayPrefab, charColor, tokenPrefix, null, sortPosition); } internal static void CreateSurvivor(GameObject bodyPrefab, GameObject displayPrefab, Color charColor, string tokenPrefix, UnlockableDef unlockableDef) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) CreateSurvivor(bodyPrefab, displayPrefab, charColor, tokenPrefix, unlockableDef, 100f); } internal static void CreateSurvivor(GameObject bodyPrefab, GameObject displayPrefab, Color charColor, string tokenPrefix, UnlockableDef unlockableDef, float sortPosition) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) SurvivorDef obj = ScriptableObject.CreateInstance<SurvivorDef>(); obj.bodyPrefab = bodyPrefab; obj.displayPrefab = displayPrefab; obj.primaryColor = charColor; obj.cachedName = ((Object)bodyPrefab).name.Replace("Body", ""); obj.displayNameToken = tokenPrefix + "NAME"; obj.descriptionToken = tokenPrefix + "DESCRIPTION"; obj.outroFlavorToken = tokenPrefix + "OUTRO_FLAVOR"; obj.mainEndingEscapeFailureFlavorToken = tokenPrefix + "OUTRO_FAILURE"; obj.desiredSortPosition = sortPosition; obj.unlockableDef = unlockableDef; AddSurvivorDef(obj); } internal static void AddUnlockableDef(UnlockableDef unlockableDef) { ContentPacks.unlockableDefs.Add(unlockableDef); } internal static UnlockableDef CreateAndAddUnlockbleDef(string identifier, string nameToken, Sprite achievementIcon) { UnlockableDef obj = ScriptableObject.CreateInstance<UnlockableDef>(); obj.cachedName = identifier; obj.nameToken = nameToken; obj.achievementIcon = achievementIcon; AddUnlockableDef(obj); return obj; } internal static void AddSkillDef(SkillDef skillDef) { ContentPacks.skillDefs.Add(skillDef); } internal static void AddSkillFamily(SkillFamily skillFamily) { ContentPacks.skillFamilies.Add(skillFamily); } internal static void AddEntityState(Type entityState) { ContentPacks.entityStates.Add(entityState); } internal static void AddBuffDef(BuffDef buffDef) { ContentPacks.buffDefs.Add(buffDef); } internal static BuffDef CreateAndAddBuff(string buffName, Sprite buffIcon, Color buffColor, bool canStack, bool isDebuff) { //IL_000d: 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) BuffDef obj = ScriptableObject.CreateInstance<BuffDef>(); ((Object)obj).name = buffName; obj.buffColor = buffColor; obj.canStack = canStack; obj.isDebuff = isDebuff; obj.eliteDef = null; obj.iconSprite = buffIcon; AddBuffDef(obj); return obj; } internal static void AddEffectDef(EffectDef effectDef) { ContentPacks.effectDefs.Add(effectDef); } internal static EffectDef CreateAndAddEffectDef(GameObject effectPrefab) { //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_000c: Expected O, but got Unknown //IL_000d: Expected O, but got Unknown EffectDef val = new EffectDef(effectPrefab); AddEffectDef(val); return val; } internal static void AddNetworkSoundEventDef(NetworkSoundEventDef networkSoundEventDef) { ContentPacks.networkSoundEventDefs.Add(networkSoundEventDef); } internal static NetworkSoundEventDef CreateAndAddNetworkSoundEventDef(string eventName) { NetworkSoundEventDef obj = ScriptableObject.CreateInstance<NetworkSoundEventDef>(); obj.akId = AkSoundEngine.GetIDFromString(eventName); obj.eventName = eventName; AddNetworkSoundEventDef(obj); return obj; } } internal class ContentPacks : IContentPackProvider { internal ContentPack contentPack = new ContentPack(); public static List<GameObject> bodyPrefabs = new List<GameObject>(); public static List<GameObject> masterPrefabs = new List<GameObject>(); public static List<GameObject> projectilePrefabs = new List<GameObject>(); public static List<SurvivorDef> survivorDefs = new List<SurvivorDef>(); public static List<UnlockableDef> unlockableDefs = new List<UnlockableDef>(); public static List<SkillFamily> skillFamilies = new List<SkillFamily>(); public static List<SkillDef> skillDefs = new List<SkillDef>(); public static List<Type> entityStates = new List<Type>(); public static List<BuffDef> buffDefs = new List<BuffDef>(); public static List<EffectDef> effectDefs = new List<EffectDef>(); public static List<NetworkSoundEventDef> networkSoundEventDefs = new List<NetworkSoundEventDef>(); public string identifier => "com.ES15.DIOOH"; public void Initialize() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown ContentManager.collectContentPackProviders += new CollectContentPackProvidersDelegate(ContentManager_collectContentPackProviders); } private void ContentManager_collectContentPackProviders(AddContentPackProviderDelegate addContentPackProvider) { addContentPackProvider.Invoke((IContentPackProvider)(object)this); } public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args) { contentPack.identifier = identifier; contentPack.bodyPrefabs.Add(bodyPrefabs.ToArray()); contentPack.masterPrefabs.Add(masterPrefabs.ToArray()); contentPack.projectilePrefabs.Add(projectilePrefabs.ToArray()); contentPack.survivorDefs.Add(survivorDefs.ToArray()); contentPack.unlockableDefs.Add(unlockableDefs.ToArray()); contentPack.skillDefs.Add(skillDefs.ToArray()); contentPack.skillFamilies.Add(skillFamilies.ToArray()); contentPack.entityStateTypes.Add(entityStates.ToArray()); contentPack.buffDefs.Add(buffDefs.ToArray()); contentPack.effectDefs.Add(effectDefs.ToArray()); contentPack.networkSoundEventDefs.Add(networkSoundEventDefs.ToArray()); args.ReportProgress(1f); yield break; } public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args) { ContentPack.Copy(contentPack, args.output); args.ReportProgress(1f); yield break; } public IEnumerator FinalizeAsync(FinalizeAsyncArgs args) { args.ReportProgress(1f); yield break; } } internal static class ItemDisplayCheck { public static List<Object> allDisplayedItems; public static void PrintUnused(ItemDisplayRuleSet itemDisplayRuleSet, string bodyName = "") { PrintUnused((IEnumerable<KeyAssetRuleGroup>)itemDisplayRuleSet.keyAssetRuleGroups.ToList(), bodyName); } public static void PrintUnused(IEnumerable<KeyAssetRuleGroup> ruleSet = null, string bodyName = "") { //IL_0036: 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_003d: 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_004d: 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_0064: Unknown result type (might be due to invalid IL or missing references) string text = "generating item displays for " + bodyName; if (allDisplayedItems == null) { LazyGatherAllItems(); } List<Object> list = new List<Object>(allDisplayedItems); string text2 = ""; if (ruleSet != null) { foreach (KeyAssetRuleGroup item in ruleSet) { if (item.displayRuleGroup.rules.Length != 0) { list.Remove(item.keyAsset); if (string.IsNullOrEmpty(text2)) { text2 = item.displayRuleGroup.rules[0].childName; } } } } if (string.IsNullOrEmpty(text2)) { text2 = "Chest"; } foreach (Object item2 in list) { string text3 = ""; if (ItemDisplays.KeyAssetDisplayPrefabs.ContainsKey(item2)) { text3 += SpitOutNewRule(item2, text2, ItemDisplays.KeyAssetDisplayPrefabs[item2]); } else { Log.Error($"COULD NOT FIND DISPLAY PREFABS FOR KEYASSET {item2}"); } text += text3; } Log.Message(text); } private static void LazyGatherAllItems() { allDisplayedItems = new List<Object>(ItemDisplays.KeyAssetDisplayPrefabs.Keys); allDisplayedItems.Sort(delegate(Object item1, Object item2) { if (item1 is ItemDef && item2 is ItemDef) { return item1.name.CompareTo(item2.name); } if (item1 is EquipmentDef && item2 is EquipmentDef) { return item1.name.CompareTo(item2.name); } if (item1 is ItemDef && item2 is EquipmentDef) { return -1; } return (item1 is EquipmentDef && item2 is ItemDef) ? 1 : 0; }); } private static string SpitOutNewRule(Object asset, string firstCompatibleChild, ItemDisplayRule[] displayRules) { //IL_0031: 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) if (displayRules.Length == 0) { return $"\n[NO DISPLAY RULES FOUND FOR THE KEYASSET {asset}"; } string text = "\n itemDisplayRules.Add(ItemDisplays.CreateDisplayRuleGroupWithRules(ItemDisplays.KeyAssets[\"" + asset.name + "\"]"; for (int i = 0; i < displayRules.Length; i++) { text = (((int)displayRules[i].limbMask != 0) ? (text + ",\n" + $" ItemDisplays.CreateLimbMaskDisplayRule(LimbFlags.{displayRules[i].limbMask})") : (text + ",\n ItemDisplays.CreateDisplayRule(ItemDisplays.LoadDisplay(\"" + ((Object)displayRules[i].followerPrefab).name + "\"),\n \"" + firstCompatibleChild + "\",\n new Vector3(2, 2, 2),\n new Vector3(0, 0, 0),\n new Vector3(1, 1, 1)\n )")); } return text + "\n ));"; } } internal static class ItemDisplays { private static Dictionary<string, GameObject> itemDisplayPrefabs = new Dictionary<string, GameObject>(); public static Dictionary<Object, ItemDisplayRule[]> KeyAssetDisplayPrefabs = new Dictionary<Object, ItemDisplayRule[]>(); public static Dictionary<string, Object> KeyAssets = new Dictionary<string, Object>(); public static int queuedDisplays; public static bool initialized = false; public static void LazyInit() { if (!initialized) { initialized = true; PopulateDisplays(); } } internal static void DisposeWhenDone() { queuedDisplays--; if (queuedDisplays <= 0 && initialized) { initialized = false; itemDisplayPrefabs = null; KeyAssetDisplayPrefabs = null; KeyAssets = null; } } internal static void PopulateDisplays() { PopulateFromBody("LoaderBody"); } private static void PopulateFromBody(string bodyName) { KeyAssetRuleGroup[] keyAssetRuleGroups = ((Component)LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterBodies/" + bodyName).GetComponent<ModelLocator>().modelTransform).GetComponent<CharacterModel>().itemDisplayRuleSet.keyAssetRuleGroups; for (int i = 0; i < keyAssetRuleGroups.Length; i++) { ItemDisplayRule[] rules = keyAssetRuleGroups[i].displayRuleGroup.rules; KeyAssetDisplayPrefabs[keyAssetRuleGroups[i].keyAsset] = rules; KeyAssets[keyAssetRuleGroups[i].keyAsset.name] = keyAssetRuleGroups[i].keyAsset; for (int j = 0; j < rules.Length; j++) { GameObject followerPrefab = rules[j].followerPrefab; if (Object.op_Implicit((Object)(object)followerPrefab)) { string key = ((Object)followerPrefab).name?.ToLowerInvariant(); if (!itemDisplayPrefabs.ContainsKey(key)) { itemDisplayPrefabs[key] = followerPrefab; } } } } } private static void PopulateCustomLightningArm() { GameObject val = PrefabAPI.InstantiateClone(itemDisplayPrefabs["displaylightningarmright"], "DisplayLightningCustom", false); LimbMatcher component = val.GetComponent<LimbMatcher>(); component.limbPairs[0].targetChildLimb = "LightningArm1"; component.limbPairs[1].targetChildLimb = "LightningArm2"; component.limbPairs[2].targetChildLimb = "LightningArmEnd"; itemDisplayPrefabs["displaylightningarmcustom"] = val; } public static GameObject LoadDisplay(string name) { if (itemDisplayPrefabs.ContainsKey(name.ToLowerInvariant()) && Object.op_Implicit((Object)(object)itemDisplayPrefabs[name.ToLowerInvariant()])) { return itemDisplayPrefabs[name.ToLowerInvariant()]; } Log.Error("item display " + name + " returned null"); return null; } public static KeyAssetRuleGroup CreateDisplayRuleGroupWithRules(string itemName, params ItemDisplayRule[] rules) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return CreateDisplayRuleGroupWithRules(GetKeyAssetFromString(itemName), rules); } public static KeyAssetRuleGroup CreateDisplayRuleGroupWithRules(Object keyAsset_, params ItemDisplayRule[] rules) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (keyAsset_ == (Object)null) { Log.Error("could not find keyasset"); } return new KeyAssetRuleGroup { keyAsset = keyAsset_, displayRuleGroup = new DisplayRuleGroup { rules = rules } }; } public static ItemDisplayRule CreateDisplayRule(string prefabName, string childName, Vector3 position, Vector3 rotation, Vector3 scale) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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) return CreateDisplayRule(LoadDisplay(prefabName), childName, position, rotation, scale); } public static ItemDisplayRule CreateDisplayRule(GameObject itemPrefab, string childName, Vector3 position, Vector3 rotation, Vector3 scale) { //IL_0002: 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_0023: 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_002b: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0041: Unknown result type (might be due to invalid IL or missing references) return new ItemDisplayRule { ruleType = (ItemDisplayRuleType)0, childName = childName, followerPrefab = itemPrefab, limbMask = (LimbFlags)0, localPos = position, localAngles = rotation, localScale = scale }; } public static ItemDisplayRule CreateLimbMaskDisplayRule(LimbFlags limb) { //IL_0002: 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_0012: 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_002c: Unknown result type (might be due to invalid IL or missing references) return new ItemDisplayRule { ruleType = (ItemDisplayRuleType)1, limbMask = limb, childName = "", followerPrefab = null }; } private static Object GetKeyAssetFromString(string itemName) { Object val = (Object)(object)LegacyResourcesAPI.Load<ItemDef>("ItemDefs/" + itemName); if (val == (Object)null) { val = (Object)(object)LegacyResourcesAPI.Load<EquipmentDef>("EquipmentDefs/" + itemName); } if (val == (Object)null) { Log.Error("Could not load keyasset for " + itemName); } return val; } } internal static class Language { public static string TokensOutput = ""; public static bool usingLanguageFolder = false; public static bool printingEnabled = false; public static void Init() { if (usingLanguageFolder) { Language.collectLanguageRootFolders += Language_collectLanguageRootFolders; } } private static void Language_collectLanguageRootFolders(List<string> obj) { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)DIOOHPlugin.instance).Info.Location), "Language"); if (Directory.Exists(text)) { obj.Add(text); } } public static void Add(string token, string text) { if (!usingLanguageFolder) { LanguageAPI.Add(token, text); } if (printingEnabled) { TokensOutput = TokensOutput + "\n \"" + token + "\" : \"" + text.Replace(Environment.NewLine, "\\n").Replace("\n", "\\n") + "\","; } } public static void PrintOutput(string fileName = "") { if (printingEnabled) { string text = "{\n strings:\n {" + TokensOutput + "\n }\n}"; Log.Message(fileName + ": \n" + text); if (!string.IsNullOrEmpty(fileName)) { File.WriteAllText(Path.Combine(Directory.GetParent(((BaseUnityPlugin)DIOOHPlugin.instance).Info.Location).FullName, "Language", "en", fileName), text); } TokensOutput = ""; } } } internal static class Materials { private static List<Material> cachedMaterials = new List<Material>(); internal static Shader hotpoo = LegacyResourcesAPI.Load<Shader>("Shaders/Deferred/HGStandard"); public static Material LoadMaterial(this AssetBundle assetBundle, string materialName) { return assetBundle.CreateHopooMaterialFromBundle(materialName); } public static Material CreateHopooMaterialFromBundle(this AssetBundle assetBundle, string materialName) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown Material val = cachedMaterials.Find(delegate(Material mat) { materialName.Replace(" (Instance)", ""); return ((Object)mat).name.Contains(materialName); }); if (Object.op_Implicit((Object)(object)val)) { Log.Debug(((Object)val).name + " has already been loaded. returning cached"); return val; } val = assetBundle.LoadAsset<Material>(materialName); if (!Object.op_Implicit((Object)(object)val)) { Log.ErrorAssetBundle(materialName, ((Object)assetBundle).name); return new Material(hotpoo); } return val.ConvertDefaultShaderToHopoo(); } public static Material SetHopooMaterial(this Material tempMat) { return tempMat.ConvertDefaultShaderToHopoo(); } public static Material ConvertDefaultShaderToHopoo(this Material tempMat) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)tempMat) && (((Object)tempMat).name.StartsWith("matDIO") || ((Object)tempMat).name.StartsWith("matTWOH"))) { return tempMat; } if (cachedMaterials.Contains(tempMat)) { Log.Debug(((Object)tempMat).name + " has already been converted. returning cached"); return tempMat; } string text = ((Object)tempMat.shader).name.ToLowerInvariant(); if (!text.StartsWith("standard") && !text.StartsWith("autodesk")) { Log.Debug(((Object)tempMat).name + " is not unity standard shader. aborting material conversion"); return tempMat; } float? num = null; Color? val = null; if (tempMat.IsKeywordEnabled("_NORMALMAP")) { num = tempMat.GetFloat("_BumpScale"); } if (tempMat.IsKeywordEnabled("_EMISSION")) { val = tempMat.GetColor("_EmissionColor"); } tempMat.shader = hotpoo; tempMat.SetTexture("_EmTex", tempMat.GetTexture("_EmissionMap")); tempMat.EnableKeyword("DITHER"); if (num.HasValue) { tempMat.SetFloat("_NormalStrength", num.Value); tempMat.SetTexture("_NormalTex", tempMat.GetTexture("_BumpMap")); } if (val.HasValue) { tempMat.SetColor("_EmColor", val.Value); tempMat.SetFloat("_EmPower", 1f); } if (tempMat.IsKeywordEnabled("NOCULL")) { tempMat.SetInt("_Cull", 0); } if (tempMat.IsKeywordEnabled("LIMBREMOVAL")) { tempMat.SetInt("_LimbRemovalOn", 1); } cachedMaterials.Add(tempMat); return tempMat; } public static Material MakeUnique(this Material material) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown if (cachedMaterials.Contains(material)) { return new Material(material); } return material; } public static Material SetColor(this Material material, Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) material.SetColor("_Color", color); return material; } public static Material SetNormal(this Material material, float normalStrength = 1f) { material.SetFloat("_NormalStrength", normalStrength); return material; } public static Material SetEmission(this Material material) { return material.SetEmission(1f); } public static Material SetEmission(this Material material, float emission) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return material.SetEmission(emission, Color.white); } public static Material SetEmission(this Material material, float emission, Color emissionColor) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) material.SetFloat("_EmPower", emission); material.SetColor("_EmColor", emissionColor); return material; } public static Material SetCull(this Material material, bool cull = false) { material.SetInt("_Cull", cull ? 1 : 0); return material; } public static Material SetSpecular(this Material material, float strength) { material.SetFloat("_SpecularStrength", strength); return material; } public static Material SetSpecular(this Material material, float strength, float exponent) { material.SetFloat("_SpecularStrength", strength); material.SetFloat("SpecularExponent", exponent); return material; } } internal static class Prefabs { private static PhysicMaterial ragdollMaterial; public static GameObject CreateDisplayPrefab(AssetBundle assetBundle, string displayPrefabName, GameObject prefab) { GameObject val = assetBundle.LoadAsset<GameObject>(displayPrefabName); if ((Object)(object)val == (Object)null) { Log.Error("could not load display prefab " + displayPrefabName + ". Make sure this prefab exists in assetbundle " + ((Object)assetBundle).name); return null; } CharacterModel val2 = val.GetComponent<CharacterModel>(); if (!Object.op_Implicit((Object)(object)val2)) { val2 = val.AddComponent<CharacterModel>(); } val2.baseRendererInfos = prefab.GetComponentInChildren<CharacterModel>().baseRendererInfos; Asset.ConvertAllRenderersToHopooShader(val); return val; } public static GameObject LoadCharacterModel(AssetBundle assetBundle, string modelName) { GameObject val = assetBundle.LoadAsset<GameObject>(modelName); if ((Object)(object)val == (Object)null) { Log.Error("could not load model prefab " + modelName + ". Make sure this prefab exists in assetbundle " + ((Object)assetBundle).name); return null; } return val; } public static GameObject LoadCharacterBody(AssetBundle assetBundle, string bodyName) { GameObject val = assetBundle.LoadAsset<GameObject>(bodyName); if ((Object)(object)val == (Object)null) { Log.Error("could not load body prefab " + bodyName + ". Make sure this prefab exists in assetbundle " + ((Object)assetBundle).name); return null; } return val; } public static GameObject CloneCharacterBody(BodyInfo bodyInfo) { GameObject val = LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterBodies/" + bodyInfo.bodyNameToClone + "Body"); if (!Object.op_Implicit((Object)(object)val)) { Log.Error(bodyInfo.bodyNameToClone + " Body to clone is not a valid body, character creation failed"); return null; } GameObject val2 = PrefabAPI.InstantiateClone(val, bodyInfo.bodyName); for (int num = val2.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val2.transform.GetChild(num)).gameObject); } return val2; } public static GameObject CreateBodyPrefab(AssetBundle assetBundle, string modelPrefabName, BodyInfo bodyInfo) { return CreateBodyPrefab(LoadCharacterModel(assetBundle, modelPrefabName), bodyInfo); } public static GameObject CreateBodyPrefab(GameObject model, BodyInfo bodyInfo) { return CreateBodyPrefab(CloneCharacterBody(bodyInfo), model, bodyInfo); } public static GameObject CreateBodyPrefab(GameObject newBodyPrefab, AssetBundle assetBundle, string modelName, BodyInfo bodyInfo) { return CreateBodyPrefab(newBodyPrefab, LoadCharacterModel(assetBundle, modelName), bodyInfo); } public static GameObject CreateBodyPrefab(AssetBundle assetBundle, string bodyPrefabName, string modelPrefabName, BodyInfo bodyInfo) { return CreateBodyPrefab(LoadCharacterBody(assetBundle, bodyPrefabName), LoadCharacterModel(assetBundle, modelPrefabName), bodyInfo); } public static GameObject CreateBodyPrefab(GameObject newBodyPrefab, GameObject model, BodyInfo bodyInfo) { if ((Object)(object)model == (Object)null || (Object)(object)newBodyPrefab == (Object)null) { Log.Error($"Character creation failed. Model: {model}, Body: {newBodyPrefab}"); return null; } SetupCharacterBody(newBodyPrefab, bodyInfo); Transform modelBaseTransform = AddCharacterModelToSurvivorBody(newBodyPrefab, model.transform, bodyInfo); SetupModelLocator(newBodyPrefab, modelBaseTransform, model.transform); SetupCharacterDirection(newBodyPrefab, modelBaseTransform, model.transform); SetupCameraTargetParams(newBodyPrefab, bodyInfo); SetupCapsuleCollider(newBodyPrefab); Content.AddCharacterBodyPrefab(newBodyPrefab); return newBodyPrefab; } private static void SetupCharacterBody(GameObject newBodyPrefab, BodyInfo bodyInfo) { //IL_002d: 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_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) CharacterBody component = newBodyPrefab.GetComponent<CharacterBody>(); component.baseNameToken = bodyInfo.bodyNameToken; component.subtitleNameToken = bodyInfo.subtitleNameToken; component.portraitIcon = bodyInfo.characterPortrait; component.bodyColor = bodyInfo.bodyColor; component._defaultCrosshairPrefab = bodyInfo.crosshair; component.hideCrosshair = false; component.preferredPodPrefab = bodyInfo.podPrefab; component.baseMaxHealth = bodyInfo.maxHealth; component.baseRegen = bodyInfo.healthRegen; component.baseArmor = bodyInfo.armor; component.baseMaxShield = bodyInfo.shield; component.baseDamage = bodyInfo.damage; component.baseAttackSpeed = bodyInfo.attackSpeed; component.baseCrit = bodyInfo.crit; component.baseMoveSpeed = bodyInfo.moveSpeed; component.baseJumpPower = bodyInfo.jumpPower; component.autoCalculateLevelStats = bodyInfo.autoCalculateLevelStats; if (bodyInfo.autoCalculateLevelStats) { component.levelMaxHealth = Mathf.Round(component.baseMaxHealth * 0.3f); component.levelMaxShield = Mathf.Round(component.baseMaxShield * 0.3f); component.levelRegen = component.baseRegen * 0.2f; component.levelMoveSpeed = 0f; component.levelJumpPower = 0f; component.levelDamage = component.baseDamage * 0.2f; component.levelAttackSpeed = 0f; component.levelCrit = 0f; component.levelArmor = 0f; } else { component.levelMaxHealth = bodyInfo.healthGrowth; component.levelMaxShield = bodyInfo.shieldGrowth; component.levelRegen = bodyInfo.regenGrowth; component.levelMoveSpeed = bodyInfo.moveSpeedGrowth; component.levelJumpPower = bodyInfo.jumpPowerGrowth; component.levelDamage = bodyInfo.damageGrowth; component.levelAttackSpeed = bodyInfo.attackSpeedGrowth; component.levelCrit = bodyInfo.critGrowth; component.levelArmor = bodyInfo.armorGrowth; } component.baseAcceleration = bodyInfo.acceleration; component.baseJumpCount = bodyInfo.jumpCount; component.sprintingSpeedMultiplier = 1.45f; component.bodyFlags = (BodyFlags)16; component.rootMotionInMainState = false; component.hullClassification = (HullClassification)0; component.isChampion = false; } private static Transform AddCharacterModelToSurvivorBody(GameObject bodyPrefab, Transform modelTransform, BodyInfo bodyInfo) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0038: 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_008c: 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_00ae: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) Transform val = bodyPrefab.transform.Find("ModelBase"); if ((Object)(object)val == (Object)null) { val = new GameObject("ModelBase").transform; val.parent = bodyPrefab.transform; val.localPosition = bodyInfo.modelBasePosition; val.localRotation = Quaternion.identity; } modelTransform.parent = ((Component)val).transform; modelTransform.localPosition = Vector3.zero; modelTransform.localRotation = Quaternion.identity; if ((Object)(object)bodyPrefab.transform.Find("CameraPivot") == (Object)null) { Transform transform = new GameObject("CameraPivot").transform; transform.parent = bodyPrefab.transform; transform.localPosition = bodyInfo.cameraPivotPosition; transform.localRotation = Quaternion.identity; } Transform val2 = bodyPrefab.transform.Find("AimOrigin"); if ((Object)(object)val2 == (Object)null) { val2 = new GameObject("AimOrigin").transform; val2.parent = bodyPrefab.transform; val2.localPosition = bodyInfo.aimOriginPosition; val2.localRotation = Quaternion.identity; } bodyPrefab.GetComponent<CharacterBody>().aimOriginTransform = val2; return ((Component)val).transform; } private static void SetupCharacterDirection(GameObject prefab, Transform modelBaseTransform, Transform modelTransform) { if (Object.op_Implicit((Object)(object)prefab.GetComponent<CharacterDirection>())) { CharacterDirection component = prefab.GetComponent<CharacterDirection>(); component.targetTransform = modelBaseTransform; component.overrideAnimatorForwardTransform = null; component.rootMotionAccumulator = null; component.modelAnimator = ((Component)modelTransform).GetComponent<Animator>(); component.driveFromRootRotation = false; component.turnSpeed = 720f; } } private static void SetupCameraTargetParams(GameObject prefab, BodyInfo bodyInfo) { CameraTargetParams component = prefab.GetComponent<CameraTargetParams>(); component.cameraParams = bodyInfo.cameraParams; component.cameraPivotTransform = prefab.transform.Find("CameraPivot"); } private static void SetupModelLocator(GameObject prefab, Transform modelBaseTransform, Transform modelTransform) { ModelLocator component = prefab.GetComponent<ModelLocator>(); component.modelTransform = modelTransform; component.modelBaseTransform = modelBaseTransform; } private static void SetupCapsuleCollider(GameObject prefab) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) CapsuleCollider component = prefab.GetComponent<CapsuleCollider>(); component.center = new Vector3(0f, 0f, 0f); component.radius = 0.5f; component.height = 1.82f; component.direction = 1; } public static CharacterModel SetupCharacterModel(GameObject bodyPrefab, CustomRendererInfo[] customInfos = null) { CharacterModel val = ((Component)bodyPrefab.GetComponent<ModelLocator>().modelTransform).gameObject.GetComponent<CharacterModel>(); bool num = (Object)(object)val != (Object)null; if (!num) { val = ((Component)bodyPrefab.GetComponent<ModelLocator>().modelTransform).gameObject.AddComponent<CharacterModel>(); } val.body = bodyPrefab.GetComponent<CharacterBody>(); val.autoPopulateLightInfos = true; val.invisibilityCount = 0; val.temporaryOverlays = new List<TemporaryOverlayInstance>(); if (!num) { SetupCustomRendererInfos(val, customInfos); } else { SetupPreAttachedRendererInfos(val); } SetupHurtboxGroup(bodyPrefab, ((Component)val).gameObject); SetupAimAnimator(bodyPrefab, ((Component)val).gameObject); SetupFootstepController(((Component)val).gameObject); SetupRagdoll(((Component)val).gameObject); return val; } public static void SetupPreAttachedRendererInfos(CharacterModel characterModel) { for (int i = 0; i < characterModel.baseRendererInfos.Length; i++) { if ((Object)(object)characterModel.baseRendererInfos[i].defaultMaterial == (Object)null) { characterModel.baseRendererInfos[i].defaultMaterial = characterModel.baseRendererInfos[i].renderer.sharedMaterial; } if ((Object)(object)characterModel.baseRendererInfos[i].defaultMaterial == (Object)null) { Log.Error($"no material for rendererinfo of this renderer: {characterModel.baseRendererInfos[i].renderer}"); } characterModel.baseRendererInfos[i].defaultMaterial.ConvertDefaultShaderToHopoo(); } } public static void SetupCustomRendererInfos(CharacterModel characterModel, CustomRendererInfo[] customInfos) { //IL_00ac: 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_00da: Unknown result type (might be due to invalid IL or missing references) ChildLocator component = ((Component)characterModel).GetComponent<ChildLocator>(); if (!Object.op_Implicit((Object)(object)component)) { Log.Error("Failed CharacterModel setup: ChildLocator component does not exist on the model"); return; } List<RendererInfo> list = new List<RendererInfo>(); for (int i = 0; i < customInfos.Length; i++) { if (!Object.op_Implicit((Object)(object)component.FindChild(customInfos[i].childName))) { Log.Error("Trying to add a RendererInfo for a renderer that does not exist: " + customInfos[i].childName); continue; } Renderer component2 = ((Component)component.FindChild(customInfos[i].childName)).GetComponent<Renderer>(); if (Object.op_Implicit((Object)(object)component2)) { Material val = customInfos[i].material; if ((Object)(object)val == (Object)null) { val = ((!customInfos[i].dontHotpoo) ? component2.sharedMaterial.ConvertDefaultShaderToHopoo() : component2.sharedMaterial); } list.Add(new RendererInfo { renderer = component2, defaultMaterial = val, ignoreOverlays = customInfos[i].ignoreOverlays, defaultShadowCastingMode = (ShadowCastingMode)1 }); } } characterModel.baseRendererInfos = list.ToArray(); } private static void SetupHurtboxGroup(GameObject bodyPrefab, GameObject model) { SetupMainHurtboxesFromChildLocator(bodyPrefab, model); SetHurtboxesHealthComponents(bodyPrefab); } private static void SetupMainHurtboxesFromChildLocator(GameObject bodyPrefab, GameObject model) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bodyPrefab.GetComponent<HurtBoxGroup>() != (Object)null) { Log.Debug("Hitboxgroup already exists on model prefab. aborting code setup"); return; } ChildLocator component = model.GetComponent<ChildLocator>(); if (string.IsNullOrEmpty(component.FindChildNameInsensitive("MainHurtbox"))) { Log.Error("Could not set up main hurtbox: make sure you have a transform pair in your prefab's ChildLocator called 'MainHurtbox'"); return; } HurtBoxGroup val = model.AddComponent<HurtBoxGroup>(); HurtBox val2 = null; GameObject val3 = component.FindChildGameObjectInsensitive("HeadHurtbox"); if (Object.op_Implicit((Object)(object)val3)) { Log.Debug("HeadHurtboxFound. Setting up"); val2 = val3.AddComponent<HurtBox>(); ((Component)val2).gameObject.layer = LayerIndex.entityPrecise.intVal; val2.healthComponent = bodyPrefab.GetComponent<HealthComponent>(); val2.isBullseye = false; val2.isSniperTarget = true; val2.damageModifier = (DamageModifier)0; val2.hurtBoxGroup = val; val2.indexInGroup = 1; } HurtBox val4 = component.FindChildGameObjectInsensitive("MainHurtbox").AddComponent<HurtBox>(); ((Component)val4).gameObject.layer = LayerIndex.entityPrecise.intVal; val4.healthComponent = bodyPrefab.GetComponent<HealthComponent>(); val4.isBullseye = true; val4.isSniperTarget = (Object)(object)val2 == (Object)null; val4.damageModifier = (DamageModifier)0; val4.hurtBoxGroup = val; val4.indexInGroup = 0; if (Object.op_Implicit((Object)(object)val2)) { val.hurtBoxes = (HurtBox[])(object)new HurtBox[2] { val4, val2 }; } else { val.hurtBoxes = (HurtBox[])(object)new HurtBox[1] { val4 }; } val.mainHurtBox = val4; val.bullseyeCount = 1; } private static string FindChildNameInsensitive(this ChildLocator childLocator, string child) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) return childLocator.transformPairs.Where((NameTransformPair pair) => pair.name.ToLowerInvariant() == child.ToLowerInvariant()).FirstOrDefault().name; } private static Transform FindChildInsensitive(this ChildLocator childLocator, string child) { return childLocator.FindChild(childLocator.FindChildNameInsensitive(child)); } private static GameObject FindChildGameObjectInsensitive(this ChildLocator childLocator, string child) { return childLocator.FindChildGameObject(childLocator.FindChildNameInsensitive(child)); } public static void SetHurtboxesHealthComponents(GameObject bodyPrefab) { HealthComponent component = bodyPrefab.GetComponent<HealthComponent>(); HurtBoxGroup[] componentsInChildren = bodyPrefab.GetComponentsInChildren<HurtBoxGroup>(); foreach (HurtBoxGroup val in componentsInChildren) { val.mainHurtBox.healthComponent = component; for (int j = 0; j < val.hurtBoxes.Length; j++) { val.hurtBoxes[j].healthComponent = component; } } } private static void SetupFootstepController(GameObject model) { FootstepHandler obj = model.AddComponent<FootstepHandler>(); obj.baseFootstepString = "Play_player_footstep"; obj.sprintFootstepOverrideString = ""; obj.enableFootstepDust = true; obj.footstepDustPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/GenericFootstepDust"); } private static void SetupRagdoll(GameObject model) { RagdollController component = model.GetComponent<RagdollController>(); if (!Object.op_Implicit((Object)(object)component)) { return; } if ((Object)(object)ragdollMaterial == (Object)null) { ragdollMaterial = ((Component)LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterBodies/CommandoBody").GetComponentInChildren<RagdollController>().bones[1]).GetComponent<Collider>().material; } Transform[] bones = component.bones; foreach (Transform val in bones) { if (Object.op_Implicit((Object)(object)val)) { ((Component)val).gameObject.layer = LayerIndex.ragdoll.intVal; Collider component2 = ((Component)val).GetComponent<Collider>(); if (Object.op_Implicit((Object)(object)component2)) { component2.sharedMaterial = ragdollMaterial; } else { Log.Error($"Ragdoll bone {((Component)val).gameObject} doesn't have a collider. Ragdoll will break."); } } } } private static void SetupAimAnimator(GameObject prefab, GameObject model) { AimAnimator obj = model.AddComponent<AimAnimator>(); obj.directionComponent = prefab.GetComponent<CharacterDirection>(); obj.pitchRangeMax = 60f; obj.pitchRangeMin = -60f; obj.yawRangeMin = -80f; obj.yawRangeMax = 80f; obj.pitchGiveupRange = 30f; obj.yawGiveupRange = 10f; obj.giveupDuration = 3f; obj.inputBank = prefab.GetComponent<InputBankTest>(); } public static void CreateGenericDoppelganger(GameObject bodyPrefab, string masterName, string masterToCopy) { CloneDopplegangerMaster(bodyPrefab, masterName, masterToCopy); } public static GameObject CloneDopplegangerMaster(GameObject bodyPrefab, string masterName, string masterToCopy) { GameObject obj = PrefabAPI.InstantiateClone(LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterMasters/" + masterToCopy + "MonsterMaster"), masterName, true); obj.GetComponent<CharacterMaster>().bodyPrefab = bodyPrefab; Content.AddMasterPrefab(obj); return obj; } public static GameObject CreateBlankMasterPrefab(GameObject bodyPrefab, string masterName) { GameObject val = PrefabAPI.InstantiateClone(LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterMasters/CommandoMonsterMaster"), masterName, true); ContentPacks.masterPrefabs.Add(val); val.GetComponent<CharacterMaster>().bodyPrefab = bodyPrefab; AISkillDriver[] components = val.GetComponents<AISkillDriver>(); for (int i = 0; i < components.Length; i++) { Object.Destroy((Object)(object)components[i]); } return val; } public static GameObject LoadMaster(this AssetBundle assetBundle, GameObject bodyPrefab, string assetName) { //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) GameObject val = assetBundle.LoadAsset<GameObject>(assetName); BaseAI val2 = val.GetComponent<BaseAI>(); if ((Object)(object)val2 == (Object)null) { val2 = val.AddComponent<BaseAI>(); val2.aimVectorDampTime = 0.1f; val2.aimVectorMaxSpeed = 360f; } val2.scanState = new SerializableEntityStateType(typeof(Wander)); EntityStateMachine component = val.GetComponent<EntityStateMachine>(); if ((Object)(object)component == (Object)null) { AddEntityStateMachine(val, "AI", typeof(Wander), typeof(Wander)); } val2.stateMachine = component; CharacterMaster val3 = val.GetComponent<CharacterMaster>(); if ((Object)(object)val3 == (Object)null) { val3 = val.AddComponent<CharacterMaster>(); } val3.bodyPrefab = bodyPrefab; val3.teamIndex = (TeamIndex)2; Content.AddMasterPrefab(val); return val; } public static void ClearEntityStateMachines(GameObject bodyPrefab) { EntityStateMachine[] components = bodyPrefab.GetComponents<EntityStateMachine>(); for (int num = components.Length - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)components[num]); } bodyPrefab.GetComponent<NetworkStateMachine>().stateMachines = Array.Empty<EntityStateMachine>(); CharacterDeathBehavior component = bodyPrefab.GetComponent<CharacterDeathBehavior>(); if (Object.op_Implicit((Object)(object)component)) { component.idleStateMachine = Array.Empty<EntityStateMachine>(); } SetStateOnHurt component2 = bodyPrefab.GetComponent<SetStateOnHurt>(); if (Object.op_Implicit((Object)(object)component2)) { component2.idleStateMachine = Array.Empty<EntityStateMachine>(); } CharacterBody component3 = bodyPrefab.GetComponent<CharacterBody>(); if (Object.op_Implicit((Object)(object)component3)) { component3.vehicleIdleStateMachine = Array.Empty<EntityStateMachine>(); } } public static EntityStateMachine AddEntityStateMachine(GameObject prefab, string machineName, Type mainStateType = null, Type initalStateType = null, bool addToHurt = true, bool addToDeath = true) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) EntityStateMachine val = EntityStateMachine.FindByCustomName(prefab, machineName); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<EntityStateMachine>(); } else { Log.Message("An Entity State Machine already exists with the name " + machineName + ". replacing."); } val.customName = machineName; if (mainStateType == null) { mainStateType = typeof(Idle); } val.mainStateType = new SerializableEntityStateType(mainStateType); if (initalStateType == null) { initalStateType = typeof(Idle); } val.initialStateType = new SerializableEntityStateType(initalStateType); NetworkStateMachine component = prefab.GetComponent<NetworkStateMachine>(); if (Object.op_Implicit((Object)(object)component)) { component.stateMachines = component.stateMachines.Append(val).ToArray(); } CharacterDeathBehavior component2 = prefab.GetComponent<CharacterDeathBehavior>(); if (Object.op_Implicit((Object)(object)component2) && addToDeath) { component2.idleStateMachine = component2.idleStateMachine.Append(val).ToArray(); } SetStateOnHurt component3 = prefab.GetComponent<SetStateOnHurt>(); if (Object.op_Implicit((Object)(object)component3) && addToHurt) { component3.idleStateMachine = component3.idleStateMachine.Append(val).ToArray(); } CharacterBody component4 = prefab.GetComponent<CharacterBody>(); if (Object.op_Implicit((Object)(object)component4)) { component4.vehicleIdleStateMachine = component4.vehicleIdleStateMachine.Append(val).ToArray(); } return val; } public static EntityStateMachine AddMainEntityStateMachine(GameObject bodyPrefab, string machineName = "Body", Type mainStateType = null, Type initalStateType = null) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) EntityStateMachine val = EntityStateMachine.FindByCustomName(bodyPrefab, machineName); if ((Object)(object)val == (Object)null) { val = bodyPrefab.AddComponent<EntityStateMachine>(); } else { Log.Message("An Entity State Machine already exists with the name " + machineName + ". replacing."); } val.customName = machineName; if (mainStateType == null) { mainStateType = typeof(GenericCharacterMain); } val.mainStateType = new SerializableEntityStateType(mainStateType); if (initalStateType == null) { initalStateType = typeof(SpawnTeleporterState); } val.initialStateType = new SerializableEntityStateType(initalStateType); NetworkStateMachine component = bodyPrefab.GetComponent<NetworkStateMachine>(); if (Object.op_Implicit((Object)(object)component)) { component.stateMachines = component.stateMachines.Append(val).ToArray(); } CharacterDeathBehavior component2 = bodyPrefab.GetComponent<CharacterDeathBehavior>(); if (Object.op_Implicit((Object)(object)component2)) { component2.deathStateMachine = val; } SetStateOnHurt component3 = bodyPrefab.GetComponent<SetStateOnHurt>(); if (Object.op_Implicit((Object)(object)component3)) { component3.targetStateMachine = val; } return val; } public static void SetupHitBoxGroup(GameObject modelPrefab, string hitBoxGroupName, params string[] hitboxChildNames) { ChildLocator component = modelPrefab.GetComponent<ChildLocator>(); Transform[] array = (Transform[])(object)new Transform[hitboxChildNames.Length]; for (int i = 0; i < hitboxChildNames.Length; i++) { array[i] = component.FindChild(hitboxChildNames[i]); if ((Object)(object)array[i] == (Object)null) { Log.Error("missing hitbox for " + hitboxChildNames[i]); } } SetupHitBoxGroup(modelPrefab, hitBoxGroupName, array); } public static void SetupHitBoxGroup(GameObject prefab, string hitBoxGroupName, params Transform[] hitBoxTransforms) { List<HitBox> list = new List<HitBox>(); foreach (Transform val in hitBoxTransforms) { if ((Object)(object)val == (Object)null) { Log.Error("Error setting up hitboxGroup for " + hitBoxGroupName + ": hitbox transform was null"); continue; } HitBox item = ((Component)val).gameObject.AddComponent<HitBox>(); ((Component)val).gameObject.layer = LayerIndex.projectile.intVal; list.Add(item); } if (list.Count == 0) { Log.Error("No hitboxes were set up. aborting setting up hitboxGroup for " + hitBoxGroupName); return; } HitBoxGroup obj = prefab.AddComponent<HitBoxGroup>(); obj.hitBoxes = list.ToArray(); obj.groupName = hitBoxGroupName; } } public class CustomRendererInfo { public string childName; public Material material; public bool dontHotpoo; public bool ignoreOverlays; } internal static class Skills { public static void CreateSkillFamilies(GameObject targetPrefab) { SkillSlot[] array = new SkillSlot[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); CreateSkillFamilies(targetPrefab, (SkillSlot[])(object)array); } public static void CreateSkillFamilies(GameObject targetPrefab, params SkillSlot[] slots) { //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_002b: Expected I4, but got Unknown SkillLocator component = targetPrefab.GetComponent<SkillLocator>(); foreach (SkillSlot val in slots) { switch (val - -1) { case 1: component.primary = CreateGenericSkillWithSkillFamily(targetPrefab, "Primary"); break; case 2: component.secondary = CreateGenericSkillWithSkillFamily(targetPrefab, "Secondary"); break; case 3: component.utility = CreateGenericSkillWithSkillFamily(targetPrefab, "Utility"); break; case 4: component.special = CreateGenericSkillWithSkillFamily(targetPrefab, "Special"); break; } } } public static void ClearGenericSkills(GameObject targetPrefab) { GenericSkill[] componentsInChildren = targetPrefab.GetComponentsInChildren<GenericSkill>(); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } } public static GenericSkill CreateGenericSkillWithSkillFamily(GameObject targetPrefab, SkillSlot skillSlot, bool hidden = false) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected I4, but got Unknown SkillLocator component = targetPrefab.GetComponent<SkillLocator>(); switch (skillSlot - -1) { case 1: return component.primary = CreateGenericSkillWithSkillFamily(targetPrefab, "Primary", hidden); case 2: return component.secondary = CreateGenericSkillWithSkillFamily(targetPrefab, "Secondary", hidden); case 3: return component.utility = CreateGenericSkillWithSkillFamily(targetPrefab, "Utility", hidden); case 4: return component.special = CreateGenericSkillWithSkillFamily(targetPrefab, "Special", hidden); case 0: Log.Error("Failed to create GenericSkill with skillslot None. If making a GenericSkill outside of the main 4, specify a familyName, and optionally a genericSkillName"); return null; default: return null; } } public static GenericSkill CreateGenericSkillWithSkillFamily(GameObject targetPrefab, string familyName, bool hidden = false) { return CreateGenericSkillWithSkillFamily(targetPrefab, familyName, familyName, hidden); } public static GenericSkill CreateGenericSkillWithSkillFamily(GameObject targetPrefab, string genericSkillName, string familyName, bool hidden = false) { GenericSkill obj = targetPrefab.AddComponent<GenericSkill>(); obj.skillName = genericSkillName; obj.hideInCharacterSelect = hidden; SkillFamily val = ScriptableObject.CreateInstance<SkillFamily>(); ((Object)val).name = ((Object)targetPrefab).name + familyName + "Family"; val.variants = (Variant[])(object)new Variant[0]; obj._skillFamily = val; Content.AddSkillFamily(val); return obj; } public static void AddSkillToFamily(SkillFamily skillFamily, SkillDef skillDef, UnlockableDef unlockableDef = null) { //IL_0027: 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_0051: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Array.Resize(ref skillFamily.variants, skillFamily.variants.Length + 1); Variant[] variants = skillFamily.variants; int num = skillFamily.variants.Length - 1; Variant val = new Variant { skillDef = skillDef, unlockableDef = unlockableDef }; ((Variant)(ref val)).viewableNode = new Node(skillDef.skillNameToken, false, (Node)null); variants[num] = val; } public static void AddSkillsToFamily(SkillFamily skillFamily, params SkillDef[] skillDefs) { foreach (SkillDef skillDef in skillDefs) { AddSkillToFamily(skillFamily, skillDef); } } public static void AddPrimarySkills(GameObject targetPrefab, params SkillDef[] skillDefs) { AddSkillsToFamily(targetPrefab.GetComponent<SkillLocator>().primary.skillFamily, skillDefs); } public static void AddSecondarySkills(GameObject targetPrefab, params SkillDef[] skillDefs) { AddSkillsToFamily(targetPrefab.GetComponent<SkillLocator>().secondary.skillFamily, skillDefs); } public static void AddUtilitySkills(GameObject targetPrefab, params SkillDef[] skillDefs) { AddSkillsToFamily(targetPrefab.GetComponent<SkillLocator>().utility.skillFamily, skillDefs); } public static void AddSpecialSkills(GameObject targetPrefab, params SkillDef[] skillDefs) { AddSkillsToFamily(targetPrefab.GetComponent<SkillLocator>().special.skillFamily, skillDefs); } public static void AddUnlockablesToFamily(SkillFamily skillFamily, params UnlockableDef[] unlockableDefs) { //IL_000b: 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_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) for (int i = 0; i < unlockableDefs.Length; i++) { Variant val = skillFamily.variants[i]; val.unlockableDef = unlockableDefs[i]; skillFamily.variants[i] = val; } } public static SkillDef CreateSkillDef(SkillDefInfo skillDefInfo) { return Skills.CreateSkillDef<SkillDef>(skillDefInfo); } public static T CreateSkillDef<T>(SkillDefInfo skillDefInfo) where T : SkillDef { //IL_0061: 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) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) T val = ScriptableObject.CreateInstance<T>(); ((SkillDef)val).skillName = skillDefInfo.skillName; ((Object)(object)val).name = skillDefInfo.skillName; ((SkillDef)val).skillNameToken = skillDefInfo.skillNameToken; ((SkillDef)val).skillDescriptionToken = skillDefInfo.skillDescriptionToken; ((SkillDef)val).icon = skillDefInfo.skillIcon; ((SkillDef)val).activationState = skillDefInfo.activationState; ((SkillDef)val).activationStateMachineName = skillDefInfo.activationStateMachineName; ((SkillDef)val).interruptPriority = skillDefInfo.interruptPriority; ((SkillDef)val).baseMaxStock = skillDefInfo.baseMaxStock; ((SkillDef)val).baseRechargeInterval = skillDefInfo.baseRechargeInterval; ((SkillDef)val).rechargeStock = skillDefInfo.rechargeStock; ((SkillDef)val).requiredStock = skillDefInfo.requiredStock; ((SkillDef)val).stockToConsume = skillDefInfo.stockToConsume; ((SkillDef)val).dontAllowPastMaxStocks = skillDefInfo.dontAllowPastMaxStocks; ((SkillDef)val).beginSkillCooldownOnSkillEnd = skillDefInfo.beginSkillCooldownOnSkillEnd; ((SkillDef)val).canceledFromSprinting = skillDefInfo.canceledFromSprinting; ((SkillDef)val).forceSprintDuringState = skillDefInfo.forceSprintDuringState; ((SkillDef)val).fullRestockOnAssign = skillDefInfo.fullRestockOnAssign; ((SkillDef)val).resetCooldownTimerOnUse = skillDefInfo.resetCooldownTimerOnUse; ((SkillDef)val).isCombatSkill = skillDefInfo.isCombatSkill; ((SkillDef)val).mustKeyPress = skillDefInfo.mustKeyPress; ((SkillDef)val).cancelSprintingOnActivation = skillDefInfo.cancelSprintingOnActivation; ((SkillDef)val).keywordTokens = skillDefInfo.keywordTokens; Content.AddSkillDef((SkillDef)(object)val); return val; } } internal class SkillDefInfo { public string skillName; public string skillNameToken; public string skillDescriptionToken; public string[] keywordTokens = Array.Empty<string>(); public Sprite skillIcon; public SerializableEntityStateType activationState; public string activationStateMachineName; public InterruptPriority interruptPriority; public float baseRechargeInterval; public int baseMaxStock = 1; public int rechargeStock = 1; public int requiredStock = 1; public int stockToConsume = 1; public bool resetCooldownTimerOnUse; public bool fullRestockOnAssign = true; public bool dontAllowPastMaxStocks; public bool beginSkillCooldownOnSkillEnd; public bool mustKeyPress; public bool isCombatSkill = true; public bool canceledFromSprinting; public bool cancelSprintingOnActivation = true; public bool forceSprintDuringState; public SkillDefInfo() { } public SkillDefInfo(string skillName, string skillNameToken, string skillDescriptionToken, Sprite skillIcon, SerializableEntityStateType activationState, string activationStateMachineName = "Weapon", bool agile = false) { //IL_0060: 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_0094: Unknown result type (might be due to invalid IL or missing references) this.skillName = skillName; this.skillNameToken = skillNameToken; this.skillDescriptionToken = skillDescriptionToken; this.skillIcon = skillIcon; this.activationState = activationState; this.activationStateMachineName = activationStateMachineName; cancelSprintingOnActivation = !agile; if (agile) { keywordTokens = new string[1] { "KEYWORD_AGILE" }; } interruptPriority = (InterruptPriority)0; isCombatSkill = true; baseRechargeInterval = 0f; requiredStock = 0; stockToConsume = 0; } } internal static class Skins { internal struct SkinDefInfo { internal SkinDef[] BaseSkins; internal Sprite Icon; internal string NameToken; internal UnlockableDef UnlockableDef; internal GameObject RootObject; internal RendererInfo[] RendererInfos; internal MeshReplacement[] MeshReplacements; internal GameObjectActivation[] GameObjectActivations; internal ProjectileGhostReplacement[] ProjectileGhostReplacements; internal MinionSkinReplacement[] MinionSkinReplacements; internal string Name; } internal static SkinDef CreateSkinDef(string skinName, Sprite skinIcon, RendererInfo[] defaultRendererInfos, GameObject root, UnlockableDef unlockableDef = null) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown SkinDefInfo skinDefInfo = new SkinDefInfo { BaseSkins = Array.Empty<SkinDef>(), GameObjectActivations = (GameObjectActivation[])(object)new GameObjectActivation[0], Icon = skinIcon, MeshReplacements = (MeshReplacement[])(object)new MeshReplacement[0], MinionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[0], Name = skinName, NameToken = skinName, ProjectileGhostReplacements = (ProjectileGhostReplacement[])(object)new ProjectileGhostReplacement[0], RendererInfos = (RendererInfo[])(object)new RendererInfo[defaultRendererInfos.Length], RootObject = root, UnlockableDef = unlockableDef }; SkinDef.Awake += new hook_Awake(DoNothing); SkinDef obj = ScriptableObject.CreateInstance<SkinDef>(); obj.baseSkins = skinDefInfo.BaseSkins; obj.icon = skinDefInfo.Icon; obj.unlockableDef = skinDefInfo.UnlockableDef; obj.rootObject = skinDefInfo.RootObject; defaultRendererInfos.CopyTo(skinDefInfo.RendererInfos, 0); obj.rendererInfos = skinDefInfo.RendererInfos; obj.gameObjectActivations = skinDefInfo.GameObjectActivations; obj.meshReplacements = skinDefInfo.MeshReplacements; obj.projectileGhostReplacements = skinDefInfo.ProjectileGhostReplacements; obj.minionSkinReplacements = skinDefInfo.MinionSkinReplacements; obj.nameToken = skinDefInfo.NameToken; ((Object)obj).name = skinDefInfo.Name; SkinDef.Awake -= new hook_Awake(DoNothing); return obj; } private static void DoNothing(orig_Awake orig, SkinDef self) { } private static RendererInfo[] getRendererMaterials(RendererInfo[] defaultRenderers, params Material[] materials) { RendererInfo[] array = (RendererInfo[])(object)new RendererInfo[defaultRenderers.Length]; defaultRenderers.CopyTo(array, 0); for (int i = 0; i < array.Length; i++) { try { array[i].defaultMaterial = materials[i]; } catch { Log.Error("error adding skin rendererinfo material. make sure you're not passing in too many"); } } return array; } internal static MeshReplacement[] getMeshReplacements(AssetBundle assetBundle, RendererInfo[] defaultRendererInfos, params string[] meshes) { //IL_0017: 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) List<MeshReplacement> list = new List<MeshReplacement>(); for (int i = 0; i < defaultRendererInfos.Length; i++) { if (!string.IsNullOrEmpty(meshes[i])) { list.Add(new MeshReplacement { renderer = defaultRendererInfos[i].renderer, mesh = assetBundle.LoadAsset<Mesh>(meshes[i]) }); } } return list.ToArray(); } } internal static class Tokens { public const string agilePrefix = "<style=cIsUtility>Agile.</style>"; public static string DamageText(string text) { return "<style=cIsDamage>" + text + "</style>"; } public static string DamageValueText(float value) { return $"<style=cIsDamage>{value * 100f}% damage</style>"; } public static string UtilityText(string text) { return "<style=cIsUtility>" + text + "</style>"; } public static string RedText(string text) { return HealthText(text); } public static string HealthText(string text) { return "<style=cIsHealth>" + text + "</style>"; } public static string KeywordText(string keyword, string sub) { return "<style=cKeywordName>" + keyword + "</style><style=cSub>" + sub + "</style>"; } public static string ScepterDescription(string desc) { return "\n<color=#d299ff>SCEPTER: " + desc + "</color>"; } public static string GetAchievementNameToken(string identifier) { return "ACHIEVEMENT_" + identifier.ToUpperInvariant() + "_NAME"; } public static string GetAchievementDescriptionToken(string identifier) { return "ACHIEVEMENT_" + identifier.ToUpperInvariant() + "_DESCRIPTION"; } } } namespace DIOOH.Modules.Characters { public abstract class CharacterBase<T> where T : CharacterBase<T>, new() { public abstract string assetBundleName { get; } public abstract string bodyName { get; } public abstract string modelPrefabName { get; } public abstract BodyInfo bodyInfo { get; } public virtual CustomRendererInfo[] customRendererInfos { get; } public virtual ItemDisplaysBase itemDisplays { get; } public static T instance { get; private set; } public abstract AssetBundle assetBundle { get; protected set; } public abstract GameObject bodyPrefab { get; protected set; } public abstract CharacterBody prefabCharacterBody { get; protected set; } public abstract GameObject characterModelObject { get; protected set; } public abstract CharacterModel prefabCharacterModel { get; protected set; } public virtual void Initialize() { instance = this as T; assetBundle = Asset.LoadAssetBundle(assetBundleName); InitializeCharacter(); } public virtual void InitializeCharacter() { InitializeCharacterBodyPrefab(); InitializeItemDisplays(); } protected virtual void InitializeCharacterBodyPrefab() { characterModelObject = Prefabs.LoadCharacterModel(assetBundle, modelPrefabName); bodyPrefab = Prefabs.CreateBodyPrefab(characterModelObject, bodyInfo); prefabCharacterBody = bodyPrefab.GetComponent<CharacterBody>(); prefabCharacterModel = Prefabs.SetupCharacterModel(bodyPrefab, customRendererInfos); } public virtual void InitializeItemDisplays() { ItemDisplayRuleSet val = ScriptableObject.CreateInstance<ItemDisplayRuleSet>(); ((Object)val).name = "idrs" + bodyName; prefabCharacterModel.itemDisplayRuleSet = val; if (itemDisplays != null) { ItemDisplays.queuedDisplays++; ContentManager.onContentPacksAssigned += SetItemDisplays; } } public void SetItemDisplays(ReadOnlyArray<ReadOnlyContentPack> obj) { itemDisplays.SetItemDisplays(prefabCharacterModel.itemDisplayRuleSet); } public abstract void InitializeEntityStateMachines(); public abstract void InitializeSkills(); public abstract void InitializeSkins(); public abstract void InitializeCharacterMaster(); } public class BodyInfo { public string bodyName = ""; public string bodyNameToken = ""; public string subtitleNameToken = ""; public string bodyNameToClone = "Commando"; public Color bodyColor = Color.white; public Texture characterPortrait; public float sortPosition = 100f; public GameObject crosshair; public GameObject podPrefab; public float maxHealth = 100f; public float healthRegen = 1f; public float armor; public float shield; public int jumpCount = 1; public float damage = 12f; public float attackSpeed = 1f; public float crit = 1f; public float moveSpeed = 7f; public float acceleration = 80f; public float jumpPower = 15f; public bool autoCalculateLevelStats = true; public float healthGrowth = 30.000002f; public float regenGrowth = 0.2f; public float armorGrowth; public float shieldGrowth; public float damageGrowth = 2.4f; public float attackSpeedGrowth; public float critGrowth; public float moveSpeedGrowth; public float jumpPowerGrowth; public Vector3 aimOriginPosition = new Vector3(0f, 1.6f, 0f); public Vector3 modelBasePosition = new Vector3(0f, -0.92f, 0f); public Vector3 cameraPivotPosition = new Vector3(0f, 0.8f, 0f); public float cameraParamsVerticalOffset = 1.37f; public float cameraParamsDepth = -10f; private CharacterCameraParams _cameraParams; public CharacterCameraParams cameraParams { get { //IL_002c: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_cameraParams == (Object)null) { _cameraParams = ScriptableObject.CreateInstance<CharacterCameraParams>(); _cameraParams.data.minPitch = BlendableFloat.op_Implicit(-70f); _cameraParams.data.maxPitch = BlendableFloat.op_Implicit(70f); _cameraParams.data.wallCushion = BlendableFloat.op_Implicit(0.1f); _cameraParams.data.pivotVerticalOffset = BlendableFloat.op_Implicit(cameraParamsVerticalOffset); _cameraParams.data.idealLocalCameraPos = BlendableVector3.op_Implicit(new Vector3(0f, 0f, cameraParamsDepth)); } return _cameraParams; } set { _cameraParams = value; } } } public abstract class ItemDisplaysBase { public void SetItemDisplays(ItemDisplayRuleSet itemDisplayRuleSet) { List<KeyAssetRuleGroup> list = new List<KeyAssetRuleGroup>(); ItemDisplays.LazyInit(); SetItemDisplayRules(list); itemDisplayRuleSet.keyAssetRuleGroups = list.ToArray(); ItemDisplays.DisposeWhenDone(); } protected abstract void SetItemDisplayRules(List<KeyAssetRuleGroup> itemDisplayRules); } public abstract class SurvivorBase<T> : CharacterBase<T> where T : SurvivorBase<T>, new() { public abstract string masterName { get; } public abstract string displayPrefabName { get; } public abstract string survivorTokenPrefix { get; } public abstract UnlockableDef characterUnlockableDef { get; } public abstract GameObject displayPrefab { get; protected set; } public override void InitializeCharacter() { base.InitializeCharacter(); InitializeDisplayPrefab(); InitializeSurvivor(); } protected virtual void InitializeDisplayPrefab() { displayPrefab = Prefabs.CreateDisplayPrefab(assetBundle, displayPrefabName, bodyPrefab); } protected virtual void InitializeSurvivor() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Content.CreateSurvivor(bodyPrefab, displayPrefab, bodyInfo.bodyColor, survivorTokenPrefix, characterUnlockableDef, bodyInfo.sortPosition); } protected virtual void AddCssPreviewSkill(int indexFromEditor, SkillFamily skillFamily, SkillDef skillDef) { CharacterSelectSurvivorPreviewDisplayController component = displayPrefab.GetComponent<CharacterSelectSurvivorPreviewDisplayController>(); if (!Object.op_Implicit((Object)(object)component)) { Log.Error("trying to add skillChangeResponse to null CharacterSelectSurvivorPreviewDisplayController.\nMake sure you created one on your Display prefab in editor"); return; } component.skillChangeResponses[indexFromEditor].triggerSkillFamily = skillFamily; component.skillChangeResponses[indexFromEditor].triggerSkill = skillDef; } protected virtual void AddCssPreviewSkin(int indexFromEditor, SkinDef skinDef) { CharacterSelectSurvivorPreviewDisplayController component = displayPrefab.GetComponent<CharacterSelectSurvivorPreviewDisplayController>(); if (!Object.op_Implicit((Object)(object)component)) { Log.Error("trying to add skinChangeResponse to null CharacterSelectSurvivorPreviewDisplayController.\nMake sure you created one on your Display prefab in editor"); } else { component.skinChangeResponses[indexFromEditor].triggerSkin = skinDef; } } protected virtual void FinalizeCSSPreviewDisplayController() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)displayPrefab)) { return; } CharacterSelectSurvivorPreviewDisplayController component = displayPrefab.GetComponent<CharacterSelectSurvivorPreviewDisplayController>(); if (!Object.op_Implicit((Object)(object)component)) { return; } component.bodyPrefab = bodyPrefab; List<SkillChangeResponse> list = new List<SkillChangeResponse>(); for (int i = 0; i < component.skillChangeResponses.Length; i++) { if ((Object)(object)component.skillChangeResponses[i].triggerSkillFamily != (Object)null) { list.Add(component.skillChangeResponses[i]); } } component.skillChangeResponses = list.ToArray(); } } } namespace DIOOH.Modules.BaseStates { public abstract class BaseMeleeAttack : BaseSkillState, IStepSetter { public int swingIndex; protected string hitboxGroupName = "SwordGroup"; protected DamageTypeCombo damageType = DamageTypeCombo.op_Implicit((DamageType)0); protected float damageCoefficient = 3.5f; protected float procCoefficient = 1f; protected float pushForce = 300f; protected Vector3 bonusForce = Vector3.zero; protected float baseDuration = 1f; protected float attackStartPercentTime = 0.2f; protected float attackEndPercentTime = 0.4f; protected float earlyExitPercentTime = 0.4f; protected float hitStopDuration = 0.012f; protected float attackRecoil = 0.75f; protected float hitHopVelocity = 4f; protected string swingSoundString = ""; protected string hitSoundString = ""; protected string muzzleString = "SwingCenter"; protected string playbackRateParam = "Slash.playbackRate"; protected GameObject swingEffectPrefab; protected GameObject hitEffectPrefab; protected NetworkSoundEventIndex impactSound = (NetworkSoundEventIndex)(-1); protected OverlapAttack attack; public float duration; private bool hasFired; private float hitPauseTimer; protected bool inHitPause; private bool hasHopped; protected float stopwatch; protected Animator animator; private HitStopCachedState hitStopCachedState; private Vector3 storedVelocity; public override void OnEnter() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0050: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) ((BaseState)this).OnEnter(); duration = baseDuration / ((BaseState)this).attackSpeedStat; animator = ((EntityState)this).GetModelAnimator(); ((BaseState)this).StartAimMode(0.5f + duration, false); PlayAttackAnimation(); attack = new OverlapAttack(); attack.damageType = damageType; attack.attacker = ((EntityState)this).gameObject; attack.inflictor = ((EntityState)this).gameObject; attack.teamIndex = ((BaseState)this).GetTeam(); attack.damage = damageCoefficient * ((BaseState)this).damageStat; attack.procCoefficient = procCoefficient; attack.hitEffectPrefab = hitEffectPrefab; attack.forceVector = bonusForce; attack.pushAwayForce = pushForce; attack.hitBoxGroup = ((BaseState)this).FindHitBoxGroup(hitboxGroupName); attack.isCrit = ((BaseState)this).RollCrit(); attack.impactSound = impactSound; ModifyOverlapAttack(attack); } protected virtual void ModifyOverlapAttack(OverlapAttack attack) { } protected virtual void PlayAttackAnimation() { ((EntityState)this).PlayCrossfade("Gesture, Override", "Slash" + (1 + swingIndex), playbackRateParam, duration, 0.05f); } public override void OnExit() { if (inHitPause) { RemoveHitstop(); } ((EntityState)this).OnExit(); } protected virtual void PlaySwingEffect() { EffectManager.SimpleMuzzleFlash(swingEffectPrefab, ((EntityState)this).gameObject, muzzleString, false); } protected virtual void OnHitEnemyAuthority() { Util.PlaySound(hitSoundString, ((EntityState)this).gameObject); if (!hasHopped) { if (Object.op_Implicit((Object)(object)((EntityState)this).characterMotor) && !((EntityState)this).characterMotor.isGrounded && hitHopVelocity > 0f) { ((BaseState)this).SmallHop(((EntityState)this).characterMotor, hitHopVelocity); } hasHopped = true; } ApplyHitstop(); } protected void ApplyHitstop() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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) if (!inHitPause && hitStopDuration > 0f) { storedVelocity = ((EntityState)this).characterMotor.velocity; hitStopCachedState = ((BaseState)this).CreateHitStopCachedState(((EntityState)this).characterMotor, animator, playbackRateParam); hitPauseTimer = hitStopDuration / ((BaseState)this).attackSpeedStat; inHitPause = true; } } private void FireAttack() { if (((EntityState)this).isAuthority && attack.Fire((List<HurtBox>)null)) { OnHitEnemyAuthority(); } } private void EnterAttack() { hasFired = true; Util.PlayAttackSpeedSound(swingSoundString, ((EntityState)this).gameObject, ((BaseState)this).attackSpeedStat); PlaySwingEffect(); if (((EntityState)this).isAuthority) { ((BaseState)this).AddRecoil(-1f * attackRecoil, -2f * attackRecoil, -0.5f * attackRecoil, 0.5f * attackRecoil); } } public override void FixedUpdate() { //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) ((EntityState)this).FixedUpdate(); hitPauseTimer -= Time.deltaTime; if (hitPauseTimer <= 0f && inHitPause) { RemoveHitstop(); } if (!inHitPause) { stopwatch += Time.deltaTime; } else { if (Object.op_Implicit((Object)(object)((EntityState)this).characterMotor)) { ((EntityState)this).characterMotor.velocity = Vector3.zero; } if (Object.op_Implicit((Object)(object)animator)) { animator.SetFloat(playbackRateParam, 0f); } } bool flag = stopwatch >= duration * attackStartPercentTime; bool flag2 = stopwatch >= duration * attackEndPercentTime; if ((flag && !flag2) || (flag && flag2 && !hasFired)) { if (!hasFired) { EnterAttack(); } FireAttack(); } if (stopwatch >= duration && ((EntityState)this).isAuthority) { ((EntityState)this).outer.SetNextStateToMain(); } } private void RemoveHitstop() { //IL_0002: 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_002b: Unknown result type (might be due to invalid IL or missing references) ((BaseState)this).ConsumeHitStopCachedState(hitStopCachedState, ((EntityState)this).characterMotor, animator); inHitPause = false; ((EntityState)this).characterMotor.velocity = storedVelocity; } public override InterruptPriority GetMinimumInterruptPriority() { if (!(stopwatch >= duration * earlyExitPercentTime)) { return (InterruptPriority)1; } return (InterruptPriority)0; } public override void OnSerialize(NetworkWriter writer) { ((BaseSkillState)this).OnSerialize(writer); writer.Write(swingIndex); } public override void OnDeserialize(NetworkReader reader) { ((BaseSkillState)this).OnDeserialize(reader); swingIndex = reader.ReadInt32(); } public void SetStep(int i) { swingIndex = i; } } public abstract class BaseTimedSkillState : BaseSkillState { protected float duration; protected float castStartTime; protected float castEndTime; protected bool hasFired; protected bool isFiring; protected bool hasExited; public abstract float TimedBaseDuration { get; } public abstract float TimedBaseCastStartPercentTime { get; } public virtual float TimedBaseCastEndPercentTime => 1f; public override void OnEnter() { InitDurationValues(); ((BaseState)this).OnEnter(); } protected virtual void InitDurationValues() { duration = TimedBaseDuration / ((BaseState)this).attackSpeedStat; castStartTime = TimedBaseCastStartPercentTime * duration; castEndTime = TimedBaseCastEndPercentTime * duration; } protected virtual void OnCastEnter() { } protected virtual void OnCastFixedUpdate() { } protected virtual void OnCastUpdate() { } protected virtual void OnCastExit() { } public override void FixedUpdate() { ((EntityState)this).FixedUpdate(); bool flag = ((EntityState)this).fixedAge >= castStartTime; bool flag2 = ((EntityState)this).fixedAge >= castEndTime; isFiring = false; if ((flag && !flag2) || (flag && flag2 && !hasFired)) { isFiring = true; OnCastFixedUpdate(); if (!hasFired) { OnCastEnter(); hasFired = true; } } if (flag2 && !hasExited) { hasExited = true; OnCastExit(); } if (((EntityState)this).fixedAge > duration) { ((EntityState)this).outer.SetNextStateToMain(); } } public override void Update() { ((EntityState)this).Update(); if (isFiring) { OnCastUpdate(); } } } public class ExampleTimedSkillState : BaseTimedSkillState { public override float TimedBaseDuration => 1.5f; public override float TimedBaseCastStartPercentTime => 0.2f; public override float TimedBaseCastEndPercentTime => 0.9f; protected override void OnCastEnter() { } protected override void OnCastFixedUpdate() { } protected override void OnCastExit() { } } public class ExampleDelayedSkillState : BaseTimedSkillState { public override float TimedBaseDuration => 1.5f; public override float TimedBaseCastStartPercentTime => 0.2f; protected override void OnCastEnter() { } } } namespace DIOOH.Modules.Achievements { public abstract class BaseMasteryAchievement : BaseAchievement { public abstract string RequiredCharacterBody { get; } public abstract float RequiredDifficultyCoefficient { get; } public override BodyIndex LookUpRequiredBodyIndex() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return BodyCatalog.FindBodyIndex(RequiredCharacterBody); } public override void OnBodyRequirementMet() { ((BaseAchievement)this).OnBodyRequirementMet(); Run.onClientGameOverGlobal += OnClientGameOverGlobal; } public override void OnBodyRequirementBroken() { Run.onClientGameOverGlobal -= OnClientGameOverGlobal; ((BaseAchievement)this).OnBodyRequirementBroken(); } private void OnClientGameOverGlobal(Run run, RunReport runReport) { //IL_0021: 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_0027: 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_0060: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)runReport.gameEnding) || !runReport.gameEnding.isWin) { return; } DifficultyIndex val = runReport.ruleBook.FindDifficulty(); DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(val); if (difficultyDef != null) { bool num = difficultyDef.countsAsHardMode && difficultyDef.scalingValue >= RequiredDifficultyCoefficient; bool flag = difficultyDef.nameToken == "INFERNO_NAME"; bool flag2 = (int)val >= 3 && (int)val <= 10; if (num || flag || flag2) { ((BaseAchievement)this).Grant(); } } } } } namespace DIOOH.Survivors.DIO { public static class DIOBuffs { public static BuffDef timeStopDebuff; public static void Init(AssetBundle assetBundle) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) timeStopDebuff = Content.CreateAndAddBuff("DIOTimeStop", assetBundle.LoadAsset<Sprite>("texTimeStopIcon"), Color.white, canStack: false, isDebuff: true); } } public static class DIOConfig { public static ConfigEntry<float> timeStopDuration; public static ConfigEntry<float> timeStopCooldown; public static ConfigEntry<float> secondaryCooldown; public static ConfigEntry<float> flurryDuration; public static ConfigEntry<float> blockCooldown; public static ConfigEntry<float> voiceVolume; public static void Init() { timeStopDuration = Config.BindAndOptions("DIO", "Time Stop Duration", 4f, 0f, 10f, "How long ZA WARUDO freezes the world, in seconds"); timeStopCooldown = Config.BindAndOptions("DIO", "Time Stop Cooldown", 30f, 0f, 120f, "Cooldown of ZA WARUDO, starts when the stop ends"); secondaryCooldown = Config.BindAndOptions("DIO", "Muda Dash Cooldown", 5f, 0f, 30f, "Cooldown of the MUDA dash"); flurryDuration = Config.BindAndOptions("DIO", "Muda Flurry Base Duration", 2f, 0.5f, 10f, "Base duration of the MUDA flurry beatdown; +0.1s per 1% bonus attack speed"); voiceVolume = Config.BindAndOptions("DIO", "Voice Volume", 0.35f, 0f, 2f, "Volume of DIO's voice lines"); blockCooldown = Config.BindAndOptions("DIO", "Stand Guard Cooldown", 15f, 0f, 60f, "Cooldown of Stand Guard, starts when the block ends"); } } public class RealityRewriteMarker : MonoBehaviour { } public static class DIOHooks { private static BodyIndex dioBodyIndex = (BodyIndex)(-1); private static bool freeChestUsedThisStage; private static bool IsDIO(CharacterBody body) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_001c: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)body)) { return false; } if ((int)dioBodyIndex == -1) { dioBodyIndex = BodyCatalog.FindBodyIndex("DIOBody"); } return body.bodyIndex == dioBodyIndex; } public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invali
plugins/NAudio.Core.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using NAudio.Dmo; using NAudio.Dsp; using NAudio.FileFormats.Wav; using NAudio.Utils; using NAudio.Wave; using NAudio.Wave.SampleProviders; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Mark Heath")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© Mark Heath 2023")] [assembly: AssemblyFileVersion("2.2.1.0")] [assembly: AssemblyInformationalVersion("2.2.1")] [assembly: AssemblyProduct("NAudio.Core")] [assembly: AssemblyTitle("NAudio.Core")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/naudio/NAudio")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.1.0")] [module: UnverifiableCode] namespace NAudio { public enum Manufacturers { Microsoft = 1, Creative = 2, Mediavision = 3, Fujitsu = 4, Artisoft = 20, TurtleBeach = 21, Ibm = 22, Vocaltec = 23, Roland = 24, DspSolutions = 25, Nec = 26, Ati = 27, Wanglabs = 28, Tandy = 29, Voyetra = 30, Antex = 31, IclPS = 32, Intel = 33, Gravis = 34, Val = 35, Interactive = 36, Yamaha = 37, Everex = 38, Echo = 39, Sierra = 40, Cat = 41, Apps = 42, DspGroup = 43, Melabs = 44, ComputerFriends = 45, Ess = 46, Audiofile = 47, Motorola = 48, Canopus = 49, Epson = 50, Truevision = 51, Aztech = 52, Videologic = 53, Scalacs = 54, Korg = 55, Apt = 56, Ics = 57, Iteratedsys = 58, Metheus = 59, Logitech = 60, Winnov = 61, Ncr = 62, Exan = 63, Ast = 64, Willowpond = 65, Sonicfoundry = 66, Vitec = 67, Moscom = 68, Siliconsoft = 69, Supermac = 73, Audiopt = 74, Speechcomp = 76, Ahead = 77, Dolby = 78, Oki = 79, Auravision = 80, Olivetti = 81, Iomagic = 82, Matsushita = 83, Controlres = 84, Xebec = 85, Newmedia = 86, Nms = 87, Lyrrus = 88, Compusic = 89, Opti = 90, Adlacc = 91, Compaq = 92, Dialogic = 93, Insoft = 94, Mptus = 95, Weitek = 96, LernoutAndHauspie = 97, Qciar = 98, Apple = 99, Digital = 100, Motu = 101, Workbit = 102, Ositech = 103, Miro = 104, Cirruslogic = 105, Isolution = 106, Horizons = 107, Concepts = 108, Vtg = 109, Radius = 110, Rockwell = 111, Xyz = 112, Opcode = 113, Voxware = 114, NorthernTelecom = 115, Apicom = 116, Grande = 117, Addx = 118, Wildcat = 119, Rhetorex = 120, Brooktree = 121, Ensoniq = 125, Fast = 126, Nvidia = 127, Oksori = 128, Diacoustics = 129, Gulbransen = 130, KayElemetrics = 131, Crystal = 132, SplashStudios = 133, Quarterdeck = 134, Tdk = 135, DigitalAudioLabs = 136, Seersys = 137, Picturetel = 138, AttMicroelectronics = 139, Osprey = 140, Mediatrix = 141, Soundesigns = 142, Aldigital = 143, SpectrumSignalProcessing = 144, Ecs = 145, Amd = 146, Coredynamics = 147, Canam = 148, Softsound = 149, Norris = 150, Ddd = 151, Euphonics = 152, Precept = 153, CrystalNet = 154, Chromatic = 155, Voiceinfo = 156, Viennasys = 157, Connectix = 158, Gadgetlabs = 159, Frontier = 160, Viona = 161, Casio = 162, Diamondmm = 163, S3 = 164, FraunhoferIis = 172 } public class MmException : Exception { public MmResult Result { get; } public string Function { get; } public MmException(MmResult result, string function) : base(ErrorMessage(result, function)) { Result = result; Function = function; } private static string ErrorMessage(MmResult result, string function) { return $"{result} calling {function}"; } public static void Try(MmResult result, string function) { if (result != 0) { throw new MmException(result, function); } } } public enum MmResult { NoError = 0, UnspecifiedError = 1, BadDeviceId = 2, NotEnabled = 3, AlreadyAllocated = 4, InvalidHandle = 5, NoDriver = 6, MemoryAllocationError = 7, NotSupported = 8, BadErrorNumber = 9, InvalidFlag = 10, InvalidParameter = 11, HandleBusy = 12, InvalidAlias = 13, BadRegistryDatabase = 14, RegistryKeyNotFound = 15, RegistryReadError = 16, RegistryWriteError = 17, RegistryDeleteError = 18, RegistryValueNotFound = 19, NoDriverCallback = 20, MoreData = 21, WaveBadFormat = 32, WaveStillPlaying = 33, WaveHeaderUnprepared = 34, WaveSync = 35, AcmNotPossible = 512, AcmBusy = 513, AcmHeaderUnprepared = 514, AcmCancelled = 515, MixerInvalidLine = 1024, MixerInvalidControl = 1025, MixerInvalidValue = 1026 } } namespace NAudio.CoreAudioApi { public enum CaptureState { Stopped, Starting, Capturing, Stopping } } namespace NAudio.Dmo { public class AudioMediaSubtypes { public static readonly Guid MEDIASUBTYPE_PCM = new Guid("00000001-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_PCMAudioObsolete = new Guid("e436eb8a-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_MPEG1Packet = new Guid("e436eb80-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_MPEG1Payload = new Guid("e436eb81-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_MPEG2_AUDIO = new Guid("e06d802b-db46-11cf-b4d1-00805f6cbbea"); public static readonly Guid MEDIASUBTYPE_DVD_LPCM_AUDIO = new Guid("e06d8032-db46-11cf-b4d1-00805f6cbbea"); public static readonly Guid MEDIASUBTYPE_DRM_Audio = new Guid("00000009-0000-0010-8000-00aa00389b71"); public static readonly Guid MEDIASUBTYPE_IEEE_FLOAT = new Guid("00000003-0000-0010-8000-00aa00389b71"); public static readonly Guid MEDIASUBTYPE_DOLBY_AC3 = new Guid("e06d802c-db46-11cf-b4d1-00805f6cbbea"); public static readonly Guid MEDIASUBTYPE_DOLBY_AC3_SPDIF = new Guid("00000092-0000-0010-8000-00aa00389b71"); public static readonly Guid MEDIASUBTYPE_RAW_SPORT = new Guid("00000240-0000-0010-8000-00aa00389b71"); public static readonly Guid MEDIASUBTYPE_SPDIF_TAG_241h = new Guid("00000241-0000-0010-8000-00aa00389b71"); public static readonly Guid MEDIASUBTYPE_I420 = new Guid("30323449-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_IYUV = new Guid("56555949-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_RGB1 = new Guid("e436eb78-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_RGB24 = new Guid("e436eb7d-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_RGB32 = new Guid("e436eb7e-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_RGB4 = new Guid("e436eb79-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_RGB555 = new Guid("e436eb7c-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_RGB565 = new Guid("e436eb7b-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_RGB8 = new Guid("e436eb7a-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_UYVY = new Guid("59565955-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_VIDEOIMAGE = new Guid("1d4a45f2-e5f6-4b44-8388-f0ae5c0e0c37"); public static readonly Guid MEDIASUBTYPE_YUY2 = new Guid("32595559-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_YV12 = new Guid("31313259-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_YVU9 = new Guid("39555659-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIASUBTYPE_YVYU = new Guid("55595659-0000-0010-8000-00AA00389B71"); public static readonly Guid WMFORMAT_MPEG2Video = new Guid("e06d80e3-db46-11cf-b4d1-00805f6cbbea"); public static readonly Guid WMFORMAT_Script = new Guid("5C8510F2-DEBE-4ca7-BBA5-F07A104F8DFF"); public static readonly Guid WMFORMAT_VideoInfo = new Guid("05589f80-c356-11ce-bf01-00aa0055595a"); public static readonly Guid WMFORMAT_WaveFormatEx = new Guid("05589f81-c356-11ce-bf01-00aa0055595a"); public static readonly Guid WMFORMAT_WebStream = new Guid("da1e6b13-8359-4050-b398-388e965bf00c"); public static readonly Guid WMMEDIASUBTYPE_ACELPnet = new Guid("00000130-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_Base = new Guid("00000000-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_DRM = new Guid("00000009-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_MP3 = new Guid("00000055-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_MP43 = new Guid("3334504D-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_MP4S = new Guid("5334504D-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_M4S2 = new Guid("3253344D-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_P422 = new Guid("32323450-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_MPEG2_VIDEO = new Guid("e06d8026-db46-11cf-b4d1-00805f6cbbea"); public static readonly Guid WMMEDIASUBTYPE_MSS1 = new Guid("3153534D-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_MSS2 = new Guid("3253534D-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_PCM = new Guid("00000001-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WebStream = new Guid("776257d4-c627-41cb-8f81-7ac7ff1c40cc"); public static readonly Guid WMMEDIASUBTYPE_WMAudio_Lossless = new Guid("00000163-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMAudioV2 = new Guid("00000161-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMAudioV7 = new Guid("00000161-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMAudioV8 = new Guid("00000161-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMAudioV9 = new Guid("00000162-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMSP1 = new Guid("0000000A-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMV1 = new Guid("31564D57-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMV2 = new Guid("32564D57-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMV3 = new Guid("33564D57-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMVA = new Guid("41564D57-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WMVP = new Guid("50564D57-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIASUBTYPE_WVP2 = new Guid("32505657-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIATYPE_Audio = new Guid("73647561-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIATYPE_FileTransfer = new Guid("D9E47579-930E-4427-ADFC-AD80F290E470"); public static readonly Guid WMMEDIATYPE_Image = new Guid("34A50FD8-8AA5-4386-81FE-A0EFE0488E31"); public static readonly Guid WMMEDIATYPE_Script = new Guid("73636d64-0000-0010-8000-00AA00389B71"); public static readonly Guid WMMEDIATYPE_Text = new Guid("9BBA1EA7-5AB2-4829-BA57-0940209BCF3E"); public static readonly Guid WMMEDIATYPE_Video = new Guid("73646976-0000-0010-8000-00AA00389B71"); public static readonly Guid WMSCRIPTTYPE_TwoStrings = new Guid("82f38a70-c29f-11d1-97ad-00a0c95ea850"); public static readonly Guid MEDIASUBTYPE_WAVE = new Guid("e436eb8b-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_AU = new Guid("e436eb8c-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIASUBTYPE_AIFF = new Guid("e436eb8d-524f-11ce-9f53-0020af0ba770"); public static readonly Guid[] AudioSubTypes = new Guid[13] { MEDIASUBTYPE_PCM, MEDIASUBTYPE_PCMAudioObsolete, MEDIASUBTYPE_MPEG1Packet, MEDIASUBTYPE_MPEG1Payload, MEDIASUBTYPE_MPEG2_AUDIO, MEDIASUBTYPE_DVD_LPCM_AUDIO, MEDIASUBTYPE_DRM_Audio, MEDIASUBTYPE_IEEE_FLOAT, MEDIASUBTYPE_DOLBY_AC3, MEDIASUBTYPE_DOLBY_AC3_SPDIF, MEDIASUBTYPE_RAW_SPORT, MEDIASUBTYPE_SPDIF_TAG_241h, WMMEDIASUBTYPE_MP3 }; public static readonly string[] AudioSubTypeNames = new string[13] { "PCM", "PCM Obsolete", "MPEG1Packet", "MPEG1Payload", "MPEG2_AUDIO", "DVD_LPCM_AUDIO", "DRM_Audio", "IEEE_FLOAT", "DOLBY_AC3", "DOLBY_AC3_SPDIF", "RAW_SPORT", "SPDIF_TAG_241h", "MP3" }; public static string GetAudioSubtypeName(Guid subType) { for (int i = 0; i < AudioSubTypes.Length; i++) { if (subType == AudioSubTypes[i]) { return AudioSubTypeNames[i]; } } return subType.ToString(); } } } namespace NAudio.Utils { public static class BufferHelpers { public static byte[] Ensure(byte[] buffer, int bytesRequired) { if (buffer == null || buffer.Length < bytesRequired) { buffer = new byte[bytesRequired]; } return buffer; } public static float[] Ensure(float[] buffer, int samplesRequired) { if (buffer == null || buffer.Length < samplesRequired) { buffer = new float[samplesRequired]; } return buffer; } } public static class ByteArrayExtensions { public static bool IsEntirelyNull(byte[] buffer) { for (int i = 0; i < buffer.Length; i++) { if (buffer[i] != 0) { return false; } } return true; } public static string DescribeAsHex(byte[] buffer, string separator, int bytesPerLine) { StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (byte b in buffer) { stringBuilder.AppendFormat("{0:X2}{1}", b, separator); if (++num % bytesPerLine == 0) { stringBuilder.Append("\r\n"); } } stringBuilder.Append("\r\n"); return stringBuilder.ToString(); } public static string DecodeAsString(byte[] buffer, int offset, int length, Encoding encoding) { for (int i = 0; i < length; i++) { if (buffer[offset + i] == 0) { length = i; } } return encoding.GetString(buffer, offset, length); } public static byte[] Concat(params byte[][] byteArrays) { int num = 0; byte[][] array = byteArrays; foreach (byte[] array2 in array) { num += array2.Length; } if (num <= 0) { return new byte[0]; } byte[] array3 = new byte[num]; int num2 = 0; array = byteArrays; foreach (byte[] array4 in array) { Array.Copy(array4, 0, array3, num2, array4.Length); num2 += array4.Length; } return array3; } } public class ByteEncoding : Encoding { public static readonly ByteEncoding Instance = new ByteEncoding(); private ByteEncoding() { } public override int GetByteCount(char[] chars, int index, int count) { return count; } public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { for (int i = 0; i < charCount; i++) { bytes[byteIndex + i] = (byte)chars[charIndex + i]; } return charCount; } public override int GetCharCount(byte[] bytes, int index, int count) { for (int i = 0; i < count; i++) { if (bytes[index + i] == 0) { return i; } } return count; } public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { for (int i = 0; i < byteCount; i++) { byte b = bytes[byteIndex + i]; if (b == 0) { return i; } chars[charIndex + i] = (char)b; } return byteCount; } public override int GetMaxCharCount(int byteCount) { return byteCount; } public override int GetMaxByteCount(int charCount) { return charCount; } } public class ChunkIdentifier { public static int ChunkIdentifierToInt32(string s) { if (s.Length != 4) { throw new ArgumentException("Must be a four character string"); } byte[] bytes = Encoding.UTF8.GetBytes(s); if (bytes.Length != 4) { throw new ArgumentException("Must encode to exactly four bytes"); } return BitConverter.ToInt32(bytes, 0); } } public class CircularBuffer { private readonly byte[] buffer; private readonly object lockObject; private int writePosition; private int readPosition; private int byteCount; public int MaxLength => buffer.Length; public int Count { get { lock (lockObject) { return byteCount; } } } public CircularBuffer(int size) { buffer = new byte[size]; lockObject = new object(); } public int Write(byte[] data, int offset, int count) { lock (lockObject) { int num = 0; if (count > buffer.Length - byteCount) { count = buffer.Length - byteCount; } int num2 = Math.Min(buffer.Length - writePosition, count); Array.Copy(data, offset, buffer, writePosition, num2); writePosition += num2; writePosition %= buffer.Length; num += num2; if (num < count) { Array.Copy(data, offset + num, buffer, writePosition, count - num); writePosition += count - num; num = count; } byteCount += num; return num; } } public int Read(byte[] data, int offset, int count) { lock (lockObject) { if (count > byteCount) { count = byteCount; } int num = 0; int num2 = Math.Min(buffer.Length - readPosition, count); Array.Copy(buffer, readPosition, data, offset, num2); num += num2; readPosition += num2; readPosition %= buffer.Length; if (num < count) { Array.Copy(buffer, readPosition, data, offset + num, count - num); readPosition += count - num; num = count; } byteCount -= num; return num; } } public void Reset() { lock (lockObject) { ResetInner(); } } private void ResetInner() { byteCount = 0; readPosition = 0; writePosition = 0; } public void Advance(int count) { lock (lockObject) { if (count >= byteCount) { ResetInner(); return; } byteCount -= count; readPosition += count; readPosition %= MaxLength; } } } public class Decibels { private const double LOG_2_DB = 8.685889638065037; private const double DB_2_LOG = 0.11512925464970228; public static double LinearToDecibels(double lin) { return Math.Log(lin) * 8.685889638065037; } public static double DecibelsToLinear(double dB) { return Math.Exp(dB * 0.11512925464970228); } } [AttributeUsage(AttributeTargets.Field)] public class FieldDescriptionAttribute : Attribute { public string Description { get; } public FieldDescriptionAttribute(string description) { Description = description; } public override string ToString() { return Description; } } public static class FieldDescriptionHelper { public static string Describe(Type t, Guid guid) { FieldInfo[] fields = t.GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsPublic || !fieldInfo.IsStatic || !(fieldInfo.FieldType == typeof(Guid)) || !((Guid)fieldInfo.GetValue(null) == guid)) { continue; } object[] customAttributes = fieldInfo.GetCustomAttributes(inherit: false); for (int j = 0; j < customAttributes.Length; j++) { if (customAttributes[j] is FieldDescriptionAttribute fieldDescriptionAttribute) { return fieldDescriptionAttribute.Description; } } return fieldInfo.Name; } return guid.ToString(); } } public static class HResult { public const int S_OK = 0; public const int S_FALSE = 1; public const int E_INVALIDARG = -2147483645; private const int FACILITY_AAF = 18; private const int FACILITY_ACS = 20; private const int FACILITY_BACKGROUNDCOPY = 32; private const int FACILITY_CERT = 11; private const int FACILITY_COMPLUS = 17; private const int FACILITY_CONFIGURATION = 33; private const int FACILITY_CONTROL = 10; private const int FACILITY_DISPATCH = 2; private const int FACILITY_DPLAY = 21; private const int FACILITY_HTTP = 25; private const int FACILITY_INTERNET = 12; private const int FACILITY_ITF = 4; private const int FACILITY_MEDIASERVER = 13; private const int FACILITY_MSMQ = 14; private const int FACILITY_NULL = 0; private const int FACILITY_RPC = 1; private const int FACILITY_SCARD = 16; private const int FACILITY_SECURITY = 9; private const int FACILITY_SETUPAPI = 15; private const int FACILITY_SSPI = 9; private const int FACILITY_STORAGE = 3; private const int FACILITY_SXS = 23; private const int FACILITY_UMI = 22; private const int FACILITY_URT = 19; private const int FACILITY_WIN32 = 7; private const int FACILITY_WINDOWS = 8; private const int FACILITY_WINDOWS_CE = 24; public static int MAKE_HRESULT(int sev, int fac, int code) { return (sev << 31) | (fac << 16) | code; } public static int GetHResult(this COMException exception) { return exception.ErrorCode; } } public static class IEEE { private static double UnsignedToFloat(ulong u) { return (double)(long)(u - int.MaxValue - 1) + 2147483648.0; } private static double ldexp(double x, int exp) { return x * Math.Pow(2.0, exp); } private static double frexp(double x, out int exp) { exp = (int)Math.Floor(Math.Log(x) / Math.Log(2.0)) + 1; return 1.0 - (Math.Pow(2.0, exp) - x) / Math.Pow(2.0, exp); } private static ulong FloatToUnsigned(double f) { return (ulong)((long)(f - 2147483648.0) + int.MaxValue + 1); } public static byte[] ConvertToIeeeExtended(double num) { int num2; if (num < 0.0) { num2 = 32768; num *= -1.0; } else { num2 = 0; } ulong num4; ulong num5; int num3; if (num == 0.0) { num3 = 0; num4 = 0uL; num5 = 0uL; } else { double num6 = frexp(num, out num3); if (num3 > 16384 || !(num6 < 1.0)) { num3 = num2 | 0x7FFF; num4 = 0uL; num5 = 0uL; } else { num3 += 16382; if (num3 < 0) { num6 = ldexp(num6, num3); num3 = 0; } num3 |= num2; num6 = ldexp(num6, 32); double num7 = Math.Floor(num6); num4 = FloatToUnsigned(num7); num6 = ldexp(num6 - num7, 32); num7 = Math.Floor(num6); num5 = FloatToUnsigned(num7); } } return new byte[10] { (byte)(num3 >> 8), (byte)num3, (byte)(num4 >> 24), (byte)(num4 >> 16), (byte)(num4 >> 8), (byte)num4, (byte)(num5 >> 24), (byte)(num5 >> 16), (byte)(num5 >> 8), (byte)num5 }; } public static double ConvertFromIeeeExtended(byte[] bytes) { if (bytes.Length != 10) { throw new Exception("Incorrect length for IEEE extended."); } int num = ((bytes[0] & 0x7F) << 8) | bytes[1]; uint num2 = (uint)((bytes[2] << 24) | (bytes[3] << 16) | (bytes[4] << 8) | bytes[5]); uint num3 = (uint)((bytes[6] << 24) | (bytes[7] << 16) | (bytes[8] << 8) | bytes[9]); double num4; if (num == 0 && num2 == 0 && num3 == 0) { num4 = 0.0; } else if (num == 32767) { num4 = double.NaN; } else { num -= 16383; num4 = ldexp(UnsignedToFloat(num2), num -= 31); num4 += ldexp(UnsignedToFloat(num3), num -= 32); } if ((bytes[0] & 0x80) == 128) { return 0.0 - num4; } return num4; } } public class IgnoreDisposeStream : Stream { public Stream SourceStream { get; private set; } public bool IgnoreDispose { get; set; } public override bool CanRead => SourceStream.CanRead; public override bool CanSeek => SourceStream.CanSeek; public override bool CanWrite => SourceStream.CanWrite; public override long Length => SourceStream.Length; public override long Position { get { return SourceStream.Position; } set { SourceStream.Position = value; } } public IgnoreDisposeStream(Stream sourceStream) { SourceStream = sourceStream; IgnoreDispose = true; } public override void Flush() { SourceStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return SourceStream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return SourceStream.Seek(offset, origin); } public override void SetLength(long value) { SourceStream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { SourceStream.Write(buffer, offset, count); } protected override void Dispose(bool disposing) { if (!IgnoreDispose) { SourceStream.Dispose(); SourceStream = null; } } } public static class NativeMethods { [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string dllToLoad); [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); [DllImport("kernel32.dll")] public static extern bool FreeLibrary(IntPtr hModule); } public static class WavePositionExtensions { public static TimeSpan GetPositionTimeSpan(this IWavePosition @this) { return TimeSpan.FromMilliseconds((double)(@this.GetPosition() / (@this.OutputWaveFormat.Channels * @this.OutputWaveFormat.BitsPerSample / 8)) * 1000.0 / (double)@this.OutputWaveFormat.SampleRate); } } } namespace NAudio.FileFormats.Wav { public class WaveFileChunkReader { private WaveFormat waveFormat; private long dataChunkPosition; private long dataChunkLength; private List<RiffChunk> riffChunks; private readonly bool strictMode; private bool isRf64; private readonly bool storeAllChunks; private long riffSize; public WaveFormat WaveFormat => waveFormat; public long DataChunkPosition => dataChunkPosition; public long DataChunkLength => dataChunkLength; public List<RiffChunk> RiffChunks => riffChunks; public WaveFileChunkReader() { storeAllChunks = true; strictMode = false; } public void ReadWaveHeader(Stream stream) { dataChunkPosition = -1L; waveFormat = null; riffChunks = new List<RiffChunk>(); dataChunkLength = 0L; BinaryReader binaryReader = new BinaryReader(stream); ReadRiffHeader(binaryReader); riffSize = binaryReader.ReadUInt32(); if (binaryReader.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE")) { throw new FormatException("Not a WAVE file - no WAVE header"); } if (isRf64) { ReadDs64Chunk(binaryReader); } int num = ChunkIdentifier.ChunkIdentifierToInt32("data"); int num2 = ChunkIdentifier.ChunkIdentifierToInt32("fmt "); long num3 = Math.Min(riffSize + 8, stream.Length); while (stream.Position <= num3 - 8) { int num4 = binaryReader.ReadInt32(); uint num5 = binaryReader.ReadUInt32(); if (num4 == num) { dataChunkPosition = stream.Position; if (!isRf64) { dataChunkLength = num5; } stream.Position += num5; } else if (num4 == num2) { if (num5 > int.MaxValue) { throw new InvalidDataException($"Format chunk length must be between 0 and {int.MaxValue}."); } waveFormat = WaveFormat.FromFormatChunk(binaryReader, (int)num5); } else { if (num5 > stream.Length - stream.Position) { if (!strictMode) { } break; } if (storeAllChunks) { if (num5 > int.MaxValue) { throw new InvalidDataException($"RiffChunk chunk length must be between 0 and {int.MaxValue}."); } riffChunks.Add(GetRiffChunk(stream, num4, (int)num5)); } stream.Position += num5; } if (num5 % 2 != 0 && binaryReader.PeekChar() == 0) { stream.Position++; } } if (waveFormat == null) { throw new FormatException("Invalid WAV file - No fmt chunk found"); } if (dataChunkPosition == -1) { throw new FormatException("Invalid WAV file - No data chunk found"); } } private void ReadDs64Chunk(BinaryReader reader) { int num = ChunkIdentifier.ChunkIdentifierToInt32("ds64"); if (reader.ReadInt32() != num) { throw new FormatException("Invalid RF64 WAV file - No ds64 chunk found"); } int num2 = reader.ReadInt32(); riffSize = reader.ReadInt64(); dataChunkLength = reader.ReadInt64(); reader.ReadInt64(); reader.ReadBytes(num2 - 24); } private static RiffChunk GetRiffChunk(Stream stream, int chunkIdentifier, int chunkLength) { return new RiffChunk(chunkIdentifier, chunkLength, stream.Position); } private void ReadRiffHeader(BinaryReader br) { int num = br.ReadInt32(); if (num == ChunkIdentifier.ChunkIdentifierToInt32("RF64")) { isRf64 = true; } else if (num != ChunkIdentifier.ChunkIdentifierToInt32("RIFF")) { throw new FormatException("Not a WAVE file - no RIFF header"); } } } } namespace NAudio.SoundFont { public class Generator { public GeneratorEnum GeneratorType { get; set; } public ushort UInt16Amount { get; set; } public short Int16Amount { get { return (short)UInt16Amount; } set { UInt16Amount = (ushort)value; } } public byte LowByteAmount { get { return (byte)(UInt16Amount & 0xFFu); } set { UInt16Amount &= 65280; UInt16Amount += value; } } public byte HighByteAmount { get { return (byte)((UInt16Amount & 0xFF00) >> 8); } set { UInt16Amount &= 255; UInt16Amount += (ushort)(value << 8); } } public Instrument Instrument { get; set; } public SampleHeader SampleHeader { get; set; } public override string ToString() { if (GeneratorType == GeneratorEnum.Instrument) { return "Generator Instrument " + Instrument.Name; } if (GeneratorType == GeneratorEnum.SampleID) { return $"Generator SampleID {SampleHeader}"; } return $"Generator {GeneratorType} {UInt16Amount}"; } } internal class GeneratorBuilder : StructureBuilder<Generator> { public override int Length => 4; public Generator[] Generators => data.ToArray(); public override Generator Read(BinaryReader br) { Generator generator = new Generator(); generator.GeneratorType = (GeneratorEnum)br.ReadUInt16(); generator.UInt16Amount = br.ReadUInt16(); data.Add(generator); return generator; } public override void Write(BinaryWriter bw, Generator o) { } public void Load(Instrument[] instruments) { Generator[] generators = Generators; foreach (Generator generator in generators) { if (generator.GeneratorType == GeneratorEnum.Instrument) { generator.Instrument = instruments[generator.UInt16Amount]; } } } public void Load(SampleHeader[] sampleHeaders) { Generator[] generators = Generators; foreach (Generator generator in generators) { if (generator.GeneratorType == GeneratorEnum.SampleID) { generator.SampleHeader = sampleHeaders[generator.UInt16Amount]; } } } } public enum GeneratorEnum { StartAddressOffset, EndAddressOffset, StartLoopAddressOffset, EndLoopAddressOffset, StartAddressCoarseOffset, ModulationLFOToPitch, VibratoLFOToPitch, ModulationEnvelopeToPitch, InitialFilterCutoffFrequency, InitialFilterQ, ModulationLFOToFilterCutoffFrequency, ModulationEnvelopeToFilterCutoffFrequency, EndAddressCoarseOffset, ModulationLFOToVolume, Unused1, ChorusEffectsSend, ReverbEffectsSend, Pan, Unused2, Unused3, Unused4, DelayModulationLFO, FrequencyModulationLFO, DelayVibratoLFO, FrequencyVibratoLFO, DelayModulationEnvelope, AttackModulationEnvelope, HoldModulationEnvelope, DecayModulationEnvelope, SustainModulationEnvelope, ReleaseModulationEnvelope, KeyNumberToModulationEnvelopeHold, KeyNumberToModulationEnvelopeDecay, DelayVolumeEnvelope, AttackVolumeEnvelope, HoldVolumeEnvelope, DecayVolumeEnvelope, SustainVolumeEnvelope, ReleaseVolumeEnvelope, KeyNumberToVolumeEnvelopeHold, KeyNumberToVolumeEnvelopeDecay, Instrument, Reserved1, KeyRange, VelocityRange, StartLoopAddressCoarseOffset, KeyNumber, Velocity, InitialAttenuation, Reserved2, EndLoopAddressCoarseOffset, CoarseTune, FineTune, SampleID, SampleModes, Reserved3, ScaleTuning, ExclusiveClass, OverridingRootKey, Unused5, UnusedEnd } public class InfoChunk { public SFVersion SoundFontVersion { get; } public string WaveTableSoundEngine { get; set; } public string BankName { get; set; } public string DataROM { get; set; } public string CreationDate { get; set; } public string Author { get; set; } public string TargetProduct { get; set; } public string Copyright { get; set; } public string Comments { get; set; } public string Tools { get; set; } public SFVersion ROMVersion { get; set; } internal InfoChunk(RiffChunk chunk) { bool flag = false; bool flag2 = false; if (chunk.ReadChunkID() != "INFO") { throw new InvalidDataException("Not an INFO chunk"); } RiffChunk nextSubChunk; while ((nextSubChunk = chunk.GetNextSubChunk()) != null) { switch (nextSubChunk.ChunkID) { case "ifil": flag = true; SoundFontVersion = nextSubChunk.GetDataAsStructure(new SFVersionBuilder()); break; case "isng": WaveTableSoundEngine = nextSubChunk.GetDataAsString(); break; case "INAM": flag2 = true; BankName = nextSubChunk.GetDataAsString(); break; case "irom": DataROM = nextSubChunk.GetDataAsString(); break; case "iver": ROMVersion = nextSubChunk.GetDataAsStructure(new SFVersionBuilder()); break; case "ICRD": CreationDate = nextSubChunk.GetDataAsString(); break; case "IENG": Author = nextSubChunk.GetDataAsString(); break; case "IPRD": TargetProduct = nextSubChunk.GetDataAsString(); break; case "ICOP": Copyright = nextSubChunk.GetDataAsString(); break; case "ICMT": Comments = nextSubChunk.GetDataAsString(); break; case "ISFT": Tools = nextSubChunk.GetDataAsString(); break; default: throw new InvalidDataException("Unknown chunk type " + nextSubChunk.ChunkID); } } if (!flag) { throw new InvalidDataException("Missing SoundFont version information"); } if (!flag2) { throw new InvalidDataException("Missing SoundFont name information"); } } public override string ToString() { return string.Format("Bank Name: {0}\r\nAuthor: {1}\r\nCopyright: {2}\r\nCreation Date: {3}\r\nTools: {4}\r\nComments: {5}\r\nSound Engine: {6}\r\nSoundFont Version: {7}\r\nTarget Product: {8}\r\nData ROM: {9}\r\nROM Version: {10}", BankName, Author, Copyright, CreationDate, Tools, "TODO-fix comments", WaveTableSoundEngine, SoundFontVersion, TargetProduct, DataROM, ROMVersion); } } public class Instrument { internal ushort startInstrumentZoneIndex; internal ushort endInstrumentZoneIndex; public string Name { get; set; } public Zone[] Zones { get; set; } public override string ToString() { return Name; } } internal class InstrumentBuilder : StructureBuilder<Instrument> { private Instrument lastInstrument; public override int Length => 22; public Instrument[] Instruments => data.ToArray(); public override Instrument Read(BinaryReader br) { Instrument instrument = new Instrument(); string text = Encoding.UTF8.GetString(br.ReadBytes(20), 0, 20); if (text.IndexOf('\0') >= 0) { text = text.Substring(0, text.IndexOf('\0')); } instrument.Name = text; instrument.startInstrumentZoneIndex = br.ReadUInt16(); if (lastInstrument != null) { lastInstrument.endInstrumentZoneIndex = (ushort)(instrument.startInstrumentZoneIndex - 1); } data.Add(instrument); lastInstrument = instrument; return instrument; } public override void Write(BinaryWriter bw, Instrument instrument) { } public void LoadZones(Zone[] zones) { for (int i = 0; i < data.Count - 1; i++) { Instrument instrument = data[i]; instrument.Zones = new Zone[instrument.endInstrumentZoneIndex - instrument.startInstrumentZoneIndex + 1]; Array.Copy(zones, instrument.startInstrumentZoneIndex, instrument.Zones, 0, instrument.Zones.Length); } data.RemoveAt(data.Count - 1); } } public enum TransformEnum { Linear } public class Modulator { public ModulatorType SourceModulationData { get; set; } public GeneratorEnum DestinationGenerator { get; set; } public short Amount { get; set; } public ModulatorType SourceModulationAmount { get; set; } public TransformEnum SourceTransform { get; set; } public override string ToString() { return $"Modulator {SourceModulationData} {DestinationGenerator} {Amount} {SourceModulationAmount} {SourceTransform}"; } } internal class ModulatorBuilder : StructureBuilder<Modulator> { public override int Length => 10; public Modulator[] Modulators => data.ToArray(); public override Modulator Read(BinaryReader br) { Modulator modulator = new Modulator(); modulator.SourceModulationData = new ModulatorType(br.ReadUInt16()); modulator.DestinationGenerator = (GeneratorEnum)br.ReadUInt16(); modulator.Amount = br.ReadInt16(); modulator.SourceModulationAmount = new ModulatorType(br.ReadUInt16()); modulator.SourceTransform = (TransformEnum)br.ReadUInt16(); data.Add(modulator); return modulator; } public override void Write(BinaryWriter bw, Modulator o) { } } public enum ControllerSourceEnum { NoController = 0, NoteOnVelocity = 2, NoteOnKeyNumber = 3, PolyPressure = 10, ChannelPressure = 13, PitchWheel = 14, PitchWheelSensitivity = 16 } public enum SourceTypeEnum { Linear, Concave, Convex, Switch } public class ModulatorType { private bool polarity; private bool direction; private bool midiContinuousController; private ControllerSourceEnum controllerSource; private SourceTypeEnum sourceType; private ushort midiContinuousControllerNumber; internal ModulatorType(ushort raw) { polarity = (raw & 0x200) == 512; direction = (raw & 0x100) == 256; midiContinuousController = (raw & 0x80) == 128; sourceType = (SourceTypeEnum)((raw & 0xFC00) >> 10); controllerSource = (ControllerSourceEnum)(raw & 0x7F); midiContinuousControllerNumber = (ushort)(raw & 0x7Fu); } public override string ToString() { if (midiContinuousController) { return $"{sourceType} CC{midiContinuousControllerNumber}"; } return $"{sourceType} {controllerSource}"; } } public class Preset { internal ushort startPresetZoneIndex; internal ushort endPresetZoneIndex; internal uint library; internal uint genre; internal uint morphology; public string Name { get; set; } public ushort PatchNumber { get; set; } public ushort Bank { get; set; } public Zone[] Zones { get; set; } public override string ToString() { return $"{Bank}-{PatchNumber} {Name}"; } } internal class PresetBuilder : StructureBuilder<Preset> { private Preset lastPreset; public override int Length => 38; public Preset[] Presets => data.ToArray(); public override Preset Read(BinaryReader br) { Preset preset = new Preset(); string text = Encoding.UTF8.GetString(br.ReadBytes(20), 0, 20); if (text.IndexOf('\0') >= 0) { text = text.Substring(0, text.IndexOf('\0')); } preset.Name = text; preset.PatchNumber = br.ReadUInt16(); preset.Bank = br.ReadUInt16(); preset.startPresetZoneIndex = br.ReadUInt16(); preset.library = br.ReadUInt32(); preset.genre = br.ReadUInt32(); preset.morphology = br.ReadUInt32(); if (lastPreset != null) { lastPreset.endPresetZoneIndex = (ushort)(preset.startPresetZoneIndex - 1); } data.Add(preset); lastPreset = preset; return preset; } public override void Write(BinaryWriter bw, Preset preset) { } public void LoadZones(Zone[] presetZones) { for (int i = 0; i < data.Count - 1; i++) { Preset preset = data[i]; preset.Zones = new Zone[preset.endPresetZoneIndex - preset.startPresetZoneIndex + 1]; Array.Copy(presetZones, preset.startPresetZoneIndex, preset.Zones, 0, preset.Zones.Length); } data.RemoveAt(data.Count - 1); } } public class PresetsChunk { private PresetBuilder presetHeaders = new PresetBuilder(); private ZoneBuilder presetZones = new ZoneBuilder(); private ModulatorBuilder presetZoneModulators = new ModulatorBuilder(); private GeneratorBuilder presetZoneGenerators = new GeneratorBuilder(); private InstrumentBuilder instruments = new InstrumentBuilder(); private ZoneBuilder instrumentZones = new ZoneBuilder(); private ModulatorBuilder instrumentZoneModulators = new ModulatorBuilder(); private GeneratorBuilder instrumentZoneGenerators = new GeneratorBuilder(); private SampleHeaderBuilder sampleHeaders = new SampleHeaderBuilder(); public Preset[] Presets => presetHeaders.Presets; public Instrument[] Instruments => instruments.Instruments; public SampleHeader[] SampleHeaders => sampleHeaders.SampleHeaders; internal PresetsChunk(RiffChunk chunk) { string text = chunk.ReadChunkID(); if (text != "pdta") { throw new InvalidDataException($"Not a presets data chunk ({text})"); } RiffChunk nextSubChunk; while ((nextSubChunk = chunk.GetNextSubChunk()) != null) { switch (nextSubChunk.ChunkID) { case "phdr": case "PHDR": nextSubChunk.GetDataAsStructureArray(presetHeaders); break; case "pbag": case "PBAG": nextSubChunk.GetDataAsStructureArray(presetZones); break; case "pmod": case "PMOD": nextSubChunk.GetDataAsStructureArray(presetZoneModulators); break; case "pgen": case "PGEN": nextSubChunk.GetDataAsStructureArray(presetZoneGenerators); break; case "inst": case "INST": nextSubChunk.GetDataAsStructureArray(instruments); break; case "ibag": case "IBAG": nextSubChunk.GetDataAsStructureArray(instrumentZones); break; case "imod": case "IMOD": nextSubChunk.GetDataAsStructureArray(instrumentZoneModulators); break; case "igen": case "IGEN": nextSubChunk.GetDataAsStructureArray(instrumentZoneGenerators); break; case "shdr": case "SHDR": nextSubChunk.GetDataAsStructureArray(sampleHeaders); break; default: throw new InvalidDataException($"Unknown chunk type {nextSubChunk.ChunkID}"); } } instrumentZoneGenerators.Load(sampleHeaders.SampleHeaders); instrumentZones.Load(instrumentZoneModulators.Modulators, instrumentZoneGenerators.Generators); instruments.LoadZones(instrumentZones.Zones); presetZoneGenerators.Load(instruments.Instruments); presetZones.Load(presetZoneModulators.Modulators, presetZoneGenerators.Generators); presetHeaders.LoadZones(presetZones.Zones); sampleHeaders.RemoveEOS(); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Preset Headers:\r\n"); Preset[] presets = presetHeaders.Presets; foreach (Preset arg in presets) { stringBuilder.AppendFormat("{0}\r\n", arg); } stringBuilder.Append("Instruments:\r\n"); Instrument[] array = instruments.Instruments; foreach (Instrument arg2 in array) { stringBuilder.AppendFormat("{0}\r\n", arg2); } return stringBuilder.ToString(); } } internal class RiffChunk { private string chunkID; private BinaryReader riffFile; public string ChunkID { get { return chunkID; } set { if (value == null) { throw new ArgumentNullException("ChunkID may not be null"); } if (value.Length != 4) { throw new ArgumentException("ChunkID must be four characters"); } chunkID = value; } } public uint ChunkSize { get; private set; } public long DataOffset { get; private set; } public static RiffChunk GetTopLevelChunk(BinaryReader file) { RiffChunk riffChunk = new RiffChunk(file); riffChunk.ReadChunk(); return riffChunk; } private RiffChunk(BinaryReader file) { riffFile = file; chunkID = "????"; ChunkSize = 0u; DataOffset = 0L; } public string ReadChunkID() { byte[] array = riffFile.ReadBytes(4); if (array.Length != 4) { throw new InvalidDataException("Couldn't read Chunk ID"); } return ByteEncoding.Instance.GetString(array, 0, array.Length); } private void ReadChunk() { chunkID = ReadChunkID(); ChunkSize = riffFile.ReadUInt32(); DataOffset = riffFile.BaseStream.Position; } public RiffChunk GetNextSubChunk() { if (riffFile.BaseStream.Position + 8 < DataOffset + ChunkSize) { RiffChunk riffChunk = new RiffChunk(riffFile); riffChunk.ReadChunk(); return riffChunk; } return null; } public byte[] GetData() { riffFile.BaseStream.Position = DataOffset; byte[] array = riffFile.ReadBytes((int)ChunkSize); if (array.Length != ChunkSize) { throw new InvalidDataException($"Couldn't read chunk's data Chunk: {this}, read {array.Length} bytes"); } return array; } public string GetDataAsString() { byte[] data = GetData(); if (data == null) { return null; } return ByteEncoding.Instance.GetString(data, 0, data.Length); } public T GetDataAsStructure<T>(StructureBuilder<T> s) { riffFile.BaseStream.Position = DataOffset; if (s.Length != ChunkSize) { throw new InvalidDataException($"Chunk size is: {ChunkSize} so can't read structure of: {s.Length}"); } return s.Read(riffFile); } public T[] GetDataAsStructureArray<T>(StructureBuilder<T> s) { riffFile.BaseStream.Position = DataOffset; if (ChunkSize % s.Length != 0L) { throw new InvalidDataException($"Chunk size is: {ChunkSize} not a multiple of structure size: {s.Length}"); } int num = (int)(ChunkSize / s.Length); T[] array = new T[num]; for (int i = 0; i < num; i++) { array[i] = s.Read(riffFile); } return array; } public override string ToString() { return $"RiffChunk ID: {ChunkID} Size: {ChunkSize} Data Offset: {DataOffset}"; } } internal class SampleDataChunk { public byte[] SampleData { get; private set; } public SampleDataChunk(RiffChunk chunk) { string text = chunk.ReadChunkID(); if (text != "sdta") { throw new InvalidDataException("Not a sample data chunk (" + text + ")"); } SampleData = chunk.GetData(); } } public class SampleHeader { public string SampleName; public uint Start; public uint End; public uint StartLoop; public uint EndLoop; public uint SampleRate; public byte OriginalPitch; public sbyte PitchCorrection; public ushort SampleLink; public SFSampleLink SFSampleLink; public override string ToString() { return SampleName; } } internal class SampleHeaderBuilder : StructureBuilder<SampleHeader> { public override int Length => 46; public SampleHeader[] SampleHeaders => data.ToArray(); public override SampleHeader Read(BinaryReader br) { SampleHeader sampleHeader = new SampleHeader(); byte[] array = br.ReadBytes(20); sampleHeader.SampleName = ByteEncoding.Instance.GetString(array, 0, array.Length); sampleHeader.Start = br.ReadUInt32(); sampleHeader.End = br.ReadUInt32(); sampleHeader.StartLoop = br.ReadUInt32(); sampleHeader.EndLoop = br.ReadUInt32(); sampleHeader.SampleRate = br.ReadUInt32(); sampleHeader.OriginalPitch = br.ReadByte(); sampleHeader.PitchCorrection = br.ReadSByte(); sampleHeader.SampleLink = br.ReadUInt16(); sampleHeader.SFSampleLink = (SFSampleLink)br.ReadUInt16(); data.Add(sampleHeader); return sampleHeader; } public override void Write(BinaryWriter bw, SampleHeader sampleHeader) { } internal void RemoveEOS() { data.RemoveAt(data.Count - 1); } } public enum SampleMode { NoLoop, LoopContinuously, ReservedNoLoop, LoopAndContinue } public enum SFSampleLink : ushort { MonoSample = 1, RightSample = 2, LeftSample = 4, LinkedSample = 8, RomMonoSample = 32769, RomRightSample = 32770, RomLeftSample = 32772, RomLinkedSample = 32776 } public class SFVersion { public short Major { get; set; } public short Minor { get; set; } } internal class SFVersionBuilder : StructureBuilder<SFVersion> { public override int Length => 4; public override SFVersion Read(BinaryReader br) { SFVersion sFVersion = new SFVersion(); sFVersion.Major = br.ReadInt16(); sFVersion.Minor = br.ReadInt16(); data.Add(sFVersion); return sFVersion; } public override void Write(BinaryWriter bw, SFVersion v) { bw.Write(v.Major); bw.Write(v.Minor); } } public class SoundFont { private InfoChunk info; private PresetsChunk presetsChunk; private SampleDataChunk sampleData; public InfoChunk FileInfo => info; public Preset[] Presets => presetsChunk.Presets; public Instrument[] Instruments => presetsChunk.Instruments; public SampleHeader[] SampleHeaders => presetsChunk.SampleHeaders; public byte[] SampleData => sampleData.SampleData; public SoundFont(string fileName) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read)) { } public SoundFont(Stream sfFile) { using (sfFile) { RiffChunk topLevelChunk = RiffChunk.GetTopLevelChunk(new BinaryReader(sfFile)); if (topLevelChunk.ChunkID == "RIFF") { string text = topLevelChunk.ReadChunkID(); if (text != "sfbk") { throw new InvalidDataException($"Not a SoundFont ({text})"); } RiffChunk nextSubChunk = topLevelChunk.GetNextSubChunk(); if (nextSubChunk.ChunkID == "LIST") { info = new InfoChunk(nextSubChunk); RiffChunk nextSubChunk2 = topLevelChunk.GetNextSubChunk(); sampleData = new SampleDataChunk(nextSubChunk2); nextSubChunk2 = topLevelChunk.GetNextSubChunk(); presetsChunk = new PresetsChunk(nextSubChunk2); return; } throw new InvalidDataException($"Not info list found ({nextSubChunk.ChunkID})"); } throw new InvalidDataException("Not a RIFF file"); } } public override string ToString() { return $"Info Chunk:\r\n{info}\r\nPresets Chunk:\r\n{presetsChunk}"; } } internal abstract class StructureBuilder<T> { protected List<T> data; public abstract int Length { get; } public T[] Data => data.ToArray(); public StructureBuilder() { Reset(); } public abstract T Read(BinaryReader br); public abstract void Write(BinaryWriter bw, T o); public void Reset() { data = new List<T>(); } } public class Zone { internal ushort generatorIndex; internal ushort modulatorIndex; internal ushort generatorCount; internal ushort modulatorCount; public Modulator[] Modulators { get; set; } public Generator[] Generators { get; set; } public override string ToString() { return $"Zone {generatorCount} Gens:{generatorIndex} {modulatorCount} Mods:{modulatorIndex}"; } } internal class ZoneBuilder : StructureBuilder<Zone> { private Zone lastZone; public Zone[] Zones => data.ToArray(); public override int Length => 4; public override Zone Read(BinaryReader br) { Zone zone = new Zone(); zone.generatorIndex = br.ReadUInt16(); zone.modulatorIndex = br.ReadUInt16(); if (lastZone != null) { lastZone.generatorCount = (ushort)(zone.generatorIndex - lastZone.generatorIndex); lastZone.modulatorCount = (ushort)(zone.modulatorIndex - lastZone.modulatorIndex); } data.Add(zone); lastZone = zone; return zone; } public override void Write(BinaryWriter bw, Zone zone) { } public void Load(Modulator[] modulators, Generator[] generators) { for (int i = 0; i < data.Count - 1; i++) { Zone zone = data[i]; zone.Generators = new Generator[zone.generatorCount]; Array.Copy(generators, zone.generatorIndex, zone.Generators, 0, zone.generatorCount); zone.Modulators = new Modulator[zone.modulatorCount]; Array.Copy(modulators, zone.modulatorIndex, zone.Modulators, 0, zone.modulatorCount); } data.RemoveAt(data.Count - 1); } } } namespace NAudio.Wave { public enum ChannelMode { Stereo, JointStereo, DualChannel, Mono } public class Id3v2Tag { private long tagStartPosition; private long tagEndPosition; private byte[] rawData; public byte[] RawData => rawData; public static Id3v2Tag ReadTag(Stream input) { try { return new Id3v2Tag(input); } catch (FormatException) { return null; } } public static Id3v2Tag Create(IEnumerable<KeyValuePair<string, string>> tags) { return ReadTag(CreateId3v2TagStream(tags)); } private static byte[] FrameSizeToBytes(int n) { byte[] bytes = BitConverter.GetBytes(n); Array.Reverse((Array)bytes); return bytes; } private static byte[] CreateId3v2Frame(string key, string value) { if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException("key"); } if (string.IsNullOrEmpty(value)) { throw new ArgumentNullException("value"); } if (key.Length != 4) { throw new ArgumentOutOfRangeException("key", "key " + key + " must be 4 characters long"); } byte[] array = new byte[2] { 255, 254 }; byte[] array2 = new byte[3]; byte[] array3 = new byte[2]; byte[] array4 = ((!(key == "COMM")) ? ByteArrayExtensions.Concat(new byte[1] { 1 }, array, Encoding.Unicode.GetBytes(value)) : ByteArrayExtensions.Concat(new byte[1] { 1 }, array2, array3, array, Encoding.Unicode.GetBytes(value))); return ByteArrayExtensions.Concat(Encoding.UTF8.GetBytes(key), FrameSizeToBytes(array4.Length), new byte[2], array4); } private static byte[] GetId3TagHeaderSize(int size) { byte[] array = new byte[4]; for (int num = array.Length - 1; num >= 0; num--) { array[num] = (byte)(size % 128); size /= 128; } return array; } private static byte[] CreateId3v2TagHeader(IEnumerable<byte[]> frames) { int num = 0; foreach (byte[] frame in frames) { num += frame.Length; } return ByteArrayExtensions.Concat(Encoding.UTF8.GetBytes("ID3"), new byte[2] { 3, 0 }, new byte[1], GetId3TagHeaderSize(num)); } private static Stream CreateId3v2TagStream(IEnumerable<KeyValuePair<string, string>> tags) { List<byte[]> list = new List<byte[]>(); foreach (KeyValuePair<string, string> tag in tags) { list.Add(CreateId3v2Frame(tag.Key, tag.Value)); } byte[] array = CreateId3v2TagHeader(list); MemoryStream memoryStream = new MemoryStream(); memoryStream.Write(array, 0, array.Length); foreach (byte[] item in list) { memoryStream.Write(item, 0, item.Length); } memoryStream.Position = 0L; return memoryStream; } private Id3v2Tag(Stream input) { tagStartPosition = input.Position; BinaryReader binaryReader = new BinaryReader(input); byte[] array = binaryReader.ReadBytes(10); if (array.Length >= 3 && array[0] == 73 && array[1] == 68 && array[2] == 51) { if ((array[5] & 0x40) == 64) { byte[] array2 = binaryReader.ReadBytes(4); _ = array2[0] * 2097152 + array2[1] * 16384 + array2[2] * 128; _ = array2[3]; } int num = array[6] * 2097152; num += array[7] * 16384; num += array[8] * 128; num += array[9]; binaryReader.ReadBytes(num); if ((array[5] & 0x10) == 16) { binaryReader.ReadBytes(10); } tagEndPosition = input.Position; input.Position = tagStartPosition; rawData = binaryReader.ReadBytes((int)(tagEndPosition - tagStartPosition)); return; } input.Position = tagStartPosition; throw new FormatException("Not an ID3v2 tag"); } } public interface IMp3FrameDecompressor : IDisposable { WaveFormat OutputFormat { get; } int DecompressFrame(Mp3Frame frame, byte[] dest, int destOffset); void Reset(); } public class Mp3Frame { private static readonly int[,,] bitRates = new int[2, 3, 15] { { { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } }, { { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } } }; private static readonly int[,] samplesPerFrame = new int[2, 3] { { 384, 1152, 1152 }, { 384, 1152, 576 } }; private static readonly int[] sampleRatesVersion1 = new int[3] { 44100, 48000, 32000 }; private static readonly int[] sampleRatesVersion2 = new int[3] { 22050, 24000, 16000 }; private static readonly int[] sampleRatesVersion25 = new int[3] { 11025, 12000, 8000 }; private const int MaxFrameLength = 16384; public int SampleRate { get; private set; } public int FrameLength { get; private set; } public int BitRate { get; private set; } public byte[] RawData { get; private set; } public MpegVersion MpegVersion { get; private set; } public MpegLayer MpegLayer { get; private set; } public ChannelMode ChannelMode { get; private set; } public int SampleCount { get; private set; } public int ChannelExtension { get; private set; } public int BitRateIndex { get; private set; } public bool Copyright { get; private set; } public bool CrcPresent { get; private set; } public long FileOffset { get; private set; } public static Mp3Frame LoadFromStream(Stream input) { return LoadFromStream(input, readData: true); } public static Mp3Frame LoadFromStream(Stream input, bool readData) { Mp3Frame mp3Frame = new Mp3Frame(); mp3Frame.FileOffset = input.Position; byte[] array = new byte[4]; if (input.Read(array, 0, array.Length) < array.Length) { return null; } while (!IsValidHeader(array, mp3Frame)) { array[0] = array[1]; array[1] = array[2]; array[2] = array[3]; if (input.Read(array, 3, 1) < 1) { return null; } mp3Frame.FileOffset++; } int num = mp3Frame.FrameLength - 4; if (readData) { mp3Frame.RawData = new byte[mp3Frame.FrameLength]; Array.Copy(array, mp3Frame.RawData, 4); if (input.Read(mp3Frame.RawData, 4, num) < num) { throw new EndOfStreamException("Unexpected end of stream before frame complete"); } } else { input.Position += num; } return mp3Frame; } private Mp3Frame() { } private static bool IsValidHeader(byte[] headerBytes, Mp3Frame frame) { if (headerBytes[0] == byte.MaxValue && (headerBytes[1] & 0xE0) == 224) { frame.MpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (frame.MpegVersion == MpegVersion.Reserved) { return false; } frame.MpegLayer = (MpegLayer)((headerBytes[1] & 6) >> 1); if (frame.MpegLayer == MpegLayer.Reserved) { return false; } int num = ((frame.MpegLayer != MpegLayer.Layer1) ? ((frame.MpegLayer == MpegLayer.Layer2) ? 1 : 2) : 0); frame.CrcPresent = (headerBytes[1] & 1) == 0; frame.BitRateIndex = (headerBytes[2] & 0xF0) >> 4; if (frame.BitRateIndex == 15) { return false; } int num2 = ((frame.MpegVersion != MpegVersion.Version1) ? 1 : 0); frame.BitRate = bitRates[num2, num, frame.BitRateIndex] * 1000; if (frame.BitRate == 0) { return false; } int num3 = (headerBytes[2] & 0xC) >> 2; if (num3 == 3) { return false; } if (frame.MpegVersion == MpegVersion.Version1) { frame.SampleRate = sampleRatesVersion1[num3]; } else if (frame.MpegVersion == MpegVersion.Version2) { frame.SampleRate = sampleRatesVersion2[num3]; } else { frame.SampleRate = sampleRatesVersion25[num3]; } bool flag = (headerBytes[2] & 2) == 2; _ = headerBytes[2]; frame.ChannelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6); frame.ChannelExtension = (headerBytes[3] & 0x30) >> 4; if (frame.ChannelExtension != 0 && frame.ChannelMode != ChannelMode.JointStereo) { return false; } frame.Copyright = (headerBytes[3] & 8) == 8; _ = headerBytes[3]; _ = headerBytes[3]; int num4 = (flag ? 1 : 0); frame.SampleCount = samplesPerFrame[num2, num]; int num5 = frame.SampleCount / 8; if (frame.MpegLayer == MpegLayer.Layer1) { frame.FrameLength = (num5 * frame.BitRate / frame.SampleRate + num4) * 4; } else { frame.FrameLength = num5 * frame.BitRate / frame.SampleRate + num4; } if (frame.FrameLength > 16384) { return false; } return true; } return false; } } public enum MpegLayer { Reserved, Layer3, Layer2, Layer1 } public enum MpegVersion { Version25, Reserved, Version2, Version1 } public class XingHeader { [Flags] private enum XingHeaderOptions { Frames = 1, Bytes = 2, Toc = 4, VbrScale = 8 } private static int[] sr_table = new int[4] { 44100, 48000, 32000, 99999 }; private int vbrScale = -1; private int startOffset; private int endOffset; private int tocOffset = -1; private int framesOffset = -1; private int bytesOffset = -1; private Mp3Frame frame; public int Frames { get { if (framesOffset == -1) { return -1; } return ReadBigEndian(frame.RawData, framesOffset); } set { if (framesOffset == -1) { throw new InvalidOperationException("Frames flag is not set"); } WriteBigEndian(frame.RawData, framesOffset, value); } } public int Bytes { get { if (bytesOffset == -1) { return -1; } return ReadBigEndian(frame.RawData, bytesOffset); } set { if (framesOffset == -1) { throw new InvalidOperationException("Bytes flag is not set"); } WriteBigEndian(frame.RawData, bytesOffset, value); } } public int VbrScale => vbrScale; public Mp3Frame Mp3Frame => frame; private static int ReadBigEndian(byte[] buffer, int offset) { return (((((buffer[offset] << 8) | buffer[offset + 1]) << 8) | buffer[offset + 2]) << 8) | buffer[offset + 3]; } private void WriteBigEndian(byte[] buffer, int offset, int value) { byte[] bytes = BitConverter.GetBytes(value); for (int i = 0; i < 4; i++) { buffer[offset + 3 - i] = bytes[i]; } } public static XingHeader LoadXingHeader(Mp3Frame frame) { XingHeader xingHeader = new XingHeader(); xingHeader.frame = frame; int num = 0; if (frame.MpegVersion == MpegVersion.Version1) { num = ((frame.ChannelMode == ChannelMode.Mono) ? 21 : 36); } else { if (frame.MpegVersion != MpegVersion.Version2) { return null; } num = ((frame.ChannelMode == ChannelMode.Mono) ? 13 : 21); } if (frame.RawData[num] == 88 && frame.RawData[num + 1] == 105 && frame.RawData[num + 2] == 110 && frame.RawData[num + 3] == 103) { xingHeader.startOffset = num; num += 4; } else { if (frame.RawData[num] != 73 || frame.RawData[num + 1] != 110 || frame.RawData[num + 2] != 102 || frame.RawData[num + 3] != 111) { return null; } xingHeader.startOffset = num; num += 4; } int num2 = ReadBigEndian(frame.RawData, num); num += 4; if (((uint)num2 & (true ? 1u : 0u)) != 0) { xingHeader.framesOffset = num; num += 4; } if (((uint)num2 & 2u) != 0) { xingHeader.bytesOffset = num; num += 4; } if (((uint)num2 & 4u) != 0) { xingHeader.tocOffset = num; num += 100; } if (((uint)num2 & 8u) != 0) { xingHeader.vbrScale = ReadBigEndian(frame.RawData, num); num += 4; } xingHeader.endOffset = num; return xingHeader; } private XingHeader() { } } public static class WaveExtensionMethods { public static ISampleProvider ToSampleProvider(this IWaveProvider waveProvider) { return SampleProviderConverters.ConvertWaveProviderIntoSampleProvider(waveProvider); } public static void Init(this IWavePlayer wavePlayer, ISampleProvider sampleProvider, bool convertTo16Bit = false) { IWaveProvider waveProvider2; if (!convertTo16Bit) { IWaveProvider waveProvider = new SampleToWaveProvider(sampleProvider); waveProvider2 = waveProvider; } else { IWaveProvider waveProvider = new SampleToWaveProvider16(sampleProvider); waveProvider2 = waveProvider; } IWaveProvider waveProvider3 = waveProvider2; wavePlayer.Init(waveProvider3); } public static WaveFormat AsStandardWaveFormat(this WaveFormat waveFormat) { if (!(waveFormat is WaveFormatExtensible waveFormatExtensible)) { return waveFormat; } return waveFormatExtensible.ToStandardWaveFormat(); } public static IWaveProvider ToWaveProvider(this ISampleProvider sampleProvider) { return new SampleToWaveProvider(sampleProvider); } public static IWaveProvider ToWaveProvider16(this ISampleProvider sampleProvider) { return new SampleToWaveProvider16(sampleProvider); } public static ISampleProvider FollowedBy(this ISampleProvider sampleProvider, ISampleProvider next) { return new ConcatenatingSampleProvider(new ISampleProvider[2] { sampleProvider, next }); } public static ISampleProvider FollowedBy(this ISampleProvider sampleProvider, TimeSpan silenceDuration, ISampleProvider next) { OffsetSampleProvider offsetSampleProvider = new OffsetSampleProvider(sampleProvider) { LeadOut = silenceDuration }; return new ConcatenatingSampleProvider(new ISampleProvider[2] { offsetSampleProvider, next }); } public static ISampleProvider Skip(this ISampleProvider sampleProvider, TimeSpan skipDuration) { return new OffsetSampleProvider(sampleProvider) { SkipOver = skipDuration }; } public static ISampleProvider Take(this ISampleProvider sampleProvider, TimeSpan takeDuration) { return new OffsetSampleProvider(sampleProvider) { Take = takeDuration }; } public static ISampleProvider ToMono(this ISampleProvider sourceProvider, float leftVol = 0.5f, float rightVol = 0.5f) { if (sourceProvider.WaveFormat.Channels == 1) { return sourceProvider; } return new StereoToMonoSampleProvider(sourceProvider) { LeftVolume = leftVol, RightVolume = rightVol }; } public static ISampleProvider ToStereo(this ISampleProvider sourceProvider, float leftVol = 1f, float rightVol = 1f) { if (sourceProvider.WaveFormat.Channels == 2) { return sourceProvider; } return new MonoToStereoSampleProvider(sourceProvider) { LeftVolume = leftVol, RightVolume = rightVol }; } } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class AdpcmWaveFormat : WaveFormat { private short samplesPerBlock; private short numCoeff; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] private short[] coefficients; public int SamplesPerBlock => samplesPerBlock; public int NumCoefficients => numCoeff; public short[] Coefficients => coefficients; private AdpcmWaveFormat() : this(8000, 1) { } public AdpcmWaveFormat(int sampleRate, int channels) : base(sampleRate, 0, channels) { waveFormatTag = WaveFormatEncoding.Adpcm; extraSize = 32; switch (base.sampleRate) { case 8000: case 11025: blockAlign = 256; break; case 22050: blockAlign = 512; break; default: blockAlign = 1024; break; } bitsPerSample = 4; samplesPerBlock = (short)((blockAlign - 7 * channels) * 8 / (bitsPerSample * channels) + 2); averageBytesPerSecond = base.SampleRate * blockAlign / samplesPerBlock; numCoeff = 7; coefficients = new short[14] { 256, 0, 512, -256, 0, 0, 192, 64, 240, 0, 460, -208, 392, -232 }; } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.Write(samplesPerBlock); writer.Write(numCoeff); short[] array = coefficients; foreach (short value in array) { writer.Write(value); } } public override string ToString() { return $"Microsoft ADPCM {base.SampleRate} Hz {channels} channels {bitsPerSample} bits per sample {samplesPerBlock} samples per block"; } } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class Gsm610WaveFormat : WaveFormat { private readonly short samplesPerBlock; public short SamplesPerBlock => samplesPerBlock; public Gsm610WaveFormat() { waveFormatTag = WaveFormatEncoding.Gsm610; channels = 1; averageBytesPerSecond = 1625; bitsPerSample = 0; blockAlign = 65; sampleRate = 8000; extraSize = 2; samplesPerBlock = 320; } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.Write(samplesPerBlock); } } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class ImaAdpcmWaveFormat : WaveFormat { private short samplesPerBlock; private ImaAdpcmWaveFormat() { } public ImaAdpcmWaveFormat(int sampleRate, int channels, int bitsPerSample) { waveFormatTag = WaveFormatEncoding.DviAdpcm; base.sampleRate = sampleRate; base.channels = (short)channels; base.bitsPerSample = (short)bitsPerSample; extraSize = 2; blockAlign = 0; averageBytesPerSecond = 0; samplesPerBlock = 0; } } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class Mp3WaveFormat : WaveFormat { public Mp3WaveFormatId id; public Mp3WaveFormatFlags flags; public ushort blockSize; public ushort framesPerBlock; public ushort codecDelay; private const short Mp3WaveFormatExtraBytes = 12; public Mp3WaveFormat(int sampleRate, int channels, int blockSize, int bitRate) { waveFormatTag = WaveFormatEncoding.MpegLayer3; base.channels = (short)channels; averageBytesPerSecond = bitRate / 8; bitsPerSample = 0; blockAlign = 1; base.sampleRate = sampleRate; extraSize = 12; id = Mp3WaveFormatId.Mpeg; flags = Mp3WaveFormatFlags.PaddingIso; this.blockSize = (ushort)blockSize; framesPerBlock = 1; codecDelay = 0; } } [Flags] public enum Mp3WaveFormatFlags { PaddingIso = 0, PaddingOn = 1, PaddingOff = 2 } public enum Mp3WaveFormatId : ushort { Unknown, Mpeg, ConstantFrameSize } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class OggWaveFormat : WaveFormat { public uint dwVorbisACMVersion; public uint dwLibVorbisVersion; } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class TrueSpeechWaveFormat : WaveFormat { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] private short[] unknown; public TrueSpeechWaveFormat() { waveFormatTag = WaveFormatEncoding.DspGroupTrueSpeech; channels = 1; averageBytesPerSecond = 1067; bitsPerSample = 1; blockAlign = 32; sampleRate = 8000; extraSize = 32; unknown = new short[16]; unknown[0] = 1; unknown[1] = 240; } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); short[] array = unknown; foreach (short value in array) { writer.Write(value); } } } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class WaveFormat { protected WaveFormatEncoding waveFormatTag; protected short channels; protected int sampleRate; protected int averageBytesPerSecond; protected short blockAlign; protected short bitsPerSample; protected short extraSize; public WaveFormatEncoding Encoding => waveFormatTag; public int Channels => channels; public int SampleRate => sampleRate; public int AverageBytesPerSecond => averageBytesPerSecond; public virtual int BlockAlign => blockAlign; public int BitsPerSample => bitsPerSample; public int ExtraSize => extraSize; public WaveFormat() : this(44100, 16, 2) { } public WaveFormat(int sampleRate, int channels) : this(sampleRate, 16, channels) { } public int ConvertLatencyToByteSize(int milliseconds) { int num = (int)((double)AverageBytesPerSecond / 1000.0 * (double)milliseconds); if (num % BlockAlign != 0) { num = num + BlockAlign - num % BlockAlign; } return num; } public static WaveFormat CreateCustomFormat(WaveFormatEncoding tag, int sampleRate, int channels, int averageBytesPerSecond, int blockAlign, int bitsPerSample) { return new WaveFormat { waveFormatTag = tag, channels = (short)channels, sampleRate = sampleRate, averageBytesPerSecond = averageBytesPerSecond, blockAlign = (short)blockAlign, bitsPerSample = (short)bitsPerSample, extraSize = 0 }; } public static WaveFormat CreateALawFormat(int sampleRate, int channels) { return CreateCustomFormat(WaveFormatEncoding.ALaw, sampleRate, channels, sampleRate * channels, channels, 8); } public static WaveFormat CreateMuLawFormat(int sampleRate, int channels) { return CreateCustomFormat(WaveFormatEncoding.MuLaw, sampleRate, channels, sampleRate * channels, channels, 8); } public WaveFormat(int rate, int bits, int channels) { if (channels < 1) { throw new ArgumentOutOfRangeException("channels", "Channels must be 1 or greater"); } waveFormatTag = WaveFormatEncoding.Pcm; this.channels = (short)channels; sampleRate = rate; bitsPerSample = (short)bits; extraSize = 0; blockAlign = (short)(channels * (bits / 8)); averageBytesPerSecond = sampleRate * blockAlign; } public static WaveFormat CreateIeeeFloatWaveFormat(int sampleRate, int channels) { WaveFormat waveFormat = new WaveFormat(); waveFormat.waveFormatTag = WaveFormatEncoding.IeeeFloat; waveFormat.channels = (short)channels; waveFormat.bitsPerSample = 32; waveFormat.sampleRate = sampleRate; waveFormat.blockAlign = (short)(4 * channels); waveFormat.averageBytesPerSecond = sampleRate * waveFormat.blockAlign; waveFormat.extraSize = 0; return waveFormat; } public static WaveFormat MarshalFromPtr(IntPtr pointer) { WaveFormat waveFormat = Marshal.PtrToStructure<WaveFormat>(pointer); switch (waveFormat.Encoding) { case WaveFormatEncoding.Pcm: waveFormat.extraSize = 0; break; case WaveFormatEncoding.Extensible: waveFormat = Marshal.PtrToStructure<WaveFormatExtensible>(pointer); break; case WaveFormatEncoding.Adpcm: waveFormat = Marshal.PtrToStructure<AdpcmWaveFormat>(pointer); break; case WaveFormatEncoding.Gsm610: waveFormat = Marshal.PtrToStructure<Gsm610WaveFormat>(pointer); break; default: if (waveFormat.ExtraSize > 0) { waveFormat = Marshal.PtrToStructure<WaveFormatExtraData>(pointer); } break; } return waveFormat; } public static IntPtr MarshalToPtr(WaveFormat format) { IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(format)); Marshal.StructureToPtr(format, intPtr, fDeleteOld: false); return intPtr; } public static WaveFormat FromFormatChunk(BinaryReader br, int formatChunkLength) { WaveFormatExtraData waveFormatExtraData = new WaveFormatExtraData(); waveFormatExtraData.ReadWaveFormat(br, formatChunkLength); waveFormatExtraData.ReadExtraData(br); return waveFormatExtraData; } private void ReadWaveFormat(BinaryReader br, int formatChunkLength) { if (formatChunkLength < 16) { throw new InvalidDataException("Invalid WaveFormat Structure"); } waveFormatTag = (WaveFormatEncoding)br.ReadUInt16(); channels = br.ReadInt16(); sampleRate = br.ReadInt32(); averageBytesPerSecond = br.ReadInt32(); blockAlign = br.ReadInt16(); bitsPerSample = br.ReadInt16(); if (formatChunkLength > 16) { extraSize = br.ReadInt16(); if (extraSize != formatChunkLength - 18) { extraSize = (short)(formatChunkLength - 18); } } } public WaveFormat(BinaryReader br) { int formatChunkLength = br.ReadInt32(); ReadWaveFormat(br, formatChunkLength); } public override string ToString() { switch (waveFormatTag) { case WaveFormatEncoding.Pcm: case WaveFormatEncoding.Extensible: return $"{bitsPerSample} bit PCM: {sampleRate}Hz {channels} channels"; case WaveFormatEncoding.IeeeFloat: return $"{bitsPerSample} bit IEEFloat: {sampleRate}Hz {channels} channels"; default: return waveFormatTag.ToString(); } } public override bool Equals(object obj) { if (obj is WaveFormat waveFormat) { if (waveFormatTag == waveFormat.waveFormatTag && channels == waveFormat.channels && sampleRate == waveFormat.sampleRate && averageBytesPerSecond == waveFormat.averageBytesPerSecond && blockAlign == waveFormat.blockAlign) { return bitsPerSample == waveFormat.bitsPerSample; } return false; } return false; } public override int GetHashCode() { return (int)waveFormatTag ^ (int)channels ^ sampleRate ^ averageBytesPerSecond ^ blockAlign ^ bitsPerSample; } public virtual void Serialize(BinaryWriter writer) { writer.Write(18 + extraSize); writer.Write((short)Encoding); writer.Write((short)Channels); writer.Write(SampleRate); writer.Write(AverageBytesPerSecond); writer.Write((short)BlockAlign); writer.Write((short)BitsPerSample); writer.Write(extraSize); } } public sealed class WaveFormatCustomMarshaler : ICustomMarshaler { private static WaveFormatCustomMarshaler marshaler; public static ICustomMarshaler GetInstance(string cookie) { if (marshaler == null) { marshaler = new WaveFormatCustomMarshaler(); } return marshaler; } public void CleanUpManagedData(object ManagedObj) { } public void CleanUpNativeData(IntPtr pNativeData) { Marshal.FreeHGlobal(pNativeData); } public int GetNativeDataSize() { throw new NotImplementedException(); } public IntPtr MarshalManagedToNative(object ManagedObj) { return WaveFormat.MarshalToPtr((WaveFormat)ManagedObj); } public object MarshalNativeToManaged(IntPtr pNativeData) { return WaveFormat.MarshalFromPtr(pNativeData); } } public enum WaveFormatEncoding : ushort { Unknown = 0, Pcm = 1, Adpcm = 2, IeeeFloat = 3, Vselp = 4, IbmCvsd = 5, ALaw = 6, MuLaw = 7, Dts = 8, Drm = 9, WmaVoice9 = 10, OkiAdpcm = 16, DviAdpcm = 17, ImaAdpcm = 17, MediaspaceAdpcm = 18, SierraAdpcm = 19, G723Adpcm = 20, DigiStd = 21, DigiFix = 22, DialogicOkiAdpcm = 23, MediaVisionAdpcm = 24, CUCodec = 25, YamahaAdpcm = 32, SonarC = 33, DspGroupTrueSpeech = 34, EchoSpeechCorporation1 = 35, AudioFileAf36 = 36, Aptx = 37, AudioFileAf10 = 38, Prosody1612 = 39, Lrc = 40, DolbyAc2 = 48, Gsm610 = 49, MsnAudio = 50, AntexAdpcme = 51, ControlResVqlpc = 52, DigiReal = 53, DigiAdpcm = 54, ControlResCr10 = 55, WAVE_FORMAT_NMS_VBXADPCM = 56, WAVE_FORMAT_CS_IMAADPCM = 57, WAVE_FORMAT_ECHOSC3 = 58, WAVE_FORMAT_ROCKWELL_ADPCM = 59, WAVE_FORMAT_ROCKWELL_DIGITALK = 60, WAVE_FORMAT_XEBEC = 61, WAVE_FORMAT_G721_ADPCM = 64, WAVE_FORMAT_G728_CELP = 65, WAVE_FORMAT_MSG723 = 66, Mpeg = 80, WAVE_FORMAT_RT24 = 82, WAVE_FORMAT_PAC = 83, MpegLayer3 = 85, WAVE_FORMAT_LUCENT_G723 = 89, WAVE_FORMAT_CIRRUS = 96, WAVE_FORMAT_ESPCM = 97, WAVE_FORMAT_VOXWARE = 98, WAVE_FORMAT_CANOPUS_ATRAC = 99, WAVE_FORMAT_G726_ADPCM = 100, WAVE_FORMAT_G722_ADPCM = 101, WAVE_FORMAT_DSAT_DISPLAY = 103, WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 105, WAVE_FORMAT_VOXWARE_AC8 = 112, WAVE_FORMAT_VOXWARE_AC10 = 113, WAVE_FORMAT_VOXWARE_AC16 = 114, WAVE_FORMAT_VOXWARE_AC20 = 115, WAVE_FORMAT_VOXWARE_RT24 = 116, WAVE_FORMAT_VOXWARE_RT29 = 117, WAVE_FORMAT_VOXWARE_RT29HW = 118, WAVE_FORMAT_VOXWARE_VR12 = 119, WAVE_FORMAT_VOXWARE_VR18 = 120, WAVE_FORMAT_VOXWARE_TQ40 = 121, WAVE_FORMAT_SOFTSOUND = 128, WAVE_FORMAT_VOXWARE_TQ60 = 129, WAVE_FORMAT_MSRT24 = 130, WAVE_FORMAT_G729A = 131, WAVE_FORMAT_MVI_MVI2 = 132, WAVE_FORMAT_DF_G726 = 133, WAVE_FORMAT_DF_GSM610 = 134, WAVE_FORMAT_ISIAUDIO = 136, WAVE_FORMAT_ONLIVE = 137, WAVE_FORMAT_SBC24 = 145, WAVE_FORMAT_DOLBY_AC3_SPDIF = 146, WAVE_FORMAT_MEDIASONIC_G723 = 147, WAVE_FORMAT_PROSODY_8KBPS = 148, WAVE_FORMAT_ZYXEL_ADPCM = 151, WAVE_FORMAT_PHILIPS_LPCBB = 152, WAVE_FORMAT_PACKED = 153, WAVE_FORMAT_MALDEN_PHONYTALK = 160, Gsm = 161, G729 = 162, G723 = 163, Acelp = 164, RawAac = 255, WAVE_FORMAT_RHETOREX_ADPCM = 256, WAVE_FORMAT_IRAT = 257, WAVE_FORMAT_VIVO_G723 = 273, WAVE_FORMAT_VIVO_SIREN = 274, WAVE_FORMAT_DIGITAL_G723 = 291, WAVE_FORMAT_SANYO_LD_ADPCM = 293, WAVE_FORMAT_SIPROLAB_ACEPLNET = 304, WAVE_FORMAT_SIPROLAB_ACELP4800 = 305, WAVE_FORMAT_SIPROLAB_ACELP8V3 = 306, WAVE_FORMAT_SIPROLAB_G729 = 307, WAVE_FORMAT_SIPROLAB_G729A = 308, WAVE_FORMAT_SIPROLAB_KELVIN = 309, WAVE_FORMAT_G726ADPCM = 320, WAVE_FORMAT_QUALCOMM_PUREVOICE = 336, WAVE_FORMAT_QUALCOMM_HALFRATE = 337, WAVE_FORMAT_TUBGSM = 341, WAVE_FORMAT_MSAUDIO1 = 352, WindowsMediaAudio = 353, WindowsMediaAudioProfessional = 354, WindowsMediaAudioLosseless = 355, WindowsMediaAudioSpdif = 356, WAVE_FORMAT_UNISYS_NAP_ADPCM = 368, WAVE_FORMAT_UNISYS_NAP_ULAW = 369, WAVE_FORMAT_UNISYS_NAP_ALAW = 370, WAVE_FORMAT_UNISYS_NAP_16K = 371, WAVE_FORMAT_CREATIVE_ADPCM = 512, WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 514, WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 515, WAVE_FORMAT_UHER_ADPCM = 528, WAVE_FORMAT_QUARTERDECK = 544, WAVE_FORMAT_ILINK_VC = 560, WAVE_FORMAT_RAW_SPORT = 576, WAVE_FORMAT_ESST_AC3 = 577, WAVE_FORMAT_IPI_HSX = 592, WAVE_FORMAT_IPI_RPELP = 593, WAVE_FORMAT_CS2 = 608, WAVE_FORMAT_SONY_SCX = 624, WAVE_FORMAT_FM_TOWNS_SND = 768, WAVE_FORMAT_BTV_DIGITAL = 1024, WAVE_FORMAT_QDESIGN_MUSIC = 1104, WAVE_FORMAT_VME_VMPCM = 1664, WAVE_FORMAT_TPC = 1665, WAVE_FORMAT_OLIGSM = 4096, WAVE_FORMAT_OLIADPCM = 4097, WAVE_FORMAT_OLICELP = 4098, WAVE_FORMAT_OLISBC = 4099, WAVE_FORMAT_OLIOPR = 4100, WAVE_FORMAT_LH_CODEC = 4352, WAVE_FORMAT_NORRIS = 5120, WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 5376, MPEG_ADTS_AAC = 5632, MPEG_RAW_AAC = 5633, MPEG_LOAS = 5634, NOKIA_MPEG_ADTS_AAC = 5640, NOKIA_MPEG_RAW_AAC = 5641, VODAFONE_MPEG_ADTS_AAC = 5642, VODAFONE_MPEG_RAW_AAC = 5643, MPEG_HEAAC = 5648, WAVE_FORMAT_DVM = 8192, Vorbis1 = 26447, Vorbis2 = 26448, Vorbis3 = 26449, Vorbis1P = 26479, Vorbis2P = 26480, Vorbis3P = 26481, Extensible = 65534, WAVE_FORMAT_DEVELOPMENT = ushort.MaxValue } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class WaveFormatExtensible : WaveFormat { private short wValidBitsPerSample; private int dwChannelMask; private Guid subFormat; public Guid SubFormat => subFormat; private WaveFormatExtensible() { } public WaveFormatExtensible(int rate, int bits, int channels) : base(rate, bits, channels) { waveFormatTag = WaveFormatEncoding.Extensible; extraSize = 22; wValidBitsPerSample = (short)bits; for (int i = 0; i < channels; i++) { dwChannelMask |= 1 << i; } if (bits == 32) { subFormat = AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT; } else { subFormat = AudioMediaSubtypes.MEDIASUBTYPE_PCM; } } public WaveFormat ToStandardWaveFormat() { if (subFormat == AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT && bitsPerSample == 32) { return WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); } if (subFormat == AudioMediaSubtypes.MEDIASUBTYPE_PCM) { return new WaveFormat(sampleRate, bitsPerSample, channels); } return this; } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.Write(wValidBitsPerSample); writer.Write(dwChannelMask); byte[] array = subFormat.ToByteArray(); writer.Write(array, 0, array.Length); } public override string ToString() { return "WAVE_FORMAT_EXTENSIBLE " + AudioMediaSubtypes.GetAudioSubtypeName(subFormat) + " " + $"{base.SampleRate}Hz {base.Channels} channels {base.BitsPerSample} bit"; } } [StructLayout(LayoutKind.Sequential, Pack = 2)] public class WaveFormatExtraData : WaveFormat { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] private byte[] extraData = new byte[100]; public byte[] ExtraData => extraData; internal WaveFormatExtraData() { } public WaveFormatExtraData(BinaryReader reader) : base(reader) { ReadExtraData(reader); } internal void ReadExtraData(BinaryReader reader) { if (extraSize > 0) { reader.Read(extraData, 0, extraSize); } } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); if (extraSize > 0) { writer.Write(extraData, 0, extraSize); } } } public interface IWaveIn : IDisposable { WaveFormat WaveFormat { get; set; } event EventHandler<WaveInEventArgs> DataAvailable; event EventHandler<StoppedEventArgs> RecordingStopped; void StartRecording(); void StopRecording(); } public class WaveInEventArgs : EventArgs { private byte[] buffer; private int bytes; public byte[] Buffer => buffer; public int BytesRecorded => bytes; public WaveInEventArgs(byte[] buffer, int bytes) { this.buffer = buffer; this.bytes = bytes; } } public class AiffFileWriter : Stream { private Stream outStream; private BinaryWriter writer; private long dataSizePos; private long commSampleCountPos; private long dataChunkSize = 8L; private WaveFormat format; private string filename; private byte[] value24 = new byte[3]; public string Filename => filename; public override long Length => dataChunkSize; public WaveFormat WaveFormat => format; public override bool CanRead => false; public override bool CanWrite => true; public override bool CanSeek => false; public override long Position { get { return dataChunkSize; } set { throw new InvalidOperationException("Repositioning an AiffFileWriter is not supported"); } } public static void CreateAiffFile(string filename, WaveStream sourceProvider) { using AiffFileWriter aiffFileWriter = new AiffFileWriter(filename, sourceProvider.WaveFormat); byte[] array = new byte[16384]; while (sourceProvider.Position < sourceProvider.Length) { int count = Math.Min((int)(sourceProvider.Length - sourceProvider.Position), array.Length); int num = sourceProvider.Read(array, 0, count); if (num == 0) { break; } aiffFileWriter.Write(array, 0, num); } } public AiffFileWriter(Stream outStream, WaveFormat format) { this.outStream = outStream; this.format = format; writer = new BinaryWriter(outStream, Encoding.UTF8); writer.Write(Encoding.UTF8.GetBytes("FORM")); writer.Write(0); writer.Write(Encoding.UTF8.GetBytes("AIFF")); CreateCommChunk(); WriteSsndChunkHeader(); } public AiffFileWriter(string filename, WaveFormat format) : this(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read), format) { this.filename = filename; } private void WriteSsndChunkHeader() { writer.Write(Encoding.UTF8.GetBytes("SSND")); dataSizePos = outStream.Position; writer.Write(0); writer.Write(0); writer.Write(SwapEndian(format.BlockAlign)); } private byte[] SwapEndian(short n) { return new byte[2] { (byte)(n >> 8), (byte)((uint)n & 0xFFu) }; } private byte[] SwapEndian(int n) { return new byte[4] { (byte)((uint)(n >> 24) & 0xFFu), (byte)((uint)(n >> 16) & 0xFFu), (byte)((uint)(n >> 8) & 0xFFu), (byte)((uint)n & 0xFFu) }; } private void CreateCommChunk() { writer.Write(Encoding.UTF8.GetBytes("COMM")); writer.Write(SwapEndian(18)); writer.Write(SwapEndian((short)format.Channels)); commSampleCountPos = outStream.Position; writer.Write(0); writer.Write(SwapEndian((short)format.BitsPerSample)); writer.Write(IEEE.ConvertToIeeeExtended(format.SampleRate)); } public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException("Cannot read from an AiffFileWriter"); } public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException("Cannot seek within an AiffFileWriter"); } public override void SetLength(long value) { throw new InvalidOperationException("Cannot set length of an AiffFileWriter"); } public override void Write(byte[] data, int offset, int count) { byte[] array = new byte[data.Length]; int num = format.BitsPerSample / 8; for (int i = 0; i < data.Length; i++) { int num2 = (int)Math.Floor((double)i / (double)num) * num + (num - i % num - 1); array[i] = data[num2]; } outStream.Write(array, offset, count); dataChunkSize += count; } public void WriteSample(float sample) { if (WaveFormat.BitsPerSample == 16) { writer.Write(SwapEndian((short)(32767f * sample))); dataChunkSize += 2L; } else if (WaveFormat.BitsPerSample == 24) { byte[] bytes = BitConverter.GetBytes((int)(2.1474836E+09f * sample)); value24[2] = bytes[1]; value24[1] = bytes[2]; value24[0] = bytes[3]; writer.Write(value24); dataChunkSize += 3L; } else { if (WaveFormat.BitsPerSample != 32 || WaveFormat.Encoding != WaveFormatEncoding.Extensible) { throw new InvalidOperationException("Only 16, 24 or 32 bit PCM or IEEE float audio data supported"); } writer.Write(SwapEndian(65535 * (int)sample)); dataChunkSize += 4L; } } public void WriteSamples(float[] samples, int offset, int count) { for (int i = 0; i < count; i++) { WriteSample(samples[offset + i]); } } public void WriteSamples(short[] samples, int offset, int count) { if (WaveFormat.BitsPerSample == 16) { for (int i = 0; i < count; i++) { writer.Write(SwapEndian(samples[i + offset])); } dataChunkSize += count * 2; } else if (WaveFormat.BitsPerSample == 24) { for (int j = 0; j < count; j++) { byte[] bytes = BitConverter.GetBytes(65535 * samples[j + offset]); value24[2] = bytes[1]; value24[1] = bytes[2]; value24[0] = bytes[3]; writer.Write(value24); } dataChunkSize += count * 3; } else { if (WaveFormat.BitsPerSample != 32 || WaveFormat.Encoding != WaveFormatEncoding.Extensible) { throw new InvalidOperationException("Only 16, 24 or 32 bit PCM audio data supported"); } for (int k = 0; k < count; k++) { writer.Write(SwapEndian(65535 * samples[k + offset])); } dataChunkSize += count * 4; } } public override void Flush() { writer.Flush(); } protected override void Dispose(bool disposing) { if (disposing && outStream != null) { try { UpdateHeader(writer); } finally { outStream.Dispose(); outStream = null; } } } protected virtual void UpdateHeader(BinaryWriter writer) { Flush(); writer.Seek(4, SeekOrigin.Begin); writer.Write(SwapEndian((int)(outStream.Length - 8))); UpdateCommChunk(writer); UpdateSsndChunk(writer); } private void UpdateCommChunk(BinaryWriter writer) { writer.Seek((int)commSampleCountPos, SeekOrigin.Begin); writer.Write(SwapEndian((int)(dataChunkSize * 8 / format.BitsPerSample / format.Channels))); } private void UpdateSsndChunk(BinaryWriter writer) { writer.Seek((int)dataSizePos, SeekOrigin.Begin); writer.Write(SwapEndian((int)dataChunkSize)); } ~AiffFileWriter() { Dispose(disposing: false); } } public class BextChunkInfo { public string Description { get; set; } public string Originator { get; set; } public string OriginatorReference { get; set; } public DateTime OriginationDateTime { get; set; } public string OriginationDate => OriginationDateTime.ToString("yyyy-MM-dd"); public string OriginationTime => OriginationDateTime.ToString("HH:mm:ss"); public long TimeReference { get; set; } public ushort Version => 1; public string UniqueMaterialIdentifier { get; set; } public byte[] Reserved { get; } public string CodingHistory { get; set; } public BextChunkInfo() { Reserved = new byte[190]; } } public class BwfWriter : IDisposable { private readonly WaveFormat format; private readonly BinaryWriter writer; private readonly long dataChunkSizePosition; private long dataLength; private bool isDisposed; public BwfWriter(string filename, WaveFormat format, BextChunkInfo bextChunkInfo) { this.format = format; writer = new BinaryWriter(File.OpenWrite(filename)); writer.Write(Encoding.UTF8.GetBytes("RIFF")); writer.Write(0); writer.Write(Encoding.UTF8.GetBytes("WAVE")); writer.Write(Encoding.UTF8.GetBytes("JUNK")); writer.Write(28); writer.Write(0L); writer.Write(0L); writer.Write(0L); writer.Write(0); writer.Write(Encoding.UTF8.GetBytes("bext")); byte[] bytes = Encoding.ASCII.GetBytes(bextChunkInfo.CodingHistory ?? ""); int num = 602 + bytes.Length; if (num % 2 != 0) { num++; } writer.Write(num); _ = writer.BaseStream.Position; writer.Write(GetAsBytes(bextChunkInfo.Description, 256)); writer.Write(GetAsBytes(bextChunkInfo.Originator, 32)); writer.Write(GetAsBytes(bextChunkInfo.OriginatorReference, 32)); writer.Write(GetAsBytes(bextChunkInfo.OriginationDate, 10)); writer.Write(GetAsBytes(bextChunkInfo.OriginationTime, 8)); writer.Write(bextChunkInfo.TimeReference); writer.Write(bextChunkInfo.Version); writer.Write(GetAsBytes(bextChunkInfo.UniqueMaterialIdentifier, 64)); writer.Write(bextChunkInfo.Reserved); writer.Write(bytes); if (bytes.Length % 2 != 0) { writer.Write((byte)0); } writer.Write(Encoding.UTF8.GetBytes("fmt ")); format.Serialize(writer); writer.Write(Encoding.UTF8.GetBytes("data")); dataChunkSizePosition = writer.BaseStream.Position; writer.Write(-1); } public void Write(byte[] buffer, int offset, int count) { if (isDisposed) { throw new ObjectDisposedException("This BWF Writer already disposed"); } writer.Write(buffer, offset, count); dataLength += count; } public void Flush() { if (isDisposed) { throw new ObjectDisposedException("This BWF Writer already disposed"); } writer.Flush(); FixUpChunkSizes(restorePosition: true); } private void FixUpChunkSizes(bool restorePosition) { long position = writer.BaseStream.Position; bool num = dataLength > int.MaxValue; long num2 = writer.BaseStream.Length - 8; if (num) { int num3 = format.BitsPerSample / 8 * format.Channels; writer.BaseStream.Position = 0L; writer.Write(Encoding.UTF8.GetBytes("RF64")); writer.Write(-1); writer.BaseStream.Position += 4L; writer.Write(Encoding.UTF8.GetBytes("ds64")); writer.BaseStream.Position += 4L; writer.Write(num2); writer.Write(dataLength); writer.Write(dataLength / num3); } else { writer.BaseStream.Position = 4L; writer.Write((uint)num2); writer.BaseStream.Position = dataChunkSizePosition; writer.Write((uint)dataLength); } if (restorePosition) { writer.BaseStream.Position = position; } } public void Dispose() { if (!isDisposed) { FixUpChunkSizes(restorePosition: false); writer.Dispose(); isDisposed = true; } } private static byte[] GetAsBytes(string message, int byteSize) { byte[] array = new byte[byteSize]; byte[] bytes = Encoding.ASCII.GetBytes(message ?? ""); Array.Copy(bytes, array, Math.Min(bytes.Length, byteSize)); return array; } } public class CueWaveFileWriter : WaveFileWriter { private CueList cues; public CueWaveFileWriter(string fileName, WaveFormat waveFormat) : base(fileName, waveFormat) { } public void AddCue(int position, string label) { if (cues == null) { cues = new CueList(); } cues.Add(new Cue(position, label)); } private void WriteCues(BinaryWriter w) { if (cues != null) { int count = cues.GetRiffChunks().Length; w.Seek(0, SeekOrigin.End); if (w.BaseStream.Length % 2 == 1) { w.Write((byte)0); } w.Write(cues.GetRiffChunks(), 0, count); w.Seek(4, SeekOrigin.Begin); w.Write((int)(w.BaseStream.Length - 8)); } } protected override void UpdateHeader(BinaryWriter writer) { base.UpdateHeader(writer); WriteCues(writer); } } public class DirectSoundOut : IWavePlayer, IDisposable { [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class BufferDescription { public int dwSize; [MarshalAs(UnmanagedType.U4)] public DirectSoundBufferCaps dwFlags; public uint dwBufferBytes; public int dwReserved; public IntPtr lpwfxFormat; public Guid guidAlgo; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class BufferCaps { public int dwSize; public int dwFlags; public int dwBufferBytes; public int dwUnlockTransferRate; public int dwPlayCpuOverhead; } internal enum DirectSoundCooperativeLevel : uint { DSSCL_NORMAL = 1u, DSSCL_PRIORITY, DSSCL_EXCLUSIVE, DSSCL_WRITEPRIMARY } [Flags] internal enum DirectSoundPlayFlags : uint { DSBPLAY_LOOPING = 1u, DSBPLAY_LOCHARDWARE = 2u, DSBPLAY_LOCSOFTWARE = 4u, DSBPLAY_TERMINATEBY_TIME = 8u, DSBPLAY_TERMINATEBY_DISTANCE = 0x10u, DSBPLAY_TERMINATEBY_PRIORITY = 0x20u } internal enum DirectSoundBufferLockFlag : uint { None, FromWriteCursor, EntireBuffer } [Flags] internal enum DirectSoundBufferStatus : uint { DSBSTATUS_PLAYING = 1u, DSBSTATUS_BUFFERLOST = 2u, DSBSTATUS_LOOPING = 4u, DSBSTATUS_LOCHARDWARE = 8u, DSBSTATUS_LOCSOFTWARE = 0x10u, DSBSTATUS_TERMINATED = 0x20u } [Flags] internal enum DirectSoundBufferCaps : uint { DSBCAPS_PRIMARYBUFFER = 1u, DSBCAPS_STATIC = 2u, DSBCAPS_LOCHARDWARE = 4u, DSBCAPS_LOCSOFTWARE = 8u, DSBCAPS_CTRL3D = 0x10u, DSBCAPS_CTRLFREQUENCY = 0x20u, DSBCAPS_CTRLPAN = 0x40u, DSBCAPS_CTRLVOLUME = 0x80u, DSBCAPS_CTRLPOSITIONNOTIFY = 0x100u, DSBCAPS_CTRLFX = 0x200u, DSBCAPS_STICKYFOCUS = 0x4000u, DSBCAPS_GLOBALFOCUS = 0x8000u, DSBCAPS_GETCURRENTPOSITION2 = 0x10000u, DSBCAPS_MUTE3DATMAXDISTANCE = 0x20000u, DSBCAPS_LOCDEFER = 0x40000u } internal struct DirectSoundBufferPositionNotify { public uint dwOffset; public IntPtr hEventNotify; } [ComImport] [Guid("279AFA83-4981-11CE-A521-0020AF0BE560")] [SuppressUnmanagedCodeSecurity] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IDirectSound { void CreateSoundBuffer([In] BufferDescription desc, [MarshalAs(UnmanagedType.Interface)] out object dsDSoundBuffer, IntPtr pUnkOuter); void GetCaps(IntPtr caps); void DuplicateSoundBuffer([In][MarshalAs(UnmanagedType.Interface)] IDirectSoundBuffer bufferOriginal, [In][MarshalAs(UnmanagedType.Interface)] IDirectSoundBuffer bufferDuplicate); void SetCooperativeLevel(IntPtr HWND, [In][MarshalAs(UnmanagedType.U4)] DirectSoundCooperativeLevel dwLevel); void Compact(); void GetSpeakerConfig(IntPtr pdwSpeakerConfig); void SetSpeakerConfig(uint pdwSpeakerConfig); void Initialize([In][MarshalAs(UnmanagedType.LPStruct)] Guid guid); } [ComImport] [Guid("279AFA85-4981-11CE-A521-0020AF0BE560")] [SuppressUnmanagedCodeSecurity] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IDirectSoundBuffer { void GetCaps([MarshalAs(UnmanagedType.LPStruct)] BufferCaps pBufferCaps); void GetCurrentPosition(out uint currentPlayCursor, out uint currentWriteCursor); void GetFormat(); [return: MarshalAs(UnmanagedType.I4)] int GetVolume(); void GetPan(out uint pan); [return: MarshalAs(UnmanagedType.I4)] int GetFrequency(); [return: MarshalAs(UnmanagedType.U4)] DirectSoundBufferStatus GetStatus(); void Initialize([In][MarshalAs(UnmanagedType.Interface)] IDirectSound directSound, [In] BufferDescription desc); void Lock(int dwOffset, uint dwBytes, out IntPtr audioPtr1, out int audioBytes1, out IntPtr audioPtr2, out int audioBytes2, [MarshalAs(UnmanagedType.U4)] DirectSoundBufferLockFlag dwFlags); void Play(uint dwReserved1, uint dwPriority, [In][MarshalAs(UnmanagedType.U4)] DirectSoundPlayFlags dwFlags); void SetCurrentPosition(uint dwNewPosition); void SetFormat([In] WaveFormat pcfxFormat); void SetVolume(int volume); void SetPan(uint pan); void SetFrequency(uint frequency); void Stop(); void Unlock(IntPtr pvAudioPtr1, int dwAudioBytes1, IntPtr pvAudioPtr2, int dwAudioBytes2); void Restore(); } [ComImport] [Guid("b0210783-89cd-11d0-af08-00a0c925cd16")] [SuppressUnmanagedCodeSecurity] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IDirectSoundNotify { void SetNotificationPositions(uint dwPositionNotifies, [In][MarshalAs(UnmanagedType.LPArray)] DirectSoundBufferPositionNotify[] pcPositionNotifies); } private delegate bool DSEnumCallback(IntPtr lpGuid, IntPtr lpcstrDescription, IntPtr lpcstrModule, IntPtr lpContext); private PlaybackState playbackState; private WaveFormat waveFormat; private int samplesTotalSize; private int samplesFrameSize; private int nextSamplesWriteIndex; private int desiredLatency; private Guid device; private byte[] samples; private IWaveProvider waveStream; private IDirectSound directSound; private IDirectSoundBuffer primarySoundBuffer; private IDirectSoundBuffer sec
plugins/NAudio.WinMM.dll
Decompiled a day agousing System; 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.Threading; using Microsoft.Win32; using NAudio.CoreAudioApi; using NAudio.Mixer; using NAudio.Utils; using NAudio.Wave.Compression; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("NAudio.WinMM")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© Mark Heath 2023")] [assembly: AssemblyFileVersion("2.2.1.0")] [assembly: AssemblyInformationalVersion("2.2.1")] [assembly: AssemblyProduct("NAudio.WinMM")] [assembly: AssemblyTitle("NAudio.WinMM")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/naudio/NAudio")] [assembly: AssemblyVersion("2.2.1.0")] namespace NAudio.Mixer { public class BooleanMixerControl : MixerControl { private MixerInterop.MIXERCONTROLDETAILS_BOOLEAN boolDetails; public bool Value { get { GetControlDetails(); return boolDetails.fValue == 1; } set { //IL_0055: Unknown result type (might be due to invalid IL or missing references) boolDetails.fValue = (value ? 1 : 0); mixerControlDetails.paDetails = Marshal.AllocHGlobal(Marshal.SizeOf(boolDetails)); Marshal.StructureToPtr(boolDetails, mixerControlDetails.paDetails, fDeleteOld: false); MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType), "mixerSetControlDetails"); Marshal.FreeHGlobal(mixerControlDetails.paDetails); } } internal BooleanMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels) { base.mixerControl = mixerControl; base.mixerHandle = mixerHandle; base.mixerHandleType = mixerHandleType; base.nChannels = nChannels; mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS); GetControlDetails(); } protected override void GetDetails(IntPtr pDetails) { boolDetails = Marshal.PtrToStructure<MixerInterop.MIXERCONTROLDETAILS_BOOLEAN>(pDetails); } } public class CustomMixerControl : MixerControl { internal CustomMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels) { base.mixerControl = mixerControl; base.mixerHandle = mixerHandle; base.mixerHandleType = mixerHandleType; base.nChannels = nChannels; mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS); GetControlDetails(); } protected override void GetDetails(IntPtr pDetails) { } } public class ListTextMixerControl : MixerControl { internal ListTextMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels) { base.mixerControl = mixerControl; base.mixerHandle = mixerHandle; base.mixerHandleType = mixerHandleType; base.nChannels = nChannels; mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS); GetControlDetails(); } protected override void GetDetails(IntPtr pDetails) { } } public class Mixer { private MixerInterop.MIXERCAPS caps; private IntPtr mixerHandle; private MixerFlags mixerHandleType; public static int NumberOfDevices => MixerInterop.mixerGetNumDevs(); public int DestinationCount => (int)caps.cDestinations; public string Name => caps.szPname; public Manufacturers Manufacturer => (Manufacturers)caps.wMid; public int ProductID => caps.wPid; public IEnumerable<MixerLine> Destinations { get { for (int destination = 0; destination < DestinationCount; destination++) { yield return GetDestination(destination); } } } public static IEnumerable<Mixer> Mixers { get { for (int device = 0; device < NumberOfDevices; device++) { yield return new Mixer(device); } } } public Mixer(int mixerIndex) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (mixerIndex < 0 || mixerIndex >= NumberOfDevices) { throw new ArgumentOutOfRangeException("mixerID"); } caps = default(MixerInterop.MIXERCAPS); MmException.Try(MixerInterop.mixerGetDevCaps((IntPtr)mixerIndex, ref caps, Marshal.SizeOf(caps)), "mixerGetDevCaps"); mixerHandle = (IntPtr)mixerIndex; mixerHandleType = MixerFlags.Mixer; } public MixerLine GetDestination(int destinationIndex) { if (destinationIndex < 0 || destinationIndex >= DestinationCount) { throw new ArgumentOutOfRangeException("destinationIndex"); } return new MixerLine(mixerHandle, destinationIndex, mixerHandleType); } } public abstract class MixerControl { internal MixerInterop.MIXERCONTROL mixerControl; internal MixerInterop.MIXERCONTROLDETAILS mixerControlDetails; protected IntPtr mixerHandle; protected int nChannels; protected MixerFlags mixerHandleType; public string Name => mixerControl.szName; public MixerControlType ControlType => mixerControl.dwControlType; public bool IsBoolean => IsControlBoolean(mixerControl.dwControlType); public bool IsListText => IsControlListText(mixerControl.dwControlType); public bool IsSigned => IsControlSigned(mixerControl.dwControlType); public bool IsUnsigned => IsControlUnsigned(mixerControl.dwControlType); public bool IsCustom => IsControlCustom(mixerControl.dwControlType); public static IList<MixerControl> GetMixerControls(IntPtr mixerHandle, MixerLine mixerLine, MixerFlags mixerHandleType) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) List<MixerControl> list = new List<MixerControl>(); if (mixerLine.ControlsCount > 0) { int num = Marshal.SizeOf<MixerInterop.MIXERCONTROL>(); MixerInterop.MIXERLINECONTROLS mixerLineControls = default(MixerInterop.MIXERLINECONTROLS); IntPtr intPtr = Marshal.AllocHGlobal(num * mixerLine.ControlsCount); mixerLineControls.cbStruct = Marshal.SizeOf(mixerLineControls); mixerLineControls.dwLineID = mixerLine.LineId; mixerLineControls.cControls = mixerLine.ControlsCount; mixerLineControls.pamxctrl = intPtr; mixerLineControls.cbmxctrl = Marshal.SizeOf<MixerInterop.MIXERCONTROL>(); try { MmResult val = MixerInterop.mixerGetLineControls(mixerHandle, ref mixerLineControls, MixerFlags.Mixer | mixerHandleType); if ((int)val != 0) { throw new MmException(val, "mixerGetLineControls"); } for (int i = 0; i < mixerLineControls.cControls; i++) { MixerInterop.MIXERCONTROL mIXERCONTROL = Marshal.PtrToStructure<MixerInterop.MIXERCONTROL>((IntPtr)(intPtr.ToInt64() + num * i)); MixerControl item = GetMixerControl(mixerHandle, mixerLine.LineId, mIXERCONTROL.dwControlID, mixerLine.Channels, mixerHandleType); list.Add(item); } } finally { Marshal.FreeHGlobal(intPtr); } } return list; } public static MixerControl GetMixerControl(IntPtr mixerHandle, int nLineId, int controlId, int nChannels, MixerFlags mixerFlags) { //IL_005d: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) MixerInterop.MIXERLINECONTROLS mixerLineControls = default(MixerInterop.MIXERLINECONTROLS); MixerInterop.MIXERCONTROL structure = default(MixerInterop.MIXERCONTROL); IntPtr intPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(structure)); mixerLineControls.cbStruct = Marshal.SizeOf(mixerLineControls); mixerLineControls.cControls = 1; mixerLineControls.dwControlID = controlId; mixerLineControls.cbmxctrl = Marshal.SizeOf(structure); mixerLineControls.pamxctrl = intPtr; mixerLineControls.dwLineID = nLineId; MmResult val = MixerInterop.mixerGetLineControls(mixerHandle, ref mixerLineControls, MixerFlags.ListText | mixerFlags); if ((int)val != 0) { Marshal.FreeCoTaskMem(intPtr); throw new MmException(val, "mixerGetLineControls"); } structure = Marshal.PtrToStructure<MixerInterop.MIXERCONTROL>(mixerLineControls.pamxctrl); Marshal.FreeCoTaskMem(intPtr); if (IsControlBoolean(structure.dwControlType)) { return new BooleanMixerControl(structure, mixerHandle, mixerFlags, nChannels); } if (IsControlSigned(structure.dwControlType)) { return new SignedMixerControl(structure, mixerHandle, mixerFlags, nChannels); } if (IsControlUnsigned(structure.dwControlType)) { return new UnsignedMixerControl(structure, mixerHandle, mixerFlags, nChannels); } if (IsControlListText(structure.dwControlType)) { return new ListTextMixerControl(structure, mixerHandle, mixerFlags, nChannels); } if (IsControlCustom(structure.dwControlType)) { return new CustomMixerControl(structure, mixerHandle, mixerFlags, nChannels); } throw new InvalidOperationException($"Unknown mixer control type {structure.dwControlType}"); } protected void GetControlDetails() { //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: 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) mixerControlDetails.cbStruct = Marshal.SizeOf(mixerControlDetails); mixerControlDetails.dwControlID = mixerControl.dwControlID; if (IsCustom) { mixerControlDetails.cChannels = 0; } else if ((mixerControl.fdwControl & (true ? 1u : 0u)) != 0) { mixerControlDetails.cChannels = 1; } else { mixerControlDetails.cChannels = nChannels; } if ((mixerControl.fdwControl & 2u) != 0) { mixerControlDetails.hwndOwner = (IntPtr)mixerControl.cMultipleItems; } else if (IsCustom) { mixerControlDetails.hwndOwner = IntPtr.Zero; } else { mixerControlDetails.hwndOwner = IntPtr.Zero; } if (IsBoolean) { mixerControlDetails.cbDetails = Marshal.SizeOf<MixerInterop.MIXERCONTROLDETAILS_BOOLEAN>(); } else if (IsListText) { mixerControlDetails.cbDetails = Marshal.SizeOf<MixerInterop.MIXERCONTROLDETAILS_LISTTEXT>(); } else if (IsSigned) { mixerControlDetails.cbDetails = Marshal.SizeOf<MixerInterop.MIXERCONTROLDETAILS_SIGNED>(); } else if (IsUnsigned) { mixerControlDetails.cbDetails = Marshal.SizeOf<MixerInterop.MIXERCONTROLDETAILS_UNSIGNED>(); } else { mixerControlDetails.cbDetails = mixerControl.Metrics.customData; } int num = mixerControlDetails.cbDetails * mixerControlDetails.cChannels; if ((mixerControl.fdwControl & 2u) != 0) { num *= (int)mixerControl.cMultipleItems; } IntPtr intPtr = Marshal.AllocCoTaskMem(num); mixerControlDetails.paDetails = intPtr; MmResult val = MixerInterop.mixerGetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType); if ((int)val == 0) { GetDetails(mixerControlDetails.paDetails); } Marshal.FreeCoTaskMem(intPtr); if ((int)val != 0) { throw new MmException(val, "mixerGetControlDetails"); } } protected abstract void GetDetails(IntPtr pDetails); private static bool IsControlBoolean(MixerControlType controlType) { switch (controlType) { case MixerControlType.BooleanMeter: case MixerControlType.Boolean: case MixerControlType.OnOff: case MixerControlType.Mute: case MixerControlType.Mono: case MixerControlType.Loudness: case MixerControlType.StereoEnhance: case MixerControlType.Button: case MixerControlType.SingleSelect: case MixerControlType.Mux: case MixerControlType.MultipleSelect: case MixerControlType.Mixer: return true; default: return false; } } private static bool IsControlListText(MixerControlType controlType) { if (controlType == MixerControlType.Equalizer || (uint)(controlType - 1879113728) <= 1u || (uint)(controlType - 1895890944) <= 1u) { return true; } return false; } private static bool IsControlSigned(MixerControlType controlType) { switch (controlType) { case MixerControlType.SignedMeter: case MixerControlType.PeakMeter: case MixerControlType.Signed: case MixerControlType.Decibels: case MixerControlType.Slider: case MixerControlType.Pan: case MixerControlType.QSoundPan: return true; default: return false; } } private static bool IsControlUnsigned(MixerControlType controlType) { switch (controlType) { case MixerControlType.UnsignedMeter: case MixerControlType.Unsigned: case MixerControlType.Percent: case MixerControlType.Fader: case MixerControlType.Volume: case MixerControlType.Bass: case MixerControlType.Treble: case MixerControlType.Equalizer: case MixerControlType.MicroTime: case MixerControlType.MilliTime: return true; default: return false; } } private static bool IsControlCustom(MixerControlType controlType) { return controlType == MixerControlType.Custom; } public override string ToString() { return $"{Name} {ControlType}"; } } [Flags] internal enum MixerControlClass { Custom = 0, Meter = 0x10000000, Switch = 0x20000000, Number = 0x30000000, Slider = 0x40000000, Fader = 0x50000000, Time = 0x60000000, List = 0x70000000, Mask = 0x70000000 } [Flags] internal enum MixerControlSubclass { SwitchBoolean = 0, SwitchButton = 0x1000000, MeterPolled = 0, TimeMicrosecs = 0, TimeMillisecs = 0x1000000, ListSingle = 0, ListMultiple = 0x1000000, Mask = 0xF000000 } [Flags] internal enum MixerControlUnits { Custom = 0, Boolean = 0x10000, Signed = 0x20000, Unsigned = 0x30000, Decibels = 0x40000, Percent = 0x50000, Mask = 0xFF0000 } public enum MixerControlType { Custom = 0, BooleanMeter = 268500992, SignedMeter = 268566528, PeakMeter = 268566529, UnsignedMeter = 268632064, Boolean = 536936448, OnOff = 536936449, Mute = 536936450, Mono = 536936451, Loudness = 536936452, StereoEnhance = 536936453, Button = 553713664, Decibels = 805568512, Signed = 805437440, Unsigned = 805502976, Percent = 805634048, Slider = 1073872896, Pan = 1073872897, QSoundPan = 1073872898, Fader = 1342373888, Volume = 1342373889, Bass = 1342373890, Treble = 1342373891, Equalizer = 1342373892, SingleSelect = 1879113728, Mux = 1879113729, MultipleSelect = 1895890944, Mixer = 1895890945, MicroTime = 1610809344, MilliTime = 1627586560 } [Flags] public enum MixerFlags { Handle = int.MinValue, Mixer = 0, MixerHandle = int.MinValue, WaveOut = 0x10000000, WaveOutHandle = -1879048192, WaveIn = 0x20000000, WaveInHandle = -1610612736, MidiOut = 0x30000000, MidiOutHandle = -1342177280, MidiIn = 0x40000000, MidiInHandle = -1073741824, Aux = 0x50000000, Value = 0, ListText = 1, QueryMask = 0xF, All = 0, OneById = 1, OneByType = 2, GetLineInfoOfDestination = 0, GetLineInfoOfSource = 1, GetLineInfoOfLineId = 2, GetLineInfoOfComponentType = 3, GetLineInfoOfTargetType = 4, GetLineInfoOfQueryMask = 0xF } internal class MixerInterop { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)] public struct MIXERCONTROLDETAILS { public int cbStruct; public int dwControlID; public int cChannels; public IntPtr hwndOwner; public int cbDetails; public IntPtr paDetails; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MIXERCAPS { public ushort wMid; public ushort wPid; public uint vDriverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szPname; public uint fdwSupport; public uint cDestinations; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MIXERLINECONTROLS { public int cbStruct; public int dwLineID; public int dwControlID; public int cControls; public int cbmxctrl; public IntPtr pamxctrl; } [Flags] public enum MIXERLINE_LINEF { MIXERLINE_LINEF_ACTIVE = 1, MIXERLINE_LINEF_DISCONNECTED = 0x8000, MIXERLINE_LINEF_SOURCE = int.MinValue } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MIXERLINE { public int cbStruct; public int dwDestination; public int dwSource; public int dwLineID; public MIXERLINE_LINEF fdwLine; public IntPtr dwUser; public MixerLineComponentType dwComponentType; public int cChannels; public int cConnections; public int cControls; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string szShortName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string szName; public uint dwType; public uint dwDeviceID; public ushort wMid; public ushort wPid; public uint vDriverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szPname; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Bounds { public int minimum; public int maximum; public int reserved2; public int reserved3; public int reserved4; public int reserved5; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Metrics { public int step; public int customData; public int reserved2; public int reserved3; public int reserved4; public int reserved5; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MIXERCONTROL { public uint cbStruct; public int dwControlID; public MixerControlType dwControlType; public uint fdwControl; public uint cMultipleItems; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string szShortName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string szName; public Bounds Bounds; public Metrics Metrics; } public struct MIXERCONTROLDETAILS_BOOLEAN { public int fValue; } public struct MIXERCONTROLDETAILS_SIGNED { public int lValue; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MIXERCONTROLDETAILS_LISTTEXT { public uint dwParam1; public uint dwParam2; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string szName; } public struct MIXERCONTROLDETAILS_UNSIGNED { public uint dwValue; } public const uint MIXERCONTROL_CONTROLF_UNIFORM = 1u; public const uint MIXERCONTROL_CONTROLF_MULTIPLE = 2u; public const uint MIXERCONTROL_CONTROLF_DISABLED = 2147483648u; public const int MAXPNAMELEN = 32; public const int MIXER_SHORT_NAME_CHARS = 16; public const int MIXER_LONG_NAME_CHARS = 64; [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern int mixerGetNumDevs(); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerOpen(out IntPtr hMixer, int uMxId, IntPtr dwCallback, IntPtr dwInstance, MixerFlags dwOpenFlags); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerClose(IntPtr hMixer); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerGetControlDetails(IntPtr hMixer, ref MIXERCONTROLDETAILS mixerControlDetails, MixerFlags dwDetailsFlags); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerGetDevCaps(IntPtr nMixerID, ref MIXERCAPS mixerCaps, int mixerCapsSize); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerGetID(IntPtr hMixer, out int mixerID, MixerFlags dwMixerIDFlags); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerGetLineControls(IntPtr hMixer, ref MIXERLINECONTROLS mixerLineControls, MixerFlags dwControlFlags); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerGetLineInfo(IntPtr hMixer, ref MIXERLINE mixerLine, MixerFlags dwInfoFlags); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerMessage(IntPtr hMixer, uint nMessage, IntPtr dwParam1, IntPtr dwParam2); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern MmResult mixerSetControlDetails(IntPtr hMixer, ref MIXERCONTROLDETAILS mixerControlDetails, MixerFlags dwDetailsFlags); } public class MixerLine { private MixerInterop.MIXERLINE mixerLine; private IntPtr mixerHandle; private MixerFlags mixerHandleType; public string Name => mixerLine.szName; public string ShortName => mixerLine.szShortName; public int LineId => mixerLine.dwLineID; public MixerLineComponentType ComponentType => mixerLine.dwComponentType; public string TypeDescription => mixerLine.dwComponentType switch { MixerLineComponentType.DestinationUndefined => "Undefined Destination", MixerLineComponentType.DestinationDigital => "Digital Destination", MixerLineComponentType.DestinationLine => "Line Level Destination", MixerLineComponentType.DestinationMonitor => "Monitor Destination", MixerLineComponentType.DestinationSpeakers => "Speakers Destination", MixerLineComponentType.DestinationHeadphones => "Headphones Destination", MixerLineComponentType.DestinationTelephone => "Telephone Destination", MixerLineComponentType.DestinationWaveIn => "Wave Input Destination", MixerLineComponentType.DestinationVoiceIn => "Voice Recognition Destination", MixerLineComponentType.SourceUndefined => "Undefined Source", MixerLineComponentType.SourceDigital => "Digital Source", MixerLineComponentType.SourceLine => "Line Level Source", MixerLineComponentType.SourceMicrophone => "Microphone Source", MixerLineComponentType.SourceSynthesizer => "Synthesizer Source", MixerLineComponentType.SourceCompactDisc => "Compact Disk Source", MixerLineComponentType.SourceTelephone => "Telephone Source", MixerLineComponentType.SourcePcSpeaker => "PC Speaker Source", MixerLineComponentType.SourceWaveOut => "Wave Out Source", MixerLineComponentType.SourceAuxiliary => "Auxiliary Source", MixerLineComponentType.SourceAnalog => "Analog Source", _ => "Invalid Component Type", }; public int Channels => mixerLine.cChannels; public int SourceCount => mixerLine.cConnections; public int ControlsCount => mixerLine.cControls; public bool IsActive => (mixerLine.fdwLine & MixerInterop.MIXERLINE_LINEF.MIXERLINE_LINEF_ACTIVE) != 0; public bool IsDisconnected => (mixerLine.fdwLine & MixerInterop.MIXERLINE_LINEF.MIXERLINE_LINEF_DISCONNECTED) != 0; public bool IsSource => (mixerLine.fdwLine & MixerInterop.MIXERLINE_LINEF.MIXERLINE_LINEF_SOURCE) != 0; public IEnumerable<MixerControl> Controls => MixerControl.GetMixerControls(mixerHandle, this, mixerHandleType); public IEnumerable<MixerLine> Sources { get { for (int source = 0; source < SourceCount; source++) { yield return GetSource(source); } } } public string TargetName => mixerLine.szPname; public MixerLine(IntPtr mixerHandle, int destinationIndex, MixerFlags mixerHandleType) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) this.mixerHandle = mixerHandle; this.mixerHandleType = mixerHandleType; mixerLine = default(MixerInterop.MIXERLINE); mixerLine.cbStruct = Marshal.SizeOf(mixerLine); mixerLine.dwDestination = destinationIndex; MmException.Try(MixerInterop.mixerGetLineInfo(mixerHandle, ref mixerLine, mixerHandleType | MixerFlags.Mixer), "mixerGetLineInfo"); } public MixerLine(IntPtr mixerHandle, int destinationIndex, int sourceIndex, MixerFlags mixerHandleType) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) this.mixerHandle = mixerHandle; this.mixerHandleType = mixerHandleType; mixerLine = default(MixerInterop.MIXERLINE); mixerLine.cbStruct = Marshal.SizeOf(mixerLine); mixerLine.dwDestination = destinationIndex; mixerLine.dwSource = sourceIndex; MmException.Try(MixerInterop.mixerGetLineInfo(mixerHandle, ref mixerLine, mixerHandleType | MixerFlags.ListText), "mixerGetLineInfo"); } public static int GetMixerIdForWaveIn(int waveInDevice) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) int mixerID = -1; MmException.Try(MixerInterop.mixerGetID((IntPtr)waveInDevice, out mixerID, MixerFlags.WaveIn), "mixerGetID"); return mixerID; } public MixerLine GetSource(int sourceIndex) { if (sourceIndex < 0 || sourceIndex >= SourceCount) { throw new ArgumentOutOfRangeException("sourceIndex"); } return new MixerLine(mixerHandle, mixerLine.dwDestination, sourceIndex, mixerHandleType); } public override string ToString() { return $"{Name} {TypeDescription} ({ControlsCount} controls, ID={mixerLine.dwLineID})"; } } public enum MixerLineComponentType { DestinationUndefined = 0, DestinationDigital = 1, DestinationLine = 2, DestinationMonitor = 3, DestinationSpeakers = 4, DestinationHeadphones = 5, DestinationTelephone = 6, DestinationWaveIn = 7, DestinationVoiceIn = 8, SourceUndefined = 4096, SourceDigital = 4097, SourceLine = 4098, SourceMicrophone = 4099, SourceSynthesizer = 4100, SourceCompactDisc = 4101, SourceTelephone = 4102, SourcePcSpeaker = 4103, SourceWaveOut = 4104, SourceAuxiliary = 4105, SourceAnalog = 4106 } public class SignedMixerControl : MixerControl { private MixerInterop.MIXERCONTROLDETAILS_SIGNED signedDetails; public int Value { get { GetControlDetails(); return signedDetails.lValue; } set { //IL_0052: Unknown result type (might be due to invalid IL or missing references) signedDetails.lValue = value; mixerControlDetails.paDetails = Marshal.AllocHGlobal(Marshal.SizeOf(signedDetails)); Marshal.StructureToPtr(signedDetails, mixerControlDetails.paDetails, fDeleteOld: false); MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType), "mixerSetControlDetails"); Marshal.FreeHGlobal(mixerControlDetails.paDetails); } } public int MinValue => mixerControl.Bounds.minimum; public int MaxValue => mixerControl.Bounds.maximum; public double Percent { get { return 100.0 * (double)(Value - MinValue) / (double)(MaxValue - MinValue); } set { Value = (int)((double)MinValue + value / 100.0 * (double)(MaxValue - MinValue)); } } internal SignedMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels) { base.mixerControl = mixerControl; base.mixerHandle = mixerHandle; base.mixerHandleType = mixerHandleType; base.nChannels = nChannels; mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS); GetControlDetails(); } protected override void GetDetails(IntPtr pDetails) { signedDetails = Marshal.PtrToStructure<MixerInterop.MIXERCONTROLDETAILS_SIGNED>(mixerControlDetails.paDetails); } public override string ToString() { return $"{base.ToString()} {Percent}%"; } } public class UnsignedMixerControl : MixerControl { private MixerInterop.MIXERCONTROLDETAILS_UNSIGNED[] unsignedDetails; public uint Value { get { GetControlDetails(); return unsignedDetails[0].dwValue; } set { //IL_008f: Unknown result type (might be due to invalid IL or missing references) int num = Marshal.SizeOf(unsignedDetails[0]); mixerControlDetails.paDetails = Marshal.AllocHGlobal(num * nChannels); for (int i = 0; i < nChannels; i++) { unsignedDetails[i].dwValue = value; long num2 = mixerControlDetails.paDetails.ToInt64() + num * i; Marshal.StructureToPtr(unsignedDetails[i], (IntPtr)num2, fDeleteOld: false); } MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType), "mixerSetControlDetails"); Marshal.FreeHGlobal(mixerControlDetails.paDetails); } } public uint MinValue => (uint)mixerControl.Bounds.minimum; public uint MaxValue => (uint)mixerControl.Bounds.maximum; public double Percent { get { return 100.0 * (double)(Value - MinValue) / (double)(MaxValue - MinValue); } set { Value = (uint)((double)MinValue + value / 100.0 * (double)(MaxValue - MinValue)); } } internal UnsignedMixerControl(MixerInterop.MIXERCONTROL mixerControl, IntPtr mixerHandle, MixerFlags mixerHandleType, int nChannels) { base.mixerControl = mixerControl; base.mixerHandle = mixerHandle; base.mixerHandleType = mixerHandleType; base.nChannels = nChannels; mixerControlDetails = default(MixerInterop.MIXERCONTROLDETAILS); GetControlDetails(); } protected override void GetDetails(IntPtr pDetails) { unsignedDetails = new MixerInterop.MIXERCONTROLDETAILS_UNSIGNED[nChannels]; for (int i = 0; i < nChannels; i++) { unsignedDetails[i] = Marshal.PtrToStructure<MixerInterop.MIXERCONTROLDETAILS_UNSIGNED>(mixerControlDetails.paDetails); } } public override string ToString() { return $"{base.ToString()} {Percent}%"; } } } namespace NAudio.Wave { internal enum AcmMetrics { CountDrivers = 1, CountCodecs = 2, CountConverters = 3, CountFilters = 4, CountDisabled = 5, CountHardware = 6, CountLocalDrivers = 20, CountLocalCodecs = 21, CountLocalConverters = 22, CountLocalFilters = 23, CountLocalDisabled = 24, HardwareWaveInput = 30, HardwareWaveOutput = 31, MaxSizeFormat = 50, MaxSizeFilter = 51, DriverSupport = 100, DriverPriority = 101 } [Flags] internal enum AcmStreamConvertFlags { BlockAlign = 4, Start = 0x10, End = 0x20 } [StructLayout(LayoutKind.Explicit)] public struct MmTime { public const int TIME_MS = 1; public const int TIME_SAMPLES = 2; public const int TIME_BYTES = 4; [FieldOffset(0)] public uint wType; [FieldOffset(4)] public uint ms; [FieldOffset(4)] public uint sample; [FieldOffset(4)] public uint cb; [FieldOffset(4)] public uint ticks; [FieldOffset(4)] public byte smpteHour; [FieldOffset(5)] public byte smpteMin; [FieldOffset(6)] public byte smpteSec; [FieldOffset(7)] public byte smpteFrame; [FieldOffset(8)] public byte smpteFps; [FieldOffset(9)] public byte smpteDummy; [FieldOffset(10)] public byte smptePad0; [FieldOffset(11)] public byte smptePad1; [FieldOffset(4)] public uint midiSongPtrPos; } public enum WaveCallbackStrategy { FunctionCallback, NewWindow, ExistingWindow, Event } [StructLayout(LayoutKind.Sequential)] public sealed class WaveHeader { public IntPtr dataBuffer; public int bufferLength; public int bytesRecorded; public IntPtr userData; public WaveHeaderFlags flags; public int loops; public IntPtr next; public IntPtr reserved; } [Flags] public enum WaveHeaderFlags { BeginLoop = 4, Done = 1, EndLoop = 8, InQueue = 0x10, Prepared = 2 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct WaveInCapabilities { private short manufacturerId; private short productId; private int driverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] private string productName; private SupportedWaveFormat supportedFormats; private short channels; private short reserved; private Guid manufacturerGuid; private Guid productGuid; private Guid nameGuid; private const int MaxProductNameLength = 32; public int Channels => channels; public string ProductName => productName; public Guid NameGuid => nameGuid; public Guid ProductGuid => productGuid; public Guid ManufacturerGuid => manufacturerGuid; public bool SupportsWaveFormat(SupportedWaveFormat waveFormat) { return (supportedFormats & waveFormat) == waveFormat; } } public static class WaveCapabilitiesHelpers { public static readonly Guid MicrosoftDefaultManufacturerId = new Guid("d5a47fa8-6d98-11d1-a21a-00a0c9223196"); public static readonly Guid DefaultWaveOutGuid = new Guid("E36DC310-6D9A-11D1-A21A-00A0C9223196"); public static readonly Guid DefaultWaveInGuid = new Guid("E36DC311-6D9A-11D1-A21A-00A0C9223196"); public static string GetNameFromGuid(Guid guid) { string result = null; using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\MediaCategories")) { using RegistryKey registryKey2 = registryKey.OpenSubKey(guid.ToString("B")); if (registryKey2 != null) { result = registryKey2.GetValue("Name") as string; } } return result; } } public class WaveInterop { [Flags] public enum WaveInOutOpenFlags { CallbackNull = 0, CallbackFunction = 0x30000, CallbackEvent = 0x50000, CallbackWindow = 0x10000, CallbackThread = 0x20000 } public enum WaveMessage { WaveInOpen = 958, WaveInClose = 959, WaveInData = 960, WaveOutClose = 956, WaveOutDone = 957, WaveOutOpen = 955 } public delegate void WaveCallback(IntPtr hWaveOut, WaveMessage message, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved); [DllImport("winmm.dll")] public static extern int mmioStringToFOURCC([MarshalAs(UnmanagedType.LPStr)] string s, int flags); [DllImport("winmm.dll")] public static extern int waveOutGetNumDevs(); [DllImport("winmm.dll")] public static extern MmResult waveOutPrepareHeader(IntPtr hWaveOut, WaveHeader lpWaveOutHdr, int uSize); [DllImport("winmm.dll")] public static extern MmResult waveOutUnprepareHeader(IntPtr hWaveOut, WaveHeader lpWaveOutHdr, int uSize); [DllImport("winmm.dll")] public static extern MmResult waveOutWrite(IntPtr hWaveOut, WaveHeader lpWaveOutHdr, int uSize); [DllImport("winmm.dll")] public static extern MmResult waveOutOpen(out IntPtr hWaveOut, IntPtr uDeviceID, WaveFormat lpFormat, WaveCallback dwCallback, IntPtr dwInstance, WaveInOutOpenFlags dwFlags); [DllImport("winmm.dll", EntryPoint = "waveOutOpen")] public static extern MmResult waveOutOpenWindow(out IntPtr hWaveOut, IntPtr uDeviceID, WaveFormat lpFormat, IntPtr callbackWindowHandle, IntPtr dwInstance, WaveInOutOpenFlags dwFlags); [DllImport("winmm.dll")] public static extern MmResult waveOutReset(IntPtr hWaveOut); [DllImport("winmm.dll")] public static extern MmResult waveOutClose(IntPtr hWaveOut); [DllImport("winmm.dll")] public static extern MmResult waveOutPause(IntPtr hWaveOut); [DllImport("winmm.dll")] public static extern MmResult waveOutRestart(IntPtr hWaveOut); [DllImport("winmm.dll")] public static extern MmResult waveOutGetPosition(IntPtr hWaveOut, ref MmTime mmTime, int uSize); [DllImport("winmm.dll")] public static extern MmResult waveOutSetVolume(IntPtr hWaveOut, int dwVolume); [DllImport("winmm.dll")] public static extern MmResult waveOutGetVolume(IntPtr hWaveOut, out int dwVolume); [DllImport("winmm.dll", CharSet = CharSet.Auto)] public static extern MmResult waveOutGetDevCaps(IntPtr deviceID, out WaveOutCapabilities waveOutCaps, int waveOutCapsSize); [DllImport("winmm.dll")] public static extern int waveInGetNumDevs(); [DllImport("winmm.dll", CharSet = CharSet.Auto)] public static extern MmResult waveInGetDevCaps(IntPtr deviceID, out WaveInCapabilities waveInCaps, int waveInCapsSize); [DllImport("winmm.dll")] public static extern MmResult waveInAddBuffer(IntPtr hWaveIn, WaveHeader pwh, int cbwh); [DllImport("winmm.dll")] public static extern MmResult waveInClose(IntPtr hWaveIn); [DllImport("winmm.dll")] public static extern MmResult waveInOpen(out IntPtr hWaveIn, IntPtr uDeviceID, WaveFormat lpFormat, WaveCallback dwCallback, IntPtr dwInstance, WaveInOutOpenFlags dwFlags); [DllImport("winmm.dll", EntryPoint = "waveInOpen")] public static extern MmResult waveInOpenWindow(out IntPtr hWaveIn, IntPtr uDeviceID, WaveFormat lpFormat, IntPtr callbackWindowHandle, IntPtr dwInstance, WaveInOutOpenFlags dwFlags); [DllImport("winmm.dll")] public static extern MmResult waveInPrepareHeader(IntPtr hWaveIn, WaveHeader lpWaveInHdr, int uSize); [DllImport("winmm.dll")] public static extern MmResult waveInUnprepareHeader(IntPtr hWaveIn, WaveHeader lpWaveInHdr, int uSize); [DllImport("winmm.dll")] public static extern MmResult waveInReset(IntPtr hWaveIn); [DllImport("winmm.dll")] public static extern MmResult waveInStart(IntPtr hWaveIn); [DllImport("winmm.dll")] public static extern MmResult waveInStop(IntPtr hWaveIn); [DllImport("winmm.dll")] public static extern MmResult waveInGetPosition(IntPtr hWaveIn, out MmTime mmTime, int uSize); } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct WaveOutCapabilities { private short manufacturerId; private short productId; private int driverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] private string productName; private SupportedWaveFormat supportedFormats; private short channels; private short reserved; private WaveOutSupport support; private Guid manufacturerGuid; private Guid productGuid; private Guid nameGuid; private const int MaxProductNameLength = 32; public int Channels => channels; public bool SupportsPlaybackRateControl => (support & WaveOutSupport.PlaybackRate) == WaveOutSupport.PlaybackRate; public string ProductName => productName; public Guid NameGuid => nameGuid; public Guid ProductGuid => productGuid; public Guid ManufacturerGuid => manufacturerGuid; public bool SupportsWaveFormat(SupportedWaveFormat waveFormat) { return (supportedFormats & waveFormat) == waveFormat; } } [Flags] public enum SupportedWaveFormat { WAVE_FORMAT_1M08 = 1, WAVE_FORMAT_1S08 = 2, WAVE_FORMAT_1M16 = 4, WAVE_FORMAT_1S16 = 8, WAVE_FORMAT_2M08 = 0x10, WAVE_FORMAT_2S08 = 0x20, WAVE_FORMAT_2M16 = 0x40, WAVE_FORMAT_2S16 = 0x80, WAVE_FORMAT_4M08 = 0x100, WAVE_FORMAT_4S08 = 0x200, WAVE_FORMAT_4M16 = 0x400, WAVE_FORMAT_4S16 = 0x800, WAVE_FORMAT_44M08 = 0x100, WAVE_FORMAT_44S08 = 0x200, WAVE_FORMAT_44M16 = 0x400, WAVE_FORMAT_44S16 = 0x800, WAVE_FORMAT_48M08 = 0x1000, WAVE_FORMAT_48S08 = 0x2000, WAVE_FORMAT_48M16 = 0x4000, WAVE_FORMAT_48S16 = 0x8000, WAVE_FORMAT_96M08 = 0x10000, WAVE_FORMAT_96S08 = 0x20000, WAVE_FORMAT_96M16 = 0x40000, WAVE_FORMAT_96S16 = 0x80000 } [Flags] internal enum WaveOutSupport { Pitch = 1, PlaybackRate = 2, Volume = 4, LRVolume = 8, Sync = 0x10, SampleAccurate = 0x20 } public class AcmMp3FrameDecompressor : IMp3FrameDecompressor, IDisposable { private readonly AcmStream conversionStream; private readonly WaveFormat pcmFormat; private bool disposed; public WaveFormat OutputFormat => pcmFormat; public AcmMp3FrameDecompressor(WaveFormat sourceFormat) { pcmFormat = AcmStream.SuggestPcmFormat(sourceFormat); try { conversionStream = new AcmStream(sourceFormat, pcmFormat); } catch (Exception) { disposed = true; GC.SuppressFinalize(this); throw; } } public int DecompressFrame(Mp3Frame frame, byte[] dest, int destOffset) { if (frame == null) { throw new ArgumentNullException("frame", "You must provide a non-null Mp3Frame to decompress"); } Array.Copy(frame.RawData, conversionStream.SourceBuffer, frame.FrameLength); int sourceBytesConverted; int num = conversionStream.Convert(frame.FrameLength, out sourceBytesConverted); if (sourceBytesConverted != frame.FrameLength) { throw new InvalidOperationException($"Couldn't convert the whole MP3 frame (converted {sourceBytesConverted}/{frame.FrameLength})"); } Array.Copy(conversionStream.DestBuffer, 0, dest, destOffset, num); return num; } public void Reset() { conversionStream.Reposition(); } public void Dispose() { if (!disposed) { disposed = true; if (conversionStream != null) { conversionStream.Dispose(); } GC.SuppressFinalize(this); } } ~AcmMp3FrameDecompressor() { Dispose(); } } public class WaveFormatConversionProvider : IWaveProvider, IDisposable { private readonly AcmStream conversionStream; private readonly IWaveProvider sourceProvider; private readonly int preferredSourceReadSize; private int leftoverDestBytes; private int leftoverDestOffset; private int leftoverSourceBytes; private bool isDisposed; public WaveFormat WaveFormat { get; } public WaveFormatConversionProvider(WaveFormat targetFormat, IWaveProvider sourceProvider) { this.sourceProvider = sourceProvider; WaveFormat = targetFormat; conversionStream = new AcmStream(sourceProvider.WaveFormat, targetFormat); preferredSourceReadSize = Math.Min(sourceProvider.WaveFormat.AverageBytesPerSecond, conversionStream.SourceBuffer.Length); preferredSourceReadSize -= preferredSourceReadSize % sourceProvider.WaveFormat.BlockAlign; } public void Reposition() { leftoverDestBytes = 0; leftoverDestOffset = 0; leftoverSourceBytes = 0; conversionStream.Reposition(); } public int Read(byte[] buffer, int offset, int count) { int i = 0; if (count % WaveFormat.BlockAlign != 0) { count -= count % WaveFormat.BlockAlign; } int num5; for (; i < count; i += num5) { int num = Math.Min(count - i, leftoverDestBytes); if (num > 0) { Array.Copy(conversionStream.DestBuffer, leftoverDestOffset, buffer, offset + i, num); leftoverDestOffset += num; leftoverDestBytes -= num; i += num; } if (i >= count) { break; } int num2 = Math.Min(preferredSourceReadSize, conversionStream.SourceBuffer.Length - leftoverSourceBytes); int num3 = sourceProvider.Read(conversionStream.SourceBuffer, leftoverSourceBytes, num2) + leftoverSourceBytes; if (num3 == 0) { break; } int sourceBytesConverted; int num4 = conversionStream.Convert(num3, out sourceBytesConverted); if (sourceBytesConverted == 0) { break; } leftoverSourceBytes = num3 - sourceBytesConverted; if (leftoverSourceBytes > 0) { Buffer.BlockCopy(conversionStream.SourceBuffer, sourceBytesConverted, conversionStream.SourceBuffer, 0, leftoverSourceBytes); } if (num4 <= 0) { break; } int val = count - i; num5 = Math.Min(num4, val); if (num5 < num4) { leftoverDestBytes = num4 - num5; leftoverDestOffset = num5; } Array.Copy(conversionStream.DestBuffer, 0, buffer, i + offset, num5); } return i; } protected virtual void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; conversionStream?.Dispose(); } } public void Dispose() { GC.SuppressFinalize(this); Dispose(disposing: true); } ~WaveFormatConversionProvider() { Dispose(disposing: false); } } public class WaveFormatConversionStream : WaveStream { private readonly WaveFormatConversionProvider conversionProvider; private readonly WaveFormat targetFormat; private readonly long length; private long position; private readonly WaveStream sourceStream; private bool isDisposed; public override long Position { get { return position; } set { value -= value % ((WaveStream)this).BlockAlign; long num = EstimateDestToSource(value); ((Stream)(object)sourceStream).Position = num; position = EstimateSourceToDest(((Stream)(object)sourceStream).Position); conversionProvider.Reposition(); } } public override long Length => length; public override WaveFormat WaveFormat => targetFormat; public WaveFormatConversionStream(WaveFormat targetFormat, WaveStream sourceStream) { this.sourceStream = sourceStream; this.targetFormat = targetFormat; conversionProvider = new WaveFormatConversionProvider(targetFormat, (IWaveProvider)(object)sourceStream); length = EstimateSourceToDest((int)((Stream)(object)sourceStream).Length); position = 0L; } public static WaveStream CreatePcmStream(WaveStream sourceStream) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown if ((int)sourceStream.WaveFormat.Encoding == 1) { return sourceStream; } WaveFormat val = AcmStream.SuggestPcmFormat(sourceStream.WaveFormat); if (val.SampleRate < 8000) { if ((int)sourceStream.WaveFormat.Encoding != 163) { throw new InvalidOperationException("Invalid suggested output format, please explicitly provide a target format"); } val = new WaveFormat(8000, 16, 1); } return (WaveStream)(object)new WaveFormatConversionStream(val, sourceStream); } [Obsolete("can be unreliable, use of this method not encouraged")] public int SourceToDest(int source) { return (int)EstimateSourceToDest(source); } private long EstimateSourceToDest(long source) { long num = source * targetFormat.AverageBytesPerSecond / sourceStream.WaveFormat.AverageBytesPerSecond; return num - num % targetFormat.BlockAlign; } private long EstimateDestToSource(long dest) { long num = dest * sourceStream.WaveFormat.AverageBytesPerSecond / targetFormat.AverageBytesPerSecond; return (int)(num - num % sourceStream.WaveFormat.BlockAlign); } [Obsolete("can be unreliable, use of this method not encouraged")] public int DestToSource(int dest) { return (int)EstimateDestToSource(dest); } public override int Read(byte[] buffer, int offset, int count) { int num = conversionProvider.Read(buffer, offset, count); position += num; return num; } protected override void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; if (disposing) { ((Stream)(object)sourceStream).Dispose(); conversionProvider.Dispose(); } } ((Stream)this).Dispose(disposing); } } public class WaveInBuffer : IDisposable { private readonly WaveHeader header; private readonly int bufferSize; private readonly byte[] buffer; private GCHandle hBuffer; private IntPtr waveInHandle; private GCHandle hHeader; private GCHandle hThis; public byte[] Data => buffer; public bool Done => (header.flags & WaveHeaderFlags.Done) == WaveHeaderFlags.Done; public bool InQueue => (header.flags & WaveHeaderFlags.InQueue) == WaveHeaderFlags.InQueue; public int BytesRecorded => header.bytesRecorded; public int BufferSize => bufferSize; public WaveInBuffer(IntPtr waveInHandle, int bufferSize) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) this.bufferSize = bufferSize; buffer = new byte[bufferSize]; hBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); this.waveInHandle = waveInHandle; header = new WaveHeader(); hHeader = GCHandle.Alloc(header, GCHandleType.Pinned); header.dataBuffer = hBuffer.AddrOfPinnedObject(); header.bufferLength = bufferSize; header.loops = 1; hThis = GCHandle.Alloc(this); header.userData = (IntPtr)hThis; MmException.Try(WaveInterop.waveInPrepareHeader(waveInHandle, header, Marshal.SizeOf(header)), "waveInPrepareHeader"); } public void Reuse() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) MmException.Try(WaveInterop.waveInUnprepareHeader(waveInHandle, header, Marshal.SizeOf(header)), "waveUnprepareHeader"); MmException.Try(WaveInterop.waveInPrepareHeader(waveInHandle, header, Marshal.SizeOf(header)), "waveInPrepareHeader"); MmException.Try(WaveInterop.waveInAddBuffer(waveInHandle, header, Marshal.SizeOf(header)), "waveInAddBuffer"); } ~WaveInBuffer() { Dispose(disposing: false); } public void Dispose() { GC.SuppressFinalize(this); Dispose(disposing: true); } protected void Dispose(bool disposing) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (waveInHandle != IntPtr.Zero) { WaveInterop.waveInUnprepareHeader(waveInHandle, header, Marshal.SizeOf(header)); waveInHandle = IntPtr.Zero; } if (hHeader.IsAllocated) { hHeader.Free(); } if (hBuffer.IsAllocated) { hBuffer.Free(); } if (hThis.IsAllocated) { hThis.Free(); } } } public class WaveInEvent : IWaveIn, IDisposable { private readonly AutoResetEvent callbackEvent; private readonly SynchronizationContext syncContext; private IntPtr waveInHandle; private volatile CaptureState captureState; private WaveInBuffer[] buffers; public static int DeviceCount => WaveInterop.waveInGetNumDevs(); public int BufferMilliseconds { get; set; } public int NumberOfBuffers { get; set; } public int DeviceNumber { get; set; } public WaveFormat WaveFormat { get; set; } public event EventHandler<WaveInEventArgs> DataAvailable; public event EventHandler<StoppedEventArgs> RecordingStopped; public WaveInEvent() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) callbackEvent = new AutoResetEvent(initialState: false); syncContext = SynchronizationContext.Current; DeviceNumber = 0; WaveFormat = new WaveFormat(8000, 16, 1); BufferMilliseconds = 100; NumberOfBuffers = 3; captureState = (CaptureState)0; } public static WaveInCapabilities GetCapabilities(int devNumber) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) WaveInCapabilities waveInCaps = default(WaveInCapabilities); int waveInCapsSize = Marshal.SizeOf(waveInCaps); MmException.Try(WaveInterop.waveInGetDevCaps((IntPtr)devNumber, out waveInCaps, waveInCapsSize), "waveInGetDevCaps"); return waveInCaps; } private void CreateBuffers() { int num = BufferMilliseconds * WaveFormat.AverageBytesPerSecond / 1000; if (num % WaveFormat.BlockAlign != 0) { num -= num % WaveFormat.BlockAlign; } buffers = new WaveInBuffer[NumberOfBuffers]; for (int i = 0; i < buffers.Length; i++) { buffers[i] = new WaveInBuffer(waveInHandle, num); } } private void OpenWaveInDevice() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) CloseWaveInDevice(); MmException.Try(WaveInterop.waveInOpenWindow(out waveInHandle, (IntPtr)DeviceNumber, WaveFormat, callbackEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, WaveInterop.WaveInOutOpenFlags.CallbackEvent), "waveInOpen"); CreateBuffers(); } public void StartRecording() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) if ((int)captureState != 0) { throw new InvalidOperationException("Already recording"); } OpenWaveInDevice(); MmException.Try(WaveInterop.waveInStart(waveInHandle), "waveInStart"); captureState = (CaptureState)1; ThreadPool.QueueUserWorkItem(delegate { RecordThread(); }, null); } private void RecordThread() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Exception e = null; try { DoRecording(); } catch (Exception ex) { e = ex; } finally { captureState = (CaptureState)0; RaiseRecordingStoppedEvent(e); } } private void DoRecording() { //IL_0002: 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_00a6: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Invalid comparison between Unknown and I4 //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown captureState = (CaptureState)2; WaveInBuffer[] array = buffers; foreach (WaveInBuffer waveInBuffer in array) { if (!waveInBuffer.InQueue) { waveInBuffer.Reuse(); } } while ((int)captureState == 2) { if (!callbackEvent.WaitOne()) { continue; } array = buffers; foreach (WaveInBuffer waveInBuffer2 in array) { if (waveInBuffer2.Done) { if (waveInBuffer2.BytesRecorded > 0) { this.DataAvailable?.Invoke(this, new WaveInEventArgs(waveInBuffer2.Data, waveInBuffer2.BytesRecorded)); } if ((int)captureState == 2) { waveInBuffer2.Reuse(); } } } } } private void RaiseRecordingStoppedEvent(Exception e) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown EventHandler<StoppedEventArgs> handler = this.RecordingStopped; if (handler == null) { return; } if (syncContext == null) { handler(this, new StoppedEventArgs(e)); return; } syncContext.Post(delegate { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown handler(this, new StoppedEventArgs(e)); }, null); } public void StopRecording() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) if ((int)captureState != 0) { captureState = (CaptureState)3; MmException.Try(WaveInterop.waveInStop(waveInHandle), "waveInStop"); MmException.Try(WaveInterop.waveInReset(waveInHandle), "waveInReset"); callbackEvent.Set(); } } public long GetPosition() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) MmTime mmTime = default(MmTime); mmTime.wType = 4u; MmException.Try(WaveInterop.waveInGetPosition(waveInHandle, out mmTime, Marshal.SizeOf(mmTime)), "waveInGetPosition"); if (mmTime.wType != 4) { throw new Exception($"waveInGetPosition: wType -> Expected {4}, Received {mmTime.wType}"); } return mmTime.cb; } protected virtual void Dispose(bool disposing) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (disposing) { if ((int)captureState != 0) { StopRecording(); } CloseWaveInDevice(); } } private void CloseWaveInDevice() { //IL_0006: 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) WaveInterop.waveInReset(waveInHandle); if (buffers != null) { for (int i = 0; i < buffers.Length; i++) { buffers[i].Dispose(); } buffers = null; } WaveInterop.waveInClose(waveInHandle); waveInHandle = IntPtr.Zero; } public MixerLine GetMixerLine() { if (waveInHandle != IntPtr.Zero) { return new MixerLine(waveInHandle, 0, MixerFlags.WaveInHandle); } return new MixerLine((IntPtr)DeviceNumber, 0, MixerFlags.WaveIn); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public class WaveOutBuffer : IDisposable { private readonly WaveHeader header; private readonly int bufferSize; private readonly byte[] buffer; private readonly IWaveProvider waveStream; private readonly object waveOutLock; private GCHandle hBuffer; private IntPtr hWaveOut; private GCHandle hHeader; private GCHandle hThis; public bool InQueue => (header.flags & WaveHeaderFlags.InQueue) == WaveHeaderFlags.InQueue; public int BufferSize => bufferSize; public WaveOutBuffer(IntPtr hWaveOut, int bufferSize, IWaveProvider bufferFillStream, object waveOutLock) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) this.bufferSize = bufferSize; buffer = new byte[bufferSize]; hBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); this.hWaveOut = hWaveOut; waveStream = bufferFillStream; this.waveOutLock = waveOutLock; header = new WaveHeader(); hHeader = GCHandle.Alloc(header, GCHandleType.Pinned); header.dataBuffer = hBuffer.AddrOfPinnedObject(); header.bufferLength = bufferSize; header.loops = 1; hThis = GCHandle.Alloc(this); header.userData = (IntPtr)hThis; lock (waveOutLock) { MmException.Try(WaveInterop.waveOutPrepareHeader(hWaveOut, header, Marshal.SizeOf(header)), "waveOutPrepareHeader"); } } ~WaveOutBuffer() { Dispose(disposing: false); } public void Dispose() { GC.SuppressFinalize(this); Dispose(disposing: true); } protected void Dispose(bool disposing) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (hHeader.IsAllocated) { hHeader.Free(); } if (hBuffer.IsAllocated) { hBuffer.Free(); } if (hThis.IsAllocated) { hThis.Free(); } if (hWaveOut != IntPtr.Zero) { lock (waveOutLock) { WaveInterop.waveOutUnprepareHeader(hWaveOut, header, Marshal.SizeOf(header)); } hWaveOut = IntPtr.Zero; } } public bool OnDone() { int num; lock (waveStream) { num = waveStream.Read(buffer, 0, buffer.Length); } if (num == 0) { return false; } for (int i = num; i < buffer.Length; i++) { buffer[i] = 0; } WriteToWaveOut(); return true; } private void WriteToWaveOut() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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) MmResult val; lock (waveOutLock) { val = WaveInterop.waveOutWrite(hWaveOut, header, Marshal.SizeOf(header)); } if ((int)val != 0) { throw new MmException(val, "waveOutWrite"); } GC.KeepAlive(this); } } public class WaveOutEvent : IWavePlayer, IDisposable, IWavePosition { private readonly object waveOutLock; private readonly SynchronizationContext syncContext; private IntPtr hWaveOut; private WaveOutBuffer[] buffers; private IWaveProvider waveStream; private volatile PlaybackState playbackState; private AutoResetEvent callbackEvent; public int DesiredLatency { get; set; } public int NumberOfBuffers { get; set; } public int DeviceNumber { get; set; } = -1; public WaveFormat OutputWaveFormat => waveStream.WaveFormat; public PlaybackState PlaybackState => playbackState; public float Volume { get { return WaveOutUtils.GetWaveOutVolume(hWaveOut, waveOutLock); } set { WaveOutUtils.SetWaveOutVolume(value, hWaveOut, waveOutLock); } } public event EventHandler<StoppedEventArgs> PlaybackStopped; public WaveOutEvent() { syncContext = SynchronizationContext.Current; if (syncContext != null && (syncContext.GetType().Name == "LegacyAspNetSynchronizationContext" || syncContext.GetType().Name == "AspNetSynchronizationContext")) { syncContext = null; } DesiredLatency = 300; NumberOfBuffers = 2; waveOutLock = new object(); } public void Init(IWaveProvider waveProvider) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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) if ((int)playbackState != 0) { throw new InvalidOperationException("Can't re-initialize during playback"); } if (hWaveOut != IntPtr.Zero) { DisposeBuffers(); CloseWaveOut(); } callbackEvent = new AutoResetEvent(initialState: false); waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult val; lock (waveOutLock) { val = WaveInterop.waveOutOpenWindow(out hWaveOut, (IntPtr)DeviceNumber, waveStream.WaveFormat, callbackEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, WaveInterop.WaveInOutOpenFlags.CallbackEvent); } MmException.Try(val, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = (PlaybackState)0; for (int i = 0; i < NumberOfBuffers; i++) { buffers[i] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } } public void Play() { //IL_001c: 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_0057: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (buffers == null || waveStream == null) { throw new InvalidOperationException("Must call Init first"); } if ((int)playbackState == 0) { playbackState = (PlaybackState)1; callbackEvent.Set(); ThreadPool.QueueUserWorkItem(delegate { PlaybackThread(); }, null); } else if ((int)playbackState == 2) { Resume(); callbackEvent.Set(); } } private void PlaybackThread() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Exception e = null; try { DoPlayback(); } catch (Exception ex) { e = ex; } finally { playbackState = (PlaybackState)0; RaisePlaybackStoppedEvent(e); } } private void DoPlayback() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_0016: 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) while ((int)playbackState != 0) { if (!callbackEvent.WaitOne(DesiredLatency)) { _ = playbackState; _ = 1; } if ((int)playbackState != 1) { continue; } int num = 0; WaveOutBuffer[] array = buffers; foreach (WaveOutBuffer waveOutBuffer in array) { if (waveOutBuffer.InQueue || waveOutBuffer.OnDone()) { num++; } } if (num == 0) { playbackState = (PlaybackState)0; callbackEvent.Set(); } } } public void Pause() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003d: 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_0046: Unknown result type (might be due to invalid IL or missing references) if ((int)playbackState == 1) { playbackState = (PlaybackState)2; MmResult val; lock (waveOutLock) { val = WaveInterop.waveOutPause(hWaveOut); } if ((int)val != 0) { throw new MmException(val, "waveOutPause"); } } } private void Resume() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_0045: 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_003d: Unknown result type (might be due to invalid IL or missing references) if ((int)playbackState == 2) { MmResult val; lock (waveOutLock) { val = WaveInterop.waveOutRestart(hWaveOut); } if ((int)val != 0) { throw new MmException(val, "waveOutRestart"); } playbackState = (PlaybackState)1; } } public void Stop() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_002f: 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_003f: 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) if ((int)playbackState != 0) { playbackState = (PlaybackState)0; MmResult val; lock (waveOutLock) { val = WaveInterop.waveOutReset(hWaveOut); } if ((int)val != 0) { throw new MmException(val, "waveOutReset"); } callbackEvent.Set(); } } public long GetPosition() { return WaveOutUtils.GetPositionBytes(hWaveOut, waveOutLock); } public void Dispose() { GC.SuppressFinalize(this); Dispose(disposing: true); } protected void Dispose(bool disposing) { Stop(); if (disposing) { DisposeBuffers(); } CloseWaveOut(); } private void CloseWaveOut() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (callbackEvent != null) { callbackEvent.Close(); callbackEvent = null; } lock (waveOutLock) { if (hWaveOut != IntPtr.Zero) { WaveInterop.waveOutClose(hWaveOut); hWaveOut = IntPtr.Zero; } } } private void DisposeBuffers() { if (buffers != null) { WaveOutBuffer[] array = buffers; for (int i = 0; i < array.Length; i++) { array[i].Dispose(); } buffers = null; } } ~WaveOutEvent() { Dispose(disposing: false); } private void RaisePlaybackStoppedEvent(Exception e) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown EventHandler<StoppedEventArgs> handler = this.PlaybackStopped; if (handler == null) { return; } if (syncContext == null) { handler(this, new StoppedEventArgs(e)); return; } syncContext.Post(delegate { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown handler(this, new StoppedEventArgs(e)); }, null); } } public static class WaveOutUtils { public static float GetWaveOutVolume(IntPtr hWaveOut, object lockObject) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) MmResult val; int dwVolume; lock (lockObject) { val = WaveInterop.waveOutGetVolume(hWaveOut, out dwVolume); } MmException.Try(val, "waveOutGetVolume"); return (float)(dwVolume & 0xFFFF) / 65535f; } public static void SetWaveOutVolume(float value, IntPtr hWaveOut, object lockObject) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) if (value < 0f) { throw new ArgumentOutOfRangeException("value", "Volume must be between 0.0 and 1.0"); } if (value > 1f) { throw new ArgumentOutOfRangeException("value", "Volume must be between 0.0 and 1.0"); } int dwVolume = (int)(value * 65535f) + ((int)(value * 65535f) << 16); MmResult val; lock (lockObject) { val = WaveInterop.waveOutSetVolume(hWaveOut, dwVolume); } MmException.Try(val, "waveOutSetVolume"); } public static long GetPositionBytes(IntPtr hWaveOut, object lockObject) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) lock (lockObject) { MmTime mmTime = default(MmTime); mmTime.wType = 4u; MmException.Try(WaveInterop.waveOutGetPosition(hWaveOut, ref mmTime, Marshal.SizeOf(mmTime)), "waveOutGetPosition"); if (mmTime.wType != 4) { throw new Exception($"waveOutGetPosition: wType -> Expected {4}, Received {mmTime.wType}"); } return mmTime.cb; } } } } namespace NAudio.Wave.Compression { public class AcmDriver : IDisposable { private static List<AcmDriver> drivers; private AcmDriverDetails details; private IntPtr driverId; private IntPtr driverHandle; private List<AcmFormatTag> formatTags; private List<AcmFormat> tempFormatsList; private IntPtr localDllHandle; public int MaxFormatSize { get { //IL_000a: Unknown result type (might be due to invalid IL or missing references) MmException.Try(AcmInterop.acmMetrics(driverHandle, AcmMetrics.MaxSizeFormat, out var output), "acmMetrics"); return output; } } public string ShortName => details.shortName; public string LongName => details.longName; public IntPtr DriverId => driverId; public IEnumerable<AcmFormatTag> FormatTags { get { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (formatTags == null) { if (driverHandle == IntPtr.Zero) { throw new InvalidOperationException("Driver must be opened first"); } formatTags = new List<AcmFormatTag>(); AcmFormatTagDetails formatTagDetails = default(AcmFormatTagDetails); formatTagDetails.structureSize = Marshal.SizeOf(formatTagDetails); MmException.Try(AcmInterop.acmFormatTagEnum(driverHandle, ref formatTagDetails, AcmFormatTagEnumCallback, IntPtr.Zero, 0), "acmFormatTagEnum"); } return formatTags; } } public static bool IsCodecInstalled(string shortName) { foreach (AcmDriver item in EnumerateAcmDrivers()) { if (item.ShortName == shortName) { return true; } } return false; } public static AcmDriver AddLocalDriver(string driverFile) { //IL_0050: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) IntPtr intPtr = NativeMethods.LoadLibrary(driverFile); if (intPtr == IntPtr.Zero) { throw new ArgumentException("Failed to load driver file"); } IntPtr procAddress = NativeMethods.GetProcAddress(intPtr, "DriverProc"); if (procAddress == IntPtr.Zero) { NativeMethods.FreeLibrary(intPtr); throw new ArgumentException("Failed to discover DriverProc"); } IntPtr hAcmDriver; MmResult val = AcmInterop.acmDriverAdd(out hAcmDriver, intPtr, procAddress, 0, AcmDriverAddFlags.Function); if ((int)val != 0) { NativeMethods.FreeLibrary(intPtr); throw new MmException(val, "acmDriverAdd"); } AcmDriver acmDriver = new AcmDriver(hAcmDriver); if (string.IsNullOrEmpty(acmDriver.details.longName)) { acmDriver.details.longName = "Local driver: " + Path.GetFileName(driverFile); acmDriver.localDllHandle = intPtr; } return acmDriver; } public static void RemoveLocalDriver(AcmDriver localDriver) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (localDriver.localDllHandle == IntPtr.Zero) { throw new ArgumentException("Please pass in the AcmDriver returned by the AddLocalDriver method"); } MmResult val = AcmInterop.acmDriverRemove(localDriver.driverId, 0); NativeMethods.FreeLibrary(localDriver.localDllHandle); MmException.Try(val, "acmDriverRemove"); } public static bool ShowFormatChooseDialog(IntPtr ownerWindowHandle, string windowTitle, AcmFormatEnumFlags enumFlags, WaveFormat enumFormat, out WaveFormat selectedFormat, out string selectedFormatDescription, out string selectedFormatTagDescription) { //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_00ab: 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_00ea: Invalid comparison between Unknown and I4 //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Invalid comparison between Unknown and I4 //IL_00ec: 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_00f5: Unknown result type (might be due to invalid IL or missing references) AcmFormatChoose formatChoose = default(AcmFormatChoose); formatChoose.structureSize = Marshal.SizeOf(formatChoose); formatChoose.styleFlags = AcmFormatChooseStyleFlags.None; formatChoose.ownerWindowHandle = ownerWindowHandle; int num = 200; formatChoose.selectedWaveFormatPointer = Marshal.AllocHGlobal(num); formatChoose.selectedWaveFormatByteSize = num; formatChoose.title = windowTitle; formatChoose.name = null; formatChoose.formatEnumFlags = enumFlags; formatChoose.waveFormatEnumPointer = IntPtr.Zero; if (enumFormat != null) { IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf<WaveFormat>(enumFormat)); Marshal.StructureToPtr<WaveFormat>(enumFormat, intPtr, fDeleteOld: false); formatChoose.waveFormatEnumPointer = intPtr; } formatChoose.instanceHandle = IntPtr.Zero; formatChoose.templateName = null; MmResult val = AcmInterop.acmFormatChoose(ref formatChoose); selectedFormat = null; selectedFormatDescription = null; selectedFormatTagDescription = null; if ((int)val == 0) { selectedFormat = WaveFormat.MarshalFromPtr(formatChoose.selectedWaveFormatPointer); selectedFormatDescription = formatChoose.formatDescription; selectedFormatTagDescription = formatChoose.formatTagDescription; } Marshal.FreeHGlobal(formatChoose.waveFormatEnumPointer); Marshal.FreeHGlobal(formatChoose.selectedWaveFormatPointer); if ((int)val != 515 && (int)val != 0) { throw new MmException(val, "acmFormatChoose"); } return (int)val == 0; } public static AcmDriver FindByShortName(string shortName) { foreach (AcmDriver item in EnumerateAcmDrivers()) { if (item.ShortName == shortName) { return item; } } return null; } public static IEnumerable<AcmDriver> EnumerateAcmDrivers() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) drivers = new List<AcmDriver>(); MmException.Try(AcmInterop.acmDriverEnum(DriverEnumCallback, IntPtr.Zero, (AcmDriverEnumFlags)0), "acmDriverEnum"); return drivers; } private static bool DriverEnumCallback(IntPtr hAcmDriver, IntPtr dwInstance, AcmDriverDetailsSupportFlags flags) { drivers.Add(new AcmDriver(hAcmDriver)); return true; } private AcmDriver(IntPtr hAcmDriver) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) driverId = hAcmDriver; details = default(AcmDriverDetails); details.structureSize = Marshal.SizeOf(details); MmException.Try(AcmInterop.acmDriverDetails(hAcmDriver, ref details, 0), "acmDriverDetails"); } public override string ToString() { return LongName; } public IEnumerable<AcmFormat> GetFormats(AcmFormatTag formatTag) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected I4, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (driverHandle == IntPtr.Zero) { throw new InvalidOperationException("Driver must be opened first"); } tempFormatsList = new List<AcmFormat>(); AcmFormatDetails formatDetails = default(AcmFormatDetails); formatDetails.structSize = Marshal.SizeOf(formatDetails); formatDetails.waveFormatByteSize = 1024; formatDetails.waveFormatPointer = Marshal.AllocHGlobal(formatDetails.waveFormatByteSize); formatDetails.formatTag = (int)formatTag.FormatTag; MmResult val = AcmInterop.acmFormatEnum(driverHandle, ref formatDetails, AcmFormatEnumCallback, IntPtr.Zero, AcmFormatEnumFlags.None); Marshal.FreeHGlobal(formatDetails.waveFormatPointer); MmException.Try(val, "acmFormatEnum"); return tempFormatsList; } public void Open() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (driverHandle == IntPtr.Zero) { MmException.Try(AcmInterop.acmDriverOpen(out driverHandle, DriverId, 0), "acmDriverOpen"); } } public void Close() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (driverHandle != IntPtr.Zero) { MmException.Try(AcmInterop.acmDriverClose(driverHandle, 0), "acmDriverClose"); driverHandle = IntPtr.Zero; } } private bool AcmFormatTagEnumCallback(IntPtr hAcmDriverId, ref AcmFormatTagDetails formatTagDetails, IntPtr dwInstance, AcmDriverDetailsSupportFlags flags) { formatTags.Add(new AcmFormatTag(formatTagDetails)); return true; } private bool AcmFormatEnumCallback(IntPtr hAcmDriverId, ref AcmFormatDetails formatDetails, IntPtr dwInstance, AcmDriverDetailsSupportFlags flags) { tempFormatsList.Add(new AcmFormat(formatDetails)); return true; } public void Dispose() { if (driverHandle != IntPtr.Zero) { Close(); GC.SuppressFinalize(this); } } } internal enum AcmDriverAddFlags { Local = 0, Global = 8, Function = 3, NotifyWindowHandle = 4 } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal struct AcmDriverDetails { public int structureSize; public uint fccType; public uint fccComp; public ushort manufacturerId; public ushort productId; public uint acmVersion; public uint driverVersion; public AcmDriverDetailsSupportFlags supportFlags; public int formatTagsCount; public int filterTagsCount; public IntPtr hicon; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string shortName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string longName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string copyright; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string licensing; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string features; private const int ShortNameChars = 32; private const int LongNameChars = 128; private const int CopyrightChars = 80; private const int LicensingChars = 128; private const int FeaturesChars = 512; } [Flags] public enum AcmDriverDetailsSupportFlags { Codec = 1, Converter = 2, Filter = 4, Hardware = 8, Async = 0x10, Local = 0x40000000, Disabled = int.MinValue } [Flags] internal enum AcmDriverEnumFlags { NoLocal = 0x40000000, Disabled = int.MinValue } public class AcmFormat { private readonly AcmFormatDetails formatDetails; public int FormatIndex => formatDetails.formatIndex; public WaveFormatEncoding FormatTag => (WaveFormatEncoding)(ushort)formatDetails.formatTag; public AcmDriverDetailsSupportFlags SupportFlags => formatDetails.supportFlags; public WaveFormat WaveFormat { get; private set; } public int WaveFormatByteSize => formatDetails.waveFormatByteSize; public string FormatDescription => formatDetails.formatDescription; internal AcmFormat(AcmFormatDetails formatDetails) { this.formatDetails = formatDetails; WaveFormat = WaveFormat.MarshalFromPtr(formatDetails.waveFormatPointer); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] internal struct AcmFormatChoose { public int structureSize; public AcmFormatChooseStyleFlags styleFlags; public IntPtr ownerWindowHandle; public IntPtr selectedWaveFormatPointer; public int selectedWaveFormatByteSize; [MarshalAs(UnmanagedType.LPTStr)] public string title; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 48)] public string formatTagDescription; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string formatDescription; [MarshalAs(UnmanagedType.LPTStr)] public string name; public int nameByteSize; public AcmFormatEnumFlags formatEnumFlags; public IntPtr waveFormatEnumPointer; public IntPtr instanceHandle; [MarshalAs(UnmanagedType.LPTStr)] public string templateName; public IntPtr customData; public AcmInterop.AcmFormatChooseHookProc windowCallbackFunction; } [Flags] internal enum AcmFormatChooseStyleFlags { None = 0, ShowHelp = 4, EnableHook = 8, EnableTemplate = 0x10, EnableTemplateHandle = 0x20, InitToWfxStruct = 0x40, ContextHelp = 0x80 } [StructLayout(LayoutKind.Sequential, Pack = 4)] internal struct AcmFormatDetails { public int structSize; public int formatIndex; public int formatTag; public AcmDriverDetailsSupportFlags supportFlags; public IntPtr waveFormatPointer; public int waveFormatByteSize; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string formatDescription; public const int FormatDescriptionChars = 128; } [Flags] public enum AcmFormatEnumFlags { None = 0, Convert = 0x100000, Hardware = 0x400000, Input = 0x800000, Channels = 0x20000, SamplesPerSecond = 0x40000, Output = 0x1000000, Suggest = 0x200000, BitsPerSample = 0x80000, FormatTag = 0x10000 } [Flags] internal enum AcmFormatSuggestFlags { FormatTag = 0x10000, Channels = 0x20000, SamplesPerSecond = 0x40000, BitsPerSample = 0x80000, TypeMask = 0xFF0000 } public class AcmFormatTag { private AcmFormatTagDetails formatTagDetails; public int FormatTagIndex => formatTagDetails.formatTagIndex; public WaveFormatEncoding FormatTag => (WaveFormatEncoding)(ushort)formatTagDetails.formatTag; public int FormatSize => formatTagDetails.formatSize; public AcmDriverDetailsSupportFlags SupportFlags => formatTagDetails.supportFlags; public int StandardFormatsCount => formatTagDetails.standardFormatsCount; public string FormatDescription => formatTagDetails.formatDescription; internal AcmFormatTag(AcmFormatTagDetails formatTagDetails) { this.formatTagDetails = formatTagDetails; } } internal struct AcmFormatTagDetails { public int structureSize; public int formatTagIndex; public int formatTag; public int formatSize; public AcmDriverDetailsSupportFlags supportFlags; public int standardFormatsCount; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 48)] public string formatDescription; public const int FormatTagDescriptionChars = 48; } internal class AcmInterop { public delegate bool AcmDriverEnumCallback(IntPtr hAcmDriverId, IntPtr instance, AcmDriverDetailsSupportFlags flags); public delegate bool AcmFormatEnumCallback(IntPtr hAcmDriverId, ref AcmFormatDetails formatDetails, IntPtr dwInstance, AcmDriverDetailsSupportFlags flags); public delegate bool AcmFormatTagEnumCallback(IntPtr hAcmDriverId, ref AcmFormatTagDetails formatTagDetails, IntPtr dwInstance, AcmDriverDetailsSupportFlags flags); public delegate bool AcmFormatChooseHookProc(IntPtr windowHandle, int message, IntPtr wParam, IntPtr lParam); [DllImport("msacm32.dll")] public static extern MmResult acmDriverAdd(out IntPtr driverHandle, IntPtr driverModule, IntPtr driverFunctionAddress, int priority, AcmDriverAddFlags flags); [DllImport("msacm32.dll")] public static extern MmResult acmDriverRemove(IntPtr driverHandle, int removeFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmDriverClose(IntPtr hAcmDriver, int closeFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmDriverEnum(AcmDriverEnumCallback fnCallback, IntPtr dwInstance, AcmDriverEnumFlags flags); [DllImport("Msacm32.dll")] public static extern MmResult acmDriverDetails(IntPtr hAcmDriver, ref AcmDriverDetails driverDetails, int reserved); [DllImport("Msacm32.dll")] public static extern MmResult acmDriverOpen(out IntPtr pAcmDriver, IntPtr hAcmDriverId, int openFlags); [DllImport("Msacm32.dll", EntryPoint = "acmFormatChooseW")] public static extern MmResult acmFormatChoose(ref AcmFormatChoose formatChoose); [DllImport("Msacm32.dll")] public static extern MmResult acmFormatEnum(IntPtr hAcmDriver, ref AcmFormatDetails formatDetails, AcmFormatEnumCallback callback, IntPtr instance, AcmFormatEnumFlags flags); [DllImport("Msacm32.dll", EntryPoint = "acmFormatSuggest")] public static extern MmResult acmFormatSuggest2(IntPtr hAcmDriver, IntPtr sourceFormatPointer, IntPtr destFormatPointer, int sizeDestFormat, AcmFormatSuggestFlags suggestFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmFormatTagEnum(IntPtr hAcmDriver, ref AcmFormatTagDetails formatTagDetails, AcmFormatTagEnumCallback callback, IntPtr instance, int reserved); [DllImport("Msacm32.dll")] public static extern MmResult acmMetrics(IntPtr hAcmObject, AcmMetrics metric, out int output); [DllImport("Msacm32.dll", EntryPoint = "acmStreamOpen")] public static extern MmResult acmStreamOpen2(out IntPtr hAcmStream, IntPtr hAcmDriver, IntPtr sourceFormatPointer, IntPtr destFormatPointer, [In] WaveFilter waveFilter, IntPtr callback, IntPtr instance, AcmStreamOpenFlags openFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmStreamClose(IntPtr hAcmStream, int closeFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmStreamConvert(IntPtr hAcmStream, [In][Out] AcmStreamHeaderStruct streamHeader, AcmStreamConvertFlags streamConvertFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmStreamPrepareHeader(IntPtr hAcmStream, [In][Out] AcmStreamHeaderStruct streamHeader, int prepareFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmStreamReset(IntPtr hAcmStream, int resetFlags); [DllImport("Msacm32.dll")] public static extern MmResult acmStreamSize(IntPtr hAcmStream, int inputBufferSize, out int outputBufferSize, AcmStreamSizeFlags flags); [DllImport("Msacm32.dll")] public static extern MmResult acmStreamUnprepareHeader(IntPtr hAcmStream, [In][Out] AcmStreamHeaderStruct streamHeader, int flags); } public class AcmStream : IDisposable { private IntPtr streamHandle; private IntPtr driverHandle; private AcmStreamHeader streamHeader; private readonly WaveFormat sourceFormat; public byte[] SourceBuffer => streamHeader.SourceBuffer; public byte[] DestBuffer => streamHeader.DestBuffer; public AcmStream(WaveFormat sourceFormat, WaveFormat destFormat) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) try { streamHandle = IntPtr.Zero; this.sourceFormat = sourceFormat; int num = Math.Max(65536, sourceFormat.AverageBytesPerSecond); num -= num % sourceFormat.BlockAlign; IntPtr intPtr = WaveFormat.MarshalToPtr(sourceFormat); IntPtr intPtr2 = WaveFormat.MarshalToPtr(destFormat); try { MmException.Try(AcmInterop.acmStreamOpen2(out streamHandle, IntPtr.Zero, intPtr, intPtr2, null, IntPtr.Zero, IntPtr.Zero, AcmStreamOpenFlags.NonRealTime), "acmStreamOpen"); } finally { Marshal.FreeHGlobal(intPtr); Marshal.FreeHGlobal(intPtr2); } int destBufferLength = SourceToDest(num); streamHeader = new AcmStreamHeader(streamHandle, num, destBufferLength); driverHandle = IntPtr.Zero; } catch { Dispose(); throw; } } public AcmStream(IntPtr driverId, WaveFormat sourceFormat, WaveFilter waveFilter) { //IL_0031: 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) int num = Math.Max(16384, sourceFormat.AverageBytesPerSecond); this.sourceFormat = sourceFormat; num -= num % sourceFormat.BlockAlign; MmException.Try(AcmInterop.acmDriverOpen(out driverHandle, driverId, 0), "acmDriverOpen"); IntPtr intPtr = WaveFormat.MarshalToPtr(sourceFormat); try { MmException.Try(AcmInterop.acmStreamOpen2(out streamHandle, driverHandle, intPtr, intPtr, waveFilter, IntPtr.Zero, IntPtr.Zero, AcmStreamOpenFlags.NonRealTime), "acmStreamOpen"); } finally { Marshal.FreeHGlobal(intPtr); } streamHeader = new AcmStreamHeader(streamHandle, num, SourceToDest(num)); } public int SourceToDest(int source) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (source == 0) { return 0; } MmException.Try(AcmInterop.acmStreamSize(streamHandle, source, out var outputBufferSize, AcmStreamSizeFlags.Source), "acmStreamSize"); return outputBufferSize; } public int DestToSource(int dest) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (dest == 0) { return 0; } MmException.Try(AcmInterop.acmStreamSize(streamHandle, dest, out var outputBufferSize, AcmStreamSizeFlags.Destination), "acmStreamSize"); return outputBufferSize; } public static WaveFormat SuggestPcmFormat(WaveFormat compressedFormat) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) WaveFormat val = new WaveFormat(compressedFormat.SampleRate, 16, compressedFormat.Channels); IntPtr intPtr = WaveFormat.MarshalToPtr(val); IntPtr intPtr2 = WaveFormat.MarshalToPtr(compressedFormat); try { MmResult val2 = AcmInterop.acmFormatSuggest2(IntPtr.Zero, intPtr2, intPtr, Marshal.SizeOf<WaveFormat>(val), AcmFormatSuggestFlags.FormatTag); val = WaveFormat.MarshalFromPtr(intPtr); MmException.Try(val2, "acmFormatSuggest"); return val; } finally { Marshal.FreeHGlobal(intPtr); Marshal.FreeHGlobal(intPtr2); } } public void Reposition() { streamHeader.Reposition(); } public int Convert(int bytesToConvert, out int sourceBytesConverted) { if (bytesToConvert % sourceFormat.BlockAlign != 0) { bytesToConvert -= bytesToConvert % sourceFormat.BlockAlign; } return streamHeader.Convert(bytesToConvert, out sourceBytesConverted); } [Obsolete("Call the version returning sourceBytesConverted instead")] public int Convert(int bytesToConvert) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) int sourceBytesConverted; int result = Convert(bytesToConvert, out sourceBytesConverted); if (sourceBytesConverted != bytesToConvert) { throw new MmException((MmResult)8, "AcmStreamHeader.Convert didn't convert everything"); } return result; } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { //IL_0036: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0050: Unknown result type (might be due to invalid IL or missing references) if (disposing && streamHeader != null) { streamHeader.Dispose(); streamHeader = null; } if (streamHandle != IntPtr.Zero) { MmResult val = AcmInterop.acmStreamClose(streamHandle, 0); streamHandle = IntPtr.Zero; if ((int)val != 0) { throw new MmException(val, "acmStreamClose"); } } if (driverHandle != IntPtr.Zero) { AcmInterop.acmDriverClose(driverHandle, 0); driverHandle = IntPtr.Zero; } } ~AcmStream() { Dispose(disposing: false); } } internal class AcmStreamHeader : IDisposable { private AcmStreamHeaderStruct streamHeader; private GCHandle hSourceBuffer; private GCHandle hDestBuffer; private IntPtr streamHandle; private bool firstTime; private bool disposed; public byte[] SourceBuffer { get; private set; } public byte[] DestBuffer { get; private set; } public AcmStreamHeader(IntPtr streamHandle, int sourceBufferLength, int destBufferLength) { streamHeader = new AcmStreamHeaderStruct(); SourceBuffer = new byte[sourceBufferLength]; hSourceBuffer = GCHandle.Alloc(SourceBuffer, GCHandleType.Pinned); DestBuffer = new byte[destBufferLength]; hDestBuffer = GCHandle.Alloc(DestBuffer, GCHandleType.Pinned); this.streamHandle = streamHandle; firstTime = true; } private void Prepare() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) streamHeader.cbStruct = Marshal.SizeOf(streamHeader); streamHeader.sourceBufferLength = SourceBuffer.Length; streamHeader.sourceBufferPointer = hSourceBuffer.AddrOfPinnedObject(); streamHeader.destBufferLength = DestBuffer.Length; streamHeader.destBufferPointer = hDestBuffer.AddrOfPinnedObject(); MmException.Try(AcmInterop.acmStreamPrepareHeader(streamHandle, streamHeader, 0), "acmStreamPrepareHeader"); } private void Unprepare() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) streamHeader.sourceBufferLength = SourceBuffer.Length; streamHeader.sourceBufferPointer = hSourceBuffer.AddrOfPinnedObject(); streamHeader.destBufferLength = DestBuffer.Length; streamHeader.destBufferPointer = hDestBuffer.AddrOfPinnedObject(); MmResult val = AcmInterop.acmStreamUnprepareHeader(streamHandle, streamHeader, 0); if ((int)val != 0) { throw new MmException(val, "acmStreamUnprepareHeader"); } } public void Reposition() { firstTime = true; } public int Convert(int bytesToConvert, out int sourceBytesConverted) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) Prepare(); try { streamHeader.sourceBufferLength = bytesToConvert; streamHeader.sourceBufferLengthUsed = bytesToConvert; AcmStreamConvertFlags streamConvertFlags = (firstTime ? (AcmStreamConvertFlags.BlockAlign | AcmStreamConvertFlags.Start) : AcmStreamConvertFlags.BlockAlign); MmException.Try(AcmInterop.acmStreamConvert(streamHandle, streamHeader, streamConvertFlags), "acmStreamConvert"); firstTime = false; sourceBytesConverted = streamHeader.sourceBufferLengthUsed; } finally { Unprepare(); } return streamHeader.destBufferLengthUsed; } public void Dispose() { GC.SuppressFinalize(this); Dispose(disposing: true); } protected virtual void Dispose(bool disposing) { if (!disposed) { SourceBuffer = null; DestBuffer = null; hSourceBuffer.Free(); hDestBuffer.Free(); } disposed = true; } ~AcmStreamHeader() { Dispose(disposing: false); } } [Flags] internal enum AcmStreamHeaderStatusFlags { Done = 0x10000, Prepared = 0x20000, InQueue = 0x100000 } [StructLayout(LayoutKind.Sequential, Size = 128)] internal class AcmStreamHeaderStruct { public int cbStruct; public AcmStreamHeaderStatusFlags fdwStatus; public IntPtr userData; public IntPtr sourceBufferPointer; public int sourceBufferLength; public int sourceBufferLengthUsed; public IntPtr sourceUserData; public IntPtr destBufferPointer; public int destBufferLength; public int destBufferLengthUsed; public IntPtr destUserData; } [Flags] internal enum AcmStreamOpenFlags { Query = 1, Async = 2, NonRealTime = 4, CallbackTypeMask = 0x70000, CallbackNull = 0, CallbackWindow = 0x10000, CallbackTask = 0x20000, CallbackFunction = 0x30000, CallbackThread = 0x20000, CallbackEvent = 0x50000 } internal enum AcmStreamSizeFlags { Source, Destination } [StructLayout(LayoutKind.Sequential)] public class WaveFilter { public int StructureSize = Marshal.SizeOf(typeof(WaveFilter)); public int FilterTag; public int Filter; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public int[] Reserved; } }