Decompiled source of Park Matches v2.0.2
Mods/ParkMatches.dll
Decompiled 3 months agousing System; using System.Collections; 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 HarmonyLib; using Il2CppPhoton.Pun; using Il2CppRUMBLE.Environment; using Il2CppRUMBLE.Environment.Park; using Il2CppRUMBLE.Interactions.InteractionBase; using Il2CppRUMBLE.Managers; using Il2CppRUMBLE.Players; using Il2CppRUMBLE.Players.Subsystems; using Il2CppRUMBLE.Utilities; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Utils; using NAudio.Wave; using ParkMatches; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(ParkMatchesClass), "Park Matches", "2.0.2", "UlvakSkillz", null)] [assembly: MelonGame("Buckethead Entertainment", "RUMBLE")] [assembly: MelonColor(255, 195, 0, 255)] [assembly: MelonAuthorColor(255, 195, 0, 255)] [assembly: VerifyLoaderVersion(0, 6, 2, true)] [assembly: AssemblyTitle("ParkMatches")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ParkMatches")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2d9b3ff8-39c5-41fe-8004-afe2d753d3cd")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] public static class Patch { private static Harmony harmony = new Harmony("_ParkMatchesClass"); public static void Start() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown harmony.Patch((MethodBase)AccessTools.Method(typeof(ParkInstance), "RPC_CleanScene", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patch), "RPCCleanScenePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void RPCCleanScenePostfix(ParkInstance __instance) { if (!ParkMatchesClass.instance.isActive || !(ParkMatchesClass.instance.matchBufferTimer <= DateTime.Now)) { return; } List<Player> allPlayers = ParkMatchesClass.instance.playerManager.AllPlayers; if (allPlayers.Count < 2 || ParkMatchesClass.instance.fightStarted) { return; } int num = 256; Enumerator<Player> enumerator = allPlayers.GetEnumerator(); while (enumerator.MoveNext()) { Player current = enumerator.Current; if (ParkMatchesClass.instance.localPlayer == current) { ParkMatchesClass.instance.clientActorNumber = current.Data.GeneralData.ActorNo; } if (current.Data.GeneralData.ActorNo == 1) { ParkMatchesClass.instance.hostPlayer = current; } else if (num == 256) { num = current.Data.GeneralData.ActorNo; } else if (current.Data.GeneralData.ActorNo < num) { num = current.Data.GeneralData.ActorNo; } } MelonLogger.Msg($"Found Lowest Actor: {num} | Player's: {ParkMatchesClass.instance.localPlayer.Data.GeneralData.ActorNo}"); if (ParkMatchesClass.instance.isHost || ParkMatchesClass.instance.localPlayer.Data.GeneralData.ActorNo == num) { MelonLogger.Msg("Player Included"); ParkMatchesClass.instance.StartFight(); } else { MelonLogger.Msg("Player Excluded"); } } } namespace ParkMatches; public class ParkMatchesClass : MelonMod { private string settingsFile = "UserData/ParkMatches/Settings.txt"; public bool isActive; public static ParkMatchesClass instance; private InteractionButton parkResetSceneButton; public PlayerManager playerManager; private PlayerResetSystem localResetSystem; private ParkMatchCounter parkMatchCounter; public DateTime matchBufferTimer; private Vector3 hostRespawn = new Vector3(-8.65f, -5.5f, -5.75f); private Quaternion hostRotation = Quaternion.Euler(0f, 40f, 0f); private Vector3 clientRespawn = new Vector3(2f, -5.5f, 8f); private Quaternion clientRotation = Quaternion.Euler(0f, 220f, 0f); private bool sceneChanged; private string currentScene = ""; public bool fightStarted = false; private bool atRoundStart = false; public bool isHost = true; private int hostPoints; private int clientPoints; private PlayerHealth localPlayerHealth; private PlayerHealth otherPlayerHealth; public Player hostPlayer; public Player clientPlayer; public short clientActorNumber; public Player localPlayer; private DateTime localDeathTimer; private DateTime otherDeathTimer; private DateTime redeathPreventionTimer; private bool localDeathTimerActive = false; private bool otherDeathTimerActive = false; private bool waitedAnUpdate = false; private string[] FilePaths = new string[6]; private static Thread[] threads = new Thread[3]; private static bool[] threadActive = new bool[threads.Length]; public override void OnInitializeMelon() { instance = this; matchBufferTimer = DateTime.Now; Patch.Start(); FilePaths[0] = "\\ParkMatches\\DingDing.mp3"; FilePaths[1] = "\\ParkMatches\\YouWin.mp3"; FilePaths[2] = "\\ParkMatches\\YouLose.mp3"; FilePaths[3] = "\\ParkMatches\\ExitArena.mp3"; FilePaths[4] = "\\ParkMatches\\EnterArena.mp3"; FilePaths[5] = "\\ParkMatches\\NewRoundStart.mp3"; bool flag = true; for (int i = 0; i < FilePaths.Length; i++) { if (!File.Exists(MelonEnvironment.UserDataDirectory + FilePaths[i])) { flag = false; MelonLogger.Msg(FilePaths[i] + " Doesn't Exist!"); } } if (flag) { MelonLogger.Msg("Initialized"); } else { MelonLogger.Msg("Initialized with Sound Files Missing"); } } public override void OnFixedUpdate() { CheckForSceneChange(); if (fightStarted) { if (!atRoundStart && redeathPreventionTimer <= DateTime.Now) { CheckHealths(); CheckPositions(); } if (atRoundStart && redeathPreventionTimer <= DateTime.Now) { parkResetSceneButton.RPC_OnPressed(); ResetPlayers(); PlaySoundIfFileExists(FilePaths[5], 0); atRoundStart = false; } } } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { sceneChanged = true; currentScene = sceneName; } public void CheckPositions() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(-3.15f, 0.25f); Vector2 val2 = default(Vector2); val2.x = ((Component)((Component)playerManager.localPlayer.Controller).gameObject.transform.GetChild(2).GetChild(13).GetChild(0)).gameObject.transform.position.x; val2.y = ((Component)((Component)playerManager.localPlayer.Controller).gameObject.transform.GetChild(2).GetChild(13).GetChild(0)).gameObject.transform.position.z; float num = Vector2.Distance(val2, val); if (localDeathTimerActive && num < 12f) { PlaySoundIfFileExists(FilePaths[4], 2); localDeathTimerActive = false; } if (localDeathTimerActive) { if (localDeathTimer <= DateTime.Now) { if (waitedAnUpdate) { localPlayerHealth.SetHealth((short)0, playerManager.AllPlayers[0].Data.HealthPoints, true); MelonLogger.Msg($"Host player died from outside arena | Distance: {num}"); localDeathTimerActive = false; waitedAnUpdate = false; } else { waitedAnUpdate = true; } } } else if (num >= 12f && !atRoundStart) { PlaySoundIfFileExists(FilePaths[3], 1); localDeathTimer = DateTime.Now.AddSeconds(2.0); localDeathTimerActive = true; } if (isHost) { val2.x = ((Component)((Component)clientPlayer.Controller).gameObject.transform.GetChild(3).GetChild(13).GetChild(0)).transform.position.x; val2.y = ((Component)((Component)clientPlayer.Controller).gameObject.transform.GetChild(3).GetChild(13).GetChild(0)).transform.position.z; } else { val2.x = ((Component)((Component)hostPlayer.Controller).gameObject.transform.GetChild(3).GetChild(13).GetChild(0)).transform.position.x; val2.y = ((Component)((Component)hostPlayer.Controller).gameObject.transform.GetChild(3).GetChild(13).GetChild(0)).transform.position.z; } num = Vector2.Distance(val2, val); if (otherDeathTimerActive && num < 12f) { otherDeathTimerActive = false; } if (otherDeathTimerActive) { if (otherDeathTimer <= DateTime.Now) { otherPlayerHealth.SetHealth((short)0, playerManager.AllPlayers[1].Data.HealthPoints, true); MelonLogger.Msg($"Client player died from outside arena | Distance: {num}"); otherDeathTimerActive = false; } } else if (num >= 13f) { otherDeathTimer = DateTime.Now.AddSeconds(2.0); otherDeathTimerActive = true; } } public void CheckHealths() { if (hostPlayer.Data.HealthPoints != 0 && clientPlayer.Data.HealthPoints != 0) { return; } if (clientPlayer.Data.HealthPoints == 0) { MelonLogger.Msg("0 hp On Client"); hostPoints++; } if (hostPlayer.Data.HealthPoints == 0) { MelonLogger.Msg("0 hp On Host"); clientPoints++; } if (hostPlayer.Data.HealthPoints == 0) { if (isHost) { otherPlayerHealth.SetHealth((short)20, playerManager.AllPlayers[1].Data.HealthPoints, false); } else { localPlayerHealth.SetHealth((short)20, playerManager.AllPlayers[0].Data.HealthPoints, false); } } if (clientPlayer.Data.HealthPoints == 0) { if (isHost) { localPlayerHealth.SetHealth((short)20, playerManager.AllPlayers[0].Data.HealthPoints, false); } else { otherPlayerHealth.SetHealth((short)20, playerManager.AllPlayers[1].Data.HealthPoints, false); } } if (hostPoints == 2 || clientPoints == 2) { if (clientPoints == 2) { MelonLogger.Msg("Client won"); if (isHost) { PlaySoundIfFileExists(FilePaths[2], 0); } else { PlaySoundIfFileExists(FilePaths[1], 0); } } else { MelonLogger.Msg("Host won"); if (isHost) { PlaySoundIfFileExists(FilePaths[1], 0); } else { PlaySoundIfFileExists(FilePaths[2], 0); } } matchBufferTimer = DateTime.Now.AddSeconds(1.0); fightStarted = false; parkMatchCounter.ringSize = 13f; MelonLogger.Msg("Match Over"); } else { MelonLogger.Msg("New Round"); redeathPreventionTimer = DateTime.Now.AddSeconds(3.0); atRoundStart = true; parkResetSceneButton.RPC_OnPressed(); ResetPlayers(); } } private void ResetPlayers() { //IL_008e: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) MelonLogger.Msg("Resetting Players"); localPlayerHealth.SetHealth((short)20, playerManager.AllPlayers[0].Data.HealthPoints, false); otherPlayerHealth.SetHealth((short)20, playerManager.AllPlayers[1].Data.HealthPoints, false); if (isHost) { localResetSystem.RPC_RelocatePlayerController(hostRespawn, hostRotation); } else { localResetSystem.RPC_RelocatePlayerController(clientRespawn, clientRotation); } } public void CheckForSceneChange() { if (!sceneChanged) { return; } try { if (currentScene == "Park") { playerManager = Singleton<PlayerManager>.instance; parkResetSceneButton = GameObject.Find("________________LOGIC__________________ /Heinhouwser products/Parkboard (Park)/Primary Display/Park/Minigame Start button/InteractionButton/Button").GetComponent<InteractionButton>(); parkMatchCounter = GameObject.Find("________________LOGIC__________________ /Park Toys/MatchCounter").GetComponent<ParkMatchCounter>(); localPlayerHealth = ((Component)GameObject.Find("Health/Local").transform.parent).GetComponent<PlayerHealth>(); localPlayer = playerManager.localPlayer; localResetSystem = ((Component)playerManager.localPlayer.Controller).gameObject.GetComponent<PlayerResetSystem>(); isHost = PhotonNetwork.IsMasterClient; readSettingsFile(); MelonLogger.Msg("Reset Park Button Found"); } else { fightStarted = false; } sceneChanged = false; } catch { } } public void StartFight() { MelonLogger.Msg("Starting Fight"); try { otherPlayerHealth = GameObject.Find("Player Controller(Clone)/Health").GetComponent<PlayerHealth>(); hostPoints = 0; clientPoints = 0; if (isHost) { hostPlayer = playerManager.AllPlayers[0]; clientPlayer = playerManager.AllPlayers[1]; } else { hostPlayer = playerManager.AllPlayers[1]; clientPlayer = playerManager.AllPlayers[0]; } PlaySoundIfFileExists(FilePaths[0], 0); redeathPreventionTimer = DateTime.Now.AddSeconds(3.0); atRoundStart = true; localDeathTimerActive = false; otherDeathTimerActive = false; fightStarted = true; ResetPlayers(); parkMatchCounter.ringSize = 50f; MelonLogger.Msg("Match Started"); } catch (Exception ex) { MelonLogger.Error("Error Starting Fight: " + ex.Message); } } private void readSettingsFile() { if (File.Exists(settingsFile)) { try { string[] array = File.ReadAllLines(settingsFile); if (array[1].ToLower() == "true") { MelonLogger.Msg("Setting to Active"); isActive = true; } else { MelonLogger.Msg("Setting to Inactive"); isActive = false; } return; } catch { MelonLogger.Error("Error reading " + settingsFile + " ! Setting Inactive"); isActive = false; return; } } MelonLogger.Error(settingsFile + " does not Exist! Setting Inactive"); isActive = false; } private IEnumerator PlaySound(string FilePath, int threadToPlayOn) { threadActive[threadToPlayOn] = true; Mp3FileReader reader = new Mp3FileReader(FilePath); WaveOutEvent waveOut = new WaveOutEvent(); waveOut.DeviceNumber = 0; waveOut.Init((IWaveProvider)(object)reader); waveOut.Play(); while ((int)waveOut.PlaybackState == 1) { yield return (object)new WaitForFixedUpdate(); } threadActive[threadToPlayOn] = false; } private void PlaySoundIfFileExists(string soundFilePath, int threadToPlayOn) { if (File.Exists(MelonEnvironment.UserDataDirectory + soundFilePath)) { if (!threadActive[threadToPlayOn]) { try { MelonCoroutines.Start(PlaySound(MelonEnvironment.UserDataDirectory + soundFilePath, threadToPlayOn)); } catch (Exception ex) { MelonLogger.Msg("Error playing sound: " + ex.Message); } } } else { MelonLogger.Msg("Sound File Doesn't Exist: " + MelonEnvironment.UserDataDirectory + soundFilePath); } } }
UserLibs/NAudio.Core.dll
Decompiled 3 months 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
UserLibs/NAudio.dll
Decompiled 3 months agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using NAudio.Wave.SampleProviders; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Mark Heath & Contributors")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© Mark Heath 2023")] [assembly: AssemblyDescription("NAudio, an audio library for .NET")] [assembly: AssemblyFileVersion("2.2.1.0")] [assembly: AssemblyInformationalVersion("2.2.1")] [assembly: AssemblyProduct("NAudio")] [assembly: AssemblyTitle("NAudio")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/naudio/NAudio")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.1.0")] [module: UnverifiableCode] namespace NAudio.Wave; public class AudioFileReader : WaveStream, ISampleProvider { private WaveStream readerStream; private readonly SampleChannel sampleChannel; private readonly int destBytesPerSample; private readonly int sourceBytesPerSample; private readonly long length; private readonly object lockObject; public string FileName { get; } public override WaveFormat WaveFormat => sampleChannel.WaveFormat; public override long Length => length; public override long Position { get { return SourceToDest(((Stream)(object)readerStream).Position); } set { lock (lockObject) { ((Stream)(object)readerStream).Position = DestToSource(value); } } } public float Volume { get { return sampleChannel.Volume; } set { sampleChannel.Volume = value; } } public AudioFileReader(string fileName) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown lockObject = new object(); FileName = fileName; CreateReaderStream(fileName); sourceBytesPerSample = readerStream.WaveFormat.BitsPerSample / 8 * readerStream.WaveFormat.Channels; sampleChannel = new SampleChannel((IWaveProvider)(object)readerStream, false); destBytesPerSample = 4 * sampleChannel.WaveFormat.Channels; length = SourceToDest(((Stream)(object)readerStream).Length); } private void CreateReaderStream(string fileName) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown if (fileName.EndsWith(".wav", StringComparison.OrdinalIgnoreCase)) { readerStream = (WaveStream)new WaveFileReader(fileName); if ((int)readerStream.WaveFormat.Encoding != 1 && (int)readerStream.WaveFormat.Encoding != 3) { readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream); readerStream = (WaveStream)new BlockAlignReductionStream(readerStream); } } else if (fileName.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)) { if (Environment.OSVersion.Version.Major < 6) { readerStream = (WaveStream)(object)new Mp3FileReader(fileName); } else { readerStream = (WaveStream)new MediaFoundationReader(fileName); } } else if (fileName.EndsWith(".aiff", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".aif", StringComparison.OrdinalIgnoreCase)) { readerStream = (WaveStream)new AiffFileReader(fileName); } else { readerStream = (WaveStream)new MediaFoundationReader(fileName); } } public override int Read(byte[] buffer, int offset, int count) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown WaveBuffer val = new WaveBuffer(buffer); int count2 = count / 4; return Read(val.FloatBuffer, offset / 4, count2) * 4; } public int Read(float[] buffer, int offset, int count) { lock (lockObject) { return sampleChannel.Read(buffer, offset, count); } } private long SourceToDest(long sourceBytes) { return destBytesPerSample * (sourceBytes / sourceBytesPerSample); } private long DestToSource(long destBytes) { return sourceBytesPerSample * (destBytes / destBytesPerSample); } protected override void Dispose(bool disposing) { if (disposing && readerStream != null) { ((Stream)(object)readerStream).Dispose(); readerStream = null; } ((Stream)this).Dispose(disposing); } } public class Mp3FileReader : Mp3FileReaderBase { public Mp3FileReader(string mp3FileName) : base((Stream)File.OpenRead(mp3FileName), new FrameDecompressorBuilder(CreateAcmFrameDecompressor), true) { }//IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown public Mp3FileReader(Stream inputStream) : base(inputStream, new FrameDecompressorBuilder(CreateAcmFrameDecompressor), false) { }//IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown public static IMp3FrameDecompressor CreateAcmFrameDecompressor(WaveFormat mp3Format) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown return (IMp3FrameDecompressor)new AcmMp3FrameDecompressor(mp3Format); } }
UserLibs/NAudio.WinMM.dll
Decompiled 3 months 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; } }