Decompiled source of NAudioLame v2.1.1

BepInEx/core/NAudio.Lame.dll

Decompiled 4 months ago
using System;
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.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using LameDLLWrap;
using NAudio.Lame;
using NAudio.Wave;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Corey Murtagh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2013-2023 Corey Murtagh")]
[assembly: AssemblyDescription("Uses libmp3lame.dll from the Lame project to provide MP3 encoding support to NAudio.  Both 64-bit and 32-bit versions of libmp3lame.dll are provided, with platform detection to determine which to use.")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0+5b5bb009d8c63ef8ab95cb36ca9105c8acc1c5fc")]
[assembly: AssemblyProduct("NAudio.Lame")]
[assembly: AssemblyTitle("NAudio.Lame")]
[assembly: AssemblyVersion("2.1.0.0")]
internal class <Module>
{
	static <Module>()
	{
		ModuleInitializer.Initialize();
	}
}
namespace NAudio.Lame;

public static class ID3Decoder
{
	private class ID3FrameData
	{
		private delegate string delGetString(byte[] buffer, ref int offset, bool requireTeminator);

		public class APICData
		{
			public string MIMEType;

			public byte ImageType;

			public string Description;

			public byte[] ImageBytes;
		}

		public readonly string FrameID;

		public readonly int Size;

		public readonly short Flags;

		public readonly byte[] Data;

		private ID3FrameData(string frameID, int size, short flags, byte[] data)
		{
			FrameID = frameID;
			Size = size;
			Flags = flags;
			Data = data;
		}

		public static ID3FrameData ReadFrame(byte[] buffer, int offset, out int size)
		{
			size = -1;
			if (buffer.Length - offset <= 10)
			{
				return null;
			}
			string @string = Encoding.ASCII.GetString(buffer, offset, 4);
			int num = DecodeBEInt32(buffer, offset + 4);
			short num2 = DecodeBEInt16(buffer, offset + 8);
			byte[] array = new byte[num];
			Array.Copy(buffer, offset + 10, array, 0, num);
			if (((uint)num2 & 0x80u) != 0)
			{
				using MemoryStream memoryStream = new MemoryStream();
				using DeflateStream deflateStream = new DeflateStream(new MemoryStream(array), CompressionMode.Decompress);
				deflateStream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			size = 10 + num;
			return new ID3FrameData(@string, num, num2, array);
		}

		private static string GetASCIIString(byte[] buffer, ref int offset, bool requireTerminator)
		{
			int num = offset;
			int i;
			for (i = offset; i < buffer.Length && buffer[i] != 0; i++)
			{
			}
			if (requireTerminator && i >= buffer.Length)
			{
				return null;
			}
			int num2 = i - num;
			offset = i + 1;
			if (num2 >= 1)
			{
				return Encoding.ASCII.GetString(buffer, num, num2);
			}
			return string.Empty;
		}

		private static string GetUnicodeString(byte[] buffer, ref int offset, bool requireTerminator = true)
		{
			int num = offset;
			int i;
			for (i = offset; i < buffer.Length - 1 && (buffer[i] != 0 || buffer[i + 1] != 0); i += 2)
			{
			}
			if (requireTerminator && i >= buffer.Length)
			{
				return null;
			}
			int num2 = i - num;
			offset = i + 2;
			return UCS2.GetString(buffer, num, num2);
		}

		private delGetString GetGetString()
		{
			byte b = Data[0];
			return b switch
			{
				0 => GetASCIIString, 
				1 => GetUnicodeString, 
				_ => throw new InvalidDataException($"Invalid string encoding: {b}"), 
			};
		}

		public string ParseString()
		{
			int offset = 1;
			return GetGetString()(Data, ref offset, requireTeminator: false);
		}

		public string ParseCommentText()
		{
			delGetString getString = GetGetString();
			int num = 1;
			Encoding.ASCII.GetString(Data, num, 3);
			num += 3;
			getString(Data, ref num, requireTeminator: true);
			return getString(Data, ref num, requireTeminator: false);
		}

		public KeyValuePair<string, string> ParseUserDefinedText()
		{
			byte b = Data[0];
			delGetString delGetString = b switch
			{
				0 => GetASCIIString, 
				1 => GetUnicodeString, 
				_ => throw new InvalidDataException($"Unknown string encoding: {b}"), 
			};
			int offset = 1;
			string key = delGetString(Data, ref offset, requireTeminator: true);
			string value = delGetString(Data, ref offset, requireTeminator: false);
			return new KeyValuePair<string, string>(key, value);
		}

		public APICData ParseAPIC()
		{
			if (FrameID != "APIC")
			{
				return null;
			}
			delGetString getString = GetGetString();
			int offset = 1;
			string mIMEType = getString(Data, ref offset, requireTeminator: true);
			byte imageType = Data[offset++];
			string description = getString(Data, ref offset, requireTeminator: true);
			int num = Data.Length - offset;
			byte[] array = new byte[num];
			Array.Copy(Data, offset, array, 0, num);
			return new APICData
			{
				MIMEType = mIMEType,
				ImageType = imageType,
				Description = description,
				ImageBytes = array
			};
		}
	}

	public static ID3TagData Decode(Stream stream)
	{
		byte[] array = new byte[10];
		if (stream.Read(array, 0, 10) != 10 || !ValidateTagHeader(array))
		{
			throw new InvalidDataException("Bad ID3 Tag Header");
		}
		int num = DecodeHeaderSize(array, 6);
		if (num < 10 || num >= 268435456)
		{
			throw new InvalidDataException($"ID3 header size '{num:#,0}' out of range.");
		}
		byte[] array2 = new byte[10 + num];
		stream.Read(array2, 0, array2.Length);
		return InternalDecode(array2, 0, num, array[5]);
	}

	public static ID3TagData Decode(byte[] buffer)
	{
		if (!ValidateTagHeader(buffer))
		{
			throw new InvalidDataException("Bad ID3 Tag Header");
		}
		int num = DecodeHeaderSize(buffer, 6);
		if (num < 10 || num > buffer.Length - 10)
		{
			throw new InvalidDataException($"ID3 header size '{num:#,0}' out of range.");
		}
		return InternalDecode(buffer, 10, num, buffer[5]);
	}

	private static ID3TagData InternalDecode(byte[] buffer, int offset, int size, byte flags)
	{
		byte[] array = new byte[size];
		Array.Copy(buffer, offset, array, 0, size);
		if ((flags & 0x80u) != 0)
		{
			array = UnsyncBytes(array);
		}
		ID3TagData iD3TagData = new ID3TagData();
		int num = 0;
		if ((flags & 0x40u) != 0)
		{
			int num2 = DecodeBEInt32(array, num);
			num += num2 + 4;
		}
		int size2;
		ID3FrameData iD3FrameData = ID3FrameData.ReadFrame(array, num, out size2);
		while (size2 > 0 && iD3FrameData != null)
		{
			switch (iD3FrameData.FrameID)
			{
			case "TIT2":
				iD3TagData.Title = iD3FrameData.ParseString();
				break;
			case "TPE1":
				iD3TagData.Artist = iD3FrameData.ParseString();
				break;
			case "TALB":
				iD3TagData.Album = iD3FrameData.ParseString();
				break;
			case "TYER":
				iD3TagData.Year = iD3FrameData.ParseString();
				break;
			case "COMM":
				iD3TagData.Comment = iD3FrameData.ParseCommentText();
				break;
			case "TCON":
				iD3TagData.Genre = iD3FrameData.ParseString();
				break;
			case "TRCK":
				iD3TagData.Track = iD3FrameData.ParseString();
				break;
			case "TIT3":
				iD3TagData.Subtitle = iD3FrameData.ParseString();
				break;
			case "TPE2":
				iD3TagData.AlbumArtist = iD3FrameData.ParseString();
				break;
			case "TXXX":
			{
				KeyValuePair<string, string> keyValuePair = iD3FrameData.ParseUserDefinedText();
				iD3TagData.UserDefinedText[keyValuePair.Key] = keyValuePair.Value;
				break;
			}
			case "APIC":
				iD3TagData.AlbumArt = iD3FrameData.ParseAPIC()?.ImageBytes;
				break;
			}
			num += size2;
			iD3FrameData = ID3FrameData.ReadFrame(array, num, out size2);
		}
		return iD3TagData;
	}

	private static bool ValidateTagHeader(byte[] buffer)
	{
		if (buffer != null && buffer.Length >= 4 && buffer[0] == 73 && buffer[1] == 68 && buffer[2] == 51 && buffer[3] == 3)
		{
			return buffer[4] == 0;
		}
		return false;
	}

	private static int DecodeHeaderSize(byte[] buffer, int offset)
	{
		return (buffer[offset] << 21) | (buffer[offset + 1] << 14) | (buffer[offset + 2] << 7) | buffer[offset + 3];
	}

	private static short DecodeBEInt16(byte[] buffer, int offset)
	{
		return (short)((buffer[offset] << 8) | buffer[offset + 1]);
	}

	private static int DecodeBEInt32(byte[] buffer, int offset)
	{
		return (buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3];
	}

	private static byte[] UnsyncBytes(IEnumerable<byte> buffer)
	{
		return ProcessBuffer().ToArray();
		IEnumerable<byte> ProcessBuffer()
		{
			byte b2 = 0;
			foreach (byte b in buffer)
			{
				if (b != 0 || b2 != byte.MaxValue)
				{
					yield return b;
				}
				b2 = b;
			}
		}
	}
}
public class ID3TagData
{
	public string Title;

	public string Artist;

	public string Album;

	public string Year;

	public string Comment;

	public string Genre;

	public string Track;

	public string Subtitle;

	public string AlbumArtist;

	public byte[] AlbumArt;

	[Obsolete("Use the UserDefinedText property instead.", false)]
	public string[] UserDefinedTags
	{
		get
		{
			return UserDefinedText.Select((KeyValuePair<string, string> kv) => kv.Key + "=" + kv.Value).ToArray();
		}
		set
		{
			SetUDT(value);
		}
	}

	public bool V2Only { get; set; } = true;


	public Dictionary<string, string> CustomFields { get; } = new Dictionary<string, string>();


	public Dictionary<string, string> UserDefinedText { get; } = new Dictionary<string, string>();


	public void SetUDT(IEnumerable<string> data)
	{
		UserDefinedText.Clear();
		foreach (string datum in data)
		{
			string text = datum.Split(new char[1] { '=' }).First();
			int num = text.Length + 1;
			string value = ((num > datum.Length) ? string.Empty : datum.Substring(num));
			UserDefinedText[text] = value;
		}
	}
}
public class LameConfig
{
	private LAMEPreset? _preset;

	private int? _bitrate;

	private int? _vbrquality;

	public LAMEPreset? Preset
	{
		get
		{
			return _preset;
		}
		set
		{
			_preset = value;
			if (value.HasValue)
			{
				_bitrate = null;
			}
		}
	}

	public int? BitRate
	{
		get
		{
			return _bitrate;
		}
		set
		{
			_bitrate = value;
			if (value.HasValue)
			{
				_preset = null;
			}
		}
	}

	public int? OutputSampleRate { get; set; }

	public VBRMode? VBR { get; set; }

	public int? ABRRateKbps { get; set; }

	public int? VBRMinimumRateKbps { get; set; }

	public int? VBRMaximumRateKbps { get; set; }

	public bool? VBREnforceMinimum { get; set; }

	public int? VBRQuality
	{
		get
		{
			return _vbrquality;
		}
		set
		{
			if (!value.HasValue)
			{
				_vbrquality = null;
			}
			else
			{
				_vbrquality = Math.Max(0, Math.Min(9, value.Value));
			}
		}
	}

	public float? Scale { get; set; }

	public float? ScaleLeft { get; set; }

	public float? ScaleRight { get; set; }

	public int? LowPassFreq { get; set; }

	public int? LowPassWidth { get; set; }

	public int? HighPassFreq { get; set; }

	public int? HighPassWidth { get; set; }

	public bool? Analysis { get; set; }

	public bool? WriteVBRTag { get; set; }

	public MPEGMode? Mode { get; set; }

	public bool? ForceMS { get; set; }

	public bool? UseFreeFormat { get; set; }

	public bool? Copyright { get; set; }

	public bool? Original { get; set; }

	public bool? ErrorProtection { get; set; }

	public bool? StrictISO { get; set; }

	public ID3TagData ID3 { get; set; }

	public LibMp3Lame ConfigureDLL(WaveFormat format)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		LibMp3Lame val = new LibMp3Lame
		{
			InputSampleRate = format.SampleRate,
			NumChannels = format.Channels
		};
		if (_bitrate.HasValue)
		{
			val.BitRate = _bitrate.Value;
		}
		else
		{
			if (_preset >= LAMEPreset.V9 && _preset <= LAMEPreset.V0 && (int)val.VBR == 0 && !VBR.HasValue)
			{
				val.VBR = (VBRMode)4;
			}
			val.SetPreset((int)_preset.GetValueOrDefault(LAMEPreset.STANDARD));
		}
		if (OutputSampleRate.HasValue)
		{
			val.OutputSampleRate = OutputSampleRate.Value;
		}
		if (VBR.HasValue)
		{
			val.VBR = (VBRMode)VBR.Value;
			if (VBR == VBRMode.ABR && ABRRateKbps.HasValue)
			{
				val.VBRMeanBitrateKbps = ABRRateKbps.Value;
			}
			if (VBRMinimumRateKbps.HasValue)
			{
				val.VBRMinBitrateKbps = VBRMinimumRateKbps.Value;
			}
			if (VBRMaximumRateKbps.HasValue)
			{
				val.VBRMaxBitrateKbps = VBRMaximumRateKbps.Value;
			}
			if (VBREnforceMinimum.HasValue)
			{
				val.VBRHardMin = VBREnforceMinimum.Value;
			}
			if (VBRQuality.HasValue)
			{
				val.VBRQualityLevel = VBRQuality.Value;
			}
		}
		if (Scale.HasValue)
		{
			val.Scale = Scale.Value;
		}
		if (ScaleLeft.HasValue)
		{
			val.ScaleLeft = ScaleLeft.Value;
		}
		if (ScaleRight.HasValue)
		{
			val.ScaleRight = ScaleRight.Value;
		}
		if (LowPassFreq.HasValue)
		{
			val.LowPassFreq = LowPassFreq.Value;
		}
		if (LowPassWidth.HasValue)
		{
			val.LowPassWidth = LowPassWidth.Value;
		}
		if (HighPassFreq.HasValue)
		{
			val.HighPassFreq = HighPassFreq.Value;
		}
		if (HighPassWidth.HasValue)
		{
			val.HighPassWidth = HighPassWidth.Value;
		}
		if (Analysis.HasValue)
		{
			val.Analysis = Analysis.Value;
		}
		if (WriteVBRTag.HasValue)
		{
			val.WriteVBRTag = WriteVBRTag.Value;
		}
		if (Mode.HasValue)
		{
			val.Mode = (MPEGMode)Mode.Value;
		}
		if (ForceMS.HasValue)
		{
			val.ForceMS = ForceMS.Value;
		}
		if (UseFreeFormat.HasValue)
		{
			val.UseFreeFormat = UseFreeFormat.Value;
		}
		if (Copyright.HasValue)
		{
			val.Copyright = Copyright.Value;
		}
		if (Original.HasValue)
		{
			val.Original = Original.Value;
		}
		if (ErrorProtection.HasValue)
		{
			val.ErrorProtection = ErrorProtection.Value;
		}
		if (StrictISO.HasValue)
		{
			val.StrictISO = StrictISO.Value;
		}
		return val;
	}
}
public static class LameDLL
{
	public static string LameVersion => LameDLLImpl.LameVersion;

	public static string LameShortVersion => LameDLLImpl.LameShortVersion;

	public static string LameVeryShortVersion => LameDLLImpl.LameVeryShortVersion;

	public static string LamePsychoacousticVersion => LameDLLImpl.LamePsychoacousticVersion;

	public static string LameURL => LameDLLImpl.LameURL;

	public static string LameOSBitness => LameDLLImpl.LameOSBitness;

	public static bool LoadNativeDLL(params string[] rootPaths)
	{
		return LameDLLImpl.Native.LoadNativeDLL(rootPaths);
	}

	public static LAMEVersion GetLameVersion()
	{
		return LameDLLImpl.GetLameVersion();
	}
}
internal static class LameDLLImpl
{
	internal static class Native
	{
		private static IntPtr _hLameDll = IntPtr.Zero;

		[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
		private static extern IntPtr LoadLibraryW([MarshalAs(UnmanagedType.LPWStr)] string lpFilename);

		private static bool TryLoadLameDLL(FileInfo file)
		{
			if (file == null || !file.Exists)
			{
				return false;
			}
			IntPtr intPtr = LoadLibraryW(file.FullName);
			if (intPtr == IntPtr.Zero)
			{
				return false;
			}
			_hLameDll = intPtr;
			return true;
		}

		internal static bool LoadNativeDLL(params string[] rootPaths)
		{
			if (_hLameDll != IntPtr.Zero)
			{
				return true;
			}
			if (!IsWindowsOS)
			{
				return false;
			}
			string text = null;
			try
			{
				text = Path.GetDirectoryName(typeof(LameDLL).Assembly.Location);
			}
			catch
			{
			}
			string[] array = (from p in rootPaths.Concat(new string[2]
				{
					AppDomain.CurrentDomain.BaseDirectory,
					text
				})
				where !string.IsNullOrEmpty(p)
				select p).Distinct().ToArray();
			string searchPattern = "libmp3lame." + (Environment.Is64BitProcess ? "64" : "32") + ".dll";
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				if (TryLoadLameDLL(new DirectoryInfo(array2[i]).GetFiles(searchPattern, SearchOption.AllDirectories).FirstOrDefault()))
				{
					return true;
				}
			}
			return false;
		}
	}

	internal static string LameVersion => LibMp3Lame.LameVersion;

	internal static string LameShortVersion => LibMp3Lame.LameShortVersion;

	internal static string LameVeryShortVersion => LibMp3Lame.LameVeryShortVersion;

	internal static string LamePsychoacousticVersion => LibMp3Lame.LamePsychoacousticVersion;

	internal static string LameURL => LibMp3Lame.LameURL;

	internal static string LameOSBitness => LibMp3Lame.LameOSBitness;

	internal static bool IsWindowsOS => Environment.OSVersion.Platform == PlatformID.Win32NT;

	internal static LAMEVersion GetLameVersion()
	{
		return new LAMEVersion(LibMp3Lame.GetLameVersion());
	}
}
public delegate void OutputHandler(string text);
public delegate void ProgressHandler(object writer, long inputBytes, long outputBytes, bool finished);
public class LameMP3FileWriter : Stream
{
	private delegate int delEncode();

	[StructLayout(LayoutKind.Explicit)]
	private class ArrayUnion
	{
		[FieldOffset(0)]
		public readonly int nBytes;

		[FieldOffset(16)]
		public readonly byte[] bytes;

		[FieldOffset(16)]
		public readonly short[] shorts;

		[FieldOffset(16)]
		public readonly int[] ints;

		[FieldOffset(16)]
		public readonly long[] longs;

		[FieldOffset(16)]
		public readonly float[] floats;

		[FieldOffset(16)]
		public readonly double[] doubles;

		public int nShorts => nBytes / 2;

		public int nInts => nBytes / 4;

		public int nLongs => nBytes / 8;

		public int nFloats => nBytes / 4;

		public int nDoubles => doubles.Length;

		public ArrayUnion(int reqBytes)
		{
			int num = (reqBytes + 7) / 8;
			doubles = new double[num];
			nBytes = num * 8;
		}

		private ArrayUnion()
		{
			throw new Exception("Default constructor cannot be called for ArrayUnion");
		}
	}

	private LibMp3Lame _lame;

	private readonly WaveFormat _inputFormat;

	private Stream _outStream;

	private readonly bool _disposeOutput;

	private readonly ArrayUnion _inBuffer;

	private int inPosition;

	protected byte[] _outBuffer;

	private long _inputByteCount;

	private long _outputByteCount;

	private readonly delEncode _encode;

	private int _minProgressTime = 100;

	private DateTime _lastProgress = DateTime.Now;

	private static Dictionary<int, string> _genres;

	public int LastLameResult => _lame.LastLameError;

	public int MinProgressTime
	{
		get
		{
			return _minProgressTime;
		}
		set
		{
			_minProgressTime = Math.Max(0, value);
		}
	}

	public override bool CanRead => false;

	public override bool CanSeek => false;

	public override bool CanWrite
	{
		get
		{
			if (_outStream != null)
			{
				return _lame != null;
			}
			return false;
		}
	}

	public override long Position
	{
		get
		{
			return 0L;
		}
		set
		{
			throw new NotImplementedException();
		}
	}

	public override long Length => 0L;

	public static Dictionary<int, string> Genres
	{
		get
		{
			if (_genres == null)
			{
				_genres = LibMp3Lame.ID3GenreList();
			}
			return _genres;
		}
	}

	public event ProgressHandler OnProgress;

	public LameMP3FileWriter(string outFileName, WaveFormat format, LAMEPreset quality, ID3TagData id3 = null)
		: this(File.Create(outFileName), format, quality, id3)
	{
		_disposeOutput = true;
	}

	public LameMP3FileWriter(Stream outStream, WaveFormat format, LAMEPreset quality, ID3TagData id3 = null)
		: this(outStream, format, new LameConfig
		{
			Preset = quality,
			ID3 = id3
		})
	{
	}

	public LameMP3FileWriter(string outFileName, WaveFormat format, int bitRate, ID3TagData id3 = null)
		: this(File.Create(outFileName), format, bitRate, id3)
	{
		_disposeOutput = true;
	}

	public LameMP3FileWriter(Stream outStream, WaveFormat format, int bitRate, ID3TagData id3 = null)
		: this(outStream, format, new LameConfig
		{
			BitRate = bitRate,
			ID3 = id3
		})
	{
	}

	public LameMP3FileWriter(string outFileName, WaveFormat format, LameConfig config)
		: this(File.Create(outFileName), format, config)
	{
		_disposeOutput = true;
	}

	public LameMP3FileWriter(Stream outStream, WaveFormat format, LameConfig config)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Invalid comparison between Unknown and I4
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Invalid comparison between Unknown and I4
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Invalid comparison between Unknown and I4
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Invalid comparison between Unknown and I4
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Invalid comparison between Unknown and I4
		if (format == null)
		{
			throw new ArgumentNullException("format");
		}
		if (format.Channels != 1 && format.Channels != 2)
		{
			throw new ArgumentException($"Unsupported number of channels {format.Channels}", "format");
		}
		if ((int)format.Encoding != 1 && (int)format.Encoding != 3)
		{
			throw new ArgumentException($"Unsupported encoding format {format.Encoding}", "format");
		}
		if ((int)format.Encoding == 1 && format.BitsPerSample != 16)
		{
			throw new ArgumentException($"Unsupported PCM sample size {format.BitsPerSample}", "format");
		}
		if ((int)format.Encoding == 3 && format.BitsPerSample != 32)
		{
			throw new ArgumentException($"Unsupported Float sample size {format.BitsPerSample}", "format");
		}
		if (format.SampleRate < 8000 || format.SampleRate > 48000)
		{
			throw new ArgumentException($"Unsupported Sample Rate {format.SampleRate}", "format");
		}
		if ((int)format.Encoding == 1)
		{
			if (format.Channels == 1)
			{
				_encode = Encode_pcm_16_mono;
			}
			else
			{
				_encode = Encode_pcm_16_stereo;
			}
		}
		else if (format.Channels == 1)
		{
			_encode = Encode_float_mono;
		}
		else
		{
			_encode = Encode_float_stereo;
		}
		_inputFormat = format;
		_outStream = outStream ?? throw new ArgumentNullException("outStream");
		_disposeOutput = false;
		_inBuffer = new ArrayUnion(format.AverageBytesPerSecond);
		_outBuffer = new byte[format.SampleRate * 5 / 4 + 7200];
		_lame = config.ConfigureDLL(format);
		if (config.ID3 != null)
		{
			ApplyID3Tag(config.ID3);
		}
		_lame.InitParams();
	}

	protected override void Dispose(bool disposing)
	{
		if (_lame != null && _outStream != null)
		{
			Flush();
		}
		LibMp3Lame lame = _lame;
		if (lame != null)
		{
			lame.Dispose();
		}
		_lame = null;
		if (_disposeOutput)
		{
			_outStream?.Dispose();
			_outStream = null;
		}
		base.Dispose(disposing);
	}

	private int Encode_pcm_16_mono()
	{
		return _lame.Write(_inBuffer.shorts, inPosition / 2, _outBuffer, _outBuffer.Length, true);
	}

	private int Encode_pcm_16_stereo()
	{
		return _lame.Write(_inBuffer.shorts, inPosition / 2, _outBuffer, _outBuffer.Length, false);
	}

	private int Encode_float_mono()
	{
		return _lame.Write(_inBuffer.floats, inPosition / 4, _outBuffer, _outBuffer.Length, true);
	}

	private int Encode_float_stereo()
	{
		return _lame.Write(_inBuffer.floats, inPosition / 4, _outBuffer, _outBuffer.Length, false);
	}

	private void Encode()
	{
		if (_outStream == null || _lame == null)
		{
			throw new InvalidOperationException("Output stream closed.");
		}
		if (inPosition >= _inputFormat.Channels * 2)
		{
			int num = _encode();
			if (num > 0)
			{
				_outStream.Write(_outBuffer, 0, num);
				_outputByteCount += num;
			}
			_inputByteCount += inPosition;
			inPosition = 0;
			RaiseProgress(finished: false);
		}
	}

	public override void Write(byte[] buffer, int offset, int count)
	{
		while (count > 0)
		{
			int num = Math.Min(_inBuffer.nBytes - inPosition, count);
			Buffer.BlockCopy(buffer, offset, _inBuffer.bytes, inPosition, num);
			inPosition += num;
			count -= num;
			offset += num;
			if (inPosition >= _inBuffer.nBytes)
			{
				Encode();
			}
		}
	}

	public override void Flush()
	{
		if (inPosition > 0)
		{
			Encode();
		}
		int num = _lame.Flush(_outBuffer, _outBuffer.Length);
		if (num > 0)
		{
			_outStream.Write(_outBuffer, 0, num);
			_outputByteCount += num;
		}
		RaiseProgress(finished: true);
		if (_lame.WriteVBRTag)
		{
			UpdateLameTagFrame();
		}
		if (_disposeOutput)
		{
			_outStream.Dispose();
		}
		_outStream = null;
	}

	private bool UpdateLameTagFrame()
	{
		if (_outStream == null || !_outStream.CanSeek || !_outStream.CanRead || !_outStream.CanWrite)
		{
			return false;
		}
		long position = _outStream.Position;
		try
		{
			byte[] lAMETagFrame = _lame.GetLAMETagFrame();
			if (lAMETagFrame == null || lAMETagFrame.Length < 4)
			{
				return false;
			}
			if (SkipId3v2(lAMETagFrame.Length) != 0)
			{
				return false;
			}
			_outStream.Write(lAMETagFrame, 0, lAMETagFrame.Length);
			return true;
		}
		finally
		{
			_outStream.Position = position;
		}
	}

	private int SkipId3v2(int framesize)
	{
		try
		{
			_outStream.Position = 0L;
		}
		catch
		{
			return -2;
		}
		byte[] array = new byte[10];
		if (_outStream.Read(array, 0, 10) != 10)
		{
			return -3;
		}
		int num = 0;
		if (array[0] == 73 || array[1] == 68 || array[2] == 51)
		{
			num = (((array[6] & 0x7F) << 21) | ((array[7] & 0x7F) << 14) | ((array[8] & 0x7F) << 7) | (array[9] & 0x7F)) + 10;
		}
		_outStream.Position = num;
		if (_outStream.Read(array, 0, 4) != 4 || array[0] != byte.MaxValue || (array[1] & 0xE0) != 224)
		{
			return -1;
		}
		_outStream.Position = num + framesize;
		if (_outStream.Read(array, 0, 4) != 4 || array[0] != byte.MaxValue || (array[1] & 0xE0) != 224)
		{
			return -1;
		}
		_outStream.Position = num;
		return 0;
	}

	public override int Read(byte[] buffer, int offset, int count)
	{
		throw new NotImplementedException();
	}

	public override void SetLength(long value)
	{
		throw new NotImplementedException();
	}

	public override long Seek(long offset, SeekOrigin origin)
	{
		throw new NotImplementedException();
	}

	private void ApplyID3Tag(ID3TagData tag)
	{
		if (tag == null)
		{
			return;
		}
		_lame.ID3Init();
		if (tag.V2Only)
		{
			_lame.ID3V2Only();
		}
		foreach (KeyValuePair<string, string> customField in tag.CustomFields)
		{
			_lame.ID3SetFieldValue(customField.Key + "=" + customField.Value);
		}
		if (!string.IsNullOrEmpty(tag.Title))
		{
			_lame.ID3SetTitle(tag.Title);
		}
		if (!string.IsNullOrEmpty(tag.Artist))
		{
			_lame.ID3SetArtist(tag.Artist);
		}
		if (!string.IsNullOrEmpty(tag.Album))
		{
			_lame.ID3SetAlbum(tag.Album);
		}
		if (!string.IsNullOrEmpty(tag.Year))
		{
			_lame.ID3SetYear(tag.Year);
		}
		if (!string.IsNullOrEmpty(tag.Comment))
		{
			_lame.ID3SetComment(tag.Comment);
		}
		if (!string.IsNullOrEmpty(tag.Genre))
		{
			_lame.ID3SetGenre(tag.Genre);
		}
		if (!string.IsNullOrEmpty(tag.Track))
		{
			_lame.ID3SetTrack(tag.Track);
		}
		if (!string.IsNullOrEmpty(tag.Subtitle))
		{
			_lame.ID3SetFieldValue("TIT3=" + tag.Subtitle);
		}
		if (!string.IsNullOrEmpty(tag.AlbumArtist))
		{
			_lame.ID3SetFieldValue("TPE2=" + tag.AlbumArtist);
		}
		foreach (KeyValuePair<string, string> item in tag.UserDefinedText)
		{
			_lame.ID3SetFieldValue("TXXX=" + item.Key + "=" + item.Value);
		}
		byte[] albumArt = tag.AlbumArt;
		if (albumArt != null && albumArt.Length != 0)
		{
			_lame.ID3SetAlbumArt(tag.AlbumArt);
		}
		byte[] array = _lame.ID3GetID3v2Tag();
		if (array != null && array.Length >= 32768)
		{
			_lame.ID3WriteTagAutomatic = false;
			_outStream.Write(array, 0, array.Length);
		}
	}

	public byte[] GetID3v1TagBytes()
	{
		return _lame.ID3GetID3v1Tag();
	}

	public byte[] GetID3v2TagBytes()
	{
		return _lame.ID3GetID3v2Tag();
	}

	public void SetErrorFunction(OutputHandler fn)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		_lame.SetErrorFunc((ReportFunction)delegate(string t)
		{
			fn(t);
		});
	}

	public void SetDebugFunction(OutputHandler fn)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		_lame.SetMsgFunc((ReportFunction)delegate(string t)
		{
			fn(t);
		});
	}

	public void SetMessageFunction(OutputHandler fn)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		_lame.SetMsgFunc((ReportFunction)delegate(string t)
		{
			fn(t);
		});
	}

	public void PrintLAMEConfig()
	{
		_lame.PrintConfig();
	}

	public void PrintLAMEInternals()
	{
		_lame.PrintInternals();
	}

	protected void RaiseProgress(bool finished)
	{
		TimeSpan timeSpan = DateTime.Now - _lastProgress;
		if (finished || timeSpan.TotalMilliseconds >= (double)_minProgressTime)
		{
			_lastProgress = DateTime.Now;
			this.OnProgress?.Invoke(this, _inputByteCount, _outputByteCount, finished);
		}
	}
}
public enum LAMEPreset
{
	ABR_8 = 8,
	ABR_16 = 16,
	ABR_32 = 32,
	ABR_48 = 48,
	ABR_64 = 64,
	ABR_96 = 96,
	ABR_128 = 128,
	ABR_160 = 160,
	ABR_256 = 256,
	ABR_320 = 320,
	V9 = 410,
	VBR_10 = 410,
	V8 = 420,
	VBR_20 = 420,
	V7 = 430,
	VBR_30 = 430,
	V6 = 440,
	VBR_40 = 440,
	V5 = 450,
	VBR_50 = 450,
	V4 = 460,
	VBR_60 = 460,
	V3 = 470,
	VBR_70 = 470,
	V2 = 480,
	VBR_80 = 480,
	V1 = 490,
	VBR_90 = 490,
	V0 = 500,
	VBR_100 = 500,
	R3MIX = 1000,
	STANDARD = 1001,
	EXTREME = 1002,
	INSANE = 1003,
	STANDARD_FAST = 1004,
	EXTREME_FAST = 1005,
	MEDIUM = 1006,
	MEDIUM_FAST = 1007
}
public class LAMEVersion
{
	public int Major { get; private set; }

	public int Minor { get; private set; }

	public bool Alpha { get; private set; }

	public bool Beta { get; private set; }

	public int PsychoAcoustic_Major { get; private set; }

	public int PsychoAcoustic_Minor { get; private set; }

	public bool PsychoAcoustic_Alpha { get; private set; }

	public bool PsychoAcoustic_Beta { get; private set; }

	public string Features { get; private set; }

	internal LAMEVersion(LAMEVersion source)
	{
		Major = source.major;
		Minor = source.minor;
		Alpha = source.alpha;
		Beta = source.beta;
		PsychoAcoustic_Major = source.psy_major;
		PsychoAcoustic_Minor = source.psy_minor;
		PsychoAcoustic_Alpha = source.psy_alpha;
		PsychoAcoustic_Beta = source.psy_beta;
		Features = source.features;
	}

	private LAMEVersion()
	{
	}
}
public static class ModuleInitializer
{
	public static void Initialize()
	{
		ResourceAssemblyLoader.Init();
	}
}
public enum MPEGMode : uint
{
	Stereo = 0u,
	JointStereo = 1u,
	Mono = 3u,
	NotSet = 4u
}
internal static class ResourceAssemblyLoader
{
	internal static bool Initialized;

	internal static string LoadedName;

	public static void Init()
	{
		lock (typeof(ResourceAssemblyLoader))
		{
			if (!Initialized)
			{
				AppDomain.CurrentDomain.AssemblyResolve += LoadLameWrapper;
				Initialized = true;
			}
		}
	}

	private static Assembly LoadLameWrapper(object sender, ResolveEventArgs args)
	{
		string value = new AssemblyName(args.Name).Name + ".dll";
		Assembly assembly = typeof(ResourceAssemblyLoader).Assembly;
		byte[] array = null;
		string[] manifestResourceNames = assembly.GetManifestResourceNames();
		foreach (string text in manifestResourceNames)
		{
			int num = text.IndexOf(Environment.Is64BitProcess ? "x64" : "x86");
			int num2 = text.IndexOf(value);
			if (num >= 0 && num2 >= 0)
			{
				LoadedName = text;
				using (Stream stream = assembly.GetManifestResourceStream(text))
				{
					array = new byte[stream.Length];
					stream.Read(array, 0, (int)stream.Length);
				}
				break;
			}
		}
		if (array == null)
		{
			return null;
		}
		LameDLL.LoadNativeDLL();
		return Assembly.Load(array);
	}
}
public enum VBRMode : uint
{
	Off = 0u,
	MT = 1u,
	RH = 2u,
	ABR = 3u,
	MTRH = 4u,
	Default = 4u
}
internal class NAudioLame_ProcessedByFody
{
	internal const string FodyVersion = "6.3.0.0";

	internal const string ModuleInit = "2.1.1.0";
}