mqGui.cpp (10183B)
1 #include "mqGui.h" 2 3 #include <iostream> 4 5 #include "mqLib/microq.h" 6 #include "mqLib/mqhardware.h" 7 8 namespace mqConsoleLib 9 { 10 constexpr int g_deviceW = 140; 11 constexpr int g_deviceH = 16; 12 13 Gui::Gui(mqLib::MicroQ& _mq) 14 : m_mq(_mq) 15 , m_win(g_deviceW, g_deviceH + 6) 16 { 17 } 18 19 void Gui::render() 20 { 21 handleTerminalSize(); 22 23 m_win.fill_fg(1,1,g_deviceW, 1, Term::fg::bright_yellow); 24 m_win.fill_fg(1,g_deviceH,g_deviceW, g_deviceH, Term::fg::bright_yellow); 25 26 for(int i=2; i<g_deviceH; ++i) 27 { 28 m_win.fill_fg(1,i,1,i, Term::fg::bright_yellow); 29 m_win.fill_fg(g_deviceW,i,g_deviceW,i, Term::fg::bright_yellow); 30 } 31 32 m_win.print_rect(1,1,g_deviceW, g_deviceH); 33 34 m_win.fill_fg(3, g_deviceH>>1, 9, g_deviceH>>1, Term::fg::bright_yellow); 35 m_win.print_str(3, g_deviceH >> 1, "microQ"); 36 m_win.fill_fg((g_deviceW>>1) - 3, g_deviceH - 1, (g_deviceW>>1) + 7 , g_deviceH - 1, Term::fg::bright_blue); 37 m_win.print_str((g_deviceW>>1) - 3, g_deviceH - 1, "waldorf"); 38 39 constexpr int lcdX = 10; 40 41 renderAboveLCD(lcdX, 3); 42 renderLCD(lcdX,6); 43 renderBelowLCD(lcdX, 12); 44 45 renderAlphaAndPlay(lcdX + 28, 7); 46 47 renderMultimodePeek(lcdX + 23, g_deviceH - 2); 48 renderVerticalLedsAndButtons(lcdX + 46, 3); 49 renderCursorBlock(lcdX + 59, 6); 50 51 constexpr int rightBase = 81; 52 renderMatrixLEDs(rightBase, 3); 53 renderMatrixText(rightBase + 18, 3); 54 renderRightEncoders(rightBase + 20, g_deviceH - 4); 55 56 renderButton(mqLib::Buttons::ButtonType::Power, g_deviceW - 6, g_deviceH - 2); 57 renderLED(m_mq.getLedState(mqLib::Leds::Led::Power), g_deviceW - 4, g_deviceH - 3); 58 renderLabel(g_deviceW - 2, g_deviceH - 1, "Power", true); 59 60 renderHelp(2, g_deviceH + 2); 61 renderDebug(2, g_deviceH + 5); 62 63 std::cout << m_win.render(1,1,true) << std::flush; 64 } 65 66 void Gui::renderAboveLCD(int xStart, int yStart) 67 { 68 constexpr int stepX = 5; 69 constexpr int stepY = 2; 70 int x = xStart + 3; 71 renderLED(mqLib::Leds::Led::Inst1, x, yStart); x += stepX; 72 renderLED(mqLib::Leds::Led::Inst2, x, yStart); x += stepX; 73 renderLED(mqLib::Leds::Led::Inst3, x, yStart); x += stepX; 74 renderLED(mqLib::Leds::Led::Inst4, x, yStart); 75 76 x = xStart + 3; 77 auto y = yStart + stepY; 78 renderButton(mqLib::Buttons::ButtonType::Inst1, x, y); x += stepX; 79 renderButton(mqLib::Buttons::ButtonType::Inst2, x, y); x += stepX; 80 renderButton(mqLib::Buttons::ButtonType::Inst3, x, y); x += stepX; 81 renderButton(mqLib::Buttons::ButtonType::Inst4, x, y); 82 83 x = xStart + 4; 84 y = yStart + 1; 85 renderLabel(x, y, "1", false); x += stepX; 86 renderLabel(x, y, "2", false); x += stepX; 87 renderLabel(x, y, "3", false); x += stepX; 88 renderLabel(x, y, "4", false); 89 } 90 91 void Gui::renderLCD(int x, int y) 92 { 93 m_win.print_rect(x+1, y+1, x+22, y+4,true); 94 95 m_win.fill_bg(x+2, y+2, x+21, y+3, Term::bg::green); 96 m_win.fill_fg(x+2, y+2, x+21, y+3, Term::fg::black); 97 98 std::array<char, 40> text{}; 99 m_mq.readLCD(text); 100 101 int cx = x + 2; 102 int cy = y + 2; 103 104 for(size_t i=0; i<text.size(); ++i) 105 { 106 // https://en.wikipedia.org/wiki/List_of_Unicode_characters 107 108 char32_t c = static_cast<uint8_t>(text[i]); 109 switch (c) 110 { 111 case 0: c = 0x24EA; break; 112 case 1: c = 0x2460; break; 113 case 2: c = 0x2461; break; 114 case 3: c = 0x2462; break; 115 case 4: c = 0x2463; break; 116 case 5: c = 0x2464; break; 117 case 6: c = 0x2465; break; 118 case 7: c = 0x2466; break; 119 case 0xdf: c = 0x2598; break; // Quadrant upper left 120 case 0xff: c = 0x2588; break; // Full block 121 default: 122 if(c < 32 || c >= 0x0010FFFF) 123 c = '?'; 124 } 125 m_win.set_char(cx, cy, c); 126 ++cx; 127 if(i == 19) 128 { 129 cx -= 20; 130 ++cy; 131 } 132 } 133 } 134 135 void Gui::renderBelowLCD(int x, int y) 136 { 137 renderEncoder(mqLib::Buttons::Encoders::LcdLeft, x + 4, y); 138 renderEncoder(mqLib::Buttons::Encoders::LcdRight, x + 14, y); 139 } 140 141 void Gui::renderAlphaAndPlay(int x, int y) 142 { 143 renderEncoder(mqLib::Buttons::Encoders::Master, x, y); 144 renderLED(mqLib::Leds::Led::Play, x + 8, y + 2); 145 renderButton(mqLib::Buttons::ButtonType::Play, x + 6, y + 3); 146 renderLabel(x+5, y+4, "Play", false); 147 } 148 149 void Gui::renderMultimodePeek(int x, int y) 150 { 151 const auto xStart = x; 152 renderLED(mqLib::Leds::Led::Multimode, x, y); 153 x += 4; 154 renderButton(mqLib::Buttons::ButtonType::Multimode, x, y); 155 x += 6; 156 renderLED(mqLib::Leds::Led::Peek, x, y); 157 x += 4; 158 renderButton(mqLib::Buttons::ButtonType::Peek, x, y); 159 renderLabel(xStart - 2, y+1, "Multimode Peek", false); 160 } 161 162 void Gui::renderCursorBlock(int x, int y) 163 { 164 renderButton(mqLib::Buttons::ButtonType::Left, x, y + 2); 165 renderButton(mqLib::Buttons::ButtonType::Right, x + 6, y + 2); 166 renderButton(mqLib::Buttons::ButtonType::Up, x + 3, y); 167 renderButton(mqLib::Buttons::ButtonType::Down, x + 3, y + 4); 168 } 169 170 void Gui::renderVerticalLedsAndButtons(int xStart, int y) 171 { 172 constexpr int spreadX = 4; 173 constexpr int stepY = 2; 174 175 int x = xStart; 176 renderLED(mqLib::Leds::Led::Global, x, y); x += spreadX; 177 renderButton(mqLib::Buttons::ButtonType::Global, x, y); 178 x = xStart; 179 renderLabel(x + 3, y + 1, "Global", true); 180 renderLabel(x + 4, y + 1, "Util", false); 181 y += stepY; 182 renderLED(mqLib::Leds::Led::Multi, x, y); x += spreadX; 183 renderButton(mqLib::Buttons::ButtonType::Multi, x, y); 184 x = xStart; 185 renderLabel(x + 3, y + 1, "Multi", true); 186 renderLabel(x + 4, y + 1, "Compare", false); 187 y += stepY; 188 renderLED(mqLib::Leds::Led::Edit, x, y); x += spreadX; 189 renderButton(mqLib::Buttons::ButtonType::Edit, x, y); 190 x = xStart; 191 renderLabel(x + 3, y + 1, "Edit", true); 192 renderLabel(x + 4, y + 1, "Recall", false); 193 y += stepY; 194 renderLED(mqLib::Leds::Led::Sound, x, y); x += spreadX; 195 renderButton(mqLib::Buttons::ButtonType::Sound, x, y); 196 x = xStart; 197 renderLabel(x + 3, y + 1, "Sound", true); 198 renderLabel(x + 4, y + 1, "Store", false); 199 y += stepY; 200 renderLED(mqLib::Leds::Led::Shift, x, y); x += spreadX; 201 renderButton(mqLib::Buttons::ButtonType::Shift, x, y); 202 x = xStart; 203 renderLabel(x + 1, y + 1, "Shift", false); 204 } 205 206 void Gui::renderMatrixLEDs(int xStart, int yStart) 207 { 208 constexpr int stepX = 4; 209 constexpr int stepY = 1; 210 211 int x = xStart; 212 int y = yStart; 213 214 renderLED(mqLib::Leds::Led::Osc1, x, y); x += stepX; 215 renderLED(mqLib::Leds::Led::Osc2, x, y); x += stepX; 216 renderLED(mqLib::Leds::Led::Osc3, x, y); 217 x = xStart; y += stepY; 218 renderLED(mqLib::Leds::Led::MixerRouting, x, y); 219 x = xStart; y += stepY; 220 renderLED(mqLib::Leds::Led::Filters1, x, y); x += stepX; 221 renderLED(mqLib::Leds::Led::Filters2, x, y); 222 x = xStart; y += stepY; 223 renderLED(mqLib::Leds::Led::AmpFx, x, y); 224 x = xStart; y += stepY; 225 renderLED(mqLib::Leds::Led::Env1, x, y); x += stepX; 226 renderLED(mqLib::Leds::Led::Env2, x, y); x += stepX; 227 renderLED(mqLib::Leds::Led::Env3, x, y); x += stepX; 228 renderLED(mqLib::Leds::Led::Env4, x, y); 229 x = xStart; y += stepY; 230 renderLED(mqLib::Leds::Led::LFOs, x, y); 231 x = xStart; y += stepY; 232 renderLED(mqLib::Leds::Led::ModMatrix, x, y); 233 } 234 235 void Gui::renderMatrixText(int x, int y) 236 { 237 m_win.fill_fg(x,y, x + 36, y + 7, Term::fg::gray); 238 239 m_win.print_str(x, y, "Octave Detune Shape PWM "); ++y; 240 m_win.print_str(x, y, "Osc1 Osc2 Osc3 Filter "); ++y; 241 m_win.print_str(x, y, "Cutoff Res Env Type "); ++y; 242 m_win.print_str(x, y, "Volume FX Mix ArpMode Tempo "); ++y; 243 m_win.print_str(x, y, "Attack Decay Sustain Release "); ++y; 244 m_win.print_str(x, y, "LFO1Speed Shapee LFO2Speed LFO3Speed"); ++y; 245 m_win.print_str(x, y, "Select Source Amount Dest "); 246 } 247 248 void Gui::renderRightEncoders(int x, int y) 249 { 250 constexpr int xStep = 8; 251 252 renderEncoder(mqLib::Buttons::Encoders::Matrix1, x, y); x += xStep; 253 renderEncoder(mqLib::Buttons::Encoders::Matrix2, x, y); x += xStep; 254 renderEncoder(mqLib::Buttons::Encoders::Matrix3, x, y); x += xStep; 255 renderEncoder(mqLib::Buttons::Encoders::Matrix4, x, y); 256 } 257 258 void Gui::renderHelp(int x, int y) 259 { 260 renderLabel(x, y , "Buttons: 1-4=Inst | Arrows=Cursor | g=Global | m=Multi | e=Edit | s=Sound | S=Shift | M=Multimode | p=Play | P=Peek | q=Power"); 261 renderLabel(x, y+1, "Encoders: F1/F2 & F3/F4=LCD Left/Right | 5/6=Alpha Dial | F5-F12=Matrix"); 262 renderLabel(x, y+2, "MIDI: 7=Note ON | 8=Note OFF | 9=Modwheel Max | 0=Modwheel Min"); 263 renderLabel(x, y+3, "Escape: Open Settings to select MIDI In/Out & Audio Out"); 264 } 265 266 void Gui::renderDebug(int x, int y) 267 { 268 // renderLabel(g_deviceW - 1, y, std::string(" DSP ") + m_hw.getDspThread().getMipsString(), true, Term::fg::red); 269 } 270 271 void Gui::renderLED(mqLib::Leds::Led _led, int x, int y) 272 { 273 renderLED(m_mq.getLedState(_led), x, y); 274 } 275 276 void Gui::renderLED(const bool on, int x, int y) 277 { 278 if(on) 279 { 280 m_win.fill_fg(x, y, x+1, y, Term::fg::bright_white); 281 m_win.fill_fg(x+1, y, x+1, y, Term::fg::bright_yellow); 282 m_win.fill_fg(x+2, y, x+1, y, Term::fg::bright_white); 283 m_win.print_str(x, y, "(*)"); 284 } 285 else 286 { 287 m_win.fill_fg(x, y, x+1, y, Term::fg::white); 288 m_win.fill_fg(x+1, y, x+1, y, Term::fg::white); 289 m_win.fill_fg(x+2, y, x+1, y, Term::fg::white); 290 m_win.print_str(x, y, "(-)"); 291 } 292 } 293 294 void Gui::renderButton(mqLib::Buttons::ButtonType _button, int x, int y) 295 { 296 const auto pressed = m_mq.getButton(_button); 297 298 if(pressed) 299 { 300 m_win.print_str(x,y, "[#]"); 301 } 302 else 303 { 304 m_win.print_str(x,y, "[ ]"); 305 } 306 } 307 308 void Gui::renderEncoder(mqLib::Buttons::Encoders _encoder, int x, int y) 309 { 310 const auto state = m_mq.getEncoder(_encoder); 311 constexpr char32_t overline = 0x0000203E; 312 313 const char c0 = state & 2 ? '*' : '.'; 314 const char c1 = state & 1 ? '*' : '.'; 315 316 if(_encoder == mqLib::Buttons::Encoders::Master) 317 { 318 m_win.fill_fg(x, y, x + 5, y + 3, Term::fg::bright_red); 319 } 320 m_win.print_str(x, y, " / \\"); 321 m_win.print_str(x, y+1, std::string("| ") + c0 + c1 + " |"); 322 m_win.print_str(x, y+2, " \\__/"); 323 324 m_win.set_char(x+2, y, overline); 325 m_win.set_char(x+3, y, overline); 326 } 327 328 void Gui::renderLabel(int x, int y, const std::string& _text, bool _rightAlign, Term::fg _color/* = Term::fg::gray*/) 329 { 330 const int len = static_cast<int>(_text.size()); 331 if(_rightAlign) 332 x -= len; 333 m_win.fill_fg(x, y, x + len - 1, y, _color); 334 m_win.print_str(x,y,_text); 335 } 336 }