Decompiled source of ResourcefulHands v0.9.60
NAudio-Unity.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using Microsoft.Win32; using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; using NAudio.Dmo; using NAudio.Dsp; using NAudio.FileFormats.Wav; using NAudio.MediaFoundation; using NAudio.Utils; using NAudio.Wave; using NAudio.Wave.Asio; using NAudio.Wave.Compression; using NAudio.Wave.SampleProviders; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("NAudio-Unity")] [assembly: AssemblyDescription("NAudio .NET Audio Library (Unity 3.5 Subset)")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Wulf Marius")] [assembly: AssemblyProduct("NAudio (Unity 3.5 Subset)")] [assembly: AssemblyCopyright("© 2018 Wulf Marius")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("678589a3-c646-4464-8afa-5ea83bff44a7")] [assembly: AssemblyFileVersion("2.0.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.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 { private MmResult result; private string function; public MmResult Result => result; public MmException(MmResult result, string function) : base(ErrorMessage(result, function)) { this.result = result; this.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.Mixer { public class BooleanMixerControl : MixerControl { private MixerInterop.MIXERCONTROLDETAILS_BOOLEAN boolDetails; public bool Value { get { GetControlDetails(); return boolDetails.fValue == 1; } set { boolDetails.fValue = (value ? 1 : 0); mixerControlDetails.paDetails = Marshal.AllocHGlobal(Marshal.SizeOf((object)boolDetails)); Marshal.StructureToPtr((object)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 = (MixerInterop.MIXERCONTROLDETAILS_BOOLEAN)Marshal.PtrToStructure(pDetails, typeof(MixerInterop.MIXERCONTROLDETAILS_BOOLEAN)); } } 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) { if (mixerIndex < 0 || mixerIndex >= NumberOfDevices) { throw new ArgumentOutOfRangeException("mixerID"); } caps = default(MixerInterop.MIXERCAPS); MmException.Try(MixerInterop.mixerGetDevCaps((IntPtr)mixerIndex, ref caps, Marshal.SizeOf((object)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) { List<MixerControl> list = new List<MixerControl>(); if (mixerLine.ControlsCount > 0) { int num = Marshal.SizeOf(typeof(MixerInterop.MIXERCONTROL)); MixerInterop.MIXERLINECONTROLS mixerLineControls = default(MixerInterop.MIXERLINECONTROLS); IntPtr intPtr = Marshal.AllocHGlobal(num * mixerLine.ControlsCount); mixerLineControls.cbStruct = Marshal.SizeOf((object)mixerLineControls); mixerLineControls.dwLineID = mixerLine.LineId; mixerLineControls.cControls = mixerLine.ControlsCount; mixerLineControls.pamxctrl = intPtr; mixerLineControls.cbmxctrl = Marshal.SizeOf(typeof(MixerInterop.MIXERCONTROL)); try { MmResult mmResult = MixerInterop.mixerGetLineControls(mixerHandle, ref mixerLineControls, MixerFlags.Mixer | mixerHandleType); if (mmResult != 0) { throw new MmException(mmResult, "mixerGetLineControls"); } for (int i = 0; i < mixerLineControls.cControls; i++) { MixerInterop.MIXERCONTROL mIXERCONTROL = (MixerInterop.MIXERCONTROL)Marshal.PtrToStructure((IntPtr)(intPtr.ToInt64() + num * i), typeof(MixerInterop.MIXERCONTROL)); 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) { MixerInterop.MIXERLINECONTROLS mixerLineControls = default(MixerInterop.MIXERLINECONTROLS); MixerInterop.MIXERCONTROL mIXERCONTROL = default(MixerInterop.MIXERCONTROL); IntPtr intPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf((object)mIXERCONTROL)); mixerLineControls.cbStruct = Marshal.SizeOf((object)mixerLineControls); mixerLineControls.cControls = 1; mixerLineControls.dwControlID = controlId; mixerLineControls.cbmxctrl = Marshal.SizeOf((object)mIXERCONTROL); mixerLineControls.pamxctrl = intPtr; mixerLineControls.dwLineID = nLineID; MmResult mmResult = MixerInterop.mixerGetLineControls(mixerHandle, ref mixerLineControls, MixerFlags.ListText | mixerFlags); if (mmResult != 0) { Marshal.FreeCoTaskMem(intPtr); throw new MmException(mmResult, "mixerGetLineControls"); } mIXERCONTROL = (MixerInterop.MIXERCONTROL)Marshal.PtrToStructure(mixerLineControls.pamxctrl, typeof(MixerInterop.MIXERCONTROL)); Marshal.FreeCoTaskMem(intPtr); if (IsControlBoolean(mIXERCONTROL.dwControlType)) { return new BooleanMixerControl(mIXERCONTROL, mixerHandle, mixerFlags, nChannels); } if (IsControlSigned(mIXERCONTROL.dwControlType)) { return new SignedMixerControl(mIXERCONTROL, mixerHandle, mixerFlags, nChannels); } if (IsControlUnsigned(mIXERCONTROL.dwControlType)) { return new UnsignedMixerControl(mIXERCONTROL, mixerHandle, mixerFlags, nChannels); } if (IsControlListText(mIXERCONTROL.dwControlType)) { return new ListTextMixerControl(mIXERCONTROL, mixerHandle, mixerFlags, nChannels); } if (IsControlCustom(mIXERCONTROL.dwControlType)) { return new CustomMixerControl(mIXERCONTROL, mixerHandle, mixerFlags, nChannels); } throw new InvalidOperationException($"Unknown mixer control type {mIXERCONTROL.dwControlType}"); } protected void GetControlDetails() { mixerControlDetails.cbStruct = Marshal.SizeOf((object)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((object)default(MixerInterop.MIXERCONTROLDETAILS_BOOLEAN)); } else if (IsListText) { mixerControlDetails.cbDetails = Marshal.SizeOf((object)default(MixerInterop.MIXERCONTROLDETAILS_LISTTEXT)); } else if (IsSigned) { mixerControlDetails.cbDetails = Marshal.SizeOf((object)default(MixerInterop.MIXERCONTROLDETAILS_SIGNED)); } else if (IsUnsigned) { mixerControlDetails.cbDetails = Marshal.SizeOf((object)default(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 mmResult = MixerInterop.mixerGetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Mixer | mixerHandleType); if (mmResult == MmResult.NoError) { GetDetails(mixerControlDetails.paDetails); } Marshal.FreeCoTaskMem(intPtr); if (mmResult != 0) { throw new MmException(mmResult, "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 } 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) { this.mixerHandle = mixerHandle; this.mixerHandleType = mixerHandleType; mixerLine = default(MixerInterop.MIXERLINE); mixerLine.cbStruct = Marshal.SizeOf((object)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) { this.mixerHandle = mixerHandle; this.mixerHandleType = mixerHandleType; mixerLine = default(MixerInterop.MIXERLINE); mixerLine.cbStruct = Marshal.SizeOf((object)mixerLine); mixerLine.dwDestination = destinationIndex; mixerLine.dwSource = sourceIndex; MmException.Try(MixerInterop.mixerGetLineInfo(mixerHandle, ref mixerLine, mixerHandleType | MixerFlags.ListText), "mixerGetLineInfo"); } public static int GetMixerIdForWaveIn(int waveInDevice) { 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})"; } } [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 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 { signedDetails.lValue = value; mixerControlDetails.paDetails = Marshal.AllocHGlobal(Marshal.SizeOf((object)signedDetails)); Marshal.StructureToPtr((object)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 = (MixerInterop.MIXERCONTROLDETAILS_SIGNED)Marshal.PtrToStructure(mixerControlDetails.paDetails, typeof(MixerInterop.MIXERCONTROLDETAILS_SIGNED)); } 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 { int num = Marshal.SizeOf((object)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((object)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] = (MixerInterop.MIXERCONTROLDETAILS_UNSIGNED)Marshal.PtrToStructure(mixerControlDetails.paDetails, typeof(MixerInterop.MIXERCONTROLDETAILS_UNSIGNED)); } } public override string ToString() { return $"{base.ToString()} {Percent}%"; } } } namespace NAudio.SoundFont { public class Generator { private GeneratorEnum generatorType; private ushort rawAmount; private Instrument instrument; private SampleHeader sampleHeader; public GeneratorEnum GeneratorType { get { return generatorType; } set { generatorType = value; } } public ushort UInt16Amount { get { return rawAmount; } set { rawAmount = value; } } public short Int16Amount { get { return (short)rawAmount; } set { rawAmount = (ushort)value; } } public byte LowByteAmount { get { return (byte)(rawAmount & 0xFFu); } set { rawAmount &= 65280; rawAmount += value; } } public byte HighByteAmount { get { return (byte)((rawAmount & 0xFF00) >> 8); } set { rawAmount &= 255; rawAmount += (ushort)(value << 8); } } public Instrument Instrument { get { return instrument; } set { instrument = value; } } public SampleHeader SampleHeader { get { return sampleHeader; } set { sampleHeader = value; } } public override string ToString() { if (generatorType == GeneratorEnum.Instrument) { return $"Generator Instrument {instrument.Name}"; } if (generatorType == GeneratorEnum.SampleID) { return $"Generator SampleID {sampleHeader}"; } return $"Generator {generatorType} {rawAmount}"; } } 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 NAudio.Utils.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 NAudio.Utils.InvalidDataException($"Unknown chunk type {nextSubChunk.ChunkID}"); } } if (!flag) { throw new NAudio.Utils.InvalidDataException("Missing SoundFont version information"); } if (!flag2) { throw new NAudio.Utils.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 { private string name; internal ushort startInstrumentZoneIndex; internal ushort endInstrumentZoneIndex; private Zone[] zones; public string Name { get { return name; } set { name = value; } } public Zone[] Zones { get { return zones; } set { zones = value; } } 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 { private ModulatorType sourceModulationData; private GeneratorEnum destinationGenerator; private short amount; private ModulatorType sourceModulationAmount; private TransformEnum sourceTransform; public ModulatorType SourceModulationData { get { return sourceModulationData; } set { sourceModulationData = value; } } public GeneratorEnum DestinationGenerator { get { return destinationGenerator; } set { destinationGenerator = value; } } public short Amount { get { return amount; } set { amount = value; } } public ModulatorType SourceModulationAmount { get { return sourceModulationAmount; } set { sourceModulationAmount = value; } } public TransformEnum SourceTransform { get { return sourceTransform; } set { sourceTransform = value; } } 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 { private string name; private ushort patchNumber; private ushort bank; internal ushort startPresetZoneIndex; internal ushort endPresetZoneIndex; internal uint library; internal uint genre; internal uint morphology; private Zone[] zones; public string Name { get { return name; } set { name = value; } } public ushort PatchNumber { get { return patchNumber; } set { patchNumber = value; } } public ushort Bank { get { return bank; } set { bank = value; } } public Zone[] Zones { get { return zones; } set { zones = value; } } 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 NAudio.Utils.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 NAudio.Utils.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 uint chunkSize; private long dataOffset; 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 => chunkSize; public long DataOffset => dataOffset; 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 NAudio.Utils.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 NAudio.Utils.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 NAudio.Utils.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 NAudio.Utils.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}"; } } 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 { private short major; private short minor; public short Major { get { return major; } set { major = value; } } public short Minor { get { return minor; } set { minor = value; } } } 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); } } 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; private Modulator[] modulators; private Generator[] generators; public Modulator[] Modulators { get { return modulators; } set { modulators = value; } } public Generator[] Generators { get { return generators; } set { generators = value; } } 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.Dmo { internal 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 WMMEDIASUBTYPE_MP3 = new Guid("00000055-0000-0010-8000-00AA00389B71"); 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(); } } public class DmoDescriptor { public string Name { get; private set; } public Guid Clsid { get; private set; } public DmoDescriptor(string name, Guid clsid) { Name = name; Clsid = clsid; } } public class DmoEnumerator { public static IEnumerable<DmoDescriptor> GetAudioEffectNames() { return GetDmos(DmoGuids.DMOCATEGORY_AUDIO_EFFECT); } public static IEnumerable<DmoDescriptor> GetAudioEncoderNames() { return GetDmos(DmoGuids.DMOCATEGORY_AUDIO_ENCODER); } public static IEnumerable<DmoDescriptor> GetAudioDecoderNames() { return GetDmos(DmoGuids.DMOCATEGORY_AUDIO_DECODER); } private static IEnumerable<DmoDescriptor> GetDmos(Guid category) { Marshal.ThrowExceptionForHR(DmoInterop.DMOEnum(ref category, DmoEnumFlags.None, 0, null, 0, null, out var enumDmo)); int itemsFetched; do { enumDmo.Next(1, out var clsid, out var name, out itemsFetched); if (itemsFetched == 1) { string name2 = Marshal.PtrToStringUni(name); Marshal.FreeCoTaskMem(name); yield return new DmoDescriptor(name2, clsid); } } while (itemsFetched > 0); } } [Flags] internal enum DmoEnumFlags { None = 0, DMO_ENUMF_INCLUDE_KEYED = 1 } internal static class DmoGuids { public static readonly Guid DMOCATEGORY_AUDIO_DECODER = new Guid("57f2db8b-e6bb-4513-9d43-dcd2a6593125"); public static readonly Guid DMOCATEGORY_AUDIO_ENCODER = new Guid("33D9A761-90C8-11d0-BD43-00A0C911CE86"); public static readonly Guid DMOCATEGORY_VIDEO_DECODER = new Guid("4a69b442-28be-4991-969c-b500adf5d8a8"); public static readonly Guid DMOCATEGORY_VIDEO_ENCODER = new Guid("33D9A760-90C8-11d0-BD43-00A0C911CE86"); public static readonly Guid DMOCATEGORY_AUDIO_EFFECT = new Guid("f3602b3f-0592-48df-a4cd-674721e7ebeb"); public static readonly Guid DMOCATEGORY_VIDEO_EFFECT = new Guid("d990ee14-776c-4723-be46-3da2f56f10b9"); public static readonly Guid DMOCATEGORY_AUDIO_CAPTURE_EFFECT = new Guid("f665aaba-3e09-4920-aa5f-219811148f09"); } internal static class DmoMediaTypeGuids { public static readonly Guid FORMAT_None = new Guid("0F6417D6-C318-11D0-A43F-00A0C9223196"); public static readonly Guid FORMAT_VideoInfo = new Guid("05589f80-c356-11ce-bf01-00aa0055595a"); public static readonly Guid FORMAT_VideoInfo2 = new Guid("F72A76A0-EB0A-11d0-ACE4-0000C0CC16BA"); public static readonly Guid FORMAT_WaveFormatEx = new Guid("05589f81-c356-11ce-bf01-00aa0055595a"); public static readonly Guid FORMAT_MPEGVideo = new Guid("05589f82-c356-11ce-bf01-00aa0055595a"); public static readonly Guid FORMAT_MPEGStreams = new Guid("05589f83-c356-11ce-bf01-00aa0055595a"); public static readonly Guid FORMAT_DvInfo = new Guid("05589f84-c356-11ce-bf01-00aa0055595a"); public static readonly Guid FORMAT_525WSS = new Guid("C7ECF04D-4582-4869-9ABB-BFB523B62EDF"); } internal enum DmoHResults { DMO_E_INVALIDSTREAMINDEX = -2147220991, DMO_E_INVALIDTYPE, DMO_E_TYPE_NOT_SET, DMO_E_NOTACCEPTING, DMO_E_TYPE_NOT_ACCEPTED, DMO_E_NO_MORE_ITEMS } internal static class DmoInterop { [DllImport("msdmo.dll")] public static extern int DMOEnum([In] ref Guid guidCategory, DmoEnumFlags flags, int inTypes, [In] DmoPartialMediaType[] inTypesArray, int outTypes, [In] DmoPartialMediaType[] outTypesArray, out IEnumDmo enumDmo); [DllImport("msdmo.dll")] public static extern int MoFreeMediaType([In] ref DmoMediaType mediaType); [DllImport("msdmo.dll")] public static extern int MoInitMediaType([In][Out] ref DmoMediaType mediaType, int formatBlockBytes); [DllImport("msdmo.dll")] public static extern int DMOGetName([In] ref Guid clsidDMO, [Out] StringBuilder name); } internal struct DmoPartialMediaType { private Guid type; private Guid subtype; public Guid Type { get { return type; } internal set { type = value; } } public Guid Subtype { get { return subtype; } internal set { subtype = value; } } } [ComImport] [SuppressUnmanagedCodeSecurity] [Guid("6d6cbb60-a223-44aa-842f-a2f06750be6d")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IMediaParamInfo { [PreserveSig] int GetParamCount(out int paramCount); [PreserveSig] int GetParamInfo(int paramIndex, ref MediaParamInfo paramInfo); [PreserveSig] int GetParamText(int paramIndex, out IntPtr paramText); [PreserveSig] int GetNumTimeFormats(out int numTimeFormats); [PreserveSig] int GetSupportedTimeFormat(int formatIndex, out Guid guidTimeFormat); [PreserveSig] int GetCurrentTimeFormat(out Guid guidTimeFormat, out int mediaTimeData); } [Guid("E7E9984F-F09F-4da4-903F-6E2E0EFE56B5")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IWMResamplerProps { int SetHalfFilterLength(int outputQuality); int SetUserChannelMtx([In] float[] channelConversionMatrix); } public class MediaBuffer : IMediaBuffer, IDisposable { private IntPtr buffer; private int length; private readonly int maxLength; public int Length { get { return length; } set { if (length > maxLength) { throw new ArgumentException("Cannot be greater than maximum buffer size"); } length = value; } } public MediaBuffer(int maxLength) { buffer = Marshal.AllocCoTaskMem(maxLength); this.maxLength = maxLength; } public void Dispose() { if (buffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(buffer); buffer = IntPtr.Zero; GC.SuppressFinalize(this); } } ~MediaBuffer() { Dispose(); } int IMediaBuffer.SetLength(int length) { if (length > maxLength) { return -2147483645; } this.length = length; return 0; } int IMediaBuffer.GetMaxLength(out int maxLength) { maxLength = this.maxLength; return 0; } int IMediaBuffer.GetBufferAndLength(IntPtr bufferPointerPointer, IntPtr validDataLengthPointer) { if (bufferPointerPointer != IntPtr.Zero) { Marshal.WriteIntPtr(bufferPointerPointer, buffer); } if (validDataLengthPointer != IntPtr.Zero) { Marshal.WriteInt32(validDataLengthPointer, length); } return 0; } public void LoadData(byte[] data, int bytes) { Length = bytes; Marshal.Copy(data, 0, buffer, bytes); } public void RetrieveData(byte[] data, int offset) { Marshal.Copy(buffer, data, offset, Length); } } public class MediaObject : IDisposable { private IMediaObject mediaObject; private readonly int inputStreams; private readonly int outputStreams; public int InputStreamCount => inputStreams; public int OutputStreamCount => outputStreams; internal MediaObject(IMediaObject mediaObject) { this.mediaObject = mediaObject; mediaObject.GetStreamCount(out inputStreams, out outputStreams); } public DmoMediaType? GetInputType(int inputStream, int inputTypeIndex) { try { if (mediaObject.GetInputType(inputStream, inputTypeIndex, out var mediaType) == 0) { DmoInterop.MoFreeMediaType(ref mediaType); return mediaType; } } catch (COMException exception) { if (exception.GetHResult() != -2147220986) { throw; } } return null; } public DmoMediaType? GetOutputType(int outputStream, int outputTypeIndex) { try { if (mediaObject.GetOutputType(outputStream, outputTypeIndex, out var mediaType) == 0) { DmoInterop.MoFreeMediaType(ref mediaType); return mediaType; } } catch (COMException exception) { if (exception.GetHResult() != -2147220986) { throw; } } return null; } public DmoMediaType GetOutputCurrentType(int outputStreamIndex) { DmoMediaType mediaType; int outputCurrentType = mediaObject.GetOutputCurrentType(outputStreamIndex, out mediaType); switch (outputCurrentType) { case 0: DmoInterop.MoFreeMediaType(ref mediaType); return mediaType; case -2147220989: throw new InvalidOperationException("Media type was not set."); default: throw Marshal.GetExceptionForHR(outputCurrentType); } } public IEnumerable<DmoMediaType> GetInputTypes(int inputStreamIndex) { int typeIndex = 0; while (true) { DmoMediaType? inputType; DmoMediaType? mediaType = (inputType = GetInputType(inputStreamIndex, typeIndex)); inputType = inputType; if (inputType.HasValue) { yield return mediaType.Value; typeIndex++; continue; } break; } } public IEnumerable<DmoMediaType> GetOutputTypes(int outputStreamIndex) { int typeIndex = 0; while (true) { DmoMediaType? outputType; DmoMediaType? mediaType = (outputType = GetOutputType(outputStreamIndex, typeIndex)); outputType = outputType; if (outputType.HasValue) { yield return mediaType.Value; typeIndex++; continue; } break; } } public bool SupportsInputType(int inputStreamIndex, DmoMediaType mediaType) { return SetInputType(inputStreamIndex, mediaType, DmoSetTypeFlags.DMO_SET_TYPEF_TEST_ONLY); } private bool SetInputType(int inputStreamIndex, DmoMediaType mediaType, DmoSetTypeFlags flags) { switch (mediaObject.SetInputType(inputStreamIndex, ref mediaType, flags)) { case -2147220991: throw new ArgumentException("Invalid stream index"); default: _ = -2147220987; return false; case 0: return true; } } public void SetInputType(int inputStreamIndex, DmoMediaType mediaType) { if (!SetInputType(inputStreamIndex, mediaType, DmoSetTypeFlags.None)) { throw new ArgumentException("Media Type not supported"); } } public void SetInputWaveFormat(int inputStreamIndex, WaveFormat waveFormat) { DmoMediaType mediaType = CreateDmoMediaTypeForWaveFormat(waveFormat); bool num = SetInputType(inputStreamIndex, mediaType, DmoSetTypeFlags.None); DmoInterop.MoFreeMediaType(ref mediaType); if (!num) { throw new ArgumentException("Media Type not supported"); } } public bool SupportsInputWaveFormat(int inputStreamIndex, WaveFormat waveFormat) { DmoMediaType mediaType = CreateDmoMediaTypeForWaveFormat(waveFormat); bool result = SetInputType(inputStreamIndex, mediaType, DmoSetTypeFlags.DMO_SET_TYPEF_TEST_ONLY); DmoInterop.MoFreeMediaType(ref mediaType); return result; } private DmoMediaType CreateDmoMediaTypeForWaveFormat(WaveFormat waveFormat) { DmoMediaType mediaType = default(DmoMediaType); int formatBlockBytes = Marshal.SizeOf((object)waveFormat); DmoInterop.MoInitMediaType(ref mediaType, formatBlockBytes); mediaType.SetWaveFormat(waveFormat); return mediaType; } public bool SupportsOutputType(int outputStreamIndex, DmoMediaType mediaType) { return SetOutputType(outputStreamIndex, mediaType, DmoSetTypeFlags.DMO_SET_TYPEF_TEST_ONLY); } public bool SupportsOutputWaveFormat(int outputStreamIndex, WaveFormat waveFormat) { DmoMediaType mediaType = CreateDmoMediaTypeForWaveFormat(waveFormat); bool result = SetOutputType(outputStreamIndex, mediaType, DmoSetTypeFlags.DMO_SET_TYPEF_TEST_ONLY); DmoInterop.MoFreeMediaType(ref mediaType); return result; } private bool SetOutputType(int outputStreamIndex, DmoMediaType mediaType, DmoSetTypeFlags flags) { int num = mediaObject.SetOutputType(outputStreamIndex, ref mediaType, flags); return num switch { -2147220987 => false, 0 => true, _ => throw Marshal.GetExceptionForHR(num), }; } public void SetOutputType(int outputStreamIndex, DmoMediaType mediaType) { if (!SetOutputType(outputStreamIndex, mediaType, DmoSetTypeFlags.None)) { throw new ArgumentException("Media Type not supported"); } } public void SetOutputWaveFormat(int outputStreamIndex, WaveFormat waveFormat) { DmoMediaType mediaType = CreateDmoMediaTypeForWaveFormat(waveFormat); bool num = SetOutputType(outputStreamIndex, mediaType, DmoSetTypeFlags.None); DmoInterop.MoFreeMediaType(ref mediaType); if (!num) { throw new ArgumentException("Media Type not supported"); } } public MediaObjectSizeInfo GetInputSizeInfo(int inputStreamIndex) { Marshal.ThrowExceptionForHR(mediaObject.GetInputSizeInfo(inputStreamIndex, out var size, out var maxLookahead, out var alignment)); return new MediaObjectSizeInfo(size, maxLookahead, alignment); } public MediaObjectSizeInfo GetOutputSizeInfo(int outputStreamIndex) { Marshal.ThrowExceptionForHR(mediaObject.GetOutputSizeInfo(outputStreamIndex, out var size, out var alignment)); return new MediaObjectSizeInfo(size, 0, alignment); } public void ProcessInput(int inputStreamIndex, IMediaBuffer mediaBuffer, DmoInputDataBufferFlags flags, long timestamp, long duration) { Marshal.ThrowExceptionForHR(mediaObject.ProcessInput(inputStreamIndex, mediaBuffer, flags, timestamp, duration)); } public void ProcessOutput(DmoProcessOutputFlags flags, int outputBufferCount, DmoOutputDataBuffer[] outputBuffers) { Marshal.ThrowExceptionForHR(mediaObject.ProcessOutput(flags, outputBufferCount, outputBuffers, out var _)); } public void AllocateStreamingResources() { Marshal.ThrowExceptionForHR(mediaObject.AllocateStreamingResources()); } public void FreeStreamingResources() { Marshal.ThrowExceptionForHR(mediaObject.FreeStreamingResources()); } public long GetInputMaxLatency(int inputStreamIndex) { Marshal.ThrowExceptionForHR(mediaObject.GetInputMaxLatency(inputStreamIndex, out var referenceTimeMaxLatency)); return referenceTimeMaxLatency; } public void Flush() { Marshal.ThrowExceptionForHR(mediaObject.Flush()); } public void Discontinuity(int inputStreamIndex) { Marshal.ThrowExceptionForHR(mediaObject.Discontinuity(inputStreamIndex)); } public bool IsAcceptingData(int inputStreamIndex) { Marshal.ThrowExceptionForHR(mediaObject.GetInputStatus(inputStreamIndex, out var flags)); return (flags & DmoInputStatusFlags.DMO_INPUT_STATUSF_ACCEPT_DATA) == DmoInputStatusFlags.DMO_INPUT_STATUSF_ACCEPT_DATA; } public void Dispose() { if (mediaObject != null) { Marshal.ReleaseComObject(mediaObject); mediaObject = null; } } } public class MediaObjectSizeInfo { public int Size { get; private set; } public int MaxLookahead { get; } public int Alignment { get; } public MediaObjectSizeInfo(int size, int maxLookahead, int alignment) { Size = size; MaxLookahead = maxLookahead; Alignment = alignment; } public override string ToString() { return $"Size: {Size}, Alignment {Alignment}, MaxLookahead {MaxLookahead}"; } } internal struct MediaParamInfo { public MediaParamType mpType; public MediaParamCurveType mopCaps; public float mpdMinValue; public float mpdMaxValue; public float mpdNeutralValue; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szUnitText; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szLabel; } internal enum MediaParamType { Int, Float, Bool, Enum, Max } [Flags] internal enum MediaParamCurveType { MP_CURVE_JUMP = 1, MP_CURVE_LINEAR = 2, MP_CURVE_SQUARE = 4, MP_CURVE_INVSQUARE = 8, MP_CURVE_SINE = 0x10 } internal static class MediaTypes { public static readonly Guid MEDIATYPE_AnalogAudio = new Guid("0482DEE1-7817-11cf-8a03-00aa006ecb65"); public static readonly Guid MEDIATYPE_AnalogVideo = new Guid("0482DDE1-7817-11cf-8A03-00AA006ECB65"); public static readonly Guid MEDIATYPE_Audio = new Guid("73647561-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIATYPE_AUXLine21Data = new Guid("670AEA80-3A82-11d0-B79B-00AA003767A7"); public static readonly Guid MEDIATYPE_File = new Guid("656c6966-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIATYPE_Interleaved = new Guid("73766169-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIATYPE_Midi = new Guid("7364696D-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIATYPE_ScriptCommand = new Guid("73636d64-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIATYPE_Stream = new Guid("e436eb83-524f-11ce-9f53-0020af0ba770"); public static readonly Guid MEDIATYPE_Text = new Guid("73747874-0000-0010-8000-00AA00389B71"); public static readonly Guid MEDIATYPE_Timecode = new Guid("0482DEE3-7817-11cf-8a03-00aa006ecb65"); public static readonly Guid MEDIATYPE_Video = new Guid("73646976-0000-0010-8000-00AA00389B71"); public static readonly Guid[] MajorTypes = new Guid[12] { MEDIATYPE_AnalogAudio, MEDIATYPE_AnalogVideo, MEDIATYPE_Audio, MEDIATYPE_AUXLine21Data, MEDIATYPE_File, MEDIATYPE_Interleaved, MEDIATYPE_Midi, MEDIATYPE_ScriptCommand, MEDIATYPE_Stream, MEDIATYPE_Text, MEDIATYPE_Timecode, MEDIATYPE_Video }; public static readonly string[] MajorTypeNames = new string[12] { "Analog Audio", "Analog Video", "Audio", "AUXLine21Data", "File", "Interleaved", "Midi", "ScriptCommand", "Stream", "Text", "Timecode", "Video" }; public static string GetMediaTypeName(Guid majorType) { for (int i = 0; i < MajorTypes.Length; i++) { if (majorType == MajorTypes[i]) { return MajorTypeNames[i]; } } throw new ArgumentException("Major Type not found"); } } [ComImport] [Guid("bbeea841-0a63-4f52-a7ab-a9b3a84ed38a")] internal class WindowsMediaMp3DecoderComObject { } public class WindowsMediaMp3Decoder : IDisposable { private MediaObject mediaObject; private IPropertyStore propertyStoreInterface; private WindowsMediaMp3DecoderComObject mediaComObject; public MediaObject MediaObject => mediaObject; public WindowsMediaMp3Decoder() { mediaComObject = new WindowsMediaMp3DecoderComObject(); mediaObject = new MediaObject((IMediaObject)mediaComObject); propertyStoreInterface = (IPropertyStore)mediaComObject; } public void Dispose() { if (propertyStoreInterface != null) { Marshal.ReleaseComObject(propertyStoreInterface); propertyStoreInterface = null; } if (mediaObject != null) { mediaObject.Dispose(); mediaObject = null; } if (mediaComObject != null) { Marshal.ReleaseComObject(mediaComObject); mediaComObject = null; } } } [Flags] public enum DmoInputDataBufferFlags { None = 0, SyncPoint = 1, Time = 2, TimeLength = 4 } [Flags] internal enum DmoInputStatusFlags { None = 0, DMO_INPUT_STATUSF_ACCEPT_DATA = 1 } public struct DmoMediaType { private Guid majortype; private Guid subtype; private bool bFixedSizeSamples; private bool bTemporalCompression; private int lSampleSize; private Guid formattype; private IntPtr pUnk; private int cbFormat; private IntPtr pbFormat; public Guid MajorType => majortype; public string MajorTypeName => MediaTypes.GetMediaTypeName(majortype); public Guid SubType => subtype; public string SubTypeName { get { if (majortype == MediaTypes.MEDIATYPE_Audio) { return AudioMediaSubtypes.GetAudioSubtypeName(subtype); } return subtype.ToString(); } } public bool FixedSizeSamples => bFixedSizeSamples; public int SampleSize => lSampleSize; public Guid FormatType => formattype; public string FormatTypeName { get { if (formattype == DmoMediaTypeGuids.FORMAT_None) { return "None"; } if (formattype == Guid.Empty) { return "Null"; } if (formattype == DmoMediaTypeGuids.FORMAT_WaveFormatEx) { return "WaveFormatEx"; } return FormatType.ToString(); } } public WaveFormat GetWaveFormat() { if (formattype == DmoMediaTypeGuids.FORMAT_WaveFormatEx) { return WaveFormat.MarshalFromPtr(pbFormat); } throw new InvalidOperationException("Not a WaveFormat type"); } public void SetWaveFormat(WaveFormat waveFormat) { majortype = MediaTypes.MEDIATYPE_Audio; if (waveFormat is WaveFormatExtensible waveFormatExtensible) { subtype = waveFormatExtensible.SubFormat; } else { switch (waveFormat.Encoding) { case WaveFormatEncoding.Pcm: subtype = AudioMediaSubtypes.MEDIASUBTYPE_PCM; break; case WaveFormatEncoding.IeeeFloat: subtype = AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT; break; case WaveFormatEncoding.MpegLayer3: subtype = AudioMediaSubtypes.WMMEDIASUBTYPE_MP3; break; default: throw new ArgumentException($"Not a supported encoding {waveFormat.Encoding}"); } } bFixedSizeSamples = SubType == AudioMediaSubtypes.MEDIASUBTYPE_PCM || SubType == AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT; formattype = DmoMediaTypeGuids.FORMAT_WaveFormatEx; if (cbFormat < Marshal.SizeOf((object)waveFormat)) { throw new InvalidOperationException("Not enough memory assigned for a WaveFormat structure"); } Marshal.StructureToPtr((object)waveFormat, pbFormat, fDeleteOld: false); } } [StructLayout(LayoutKind.Sequential, Pack = 8)] public struct DmoOutputDataBuffer : IDisposable { [MarshalAs(UnmanagedType.Interface)] private IMediaBuffer pBuffer; private DmoOutputDataBufferFlags dwStatus; private long rtTimestamp; private long referenceTimeDuration; public IMediaBuffer MediaBuffer { get { return pBuffer; } internal set { pBuffer = value; } } public int Length => ((MediaBuffer)pBuffer).Length; public DmoOutputDataBufferFlags StatusFlags { get { return dwStatus; } internal set { dwStatus = value; } } public long Timestamp { get { return rtTimestamp; } internal set { rtTimestamp = value; } } public long Duration { get { return referenceTimeDuration; } internal set { referenceTimeDuration = value; } } public bool MoreDataAvailable => (StatusFlags & DmoOutputDataBufferFlags.Incomplete) == DmoOutputDataBufferFlags.Incomplete; public DmoOutputDataBuffer(int maxBufferSize) { pBuffer = new MediaBuffer(maxBufferSize); dwStatus = DmoOutputDataBufferFlags.None; rtTimestamp = 0L; referenceTimeDuration = 0L; } public void Dispose() { if (pBuffer != null) { ((MediaBuffer)pBuffer).Dispose(); pBuffer = null; GC.SuppressFinalize(this); } } public void RetrieveData(byte[] data, int offset) { ((MediaBuffer)pBuffer).RetrieveData(data, offset); } } [Flags] public enum DmoOutputDataBufferFlags { None = 0, SyncPoint = 1, Time = 2, TimeLength = 4, Incomplete = 0x1000000 } [Flags] public enum DmoProcessOutputFlags { None = 0, DiscardWhenNoBuffer = 1 } [Flags] internal enum DmoSetTypeFlags { None = 0, DMO_SET_TYPEF_TEST_ONLY = 1, DMO_SET_TYPEF_CLEAR = 2 } [Guid("2c3cd98a-2bfa-4a53-9c27-5249ba64ba0f")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IEnumDmo { int Next(int itemsToFetch, out Guid clsid, out IntPtr name, out int itemsFetched); int Skip(int itemsToSkip); int Reset(); int Clone(out IEnumDmo enumPointer); } [ComImport] [SuppressUnmanagedCodeSecurity] [Guid("59eff8b9-938c-4a26-82f2-95cb84cdc837")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IMediaBuffer { [PreserveSig] int SetLength(int length); [PreserveSig] int GetMaxLength(out int maxLength); [PreserveSig] int GetBufferAndLength(IntPtr bufferPointerPointer, IntPtr validDataLengthPointer); } [ComImport] [SuppressUnmanagedCodeSecurity] [Guid("d8ad0f58-5494-4102-97c5-ec798e59bcf4")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IMediaObject { [PreserveSig] int GetStreamCount(out int inputStreams, out int outputStreams); [PreserveSig] int GetInputStreamInfo(int inputStreamIndex, out InputStreamInfoFlags flags); [PreserveSig] int GetOutputStreamInfo(int outputStreamIndex, out OutputStreamInfoFlags flags); [PreserveSig] int GetInputType(int inputStreamIndex, int typeIndex, out DmoMediaType mediaType); [PreserveSig] int GetOutputType(int outputStreamIndex, int typeIndex, out DmoMediaType mediaType); [PreserveSig] int SetInputType(int inputStreamIndex, [In] ref DmoMediaType mediaType, DmoSetTypeFlags flags); [PreserveSig] int SetOutputType(int outputStreamIndex, [In] ref DmoMediaType mediaType, DmoSetTypeFlags flags); [PreserveSig] int GetInputCurrentType(int inputStreamIndex, out DmoMediaType mediaType); [PreserveSig] int GetOutputCurrentType(int outputStreamIndex, out DmoMediaType mediaType); [PreserveSig] int GetInputSizeInfo(int inputStreamIndex, out int size, out int maxLookahead, out int alignment); [PreserveSig] int GetOutputSizeInfo(int outputStreamIndex, out int size, out int alignment); [PreserveSig] int GetInputMaxLatency(int inputStreamIndex, out long referenceTimeMaxLatency); [PreserveSig] int SetInputMaxLatency(int inputStreamIndex, long referenceTimeMaxLatency); [PreserveSig] int Flush(); [PreserveSig] int Discontinuity(int inputStreamIndex); [PreserveSig] int AllocateStreamingResources(); [PreserveSig] int FreeStreamingResources(); [PreserveSig] int GetInputStatus(int inputStreamIndex, out DmoInputStatusFlags flags); [PreserveSig] int ProcessInput(int inputStreamIndex, [In] IMediaBuffer mediaBuffer, DmoInputDataBufferFlags flags, long referenceTimeTimestamp, long referenceTimeDuration); [PreserveSig] int ProcessOutput(DmoProcessOutputFlags flags, int outputBufferCount, [In][Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] DmoOutputDataBuffer[] outputBuffers, out int statusReserved); [PreserveSig] int Lock(bool acquireLock); } [Flags] internal enum InputStreamInfoFlags { None = 0, DMO_INPUT_STREAMF_WHOLE_SAMPLES = 1, DMO_INPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER = 2, DMO_INPUT_STREAMF_FIXED_SAMPLE_SIZE = 4, DMO_INPUT_STREAMF_HOLDS_BUFFERS = 8 } [Flags] internal enum OutputStreamInfoFlags { DMO_OUTPUT_STREAMF_WHOLE_SAMPLES = 1, DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER = 2, DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE = 4, DMO_OUTPUT_STREAMF_DISCARDABLE = 8, DMO_OUTPUT_STREAMF_OPTIONAL = 0x10 } [ComImport] [Guid("f447b69e-1884-4a7e-8055-346f74d6edb3")] internal class ResamplerMediaComObject { } public class DmoResampler : IDisposable { private MediaObject mediaObject; private IPropertyStore propertyStoreInterface; private IWMResamplerProps resamplerPropsInterface; private ResamplerMediaComObject mediaComObject; public MediaObject MediaObject => mediaObject; public DmoResampler() { mediaComObject = new ResamplerMediaComObject(); mediaObject = new MediaObject((IMediaObject)mediaComObject); propertyStoreInterface = (IPropertyStore)mediaComObject; resamplerPropsInterface = (IWMResamplerProps)mediaComObject; } public void Dispose() { if (propertyStoreInterface != null) { Marshal.ReleaseComObject(propertyStoreInterface); propertyStoreInterface = null; } if (resamplerPropsInterface != null) { Marshal.ReleaseComObject(resamplerPropsInterface); resamplerPropsInterface = null; } if (mediaObject != null) { mediaObject.Dispose(); mediaObject = null; } if (mediaComObject != null) { Marshal.ReleaseComObject(mediaComObject); mediaComObject = null; } } } } namespace NAudio.Wave { 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 }; } } 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 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 = 0; 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 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
ResourcefulHands.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using NAudio.Wave; using Newtonsoft.Json; using ResourcefulHands.Patches; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ResourcefulHands")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+b770ebe2ed528182a684f486d8217e8a774fa5e6")] [assembly: AssemblyProduct("ResourcefulHands")] [assembly: AssemblyTitle("ResourcefulHands")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ResourcefulHands { public static class MiscUtils { private static int StartIndex; public static string CleanString(string str) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char c in invalidFileNameChars) { str = str.Replace(c.ToString(), ""); } StringBuilder stringBuilder = new StringBuilder(); string text = str; foreach (char c2 in text) { if (c2 <= '\u007f') { stringBuilder.Append(c2); } } return stringBuilder.ToString(); } public static void WriteString(this Stream stream, string value) { foreach (char c in value) { stream.WriteByte((byte)c); } } public static void WriteInteger(this Stream stream, uint value) { stream.WriteByte((byte)(value & 0xFFu)); stream.WriteByte((byte)((value >> 8) & 0xFFu)); stream.WriteByte((byte)((value >> 16) & 0xFFu)); stream.WriteByte((byte)((value >> 24) & 0xFFu)); } public static void WriteShort(this Stream stream, ushort value) { stream.WriteByte((byte)(value & 0xFFu)); stream.WriteByte((byte)((uint)(value >> 8) & 0xFFu)); } public static RenderTexture ConvertToARGB32(this RenderTexture self) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)self.format == 0) { return self; } RenderTexture temporary = RenderTexture.GetTemporary(((Texture)self).width, ((Texture)self).height, 0, (RenderTextureFormat)0); Graphics.Blit((Texture)(object)self, temporary); return temporary; } public static float[] LoadAudioFile(string filePath, out int sampleRate, out int channels) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown AudioFileReader val = new AudioFileReader(filePath); try { sampleRate = ((WaveStream)val).WaveFormat.SampleRate; channels = ((WaveStream)val).WaveFormat.Channels; int num = (int)(((Stream)(object)val).Length / 4); float[] array = new float[num]; int num2 = val.Read(array, 0, num); return array[..num2]; } finally { ((IDisposable)val)?.Dispose(); } } public static AudioClip CreateAudioClip(float[] samples, int sampleRate, int channels, string name = "GeneratedClip") { int num = samples.Length / channels; AudioClip obj = AudioClip.Create(name, num, channels, sampleRate, true); obj.SetData(samples, 0); return obj; } public static AudioClip LoadAudioClipFromFile(string path) { int sampleRate; int channels; return CreateAudioClip(LoadAudioFile(path, out sampleRate, out channels), sampleRate, channels); } public static string GetSHA256Checksum(string filePath) { using FileStream inputStream = File.OpenRead(filePath); using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(inputStream); StringBuilder stringBuilder = new StringBuilder(); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString(); } public static byte[] ToWav(this AudioClip clip) { float[] array = new float[clip.samples * clip.channels]; clip.GetData(array, 0); byte[] array2 = new byte[array.Length * 2]; for (int i = 0; i < array.Length; i++) { byte[] bytes = BitConverter.GetBytes((short)(array[i] * 32767f)); array2[i * 2] = bytes[0]; array2[i * 2 + 1] = bytes[1]; } byte[] array3 = new byte[44 + array2.Length]; byte[] array4 = new byte[40] { 82, 73, 70, 70, 0, 0, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 16, 0, 100, 97, 116, 97 }; Buffer.BlockCopy(array4, 0, array3, 0, array4.Length); Buffer.BlockCopy(BitConverter.GetBytes(36 + array2.Length), 0, array3, 4, 4); Buffer.BlockCopy(BitConverter.GetBytes(clip.channels), 0, array3, 22, 2); Buffer.BlockCopy(BitConverter.GetBytes(clip.frequency), 0, array3, 24, 4); Buffer.BlockCopy(BitConverter.GetBytes(clip.frequency * clip.channels * 2), 0, array3, 28, 4); Buffer.BlockCopy(BitConverter.GetBytes(clip.channels * 2), 0, array3, 32, 2); Buffer.BlockCopy(BitConverter.GetBytes(array2.Length), 0, array3, 40, 4); Buffer.BlockCopy(array2, 0, array3, 44, array2.Length); return array3; } public static void Start() { StartIndex = 0; } public static void End() { StartIndex = 0; } public static string MeshToString(this MeshFilter mf, Transform t) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) _ = t.localScale; _ = t.localPosition; Quaternion localRotation = t.localRotation; int num = 0; Mesh sharedMesh = mf.sharedMesh; if (!Object.op_Implicit((Object)(object)sharedMesh)) { return "####Error####"; } Material[] sharedMaterials = ((Component)mf).GetComponent<Renderer>().sharedMaterials; StringBuilder stringBuilder = new StringBuilder(); Vector3[] vertices = sharedMesh.vertices; foreach (Vector3 val in vertices) { Vector3 val2 = t.TransformPoint(val); num++; stringBuilder.Append($"v {val2.x} {val2.y} {0f - val2.z}\n"); } stringBuilder.Append("\n"); vertices = sharedMesh.normals; foreach (Vector3 val3 in vertices) { Vector3 val4 = localRotation * val3; stringBuilder.Append($"vn {0f - val4.x} {0f - val4.y} {val4.z}\n"); } stringBuilder.Append("\n"); Vector2[] uv = sharedMesh.uv; for (int i = 0; i < uv.Length; i++) { Vector3 val5 = Vector2.op_Implicit(uv[i]); stringBuilder.Append($"vt {val5.x} {val5.y}\n"); } for (int j = 0; j < sharedMesh.subMeshCount; j++) { stringBuilder.Append("\n"); stringBuilder.Append("usemtl ").Append(((Object)sharedMaterials[j]).name).Append("\n"); stringBuilder.Append("usemap ").Append(((Object)sharedMaterials[j]).name).Append("\n"); int[] triangles = sharedMesh.GetTriangles(j); for (int k = 0; k < triangles.Length; k += 3) { stringBuilder.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", triangles[k] + 1 + StartIndex, triangles[k + 1] + 1 + StartIndex, triangles[k + 2] + 1 + StartIndex)); } } StartIndex += num; return stringBuilder.ToString(); } } [BepInPlugin("triggeredidiot.wkd.resourcefulhands", "Resourceful Hands", "0.9.6")] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static UnityAction <0>__ReloadPacks; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<UI_TabGroup, bool> <>9__27_0; public static UnityAction <>9__27_1; public static Action <>9__28_1; internal bool <LoadCustomSettings>b__27_0(UI_TabGroup tabGroup) { return ((Object)tabGroup).name.ToLower() == "tab selection hor"; } internal void <LoadCustomSettings>b__27_1() { Application.OpenURL("file://" + ConfigFolder.Replace("\\", "/")); } internal void <Awake>b__28_1() { SpriteRenderer[] array = Object.FindObjectsByType<SpriteRenderer>((FindObjectsSortMode)0); foreach (SpriteRenderer obj in array) { obj.sprite = obj.sprite; } } } [CompilerGenerated] private sealed class <>c__DisplayClass27_0 { public UI_TabGroup tabGroup; internal void <LoadCustomSettings>b__2() { tabGroup.SelectTab("packs"); } } [CompilerGenerated] private sealed class <LoadCustomSettings>d__27 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public UI_SettingsMenu settingsMenu; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadCustomSettings>d__27(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Expected O, but got Unknown //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSecondsRealtime(1f); <>1__state = 1; return true; case 1: <>1__state = -1; RHLog.Info("Loading custom settings menu...", 123, "C:\\Dev\\VSProjects\\ResourcefulHands\\Plugin.cs"); if ((Object)(object)Assets == (Object)null) { RHLog.Warning("No assets?", 126, "C:\\Dev\\VSProjects\\ResourcefulHands\\Plugin.cs"); return false; } try { <>c__DisplayClass27_0 CS$<>8__locals0 = new <>c__DisplayClass27_0(); UI_TabGroup[] componentsInChildren = ((Component)settingsMenu).GetComponentsInChildren<UI_TabGroup>(); CS$<>8__locals0.tabGroup = ((IEnumerable<UI_TabGroup>)componentsInChildren).FirstOrDefault((Func<UI_TabGroup, bool>)((UI_TabGroup tabGroup) => ((Object)tabGroup).name.ToLower() == "tab selection hor")); if ((Object)(object)CS$<>8__locals0.tabGroup != (Object)null) { GameObject obj = Object.Instantiate<GameObject>(Assets.LoadAsset<GameObject>("Packs"), ((Component)CS$<>8__locals0.tabGroup).transform, false); Button componentInChildren = obj.GetComponentInChildren<Button>(); TextMeshProUGUI componentInChildren2 = obj.GetComponentInChildren<TextMeshProUGUI>(); GameObject val = Object.Instantiate<GameObject>(Assets.LoadAsset<GameObject>("Pack Settings"), ((Component)CS$<>8__locals0.tabGroup).transform.parent, false); ButtonClickedEvent onClick = ((Component)val.transform.Find("Reload")).GetComponentInChildren<Button>().onClick; object obj2 = <>O.<0>__ReloadPacks; if (obj2 == null) { UnityAction val2 = ResourcePacksManager.ReloadPacks; <>O.<0>__ReloadPacks = val2; obj2 = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); ButtonClickedEvent onClick2 = ((Component)val.transform.Find("OpenFolder")).GetComponentInChildren<Button>().onClick; object obj3 = <>c.<>9__27_1; if (obj3 == null) { UnityAction val3 = delegate { Application.OpenURL("file://" + ConfigFolder.Replace("\\", "/")); }; <>c.<>9__27_1 = val3; obj3 = (object)val3; } ((UnityEvent)onClick2).AddListener((UnityAction)obj3); val.AddComponent<UI_RHPacksList>(); val.SetActive(false); for (int i = 0; i < ((Component)CS$<>8__locals0.tabGroup).transform.childCount; i++) { Transform child = ((Component)CS$<>8__locals0.tabGroup).transform.GetChild(i); string text = ((Object)child).name.ToLower(); if (text.StartsWith("lb") || text.StartsWith("rb")) { ((Component)child).gameObject.SetActive(false); } } Tab val4 = CS$<>8__locals0.tabGroup.tabs.FirstOrDefault(); if (val4 != null) { ((TMP_Text)componentInChildren2).font = ((TMP_Text)((Component)val4.button).GetComponentInChildren<TextMeshProUGUI>()).font; for (int j = 0; j < val4.tabObject.transform.childCount; j++) { Transform child2 = val4.tabObject.transform.GetChild(j); if (((Object)child2).name.ToLower().Contains("title") && Object.op_Implicit((Object)(object)((Component)child2).GetComponentInChildren<TextMeshProUGUI>())) { TextMeshProUGUI componentInChildren3 = Object.Instantiate<GameObject>(((Component)child2).gameObject, val.transform, true).GetComponentInChildren<TextMeshProUGUI>(); ((TMP_Text)componentInChildren3).text = "PACKS"; TextMeshProUGUI[] componentsInChildren2 = val.GetComponentsInChildren<TextMeshProUGUI>(true); for (int k = 0; k < componentsInChildren2.Length; k++) { ((TMP_Text)componentsInChildren2[k]).font = ((TMP_Text)componentInChildren3).font; } } } } Tab item = new Tab { button = componentInChildren, name = "packs", tabObject = val }; ((UnityEvent)componentInChildren.onClick).AddListener((UnityAction)delegate { CS$<>8__locals0.tabGroup.SelectTab("packs"); }); CS$<>8__locals0.tabGroup.tabs.Add(item); } } catch (Exception ex) { RHLog.Error("Failed to load custom settings menu:\n" + ex.ToString(), 197, "C:\\Dev\\VSProjects\\ResourcefulHands\\Plugin.cs"); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string GUID = "triggeredidiot.wkd.resourcefulhands"; public const string ModifiedStr = " [modified asset]"; private static AssetBundle? _assets; public static Texture2D? CorruptionTexture; public static Texture2D? Icon; public static Texture2D? IconGray; public static AssetBundle? Assets { get { if ((Object)(object)_assets != (Object)null) { return _assets; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = "ResourcefulHands.rh_assets.bundle"; using Stream stream = executingAssembly.GetManifestResourceStream(name); if (stream != null) { _assets = AssetBundle.LoadFromStream(stream); } AssetBundle? assets = _assets; CorruptionTexture = ((assets != null) ? assets.LoadAsset<Texture2D>("Corruption1") : null); AssetBundle? assets2 = _assets; Icon = ((assets2 != null) ? assets2.LoadAsset<Texture2D>("icon") : null); AssetBundle? assets3 = _assets; IconGray = ((assets3 != null) ? assets3.LoadAsset<Texture2D>("gray_icon") : null); return _assets; } private set { _assets = value; } } public static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } public static string ConfigFolder => Path.Combine(Paths.ConfigPath, "RHPacks"); public static bool IsDemo { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { if (SteamClient.AppId.Value == 3218540) { return true; } } catch (Exception data) { RHLog.Error(data, 68, "C:\\Dev\\VSProjects\\ResourcefulHands\\Plugin.cs"); } return false; } } public Harmony? Harmony { get; private set; } internal static void RefreshTextures() { SpriteRendererPatches._customSpriteCache.Clear(); List<Material> allMaterials = Resources.FindObjectsOfTypeAll<Material>().ToList(); Renderer[] array = Object.FindObjectsOfType<Renderer>(true); foreach (Renderer val in array) { allMaterials.AddRange(val.sharedMaterials.Where((Material mat) => !allMaterials.Contains(mat))); } int num = Shader.PropertyToID("_MainTex"); int num2 = Shader.PropertyToID("_CORRUPTTEXTURE"); Texture2D textureFromPacks = ResourcePacksManager.GetTextureFromPacks("_CORRUPTTEXTURE"); foreach (Material item in allMaterials) { if ((Object)(object)item != (Object)null) { if (item.HasTexture(num)) { item.mainTexture = item.mainTexture; } try { item.SetTexture(num2, (Texture)(object)textureFromPacks); } catch (Exception data) { RHLog.Error(data, 100, "C:\\Dev\\VSProjects\\ResourcefulHands\\Plugin.cs"); } } } SpriteRenderer[] array2 = Object.FindObjectsOfType<SpriteRenderer>(true); foreach (SpriteRenderer obj in array2) { obj.sprite = obj.sprite; } } internal static void RefreshSounds() { foreach (AudioSource item in Resources.FindObjectsOfTypeAll<AudioSource>().ToList()) { item.clip = item.clip; } AudioSource[] array = Object.FindObjectsOfType<AudioSource>(true); foreach (AudioSource obj in array) { obj.clip = obj.clip; } } [IteratorStateMachine(typeof(<LoadCustomSettings>d__27))] private IEnumerator LoadCustomSettings(UI_SettingsMenu settingsMenu) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadCustomSettings>d__27(0) { settingsMenu = settingsMenu }; } public void Awake() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; RHLog.Info("Setting up config", 205, "C:\\Dev\\VSProjects\\ResourcefulHands\\Plugin.cs"); if (!Directory.Exists(ConfigFolder)) { Directory.CreateDirectory(ConfigFolder); } RHConfig.BindConfigs(); Harmony = new Harmony("triggeredidiot.wkd.resourcefulhands"); Harmony.PatchAll(); bool hasLoadedIntro = false; SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!((Scene)(ref scene)).name.ToLower().Contains("intro") && !hasLoadedIntro) { hasLoadedIntro = true; AssetBundle? assets = Assets; if (assets != null) { assets.LoadAllAssets(); } CoroutineDispatcher.AddToUpdate(delegate { SpriteRenderer[] array = Object.FindObjectsByType<SpriteRenderer>((FindObjectsSortMode)0); foreach (SpriteRenderer obj in array) { obj.sprite = obj.sprite; } }); DebugTools.Create(); } if (hasLoadedIntro) { if (ResourcePacksManager.HasPacksChanged) { ResourcePacksManager.ReloadPacks_Internal(); } RHCommands.RefreshCommands(); UI_SettingsMenu val = ((IEnumerable<UI_SettingsMenu>)Object.FindObjectsOfType<UI_SettingsMenu>(true)).FirstOrDefault((Func<UI_SettingsMenu, bool>)((UI_SettingsMenu m) => ((Component)m).gameObject.scene == scene)); if (Object.op_Implicit((Object)(object)val) && (Object)(object)Assets != (Object)null) { CoroutineDispatcher.Dispatch(LoadCustomSettings(val)); } RefreshTextures(); RefreshSounds(); } }; } } public static class RHCommands { public const string DumpCommand = "dumptopack"; public const string ReloadCommand = "reloadpacks"; public const string MoveCommand = "reorderpack"; public const string ListCommand = "listpacks"; public const string EnableCommand = "enablepack"; public const string DisableCommand = "disablepack"; public const string ToggleDebug = "rhtoggledebug"; public static void RefreshCommands() { CommandConsole instance = CommandConsole.instance; if (Object.op_Implicit((Object)(object)instance)) { CommandConsole.RemoveCommand("dumptopack"); CommandConsole.RemoveCommand("reloadpacks"); CommandConsole.RemoveCommand("reorderpack"); CommandConsole.RemoveCommand("listpacks"); CommandConsole.RemoveCommand("enablepack"); CommandConsole.RemoveCommand("disablepack"); CommandConsole.RemoveCommand("rhtoggledebug"); instance.RegisterCommand("dumptopack", (Action<string[]>)DumpAllToPack, false); instance.RegisterCommand("reloadpacks", (Action<string[]>)ReloadPacks, false); instance.RegisterCommand("reorderpack", (Action<string[]>)MovePacks, false); instance.RegisterCommand("listpacks", (Action<string[]>)ListPacks, false); instance.RegisterCommand("enablepack", (Action<string[]>)EnablePack, false); instance.RegisterCommand("disablepack", (Action<string[]>)DisablePack, false); instance.RegisterCommand("rhtoggledebug", (Action<string[]>)delegate { DebugTools.isOn = !DebugTools.isOn; }, false); } } internal static void MovePack(TexturePack pack, bool isUp) { TexturePack pack2 = pack; int num = ResourcePacksManager.LoadedPacks.FindIndex((TexturePack p) => p == pack2); int num2 = 0; num2 = (isUp ? Math.Clamp(num - 1, 0, ResourcePacksManager.LoadedPacks.Count - 1) : Math.Clamp(num + 1, 0, ResourcePacksManager.LoadedPacks.Count - 1)); try { TexturePack texturePack = ResourcePacksManager.LoadedPacks[num2]; TexturePack texturePack2 = ResourcePacksManager.LoadedPacks[num]; texturePack.GetHashCode(); texturePack2.GetHashCode(); } catch (ArgumentOutOfRangeException) { RHLog.Warning("Failed to move packs!", 62, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\Commands.cs"); return; } TexturePack value = ResourcePacksManager.LoadedPacks[num2]; ResourcePacksManager.LoadedPacks[num2] = pack2; ResourcePacksManager.LoadedPacks[num] = value; } private static void MovePacks(string[] args) { if (args.Length != 2) { RHLog.Player.Error("Invalid number of arguments!"); RHLog.Player.Info("Usage: reorderpack [pack guid/pack index] [up/down]\nResource packs at the bottom of the loaded list will override textures at the top, use this command to move a texture pack up or down the list."); return; } TexturePack texturePack = null; if (int.TryParse(args[0], out var result)) { try { texturePack = ResourcePacksManager.LoadedPacks[result]; } catch { } if (texturePack == null) { RHLog.Player.Error($"Invalid first argument!\nThe resource pack at index {result} doesn't exist!"); RHLog.Player.Info("Usage: reorderpack [pack guid/pack index] [up/down]\nResource packs at the bottom of the loaded list will override textures at the top, use this command to move a texture pack up or down the list."); return; } } else { string packName = args[0].ToLower(); texturePack = ResourcePacksManager.LoadedPacks.FirstOrDefault((TexturePack p) => p.guid == packName); if (texturePack == null) { RHLog.Player.Error("Invalid first argument!\nThe resource pack with guid '" + packName + "' doesn't exist!"); RHLog.Player.Info("Usage: reorderpack [pack guid/pack index] [up/down]\nResource packs at the bottom of the loaded list will override textures at the top, use this command to move a texture pack up or down the list."); return; } } string text = args[1].ToLower(); bool flag; switch (text) { case "up": case "down": case "u": case "d": flag = true; break; default: flag = false; break; } if (!flag) { RHLog.Player.Error("Invalid second argument!\nExpected: up or down"); RHLog.Player.Info("Usage: reorderpack [pack guid/pack index] [up/down]\nResource packs at the bottom of the loaded list will override textures at the top, use this command to move a texture pack up or down the list."); return; } flag = ((text == "up" || text == "u") ? true : false); bool flag2 = flag; MovePack(texturePack, flag2); RHLog.Player.Info("Reloading packs..."); ResourcePacksManager.ReloadPacks_Internal(); RHLog.Player.Info(string.Format("Moved {0} {1}{2}{3} {4} successfully!", texturePack.name, '{', texturePack.guid, '}', flag2 ? "up" : "down")); } private static void ListPacks(string[] args) { for (int i = 0; i < ResourcePacksManager.LoadedPacks.Count; i++) { TexturePack texturePack = ResourcePacksManager.LoadedPacks[i]; RHLog.Player.Info(((!texturePack.IsActive) ? "[DISABLED] " : $"[{i}] ") + texturePack.name + " by " + texturePack.author + "\n-- description:\n" + texturePack.desc + "\n-- guid: '" + texturePack.guid + "'\n____"); } } private static void ReloadPacks(string[] args) { ResourcePacksManager.ReloadPacks_Internal(); RHLog.Player.Info("Resource packs reloaded successfully!"); } private static TexturePack? GetPackFromArgs(string[] args, Action<string> logErr) { TexturePack texturePack = null; if (int.TryParse(args[0], out var result)) { try { texturePack = ResourcePacksManager.LoadedPacks[result]; } catch { } if (texturePack == null) { logErr($"Invalid first argument!\nThe resource pack at index {result} doesn't exist!"); return null; } } else { string packName = args[0].ToLower(); texturePack = ResourcePacksManager.LoadedPacks.FirstOrDefault((TexturePack p) => p.guid.ToLower() == packName); if (texturePack == null) { logErr("Invalid first argument!\nThe resource pack with guid '" + packName + "' doesn't exist!"); return null; } } return texturePack; } private static void DisablePack(string[] args) { TexturePack packFromArgs = GetPackFromArgs(args, RHLog.Player.Error); if (packFromArgs == null) { RHLog.Player.Info("Usage: disablepack [pack guid/pack index]\nDisables a resource pack."); return; } packFromArgs.IsActive = false; RHLog.Player.Info("Reloading packs..."); ResourcePacksManager.ReloadPacks_Internal(); RHLog.Player.Info($"Disabled {packFromArgs.name} {'{'}{packFromArgs.guid}{'}'} successfully!"); } private static void EnablePack(string[] args) { TexturePack packFromArgs = GetPackFromArgs(args, RHLog.Player.Error); if (packFromArgs == null) { RHLog.Player.Info("Usage: enablepack [pack guid/pack index]\nEnables a resource pack."); return; } packFromArgs.IsActive = true; RHLog.Player.Info("Reloading packs..."); ResourcePacksManager.ReloadPacks_Internal(); RHLog.Player.Info($"Enabled {packFromArgs.name} {'{'}{packFromArgs.guid}{'}'} successfully!"); } private static void DumpAllToPack(string[] args) { if (args.Any((string arg) => arg.ToLower() == "help")) { RHLog.Player.Info("Use this command to generate a resource pack that contains every in-game asset. Good to find assets to replace but beware that there will probably be unused assets!"); return; } if (!args.Any((string arg) => arg.ToLower() == "confirm")) { RHLog.Player.Error("Warning: This takes up alot of storage space due to uncompressed audio!\nTHIS WILL ALSO END YOUR RUN AND LOAD YOU BACK TO THE MAIN MENU!!\nARE YOU SURE? (type 'dumptopack confirm')"); return; } RHLog.Player.Info("Dumping all resources to a template texture pack [this will take some time]..."); List<Texture2D> textures = new List<Texture2D>(); List<Texture2D> spriteTextures = new List<Texture2D>(); List<AudioClip> sounds = new List<AudioClip>(); Texture2D[] source = Resources.FindObjectsOfTypeAll<Texture2D>(); textures.AddRange(source.Where((Texture2D tex) => !textures.Contains(tex))); AudioClip[] source2 = Resources.FindObjectsOfTypeAll<AudioClip>(); sounds.AddRange(source2.Where((AudioClip sound) => !sounds.Contains(sound))); Sprite[] source3 = Resources.FindObjectsOfTypeAll<Sprite>(); spriteTextures.AddRange(from sprite in source3 where Object.op_Implicit((Object)(object)sprite.texture) && !spriteTextures.Contains(sprite.texture) select sprite.texture); RHLog.Player.Info("Loading Playground [to extract assets]"); SceneManager.LoadScene("Playground"); source = Resources.FindObjectsOfTypeAll<Texture2D>(); textures.AddRange(source.Where((Texture2D tex) => !textures.Contains(tex))); source2 = Resources.FindObjectsOfTypeAll<AudioClip>(); sounds.AddRange(source2.Where((AudioClip sound) => !sounds.Contains(sound))); source3 = Resources.FindObjectsOfTypeAll<Sprite>(); spriteTextures.AddRange(from sprite in source3 where Object.op_Implicit((Object)(object)sprite.texture) && !spriteTextures.Contains(sprite.texture) select sprite.texture); RHLog.Player.Info("Loading Training-Level [to extract assets]"); SceneManager.LoadScene("Training-Level"); source = Resources.FindObjectsOfTypeAll<Texture2D>(); textures.AddRange(source.Where((Texture2D tex) => !textures.Contains(tex))); source2 = Resources.FindObjectsOfTypeAll<AudioClip>(); sounds.AddRange(source2.Where((AudioClip sound) => !sounds.Contains(sound))); source3 = Resources.FindObjectsOfTypeAll<Sprite>(); spriteTextures.AddRange(from sprite in source3 where Object.op_Implicit((Object)(object)sprite.texture) && !spriteTextures.Contains(sprite.texture) select sprite.texture); RHLog.Player.Info("Loading Main-Menu [to extract assets and finish]"); SceneManager.LoadScene("Main-Menu"); source = Resources.FindObjectsOfTypeAll<Texture2D>(); textures.AddRange(source.Where((Texture2D tex) => !textures.Contains(tex))); source2 = Resources.FindObjectsOfTypeAll<AudioClip>(); sounds.AddRange(source2.Where((AudioClip sound) => !sounds.Contains(sound))); source3 = Resources.FindObjectsOfTypeAll<Sprite>(); spriteTextures.AddRange(from sprite in source3 where Object.op_Implicit((Object)(object)sprite.texture) && !spriteTextures.Contains(sprite.texture) select sprite.texture); RHLog.Player.Info("Packing assets..."); int count = textures.Count; int count2 = spriteTextures.Count; int count3 = sounds.Count; string text = Path.Combine(Plugin.ConfigFolder, $"extracted-assets-{count + count3 + count2}-{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } string texturesPath = Path.Combine(text, "Textures"); string path = Path.Combine(texturesPath, "Sprites"); string text2 = Path.Combine(text, "Sounds"); if (!Directory.Exists(texturesPath)) { Directory.CreateDirectory(texturesPath); } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } if (!Directory.Exists(text2)) { Directory.CreateDirectory(text2); } StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = new StringBuilder(); StringBuilder stringBuilder3 = new StringBuilder(); stringBuilder.AppendLine("-- ingame textures list --"); stringBuilder2.AppendLine("-- ingame sprite textures list --"); stringBuilder3.AppendLine("-- ingame sounds list --"); int num = 0; int num2 = 0; int num3 = 0; for (int i = 0; i < count; i++) { Texture2D val = textures[i]; RHLog.Player.Info($"Saving textures ({i}/{count})"); stringBuilder.Append(((Object)val).name); bool flag = false; try { flag = ExportTexture(val); } catch (Exception ex) { RHLog.Player.Error(((Object)val).name + " failed because " + ex.Message); } if (flag) { num++; } stringBuilder.AppendLine(flag ? "" : " [failed to extract]"); } for (int j = 0; j < count2; j++) { Texture2D val2 = spriteTextures[j]; RHLog.Player.Info($"Saving textures ({j}/{count2})"); stringBuilder2.Append(((Object)val2).name); bool flag2 = false; try { flag2 = ExportTexture(val2); } catch (Exception ex2) { RHLog.Player.Error(((Object)val2).name + " failed because " + ex2.Message); } if (flag2) { num3++; } stringBuilder2.AppendLine(flag2 ? "" : " [failed to extract]"); } for (int k = 0; k < count3; k++) { AudioClip val3 = sounds[k]; RHLog.Player.Info($"Saving sounds ({k}/{count3})"); stringBuilder3.Append(((Object)val3).name); bool flag3 = false; try { string path2 = Path.Combine(text2, ((Object)val3).name + ".wav"); float[] array = new float[val3.samples * val3.channels]; if (!val3.GetData(array, 0)) { RHLog.Player.Error("Failed to access " + ((Object)val3).name + "'s audio data!"); stringBuilder3.AppendLine(" [failed to extract]"); continue; } using (FileStream stream = new FileStream(path2, FileMode.CreateNew, FileAccess.Write)) { ushort num4 = 16; string value = "RIFF"; string value2 = "WAVE"; string value3 = "fmt "; uint value4 = 16u; ushort value5 = 1; ushort num5 = (ushort)val3.channels; uint frequency = (uint)val3.frequency; uint value6 = (uint)(frequency * val3.channels * num4 / 8); ushort value7 = (ushort)(num5 * num4 / 8); string value8 = "data"; uint num6 = (uint)(array.Length * val3.channels * num4 / 8); uint value9 = 36 + num6; stream.WriteString(value); stream.WriteInteger(value9); stream.WriteString(value2); stream.WriteString(value3); stream.WriteInteger(value4); stream.WriteShort(value5); stream.WriteShort(num5); stream.WriteInteger(frequency); stream.WriteInteger(value6); stream.WriteShort(value7); stream.WriteShort(num4); stream.WriteString(value8); stream.WriteInteger(num6); float[] array2 = array; foreach (float num7 in array2) { short num8 = 0; if (num7 > 0f) { float num9 = num7 * 32767f; if (num9 > 32767f) { num9 = 32767f; } num8 = (short)num9; } if (num7 < 0f) { float num10 = num7 * 32768f; if (num10 < -32768f) { num10 = -32768f; } num8 = (short)num10; } stream.WriteShort((ushort)num8); } num2++; flag3 = true; } goto IL_07d9; } catch (Exception ex3) { RHLog.Player.Info(((Object)val3).name + " failed because " + ex3.Message); goto IL_07d9; } IL_07d9: stringBuilder3.AppendLine(flag3 ? "" : " [failed to extract]"); } RHLog.Player.Info("Writing data files"); File.WriteAllText(Path.Combine(text, "info.json"), "{\r\n \"name\":\"generated-game-assets\",\r\n \"desc\":\"Every game asset\",\r\n \r\n \"author\":\"Dark Machine Games\",\r\n \"steamid\":0,\r\n \r\n \"guid\":\"generated-game-assets\",\r\n \r\n \"hidden-from-list\":true,\r\n \"only-in-full-game\":false,\r\n \r\n \"textures-folder\":\"Textures\",\r\n \"sounds-folder\":\"Sounds\",\r\n \"icon-file\":\"pack.png\",\r\n \r\n \"format-version\":2\r\n} "); File.WriteAllText(Path.Combine(text, "textures_list.txt"), stringBuilder.ToString()); File.WriteAllText(Path.Combine(text, "sprite_textures_list.txt"), stringBuilder2.ToString()); File.WriteAllText(Path.Combine(text, "audio_list.txt"), stringBuilder3.ToString()); RHLog.Player.Info($"Successfully saved {num} of {count} textures!"); RHLog.Player.Info($"Successfully saved {num3} of {count2} sprite textures!"); RHLog.Player.Info($"Successfully saved {num2} of {count3} sounds!"); RHLog.Player.Info("Packed all assets to '" + text + "'"); bool ExportTexture(Texture2D texture) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0088: 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_00a5: Expected O, but got Unknown bool result = false; try { if (!((Texture)texture).isReadable) { RHLog.Player.Info(((Object)texture).name + " isn't readable, saving the slow way..."); RenderTexture val4 = new RenderTexture(((Texture)texture).width, ((Texture)texture).height, 24); RenderTexture active = RenderTexture.active; try { RenderTexture.active = val4; Graphics.Blit((Texture)(object)texture, val4); RenderTexture val6 = (RenderTexture.active = val4.ConvertToARGB32()); Texture2D val7 = new Texture2D(((Texture)texture).width, ((Texture)texture).height, texture.format, false); val7.ReadPixels(new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), 0, 0); val7.Apply(); val6.Release(); byte[] bytes = ImageConversion.EncodeToPNG(val7); File.WriteAllBytes(Path.Combine(texturesPath, ((Object)texture).name + ".png"), bytes); result = true; } catch { } RenderTexture.active = active; val4.Release(); } else { byte[] bytes2 = ImageConversion.EncodeToPNG(texture); File.WriteAllBytes(Path.Combine(texturesPath, ((Object)texture).name + ".png"), bytes2); result = true; } } catch (Exception ex4) { RHLog.Player.Error(((Object)texture).name + " failed because " + ex4.Message); } return result; } } } public static class RHConfig { internal static ConfigEntry<bool>? LoadFullAudio; internal static ConfigEntry<bool>? AlwaysDebug; internal static ConfigEntry<bool>? LazyManip; internal static void BindConfigs() { LoadFullAudio = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("General", "Load entire audio file", false, "When enabled every audio file is always fully loaded, this can reduce stutters but will slow down loading."); AlwaysDebug = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("General", "Always debug mode", false, "When enabled pack debug mode is always enabled unless toggled via the command (rhtoggledebug)."); LazyManip = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("General", "Lazy Loading", true, "When enabled every pack doesn't get reloaded when reordering or enabling/disabling packs in the settings menu."); } } public class CoroutineDispatcher : MonoBehaviour { private static CoroutineDispatcher? _instance; private static Dictionary<string, Action> updateActions = new Dictionary<string, Action>(); public static void Dispatch(IEnumerator routine) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_instance == (Object)null) { _instance = new GameObject("CoroutineDispatcher").AddComponent<CoroutineDispatcher>(); Object.DontDestroyOnLoad((Object)(object)_instance); } ((MonoBehaviour)_instance).StartCoroutine(routine); } public static string AddToUpdate(Action action) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_instance == (Object)null) { _instance = new GameObject("CoroutineDispatcher").AddComponent<CoroutineDispatcher>(); Object.DontDestroyOnLoad((Object)(object)_instance); } string text = Guid.NewGuid().ToString(); updateActions.Add(text, action); return text; } public static void RemoveFromUpdate(string guid) { if (updateActions.ContainsKey(guid)) { updateActions.Remove(guid); } } public void LateUpdate() { foreach (Action value in updateActions.Values) { value(); } } } public class DebugTools : MonoBehaviour { [CompilerGenerated] private sealed class <_queueSound>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public bool force; public AudioClip clip; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <_queueSound>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!force && _playingClips.Contains(clip)) { return false; } _playingClips.Add(clip); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; if (Object.op_Implicit((Object)(object)clip)) { _playingClips.Remove(clip); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static DebugTools? Instance; public static bool isOn = false; private static List<AudioClip> _playingClips = new List<AudioClip>(); private GUIStyle _style = GUIStyle.none; private bool _enableNextFrame; internal static void Create() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) Instance = new GameObject("DebugTools").AddComponent<DebugTools>(); Object.DontDestroyOnLoad((Object)(object)Instance); } public static void QueueSound(AudioClip clip, bool force = false) { CoroutineDispatcher.Dispatch(_queueSound(clip, force)); } [IteratorStateMachine(typeof(<_queueSound>d__7))] private static IEnumerator _queueSound(AudioClip clip, bool force) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <_queueSound>d__7(0) { clip = clip, force = force }; } public void Awake() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0035: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004f: Expected O, but got Unknown Instance = this; ConfigEntry<bool>? alwaysDebug = RHConfig.AlwaysDebug; if (alwaysDebug != null && alwaysDebug.Value) { isOn = true; } _style = new GUIStyle { fontSize = 32, fontStyle = (FontStyle)1, normal = new GUIStyleState { textColor = Color.white } }; SceneManager.sceneUnloaded += delegate { _enableNextFrame |= isOn; isOn = false; }; SceneManager.sceneLoaded += delegate(Scene arg0, LoadSceneMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)mode == 0) { _playingClips.Clear(); _enableNextFrame |= isOn; isOn = false; } }; } public void OnGUI() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!isOn) { return; } Color contentColor = GUI.contentColor; GUI.contentColor = Color.white; GUILayout.Label("Recent sounds:", _style, Array.Empty<GUILayoutOption>()); foreach (AudioClip playingClip in _playingClips) { GUILayout.Label(((Object)playingClip).name, _style, Array.Empty<GUILayoutOption>()); } GUI.contentColor = contentColor; } public void LateUpdate() { if (_enableNextFrame) { isOn = true; _enableNextFrame = false; } } } [HarmonyPatch(typeof(AudioSource))] [HarmonyPriority(200)] public static class DEBUG_AudioSourcePatches { [HarmonyPatch("set_clip")] [HarmonyPostfix] private static void Setter_Postfix(AudioSource __instance, ref AudioClip value) { if (DebugTools.isOn && !((Object)(object)value == (Object)null) && (__instance.isPlaying || (__instance.playOnAwake && Time.timeSinceLevelLoad <= 0.25f))) { DebugTools.QueueSound(value); } } [HarmonyPatch("get_clip")] [HarmonyPostfix] private static void Getter_Postfix(AudioSource __instance, ref AudioClip __result) { if (DebugTools.isOn && !((Object)(object)__result == (Object)null) && (__instance.isPlaying || (__instance.playOnAwake && Time.timeSinceLevelLoad <= 0.25f))) { DebugTools.QueueSound(__result); } } [HarmonyPatch("Play", new Type[] { typeof(double) })] [HarmonyPostfix] private static void Play_Prefix(AudioSource __instance, double delay) { if (DebugTools.isOn && !((Object)(object)__instance.clip == (Object)null)) { DebugTools.QueueSound(__instance.clip); } } [HarmonyPatch("PlayHelper", new Type[] { typeof(AudioSource), typeof(ulong) })] [HarmonyPostfix] private static void PlayHelper_Prefix(AudioSource source, ulong delay) { if (DebugTools.isOn && !((Object)(object)source.clip == (Object)null)) { DebugTools.QueueSound(source.clip); } } } public static class RHLog { public static class Player { public static void Message(string message, bool printToConsole = true) { CommandConsole.Log("[Resourceful Hands] " + message, printToConsole); } public static void Info(string message, bool printToConsole = true) { Message(message, printToConsole); } public static void Warning(string message, bool printToConsole = true) { CommandConsole.Log("[Resourceful Hands] [WARNING] " + message, printToConsole); } public static void Error(string message) { CommandConsole.LogError("[Resourceful Hands] " + message); } } private const string Prefix = "[Resourceful Hands] "; [Conditional("DEBUG")] public static void Debug(object data, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string file = "") { Plugin.Log.LogInfo((object)$"[{Path.GetFileName(file)}:{lineNumber}] {data}"); } public static void Info(object data, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string file = "") { Plugin.Log.LogInfo((object)$"[{Path.GetFileName(file)}:{lineNumber}] {data}"); } public static void Message(object data, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string file = "") { Plugin.Log.LogMessage((object)$"[{Path.GetFileName(file)}:{lineNumber}] {data}"); } public static void Warning(object data, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string file = "") { Plugin.Log.LogWarning((object)$"[{Path.GetFileName(file)}:{lineNumber}] {data}"); } public static void Error(object data, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string file = "") { Plugin.Log.LogError((object)$"[{Path.GetFileName(file)}:{lineNumber}] {data}"); } } public static class ResourcePacksManager { public static bool HasPacksChanged = true; public const string PackPrefsName = "__ResourcefulHands_Mod_PackOrder"; public const string DisabledPacksPrefsName = "__ResourcefulHands_Mod_DisabledPacks"; public static List<TexturePack> LoadedPacks { get; internal set; } = new List<TexturePack>(); public static TexturePack[] ActivePacks => LoadedPacks.Where((TexturePack pack) => pack.IsActive).ToArray(); public static Texture2D? GetTextureFromPacks(string textureName) { Texture2D val = null; TexturePack[] activePacks = ActivePacks; for (int i = 0; i < activePacks.Length; i++) { Texture2D texture = activePacks[i].GetTexture(textureName); if ((Object)(object)texture != (Object)null) { val = texture; } } if (Object.op_Implicit((Object)(object)val)) { return val; } if (textureName == "DeathFloor_02" || textureName == "_CORRUPTTEXTURE") { return Plugin.CorruptionTexture; } return null; } public static AudioClip? GetSoundFromPacks(string soundName) { AudioClip result = null; TexturePack[] activePacks = ActivePacks; for (int i = 0; i < activePacks.Length; i++) { AudioClip sound = activePacks[i].GetSound(soundName); if ((Object)(object)sound != (Object)null) { result = sound; } } return result; } internal static void SaveDisabledPacks() { List<string> list = new List<string>(); foreach (TexturePack loadedPack in LoadedPacks) { if (!loadedPack.IsActive) { list.Add(loadedPack.guid); } } string text = JsonConvert.SerializeObject((object)list.ToArray()); PlayerPrefs.SetString("__ResourcefulHands_Mod_DisabledPacks", text); } internal static void LoadDisabledPacks() { string @string = PlayerPrefs.GetString("__ResourcefulHands_Mod_DisabledPacks", ""); if (string.IsNullOrWhiteSpace(@string)) { return; } string[] array = JsonConvert.DeserializeObject<string[]>(@string); if (array == null || array.Length == 0) { return; } string[] array2 = array; foreach (string disabledPackGuid in array2) { foreach (TexturePack item in LoadedPacks.Where((TexturePack pack) => pack.guid == disabledPackGuid)) { item.IsActive = false; } } } internal static void SavePackOrder() { string[] array = new string[LoadedPacks.Count]; for (int i = 0; i < LoadedPacks.Count; i++) { TexturePack texturePack = LoadedPacks[i]; array[i] = texturePack.guid; } string text = JsonConvert.SerializeObject((object)array); PlayerPrefs.SetString("__ResourcefulHands_Mod_PackOrder", text); } internal static void LoadPackOrder() { string @string = PlayerPrefs.GetString("__ResourcefulHands_Mod_PackOrder", ""); if (string.IsNullOrWhiteSpace(@string)) { return; } string[] array = JsonConvert.DeserializeObject<string[]>(@string); if (array == null) { return; } TexturePack[] array2 = LoadedPacks.ToArray(); TexturePack[] array3 = new TexturePack[array.Length]; for (int i = 0; i < array3.Length; i++) { array3[i] = null; } for (int j = 0; j < array.Length; j++) { string guid = array[j]; TexturePack texturePack = array2.FirstOrDefault((TexturePack p) => p.guid == guid); if (texturePack != null) { array3[j] = texturePack; } } List<TexturePack> list = new List<TexturePack>(); TexturePack[] array4 = array3; foreach (TexturePack texturePack2 in array4) { if (texturePack2 != null) { list.Add(texturePack2); } } array4 = array2; foreach (TexturePack item in array4) { if (!list.Contains(item)) { list.Add(item); } } LoadedPacks = list; SavePackOrder(); } public static void ReloadPacks() { ReloadPacks_Internal(); } internal static void ReloadPacks_Internal() { HasPacksChanged = false; if (LoadedPacks.Count != 0) { SavePackOrder(); SaveDisabledPacks(); } LoadedPacks.Clear(); RHLog.Info("Expanding zips...", 137, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); string[] files = Directory.GetFiles(Plugin.ConfigFolder, "*.zip", SearchOption.TopDirectoryOnly); foreach (string text in files) { try { RHLog.Info("Expanding texture pack zip: " + text, 143, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); bool flag = true; using (ZipArchive zipArchive = ZipFile.OpenRead(text)) { flag = zipArchive.GetEntry("info.json") != null; } if (flag) { DirectoryInfo directoryInfo = Directory.CreateDirectory(Path.Combine(Plugin.ConfigFolder, Path.GetFileNameWithoutExtension(text))); ZipFile.ExtractToDirectory(text, directoryInfo.FullName); } else { ZipFile.ExtractToDirectory(text, Plugin.ConfigFolder); } File.Delete(text); RHLog.Info("Expanded!", 157, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); } catch (Exception data) { RHLog.Info("Failed to expand!", 161, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); RHLog.Error(data, 162, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); } } RHLog.Info("Loading texture packs...", 165, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); List<string> list = new List<string>(); list.AddRange(Directory.GetDirectories(Plugin.ConfigFolder, "*", SearchOption.TopDirectoryOnly)); list.AddRange(Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly)); foreach (string item in list) { if (!File.Exists(Path.Combine(item, "info.json"))) { continue; } try { RHLog.Info("Loading texture pack: " + item, 178, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); TexturePack texturePack = TexturePack.Load(item); if (texturePack == null) { RHLog.Warning("Failed to load pack at " + item + "!", 182, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); continue; } LoadedPacks.Add(texturePack); RHLog.Info("Loaded!", 187, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); } catch (Exception data2) { RHLog.Info("Failed to load!", 191, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); RHLog.Error(data2, 192, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); } } RHLog.Info("Re-ordering to user order...", 196, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); LoadPackOrder(); RHLog.Info("Disabling packs that should be disabled...", 198, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); LoadDisabledPacks(); RHLog.Info($"Loaded {LoadedPacks.Count}/{list.Count} texture packs", 201, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\ResourcePacksManager.cs"); Plugin.RefreshTextures(); Plugin.RefreshSounds(); if ((Object)(object)UI_RHPacksList.Instance != (Object)null) { UI_RHPacksList.Instance?.BuildList(); } } } public class StreamedAudioClip { private int _position; private int _sampleRate; private int _channels; private float[] _samples = Array.Empty<float>(); public AudioClip clip { get; private set; } public string path { get; private set; } public StreamedAudioClip(string fileName) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_0099: Expected O, but got Unknown path = fileName; int num = 0; AudioFileReader val = new AudioFileReader(path); try { _sampleRate = ((WaveStream)val).WaveFormat.SampleRate; _channels = ((WaveStream)val).WaveFormat.Channels; num = (int)(((Stream)(object)val).Length / 4); } finally { ((IDisposable)val)?.Dispose(); } int num2 = num / _channels; clip = AudioClip.Create("MemoryStreamedAudioClip", num2, _channels, _sampleRate, true, new PCMReaderCallback(OnAudioRead), new PCMSetPositionCallback(OnAudioSetPosition)); ConfigEntry<bool>? loadFullAudio = RHConfig.LoadFullAudio; if (loadFullAudio != null && loadFullAudio.Value) { LoadFile(); } } public void LoadFile() { int sampleRate; int channels; float[] samples = MiscUtils.LoadAudioFile(path, out sampleRate, out channels); _sampleRate = sampleRate; _channels = channels; _samples = samples; } private void OnAudioRead(float[] data) { if (_samples.Length == 0) { LoadFile(); } int num = data.Length; int num2 = _samples.Length - _position; int num3 = Mathf.Min(num, num2); Array.Copy(_samples, _position, data, 0, num3); for (int i = num3; i < num; i++) { data[i] = 0f; } _position += num3; } private void OnAudioSetPosition(int newPosition) { _position = newPosition; } } [Serializable] public class TexturePack { public string name = string.Empty; public string desc = string.Empty; public string author = string.Empty; [JsonProperty(/*Could not decode attribute arguments.*/)] public ulong steamid; [JsonProperty(/*Could not decode attribute arguments.*/)] public string guid = string.Empty; [JsonProperty(/*Could not decode attribute arguments.*/)] public bool hiddenFromList; [JsonProperty(/*Could not decode attribute arguments.*/)] public bool onlyInFullGame; [JsonProperty(/*Could not decode attribute arguments.*/)] public string relativeTexturesPath = "Textures"; [JsonProperty(/*Could not decode attribute arguments.*/)] public string relativeSoundsPath = "Sounds"; [JsonProperty(/*Could not decode attribute arguments.*/)] public string relativeIconPath = "pack.png"; [JsonProperty(/*Could not decode attribute arguments.*/)] public int texturePackVersion = 2; [NonSerialized] [JsonIgnore] public const int CurrentFormatVersion = 2; [NonSerialized] [JsonIgnore] public bool IsActive = true; [NonSerialized] [JsonIgnore] public Dictionary<string, Texture2D> Textures = new Dictionary<string, Texture2D>(); [NonSerialized] [JsonIgnore] public Dictionary<string, AudioClip> Sounds = new Dictionary<string, AudioClip>(); [NonSerialized] [JsonIgnore] protected List<StreamedAudioClip> RawSounds = new List<StreamedAudioClip>(); [NonSerialized] [JsonIgnore] public const string DefaultJson = "{\r\n \"name\":\"generated-game-assets\",\r\n \"desc\":\"Every game asset\",\r\n \r\n \"author\":\"Dark Machine Games\",\r\n \"steamid\":0,\r\n \r\n \"guid\":\"generated-game-assets\",\r\n \r\n \"hidden-from-list\":true,\r\n \"only-in-full-game\":false,\r\n \r\n \"textures-folder\":\"Textures\",\r\n \"sounds-folder\":\"Sounds\",\r\n \"icon-file\":\"pack.png\",\r\n \r\n \"format-version\":2\r\n} "; [JsonIgnore] public Texture2D Icon { get; private set; } public Texture2D? GetTexture(string textureName) { Textures.TryGetValue(textureName, out Texture2D value); return value; } public AudioClip? GetSound(string soundName) { Sounds.TryGetValue(soundName, out AudioClip value); return value; } public static TexturePack? Load(string path, bool force = false) { //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(path, "info.json"); if (!File.Exists(text)) { RHLog.Warning(path + " doesn't have an info.json!", 133, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); return null; } TexturePack texturePack = JsonConvert.DeserializeObject<TexturePack>(File.ReadAllText(text)); if (texturePack == null) { RHLog.Warning(text + " isn't a valid TexturePack json!", 139, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); RHLog.Info("Example: {\r\n \"name\":\"generated-game-assets\",\r\n \"desc\":\"Every game asset\",\r\n \r\n \"author\":\"Dark Machine Games\",\r\n \"steamid\":0,\r\n \r\n \"guid\":\"generated-game-assets\",\r\n \r\n \"hidden-from-list\":true,\r\n \"only-in-full-game\":false,\r\n \r\n \"textures-folder\":\"Textures\",\r\n \"sounds-folder\":\"Sounds\",\r\n \"icon-file\":\"pack.png\",\r\n \r\n \"format-version\":2\r\n} ", 140, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); return null; } if (!force) { if (texturePack.hiddenFromList) { RHLog.Info("Not loading texture pack at " + path + " because it is hidden.", 147, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); return null; } if (texturePack.onlyInFullGame && Plugin.IsDemo) { RHLog.Info("Skipping incompatible texture pack (it says it only works for the fullgame): " + path, 152, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); return null; } } if (texturePack.texturePackVersion != 2) { RHLog.Warning($"Texture pack at {path} is format version {texturePack.texturePackVersion} which isn't {2} (the current version), it may not function correctly.", 158, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); } string text2 = Path.Combine(path, texturePack.relativeIconPath); if (!File.Exists(text2)) { RHLog.Warning(path + " doesn't have an pack.png! (icon path: '" + texturePack.relativeIconPath + "')", 163, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); texturePack.Icon = (Texture2D)(((object)Plugin.IconGray) ?? ((object)new Texture2D(2, 2))); } else { byte[] array = File.ReadAllBytes(text2); Texture2D val = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val, array, false)) { RHLog.Warning(text2 + " isn't a valid texture!", 172, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); try { Object.Destroy((Object)(object)val); } catch { } } else { ((Object)val).name = Path.GetFileNameWithoutExtension(text2); ((Texture)val).filterMode = (FilterMode)0; val.Apply(); texturePack.Icon = val; } } string text3 = texturePack.guid; if (string.IsNullOrWhiteSpace(texturePack.guid)) { texturePack.guid = texturePack.author.ToLower() + "." + texturePack.name.ToLower(); } texturePack.guid = MiscUtils.CleanString(texturePack.guid.Replace(' ', '_')); if (texturePack.guid != text3) { string contents = JsonConvert.SerializeObject((object)texturePack); File.WriteAllText(text, contents); RHLog.Warning("Corrected " + texturePack.name + "'s guid: " + text3 + " -> " + texturePack.guid, 193, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); } RHLog.Info("Texture pack at " + path + " is valid, loading assets...", 196, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); string path2 = Path.Combine(path, texturePack.relativeTexturesPath); string path3 = Path.Combine(path, texturePack.relativeSoundsPath); string[] array2 = Array.Empty<string>(); string[] array3 = Array.Empty<string>(); if (Directory.Exists(path2)) { array2 = Directory.GetFiles(path2, "*.*", SearchOption.AllDirectories); } if (Directory.Exists(path3)) { array3 = Directory.GetFiles(path3, "*.*", SearchOption.AllDirectories); } int num = array2.Length; int num2 = array3.Length; int num3 = 0; string[] array4 = array2; foreach (string text4 in array4) { RHLog.Info($"Loading textures ({num3++}/{num})", 214, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); string text5 = Path.GetExtension(text4).ToLower(); if (!text5.Contains("png") && !text5.Contains("jpg")) { RHLog.Warning(text5 + " isn't supported! Only png and jpg files are supported! [at: " + text4 + "]", 218, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); continue; } byte[] array5 = File.ReadAllBytes(text4); Texture2D val2 = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val2, array5, false)) { RHLog.Warning(text4 + " isn't a valid texture!", 225, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); try { Object.Destroy((Object)(object)val2); } catch { } continue; } ((Object)val2).name = Path.GetFileNameWithoutExtension(text4); ((Texture)val2).filterMode = (FilterMode)0; val2.Apply(); if (!texturePack.Textures.TryAdd(((Object)val2).name, val2)) { RHLog.Error("Failed to add " + text4 + " because texture of that name already exists in the same pack!", 233, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); } } num3 = 0; new ConcurrentStack<Tuple<int, int, float[], string>>(); new List<Task>(); array4 = array3; foreach (string text6 in array4) { RHLog.Info($"Queuing sounds ({num3++}/{num2})", 242, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); string text7 = Path.GetExtension(text6).ToLower(); if (text7.Contains("ogg")) { RHLog.Warning(text7 + " isn't supported! Only mp3, wav, aiff, wma, acc files are supported! [at: " + text6 + "]", 246, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); continue; } StreamedAudioClip streamedAudioClip = new StreamedAudioClip(text6); texturePack.RawSounds.Add(streamedAudioClip); AudioClip clip = streamedAudioClip.clip; ((Object)clip).name = Path.GetFileNameWithoutExtension(text6); if (!texturePack.Sounds.TryAdd(((Object)clip).name, clip)) { RHLog.Error("Failed to add " + text6 + " because texture of that name already exists in the same pack!", 256, "C:\\Dev\\VSProjects\\ResourcefulHands\\Types\\TexturePack.cs"); } } return texturePack; } } public class UI_RHPack : MonoBehaviour { public RawImage? Icon; public TextMeshProUGUI? Title; public TextMeshProUGUI? Author; public Button? SteamAuthor; public TextMeshProUGUI? Description; public TextMeshProUGUI? Guid; public Button? Up; public Button? Down; public Button? EnableToggle; public Image? EnableOn; public Image? EnableOff; private TexturePack _pack; private T? FindAt<T>(string path) where T : Component { Transform val = ((Component)this).transform; string[] array = path.Split('/'); foreach (string text in array) { val = val.Find(text); if ((Object)(object)val == (Object)null) { return default(T); } } return ((Component)val).GetComponentInChildren<T>(); } public void Awake() { Icon = FindAt<RawImage>("IconContainer/Icon"); Title = FindAt<TextMeshProUGUI>("Title"); Author = FindAt<TextMeshProUGUI>("AuthorPanel/Author"); SteamAuthor = FindAt<Button>("AuthorPanel/ViewOnSteam"); Description = FindAt<TextMeshProUGUI>("Desc"); Guid = FindAt<TextMeshProUGUI>("Guid"); Up = FindAt<Button>("Up/Arrow"); Down = FindAt<Button>("Down/Arrow"); EnableToggle = FindAt<Button>("Disable"); EnableOff = FindAt<Image>("Disable/Toggle/OffImg"); EnableOn = FindAt<Image>("Disable/Toggle/ToggleImg"); } public void Load(TexturePack pack, bool active = true) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown TexturePack pack2 = pack; _pack = pack2; Icon.texture = (Texture)(object)_pack.Icon; ((TMP_Text)Title).text = _pack.name; ((TMP_Text)Author).text = _pack.author; ((TMP_Text)Description).text = _pack.desc; ((TMP_Text)Guid).text = _pack.guid; ((Behaviour)EnableOff).enabled = !active; ((Behaviour)EnableOn).enabled = active; if (pack2.steamid != 0) { Button? steamAuthor = SteamAuthor; if (steamAuthor != null) { ((UnityEvent)steamAuthor.onClick).AddListener((UnityAction)delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) SteamFriends.OpenUserOverlay(SteamId.op_Implicit(pack2.steamid), "steamid"); }); } } else { Button? steamAuthor2 = SteamAuthor; if (steamAuthor2 != null) { ((Component)steamAuthor2).gameObject.SetActive(false); } } ((UnityEvent)Up.onClick).AddListener((UnityAction)delegate { RHCommands.MovePack(_pack, isUp: true); UI_RHPacksList.Instance?.BuildList(); ConfigEntry<bool>? lazyManip3 = RHConfig.LazyManip; if (lazyManip3 != null && lazyManip3.Value) { Plugin.RefreshTextures(); Plugin.RefreshSounds(); } else { ResourcePacksManager.ReloadPacks_Internal(); } }); ((UnityEvent)Down.onClick).AddListener((UnityAction)delegate { RHCommands.MovePack(_pack, isUp: false); UI_RHPacksList.Instance?.BuildList(); ConfigEntry<bool>? lazyManip2 = RHConfig.LazyManip; if (lazyManip2 != null && lazyManip2.Value) { Plugin.RefreshTextures(); Plugin.RefreshSounds(); } else { ResourcePacksManager.ReloadPacks_Internal(); } }); ((UnityEvent)EnableToggle.onClick).AddListener((UnityAction)delegate { _pack.IsActive = !_pack.IsActive; UI_RHPacksList.Instance?.BuildList(); ConfigEntry<bool>? lazyManip = RHConfig.LazyManip; if (lazyManip != null && lazyManip.Value) { Plugin.RefreshTextures(); Plugin.RefreshSounds(); } else { ResourcePacksManager.ReloadPacks_Internal(); } }); } } public class UI_RHPacksList : MonoBehaviour { [CompilerGenerated] private sealed class <EnableCoroutine>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public UI_RHPacksList <>4__this; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnableCoroutine>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown int num = <>1__state; UI_RHPacksList uI_RHPacksList = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; Transform? container2 = uI_RHPacksList.container; if (container2 != null) { ((Component)container2).gameObject.SetActive(false); } <>2__current = (object)new WaitForSecondsRealtime(0.075f); <>1__state = 1; return true; } case 1: { <>1__state = -1; Transform? container = uI_RHPacksList.container; if (container != null) { ((Component)container).gameObject.SetActive(true); } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static UI_RHPacksList? Instance; public ScrollRect? scrollRect; public Transform? container; public UI_RHPack? packTemplate; public void Awake() { Instance = this; scrollRect = ((Component)this).GetComponentInChildren<ScrollRect>(); container = (Transform?)(object)scrollRect.content; packTemplate = ((Component)container.Find("Pack")).gameObject.AddComponent<UI_RHPack>(); ((Component)packTemplate).gameObject.SetActive(false); } [IteratorStateMachine(typeof(<EnableCoroutine>d__5))] private IEnumerator EnableCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnableCoroutine>d__5(0) { <>4__this = this }; } public void OnEnable() { BuildList(); CoroutineDispatcher.Dispatch(EnableCoroutine()); } private void ClearList() { if ((Object)(object)container == (Object)null || (Object)(object)packTemplate == (Object)null) { return; } for (int i = 0; i < container.childCount; i++) { Transform child = container.GetChild(i); if (!((Object)(object)child == (Object)(object)((Component)packTemplate).transform)) { Object.Destroy((Object)(object)((Component)child).gameObject); } } } public void BuildList() { ClearList(); foreach (TexturePack loadedPack in ResourcePacksManager.LoadedPacks) { UI_RHPack uI_RHPack = Object.Instantiate<UI_RHPack>(packTemplate, container); if (!((Object)(object)uI_RHPack == (Object)null)) { TexturePack pack1 = loadedPack; uI_RHPack.Load(loadedPack, ResourcePacksManager.ActivePacks.FirstOrDefault((TexturePack p) => p == pack1) != null); ((Object)((Component)uI_RHPack).gameObject).name = loadedPack.guid; ((Component)uI_RHPack).gameObject.SetActive(true); } } } } } namespace ResourcefulHands.Patches { [HarmonyPatch(typeof(Image))] public static class ImagePatches { [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] public static void Getter_sprite_Postfix(Image __instance, ref Sprite __result) { if (!((Object)(object)__result == (Object)null)) { __result = SpriteRendererPatches.GetSprite(__result); } } } [HarmonyPatch(typeof(SpriteRenderer))] public static class SpriteRendererPatches { private static bool dontPatch = false; internal static Dictionary<string, Sprite> _customSpriteCache { get; private set; } = new Dictionary<string, Sprite>(); public static Sprite? GetSprite(Sprite sprite) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sprite == (Object)null) { return sprite; } bool num = ((Object)sprite).name.EndsWith(" [modified asset]"); string text = ((Object)sprite).name; if (num) { text = text.Substring(0, text.Length - " [modified asset]".Length); } if (_customSpriteCache.TryGetValue(text, out Sprite value)) { if ((Object)(object)value != (Object)null) { return value; } _customSpriteCache.Remove(text); } Texture2D textureFromPacks = ResourcePacksManager.GetTextureFromPacks(((Object)sprite.texture).name); if ((Object)(object)textureFromPacks == (Object)null) { return sprite; } Rect rect = sprite.rect; float num2 = Mathf.Clamp(((Rect)(ref rect)).x, 0f, (float)((Texture)textureFromPacks).width); rect = sprite.rect; float num3 = Mathf.Clamp(((Rect)(ref rect)).y, 0f, (float)((Texture)textureFromPacks).height); rect = sprite.rect; float num4 = Mathf.Clamp(((Rect)(ref rect)).width, 0f, (float)((Texture)textureFromPacks).width - num2); rect = sprite.rect; float num5 = Mathf.Clamp(((Rect)(ref rect)).height, 0f, (float)((Texture)textureFromPacks).height - num3); Rect val = new Rect(num2, num3, num4, num5); float x = sprite.pivot.x; rect = sprite.rect; float num6 = x / ((Rect)(ref rect)).width; float y = sprite.pivot.y; rect = sprite.rect; Sprite val2 = Sprite.Create(textureFromPacks, val, new Vector2(num6, y / ((Rect)(ref rect)).height), sprite.pixelsPerUnit); ((Object)val2).name = text + " [modified asset]"; _customSpriteCache.Add(text, val2); return val2; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void Constructor_Postfix(SpriteRenderer __instance) { __instance.sprite = __instance.sprite; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void Getter_Postfix(SpriteRenderer __instance, ref Sprite __result) { if (dontPatch) { dontPatch = false; return; } __result = GetSprite(__result); dontPatch = true; __instance.sprite = __result; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void Setter_Prefix(SpriteRenderer __instance, ref Sprite value) { if (dontPatch) { dontPatch = false; return; } value = GetSprite(value); dontPatch = true; __instance.sprite = value; } } [HarmonyPatch(typeof(AudioSource))] public static class AudioSourcePatches { private static bool dontPatch; [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void Constructor_Postfix(AudioSource __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.clip == (Object)null) { return; } AudioClip soundFromPacks = ResourcePacksManager.GetSoundFromPacks(((Object)__instance.clip).name); if ((Object)(object)soundFromPacks != (Object)null) { __instance.clip = soundFromPacks; if (__instance.playOnAwake && Time.timeSinceLevelLoad <= 0.25f && !__instance.isPlaying) { dontPatch = true; __instance.Play(); } } } [HarmonyPatch("set_clip")] [HarmonyPostfix] private static void Setter_Postfix(AudioSource __instance, ref AudioClip value) { if (dontPatch) { dontPatch = false; } else { if ((Object)(object)value == (Object)null) { return; } AudioClip soundFromPacks = ResourcePacksManager.GetSoundFromPacks(((Object)value).name); if (!((Object)(object)soundFromPacks != (Object)null)) { return; } dontPatch = true; __instance.clip = soundFromPacks; value = soundFromPacks; if (__instance.playOnAwake && Time.timeSinceLevelLoad <= 0.25f && !__instance.isPlaying) { dontPatch = true; if (((Behaviour)__instance).enabled) { __instance.Play(); } } } } [HarmonyPatch("get_clip")] [HarmonyPostfix] private static void Getter_Postfix(AudioSource __instance, ref AudioClip __result) { if (dontPatch) { dontPatch = false; } else { if ((Object)(object)__result == (Object)null) { return; } AudioClip soundFromPacks = ResourcePacksManager.GetSoundFromPacks(((Object)__result).name); if (!((Object)(object)soundFromPacks != (Object)null)) { return; } dontPatch = true; __instance.clip = soundFromPacks; __result = soundFromPacks; if (__instance.playOnAwake && Time.timeSinceLevelLoad <= 0.25f && !__instance.isPlaying) { dontPatch = true; if (((Behaviour)__instance).enabled) { __instance.Play(); } } } } [HarmonyPatch("Play", new Type[] { typeof(double) })] [HarmonyPostfix] private static void Play_Prefix(AudioSource __instance, double delay) { if (dontPatch) { dontPatch = false; } else if (!((Object)(object)__instance.clip == (Object)null)) { __instance.clip = __instance.clip; } } [HarmonyPatch("PlayHelper", new Type[] { typeof(AudioSource), typeof(ulong) })] [HarmonyPostfix] private static void PlayHelper_Prefix(AudioSource source, ulong delay) { if (dontPatch) { dontPatch = false; } else if (!((Object)(object)source.clip == (Object)null)) { source.clip = source.clip; } } } [HarmonyPatch(typeof(Material))] public static class MaterialPatches { private static bool dontPatch = false; internal static Dictionary<string, Texture> previousTextures = new Dictionary<string, Texture>(); private static readonly int MainTex = Shader.PropertyToID("_MainTex"); public static void SetMainTexture(Material m, Texture texture) { dontPatch = true; m.mainTexture = texture; } public static Texture GetMainTexture(Material m) { dontPatch = true; return m.mainTexture; } [HarmonyPatch("get_mainTexture")] [HarmonyPostfix] private static void Getter_Postfix(Material __instance, ref Texture __result) { if (dontPatch) { dontPatch = false; } else { if ((Object)(object)__instance == (Object)null || !__instance.HasTexture(MainTex)) { return; } dontPatch = true; Texture mainTexture = __instance.mainTexture; if (!((Object)(object)mainTexture == (Object)null)) { Texture2D textureFromPacks = ResourcePacksManager.GetTextureFromPacks(((Object)mainTexture).name); if (!((Object)(object)textureFromPacks == (Object)null)) { ((Object)textureFromPacks).name = ((Object)mainTexture).name + " [replaced]"; previousTextures.TryAdd(((Object)mainTexture).name, mainTexture); __instance.mainTexture = (Texture)(object)textureFromPacks; } } } } [HarmonyPatch("set_mainTexture")] [HarmonyPostfix] private static void Setter_Prefix(Material __instance, ref Texture value) { if (dontPatch) { dontPatch = false; } else { if ((Object)(object)__instance == (Object)null || !__instance.HasTexture(MainTex)) { return; } dontPatch = true; Texture mainTexture = __instance.mainTexture; if (!((Object)(object)mainTexture == (Object)null)) { Texture2D textureFromPacks = ResourcePacksManager.GetTextureFromPacks(((Object)mainTexture).name); if (!((Object)(object)textureFromPacks == (Object)null)) { ((Object)textureFromPacks).name = ((Object)mainTexture).name + " [replaced]"; previousTextures.TryAdd(((Object)mainTexture).name, mainTexture); __instance.mainTexture = (Texture)(object)textureFromPacks; } } } } } [HarmonyPatch(typeof(Renderer))] public static class RendererPatches { private static readonly int MainTex = Shader.PropertyToID("_MainTex"); [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void Constructor_Postfix(Renderer __instance) { Material[] sharedMaterials = __instance.sharedMaterials; foreach (Material val in sharedMaterials) { if (val.HasProperty(MainTex)) { _ = val.mainTexture; } } } public static void Patch(ref Material material) { if (!((Object)(object)material == (Object)null) && material.HasProperty(MainTex)) { _ = material.mainTexture; } } [HarmonyPatch("get_material")] [HarmonyPostfix] private static void Getter_material_Postfix(Renderer __instance, ref Material __result) { Patch(ref __result); } [HarmonyPatch("set_material")] [HarmonyPostfix] private static void Setter_material_Prefix(Renderer __instance, ref Material value) { Patch(ref value); } [HarmonyPatch("get_materials")] [HarmonyPostfix] private static void Getter_materials_Postfix(Renderer __instance, ref Material[] __result) { for (int i = 0; i < __result.Length; i++) { Patch(ref __result[i]); } } [HarmonyPatch("set_materials")] [HarmonyPostfix] private static void Setter_materials_Prefix(Renderer __instance, ref Material[] value) { for (int i = 0; i < value.Length; i++) { Patch(ref value[i]); } } [HarmonyPatch("get_sharedMaterial")] [HarmonyPostfix] private static void Getter_sharedMaterial_Postfix(Renderer __instance, ref Material __result) { Patch(ref __result); } [HarmonyPatch("set_sharedMaterial")] [HarmonyPostfix] private static void Setter_sharedMaterial_Prefix(Renderer __instance, ref Material value) { Patch(ref value); } [HarmonyPatch("get_sharedMaterials")] [HarmonyPostfix] private static void Getter_sharedMaterials_Postfix(Renderer __instance, ref Material[] __result) { for (int i = 0; i < __result.Length; i++) { Patch(ref __result[i]); } } [HarmonyPatch("set_sharedMaterials")] [HarmonyPostfix] private static void Setter_sharedMaterials_Prefix(Renderer __instance, ref Material[] value) { for (int i = 0; i < value.Length; i++) { Patch(ref value[i]); } } } }