Coded using the CA65 assembler.
use like this:
call NMIDIGI_Init once for init, then call NMIDIGI_Play with a pointer (x=hi,y=lo) to a table with parameters (data start lo/hi, data end lo/hi, samplerate lo/hi). NMIDIGI_Off temporarily disables the player, NMIDIGI_On enables it again.
the various compile-time options should be self-explaining (i hope) :)
;-------------------------------------------------------------------------
; NMI Sample player (w) Groepaz/Hitmen
;-------------------------------------------------------------------------
.export NMIDIGI_Init
.export NMIDIGI_On
.export NMIDIGI_Off
.export NMIDIGI_Play
.export NMIDIGION
.export NMIDIGIOFF
withsidplayer=0
.if(withsidplayer=1)
sidplayervol=D418HLP
.endif
;0: high nibble first 1: low nibble first
firstnibble=1
;1: no nibbles
nonibbles=1
NMIDIGI_Init:
jsr NMIDIGI_Off
lda #$00
ldx #$00
@l:
sta __SID__,x
inx
bne @l
lda #$00
sta __SID__+$05 ; voice 1 ad
lda #$f0
sta __SID__+$06 ; sr
lda #$01
sta __SID__+$04 ; ctrl
lda #$00
sta __SID__+$0c ; voice 2 ad
lda #$f0
sta __SID__+$0d ; sr
lda #$01
sta __SID__+$0b ; ctrl
lda #$00
sta __SID__+$13 ; voice 3 ad
lda #$f0
sta __SID__+$14 ; sr
lda #$01
sta __SID__+$12 ; ctrl
lda #$00
sta __SID__+$15 ; filter lo
lda #$10
sta __SID__+$16 ; filter hi
lda #%11110111
sta __SID__+$17 ; filter voices+reso
rts
NMIDIGI_On:
LDA #>NMIDIGION
STA $FFFB
LDA #<NMIDIGION
STA $FFFA
LDA #%10000001 ; enable CIA-2 timer A nmi
STA $DD0D
lda $DD0D
LDA #%00000001 ; timer A start
STA $DD0E
rts
NMIDIGI_Off:
LDA #%00000000
STA $DD0E ; timer A stop
LDA #%01001111 ; disable all CIA-2 nmi's
STA $DD0D
lda $DD0D
LDA #>NMIDIGIOFF
STA $FFFB
LDA #<NMIDIGIOFF
STA $FFFA
lda #$00
sta NMIPOINT
sta NMIPOINT+1
sta DIGISTOPLO+1
sta DIGISTOPHI+1
rts
NMIDIGI_Play:
jsr NMIDIGI_Off
stx NMIDIGIPTR+1
sty NMIDIGIPTR
ldy #$00
lda (NMIDIGIPTR),y
sta NMIPOINT
iny
lda (NMIDIGIPTR),y
sta NMIPOINT+1
iny
lda (NMIDIGIPTR),y
sta DIGISTOPLO+1
iny
lda (NMIDIGIPTR),y
sta DIGISTOPHI+1
iny
lda (NMIDIGIPTR),y
sta $DD04
iny
lda (NMIDIGIPTR),y
sta $DD05
.if(nonibbles=0)
lda #$00
sta nib+1
.endif
jsr NMIDIGI_On
rts
;-------------------------------------------
NMIDIGION:
STA NMIABUFF
STY NMIYBUFF
.if (withsidplayer=1)
lda sidplayervol
and #$f0
.else
lda #$10
.endif
D418NMI: ora #$00
sta __SID__+$18 ; volume reg
.if (withsidplayer=1)
sta sidplayervol
.endif
.if (DEBUG=1)
sta $d020
.endif
LDA NMIPOINT+1
DIGISTOPHI: CMP #$12 ;ENDHIGH
BNE SK1
LDA NMIPOINT
DIGISTOPLO: CMP #$00 ;ENDLOW
BNE SK1
.if (withsidplayer=1)
lda #$08
.else
lda #$00
.endif
STA D418NMI+1
jsr NMIDIGI_Off
LDA NMIABUFF
RTI
SK1:
LDY #$00
.if(nonibbles=0)
nib: lda #$00
and #$01
bne s1
.endif
LDA (NMIPOINT),Y
.if(nonibbles=0)
.if(firstnibble=0) ; high nibble first
lsr a
lsr a
lsr a
lsr a
.else ; low nibble first
AND #$0F
.endif
jmp s2
s1:
LDA (NMIPOINT),Y
.if(firstnibble=1) ; high nibble second
lsr a
lsr a
lsr a
lsr a
.else ; low nibble second
AND #$0F
.endif
.endif
INC NMIPOINT
BNE @SK
INC NMIPOINT+1
@SK:
s2:
STA D418NMI+1
.if(nonibbles=0)
inc nib+1
.endif
LDA $DD0D
NMIABUFF=*+1
LDA #$00
NMIYBUFF=*+1
LDY #$00
NMIDIGIOFF:
RTI
(Edit: Suggestion from Algorithm)
the digiboost should be something along the lines of..
lda #$ff sta $d406 sta $d406+7 sta $d496+14 lda #$49 sta $d404 sta $d404+7 sta $d404+14
and the nmi frequency needs to be set. eg
lda #$3c sta $dd04 lda #$00 sta $dd05
(Edit enthusi)
If you are in real need for cycles and have some RAM left you can replace the LSRs with:
tay
lda freq_table,y
and set up a table via
ldx #0
loop2
ldy #16
value
lda #0
loop
sta freq_table,x
inx
dey
bne loop
cpx #$00
beq end
inc value+1
jmp loop2
end
rts