( a blank file ) ( macros ) %RTN { JMP2r } ( return from a subroutine ) ( data structure access macros ) %NOTE { NOP } ( get the note of a pattern line addr ) %INST { #0001 ADD2 } ( get the instrument of a pattern line addr ) %VOL { #0002 ADD2 } ( get the volume of a pattern line addr ) ( debugging macros ) %LOG { DUP .Console/byte DEO } ( prints a byte to the console non-destructively ) ( constants ) %PTN_WIDTH { #0003 } ( pattern width. a short ) %PTN_LEN { #0010 } ( pattern length. a short ) ( devices ) |00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 ] |10 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ] |20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ] |30 @Audio0 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |40 @Audio1 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |50 @Audio2 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |60 @Audio3 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |70 @Midi [ &vector $2 &channel $1 ¬e $1 &velocity $1 ] |80 @Controller [ &vector $2 &button $1 &key $1 ] |90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &chord $1 ] |a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ] |b0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ] ( variables ) |0000 @State [ &position $2 &pattern-addr $2 &tick $1 &speed $1 ] ( program ) |0100 ( -> ) ( set a pallete ) #0f00 .System/r DEO2 #00f0 .System/g DEO2 #000f .System/b DEO2 ( speed - how many ticks we play a note every ) #10 .State/speed POK ;pattern .State/pattern-addr POK2 ( display/audio init ) ;on-frame .Screen/vector DEO2 #0180 .Audio0/adsr DEO2 ;wave .Audio0/addr DEO2 #0002 .Audio0/length DEO2 BRK @on-frame ( -> ) .State/tick PEK .State/speed PEK NEQ ,&inc JNZ ( if the tick != speed, skip to inc ) ;on-step JSR2 ( otherwise, run the on-step routine ) #00 .State/tick POK ( reset the tick ) ,&end JMP ( jump to end ) &inc #01 .State/tick PEK ADD .State/tick POK ( tick up 1 ) &end BRK @on-step ( whenever a pattern step should be played ) PTN_WIDTH PTN_LEN MUL2 .State/position PEK2 NEQ2 ,&continue JNZ ( if we're at the end of the pattern, reset the counter ) #ff .Console/byte DEO #0000 .State/position POK2 &continue .State/position PEK2 .State/pattern-addr PEK2 ADD2 ( put pattern line address on the stack ) DUP2 VOL GET .Audio0/volume DEO ( ln -- ) ( put the address of the pattern line on the stack ) NOTE GET ( get the current note ) DUP #00 EQU ,&rest JNZ ( if the note is 00, aka empty, skip playing it ) .Audio0/pitch DEO ( play the note ) ,&end JMP ( jump to the end ) &rest POP ( if the note is a 00, jump here. POP to clean up the stack ) &end PTN_WIDTH .State/position PEK2 ADD2 .State/position POK2 RTN @wave [ a8 58 ] ( pattern format - each note has 3 bytes. Pitch, instrument, volume. patterns are 0x10 long. an ff in the note column of the pattern will kill the existing note without starting a new one (this is the tracker "box" note) ) @pattern [ 3c 00 66 ff 00 66 3e 00 22 00 00 66 3c 00 88 00 00 66 3e 00 66 00 00 66 3c 00 22 00 00 66 3e 00 20 00 00 66 3c 00 66 ff 00 66 3e 00 ff 40 00 66 ]