]> hydra-www.ietfng.org Git - acmetensortoys-chiptunes/commitdiff
Initial checkin of lft's excellent work
authorLinus Åkesson <lft@linusakesson.net>
Fri, 1 Jun 2007 11:58:00 +0000 (07:58 -0400)
committerNathaniel Wesley Filardo <nwf@pf.priv.oc.ietfng.org>
Thu, 18 Feb 2010 00:58:46 +0000 (19:58 -0500)
target/Makefile [new file with mode: 0644]
target/asm.s [new file with mode: 0644]
target/main.c [new file with mode: 0644]
tracker/Makefile [new file with mode: 0644]
tracker/README [new file with mode: 0644]
tracker/chip.c [new file with mode: 0644]
tracker/gui.c [new file with mode: 0644]
tracker/main.c [new file with mode: 0644]
tracker/packedformat [new file with mode: 0644]
tracker/stuff.h [new file with mode: 0644]
tracker/test2.song [new file with mode: 0644]

diff --git a/target/Makefile b/target/Makefile
new file mode 100644 (file)
index 0000000..3e3e80e
--- /dev/null
@@ -0,0 +1,7 @@
+all:           flash.hex
+
+flash.o:       main.c asm.s ../tracker/exported.s
+               avr-gcc -Xlinker -Tdata -Xlinker 0x800160 -Xlinker -M -O2 -B/usr/avr/lib -I/usr/local/avr/include -Wall -mmcu=avr4 -D__AVR_ATmega88__ -o $@ $^ >mapfile
+
+flash.hex:     flash.o
+               avr-ld --oformat ihex -o $@ $^
diff --git a/target/asm.s b/target/asm.s
new file mode 100644 (file)
index 0000000..3ac7ffd
--- /dev/null
@@ -0,0 +1,230 @@
+               .global readsongbyte
+               .global watchdogoff
+               .global __vector_14
+
+               .extern lastsample
+               .extern noiseseed
+               .extern osc
+               .extern songdata
+
+readsongbyte:
+                ldi     r30, lo8(songdata)
+                add     r30, r24
+                ldi     r31, hi8(songdata)
+                adc     r31, r25
+                lpm
+                mov     r24, r0
+                mov     r25, r1
+                ret
+
+watchdogoff:
+               wdr
+               in      r24, 0x34               ; mcusr
+               andi    r24, 0xf7
+               out     0x34, r24
+               lds     r24, 0x60               ; wdtcsr
+               ori     r24, 0x18
+               sts     0x60, r24
+               ldi     r24, 0x00
+               sts     0x60, r24
+               ret
+
+__vector_14:
+               ; Entire interrupt routine, worst case: 308 clocks.
+
+               ; ---------------------------------------------
+               ; Save processor state.
+               ; 27 clocks.
+
+               push    r1                      ;                               2
+               push    r0                      ;                               2
+               in      r0, 0x3f                ;                               1
+               push    r0                      ;                               2
+               push    r18                     ;                               2
+               push    r19                     ;                               2
+               push    r20                     ;                               2
+               push    r21                     ;                               2
+               push    r22                     ;                               2
+               push    r23                     ;                               2
+               push    r24                     ;                               2
+               push    r25                     ;                               2
+               push    r30                     ;                               2
+               push    r31                     ;                               2
+
+               ; ---------------------------------------------
+               ; Write previously generated sample to PORTD.
+               ; 3 clocks.
+
+               lds     r24, lastsample         ;                               2
+               out     0x0b, r24               ;                               1
+
+               ; ---------------------------------------------
+               ; Run the noise shift register.
+               ; 31 clocks.
+
+               eor     r22, r22                ;                               1
+               ldi     r24, 1                  ;                               1
+               lds     r18, noiseseed+0        ;                               2
+               lds     r19, noiseseed+1        ;                               2
+               lds     r20, noiseseed+2        ;                               2
+               lds     r21, noiseseed+3        ;                               2
+               sbrc    r21, 7                  ; 0x80000000                    1/2 \__ 2
+               eor     r22, r24                ;                               1   /
+               sbrc    r21, 0                  ; 0x01000000                    1/2 \__ 2
+               eor     r22, r24                ;                               1   /
+               sbrc    r19, 1                  ; 0x00000200                    1/2 \__ 2
+               eor     r22, r24                ;                               1   /
+               sbrc    r18, 6                  ; 0x00000040                    1/2 \__ 2
+               eor     r22, r24                ;                               1   /
+               add     r18, r18                ;                               1
+               adc     r19, r19                ;                               1
+               adc     r20, r20                ;                               1
+               adc     r21, r21                ;                               1
+               or      r18, r22                ;                               1
+               sts     noiseseed+0, r18        ;                               2
+               sts     noiseseed+1, r19        ;                               2
+               sts     noiseseed+2, r20        ;                               2
+               sts     noiseseed+3, r21        ;                               2
+
+               ; ---------------------------------------------
+               ; Request calls to playroutine() at the
+               ; appropriate rate.
+               ; 13 or 8 clocks.
+
+               lds     r24, callbackwait       ;                               2
+               and     r24, r24                ;                               1
+               brne    nocallb                 ;                               1/2
+
+               lds     r24, timetoplay         ;                               2
+               subi    r24, 0xff               ;                               1
+               sts     timetoplay, r24         ;                               2
+               ldi     r24, 180                ;                               1
+
+nocallb:       subi    r24, 0x01               ;                               1
+               sts     callbackwait, r24       ;                               2
+
+               ; ---------------------------------------------
+               ; Loop through the channels
+               ; Worst case for entire loop: 5+(4+18+27)*4-1 = 200 clocks.
+
+               ; Setup: 5 clocks.
+
+               eor     r22, r22                ; acc = 0                       1
+               eor     r23, r23                ;                               1
+
+               ldi     r30, lo8(osc)           ; Z = &osc[0]                   1
+               ldi     r31, hi8(osc)           ;                               1
+
+               ldi     r21, 3                  ; i = 3                         1
+
+chloop:
+               ; Loop prologue: 4 clocks.
+
+               ldd     r24, Z+2                ; phase                         2
+               ldd     r25, Z+3                ;                               2
+               ldd     r18, Z+6                ; waveform                      2
+
+               ; WF_TRI: 12 or 10 clocks.
+               ; WF_SAW: 11 clocks.
+               ; WF_PUL: 16 or 18 clocks.
+               ; WF_NOI: 12 clocks.
+
+               cpi     r18, 0x00               ; WF_TRI                        1
+               breq    wftri                   ;                               1/2
+               cpi     r18, 0x01               ; WF_SAW                        1
+               breq    wfsaw                   ;                               1/2
+               cpi     r18, 0x02               ; WF_PUL                        1
+               breq    wfpul                   ;                               1/2
+
+wfnoi:
+               lds     r20, noiseseed          ;                               2
+               andi    r20, 63                 ;                               1
+               subi    r20, 32                 ;                               1
+               rjmp    chcont                  ;                               2
+
+wfpul:
+               ldi     r20, -32                ;                               1
+               ldd     r18, Z+4                ; duty                          2
+               ldd     r19, Z+5                ;                               2
+               cp      r18, r24                ;                               1
+               cpc     r19, r25                ;                               1
+               brcc    chcont                  ;                               1/2 \
+               ldi     r20, 31                 ;                               1   |-- 4/2
+               rjmp    chcont                  ;                               2   /
+
+wfsaw:
+               mov     r20, r25                ; high byte of phase            1
+               lsr     r20                     ;                               1
+               lsr     r20                     ;                               1
+               subi    r20, 32                 ;                               1
+               rjmp    chcont                  ;                               2
+
+wftri:
+               mov     r20, r25                ; high byte of phase            1
+               sbrc    r20, 7                  ; check high bit                1/2 \__ 3/2
+               rjmp    tri_down                ;                               2   /
+
+               lsr     r20                     ;                               1
+               subi    r20, 32                 ;                               1
+               rjmp    chcont                  ;                               2
+tri_down:
+               andi    r20, 0x7f               ;                               1
+               lsr     r20                     ;                               1
+               ldi     r18, 31                 ;                               1
+               sub     r18, r20                ;                               1
+               mov     r20, r18                ;                               1
+
+chcont:
+               ; Loop epilogue: 26 or 27 clocks (26 last time)
+
+               ; value is in r20
+
+               ldd     r18, Z+7                ; volume                        2
+               lsr     r18                     ;                               1
+               andi    r18, 0x7f               ;                               1
+               muls    r18, r20                ; r1:r0 = value * volume        2
+               add     r22, r0                 ; add to acc                    1
+               adc     r23, r1                 ;                               1
+               add     r22, r0                 ; add to acc                    1
+               adc     r23, r1                 ;                               1
+
+               ld      r18, Z                  ; freq                          2
+               ldd     r19, Z+1                ;                               2
+               add     r24, r18                ; phase += freq                 1
+               adc     r25, r19                ;                               1
+
+               std     Z+2, r24                ; write new phase               2
+               std     Z+3, r25                ;                               2
+
+               subi    r21, 0x01               ; i--                           1
+               adiw    r30, 0x08               ; Z++                           2
+               sbrs    r21, 7                  ; skip if i < 0                 1/2
+               rjmp    chloop                  ;                               2
+
+               ; ---------------------------------------------
+               ; Adjust acc and write to lastsample
+               ; 3 clocks.
+
+               ; r23 is acc >> 8
+               subi    r23, 0x80               ; add 128                       1
+               sts     lastsample, r23         ;                               2
+
+               ; ---------------------------------------------
+               ; Restore processor state.
+               ; 31 clocks.
+
+               pop     r31                     ;                               2
+               pop     r30                     ;                               2
+               pop     r25                     ;                               2
+               pop     r24                     ;                               2
+               pop     r23                     ;                               2
+               pop     r22                     ;                               2
+               pop     r21                     ;                               2
+               pop     r20                     ;                               2
+               pop     r19                     ;                               2
+               pop     r18                     ;                               2
+               pop     r0                      ;                               2
+               out     0x3f, r0                ;                               1
+               pop     r0                      ;                               2
+               pop     r1                      ;                               2
+               reti                            ;                               4
diff --git a/target/main.c b/target/main.c
new file mode 100644 (file)
index 0000000..fac68d6
--- /dev/null
@@ -0,0 +1,474 @@
+#include <avr/io.h>
+#include <avr/signal.h>
+#include <avr/interrupt.h>
+
+#define TRACKLEN 32
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef char s8;
+typedef short s16;
+typedef unsigned long u32;
+
+volatile u8 callbackwait;
+volatile u8 lastsample;
+
+volatile u8 timetoplay;
+
+volatile u8 test;
+volatile u8 testwait;
+
+u8 trackwait;
+u8 trackpos;
+u8 playsong;
+u8 songpos;
+
+u32 noiseseed = 1;
+
+u8 light[2];
+
+#include "../tracker/exported.h"
+
+/*const u16 freqtable[] = {
+       0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165, 0x017a, 0x0191, 0x01a9,
+       0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259, 0x027d, 0x02a3, 0x02cb,
+       0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3, 0x042f, 0x046f, 0x04b2,
+       0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5, 0x070a, 0x0775, 0x07e6,
+       0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c, 0x0bd6, 0x0c8b, 0x0d4a,
+       0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb, 0x13e9, 0x1518, 0x1659,
+       0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b, 0x217c, 0x237a, 0x2596,
+       0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528, 0x3851, 0x3bab, 0x3f37,
+       0x42f9, 0x46f5, 0x4b2d, 0x4fa6, 0x5462, 0x5967, 0x5eb7, 0x6459, 0x6a51,
+       0x70a3, 0x7756, 0x7e6f
+};*/
+
+const u16 freqtable[] = {
+       0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8, 0x00d4,
+       0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165,
+       0x017a, 0x0191, 0x01a9, 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259,
+       0x027d, 0x02a3, 0x02cb, 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3,
+       0x042f, 0x046f, 0x04b2, 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5,
+       0x070a, 0x0775, 0x07e6, 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c,
+       0x0bd6, 0x0c8b, 0x0d4a, 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb,
+       0x13e9, 0x1518, 0x1659, 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b,
+       0x217c, 0x237a, 0x2596, 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528,
+       0x3851, 0x3bab, 0x3f37
+};
+
+const s8 sinetable[] = {
+       0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
+       127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
+       0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
+       -125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
+       -71, -60, -49, -37, -25, -12
+};
+
+const u8 validcmds[] = "0dfijlmtvw~+=";
+
+enum {
+       WF_TRI,
+       WF_SAW,
+       WF_PUL,
+       WF_NOI
+};
+
+volatile struct oscillator {
+       u16     freq;
+       u16     phase;
+       u16     duty;
+       u8      waveform;
+       u8      volume; // 0-255
+} osc[4];
+
+struct trackline {
+       u8      note;
+       u8      instr;
+       u8      cmd[2];
+       u8      param[2];
+       };
+
+struct track {
+       struct trackline        line[TRACKLEN];
+};
+
+struct unpacker {
+       u16     nextbyte;
+       u8      buffer;
+       u8      bits;
+};
+
+struct channel {
+       struct unpacker         trackup;
+       u8                      tnum;
+       s8                      transp;
+       u8                      tnote;
+       u8                      lastinstr;
+       u8                      inum;
+       u16                     iptr;
+       u8                      iwait;
+       u8                      inote;
+       s8                      bendd;
+       s16                     bend;
+       s8                      volumed;
+       s16                     dutyd;
+       u8                      vdepth;
+       u8                      vrate;
+       u8                      vpos;
+       s16                     inertia;
+       u16                     slur;
+} channel[4];
+
+u16 resources[16 + MAXTRACK];
+
+struct unpacker songup;
+
+u8 readsongbyte(u16 offset);
+void watchdogoff();
+
+void initup(struct unpacker *up, u16 offset) {
+       up->nextbyte = offset;
+       up->bits = 0;
+}
+
+u8 readbit(struct unpacker *up) {
+       u8 val;
+
+       if(!up->bits) {
+               up->buffer = readsongbyte(up->nextbyte++);
+               up->bits = 8;
+       }
+
+       up->bits--;
+       val = up->buffer & 1;
+       up->buffer >>= 1;
+
+       return val;
+}
+
+u16 readchunk(struct unpacker *up, u8 n) {
+       u16 val = 0;
+       u8 i;
+
+       for(i = 0; i < n; i++) {
+               if(readbit(up)) {
+                       val |= (1 << i);
+               }
+       }
+
+       return val;
+}
+
+void readinstr(u8 num, u8 pos, u8 *dest) {
+       dest[0] = readsongbyte(resources[num] + 2 * pos + 0);
+       dest[1] = readsongbyte(resources[num] + 2 * pos + 1);
+}
+
+void runcmd(u8 ch, u8 cmd, u8 param) {
+       switch(validcmds[cmd]) {
+               case '0':
+                       channel[ch].inum = 0;
+                       break;
+               case 'd':
+                       osc[ch].duty = param << 8;
+                       break;
+               case 'f':
+                       channel[ch].volumed = param;
+                       break;
+               case 'i':
+                       channel[ch].inertia = param << 1;
+                       break;
+               case 'j':
+                       channel[ch].iptr = param;
+                       break;
+               case 'l':
+                       channel[ch].bendd = param;
+                       break;
+               case 'm':
+                       channel[ch].dutyd = param << 6;
+                       break;
+               case 't':
+                       channel[ch].iwait = param;
+                       break;
+               case 'v':
+                       osc[ch].volume = param;
+                       break;
+               case 'w':
+                       osc[ch].waveform = param;
+                       break;
+               case '+':
+                       channel[ch].inote = param + channel[ch].tnote - 12 * 4;
+                       break;
+               case '=':
+                       channel[ch].inote = param;
+                       break;
+               case '~':
+                       if(channel[ch].vdepth != (param >> 4)) {
+                               channel[ch].vpos = 0;
+                       }
+                       channel[ch].vdepth = param >> 4;
+                       channel[ch].vrate = param & 15;
+                       break;
+       }
+}
+
+void playroutine() {                   // called at 50 Hz
+       u8 ch;
+       u8 lights;
+
+       if(playsong) {
+               if(trackwait) {
+                       trackwait--;
+               } else {
+                       trackwait = 4;
+
+                       if(!trackpos) {
+                               if(playsong) {
+                                       if(songpos >= SONGLEN) {
+                                               playsong = 0;
+                                       } else {
+                                               for(ch = 0; ch < 4; ch++) {
+                                                       u8 gottransp;
+                                                       u8 transp;
+
+                                                       gottransp = readchunk(&songup, 1);
+                                                       channel[ch].tnum = readchunk(&songup, 6);
+                                                       if(gottransp) {
+                                                               transp = readchunk(&songup, 4);
+                                                               if(transp & 0x8) transp |= 0xf0;
+                                                       } else {
+                                                               transp = 0;
+                                                       }
+                                                       channel[ch].transp = (s8) transp;
+                                                       if(channel[ch].tnum) {
+                                                               initup(&channel[ch].trackup, resources[16 + channel[ch].tnum - 1]);
+                                                       }
+                                               }
+                                               songpos++;
+                                       }
+                               }
+                       }
+
+                       if(playsong) {
+                               for(ch = 0; ch < 4; ch++) {
+                                       if(channel[ch].tnum) {
+                                               u8 note, instr, cmd, param;
+                                               u8 fields;
+
+                                               fields = readchunk(&channel[ch].trackup, 3);
+                                               note = 0;
+                                               instr = 0;
+                                               cmd = 0;
+                                               param = 0;
+                                               if(fields & 1) note = readchunk(&channel[ch].trackup, 7);
+                                               if(fields & 2) instr = readchunk(&channel[ch].trackup, 4);
+                                               if(fields & 4) {
+                                                       cmd = readchunk(&channel[ch].trackup, 4);
+                                                       param = readchunk(&channel[ch].trackup, 8);
+                                               }
+                                               if(note) {
+                                                       channel[ch].tnote = note + channel[ch].transp;
+                                                       if(!instr) instr = channel[ch].lastinstr;
+                                               }
+                                               if(instr) {
+                                                       if(instr == 2) light[1] = 5;
+                                                       if(instr == 1) {
+                                                               light[0] = 5;
+                                                               if(channel[ch].tnum == 4) {
+                                                                       light[0] = light[1] = 3;
+                                                               }
+                                                       }
+                                                       if(instr == 7) {
+                                                               light[0] = light[1] = 30;
+                                                       }
+                                                       channel[ch].lastinstr = instr;
+                                                       channel[ch].inum = instr;
+                                                       channel[ch].iptr = 0;
+                                                       channel[ch].iwait = 0;
+                                                       channel[ch].bend = 0;
+                                                       channel[ch].bendd = 0;
+                                                       channel[ch].volumed = 0;
+                                                       channel[ch].dutyd = 0;
+                                                       channel[ch].vdepth = 0;
+                                               }
+                                               if(cmd) runcmd(ch, cmd, param);
+                                       }
+                               }
+
+                               trackpos++;
+                               trackpos &= 31;
+                       }
+               }
+       }
+
+       for(ch = 0; ch < 4; ch++) {
+               s16 vol;
+               u16 duty;
+               u16 slur;
+
+               while(channel[ch].inum && !channel[ch].iwait) {
+                       u8 il[2];
+
+                       readinstr(channel[ch].inum, channel[ch].iptr, il);
+                       channel[ch].iptr++;
+
+                       runcmd(ch, il[0], il[1]);
+               }
+               if(channel[ch].iwait) channel[ch].iwait--;
+
+               if(channel[ch].inertia) {
+                       s16 diff;
+
+                       slur = channel[ch].slur;
+                       diff = freqtable[channel[ch].inote] - slur;
+                       //diff >>= channel[ch].inertia;
+                       if(diff > 0) {
+                               if(diff > channel[ch].inertia) diff = channel[ch].inertia;
+                       } else if(diff < 0) {
+                               if(diff < -channel[ch].inertia) diff = -channel[ch].inertia;
+                       }
+                       slur += diff;
+                       channel[ch].slur = slur;
+               } else {
+                       slur = freqtable[channel[ch].inote];
+               }
+               osc[ch].freq =
+                       slur +
+                       channel[ch].bend +
+                       ((channel[ch].vdepth * sinetable[channel[ch].vpos & 63]) >> 2);
+               channel[ch].bend += channel[ch].bendd;
+               vol = osc[ch].volume + channel[ch].volumed;
+               if(vol < 0) vol = 0;
+               if(vol > 255) vol = 255;
+               osc[ch].volume = vol;
+
+               duty = osc[ch].duty + channel[ch].dutyd;
+               if(duty > 0xe000) duty = 0x2000;
+               if(duty < 0x2000) duty = 0xe000;
+               osc[ch].duty = duty;
+
+               channel[ch].vpos += channel[ch].vrate;
+       }
+
+       lights = 0;
+       if(light[0]) {
+               light[0]--;
+               lights |= 0x02;
+       }
+       if(light[1]) {
+               light[1]--;
+               lights |= 0x10;
+       }
+       PORTC = lights;
+}
+
+void initresources() {
+       u8 i;
+       struct unpacker up;
+
+       initup(&up, 0);
+       for(i = 0; i < 16 + MAXTRACK; i++) {
+               resources[i] = readchunk(&up, 13);
+       }
+
+       initup(&songup, resources[0]);
+}
+
+int main() {
+       asm("cli");
+       watchdogoff();
+       CLKPR = 0x80;
+       CLKPR = 0x80;
+
+       DDRC = 0x12;
+       DDRD = 0xff;
+
+       PORTC = 0;
+
+       timetoplay = 0;
+       trackwait = 0;
+       trackpos = 0;
+       playsong = 1;
+       songpos = 0;
+
+       osc[0].volume = 0;
+       channel[0].inum = 0;
+       osc[1].volume = 0;
+       channel[1].inum = 0;
+       osc[2].volume = 0;
+       channel[2].inum = 0;
+       osc[3].volume = 0;
+       channel[3].inum = 0;
+
+       initresources();
+
+       TCCR0A = 0x02;
+       TCCR0B = 0x02;  // clkIO/8, so 1/8 MHz
+       OCR0A = 62;//125; // 8 KHz
+
+       TIMSK0 = 0x02;
+
+       asm("sei");
+       for(;;) {
+               while(!timetoplay);
+
+               timetoplay--;
+               playroutine();
+       }
+}
+
+/*
+INTERRUPT(_VECTOR(14))         // called at 8 KHz
+{
+       u8 i;
+       s16 acc;
+       u8 newbit;
+
+       PORTD = lastsample;
+
+       newbit = 0;
+       if(noiseseed & 0x80000000L) newbit ^= 1;
+       if(noiseseed & 0x01000000L) newbit ^= 1;
+       if(noiseseed & 0x00000040L) newbit ^= 1;
+       if(noiseseed & 0x00000200L) newbit ^= 1;
+       noiseseed = (noiseseed << 1) | newbit;
+
+       if(callbackwait) {
+               callbackwait--;
+       } else {
+               timetoplay++;
+               callbackwait = 90 - 1;
+       }
+
+       acc = 0;
+       for(i = 0; i < 4; i++) {
+               s8 value; // [-32,31]
+
+               switch(osc[i].waveform) {
+                       case WF_TRI:
+                               if(osc[i].phase < 0x8000) {
+                                       value = -32 + (osc[i].phase >> 9);
+                               } else {
+                                       value = 31 - ((osc[i].phase - 0x8000) >> 9);
+                               }
+                               break;
+                       case WF_SAW:
+                               value = -32 + (osc[i].phase >> 10);
+                               break;
+                       case WF_PUL:
+                               value = (osc[i].phase > osc[i].duty)? -32 : 31;
+                               break;
+                       case WF_NOI:
+                               value = (noiseseed & 63) - 32;
+                               break;
+                       default:
+                               value = 0;
+                               break;
+               }
+               osc[i].phase += osc[i].freq;
+
+               acc += value * osc[i].volume; // rhs = [-8160,7905]
+       }
+       // acc [-32640,31620]
+       lastsample = 128 + (acc >> 8);  // [1,251]
+}
+*/
diff --git a/tracker/Makefile b/tracker/Makefile
new file mode 100644 (file)
index 0000000..c091378
--- /dev/null
@@ -0,0 +1,10 @@
+LDFLAGS=-lSDL -lncurses
+CFLAGS=-Wall
+CC=gcc
+
+all:           tracker
+
+tracker:       main.o chip.o gui.o
+               gcc -o $@ $^ ${LDFLAGS}
+
+%.o:           %.c stuff.h Makefile
diff --git a/tracker/README b/tracker/README
new file mode 100644 (file)
index 0000000..28dc575
--- /dev/null
@@ -0,0 +1,62 @@
+Hi!
+
+This is the tracker I used in the hardware chiptune project
+(http://www.linusakesson.net/hardware/chiptune.php). It was never intended to
+be used by anyone other than me, so it's not exactly user friendly.
+
+This is a quick documentation attempt.
+
+You have to give the tracker a file name when you're starting it. So type
+"./tracker test2.song" to start working on the existing song, or type e.g.
+"./tracker my_song.song" to start from scratch. Although the GUI hints that you
+can later press ^F to change the file name, this was never implemented.
+
+Once you've started the tracker, you'll see that the screen is divided into
+three sections: song, track and instrument. Use TAB to move between these
+sections. Alternatively, if you're in the song section and the cursor is on a
+track identifier, you can press ` (backquote) to start editing this track.
+
+Use { and } to change the current track, and [ and ] to change the current
+instrument. Use enter to start playing the current track (in the track section)
+or the song (in the song section). Use space to stop playing or to enter edit
+mode.
+
+Use < and > to change the current octave. The main part of the keyboard is used
+to enter notes. The keyboard layout is adapted for a US qwerty keymap. You can
+edit gui.c to change this to fit a Dvorak keymap instead.
+
+Press ^E (control-E) to exit without saving. Press ^W ("write") to save. Press
+# to optimize the song (remove unused tracks, move tracks together) and % to
+export the song into a packed format. (% will always export to two files called
+"exported.s" and "exported.h" in the current working directory).
+
+In the song and instrument editors, use capital A, I and D to add, insert and
+delete lines. In the track and instrument editors, use capital C and V for copy
+and paste.
+
+A line in the instrument editor is either a command, a relative note or an
+absolute note. Relative notes are indicated by + in the command column,
+absolute notes by =. Commands in the instrument editor are the same as commands
+in the track editor.
+
+The available commands are:
+
+       dxx Set duty cycle (pulse width) to xx.
+       fxx Set volume fade speed to xx. So, fff is a slow fadeout, f01 is a slow fadein.
+       ixx Set channel inertia. A high inertia causes automatic slides between notes. Default 0.
+       jxx Jump to instrument line xx. Used to create arpeggio loops.
+               Warning: The loop must contain a delay element (t command), otherwise you'll crash the software.
+       lxx Set sLide. So, lff is a slow slide down, l01 is a slow slide up.
+       mxx Set pulse width modulation rate to xx.
+       txx Wait xx time units.
+       vxx Set channel volume to xx.
+       wxx Set waveform. 00 = triangle, 01 = saw, 02 = pulse, 03 = noise.
+       ~xy Set vibrato. x = depth, y = rate.
+
+Investigate test2.song, and play around, and you'll probably get the hang of
+things! Remember that the packed format only supports one command per track
+line (see homepage).
+
+Good luck!
+
+Linus (lft^kryo)
diff --git a/tracker/chip.c b/tracker/chip.c
new file mode 100644 (file)
index 0000000..86ddf39
--- /dev/null
@@ -0,0 +1,348 @@
+#include "stuff.h"
+
+volatile u8 callbackwait;
+
+volatile u8 test;
+volatile u8 testwait;
+
+u8 trackwait;
+u8 trackpos;
+u8 songpos;
+
+u8 playsong;
+u8 playtrack;
+
+/*const u16 freqtable[] = {
+       0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165, 0x017a, 0x0191, 0x01a9,
+       0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259, 0x027d, 0x02a3, 0x02cb,
+       0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3, 0x042f, 0x046f, 0x04b2,
+       0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5, 0x070a, 0x0775, 0x07e6,
+       0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c, 0x0bd6, 0x0c8b, 0x0d4a,
+       0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb, 0x13e9, 0x1518, 0x1659,
+       0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b, 0x217c, 0x237a, 0x2596,
+       0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528, 0x3851, 0x3bab, 0x3f37,
+       0x42f9, 0x46f5, 0x4b2d, 0x4fa6, 0x5462, 0x5967, 0x5eb7, 0x6459, 0x6a51,
+       0x70a3, 0x7756, 0x7e6f
+};*/
+
+const u16 freqtable[] = {
+       0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8, 0x00d4,
+       0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165,
+       0x017a, 0x0191, 0x01a9, 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259,
+       0x027d, 0x02a3, 0x02cb, 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3,
+       0x042f, 0x046f, 0x04b2, 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5,
+       0x070a, 0x0775, 0x07e6, 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c,
+       0x0bd6, 0x0c8b, 0x0d4a, 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb,
+       0x13e9, 0x1518, 0x1659, 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b,
+       0x217c, 0x237a, 0x2596, 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528,
+       0x3851, 0x3bab, 0x3f37
+};
+
+const s8 sinetable[] = {
+       0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
+       127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
+       0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
+       -125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
+       -71, -60, -49, -37, -25, -12
+};
+
+volatile struct oscillator {
+       u16     freq;
+       u16     phase;
+       u16     duty;
+       u8      waveform;
+       u8      volume; // 0-255
+} osc[4];
+
+struct channel {
+       u8      tnum;
+       s8      transp;
+       u8      tnote;
+       u8      lastinstr;
+       u8      inum;
+       u8      iptr;
+       u8      iwait;
+       u8      inote;
+       s8      bendd;
+       s16     bend;
+       s8      volumed;
+       s16     dutyd;
+       u8      vdepth;
+       u8      vrate;
+       u8      vpos;
+       s16     inertia;
+       u16     slur;
+} channel[4];
+
+void silence() {
+       u8 i;
+
+       for(i = 0; i < 4; i++) {
+               osc[i].volume = 0;
+       }
+       playsong = 0;
+       playtrack = 0;
+}
+
+void runcmd(u8 ch, u8 cmd, u8 param) {
+       switch(cmd) {
+               case 0:
+                       channel[ch].inum = 0;
+                       break;
+               case 'd':
+                       osc[ch].duty = param << 8;
+                       break;
+               case 'f':
+                       channel[ch].volumed = param;
+                       break;
+               case 'i':
+                       channel[ch].inertia = param << 1;
+                       break;
+               case 'j':
+                       channel[ch].iptr = param;
+                       break;
+               case 'l':
+                       channel[ch].bendd = param;
+                       break;
+               case 'm':
+                       channel[ch].dutyd = param << 6;
+                       break;
+               case 't':
+                       channel[ch].iwait = param;
+                       break;
+               case 'v':
+                       osc[ch].volume = param;
+                       break;
+               case 'w':
+                       osc[ch].waveform = param;
+                       break;
+               case '+':
+                       channel[ch].inote = param + channel[ch].tnote - 12 * 4;
+                       break;
+               case '=':
+                       channel[ch].inote = param;
+                       break;
+               case '~':
+                       if(channel[ch].vdepth != (param >> 4)) {
+                               channel[ch].vpos = 0;
+                       }
+                       channel[ch].vdepth = param >> 4;
+                       channel[ch].vrate = param & 15;
+                       break;
+       }
+}
+
+void iedplonk(int note, int instr) {
+       channel[0].tnote = note;
+       channel[0].inum = instr;
+       channel[0].iptr = 0;
+       channel[0].iwait = 0;
+       channel[0].bend = 0;
+       channel[0].bendd = 0;
+       channel[0].volumed = 0;
+       channel[0].dutyd = 0;
+       channel[0].vdepth = 0;
+}
+
+void startplaytrack(int t) {
+       channel[0].tnum = t;
+       channel[1].tnum = 0;
+       channel[2].tnum = 0;
+       channel[3].tnum = 0;
+       trackpos = 0;
+       trackwait = 0;
+       playtrack = 1;
+       playsong = 0;
+}
+
+void startplaysong(int p) {
+       songpos = p;
+       trackpos = 0;
+       trackwait = 0;
+       playtrack = 0;
+       playsong = 1;
+}
+
+void playroutine() {                   // called at 50 Hz
+       u8 ch;
+
+       if(playtrack || playsong) {
+               if(trackwait) {
+                       trackwait--;
+               } else {
+                       trackwait = 4;
+
+                       if(!trackpos) {
+                               if(playsong) {
+                                       if(songpos >= songlen) {
+                                               playsong = 0;
+                                       } else {
+                                               for(ch = 0; ch < 4; ch++) {
+                                                       u8 tmp[2];
+
+                                                       readsong(songpos, ch, tmp);
+                                                       channel[ch].tnum = tmp[0];
+                                                       channel[ch].transp = tmp[1];
+                                               }
+                                               songpos++;
+                                       }
+                               }
+                       }
+
+                       if(playtrack || playsong) {
+                               for(ch = 0; ch < 4; ch++) {
+                                       if(channel[ch].tnum) {
+                                               struct trackline tl;
+                                               u8 instr = 0;
+
+                                               readtrack(channel[ch].tnum, trackpos, &tl);
+                                               if(tl.note) {
+                                                       channel[ch].tnote = tl.note + channel[ch].transp;
+                                                       instr = channel[ch].lastinstr;
+                                               }
+                                               if(tl.instr) {
+                                                       instr = tl.instr;
+                                               }
+                                               if(instr) {
+                                                       channel[ch].lastinstr = instr;
+                                                       channel[ch].inum = instr;
+                                                       channel[ch].iptr = 0;
+                                                       channel[ch].iwait = 0;
+                                                       channel[ch].bend = 0;
+                                                       channel[ch].bendd = 0;
+                                                       channel[ch].volumed = 0;
+                                                       channel[ch].dutyd = 0;
+                                                       channel[ch].vdepth = 0;
+                                               }
+                                               if(tl.cmd[0])
+                                                       runcmd(ch, tl.cmd[0], tl.param[0]);
+                                               /*if(tl.cmd[1])
+                                                       runcmd(ch, tl.cmd[1], tl.param[1]);*/
+                                       }
+                               }
+
+                               trackpos++;
+                               trackpos &= 31;
+                       }
+               }
+       }
+
+       for(ch = 0; ch < 4; ch++) {
+               s16 vol;
+               u16 duty;
+               u16 slur;
+
+               while(channel[ch].inum && !channel[ch].iwait) {
+                       u8 il[2];
+
+                       readinstr(channel[ch].inum, channel[ch].iptr, il);
+                       channel[ch].iptr++;
+
+                       runcmd(ch, il[0], il[1]);
+               }
+               if(channel[ch].iwait) channel[ch].iwait--;
+
+               if(channel[ch].inertia) {
+                       s16 diff;
+
+                       slur = channel[ch].slur;
+                       diff = freqtable[channel[ch].inote] - slur;
+                       //diff >>= channel[ch].inertia;
+                       if(diff > 0) {
+                               if(diff > channel[ch].inertia) diff = channel[ch].inertia;
+                       } else if(diff < 0) {
+                               if(diff < -channel[ch].inertia) diff = -channel[ch].inertia;
+                       }
+                       slur += diff;
+                       channel[ch].slur = slur;
+               } else {
+                       slur = freqtable[channel[ch].inote];
+               }
+               osc[ch].freq =
+                       slur +
+                       channel[ch].bend +
+                       ((channel[ch].vdepth * sinetable[channel[ch].vpos & 63]) >> 2);
+               channel[ch].bend += channel[ch].bendd;
+               vol = osc[ch].volume + channel[ch].volumed;
+               if(vol < 0) vol = 0;
+               if(vol > 255) vol = 255;
+               osc[ch].volume = vol;
+
+               duty = osc[ch].duty + channel[ch].dutyd;
+               if(duty > 0xe000) duty = 0x2000;
+               if(duty < 0x2000) duty = 0xe000;
+               osc[ch].duty = duty;
+
+               channel[ch].vpos += channel[ch].vrate;
+       }
+}
+
+void initchip() {
+       trackwait = 0;
+       trackpos = 0;
+       playsong = 0;
+       playtrack = 0;
+
+       osc[0].volume = 0;
+       channel[0].inum = 0;
+       osc[1].volume = 0;
+       channel[1].inum = 0;
+       osc[2].volume = 0;
+       channel[2].inum = 0;
+       osc[3].volume = 0;
+       channel[3].inum = 0;
+}
+
+u8 interrupthandler()
+{
+       u8 i;
+       s16 acc;
+       static u32 noiseseed = 1;
+       u8 newbit;
+
+       newbit = 0;
+       if(noiseseed & 0x80000000L) newbit ^= 1;
+       if(noiseseed & 0x01000000L) newbit ^= 1;
+       if(noiseseed & 0x00000040L) newbit ^= 1;
+       if(noiseseed & 0x00000200L) newbit ^= 1;
+       noiseseed = (noiseseed << 1) | newbit;
+
+       if(callbackwait) {
+               callbackwait--;
+       } else {
+               playroutine();
+               callbackwait = 180 - 1;
+       }
+
+       acc = 0;
+       for(i = 0; i < 4; i++) {
+               s8 value; // [-32,31]
+
+               switch(osc[i].waveform) {
+                       case WF_TRI:
+                               if(osc[i].phase < 0x8000) {
+                                       value = -32 + (osc[i].phase >> 9);
+                               } else {
+                                       value = 31 - ((osc[i].phase - 0x8000) >> 9);
+                               }
+                               break;
+                       case WF_SAW:
+                               value = -32 + (osc[i].phase >> 10);
+                               break;
+                       case WF_PUL:
+                               value = (osc[i].phase > osc[i].duty)? -32 : 31;
+                               break;
+                       case WF_NOI:
+                               value = (noiseseed & 63) - 32;
+                               break;
+                       default:
+                               value = 0;
+                               break;
+               }
+               osc[i].phase += osc[i].freq;
+
+               acc += value * osc[i].volume; // rhs = [-8160,7905]
+       }
+       // acc [-32640,31620]
+       return 128 + (acc >> 8);        // [1,251]
+}
diff --git a/tracker/gui.c b/tracker/gui.c
new file mode 100644 (file)
index 0000000..810e683
--- /dev/null
@@ -0,0 +1,907 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include <math.h>
+#include <err.h>
+
+#include "stuff.h"
+
+#define SETLO(v,x) v = ((v) & 0xf0) | (x)
+#define SETHI(v,x) v = ((v) & 0x0f) | ((x) << 4)
+
+int songx, songy, songoffs, songlen = 1;
+int trackx, tracky, trackoffs, tracklen = TRACKLEN;
+int instrx, instry, instroffs;
+int currtrack = 1, currinstr = 1;
+int currtab = 0;
+int octave = 4;
+
+char filename[1024];
+
+char *notenames[] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "H-"};
+
+char *validcmds = "0dfijlmtvw~+=";
+
+/*char *keymap[2] = {
+       ";oqejkixdbhmwnvsz",
+       "'2,3.p5y6f7gc9r0l/="
+};*/
+
+char *keymap[2] = {
+       "zsxdcvgbhnjm,l.;/",
+       "q2w3er5t6y7ui9o0p"
+};
+
+struct instrline {
+       u8                      cmd;
+       u8                      param;
+};
+
+struct instrument {
+       int                     length;
+       struct instrline        line[256];
+};
+
+struct songline {
+       u8                      track[4];
+       u8                      transp[4];
+};
+
+struct instrument instrument[256], iclip;
+struct track track[256], tclip;
+struct songline song[256];
+
+enum {
+       PM_IDLE,
+       PM_PLAY,
+       PM_EDIT
+};
+int playmode = PM_IDLE;
+
+int hexdigit(char c) {
+       if(c >= '0' && c <= '9') return c - '0';
+       if(c >= 'a' && c <= 'f') return c - 'a' + 10;
+       return -1;
+}
+
+int freqkey(int c) {
+       char *s;
+       int f = -1;
+
+       if(c == '-' || c == KEY_DC) return 0;
+       if(c > 0 && c < 256) {
+               s = strchr(keymap[0], c);
+               if(s) {
+                       f = (s - (keymap[0])) + octave * 12 + 1;
+               } else {
+                       s = strchr(keymap[1], c);
+                       if(s) {
+                               f = (s - (keymap[1])) + octave * 12 + 12 + 1;
+                       }
+               }
+       }
+       if(f > 12 * 9 + 1) return -1;
+       return f;
+}
+
+void readsong(int pos, int ch, u8 *dest) {
+       dest[0] = song[pos].track[ch];
+       dest[1] = song[pos].transp[ch];
+}
+
+void readtrack(int num, int pos, struct trackline *tl) {
+       tl->note = track[num].line[pos].note;
+       tl->instr = track[num].line[pos].instr;
+       tl->cmd[0] = track[num].line[pos].cmd[0];
+       tl->cmd[1] = track[num].line[pos].cmd[1];
+       tl->param[0] = track[num].line[pos].param[0];
+       tl->param[1] = track[num].line[pos].param[1];
+}
+
+void readinstr(int num, int pos, u8 *il) {
+       if(pos >= instrument[num].length) {
+               il[0] = 0;
+               il[1] = 0;
+       } else {
+               il[0] = instrument[num].line[pos].cmd;
+               il[1] = instrument[num].line[pos].param;
+       }
+}
+
+void savefile(char *fname) {
+       FILE *f;
+       int i, j;
+
+       f = fopen(fname, "w");
+       if(!f) {
+               fprintf(stderr, "save error!\n");
+               return;
+       }
+
+       fprintf(f, "musicchip tune\n");
+       fprintf(f, "version 1\n");
+       fprintf(f, "\n");
+       for(i = 0; i < songlen; i++) {
+               fprintf(f, "songline %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                       i,
+                       song[i].track[0],
+                       song[i].transp[0],
+                       song[i].track[1],
+                       song[i].transp[1],
+                       song[i].track[2],
+                       song[i].transp[2],
+                       song[i].track[3],
+                       song[i].transp[3]);
+       }
+       fprintf(f, "\n");
+       for(i = 1; i < 256; i++) {
+               for(j = 0; j < tracklen; j++) {
+                       struct trackline *tl = &track[i].line[j];
+
+                       if(tl->note || tl->instr || tl->cmd[0] || tl->cmd[1]) {
+                               fprintf(f, "trackline %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                                       i,
+                                       j,
+                                       tl->note,
+                                       tl->instr,
+                                       tl->cmd[0],
+                                       tl->param[0],
+                                       tl->cmd[1],
+                                       tl->param[1]);
+                       }
+               }
+       }
+       fprintf(f, "\n");
+       for(i = 1; i < 256; i++) {
+               if(instrument[i].length > 1) {
+                       for(j = 0; j < instrument[i].length; j++) {
+                               fprintf(f, "instrumentline %02x %02x %02x %02x\n",
+                                       i,
+                                       j,
+                                       instrument[i].line[j].cmd,
+                                       instrument[i].line[j].param);
+                       }
+               }
+       }
+
+       fclose(f);
+}
+
+void loadfile(char *fname) {
+       FILE *f;
+       char buf[1024];
+       int cmd[3];
+       int i1, i2, trk[4], transp[4], param[3], note, instr;
+       int i;
+
+       snprintf(filename, sizeof(filename), "%s", fname);
+
+       f = fopen(fname, "r");
+       if(!f) {
+               return;
+       }
+
+       songlen = 1;
+       while(!feof(f) && fgets(buf, sizeof(buf), f)) {
+               if(9 == sscanf(buf, "songline %x %x %x %x %x %x %x %x %x",
+                       &i1,
+                       &trk[0],
+                       &transp[0],
+                       &trk[1],
+                       &transp[1],
+                       &trk[2],
+                       &transp[2],
+                       &trk[3],
+                       &transp[3])) {
+
+                       for(i = 0; i < 4; i++) {
+                               song[i1].track[i] = trk[i];
+                               song[i1].transp[i] = transp[i];
+                       }
+                       if(songlen <= i1) songlen = i1 + 1;
+               } else if(8 == sscanf(buf, "trackline %x %x %x %x %x %x %x %x",
+                       &i1,
+                       &i2,
+                       &note,
+                       &instr,
+                       &cmd[0],
+                       &param[0],
+                       &cmd[1],
+                       &param[1])) {
+
+                       track[i1].line[i2].note = note;
+                       track[i1].line[i2].instr = instr;
+                       for(i = 0; i < 2; i++) {
+                               track[i1].line[i2].cmd[i] = cmd[i];
+                               track[i1].line[i2].param[i] = param[i];
+                       }
+               } else if(4 == sscanf(buf, "instrumentline %x %x %x %x",
+                       &i1,
+                       &i2,
+                       &cmd[0],
+                       &param[0])) {
+
+                       instrument[i1].line[i2].cmd = cmd[0];
+                       instrument[i1].line[i2].param = param[0];
+                       if(instrument[i1].length <= i2) instrument[i1].length = i2 + 1;
+               }
+       }
+
+       fclose(f);
+}
+
+void exitgui() {
+       endwin();
+}
+
+void initgui() {
+       int i;
+
+       initscr();
+       noecho();
+       keypad(stdscr, TRUE);
+       //cbreak();
+       //nodelay(stdscr, TRUE);
+       //halfdelay(1);
+       raw();
+
+       for(i = 1; i < 256; i++) {
+               instrument[i].length = 1;
+               instrument[i].line[0].cmd = '0';
+               instrument[i].line[0].param = 0;
+       }
+
+       atexit(exitgui);
+}
+
+void drawsonged(int x, int y, int height) {
+       int i, j;
+       char buf[1024];
+
+       if(songy < songoffs) songoffs = songy;
+       if(songy >= songoffs + height) songoffs = songy - height + 1;
+
+       for(i = 0; i < songlen; i++) {
+               if(i >= songoffs && i - songoffs < height) {
+                       move(y + i - songoffs, x + 0);
+                       if(i == songy) attrset(A_BOLD);
+                       snprintf(buf, sizeof(buf), "%02x: ", i);
+                       addstr(buf);
+                       for(j = 0; j < 4; j++) {
+                               snprintf(buf, sizeof(buf), "%02x:%02x", song[i].track[j], song[i].transp[j]);
+                               addstr(buf);
+                               if(j != 3) addch(' ');
+                       }
+                       attrset(A_NORMAL);
+                       if(playsong && songpos == (i + 1)) addch('*');
+               }
+       }
+}
+
+void drawtracked(int x, int y, int height) {
+       int i, j;
+       char buf[1024];
+
+       if(tracky < trackoffs) trackoffs = tracky;
+       if(tracky >= trackoffs + height) trackoffs = tracky - height + 1;
+
+       for(i = 0; i < tracklen; i++) {
+               if(i >= trackoffs && i - trackoffs < height) {
+                       move(y + i - trackoffs, x + 0);
+                       if(i == tracky) attrset(A_BOLD);
+                       snprintf(buf, sizeof(buf), "%02x: ", i);
+                       addstr(buf);
+                       if(track[currtrack].line[i].note) {
+                               snprintf(buf, sizeof(buf), "%s%d",
+                                       notenames[(track[currtrack].line[i].note - 1) % 12],
+                                       (track[currtrack].line[i].note - 1) / 12);
+                       } else {
+                               snprintf(buf, sizeof(buf), "---");
+                       }
+                       addstr(buf);
+                       snprintf(buf, sizeof(buf), " %02x", track[currtrack].line[i].instr);
+                       addstr(buf);
+                       for(j = 0; j < 2; j++) {
+                               if(track[currtrack].line[i].cmd[j]) {
+                                       snprintf(buf, sizeof(buf), " %c%02x",
+                                               track[currtrack].line[i].cmd[j],
+                                               track[currtrack].line[i].param[j]);
+                               } else {
+                                       snprintf(buf, sizeof(buf), " ...");
+                               }
+                               addstr(buf);
+                       }
+                       attrset(A_NORMAL);
+                       if(playtrack && ((i + 1) % tracklen) == trackpos) {
+                               addch('*');
+                       }
+               }
+       }
+}
+
+void drawinstred(int x, int y, int height) {
+       int i;
+       char buf[1024];
+
+       if(instry >= instrument[currinstr].length) instry = instrument[currinstr].length - 1;
+
+       if(instry < instroffs) instroffs = instry;
+       if(instry >= instroffs + height) instroffs = instry - height + 1;
+
+       for(i = 0; i < instrument[currinstr].length; i++) {
+               if(i >= instroffs && i - instroffs < height) {
+                       move(y + i - instroffs, x + 0);
+                       if(i == instry) attrset(A_BOLD);
+                       snprintf(buf, sizeof(buf), "%02x: %c ", i, instrument[currinstr].line[i].cmd);
+                       addstr(buf);
+                       if(instrument[currinstr].line[i].cmd == '+' || instrument[currinstr].line[i].cmd == '=') {
+                               if(instrument[currinstr].line[i].param) {
+                                       snprintf(buf, sizeof(buf), "%s%d",
+                                               notenames[(instrument[currinstr].line[i].param - 1) % 12],
+                                               (instrument[currinstr].line[i].param - 1) / 12);
+                               } else {
+                                       snprintf(buf, sizeof(buf), "---");
+                               }
+                       } else {
+                               snprintf(buf, sizeof(buf), "%02x", instrument[currinstr].line[i].param);
+                       }
+                       addstr(buf);
+                       attrset(A_NORMAL);
+               }
+       }
+}
+
+void drawmodeinfo(int x, int y) {
+       switch(playmode) {
+               case PM_IDLE:
+                       if(currtab == 2) {
+                               mvaddstr(y, x, "PLAY         IDLE space-> EDIT");
+                       } else {
+                               mvaddstr(y, x, "PLAY <-enter IDLE space-> EDIT");
+                       }
+                       attrset(A_REVERSE);
+                       mvaddstr(y, x + 13, "IDLE");
+                       attrset(A_NORMAL);
+                       break;
+               case PM_PLAY:
+                       mvaddstr(y, x, "PLAY space-> IDLE         EDIT");
+                       attrset(A_REVERSE);
+                       mvaddstr(y, x + 0, "PLAY");
+                       attrset(A_NORMAL);
+                       break;
+               case PM_EDIT:
+                       mvaddstr(y, x, "PLAY         IDLE <-space EDIT");
+                       attrset(A_REVERSE);
+                       mvaddstr(y, x + 26, "EDIT");
+                       attrset(A_NORMAL);
+                       break;
+       }
+}
+
+void optimize() {
+       u8 used[256], replace[256];
+       int i, j;
+
+       memset(used, 0, sizeof(used));
+       for(i = 0; i < songlen; i++) {
+               for(j = 0; j < 4; j++) {
+                       used[song[i].track[j]] = 1;
+               }
+       }
+
+       j = 1;
+       replace[0] = 0;
+       for(i = 1; i < 256; i++) {
+               if(used[i]) {
+                       replace[i] = j;
+                       j++;
+               } else {
+                       replace[i] = 0;
+               }
+       }
+
+       for(i = 1; i < 256; i++) {
+               if(replace[i] && replace[i] != i) {
+                       memcpy(&track[replace[i]], &track[i], sizeof(struct track));
+               }
+       }
+
+       for(i = 0; i < songlen; i++) {
+               for(j = 0; j < 4; j++) {
+                       song[i].track[j] = replace[song[i].track[j]];
+               }
+       }
+
+       for(i = 1; i < 256; i++) {
+               u8 last = 255;
+
+               for(j = 0; j < tracklen; j++) {
+                       if(track[i].line[j].instr) {
+                               if(track[i].line[j].instr == last) {
+                                       track[i].line[j].instr = 0;
+                               } else {
+                                       last = track[i].line[j].instr;
+                               }
+                       }
+               }
+       }
+}
+
+static FILE *exportfile = 0;
+static int exportbits = 0;
+static int exportcount = 0;
+static int exportseek = 0;
+
+void putbit(int x) {
+       if(x) {
+               exportbits |= (1 << exportcount);
+       }
+       exportcount++;
+       if(exportcount == 8) {
+               if(exportfile) {
+                       fprintf(exportfile, "\t.byte\t0x%02x\n", exportbits);
+               }
+               exportseek++;
+               exportbits = 0;
+               exportcount = 0;
+       }
+}
+
+void exportchunk(int data, int bits) {
+       int i;
+
+       for(i = 0; i < bits; i++) {
+               putbit(!!(data & (1 << i)));
+       }
+}
+
+int alignbyte() {
+       if(exportcount) {
+               if(exportfile) {
+                       fprintf(exportfile, "\t.byte\t0x%02x\n", exportbits);
+               }
+               exportseek++;
+               exportbits = 0;
+               exportcount = 0;
+       }
+       if(exportfile) fprintf(exportfile, "\n");
+       return exportseek;
+}
+
+int packcmd(u8 ch) {
+       if(!ch) return 0;
+       if(strchr(validcmds, ch)) {
+               return strchr(validcmds, ch) - validcmds;
+       }
+       return 0;
+}
+
+void exportdata(FILE *f, int maxtrack, int *resources) {
+       int i, j;
+       int nres = 0;
+
+       exportfile = f;
+       exportbits = 0;
+       exportcount = 0;
+       exportseek = 0;
+
+       for(i = 0; i < 16 + maxtrack; i++) {
+               exportchunk(resources[i], 13);
+       }
+
+       resources[nres++] = alignbyte();
+
+       for(i = 0; i < songlen; i++) {
+               for(j = 0; j < 4; j++) {
+                       if(song[i].transp[j]) {
+                               exportchunk(1, 1);
+                               exportchunk(song[i].track[j], 6);
+                               exportchunk(song[i].transp[j], 4);
+                       } else {
+                               exportchunk(0, 1);
+                               exportchunk(song[i].track[j], 6);
+                       }
+               }
+       }
+
+       for(i = 1; i < 16; i++) {
+               resources[nres++] = alignbyte();
+
+               if(instrument[i].length > 1) {
+                       for(j = 0; j < instrument[i].length; j++) {
+                               exportchunk(packcmd(instrument[i].line[j].cmd), 8);
+                               exportchunk(instrument[i].line[j].param, 8);
+                       }
+               }
+
+               exportchunk(0, 8);
+       }
+
+       for(i = 1; i <= maxtrack; i++) {
+               resources[nres++] = alignbyte();
+
+               for(j = 0; j < tracklen; j++) {
+                       u8 cmd = packcmd(track[i].line[j].cmd[0]);
+
+                       exportchunk(!!track[i].line[j].note, 1);
+                       exportchunk(!!track[i].line[j].instr, 1);
+                       exportchunk(!!cmd, 1);
+
+                       if(track[i].line[j].note) {
+                               exportchunk(track[i].line[j].note, 7);
+                       }
+
+                       if(track[i].line[j].instr) {
+                               exportchunk(track[i].line[j].instr, 4);
+                       }
+
+                       if(cmd) {
+                               exportchunk(cmd, 4);
+                               exportchunk(track[i].line[j].param[0], 8);
+                       }
+               }
+       }
+}
+
+void export() {
+       FILE *f = fopen("exported.s", "w");
+       FILE *hf = fopen("exported.h", "w");
+       int i, j;
+       int maxtrack = 0;
+       int resources[256];
+
+       exportfile = 0;
+       exportbits = 0;
+       exportcount = 0;
+       exportseek = 0;
+
+       for(i = 0; i < songlen; i++) {
+               for(j = 0; j < 4; j++) {
+                       if(maxtrack < song[i].track[j]) maxtrack = song[i].track[j];
+               }
+       }
+
+       fprintf(f, "\t.global\tsongdata\n\n");
+
+       fprintf(hf, "#define MAXTRACK\t0x%02x\n", maxtrack);
+       fprintf(hf, "#define SONGLEN\t\t0x%02x\n", songlen);
+
+       fprintf(f, "songdata:\n");
+
+       exportdata(0, maxtrack, resources);
+
+       fprintf(f, "# ");
+       for(i = 0; i < 16 + maxtrack; i++) {
+               fprintf(f, "%04x ", resources[i]);
+       }
+       fprintf(f, "\n");
+
+       exportdata(f, maxtrack, resources);
+
+       fclose(f);
+       fclose(hf);
+}
+
+void handleinput() {
+       int c, x;
+       
+       if((c = getch()) != ERR) switch(c) {
+               case 10:
+               case 13:
+                       if(currtab != 2) {
+                               playmode = PM_PLAY;
+                               if(currtab == 1) {
+                                       startplaytrack(currtrack);
+                               } else if(currtab == 0) {
+                                       startplaysong(songy);
+                               }
+                       }
+                       break;
+               case ' ':
+                       silence();
+                       if(playmode == PM_IDLE) {
+                               playmode = PM_EDIT;
+                       } else {
+                               playmode = PM_IDLE;
+                       }
+                       break;
+               case 9:
+                       currtab++;
+                       currtab %= 3;
+                       break;
+               case 'E' - '@':
+                       erase();
+                       refresh();
+                       endwin();
+                       exit(0);
+                       break;
+               case 'W' - '@':
+                       savefile(filename);
+                       break;
+               case '<':
+                       if(octave) octave--;
+                       break;
+               case '>':
+                       if(octave < 8) octave++;
+                       break;
+               case '[':
+                       if(currinstr > 1) currinstr--;
+                       break;
+               case ']':
+                       if(currinstr < 255) currinstr++;
+                       break;
+               case '{':
+                       if(currtrack > 1) currtrack--;
+                       break;
+               case '}':
+                       if(currtrack < 255) currtrack++;
+                       break;
+               case '`':
+                       if(currtab == 0) {
+                               int t = song[songy].track[songx / 4];
+                               if(t) currtrack = t;
+                               currtab = 1;
+                       } else if(currtab == 1) {
+                               currtab = 0;
+                       }
+                       break;
+               case '#':
+                       optimize();
+                       break;
+               case '%':
+                       export();
+                       break;
+               case KEY_LEFT:
+                       switch(currtab) {
+                               case 0:
+                                       if(songx) songx--;
+                                       break;
+                               case 1:
+                                       if(trackx) trackx--;
+                                       break;
+                               case 2:
+                                       if(instrx) instrx--;
+                                       break;
+                       }
+                       break;
+               case KEY_RIGHT:
+                       switch(currtab) {
+                               case 0:
+                                       if(songx < 15) songx++;
+                                       break;
+                               case 1:
+                                       if(trackx < 8) trackx++;
+                                       break;
+                               case 2:
+                                       if(instrx < 2) instrx++;
+                                       break;
+                       }
+                       break;
+               case KEY_UP:
+                       switch(currtab) {
+                               case 0:
+                                       if(songy) songy--;
+                                       break;
+                               case 1:
+                                       if(tracky) {
+                                               tracky--;
+                                       } else {
+                                               tracky = tracklen - 1;
+                                       }
+                                       break;
+                               case 2:
+                                       if(instry) instry--;
+                                       break;
+                       }
+                       break;
+               case KEY_DOWN:
+                       switch(currtab) {
+                               case 0:
+                                       if(songy < songlen - 1) songy++;
+                                       break;
+                               case 1:
+                                       if(tracky < tracklen - 1) {
+                                               tracky++;
+                                       } else {
+                                               tracky = 0;
+                                       }
+                                       break;
+                               case 2:
+                                       if(instry < instrument[currinstr].length - 1) instry++;
+                                       break;
+                       }
+                       break;
+               case 'C':
+                       if(currtab == 2) {
+                               memcpy(&iclip, &instrument[currinstr], sizeof(struct instrument));
+                       } else if(currtab == 1) {
+                               memcpy(&tclip, &track[currtrack], sizeof(struct track));
+                       }
+                       break;
+               case 'V':
+                       if(currtab == 2) {
+                               memcpy(&instrument[currinstr], &iclip, sizeof(struct instrument));
+                       } else if(currtab == 1) {
+                               memcpy(&track[currtrack], &tclip, sizeof(struct track));
+                       }
+                       break;
+               default:
+                       if(playmode == PM_EDIT) {
+                               x = hexdigit(c);
+                               if(x >= 0) {
+                                       if(currtab == 2
+                                       && instrx > 0
+                                       && instrument[currinstr].line[instry].cmd != '+'
+                                       && instrument[currinstr].line[instry].cmd != '=') {
+                                               switch(instrx) {
+                                                       case 1: SETHI(instrument[currinstr].line[instry].param, x); break;
+                                                       case 2: SETLO(instrument[currinstr].line[instry].param, x); break;
+                                               }
+                                       }
+                                       if(currtab == 1 && trackx > 0) {
+                                               switch(trackx) {
+                                                       case 1: SETHI(track[currtrack].line[tracky].instr, x); break;
+                                                       case 2: SETLO(track[currtrack].line[tracky].instr, x); break;
+                                                       case 4: if(track[currtrack].line[tracky].cmd[0])
+                                                               SETHI(track[currtrack].line[tracky].param[0], x); break;
+                                                       case 5: if(track[currtrack].line[tracky].cmd[0])
+                                                               SETLO(track[currtrack].line[tracky].param[0], x); break;
+                                                       case 7: if(track[currtrack].line[tracky].cmd[1])
+                                                               SETHI(track[currtrack].line[tracky].param[1], x); break;
+                                                       case 8: if(track[currtrack].line[tracky].cmd[1])
+                                                               SETLO(track[currtrack].line[tracky].param[1], x); break;
+                                               }
+                                       }
+                                       if(currtab == 0) {
+                                               switch(songx & 3) {
+                                                       case 0: SETHI(song[songy].track[songx / 4], x); break;
+                                                       case 1: SETLO(song[songy].track[songx / 4], x); break;
+                                                       case 2: SETHI(song[songy].transp[songx / 4], x); break;
+                                                       case 3: SETLO(song[songy].transp[songx / 4], x); break;
+                                               }
+                                       }
+                               }
+                               x = freqkey(c);
+                               if(x >= 0) {
+                                       if(currtab == 2
+                                       && instrx
+                                       && (instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '=')) {
+                                               instrument[currinstr].line[instry].param = x;
+                                       }
+                                       if(currtab == 1 && !trackx) {
+                                               track[currtrack].line[tracky].note = x;
+                                               if(x) {
+                                                       track[currtrack].line[tracky].instr = currinstr;
+                                               } else {
+                                                       track[currtrack].line[tracky].instr = 0;
+                                               }
+                                               tracky++;
+                                               tracky %= tracklen;
+                                               if(x) iedplonk(x, currinstr);
+                                       }
+                               }
+                               if(currtab == 2 && instrx == 0) {
+                                       if(strchr(validcmds, c)) {
+                                               instrument[currinstr].line[instry].cmd = c;
+                                       }
+                               }
+                               if(currtab == 1 && (trackx == 3 || trackx == 6 || trackx == 9)) {
+                                       if(strchr(validcmds, c)) {
+                                               if(c == '.' || c == '0') c = 0;
+                                               track[currtrack].line[tracky].cmd[(trackx - 3) / 3] = c;
+                                       }
+                               }
+                               if(c == 'A') {
+                                       if(currtab == 2) {
+                                               struct instrument *in = &instrument[currinstr];
+
+                                               if(in->length < 256) {
+                                                       memmove(&in->line[instry + 2], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
+                                                       instry++;
+                                                       in->length++;
+                                                       in->line[instry].cmd = '0';
+                                                       in->line[instry].param = 0;
+                                               }
+                                       } else if(currtab == 0) {
+                                               if(songlen < 256) {
+                                                       memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
+                                                       songy++;
+                                                       songlen++;
+                                                       memset(&song[songy], 0, sizeof(struct songline));
+                                               }
+                                       }
+                               } else if(c == 'I') {
+                                       if(currtab == 2) {
+                                               struct instrument *in = &instrument[currinstr];
+
+                                               if(in->length < 256) {
+                                                       memmove(&in->line[instry + 1], &in->line[instry + 0], sizeof(struct instrline) * (in->length - instry));
+                                                       in->length++;
+                                                       in->line[instry].cmd = '0';
+                                                       in->line[instry].param = 0;
+                                               }
+                                       } else if(currtab == 0) {
+                                               if(songlen < 256) {
+                                                       memmove(&song[songy + 1], &song[songy + 0], sizeof(struct songline) * (songlen - songy));
+                                                       songlen++;
+                                                       memset(&song[songy], 0, sizeof(struct songline));
+                                               }
+                                       }
+                               } else if(c == 'D') {
+                                       if(currtab == 2) {
+                                               struct instrument *in = &instrument[currinstr];
+
+                                               if(in->length > 1) {
+                                                       memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
+                                                       in->length--;
+                                                       if(instry >= in->length) instry = in->length - 1;
+                                               }
+                                       } else if(currtab == 0) {
+                                               if(songlen > 1) {
+                                                       memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
+                                                       songlen--;
+                                                       if(songy >= songlen) songy = songlen - 1;
+                                               }
+                                       }
+                               }
+                       } else if(playmode == PM_IDLE) {
+                               x = freqkey(c);
+
+                               if(x > 0) {
+                                       iedplonk(x, currinstr);
+                               }
+                       }
+                       break;
+       }
+}
+
+void drawgui() {
+       char buf[1024];
+       int lines = LINES, cols = 79;
+       int songcols[] = {0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22};
+       int trackcols[] = {0, 4, 5, 7, 8, 9, 11, 12, 13};
+       int instrcols[] = {0, 2, 3};
+
+       erase();
+       mvaddstr(0, 0, "music chip tracker 0.1 by lft");
+       drawmodeinfo(cols - 30, 0);
+       snprintf(buf, sizeof(buf), "Octave:   %d <>", octave);
+       mvaddstr(2, cols - 14, buf);
+       mvaddstr(3, cols - 14, "^W)rite ^E)xit");
+
+       snprintf(buf, sizeof(buf), "^F)ilename:        %s", filename);
+       mvaddstr(2, 15, buf);
+
+       mvaddstr(5, 0, "Song");
+       drawsonged(0, 6, lines - 12);
+
+       snprintf(buf, sizeof(buf), "Track %02x {}", currtrack);
+       mvaddstr(5, 29, buf);
+       drawtracked(29, 6, lines - 8);
+
+       snprintf(buf, sizeof(buf), "Instr. %02x []", currinstr);
+       mvaddstr(5, 49, buf);
+       drawinstred(49, 6, lines - 12);
+
+       switch(currtab) {
+               case 0:
+                       move(6 + songy - songoffs, 0 + 4 + songcols[songx]);
+                       break;
+               case 1:
+                       move(6 + tracky - trackoffs, 29 + 4 + trackcols[trackx]);
+                       break;
+               case 2:
+                       move(6 + instry - instroffs, 49 + 4 + instrcols[instrx]);
+                       break;
+       }
+
+       refresh();
+}
+
+void guiloop() {
+       for(;;) {
+               drawgui();
+               handleinput();
+       }
+}
diff --git a/tracker/main.c b/tracker/main.c
new file mode 100644 (file)
index 0000000..99e161b
--- /dev/null
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <err.h>
+#include <SDL/SDL.h>
+
+#include "stuff.h"
+
+const u16 instrptr[] = {
+       0, 1
+};
+
+const u8 instrdata[] = {
+       0, 0,
+       'v', 255, 'm', 0x11, '+', 0, 'w', WF_PUL, 'f', 0xef, 't', 8, 'f', 0xfc, 0, 0, // lead
+       'v', 255, 'w', WF_NOI, 't', 2, '+', 0, 'w', WF_SAW, 'f', 0xef, 't', 8, 'f', 0, 't', 12, '~', 0x37, 'f', 0xfc, 0, 0, // lead+vibr
+       'v', 255, 'w', WF_NOI, 't', 2, 'm', 0x11, '+', 12, 'w', WF_PUL, 'f', 0xfc, 't', 2, '+', 7, 't', 2, '+', 3, 't', 2, '+', 0, 't', 2, 'j', 5, 0, 0, // arp
+       'v', 255, 'w', WF_NOI, 't', 2, 'd', 0x80, '+', 0, 'w', WF_PUL, 'l', 0x80, 't', 12, 'v', 0, 0, 0 // bass drum
+};
+
+const struct track trackdata = {
+       {
+               {12*3+0,        1,      {'i',   0},     {0xff,  0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+0,        1,      {0,     0},     {0,     0}},
+               {12*3+3,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+3,        1,      {0,     0},     {0,     0}},
+               {12*3+2,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+7,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+3,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+2,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*2+10,       1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+0,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+0,        1,      {0,     0},     {0,     0}},
+               {12*3+3,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*3+3,        1,      {0,     0},     {0,     0}},
+               {12*3+7,        1,      {0,     0},     {0,     0}},
+               {12*3+8,        1,      {0,     0},     {0,     0}},
+               {12*3+5,        1,      {0,     0},     {0,     0}},
+               {12*3+7,        1,      {0,     0},     {0,     0}},
+               {12*3+3,        1,      {0,     0},     {0,     0}},
+               {12*3+2,        1,      {0,     0},     {0,     0}},
+               {12*2+0,        1,      {0,     0},     {0,     0}},
+               {12*2+10,       1,      {0,     0},     {0,     0}},
+               {12*2+7,        1,      {0,     0},     {0,     0}},
+               {12*3+2,        1,      {0,     0},     {0,     0}},
+       }
+};
+
+void audiocb(void *userdata, Uint8 *buf, int len) {
+       int i;
+
+       for(i = 0; i < len; i++) {
+               buf[i] = interrupthandler();
+       }
+}
+
+int main(int argc, char **argv) {
+       SDL_AudioSpec requested, obtained;
+
+       if(argc != 2) {
+               err(1, "usage: %s <filename>\n", argv[0]);
+       }
+
+       SDL_Init(SDL_INIT_AUDIO);
+
+       atexit(SDL_Quit);
+
+       requested.freq = 16000;
+       requested.format = AUDIO_U8;
+       requested.samples = 256;
+       requested.callback = audiocb;
+       requested.channels = 1;
+       if(SDL_OpenAudio(&requested, &obtained) == -1) {
+               err(1, "SDL_OpenAudio");
+       }
+
+       fprintf(stderr, "freq %d\n", obtained.freq);
+       fprintf(stderr, "samples %d\n", obtained.samples);
+
+       initchip();
+       initgui();
+
+       loadfile(argv[1]);
+
+       SDL_PauseAudio(0);
+
+       guiloop();
+       
+       return 0;
+}
diff --git a/tracker/packedformat b/tracker/packedformat
new file mode 100644 (file)
index 0000000..e9cae42
--- /dev/null
@@ -0,0 +1,31 @@
+
+
+resource 0 = song
+resource 1 = instrument 1
+...
+resource 15 = instrument 15
+resource 16 = track 1
+...
+
+resource table:
+       xxxxxxxxxxxxx                   = byte offset into songdata
+       (for each resource)
+
+song:
+       0xxxxxx                         = track x, transp 0
+       1xxxxxxyyyy                     = track x, transp y (signed)
+       (times four, for each line)
+
+instrument:
+       00000000                        = end
+       0000ccccpppppppp                = command c, parameter p
+       (for each cmd)
+
+track:
+       000                             = blank line
+       100xxxxxxx                      = note x, instr 0 (last)
+       110xxxxxxxiiii                  = note x, instr i
+       001ccccpppppppp                 = cmd c, param p
+       101xxxxxxxccccpppppppp          = note x, instr 0 (last), cmd c, param p
+       111xxxxxxxiiiiccccpppppppp      = note x, instr i, cmd c, param p
+       (for each line)
diff --git a/tracker/stuff.h b/tracker/stuff.h
new file mode 100644 (file)
index 0000000..b32caec
--- /dev/null
@@ -0,0 +1,50 @@
+#define TRACKLEN 32
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef char s8;
+typedef short s16;
+typedef unsigned long u32;
+
+enum {
+       WF_TRI,
+       WF_SAW,
+       WF_PUL,
+       WF_NOI
+};
+
+
+struct trackline {
+       u8      note;
+       u8      instr;
+       u8      cmd[2];
+       u8      param[2];
+       };
+
+struct track {
+       struct trackline        line[TRACKLEN];
+};
+
+
+void initchip();
+u8 interrupthandler();
+
+void readsong(int pos, int ch, u8 *dest);
+void readtrack(int num, int pos, struct trackline *tl);
+void readinstr(int num, int pos, u8 *il);
+
+void silence();
+void iedplonk(int, int);
+
+void initgui();
+void guiloop();
+
+void startplaysong(int);
+void startplaytrack(int);
+void loadfile(char *);
+
+extern u8 trackpos;
+extern u8 playtrack;
+extern u8 playsong;
+extern u8 songpos;
+extern int songlen;
diff --git a/tracker/test2.song b/tracker/test2.song
new file mode 100644 (file)
index 0000000..a06ec22
--- /dev/null
@@ -0,0 +1,924 @@
+musicchip tune
+version 1
+
+songline 00 00 00 00 00 81 00 00 00
+songline 01 00 00 00 00 80 00 67 00
+songline 02 00 00 00 00 82 00 68 00
+songline 03 01 00 00 00 00 00 00 00
+songline 04 01 00 00 00 00 00 00 00
+songline 05 01 00 10 00 03 00 00 00
+songline 06 01 00 10 00 00 00 00 00
+songline 07 01 00 10 00 00 00 30 00
+songline 08 01 00 10 00 00 00 31 00
+songline 09 01 00 10 00 00 00 32 00
+songline 0a 08 00 10 00 00 00 30 00
+songline 0b 01 00 10 00 00 00 30 00
+songline 0c 01 00 10 00 00 00 31 00
+songline 0d 01 00 10 00 00 00 32 00
+songline 0e 01 00 10 00 04 00 30 00
+songline 0f 01 00 10 00 20 00 30 00
+songline 10 01 00 10 00 21 00 31 00
+songline 11 01 00 10 00 22 00 32 00
+songline 12 01 00 10 00 23 00 30 00
+songline 13 01 00 10 00 24 00 30 00
+songline 14 01 00 10 00 25 00 31 00
+songline 15 01 00 10 00 28 00 34 00
+songline 16 08 00 10 00 23 00 30 00
+songline 17 02 00 60 00 40 00 50 00
+songline 18 02 00 61 00 41 00 51 00
+songline 19 02 00 62 00 42 00 52 00
+songline 1a 02 00 63 00 43 00 53 00
+songline 1b 02 00 62 ff 44 00 54 00
+songline 1c 02 00 64 00 45 00 55 00
+songline 1d 02 00 66 00 46 00 56 00
+songline 1e 08 00 65 00 03 00 04 00
+songline 1f 01 00 10 00 70 00 30 00
+songline 20 01 00 10 00 71 00 31 00
+songline 21 01 00 10 00 72 00 32 00
+songline 22 01 00 10 00 73 00 30 00
+songline 23 01 00 10 00 74 00 30 00
+songline 24 01 00 10 00 75 00 31 00
+songline 25 01 00 10 00 72 00 34 00
+songline 26 08 00 10 00 73 00 30 00
+songline 27 01 00 70 03 24 03 30 03
+songline 28 01 00 71 03 25 03 31 03
+songline 29 02 00 72 03 22 03 32 03
+songline 2a 01 00 73 03 23 03 30 03
+songline 2b 01 00 10 03 26 03 30 03
+songline 2c 01 00 10 03 26 03 31 03
+songline 2d 02 00 10 03 27 03 32 03
+songline 2e 08 00 10 03 27 03 30 03
+songline 2f 06 00 91 03 92 03 30 03
+songline 30 06 00 91 03 92 03 31 03
+songline 31 06 00 91 03 92 03 32 03
+songline 32 06 00 91 03 92 03 30 03
+songline 33 06 00 91 03 92 03 30 03
+songline 34 06 00 91 03 92 03 31 03
+songline 35 04 00 67 03 92 03 34 03
+songline 36 09 00 68 03 05 00 33 03
+
+trackline 01 00 0d 01 00 00 00 00
+trackline 01 06 0d 01 00 00 00 00
+trackline 01 08 19 02 00 00 00 00
+trackline 01 0a 0d 01 00 00 00 00
+trackline 01 0e 0d 01 76 80 00 00
+trackline 01 0f 00 00 76 80 00 00
+trackline 01 10 0d 01 00 00 00 00
+trackline 01 12 0d 01 00 00 00 00
+trackline 01 14 0d 01 00 00 00 00
+trackline 01 16 19 02 00 00 00 00
+trackline 01 1a 0d 01 00 00 00 00
+trackline 01 1c 0d 01 00 00 00 00
+trackline 01 1f 00 00 76 00 00 00
+trackline 02 00 0d 01 00 00 00 00
+trackline 02 02 0d 01 00 00 00 00
+trackline 02 08 19 02 00 00 00 00
+trackline 02 0e 0d 01 00 00 00 00
+trackline 02 14 0d 01 00 00 00 00
+trackline 02 18 19 02 00 00 00 00
+trackline 03 00 00 00 66 ff 00 00
+trackline 04 03 00 00 69 00 00 00
+trackline 04 04 31 01 00 00 00 00
+trackline 04 05 31 01 00 00 00 00
+trackline 04 06 31 01 00 00 00 00
+trackline 04 07 31 01 00 00 00 00
+trackline 04 08 31 01 00 00 00 00
+trackline 04 0a 31 01 00 00 00 00
+trackline 04 0e 31 01 00 00 00 00
+trackline 04 10 2c 01 00 00 00 00
+trackline 04 12 2c 01 00 00 00 00
+trackline 04 16 2c 01 00 00 00 00
+trackline 04 18 25 01 00 00 00 00
+trackline 04 1a 25 01 00 00 00 00
+trackline 04 1c 20 01 00 00 00 00
+trackline 04 1e 20 01 00 00 00 00
+trackline 05 00 25 07 00 00 00 00
+trackline 06 00 19 02 00 00 00 00
+trackline 06 01 00 00 76 50 00 00
+trackline 06 02 0d 01 00 00 00 00
+trackline 06 03 0d 01 00 00 00 00
+trackline 06 04 0d 01 00 00 00 00
+trackline 06 06 0d 01 00 00 00 00
+trackline 06 08 19 02 00 00 00 00
+trackline 06 09 00 00 76 00 00 00
+trackline 06 0a 19 02 76 50 00 00
+trackline 06 0b 00 00 76 00 00 00
+trackline 06 0c 0d 01 00 00 00 00
+trackline 06 0e 0d 01 00 00 00 00
+trackline 06 10 19 02 00 00 00 00
+trackline 06 11 00 00 76 50 00 00
+trackline 06 12 0d 01 00 00 00 00
+trackline 06 14 0d 01 00 00 00 00
+trackline 06 16 0d 01 00 00 00 00
+trackline 06 18 19 02 00 00 00 00
+trackline 06 19 00 00 76 50 00 00
+trackline 06 1a 0d 01 00 00 00 00
+trackline 06 1c 0d 01 00 00 00 00
+trackline 06 1d 0d 01 00 00 00 00
+trackline 06 1e 0d 01 00 00 00 00
+trackline 06 1f 0d 01 00 00 00 00
+trackline 07 00 0d 01 00 00 00 00
+trackline 07 03 00 00 69 00 00 00
+trackline 07 04 31 01 00 00 00 00
+trackline 07 05 31 01 00 00 00 00
+trackline 07 06 31 01 00 00 00 00
+trackline 07 07 31 01 00 00 00 00
+trackline 07 08 31 01 00 00 00 00
+trackline 07 0a 31 01 00 00 00 00
+trackline 07 0e 31 01 00 00 00 00
+trackline 07 10 2c 01 00 00 00 00
+trackline 07 12 2c 01 00 00 00 00
+trackline 07 16 2c 01 00 00 00 00
+trackline 07 18 25 01 00 00 00 00
+trackline 07 1a 25 01 00 00 00 00
+trackline 07 1c 20 01 00 00 00 00
+trackline 07 1e 20 01 00 00 00 00
+trackline 08 00 0d 01 00 00 00 00
+trackline 08 06 0d 01 00 00 00 00
+trackline 08 08 19 02 00 00 00 00
+trackline 08 09 00 00 76 00 00 00
+trackline 08 0a 0d 01 00 00 00 00
+trackline 08 0e 0d 01 76 80 00 00
+trackline 08 0f 0d 01 00 80 00 00
+trackline 08 10 19 02 00 00 00 00
+trackline 08 11 00 00 76 00 00 00
+trackline 08 12 0d 01 00 00 00 00
+trackline 08 14 0d 01 00 00 00 00
+trackline 08 16 0d 01 00 00 00 00
+trackline 08 18 19 02 00 00 00 00
+trackline 08 1a 0d 01 00 00 00 00
+trackline 08 1c 19 02 00 00 00 00
+trackline 08 1d 00 00 76 00 00 00
+trackline 08 1e 19 02 00 00 00 00
+trackline 08 1f 00 00 76 00 00 00
+trackline 09 00 0d 01 00 00 00 00
+trackline 10 00 34 04 69 00 00 00
+trackline 10 02 25 04 00 00 00 00
+trackline 10 04 34 04 00 00 00 00
+trackline 10 06 33 04 00 00 00 00
+trackline 10 08 25 04 00 00 00 00
+trackline 10 0a 31 04 00 00 00 00
+trackline 10 0c 36 04 00 00 00 00
+trackline 10 0e 33 04 00 00 00 00
+trackline 10 10 34 04 00 00 00 00
+trackline 10 12 25 04 00 00 00 00
+trackline 10 14 34 04 00 00 00 00
+trackline 10 16 33 04 00 00 00 00
+trackline 10 18 25 04 00 00 00 00
+trackline 10 1a 31 04 00 00 00 00
+trackline 10 1c 33 04 00 00 00 00
+trackline 10 1e 2f 04 00 00 00 00
+trackline 20 00 38 03 69 00 00 00
+trackline 20 03 00 00 76 c0 00 00
+trackline 20 08 31 03 00 00 00 00
+trackline 20 0b 00 00 76 c0 00 00
+trackline 20 10 38 03 00 00 00 00
+trackline 20 11 00 00 76 40 00 00
+trackline 20 12 00 00 76 00 00 00
+trackline 20 14 38 03 00 00 00 00
+trackline 20 15 00 00 76 00 00 00
+trackline 20 16 39 03 00 00 00 00
+trackline 20 19 00 00 76 00 00 00
+trackline 20 1a 36 03 00 00 00 00
+trackline 20 1b 00 00 76 00 00 00
+trackline 20 1c 3d 03 00 00 00 00
+trackline 20 1e 37 03 00 00 00 00
+trackline 21 00 38 03 00 00 00 00
+trackline 21 03 00 00 76 c0 00 00
+trackline 21 08 31 03 00 00 00 00
+trackline 21 0b 00 00 76 c0 00 00
+trackline 21 10 38 03 00 00 00 00
+trackline 21 12 36 03 00 00 00 00
+trackline 21 14 34 03 00 00 00 00
+trackline 21 15 00 00 76 00 00 00
+trackline 21 16 31 03 00 00 00 00
+trackline 21 19 00 00 76 00 00 00
+trackline 21 1a 34 03 00 00 00 00
+trackline 21 1b 00 00 76 00 00 00
+trackline 21 1c 38 03 00 00 00 00
+trackline 21 1d 39 03 00 00 00 00
+trackline 21 1e 3b 03 00 00 00 00
+trackline 21 1f 3d 03 00 00 00 00
+trackline 22 00 40 03 00 00 00 00
+trackline 22 04 40 03 00 00 00 00
+trackline 22 06 3d 03 00 00 00 00
+trackline 22 0a 39 03 00 00 00 00
+trackline 22 0c 42 03 00 00 00 00
+trackline 22 0e 40 03 00 00 00 00
+trackline 22 10 3f 03 00 00 00 00
+trackline 22 12 40 03 00 00 00 00
+trackline 22 14 42 03 00 00 00 00
+trackline 22 16 3b 03 00 00 00 00
+trackline 22 1a 38 03 00 00 00 00
+trackline 22 1c 33 03 00 00 00 00
+trackline 22 1e 36 03 00 00 00 00
+trackline 23 00 40 03 00 00 00 00
+trackline 23 02 3f 03 00 00 00 00
+trackline 23 04 00 00 76 00 00 00
+trackline 23 06 3d 03 00 00 00 00
+trackline 23 14 00 00 66 fe 00 00
+trackline 24 00 31 03 00 00 00 00
+trackline 24 01 00 00 76 00 00 00
+trackline 24 02 33 03 00 00 00 00
+trackline 24 03 00 00 76 c0 00 00
+trackline 24 06 34 03 00 00 00 00
+trackline 24 08 00 00 76 00 00 00
+trackline 24 0a 31 03 00 00 00 00
+trackline 24 0b 00 00 76 c0 00 00
+trackline 24 0c 36 03 00 00 00 00
+trackline 24 0d 00 00 76 00 00 00
+trackline 24 0e 31 03 00 00 00 00
+trackline 24 0f 00 00 76 00 00 00
+trackline 24 10 38 03 00 00 00 00
+trackline 24 11 36 03 00 40 00 00
+trackline 24 12 34 03 00 00 00 00
+trackline 24 14 38 03 00 00 00 00
+trackline 24 15 00 00 76 00 00 00
+trackline 24 16 36 03 00 00 00 00
+trackline 24 18 34 03 00 00 00 00
+trackline 24 19 00 00 76 00 00 00
+trackline 24 1a 33 03 00 00 00 00
+trackline 24 1b 00 00 76 00 00 00
+trackline 24 1c 31 03 00 00 00 00
+trackline 25 00 2c 03 00 00 00 00
+trackline 25 01 00 00 69 ff 00 00
+trackline 25 02 25 03 00 00 00 00
+trackline 25 04 31 03 00 00 00 00
+trackline 25 06 25 03 00 00 00 00
+trackline 25 08 2c 03 00 00 00 00
+trackline 25 0a 25 03 00 00 00 00
+trackline 25 0c 31 03 00 00 00 00
+trackline 25 0d 00 00 69 00 00 00
+trackline 25 0e 25 03 00 00 00 00
+trackline 25 10 34 03 00 00 00 00
+trackline 25 11 33 03 00 00 00 00
+trackline 25 12 31 03 00 00 00 00
+trackline 25 13 2c 03 00 00 00 00
+trackline 25 14 2a 03 00 00 00 00
+trackline 25 15 28 03 00 00 00 00
+trackline 25 16 25 03 00 00 00 00
+trackline 25 17 20 03 00 00 00 00
+trackline 25 18 1c 03 00 00 00 00
+trackline 25 19 1e 03 00 00 00 00
+trackline 25 1a 1f 03 00 00 00 00
+trackline 25 1b 20 03 00 00 00 00
+trackline 25 1c 25 03 00 00 00 00
+trackline 25 1d 2d 03 00 00 00 00
+trackline 25 1e 31 03 00 00 00 00
+trackline 25 1f 38 03 00 00 00 00
+trackline 26 00 25 03 00 00 00 00
+trackline 26 01 00 00 69 ff 00 00
+trackline 26 02 19 03 00 00 00 00
+trackline 26 04 19 03 00 00 00 00
+trackline 26 06 28 03 00 00 00 00
+trackline 26 08 19 03 00 00 00 00
+trackline 26 0a 25 03 00 00 00 00
+trackline 26 0c 2c 03 00 00 00 00
+trackline 26 0e 23 03 00 00 00 00
+trackline 26 10 25 03 00 00 00 00
+trackline 26 12 19 03 00 00 00 00
+trackline 26 14 19 03 00 00 00 00
+trackline 26 16 28 03 00 00 00 00
+trackline 26 18 2f 03 00 00 00 00
+trackline 26 1a 2c 03 00 00 00 00
+trackline 26 1b 00 00 69 00 00 00
+trackline 26 1c 25 03 00 00 00 00
+trackline 26 1d 27 03 00 00 00 00
+trackline 26 1e 28 03 00 00 00 00
+trackline 26 1f 2c 03 00 00 00 00
+trackline 27 00 2c 03 00 00 00 00
+trackline 27 01 00 00 69 ff 00 00
+trackline 27 02 31 03 00 00 00 00
+trackline 27 04 19 03 00 00 00 00
+trackline 27 06 2c 03 00 00 00 00
+trackline 27 08 25 03 00 00 00 00
+trackline 27 0a 19 03 00 00 00 00
+trackline 27 0c 2c 03 00 00 00 00
+trackline 27 0d 00 00 76 00 00 00
+trackline 27 0e 31 03 69 00 00 00
+trackline 27 0f 00 00 76 00 00 00
+trackline 27 10 19 03 00 00 00 00
+trackline 27 11 00 00 69 ff 00 00
+trackline 27 12 2c 03 00 00 00 00
+trackline 27 14 25 03 00 00 00 00
+trackline 27 16 19 03 00 00 00 00
+trackline 27 18 25 03 00 00 00 00
+trackline 27 1a 19 03 00 00 00 00
+trackline 27 1b 00 00 69 00 00 00
+trackline 27 1c 2c 03 00 00 00 00
+trackline 27 1d 00 00 76 00 00 00
+trackline 27 1e 2f 03 00 00 00 00
+trackline 27 1f 00 00 76 00 00 00
+trackline 28 00 34 03 00 00 00 00
+trackline 28 01 00 00 76 00 00 00
+trackline 28 02 36 03 00 00 00 00
+trackline 28 06 38 03 00 00 00 00
+trackline 28 07 00 00 76 80 00 00
+trackline 28 0a 34 03 00 00 00 00
+trackline 28 0c 3b 03 00 00 00 00
+trackline 28 0d 39 03 00 00 00 00
+trackline 28 0e 38 03 00 00 00 00
+trackline 28 10 3b 03 00 00 00 00
+trackline 28 12 3d 03 00 00 00 00
+trackline 28 14 3f 03 00 00 00 00
+trackline 28 15 00 00 76 00 00 00
+trackline 28 16 42 03 00 00 00 00
+trackline 28 1a 38 03 00 00 00 00
+trackline 28 1c 33 03 00 00 00 00
+trackline 28 1e 36 03 00 00 00 00
+trackline 30 00 0d 05 00 00 00 00
+trackline 30 02 01 05 00 00 00 00
+trackline 30 09 00 00 76 00 00 00
+trackline 30 0c 06 05 00 00 00 00
+trackline 30 0d 08 05 00 00 00 00
+trackline 30 0e 0b 05 00 00 00 00
+trackline 30 10 0d 05 00 00 00 00
+trackline 30 12 01 05 00 00 00 00
+trackline 30 14 01 05 00 00 00 00
+trackline 30 19 00 00 76 00 00 00
+trackline 31 04 0d 05 00 00 00 00
+trackline 31 07 00 00 76 80 00 00
+trackline 31 0a 0d 05 00 00 00 00
+trackline 31 0c 00 00 76 00 00 00
+trackline 31 0e 0d 05 00 00 00 00
+trackline 31 10 01 05 00 00 00 00
+trackline 32 00 09 05 00 00 00 00
+trackline 32 06 15 05 00 00 00 00
+trackline 32 08 00 00 76 00 00 00
+trackline 32 0a 10 05 00 00 00 00
+trackline 32 0c 09 05 00 00 00 00
+trackline 32 0e 06 05 00 00 00 00
+trackline 32 10 0b 05 00 00 00 00
+trackline 32 12 0b 05 00 00 00 00
+trackline 32 15 00 00 76 00 00 00
+trackline 32 16 08 05 00 00 00 00
+trackline 32 17 00 00 76 c0 00 00
+trackline 32 1a 03 05 00 00 00 00
+trackline 32 1b 00 00 76 c0 00 00
+trackline 32 1e 08 05 00 00 00 00
+trackline 33 00 01 05 00 00 00 00
+trackline 34 00 09 05 00 00 00 00
+trackline 34 06 15 05 00 00 00 00
+trackline 34 08 00 00 76 00 00 00
+trackline 34 0a 10 05 00 00 00 00
+trackline 34 0c 09 05 00 00 00 00
+trackline 34 0e 06 05 00 00 00 00
+trackline 34 10 08 05 00 00 00 00
+trackline 34 12 08 05 00 00 00 00
+trackline 34 15 00 00 76 00 00 00
+trackline 34 16 08 05 00 00 00 00
+trackline 34 17 00 00 76 c0 00 00
+trackline 34 1a 03 05 00 00 00 00
+trackline 34 1b 00 00 76 c0 00 00
+trackline 34 1e 08 05 00 00 00 00
+trackline 40 00 28 06 00 00 00 00
+trackline 40 0c 23 06 00 00 00 00
+trackline 40 0e 00 00 76 00 00 00
+trackline 40 10 2b 06 00 00 00 00
+trackline 40 15 00 00 76 00 00 00
+trackline 40 16 2a 06 00 00 00 00
+trackline 40 1b 00 00 76 00 00 00
+trackline 40 1c 28 06 00 00 00 00
+trackline 40 1f 00 00 76 00 00 00
+trackline 41 00 27 06 00 34 00 00
+trackline 41 05 00 00 76 00 00 00
+trackline 41 06 28 06 00 00 00 00
+trackline 41 07 00 00 76 00 00 00
+trackline 41 08 2a 06 00 00 00 00
+trackline 41 12 00 00 66 fd 00 00
+trackline 42 00 24 06 00 00 00 00
+trackline 42 0c 26 06 00 00 00 00
+trackline 42 10 28 06 00 00 00 00
+trackline 42 18 24 06 00 00 00 00
+trackline 42 1b 00 00 6c f8 00 00
+trackline 43 00 23 06 00 00 00 00
+trackline 43 08 00 00 66 ff 00 00
+trackline 44 00 27 06 00 00 00 00
+trackline 44 04 27 06 00 00 00 00
+trackline 44 06 28 06 00 00 00 00
+trackline 44 0a 28 06 00 00 00 00
+trackline 44 0c 2a 06 00 00 00 00
+trackline 44 10 00 00 66 f8 00 00
+trackline 44 14 2d 06 00 00 00 00
+trackline 44 18 2d 06 00 00 00 00
+trackline 44 1a 2a 06 00 00 00 00
+trackline 44 1b 00 00 76 00 00 00
+trackline 44 1c 24 06 00 00 00 00
+trackline 44 1d 00 00 76 00 00 00
+trackline 44 1e 23 06 00 00 00 00
+trackline 44 1f 00 00 76 00 00 00
+trackline 45 00 28 06 00 00 00 00
+trackline 45 04 00 00 66 fc 00 00
+trackline 45 08 2b 06 00 00 00 00
+trackline 45 0c 00 00 66 fc 00 00
+trackline 45 10 2a 06 00 00 00 00
+trackline 45 14 00 00 66 fc 00 00
+trackline 45 18 26 06 00 00 00 00
+trackline 45 1a 00 00 6c 03 00 00
+trackline 46 00 28 06 00 00 00 00
+trackline 50 00 04 05 00 00 00 00
+trackline 50 04 04 05 00 00 00 00
+trackline 50 06 10 05 00 00 00 00
+trackline 50 0a 0b 05 00 00 00 00
+trackline 50 0c 0e 05 00 00 00 00
+trackline 50 0e 0f 05 00 00 00 00
+trackline 50 10 04 05 00 00 00 00
+trackline 50 14 04 05 00 00 00 00
+trackline 50 16 10 05 00 00 00 00
+trackline 50 1a 0b 05 00 00 00 00
+trackline 50 1c 10 05 00 00 00 00
+trackline 50 1d 10 05 00 00 00 00
+trackline 50 1e 0b 05 00 00 00 00
+trackline 50 1f 04 05 00 00 00 00
+trackline 51 00 0b 05 00 00 00 00
+trackline 51 04 0b 05 00 00 00 00
+trackline 51 06 17 05 00 00 00 00
+trackline 51 0a 06 05 00 00 00 00
+trackline 51 0c 09 05 00 00 00 00
+trackline 51 0e 0a 05 00 00 00 00
+trackline 51 10 0b 05 00 00 00 00
+trackline 51 14 0d 05 00 00 00 00
+trackline 51 18 0e 05 00 00 00 00
+trackline 51 1c 0f 05 00 00 00 00
+trackline 51 1d 00 00 6c e0 00 00
+trackline 52 00 0c 05 00 00 00 00
+trackline 52 02 0c 05 00 00 00 00
+trackline 52 04 00 00 76 00 00 00
+trackline 52 06 07 05 00 00 00 00
+trackline 52 08 0a 05 00 00 00 00
+trackline 52 0a 0c 05 00 00 00 00
+trackline 52 0c 00 00 76 00 00 00
+trackline 52 0e 0a 05 00 00 00 00
+trackline 52 10 0c 05 00 00 00 00
+trackline 52 12 0c 05 00 00 00 00
+trackline 52 14 00 00 76 00 00 00
+trackline 52 16 07 05 00 00 00 00
+trackline 52 18 0f 05 00 00 00 00
+trackline 52 1a 0e 05 00 00 00 00
+trackline 52 1c 0c 05 00 00 00 00
+trackline 52 1e 05 05 00 00 00 00
+trackline 53 00 07 05 00 00 00 00
+trackline 53 02 07 05 00 00 00 00
+trackline 53 06 13 05 00 00 00 00
+trackline 53 0a 10 05 00 00 00 00
+trackline 53 0c 0e 05 00 00 00 00
+trackline 53 0e 0b 05 00 00 00 00
+trackline 53 10 09 05 00 00 00 00
+trackline 53 11 07 05 00 00 00 00
+trackline 53 12 17 05 00 00 00 00
+trackline 53 13 15 05 00 00 00 00
+trackline 53 14 13 05 00 00 00 00
+trackline 53 15 10 05 00 00 00 00
+trackline 53 16 0e 05 00 00 00 00
+trackline 53 17 09 05 00 00 00 00
+trackline 53 18 07 05 00 00 00 00
+trackline 53 1c 09 05 00 00 00 00
+trackline 54 00 0b 05 00 00 00 00
+trackline 55 00 0c 05 00 00 00 00
+trackline 55 0c 0c 05 00 00 00 00
+trackline 55 10 0e 05 00 00 00 00
+trackline 55 1c 0e 05 00 00 00 00
+trackline 56 00 10 05 00 00 00 00
+trackline 56 06 10 05 00 00 00 00
+trackline 56 08 00 00 76 00 00 00
+trackline 56 0c 04 05 00 00 00 00
+trackline 60 00 25 07 00 00 00 00
+trackline 60 0a 28 08 00 00 00 00
+trackline 60 0e 28 08 00 00 00 00
+trackline 60 0f 00 00 76 00 00 00
+trackline 60 10 28 08 00 00 00 00
+trackline 60 16 34 08 00 00 00 00
+trackline 60 17 00 00 76 80 00 00
+trackline 60 1a 34 08 00 00 00 00
+trackline 60 1b 00 00 76 00 00 00
+trackline 60 1c 28 08 00 00 00 00
+trackline 61 00 23 09 00 00 00 00
+trackline 61 05 00 00 76 00 00 00
+trackline 61 06 2f 09 00 00 00 00
+trackline 61 07 00 00 76 80 00 00
+trackline 61 0a 23 09 00 00 00 00
+trackline 61 0e 23 09 00 00 00 00
+trackline 61 0f 00 00 76 00 00 00
+trackline 61 10 2f 09 00 00 00 00
+trackline 61 14 23 09 00 00 00 00
+trackline 61 18 23 09 00 00 00 00
+trackline 61 1a 2f 09 00 00 00 00
+trackline 61 1c 23 09 00 00 00 00
+trackline 62 00 24 09 00 00 00 00
+trackline 62 05 00 00 76 00 00 00
+trackline 62 06 30 09 00 00 00 00
+trackline 62 07 00 00 76 80 00 00
+trackline 62 0a 24 09 00 00 00 00
+trackline 62 0e 24 09 00 00 00 00
+trackline 62 0f 00 00 76 00 00 00
+trackline 62 10 24 09 00 00 00 00
+trackline 62 16 30 09 00 00 00 00
+trackline 62 17 00 00 76 80 00 00
+trackline 62 1a 30 09 00 00 00 00
+trackline 62 1b 00 00 76 00 00 00
+trackline 62 1c 24 09 00 00 00 00
+trackline 63 00 2b 09 00 00 00 00
+trackline 63 01 00 00 76 00 00 00
+trackline 63 02 1f 09 00 00 00 00
+trackline 63 05 00 00 76 00 00 00
+trackline 63 06 2b 09 00 00 00 00
+trackline 63 07 00 00 76 00 00 00
+trackline 63 08 2b 09 00 00 00 00
+trackline 63 09 00 00 76 00 00 00
+trackline 63 0a 1f 09 00 00 00 00
+trackline 63 0d 00 00 76 00 00 00
+trackline 63 0e 2b 09 00 00 00 00
+trackline 63 0f 00 00 76 00 00 00
+trackline 63 10 2b 09 00 00 00 00
+trackline 63 11 00 00 76 00 00 00
+trackline 63 12 1f 09 00 00 00 00
+trackline 63 15 00 00 76 00 00 00
+trackline 63 16 1f 09 00 00 00 00
+trackline 63 1a 2b 09 00 00 00 00
+trackline 63 1b 00 00 76 80 00 00
+trackline 63 1e 1f 09 00 00 00 00
+trackline 63 1f 00 00 76 00 00 00
+trackline 64 00 24 09 00 00 00 00
+trackline 64 04 24 09 00 00 00 00
+trackline 64 05 00 00 76 00 00 00
+trackline 64 06 30 09 00 00 00 00
+trackline 64 08 00 00 76 00 00 00
+trackline 64 0a 30 09 00 00 00 00
+trackline 64 0b 00 00 76 00 00 00
+trackline 64 0c 24 09 00 00 00 00
+trackline 64 10 26 09 00 00 00 00
+trackline 64 12 00 00 76 00 00 00
+trackline 64 14 26 09 00 00 00 00
+trackline 64 15 00 00 76 00 00 00
+trackline 64 16 32 09 00 00 00 00
+trackline 64 19 00 00 76 00 00 00
+trackline 64 1a 32 09 00 00 00 00
+trackline 64 1b 00 00 76 00 00 00
+trackline 64 1c 26 09 00 00 00 00
+trackline 64 1d 00 00 76 00 00 00
+trackline 64 1e 32 09 00 00 00 00
+trackline 64 1f 00 00 76 00 00 00
+trackline 65 00 34 09 00 00 00 00
+trackline 65 02 34 09 00 00 00 00
+trackline 65 03 34 09 00 00 00 00
+trackline 65 04 34 09 00 00 00 00
+trackline 65 05 00 00 76 00 00 00
+trackline 65 06 28 09 00 00 00 00
+trackline 65 08 00 00 76 00 00 00
+trackline 65 0a 28 09 00 00 00 00
+trackline 65 0b 00 00 76 00 00 00
+trackline 65 0c 28 09 00 00 00 00
+trackline 65 0e 34 09 00 00 00 00
+trackline 65 10 28 09 00 00 00 00
+trackline 66 00 34 0a 00 00 00 00
+trackline 66 02 34 0a 00 00 00 00
+trackline 66 03 28 0a 00 00 00 00
+trackline 66 04 34 0a 00 00 00 00
+trackline 66 05 00 00 76 00 00 00
+trackline 66 06 28 0a 00 00 00 00
+trackline 66 08 00 00 76 00 00 00
+trackline 66 0a 28 0a 00 00 00 00
+trackline 66 0b 00 00 76 00 00 00
+trackline 66 0c 28 0a 00 00 00 00
+trackline 66 10 34 0a 00 00 00 00
+trackline 66 12 34 0a 00 00 00 00
+trackline 66 13 34 0a 00 00 00 00
+trackline 66 14 34 0a 00 00 00 00
+trackline 66 15 00 00 76 00 00 00
+trackline 66 16 28 0a 00 00 00 00
+trackline 66 18 00 00 76 00 00 00
+trackline 66 1a 28 0a 00 00 00 00
+trackline 66 1b 00 00 76 00 00 00
+trackline 66 1c 28 0a 00 00 00 00
+trackline 66 1e 34 0a 00 00 00 00
+trackline 67 00 21 09 00 00 00 00
+trackline 67 10 23 09 00 00 00 00
+trackline 68 00 25 08 00 00 00 00
+trackline 70 00 25 07 00 ff 00 00
+trackline 70 08 2c 0b 00 00 00 00
+trackline 70 0a 25 0b 00 00 00 00
+trackline 70 0e 2c 0b 00 00 00 00
+trackline 70 10 31 0b 00 00 00 00
+trackline 70 12 2c 0b 00 00 00 00
+trackline 70 14 25 0b 00 00 00 00
+trackline 70 16 34 0b 00 00 00 00
+trackline 70 17 00 00 66 00 00 00
+trackline 70 18 33 0b 00 00 00 00
+trackline 70 1a 2c 0b 00 00 00 00
+trackline 70 1c 25 0b 00 00 00 00
+trackline 70 1e 36 0b 00 00 00 00
+trackline 71 00 38 0b 00 00 00 00
+trackline 71 18 31 0b 00 00 00 00
+trackline 71 1a 34 0b 00 00 00 00
+trackline 71 1b 36 0b 00 00 00 00
+trackline 71 1c 37 0b 00 00 00 00
+trackline 71 1d 38 0b 00 00 00 00
+trackline 71 1e 3b 0b 00 00 00 00
+trackline 71 1f 3d 0b 00 00 00 00
+trackline 72 00 40 0b 00 00 00 00
+trackline 72 08 3d 0b 00 00 00 00
+trackline 72 0c 40 0b 00 00 00 00
+trackline 72 10 3f 0b 00 00 00 00
+trackline 72 11 00 00 76 00 00 00
+trackline 72 12 3b 0b 00 00 00 00
+trackline 72 14 00 00 76 00 00 00
+trackline 72 16 38 0b 00 00 00 00
+trackline 72 1a 38 0b 00 00 00 00
+trackline 72 1b 00 00 76 00 00 00
+trackline 72 1c 3f 0b 00 00 00 00
+trackline 72 1e 3b 0b 00 00 00 00
+trackline 73 00 40 0b 00 00 00 00
+trackline 73 01 3f 0b 00 00 00 00
+trackline 73 02 3d 0b 00 00 00 00
+trackline 73 03 38 0b 00 00 00 00
+trackline 73 04 34 0b 00 00 00 00
+trackline 73 05 33 0b 00 00 00 00
+trackline 73 06 36 0b 00 00 00 00
+trackline 73 07 33 0b 00 00 00 00
+trackline 73 08 34 0b 00 00 00 00
+trackline 73 09 33 0b 00 00 00 00
+trackline 73 0a 31 0b 00 00 00 00
+trackline 73 0b 2c 0b 00 00 00 00
+trackline 73 0c 2f 0b 00 00 00 00
+trackline 73 0d 2a 0b 00 00 00 00
+trackline 73 0e 33 0b 00 00 00 00
+trackline 73 0f 2f 0b 00 00 00 00
+trackline 73 10 31 0b 00 00 00 00
+trackline 73 11 00 00 76 00 00 00
+trackline 73 12 31 0b 00 00 00 00
+trackline 73 13 00 00 76 00 00 00
+trackline 73 14 31 0b 00 00 00 00
+trackline 73 15 00 00 76 00 00 00
+trackline 73 16 31 0b 00 00 00 00
+trackline 73 19 00 00 76 00 00 00
+trackline 73 1a 31 0b 00 00 00 00
+trackline 73 1b 00 00 76 00 00 00
+trackline 73 1c 3d 0b 00 00 00 00
+trackline 73 1d 00 00 76 00 00 00
+trackline 73 1e 31 0b 00 00 00 00
+trackline 73 1f 00 00 76 00 00 00
+trackline 74 00 40 0b 00 00 00 00
+trackline 74 02 31 0b 00 00 00 00
+trackline 74 04 31 0b 00 00 00 00
+trackline 74 06 3d 0b 00 00 00 00
+trackline 74 08 31 0b 00 00 00 00
+trackline 74 0a 3d 0b 00 00 00 00
+trackline 74 0c 42 0b 00 00 00 00
+trackline 74 0d 40 0b 00 00 00 00
+trackline 74 0e 3f 0b 00 00 00 00
+trackline 74 10 40 0b 00 00 00 00
+trackline 74 12 31 0b 00 00 00 00
+trackline 74 14 31 0b 00 00 00 00
+trackline 74 16 3d 0b 00 00 00 00
+trackline 74 18 31 0b 00 00 00 00
+trackline 74 1a 3d 0b 00 00 00 00
+trackline 74 1c 42 0b 00 00 00 00
+trackline 74 1d 40 0b 00 00 00 00
+trackline 74 1e 3f 0b 00 00 00 00
+trackline 75 00 3f 0b 00 00 00 00
+trackline 75 02 40 0b 00 00 00 00
+trackline 75 03 00 00 76 00 00 00
+trackline 75 04 44 0b 00 00 00 00
+trackline 75 05 00 00 76 00 00 00
+trackline 75 06 3d 0b 00 00 00 00
+trackline 75 07 44 0d 00 10 00 00
+trackline 75 08 42 0b 00 00 00 00
+trackline 75 09 3d 0d 00 10 00 00
+trackline 75 0a 31 0b 00 00 00 00
+trackline 75 0b 42 0d 00 00 00 00
+trackline 75 0c 40 0b 00 00 00 00
+trackline 75 0d 31 0d 00 00 00 00
+trackline 75 0e 38 0b 00 00 00 00
+trackline 75 0f 40 0d 00 00 00 00
+trackline 75 10 3f 0b 00 00 00 00
+trackline 75 11 3d 0d 00 00 00 00
+trackline 75 12 31 0b 00 00 00 00
+trackline 75 13 3f 0d 00 00 00 00
+trackline 75 14 3b 0b 00 00 00 00
+trackline 75 15 31 0d 00 00 00 00
+trackline 75 16 38 0b 00 00 00 00
+trackline 75 17 3b 0d 00 00 00 00
+trackline 75 18 38 0b 00 00 00 00
+trackline 75 19 38 0d 00 00 00 00
+trackline 75 1a 31 0b 00 00 00 00
+trackline 75 1b 44 0d 00 00 00 00
+trackline 75 1c 3b 0b 00 00 00 00
+trackline 75 1d 31 0d 00 00 00 00
+trackline 75 1e 3d 0b 00 00 00 00
+trackline 75 1f 3f 0b 00 00 00 00
+trackline 80 00 34 03 00 00 00 00
+trackline 80 08 31 03 00 00 00 00
+trackline 80 0c 34 03 00 00 00 00
+trackline 80 10 33 03 00 00 00 00
+trackline 80 18 31 03 00 00 00 00
+trackline 80 1c 2f 03 00 00 00 00
+trackline 81 1d 2f 03 00 00 00 00
+trackline 81 1e 31 03 00 00 00 00
+trackline 81 1f 33 03 00 00 00 00
+trackline 82 00 2f 03 6c 10 00 00
+trackline 82 04 31 03 00 00 00 00
+trackline 83 00 01 0b 00 00 00 00
+trackline 90 00 21 09 69 00 00 00
+trackline 90 04 21 09 00 00 00 00
+trackline 90 05 00 00 76 00 00 00
+trackline 90 06 2d 09 00 00 00 00
+trackline 90 0a 2d 09 00 00 00 00
+trackline 90 0b 00 00 76 00 00 00
+trackline 90 0c 21 09 00 00 00 00
+trackline 90 10 23 09 00 00 00 00
+trackline 90 12 00 00 76 80 00 00
+trackline 90 14 23 09 00 00 00 00
+trackline 90 16 00 00 76 80 00 00
+trackline 90 18 20 08 00 00 00 00
+trackline 90 1a 00 00 76 80 00 00
+trackline 90 1c 20 08 00 00 00 00
+trackline 90 1e 00 00 76 80 00 00
+trackline 91 00 25 08 00 00 00 00
+trackline 91 01 00 00 76 00 00 00
+trackline 91 02 25 08 00 00 00 00
+trackline 91 05 00 00 76 00 00 00
+trackline 91 06 31 08 00 00 00 00
+trackline 91 07 31 08 00 00 00 00
+trackline 91 08 25 08 00 00 00 00
+trackline 91 09 00 00 76 00 00 00
+trackline 91 0a 25 08 00 00 00 00
+trackline 91 0b 00 00 76 00 00 00
+trackline 91 0e 25 08 00 00 00 00
+trackline 91 0f 00 00 76 00 00 00
+trackline 91 10 25 0a 00 00 00 00
+trackline 91 11 00 00 76 00 00 00
+trackline 91 14 25 0a 00 00 00 00
+trackline 91 15 00 00 76 00 00 00
+trackline 91 16 25 08 00 00 00 00
+trackline 91 17 00 00 76 00 00 00
+trackline 91 1a 25 08 00 00 00 00
+trackline 91 1b 00 00 76 00 00 00
+trackline 91 1c 25 08 00 00 00 00
+trackline 91 1d 00 00 76 00 00 00
+trackline 91 1e 25 08 00 00 00 00
+trackline 91 1f 00 00 76 00 00 00
+trackline 92 00 19 03 69 70 00 00
+trackline 92 01 00 00 76 00 00 00
+trackline 92 02 25 03 00 00 00 00
+trackline 92 03 00 00 76 00 00 00
+trackline 92 04 25 03 00 00 00 00
+trackline 92 05 00 00 76 00 00 00
+trackline 92 06 19 03 00 00 00 00
+trackline 92 07 00 00 76 00 00 00
+trackline 92 08 25 03 00 00 00 00
+trackline 92 09 00 00 76 00 00 00
+trackline 92 0a 19 03 00 00 00 00
+trackline 92 0b 00 00 76 00 00 00
+trackline 92 0c 25 03 00 00 00 00
+trackline 92 0d 00 00 76 00 00 00
+trackline 92 0e 25 03 00 00 00 00
+trackline 92 0f 00 00 76 00 00 00
+trackline 92 10 19 03 00 00 00 00
+trackline 92 11 00 00 76 00 00 00
+trackline 92 12 25 03 00 00 00 00
+trackline 92 13 00 00 76 00 00 00
+trackline 92 14 25 03 00 00 00 00
+trackline 92 15 00 00 76 00 00 00
+trackline 92 16 19 03 00 00 00 00
+trackline 92 17 00 00 76 00 00 00
+trackline 92 18 25 03 00 00 00 00
+trackline 92 19 00 00 76 00 00 00
+trackline 92 1a 19 03 69 00 00 00
+trackline 92 1b 19 03 66 c0 00 00
+trackline 92 1c 25 03 00 00 00 00
+trackline 92 1d 00 00 76 00 00 00
+trackline 92 1e 25 03 00 00 00 00
+trackline 92 1f 00 00 76 00 00 00
+
+instrumentline 01 00 77 03
+instrumentline 01 01 76 ff
+instrumentline 01 02 74 01
+instrumentline 01 03 77 02
+instrumentline 01 04 64 90
+instrumentline 01 05 2b 31
+instrumentline 01 06 6c a0
+instrumentline 01 07 66 f0
+instrumentline 02 00 76 ff
+instrumentline 02 01 77 03
+instrumentline 02 02 74 02
+instrumentline 02 03 77 02
+instrumentline 02 04 2b 31
+instrumentline 02 05 64 70
+instrumentline 02 06 6c d0
+instrumentline 02 07 74 02
+instrumentline 02 08 66 f8
+instrumentline 02 09 6a 01
+instrumentline 03 00 77 02
+instrumentline 03 01 6d 05
+instrumentline 03 02 2b 31
+instrumentline 03 03 76 ff
+instrumentline 03 04 66 f0
+instrumentline 03 05 74 06
+instrumentline 03 06 66 00
+instrumentline 03 07 74 16
+instrumentline 03 08 7e 25
+instrumentline 04 00 77 03
+instrumentline 04 01 76 ff
+instrumentline 04 02 74 01
+instrumentline 04 03 77 00
+instrumentline 04 04 6d 05
+instrumentline 04 05 2b 3d
+instrumentline 04 06 66 f0
+instrumentline 04 07 74 06
+instrumentline 04 08 66 00
+instrumentline 04 09 74 20
+instrumentline 04 0a 66 f0
+instrumentline 05 00 77 03
+instrumentline 05 01 76 ff
+instrumentline 05 02 74 01
+instrumentline 05 03 77 02
+instrumentline 05 04 64 50
+instrumentline 05 05 6d 01
+instrumentline 05 06 2b 31
+instrumentline 05 07 74 05
+instrumentline 05 08 66 fe
+instrumentline 06 00 77 02
+instrumentline 06 01 64 80
+instrumentline 06 02 2b 3d
+instrumentline 06 03 76 c0
+instrumentline 06 04 66 08
+instrumentline 06 05 74 02
+instrumentline 06 06 66 f0
+instrumentline 06 07 74 02
+instrumentline 06 08 66 00
+instrumentline 06 09 74 16
+instrumentline 06 0a 7e 34
+instrumentline 07 00 77 03
+instrumentline 07 01 76 ff
+instrumentline 07 02 66 fc
+instrumentline 08 00 69 00
+instrumentline 08 01 77 03
+instrumentline 08 02 76 ff
+instrumentline 08 03 74 01
+instrumentline 08 04 77 02
+instrumentline 08 05 6d 05
+instrumentline 08 06 66 ff
+instrumentline 08 07 2b 3d
+instrumentline 08 08 74 03
+instrumentline 08 09 2b 38
+instrumentline 08 0a 74 03
+instrumentline 08 0b 2b 34
+instrumentline 08 0c 74 03
+instrumentline 08 0d 2b 31
+instrumentline 08 0e 74 03
+instrumentline 08 0f 6a 07
+instrumentline 09 00 69 00
+instrumentline 09 01 77 03
+instrumentline 09 02 76 ff
+instrumentline 09 03 74 01
+instrumentline 09 04 77 02
+instrumentline 09 05 6d 05
+instrumentline 09 06 66 ff
+instrumentline 09 07 2b 3d
+instrumentline 09 08 74 03
+instrumentline 09 09 2b 38
+instrumentline 09 0a 74 03
+instrumentline 09 0b 2b 35
+instrumentline 09 0c 74 03
+instrumentline 09 0d 2b 31
+instrumentline 09 0e 74 03
+instrumentline 09 0f 6a 07
+instrumentline 0a 00 69 00
+instrumentline 0a 01 77 03
+instrumentline 0a 02 76 ff
+instrumentline 0a 03 74 01
+instrumentline 0a 04 77 02
+instrumentline 0a 05 6d 05
+instrumentline 0a 06 66 ff
+instrumentline 0a 07 2b 3d
+instrumentline 0a 08 74 03
+instrumentline 0a 09 2b 38
+instrumentline 0a 0a 74 03
+instrumentline 0a 0b 2b 36
+instrumentline 0a 0c 74 03
+instrumentline 0a 0d 2b 31
+instrumentline 0a 0e 74 03
+instrumentline 0a 0f 6a 07
+instrumentline 0b 00 77 03
+instrumentline 0b 01 76 ff
+instrumentline 0b 02 74 01
+instrumentline 0b 03 77 00
+instrumentline 0b 04 6d 05
+instrumentline 0b 05 2b 3d
+instrumentline 0b 06 66 f0
+instrumentline 0b 07 74 06
+instrumentline 0b 08 66 00
+instrumentline 0b 09 74 06
+instrumentline 0b 0a 7e 25
+instrumentline 0c 00 77 03
+instrumentline 0c 01 76 ff
+instrumentline 0c 02 66 f0
+instrumentline 0d 00 76 c4
+instrumentline 0d 01 77 00
+instrumentline 0d 02 6d 05
+instrumentline 0d 03 2b 3d
+instrumentline 0d 04 66 f0
+instrumentline 0d 05 74 06
+instrumentline 0d 06 66 00
+instrumentline 0d 07 74 06
+instrumentline 0d 08 7e 25