login

Memory Layout
=============

unsigned char matrix[4096][16][8];
----------------------------------

        "track 0" (durations)         track 1               track F
       -----------------------    ---------------  ~~~  ---------------
0x000 [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
0x001 [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
0x002 [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
0x003 [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
0x004 [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
..... ~.. .. .. .. .. .. .. ..~  ~. . . . . . . .~ ~~~ ~. . . . . . . .~
0xFFE [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
0xFFF [?D DD DD DD DD DD DD DD]  [P P P P P P P P] ... [P P P P P P P P]
  |    -----------------------    ---------------  ~~~  ---------------
  |    01 23 45 67 89 AB CD EF    0 1 2 3 4 5 6 7       0 1 2 3 4 5 6 7
  |    \__________ __________/    \______ ______/       \______ ______/
  V               V                      V                     V
index          track #                voice #               voice #

? = one nibble
  always zero; reserved for future use

D = one nibble (highest bit always zero)
  0: EOT end-of-track     4:  1/8 eighth note
  1:  1  whole note       5: 1/16 sixteenth note
  2: 1/2 half note        6: 1/32 thirdy-second note
  3: 1/4 quarter note     7: 1/64 sixty-fourth note

P = one byte
  0x00: silence           0x80:\
  0x01: sustain           ....: > attack -> MIDI pitch = P & ~0x80 + 12
  0x02:\                  0xE3:/
  ....: > invalid         0xE4:\
  0x7F:/                  ....: > invalid
                          0xFF:/


char map[32][32];
-----------------

     |<----- 32 bytes ---->|
      ---------------------
0x00 [T K ... 0 V ... 0 ...]
0x01 [T K ... 0 V ... 0 ...]
0x02 [T K ... 0 V ... 0 ...]
.... ~. . ~~~ . . ~~~ . ~~~~
0x1E [T K ... 0 V ... 0 ...]
0x1F [T K ... 0 V ... 0 ...]
 |    ---------------------
 |    | \__ __/ \__ __/
 |    V    V       V
 |  type  key    value
 |
 +-> record #

type = one byte
  '@': track name
  '#': metadata
  NUL: empty

key = NUL-terminated string

value = NUL-terminated string

key and value may have any length as long as the following holds
  strlen(key) + strlen(value) + 3 <= 32


uint32_t stack[8192];
---------------------

(this buffer is private to edit.c)

 +-- index 0x0000                +-- index 0x1FFF
 |                               |
 v                               v
[?? ~~~ ?? Op Op Op Op Op ?? ~~~ ??]
           ^     ^     ^
           |     |     |
           |     |     +--> r: dead top of the stack (for redo)
           |     |
           |     +--> q: live top of the stack
           |
           +--> p: bottom of the stack

the stack is actually a circular buffer
  push() never fails
  when the buffer is full, new operations overwrite old ones
    this is the only situation where the bottom of the stack (p) moves

variables p, q and r in edit.c:
  p and q are indices for stack[]
  r is a counter for how many operations can be redone
    i.e. the distance between live and dead tops
    push() zeroes r, pop() increments r, unpop() decrements r

Op = 0xAAATIIIF
  A: args
  T: track
  I: index
  F: flags
flags = 0b0MCC
  M: action mark bit
  C: opcode
    0: DUR,  1: PIT,  2: INS,  3: DEL
args = 0xAAA
  if C == DUR then args = 0x00D
    D: delta
  if C == PIT then args = 0xVDD
    V: voice (u3; highest bit always zero)
    D: delta
  if C == INS then args = 0xNNN
    N: number of rows (u10; highest half-nibble always zero)
  if C == DEL then args = 0xNNN
    N: number of rows (u10; highest half-nibble always zero)