]> git.sur5r.net Git - cc65/commitdiff
Work in progress
authorkarri <karri@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 12 Dec 2012 14:29:39 +0000 (14:29 +0000)
committerkarri <karri@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 12 Dec 2012 14:29:39 +0000 (14:29 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@5948 b7a2c559-68d2-44c3-8de9-860c34a00d81

libsrc/lynx/lynx-snd.s

index 1a276f543584f21b2acf18fdd346702f13a11a76..3f02efd0e68820c0f23913344e27fd79d4026729 100644 (file)
@@ -8,6 +8,11 @@
        .include        "zeropage.inc"
 
        .export         _lynx_snd_init
+        .export                _lynx_snd_play
+        .export                _lynx_snd_stop
+        .export                _lynx_snd_pause
+        .export                _lynx_snd_unpause
+       .interruptor    lynx_snd_handler
 
 ;----------------------------------------------------------------------------
 ; ZP variables that go into APPZP
@@ -74,6 +79,75 @@ SndEnvWavePtrHi:     .res    MAX_INSTRUMENTS
 
 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
 
 ;----------------------------------------------------------------------------
@@ -122,3 +196,1062 @@ init0:   stz     SndActive,x
        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:
+
+                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
+
+SndStopChannel:
+                lda SndActive,x
+                _IFNE
+                  dec SndReqStop,x
+                  lda #1
+                  sta SndDelay,x
+stopc1:                lda SndActive,x
+                  bne stopc1
+                _ENDIF
+                rts
+
+SndChannelsActive:
+                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_unpause:   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
+
+
+