1 module test1.virtmidikeyb; 2 3 import pixelperfectengine.concrete.window; 4 import pixelperfectengine.system.input.types; 5 import pixelperfectengine.system.etc : hashCalc; 6 import midi2.types.structs; 7 import midi2.types.enums; 8 import test1.app; 9 import std.conv : to; 10 11 public class VirtualMidiKeyboard : Window { 12 SmallButton[] keys; 13 TextBox textBox_NoteOffset; 14 TextBox textBox_Channel; 15 TextBox textBox_PrgChange; 16 ubyte noteOffset = 36; 17 ubyte channel; 18 bool typematicBlock; 19 AudioDevKit app; 20 public this(AudioDevKit app) { 21 this.app = app; 22 super(Box.bySize(0,0,200,85), "Virtual MIDI keyboard"); 23 for (int i ; i < 20 ; i++) { 24 Box b; 25 const int note = i % 12, oct = i / 12; 26 switch (note) { 27 case 1, 3, 6, 8, 10: 28 b.top = 20; 29 b.bottom = 20 + 15; 30 break; 31 default: 32 b.top = 20 + 16; 33 b.bottom = 20 + 16 + 15; 34 break; 35 } 36 switch (note) { 37 default: //c 38 b.left = 4 + (oct * 112); 39 b.right = 4 + 15 + (oct * 112); 40 break; 41 case 1: //c# 42 b.left = 4 + (oct * 112) + 8; 43 b.right = 4 + 15 + (oct * 112) + 8; 44 break; 45 case 2: //d 46 b.left = 4 + (oct * 112) + (16 * 1); 47 b.right = 4 + 15 + (oct * 112) + (16 * 1); 48 break; 49 case 3: //d# 50 b.left = 4 + (oct * 112) + 8 + (16 * 1); 51 b.right = 4 + 15 + (oct * 112) + 8 + (16 * 1); 52 break; 53 case 4: //e 54 b.left = 4 + (oct * 112) + (16 * 2); 55 b.right = 4 + 15 + (oct * 112) + (16 * 2); 56 break; 57 case 5: //f 58 b.left = 4 + (oct * 112) + (16 * 3); 59 b.right = 4 + 15 + (oct * 112) + (16 * 3); 60 break; 61 case 6: //f# 62 b.left = 4 + (oct * 112) + 8 + (16 * 3); 63 b.right = 4 + 15 + (oct * 112) + 8 + (16 * 3); 64 break; 65 case 7: //g 66 b.left = 4 + (oct * 112) + (16 * 4); 67 b.right = 4 + 15 + (oct * 112) + (16 * 4); 68 break; 69 case 8: //g# 70 b.left = 4 + (oct * 112) + 8 + (16 * 4); 71 b.right = 4 + 15 + (oct * 112) + 8 + (16 * 4); 72 break; 73 case 9: //a 74 b.left = 4 + (oct * 112) + (16 * 5); 75 b.right = 4 + 15 + (oct * 112) + (16 * 5); 76 break; 77 case 10: //a# 78 b.left = 4 + (oct * 112) + 8 + (16 * 5); 79 b.right = 4 + 15 + (oct * 112) + 8 + (16 * 5); 80 break; 81 case 11: //b 82 b.left = 4 + (oct * 112) + (16 * 6); 83 b.right = 4 + 15 + (oct * 112) + (16 * 6); 84 break; 85 } 86 SmallButton sb = new SmallButton("closeButtonB", "closeButtonA", [cast(char)i], b); 87 sb.mousePressEvent = true; 88 sb.onMouseLClick = &onKey!(0xFFFF_0000); 89 sb.onMouseMClick = &onKey!(0x7FFF_0000); 90 sb.onMouseRClick = &onKey!(0x3FFF_0000); 91 addElement(sb); 92 keys ~= sb; 93 } 94 textBox_NoteOffset = new TextBox("36", "textBox_NoteOffset", Box(5, 25+16+16 , 45, 25+16+16+20)); 95 textBox_Channel = new TextBox("0", "textBox_Channel", Box(50, 25+16+16 , 95, 25+16+16+20)); 96 textBox_PrgChange = new TextBox("PrgCh", "textBox_PrgChange", Box(100, 25+16+16 , 170, 25+16+16+20)); 97 addElement(textBox_NoteOffset); 98 addElement(textBox_Channel); 99 addElement(textBox_PrgChange); 100 textBox_NoteOffset.onTextInput = &textBox_NoteOffset_onTextInput; 101 textBox_Channel.onTextInput = &textBox_Channel_onTextInput; 102 textBox_PrgChange.onTextInput = &textBox_PrgChange_onTextInput; 103 onClose = &app.onVirtMIDIKeybClose; 104 } 105 public int keyEventReceive(uint id, BindingCode code, uint timestamp, bool isPressed) { 106 if (!active) 107 return 0; 108 if (isPressed) { 109 if (typematicBlock) { 110 return 1; 111 } 112 typematicBlock = true; 113 } else { 114 typematicBlock = false; 115 } 116 ubyte note; 117 switch (id) { 118 case hashCalc("VirtMIDIKB-C-0"): 119 note = 0; 120 break; 121 case hashCalc("VirtMIDIKB-C#0"): 122 note = 1; 123 break; 124 case hashCalc("VirtMIDIKB-D-0"): 125 note = 2; 126 break; 127 case hashCalc("VirtMIDIKB-D#0"): 128 note = 3; 129 break; 130 case hashCalc("VirtMIDIKB-E-0"): 131 note = 4; 132 break; 133 case hashCalc("VirtMIDIKB-F-0"): 134 note = 5; 135 break; 136 case hashCalc("VirtMIDIKB-F#0"): 137 note = 6; 138 break; 139 case hashCalc("VirtMIDIKB-G-0"): 140 note = 7; 141 break; 142 case hashCalc("VirtMIDIKB-G#0"): 143 note = 8; 144 break; 145 case hashCalc("VirtMIDIKB-A-0"): 146 note = 9; 147 break; 148 case hashCalc("VirtMIDIKB-A#0"): 149 note = 10; 150 break; 151 case hashCalc("VirtMIDIKB-B-0"): 152 note = 11; 153 break; 154 case hashCalc("VirtMIDIKB-C-1"): 155 note = 12; 156 break; 157 case hashCalc("VirtMIDIKB-C#1"): 158 note = 13; 159 break; 160 case hashCalc("VirtMIDIKB-D-1"): 161 note = 14; 162 break; 163 case hashCalc("VirtMIDIKB-D#1"): 164 note = 15; 165 break; 166 case hashCalc("VirtMIDIKB-E-1"): 167 note = 16; 168 break; 169 case hashCalc("VirtMIDIKB-F-1"): 170 note = 17; 171 break; 172 case hashCalc("VirtMIDIKB-F#1"): 173 note = 18; 174 break; 175 case hashCalc("VirtMIDIKB-G-1"): 176 note = 19; 177 break; 178 case hashCalc("VirtMIDIKB-oct+"): 179 if (!isPressed) { 180 noteOffset += 12; 181 textBox_NoteOffset.setText(to!dstring(noteOffset)); 182 } 183 return 1; 184 case hashCalc("VirtMIDIKB-oct-"): 185 if (!isPressed) { 186 noteOffset -= 12; 187 textBox_NoteOffset.setText(to!dstring(noteOffset)); 188 } 189 return 1; 190 case hashCalc("VirtMIDIKB-note+"): 191 if (!isPressed) { 192 noteOffset++; 193 textBox_NoteOffset.setText(to!dstring(noteOffset)); 194 } 195 return 1; 196 case hashCalc("VirtMIDIKB-note-"): 197 if (!isPressed) { 198 noteOffset--; 199 textBox_NoteOffset.setText(to!dstring(noteOffset)); 200 } 201 return 1; 202 default: 203 return 0; 204 } 205 UMP midiPacket = UMP(MessageType.MIDI2, cast(ubyte)(channel>>4), isPressed ? MIDI2_0Cmd.NoteOn : MIDI2_0Cmd.NoteOff, 206 cast(ubyte)(channel&0x0F), cast(ubyte)(note + noteOffset), 0x00); 207 uint velo = 0xFFFF_0000; 208 if (app.selectedModule !is null) { 209 app.selectedModule.midiReceive(midiPacket, velo); 210 } 211 return 1; 212 } 213 protected void onKey(uint velo)(Event ev) { 214 SmallButton sender = cast(SmallButton)ev.sender; 215 ubyte note = cast(ubyte)(noteOffset + sender.getSource[0]); 216 UMP midiPacket = UMP(MessageType.MIDI2, cast(ubyte)(channel>>4), sender.isPressed ? MIDI2_0Cmd.NoteOn : 217 MIDI2_0Cmd.NoteOff, cast(ubyte)(channel&0x0F), note, 0x00); 218 //uint velo = 0xFFFF_0000; 219 if (app.selectedModule !is null) { 220 app.selectedModule.midiReceive(midiPacket, velo); 221 } 222 } 223 protected void textBox_PrgChange_onTextInput(Event ev) { 224 dstring text = textBox_PrgChange.getText().toDString(); 225 if (text.length & 1 || text.length >= 7) { 226 textBox_PrgChange.setText("Error!"); 227 return; 228 } 229 try { 230 uint bankMSB, bankLSB, prg; 231 if (text.length == 6) { 232 bankMSB = to!uint(text[0..2], 16); 233 text = text[2..$]; 234 } 235 if (text.length == 4) { 236 bankLSB = to!uint(text[0..2], 16); 237 text = text[2..$]; 238 } 239 prg = to!uint(text, 16); 240 UMP midiPacket = UMP(MessageType.MIDI2, cast(ubyte)(channel>>4), MIDI2_0Cmd.PrgCh, 241 cast(ubyte)(channel&0x0F), 0x00, 0x00); 242 uint velo = (prg<<24) | (bankMSB<<8) | bankLSB; 243 if (app.selectedModule !is null) { 244 app.selectedModule.midiReceive(midiPacket, velo); 245 } 246 } catch (Exception e) { 247 textBox_PrgChange.setText("Error!"); 248 } 249 } 250 protected void textBox_NoteOffset_onTextInput(Event ev) { 251 try { 252 noteOffset = to!ubyte(textBox_NoteOffset.getText().toDString()); 253 } catch (Exception e) { 254 textBox_NoteOffset.setText("Error!"); 255 } 256 } 257 protected void textBox_Channel_onTextInput(Event ev) { 258 try { 259 channel = to!ubyte(textBox_Channel.getText().toDString()); 260 } catch (Exception e) { 261 textBox_Channel.setText("Error!"); 262 } 263 } 264 }