using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
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 System.Windows.Forms;
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.Mixer;
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")]
[assembly: AssemblyDescription("NAudio .NET Audio Library")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Mark Heath")]
[assembly: AssemblyProduct("NAudio")]
[assembly: AssemblyCopyright("© 2001-2017 Mark Heath")]
[assembly: AssemblyTrademark("")]
[assembly: InternalsVisibleTo("NAudioTests")]
[assembly: ComVisible(false)]
[assembly: Guid("e82fa7f0-f952-4d93-b7b0-392bbf53b2a4")]
[assembly: AssemblyFileVersion("1.8.4.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.8.4.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.Gui
{
public class Fader : Control
{
private int minimum;
private int maximum;
private float percent;
private Orientation orientation;
private Container components;
private readonly int SliderHeight = 30;
private readonly int SliderWidth = 15;
private Rectangle sliderRectangle;
private bool dragging;
private int dragY;
public int Minimum
{
get
{
return minimum;
}
set
{
minimum = value;
}
}
public int Maximum
{
get
{
return maximum;
}
set
{
maximum = value;
}
}
public int Value
{
get
{
return (int)(percent * (float)(maximum - minimum)) + minimum;
}
set
{
percent = (float)(value - minimum) / (float)(maximum - minimum);
}
}
public Orientation Orientation
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return orientation;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
orientation = value;
}
}
public Fader()
{
InitializeComponent();
((Control)this).SetStyle((ControlStyles)73730, true);
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((Control)this).Dispose(disposing);
}
private void DrawSlider(Graphics g)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
Brush val = (Brush)new SolidBrush(Color.White);
Pen val2 = new Pen(Color.Black);
sliderRectangle.X = (((Control)this).Width - SliderWidth) / 2;
sliderRectangle.Width = SliderWidth;
sliderRectangle.Y = (int)((float)(((Control)this).Height - SliderHeight) * percent);
sliderRectangle.Height = SliderHeight;
g.FillRectangle(val, sliderRectangle);
g.DrawLine(val2, sliderRectangle.Left, sliderRectangle.Top + sliderRectangle.Height / 2, sliderRectangle.Right, sliderRectangle.Top + sliderRectangle.Height / 2);
val.Dispose();
val2.Dispose();
}
protected override void OnPaint(PaintEventArgs e)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Invalid comparison between Unknown and I4
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
Graphics graphics = e.Graphics;
if ((int)Orientation == 1)
{
Brush val = (Brush)new SolidBrush(Color.Black);
graphics.FillRectangle(val, ((Control)this).Width / 2, SliderHeight / 2, 2, ((Control)this).Height - SliderHeight);
val.Dispose();
DrawSlider(graphics);
}
((Control)this).OnPaint(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (sliderRectangle.Contains(e.X, e.Y))
{
dragging = true;
dragY = e.Y - sliderRectangle.Y;
}
((Control)this).OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (dragging)
{
int num = e.Y - dragY;
if (num < 0)
{
percent = 0f;
}
else if (num > ((Control)this).Height - SliderHeight)
{
percent = 1f;
}
else
{
percent = (float)num / (float)(((Control)this).Height - SliderHeight);
}
((Control)this).Invalidate();
}
((Control)this).OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
dragging = false;
((Control)this).OnMouseUp(e);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
}
}
public class PanSlider : UserControl
{
private Container components;
private float pan;
public float Pan
{
get
{
return pan;
}
set
{
if (value < -1f)
{
value = -1f;
}
if (value > 1f)
{
value = 1f;
}
if (value != pan)
{
pan = value;
if (this.PanChanged != null)
{
this.PanChanged(this, EventArgs.Empty);
}
((Control)this).Invalidate();
}
}
}
public event EventHandler PanChanged;
public PanSlider()
{
InitializeComponent();
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((ContainerControl)this).Dispose(disposing);
}
private void InitializeComponent()
{
((Control)this).Name = "PanSlider";
((Control)this).Size = new Size(104, 16);
}
protected override void OnPaint(PaintEventArgs pe)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Expected O, but got Unknown
StringFormat val = new StringFormat();
val.LineAlignment = (StringAlignment)1;
val.Alignment = (StringAlignment)1;
string text;
if ((double)pan == 0.0)
{
pe.Graphics.FillRectangle(Brushes.Orange, ((Control)this).Width / 2 - 1, 1, 3, ((Control)this).Height - 2);
text = "C";
}
else if (pan > 0f)
{
pe.Graphics.FillRectangle(Brushes.Orange, ((Control)this).Width / 2, 1, (int)((float)(((Control)this).Width / 2) * pan), ((Control)this).Height - 2);
text = $"{pan * 100f:F0}%R";
}
else
{
pe.Graphics.FillRectangle(Brushes.Orange, (int)((float)(((Control)this).Width / 2) * (pan + 1f)), 1, (int)((float)(((Control)this).Width / 2) * (0f - pan)), ((Control)this).Height - 2);
text = $"{pan * -100f:F0}%L";
}
pe.Graphics.DrawRectangle(Pens.Black, 0, 0, ((Control)this).Width - 1, ((Control)this).Height - 1);
pe.Graphics.DrawString(text, ((Control)this).Font, Brushes.Black, (RectangleF)((Control)this).ClientRectangle, val);
}
protected override void OnMouseMove(MouseEventArgs e)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
if ((int)e.Button == 1048576)
{
SetPanFromMouse(e.X);
}
((Control)this).OnMouseMove(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
SetPanFromMouse(e.X);
((UserControl)this).OnMouseDown(e);
}
private void SetPanFromMouse(int x)
{
Pan = (float)x / (float)((Control)this).Width * 2f - 1f;
}
}
public class Pot : UserControl
{
private double minimum;
private double maximum = 1.0;
private double value = 0.5;
private int beginDragY;
private double beginDragValue;
private bool dragging;
private IContainer components;
public double Minimum
{
get
{
return minimum;
}
set
{
if (value >= maximum)
{
throw new ArgumentOutOfRangeException("Minimum must be less than maximum");
}
minimum = value;
if (Value < minimum)
{
Value = minimum;
}
}
}
public double Maximum
{
get
{
return maximum;
}
set
{
if (value <= minimum)
{
throw new ArgumentOutOfRangeException("Maximum must be greater than minimum");
}
maximum = value;
if (Value > maximum)
{
Value = maximum;
}
}
}
public double Value
{
get
{
return value;
}
set
{
SetValue(value, raiseEvents: false);
}
}
public event EventHandler ValueChanged;
public Pot()
{
((Control)this).SetStyle((ControlStyles)73730, true);
InitializeComponent();
}
private void SetValue(double newValue, bool raiseEvents)
{
if (value != newValue)
{
value = newValue;
if (raiseEvents && this.ValueChanged != null)
{
this.ValueChanged(this, EventArgs.Empty);
}
((Control)this).Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected O, but got Unknown
int num = Math.Min(((Control)this).Width - 4, ((Control)this).Height - 4);
Pen val = new Pen(((Control)this).ForeColor, 3f);
val.LineJoin = (LineJoin)2;
GraphicsState val2 = e.Graphics.Save();
e.Graphics.TranslateTransform((float)(((Control)this).Width / 2), (float)(((Control)this).Height / 2));
e.Graphics.SmoothingMode = (SmoothingMode)4;
e.Graphics.DrawArc(val, new Rectangle(num / -2, num / -2, num, num), 135f, 270f);
double num2 = (value - minimum) / (maximum - minimum);
double num3 = 135.0 + num2 * 270.0;
double num4 = (double)num / 2.0 * Math.Cos(Math.PI * num3 / 180.0);
double num5 = (double)num / 2.0 * Math.Sin(Math.PI * num3 / 180.0);
e.Graphics.DrawLine(val, 0f, 0f, (float)num4, (float)num5);
e.Graphics.Restore(val2);
((Control)this).OnPaint(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
dragging = true;
beginDragY = e.Y;
beginDragValue = value;
((UserControl)this).OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
dragging = false;
((Control)this).OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (dragging)
{
int num = beginDragY - e.Y;
double num2 = (maximum - minimum) * ((double)num / 150.0);
double num3 = beginDragValue + num2;
if (num3 < minimum)
{
num3 = minimum;
}
if (num3 > maximum)
{
num3 = maximum;
}
SetValue(num3, raiseEvents: true);
}
((Control)this).OnMouseMove(e);
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((ContainerControl)this).Dispose(disposing);
}
private void InitializeComponent()
{
((Control)this).SuspendLayout();
((ContainerControl)this).AutoScaleDimensions = new SizeF(6f, 13f);
((ContainerControl)this).AutoScaleMode = (AutoScaleMode)1;
((Control)this).Name = "Pot";
((Control)this).Size = new Size(32, 32);
((Control)this).ResumeLayout(false);
}
}
public class VolumeMeter : Control
{
private Brush foregroundBrush;
private float amplitude;
private IContainer components;
[DefaultValue(-3.0)]
public float Amplitude
{
get
{
return amplitude;
}
set
{
amplitude = value;
((Control)this).Invalidate();
}
}
[DefaultValue(-60.0)]
public float MinDb { get; set; }
[DefaultValue(18.0)]
public float MaxDb { get; set; }
[DefaultValue(/*Could not decode attribute arguments.*/)]
public Orientation Orientation { get; set; }
public VolumeMeter()
{
((Control)this).SetStyle((ControlStyles)139266, true);
MinDb = -60f;
MaxDb = 18f;
Amplitude = 0f;
Orientation = (Orientation)1;
InitializeComponent();
((Control)this).OnForeColorChanged(EventArgs.Empty);
}
protected override void OnForeColorChanged(EventArgs e)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
foregroundBrush = (Brush)new SolidBrush(((Control)this).ForeColor);
((Control)this).OnForeColorChanged(e);
}
protected override void OnPaint(PaintEventArgs pe)
{
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
pe.Graphics.DrawRectangle(Pens.Black, 0, 0, ((Control)this).Width - 1, ((Control)this).Height - 1);
double num = 20.0 * Math.Log10(Amplitude);
if (num < (double)MinDb)
{
num = MinDb;
}
if (num > (double)MaxDb)
{
num = MaxDb;
}
double num2 = (num - (double)MinDb) / (double)(MaxDb - MinDb);
int num3 = ((Control)this).Width - 2;
int num4 = ((Control)this).Height - 2;
if ((int)Orientation == 0)
{
num3 = (int)((double)num3 * num2);
pe.Graphics.FillRectangle(foregroundBrush, 1, 1, num3, num4);
}
else
{
num4 = (int)((double)num4 * num2);
pe.Graphics.FillRectangle(foregroundBrush, 1, ((Control)this).Height - 1 - num4, num3, num4);
}
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((Control)this).Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
}
}
public class VolumeSlider : UserControl
{
private Container components;
private float volume = 1f;
private float MinDb = -48f;
[DefaultValue(1f)]
public float Volume
{
get
{
return volume;
}
set
{
if (value < 0f)
{
value = 0f;
}
if (value > 1f)
{
value = 1f;
}
if (volume != value)
{
volume = value;
if (this.VolumeChanged != null)
{
this.VolumeChanged(this, EventArgs.Empty);
}
((Control)this).Invalidate();
}
}
}
public event EventHandler VolumeChanged;
public VolumeSlider()
{
InitializeComponent();
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((ContainerControl)this).Dispose(disposing);
}
private void InitializeComponent()
{
((Control)this).Name = "VolumeSlider";
((Control)this).Size = new Size(96, 16);
}
protected override void OnPaint(PaintEventArgs pe)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Expected O, but got Unknown
StringFormat val = new StringFormat();
val.LineAlignment = (StringAlignment)1;
val.Alignment = (StringAlignment)1;
pe.Graphics.DrawRectangle(Pens.Black, 0, 0, ((Control)this).Width - 1, ((Control)this).Height - 1);
float num = 20f * (float)Math.Log10(Volume);
float num2 = 1f - num / MinDb;
pe.Graphics.FillRectangle(Brushes.LightGreen, 1, 1, (int)((float)(((Control)this).Width - 2) * num2), ((Control)this).Height - 2);
string text = $"{num:F2} dB";
pe.Graphics.DrawString(text, ((Control)this).Font, Brushes.Black, (RectangleF)((Control)this).ClientRectangle, val);
}
protected override void OnMouseMove(MouseEventArgs e)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
if ((int)e.Button == 1048576)
{
SetVolumeFromMouse(e.X);
}
((Control)this).OnMouseMove(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
SetVolumeFromMouse(e.X);
((UserControl)this).OnMouseDown(e);
}
private void SetVolumeFromMouse(int x)
{
float num = (1f - (float)x / (float)((Control)this).Width) * MinDb;
if (x <= 0)
{
Volume = 0f;
}
else
{
Volume = (float)Math.Pow(10.0, num / 20f);
}
}
}
public class WaveformPainter : Control
{
private Pen foregroundPen;
private List<float> samples = new List<float>(1000);
private int maxSamples;
private int insertPos;
private IContainer components;
public WaveformPainter()
{
((Control)this).SetStyle((ControlStyles)139266, true);
InitializeComponent();
((Control)this).OnForeColorChanged(EventArgs.Empty);
((Control)this).OnResize(EventArgs.Empty);
}
protected override void OnResize(EventArgs e)
{
maxSamples = ((Control)this).Width;
((Control)this).OnResize(e);
}
protected override void OnForeColorChanged(EventArgs e)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
foregroundPen = new Pen(((Control)this).ForeColor);
((Control)this).OnForeColorChanged(e);
}
public void AddMax(float maxSample)
{
if (maxSamples != 0)
{
if (samples.Count <= maxSamples)
{
samples.Add(maxSample);
}
else if (insertPos < maxSamples)
{
samples[insertPos] = maxSample;
}
insertPos++;
insertPos %= maxSamples;
((Control)this).Invalidate();
}
}
protected override void OnPaint(PaintEventArgs pe)
{
((Control)this).OnPaint(pe);
for (int i = 0; i < ((Control)this).Width; i++)
{
float num = (float)((Control)this).Height * GetSample(i - ((Control)this).Width + insertPos);
float num2 = ((float)((Control)this).Height - num) / 2f;
pe.Graphics.DrawLine(foregroundPen, (float)i, num2, (float)i, num2 + num);
}
}
private float GetSample(int index)
{
if (index < 0)
{
index += maxSamples;
}
if ((index >= 0) & (index < samples.Count))
{
return samples[index];
}
return 0f;
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((Control)this).Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
}
}
public class WaveViewer : UserControl
{
private Container components;
private WaveStream waveStream;
private int samplesPerPixel = 128;
private long startPosition;
private int bytesPerSample;
public WaveStream WaveStream
{
get
{
return waveStream;
}
set
{
waveStream = value;
if (waveStream != null)
{
bytesPerSample = waveStream.WaveFormat.BitsPerSample / 8 * waveStream.WaveFormat.Channels;
}
((Control)this).Invalidate();
}
}
public int SamplesPerPixel
{
get
{
return samplesPerPixel;
}
set
{
samplesPerPixel = value;
((Control)this).Invalidate();
}
}
public long StartPosition
{
get
{
return startPosition;
}
set
{
startPosition = value;
}
}
public WaveViewer()
{
InitializeComponent();
((Control)this).DoubleBuffered = true;
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((ContainerControl)this).Dispose(disposing);
}
protected override void OnPaint(PaintEventArgs e)
{
if (waveStream != null)
{
waveStream.Position = 0L;
byte[] array = new byte[samplesPerPixel * bytesPerSample];
waveStream.Position = startPosition + e.ClipRectangle.Left * bytesPerSample * samplesPerPixel;
for (float num = e.ClipRectangle.X; num < (float)e.ClipRectangle.Right; num += 1f)
{
short num2 = 0;
short num3 = 0;
int num4 = waveStream.Read(array, 0, samplesPerPixel * bytesPerSample);
if (num4 == 0)
{
break;
}
for (int i = 0; i < num4; i += 2)
{
short num5 = BitConverter.ToInt16(array, i);
if (num5 < num2)
{
num2 = num5;
}
if (num5 > num3)
{
num3 = num5;
}
}
float num6 = ((float)num2 - -32768f) / 65535f;
float num7 = ((float)num3 - -32768f) / 65535f;
e.Graphics.DrawLine(Pens.Black, num, (float)((Control)this).Height * num6, num, (float)((Control)this).Height * num7);
}
}
((Control)this).OnPaint(e);
}
private void InitializeComponent()
{
components = new Container();
}
}
}
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 InvalidDataException("Not an INFO chunk");
}
RiffChunk nextSubChunk;
while ((nextSubChunk = chunk.GetNextSubChunk()) != null)
{
switch (nextSubChunk.ChunkID)
{
case "ifil":
flag = true;
SoundFontVersion = nextSubChunk.GetDataAsStructure(new SFVersionBuilder());
break;
case "isng":
WaveTableSoundEngine = nextSubChunk.GetDataAsString();
break;
case "INAM":
flag2 = true;
BankName = nextSubChunk.GetDataAsString();
break;
case "irom":
DataROM = nextSubChunk.GetDataAsString();
break;
case "iver":
ROMVersion = nextSubChunk.GetDataAsStructure(new SFVersionBuilder());
break;
case "ICRD":
CreationDate = nextSubChunk.GetDataAsString();
break;
case "IENG":
Author = nextSubChunk.GetDataAsString();
break;
case "IPRD":
TargetProduct = nextSubChunk.GetDataAsString();
break;
case "ICOP":
Copyright = nextSubChunk.GetDataAsString();
break;
case "ICMT":
Comments = nextSubChunk.GetDataAsString();
break;
case "ISFT":
Tools = nextSubChunk.GetDataAsString();
break;
default:
throw new InvalidDataException($"Unknown chunk type {nextSubChunk.ChunkID}");
}
}
if (!flag)
{
throw new InvalidDataException("Missing SoundFont version information");
}
if (!flag2)
{
throw new InvalidDataException("Missing SoundFont name information");
}
}
public override string ToString()
{
return string.Format("Bank Name: {0}\r\nAuthor: {1}\r\nCopyright: {2}\r\nCreation Date: {3}\r\nTools: {4}\r\nComments: {5}\r\nSound Engine: {6}\r\nSoundFont Version: {7}\r\nTarget Product: {8}\r\nData ROM: {9}\r\nROM Version: {10}", BankName, Author, Copyright, CreationDate, Tools, "TODO-fix comments", WaveTableSoundEngine, SoundFontVersion, TargetProduct, DataROM, ROMVersion);
}
}
public class Instrument
{
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 InvalidDataException($"Not a presets data chunk ({text})");
}
RiffChunk nextSubChunk;
while ((nextSubChunk = chunk.GetNextSubChunk()) != null)
{
switch (nextSubChunk.ChunkID)
{
case "PHDR":
case "phdr":
nextSubChunk.GetDataAsStructureArray(presetHeaders);
break;
case "PBAG":
case "pbag":
nextSubChunk.GetDataAsStructureArray(presetZones);
break;
case "PMOD":
case "pmod":
nextSubChunk.GetDataAsStructureArray(presetZoneModulators);
break;
case "PGEN":
case "pgen":
nextSubChunk.GetDataAsStructureArray(presetZoneGenerators);
break;
case "INST":
case "inst":
nextSubChunk.GetDataAsStructureArray(instruments);
break;
case "IBAG":
case "ibag":
nextSubChunk.GetDataAsStructureArray(instrumentZones);
break;
case "IMOD":
case "imod":
nextSubChunk.GetDataAsStructureArray(instrumentZoneModulators);
break;
case "IGEN":
case "igen":
nextSubChunk.GetDataAsStructureArray(instrumentZoneGenerators);
break;
case "SHDR":
case "shdr":
nextSubChunk.GetDataAsStructureArray(sampleHeaders);
break;
default:
throw new InvalidDataException($"Unknown chunk type {nextSubChunk.ChunkID}");
}
}
instrumentZoneGenerators.Load(sampleHeaders.SampleHeaders);
instrumentZones.Load(instrumentZoneModulators.Modulators, instrumentZoneGenerators.Generators);
instruments.LoadZones(instrumentZones.Zones);
presetZoneGenerators.Load(instruments.Instruments);
presetZones.Load(presetZoneModulators.Modulators, presetZoneGenerators.Generators);
presetHeaders.LoadZones(presetZones.Zones);
sampleHeaders.RemoveEOS();
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Preset Headers:\r\n");
Preset[] presets = presetHeaders.Presets;
foreach (Preset arg in presets)
{
stringBuilder.AppendFormat("{0}\r\n", arg);
}
stringBuilder.Append("Instruments:\r\n");
Instrument[] array = instruments.Instruments;
foreach (Instrument arg2 in array)
{
stringBuilder.AppendFormat("{0}\r\n", arg2);
}
return stringBuilder.ToString();
}
}
internal class RiffChunk
{
private string chunkID;
private 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 InvalidDataException("Couldn't read Chunk ID");
}
return ByteEncoding.Instance.GetString(array, 0, array.Length);
}
private void ReadChunk()
{
chunkID = ReadChunkID();
chunkSize = riffFile.ReadUInt32();
dataOffset = riffFile.BaseStream.Position;
}
public RiffChunk GetNextSubChunk()
{
if (riffFile.BaseStream.Position + 8 < dataOffset + chunkSize)
{
RiffChunk riffChunk = new RiffChunk(riffFile);
riffChunk.ReadChunk();
return riffChunk;
}
return null;
}
public byte[] GetData()
{
riffFile.BaseStream.Position = dataOffset;
byte[] array = riffFile.ReadBytes((int)chunkSize);
if (array.Length != chunkSize)
{
throw new InvalidDataException($"Couldn't read chunk's data Chunk: {this}, read {array.Length} bytes");
}
return array;
}
public string GetDataAsString()
{
byte[] data = GetData();
if (data == null)
{
return null;
}
return ByteEncoding.Instance.GetString(data, 0, data.Length);
}
public T GetDataAsStructure<T>(StructureBuilder<T> s)
{
riffFile.BaseStream.Position = dataOffset;
if (s.Length != chunkSize)
{
throw new InvalidDataException($"Chunk size is: {chunkSize} so can't read structure of: {s.Length}");
}
return s.Read(riffFile);
}
public T[] GetDataAsStructureArray<T>(StructureBuilder<T> s)
{
riffFile.BaseStream.Position = dataOffset;
if (chunkSize % s.Length != 0L)
{
throw new InvalidDataException($"Chunk size is: {chunkSize} not a multiple of structure size: {s.Length}");
}
int num = (int)(chunkSize / s.Length);
T[] array = new T[num];
for (int i = 0; i < num; i++)
{
array[i] = s.Read(riffFile);
}
return array;
}
public override string ToString()
{
return $"RiffChunk ID: {ChunkID} Size: {ChunkSize} Data Offset: {DataOffset}";
}
}
internal class SampleDataChunk
{
private byte[] sampleData;
public byte[] SampleData => sampleData;
public SampleDataChunk(RiffChunk chunk)
{
string text = chunk.ReadChunkID();
if (text != "sdta")
{
throw new InvalidDataException($"Not a sample data chunk ({text})");
}
sampleData = chunk.GetData();
}
}
public class SampleHeader
{
public string SampleName;
public uint Start;
public uint End;
public uint StartLoop;
public uint EndLoop;
public uint SampleRate;
public byte OriginalPitch;
public sbyte PitchCorrection;
public ushort SampleLink;
public SFSampleLink SFSampleLink;
public override string ToString()
{
return SampleName;
}
}
internal class SampleHeaderBuilder : StructureBuilder<SampleHeader>
{
public override int Length => 46;
public SampleHeader[] SampleHeaders => data.ToArray();
public override SampleHeader Read(BinaryReader br)
{
SampleHeader sampleHeader = new SampleHeader();
byte[] array = br.ReadBytes(20);
sampleHeader.SampleName = ByteEncoding.Instance.GetString(array, 0, array.Length);
sampleHeader.Start = br.ReadUInt32();
sampleHeader.End = br.ReadUInt32();
sampleHeader.StartLoop = br.ReadUInt32();
sampleHeader.EndLoop = br.ReadUInt32();
sampleHeader.SampleRate = br.ReadUInt32();
sampleHeader.OriginalPitch = br.ReadByte();
sampleHeader.PitchCorrection = br.ReadSByte();
sampleHeader.SampleLink = br.ReadUInt16();
sampleHeader.SFSampleLink = (SFSampleLink)br.ReadUInt16();
data.Add(sampleHeader);
return sampleHeader;
}
public override void Write(BinaryWriter bw, SampleHeader sampleHeader)
{
}
internal void RemoveEOS()
{
data.RemoveAt(data.Count - 1);
}
}
public enum SampleMode
{
NoLoop,
LoopContinuously,
ReservedNoLoop,
LoopAndContinue
}
public enum SFSampleLink : ushort
{
MonoSample = 1,
RightSample = 2,
LeftSample = 4,
LinkedSample = 8,
RomMonoSample = 32769,
RomRightSample = 32770,
RomLeftSample = 32772,
RomLinkedSample = 32776
}
public class SFVersion
{
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);
}
}
public class SoundFont
{
private InfoChunk info;
private PresetsChunk presetsChunk;
private SampleDataChunk sampleData;
public InfoChunk FileInfo => info;
public Preset[] Presets => presetsChunk.Presets;
public Instrument[] Instruments => presetsChunk.Instruments;
public SampleHeader[] SampleHeaders => presetsChunk.SampleHeaders;
public byte[] SampleData => sampleData.SampleData;
public SoundFont(string fileName)
: this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
}
public SoundFont(Stream sfFile)
{
using (sfFile)
{
RiffChunk topLevelChunk = RiffChunk.GetTopLevelChunk(new BinaryReader(sfFile));
if (topLevelChunk.ChunkID == "RIFF")
{
string text = topLevelChunk.ReadChunkID();
if (text != "sfbk")
{
throw new InvalidDataException($"Not a SoundFont ({text})");
}
RiffChunk nextSubChunk = topLevelChunk.GetNextSubChunk();
if (nextSubChunk.ChunkID == "LIST")
{
info = new InfoChunk(nextSubChunk);
RiffChunk nextSubChunk2 = topLevelChunk.GetNextSubChunk();
sampleData = new SampleDataChunk(nextSubChunk2);
nextSubChunk2 = topLevelChunk.GetNextSubChunk();
presetsChunk = new PresetsChunk(nextSubChunk2);
return;
}
throw new InvalidDataException($"Not info list found ({nextSubChunk.ChunkID})");
}
throw new InvalidDataException("Not a RIFF file");
}
}
public override string ToString()
{
return $"Info Chunk:\r\n{info}\r\nPresets Chunk:\r\n{presetsChunk}";
}
}
internal abstract class StructureBuilder<T>
{
protected List<T> data;
public abstract int Length { get; }
public T[] Data => data.ToArray();
public StructureBuilder()
{
Reset();
}
public abstract T Read(BinaryReader br);
public abstract void Write(BinaryWriter bw, T o);
public void Reset()
{
data = new List<T>();
}
}
public class Zone
{
internal ushort generatorIndex;
internal ushort modulatorIndex;
internal ushort generatorCount;
internal ushort modulatorCount;
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;