shithub: pt2-clone

Download patch

ref: 9fca319758c1194a953ad582a9c55e0a0f873ee4
parent: 6f0d2c3ee753d40fd9bc5d325fe6605e4e38c3bc
author: Olav Sørensen <[email protected]>
date: Thu Apr 9 17:21:01 EDT 2020

Pushed v1.09 code

- Bug fix: "Play pattern" mode didn't work like it should in v1.08
- PATTDOTS mode (protracker.ini) is now even easier on the eye
- Overflown arpeggios on -1 finetuned samples now behave exactly like real PT.
  This is a special case where overflown arpeggios sound very different.
- Code cleanup

--- a/release/macos/protracker.ini
+++ b/release/macos/protracker.ini
@@ -86,7 +86,7 @@
 ; Default value: FALSE
 ;       Comment: Setting it to TRUE removes the first sample number
 ;         digit in the pattern viewer, if it's zero. E.g. "0F" -> " F".
-;
+;         This mode is always enabled if PATTDOTS is set to true.
 BLANKZERO=FALSE
 
 ; Real VU-meters
--- a/release/other/protracker.ini
+++ b/release/other/protracker.ini
@@ -86,7 +86,7 @@
 ; Default value: FALSE
 ;       Comment: Setting it to TRUE removes the first sample number
 ;         digit in the pattern viewer, if it's zero. E.g. "0F" -> " F".
-;
+;         This mode is always enabled if PATTDOTS is set to true.
 BLANKZERO=FALSE
 
 ; Real VU-meters
--- a/release/win32/protracker.ini
+++ b/release/win32/protracker.ini
@@ -86,7 +86,7 @@
 ; Default value: FALSE
 ;       Comment: Setting it to TRUE removes the first sample number
 ;         digit in the pattern viewer, if it's zero. E.g. "0F" -> " F".
-;
+;         This mode is always enabled if PATTDOTS is set to true.
 BLANKZERO=FALSE
 
 ; Real VU-meters
--- a/release/win64/protracker.ini
+++ b/release/win64/protracker.ini
@@ -86,7 +86,7 @@
 ; Default value: FALSE
 ;       Comment: Setting it to TRUE removes the first sample number
 ;         digit in the pattern viewer, if it's zero. E.g. "0F" -> " F".
-;
+;         This mode is always enabled if PATTDOTS is set to true.
 BLANKZERO=FALSE
 
 ; Real VU-meters
binary files a/src/gfx/bmp/font.bmp b/src/gfx/bmp/font.bmp differ
binary files a/src/gfx/bmp/terminal_scrollbar.bmp /dev/null differ
binary files a/src/gfx/bmp/terminal_top.bmp /dev/null differ
--- a/src/gfx/pt2_gfx_font.c
+++ b/src/gfx/pt2_gfx_font.c
@@ -1,22 +1,84 @@
 #include <stdint.h>
 
-const uint8_t fontBMP[5168] =
+const uint8_t fontBMP[6096] =
 {
+	0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,
+	0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,0,
+	0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
+	0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
+	0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,
+	0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
+	0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
+	0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,
+	0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
+	0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,
+	0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,0,1,1,1,0,0,0,0,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0,0,1,1,0,1,1,0,0,
+	0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,
+	0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
+	0,1,1,0,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,0,
+	0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,
+	0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,
+	0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,
+	0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,0,0,
+	0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,1,1,0,0,
+	0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,
+	0,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,
+	0,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
+	0,0,0,0,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,
+	0,0,0,1,1,1,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,
+	0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,
+	0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,
+	0,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,
+	0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,
+	0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,
+	0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
+	0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,
+	0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -23,11 +85,50 @@
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,0,1,1,0,0,0,1,1,0,1,1,0,0,1,0,0,0,1,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,
+	0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,
+	0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,
+	0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
+	0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,1,1,0,
+	0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
+	0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,
+	0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,0,0,0,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,0,0,
+	0,1,1,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
+	0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,
+	0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,1,0,0,
+	0,1,1,0,0,1,1,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,
+	0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
+	0,0,0,0,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,
+	0,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
+	0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,
+	0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,
+	0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,1,1,0,
+	0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,1,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,
+	0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+	0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,
+	0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
+	0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
+	0,1,1,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
+	0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,
+	0,1,1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -35,101 +136,23 @@
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,0,
-	0,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,0,1,1,0,1,1,1,1,1,1,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,
-	0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,
-	0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,
-	0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,
-	0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,
-	0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,
-	0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
-	0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,
-	0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,
-	0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,1,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,0,0,1,1,0,0,1,1,0,
-	0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,1,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,1,1,0,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,0,1,1,0,1,1,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,1,1,0,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,
-	0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,
-	0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,
-	0,0,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,0,0,
-	0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,
-	0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,1,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,0,0,1,1,0,0,1,1,0,
-	0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,1,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
-	0,1,1,0,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,
-	0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,0,1,1,0,1,1,0,
-	0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,1,1,0,0,0,1,1,0,0,1,1,0,
-	0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,
-	0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,
-	0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,0,
-	0,0,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,0,
-	0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
-	0,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,0,0,
-	0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 };
--- a/src/gfx/pt2_gfx_sampler.c
+++ b/src/gfx/pt2_gfx_sampler.c
@@ -3,14 +3,14 @@
 
 uint32_t samplingPosBMP[64] =
 {
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
-	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,
+	0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF,0x00FFFF
 };
 
 // Final unpack length: 4488
--- a/src/pt2_audio.c
+++ b/src/pt2_audio.c
@@ -379,12 +379,8 @@
 	setScopeDelta(ch, oldScopeDelta);
 
 	// for BLEP synthesis
-
-	if (v->dLastDelta == 0.0)
-		v->dLastDelta = v->dDelta;
-
-	if (v->dLastDeltaMul == 0.0)
-		v->dLastDeltaMul = v->dDeltaMul;
+	if (v->dLastDelta == 0.0) v->dLastDelta = v->dDelta;
+	if (v->dLastDeltaMul == 0.0) v->dLastDeltaMul = v->dDeltaMul;
 }
 
 void paulaSetVolume(uint8_t ch, uint16_t vol)
--- a/src/pt2_header.h
+++ b/src/pt2_header.h
@@ -14,7 +14,7 @@
 #include "pt2_unicode.h"
 #include "pt2_palette.h"
 
-#define PROG_VER_STR "1.08"
+#define PROG_VER_STR "1.09"
 
 #ifdef _WIN32
 #define DIR_DELIMITER '\\'
@@ -54,6 +54,7 @@
 
 #define AMIGA_PAL_VBLANK_HZ 50
 
+#define FONT_BMP_WIDTH 
 #define FONT_CHAR_W 8 // actual data length is 7, includes right spacing (1px column)
 #define FONT_CHAR_H 5
 
@@ -469,7 +470,7 @@
 void decPatt(void);
 void modSetPos(int16_t order, int16_t row);
 void modStop(void);
-void doStopIt(void);
+void doStopIt(bool resetPlayMode);
 void playPattern(int8_t startRow);
 void modPlay(int16_t patt, int16_t order, int8_t row);
 void modSetSpeed(uint8_t speed);
--- a/src/pt2_keyboard.c
+++ b/src/pt2_keyboard.c
@@ -853,7 +853,7 @@
 					editor.stepPlayEnabled = true;
 					editor.stepPlayBackwards = false;
 
-					doStopIt();
+					doStopIt(true);
 					playPattern(modEntry->currRow);
 				}
 			}
@@ -4285,7 +4285,7 @@
 					editor.stepPlayEnabled = true;
 					editor.stepPlayBackwards = true;
 
-					doStopIt();
+					doStopIt(true);
 					playPattern((modEntry->currRow - 1) & 0x3F);
 				}
 			}
--- a/src/pt2_modplayer.c
+++ b/src/pt2_modplayer.c
@@ -56,7 +56,7 @@
 	editor.modTick = 0;
 }
 
-void doStopIt(void)
+void doStopIt(bool resetPlayMode)
 {
 	moduleChannel_t *c;
 	uint8_t i;
@@ -67,11 +67,15 @@
 
 	pattDelTime = 0;
 	pattDelTime2 = 0;
-	editor.playMode = PLAY_MODE_NORMAL;
-	editor.currMode = MODE_IDLE;
 
-	pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
+	if (resetPlayMode)
+	{
+		editor.playMode = PLAY_MODE_NORMAL;
+		editor.currMode = MODE_IDLE;
 
+		pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
+	}
+
 	for (i = 0; i < AMIGA_VOICES; i++)
 	{
 		c = &modEntry->channels[i];
@@ -338,27 +342,38 @@
 
 static void arpeggio(moduleChannel_t *ch)
 {
-	uint8_t dat;
-	const int16_t *arpPointer;
+	uint8_t arpTick, arpNote;
+	const int16_t *periods;
 
-	dat = editor.modTick % 3;
-	if (dat == 0)
+	assert(editor.modTick < 32);
+	arpTick = arpTickTable[editor.modTick]; // 0, 1, 2
+
+	if (arpTick == 1)
 	{
-		paulaSetPeriod(ch->n_chanindex, ch->n_period);
+		arpNote = ch->n_cmd >> 4;
 	}
-	else
+	else if (arpTick == 2)
 	{
-		     if (dat == 1) dat = (ch->n_cmd & 0xF0) >> 4;
-		else if (dat == 2) dat =  ch->n_cmd & 0x0F;
+		arpNote = ch->n_cmd & 0xF;
+	}
+	else // arpTick 0
+	{
+		paulaSetPeriod(ch->n_chanindex, ch->n_period);
+		return;
+	}
 
-		arpPointer = &periodTable[ch->n_finetune * 37];
-		for (uint8_t i = 0; i < 37; i++)
+	/* 8bitbubsy: If the finetune is -1, this can overflow up to
+	** 15 words outside of the table. The table is padded with
+	** the correct overflow values to allow this to safely happen
+	** and sound correct at the same time.
+	*/
+	periods = &periodTable[ch->n_finetune * 37];
+	for (int32_t baseNote = 0; baseNote < 37; baseNote++)
+	{
+		if (ch->n_period >= periods[baseNote])
 		{
-			if (ch->n_period >= arpPointer[i])
-			{
-				paulaSetPeriod(ch->n_chanindex, arpPointer[i+dat]);
-				break;
-			}
+			paulaSetPeriod(ch->n_chanindex, periods[baseNote+arpNote]);
+			break;
 		}
 	}
 }
@@ -901,7 +916,7 @@
 	{
 		if (editor.stepPlayEnabled)
 		{
-			doStopIt();
+			doStopIt(true);
 
 			editor.stepPlayEnabled = false;
 			editor.stepPlayBackwards = false;
@@ -920,7 +935,7 @@
 
 			if (config.compoMode) // stop song for music competitions playing
 			{
-				doStopIt();
+				doStopIt(true);
 				turnOffVoices();
 
 				modEntry->currOrder = 0;
@@ -1058,7 +1073,7 @@
 
 		if (editor.stepPlayEnabled)
 		{
-			doStopIt();
+			doStopIt(true);
 
 			modEntry->currRow = modEntry->row & 0x3F;
 			editor.ui.updatePatternData = true;
@@ -1248,7 +1263,7 @@
 {
 	uint8_t oldPlayMode, oldMode;
 
-	doStopIt();
+	doStopIt(false);
 	turnOffVoices();
 	mixerClearSampleCounter();
 
@@ -1524,7 +1539,7 @@
 	modSetSpeed(oldSpeed);
 	modSetTempo(oldBPM);
 
-	doStopIt();
+	doStopIt(true);
 
 	editor.modTick = 0;
 	modHasBeenPlayed = false;
--- a/src/pt2_patternviewer.c
+++ b/src/pt2_patternviewer.c
@@ -1,309 +1,242 @@
-// for finding memory leaks in debug mode with Visual Studio 
-#if defined _DEBUG && defined _MSC_VER
-#include <crtdbg.h>
-#endif
-
 #include <stdint.h>
+#include <stdbool.h>
 #include "pt2_header.h"
 #include "pt2_palette.h"
 #include "pt2_tables.h"
 #include "pt2_textout.h"
-#include "pt2_helpers.h"
 
+#define MIDDLE_ROW 7
 #define VISIBLE_ROWS 15
 
-static uint8_t periodToNote(int16_t period)
+static const char *emptyRowNum = "  ";
+static const char *emptyRowData = "        ";
+static const char emptyDottedEffect[4] = { 0x02, 0x02, 0x02, 0x00 };
+static const char emptyDottedSample[3] = { 0x02, 0x02, 0x00 };
+
+static int32_t periodToNote(int32_t period) // 0 = no note, 1 = illegal note, 2..37 = note
 {
-	uint8_t l, m, h;
+	int32_t beg, end, tableVal;
 
-	l = 0;
-	h = 35;
+	if (period == 0)
+		return 0;
 
-	while (h >= l)
+	beg = 0;
+	end = 36 - 1;
+
+	// do binary search
+	while (beg <= end)
 	{
-		m = (h + l) / 2;
-		if (m >= 36)
-			break; // should never happen, but let's stay on the safe side
+		const int32_t mid = (beg + end) >> 1;
 
-		     if (periodTable[m] == period) return m;
-		else if (periodTable[m] > period) l = m + 1;
-		else h = m - 1;
+		tableVal = periodTable[mid];
+		if (period == tableVal)
+			return 2+mid;
+
+		if (period < tableVal)
+			beg = mid+1;
+		else
+			end = mid-1;
 	}
 
-	return 255; // illegal period
+	return 1; // illegal note
 }
 
 static void drawPatternNormal(void)
 {
-	int8_t rowMiddlePos;
-	uint8_t j, h, tempNote, rowDispCheck;
-	uint16_t x, y, rowData;
-	const uint32_t *srcPtr;
-	uint32_t bufferOffset, *dstPtr;
-	note_t note;
+	const char **noteNames;
+	char smpChar;
+	int32_t row, j, x, y;
+	note_t *patt, *note;
 
-	for (uint8_t i = 0; i < VISIBLE_ROWS; i++)
-	{
-		rowMiddlePos = i - 7;
-		rowDispCheck = modEntry->currRow + rowMiddlePos;
+	if (config.accidental)
+		noteNames = (const char **)noteNames2;
+	else
+		noteNames = (const char **)noteNames1;
 
-		if (rowDispCheck < MOD_ROWS)
-		{
-			rowData = rowDispCheck * 4;
-			y = 140 + (i * 7);
+	patt = modEntry->patterns[modEntry->currPattern];
+	row = modEntry->currRow - MIDDLE_ROW;
+	y = 140;
 
-			if (i == 7) // are we on the play row (middle)?
+	for (int32_t i = 0; i < VISIBLE_ROWS; i++, y += 7, row++)
+	{
+		if (row < 0 || row >= MOD_ROWS)
+		{
+			// clear empty rows outside of pattern data
+			textOutBg(8, y, emptyRowNum, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(0*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(1*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(2*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(3*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+		}
+		else
+		{
+			if (i == MIDDLE_ROW) // middle row has twice as tall glyphs
 			{
-				y++; // align font to play row (middle)
+				y++;
+				printTwoDecimalsBigBg(8, y, row, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 
-				// put current row number
-				printTwoDecimalsBigBg(8, y, rowMiddlePos + modEntry->currRow, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-
-				// pattern data
-				for (j = 0; j < AMIGA_VOICES; j++)
+				note = patt + (row << 2);
+				x = 32;
+				for (j = 0; j < AMIGA_VOICES; j++, note++)
 				{
-					note = modEntry->patterns[modEntry->currPattern][rowData + j];
-					x = 26 + (j * 72);
+					textOutBigBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					x += 8*3;
 
-					if (note.period == 0)
-					{
-						textOutBigBg(x + 6, y, "---", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					}
-					else
-					{
-						tempNote = periodToNote(note.period);
-						if (tempNote == 255)
-							textOutBigBg(x + 6, y, "???", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						else
-							textOutBigBg(x + 6, y, config.accidental ? noteNames2[tempNote] : noteNames1[tempNote], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					}
+					smpChar = (config.blankZeroFlag && !(note->sample & 0xF0)) ? ' ' : hexTable[note->sample >> 4];
+					charOutBigBg(x, y, smpChar, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					x += 8;
 
-					if (config.blankZeroFlag)
-					{
-						if (note.sample & 0xF0)
-							printOneHexBigBg(x + 30, y, note.sample >> 4, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						else
-							printOneHexBigBg(x + 30, y, ' ', video.palette[PAL_GENBKG], video.palette[PAL_GENBKG]);
-					}
-					else
-					{
-						printOneHexBigBg(x + 30, y, note.sample >> 4, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					}
+					printOneHexBigBg(x, y, note->sample & 0x0F, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					x += 8;
 
-					printOneHexBigBg(x + 38, y, note.sample & 0x0F, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					printOneHexBigBg(x + 46, y, note.command, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					printTwoHexBigBg(x + 54, y, note.param, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					printOneHexBigBg(x, y, note->command, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					x += 8;
+
+					printTwoHexBigBg(x, y, note->param, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					x += (8*2)+8;
 				}
+				y += 6;
 			}
-			else
+			else // non-middle rows
 			{
-				if (i > 7)
-					y += 7; // beyond play row, jump some pixels out of the row (middle)
+				printTwoDecimalsBg(8, y, row, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 
-				// put current row number
-				printTwoDecimalsBg(8, y, rowMiddlePos + modEntry->currRow, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-
-				// pattern data
-				for (j = 0; j < AMIGA_VOICES; j++)
+				note = patt + (row << 2);
+				x = 32;
+				for (j = 0; j < AMIGA_VOICES; j++, note++)
 				{
-					note = modEntry->patterns[modEntry->currPattern][rowData + j];
-					x = 26 + (j * 72);
+					textOutBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					x += 8*3;
 
-					if (note.period == 0)
-					{
-						textOutBg(x + 6, y, "---", video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					}
-					else
-					{
-						tempNote = periodToNote(note.period);
-						if (tempNote == 255)
-							textOutBg(x + 6, y, "???", video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						else
-							textOutBg(x + 6, y, config.accidental ? noteNames2[tempNote] : noteNames1[tempNote], video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					}
+					smpChar = (config.blankZeroFlag && !(note->sample & 0xF0)) ? ' ' : hexTable[note->sample >> 4];
+					charOutBg(x, y, smpChar, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					x += 8;
 
-					if (config.blankZeroFlag)
-					{
-						if (note.sample & 0xF0)
-							printOneHexBg(x + 30, y, note.sample >> 4, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						else
-							printOneHexBg(x + 30, y, ' ', video.palette[PAL_BACKGRD], video.palette[PAL_BACKGRD]);
-					}
-					else
-					{
-						printOneHexBg(x + 30, y, note.sample >> 4, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					}
+					printOneHexBg(x , y, note->sample & 0x0F, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					x += 8;
 
-					printOneHexBg(x + 38, y, note.sample & 0x0F, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					printOneHexBg(x + 46, y, note.command, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					printTwoHexBg(x + 54, y, note.param, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					printOneHexBg(x, y, note->command, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					x += 8;
+
+					printTwoHexBg(x, y, note->param, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					x += (8*2)+8;
 				}
 			}
 		}
 	}
-
-	// clear outside rows
-
-	if (modEntry->currRow <= 6)
-	{
-		srcPtr = &trackerFrameBMP[140 * SCREEN_W];
-		dstPtr = &video.frameBuffer[140 * SCREEN_W];
-		memcpy(dstPtr, srcPtr, (SCREEN_W * sizeof (int32_t)) * ((7 - modEntry->currRow) * 7));
-	}
-	else if (modEntry->currRow >= 57)
-	{
-		h = (modEntry->currRow - 56) * 7;
-		bufferOffset = (250 - h) * SCREEN_W;
-
-		srcPtr = &trackerFrameBMP[bufferOffset];
-		dstPtr = &video.frameBuffer[bufferOffset];
-		memcpy(dstPtr, srcPtr, (SCREEN_W * sizeof (int32_t)) * h);
-	}
 }
 
 static void drawPatternDotted(void)
 {
-	int8_t rowMiddlePos;
-	uint8_t j, h, tempNote, rowDispCheck;
-	uint16_t x, y, rowData;
-	const uint32_t *srcPtr;
-	uint32_t bufferOffset, *dstPtr;
-	note_t note;
+	char smpChar;
+	const char **noteNames;
+	int32_t row, j, x, y;
+	note_t *patt, *note;
 
-	for (uint8_t i = 0; i < VISIBLE_ROWS; i++)
-	{
-		rowMiddlePos = i - 7;
-		rowDispCheck = modEntry->currRow + rowMiddlePos;
+	if (config.accidental)
+		noteNames = (const char **)noteNames4;
+	else
+		noteNames = (const char **)noteNames3;
 
-		if (rowDispCheck < MOD_ROWS)
-		{
-			rowData = rowDispCheck * 4;
-			y = 140 + (i * 7);
+	patt = modEntry->patterns[modEntry->currPattern];
+	row = modEntry->currRow - MIDDLE_ROW;
+	y = 140; 
 
-			if (i == 7) // are we on the play row (middle)?
+	for (int32_t i = 0; i < VISIBLE_ROWS; i++, y += 7, row++)
+	{
+		if (row < 0 || row >= MOD_ROWS)
+		{
+			// clear empty rows outside of pattern data
+			textOutBg(8, y, emptyRowNum, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(0*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(1*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(2*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+			textOutBg(32+(3*72), y, emptyRowData, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+		}
+		else
+		{
+			if (i == MIDDLE_ROW) // middle row has twice as tall glyphs
 			{
-				y++; // align font to play row (middle)
+				y++;
+				printTwoDecimalsBigBg(8, y, row, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 
-				// put current row number
-				printTwoDecimalsBigBg(8, y, rowMiddlePos + modEntry->currRow, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-
-				// pattern data
-				for (j = 0; j < AMIGA_VOICES; j++)
+				note = patt + (row << 2);
+				x = 32;
+				for (j = 0; j < AMIGA_VOICES; j++, note++)
 				{
-					note = modEntry->patterns[modEntry->currPattern][rowData + j];
-					x = 26 + (j * 72);
+					textOutBigBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+					x += 8*3;
 
-					if (note.period == 0)
+					if (note->sample == 0)
 					{
-						charOutBigBg(x + 6, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						charOutBigBg(x + 14, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						charOutBigBg(x + 22, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						textOutBigBg(x, y, emptyDottedSample, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						x += 8*2;
 					}
 					else
 					{
-						tempNote = periodToNote(note.period);
-						if (tempNote == 255)
-							textOutBigBg(x + 6, y, "???", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						else
-							textOutBigBg(x + 6, y, config.accidental ? noteNames2[tempNote] : noteNames1[tempNote], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						smpChar = (note->sample & 0xF0) ? hexTable[note->sample >> 4] : 0x02;
+						charOutBigBg(x, y, smpChar, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						x += 8;
+						printOneHexBigBg(x, y, note->sample & 0x0F, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						x += 8;
 					}
 
-					if (note.sample)
+					if (note->command == 0 && note->param == 0)
 					{
-						printOneHexBigBg(x + 30, y, note.sample >> 4, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						printOneHexBigBg(x + 38, y, note.sample & 0x0F, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						textOutBigBg(x, y, emptyDottedEffect, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						x += (8*3)+8;
 					}
 					else
 					{
-						charOutBigBg(x + 30, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						charOutBigBg(x + 38, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						printOneHexBigBg(x, y, note->command, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						x += 8;
+						printTwoHexBigBg(x, y, note->param, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+						x += (8*2)+8;
 					}
-
-					if ((note.command | note.param) == 0)
-					{
-						charOutBigBg(x + 46, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						charOutBigBg(x + 54, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						charOutBigBg(x + 62, y, -128, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					}
-					else
-					{
-						printOneHexBigBg(x + 46, y, note.command, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-						printTwoHexBigBg(x + 54, y, note.param, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-					}
 				}
+				y += 6;
 			}
-			else
+			else // non-middle rows
 			{
-				if (i > 7)
-					y += 7; // beyond play row, jump some pixels out of the row (middle)
+				printTwoDecimalsBg(8, y, row, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 
-				// put current row number
-				printTwoDecimalsBg(8, y, rowMiddlePos + modEntry->currRow, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-
 				// pattern data
-				for (j = 0; j < AMIGA_VOICES; j++)
+				note = patt + (row << 2);
+				x = 32;
+				for (j = 0; j < AMIGA_VOICES; j++, note++)
 				{
-					note = modEntry->patterns[modEntry->currPattern][rowData + j];
-					x = 26 + (j * 72);
+					textOutBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+					x += 8*3;
 
-					if (note.period == 0)
+					if (note->sample == 0)
 					{
-						charOutBg(x + 6, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						charOutBg(x + 14, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						charOutBg(x + 22, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						textOutBg(x, y, emptyDottedSample, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						x += 8*2;
 					}
 					else
 					{
-						tempNote = periodToNote(note.period);
-						if (tempNote == 255)
-							textOutBg(x + 6, y, "???", video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						else
-							textOutBg(x + 6, y, config.accidental ? noteNames2[tempNote] : noteNames1[tempNote], video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						smpChar = (note->sample & 0xF0) ? hexTable[note->sample >> 4] : 0x02;
+						charOutBg(x, y, smpChar, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						x += 8;
+						printOneHexBg(x, y, note->sample & 0x0F, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						x += 8;
 					}
 
-					if (note.sample)
+					if (note->command == 0 && note->param == 0)
 					{
-						printOneHexBg(x + 30, y, note.sample >> 4, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						printOneHexBg(x + 38, y, note.sample & 0x0F, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						textOutBg(x, y, emptyDottedEffect, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						x += (8*3)+8;
 					}
 					else
 					{
-						charOutBg(x + 30, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						charOutBg(x + 38, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						printOneHexBg(x, y, note->command, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						x += 8;
+						printTwoHexBg(x, y, note->param, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
+						x += (8*2)+8;
 					}
-
-					if ((note.command | note.param) == 0)
-					{
-						charOutBg(x + 46, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						charOutBg(x + 54, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						charOutBg(x + 62, y, -128, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					}
-					else
-					{
-						printOneHexBg(x + 46, y, note.command, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-						printTwoHexBg(x + 54, y, note.param, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
-					}
 				}
 			}
 		}
-	}
-
-	// clear outside rows
-
-	if (modEntry->currRow <= 6)
-	{
-		srcPtr = &trackerFrameBMP[140 * SCREEN_W];
-		dstPtr = &video.frameBuffer[140 * SCREEN_W];
-		memcpy(dstPtr, srcPtr, (SCREEN_W * sizeof (int32_t)) * ((7 - modEntry->currRow) * 7));
-	}
-	else if (modEntry->currRow >= 57)
-	{
-		h = (modEntry->currRow - 56) * 7;
-		bufferOffset = (250 - h) * SCREEN_W;
-
-		srcPtr = &trackerFrameBMP[bufferOffset];
-		dstPtr = &video.frameBuffer[bufferOffset];
-		memcpy(dstPtr, srcPtr, (SCREEN_W * sizeof (int32_t)) * h);
 	}
 }
 
--- a/src/pt2_tables.c
+++ b/src/pt2_tables.c
@@ -3,7 +3,7 @@
 #include <stdint.h>
 #include "pt2_mouse.h"
 
-uint32_t *aboutScreenBMP   = NULL, *arrowBMP           = NULL, *clearDialogBMP     = NULL;
+uint32_t *aboutScreenBMP   = NULL, *clearDialogBMP     = NULL;
 uint32_t *diskOpScreenBMP  = NULL, *editOpModeCharsBMP = NULL, *mod2wavBMP         = NULL;
 uint32_t *editOpScreen1BMP = NULL, *editOpScreen2BMP   = NULL, *samplerVolumeBMP   = NULL;
 uint32_t *editOpScreen3BMP = NULL, *editOpScreen4BMP   = NULL, *spectrumVisualsBMP = NULL;
@@ -11,6 +11,11 @@
 uint32_t *samplerScreenBMP = NULL, *pat2SmpDialogBMP   = NULL, *trackerFrameBMP    = NULL;
 uint32_t *yesNoDialogBMP   = NULL, *bigYesNoDialogBMP  = NULL;
 
+const char hexTable[16] =
+{
+	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
 const uint32_t cursorColors[6][3] =
 {
 	{ 0x444444, 0x777777, 0xAAAAAA }, // gray
@@ -29,20 +34,38 @@
 	24, 24
 };
 
-const char noteNames1[36][4] =
+const char *noteNames1[2+36] =
 {
+	"---","???",
 	"C-1", "C#1", "D-1", "D#1", "E-1", "F-1", "F#1" ,"G-1", "G#1", "A-1", "A#1", "B-1",
 	"C-2", "C#2", "D-2", "D#2", "E-2", "F-2", "F#2" ,"G-2", "G#2", "A-2", "A#2", "B-2",
 	"C-3", "C#3", "D-3", "D#3", "E-3", "F-3", "F#3" ,"G-3", "G#3", "A-3", "A#3", "B-3"
 };
 
-const char noteNames2[36][4] =
+const char *noteNames2[2+36] =
 {
-	"C-1", { 'D', 127, '1'}, "D-1", { 'E', 127, '1'}, "E-1", "F-1", { 'G', 127, '1'}, "G-1", { 'A', 127, '1'}, "A-1", { 'B', 127, '1'}, "B-1",
-	"C-2", { 'D', 127, '2'}, "D-2", { 'E', 127, '2'}, "E-2", "F-2", { 'G', 127, '2'}, "G-2", { 'A', 127, '2'}, "A-2", { 'B', 127, '2'}, "B-2",
-	"C-3", { 'D', 127, '3'}, "D-3", { 'E', 127, '3'}, "E-3", "F-3", { 'G', 127, '3'}, "G-3", { 'A', 127, '3'}, "A-3", { 'B', 127, '3'}, "B-3"
+	"---","???",
+	"C-1", "D\x01""1", "D-1", "E\x01""1", "E-1", "F-1", "G\x01""1", "G-1", "A\x01""1", "A-1", "B\x01""1", "B-1",
+	"C-2", "D\x01""2", "D-2", "E\x01""2", "E-2", "F-2", "G\x01""2", "G-2", "A\x01""2", "A-2", "B\x01""2", "B-2",
+	"C-3", "D\x01""3", "D-3", "E\x01""3", "E-3", "F-3", "G\x01""3", "G-3", "A\x01""3", "A-3", "B\x01""3", "B-3"
 };
 
+const char *noteNames3[2+36] = // for PATTDOTS mode
+{
+	"\x02\x02\x02","???",
+	"C-1", "C#1", "D-1", "D#1", "E-1", "F-1", "F#1" ,"G-1", "G#1", "A-1", "A#1", "B-1",
+	"C-2", "C#2", "D-2", "D#2", "E-2", "F-2", "F#2" ,"G-2", "G#2", "A-2", "A#2", "B-2",
+	"C-3", "C#3", "D-3", "D#3", "E-3", "F-3", "F#3" ,"G-3", "G#3", "A-3", "A#3", "B-3"
+};
+
+const char *noteNames4[2+36] = // for PATTDOTS mode
+{
+	"\x02\x02\x02","???",
+	"C-1", "D\x01""1", "D-1", "E\x01""1", "E-1", "F-1", "G\x01""1", "G-1", "A\x01""1", "A-1", "B\x01""1", "B-1",
+	"C-2", "D\x01""2", "D-2", "E\x01""2", "E-2", "F-2", "G\x01""2", "G-2", "A\x01""2", "A-2", "B\x01""2", "B-2",
+	"C-3", "D\x01""3", "D-3", "E\x013""", "E-3", "F-3", "G\x01""3", "G-3", "A\x01""3", "A-3", "B\x01""3", "B-3"
+};
+
 const uint8_t vibratoTable[32] =
 {
 	0x00, 0x18, 0x31, 0x4A, 0x61, 0x78, 0x8D, 0xA1,
@@ -51,8 +74,15 @@
 	0xB4, 0xA1, 0x8D, 0x78, 0x61, 0x4A, 0x31, 0x18
 };
 
-const int16_t periodTable[606] =
+const uint8_t arpTickTable[32] =
 {
+	0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,
+	0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,
+	0,1
+};
+
+const int16_t periodTable[(37*16)+15] =
+{
 	856,808,762,720,678,640,604,570,538,508,480,453,
 	428,404,381,360,339,320,302,285,269,254,240,226,
 	214,202,190,180,170,160,151,143,135,127,120,113,0,
@@ -102,8 +132,16 @@
 	431,407,384,363,342,323,305,288,272,256,242,228,
 	216,203,192,181,171,161,152,144,136,128,121,114,0,
 
-	// PT BUGFIX: overflowing arpeggio on -1 finetuned samples, add extra zeroes
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0
+	/* Arpeggio on -1 finetuned samples can do an overflown read from
+	** the period table. Here's the correct overflow values from the
+	** "CursorPosTable" and "UnshiftedKeymap" table, which are located
+	** right after the period table. These tables and their order didn't
+	** seem to change in the different PT1.x/PT2.x versions (I checked
+	** the source codes).
+	** PS: This is not a guess, these values *are* correct!
+	*/
+	774,1800,2314,3087,4113,4627,5400,6426,6940,7713,
+	8739,9253,24625,12851,13365
 };
 
 // button tables taken from the ptplay project + modified
--- a/src/pt2_tables.h
+++ b/src/pt2_tables.h
@@ -5,18 +5,21 @@
 #include "pt2_mouse.h"
 
 // TABLES
+extern const char hexTable[16];
 extern const uint32_t cursorColors[6][3];
-extern const char noteNames1[36][4];
-extern const char noteNames2[36][4];
+extern const char *noteNames1[2+36];
+extern const char *noteNames2[2+36];
+extern const char *noteNames3[2+36];
+extern const char *noteNames4[2+36];
 extern const uint8_t vibratoTable[32];
-extern const int16_t periodTable[606];
+extern const uint8_t arpTickTable[32];
+extern const int16_t periodTable[(37*16)+15];
 extern int8_t pNoteTable[32];
 
 // GFX
 extern uint32_t iconBMP[1024];
 extern const uint8_t mousePointerBMP[256];
-extern const uint8_t fontBMP[5120];
-extern const uint8_t arrowPaletteBMP[30];
+extern const uint8_t fontBMP[6096];
 
 // PACKED GFX
 extern const uint8_t aboutScreenPackedBMP[1684];
@@ -66,7 +69,6 @@
 extern uint32_t *trackerFrameBMP;
 extern uint32_t *aboutScreenBMP;
 extern uint32_t *muteButtonsBMP;
-extern uint32_t *arrowBMP;
 extern uint32_t *editOpModeCharsBMP;
 extern uint32_t *pat2SmpDialogBMP;
 
--- a/src/pt2_textout.c
+++ b/src/pt2_textout.c
@@ -7,55 +7,82 @@
 #include "pt2_palette.h"
 #include "pt2_visuals.h"
 
-static const char hexTable[16] =
-{
-	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-};
-
 void charOut(uint32_t xPos, uint32_t yPos, char ch, uint32_t color)
 {
 	const uint8_t *srcPtr;
 	uint32_t *dstPtr;
 
-	if (ch == '\0' && (ch <= ' ' || ch > '~'))
+	if (ch == '\0' || ch == ' ')
 		return;
-
-	srcPtr = &fontBMP[(uint8_t)ch * (FONT_CHAR_W * FONT_CHAR_H)];
+	
+	srcPtr = &fontBMP[(ch & 0x7F) << 3];
 	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 
-	for (uint32_t y = 0; y < FONT_CHAR_H; y++)
+	for (int32_t y = 0; y < FONT_CHAR_H; y++)
 	{
-		for (uint32_t x = 0; x < FONT_CHAR_W; x++)
+		for (int32_t x = 0; x < FONT_CHAR_W; x++)
 		{
 			if (srcPtr[x])
 				dstPtr[x] = color;
 		}
 
-		srcPtr += FONT_CHAR_W;
+		srcPtr += 127*FONT_CHAR_W;
 		dstPtr += SCREEN_W;
 	}
 }
 
+void charOut2(uint32_t xPos, uint32_t yPos, char ch)
+{
+	const uint8_t *srcPtr;
+	uint32_t *dstPtr1, *dstPtr2;
+
+	if (ch == '\0' || ch == ' ')
+		return;
+
+	srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	dstPtr2 = dstPtr1 + (SCREEN_W+1);
+
+	const uint32_t color1 = video.palette[PAL_BORDER];
+	const uint32_t color2 = video.palette[PAL_GENBKG2];
+
+	for (int32_t y = 0; y < FONT_CHAR_H; y++)
+	{
+		for (int32_t x = 0; x < FONT_CHAR_W; x++)
+		{
+			if (srcPtr[x])
+			{
+				dstPtr2[x] = color2;
+				dstPtr1[x] = color1;
+			}
+		}
+
+		srcPtr += 127*FONT_CHAR_W;
+		dstPtr1 += SCREEN_W;
+		dstPtr2 += SCREEN_W;
+	}
+}
+
 void charOutBg(uint32_t xPos, uint32_t yPos, char ch, uint32_t fgColor, uint32_t bgColor)
 {
 	const uint8_t *srcPtr;
-	uint32_t *dstPtr;
+	uint32_t *dstPtr, colors[2];
 
 	if (ch == '\0')
 		return;
 
-	if (ch < ' ' || ch > '~')
-		ch = ' ';
-
-	srcPtr = &fontBMP[(uint8_t)ch * (FONT_CHAR_W * FONT_CHAR_H)];
+	srcPtr = &fontBMP[(ch & 0x7F) << 3];
 	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 
-	for (uint32_t y = 0; y < FONT_CHAR_H; y++)
+	colors[0] = bgColor;
+	colors[1] = fgColor;
+
+	for (int32_t y = 0; y < FONT_CHAR_H; y++)
 	{
-		for (uint32_t x = 0; x < FONT_CHAR_W; x++)
-			dstPtr[x] = srcPtr[x] ? fgColor : bgColor;
+		for (int32_t x = 0; x < FONT_CHAR_W; x++)
+			dstPtr[x] = colors[srcPtr[x]];
 
-		srcPtr += FONT_CHAR_W;
+		srcPtr += 127*FONT_CHAR_W;
 		dstPtr += SCREEN_W;
 	}
 }
@@ -63,27 +90,29 @@
 void charOutBig(uint32_t xPos, uint32_t yPos, char ch, uint32_t color)
 {
 	const uint8_t *srcPtr;
-	uint32_t *dstPtr;
+	uint32_t *dstPtr1, *dstPtr2;
 
-	if (ch != '\0' && (ch <= ' ' || ch > '~'))
+	if (ch == '\0' || ch == ' ')
 		return;
 
-	srcPtr = &fontBMP[(uint8_t)ch * (FONT_CHAR_W * FONT_CHAR_H)];
-	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	dstPtr2 = dstPtr1 + SCREEN_W;
 
-	for (uint32_t y = 0; y < FONT_CHAR_H; y++)
+	for (int32_t y = 0; y < FONT_CHAR_H; y++)
 	{
-		for (uint32_t x = 0; x < FONT_CHAR_W; x++)
+		for (int32_t x = 0; x < FONT_CHAR_W; x++)
 		{
 			if (srcPtr[x])
 			{
-				dstPtr[x] = color;
-				dstPtr[x+SCREEN_W] = color;
+				dstPtr1[x] = color;
+				dstPtr2[x] = color;
 			}
 		}
 
-		srcPtr += FONT_CHAR_W;
-		dstPtr += SCREEN_W * 2;
+		srcPtr += 127*FONT_CHAR_W;
+		dstPtr1 += SCREEN_W*2;
+		dstPtr2 += SCREEN_W*2;
 	}
 }
 
@@ -90,40 +119,37 @@
 void charOutBigBg(uint32_t xPos, uint32_t yPos, char ch, uint32_t fgColor, uint32_t bgColor)
 {
 	const uint8_t *srcPtr;
-	uint32_t *dstPtr;
+	uint32_t *dstPtr1, *dstPtr2, colors[2];
 
 	if (ch == '\0')
 		return;
 
-	if (ch < ' ' || ch > '~')
-		ch = ' ';
+	srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	dstPtr2 = dstPtr1 + SCREEN_W;
 
-	srcPtr = &fontBMP[(uint8_t)ch * (FONT_CHAR_W * FONT_CHAR_H)];
-	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	colors[0] = bgColor;
+	colors[1] = fgColor;
 
-	for (uint32_t y = 0; y < FONT_CHAR_H; y++)
+	for (int32_t y = 0; y < FONT_CHAR_H; y++)
 	{
-		for (uint32_t x = 0; x < FONT_CHAR_W; x++)
+		for (int32_t x = 0; x < FONT_CHAR_W; x++)
 		{
-			if (srcPtr[x])
-			{
-				dstPtr[x] = fgColor;
-				dstPtr[x+SCREEN_W] = fgColor;
-			}
-			else
-			{
-				dstPtr[x] = bgColor;
-				dstPtr[x+SCREEN_W] = bgColor;
-			}
+			const uint32_t pixel = colors[srcPtr[x]];
+			dstPtr1[x] = pixel;
+			dstPtr2[x] = pixel;
 		}
 
-		srcPtr += FONT_CHAR_W;
-		dstPtr += SCREEN_W * 2;
+		srcPtr += 127*FONT_CHAR_W;
+		dstPtr1 += SCREEN_W*2;
+		dstPtr2 += SCREEN_W*2;
 	}
 }
 
 void textOut(uint32_t xPos, uint32_t yPos, const char *text, uint32_t color)
 {
+	assert(text != NULL);
+
 	uint32_t x = xPos;
 	while (*text != '\0')
 	{
@@ -132,8 +158,22 @@
 	}
 }
 
+void textOut2(uint32_t xPos, uint32_t yPos, const char *text)
+{
+	assert(text != NULL);
+
+	uint32_t x = xPos;
+	while (*text != '\0')
+	{
+		charOut2(x, yPos, *text++);
+		x += FONT_CHAR_W;
+	}
+}
+
 void textOutTight(uint32_t xPos, uint32_t yPos, const char *text, uint32_t color)
 {
+	assert(text != NULL);
+
 	uint32_t x = xPos;
 	while (*text != '\0')
 	{
@@ -144,6 +184,8 @@
 
 void textOutBg(uint32_t xPos, uint32_t yPos, const char *text, uint32_t fgColor, uint32_t bgColor)
 {
+	assert(text != NULL);
+
 	uint32_t x = xPos;
 	while (*text != '\0')
 	{
@@ -154,6 +196,8 @@
 
 void textOutBig(uint32_t xPos, uint32_t yPos, const char *text, uint32_t color)
 {
+	assert(text != NULL);
+
 	uint32_t x = xPos;
 	while (*text != '\0')
 	{
@@ -164,6 +208,8 @@
 
 void textOutBigBg(uint32_t xPos, uint32_t yPos, const char *text, uint32_t fgColor, uint32_t bgColor)
 {
+	assert(text != NULL);
+
 	uint32_t x = xPos;
 	while (*text != '\0')
 	{
--- a/src/pt2_textout.h
+++ b/src/pt2_textout.h
@@ -4,10 +4,12 @@
 #include <stdbool.h>
 
 void charOut(uint32_t xPos, uint32_t yPos, char ch, uint32_t color);
+void charOut2(uint32_t xPos, uint32_t yPos, char ch);
 void charOutBg(uint32_t xPos, uint32_t yPos, char ch, uint32_t fgColor, uint32_t bgColor);
 void charOutBig(uint32_t xPos, uint32_t yPos, char ch, uint32_t color);
 void charOutBigBg(uint32_t xPos, uint32_t yPos, char ch, uint32_t fgColor, uint32_t bgColor);
 void textOut(uint32_t xPos, uint32_t yPos, const char *text, uint32_t color);
+void textOut2(uint32_t xPos, uint32_t yPos, const char *text);
 void textOutTight(uint32_t xPos, uint32_t yPos, const char *text, uint32_t color);
 void textOutBg(uint32_t xPos, uint32_t yPos, const char *text, uint32_t fgColor, uint32_t bgColor);
 void textOutBig(uint32_t xPos, uint32_t yPos, const char *text, uint32_t color);
--- a/src/pt2_visuals.c
+++ b/src/pt2_visuals.c
@@ -824,8 +824,6 @@
 void updateDiskOp(void)
 {
 	char tmpChar;
-	const uint32_t *srcPtr;
-	uint32_t *dstPtr;
 
 	if (!editor.ui.diskOpScreenShown || editor.ui.posEdScreenShown)
 		return;
@@ -840,23 +838,17 @@
 	{
 		editor.ui.updateLoadMode = false;
 
-		// clear backgrounds
-		charOutBg(147,  3, ' ', video.palette[PAL_GENBKG], video.palette[PAL_GENBKG]);
-		charOutBg(147, 14, ' ', video.palette[PAL_GENBKG], video.palette[PAL_GENBKG]);
-
 		// draw load mode arrow
-
-		srcPtr = arrowBMP;
-		dstPtr = &video.frameBuffer[(((11 * editor.diskop.mode) + 3) * SCREEN_W) + 148];
-
-		for (uint32_t y = 0; y < 5; y++)
+		if (editor.diskop.mode == 0)
 		{
-			for (uint32_t x = 0; x < 6; x++)
-				dstPtr[x] = srcPtr[x];
-
-			srcPtr += 6;
-			dstPtr += SCREEN_W;
+			charOutBg(147,14, ' ', video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); // clear other box
+			charOutBg(147, 3, 0x3, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 		}
+		else
+		{
+			charOutBg(147, 3, ' ', video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); // clear other box
+			charOutBg(147,14, 0x3, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+		}
 	}
 
 	if (editor.ui.updatePackText)
@@ -2331,10 +2323,6 @@
 		vuMeterBMP[(i * 10) + 8] = pixel24;
 		vuMeterBMP[(i * 10) + 9] = pixel24;
 	}
-
-	for (i = 0; i < 30; i++) arrowBMP[i] = video.palette[arrowPaletteBMP[i]];
-	for (i = 0; i < 64; i++) samplingPosBMP[i] = samplingPosBMP[i];
-	for (i = 0; i < 512; i++) loopPinsBMP[i] = loopPinsBMP[i];
 }
 
 void freeBMPs(void)
@@ -2358,7 +2346,6 @@
 	if (aboutScreenBMP != NULL) free(aboutScreenBMP);
 	if (muteButtonsBMP != NULL) free(muteButtonsBMP);
 	if (editOpModeCharsBMP != NULL) free(editOpModeCharsBMP);
-	if (arrowBMP != NULL) free(arrowBMP);
 }
 
 uint32_t *unpackBMP(const uint8_t *src, uint32_t packedLen)
@@ -2453,15 +2440,13 @@
 	muteButtonsBMP = unpackBMP(muteButtonsPackedBMP, sizeof (muteButtonsPackedBMP));
 	editOpModeCharsBMP = unpackBMP(editOpModeCharsPackedBMP, sizeof (editOpModeCharsPackedBMP));
 
-	arrowBMP = (uint32_t *)malloc(30 * sizeof (int32_t)); // different format
-
 	if (trackerFrameBMP    == NULL || samplerScreenBMP   == NULL || samplerVolumeBMP  == NULL ||
 		clearDialogBMP     == NULL || diskOpScreenBMP    == NULL || mod2wavBMP        == NULL ||
 		posEdBMP           == NULL || spectrumVisualsBMP == NULL || yesNoDialogBMP    == NULL ||
 		editOpScreen1BMP   == NULL || editOpScreen2BMP   == NULL || editOpScreen3BMP  == NULL ||
 		editOpScreen4BMP   == NULL || aboutScreenBMP     == NULL || muteButtonsBMP    == NULL ||
-		editOpModeCharsBMP == NULL || arrowBMP           == NULL || samplerFiltersBMP == NULL ||
-		yesNoDialogBMP     == NULL || bigYesNoDialogBMP  == NULL)
+		editOpModeCharsBMP == NULL || samplerFiltersBMP  == NULL || yesNoDialogBMP    == NULL ||
+		bigYesNoDialogBMP  == NULL)
 	{
 		showErrorMsgBox("Out of memory!");
 		return false; // BMPs are free'd in cleanUp()
--- a/vs2019_project/pt2-clone/protracker.ini
+++ b/vs2019_project/pt2-clone/protracker.ini
@@ -86,7 +86,7 @@
 ; Default value: FALSE
 ;       Comment: Setting it to TRUE removes the first sample number
 ;         digit in the pattern viewer, if it's zero. E.g. "0F" -> " F".
-;
+;         This mode is always enabled if PATTDOTS is set to true.
 BLANKZERO=FALSE
 
 ; Real VU-meters
--- a/vs2019_project/pt2-clone/pt2-clone.vcxproj
+++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj
@@ -305,7 +305,6 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_aboutscreen.c" />
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_arrow.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_clear.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_diskop.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_editop.c" />
--- a/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters
+++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters
@@ -94,9 +94,6 @@
     <ClCompile Include="..\..\src\gfx\pt2_gfx_aboutscreen.c">
       <Filter>gfx</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_arrow.c">
-      <Filter>gfx</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_clear.c">
       <Filter>gfx</Filter>
     </ClCompile>