From 6be18aec30d56a5dc2de325557a26c8be20462dd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Linus=20=C3=85kesson?= Date: Fri, 1 Jun 2007 07:58:00 -0400 Subject: [PATCH] Initial checkin of lft's excellent work --- target/Makefile | 7 + target/asm.s | 230 +++++++++++ target/main.c | 474 ++++++++++++++++++++++ tracker/Makefile | 10 + tracker/README | 62 +++ tracker/chip.c | 348 ++++++++++++++++ tracker/gui.c | 907 ++++++++++++++++++++++++++++++++++++++++++ tracker/main.c | 97 +++++ tracker/packedformat | 31 ++ tracker/stuff.h | 50 +++ tracker/test2.song | 924 +++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 3140 insertions(+) create mode 100644 target/Makefile create mode 100644 target/asm.s create mode 100644 target/main.c create mode 100644 tracker/Makefile create mode 100644 tracker/README create mode 100644 tracker/chip.c create mode 100644 tracker/gui.c create mode 100644 tracker/main.c create mode 100644 tracker/packedformat create mode 100644 tracker/stuff.h create mode 100644 tracker/test2.song diff --git a/target/Makefile b/target/Makefile new file mode 100644 index 0000000..3e3e80e --- /dev/null +++ b/target/Makefile @@ -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 index 0000000..3ac7ffd --- /dev/null +++ b/target/asm.s @@ -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 index 0000000..fac68d6 --- /dev/null +++ b/target/main.c @@ -0,0 +1,474 @@ +#include +#include +#include + +#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 index 0000000..c091378 --- /dev/null +++ b/tracker/Makefile @@ -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 index 0000000..28dc575 --- /dev/null +++ b/tracker/README @@ -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 index 0000000..86ddf39 --- /dev/null +++ b/tracker/chip.c @@ -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 index 0000000..810e683 --- /dev/null +++ b/tracker/gui.c @@ -0,0 +1,907 @@ +#include +#include +#include +#include +#include +#include + +#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(); + } +} diff --git a/tracker/main.c b/tracker/main.c new file mode 100644 index 0000000..99e161b --- /dev/null +++ b/tracker/main.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#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 \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 index 0000000..e9cae42 --- /dev/null +++ b/tracker/packedformat @@ -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 index 0000000..b32caec --- /dev/null +++ b/tracker/stuff.h @@ -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 index 0000000..a06ec22 --- /dev/null +++ b/tracker/test2.song @@ -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 -- 2.50.1