├── MidiBridge.cs ├── MidiInput.cs ├── MidiOut.cs ├── README.md ├── midi-bridge-osx.zip └── midi-bridge-windows.zip /MidiBridge.cs: -------------------------------------------------------------------------------- 1 | // 2 | // MidiBridge.cs - C# interface for MIDI Bridge 3 | // 4 | // Copyright (C) 2013 Keijiro Takahashi 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | // this software and associated documentation files (the "Software"), to deal in 8 | // the Software without restriction, including without limitation the rights to 9 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | // the Software, and to permit persons to whom the Software is furnished to do so, 11 | // subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | // 23 | using UnityEngine; 24 | using System.Collections; 25 | using System.Collections.Generic; 26 | using System.Net.Sockets; 27 | using System.Net; 28 | 29 | public class MidiBridge : MonoBehaviour 30 | { 31 | #region Public interface 32 | 33 | public struct Message 34 | { 35 | public byte status; 36 | public byte data1; 37 | public byte data2; 38 | 39 | public Message (byte status, byte data1, byte data2) 40 | { 41 | this.status = status; 42 | this.data1 = data1; 43 | this.data2 = data2; 44 | } 45 | 46 | public override string ToString () 47 | { 48 | return string.Format ("s({0:X2}) d({1:X2},{2:X2})", status, data1, data2); 49 | } 50 | } 51 | 52 | public Queue incomingMessageQueue; 53 | 54 | public void Send (int status, int data1 = 0xff, int data2 = 0xff) 55 | { 56 | if (tcpClient != null && tcpClient.Connected) { 57 | smallBuffer [0] = (byte)status; 58 | smallBuffer [1] = (byte)data1; 59 | smallBuffer [2] = (byte)data2; 60 | smallBuffer [3] = 0xff; 61 | try { 62 | tcpClient.GetStream ().Write (smallBuffer, 0, 4); 63 | } catch (System.IO.IOException exception) { 64 | Debug.Log (exception); 65 | } 66 | } 67 | } 68 | 69 | public void Warmup() 70 | { 71 | // Do nothing! 72 | } 73 | 74 | #endregion 75 | 76 | #region Monobehaviour functions 77 | 78 | void Awake () 79 | { 80 | incomingMessageQueue = new Queue (); 81 | smallBuffer = new byte[4]; 82 | } 83 | 84 | void Start () 85 | { 86 | StartCoroutine (ConnectionCoroutine ()); 87 | StartCoroutine (ReceiverCoroutine ()); 88 | } 89 | 90 | #endregion 91 | 92 | #region TCP connection 93 | 94 | // Port number used to communicate with Bridge. 95 | const int portNumber = 52364; 96 | 97 | // TCP connection. 98 | TcpClient tcpClient; 99 | bool isConnecting; 100 | 101 | // A small buffer used for sending messages. 102 | byte[] smallBuffer; 103 | 104 | // Coroutine for managing the connection. 105 | IEnumerator ConnectionCoroutine () 106 | { 107 | // "Active Sense" message for heartbeating. 108 | var heartbeat = new byte[4] {0xfe, 0xff, 0xff, 0xff}; 109 | 110 | while (true) { 111 | // Try to open the connection. 112 | for (var retryCount = 0;; retryCount++) { 113 | // Start to connect. 114 | var tempClient = new TcpClient (); 115 | tempClient.BeginConnect (IPAddress.Loopback, portNumber, ConnectCallback, null); 116 | // Wait for callback. 117 | isConnecting = true; 118 | while (isConnecting) { 119 | yield return null; 120 | } 121 | // Break if the connection is established. 122 | if (tempClient.Connected) { 123 | tcpClient = tempClient; 124 | break; 125 | } 126 | // Dispose the connection. 127 | tempClient.Close (); 128 | tempClient = null; 129 | // Show warning and wait a second. 130 | if (retryCount % 3 == 0) { 131 | Debug.LogWarning ("Failed to connect to MIDI Bridge."); 132 | } 133 | yield return new WaitForSeconds (1.0f); 134 | } 135 | 136 | // Watch the connection. 137 | while (tcpClient.Connected) { 138 | yield return new WaitForSeconds (1.0f); 139 | // Send a heartbeat and break if it failed. 140 | try { 141 | tcpClient.GetStream ().Write (heartbeat, 0, heartbeat.Length); 142 | } catch (System.IO.IOException exception) { 143 | Debug.Log (exception); 144 | } 145 | } 146 | 147 | // Show warning. 148 | Debug.LogWarning ("Disconnected from MIDI Bridge."); 149 | 150 | // Close the connection and retry. 151 | tcpClient.Close (); 152 | tcpClient = null; 153 | } 154 | } 155 | 156 | void ConnectCallback (System.IAsyncResult result) 157 | { 158 | isConnecting = false; 159 | } 160 | 161 | // Coroutine for receiving messages. 162 | IEnumerator ReceiverCoroutine () 163 | { 164 | byte[] buffer = new byte[2048]; 165 | 166 | while (true) { 167 | // Do nothing if the connection is not ready. 168 | if (tcpClient == null || !tcpClient.Connected || tcpClient.Available < 4) { 169 | yield return null; 170 | continue; 171 | } 172 | 173 | // Receive data from the socket. 174 | var available = Mathf.Min ((tcpClient.Available / 4) * 4, buffer.Length); 175 | var bufferFilled = tcpClient.GetStream ().Read (buffer, 0, available); 176 | 177 | for (var offset = 0; offset < bufferFilled; offset += 4) { 178 | incomingMessageQueue.Enqueue (new Message (buffer [offset], buffer [offset + 1], buffer [offset + 2])); 179 | } 180 | 181 | yield return null; 182 | } 183 | } 184 | 185 | #endregion 186 | 187 | #region Singleton class handling 188 | 189 | static MidiBridge _instance; 190 | 191 | public static MidiBridge instance { 192 | get { 193 | if (_instance == null) { 194 | var previous = FindObjectOfType (typeof(MidiBridge)); 195 | if (previous) { 196 | Debug.LogWarning ("Initialized twice. Don't use MidiBridge in the scene hierarchy."); 197 | _instance = (MidiBridge)previous; 198 | } else { 199 | var go = new GameObject ("__MidiBridge"); 200 | _instance = go.AddComponent (); 201 | DontDestroyOnLoad (go); 202 | go.hideFlags = HideFlags.HideInHierarchy; 203 | } 204 | } 205 | return _instance; 206 | } 207 | } 208 | 209 | #endregion 210 | } 211 | -------------------------------------------------------------------------------- /MidiInput.cs: -------------------------------------------------------------------------------- 1 | // 2 | // MidiInput.cs - MIDI input manager 3 | // 4 | // Copyright (C) 2013 Keijiro Takahashi 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | // this software and associated documentation files (the "Software"), to deal in 8 | // the Software without restriction, including without limitation the rights to 9 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | // the Software, and to permit persons to whom the Software is furnished to do so, 11 | // subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | // 23 | using UnityEngine; 24 | using System.Collections; 25 | using System.Collections.Generic; 26 | 27 | public enum MidiChannel 28 | { 29 | Ch1, // 0 30 | Ch2, // 1 31 | Ch3, 32 | Ch4, 33 | Ch5, 34 | Ch6, 35 | Ch7, 36 | Ch8, 37 | Ch9, 38 | Ch10, 39 | Ch11, 40 | Ch12, 41 | Ch13, 42 | Ch14, 43 | Ch15, 44 | Ch16, 45 | All // 16 46 | } 47 | 48 | public class MidiInput : MonoBehaviour 49 | { 50 | #region Public interface 51 | 52 | // Knob filter coefficient. 53 | public static float knobSensibility = 20.0f; 54 | 55 | // Returns the key state (on: velocity, off: zero). 56 | public static float GetKey (MidiChannel channel, int noteNumber) 57 | { 58 | var v = instance.channelArray [(int)channel].noteArray [noteNumber]; 59 | if (v > 1.0f) { 60 | return v - 1.0f; 61 | } else if (v > 0.0) { 62 | return v; 63 | } else { 64 | return 0.0f; 65 | } 66 | } 67 | 68 | public static float GetKey (int noteNumber) 69 | { 70 | return GetKey (MidiChannel.All, noteNumber); 71 | } 72 | 73 | // Returns true if the key was pressed down in the current frame. 74 | public static bool GetKeyDown (MidiChannel channel, int noteNumber) 75 | { 76 | return instance.channelArray [(int)channel].noteArray [noteNumber] > 1.0f; 77 | } 78 | 79 | public static bool GetKeyDown (int noteNumber) 80 | { 81 | return GetKeyDown (MidiChannel.All, noteNumber); 82 | } 83 | 84 | // Returns true if the key was released in the current frame. 85 | public static bool GetKeyUp (MidiChannel channel, int noteNumber) 86 | { 87 | return instance.channelArray [(int)channel].noteArray [noteNumber] < 0.0f; 88 | } 89 | 90 | public static bool GetKeyUp (int noteNumber) 91 | { 92 | return GetKeyUp (MidiChannel.All, noteNumber); 93 | } 94 | 95 | // Provides the CC (knob) list. 96 | public static int[] GetKnobNumbers (MidiChannel channel) 97 | { 98 | var cs = instance.channelArray [(int)channel]; 99 | var numbers = new int[cs.knobMap.Count]; 100 | cs.knobMap.Keys.CopyTo (numbers, 0); 101 | return numbers; 102 | } 103 | 104 | public static int[] GetKnobNumbers () 105 | { 106 | return GetKnobNumbers (MidiChannel.All); 107 | } 108 | 109 | // Get the CC (knob) value. 110 | public static float GetKnob (MidiChannel channel, int knobNumber) 111 | { 112 | var cs = instance.channelArray [(int)channel]; 113 | if (cs.knobMap.ContainsKey (knobNumber)) { 114 | return cs.knobMap [knobNumber].filteredValue; 115 | } else { 116 | return 0.0f; 117 | } 118 | } 119 | 120 | public static float GetKnob (int knobNumber) 121 | { 122 | return GetKnob (MidiChannel.All, knobNumber); 123 | } 124 | 125 | #endregion 126 | 127 | #region Internal data structure 128 | 129 | // CC (knob) state. 130 | class KnobState 131 | { 132 | public float realtimeValue; 133 | public float filteredValue; 134 | 135 | public KnobState (float initial) 136 | { 137 | realtimeValue = filteredValue = initial; 138 | } 139 | 140 | public void Update (float value) 141 | { 142 | realtimeValue = value; 143 | } 144 | 145 | public void UpdateFilter (float filterCoeff) 146 | { 147 | if (filterCoeff == 0.0f) { 148 | filteredValue = realtimeValue; 149 | } else { 150 | filteredValue = realtimeValue - (realtimeValue - filteredValue) * filterCoeff; 151 | } 152 | } 153 | } 154 | 155 | // Channel State. 156 | class ChannelState 157 | { 158 | // Note state array. 159 | // X<0 : Released on this frame. 160 | // X=0 : Off. 161 | // 0 knobMap; 167 | 168 | public ChannelState () 169 | { 170 | noteArray = new float[128]; 171 | knobMap = new Dictionary (); 172 | } 173 | } 174 | 175 | // Channel state array. 176 | ChannelState[] channelArray; 177 | 178 | #endregion 179 | 180 | #region Monobehaviour functions 181 | 182 | void Awake () 183 | { 184 | channelArray = new ChannelState[17]; 185 | for (var i = 0; i < 17; i++) { 186 | channelArray [i] = new ChannelState (); 187 | } 188 | } 189 | 190 | void Update () 191 | { 192 | // Update the note state array. 193 | foreach (var cs in channelArray) { 194 | for (var i = 0; i < 128; i++) { 195 | var x = cs.noteArray [i]; 196 | if (x > 1.0f) { 197 | // Key down -> Hold. 198 | cs.noteArray [i] = x - 1.0f; 199 | } else if (x < 0) { 200 | // Key up -> Off. 201 | cs.noteArray [i] = 0.0f; 202 | } 203 | } 204 | } 205 | 206 | // Calculate the filter coefficient. 207 | var filterCoeff = (knobSensibility > 0.0f) ? Mathf.Exp (-knobSensibility * Time.deltaTime) : 0.0f; 208 | 209 | // Update the filtered value. 210 | foreach (var cs in channelArray) { 211 | foreach (var k in cs.knobMap.Values) { 212 | k.UpdateFilter (filterCoeff); 213 | } 214 | } 215 | 216 | // Process the message queue. 217 | while (MidiBridge.instance.incomingMessageQueue.Count > 0) { 218 | // Pop from the queue. 219 | var message = MidiBridge.instance.incomingMessageQueue.Dequeue (); 220 | 221 | // Split the first byte. 222 | var statusCode = message.status >> 4; 223 | var channelNumber = message.status & 0xf; 224 | 225 | // Note on message? 226 | if (statusCode == 9) { 227 | var velocity = 1.0f / 127 * message.data2 + 1.0f; 228 | channelArray [channelNumber].noteArray [message.data1] = velocity; 229 | channelArray [(int)MidiChannel.All].noteArray [message.data1] = velocity; 230 | } 231 | 232 | // Note off message? 233 | if (statusCode == 8 || (statusCode == 9 && message.data2 == 0)) { 234 | channelArray [channelNumber].noteArray [message.data1] = -1.0f; 235 | channelArray [(int)MidiChannel.All].noteArray [message.data1] = -1.0f; 236 | } 237 | 238 | // CC message? 239 | if (statusCode == 0xb) { 240 | // Normalize the value. 241 | var value = 1.0f / 127 * message.data2; 242 | 243 | // Update the channel if it already exists, or add a new channel. 244 | if (channelArray [channelNumber].knobMap.ContainsKey (message.data1)) { 245 | channelArray [channelNumber].knobMap [message.data1].Update (value); 246 | } else { 247 | channelArray [channelNumber].knobMap [message.data1] = new KnobState (value); 248 | } 249 | 250 | // Do again for All-ch. 251 | if (channelArray [(int)MidiChannel.All].knobMap.ContainsKey (message.data1)) { 252 | channelArray [(int)MidiChannel.All].knobMap [message.data1].Update (value); 253 | } else { 254 | channelArray [(int)MidiChannel.All].knobMap [message.data1] = new KnobState (value); 255 | } 256 | } 257 | } 258 | } 259 | 260 | #endregion 261 | 262 | #region Singleton class handling 263 | 264 | static MidiInput _instance; 265 | 266 | public static MidiInput instance { 267 | get { 268 | if (_instance == null) { 269 | var previous = FindObjectOfType (typeof(MidiInput)); 270 | if (previous) { 271 | Debug.LogWarning ("Initialized twice. Don't use MidiInput in the scene hierarchy."); 272 | _instance = (MidiInput)previous; 273 | } else { 274 | var go = new GameObject ("__MidiInput"); 275 | _instance = go.AddComponent (); 276 | DontDestroyOnLoad (go); 277 | go.hideFlags = HideFlags.HideInHierarchy; 278 | } 279 | } 280 | return _instance; 281 | } 282 | } 283 | 284 | #endregion 285 | } 286 | -------------------------------------------------------------------------------- /MidiOut.cs: -------------------------------------------------------------------------------- 1 | // 2 | // MidiOut.cs - MIDI output manager 3 | // 4 | // Copyright (C) 2013 Keijiro Takahashi 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | // this software and associated documentation files (the "Software"), to deal in 8 | // the Software without restriction, including without limitation the rights to 9 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | // the Software, and to permit persons to whom the Software is furnished to do so, 11 | // subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | // 23 | using UnityEngine; 24 | 25 | public static class MidiOut 26 | { 27 | public static void SendNoteOn(MidiChannel channel, int noteNumber, float velocity) 28 | { 29 | int cn = Mathf.Clamp ((int)channel, 0, 15); 30 | noteNumber = Mathf.Clamp (noteNumber, 0, 127); 31 | velocity = Mathf.Clamp (127.0f * velocity, 0.0f, 127.0f); 32 | MidiBridge.instance.Send (0x90 + cn, noteNumber, (int)velocity); 33 | } 34 | 35 | public static void SendNoteOff(MidiChannel channel, int noteNumber) 36 | { 37 | int cn = Mathf.Clamp ((int)channel, 0, 15); 38 | noteNumber = Mathf.Clamp (noteNumber, 0, 127); 39 | MidiBridge.instance.Send (0x80 + cn, noteNumber, 0); 40 | } 41 | 42 | public static void SendControlChange(MidiChannel channel, int controlNumber, float value) 43 | { 44 | int cn = Mathf.Clamp ((int)channel, 0, 15); 45 | controlNumber = Mathf.Clamp (controlNumber, 0, 127); 46 | value = Mathf.Clamp (127.0f * value, 0.0f, 127.0f); 47 | MidiBridge.instance.Send (0xb0 + cn, controlNumber, (int)value); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Unity MIDI Bridge 2 | ================= 3 | 4 | **Unity MIDI Bridge** is a C# plug-in for Unity that provides APIs for 5 | communicating with MIDI devices. It sends and receives MIDI messages via the 6 | bridge software and doesn't need to deal with any native code. It means that 7 | you can access to the MIDI devices without Unity Pro license. 8 | 9 | System Requirements 10 | ------------------- 11 | 12 | - Unity 4 (Basic or Pro) 13 | - This plug-in runs only on the desktop platforms (Windows or Mac OS X). 14 | 15 | Sample Projects 16 | --------------- 17 | 18 | You can find some sample projects in the [test branch] 19 | (https://github.com/keijiro/unity-midi-bridge/tree/test). These sample projects 20 | demonstrate functionalities and features of the plug-in. 21 | 22 | Setting up 23 | ---------- 24 | 25 | #### Importing C# files 26 | 27 | Import the C# source files (MidiBridge.cs, MidiInput.cs and MidiOut.cs). You 28 | can simply drag and drop these files into the project view on Unity. 29 | 30 | #### Launching Bridge 31 | 32 | Extract the archive file (midi-bridge-osx.zip or midi-bridge-windows.zip) and 33 | run "MIDI Bridge" which is in it. 34 | 35 | Scripting Reference: MidiInput 36 | ------------------------------ 37 | 38 | You can omit *channel* arguments from these methods. In this case it returns 39 | the union of the all channels. 40 | 41 | #### GetKey (channel, noteNumber) 42 | 43 | Returns the state of the key. If the key is "on", it returns the velocity value 44 | (more than zero, up to 1.0f). If the key is "off", it returns zero. 45 | 46 | #### GetKeyDown (channel, noteNumber) 47 | 48 | Returns true only if the key was pressed down in the current frame. 49 | 50 | #### GetKeyUp (channel, noteNumber) 51 | 52 | Returns true only if the key was released in the current frame. 53 | 54 | #### GetKnob (channel, knobNumber) 55 | 56 | Returns the current knob (CC) value which will be between 0.0f and 1.0f. 57 | 58 | #### GetKnobNumbers (channel) 59 | 60 | Provides the list of knob (CC) numbers that has sent any CC messages. 61 | 62 | Scripting Reference: MidiOut 63 | ---------------------------- 64 | 65 | #### SendNoteOn (channel, noteNumber, velocity) 66 | 67 | Sends a note-on message to the specified channel with a note number and a 68 | velocity value. The velocity value must be more than zero and up to 1.0f. 69 | 70 | #### SendNoteOff (channel, noteNumber) 71 | 72 | Sends a note-off message to the specified channel with a note number. 73 | 74 | #### SendControlChange (channel, controllerNumber, value) 75 | 76 | Sends a control-change (CC) message to the specified channel with a controller 77 | number. The value must be between 0.0f and 1.0f. 78 | 79 | MIDI Bridge for Mac OS X 80 | ------------------------ 81 | 82 | ![screenshot] 83 | (http://keijiro.github.io/unity-midi-bridge/bridge-screenshot-osx.png) 84 | 85 | **MIDI Bridge for Mac OS X** is a kind of menu bar app which relays MIDI 86 | messages between Unity and MIDI devices. 87 | 88 | Simply run "MIDI Bridge" and then it appears as a status menu item on the 89 | top-right corder of the screen. You can click the icon and it opens the 90 | function menu. It shows the device list available at the moment, and provides 91 | some other functionality. 92 | 93 | You can select the destination device from the "MIDI Destinations" list. All 94 | outgoing MIDI messages are delivered to it. 95 | 96 | MIDI Bridge for Windows 97 | ----------------------- 98 | 99 | ![screenshot] 100 | (http://keijiro.github.io/unity-midi-bridge/bridge-screenshot-windows1.png) 101 | 102 | **MIDI Bridge for Windows** (MidiBridge.exe) is a command line application to 103 | relay MIDI messages between Unity and MIDI devices. 104 | 105 | Basically, what you need to do is just run the application. It captures the all 106 | MIDI devices available on the launch and shows the list of these devices. 107 | 108 | There are few points you have to take care. 109 | 110 | - Every time you change the configuration (plug a new MIDI device, disconnect 111 | a device from the computer, etc.), it have to be restarted. You can restart 112 | the bridge internally by pressing down the enter key, or simply close and 113 | relaunch the application. 114 | - Sometimes you may want to free a MIDI device to share it with other 115 | applications. In this case you have to use the **interactive mode** (see 116 | below), or run the application before launching MidiBridge and capture the 117 | device in advance. 118 | - It sends outgoing messages to the all active output devices. 119 | 120 | #### Interactive Mode 121 | 122 | ![screenshot] 123 | (http://keijiro.github.io/unity-midi-bridge/bridge-screenshot-windows2.png) 124 | 125 | You can run MidiBridge in the **interactive mode** by giving "/i" or "-i" 126 | option. In this mode you can control MidiBridge at runtime from the console. 127 | 128 | There are few commands you can use in this mode. You can input these commands 129 | entirely or just the first character of the command. 130 | 131 | - ID - activates/deactivates the specified device. 132 | - scan - rescans and shows the all devices. 133 | - reset - resets and recaptures the all devices. 134 | - log - pops up the log viewer. Press the enter key to return to the command line. 135 | - quit - terminates the bridge. 136 | 137 | Related Projects 138 | ---------------- 139 | 140 | - [github.com/keijiro/midi-bridge-osx] 141 | (https://github.com/keijiro/midi-bridge-osx) - MIDI Bridge for OS X 142 | - [github.com/keijiro/midi-bridge-windows] 143 | (https://github.com/keijiro/midi-bridge-windows) - MIDI Bridge for Windows 144 | 145 | License 146 | ------- 147 | 148 | Copyright (C) 2013 Keijiro Takahashi 149 | 150 | Permission is hereby granted, free of charge, to any person obtaining a copy of 151 | this software and associated documentation files (the "Software"), to deal in 152 | the Software without restriction, including without limitation the rights to 153 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 154 | the Software, and to permit persons to whom the Software is furnished to do so, 155 | subject to the following conditions: 156 | 157 | The above copyright notice and this permission notice shall be included in all 158 | copies or substantial portions of the Software. 159 | 160 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 162 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 163 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 164 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 165 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 166 | -------------------------------------------------------------------------------- /midi-bridge-osx.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keijiro/unity-midi-bridge/34bfeb82febce22857e40cd7879f658c6b055e87/midi-bridge-osx.zip -------------------------------------------------------------------------------- /midi-bridge-windows.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keijiro/unity-midi-bridge/34bfeb82febce22857e40cd7879f658c6b055e87/midi-bridge-windows.zip --------------------------------------------------------------------------------