268 lines
9.6 KiB
C#

/*
* ExternalReceiver
* https://sabowl.sakura.ne.jp/gpsnmeajp/
*
* MIT License
*
* Copyright (c) 2019 gpsnmeajp
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma warning disable 0414,0219
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Profiling;
namespace EVMC4U
{
public class InputReceiver : MonoBehaviour, IExternalReceiver
{
[Header("InputReceiver v1.1")]
[SerializeField, Label("動作状況")]
private string StatusMessage = ""; //Inspector表示用
[SerializeField, Label("最終入力")]
private string LastInput = "";
#if EVMC4U_JA
[Header("入力イベント")]
#else
[Header("Event Callback")]
#endif
public KeyInputEvent KeyInputAction = new KeyInputEvent(); //キーボード入力イベント
public ControllerInputEvent ControllerInputAction = new ControllerInputEvent(); //コントローラボタンイベント
public MidiNoteInputEvent MidiNoteInputAction = new MidiNoteInputEvent();
public MidiCCValueInputEvent MidiCCValueInputAction = new MidiCCValueInputEvent();
public MidiCCButtonInputEvent MidiCCButtonInputAction = new MidiCCButtonInputEvent();
#if EVMC4U_JA
[Header("MIDI CC モニタ(つまみ、ボタン)")]
#else
[Header("MIDI CC Monitor")]
#endif
public float[] CCValuesMonitor = new float[128];
#if EVMC4U_JA
[Header("デイジーチェーン")]
#else
[Header("Daisy Chain")]
#endif
public GameObject[] NextReceivers = new GameObject[1];
//---
//入力辞書(コールバックではなく定値で取得したい場合に使う)
public Dictionary<string, bool> InputDictionary = new Dictionary<string, bool>();
//---
private ExternalReceiverManager externalReceiverManager = null;
bool shutdown = false;
//メッセージ処理一時変数struct(負荷対策)
ControllerInput con;
KeyInput key;
MidiNote note;
MidiCCValue ccvalue;
MidiCCButton ccbutton;
void Start()
{
externalReceiverManager = new ExternalReceiverManager(NextReceivers);
StatusMessage = "Waiting for Master...";
//強制
CCValuesMonitor = new float[128];
}
//デイジーチェーンを更新
public void UpdateDaisyChain()
{
externalReceiverManager.GetIExternalReceiver(NextReceivers);
}
public void MessageDaisyChain(ref uOSC.Message message, int callCount)
{
//Startされていない場合無視
if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false)
{
return;
}
if (shutdown)
{
return;
}
StatusMessage = "OK";
//異常を検出して動作停止
try
{
ProcessMessage(ref message);
}
catch (Exception e)
{
StatusMessage = "Error: Exception";
Debug.LogError(" --- Communication Error ---");
Debug.LogError(e.ToString());
shutdown = true;
return;
}
if (!externalReceiverManager.SendNextReceivers(message, callCount))
{
StatusMessage = "Infinite loop detected!";
shutdown = true;
}
}
private void ProcessMessage(ref uOSC.Message message)
{
//メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない
if (message.address == null || message.values == null)
{
StatusMessage = "Bad message.";
return;
}
//コントローラ操作情報 v2.1
if (message.address == "/VMC/Ext/Con"
&& (message.values[0] is int)
&& (message.values[1] is string)
&& (message.values[2] is int)
&& (message.values[3] is int)
&& (message.values[4] is int)
&& (message.values[5] is float)
&& (message.values[6] is float)
&& (message.values[7] is float)
)
{
con.active = (int)message.values[0];
con.name = (string)message.values[1];
con.IsLeft = (int)message.values[2];
con.IsTouch = (int)message.values[3];
con.IsAxis = (int)message.values[4];
con.Axis.x = (float)message.values[5];
con.Axis.y = (float)message.values[6];
con.Axis.z = (float)message.values[7];
//イベントを呼び出す
if (ControllerInputAction != null)
{
ControllerInputAction.Invoke(con);
}
if (con.IsAxis == 0) {
if (con.IsLeft == 1)
{
LastInput = "Left-" + con.name + " = " + con.active;
InputDictionary["Left-" + con.name] = (con.active != 0);
}
else
{
LastInput = "Right-" + con.name + " = " + con.active;
InputDictionary["Right-" + con.name] = (con.active != 0);
}
}
}
//キーボード操作情報 v2.1
else if (message.address == "/VMC/Ext/Key"
&& (message.values[0] is int)
&& (message.values[1] is string)
&& (message.values[2] is int)
)
{
key.active = (int)message.values[0];
key.name = (string)message.values[1];
key.keycode = (int)message.values[2];
//イベントを呼び出す
if (KeyInputAction != null)
{
KeyInputAction.Invoke(key);
}
LastInput = "Key-" + key.name +" = "+key.active + " (" + key.keycode + ")";
}
// v2.2
else if (message.address == "/VMC/Ext/Midi/Note"
&& (message.values[0] is int)
&& (message.values[1] is int)
&& (message.values[2] is int)
&& (message.values[3] is float)
)
{
note.active = (int)message.values[0];
note.channel = (int)message.values[1];
note.note = (int)message.values[2];
note.velocity = (float)message.values[3];
//イベントを呼び出す
if (MidiNoteInputAction != null)
{
MidiNoteInputAction.Invoke(note);
}
LastInput = "Note-" + note.note + " = "+note.active + "/" + note.channel + "/" + note.velocity;
InputDictionary["Note-" + note.note] = (note.active != 0);
}
// v2.2
else if (message.address == "/VMC/Ext/Midi/CC/Val"
&& (message.values[0] is int)
&& (message.values[1] is float)
)
{
ccvalue.knob = (int)message.values[0];
ccvalue.value = (float)message.values[1];
//イベントを呼び出す
if (MidiCCValueInputAction != null)
{
MidiCCValueInputAction.Invoke(ccvalue);
}
LastInput = "CC Val " + ccvalue.knob + " = " + ccvalue.value;
if (ccvalue.knob >= 0 && ccvalue.knob < 128) {
CCValuesMonitor[ccvalue.knob] = ccvalue.value;
}
}
// v2.2
else if (message.address == "/VMC/Ext/Midi/CC/Bit"
&& (message.values[0] is int)
&& (message.values[1] is int)
)
{
ccbutton.knob = (int)message.values[0];
ccbutton.active = (int)message.values[1];
//イベントを呼び出す
if (MidiCCButtonInputAction != null)
{
MidiCCButtonInputAction.Invoke(ccbutton);
}
LastInput = "CC-" + ccbutton.knob + " = " + ccbutton.active;
InputDictionary["CC-" + ccbutton.knob] = (ccbutton.active != 0);
}
}
}
}