// Written by Kouzerumatsukite (28-30 Ags 2022)
// The `macro-based` music driver here is written by me,
// which in the design was inspired by Trackers known to me,
// like FamiTracker, VortexTracker, and Monotone Tracker.

// Its simply migration from
// https://johnearnest.github.io/Octo/index.html?key=TloHp4JQ
// (click the site to activate sound, click X to view source)

// Monotonic (square wave only) version:
// https://wokwi.com/projects/341297619980517970

// This is bufferless version

//BROAD: Use 128X64 screen;
//Comment this if you're using 128x32
#define SCREEN_BROAD 1

//#define DEBUG 1 // monitor the states to serial
//#define MONITOR 1 // monitor the buffer health to serial

#include <Adafruit_SSD1306.h>
#include <PGMWrap.h>
#include <Wire.h>


#ifdef SCREEN_BROAD
 #define SCREEN_HEIGHT 64
#else
 #define SCREEN_HEIGHT 32
#endif

static Adafruit_SSD1306 display(128,SCREEN_HEIGHT,&Wire,-1,800000L,100000L);

#define ____ 0b00000000
#define H___ 0b11000000
#define HH__ 0b11110000
#define HHH_ 0b11111100
#define HHHH 0b11111111

const uint8_p PROGMEM smpData[] {   // SAMPLE BUFFER DATA  [ 128 bytes ]
  ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,  // 0x00 |        Silence
  HH__,____,____,____,HH__,____,____,____,HH__,____,____,____,HH__,____,____,____,  // 0x10 |  12.5% Pulse Duty
  HHHH,____,____,____,HHHH,____,____,____,HHHH,____,____,____,HHHH,____,____,____,  // 0x20 |  25.0% Pulse Duty
  HHHH,HHHH,____,____,HHHH,HHHH,____,____,HHHH,HHHH,____,____,HHHH,HHHH,____,____,  // 0x30 |  50.0% Pulse Duty
	0x41,0x47,0xE1,0xE4,0x91,0x16,0xD9,0x9D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 0x40 |  50.0% Pulse Noise
	0x35,0x53,0xAF,0xFA,0xF8,0x87,0x04,0xC4,0x06,0xA6,0x05,0x75,0x87,0xCF,0x44,0xA8,  // 0x50 | 100.0% Pulse Noise
	0x66,0xFC,0x55,0x02,0x7F,0x83,0xC0,0xC2,0xA0,0xA3,0x70,0xF2,0x48,0x8B,0xEC,0xCE,  // 0x60 | 100.0% Pulse Noise
	0x9A,0xA9,0x57,0x7D,0xFC,0x43,0x02,0x62,0x03,0xD3,0x82,0xBA,0xC3,0x67,0x22,0x54,  // 0x70 | 100.0% Pulse Noise
	HHHH,HHH_,____,____,HHHH,HHH_,____,____,HHHH,HHH_,____,____,HHHH,HHH_,____,____,  // 0x80 | 43.25% Pulse Duty
	HHHH,HH__,____,____,HHHH,HH__,____,____,HHHH,HH__,____,____,HHHH,HH__,____,____,  // 0x90 | 37.50% Pulse Duty
	HHHH,H___,____,____,HHHH,H___,____,____,HHHH,H___,____,____,HHHH,H___,____,____,  // 0xA0 | 31.75% Pulse Duty
	HHH_,____,____,____,HHH_,____,____,____,HHH_,____,____,____,HHH_,____,____,____,  // 0xB0 | 18.25% Pulse Duty
};

const uint8_p PROGMEM instrSet[] {   // SAMPLE AND ORNAMENT SEQUENCE MAPPER [ 128 bytes ]
//    0          1          2          3          4          5          6          7  
//          8          9         10         11         12         13         14         15  
// __________ __________ __________ __________ __________ __________ __________ __________
//| smpI ornI| smpI ornI| smpI ornI| smpI ornI| smpI ornI| smpI ornI| smpI ornI| smpI ornI|
    0x00,0x00, 0x10,0x10, 0x20,0x20, 0x30,0x30, 0x80,0x01, 0x80,0x11, 0xC0,0x01, 0xC0,0x11,  // Silence + HKS & 12
    0x01,0x00, 0x11,0x10, 0x21,0x20, 0x31,0x30, 0x01,0x21, 0x40,0x21, 0x80,0x21, 0xC0,0x21,  // User-def instruments
    0x40,0x00, 0x50,0x10, 0x60,0x20, 0x70,0x30, 0x40,0x40, 0x50,0x50, 0x60,0x60, 0x70,0x70,  // 12.5% Lead + HKS +
    0x40,0x80, 0x50,0x90, 0x60,0xA0, 0x70,0xB0, 0x40,0xC0, 0x50,0xD0, 0x60,0xE0, 0x70,0xF0,  // maj-min-dim chords
    0x80,0x00, 0x90,0x10, 0xA0,0x20, 0xB0,0x30, 0x80,0x40, 0x90,0x50, 0xA0,0x60, 0xB0,0x70,  // 25.0% Lead + HKS +
    0x80,0x80, 0x90,0x90, 0xA0,0xA0, 0xB0,0xB0, 0x80,0xC0, 0x90,0xD0, 0xA0,0xE0, 0xB0,0xF0,  // maj-min-dim chords
    0xC0,0x00, 0xD0,0x10, 0xE0,0x20, 0xF0,0x30, 0xC0,0x40, 0xD0,0x50, 0xE0,0x60, 0xF0,0x70,  // 50.0% Lead + HKS +
    0xC0,0x80, 0xD0,0x90, 0xE0,0xA0, 0xF0,0xB0, 0xC0,0xC0, 0xD0,0xD0, 0xE0,0xE0, 0xF0,0xF0,  // maj-min-dim chords
};


const uint8_p PROGMEM smpRef[] {   // SAMPLE SEQUENCE DATA [ 256 bytes ]
// Loop    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
// PREDEFINED SAMPLE DATA
    15, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // [0x00] Silence
    15, 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // [0x10] Hat only
    15, 0x50,0x40,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // [0x20] Kick only
    15, 0x70,0x60,0x50,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // [0x30] Snare only
    15, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // [0x40] 12.5 % Pulse Tone
    15, 0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // [0x50] Hat + 12.5 % Pulse
    15, 0x50,0x40,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // [0x60] Kick + 12.5 % Pulse
    15, 0x70,0x60,0x50,0x40,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // [0x70] Snare + 12.5 % Pulse
    15, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, // [0x80] 25 % Pulse Tone
    15, 0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, // [0x90] Hat + 25 % Pulse 
    15, 0x50,0x40,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, // [0xA0] Kick + 25 % Pulse
    15, 0x70,0x60,0x50,0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, // [0xB0] Snare + 25 % Pulse
    15, 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, // [0xC0] 50 % Pulse Tone
    15, 0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, // [0xD0] Hat + 50 % Pulse
    15, 0x50,0x40,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, // [0xE0] Kick + 50 % Pulse
    15, 0x70,0x60,0x50,0x40,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, // [0xF0] Snare + 50 % Pulse
     8, 0x20,0xA0,0x90,0x80,0x30,0x80,0x90,0xA0,0x20,0xA0,0x90,0x80,0x30,0x80,0x90, // [0x01] 25%-50% PWM Tone
     8, 0x70,0xA0,0x90,0x80,0x30,0x80,0x90,0xA0,0x20,0xA0,0x90,0x80,0x30,0x80,0x90, // [0x11] Hat + 25%-50% PWM
     8, 0x50,0x40,0x30,0x80,0x30,0x80,0x90,0xA0,0x20,0xA0,0x90,0x80,0x30,0x80,0x90, // [0x21] Kick + 25%-50% PWM
     8, 0x70,0x60,0x50,0x40,0x30,0x80,0x90,0xA0,0x20,0xA0,0x90,0x80,0x30,0x80,0x90, // [0x31] Snare + 25%-50% PWM
  //   theres no other samples needed beside above, hence nothing.
};

const uint8_p PROGMEM ornData[] {  // ORNAMENT SEQUENCE DATA [ 256 bytes ]
//       Odd values (e.g. 63 67 71 ) is fixed pitch alter.
//       Even values (e.g 4 8 12 -4 -8 -12 ) is relative pitch alter.
//       Zero value won't alter the current pitch.
// Loop    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15  
//  PREDEFINED ORNAMENTS DATA
  13,    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // [0x00] Tone
  13,  211,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // [0x10] Hat + tone
  13,  147, 103,  67,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // [0x20] Kick + tone
  13,  107, 171, 159, 147,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // [0x30] Snare + tone
  13,   16,  28,   0,  16,  28,   0,  16,  28,   0,  16,  28,   0,  16,  28,   0, // [0x40] Major chord tone
  13,  211,  16,  28,   0,  16,  28,   0,  16,  28,   0,  16,  28,   0,  16,  28, // [0x50] Hat + major chord
  13,  147, 103,  67,  16,  28,   0,  16,  28,   0,  16,  28,   0,  16,  28,   0, // [0x60] Kick + major chord
  13,  107, 171, 159, 147,  16,  28,   0,  16,  28,   0,  16,  28,   0,  16,  28, // [0x70] Snare + major chord
  13,   12,  28,   0,  12,  28,   0,  12,  28,   0,  12,  28,   0,  12,  28,   0, // [0x80] Minor chord tone
  13,  211,  12,  28,   0,  12,  28,   0,  12,  28,   0,  12,  28,   0,  12,  28, // [0x90] Hat + minor chord 
  13,  147, 103,  67,  12,  28,   0,  12,  28,   0,  12,  28,   0,  12,  28,   0, // [0xA0] Kick + minor chord
  13,  107, 171, 159, 147,  12,  28,   0,  12,  28,   0,  12,  28,   0,  12,  28, // [0xB0] Snare + minor chord
  13,   12,  24,   0,  12,  24,   0,  12,  24,   0,  12,  24,   0,  12,  24,   0, // [0xC0] Diminish chord tone
  13,  211,  12,  24,   0,  12,  24,   0,  12,  24,   0,  12,  24,   0,  12,  24, // [0xD0] Hat + diminish chord
  13,  147, 103,  67,  12,  24,   0,  12,  24,   0,  12,  24,   0,  12,  24,   0, // [0xE0] Kick + diminish chord
  13,  107, 171, 159, 147,  12,  24,   0,  12,  24,   0,  12,  24,   0,  12,  24, // [0xF0] Snare + diminish chord
  15,  -20, -16,  -8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // [0x01] SlideUp
  15,   20,  16,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // [0x11] SlideDown
  10,    2,   2,   0,  -2,  -2,   0,   2,   2,   0,  -2,  -2,   0,   2,   2,   0, // [0x21] Vibratio
};

const uint8_p PROGMEM seqData[] { // the sequence data, song name: Nyan Cat Theme - PTGuitarMan
  0xAF, 0x4C, 0xB3, 0x40, 0xBB, 0x40, 0xBB, 0x3C, 0xCF, 0x4C, 0xBB, 0x40, 0xB3, 0x40, 0xBB, 0x40, 
  0xCF, 0x48, 0xD7, 0x40, 0xDF, 0x40, 0xE3, 0x40, 0xDF, 0x4C, 0xCB, 0x40, 0xCF, 0x48, 0xEB, 0x10, 
  0xBB, 0x48, 0xBB, 0x3C, 0xAB, 0x40, 0xAF, 0x40, 0xBB, 0x4C, 0xBB, 0x3C, 0xCF, 0x48, 0xBB, 0x14, 
  0xD7, 0x4C, 0xCB, 0x40, 0xCF, 0x44, 0xD7, 0x40, 0xE3, 0x4C, 0xDF, 0x40, 0xE3, 0x44, 0xD7, 0x44, 
  0xBB, 0x89, 0x53, 0xC2, 0xBB, 0x82, 0x00, 0x03, 0xC3, 0x85, 0x00, 0x02, 0x93, 0xD2, 0x00, 0x03, 
  0xAB, 0x8D, 0x5B, 0xC2, 0xAF, 0x82, 0x00, 0x03, 0xAF, 0x85, 0xAF, 0x3A, 0x9F, 0xC6, 0x00, 0x03, 
  0xA7, 0x89, 0x4F, 0xC2, 0xA3, 0xC2, 0x00, 0x03, 0x9F, 0xC5, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 
  0x9F, 0xCD, 0x63, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0xA7, 0x85, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 
  0xAB, 0x29, 0x4B, 0xC2, 0xAB, 0x82, 0x00, 0x03, 0xAB, 0xC5, 0x00, 0x02, 0xA7, 0xC2, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0xA7, 0xC2, 0x00, 0x03, 0xAF, 0x85, 0x00, 0x02, 0xBB, 0x86, 0x00, 0x03, 
  0xC3, 0x89, 0x3F, 0xC2, 0xAF, 0xC6, 0x00, 0x03, 0xBB, 0xC5, 0x00, 0x02, 0xA7, 0xC2, 0x00, 0x03, 
  0xAF, 0xCD, 0x00, 0x02, 0x9F, 0xC2, 0x00, 0x03, 0xA7, 0x85, 0x00, 0x02, 0x9F, 0xC2, 0x00, 0x03, 
  0xAF, 0x89, 0x53, 0xC2, 0xAF, 0x82, 0x00, 0x03, 0xBB, 0x85, 0x00, 0x02, 0x93, 0xD2, 0x00, 0x03, 
  0xC3, 0x8D, 0x00, 0x02, 0xAF, 0xC2, 0x00, 0x03, 0xBB, 0xC5, 0x00, 0x02, 0xA7, 0xC6, 0x00, 0x03, 
  0xAF, 0xC9, 0x4F, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0xAB, 0xC5, 0x00, 0x02, 0xAF, 0xC2, 0x00, 0x03, 
  0xAB, 0xCD, 0x00, 0x02, 0xA7, 0xC2, 0x00, 0x03, 0x9F, 0xC5, 0x00, 0x02, 0xA7, 0xC2, 0x00, 0x03, 
  0xAB, 0xC9, 0x4B, 0xC2, 0xAB, 0xC2, 0x00, 0x03, 0x9F, 0x85, 0x00, 0x02, 0xA7, 0x82, 0x00, 0x03, 
  0xAF, 0x8D, 0x00, 0x02, 0xBB, 0x82, 0x00, 0x03, 0xA7, 0xC5, 0x00, 0x02, 0xAB, 0xC6, 0x00, 0x03, 
  0xA7, 0xC9, 0x3F, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0xA7, 0xC5, 0x00, 0x02, 0xA7, 0x3E, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0xA7, 0xCD, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 
  0xAB, 0xC9, 0x4B, 0xC2, 0xAB, 0xC2, 0x00, 0x03, 0x9F, 0xC5, 0x00, 0x02, 0xA7, 0xC2, 0x00, 0x03, 
  0xAF, 0x8D, 0x00, 0x02, 0xBB, 0x82, 0x00, 0x03, 0xA7, 0xC5, 0x00, 0x02, 0xAB, 0xC6, 0x00, 0x03, 
  0xA7, 0xC9, 0x3F, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0xA7, 0x85, 0x00, 0x02, 0xA7, 0x86, 0x00, 0x03, 
  0x9F, 0x8D, 0x00, 0x02, 0x9F, 0x3A, 0x00, 0x03, 0x9F, 0x8D, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 
  0x9F, 0xC9, 0x53, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0x8B, 0x85, 0x93, 0xE2, 0x93, 0x82, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x9F, 0xC2, 0x00, 0x03, 0x8B, 0x85, 0x93, 0xE2, 0x93, 0x82, 0x00, 0x03, 
  0x9F, 0xC9, 0x4F, 0xC2, 0xA7, 0xC2, 0x00, 0x03, 0xAF, 0xC5, 0x93, 0xE2, 0x9F, 0xC2, 0x00, 0x03, 
  0xB3, 0xCD, 0x00, 0x02, 0xAF, 0xC2, 0x00, 0x03, 0xB3, 0xC5, 0x93, 0xE2, 0xBB, 0xC2, 0x00, 0x03, 
  0x9F, 0xC9, 0x4B, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0x9F, 0xC5, 0x8B, 0xE2, 0x9F, 0xC2, 0x00, 0x03, 
  0x8B, 0x8D, 0x00, 0x02, 0x93, 0x82, 0x00, 0x03, 0x9F, 0x85, 0x8B, 0xE2, 0x93, 0xC6, 0x00, 0x03, 
  0xB3, 0xC9, 0x3F, 0xC2, 0xAF, 0x22, 0x00, 0x03, 0xA7, 0x25, 0x8B, 0xE2, 0x9F, 0x22, 0x00, 0x03, 
  0x8B, 0x2D, 0x00, 0x02, 0x7F, 0x22, 0x00, 0x03, 0x83, 0x2D, 0x8B, 0xE2, 0x8B, 0x22, 0x00, 0x03, 
  0x9F, 0xC9, 0x53, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0x8B, 0x85, 0x93, 0xE2, 0x93, 0x82, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x8B, 0x85, 0x93, 0xE2, 0x93, 0x82, 0x00, 0x03, 
  0x9F, 0xC9, 0x4F, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0xA7, 0xC5, 0x93, 0xE2, 0xAF, 0xC2, 0x00, 0x03, 
  0x9F, 0x8D, 0x00, 0x02, 0x8B, 0x82, 0x00, 0x03, 0x93, 0x85, 0x93, 0xE2, 0x8B, 0x82, 0x00, 0x03, 
  0x9F, 0xC9, 0x4B, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0x9F, 0xC5, 0x8B, 0xE2, 0x9B, 0x82, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x8B, 0x82, 0x00, 0x03, 0x93, 0x85, 0x8B, 0xE2, 0x9F, 0x86, 0x00, 0x03, 
  0xB3, 0xC9, 0x3F, 0xC2, 0xAF, 0xC2, 0x00, 0x03, 0xB3, 0xC5, 0x8B, 0xE2, 0xBB, 0xC2, 0x00, 0x03, 
  0x9F, 0x2D, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x9B, 0x2D, 0x8B, 0xE2, 0x9B, 0x2E, 0x00, 0x03, 
  0x9F, 0xC9, 0x53, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0x8B, 0x85, 0x93, 0xE2, 0x93, 0x82, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x8B, 0x85, 0x93, 0xE2, 0x93, 0x86, 0x00, 0x03, 
  0x9F, 0xC9, 0x4F, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0xA7, 0xC5, 0x93, 0xE2, 0xAF, 0xC2, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x8B, 0x82, 0x00, 0x03, 0x93, 0x85, 0x93, 0xE2, 0x8B, 0x82, 0x00, 0x03, 
  0x9F, 0xC9, 0x4B, 0xC2, 0x9F, 0xC2, 0x00, 0x03, 0x9F, 0xC5, 0x8B, 0xE2, 0x9B, 0x82, 0x00, 0x03, 
  0x9F, 0xCD, 0x00, 0x02, 0x8B, 0x82, 0x00, 0x03, 0x93, 0x85, 0x8B, 0xE2, 0x9F, 0xC2, 0x00, 0x03, 
  0xB3, 0xCD, 0x00, 0x02, 0xAF, 0xC2, 0x00, 0x03, 0xB3, 0xC5, 0x00, 0x02, 0xBB, 0xC2, 0x00, 0x03, 
  0x9F, 0x8D, 0x3F, 0xC2, 0x9F, 0x82, 0x00, 0x03, 0xA7, 0xCD, 0x8B, 0xE2, 0xA7, 0xCE, 0x00, 0x03,
};

const uint8_p PROGMEM seqTime[] { // Song timeline of pages
  0,  1,  2,  3,
	4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
	4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 
	24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
	24, 25, 26, 27, 28, 29, 30, 31, 40, 41, 42, 43, 44, 45, 46, 47,
};

const uint8_t seqLoop = 4; // The song loop point

uint16_t ornPtr = 1; // ornament pointer
uint16_t smpPtr = 1; // sample pointer
uint8_t tickCtr = 0; // tick counter
uint8_t tickFin = 1; // tick final
uint8_t rowCtr = 255; // row counter
uint8_t rowFin = 8; // row final
uint16_t pageCtr = 0; // page counter
uint16_t pageFin = sizeof(seqTime); // page fin
uint8_t orn = 0; // currently loaded orn
uint8_t notekey = 0; // current loaded pitch
uint8_t pitch = 0; // currently playing pitch
uint16_t freq = 0; // translated to freq
uint8_t freqLo = 0; // extra 8-bits of freq


const uint8_p PROGMEM seqTicks[] {
// Ticks speed
//  _______ _______ _______ _______ 
// |Speed A|Speed B|Speed C|Speed D|
    6,      4,      3,      2,    
};

const PROGMEM unsigned char sprite_stars[] {
  0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,16,40,16,0,0,0,0,0,0,0,0,0,0,0,
  0,16,16,108,16,16,0,0,0,0,0,0,0,0,0,0,
  16,16,16,238,16,16,16,0,0,0,0,0,0,0,0,0,
  16,84,0,198,0,84,16,0,0,0,0,0,0,0,0,0,
  16,68,0,130,0,68,16,0,0,0,0,0,0,0,0,0,
  16,0,0,130,0,0,16,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};

const PROGMEM unsigned char sprite_nyan[] {

0,0,0,192,255,255,255,255,255,255,255,255,0,0,0,0,0,192,63,192,255,63,192,255,
0,0,0,252,255,255,255,255,255,255,254,255,0,0,0,0,0,252,3,252,255,3,255,255,
0,0,3,15,255,255,255,255,255,255,127,63,0,0,3,4,8,8,248,8,248,248,232,248,
0,0,255,255,255,255,255,255,255,255,255,255,0,0,255,0,0,4,128,0,1,9,1,65,
0,0,254,255,255,255,255,255,63,31,15,0,0,0,254,1,0,128,0,200,224,240,255,255,
0,0,0,0,128,128,128,176,200,136,8,8,0,0,0,0,128,128,128,176,248,248,248,248,
255,255,255,255,255,255,255,255,255,63,0,0,255,255,63,192,255,63,192,63,0,0,0,0,
255,255,255,255,255,255,255,255,255,3,0,0,255,255,3,252,255,3,252,3,0,0,0,0,
159,207,255,255,255,255,255,227,230,252,0,0,248,249,248,24,248,248,28,255,62,60,0,0,
254,254,254,254,254,255,255,255,144,224,0,0,7,3,3,19,131,1,0,255,240,224,0,0,
0,48,49,192,210,31,128,255,74,57,0,0,255,223,255,63,63,255,255,255,123,57,0,0,
4,100,100,28,92,200,16,224,64,128,0,0,252,188,252,228,228,248,240,224,192,128,0,0,

0,0,0,3,255,255,255,255,255,255,255,255,0,0,0,0,0,3,252,3,255,252,3,255,
0,0,0,240,255,255,255,255,255,255,255,254,0,0,0,0,0,240,15,240,255,15,241,255,
0,0,3,63,255,255,255,255,255,255,255,127,0,0,3,4,8,56,200,56,248,200,184,200,
0,0,255,255,255,255,255,255,255,255,255,255,0,0,255,0,0,4,128,0,0,8,0,64,
0,0,254,255,255,255,255,255,159,143,135,128,0,0,254,1,0,128,0,104,240,248,255,255,
0,0,0,0,128,128,128,152,164,196,132,4,0,0,0,0,128,128,128,152,188,252,252,252,
255,255,255,255,255,255,255,255,255,252,0,0,255,255,252,3,255,252,3,252,0,0,0,0,
254,255,255,255,255,255,255,255,255,15,0,0,255,255,15,240,255,15,240,15,0,0,0,0,
127,15,207,255,255,255,255,243,242,220,0,0,248,249,248,56,248,200,60,223,30,28,0,0,
255,255,255,255,255,255,255,255,144,112,0,0,5,1,1,17,129,0,0,255,240,112,0,0,
0,24,24,96,105,143,192,255,37,28,0,0,255,239,255,159,159,255,127,255,61,28,0,0,
2,50,178,14,46,228,8,240,32,224,0,0,254,222,254,242,242,252,248,240,224,224,0,0,

0,0,0,15,255,255,255,255,255,255,255,255,0,0,0,0,0,15,240,15,255,240,15,255,
0,0,0,192,255,255,255,255,255,255,255,255,0,0,0,0,0,192,63,192,255,63,192,255,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,3,4,248,8,248,248,8,248,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,0,0,8,0,
0,0,0,254,255,255,255,255,255,159,143,135,0,0,0,254,1,0,128,0,104,240,248,255,
0,0,0,0,0,128,128,128,152,164,196,132,0,0,0,0,0,128,128,128,152,188,252,252,
255,255,255,255,255,255,255,255,255,240,0,0,255,255,240,15,255,240,15,240,0,0,0,0,
255,255,255,255,254,255,255,255,255,63,0,0,255,255,63,195,255,63,192,63,0,0,0,0,
255,255,255,15,63,255,255,255,251,9,14,0,248,248,249,248,248,232,248,12,15,15,14,0,
255,255,255,255,255,255,255,255,255,72,56,0,64,5,1,1,17,129,0,0,255,120,56,0,
128,0,24,24,96,105,143,192,255,18,14,0,255,255,239,255,159,159,255,127,255,30,14,0,
4,2,50,178,14,46,228,8,240,144,112,0,252,254,222,254,242,242,252,248,240,240,112,0,

0,0,0,63,255,255,255,255,255,255,255,255,0,0,0,0,0,63,192,63,255,192,63,255,
0,0,0,3,255,255,255,255,255,255,255,255,0,0,0,0,0,3,252,3,255,252,3,255,
0,0,0,243,255,255,255,255,255,255,255,255,0,0,0,3,4,248,8,248,248,8,248,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,0,0,8,0,
0,0,0,254,255,255,255,255,255,159,143,135,0,0,0,254,1,0,128,0,104,240,248,255,
0,0,0,0,0,128,128,128,152,164,196,132,0,0,0,0,0,128,128,128,152,188,252,252,
255,255,255,255,255,255,255,255,255,192,0,0,255,255,192,63,255,192,63,192,0,0,0,0,
255,255,255,255,254,254,255,255,255,252,0,0,255,255,252,3,255,255,3,252,0,0,0,0,
255,255,207,15,127,127,255,255,243,18,28,0,248,248,249,248,248,200,248,12,31,30,28,0,
255,255,255,255,255,255,255,255,255,144,112,0,64,5,1,1,17,129,0,0,255,240,112,0,
128,0,24,24,96,105,143,192,255,37,28,0,255,255,239,255,159,159,255,127,255,61,28,0,
4,2,50,178,14,46,228,8,240,32,224,0,252,254,222,254,242,242,252,248,240,224,224,0,

0,0,0,252,255,255,255,255,255,255,255,255,0,0,0,0,0,252,3,252,255,3,252,255,
0,0,0,15,255,255,255,255,255,255,255,255,0,0,0,0,0,15,240,15,255,240,15,255,
0,0,0,195,255,255,255,255,255,255,255,255,0,0,0,3,4,200,56,200,248,56,200,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,0,1,9,1,
0,0,0,254,255,255,255,255,255,63,31,15,0,0,0,254,1,0,128,0,200,224,240,255,
0,0,0,0,0,128,128,128,176,200,136,8,0,0,0,0,0,128,128,128,176,248,248,248,
255,255,255,255,255,255,255,255,255,3,0,0,255,255,3,252,255,3,252,3,0,0,0,0,
252,254,255,255,255,255,255,255,255,240,0,0,255,255,241,15,255,240,15,240,0,0,0,0,
127,31,239,255,255,255,255,255,199,78,113,0,248,248,249,248,248,56,216,60,127,123,113,0,
255,254,254,254,254,254,255,255,255,64,192,0,65,7,3,3,19,131,1,0,255,192,192,0,
0,0,48,49,192,210,31,128,255,148,115,0,255,255,223,255,63,63,255,255,255,247,115,0,
8,4,100,100,28,92,200,16,224,128,128,0,248,252,188,252,228,228,248,240,224,128,128,0,

0,0,0,240,255,255,255,255,255,255,255,255,0,0,0,0,0,240,15,240,255,15,240,255,
0,0,0,63,255,255,255,255,255,255,255,254,0,0,0,0,0,63,192,63,255,192,63,255,
0,0,0,3,255,255,255,255,255,255,255,127,0,0,0,3,4,8,248,8,248,248,136,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,1,1,9,1,
0,0,0,254,255,255,255,255,63,31,15,0,0,0,0,254,1,0,128,192,232,240,255,255,
0,0,0,0,0,128,128,176,200,136,8,8,0,0,0,0,0,128,128,176,248,248,248,248,
255,255,255,255,255,255,255,255,255,15,0,0,255,255,15,240,255,15,240,15,0,0,0,0,
254,255,255,255,255,255,255,255,255,192,0,0,255,255,192,63,255,192,63,192,0,0,0,0,
127,15,207,255,255,255,255,239,199,206,115,0,248,248,249,56,248,248,24,252,127,123,115,0,
254,254,254,254,254,255,255,255,255,64,128,0,67,7,3,3,19,129,0,0,255,192,128,0,
0,48,49,192,210,31,128,255,254,148,227,0,255,223,255,63,63,255,255,127,255,247,227,0,
4,100,100,28,92,200,16,224,128,128,128,0,252,188,252,228,228,248,240,224,128,128,128,0,

0,0,0,192,255,255,255,255,255,255,255,255,0,0,0,0,0,192,63,192,255,63,192,255,
0,0,0,252,255,255,255,255,255,255,254,255,0,0,0,0,0,252,3,252,255,3,255,255,
0,0,3,15,255,255,255,255,255,255,127,63,0,0,3,4,8,8,248,8,248,248,232,248,
0,0,255,255,255,255,255,255,255,255,255,255,0,0,255,0,0,4,128,0,1,9,1,65,
0,0,254,255,255,255,255,255,63,31,15,0,0,0,254,1,0,128,0,200,224,240,255,255,
0,0,0,0,128,128,128,176,200,136,8,8,0,0,0,0,128,128,128,176,248,248,248,248,
255,255,255,255,255,255,255,255,255,63,0,0,255,255,63,192,255,63,192,63,0,0,0,0,
255,255,255,255,255,255,255,255,255,3,0,0,255,255,3,252,255,3,252,3,0,0,0,0,
159,207,255,255,255,255,255,227,230,252,0,0,248,249,248,24,248,248,28,255,62,60,0,0,
254,254,254,254,254,255,255,255,144,224,0,0,7,3,3,19,131,1,0,255,240,224,0,0,
0,48,49,192,210,31,128,255,74,57,0,0,255,223,255,63,63,255,255,255,123,57,0,0,
4,100,100,28,92,200,16,224,64,128,0,0,252,188,252,228,228,248,240,224,192,128,0,0,

0,0,0,3,255,255,255,255,255,255,255,255,0,0,0,0,0,3,252,3,255,252,3,255,
0,0,0,240,255,255,255,255,255,255,255,254,0,0,0,0,0,240,15,240,255,15,241,255,
0,0,3,63,255,255,255,255,255,255,255,127,0,0,3,4,8,56,200,56,248,200,184,248,
0,0,255,255,255,255,255,255,255,255,255,255,0,0,255,0,0,4,128,0,0,8,0,64,
0,0,254,255,255,255,255,255,159,143,135,128,0,0,254,1,0,128,0,104,240,248,255,255,
0,0,0,0,128,128,128,152,164,196,132,4,0,0,0,0,128,128,128,152,188,252,252,252,
255,255,255,255,255,255,255,255,255,252,0,0,255,255,252,3,255,252,3,252,0,0,0,0,
254,255,255,255,255,255,255,255,255,15,0,0,255,255,15,240,255,15,240,15,0,0,0,0,
127,15,207,255,255,255,255,243,242,220,0,0,248,249,248,56,248,200,60,223,30,28,0,0,
255,255,255,255,255,255,255,255,144,112,0,0,5,1,1,17,129,0,0,255,240,112,0,0,
0,24,24,96,105,143,192,255,37,28,0,0,255,239,255,159,159,255,127,255,61,28,0,0,
2,50,178,14,46,228,8,240,32,224,0,0,254,222,254,242,242,252,248,240,224,224,0,0,

0,0,0,15,255,255,255,255,255,255,255,255,0,0,0,0,0,15,240,15,255,240,15,255,
0,0,0,192,255,255,255,255,255,255,255,255,0,0,0,0,0,192,63,192,255,63,192,255,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,3,4,248,8,248,248,8,248,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,0,0,8,0,
0,0,0,254,255,255,255,255,255,159,143,135,0,0,0,254,1,0,128,0,104,240,248,255,
0,0,0,0,0,128,128,128,152,164,196,132,0,0,0,0,0,128,128,128,152,188,252,252,
255,255,255,255,255,255,255,255,255,240,0,0,255,255,240,15,255,240,15,240,0,0,0,0,
255,255,255,255,254,255,255,255,255,63,0,0,255,255,63,195,255,63,192,63,0,0,0,0,
255,255,255,15,63,255,255,255,251,9,14,0,248,248,249,248,248,232,248,12,15,15,14,0,
255,255,255,255,255,255,255,255,255,72,56,0,64,5,1,1,17,129,0,0,255,120,56,0,
128,0,24,24,96,105,143,192,255,18,14,0,255,255,239,255,159,159,255,127,255,30,14,0,
4,2,50,178,14,46,228,8,240,144,112,0,252,254,222,254,242,242,252,248,240,240,112,0,

0,0,0,63,255,255,255,255,255,255,255,255,0,0,0,0,0,63,192,63,255,192,63,255,
0,0,0,3,255,255,255,255,255,255,255,255,0,0,0,0,0,3,252,3,255,252,3,255,
0,0,0,243,255,255,255,255,255,255,255,255,0,0,0,3,4,248,8,248,248,8,248,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,0,0,8,0,
0,0,0,254,255,255,255,255,255,159,143,135,0,0,0,254,1,0,128,0,104,240,248,255,
0,0,0,0,0,128,128,128,152,164,196,132,0,0,0,0,0,128,128,128,152,188,252,252,
255,255,255,255,255,255,255,255,255,192,0,0,255,255,192,63,255,192,63,192,0,0,0,0,
255,255,255,255,254,254,255,255,255,252,0,0,255,255,252,3,255,255,3,252,0,0,0,0,
255,255,207,15,127,127,255,255,243,18,28,0,248,248,249,248,248,200,248,12,31,30,28,0,
255,255,255,255,255,255,255,255,255,144,112,0,64,5,1,1,17,129,0,0,255,240,112,0,
128,0,24,24,96,105,143,192,255,37,28,0,255,255,239,255,159,159,255,127,255,61,28,0,
4,2,50,178,14,46,228,8,240,32,224,0,252,254,222,254,242,242,252,248,240,224,224,0,

0,0,0,252,255,255,255,255,255,255,255,255,0,0,0,0,0,252,3,252,255,3,252,255,
0,0,0,15,255,255,255,255,255,255,255,255,0,0,0,0,0,15,240,15,255,240,15,255,
0,0,0,195,255,255,255,255,255,255,255,255,0,0,0,3,4,200,56,200,248,56,200,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,0,1,9,1,
0,0,0,254,255,255,255,255,255,63,31,15,0,0,0,254,1,0,128,0,200,224,240,255,
0,0,0,0,0,128,128,128,176,200,136,8,0,0,0,0,0,128,128,128,176,248,248,248,
255,255,255,255,255,255,255,255,255,3,0,0,255,255,3,252,255,3,252,3,0,0,0,0,
252,254,255,255,255,255,255,255,255,240,0,0,255,255,241,15,255,240,15,240,0,0,0,0,
127,31,239,255,255,255,255,255,199,78,113,0,248,248,249,248,248,56,216,60,127,123,113,0,
255,254,254,254,254,254,255,255,255,64,192,0,65,7,3,3,19,131,1,0,255,192,192,0,
0,0,48,49,192,210,31,128,255,148,115,0,255,255,223,255,63,63,255,255,255,247,115,0,
8,4,100,100,28,92,200,16,224,128,128,0,248,252,188,252,228,228,248,240,224,128,128,0,

0,0,0,240,255,255,255,255,255,255,255,255,0,0,0,0,0,240,15,240,255,15,240,255,
0,0,0,63,255,255,255,255,255,255,255,254,0,0,0,0,0,63,192,63,255,192,63,255,
0,0,0,3,255,255,255,255,255,255,255,127,0,0,0,3,4,8,248,8,248,248,136,248,
0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,0,0,4,128,1,1,9,1,
0,0,0,254,255,255,255,255,63,31,15,0,0,0,0,254,1,0,128,192,232,240,255,255,
0,0,0,0,0,128,128,176,200,136,8,8,0,0,0,0,0,128,128,176,248,248,248,248,
255,255,255,255,255,255,255,255,255,15,0,0,255,255,15,240,255,15,240,15,0,0,0,0,
254,255,255,255,255,255,255,255,255,192,0,0,255,255,192,63,255,192,63,192,0,0,0,0,
127,15,207,255,255,255,255,239,199,206,115,0,248,248,249,56,248,248,24,252,127,123,115,0,
254,254,254,254,254,255,255,255,255,64,128,0,67,7,3,3,19,129,0,0,255,192,128,0,
0,48,49,192,210,31,128,255,254,148,227,0,255,223,255,63,63,255,255,127,255,247,227,0,
4,100,100,28,92,200,16,224,128,128,128,0,252,188,252,228,228,248,240,224,128,128,128,0,

};

static char* toHex(uint64_t value, uint8_t digits){
  static char result[17]; if(digits>16) digits=16;
  for(byte k=0; k<digits; k++)
    result[k] = "0123456789ABCDEF"[value>>(digits-1-k)*4&15];
  result[digits] = 0;
  return result;
}

static char* toPatt2(uint16_t value){
  static char result[8];
  uint8_t note = ( value >> 8 ) - 3 >> 2;
  uint8_t macr = ( value & 0xFF ) >> 2;
  if((value >> 8)==0){
      result[0] = '.';
      result[1] = '.';
      result[2] = '.';
  }else{
    if(value&0xF0){
      result[0] = "GAABCCDDEFFG"[note%12];
      result[1] = "#-#--#-#--#-"[note%12]; 
      result[2] = (note-4)/12+0x31;
    }else{
      result[0] = '-';
      result[1] = '-';
      result[2] = '-';
    }
  }
  result[3] = 32;
  result[4] = "-UUUAAAABBBBCCCC"[macr/4];
  result[5] = ".---.JID.JID.JID"[macr/4];
  result[6] = macr<16?".HKS0123456789AB"[macr]:".HDS"[macr&3];
  result[7] = 0;
  return result;
}
static char* toPatt(uint16_t value){
  static char result[8];
  uint8_t note = ( value >> 8 ) - 3 >> 2;
  uint8_t macr = ( value & 0xFF ) >> 2;
  if((value >> 8)==0){
      result[0] = '.';
      result[1] = '.';
      result[2] = '.';
  }else{
    if(value&0xF0){
      result[0] = "GAABCCDDEFFG"[note%12];
      result[1] = "#-#--#-#--#-"[note%12]; 
      result[2] = (note-4)/12+0x31;
    }else{
      result[0] = '-';
      result[1] = '-';
      result[2] = '-';
    }
  }
  result[3] = "-UUUAAAABBBBCCCC"[macr/4];
  result[4] = ".---.JID.JID.JID"[macr/4];
  result[5] = macr<16?".HDS0123456789AB"[macr]:".HDS"[macr&3];
  result[6] = 0;
  return result;
}

#ifdef SCREEN_BROAD
 #define AUDIO_BUFFER_LENGTH 0x1FF
#else
 #define AUDIO_BUFFER_LENGTH 0xFF
#endif

static byte buffPtr;
static bool lastSamp;
static uint16_t sampPos=0;
static uint8_t sampPosLo=0;
bool getSamp(){
  sampPosLo += freqLo;
  sampPos += freq + (sampPosLo - freqLo < 0);
  lastSamp = smpData[buffPtr+(sampPos>>12&15)]>>7-(sampPos>>9&7)&1;
  return lastSamp;
};

static byte freqDiv = 32;
static bool refreshDisp = false;
static byte refreshTick = 0;

void performTick(){ refreshTick--;
  buffPtr = smpRef[smpPtr]; // update buffer
  orn = ornData[ornPtr];
  pitch = orn&1?orn:notekey+(int8_t)orn;
  uint32_t freqc = 1024*pow(2,(double)(pitch-64.)/48.)*freqDiv;
  freq = freqc>>8; freqLo = freqc;

  uint16_t l = 256/freqDiv*32;

  if(!(++ornPtr&15)){ornPtr -= 16; ornPtr += ornData[ornPtr];}
  if(!(++smpPtr&15)){smpPtr -= 16; smpPtr += smpRef[smpPtr];}
  if(++tickCtr==tickFin){ tickCtr = 0; // update row
    if(++rowCtr==rowFin){ rowCtr = 0; // update page
      if(++pageCtr==pageFin) pageCtr = seqLoop; // loop
    }
    auto idx = rowCtr*2+16*seqTime[pageCtr];
    uint16_t seq = (seqData[idx]<<8)+seqData[idx+1];
    tickFin = seqTicks[seq&3]; // extract tickspeed
    if(seq >> 8){
      notekey = seq >> 8; // extract pitch
      auto insidx = (seq>>2&0b111111)*2;
      uint16_t ins = (instrSet[insidx]<<8)+instrSet[insidx+1]; // extract instrument
      smpPtr = ins>>8&0xF0 | (ins>>8&0xF)<<8 | 1; // sample pointer
      ornPtr = ins>>0&0xF0 | (ins>>0&0xF)<<8 | 1; // orn pointer
    }
    refreshDisp = true;
  }
}

void performDisp2(uint8_t xpos){
  refreshDisp = false;
  display.setTextSize(1);
  #ifndef SCREEN_BROAD
    #define TRK_LEN 4
    byte o = rowCtr&0b100;
  #else
    #define TRK_LEN 8
    byte o = 0;
  #endif
  auto idx = 16*seqTime[pageCtr+o];
  for(byte j = o; j < TRK_LEN+o; j++){
    //display.setCursor((j>>2)*64,(j&3)*8);
    display.setCursor(xpos,(j-o)*8);
    display.setTextColor(j!=rowCtr,j==rowCtr);
    uint16_t seq = (seqData[idx+0+j*2]<<8)+seqData[idx+1+j*2];
    display.print(j); display.print(" ");
    display.print(toPatt2(seq));
    display.print(seq&3); 
  }
}
void performDisp(uint8_t xpos){
  refreshDisp = false;
  display.setTextSize(1);
  #ifndef SCREEN_BROAD
    #define TRK_LEN 4
    byte o = rowCtr&0b100;
  #else
    #define TRK_LEN 8
    byte o = 0;
  #endif
  auto idx = 16*seqTime[pageCtr+o];
  for(byte j = o; j < TRK_LEN+o; j++){
    //display.setCursor((j>>2)*64,(j&3)*8);
    display.setCursor(xpos,(j-o)*8);
    display.setTextColor(j!=rowCtr,j==rowCtr);
    uint16_t seq = (seqData[idx+0+j*2]<<8)+seqData[idx+1+j*2];
    display.print(toPatt(seq));
  }
}

static uint16_t divVal = 256;
static uint16_t divCnt = divVal;
static uint16_t sampleCount=0;
static double sampleSpeed=0;

#ifndef ESP32
/******** Called every time TCNT2 = OCR2A ********/
ISR(TIMER1_COMPA_vect) { // Called when TCNT2 == OCR2A
  TCNT1 -= OCR1A;
  PORTB = 0-lastSamp;
  sampleCount++;
  getSamp();
  if(!--divCnt){
    divCnt += divVal;
    sei();
    performTick();
  }
}
void setupTimers(){
  freqDiv = 16;
  // Modified in slight bit for suitable need, from reference:
  // https://makezine.com/projects/advanced-arduino-sound-synthesis/#:~:text=Just%20connect%20a%20digital%20output,and%20ground%20without%20any%20amplification.
  /******** Set up timer2 to call ISR ********/
  TCCR1A = 0; 
  TCCR1B = 0; 
  TCCR1B |= 0b011; // 3-bit of prescaler
  TIMSK1 = (1 << OCIE1A); // Call ISR when TCNT2 = OCRA2
  OCR1A = freqDiv/2; // Set frequency of generated wave
  sei(); // Enable interrupts to generate waveform!
}
#else

#endif

void setup() {
  Serial.begin(9600);
  pinMode(27,OUTPUT);
  pinMode(13,OUTPUT);
  digitalWrite(0,LOW);
  digitalWrite(1,LOW);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.ssd1306_command(0xDA);
  #ifdef SCREEN_BROAD
  display.ssd1306_command(0x10);
  #else
  display.ssd1306_command(0x00);
  #endif

  display.display();
  display.clearDisplay();

  // put your setup code here, to run once:
  setupTimers();

  divVal = 256/freqDiv*32;
  divCnt = divVal;
  //DEPLOY_TASK_OF_FLICKER
}

uint32_t lastMillis=millis();

void fillzero(int32_t value){
  if(value<1000){
    Serial.print(' ');
    if(value<100){
      Serial.print(' ');
      if(value<10){
        Serial.print(' ');
      }
    }
  }
}

void performDispDebug(uint8_t xpos){
  display.setTextColor(1,0);
  display.setCursor(xpos,0);
  display.print(toHex(pageCtr,2));
  display.print(toHex(rowCtr,1));
  display.print(toHex(tickCtr,1));
  display.setCursor(xpos,8);
  display.print(toHex(pitch,2));
  display.print(toHex(orn,2));
  display.setCursor(xpos,16);
  display.print(toHex(ornPtr>>4,2));
  display.print(toHex(smpPtr>>4,2));
  display.setCursor(xpos,24);
  display.print(toHex(freq,4));
}

void performDispDebug2(uint8_t xpos){
  display.setTextColor(1,0);
  display.setCursor(xpos,0);
  display.print("PRT:");
  display.print(toHex(pageCtr,2));
  display.print(toHex(rowCtr,2));
  display.print(toHex(tickCtr,2));
  display.setCursor(xpos,8);
  display.print("NOP:");
  display.print(toHex(notekey,2));
  display.print(toHex(orn,2));
  display.print(toHex(pitch,2));
  display.setCursor(xpos,16);
  display.print("ptr:");
  display.print(toHex(ornPtr,3));
  display.print(toHex(smpPtr,3));
  display.setCursor(xpos,24);
  display.print("frq:");
  display.print(toHex(freq,4));
  display.print(toHex(freqLo,2));
}

static byte starsX[8],starsY[8],starsV[8],starsS[8];
static bool starsInitialized = false;

void performDispNyan(int8_t xpos, int8_t ypos, int8_t frame){
  for(byte y=0;y<2;y++)
    for(byte x=0;x<6;x++){
      display.drawBitmap(xpos+x*8,ypos+y*12,sprite_nyan+x*24+y*24*6+frame*24*6*2+12,8,12,1);
      display.drawBitmap(xpos+x*8,ypos+y*12,sprite_nyan+x*24+y*24*6+frame*24*6*2+ 0,8,12,2);
    }
}

void randomisestar(byte k){
  starsX[k] = random()&255;
  starsY[k] = random()&31;
  starsV[k] = random()&15;
  starsS[k] = (random()&31)<<3|k;
}

void loop() {
  if(!starsInitialized){
    for(byte k=0;k<8;k++)
      randomisestar(k);
    starsInitialized = true;
  }
  uint8_t delta = (millis() - lastMillis)*10/1000;
  lastMillis += delta*1000/10;
  for(byte k=0;k<8;k++){
      starsS[k] -= delta;
      starsX[k] -= (starsV[k]+1)*delta;
      if(starsS[k]>127) randomisestar(k);
  }
  
  display.fillRect(64,32,64,32,0);
  performDispNyan(64,36+3*sin((double)millis()/1000*2),millis()*8/1000%12);

  for(byte k=0;k<8;k++)
    display.drawBitmap((starsX[k]>>2)+64,(starsY[k]&31)+32,sprite_stars+((7-(starsS[k]>>2&7))*16),8,8,1);

  performDisp2(0);
  performDispDebug2(64);
  display.display();

  #ifdef DEBUG
    Serial.print("PRT: ");
    Serial.print(toHex(pageCtr,2));
    Serial.print(toHex(rowCtr,2));
    Serial.print(toHex(tickCtr,2));
    Serial.print(", PNO: ");
    Serial.print(toHex(pitch,2));
    Serial.print(toHex(notekey,2));
    Serial.print(toHex(orn,2));
    Serial.print(", Ptrs: ");
    Serial.print(toHex(ornPtr,3));
    Serial.print(toHex(smpPtr,3));
    Serial.println();
  #endif
   /* //monitor the samplerate   
  uint32_t currMillis = millis();
  if(currMillis - lastMillis >= 1000){
    double val = (double)(currMillis-lastMillis)/1000.;
    val = sampleCount / val; sampleCount = 0;
    if(sampleSpeed==0.) sampleSpeed = val; 
    else sampleSpeed += (val-sampleSpeed)/4;
    Serial.println(sampleSpeed);
    lastMillis = millis();
  }
  */
}