%k-RTN { JMP2r } @k-tick &run .kalama/tick LDZ #01 ADD DUP .kalama/speed LDZ EQU ,&play JCN .kalama/tick STZ k-RTN &play POP #ff .kalama/tick STZ .kalama/line LDZ #01 ADD STHk ( rst: line ) #00 SWP #0003 MUL2 ;&lineaddr STA2 ( store line address offset ) .kalama/songpos LDZ2 DUP2 ( songpos* songpos ) ( don't play if song pos is ffff aka song is stopped or over ) #ffff EQU2 ;&no-play JCN2 ( songpos* ) #0005 ADD2 .kalama/module LDZ2 ADD2 ( songposinmod* ) DUP2 LDA ;k-get-pattern/run JSR2 ;&lineaddr LDA2 ADD2 #00 ;k-play-line/run JSR2 DUP2 #0001 ADD2 LDA ;k-get-pattern/run JSR2 ;&lineaddr LDA2 ADD2 #01 ;k-play-line/run JSR2 DUP2 #0002 ADD2 LDA ;k-get-pattern/run JSR2 ;&lineaddr LDA2 ADD2 #02 ;k-play-line/run JSR2 #0003 ADD2 LDA ;k-get-pattern/run JSR2 ;&lineaddr LDA2 ADD2 #03 ;k-play-line/run JSR2 STHrk #0f EQU ,&next JCN STHr .kalama/line STZ k-RTN &next POPr #ff .kalama/line STZ .kalama/songpos LDZ2 #0004 ADD2 DUP2 .kalama/module LDZ2 #0003 ADD2 LDA2 ( song length ) EQU2 ,&reset JCN .kalama/songpos STZ2 k-RTN &reset POP2 .kalama/songloop LDZ #00 EQU ,&end JCN #0000 .kalama/songpos STZ2 k-RTN &end #ffff .kalama/songpos STZ2 k-RTN &no-play POP2 POP2 POPr k-RTN &lineaddr $2 ( initialises kalama with module data ) @k-init-module ( addr* -- ) &run DUP2 .kalama/module STZ2 ( store module address ) DUP2 LDA DUP #0f AND .kalama/speed STZ ( set speed ) #80 AND .kalama/songloop STZ ( set song loop or not ) #0001 ADD2 LDA ( stash pattern count byte ) ;k-get-pattern JSR2 .kalama/instruments STZ2 #ff .kalama/tick STZ #ff .kalama/line STZ #0000 .kalama/songpos STZ2 k-RTN ( gets the memory address of the given pattern in loaded module ) @k-get-pattern ( number -- addr* ) &run DUP #ff EQU ,&blank JCN #00 SWP #0030 MUL2 .kalama/module LDZ2 #0003 ADD2 DUP2 LDA2 ADD2 #0002 ADD2 ADD2 k-RTN &blank POP ;k-blank-pattern k-RTN ( gets the memory address of the given instrument in loaded module ) @k-get-instrument ( number -- addr* ) &run STH ( store instrument number for later ) .kalama/instruments LDZ2 ( we are now at the size byte of instrument 00, the start of instrument memory ) &loop STHrk #00 EQU ,&end JCN STHr #01 SUB STH ( decrement counter ) DUP2 LDA2 ( load length byte and convert to short ) #0006 ADD2 ( jump over length short, vol, flags, ADSR ) ADD2 ( jump to next instrument ) ,&loop JMP &end POPr k-RTN @k-play-line ( *l channel -- ) &chan $1 &run ,&chan STR DUP2 #0001 ADD2 LDA2 ,&chan LDR ;k-run-command/run JSR2 LDA DUP #00 EQU ,&rest JCN .kalama/loopflags LDZ ,&chan LDR #10 MUL #01 SWP SFT AND #00 NEQ ,&noloop JCN #80 ORA &noloop .Audio0/pitch ,&chan LDR #10 MUL ADD DEO ( TODO effects, use loop bit ) k-RTN &rest POP k-RTN @k-run-command ( c arg channel ) &chan $1 &run ;&chan STA SWP ( get command ) DUP #01 EQU ;&vol JCN2 ( set volume ) DUP #02 EQU ;&instrument JCN2 ( set instrument ) DUP #03 EQU ;&attack JCN2 ( set attack time ) DUP #04 EQU ;&decay JCN2 ( set decay time ) DUP #05 EQU ;&sustain JCN2 ( set sustain time ) DUP #06 EQU ;&release JCN2 ( set sustain time ) DUP #07 EQU ;&speed JCN2 ( set speed ) POP2 k-RTN &vol POP ;&chan LDA #10 MUL .Audio0/volume ADD DEO k-RTN &instrument POP ;&chan LDA ;k-load-instrument JSR2 k-RTN &attack POP #0f AND #40 SFT ( shift new value into appropriate position ) ;&chan LDA #10 MUL .Audio0/adsr ADD DEI ( load current value ) #0f AND ( take only decay nibble ) ADD ( add together new attack and old decay ) ;&chan LDA #10 MUL .Audio0/adsr ADD DEO ( store ) k-RTN &decay POP #0f AND ;&chan LDA #10 MUL .Audio0/adsr ADD DEI ( load current value ) #f0 AND ( take only attack nibble ) ADD ( add together new decay and old attack ) ;&chan LDA #10 MUL .Audio0/adsr ADD DEO ( store ) k-RTN &sustain POP #0f AND #40 SFT ( shift new value into appropriate position ) ;&chan LDA #10 MUL .Audio0/adsr #01 ADD ADD DEI ( load current value ) #0f AND ( take only decay nibble ) ADD ( add together new attack and old decay ) ;&chan LDA #10 MUL .Audio0/adsr #01 ADD ADD DEO ( store ) k-RTN &release POP #0f AND ;&chan LDA #10 MUL .Audio0/adsr #01 ADD ADD DEI ( load current value ) #f0 AND ( take only attack nibble ) ADD ( add together new decay and old attack ) ;&chan LDA #10 MUL .Audio0/adsr #01 ADD ADD DEO ( store ) k-RTN &speed POP #0f AND .kalama/speed STZ #00 .kalama/tick STZ k-RTN ( loads instrument with number into specified audio channel, 0-indexed ) @k-load-instrument ( number channel -- ) &run #10 MUL STH ( stash channel * 0x10, offset for that channel's data relative to Audio0 ) ;k-get-instrument JSR2 ( get instrument location ) DUP2 LDA2 STHrk .Audio0/length ADD DEO2 ( copy ADSR value ) #0002 ADD2 ( move to volume value ) DUP2 LDA STHrk .Audio0/volume ADD DEO ( copy volume value ) #0001 ADD2 DUP2 ( move to flags value ) LDA #07 SFT ( MSB is set for looping sample, turn it into 0/1 ) ( set or clear loop bit ) #00 EQU ,&clear JCN #01 STHrk SFT .kalama/loopflags LDZ ORA .kalama/loopflags STZ ( set bit on ) ,&end JMP &clear #01 STHrk SFT #ff EOR .kalama/loopflags LDZ AND .kalama/loopflags STZ ( set bit off ) &end #0001 ADD2 LDA2k STHrk .Audio0/adsr ADD DEO2 ( copy ADSR value ) #0002 ADD2 STHrk .Audio0/addr ADD DEO2 POPr k-RTN @k-blank-pattern $30