1 /+ 2 Copyright Elias Batek 2017 - 2018. 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at 5 https://www.boost.org/LICENSE_1_0.txt) 6 +/ 7 module midigamepad.lib.translation.ioprocessor; 8 9 import core.sys.windows.mmsystem; 10 import core.thread; 11 12 import dplug.client.midi; 13 14 import midigamepad.lib.midi; 15 16 public import midigamepad.lib.midi.device; 17 public import midigamepad.lib.keyboard; 18 public import midigamepad.lib.translation.mapping; 19 20 /++ 21 Stops the IO processor based on the passed data. 22 This will also stop the keyboard simulator thread. 23 +/ 24 bool haltIOProcessor(IOProcessorData pcd) 25 { 26 if (pcd.keyboardSynthesizerLoopMgr.isRunning) 27 pcd.keyboardSynthesizerLoopMgr.stop(); 28 29 return (closeMIDIInputDevice(pcd.deviceHandle) == MMSYSERR_NOERROR); 30 } 31 32 /++ 33 Bootstraps the specified MIDI input device, 34 start the keyboard simulator thread, 35 and enables the translation of MIDI input to keystrokes 36 37 Returns: success = true 38 +/ 39 bool runIOProcessor(MIDIDeviceInfo di, IOProcessorData* pcd, out HMIDIIN handle) 40 in 41 { 42 assert(di.type == MIDIDeviceType.input); 43 } 44 body 45 { 46 if (!bootstrapMIDIInputDevice(di, &midigamepadProcessMIDIIn, handle, cast(size_t)(pcd))) 47 { 48 // initalization failure 49 return false; 50 } 51 52 pcd.deviceHandle = handle; 53 54 pcd.keyboardSynthesizerLoopMgr.tryStart(); 55 return true; 56 } 57 58 /++ 59 Data and config used by the IO processor 60 +/ 61 struct IOProcessorData 62 { 63 @nogc nothrow pure @safe: 64 65 private 66 { 67 HMIDIIN _deviceHandle; 68 KeyboardSynthesizerLoopMgr _keyboardSynthesizerLoopMgr; 69 MappingsCollection _mappings; 70 71 } 72 73 /++ 74 ctor 75 +/ 76 this(KeyboardSynthesizerLoopMgr keyboardSynthesizerLoopMgr, MappingsCollection mappings) 77 { 78 this._keyboardSynthesizerLoopMgr = keyboardSynthesizerLoopMgr; 79 this._mappings = mappings; 80 } 81 82 /++ 83 Keyboard simulator to use 84 +/ 85 @property KeyboardSynthesizerLoopMgr keyboardSynthesizerLoopMgr() 86 { 87 return this._keyboardSynthesizerLoopMgr; 88 } 89 90 /++ 91 MIDI input to keyboard mappings 92 +/ 93 @property MappingsCollection mappings() 94 { 95 return this._mappings; 96 } 97 98 @property 99 { 100 /++ 101 OS handle for the MIDI input device 102 +/ 103 HMIDIIN deviceHandle() 104 { 105 return this._deviceHandle; 106 } 107 108 protected void deviceHandle(HMIDIIN deviceHandle) 109 { 110 this._deviceHandle = deviceHandle; 111 } 112 } 113 } 114 115 private 116 { 117 extern (Windows) void midigamepadProcessMIDIIn(HMIDIIN, uint msgType, 118 size_t callbackData, size_t msgParam1, size_t) 119 { 120 auto pcd = cast(IOProcessorData*)(callbackData); 121 122 switch (msgType) 123 { 124 case MIM_DATA: 125 immutable auto msg = parseMIMDATA(msgParam1); 126 switch (msg.status) 127 { 128 case MidiStatus.noteOn: 129 { 130 if (msg.noteVelocity == 0) 131 goto case MidiStatus.noteOff; 132 133 foreach (NoteOnOffMapping mp; pcd.mappings.noteOnOff) 134 { 135 if (mp.noteNumber == msg.noteNumber) 136 { 137 pcd.keyboardSynthesizerLoopMgr.press(mp); 138 } 139 } 140 141 break; 142 } 143 144 case MidiStatus.noteOff: 145 { 146 foreach (NoteOnOffMapping mp; pcd.mappings.noteOnOff) 147 { 148 if (mp.noteNumber == msg.noteNumber) 149 { 150 pcd.keyboardSynthesizerLoopMgr.tryRelease(mp); 151 } 152 } 153 break; 154 } 155 156 default: 157 break; 158 } 159 break; 160 161 default: 162 break; 163 } 164 } 165 }