--- /dev/null
+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 $@ $^
--- /dev/null
+ .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
--- /dev/null
+#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]
+}
+*/
--- /dev/null
+LDFLAGS=-lSDL -lncurses
+CFLAGS=-Wall
+CC=gcc
+
+all: tracker
+
+tracker: main.o chip.o gui.o
+ gcc -o $@ $^ ${LDFLAGS}
+
+%.o: %.c stuff.h Makefile
--- /dev/null
+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)
--- /dev/null
+#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]
+}
--- /dev/null
+#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,
+ ¬e,
+ &instr,
+ &cmd[0],
+ ¶m[0],
+ &cmd[1],
+ ¶m[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],
+ ¶m[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();
+ }
+}
--- /dev/null
+#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;
+}
--- /dev/null
+
+
+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)
--- /dev/null
+#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;
--- /dev/null
+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