Four firmware improvements (web simulator already had these):
- Smooth lettering: replace the upscaled 8x8 bitmap font (and the 7-seg BPM) with
baked anti-aliased proportional fonts (DejaVuSans-Bold 22 + 78), rendered by
blending fg over bg through a 16-entry alpha LUT. Generator: pico/gen_font.py.
- All grooves: PROGRAMS now carries the full web set list (23 grooves), not 5.
- Fix: the RGB LED stayed lit when stopped — the stop path now zeroes the colour
and the fade only runs while playing (led_off()).
- Fix: the on-screen play button played one beep then stopped — a finger held past
the old lockout re-fired the toggle. Touch is now edge-detected like the hardware
buttons (fires once on finger-down, ignores held).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
511 lines
58 KiB
Python
511 lines
58 KiB
Python
# VARASYS PolyMeter — PM_K-1 "Kit" firmware
|
|
# Raspberry Pi Pico (or Pico W / Pico 2) on the 52Pi EP-0172 "Pico Breadboard Kit Plus":
|
|
# 3.5" ST7796 320x480 capacitive-touch screen (GT911), PSP joystick, WS2812 RGB, buzzer, 2 buttons.
|
|
#
|
|
# It runs the SAME program-string language as https://metronome.varasys.io — design a groove in
|
|
# the web editor, copy its program string, paste it into PROGRAMS below, and it plays here.
|
|
#
|
|
# FLASH (two steps — main.py is NOT drag-and-drop):
|
|
# 1) Install MicroPython: hold BOOTSEL, plug in, drop the MicroPython .uf2 on the RPI-RP2 drive
|
|
# (https://micropython.org/download/RPI_PICO/ ; RPI_PICO2 for a Pico 2). It reboots itself.
|
|
# 2) Copy THIS file to the Pico AS main.py over USB serial — Thonny: File > Save as > Raspberry Pi
|
|
# Pico (name it main.py); or mpremote cp main.py :main.py . Then reset.
|
|
#
|
|
# IF SOMETHING LOOKS WRONG, flip a flag in CONFIG below (colours, inversion, touch axes) — see README.md.
|
|
#
|
|
# Text is drawn with baked anti-aliased fonts (see pico/gen_font.py) for smooth lettering.
|
|
# MIT-style. VARASYS — Simplifying Complexity.
|
|
|
|
from machine import Pin, SPI, I2C, ADC, PWM
|
|
from binascii import a2b_base64
|
|
import time
|
|
|
|
try:
|
|
import neopixel
|
|
except ImportError:
|
|
neopixel = None
|
|
|
|
# ============================== CONFIG (tweak if needed) ==============================
|
|
SPI_BAUD = 40_000_000 # 40 MHz safe-fast default; vendor demo uses 62.5 MHz
|
|
WIDTH, HEIGHT = 320, 480 # ST7796 portrait
|
|
MADCTL = 0x48 # memory access ctrl (MX | BGR) -> portrait, 320 wide x 480 tall
|
|
INVERT_COLORS = True # most ST7796 modules need display inversion ON; set False if colours look negative
|
|
SWAP_RB = False # set True if red and blue are swapped
|
|
# Touch (GT911) calibration — flip these if taps land on the wrong spot:
|
|
TOUCH_SWAP_XY = False
|
|
TOUCH_INVERT_X = False
|
|
TOUCH_INVERT_Y = False
|
|
TOUCH_DEBUG = False # True -> print raw touch coords over USB serial to calibrate
|
|
# Joystick calibration:
|
|
JOY_INVERT_X = False
|
|
JOY_INVERT_Y = False
|
|
JOY_DEADZONE = 9000 # of 0..65535 around centre
|
|
|
|
# ----- pins (fixed by the EP-0172 board) -----
|
|
PIN_SCK, PIN_MOSI, PIN_CS, PIN_DC, PIN_RST = 2, 3, 5, 6, 7
|
|
PIN_SDA, PIN_SCL = 8, 9
|
|
PIN_RGB = 12
|
|
PIN_BUZZER = 13
|
|
PIN_BTN_A = 15 # play / stop
|
|
PIN_BTN_B = 14 # tap tempo
|
|
PIN_JOY_X = 26 # ADC0
|
|
PIN_JOY_Y = 27 # ADC1
|
|
|
|
# ----- the grooves on the device (the web set lists; paste your own from the editor) -----
|
|
PROGRAMS = [
|
|
# Styles
|
|
("Four on the floor", "t120;kick:4;snare:4=.x.x;hatClosed:4/2"),
|
|
("Swing ride", "t150;ride:4/2s;kick:4=X..x;snare:4=.x.x"),
|
|
("Purdie half shuffle", "t92;kick:4/3=X....x...x..;snare:4/3=..gg.gX.gg.g;hatClosed:4/3=X.xX.xX.xX.x"),
|
|
("Samba (2/4)", "t104;tomLow:2/4=x...X...;hatClosed:2/4;woodblock:2/4=X.xx.xX."),
|
|
("Nanigo (6/8 bembe)", "t130;cowbell:4/3=X.xx.x.xx.x.;kick:4/3=X.....X.....;hatClosed:4/3=..x..x..x..x"),
|
|
("6/8 groove", "t100;kick:3+3=x..x..;snare:3+3=...x..;hatClosed:3+3/2"),
|
|
("7/8 (2+2+3)", "t130;kick:2+2+3=x..x..x;hatClosed:2+2+3/2"),
|
|
("5/4 (3+2)", "t112;kick:3+2=x..x.;snare:3+2=..x..;hatClosed:3+2/2"),
|
|
# Practice
|
|
("5 over 4 polyrhythm", "t100;kick:4;claves:5~"),
|
|
("3 over 2 hemiola", "t96;woodblock:2;cowbell:3~"),
|
|
("2 & 4 & 3 per bar", "t100;kick:3;cowbell:2~;claves:4~"),
|
|
("Triplet hats", "t100;kick:4;snare:4=.x.x;hatClosed:4/3"),
|
|
("Accents", "t92;kick:4=X..X;snare:4=.X.X;hatClosed:4/2"),
|
|
("Tempo builder 80+", "t80;woodblock:4;rmp80/4/4"),
|
|
("Gap trainer 2/2", "t100;kick:4;hatClosed:4/2;tr2/2"),
|
|
# Song (continuous on the web; here they play as standalone grooves)
|
|
("Intro - hats+kick", "t88;kick:4=X.x.;hatClosed:4/2=gggggggg"),
|
|
("Groove in", "t88;kick:4=X.x.;snare:4=.X.X;hatClosed:4/2"),
|
|
("Half-time shuffle", "t92;kick:4/3=X....x...x..;snare:4/3=..gg.gX.gg.g;hatClosed:4/3=X.xX.xX.xX.x"),
|
|
("Build 92 to 120", "t92;kick:4;snare:4=.X.X;hatClosed:4/2"),
|
|
("Four-floor (909)", "t124;kick909:4;clap909:4=.X.X;hat909:4/2=.X.X.X.X"),
|
|
("Samba break", "t116;tomLow:2/4=x...X...;hatClosed:2/4;woodblock:2/4=X.xx.xX."),
|
|
("Peak - 16ths", "t132;kick:4=X..x;snare:4=.X.X;hatClosed:4/4"),
|
|
("Outro", "t132;kick:4=X..x;hatClosed:4/2=gggggggg"),
|
|
]
|
|
|
|
# ============================== COLOURS ==============================
|
|
def rgb565(r, g, b):
|
|
if SWAP_RB: r, b = b, r
|
|
v = ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3) # packed BGR for the BGR panel
|
|
return bytes((v >> 8, v & 0xFF)) # MSB-first for ST7796
|
|
|
|
C_BG = rgb565(6, 9, 14)
|
|
C_PANEL = rgb565(28, 34, 44)
|
|
C_TXT = rgb565(199, 208, 219)
|
|
C_MUTE = rgb565(120, 132, 148)
|
|
C_CYAN = rgb565(10, 179, 247) # brand cyan / normal beat
|
|
C_AMBER = rgb565(255, 155, 46) # accent
|
|
C_GREEN = rgb565(47, 224, 122) # running
|
|
C_DIMDOT = rgb565(36, 50, 64)
|
|
C_BTN = rgb565(28, 34, 44)
|
|
C_BTNHI = rgb565(44, 56, 72)
|
|
LEVEL_RGB = {2: (255, 110, 0), 1: (0, 150, 255), 3: (130, 70, 255)} # WS2812 accent / normal / ghost
|
|
|
|
# ============================== ANTI-ALIASED FONTS (baked; see gen_font.py) ==============================
|
|
FONT_M_B64 = "YgAgAAAAAAgAIQoQAAUKACILEAAFCwAjEhAABRIAJA8TAAUPACUWEAAFFgAmExAABRMAJwcQAAUHACgKFAAECgApChQABAoAKgwQAAUMACsSDQAIEgAsCAcAEQgALQkIAA0JAC4IBAARCAAvCRIABQgAMA8QAAUPADEPEAAFDwAyDxAABQ8AMw8QAAUPADQPEAAFDwA1DxAABQ8ANg8QAAUPADcPEAAFDwA4DxAABQ8AOQ8QAAUPADoJDAAJCQA7CQ8ACQkAPBINAAgSAD0SCwAKEgA+Eg0ACBIAPw0QAAUNAEAWEwAFFgBBERAABREAQhEQAAURAEMQEAAFEABEEhAABRIARQ8QAAUPAEYPEAAFDwBHEhAABRIASBIQAAUSAEkIEAAFCABKChT+BQgASxIQAAURAEwOEAAFDgBNFhAABRYAThIQAAUSAE8TEAAFEwBQEBAABRAAURMTAAUTAFIREAAFEQBTEBAABRAAVA8QAAUPAFUSEAAFEgBWERAABREAVxgQAAUYAFgREAAFEQBZEhD/BRAAWhAQAAUQAFsKFAAECgBcCRIABQgAXQoUAAQKAF4SEAAFEgBfCwUAFQsAYAsSAAMLAGEPDAAJDwBiEBEABBAAYw0MAAkNAGQQEQAEEABlDwwACQ8AZgoRAAQKAGcQEQAJEABoEBEABBAAaQgRAAQIAGoJFv8ECABrEBEABA8AbAgRAAQIAG0XDAAJFwBuEAwACRAAbw8MAAkPAHAQEQAJEABxEBEACRAAcgsMAAkLAHMNDAAJDQB0Cw8ABgsAdRAMAAkQAHYPDAAJDgB3FAwACRQAeA4MAAkOAHkOEQAJDgB6DQwACQ0AexAUAAQQAHwIFgAECAB9EBQABBAAfhIKAAsSJcAREgAGESW2ERIABhEloBUSAAYVAA7/8AAADv/wAAAO//AAAA7/8AAADv/wAAAO//AAAA3/0AAAC/+wAAAJ/5AAAAf/cAAAAAAAAAAAAAAAAA7/8AAADv/wAAAO//AAAA7/8AAA76Av9gAO+gL/YADvoC/2AA76Av9gAO+gL/YADvoC/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/oAf+AAAAAADvcAr7AAAAAAL/QA73AAAAAAX/EB/0AAAAAAj9AE/xAAAE/////////wAE/////////wAAAF/wAv9AAAAAAJ/ABv8AAAAAAN+ACvwAAACP////////sACP////////sAAACvwAb/AAAAAADvgAr7AAAAAAL/MA73AAAAAAb/AC/zAAAAAAAAP4AAAAAAAAP4AAAAAAGM7/2mEAAD//////0AAN/6T4JJsAA//yP4AAAABP/5P4AAAAAv///8cwAAAL/////9QAABr/////8wAAAnv///+gAAAAP5Xv/AAAAAP4Cv+wBMcxP4Lv9wBP//////sAADi9//61AAAAAAP4AAAAAAAAP4AAAAAAAAP4AAAAAATP/EAAAAf+AAAAX///9QAAL/QAAADv4i7+AAC/oAAAA/+ACP8gBf8QAAAE/2AG/0Ae9gAAAAP/gAj/IJ/AAAAAAO/iLv4D/yAAAAAAX///9Q34BM/8UAAEz/xAf9Bf///2AAAAAAL/QO/iLv8AAAAAC/oC/5AH/zAAAABf4QP/cAb/UAAAAe9gAv+QB/8wAAAJ/AAA7+It/gAAAD/yAABf///2AAAA34AAAATP/FAAAAA63+xyAAAAAACP////8AAAAAAf/9ICbAAAAAAD//oAAAAAAAAAH//zAAAAAAAAAK//4QAAAAAAAK///8AADf9wAJ////+gAP/1AD//wu//gD//IAj/9AP//1n/0ACv/xAG////+AAJ//IACf///xAAX/+QAAz//2AAAM//khTf//sAAAHP///////7AAAAW+/ttiz/+wAO+gAA76AADvoAAO+gAA76AADvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC//EAAAv/kAAAP/8gAACv/AAAAf/2AAAG//IAAAr/4AAADv+wAAAP/6AAAB//kAAAH/+QAAAP/6AAAA7/sAAACv/gAAAG//IAAAH/9gAAAK/8AAAAP/8gAAAL/5AAAAL/8QAP/zAAAAj/wAAAAf/0AAAAv/sAAABf/xAAAB//cAAADv+wAAAK/+AAAAn/8AAACP/yAAAI//IAAAn/8AAACv/wAAAO/7AAAB//cAAAb/8gAAC/+wAAAf/0AAAI/8AAAA//MAAAAAL6AAAAAAL6AAABxgL6AqgD3+j8r/kABM//+BAABM//+BAD3+j8r/kB1gL6AqgAAAL6AAAAAAL6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gAAAAAAAAAH/gAAAAAAAAAH/gAAAAAAAAAH/gAAAAAAAAAH/gAAAAACv////////EACv////////EACv////////EAAAAAH/gAAAAAAAAAH/gAAAAAAAAAH/gAAAAAAAAAH/gAAAAAAAAAH/gAAAAADP/xAAz/8QAM//EADf/QAC//MABv9wAAv8AAAN////AN////AN////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz/8QAM//EADP/xAAz/8QAAAI/QAAAN+AAAAv8wAAB/4AAADPkAAAH/QAAAb/AAAAv6AAAA/1AAAF/xAAAK+wAAAO9gAABP8QAACfwAAADvcAAAP/IAAAj9AAAA34AAAAAABK7+xgAAAAn////9EAAI//YD7/wAAf/7AAb/9gB//3AAL//AC//0AAD//wDf/zAADv/yDv/zAADv/zDv/zAADv/zDf/zAADv/yC//0AAD//wB//3AAL//AAf/7AAb/9gAI//YD7/wAAAn////9EAAABK7+xgAAAASM//8gAAAI////8gAAAHtzz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAAAAz/8gAAAG///////AAG///////AADe9/+tQAAA//////7AAA/+iBO//kAA/UAAE//8AA0AAAA//8wAAAAAA7/8wAAAAAB//8QAAAAAI//oAAAAABP/+IAAAAAT//zAAAAAG//9AAAAAB//+MAAAAAn//SAAAAAK//wQAAAABP//////9gBP//////9gABa9/+xxAAAN/////+MAALgxBN//0AAAAAAC//8QAAAAAA//8gAAAAAC//4AAAAABN//UAAADP///DAAAADP///8IAAAAAE7//4AAAAAAA3/9gAAAAAAr/+AAAAAAA3/9gB6UgA6//4QCP/////+MAAFnO/9tgAAAAAAHv//AAAAAAv///AAAAAG////AAAAA//v//AAAADf9e//AAAAr/oO//AAAF/+AO//AAAv/0AO//AADP+QAO//AAD/0AAO//AAD////////0D////////0AAAAAO//AAAAAAAO//AAAAAAAO//AAAAAAAO//AAAK//////kAAK//////kAAK/6AAAAAAAK/6AAAAAAAK/6AAAAAAAK/6AAAAAAAK//7/yBAAAK//////QAAJhBAq//8gAAAAAAz/+AAAAAAAf/+wAAAAAAf/+wAAAAAAz/+ABMcxAq//8QBP/////+MAADjN/+twAAAAAFrv7JMAAAHP////8QAA3/5iAlsQAI//IAAAAAAP/5AAAAAABP/5rf61AACP//////kACf//sRz/9gCf//EAL//QCf/+AAD//wBv/9AADv/xA//+AAD//wAN//EAL/+wAE//sRz/8wAAb/////UAAAAp3/2SAACP//////+QCP//////+QAAAAAA//9wAAAAAG//8QAAAAAN//kAAAAABP//IAAAAAC//6AAAAAAL//zAAAAAAj/+wAAAAAA7/9AAAAAAG//0AAAAAAN//UAAAAAA//+AAAAAACv/3AAAAAAH//wAAAAAAj/+AAAAAAAGM7/2jAAAE//////gAAO//YD7/8wA//8AAf/+ABP/6AAX/+AAf/8AAf/9QAI//YD7/wAAAbv///5AAABn////7MAAO/+QCz/8wB//3AAL/+wCf/0AAD//gCP/2AAL//QA//+QCz/+AAH//////sAAAOd//2lAAAAB87+pAAAAC3////5AAAO/+MX//cAB//3AA3/8QC//zAAn/9wDf/yAAj/+gDP/zAAn//QCf/2AA3//gAv/+MX///QAG///////AAAOu/sf/+QAAAAAAX/9AAAAAAA3/wAAKcwFM//IAAM/////jAAABfO/rYAAAAI//UAAI//UAAI//UAAI//UAAAAAAAAAAAAAAAAAAAAAAAAAAI//UAAI//UAAI//UAAI//UAAI//UAAI//UAAI//UAAI//UAAAAAAAAAAAAAAAAAAAAAAAAAAI//UAAI//UAAI//UAAK//IAAO/2AAA/+wAAB/4QAAAAAAAAAAABfBAAAAAAABa//xAAAAAAW////BAAAAWv///HEAAAOf///HEAAAAAr//GEAAAAAAAr/+2EAAAAAAAOv///GEAAAAAAAWv///GEAAAAAAAW////BAAAAAAABbP/xAAAAAAAAABfBAAAAAAAAAAAAAAr////////xAAr////////xAAr////////xAAAAAAAAAAAAAAAAAAAAAAAAAAr////////xAAr////////xAAr////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmTAAAAAAAAAAr/6DAAAAAAAAf///2CAAAAAAAErv//1yAAAAAAAErv//xgAAAAAAAEnv/xAAAAAAAEnv/xAAAAAEnv//xgAAAEnv//1yAAAAf///2CAAAAAAr/6DAAAAAAAAmTAAAAAAAAAAAAAAAAAAAAAAWt/+tAAAf/////gAB6QgPv/yAAAAAJ//QAAAAB7/8gAAAB3/+wAAAB3/+wAAAAv/+wAAAAL//gAAAABP/6AAAAAAAAAAAAAAAAAAAAAABP/5AAAAAE//kAAAAAT/+QAAAABP/5AAAAAAAASd/9thAAAAAAADz/////+AAAAAAG/9cwAVr/wQAAAF/4AAAAAD38AAAC/2AAAAAAAd9wAAr6AAbf1q+QP+AAD/IAj///75AN8wBfsAL/sRv/kAn2AH+QBv8QAf+QCfYAj3AI/wAA75AM9AB/gAb/EAH/kD/wAF+wAv+xG/+V74AAH/EAj///7//5AAAK+QAG39av6kAAAAL/YAAAAAAAAAAAAG/3AAAAAHcAAAAAB//XIAJt/xAAAAAATf/////mAAAAAAAAWt/+pgAAAAAAAC///yAAAAAACP//+AAAAAAA7///4AAAAABP////QAAAAAr/9//6AAAAAP/+Df/wAAAAX/+Aj/9gAAAL//IC//wAAAH//QAN//IAAH//cAB//4AADf///////QAD////////8wCf/yAAAC//kA7/4AAAAN//Bf/6AAAACf/1v/9gAAAAX/+wD/////2TAAAA///////3AAAP//IAX//yAAD//yAAv/9wAA//8gAJ//gAAP//IAC//2AAD//yAF//8QAA///////TAAAP//////+QAAD//yACv/+QAA//8gAB//8AAP//IAAP//IAD//yAAH//yAA//8gAr//0AAP///////jAAD/////7HEAAAAAKM7/24MAAAn/////+wAAz//EEDj7AAr/+wAAABgAP//xAAAAAACP/7AAAAAAAM//cAAAAAAA3/9gAAAAAADf/2AAAAAAAM//cAAAAAAAj/+wAAAAAAA///EAAAAAAAr/+wAAABgAAM//xAAo+wAACf/////7AAAAKM7/3IMAD////tuCAAAAD///////sQAAD//yAUv//iAAD//yAACf/9AAD//yAAAN//YAD//yAAAH//wAD//yAAAE//8AD//yAAAC//8QD//yAAAD//8QD//yAAAE//8AD//yAAAH//wAD//yAAAN//YAD//yAACf/9AAD//yAUv//iAAD///////sQAAD////9uCAAAAD///////MAD///////MAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//////8AAD//////8AAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD///////YAD///////YAD///////MAD///////MAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//////8AAD//////8AAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAD//yAAAAAAAAAnvv/ttzAAAAn//////9AAAM//1RAVr9AACv/8AAAAApAAP//yAAAAAAAAj/+wAAAAAAAAz/9wAAAAAAAA3/9gAA////cA3/9gAA////cAz/9wAAAH//cAj/+wAAAH//cAP//xAAAH//cACv/7AAAH//cAAM//xRAq//cAAAn///////cAAAAozv/spzAAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD/////////YAD/////////YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAAAM//YAD//yAA//8gAP//IAD//yAA//8gAP//IAD//yAA//8gAP//IAD//yAA//8gAP//IAD//yAA//8gAP//IAD//yAAAP//IAAA//8gAAD//yAAAP//IAAA//8gAAD//yAAAP//IAAA//8gAAD//yAAAP//IAAA//8gAAD//yAAAP//IAAA//8gAAD//yAAAP//EAAE//8AAD3/+QA///+wAD/9pQAAAP//IAAG//9gAP//IABv//YAAP//IAb//2AAAP//IH//9QAAAP//J///UAAAAP//r//1AAAAAP////9QAAAAAP////cAAAAAAP////4wAAAAAP/////jAAAAAP//Tv//MAAAAP//Iu//8wAAAP//IC7//zAAAP//IAHf//MAAP//IAAd//8wAP//IAAB3//0AP//IAAAAAD//yAAAAAA//8gAAAAAP//IAAAAAD//yAAAAAA//8gAAAAAP//IAAAAAD//yAAAAAA//8gAAAAAP//IAAAAAD//yAAAAAA//8gAAAAAP//IAAAAAD//yAAAAAA///////2AP//////9gD///cAAACf//0AAP///gAAAf///QAA////UAAH///9AAD////AAA3///0AAP////MAT/7//QAA//+f+QC/9//9AAD//y//Ev/x//0AAP//C/95/5D//QAA//8E/+//IP/9AAD//wDf//sA//0AAP//AG//9QD//QAA//8AD//gAP/9AAD//wAJ/3AA//0AAP//AAAAAAD//QAA//8AAAAAAP/9AAD//wAAAAAA//0AAP//4AAAj/9gAP//9wAAj/9gAP///gAAj/9gAP///4AAj/9gAP////EAj/9gAP//z/kAj/9gAP//T/8Qj/9gAP//C/+gj/9gAP//A//yj/9gAP//AK/7j/9gAP//AC//z/9gAP//AAn///9gAP//AAH///9gAP//AACP//9gAP//AAAf//9gAP//AAAH//9gAAAEnf/sggAAAAAc//////kAAAAe//gQO//7AAAM//cAAAz/9wAE//4AAABP/+AAn/+gAAAA7/9ADP/3AAAADP/3AN//YAAAAL//gA3/9gAAAAv/+ADP/3AAAADP/3AJ//oAAAAO//QAT//gAAAE//4AAM//cAAAz/9wAAHv/4EDv/+wAAABz/////+QAAAAAEnf/sggAAAA/////+pQAAD///////sAAP//IATv/5AA//8gAF//8AD//yAAH//yAP//IAAf//IA//8gAF//8AD//yAE7/+QAP//////+wAA/////+pQAAD//yAAAAAAAP//IAAAAAAA//8gAAAAAAD//yAAAAAAAP//IAAAAAAA//8gAAAAAAAABJ3v7IIAAAAAHP/////5AAAAHv/4EDv/+wAADP/3AAAM//cABP/+AAAAT//gAJ//oAAAAO//QAz/9wAAAAz/9wDf/2AAAAC//4AN//YAAAAL//kAz/9wAAAAz/9wCf/6AAAADv/0AE//4AAABP//AADP/3AAAM//gAAB7/+BA7//wAAAAc//////sAAAAABJ3v//cAAAAAAAAAC//hAAAAAAAAAB3/0QAAAAAAAAAe/9EAAA/////9kgAAAP//////9QAAD//yAY//8QAA//8gAO//UAAP//IAC//2AAD//yAAv/9QAA//8gAO//IAAP//IBj/+AAAD//////nAAAA//////6AAAAP//ID7/+AAAD//yAD//8wAA//8gAK//sAAP//IAAv//MAD//yAACv/7AA//8gAAL//0AAF87/7bgQAALv/////zAADf/lECjvMAA//3AAAAggAG//YAAAAAAAb//TAAAAAAAv///aYwAAAAr/////1QAAAJ//////cAAAAWrv///wAAAAAAOv//MAAAAAAA3/8wBIAAAADf/wAE/5QQKf/6AAT//////9EAAWnN7/62AADv////////7v////////4AAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAAAAn/+QAAAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAT//QAA//8gAAX//AAA3/9AAAb/+wAAn/+AAAr/9wAAL//2EX//4QAABf/////+MAAAABfO/+twAAC//3AAAABv/7X//AAAAAz/9Q7/8gAAAv//AJ//gAAAf/+QA//+AAAN//MADf/zAAP//QAAf/+QAJ//gAAB//4ADv/yAAAL//UE//wAAABf/6Cv/2AAAAD//x//8AAAAAr//P/6AAAAAE////9AAAAAAO///+AAAAAACP//+AAAAAAAL///IAAAP/+wAAD//zAAB//3D//wAAP//3AAC//zDP/zAAf//7AAD//wCP/3AAv///AAP/+wBP/7AA7/v/MAb/+AAP/+AC/7f/YAr/9AAM//IG/3P/oA7/8AAI//YK/0D/4C//wAAF//oN/wDP8m//kAAB//4f/ACP9Z//UAAA3/9/+ABP+d//EAAAn//v9AAP/v/9AAAAX///8QAM///5AAAAL///0AAJ///2AAAADv//kAAF///yAAAACv//UAAB///gAAHv/0AAAF//4QX//hAAH//0AAr/+gAL//kAAB7/9Qb//QAAAE//4///MAAAAJ////+AAAAAAN///9AAAAAABP//8wAAAAAAf///YAAAAAAv////IAAAAAz//f/8AAAACP/8Df/3AAAD//8gP//yAADf/3AAf//AAI//wAAAz/9wP//yAAAC//8w3/+QAAAL//wAP//0AABf//IACf/9AAHv/3AAAN//gAr//QAAAE//80//8wAAAAn//N//gAAAAADv///9AAAAAABP///zAAAAAAAJ//+AAAAAAAAC//8AAAAAAAAB//8AAAAAAAAB//8AAAAAAAAB//8AAAAAAAAB//8AAAAAAAAB//8AAAAAAAAB//8AAAAAz///////+wDP///////7AAAAAADP//sAAAAACP//8gAAAABf//9QAAAAAv//+QAAAAAM///AAAAAAJ///iAAAAAF///0AAAAAC///4AAAAAA3//8AAAAAAr//+EAAAAAb///QAAAAAD///cAAAAAAP////////8A/////////wAf///5AB////kAH/+AAAAf/4AAAB//gAAAH/+AAAAf/4AAAB//gAAAH/+AAAAf/4AAAB//gAAAH/+AAAAf/4AAAB//gAAAH/+AAAAf/4AAAB//gAAAH/+AAAAf///5AB////kN+AAAAI/QAAAD/yAAAA73AAAAn8AAAAT/EAAADvYAAACvsAAABf8QAAAP9QAAAL+gAAAG/wAAAB/0AAAAz5AAAAf+AAAAL/MAAADfgAAACP0Aj///8gCP///yAAAH//IAAAf/8gAAB//yAAAH//IAAAf/8gAAB//yAAAH//IAAAf/8gAAB//yAAAH//IAAAf/8gAAB//yAAAH//IAAAf/8gAAB//yAAAH//IAj///8gCP///yAAAAAJ/+EAAAAAAACP//0QAAAAAAf//v/RAAAAAG/+Qb/8AAAABf/BAAb/sAAAX/gAAAA9+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wB/9gAAAACP8wAAAACP0QAAAACPsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACe+/+xwAAAP/////+EAAMYxAX//oAAAAAAA3/8AABjO////8QA+//////8QDP/4EAz/8QD//gAA7/8QD//gAE//8QDP/3A+//8QBP///8z/8QADv/1wz/8QAv/7AAAAAAAC//sAAAAAAAL/+wAAAAAAAv/7AAAAAAAC//sAAAAAAAL/+wff6iAAAv/7z///4wAC///CBv/9AAL//yAAv/9QAv/9AABf/5AC//sAAE//sAL/+wAAT/+wAv/9AABf/5AC//8gAK//UAL//8IG//0AAv/7z///4wAC//sH3+ogAAAAa+/sYQAC3////5AB7/+BAncAn/+QAAAADv/yAAAAAP//AAAAAA//8AAAAADv/yAAAAAJ//kAAAAAHv/4ECdwAD3////5AAAGvv7HEAAAAAAA//4AAAAAAAD//gAAAAAAAP/+AAAAAAAA//4AAAAAAAD//gAABL/8UP/+AABv///4//4AAv/+QE7//gAJ//YAB//+AA3/8QAB//4AD//wAAD//gAP//AAAP/+AA3/8QAB//4ACf/2AAb//gAC//4wTv/+AABv///4//4AAAS//FD//gAAAHvv7GAAAAPv////0QAB7/5ATv/AAJ//UABv/1AO//AAAv/6AP///////8AP///////9AO//AAAAAAAJ//UAAAAAAB7/5hAjfEAAPv/////0AAAGvv/bcwAAAq7//AAe///8AH//gAAAr/8wAACv/yAAn/////ef////9wCv/yAAAK//IAAAr/8gAACv/yAAAK//IAAAr/8gAACv/yAAAK//IAAAr/8gAACv/yAAAAO//FD//gAAb///+P/+AAL//kBO//4ACf/3AAf//gAN//IAAv/+AA//8AAA//4AD//wAAD//gAN//EAAv/+AAn/9gAH//4AAv/+ME7//gAAb///+P/+AAADv/xQ//0AAAAAAAL/+wAAAAAACP/2AAB5QQKP/9AAAI/////8EAAABb3/2lAAAAL/+wAAAAAAAv/7AAAAAAAC//sAAAAAAAL/+wAAAAAAAv/7AAAAAAAC//sH3+swAAL/+8////MAAv//0xn/+gAC//8gAP/+AAL//QAA//4AAv/7AADv/wAC//sAAO//AAL/+wAA7/8AAv/7AADv/wAC//sAAO//AAL/+wAA7/8AAv/7AADv/wAC//sAAv/7AAL/+wAC//sAAAAAAAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAAAAAAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/7AAAv/6AAA//5AAGv/1AL///AAL/9gAAAL/+wAAAAAAAv/7AAAAAAAC//sAAAAAAAL/+wAAAAAAAv/7AAAAAAAC//sABv/+IAL/+wBv/9IAAv/7Bv/9EAAC//tv/8EAAAL//v/7AAAAAv///+AAAAAC////+gAAAAL/+8//oAAAAv/7Hf/6AAAC//sB3/+QAAL/+wAu//kAAv/7AALv/4AC//sAAv/7AAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAL/+wAC//sAAv/7AAL/+wjv1wBc/8UAAC//vf//+o////YAAv//sR3//4FP/+AAL//xAI//0ADP/yAC//wAB//4AAr/8gAv/7AAb/9wAK//MAL/+wAG//cAC//zAC//sABv/3AAv/8wAv/7AAb/9wAL//MAL/+wAG//cAC//zAC//sABv/3AAv/8wAv/7AAb/9wAL//MAL/+wff6zAAAv/7z///8wAC///TGf/6AAL//yAA//4AAv/9AAD//gAC//sAAO//AAL/+wAA7/8AAv/7AADv/wAC//sAAO//AAL/+wAA7/8AAv/7AADv/wAC//sAAO//AAABfO/sgQAAA+/////0AAHv/kA9//MAn/9gAF//sA7/8QAA//8A//8AAA7/8g//8AAA7/8g7/8QAA//8An/9gAF//sAHv/kA9//MAA+/////0AAABfO/8gQAAL/+wff6iAAAv/7z///4wAC///CBv/9AAL//yAAv/9QAv/9AABf/5AC//sAAE//sAL/+wAAT/+wAv/9AABf/5AC//8gAK//UAL//8IG//0AAv/7z///4wAC//sH3+ogAAL/+wAAAAAAAv/7AAAAAAAC//sAAAAAAAL/+wAAAAAAAv/7AAAAAAAABL/8UP/+AABv///4//4AAv/+QE7//gAJ//YAB//+AA3/8QAB//4AD//wAAD//gAP//AAAP/+AA3/8QAB//4ACf/2AAb//gAC//4wTv/+AABv///4//4AAAS//FD//gAAAAAAAP/+AAAAAAAA//4AAAAAAAD//gAAAAAAAP/+AAAAAAAA//4AAv/7CN/AL/+9//wC///kAAAv//MAAAL//QAAAC//sAAAAv/7AAAAL/+wAAAC//sAAAAv/7AAAAL/+wAAAC//sAAAACnf/shAAC//////QAr/0gE3wwDf+gAAAAAM//6oUQAAb/////sQAH/////6AAAEac//8AAAAAC//wCaUhA+/9AK//////QAFazv/ZIAAM//AAAADP/wAAAAz/8AAAv/////8L//////AAz/8AAAAM//AAAADP/wAAAAz/8AAAAM//AAAADP/wAAAAz/8QAAAK//YAAABf///6AABs//+gAE//kAAP/9AAT/+QAA//0ABP/5AAD//QAE//kAAP/9AAT/+QAA//0ABP/5AAD//QAE//kAAP/9AAT/+QAC//0AA//7AAf//QAA//9AX//9AACP///3//0AAAbP+0D//QB//1AAAP/9Af/7AABv/2AL//EAC//xAE//YAH/+gAA7/wAf/8wAAj/8g3/0AAAH/+C//cAAAC//o//EAAABf///6AAAAAO///0AAAAAI///QAAAAAC//9wAAAf/6AAn/4ABP/2Df/gAM//IAj/8gn/8QD//2AM/+AE//UE//+gD/+gAP/5CP+v4E//UADP/Qz7b/KP/xAAj/8v9y/2z/0AAD//r/MO+v/5AAAP///wCv//9QAAC///wAb///AAAAf//4AC///AAAAD//9AAO//gAAv/+EADP/0Bf/6AH//gACf/1P//AAADf/t/+EAAAL///9AAAAAb//5AAAAAJ///AAAAAX///+AAAAv/9v/9AAAz/8x7/4QCP/3AE//sE//wAAJ//eP/0AAAf/8H/+wAAb/9gr/8QAM//AE//cAH/+gAN/+AG//QABv/0DP/gAAD/+x//kAAAn/+P/zAAAC////0AAAAL///3AAAABf//8QAAAADv/7AAAAAAj/9gAAAAAJ//AAAAAAT/+QAAAAz//9AAAAAM/+kQAAAAz//////ADP/////8AAAAAv//sAAAAe//8wAAAd//9QAAAM//9gAAAK//+AAAAJ//+gAAAH//+wAAAA///QAAAAD//////8AP//////wAAAAAW+/+AAAAAAX///4AAAAADP/1AAAAAAAO/9AAAAAAAA7/wAAAAAAADv/AAAAAAAAO/7AAAAAAAB//oAAAAAACv/9gAAAABP//+AAAAAAE///6AAAAAAACv/9wAAAAAAAv/6AAAAAAAA//sAAAAAAADv/AAAAAAAAO/8AAAAAAAA7/0AAAAAAADP/1AAAAAAAF///+AAAAAABb7/4AAAP/MAAD/zAAA/8wAAP/MAAD/zAAA/8wAAP/MAAD/zAAA/8wAAP/MAAD/zAAA/8wAAP/MAAD/zAAA/8wAAP/MAAD/zAAA/8wAAP/MAAD/zAAA/8wAAP/MAAE//6iAAAAAAT///4QAAAAAAGv/3AAAAAAAC//gAAAAAAAH/+QAAAAAAAf/5AAAAAAAB//kAAAAAAAD//AAAAAAAAL//cQAAAAAAK///4AAAAAAt///gAAAAAM//gQAAAAAA//wAAAAAAAH/+QAAAAAAAf/5AAAAAAAB//kAAAAAAAL/+AAAAAAAGv/2AAAAAE///+EAAAAAT//qIAAAAAAAAAAAAAAAAAAFvv63MQJ+EACf////////EACv////////EACtUQJZ3/2BAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAAAAAB+/QAAAAAAB+//0AAAAAB+///9AAAAB+/////QAAB+//////0AB+///////9B+/////////W//////////0Bj////////9AAGP///////QAAAY//////0AAAABj////9AAAAAAGP///QAAAAAAAY//0AAAAAAAABj9AAAAAAAAAAFgAAAAAAAAAADWAAAAAAAAAA/+YAAAAAAAAP//5gAAAAAAD////mAAAAAA/////+YAAAAP//////5gAAD////////mAA/////////+YP/////////+X////////+cA///////+cAAP/////+cAAAD////+cAAAAA///+cAAAAAAP/+cAAAAAAAD+cAAAAAAAAAcAAAAAAAAAAAAiIiIiIiIiIhAAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAD//////////8AAC7u7u7u7u7u4AA==" # labels / buttons (DejaVuSans-Bold 22)
|
|
FONT_L_B64 = "CwAwNjsADzYAMTY5ABA2ADI2OgAPNgAzNjsADzYANDY5ABA2ADU2OgAQNgA2NjsADzYANzY5ABA2ADg2OwAPNgA5NjsADzYAIAAAAAAbAAAAAAAAAAAAACab3v/+ynQAAAAAAAAAAAAAAAAAAAAAAAADjv/////////6QAAAAAAAAAAAAAAAAAAAAAO//////////////VAAAAAAAAAAAAAAAAAAAJ////////////////wgAAAAAAAAAAAAAAAALf/////////////////1AAAAAAAAAAAAAAAD7///////////////////YAAAAAAAAAAAAAAv////////////////////9gAAAAAAAAAAAAHv/////////////////////0AAAAAAAAAAAAv//////////////////////+EAAAAAAAAAAH////////////////////////sAAAAAAAAAAf/////////9YgAVv/////////9QAAAAAAAACf////////+AAAAABf/////////QAAAAAAAAH/////////kAAAAAAE/////////1AAAAAAAAj////////9AAAAAAAAn////////8AAAAAAAA7////////1AAAAAAAAH/////////MAAAAAAE/////////gAAAAAAAAC/////////gAAAAAAJ////////+gAAAAAAAABv////////0AAAAAAN////////9gAAAAAAAAAv////////8gAAAAAf////////8gAAAAAAAAAO////////9gAAAABf////////8AAAAAAAAAAM////////+QAAAACP////////0AAAAAAAAAAJ/////////AAAAACv////////wAAAAAAAAAAH/////////wAAAADf////////oAAAAAAAAAAG/////////xAAAAD/////////kAAAAAAAAAAF/////////zAAAAD/////////gAAAAAAAAAAE/////////0AAAAH/////////cAAAAAAAAAAD/////////2AAAAL/////////YAAAAAAAAAAC/////////3AAAAP/////////YAAAAAAAAAAC/////////3AAAAP/////////YAAAAAAAAAAC/////////4AAAAT/////////YAAAAAAAAAAC/////////4AAAAP/////////YAAAAAAAAAAC/////////4AAAAP/////////YAAAAAAAAAAC/////////3AAAAL/////////cAAAAAAAAAAC/////////3AAAAL/////////cAAAAAAAAAAD/////////2AAAAD/////////gAAAAAAAAAAE/////////0AAAAD/////////kAAAAAAAAAAF/////////zAAAADf////////oAAAAAAAAAAG/////////xAAAACv////////wAAAAAAAAAAI/////////wAAAACP////////4AAAAAAAAAAK/////////AAAAABf////////8AAAAAAAAAAM////////+QAAAAAf////////8wAAAAAAAAAP////////9gAAAAAN////////9gAAAAAAAAAv////////8gAAAAAJ////////+gAAAAAAAABv////////0AAAAAAE/////////wAAAAAAAAC/////////gAAAAAAA7////////2AAAAAAAAL/////////MAAAAAAAj////////9AAAAAAAAr////////8AAAAAAAAH/////////kAAAAAAF/////////1AAAAAAAACf////////+QAAAABf/////////QAAAAAAAAAf/////////9YgAVv/////////9QAAAAAAAAAH////////////////////////sAAAAAAAAAAAz//////////////////////+EAAAAAAAAAAAHv/////////////////////0AAAAAAAAAAAAAv////////////////////9gAAAAAAAAAAAAAD7///////////////////YAAAAAAAAAAAAAAALf/////////////////1AAAAAAAAAAAAAAAAAJ////////////////wgAAAAAAAAAAAAAAAAAAO//////////////VAAAAAAAAAAAAAAAAAAAAADnv/////////6QAAAAAAAAAAAAAAAAAAAAAAAADac7v/+ynQAAAAAAAAAAAAAAAAAAAAAAAAANq7/////////AAAAAAAAAAAAAAAAAAAAAUi/////////////AAAAAAAAAAAAAAAAAAJp3///////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////////////////AAAAAAAAAAAAAAAAAD//////2VLv////////AAAAAAAAAAAAAAAAAD///rdAAADv////////AAAAAAAAAAAAAAAAAD2WIAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAAAAAAAAAADv////////AAAAAAAAAAAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAA3/////////////////////////4AAAAAAAAAAAAAFGis3e///suGIAAAAAAAAAAAAAAAAAAAAVi+/////////////pQAAAAAAAAAAAAAAABJ3//////////////////VAAAAAAAAAAAAAAr/////////////////////wwAAAAAAAAAAAAr//////////////////////3AAAAAAAAAAAAr///////////////////////gAAAAAAAAAAAr///////////////////////+AAAAAAAAAAAr////////////////////////0AAAAAAAAAAr////////////////////////+AAAAAAAAAAr/////////////////////////cAAAAAAAAAr//////7dCABJZ////////////4AAAAAAAAAr////7UAAAAAAAGf//////////9AAAAAAAAAr///kgAAAAAAAAAF//////////+QAAAAAAAAr/+RAAAAAAAAAAAAb//////////AAAAAAAAAr6IAAAAAAAAAAAAAC//////////gAAAAAAAAhAAAAAAAAAAAAAAAA//////////wAAAAAAAAAAAAAAAAAAAAAAAAAO/////////xAAAAAAAAAAAAAAAAAAAAAAAAAM/////////xAAAAAAAAAAAAAAAAAAAAAAAAAK/////////wAAAAAAAAAAAAAAAAAAAAAAAAAK/////////gAAAAAAAAAAAAAAAAAAAAAAAAAM////////+wAAAAAAAAAAAAAAAAAAAAAAAAAP////////9wAAAAAAAAAAAAAAAAAAAAAAAABf////////8gAAAAAAAAAAAAAAAAAAAAAAAADP////////wAAAAAAAAAAAAAAAAAAAAAAAAAX/////////QAAAAAAAAAAAAAAAAAAAAAAAAB7////////8AAAAAAAAAAAAAAAAAAAAAAAAAM/////////yAAAAAAAAAAAAAAAAAAAAAAAAC/////////9gAAAAAAAAAAAAAAAAAAAAAAAAv/////////oAAAAAAAAAAAAAAAAAAAAAAAAc/////////7AAAAAAAAAAAAAAAAAAAAAAAALf/////////AAAAAAAAAAAAAAAAAAAAAAAAD7/////////0QAAAAAAAAAAAAAAAAAAAAAABP/////////8EAAAAAAAAAAAAAAAAAAAAAAAb//////////BAAAAAAAAAAAAAAAAAAAAAAAI//////////sAAAAAAAAAAAAAAAAAAAAAAACv/////////6AAAAAAAAAAAAAAAAAAAAAAABz/////////+AAAAAAAAAAAAAAAAAAAAAAAAt//////////YAAAAAAAAAAAAAAAAAAAAAAAPv/////////0AAAAAAAAAAAAAAAAAAAAAAAE//////////4wAAAAAAAAAAAAAAAAAAAAAABv/////////9EAAAAAAAAAAAAAAAAAAAAAAAj/////////+wAAAAAAAAAAAAAAAAAAAAAAAK//////////kAAAAAAAAAAAAAAAAAAAAAAAHP/////////3AAAAAAAAAAAAAAAAAAAAAAAC3/////////9QAAAAAAAAAAAAAAAAAAAAAAA+/////////+QAAAAAAAAAAAAAAAAAAAAAAAT//////////iAAAAAAAAAAAAAAAAAAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAA3//////////////////////////4AAAAAAAAAAAAATaJvN7v//7cuXQQAAAAAAAAAAAAAAAAACWc///////////////9gwAAAAAAAAAAAAAABf///////////////////9YAAAAAAAAAAAAABf/////////////////////UAAAAAAAAAAAABf//////////////////////gAAAAAAAAAAABf//////////////////////+QAAAAAAAAAABf///////////////////////2AAAAAAAAAABf////////////////////////EAAAAAAAAABf////////////////////////kAAAAAAAAABf////////////////////////8AAAAAAAAABf///9qFMhABJHz///////////9AAAAAAAAABf/6YQAAAAAAAAA8//////////9wAAAAAAAABbUAAAAAAAAAAAAAn/////////+gAAAAAAAAAAAAAAAAAAAAAAAADP////////+wAAAAAAAAAAAAAAAAAAAAAAAABP////////+wAAAAAAAAAAAAAAAAAAAAAAAAAP////////+gAAAAAAAAAAAAAAAAAAAAAAAAAP////////+AAAAAAAAAAAAAAAAAAAAAAAAAAP////////9QAAAAAAAAAAAAAAAAAAAAAAAABP////////8QAAAAAAAAAAAAAAAAAAAAAAAADP////////sAAAAAAAAAAAAAAAAAAAAAAAAAj/////////MAAAAAAAAAAAAAAAAAAAAAAAA7/////////5AAAAAAAAAAAAAAAAAAAAABNY3/////////+wAAAAAAAAAAAAAAAA//////////////////oAAAAAAAAAAAAAAAAA/////////////////mAAAAAAAAAAAAAAAAAA///////////////9cAAAAAAAAAAAAAAAAAAA//////////////1AAAAAAAAAAAAAAAAAAAAA///////////////7UAAAAAAAAAAAAAAAAAAA/////////////////EAAAAAAAAAAAAAAAAAA//////////////////kAAAAAAAAAAAAAAAAA///////////////////AAAAAAAAAAAAAAAAA///////////////////7AAAAAAAAAAAAAAAA////////////////////gAAAAAAAAAAAAAAAAAAAARNp3///////////8gAAAAAAAAAAAAAAAAAAAAAAA6//////////+gAAAAAAAAAAAAAAAAAAAAAAAAT//////////xAAAAAAAAAAAAAAAAAAAAAAAAA//////////2AAAAAAAAAAAAAAAAAAAAAAAAAH/////////6AAAAAAAAAAAAAAAAAAAAAAAAAB/////////9AAAAAAAAAAAAAAAAAAAAAAAAAAz////////+AAAAAAAAAAAAAAAAAAAAAAAAAAr/////////AAAAAAAAAAAAAAAAAAAAAAAAAAr/////////AAAAAAAAAAAAAAAAAAAAAAAAAAz/////////AAAAAAAAAAAAAAAAAAAAAAAAAA//////////AAAAAAAAAAAAAAAAAAAAAAAAAH/////////8AAAAAAAKcQAAAAAAAAAAAAAAAv/////////6AAAAAAAM/5MAAAAAAAAAAAAAPv/////////1AAAAAAAM///pQAAAAAAAAAAq///////////xAAAAAAAM/////8lkIQABJY3///////////+gAAAAAAAM//////////////////////////8gAAAAAAAM//////////////////////////gAAAAAAAAM/////////////////////////8AAAAAAAAAM/////////////////////////RAAAAAAAAAM////////////////////////wQAAAAAAAAAM///////////////////////4AAAAAAAAAAAM//////////////////////swAAAAAAAAAAABa///////////////////+jAAAAAAAAAAAAAAAASL//////////////6lAAAAAAAAAAAAAAAAAAAAAleb3e///+y5dBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//////////kAAAAAAAAAAAAAAAAAAAAAAAC///////////kAAAAAAAAAAAAAAAAAAAAAAAb///////////kAAAAAAAAAAAAAAAAAAAAAAC////////////kAAAAAAAAAAAAAAAAAAAAAAM////////////kAAAAAAAAAAAAAAAAAAAAAB/////////////kAAAAAAAAAAAAAAAAAAAAAL/////////////kAAAAAAAAAAAAAAAAAAAAAz/////////////kAAAAAAAAAAAAAAAAAAAAH//////////////kAAAAAAAAAAAAAAAAAAAA///////////////kAAAAAAAAAAAAAAAAAAADf//////////////kAAAAAAAAAAAAAAAAAAAj///////////////kAAAAAAAAAAAAAAAAAAD//////+/////////kAAAAAAAAAAAAAAAAAAN//////xP////////kAAAAAAAAAAAAAAAAACf//////JP////////kAAAAAAAAAAAAAAAAAP//////2BP////////kAAAAAAAAAAAAAAAAA3//////ABP////////kAAAAAAAAAAAAAAAAJ//////8gBP////////kAAAAAAAAAAAAAAABP//////YABP////////kAAAAAAAAAAAAAAAHv/////7AABP////////kAAAAAAAAAAAAAAAr//////xAABP////////kAAAAAAAAAAAAAAE//////9gAABP////////kAAAAAAAAAAAAAAe//////sAAABP////////kAAAAAAAAAAAAACv//////EAAABP////////kAAAAAAAAAAAAAX//////2AAAABP////////kAAAAAAAAAAAAB7/////+wAAAABP////////kAAAAAAAAAAAAL//////4QAAAABP////////kAAAAAAAAAAABv//////UAAAAABP////////kAAAAAAAAAAAH//////6AAAAAABP////////kAAAAAAAAAAAv//////hAAAAAABP////////kAAAAAAAAAAG//////9QAAAAAABP////////kAAAAAAAAAAv//////oAAAAAAABP////////kAAAAAAAAADP/////+EAAAAAAABP////////kAAAAAAAAAb//////1AAAAAAAABP////////kAAAAAAAAAj/////+gAAAAAAAABP////////kAAAAAAAAAj/////4QAAAAAAAABP////////kAAAAAAAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAj//////////////////////////////7AAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAAAAAAAAAAAAAABP////////kAAAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////////////////////7AAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAL///////yWc3v/+y4UgAAAAAAAAAAAAAAAAAL/////////////////9ggAAAAAAAAAAAAAAAL///////////////////8QAAAAAAAAAAAAAAL////////////////////+hAAAAAAAAAAAAAL/////////////////////+QAAAAAAAAAAAAL//////////////////////9gAAAAAAAAAAAL///////////////////////1AAAAAAAAAAAL////////////////////////MAAAAAAAAAAL////////////////////////0AAAAAAAAAAL////////////////////////9wAAAAAAAAAL////2nUyEAE2r////////////gAAAAAAAAAL/+lRAAAAAAAAAY///////////2AAAAAAAAAKlAAAAAAAAAAAAALf/////////8AAAAAAAAAAAAAAAAAAAAAAAAAd//////////EAAAAAAAAAAAAAAAAAAAAAAAAD//////////QAAAAAAAAAAAAAAAAAAAAAAAAAr/////////gAAAAAAAAAAAAAAAAAAAAAAAAAX/////////oAAAAAAAAAAAAAAAAAAAAAAAAAD/////////sAAAAAAAAAAAAAAAAAAAAAAAAAD/////////wAAAAAAAAAAAAAAAAAAAAAAAAADf////////0AAAAAAAAAAAAAAAAAAAAAAAAAD/////////wAAAAAAAAAAAAAAAAAAAAAAAAAD/////////sAAAAAAAAAAAAAAAAAAAAAAAAAX/////////kAAAAAAAAAAAAAAAAAAAAAAAAAr/////////cAAAAAAAswAAAAAAAAAAAAAAAD//////////QAAAAAAA/7QAAAAAAAAAAAAAAe//////////AAAAAAAA///WEAAAAAAAAAAALf/////////6AAAAAAAA////+1EAAAAAAAAY///////////0AAAAAAAA///////JYxAAE2r////////////QAAAAAAAA//////////////////////////9AAAAAAAAA//////////////////////////kAAAAAAAAA/////////////////////////8AAAAAAAAAA/////////////////////////RAAAAAAAAAA////////////////////////wQAAAAAAAAAA///////////////////////5AAAAAAAAAAAA//////////////////////1AAAAAAAAAAAAAJr///////////////////FAAAAAAAAAAAAAAAABHrv/////////////YMAAAAAAAAAAAAAAAAAAAABRom93v//7cp0EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN5ze//7tyoYxAAAAAAAAAAAAAAAAAAAAAAa/////////////6nMAAAAAAAAAAAAAAAAAGf////////////////9QAAAAAAAAAAAAAAAI//////////////////9QAAAAAAAAAAAAAAPf//////////////////9QAAAAAAAAAAAAAG////////////////////9QAAAAAAAAAAAACP////////////////////9QAAAAAAAAAAAAj/////////////////////9QAAAAAAAAAAAG//////////////////////9QAAAAAAAAAAA///////////////////////9QAAAAAAAAAADv//////////6mMgASNov///9QAAAAAAAAAAj//////////FAAAAAAAAAEnv9QAAAAAAAAAC//////////YAAAAAAAAAAAAEpQAAAAAAAAAK/////////jAAAAAAAAAAAAAAAAAAAAAAAAAv////////9AAAAAAAAAAAAAAAAAAAAAAAAACf////////cAAAAAAAAAAAAAAAAAAAAAAAAADv///////+AAAAAAAAAAAAAAAAAAAAAAAAAAX////////2AAAAAAAAAAAAAAAAAAAAAAAAAAn////////wAAAAAAAAAAAAAAAAAAAAAAAAAA7///////+gAAAAAAAAAAAAAAAAAAAAAAAAAC////////9gAAFYze/+24UAAAAAAAAAAAAAAF////////8gA6/////////7QAAAAAAAAAAAAI////////8Cz////////////UAAAAAAAAAAAL////////6P//////////////oAAAAAAAAAAN/////////////////////////RAAAAAAAAAO/////////////////////////+IAAAAAAAAP//////////////////////////0QAAAAAAAf//////////////////////////+wAAAAAAAf///////////////////////////2AAAAAAAv///////////////////////////+AAAAAAAv////////////xiABSf//////////cAAAAAAf///////////2AAAAABz/////////0AAAAAAf//////////9gAAAAAAHf////////8wAAAAAP//////////wAAAAAAABP////////9wAAAAAP//////////UAAAAAAAAN////////+wAAAAAO//////////AAAAAAAAAI/////////QAAAAAM/////////8AAAAAAAAAF/////////wAAAAAK/////////6AAAAAAAAAC/////////wAAAAAH/////////5AAAAAAAAAB/////////xAAAAAF/////////4AAAAAAAAAA/////////wAAAAAB/////////5AAAAAAAAAB/////////wAAAAAA3////////6AAAAAAAAAC/////////gAAAAAAn////////8AAAAAAAAAF/////////AAAAAAAT/////////AAAAAAAAAI////////+QAAAAAADv////////UAAAAAAAAN////////9QAAAAAACf////////sAAAAAAABP////////8QAAAAAAAv////////9gAAAAAADf////////sAAAAAAAAK/////////2AAAAABz/////////UAAAAAAAAC//////////xiABSf/////////9AAAAAAAAAAj////////////////////////0AAAAAAAAAADP//////////////////////+gAAAAAAAAAAAu//////////////////////0AAAAAAAAAAAAD/////////////////////+IAAAAAAAAAAAAAT////////////////////SAAAAAAAAAAAAAAA+//////////////////wQAAAAAAAAAAAAAAABr////////////////3AAAAAAAAAAAAAAAAAAA8//////////////kQAAAAAAAAAAAAAAAAAAAAOe//////////xxAAAAAAAAAAAAAAAAAAAAAAAAN6zu//7LhRAAAAAAAAAAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM////////////////////////////EAAAAAAM///////////////////////////+AAAAAAAM///////////////////////////4AAAAAAAM///////////////////////////xAAAAAAAAAAAAAAAAAAAAAAAAAJ////////+QAAAAAAAAAAAAAAAAAAAAAAAAAf////////8gAAAAAAAAAAAAAAAAAAAAAAAACP////////sAAAAAAAAAAAAAAAAAAAAAAAAADv////////MAAAAAAAAAAAAAAAAAAAAAAAAAf////////8AAAAAAAAAAAAAAAAAAAAAAAAAA7////////1AAAAAAAAAAAAAAAAAAAAAAAAAF/////////QAAAAAAAAAAAAAAAAAAAAAAAAAN////////9gAAAAAAAAAAAAAAAAAAAAAAAABP////////4AAAAAAAAAAAAAAAAAAAAAAAAAC/////////gAAAAAAAAAAAAAAAAAAAAAAAAAL/////////EAAAAAAAAAAAAAAAAAAAAAAAAAr////////5AAAAAAAAAAAAAAAAAAAAAAAAAB/////////yAAAAAAAAAAAAAAAAAAAAAAAAAI////////+gAAAAAAAAAAAAAAAAAAAAAAAAAf////////8wAAAAAAAAAAAAAAAAAAAAAAAAB/////////wAAAAAAAAAAAAAAAAAAAAAAAAADv////////UAAAAAAAAAAAAAAAAAAAAAAAAAb////////9AAAAAAAAAAAAAAAAAAAAAAAAAA3////////2AAAAAAAAAAAAAAAAAAAAAAAAAE/////////gAAAAAAAAAAAAAAAAAAAAAAAAAM////////+AAAAAAAAAAAAAAAAAAAAAAAAAA/////////8QAAAAAAAAAAAAAAAAAAAAAAAACv////////kAAAAAAAAAAAAAAAAAAAAAAAAAL/////////IAAAAAAAAAAAAAAAAAAAAAAAAAn////////6AAAAAAAAAAAAAAAAAAAAAAAAAB/////////zAAAAAAAAAAAAAAAAAAAAAAAAAH/////////AAAAAAAAAAAAAAAAAAAAAAAAAAO////////9QAAAAAAAAAAAAAAAAAAAAAAAABv////////0AAAAAAAAAAAAAAAAAAAAAAAAADf////////YAAAAAAAAAAAAAAAAAAAAAAAAAX////////+AAAAAAAAAAAAAAAAAAAAAAAAAAz////////3AAAAAAAAAAAAAAAAAAAAAAAAAD/////////xAAAAAAAAAAAAAAAAAAAAAAAAAK////////+QAAAAAAAAAAAAAAAAAAAAAAAAAv////////8gAAAAAAAAAAAAAAAAAAAAAAAACf////////oAAAAAAAAAAAAAAAAAAAAAAAAAH/////////MAAAAAAAAAAAAAAAAAAAAAAAAAj////////8AAAAAAAAAAAAAAAAAAAAAAAAAA7////////1AAAAAAAAAAAAAAAAAAAAAAAAAG/////////QAAAAAAAAAAAAAAAAAAAAAAAAAN////////9gAAAAAAAAAAAAAAAAAAAAAAAABf////////4AAAAAAAAAAAAAAAAAAAAAAAAADP////////cAAAAAAAAAAAAAAAAAAAAAAAAAT/////////EAAAAAAAAAAAAAAAAAAAAAAAAAv////////5AAAAAAAAAAAAAAAAAAAAAAAAAC/////////yAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJorN7///7LljAAAAAAAAAAAAAAAAAAAAAAWu////////////+2EAAAAAAAAAAAAAAAAAGP////////////////+iAAAAAAAAAAAAAAAG7///////////////////kAAAAAAAAAAAAACv/////////////////////SAAAAAAAAAAAAv//////////////////////+IAAAAAAAAAAJ////////////////////////0AAAAAAAAABP////////////////////////+AAAAAAAAADP/////////////////////////xAAAAAAAAP//////////////////////////3AAAAAAAAj//////////5QQAUjv/////////7AAAAAAAAv/////////wQAAAAAK//////////AAAAAAAA7////////9AAAAAAAAv/////////EAAAAAAA/////////1AAAAAAAAL/////////IAAAAAAA/////////wAAAAAAAADf////////MAAAAAAA7////////gAAAAAAAAC/////////EAAAAAAAz////////gAAAAAAAAC/////////AAAAAAAAn////////wAAAAAAAADf///////9AAAAAAAAX////////1AAAAAAAAL////////4AAAAAAAADv///////9AAAAAAAAv////////yAAAAAAAAB/////////wQAAAAAK////////+gAAAAAAAAAM/////////5QQATjv////////4QAAAAAAAAAB3///////////////////////MAAAAAAAAAAAHP/////////////////////jAAAAAAAAAAAAAI////////////////////oQAAAAAAAAAAAAAAKf////////////////+zAAAAAAAAAAAAAAAAABbv/////////////4EAAAAAAAAAAAAAAAAAA57///////////////pAAAAAAAAAAAAAAAACr//////////////////8QAAAAAAAAAAAAAB/////////////////////+QAAAAAAAAAAAAv//////////////////////9EAAAAAAAAAAL////////////////////////0QAAAAAAAACP/////////5UgATfv/////////AAAAAAAAAP/////////oQAAAAAH/////////2AAAAAAAAz////////5AAAAAAAAX////////+AAAAAAAC/////////QAAAAAAAACv////////YAAAAAAI////////9QAAAAAAAAAv////////sAAAAAAM////////8AAAAAAAAAAN////////8AAAAAAP////////wAAAAAAAAAAJ////////8wAAAAAf////////sAAAAAAAAAAH////////9AAAAAAv////////oAAAAAAAAAAH////////9QAAAAA/////////sAAAAAAAAAAH////////9gAAAAA/////////wAAAAAAAAAAJ////////9gAAAAAv////////8AAAAAAAAAAN////////9QAAAAAP////////9QAAAAAAAAAv////////8wAAAAAN/////////QAAAAAAAACf////////8QAAAAAK/////////5AAAAAAAAX/////////0AAAAAAG//////////oQAAAAAH//////////kAAAAAAA///////////5QQATfv//////////MAAAAAAAn//////////////////////////8AAAAAAAAH//////////////////////////0AAAAAAAAB/////////////////////////+gAAAAAAAAAK////////////////////////0QAAAAAAAAAAv//////////////////////9EAAAAAAAAAAACf/////////////////////BAAAAAAAAAAAAAF7///////////////////cAAAAAAAAAAAAAAAB+////////////////+RAAAAAAAAAAAAAAAAAASe////////////+1AAAAAAAAAAAAAAAAAAAAAAJYrN7///7LhjAAAAAAAAAAAAAAAAAAAAAAAAFIrO//7slzAAAAAAAAAAAAAAAAAAAAAAAABs//////////+TAAAAAAAAAAAAAAAAAAAAAY//////////////xAAAAAAAAAAAAAAAAAAAb////////////////6EAAAAAAAAAAAAAAAAK//////////////////4wAAAAAAAAAAAAAAHf///////////////////1AAAAAAAAAAAAAB3/////////////////////QAAAAAAAAAAAAM//////////////////////8wAAAAAAAAAACP///////////////////////QAAAAAAAAAAP////////////////////////5AAAAAAAAAAz/////////+lEAJr//////////MAAAAAAAAD/////////+MAAAAAX/////////wAAAAAAAAK/////////yAAAAAABP////////8wAAAAAAAP////////9gAAAAAAAJ////////+gAAAAAABP////////8AAAAAAAAC/////////xAAAAAAB/////////oAAAAAAAAA3////////2AAAAAACv////////cAAAAAAAAAr////////7AAAAAADP////////QAAAAAAAAAf/////////AAAAAADv////////MAAAAAAAAAb/////////MAAAAADv////////IAAAAAAAAAb/////////cAAAAAD/////////MAAAAAAAAAb/////////kAAAAADv////////QAAAAAAAAAf/////////wAAAAADf////////cAAAAAAAAAr/////////4AAAAADP////////oAAAAAAAAA3/////////8AAAAACf////////4AAAAAAAAC//////////8QAAAABv////////9gAAAAAAAJ//////////8gAAAAAf/////////hAAAAAABP//////////8wAAAAAM/////////+IAAAAAX///////////8wAAAAAG//////////+lEAJb////////////9AAAAAAA7///////////////////////////9AAAAAAAX///////////////////////////8wAAAAAACv//////////////////////////8wAAAAAAAN//////////////////////////8gAAAAAAAB3/////////////////////////8AAAAAAAAAHP////////////////////////4AAAAAAAAAAJ//////////////+M////////0AAAAAAAAAAAPP///////////8MO////////oAAAAAAAAAAAAEr/////////tAAP////////cAAAAAAAAAAAAAAEi97/7clRAAA/////////QAAAAAAAAAAAAAAAAAAAAAAAAACP////////AAAAAAAAAAAAAAAAAAAAAAAAAADf///////7AAAAAAAAAAAAAAAAAAAAAAAAAAT////////3AAAAAAAAAAAAAAAAAAAAAAAAAAz////////xAAAAAAAAAAAAAAAAAAAAAAAAAF////////+wAAAAAAAAAAAAAAAAAAAAAAAAA/////////9AAAAAAAAAAAAAAAAAAAAAAAAALv////////wAAAAAAAAAArUAAAAAAAAAAAAF//////////QAAAAAAAAAA//pUAAAAAAAAAS//////////6AAAAAAAAAAA////8ljIQATWd///////////hAAAAAAAAAAA///////////////////////9AAAAAAAAAAAA///////////////////////gAAAAAAAAAAAA//////////////////////5AAAAAAAAAAAAA/////////////////////+QAAAAAAAAAAAAA/////////////////////cAAAAAAAAAAAAAA////////////////////kAAAAAAAAAAAAAAA///////////////////kAAAAAAAAAAAAAAAA/////////////////+SAAAAAAAAAAAAAAAAACau/////////////GEAAAAAAAAAAAAAAAAAAAAAE2is3u//7sp0AAAAAAAAAAAAAAAA" # big BPM number (DejaVuSans-Bold 78)
|
|
|
|
def load_font(b64):
|
|
blob = a2b_base64(b64); count = blob[0]; p = 1; pixoff = 1 + count * 7; glyphs = {}
|
|
for _ in range(count):
|
|
cp = (blob[p] << 8) | blob[p + 1]; w = blob[p + 2]; h = blob[p + 3]
|
|
xoff = blob[p + 4]; xoff = xoff - 256 if xoff > 127 else xoff
|
|
top = blob[p + 5]; adv = blob[p + 6]; p += 7
|
|
glyphs[cp] = (w, h, xoff, top, adv, pixoff); pixoff += (w * h + 1) // 2
|
|
return (glyphs, blob)
|
|
|
|
FONT_M = load_font(FONT_M_B64)
|
|
FONT_L = load_font(FONT_L_B64)
|
|
|
|
# ============================== ST7796 DISPLAY ==============================
|
|
class ST7796:
|
|
def __init__(self):
|
|
self.spi = SPI(0, baudrate=SPI_BAUD, polarity=0, phase=0,
|
|
sck=Pin(PIN_SCK), mosi=Pin(PIN_MOSI))
|
|
self.cs = Pin(PIN_CS, Pin.OUT, value=1)
|
|
self.dc = Pin(PIN_DC, Pin.OUT, value=0)
|
|
self.rst = Pin(PIN_RST, Pin.OUT, value=1)
|
|
self._chunk = bytearray(1024)
|
|
self.reset(); self.init()
|
|
|
|
def _cmd(self, c, data=None):
|
|
self.cs(0); self.dc(0); self.spi.write(bytes((c,)))
|
|
if data is not None:
|
|
self.dc(1); self.spi.write(bytes(data))
|
|
self.cs(1)
|
|
|
|
def reset(self):
|
|
self.rst(1); time.sleep_ms(20); self.rst(0); time.sleep_ms(40); self.rst(1); time.sleep_ms(150)
|
|
|
|
def init(self):
|
|
c = self._cmd
|
|
c(0x01); time.sleep_ms(120)
|
|
c(0x11); time.sleep_ms(120)
|
|
c(0xF0, b'\xC3'); c(0xF0, b'\x96')
|
|
c(0x36, bytes((MADCTL,)))
|
|
c(0x3A, b'\x55')
|
|
c(0xB4, b'\x01')
|
|
c(0xB6, b'\x80\x02\x3B')
|
|
c(0xE8, b'\x40\x8A\x00\x00\x29\x19\xA5\x33')
|
|
c(0xC1, b'\x06'); c(0xC2, b'\xA7'); c(0xC5, b'\x18'); time.sleep_ms(120)
|
|
c(0xE0, b'\xF0\x09\x0B\x06\x04\x15\x2F\x54\x42\x3C\x17\x14\x18\x1B')
|
|
c(0xE1, b'\xE0\x09\x0B\x06\x04\x03\x2B\x43\x42\x3B\x16\x14\x17\x1B')
|
|
c(0xF0, b'\x3C'); c(0xF0, b'\x69'); time.sleep_ms(120)
|
|
c(0x21 if INVERT_COLORS else 0x20)
|
|
c(0x29); time.sleep_ms(50)
|
|
|
|
def _window(self, x, y, w, h):
|
|
x1, y1 = x + w - 1, y + h - 1
|
|
self._cmd(0x2A, bytes((x >> 8, x & 0xFF, x1 >> 8, x1 & 0xFF)))
|
|
self._cmd(0x2B, bytes((y >> 8, y & 0xFF, y1 >> 8, y1 & 0xFF)))
|
|
self.cs(0); self.dc(0); self.spi.write(bytes((0x2C,))); self.dc(1)
|
|
|
|
def fill_rect(self, x, y, w, h, color):
|
|
if w <= 0 or h <= 0: return
|
|
self._window(x, y, w, h)
|
|
ch = self._chunk; px = len(ch) // 2
|
|
for i in range(px): ch[i*2] = color[0]; ch[i*2+1] = color[1]
|
|
n = w * h
|
|
while n > 0:
|
|
k = px if n >= px else n
|
|
self.spi.write(ch if k == px else ch[:k*2]); n -= k
|
|
self.cs(1)
|
|
|
|
def fill(self, color): self.fill_rect(0, 0, WIDTH, HEIGHT, color)
|
|
|
|
# ---- anti-aliased text (fg blended over bg via a 16-entry alpha LUT) ----
|
|
def _lut(self, fg, bg):
|
|
fgv = (fg[0] << 8) | fg[1]; bgv = (bg[0] << 8) | bg[1]
|
|
fr = (fgv >> 11) & 0x1F; fg6 = (fgv >> 5) & 0x3F; fb = fgv & 0x1F
|
|
br = (bgv >> 11) & 0x1F; bg6 = (bgv >> 5) & 0x3F; bb = bgv & 0x1F
|
|
out = []
|
|
for a in range(16):
|
|
t = a * 17
|
|
r = (br*(255-t) + fr*t) // 255; gg = (bg6*(255-t) + fg6*t) // 255; b = (bb*(255-t) + fb*t) // 255
|
|
v = (r << 11) | (gg << 5) | b; out.append((v >> 8, v & 0xFF))
|
|
return out
|
|
|
|
def text_w(self, s, font):
|
|
glyphs = font[0]; w = 0
|
|
for ch in s:
|
|
g = glyphs.get(ord(ch))
|
|
if g: w += g[4]
|
|
return w
|
|
|
|
def text_aa(self, s, x, y, fg, bg, font):
|
|
glyphs, blob = font; L = self._lut(fg, bg); pen = x
|
|
for ch in s:
|
|
g = glyphs.get(ord(ch))
|
|
if not g: continue
|
|
w, h, xoff, top, adv, off = g
|
|
if w and h:
|
|
buf = bytearray(w * h * 2); di = 0; k = 0
|
|
for _ in range(h):
|
|
for _ in range(w):
|
|
byte = blob[off + (k >> 1)]
|
|
e = L[(byte >> 4) if (k & 1) == 0 else (byte & 0xF)]
|
|
buf[di] = e[0]; buf[di+1] = e[1]; di += 2; k += 1
|
|
self._window(pen + xoff, y + top, w, h); self.spi.write(buf); self.cs(1)
|
|
pen += adv
|
|
return pen
|
|
|
|
def text_center(self, s, cx, cy, fg, bg, font):
|
|
tw = self.text_w(s, font); glyphs = font[0]; t0 = 999; b1 = 0
|
|
for ch in s:
|
|
g = glyphs.get(ord(ch))
|
|
if g and g[1]:
|
|
if g[3] < t0: t0 = g[3]
|
|
if g[3] + g[1] > b1: b1 = g[3] + g[1]
|
|
if t0 == 999: t0 = 0
|
|
self.text_aa(s, cx - tw // 2, cy - (t0 + b1) // 2, fg, bg, font)
|
|
|
|
# ============================== GT911 TOUCH ==============================
|
|
class GT911:
|
|
def __init__(self, i2c):
|
|
self.i2c = i2c; self.addr = None
|
|
found = i2c.scan()
|
|
for a in (0x5D, 0x14):
|
|
if a in found: self.addr = a; break
|
|
if self.addr is None and found: self.addr = found[0]
|
|
def read(self):
|
|
if self.addr is None: return None
|
|
try: # GT911 uses 16-bit register addresses
|
|
st = self.i2c.readfrom_mem(self.addr, 0x814E, 1, addrsize=16)[0]
|
|
except OSError:
|
|
return None
|
|
if not (st & 0x80):
|
|
return None
|
|
n = st & 0x0F
|
|
pt = None
|
|
if n >= 1:
|
|
b = self.i2c.readfrom_mem(self.addr, 0x8150, 4, addrsize=16)
|
|
tx = b[0] | (b[1] << 8); ty = b[2] | (b[3] << 8)
|
|
pt = self._map(tx, ty)
|
|
try: self.i2c.writeto_mem(self.addr, 0x814E, b'\x00', addrsize=16)
|
|
except OSError: pass
|
|
return pt
|
|
def _map(self, tx, ty):
|
|
if TOUCH_DEBUG: print("touch raw", tx, ty)
|
|
if TOUCH_SWAP_XY: tx, ty = ty, tx
|
|
if TOUCH_INVERT_X: tx = WIDTH - 1 - tx
|
|
if TOUCH_INVERT_Y: ty = HEIGHT - 1 - ty
|
|
if 0 <= tx < WIDTH and 0 <= ty < HEIGHT: return (tx, ty)
|
|
return None
|
|
|
|
# ============================== POLYMETER ENGINE ==============================
|
|
# program string: [v1;]t<bpm>;<lane>;<lane>;... (globals like b/rmp/tr are ignored on-device)
|
|
# lane = <sound>:<grouping>[/<sub>[s]][=pattern][@db][~][!]
|
|
# pattern chars: X=accent(2) x=normal(1) g=ghost(3) . - _ =mute(0)
|
|
PAT = {'X': 2, 'x': 1, 'g': 3, '.': 0, '-': 0, '_': 0}
|
|
PRIO = {2: 3, 1: 2, 3: 1} # click priority when lanes coincide: accent > normal > ghost
|
|
|
|
def parse_program(s):
|
|
bpm = 120; lanes = []
|
|
for tok in s.strip().split(';'):
|
|
tok = tok.strip()
|
|
if not tok: continue
|
|
if tok[0] == 't' and tok[1:].isdigit():
|
|
bpm = int(tok[1:]); continue
|
|
if ':' not in tok: # skip v1, vol, cd, b, rmp, tr and other globals
|
|
continue
|
|
lane = _parse_lane(tok)
|
|
if lane: lanes.append(lane)
|
|
if not lanes: lanes = [_parse_lane("beep:4")]
|
|
return max(30, min(300, bpm)), lanes
|
|
|
|
def _parse_lane(tok):
|
|
poly = '~' in tok
|
|
mute = '!' in tok
|
|
tok = tok.replace('~', '').replace('!', '')
|
|
if '@' in tok:
|
|
tok = tok.partition('@')[0]
|
|
sound, _, rest = tok.partition(':')
|
|
pattern = None
|
|
if '=' in rest:
|
|
rest, _, pattern = rest.partition('=')
|
|
sub = 1
|
|
if '/' in rest:
|
|
rest, _, sd = rest.partition('/')
|
|
sd = sd.rstrip('s')
|
|
sub = int(sd) if sd.isdigit() else 1
|
|
groups = [int(g) for g in rest.split('+') if g.isdigit()] or [4]
|
|
beats = sum(groups)
|
|
starts = set(); acc = 0
|
|
for gp in groups: starts.add(acc); acc += gp
|
|
steps = beats * sub
|
|
if pattern:
|
|
levels = [PAT.get(ch, 0) for ch in pattern]
|
|
if len(levels) < steps: levels += [0] * (steps - len(levels))
|
|
steps = len(levels)
|
|
else:
|
|
levels = []
|
|
for i in range(steps):
|
|
if i % sub == 0: levels.append(2 if (i // sub) in starts else 1)
|
|
else: levels.append(0)
|
|
return {'sound': sound, 'sub': sub, 'steps': steps, 'levels': levels, 'poly': poly, 'mute': mute}
|
|
|
|
# ============================== APP ==============================
|
|
class App:
|
|
def __init__(self):
|
|
self.d = ST7796()
|
|
self.i2c = I2C(0, sda=Pin(PIN_SDA), scl=Pin(PIN_SCL), freq=100_000)
|
|
self.touch = GT911(self.i2c)
|
|
self.np = neopixel.NeoPixel(Pin(PIN_RGB), 1) if neopixel else None
|
|
self.buz = PWM(Pin(PIN_BUZZER)); self.buz.duty_u16(0)
|
|
self.buz_off = 0
|
|
self.btnA = Pin(PIN_BTN_A, Pin.IN, Pin.PULL_UP)
|
|
self.btnB = Pin(PIN_BTN_B, Pin.IN, Pin.PULL_UP)
|
|
self._aPrev = 1; self._bPrev = 1
|
|
self.jx = ADC(PIN_JOY_X); self.jy = ADC(PIN_JOY_Y)
|
|
self._joyNext = 0
|
|
self._unpressAt = 0; self._pending = None
|
|
self._touchDown = False; self._touchSeen = 0
|
|
self.running = False
|
|
self.bpm = 120; self.idx = 0; self.lanes = []
|
|
self.rgb = (0, 0, 0)
|
|
self.buttons = []
|
|
self.load(0)
|
|
self.draw_static()
|
|
self.draw_bpm(); self.draw_status(); self.draw_dots()
|
|
|
|
# ---------- program ----------
|
|
def load(self, i):
|
|
n = len(PROGRAMS); self.idx = i % n
|
|
self.name, prog = PROGRAMS[self.idx]
|
|
self.bpm, self.lanes = parse_program(prog)
|
|
self.master = self.lanes[0]
|
|
self.beat = -1
|
|
self._reset_clock()
|
|
def _reset_clock(self):
|
|
now = time.ticks_us()
|
|
for L in self.lanes:
|
|
L['next'] = now; L['step'] = -1
|
|
L['stepdur'] = int(60_000_000 / self.bpm / L['sub'])
|
|
|
|
# ---------- audio + light ----------
|
|
def click(self, level):
|
|
f = {2: 2300, 1: 1600, 3: 1050}.get(level, 1600)
|
|
duty = {2: 42000, 1: 30000, 3: 14000}.get(level, 30000)
|
|
self.buz.freq(f); self.buz.duty_u16(duty)
|
|
self.buz_off = time.ticks_add(time.ticks_us(), 22000)
|
|
def flash(self, level):
|
|
self.rgb = LEVEL_RGB.get(level, (0, 150, 255))
|
|
if self.np: self.np[0] = self.rgb; self.np.write()
|
|
def led_off(self):
|
|
self.rgb = (0, 0, 0)
|
|
if self.np: self.np[0] = (0, 0, 0); self.np.write()
|
|
|
|
# ---------- transport ----------
|
|
def toggle(self):
|
|
self.running = not self.running
|
|
if self.running: self._reset_clock(); self.beat = -1
|
|
else: self.buz.duty_u16(0); self.led_off()
|
|
self.draw_status(); self.draw_dots(); self._redraw_play()
|
|
def _redraw_play(self):
|
|
for (x, y, w, h, key) in self.buttons:
|
|
if key == "play": self._draw_button(x, y, w, h, key); return
|
|
def set_bpm(self, v):
|
|
v = max(30, min(300, v))
|
|
if v != self.bpm:
|
|
self.bpm = v
|
|
for L in self.lanes: L['stepdur'] = int(60_000_000 / self.bpm / L['sub'])
|
|
self.draw_bpm()
|
|
def goto(self, i):
|
|
was = self.running; self.load(i)
|
|
self.draw_bpm(); self.draw_status(); self.draw_dots(); self._redraw_play()
|
|
if was: self.running = True; self._reset_clock(); self.beat = -1
|
|
def tap(self):
|
|
now = time.ticks_ms()
|
|
if not hasattr(self, '_taps'): self._taps = []
|
|
self._taps = [t for t in self._taps if time.ticks_diff(now, t) < 2400]
|
|
self._taps.append(now)
|
|
if len(self._taps) >= 2:
|
|
span = time.ticks_diff(self._taps[-1], self._taps[0]) / (len(self._taps) - 1)
|
|
if span > 0: self.set_bpm(round(60000 / span))
|
|
|
|
# ---------- scheduler ----------
|
|
def tick(self):
|
|
now = time.ticks_us()
|
|
if self.buz_off and time.ticks_diff(now, self.buz_off) >= 0:
|
|
self.buz.duty_u16(0); self.buz_off = 0
|
|
if self.running:
|
|
fired = []; beat_hit = False
|
|
for L in self.lanes:
|
|
while time.ticks_diff(now, L['next']) >= 0:
|
|
L['step'] = (L['step'] + 1) % L['steps']
|
|
lvl = 0 if L['mute'] else L['levels'][L['step']]
|
|
if lvl > 0: fired.append(lvl)
|
|
if L is self.master and L['step'] % L['sub'] == 0: beat_hit = True
|
|
L['next'] = time.ticks_add(L['next'], L['stepdur'])
|
|
if fired:
|
|
best = max(fired, key=lambda l: PRIO.get(l, 0))
|
|
self.click(best); self.flash(best)
|
|
if beat_hit:
|
|
self.beat = (self.master['step'] // self.master['sub']); self.draw_dots()
|
|
# fade the RGB between beats (only while running)
|
|
if self.rgb != (0, 0, 0):
|
|
r, g, b = self.rgb; r = r*7//10; g = g*7//10; b = b*7//10
|
|
self.rgb = (r, g, b) if (r + g + b) > 12 else (0, 0, 0)
|
|
if self.np: self.np[0] = self.rgb; self.np.write()
|
|
|
|
# ---------- inputs ----------
|
|
def poll(self):
|
|
a = self.btnA.value()
|
|
if a == 0 and self._aPrev == 1: self.toggle()
|
|
self._aPrev = a
|
|
b = self.btnB.value()
|
|
if b == 0 and self._bPrev == 1: self.tap()
|
|
self._bPrev = b
|
|
now = time.ticks_ms()
|
|
if time.ticks_diff(now, self._joyNext) >= 0:
|
|
x = self.jx.read_u16() - 32768; y = self.jy.read_u16() - 32768
|
|
if JOY_INVERT_X: x = -x
|
|
if JOY_INVERT_Y: y = -y
|
|
if abs(y) > JOY_DEADZONE:
|
|
self.set_bpm(self.bpm + (1 if y > 0 else -1) * (5 if abs(y) > 26000 else 1))
|
|
self._joyNext = time.ticks_add(now, 70)
|
|
elif abs(x) > JOY_DEADZONE:
|
|
self.goto(self.idx + (1 if x > 0 else -1)); self._joyNext = time.ticks_add(now, 350); return
|
|
else:
|
|
self._joyNext = time.ticks_add(now, 20)
|
|
if self._unpressAt and time.ticks_diff(now, self._unpressAt) >= 0:
|
|
x, y, w, h, key = self._pending; self._draw_button(x, y, w, h, key); self._unpressAt = 0
|
|
# edge-detect the touch like the hardware buttons: act once on finger-DOWN, ignore held
|
|
pt = self.touch.read()
|
|
if pt:
|
|
self._touchSeen = now
|
|
if not self._touchDown:
|
|
self._touchDown = True; self.hit(pt[0], pt[1])
|
|
elif self._touchDown and time.ticks_diff(now, self._touchSeen) > 140:
|
|
self._touchDown = False
|
|
|
|
def hit(self, x, y):
|
|
for bx, by, bw, bh, key in self.buttons:
|
|
if bx <= x <= bx+bw and by <= y <= by+bh:
|
|
self.d.fill_rect(bx, by, bw, bh, C_BTNHI); self._btn_label(bx, by, bw, bh, key)
|
|
if key == 'play': self.toggle()
|
|
elif key == 'prev': self.goto(self.idx - 1)
|
|
elif key == 'next': self.goto(self.idx + 1)
|
|
elif key == 'minus': self.set_bpm(self.bpm - 1)
|
|
elif key == 'plus': self.set_bpm(self.bpm + 1)
|
|
elif key == 'tap': self.tap()
|
|
self._pending = (bx, by, bw, bh, key)
|
|
self._unpressAt = time.ticks_add(time.ticks_ms(), 120)
|
|
return
|
|
|
|
# ---------- drawing ----------
|
|
def draw_static(self):
|
|
d = self.d; d.fill(C_BG)
|
|
d.text_aa("PM_K-1 KIT", 12, 10, C_CYAN, C_BG, FONT_M) # VARASYS logo is on the case, not the screen
|
|
d.fill_rect(0, 42, WIDTH, 2, C_PANEL)
|
|
d.text_aa("BPM", 12, 120, C_MUTE, C_BG, FONT_M)
|
|
self.buttons = []
|
|
bw = 96; bh = 56; gap = (WIDTH - 3*bw) // 4; xs = [gap, gap*2+bw, gap*3+bw*2]
|
|
for x, key in zip(xs, ("prev", "play", "next")):
|
|
self.buttons.append((x, 300, bw, bh, key)); self._draw_button(x, 300, bw, bh, key)
|
|
for x, key in zip(xs, ("minus", "tap", "plus")):
|
|
self.buttons.append((x, 372, bw, bh, key)); self._draw_button(x, 372, bw, bh, key)
|
|
|
|
def _draw_button(self, x, y, w, h, key):
|
|
d = self.d; d.fill_rect(x, y, w, h, C_BTN)
|
|
d.fill_rect(x, y, w, 2, C_PANEL); d.fill_rect(x, y+h-2, w, 2, C_PANEL)
|
|
self._btn_label(x, y, w, h, key)
|
|
def _btn_label(self, x, y, w, h, key):
|
|
sym = {"prev": "◀◀", "next": "▶▶", "minus": "-", "plus": "+", "tap": "TAP",
|
|
"play": "■" if self.running else "▶"}[key]
|
|
col = C_GREEN if key == "play" else C_TXT
|
|
bg = C_BTNHI if False else C_BTN
|
|
self.d.text_center(sym, x + w//2, y + h//2, col, bg, FONT_M)
|
|
|
|
def draw_bpm(self):
|
|
d = self.d; s = str(self.bpm)
|
|
d.fill_rect(60, 84, WIDTH - 60, 96, C_BG)
|
|
tw = d.text_w(s, FONT_L)
|
|
d.text_aa(s, WIDTH - 14 - tw, 90, C_TXT, C_BG, FONT_L)
|
|
|
|
def draw_status(self):
|
|
d = self.d; d.fill_rect(0, 236, WIDTH, 58, C_BG)
|
|
d.text_aa("▶ RUN" if self.running else "■ STOP", 12, 240,
|
|
C_GREEN if self.running else C_MUTE, C_BG, FONT_M)
|
|
idx = "%d/%d" % (self.idx + 1, len(PROGRAMS)); tw = d.text_w(idx, FONT_M)
|
|
d.text_aa(idx, WIDTH - 12 - tw, 240, C_MUTE, C_BG, FONT_M)
|
|
d.text_aa(self.name[:26], 12, 268, C_TXT, C_BG, FONT_M)
|
|
|
|
def draw_dots(self):
|
|
d = self.d; m = self.master
|
|
bpb = max(1, m['steps'] // m['sub'])
|
|
yy = 200; sz = 18; sp = 26
|
|
x0 = max(12, WIDTH - 12 - bpb * sp)
|
|
d.fill_rect(0, yy, WIDTH, sz, C_BG)
|
|
for i in range(bpb):
|
|
lvl = m['levels'][(i*m['sub']) % m['steps']]
|
|
on = self.running and i == self.beat
|
|
col = (C_AMBER if lvl == 2 else C_CYAN) if on else C_DIMDOT
|
|
d.fill_rect(x0 + i*sp, yy, sz, sz, col)
|
|
|
|
def run(self):
|
|
if self.touch.addr is None:
|
|
self.d.text_aa("touch: not found", 12, HEIGHT - 30, C_AMBER, C_BG, FONT_M)
|
|
while True:
|
|
self.tick(); self.poll(); time.sleep_us(200)
|
|
|
|
# ============================== GO ==============================
|
|
App().run()
|