1
0
mirror of https://github.com/cc65/cc65.git synced 2024-11-18 00:07:21 +00:00
cc65/libsrc/lynx/lynx-snd.s

1271 lines
32 KiB
ArmAsm

;
; Sound driver for the Atari Lynx.
;
; Karri Kaksonen and Bjoern Spruck, 11.12.2012
;
.include "lynx.inc"
.include "zeropage.inc"
.export _lynx_snd_init
.export _lynx_snd_active
.export _lynx_snd_play
.export _lynx_snd_stop
.export _lynx_snd_stop_channel
.export _lynx_snd_pause
.export _lynx_snd_continue
.interruptor lynx_snd_handler
.import popa
.importzp ptr1
;----------------------------------------------------------------------------
; ZP variables that go into APPZP
;
.segment "APPZP" : zeropage
SndSema: .res 1
SndPtrTmp: .res 2
SndTmp: .res 2
SndEnvPtr: .res 2
;----------------------------------------------------------------------------
; Global variables
;
.bss
SndRetAFlag2: .res 1
SndRetAFlag: .res 1
SndPtrLo: .res 4
SndPtrHi: .res 4
SndDelay: .res 4
SndLoopCnt: .res 4
SndLoopPtrLo: .res 4
SndLoopPtrHi: .res 4
SndVolume: .res 4
SndMaxVolume: .res 4
SndNotePlaying: .res 4
SndRetAddr: .res 8
SndActive: .res 4
SndReqStop: .res 4
SndEnvVol: .res 4
SndEnvFrq: .res 4
SndEnvWave: .res 4
SndChannel: .res 32
SndEnvVolCnt: .res 4
SndEnvVolInc: .res 4
SndEnvVolOff: .res 4
SndEnvVolLoop: .res 4
SndEnvVolParts: .res 4
SndEnvVolParts2: .res 4
SndEnvFrqCnt: .res 4
SndEnvFrqInc: .res 4
SndEnvFrqOff: .res 4
SndEnvFrqLoop: .res 4
SndEnvFrqParts: .res 4
SndEnvFrqParts2: .res 4
SndEnvWaveCnt: .res 4
SndEnvWaveOff: .res 4
SndEnvWaveLoop: .res 4
SndEnvWaveParts: .res 4
SndEnvWaveParts2: .res 4
MAX_INSTRUMENTS .set 64
SndEnvVolPtrLo: .res MAX_INSTRUMENTS
SndEnvVolPtrHi: .res MAX_INSTRUMENTS
SndEnvFrqPtrLo: .res MAX_INSTRUMENTS
SndEnvFrqPtrHi: .res MAX_INSTRUMENTS
SndEnvWavePtrLo: .res MAX_INSTRUMENTS
SndEnvWavePtrHi: .res MAX_INSTRUMENTS
.rodata
SndOffsets: .byte $00,$08,$10,$18
;----------------------------------------------------------------------------
; Macros
;
if_count .set 0
nest_count .set 0
.macro _IFNE
if_count .set if_count +1
nest_count .set nest_count +1
beq .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _IFEQ
if_count .set if_count +1
nest_count .set nest_count +1
bne .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _IFMI
if_count .set if_count +1
nest_count .set nest_count +1
bpl .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _IFPL
if_count .set if_count +1
nest_count .set nest_count +1
bmi .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _IFGE
if_count .set if_count +1
nest_count .set nest_count +1
bcc .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _IFCS
if_count .set if_count +1
nest_count .set nest_count +1
bcc .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _IFCC
if_count .set if_count +1
nest_count .set nest_count +1
bcs .ident (.sprintf ("else%04d", if_count))
.ident (.sprintf ("push%04d", nest_count)) .set if_count
.endmacro
.macro _ELSE
bra .ident (.sprintf ("endif%04d", .ident (.sprintf ("push%04d", nest_count))))
.ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
.endmacro
.macro _ENDIF
.if .not .defined( .ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))))
.ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
.endif
.ident (.sprintf ("endif%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
nest_count .set nest_count -1
.endmacro
.code
;----------------------------------------------------------------------------
; void lynx_snd_init() will initialize the sound engine.
;
_31250Hz .set %101
_lynx_snd_init:
php
sei
lda #%10011000|_31250Hz
sta STIMCTLA
lda #129
sta STIMBKUP ; set up a 240Hz IRQ
stz AUD0VOL
stz AUD1VOL
stz AUD2VOL
stz AUD3VOL
stz $fd44 ; all channels full volume / no attenuation
lda #$ff
stz MSTEREO
lda #0
sta AUD0CTLA
sta AUD1CTLA
sta AUD2CTLA
sta AUD3CTLA
ldx #3
lda #0
init0: stz SndActive,x
stz SndReqStop,x
stz SndEnvVol,x
stz SndEnvFrq,x
stz SndEnvWave,x
ldy SndOffsets,x
sta SndChannel+2,y
dex
bpl init0
stz SndRetAFlag
stz SndRetAFlag2
stz SndSema
plp
rts
;----------------------------------------------------------------------------
; lynx_snd_handler is run at every sound interrupt
;
lynx_snd_handler:
lda INTSET
and #SND_INTERRUPT
bne @L0
clc
rts
@L0:
lda #$ff
tsb SndSema
bne endirq
phy
; *NOW* set all values which were "pre-set" in last interrupt
jsr SndSetValues
cli
lda SndRetAFlag ; reset the return flag, but save it first
_IFNE
lda #$0F ; MASK
sta SndRetAFlag2
stz SndRetAFlag
_ENDIF
ldx #3
irq0: phx
lda SndActive,x
_IFNE
lda SndEnvVol,x
_IFNE
phx
jsr SndChangeVol
plx
_ENDIF
lda SndEnvFrq,x
_IFNE
phx
jsr SndChangeFrq
plx
_ENDIF
lda SndEnvWave,x
_IFNE
phx
jsr SndChangeWave
plx
_ENDIF
jsr SndGetCmd
_ENDIF
plx
dex
bpl irq0
sei
ply
stz SndSema
endirq:
clc
rts
;----------------------------------------------------------------------------
; A process table with addresses to sound functions
;
SndCmdsLo:
.byte <((SndLoop)-1)
.byte <((SndDo)-1)
.byte <((SndPause)-1)
.byte <((SndNoteOff)-1)
.byte <((SndSetInstr)-1)
.byte <((SndNewNote2)-1)
.byte <((SndCallPattern)-1)
.byte <((SndRetToSong)-1)
.byte <((SndDefEnvVol)-1)
.byte <((SndSetEnvVol)-1)
.byte <((SndDefEnvFrq)-1)
.byte <((SndSetEnvFrq)-1)
.byte <((SndDefEnvWave)-1)
.byte <((SndSetEnvWave)-1)
.byte <((SndSetStereo)-1)
.byte <((SndSetAttenuationOn)-1)
.byte <((SndSetChnAttenution)-1)
.byte <((SndPlayerFreq)-1)
.byte <((SndReturnAll)-1)
SndCmdsHi:
.byte >((SndLoop)-1)
.byte >((SndDo)-1)
.byte >((SndPause)-1)
.byte >((SndNoteOff)-1)
.byte >((SndSetInstr)-1)
.byte >((SndNewNote2)-1)
.byte >((SndCallPattern)-1)
.byte >((SndRetToSong)-1)
.byte >((SndDefEnvVol)-1)
.byte >((SndSetEnvVol)-1)
.byte >((SndDefEnvFrq)-1)
.byte >((SndSetEnvFrq)-1)
.byte >((SndDefEnvWave)-1)
.byte >((SndSetEnvWave)-1)
.byte >((SndSetStereo)-1)
.byte >((SndSetAttenuationOn)-1)
.byte >((SndSetChnAttenution)-1)
.byte >((SndPlayerFreq)-1)
.byte >((SndReturnAll)-1)
;----------------------------------------------------------------------------
; Get next sound command from stream
;
SndGetCmd:
lda SndReqStop,x
bne SndStop
lda SndRetAFlag2
and SndMask,x
_IFNE
eor SndRetAFlag2
sta SndRetAFlag2
lda SndRetAddr,x
sta SndPtrLo,x
lda SndRetAddr+4,x
sta SndPtrHi,x
;;; force the direct continue return
_ELSE
dec SndDelay,x
bne cmd991 ;; check special case
_ENDIF
lda SndPtrLo,x
sta SndPtrTmp
lda SndPtrHi,x
sta SndPtrTmp+1
cmd0: lda (SndPtrTmp)
beq SndStop
_IFMI
and #$7f
tay
jsr SndCallCmd
_ELSE
jsr SndNewNote
_ENDIF
clc
tya
and #$7f
adc SndPtrTmp
sta SndPtrLo,x
sta SndPtrTmp
lda #0
adc SndPtrTmp+1
sta SndPtrHi,x
sta SndPtrTmp+1
tya
bmi cmd0
cmd991:
;; now check if delay is only 1 AND next one is return all.
lda #1
cmp SndDelay,x
bne cmd99
;; NOW read ahead ONE
lda SndPtrLo,x
sta SndPtrTmp
lda SndPtrHi,x
sta SndPtrTmp+1
lda (SndPtrTmp)
cmp #$92 ;; Return all
_IFEQ
sta SndRetAFlag ; just set !=0
_ENDIF
cmd99: rts
;----------------------------------------------------------------------------
; Call function pointed to by y
;
SndCallCmd:
lda SndCmdsHi,y
pha
lda SndCmdsLo,y
pha
ldy #1
rts
;----------------------------------------------------------------------------
; Stop sound on one channel
;
SndStop:
stz SndReqStop,x
stz SndActive,x
ldy SndOffsets,x
lda #0
sta SndChannel,y
ina ;lda #1
sta SndChannel+2,y
tay ;ldy #1
rts
;----------------------------------------------------------------------------
; Send a new note, length, volume triplet
;
SndNewNote:
phx
sta SndNotePlaying,x
pha
ldy #1
lda (SndPtrTmp),y
sta SndDelay,x
ldy SndOffsets,x
lda SndVolume,x
sta SndChannel,y
plx
lda SndPrescaler,x
sta SndChannel+5,y
lda SndReload,x
sta SndChannel+4,y
lda #$FF ; = -1
sta SndChannel+2,y
plx
lda SndEnvVol,x
_IFNE
jsr SndSetEnvVol1
_ENDIF
lda SndEnvFrq,x
_IFNE
jsr SndSetEnvFrq1
_ENDIF
lda SndEnvWave,x
_IFNE
jsr SndSetEnvWave1
_ENDIF
lda #$2
ldy SndDelay,x
_IFNE
ora #$80
_ENDIF
tay
rts
;----------------------------------------------------------------------------
; Start a loop with count
;
SndLoop:
lda (SndPtrTmp),y
sta SndLoopCnt,x
lda SndPtrTmp
sta SndLoopPtrLo,x
lda SndPtrTmp+1
sta SndLoopPtrHi,x
ldy #$82
rts
SndDo:
dec SndLoopCnt,x
_IFNE
lda SndLoopPtrLo,x
sta SndPtrTmp
lda SndLoopPtrHi,x
sta SndPtrTmp+1
ldy #$82
_ELSE
ldy #$81
_ENDIF
rts
;----------------------------------------------------------------------------
; Sound volume envelope
;
SndDefEnvVol:
phx
lda (SndPtrTmp),y ; env #
tax
iny
lda (SndPtrTmp),y
sta SndEnvVolPtrLo,x
iny
lda (SndPtrTmp),y
sta SndEnvVolPtrHi,x ; Ptr to [cnt,inc]
ldy #$84
plx
rts
SndSetEnvVol:
lda (SndPtrTmp),y ; # env
SndSetEnvVol1:
and #$7f
sta SndEnvVol,x ; save
_IFEQ
ldy #$82
rts
_ENDIF
tay
lda SndEnvVolPtrLo,y
sta SndEnvPtr
lda SndEnvVolPtrHi,y
sta SndEnvPtr+1
lda (SndEnvPtr)
sta SndTmp
asl
sta SndEnvVolLoop,x ; here is the loop-start
ldy #1
lda (SndEnvPtr),y
sta SndEnvVolParts,x
sec
sbc SndTmp
sta SndEnvVolParts2,x
stz SndEnvVolCnt,x
lda #2
sta SndEnvVolOff,x
ldy #$82
rts
;----------------------------------------------------------------------------
; Sound frequency envelope
;
SndDefEnvFrq:
phx
lda (SndPtrTmp),y ; env #
tax
iny
lda (SndPtrTmp),y
sta SndEnvFrqPtrLo,x
iny
lda (SndPtrTmp),y
sta SndEnvFrqPtrHi,x ; Ptr to [inc,cnt]
plx
ldy #$84
rts
SndSetEnvFrq:
lda (SndPtrTmp),y ; # env
SndSetEnvFrq1:
and #$7f
sta SndEnvFrq,x ; save
_IFEQ
ldy #$82
rts
_ENDIF
tay
lda SndEnvFrqPtrLo,y
sta SndEnvPtr
lda SndEnvFrqPtrHi,y
sta SndEnvPtr+1
lda (SndEnvPtr)
sta SndTmp
asl
sta SndEnvFrqLoop,x
ldy #1
lda (SndEnvPtr),y
sta SndEnvFrqParts,x
sec
sbc SndTmp
sta SndEnvFrqParts2,x
stz SndEnvFrqCnt,x
lda #2
sta SndEnvFrqOff,x
ldy #$82
rts
;----------------------------------------------------------------------------
; Sound frequency envelope
;
SndDefEnvWave:
phx
lda (SndPtrTmp),y ; env #
tax
iny
lda (SndPtrTmp),y
sta SndEnvWavePtrLo,x
iny
lda (SndPtrTmp),y
sta SndEnvWavePtrHi,x ; Ptr to [inc,cnt]
plx
ldy #$84
rts
SndSetEnvWave:
lda (SndPtrTmp),y ; # env
SndSetEnvWave1:
and #$7f
sta SndEnvWave,x ; save
_IFEQ
ldy #$82
rts
_ENDIF
tay
lda SndEnvWavePtrLo,y
sta SndEnvPtr
lda SndEnvWavePtrHi,y
sta SndEnvPtr+1
lda (SndEnvPtr)
sta SndTmp
asl ; *4 -2
dea
asl
sta SndEnvWaveLoop,x
ldy #1
lda (SndEnvPtr),y
sta SndEnvWaveParts,x
sec
sbc SndTmp
sta SndEnvWaveParts2,x
stz SndEnvWaveCnt,x
lda #2
sta SndEnvWaveOff,x
ldy #$82
rts
;----------------------------------------------------------------------------
; Pause sound
;
SndPause:
lda (SndPtrTmp),y
sta SndDelay,x
iny
SndDummy: rts
;;;* This set the new Player Freq instantanious!!!
SndPlayerFreq:
lda (SndPtrTmp),y
sta STIMCTLA
iny
lda (SndPtrTmp),y
sta STIMBKUP
ldy #$83
rts
SndNoteOff:
ldy SndOffsets,x
stz SndNotePlaying,x
lda SndEnvVol,x
ora #$80
sta SndEnvVol,x
lda SndEnvFrq,x
ora #$80
sta SndEnvFrq,x
lda SndEnvWave,x
ora #$80
sta SndEnvWave,x
lda #0
sta SndChannel,y
sta SndChannel+4,y
sta SndChannel+5,y
dea
sta SndChannel+2,y
ldy #$81
rts
SndSetInstr:
phx
lda SndOffsets,x
tax
lda (SndPtrTmp),y
sta SndChannel+3,x
iny
lda (SndPtrTmp),y
sta SndChannel+7,x
iny
lda (SndPtrTmp),y
sta SndChannel+1,x
plx
iny
lda (SndPtrTmp),y
sta SndVolume,x
iny
lda (SndPtrTmp),y
sta SndMaxVolume,x
ldy #$86
rts
SndCallPattern:
clc
lda SndPtrTmp
adc #3
sta SndRetAddr,x
lda SndPtrTmp+1
adc #0
sta SndRetAddr+4,x
ldy #1
lda (SndPtrTmp),y
pha
iny
lda (SndPtrTmp),y
sta SndPtrTmp+1
pla
sta SndPtrTmp
ldy #$80
rts
SndRetToSong:
lda SndRetAddr,x
sta SndPtrTmp
lda SndRetAddr+4,x
sta SndPtrTmp+1
ldy #$80
rts
SndReturnAll:
lda #1
sta SndRetAFlag
sta SndDelay,x
ldy #$0
rts
SndNewNote2:
;;; Note,length,volume
phx
sta SndNotePlaying,x
ldy #1
lda (SndPtrTmp),y ; reload
pha
iny
lda (SndPtrTmp),y ; prescale
pha
iny
lda (SndPtrTmp),y ; laenge
sta SndDelay,x
ldy SndOffsets,x
lda SndVolume,x
sta SndChannel,y
pla
sta SndChannel+5,y
pla
sta SndChannel+4,y
lda #$FF ; = -1
sta SndChannel+2,y
plx
lda SndEnvVol,x
_IFNE
jsr SndSetEnvVol1
_ENDIF
lda SndEnvFrq,x
_IFNE
jsr SndSetEnvFrq1
_ENDIF
lda SndEnvWave,x
_IFNE
jsr SndSetEnvWave1
_ENDIF
ldy #4
rts
SndSetStereo:
ldy #1
lda (SndPtrTmp),y
sta MSTEREO
ldy #$82
rts
SndSetAttenuationOn:
ldy #1
lda (SndPtrTmp),y
sta $FD44
ldy #$82
rts
SndSetChnAttenution:
ldy #1
lda (SndPtrTmp),y
sta $FD40,x
ldy #$82
rts
SndChangeVol:
tay
_IFMI
vol99: rts
_ENDIF
lda SndNotePlaying,x
beq vol99
lda SndEnvVolPtrLo,y
sta SndEnvPtr
lda SndEnvVolPtrHi,y
sta SndEnvPtr+1
dec SndEnvVolCnt,x
_IFMI
dec SndEnvVolParts,x
_IFMI
lda SndEnvVolLoop,x
_IFNE
tay
lda SndEnvVolParts2,x
sta SndEnvVolParts,x
bra vol1v
_ELSE
tya
ora #$80
sta SndEnvVol,x
_ENDIF
_ELSE
ldy SndEnvVolOff,x
vol1v: lda (SndEnvPtr),y
sta SndEnvVolCnt,x
iny
lda (SndEnvPtr),y
sta SndEnvVolInc,x
iny
tya
sta SndEnvVolOff,x
_ENDIF
rts
_ENDIF
ldy SndOffsets,x
clc
lda SndEnvVolInc,x
_IFEQ
rts
_ENDIF
_IFPL
adc SndChannel,y
cmp SndMaxVolume,x
_IFCS
lda SndMaxVolume,x
stz SndEnvVolInc,x
_ENDIF
cmp #$80
_IFGE
lda #$7f
stz SndEnvVolInc,x
_ENDIF
_ELSE
adc SndChannel,y
_IFCC
lda #0
sta SndEnvVolInc,x
;; NEU: switch Tremolo off
sta SndNotePlaying,x
_ENDIF
cmp #$80
_IFGE
lda #0
sta SndEnvVolInc,x
;; NEU: switch Tremolo off
sta SndNotePlaying,x
_ENDIF
_ENDIF
sta SndChannel,y
lda SndChannel+2,y
ora #1 ;; if already -1 ... no effect
sta SndChannel+2,y
rts
SndChangeFrq:
tay
_IFMI
frq99: rts
_ENDIF
lda SndNotePlaying,x
beq frq99
lda SndEnvFrqPtrLo,y
sta SndEnvPtr
lda SndEnvFrqPtrHi,y
sta SndEnvPtr+1
dec SndEnvFrqCnt,x
_IFMI
dec SndEnvFrqParts,x
_IFMI
lda SndEnvFrqLoop,x
_IFNE
tay
lda SndEnvFrqParts2,x
sta SndEnvFrqParts,x
bra frq1f
_ELSE
tya
ora #$80
sta SndEnvFrq,x
_ENDIF
_ELSE
ldy SndEnvFrqOff,x
frq1f: lda (SndEnvPtr),y
sta SndEnvFrqCnt,x
iny
lda (SndEnvPtr),y
eor #$ff
ina
sta SndEnvFrqInc,x
iny
tya
sta SndEnvFrqOff,x
_ENDIF
rts
_ENDIF
ldy SndOffsets,x
clc
lda SndEnvFrqInc,x
_IFEQ
rts
_ENDIF
_IFMI
adc SndChannel+4,y
_IFPL
pha
lda SndChannel+5,y
_IFNE
dea
sta SndChannel+5,y
pla
eor #128
_ELSE
pla
pha
clc
adc SndEnvFrqInc,x
pla
_ENDIF
_ELSE
pha
lda SndChannel+5,y
_IFEQ
pla
sta SndChannel+4,y
rts
_ENDIF
pla
_ENDIF
_ELSE
adc SndChannel+4,y
_IFPL
pha
lda SndChannel+5,y
cmp #6
_IFNE
ina
sta SndChannel+5,y
pla
eor #128
_ELSE
lda SndChannel+4,y
_IFMI
pla
rts
_ENDIF
pla
_ENDIF
_ELSE
pha
lda SndChannel+5,y
cmp #6
_IFEQ
lda SndChannel+4,y
_IFPL
pla
rts
_ENDIF
_ENDIF
pla
_ENDIF
_ENDIF
sta SndChannel+4,y
ora #1 ;; if already -1 -> no effect
rts
SndChangeWave:
tay
;; Ab hier x Kanal 0-3, y Environment
_IFMI
wav99: rts
_ENDIF
lda SndNotePlaying,x
beq wav99
lda SndEnvWavePtrLo,y
sta SndEnvPtr
lda SndEnvWavePtrHi,y
sta SndEnvPtr+1
dec SndEnvWaveCnt,x
_IFMI
dec SndEnvWaveParts,x
_IFMI
lda SndEnvWaveLoop,x
_IFNE
tay
;; Ab hier x Kanal 0-3, y Offset im Environment
lda SndEnvWaveParts2,x
sta SndEnvWaveParts,x
bra wav1v
_ELSE
tya
ora #$80 ;; beende Env
sta SndEnvWave,x
_ENDIF
_ELSE
ldy SndEnvWaveOff,x
;; Ab hier x Kanal 0-3, y Offset im Environment
wav1v: lda (SndEnvPtr),y
sta SndEnvWaveCnt,x
phx
lda SndOffsets,x
tax
;; Ab hier x Kanal (0-3)*8, y Offset im Environment
iny
lda (SndEnvPtr),y
sta SndChannel+3,x ; Shift LO
iny
lda (SndEnvPtr),y
sta SndChannel+7,x ; Shift HI
iny
lda (SndEnvPtr),y
sta SndChannel+1,x ; Feedback
iny
tya
ply
;; Ab hier x Kanal (0-3)*8, y Kanal 0-3
sta SndEnvWaveOff,y
lda #$FF ; =-1 ;; stop timer to set new values...
sta SndChannel+2,x
_ENDIF
_ENDIF
rts
SndSetValues:
ldx #4-1
set0: ldy SndOffsets,x
lda SndChannel+2,y
_IFNE ; flag == 0 => don`t set
bit #$80
_IFNE ;
lda #0
sta $fd25,y ; stop sound timer
lda SndChannel+3,y
sta $fd23,y ; shifter 1
;;lda $fd27,y
;;and #$0F
;;ora SndChannel+7,y ; shifter 2
lda SndChannel+7,y ; shifter 2
sta $fd27,y
lda SndChannel+1,y
sta $fd21,y ; feedback
_ENDIF
lda SndChannel,y
sta $fd20,y ; volume
lda SndChannel+2,y
bit #$80
_IFNE ;
lda SndChannel+4,y
sta $fd24,y ; reload
lda SndChannel+5,y
ora #%00011000 ;;; #%01011000
;; and #%00111111
sta $fd25,y ; re-enable timer
_ENDIF
lda #0
sta SndChannel+2,y ; clear flag
_ENDIF
dex
_IFPL
jmp set0
_ENDIF
rts
_lynx_snd_play:
sta ptr1
stx ptr1+1
jsr popa
tax
lda ptr1
ldy ptr1+1
php
pha
lda SndActive,x
_IFNE
dec SndReqStop,x
lda #1
sta SndDelay,x
start0: lda SndActive,x
bne start0
_ENDIF
bra start1
SndStartSoundx:
php
pha
start1:
sei
pla
sta SndPtrLo,x
tya
sta SndPtrHi,x
lda #1
sta SndDelay,x
stz SndEnvVol,x
stz SndEnvFrq,x
stz SndEnvWave,x
sta SndActive,x
stz SndReqStop,x
plp
rts
SndStartSound2:
pha
lda SndActive,x ; check default
beq start20 ; inactive => ok
phx
ldx #3 ; search free channel
start21:
lda SndActive,x
beq start22 ; found =>
dex
bpl start21
plx ; not found
dec SndReqStop,x ; stop default-channel
lda #1
sta SndDelay,x
start23:
lda SndActive,x
bne start23
bra start20
start22:
pla ; clear stack
start20:
pla
phx
jsr SndStartSoundx ; launch new sound
plx
rts
_lynx_snd_stop:
ldx #3
lda SndActive,x
_IFNE
stop0: dec SndReqStop,x
lda #1
sta SndDelay,x
stop1: lda SndActive,x
bne stop1
_ENDIF
dex
bpl stop0
rts
_lynx_snd_stop_channel:
tax
lda SndActive,x
_IFNE
dec SndReqStop,x
lda #1
sta SndDelay,x
stopc1: lda SndActive,x
bne stopc1
_ENDIF
rts
_lynx_snd_active:
ldx #3
lda #0
act0: ldy SndActive,x
_IFNE
ora SndMask,x
_ENDIF
dex
bpl act0
rts
_lynx_snd_pause:
php
sei
lda STIMCTLA
sta SndPauseOff1+1
stz STIMCTLA
lda MSTEREO
sta SndPauseOff2+1
lda #$ff
sta MSTEREO
lda #$18
trb AUD0CTLA
trb AUD1CTLA
trb AUD2CTLA
trb AUD3CTLA
plp
rts
_lynx_snd_continue:
php
sei
SndPauseOff1:
lda #0 ; Selbsmodifizierter Code!!!
sta STIMCTLA
SndPauseOff2:
lda #0 ; Selbsmodifizierter Code!!!
sta MSTEREO
lda #$18
tsb AUD0CTLA
tsb AUD1CTLA
tsb AUD2CTLA
tsb AUD3CTLA
plp
rts
.rodata
SndMask:
.byte 1,2,4,8
SndPrescaler:
.byte $00,$06,$06,$06,$06,$05,$05,$05,$05,$05,$05,$05,$04,$04,$04,$04
.byte $04,$04,$04,$04,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$02,$02
.byte $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$01,$01,$01,$01,$01
.byte $01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
SndReload:
.byte $00,$9A,$96,$8F,$86,$FA,$E5,$D1,$BE,$AC,$9C,$8D,$00,$E8,$D3,$C0
.byte $AF,$A0,$93,$87,$FA,$E7,$D6,$C6,$B8,$AC,$A1,$96,$8D,$84,$FA,$EB
.byte $DE,$D2,$C7,$BC,$B3,$AA,$A1,$9A,$93,$8C,$86,$00,$F5,$EB,$E1,$D8
.byte $CF,$C7,$C0,$B9,$B2,$AB,$A5,$A0,$9A,$95,$90,$8B,$87,$82,$FD,$F5
.byte $EE,$E7,$E0,$D9,$D3,$CD,$C8,$C2,$BD,$B8,$B3,$AE,$AA,$A5,$A1,$9D
.byte $99,$96,$92,$8F,$8B,$88,$85,$82,$7F,$7C,$79,$77,$74,$72,$6F,$6D
.byte $6B,$69,$67,$64,$63,$61,$5F,$5D,$5B,$59,$58,$56,$55,$53,$51,$50
.byte $4F,$4D,$4C,$4B,$49,$48,$47,$46,$44,$43,$42,$41,$40,$3F,$3E,$3D