Prioritized multitasking by interrupts help

(I can't upload multiple images, hence i put this illustration to one single image instead)

I really want a consistent sampling in Task 3, while Task 2 overshadows the Task 1...

The ISR interval can be changed any time (for custom sample rate)

You wanted co-operative multitasking, but programmed for interrupt oriented multi-tasking. Why?

I think that your question is lacking details. Although real multitasking is mostly outside my area of knowledge, some more details might help others to help you

  1. Which board?
  2. Using a RTOS?
  3. Your code
  1. I'm using Arduino UNO board
  2. No. I can port my code for ESP32 however, and that already solves the problem. I'm doing this for the slow Arduino Uno, where the Task 3 ran consistently, while the Task 2 could be also ran consistently. Task 1 only have the control after all other tasks done. FreeRTOS is heavy though, and I can't get everything working due to large memory use there.
  3. My source is here: Bufferless - Wokwi Arduino and ESP32 Simulator

The example image I had illustrated above, the second illustration, is when i put the Task 2 inside ISR. And the Wokwi project is when I put the Task 2 inside the main loop(). The result is still not something I wanted. It supposed to be sounded like this however 1-bit Sampler Monotonic Music Player (XO-Chip Music) - Wokwi Arduino and ESP32 Simulator, where the Task 2 ran consistently, doesn't be slowed down by the Task 3.

With those long blocks of code blocking, I’d guess there are delay()s, or for/while() loops that are hogging the cpu in some way.

I’m sure what you want can be done, but without seeing your code, or attached devices, it’s pretty hard to tell.

Actually, i want that long block (Task 2) became interrupted, therefore that long block became paused at a time, the CPU does the Task 3, and the Task 3 is short task.

The Task 1 would be only continued when Task 2 and Task 3 already done. Task 3 retriggered again on the next interrupt

There is might be misunderstanding to my question. The Task 2 on the first illustration is actually a long task, being sliced by the interrupts. Task 3 is the important ones therefore should be executed first, and it only last in short time before Task 2 continued again. When Task 2 is done, the Task 1 continues until next interrupt

OP's code where it should be :wink:

// Written by Kouzerumatsukite (28-30 Ags 2022)
// The "Tsukite the Bananafox" song is composed by me
// Original: https://www.youtube.com/watch?v=YDCRszWIDwk
// the song in this project is the stripped version of it.
// And 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

// The playback consistency relies on the audiobuffer
// the buffer length is set to 2048 samples
// means it lags 4 frames behind before buffer runs out,
// This should be good enough for 15625hz samplerate


//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 <avr/pgmspace.h>
#include <Adafruit_SSD1306.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 byte 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 byte 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 byte 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 byte 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 PROGMEM byte seqData[]{
  // the sequence data, song name: Tsukite the Bananafox
  0x13,
  0x80,
  0x00,
  0x00,
  0x43,
  0x80,
  0x00,
  0x00,
  0x73,
  0x00,
  0x00,
  0x00,
  0x43,
  0x80,
  0x5F,
  0x10,
  0x57,
  0x88,
  0x00,
  0x00,
  0x57,
  0x88,
  0x00,
  0x00,
  0x57,
  0x8C,
  0x00,
  0x00,
  0x57,
  0x88,
  0x57,
  0x8C,
  0x00,
  0x00,
  0x57,
  0x8C,
  0x57,
  0x88,
  0x57,
  0xD0,
  0x57,
  0x8C,
  0x00,
  0x00,
  0x53,
  0x84,
  0x57,
  0x80,
  0x53,
  0x88,
  0x00,
  0x00,
  0x53,
  0x88,
  0x00,
  0x00,
  0x53,
  0x8C,
  0x00,
  0x00,
  0x53,
  0x88,
  0x53,
  0x8C,
  0x00,
  0x00,
  0x53,
  0x8C,
  0x53,
  0x88,
  0x43,
  0x90,
  0x53,
  0x8C,
  0x00,
  0x00,
  0x4B,
  0x84,
  0x43,
  0x80,
  0x43,
  0x88,
  0x4B,
  0x80,
  0x53,
  0x88,
  0x57,
  0x80,
  0x5F,
  0x8C,
  0x00,
  0x00,
  0x5F,
  0x88,
  0x5F,
  0x8C,
  0x00,
  0x00,
  0x5F,
  0x8C,
  0x5F,
  0x88,
  0x5F,
  0xD0,
  0x5F,
  0x8C,
  0x00,
  0x00,
  0x57,
  0x84,
  0x53,
  0x84,
  0x43,
  0x88,
  0x00,
  0x00,
  0x43,
  0x88,
  0x00,
  0x00,
  0x43,
  0x8C,
  0x43,
  0x90,
  0x43,
  0x88,
  0x43,
  0x8C,
  0x00,
  0x00,
  0x43,
  0x38,
  0x00,
  0x00,
  0x00,
  0x00,
  0x5F,
  0x8C,
  0x73,
  0xD0,
  0x5F,
  0x8C,
  0x5F,
  0x8C,
  0x43,
  0x88,
  0x4B,
  0x80,
  0x53,
  0x8C,
  0x57,
  0x80,
  0x5F,
  0x80,
  0x73,
  0xD8,
  0x57,
  0x8C,
  0x53,
  0x80,
  0x43,
  0x88,
  0x43,
  0x38,
  0x5F,
  0x8C,
  0x53,
  0x88,
  0x57,
  0x80,
  0x73,
  0xD8,
  0x53,
  0x8C,
  0x4B,
  0x80,
  0x43,
  0x88,
  0x43,
  0x38,
  0x53,
  0x8C,
  0x57,
  0x80,
  0x5F,
  0x80,
  0x73,
  0xD8,
  0x57,
  0x8C,
  0x53,
  0x80,
  0x43,
  0x88,
  0x43,
  0x38,
  0x5F,
  0x8C,
  0x67,
  0x88,
  0x57,
  0x80,
  0x73,
  0xD8,
  0x53,
  0x8C,
  0x4B,
  0x8C,
  0x43,
  0x88,
  0x2F,
  0x14,
  0x53,
  0x8C,
  0x57,
  0x80,
  0x5F,
  0x80,
  0x73,
  0xD8,
  0x57,
  0x8C,
  0x53,
  0x80,
  0x43,
  0x88,
  0x43,
  0x38,
  0x5F,
  0x8C,
  0x53,
  0x88,
  0x57,
  0x80,
  0x5F,
  0x88,
  0x57,
  0x8C,
  0x53,
  0x88,
  0x43,
  0x88,
  0x43,
  0x38,
  0x53,
  0x8C,
  0x57,
  0x80,
  0x5F,
  0x80,
  0x73,
  0xD8,
  0x57,
  0x8C,
  0x53,
  0x80,
  0x5F,
  0x88,
  0x73,
  0xD0,
  0x57,
  0x8C,
  0x53,
  0x88,
  0x5F,
  0x80,
  0x73,
  0xDC,
  0x67,
  0x8C,
  0x5F,
  0x8C,
  0x73,
  0x89,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x73,
  0x59,
  0x00,
  0x02,
  0x87,
  0x8D,
  0x37,
  0xC2,
  0x83,
  0x85,
  0x00,
  0x02,
  0x73,
  0x89,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x83,
  0x89,
  0x57,
  0xC2,
  0x87,
  0x85,
  0x87,
  0x3A,
  0x73,
  0x59,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x43,
  0xC2,
  0x7B,
  0x85,
  0x00,
  0x02,
  0x73,
  0x89,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x73,
  0x59,
  0x00,
  0x02,
  0x8F,
  0xCD,
  0xA3,
  0x1A,
  0xA3,
  0xC5,
  0x00,
  0x02,
  0x9F,
  0xC9,
  0x5F,
  0xC2,
  0x9F,
  0xC5,
  0x00,
  0x02,
  0xA3,
  0xCD,
  0x00,
  0x02,
  0x8F,
  0xC9,
  0x67,
  0xC2,
  0x8F,
  0xCD,
  0x8F,
  0x3E,
  0x87,
  0xC9,
  0x00,
  0x02,
  0x97,
  0xCD,
  0x00,
  0x02,
  0x8F,
  0xCD,
  0x73,
  0x1E,
  0x73,
  0x89,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x73,
  0x59,
  0x00,
  0x02,
  0x87,
  0x8D,
  0x37,
  0xC2,
  0x83,
  0x85,
  0x00,
  0x02,
  0x73,
  0x89,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x83,
  0x89,
  0x57,
  0xC2,
  0x87,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x00,
  0x02,
  0x87,
  0x8D,
  0x43,
  0xC2,
  0x83,
  0x85,
  0x00,
  0x02,
  0x73,
  0x89,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x73,
  0x59,
  0x00,
  0x02,
  0x8F,
  0x8D,
  0xA3,
  0x12,
  0xA3,
  0x85,
  0xA3,
  0x3A,
  0xAB,
  0x8D,
  0x00,
  0x02,
  0xAB,
  0x85,
  0xAB,
  0x3A,
  0xA3,
  0x8D,
  0x00,
  0x02,
  0x9F,
  0x8D,
  0x00,
  0x02,
  0x9F,
  0x85,
  0x9F,
  0x3A,
  0x9F,
  0x8D,
  0x8F,
  0x16,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x8F,
  0x8D,
  0x8F,
  0x3A,
  0xA3,
  0x4C,
  0x9F,
  0x80,
  0xA3,
  0x48,
  0x8F,
  0x4C,
  0x73,
  0x90,
  0x83,
  0x88,
  0x87,
  0x8C,
  0x87,
  0x38,
  0x00,
  0x00,
  0x83,
  0x8C,
  0x87,
  0xC8,
  0x83,
  0x88,
  0x87,
  0x8C,
  0x8F,
  0xC8,
  0x87,
  0x8C,
  0x83,
  0x8C,
  0x87,
  0x89,
  0x53,
  0xC2,
  0x83,
  0x85,
  0x73,
  0x92,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x73,
  0x89,
  0x53,
  0xC2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x73,
  0x89,
  0x73,
  0x3A,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x00,
  0x02,
  0x97,
  0x89,
  0x57,
  0xC2,
  0x8F,
  0x85,
  0x87,
  0xD2,
  0x8F,
  0x8D,
  0x8F,
  0x3A,
  0x8F,
  0x89,
  0x57,
  0xC2,
  0x87,
  0x85,
  0x87,
  0x82,
  0x83,
  0x89,
  0x83,
  0x3A,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x83,
  0x85,
  0x83,
  0x3A,
  0x87,
  0x89,
  0x5F,
  0xC2,
  0x83,
  0x85,
  0x73,
  0x92,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x8F,
  0x3A,
  0x9F,
  0x89,
  0xA3,
  0x82,
  0x9F,
  0x8D,
  0x00,
  0x02,
  0xA3,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x57,
  0xC2,
  0x87,
  0x85,
  0x87,
  0xD2,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x89,
  0x57,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x00,
  0x02,
  0x8F,
  0x8D,
  0x8F,
  0x3A,
  0x8F,
  0x8D,
  0x8F,
  0x3A,
  0x87,
  0x89,
  0x53,
  0xC2,
  0x83,
  0x85,
  0x73,
  0x92,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x83,
  0x89,
  0x53,
  0xC2,
  0x87,
  0x85,
  0x00,
  0x02,
  0x83,
  0x89,
  0x83,
  0x3A,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x83,
  0x85,
  0x83,
  0x3A,
  0x83,
  0x89,
  0x57,
  0xC2,
  0x7B,
  0x85,
  0x87,
  0xD2,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x7B,
  0x89,
  0x57,
  0xC2,
  0x83,
  0x85,
  0x00,
  0x02,
  0x7B,
  0x89,
  0x7B,
  0x3A,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x5F,
  0xC2,
  0x87,
  0x85,
  0x8F,
  0xD2,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x89,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x87,
  0x89,
  0x87,
  0x3A,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x85,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x5F,
  0xC2,
  0x87,
  0x85,
  0x8F,
  0xD2,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x89,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x97,
  0x89,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x73,
  0x49,
  0x53,
  0xC2,
  0x6F,
  0x45,
  0x73,
  0x92,
  0x73,
  0x4D,
  0x00,
  0x02,
  0x8F,
  0x49,
  0x53,
  0xC2,
  0x8F,
  0x45,
  0x8F,
  0x36,
  0x8F,
  0x49,
  0x8F,
  0x36,
  0x87,
  0x4D,
  0x53,
  0xC2,
  0x83,
  0x45,
  0x00,
  0x02,
  0x87,
  0x49,
  0x57,
  0xC2,
  0x8F,
  0x45,
  0x87,
  0xD2,
  0x8F,
  0x4D,
  0x8F,
  0x36,
  0x8F,
  0x49,
  0x57,
  0xC2,
  0xA3,
  0x45,
  0x00,
  0x02,
  0x9F,
  0x49,
  0x00,
  0x02,
  0xA3,
  0x4D,
  0x57,
  0xC2,
  0x9F,
  0x45,
  0x00,
  0x02,
  0xAB,
  0x49,
  0x5F,
  0xC2,
  0xAB,
  0x45,
  0x8F,
  0xD2,
  0xA3,
  0x4D,
  0xA3,
  0x36,
  0x9F,
  0x49,
  0x5F,
  0xC2,
  0x8F,
  0x45,
  0x00,
  0x02,
  0x8F,
  0x49,
  0x8F,
  0x36,
  0x87,
  0x4D,
  0x5F,
  0xC2,
  0x87,
  0x45,
  0x00,
  0x02,
  0x83,
  0x49,
  0x57,
  0xC2,
  0x83,
  0x45,
  0x87,
  0x42,
  0x87,
  0x0D,
  0x87,
  0x42,
  0x8F,
  0x49,
  0x57,
  0xC2,
  0x73,
  0x45,
  0x00,
  0x02,
  0x73,
  0x49,
  0x00,
  0x02,
  0x8F,
  0x4D,
  0x57,
  0xC2,
  0x8F,
  0x4D,
  0x8F,
  0x36,
  0x87,
  0x89,
  0x57,
  0xC2,
  0x83,
  0x85,
  0x87,
  0xD2,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x83,
  0x89,
  0x57,
  0xC2,
  0x87,
  0x85,
  0x00,
  0x02,
  0x83,
  0x89,
  0x00,
  0x02,
  0x87,
  0x8D,
  0x57,
  0xC2,
  0x83,
  0x85,
  0x00,
  0x02,
  0x83,
  0x89,
  0x53,
  0xC2,
  0x7B,
  0x85,
  0x83,
  0xE2,
  0x83,
  0x8D,
  0x00,
  0x02,
  0x7B,
  0x89,
  0x53,
  0xC2,
  0x83,
  0x85,
  0x00,
  0x02,
  0x7B,
  0x89,
  0x00,
  0x02,
  0x83,
  0x8D,
  0x53,
  0xC2,
  0x87,
  0x8D,
  0x00,
  0x02,
  0x8F,
  0x89,
  0x5F,
  0xC2,
  0x87,
  0x85,
  0x8F,
  0xD2,
  0x8F,
  0x8D,
  0x00,
  0x02,
  0x87,
  0x89,
  0x5F,
  0xC2,
  0x8F,
  0x85,
  0x00,
  0x02,
  0x97,
  0x89,
  0x00,
  0x02,
  0x8F,
  0x8D,
  0x5F,
  0xC2,
  0x87,
  0x85,
  0x00,
  0x02,
  0x73,
  0x8D,
  0x43,
  0xC2,
  0x73,
  0x85,
  0x73,
  0xD2,
  0x73,
  0x85,
  0x00,
  0x02,
  0x6F,
  0x8D,
  0x3F,
  0xC2,
  0x6F,
  0x85,
  0x00,
  0x02,
  0x6F,
  0x8D,
  0x00,
  0x02,
  0x6F,
  0x8D,
  0x5F,
  0x16,
  0x5F,
  0x8D,
  0x00,
  0x02,
};

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 = 67;  // page fin
uint8_t notekey = 0;    // current loaded pitch
uint8_t pitch = 0;      // currently playing pitch
uint16_t freq = 0;      // translated to freq

const byte 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,
  20,
  21,
  22,
  23,
  24,
  25,
  26,
  27,
  28,
  29,
  30,
  31,
  32,
  33,
  34,
  35,
  36,
  37,
  38,
  39,
  40,
  41,
  42,
  43,
  44,
  45,
  46,
  47,
  48,
  49,
  50,
  51,
  52,
  53,
  54,
  55,
  56,
  57,
  58,
  59,
  60,
  61,
  62,
  63,
  64,
  65,
  66,
};

const byte seqLoop = 9;  // The song loop point

const byte PROGMEM seqTicks[]{
  // Ticks speed
  //  _______ _______ _______ _______
  // |Speed A|Speed B|Speed C|Speed D|
  9,
  5,
  4,
  3,
};

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* 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] = 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;
}

void setupTimers()
{
  // 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 ********/
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2B |= 0b011;         // 3-bit of prescaler
  TIMSK2 = (1 << OCIE2A);  // Call ISR when TCNT2 = OCRA2
  OCR2A = 32;              // Set frequency of generated wave
  sei();                   // Enable interrupts to generate waveform!
}
/******** Lookup table ********/
static byte* bufferData = NULL;  // Storage for waveform
static uint16_t bufferPosA = 0;
static uint16_t bufferPosB = 0;
static uint16_t bufferNeed = 0;
static uint8_t buffPtr;

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

uint8_t getBufferByte(uint16_t addr)
{
  addr &= AUDIO_BUFFER_LENGTH;
  //addr = (addr&7)<<7 | (addr>>3&63);
  addr = addr & 63 | addr >> 6 << 7;
  return bufferData[addr];
};

void setBufferByte(uint16_t addr, uint8_t val)
{
  addr &= AUDIO_BUFFER_LENGTH;
  //addr = (addr&7)<<7 | (addr>>3&63);
  addr = addr & 63 | addr >> 6 << 7;
  bufferData[addr] = val;
};

static uint16_t sampPos = 0;
static bool lastSamp;
bool getSamp()
{
  sampPos += freq;
  lastSamp = pgm_read_byte(smpData + buffPtr + (sampPos >> 12 & 15)) >> 7 - (sampPos >> 9 & 7) & 1;
  return lastSamp;
};

static bool refreshDisp = false;
static byte refreshTick = 0;
void performTick()
{
  refreshTick--;
  buffPtr = pgm_read_byte(smpRef + smpPtr);  // update buffer
  uint8_t orn = pgm_read_byte(ornData + ornPtr);
  pitch = orn & 1 ? orn : notekey + (int8_t)orn;
  freq = (uint16_t)(128 * pow(2, (double)(pitch - 64.) / 48.) * OCR2A / 32);

  if (!digitalRead(2))
  {
    uint16_t l = 256 / OCR2A * 32;
    for (byte k = 0; k < l / 8; k++)
    {
      if (bufferPosA - bufferPosB + 8 > AUDIO_BUFFER_LENGTH * 8)
      {
        break;
      }
      byte val = getSamp();
      val += val + getSamp();
      val += val + getSamp();
      val += val + getSamp();
      val += val + getSamp();
      val += val + getSamp();
      val += val + getSamp();
      val += val + getSamp();
      setBufferByte(bufferPosA >> 3, val);
      bufferPosA += 8;
    }
  }

  if (!(++ornPtr & 15))
  {
    ornPtr -= 16;
    ornPtr += pgm_read_byte(ornData + ornPtr);
  }
  if (!(++smpPtr & 15))
  {
    smpPtr -= 16;
    smpPtr += pgm_read_byte(smpRef + smpPtr);
  }
  if (++tickCtr == tickFin)
  {
    tickCtr = 0;  // update row
    if (++rowCtr == rowFin)
    {
      rowCtr = 0;                                   // update page
      if (++pageCtr == pageFin) pageCtr = seqLoop;  // loop
    }
    auto idx = seqData + rowCtr * 2 + 16 * pgm_read_byte(seqTime + pageCtr);
    uint16_t seq = (pgm_read_byte(idx + 0) << 8) + pgm_read_byte(idx + 1);
    ;
    tickFin = pgm_read_byte(seqTicks + (seq & 3));  // extract tickspeed
    if (seq >> 8)
    {
      notekey = seq >> 8;  // extract pitch
      auto insidx = instrSet + (seq >> 2 & 0b111111) * 2;
      uint16_t ins = (pgm_read_byte(insidx) << 8) + pgm_read_byte(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;
  }
  // print buffer health
  // vvbvvvvvvvvvvvvvvvvvvvvv
  //Serial.println(bufferNeed);
  // ^^^^^^^^^^^^^^^^^^^^^^^^
  // print buffer health
}

void performDisp()
{
  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 = seqData + 16 * pgm_read_byte(seqTime + pageCtr + o);
  for (byte j = o; j < TRK_LEN + o; j++)
  {
    //display.setCursor((j>>2)*64,(j&3)*8);
    display.setCursor(0, (j - o) * 8);
    display.setTextColor(j != rowCtr, j == rowCtr);
    uint16_t seq = (pgm_read_byte(idx + 0 + j * 2) << 8) + pgm_read_byte(idx + 1 + j * 2);
    display.print(j);
    display.print(" ");
    display.print(toPatt(seq));
    display.print(seq & 3);
  }
  display.display();
}

#include <avr/interrupt.h>  // Use timer interrupt library

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

/******** Called every time TCNT2 = OCR2A ********/
ISR(TIMER2_COMPA_vect)
{  // Called when TCNT2 == OCR2A
  TCNT2 -= OCR2A;
  if (bufferPosA - bufferPosB)
  {
    PORTB = 0 - (getBufferByte(bufferPosB >> 3) >> 7 - (bufferPosB & 7) & 1);
    if ((bufferPosB & 0b111) == 7) setBufferByte(bufferPosB >> 3, 0);
    bufferPosB++;
  }
  if (!--divCnt)
  {
    divCnt += divVal;
    refreshTick++;
  }
  sampleCount++;
}

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

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  //display.ssd1306_command(0xDA);
  //display.ssd1306_command(0x10);
  display.display();
  display.clearDisplay();
  bufferData = display.getBuffer() + 64;

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

  divVal = 256 / OCR2A * 32;
  divCnt = divVal;
}

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 loop()
{
  uint16_t bufferLast = bufferPosA - bufferPosB;
  while (refreshTick) performTick();
  uint16_t bufferLeft = bufferPosA - bufferPosB;
#ifdef MONITOR
  fillzero(bufferLast);
  Serial.print(bufferLast);
  Serial.print(", ");
  fillzero(bufferLeft);
  Serial.print(bufferLeft);
  Serial.println();
#endif
  //if(refreshDisp) // update screen only when the row updates
  performDisp();
#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();
  }
  */
}

Honestly that code is intimating :sweat:
That's why I was presenting simpler question, which is straight to the point.

Anyhow though, all the white spaces, tab, and line arrangements are important for me, as it's for my aid of data manipulations of something. Therefore it's harder if the array elements became unrolled, or get the white spaces removed.

I did notice that some things changed due to the auto-format; I did not expect some of them to go from a e.g. few lines to 67 lines.

If you would have posted your code here, we would not have had that problem. I suggest that you post your code here.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.