summaryrefslogtreecommitdiff
path: root/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime
diff options
context:
space:
mode:
authortylermurphy534 <tylermurphy534@gmail.com>2022-11-06 15:12:42 -0500
committertylermurphy534 <tylermurphy534@gmail.com>2022-11-06 15:12:42 -0500
commiteb84bb298d2b95aec7b2ae12cbf25ac64f25379a (patch)
treeefd616a157df06ab661c6d56651853431ac6b08b /VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime
downloadunityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.gz
unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.bz2
unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.zip
move to self host
Diffstat (limited to 'VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime')
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi.meta8
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi.meta8
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs17
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs34
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs69
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs18
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs31
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs22
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs30
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs57
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs20
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs67
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs41
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs7
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins.meta8
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows.meta8
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dllbin0 -> 29184 bytes
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll.meta96
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs21
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs105
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs.meta11
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs116
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs.meta3
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs1069
-rw-r--r--VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs.meta3
40 files changed, 2034 insertions, 0 deletions
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi.meta
new file mode 100644
index 00000000..96e1993a
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 41b228f88e2afce4fa7152bf11eda080
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi.meta
new file mode 100644
index 00000000..0b38e67b
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c4ba92a5dc8e6c14bb9b8dfce6851a99
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs
new file mode 100644
index 00000000..110564e7
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs
@@ -0,0 +1,17 @@
+namespace PortMidi
+{
+ public class Event
+ {
+ public Event(PmEvent pmEvent)
+ {
+ this.Status = PortMidiMarshal.Pm_MessageStatus(pmEvent.message);
+ this.Data1 = PortMidiMarshal.Pm_MessageData1(pmEvent.message);
+ this.Data2 = PortMidiMarshal.Pm_MessageData2(pmEvent.message);
+ }
+
+ public long Timestamp { get; set; }
+ public long Status { get; set; }
+ public long Data1 { get; set; }
+ public long Data2 { get; set; }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs.meta
new file mode 100644
index 00000000..d02de3b3
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Event.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 61b00e22036b5cc49a565aaec91ca8cb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs
new file mode 100644
index 00000000..001816fe
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace PortMidi
+{
+ public struct MidiDeviceInfo
+ {
+ PmDeviceInfo info;
+
+ internal MidiDeviceInfo(int id, IntPtr ptr)
+ {
+ ID = id;
+ this.info = (PmDeviceInfo) Marshal.PtrToStructure(ptr, typeof(PmDeviceInfo));
+ }
+
+ public int ID { get; set; }
+
+ public string Interface => Marshal.PtrToStringAnsi(info.Interface);
+
+ public string Name => Marshal.PtrToStringAnsi(info.Name);
+
+ public bool IsInput => info.Input != 0;
+
+ public bool IsOutput => info.Output != 0;
+
+ public bool IsOpened => info.Opened != 0;
+
+ public override string ToString()
+ {
+ return
+ $"{Interface} - {Name} ({(IsInput ? (IsOutput ? "I/O" : "Input") : (IsOutput ? "Output" : "N/A"))} {(IsOpened ? "open" : String.Empty)})";
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs.meta
new file mode 100644
index 00000000..60628362
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bbb88a986ea685d41a9eac3aa3dd8c60
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs
new file mode 100644
index 00000000..4628afc1
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using PmDeviceID = System.Int32;
+using PortMidiStream = System.IntPtr;
+using PmError = PortMidi.MidiErrorType;
+
+namespace PortMidi
+{
+ public static class MidiDeviceManager
+ {
+ private const int DefaultBufferSize = 1024;
+
+ static MidiDeviceManager()
+ {
+ PortMidiMarshal.Pm_Initialize();
+ AppDomain.CurrentDomain.DomainUnload += delegate { PortMidiMarshal.Pm_Terminate(); };
+ }
+
+ public static int DeviceCount => PortMidiMarshal.Pm_CountDevices();
+
+ public static int DefaultInputDeviceId => PortMidiMarshal.Pm_GetDefaultInputDeviceID();
+
+ public static int DefaultOutputDeviceId => PortMidiMarshal.Pm_GetDefaultOutputDeviceID();
+
+ public static IEnumerable<MidiDeviceInfo> AllDevices
+ {
+ get
+ {
+ for (var i = 0; i < DeviceCount; i++)
+ {
+ yield return GetDeviceInfo(i);
+ }
+ }
+ }
+
+ private static MidiDeviceInfo GetDeviceInfo(PmDeviceID id)
+ {
+ return new MidiDeviceInfo(id, PortMidiMarshal.Pm_GetDeviceInfo(id));
+ }
+
+ public static MidiInput OpenInput(PmDeviceID inputDevice)
+ {
+ return OpenInput(inputDevice, DefaultBufferSize);
+ }
+
+ private static MidiInput OpenInput(PmDeviceID inputDevice, int bufferSize)
+ {
+ PortMidiStream stream = default;
+ var e = PortMidiMarshal.Pm_OpenInput(out stream, inputDevice, IntPtr.Zero, bufferSize, null, IntPtr.Zero);
+ if (e != PmError.NoError)
+ {
+ throw new MidiException(e, $"Failed to open MIDI input device {e}");
+ }
+
+ return new MidiInput(stream, inputDevice);
+ }
+
+ public static MidiOutput OpenOutput(PmDeviceID outputDevice)
+ {
+ PortMidiStream stream;
+ var e = PortMidiMarshal.Pm_OpenOutput(out stream, outputDevice, IntPtr.Zero, 0, null, IntPtr.Zero, 0);
+ if (e != PmError.NoError)
+ {
+ throw new MidiException(e, $"Failed to open MIDI output device {e}");
+ }
+ return new MidiOutput(stream, outputDevice, 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs.meta
new file mode 100644
index 00000000..3874e4b5
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiDeviceManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 02b0549f0815d8a4982133c0a99880cf
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs
new file mode 100644
index 00000000..e03dfdcf
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs
@@ -0,0 +1,18 @@
+namespace PortMidi
+{
+ public enum MidiErrorType
+ {
+ NoError = 0,
+ NoData = 0,
+ GotData = 1,
+ HostError = -10000,
+ InvalidDeviceId,
+ InsufficientMemory,
+ BufferTooSmall,
+ BufferOverflow,
+ BadPointer,
+ BadData,
+ InternalError,
+ BufferMaxSize,
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs.meta
new file mode 100644
index 00000000..15768ae2
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiErrorType.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6b1e1637c177e0c43af16fefddc0826c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs
new file mode 100644
index 00000000..b304cefd
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace PortMidi
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MidiEvent
+ {
+ MidiMessage msg;
+ Int32 ts;
+ [NonSerialized] byte[] sysex;
+
+ public MidiMessage Message
+ {
+ get => msg;
+ set => msg = value;
+ }
+
+ public Int32 Timestamp
+ {
+ get => ts;
+ set => ts = value;
+ }
+
+ public byte[] SysEx
+ {
+ get => sysex;
+ set => sysex = value;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs.meta
new file mode 100644
index 00000000..cb252310
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiEvent.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b8f59aea3b1948f4ebb0d7835b69bbb7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs
new file mode 100644
index 00000000..551297b2
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace PortMidi
+{
+ public class MidiException : Exception
+ {
+ MidiErrorType error_type;
+
+ public MidiException(MidiErrorType errorType, string message)
+ : this(errorType, message, null)
+ {
+ }
+
+ public MidiException(MidiErrorType errorType, string message, Exception innerException)
+ : base(message, innerException)
+ {
+ error_type = errorType;
+ }
+
+ public MidiErrorType ErrorType => error_type;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs.meta
new file mode 100644
index 00000000..82da420f
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiException.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a9aa39367a5a6014e8ae35c4c0fc0fd0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs
new file mode 100644
index 00000000..d270806a
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace PortMidi
+{
+ [Flags]
+ public enum MidiFilter : int
+ {
+ Active = 1 << 0x0E,
+ SysEx = 1,
+ Clock = 1 << 0x08,
+ Play = ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B)),
+ Tick = (1 << 0x09),
+ FD = (1 << 0x0D),
+ Undefined = FD,
+ Reset = (1 << 0x0F),
+ RealTime = (Active | SysEx | Clock | Play | Undefined | Reset | Tick),
+ Note = ((1 << 0x19) | (1 << 0x18)),
+ CAF = (1 << 0x1D),
+ PAF = (1 << 0x1A),
+ AF = (CAF | PAF),
+ Program = (1 << 0x1C),
+ Control = (1 << 0x1B),
+ PitchBend = (1 << 0x1E),
+ MTC = (1 << 0x01),
+ SongPosition = (1 << 0x02),
+ SongSelect = (1 << 0x03),
+ Tune = (1 << 0x06),
+ SystemCommon = (MTC | SongPosition | SongSelect | Tune)
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs.meta
new file mode 100644
index 00000000..f553d7f5
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiFilter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9ddf13cca3c55164692f303b16a5fb2d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs
new file mode 100644
index 00000000..dbb35623
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace PortMidi
+{
+ public class MidiInput : MidiStream
+ {
+ public MidiInput(IntPtr stream, Int32 inputDevice)
+ : base(stream, inputDevice)
+ {
+ }
+
+ public bool HasData => PortMidiMarshal.Pm_Poll(stream) == MidiErrorType.GotData;
+
+ public int Read(byte[] buffer, int index, int length)
+ {
+ var gch = GCHandle.Alloc(buffer);
+ try
+ {
+ var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, index);
+ int size = PortMidiMarshal.Pm_Read(stream, ptr, length);
+ if (size < 0)
+ {
+ throw new MidiException((MidiErrorType) size,
+ PortMidiMarshal.Pm_GetErrorText((MidiErrorType) size));
+ }
+ return size * 4;
+ }
+ finally
+ {
+ gch.Free();
+ }
+ }
+
+ public Event ReadEvent(byte[] buffer, int index, int length)
+ {
+ var gch = GCHandle.Alloc(buffer);
+ try
+ {
+ var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, index);
+ int size = PortMidiMarshal.Pm_Read(stream, ptr, length);
+ if (size < 0)
+ {
+ throw new MidiException((MidiErrorType) size,
+ PortMidiMarshal.Pm_GetErrorText((MidiErrorType) size));
+ }
+
+ return new Event(Marshal.PtrToStructure<PmEvent>(ptr));
+ }
+ finally
+ {
+ gch.Free();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs.meta
new file mode 100644
index 00000000..c46ce4b1
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiInput.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 324be2ea40d796c49b74c60b8c2e5c97
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs
new file mode 100644
index 00000000..a7b7c9c4
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace PortMidi
+{
+ public struct MidiMessage
+ {
+ private int v;
+ public MidiMessage(int value)
+ {
+ v = value;
+ }
+
+ public MidiMessage(int status, int data1, int data2)
+ {
+ v = ((data2 << 16) & 0xFF0000) | ((data1 << 8) & 0xFF00) | (status & 0xFF);
+ }
+
+ public Int32 Value => v;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs.meta
new file mode 100644
index 00000000..02f67375
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiMessage.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c18643a5c49be3649ade32f7c9b19e99
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs
new file mode 100644
index 00000000..fe56081c
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace PortMidi
+{
+ public class MidiOutput : MidiStream
+ {
+ public MidiOutput(IntPtr stream, Int32 outputDevice, int latency)
+ : base(stream, outputDevice)
+ {
+ }
+
+ public void Write(MidiEvent midiEvent)
+ {
+ if (midiEvent.SysEx != null)
+ {
+ WriteSysEx(midiEvent.Timestamp, midiEvent.SysEx);
+ }
+ else
+ {
+ Write(midiEvent.Timestamp, midiEvent.Message);
+ }
+ }
+
+ private void Write(Int32 when, MidiMessage msg)
+ {
+ var ret = PortMidiMarshal.Pm_WriteShort(stream, when, msg);
+ if (ret != MidiErrorType.NoError)
+ {
+ throw new MidiException(ret,
+ $"Failed to write message {msg.Value} : {PortMidiMarshal.Pm_GetErrorText((MidiErrorType) ret)}");
+ }
+ }
+
+ private void WriteSysEx(Int32 when, byte[] sysEx)
+ {
+ var ret = PortMidiMarshal.Pm_WriteSysEx(stream, when, sysEx);
+ if (ret != MidiErrorType.NoError)
+ throw new MidiException(ret,
+ $"Failed to write sysEx message : {PortMidiMarshal.Pm_GetErrorText((MidiErrorType) ret)}");
+ }
+
+ public void Write(MidiEvent[] buffer)
+ {
+ Write(buffer, 0, buffer.Length);
+ }
+
+ private void Write(MidiEvent[] buffer, int index, int length)
+ {
+ var gch = GCHandle.Alloc(buffer);
+ try
+ {
+ var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, index);
+ var ret = PortMidiMarshal.Pm_Write(stream, ptr, length);
+ if (ret != MidiErrorType.NoError)
+ {
+ throw new MidiException(ret,
+ $"Failed to write messages : {PortMidiMarshal.Pm_GetErrorText((MidiErrorType) ret)}");
+ }
+ }
+ finally
+ {
+ gch.Free();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs.meta
new file mode 100644
index 00000000..cc6a9a22
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiOutput.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a806da9b51653af47b83c3c10a6eed65
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs
new file mode 100644
index 00000000..e4d80447
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace PortMidi
+{
+ public abstract class MidiStream : IDisposable
+ {
+ internal IntPtr stream;
+ internal Int32 device;
+
+ protected MidiStream(IntPtr stream, Int32 deviceID)
+ {
+ this.stream = stream;
+ this.device = deviceID;
+ }
+
+ public void Abort()
+ {
+ PortMidiMarshal.Pm_Abort(stream);
+ }
+
+ public void Close()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ PortMidiMarshal.Pm_Close(stream);
+ }
+
+ public void SetFilter(MidiFilter filters)
+ {
+ PortMidiMarshal.Pm_SetFilter(stream, filters);
+ }
+
+ public void SetChannelMask(int mask)
+ {
+ PortMidiMarshal.Pm_SetChannelMask(stream, mask);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs.meta
new file mode 100644
index 00000000..a16d7e5c
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiStream.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f858f0a52902aaf4298247159434e1ae
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs
new file mode 100644
index 00000000..c0a21dc2
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs
@@ -0,0 +1,7 @@
+using System;
+using PmTimestamp = System.Int32;
+
+namespace PortMidi
+{
+ public delegate PmTimestamp MidiTimeProcDelegate(IntPtr timeInfo);
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs.meta
new file mode 100644
index 00000000..79fb10f5
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/MidiTimeProcDelegate.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63050b27ae9f6ab4cb3837f915f15067
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins.meta
new file mode 100644
index 00000000..9828731f
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 743cfca463c6cc94fabfda636f4eb439
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows.meta
new file mode 100644
index 00000000..fe5fb2cb
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bc4d155a8e6f6f144871b6ee03542b7c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll
new file mode 100644
index 00000000..ba5be4e5
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll
Binary files differ
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll.meta
new file mode 100644
index 00000000..36f81d69
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/Plugins/Windows/portmidi.dll.meta
@@ -0,0 +1,96 @@
+fileFormatVersion: 2
+guid: 372656c38e5c12f48b819e12fa08ac7b
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ '': Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 0
+ Exclude Linux: 0
+ Exclude Linux64: 0
+ Exclude LinuxUniversal: 0
+ Exclude OSXUniversal: 0
+ Exclude WebGL: 1
+ Exclude Win: 0
+ Exclude Win64: 0
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: AnyOS
+ - first:
+ Facebook: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Facebook: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Linux
+ second:
+ enabled: 1
+ settings:
+ CPU: x86
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 1
+ settings:
+ CPU: x86_64
+ - first:
+ Standalone: LinuxUniversal
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs
new file mode 100644
index 00000000..e2ecccdd
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace PortMidi
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PmDeviceInfo
+ {
+ public int StructVersion;
+ public IntPtr Interface;
+ public IntPtr Name;
+ public int Input;
+ public int Output;
+ public int Opened;
+
+ public override string ToString()
+ {
+ return $"{StructVersion}, {Interface}, {Name}, {Input}, {Output}, {Opened}";
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs.meta
new file mode 100644
index 00000000..048fa702
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmDeviceInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e20f952b815e0fd4c89e244be795b605
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs
new file mode 100644
index 00000000..b5d68bce
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs
@@ -0,0 +1,11 @@
+using PmMessage = System.Int32;
+using PmTimestamp = System.Int32;
+
+namespace PortMidi
+{
+ public struct PmEvent
+ {
+ public PmMessage message;
+ public PmTimestamp timestamp;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs.meta
new file mode 100644
index 00000000..d8ec66ee
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PmEvent.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 36b7824d7ad3b3f4fbb5ed6d2a5766ec
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs
new file mode 100644
index 00000000..58f02e11
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace PortMidi
+{
+ internal class PortMidiMarshal
+ {
+ private const int Hdrlength = 50;
+ private const uint PmHostErrorMsgLen = 256;
+ const int PmNoDevice = -1;
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_Initialize();
+
+ [DllImport("portmidi")]
+ public static extern IntPtr Pm_GetDeviceInfo(Int32 id);
+
+ [DllImport("portmidi")]
+ public static extern int Pm_CountDevices();
+
+ [DllImport("portmidi")]
+ public static extern Int32 Pm_GetDefaultInputDeviceID();
+
+ [DllImport("portmidi")]
+ public static extern Int32 Pm_GetDefaultOutputDeviceID();
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_OpenInput(
+ out IntPtr stream,
+ Int32 inputDevice,
+ IntPtr inputDriverInfo,
+ int bufferSize,
+ MidiTimeProcDelegate timeProc,
+ IntPtr timeInfo);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_OpenOutput(
+ out IntPtr stream,
+ Int32 outputDevice,
+ IntPtr outputDriverInfo,
+ int bufferSize,
+ MidiTimeProcDelegate time_proc,
+ IntPtr time_info,
+ int latency);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_SetFilter(IntPtr stream, MidiFilter filters);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_SetChannelMask(IntPtr stream, int mask);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_Poll(IntPtr stream);
+
+ [DllImport("portmidi")]
+ public static extern int Pm_Read(IntPtr stream, IntPtr buffer, int length);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_Write(IntPtr stream, IntPtr buffer, int length);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_WriteSysEx(IntPtr stream, Int32 when, byte[] msg);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_WriteShort(IntPtr stream, Int32 when, MidiMessage msg);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_Abort(IntPtr stream);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_Close(IntPtr stream);
+
+ [DllImport("portmidi")]
+ public static extern MidiErrorType Pm_Terminate();
+
+ [DllImport("portmidi")]
+ public static extern int Pm_HasHostError(IntPtr stream);
+
+ [DllImport("portmidi")]
+ public static extern string Pm_GetErrorText(MidiErrorType errnum);
+
+ [DllImport("portmidi")]
+ public static extern void Pm_GetHostErrorText(IntPtr msg, uint len);
+
+ public static int Pm_Channel(int channel)
+ {
+ return 1 << channel;
+ }
+
+ public static int Pm_MessageStatus(int msg)
+ {
+ return msg & 0xFF;
+ }
+
+ public static int Pm_MessageData1(int msg)
+ {
+ return (msg >> 8) & 0xFF;
+ }
+
+ public static int Pm_MessageData2(int msg)
+ {
+ return (msg >> 16) & 0xFF;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs.meta
new file mode 100644
index 00000000..09c36972
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/PortMidi/PortMidiMarshal.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5d4b9d0d9dfad1c4894df5c2a5530696
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs
new file mode 100644
index 00000000..e4a6200b
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs
@@ -0,0 +1,116 @@
+#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) && !UNITY_ANDROID
+using System;
+using System.Collections.Generic;
+using System.Linq;
+#if VRC_CLIENT
+using VRC.Core;
+#endif
+using PortMidi;
+using UnityEngine;
+using VRC.SDK3.Midi;
+
+
+namespace VRC.SDKBase.Midi
+{
+ public class VRCPortMidiInput: IVRCMidiInput
+ {
+
+ private MidiInput _input;
+ private byte[] _data;
+ private MidiDeviceInfo _info;
+
+ public bool OpenDevice(string name = null)
+ {
+ try
+ {
+ if (!string.IsNullOrWhiteSpace(name))
+ {
+ _info = MidiDeviceManager.AllDevices.FirstOrDefault(device =>
+ device.IsInput && device.Name.ToLower().Contains(name.ToLower()));
+ }
+ else
+ {
+ _info = MidiDeviceManager.AllDevices.FirstOrDefault(device =>
+ device.ID == MidiDeviceManager.DefaultInputDeviceId);
+ }
+
+ _input = MidiDeviceManager.OpenInput(_info.ID);
+ _input.SetFilter(MidiFilter.Active | MidiFilter.SysEx | MidiFilter.Clock | MidiFilter.Play | MidiFilter.Tick | MidiFilter.Undefined | MidiFilter.Reset | MidiFilter.RealTime | MidiFilter.AF | MidiFilter.Program | MidiFilter.PitchBend | MidiFilter.SystemCommon);
+ _data = new byte[1024];
+ return true;
+ }
+ catch (Exception e)
+ {
+ #if VRC_CLIENT
+ VRC.Core.Logger.LogError($"Error opening Default Device: {e.Message}");
+ #else
+ Debug.Log($"Error opening Default Device: {e.Message}");
+ #endif
+ return false;
+ }
+ }
+
+ public void Close()
+ {
+ if (_input != null)
+ {
+ _input.Close();
+ }
+ }
+
+ public void Update()
+ {
+ if (_input == null) return;
+
+ if (_input.HasData)
+ {
+ // Portmidi reports 4 bytes per event but the buffer has 8 bytes so we multiply count by 2
+ int count = (_input.Read(_data, 0, _data.Length)) * 2;
+ for (int i = 0; i < count; i+=8)
+ {
+ ConvertAndSend(_data[i], _data[i + 1], _data[i + 2]);
+ }
+ }
+ }
+
+ public IEnumerable<string> GetDeviceNames()
+ {
+ return MidiDeviceManager.AllDevices.Select(d => d.Name);
+ }
+
+ private void ConvertAndSend(byte status, byte data1, byte data2)
+ {
+ var command = status & 0xF0; // mask off all but top 4 bits
+
+ if (command >= 0x80 && command <= 0xE0) {
+ // it's a voice message
+ // find the channel by masking off all but the low 4 bits
+ var channel = status & 0x0F;
+
+ if (command == VRCMidiHandler.STATUS_NOTE_ON || command == VRCMidiHandler.STATUS_NOTE_OFF || command == VRCMidiHandler.STATUS_CONTROL_CHANGE)
+ {
+ OnMidiVoiceMessage?.Invoke(this, new MidiVoiceEventArgs(command, channel, data1, data2));
+ }
+ else
+ {
+#if VRC_CLIENT
+ VRC.Core.Logger.Log($"command:{command} channel:{channel} data1:{data1} data2:{data2}");
+#else
+ Debug.Log($"command:{command} channel:{channel} data1:{data1} data2:{data2}");
+#endif
+ }
+
+ }
+ else
+ {
+ // it's a system message, ignore for now
+ OnMidiRawMessage?.Invoke(this, new MidiRawEventArgs(status, data1, data2));
+ }
+ }
+
+ public string Name => _info.Name;
+ public event MidiVoiceMessageDelegate OnMidiVoiceMessage;
+ public event MidiRawMessageDelegate OnMidiRawMessage;
+ }
+}
+#endif \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs.meta
new file mode 100644
index 00000000..156b4665
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: fb33369bfa554472b08fc6828450a2c4
+timeCreated: 1607454401 \ No newline at end of file
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs
new file mode 100644
index 00000000..79228fad
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs
@@ -0,0 +1,1069 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using JetBrains.Annotations;
+using UnityEngine;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+using UnityEngine.Video;
+#if VRC_SDK_VRCSDK3
+using VRC.SDK3.Components;
+using TMPro;
+#endif
+#if UDON
+using VRC.Udon;
+
+#endif
+#if !VRC_CLIENT && UNITY_EDITOR && VRC_SDK_VRCSDK3
+using UnityEditor;
+using UnityEngine.SceneManagement;
+#endif
+
+namespace VRC.Core
+{
+ public static class UnityEventFilter
+ {
+ // These types are will always be prohibited even if they are derived from an allowed type.
+ private static readonly HashSet<Type> _prohibitedUIEventTargetTypes = new HashSet<Type>
+ {
+ #if VRC_CLIENT
+ typeof(RenderHeads.Media.AVProVideo.MediaPlayer),
+ #endif
+ #if VRC_SDK_VRCSDK3
+ typeof(VRCUrlInputField),
+ #endif
+ typeof(VideoPlayer)
+ };
+
+ private static readonly Lazy<Dictionary<Type, AllowedMethodFilter>> _allowedUnityEventTargetTypes =
+ new Lazy<Dictionary<Type, AllowedMethodFilter>>(GetRuntimeUnityEventTargetAccessFilterDictionary);
+
+ private static Dictionary<Type, AllowedMethodFilter> AllowedUnityEventTargetTypes => _allowedUnityEventTargetTypes.Value;
+
+ private static readonly Lazy<int> _debugLevel = new Lazy<int>(InitializeLogging);
+ private static int DebugLevel => _debugLevel.Value;
+
+ // Builds a HashSet of allowed types, and their derived types, and removes explicitly prohibited types.
+ private static Dictionary<Type, AllowedMethodFilter> GetRuntimeUnityEventTargetAccessFilterDictionary()
+ {
+ Dictionary<Type, AllowedMethodFilter> accessFilterDictionary = new Dictionary<Type, AllowedMethodFilter>(_initialTargetAccessFilters);
+ AddDerivedTypes(accessFilterDictionary);
+ RemoveProhibitedTypes(accessFilterDictionary);
+
+ #if VERBOSE_EVENT_SANITIZATION_LOGGING
+ StringBuilder stringBuilder = new StringBuilder();
+ foreach(KeyValuePair<Type, AllowedMethodFilter> entry in accessFilterDictionary)
+ {
+ stringBuilder.AppendLine(entry.Key.FullName);
+ AllowedMethodFilter targetMethodAccessFilter = entry.Value;
+ foreach(string targetMethod in targetMethodAccessFilter.GetTargetMethodNames())
+ {
+ stringBuilder.AppendLine($" {targetMethod}");
+ }
+
+ stringBuilder.AppendLine();
+ }
+
+ VerboseLog(stringBuilder.ToString());
+ #endif
+
+ return accessFilterDictionary;
+ }
+
+ #if !VRC_CLIENT && UNITY_EDITOR && VRC_SDK_VRCSDK3
+ [RuntimeInitializeOnLoadMethod]
+ private static void SetupPlayMode()
+ {
+ EditorApplication.playModeStateChanged += RunFilteringOnPlayModeEntry;
+ }
+
+ private static void RunFilteringOnPlayModeEntry(PlayModeStateChange playModeStateChange)
+ {
+ switch(playModeStateChange)
+ {
+ case PlayModeStateChange.EnteredPlayMode:
+ {
+ for(int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++)
+ {
+ Scene currentScene = SceneManager.GetSceneAt(sceneIndex);
+ List<GameObject> rootGameObjects = new List<GameObject>();
+ currentScene.GetRootGameObjects(rootGameObjects);
+
+ FilterEvents(rootGameObjects);
+ }
+
+ break;
+ }
+ case PlayModeStateChange.EnteredEditMode:
+ case PlayModeStateChange.ExitingEditMode:
+ case PlayModeStateChange.ExitingPlayMode:
+ {
+ return;
+ }
+ default:
+ {
+ throw new ArgumentOutOfRangeException(nameof(playModeStateChange), playModeStateChange, null);
+ }
+ }
+ }
+ #endif
+
+ private static int InitializeLogging()
+ {
+ int hashCode = typeof(UnityEventFilter).GetHashCode();
+ Logger.DescribeDebugLevel(hashCode, "UnityEventFilter", Logger.Color.red);
+ Logger.AddDebugLevel(hashCode);
+ return hashCode;
+ }
+
+ [PublicAPI]
+ public static void FilterEvents(GameObject gameObject)
+ {
+ FilterUIEvents(gameObject);
+ FilterEventTriggerEvents(gameObject);
+ FilterAnimatorEvents(gameObject);
+ }
+
+ [PublicAPI]
+ public static void FilterEvents(List<GameObject> gameObjects)
+ {
+ FilterUIEvents(gameObjects);
+ FilterEventTriggerEvents(gameObjects);
+ FilterAnimatorEvents(gameObjects);
+ }
+
+ [PublicAPI]
+ public static void FilterUIEvents(GameObject gameObject)
+ {
+ List<UIBehaviour> uiBehaviours = new List<UIBehaviour>();
+ gameObject.GetComponentsInChildren(true, uiBehaviours);
+
+ FilterUIBehaviourEvents(uiBehaviours);
+ }
+
+ [PublicAPI]
+ public static void FilterUIEvents(List<GameObject> gameObjects)
+ {
+ HashSet<UIBehaviour> uiBehaviours = new HashSet<UIBehaviour>();
+ List<UIBehaviour> uiBehavioursWorkingList = new List<UIBehaviour>();
+ foreach(GameObject gameObject in gameObjects)
+ {
+ gameObject.GetComponentsInChildren(true, uiBehavioursWorkingList);
+ uiBehaviours.UnionWith(uiBehavioursWorkingList);
+ }
+
+ FilterUIBehaviourEvents(uiBehaviours);
+ }
+
+ [PublicAPI]
+ public static void FilterEventTriggerEvents(GameObject gameObject)
+ {
+ List<EventTrigger> eventTriggers = new List<EventTrigger>();
+ gameObject.GetComponentsInChildren(true, eventTriggers);
+
+ FilterEventTriggerEvents(eventTriggers);
+ }
+
+ [PublicAPI]
+ public static void FilterEventTriggerEvents(List<GameObject> gameObjects)
+ {
+ HashSet<EventTrigger> eventTriggers = new HashSet<EventTrigger>();
+ List<EventTrigger> eventTriggerWorkingList = new List<EventTrigger>();
+ foreach(GameObject gameObject in gameObjects)
+ {
+ gameObject.GetComponentsInChildren(true, eventTriggerWorkingList);
+ eventTriggers.UnionWith(eventTriggerWorkingList);
+ }
+
+ FilterEventTriggerEvents(eventTriggers);
+ }
+
+ [PublicAPI]
+ public static void FilterAnimatorEvents(GameObject gameObject)
+ {
+ List<Animator> animators = new List<Animator>();
+ gameObject.GetComponentsInChildren(true, animators);
+
+ FilterAnimatorEvents(animators);
+ }
+
+ [PublicAPI]
+ public static void FilterAnimatorEvents(List<GameObject> gameObjects)
+ {
+ HashSet<Animator> animators = new HashSet<Animator>();
+ List<Animator> animatorsWorkingList = new List<Animator>();
+ foreach(GameObject gameObject in gameObjects)
+ {
+ gameObject.GetComponentsInChildren(true, animatorsWorkingList);
+ animators.UnionWith(animatorsWorkingList);
+ }
+
+ FilterAnimatorEvents(animators);
+ }
+
+ private static void FilterUIBehaviourEvents(IEnumerable<UIBehaviour> uiBehaviours)
+ {
+ Dictionary<Type, List<UIBehaviour>> uiBehavioursByType = new Dictionary<Type, List<UIBehaviour>>();
+ foreach(UIBehaviour uiBehaviour in uiBehaviours)
+ {
+ if(uiBehaviour == null)
+ {
+ continue;
+ }
+
+ Type uiBehaviourType = uiBehaviour.GetType();
+ if(!uiBehavioursByType.TryGetValue(uiBehaviourType, out List<UIBehaviour> uiBehavioursOfType))
+ {
+ uiBehavioursByType.Add(uiBehaviourType, new List<UIBehaviour> {uiBehaviour});
+ continue;
+ }
+
+ uiBehavioursOfType.Add(uiBehaviour);
+ }
+
+ foreach(KeyValuePair<Type, List<UIBehaviour>> uiBehavioursOfTypeKvp in uiBehavioursByType)
+ {
+ Type uiBehaviourType = uiBehavioursOfTypeKvp.Key;
+ FieldInfo[] fieldInfos = uiBehaviourType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
+ List<FieldInfo> unityEventFieldInfos = new List<FieldInfo>();
+ foreach(FieldInfo fieldInfo in fieldInfos)
+ {
+ if(typeof(UnityEventBase).IsAssignableFrom(fieldInfo.FieldType))
+ {
+ unityEventFieldInfos.Add(fieldInfo);
+ }
+ }
+
+ if(unityEventFieldInfos.Count <= 0)
+ {
+ continue;
+ }
+
+ FieldInfo persistentCallsGroupFieldInfo = typeof(UnityEventBase).GetField("m_PersistentCalls", BindingFlags.Instance | BindingFlags.NonPublic);
+ if(persistentCallsGroupFieldInfo == null)
+ {
+ VerboseLog($"Could not find 'm_PersistentCalls' on UnityEventBase.");
+ return;
+ }
+
+ foreach(UIBehaviour uiBehaviour in uiBehavioursOfTypeKvp.Value)
+ {
+ VerboseLog($"Checking '{uiBehaviour.name} for UI Events.", uiBehaviour);
+ foreach(FieldInfo unityEventFieldInfo in unityEventFieldInfos)
+ {
+ VerboseLog($"Checking field '{unityEventFieldInfo.Name}' on '{uiBehaviour.name}.", uiBehaviour);
+ UnityEventBase unityEventBase = unityEventFieldInfo.GetValue(uiBehaviour) as UnityEventBase;
+ if(unityEventBase == null)
+ {
+ VerboseLog($"Null '{unityEventFieldInfo.Name}' UnityEvent on {uiBehaviour.name}.", uiBehaviour);
+ continue;
+ }
+
+ int numEventListeners = unityEventBase.GetPersistentEventCount();
+ VerboseLog($"There are '{numEventListeners}' on event '{unityEventFieldInfo.Name}' on '{uiBehaviour.name}.", uiBehaviour);
+ for(int index = 0; index < numEventListeners; index++)
+ {
+ string persistentMethodName = unityEventBase.GetPersistentMethodName(index);
+
+ UnityEngine.Object persistentTarget = unityEventBase.GetPersistentTarget(index);
+ if(persistentTarget == null)
+ {
+ VerboseLog($"The target for listener '{index}' on event '{unityEventFieldInfo.Name}' on '{uiBehaviour.name} is null.", uiBehaviour);
+ continue;
+ }
+
+ if(IsTargetPermitted(persistentTarget, persistentMethodName))
+ {
+ VerboseLog(
+ $"Allowing event '{unityEventFieldInfo.Name}' on '{uiBehaviour.name}' to call '{persistentMethodName}' on target '{persistentTarget.name}'.",
+ uiBehaviour);
+
+ continue;
+ }
+
+ LogRemoval(
+ $"Events on '{uiBehaviour.name}' were removed because one of them targeted a prohibited type '{persistentTarget.GetType().Name}', method '{persistentMethodName}' or object '{persistentTarget.name}'.",
+ uiBehaviour);
+
+ unityEventFieldInfo.SetValue(uiBehaviour, Activator.CreateInstance(unityEventBase.GetType()));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private static void FilterEventTriggerEvents(IEnumerable<EventTrigger> eventTriggers)
+ {
+ FieldInfo persistentCallsGroupFieldInfo = typeof(UnityEventBase).GetField("m_PersistentCalls", BindingFlags.Instance | BindingFlags.NonPublic);
+ if(persistentCallsGroupFieldInfo == null)
+ {
+ VerboseLog($"Could not find 'm_PersistentCalls' on UnityEventBase.");
+ return;
+ }
+
+ foreach(EventTrigger eventTrigger in eventTriggers)
+ {
+ VerboseLog($"Checking '{eventTrigger.name} for Unity Events.", eventTrigger);
+
+ List<EventTrigger.Entry> triggers = eventTrigger.triggers;
+ if(triggers.Count <= 0)
+ {
+ continue;
+ }
+
+ for(int i = triggers.Count - 1; i >= 0; i--)
+ {
+ EventTrigger.Entry entry = triggers[i];
+ UnityEventBase unityEventBase = entry.callback;
+ if(unityEventBase == null)
+ {
+ VerboseLog($"Null '{entry.eventID}' UnityEvent on {eventTrigger.name}.", eventTrigger);
+ continue;
+ }
+
+ int numEventListeners = unityEventBase.GetPersistentEventCount();
+ VerboseLog($"There are '{numEventListeners}' on event '{entry.eventID}' on '{eventTrigger.name}.", eventTrigger);
+ for(int index = 0; index < numEventListeners; index++)
+ {
+ string persistentMethodName = unityEventBase.GetPersistentMethodName(index);
+
+ UnityEngine.Object persistentTarget = unityEventBase.GetPersistentTarget(index);
+ if(persistentTarget == null)
+ {
+ VerboseLog($"The target for listener '{index}' on event '{entry.eventID}' on '{eventTrigger.name} is null.", eventTrigger);
+ continue;
+ }
+
+ if(IsTargetPermitted(persistentTarget, persistentMethodName))
+ {
+ VerboseLog(
+ $"Allowing event '{entry.eventID}' on '{eventTrigger.name}' to call '{persistentMethodName}' on target '{persistentTarget.name}'.",
+ eventTrigger);
+
+ continue;
+ }
+
+ LogRemoval(
+ $"Events on '{eventTrigger.name}' were removed because one of them targeted a prohibited type '{persistentTarget.GetType().Name}', method '{persistentMethodName}' or object '{persistentTarget.name}'.",
+ eventTrigger);
+
+ triggers.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ }
+
+ private static void FilterAnimatorEvents(IEnumerable<Animator> animators)
+ {
+ foreach(Animator animator in animators)
+ {
+ if(animator == null)
+ {
+ continue;
+ }
+
+ RuntimeAnimatorController animatorController = animator.runtimeAnimatorController;
+ if(animatorController == null)
+ {
+ return;
+ }
+
+ foreach(AnimationClip animationClip in animatorController.animationClips)
+ {
+ if(animationClip == null)
+ {
+ continue;
+ }
+
+ foreach(AnimationEvent animationEvent in animationClip.events)
+ {
+ if(animationEvent == null)
+ {
+ continue;
+ }
+
+ string animationEventFunctionName = animationEvent.functionName;
+ if(_allowedAnimationEventFunctionNames.Contains(animationEventFunctionName))
+ {
+ continue;
+ }
+
+ animationClip.events = null;
+ LogRemoval(
+ $"Removed AnimationEvents from AnimationClip used by the Animator on '{animator.gameObject}' because the event targets '{animationEventFunctionName}' which is not allowed.");
+
+ break;
+ }
+ }
+ }
+ }
+
+ [Conditional("VERBOSE_EVENT_SANITIZATION_LOGGING")]
+ private static void VerboseLog(string message, UnityEngine.Object target = null)
+ {
+ Logger.LogWarning(message, DebugLevel, target);
+ }
+
+ private static void LogRemoval(string message, UnityEngine.Object target = null)
+ {
+ Logger.LogWarning(message, DebugLevel, target);
+ }
+
+ private static bool IsTargetPermitted(UnityEngine.Object target, string targetMethod)
+ {
+ // Block anything blacklisted by Udon to prevent UnityEvents from being used to bypass the blacklist.
+ // NOTE: This will only block events targeting objects that are blacklisted before the UnityEventSanitizer is run.
+ // If objects are added to the blacklist after scene loading has finished it will be necessary to re-run the UnityEventSanitizer.
+ #if UDON
+ if(UdonManager.Instance.IsBlacklisted(target))
+ {
+ return false;
+ }
+ #endif
+
+ Type persistentTargetType = target.GetType();
+ if(!AllowedUnityEventTargetTypes.TryGetValue(persistentTargetType, out AllowedMethodFilter accessFilter))
+ {
+ return false;
+ }
+
+ return accessFilter.IsTargetMethodAllowed(targetMethod);
+ }
+
+ // Adds types derived from whitelisted types.
+ private static void AddDerivedTypes(Dictionary<Type, AllowedMethodFilter> accessFilterDictionary)
+ {
+ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ foreach(Assembly assembly in assemblies)
+ {
+ foreach(Type type in assembly.GetTypes())
+ {
+ if(accessFilterDictionary.ContainsKey(type))
+ {
+ continue;
+ }
+
+ if(!typeof(Component).IsAssignableFrom(type))
+ {
+ continue;
+ }
+
+ Type currentType = type;
+ while(currentType != typeof(object) && currentType != null)
+ {
+ if(accessFilterDictionary.TryGetValue(currentType, out AllowedMethodFilter accessFilter))
+ {
+ accessFilterDictionary.Add(type, accessFilter);
+ break;
+ }
+
+ currentType = currentType.BaseType;
+ }
+ }
+ }
+ }
+
+ // Removes prohibited types and types derived from them.
+ private static void RemoveProhibitedTypes(Dictionary<Type, AllowedMethodFilter> accessFilterDictionary)
+ {
+ foreach(Type prohibitedType in _prohibitedUIEventTargetTypes)
+ {
+ foreach(Type accessFilterType in accessFilterDictionary.Keys.ToArray())
+ {
+ if(prohibitedType.IsAssignableFrom(accessFilterType))
+ {
+ accessFilterDictionary.Remove(accessFilterType);
+ }
+ }
+ }
+ }
+
+ private static readonly Dictionary<Type, AllowedMethodFilter> _initialTargetAccessFilters = new Dictionary<Type, AllowedMethodFilter>
+ {
+ {
+ typeof(GameObject), new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(GameObject.SetActive)
+ },
+ new List<string>())
+ },
+ {
+ typeof(AudioSource),
+ new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(AudioSource.Pause),
+ nameof(AudioSource.Play),
+ nameof(AudioSource.PlayDelayed),
+ nameof(AudioSource.PlayOneShot),
+ nameof(AudioSource.Stop),
+ nameof(AudioSource.UnPause)
+ },
+ new List<string>
+ {
+ nameof(AudioSource.bypassEffects),
+ nameof(AudioSource.bypassListenerEffects),
+ nameof(AudioSource.bypassReverbZones),
+ nameof(AudioSource.dopplerLevel),
+ nameof(AudioSource.enabled),
+ nameof(AudioSource.loop),
+ nameof(AudioSource.maxDistance),
+ nameof(AudioSource.rolloffMode),
+ nameof(AudioSource.minDistance),
+ nameof(AudioSource.mute),
+ nameof(AudioSource.pitch),
+ nameof(AudioSource.playOnAwake),
+ nameof(AudioSource.priority),
+ nameof(AudioSource.spatialize),
+ nameof(AudioSource.spread),
+ nameof(AudioSource.time),
+ nameof(AudioSource.volume)
+ }
+ )
+ },
+ {
+ typeof(AudioDistortionFilter), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(AudioDistortionFilter.distortionLevel),
+ nameof(AudioDistortionFilter.enabled)
+ })
+ },
+ {
+ typeof(AudioEchoFilter), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(AudioEchoFilter.decayRatio),
+ nameof(AudioEchoFilter.delay),
+ nameof(AudioEchoFilter.dryMix),
+ nameof(AudioEchoFilter.enabled),
+ nameof(AudioEchoFilter.wetMix)
+ })
+ },
+ {
+ typeof(AudioHighPassFilter), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(AudioHighPassFilter.cutoffFrequency),
+ nameof(AudioHighPassFilter.enabled),
+ nameof(AudioHighPassFilter.highpassResonanceQ)
+ })
+ },
+ {
+ typeof(AudioLowPassFilter), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(AudioLowPassFilter.cutoffFrequency),
+ nameof(AudioLowPassFilter.enabled),
+ nameof(AudioLowPassFilter.lowpassResonanceQ)
+ })
+ },
+ {
+ typeof(AudioReverbFilter), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(AudioReverbFilter.decayHFRatio),
+ nameof(AudioReverbFilter.decayTime),
+ nameof(AudioReverbFilter.density),
+ nameof(AudioReverbFilter.diffusion),
+ nameof(AudioReverbFilter.dryLevel),
+ nameof(AudioReverbFilter.enabled),
+ nameof(AudioReverbFilter.hfReference),
+ nameof(AudioReverbFilter.reflectionsDelay),
+ nameof(AudioReverbFilter.reflectionsLevel),
+ nameof(AudioReverbFilter.reverbDelay),
+ nameof(AudioReverbFilter.reverbLevel),
+ nameof(AudioReverbFilter.room),
+ nameof(AudioReverbFilter.roomHF),
+ nameof(AudioReverbFilter.roomLF)
+ })
+ },
+ {
+ typeof(AudioReverbZone), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(AudioReverbZone.decayHFRatio),
+ nameof(AudioReverbZone.decayTime),
+ nameof(AudioReverbZone.density),
+ nameof(AudioReverbZone.diffusion),
+ nameof(AudioReverbZone.enabled),
+ nameof(AudioReverbZone.HFReference),
+ nameof(AudioReverbZone.LFReference),
+ nameof(AudioReverbZone.maxDistance),
+ nameof(AudioReverbZone.minDistance),
+ nameof(AudioReverbZone.reflections),
+ nameof(AudioReverbZone.reflectionsDelay),
+ nameof(AudioReverbZone.room),
+ nameof(AudioReverbZone.roomHF),
+ nameof(AudioReverbZone.roomLF)
+ })
+ },
+ #if UDON
+ {
+ typeof(UdonBehaviour), new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(UdonBehaviour.RunProgram),
+ nameof(UdonBehaviour.SendCustomEvent),
+ nameof(UdonBehaviour.Interact),
+ },
+ new List<string>()
+ {
+ nameof(UdonBehaviour.enabled)
+ })
+ },
+ #endif
+ {
+ typeof(MeshRenderer), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(MeshRenderer.shadowCastingMode),
+ nameof(MeshRenderer.enabled),
+ nameof(MeshRenderer.probeAnchor),
+ nameof(MeshRenderer.probeAnchor),
+ nameof(MeshRenderer.receiveShadows),
+ nameof(MeshRenderer.lightProbeUsage)
+ })
+ },
+ {
+ typeof(Collider), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Collider.enabled),
+ nameof(Collider.isTrigger)
+ })
+ },
+ {
+ typeof(SkinnedMeshRenderer), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(SkinnedMeshRenderer.allowOcclusionWhenDynamic),
+ nameof(SkinnedMeshRenderer.shadowCastingMode),
+ nameof(SkinnedMeshRenderer.enabled),
+ nameof(SkinnedMeshRenderer.lightProbeProxyVolumeOverride),
+ nameof(SkinnedMeshRenderer.motionVectorGenerationMode),
+ nameof(SkinnedMeshRenderer.probeAnchor),
+ nameof(SkinnedMeshRenderer.receiveShadows),
+ nameof(SkinnedMeshRenderer.rootBone),
+ nameof(SkinnedMeshRenderer.skinnedMotionVectors),
+ nameof(SkinnedMeshRenderer.updateWhenOffscreen),
+ nameof(SkinnedMeshRenderer.lightProbeUsage)
+ })
+ },
+ {
+ typeof(Light), new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(Light.Reset)
+ },
+ new List<string>
+ {
+ nameof(Light.bounceIntensity),
+ nameof(Light.colorTemperature),
+ nameof(Light.cookie),
+ nameof(Light.enabled),
+ nameof(Light.intensity),
+ nameof(Light.range),
+ nameof(Light.shadowBias),
+ nameof(Light.shadowNearPlane),
+ nameof(Light.shadowNormalBias),
+ nameof(Light.shadowStrength),
+ nameof(Light.spotAngle)
+ })
+ },
+ {
+ typeof(ParticleSystem), new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(ParticleSystem.Clear),
+ nameof(ParticleSystem.Emit),
+ nameof(ParticleSystem.Pause),
+ nameof(ParticleSystem.Pause),
+ nameof(ParticleSystem.Play),
+ nameof(ParticleSystem.Simulate),
+ nameof(ParticleSystem.Stop),
+ nameof(ParticleSystem.Stop),
+ nameof(ParticleSystem.TriggerSubEmitter)
+ },
+ new List<string>
+ {
+ nameof(ParticleSystem.time),
+ nameof(ParticleSystem.useAutoRandomSeed)
+ })
+ },
+ {
+ typeof(ParticleSystemForceField), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(ParticleSystemForceField.endRange),
+ nameof(ParticleSystemForceField.gravityFocus),
+ nameof(ParticleSystemForceField.length),
+ nameof(ParticleSystemForceField.multiplyDragByParticleSize),
+ nameof(ParticleSystemForceField.multiplyDragByParticleVelocity),
+ nameof(ParticleSystemForceField.startRange)
+ })
+ },
+ {
+ typeof(Projector), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Projector.aspectRatio),
+ nameof(Projector.enabled),
+ nameof(Projector.nearClipPlane),
+ nameof(Projector.farClipPlane),
+ nameof(Projector.fieldOfView),
+ nameof(Projector.orthographic),
+ nameof(Projector.orthographicSize)
+ })
+ },
+ {
+ typeof(LineRenderer), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(LineRenderer.allowOcclusionWhenDynamic),
+ nameof(LineRenderer.shadowCastingMode),
+ nameof(LineRenderer.enabled),
+ nameof(LineRenderer.endWidth),
+ nameof(LineRenderer.loop),
+ nameof(LineRenderer.motionVectorGenerationMode),
+ nameof(LineRenderer.numCapVertices),
+ nameof(LineRenderer.numCornerVertices),
+ nameof(LineRenderer.probeAnchor),
+ nameof(LineRenderer.receiveShadows),
+ nameof(LineRenderer.shadowBias),
+ nameof(LineRenderer.startWidth),
+ nameof(LineRenderer.lightProbeUsage),
+ nameof(LineRenderer.useWorldSpace),
+ nameof(LineRenderer.widthMultiplier)
+ })
+ },
+ {
+ typeof(TrailRenderer), new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(TrailRenderer.Clear)
+ },
+ new List<string>
+ {
+ nameof(TrailRenderer.allowOcclusionWhenDynamic),
+ nameof(TrailRenderer.autodestruct),
+ nameof(TrailRenderer.shadowCastingMode),
+ nameof(TrailRenderer.enabled),
+ nameof(TrailRenderer.emitting),
+ nameof(TrailRenderer.endWidth),
+ nameof(TrailRenderer.motionVectorGenerationMode),
+ nameof(TrailRenderer.numCapVertices),
+ nameof(TrailRenderer.numCornerVertices),
+ nameof(TrailRenderer.probeAnchor),
+ nameof(TrailRenderer.receiveShadows),
+ nameof(TrailRenderer.shadowBias),
+ nameof(TrailRenderer.startWidth),
+ nameof(TrailRenderer.lightProbeUsage),
+ nameof(TrailRenderer.widthMultiplier)
+ })
+ },
+ {
+ typeof(Animator), new AllowedMethodFilter(
+ new List<string>
+ {
+ nameof(Animator.Play),
+ nameof(Animator.PlayInFixedTime),
+ nameof(Animator.Rebind),
+ nameof(Animator.SetBool),
+ nameof(Animator.SetFloat),
+ nameof(Animator.SetInteger),
+ nameof(Animator.SetTrigger),
+ nameof(Animator.ResetTrigger)
+ },
+ new List<string>
+ {
+ nameof(Animator.speed),
+ nameof(Animator.enabled)
+ })
+ },
+ {
+ typeof(Text), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Text.alignByGeometry),
+ nameof(Text.enabled),
+ nameof(Text.fontSize),
+ nameof(Text.lineSpacing),
+ nameof(Text.maskable),
+ nameof(Text.raycastTarget),
+ nameof(Text.resizeTextForBestFit),
+ nameof(Text.resizeTextMaxSize),
+ nameof(Text.resizeTextMinSize),
+ nameof(Text.supportRichText),
+ nameof(Text.text)
+ })
+ },
+ {
+ typeof(Image), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Image.alphaHitTestMinimumThreshold),
+ nameof(Image.enabled),
+ nameof(Image.fillAmount),
+ nameof(Image.fillCenter),
+ nameof(Image.fillClockwise),
+ nameof(Image.fillOrigin),
+ nameof(Image.maskable),
+ nameof(Image.preserveAspect),
+ nameof(Image.raycastTarget),
+ nameof(Image.useSpriteMesh)
+ })
+ },
+ {
+ typeof(RawImage), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(RawImage.enabled),
+ nameof(RawImage.maskable),
+ nameof(RawImage.raycastTarget)
+ })
+ },
+ {
+ typeof(InputField), new AllowedMethodFilter(
+ new List<string>
+ {
+ "Append",
+ nameof(InputField.ForceLabelUpdate)
+ },
+ new List<string>
+ {
+ nameof(InputField.caretBlinkRate),
+ nameof(InputField.caretPosition),
+ nameof(InputField.caretWidth),
+ nameof(InputField.characterLimit),
+ nameof(InputField.customCaretColor),
+ nameof(InputField.enabled),
+ nameof(InputField.interactable),
+ nameof(InputField.readOnly),
+ nameof(InputField.selectionAnchorPosition),
+ nameof(InputField.text),
+ nameof(InputField.textComponent),
+ nameof(InputField.selectionFocusPosition)
+ })
+ },
+ {
+ typeof(Dropdown), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Dropdown.captionText),
+ nameof(Dropdown.enabled),
+ nameof(Dropdown.interactable),
+ nameof(Dropdown.itemText),
+ nameof(Dropdown.targetGraphic),
+ nameof(Dropdown.template),
+ nameof(Dropdown.value)
+ })
+ },
+ {
+ typeof(Slider), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Slider.enabled),
+ nameof(Slider.fillRect),
+ nameof(Slider.handleRect),
+ nameof(Slider.interactable),
+ nameof(Slider.maxValue),
+ nameof(Slider.minValue),
+ nameof(Slider.normalizedValue),
+ nameof(Slider.targetGraphic),
+ nameof(Slider.value),
+ nameof(Slider.wholeNumbers)
+ })
+ },
+ {
+ typeof(Toggle), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Toggle.enabled),
+ nameof(Toggle.group),
+ nameof(Toggle.interactable),
+ nameof(Toggle.isOn),
+ nameof(Toggle.targetGraphic)
+ })
+ },
+ {
+ typeof(Scrollbar), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Scrollbar.enabled),
+ nameof(Scrollbar.handleRect),
+ nameof(Scrollbar.interactable),
+ nameof(Scrollbar.numberOfSteps),
+ nameof(Scrollbar.size),
+ nameof(Scrollbar.targetGraphic),
+ nameof(Scrollbar.value)
+ })
+ },
+ {
+ typeof(ScrollRect), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(ScrollRect.content),
+ nameof(ScrollRect.decelerationRate),
+ nameof(ScrollRect.elasticity),
+ nameof(ScrollRect.enabled),
+ nameof(ScrollRect.horizontal),
+ nameof(ScrollRect.horizontalNormalizedPosition),
+ nameof(ScrollRect.horizontalScrollbar),
+ nameof(ScrollRect.horizontalScrollbarSpacing),
+ nameof(ScrollRect.inertia),
+ nameof(ScrollRect.scrollSensitivity),
+ nameof(ScrollRect.vertical),
+ nameof(ScrollRect.verticalNormalizedPosition),
+ nameof(ScrollRect.verticalScrollbar),
+ nameof(ScrollRect.verticalScrollbarSpacing),
+ nameof(ScrollRect.viewport)
+ })
+ },
+ {
+ typeof(Button), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Button.enabled),
+ nameof(Button.interactable),
+ nameof(Button.targetGraphic)
+ })
+ },
+ {
+ typeof(Mask), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Mask.enabled),
+ nameof(Mask.showMaskGraphic)
+ })
+ },
+ {
+ typeof(RectMask2D), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(RectMask2D.enabled)
+ })
+ },
+ {
+ typeof(Selectable), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(Selectable.enabled),
+ nameof(Selectable.interactable),
+ nameof(Selectable.targetGraphic)
+ })
+ },
+ {
+ typeof(ToggleGroup), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(ToggleGroup.allowSwitchOff),
+ nameof(ToggleGroup.enabled)
+ })
+ },
+ #if VRC_SDK_VRCSDK3 // only access Cinemachine and TMPro after install
+ {
+ typeof(TextMeshPro), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(TextMeshPro.text),
+ })
+ },
+ {
+ typeof(TextMeshProUGUI), new AllowedMethodFilter(
+ new List<string>(),
+ new List<string>
+ {
+ nameof(TextMeshProUGUI.text),
+ })
+ },
+ {
+ typeof(Cinemachine.CinemachineVirtualCamera), new AllowedMethodFilter(
+ new List<string>()
+ {
+ nameof(Cinemachine.CinemachineVirtualCamera.Priority),
+ },
+ new List<string>())
+ },
+ #endif
+ };
+
+ private static readonly HashSet<string> _allowedAnimationEventFunctionNames = new HashSet<string>
+ {
+ "RunProgram",
+ "SendCustomEvent",
+ "Play",
+ "Pause",
+ "Stop",
+ "PlayInFixedTime",
+ "Rebind",
+ "SetBool",
+ "SetFloat",
+ "SetInteger",
+ "SetTrigger",
+ "ResetTrigger",
+ "SetActive"
+ };
+
+ private class AllowedMethodFilter
+ {
+ private readonly HashSet<string> _allowedTargets;
+
+ [PublicAPI]
+ public AllowedMethodFilter(List<string> allowedTargetMethodNames, List<string> allowedTargetPropertyNames)
+ {
+ _allowedTargets = new HashSet<string>();
+ _allowedTargets.UnionWith(allowedTargetMethodNames);
+ foreach(string allowedTargetProperty in allowedTargetPropertyNames)
+ {
+ _allowedTargets.Add($"get_{allowedTargetProperty}");
+ _allowedTargets.Add($"set_{allowedTargetProperty}");
+ }
+ }
+
+ public bool IsTargetMethodAllowed(string targetMethodName)
+ {
+ return _allowedTargets.Contains(targetMethodName);
+ }
+
+ #if VERBOSE_EVENT_SANITIZATION_LOGGING
+ public List<string> GetTargetMethodNames()
+ {
+ return _allowedTargets.ToList();
+ }
+ #endif
+ }
+ }
+}
diff --git a/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs.meta b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs.meta
new file mode 100644
index 00000000..5137d5fe
--- /dev/null
+++ b/VRCSDK3Worlds/Assets/VRCSDK/SDK3/Runtime/UnityEventFilter.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 87f13d6a98e54fb78ca47650a29029a5
+timeCreated: 1594690552 \ No newline at end of file