]> git.sur5r.net Git - cc65/blob - libsrc/lynx/lynx-snd.s
Export lynx_snd_active
[cc65] / libsrc / lynx / lynx-snd.s
1 ;
2 ; Sound driver for the Atari Lynx.
3 ;
4 ; Karri Kaksonen and Bjoern Spruck, 11.12.2012
5 ;
6
7         .include        "lynx.inc"
8         .include        "zeropage.inc"
9
10         .export         _lynx_snd_init
11         .export         _lynx_snd_active
12         .export         _lynx_snd_play
13         .export         _lynx_snd_stop
14         .export         _lynx_snd_pause
15         .export         _lynx_snd_continue
16         .interruptor    lynx_snd_handler
17         .import         popa
18         .importzp       ptr1
19
20 ;----------------------------------------------------------------------------
21 ; ZP variables that go into APPZP
22 ;
23
24         .segment "APPZP" : zeropage
25
26 SndSema:                .res    1
27 SndPtrTmp:              .res    2
28 SndTmp:                 .res    2
29 SndEnvPtr:              .res    2
30
31 ;----------------------------------------------------------------------------
32 ; Global variables
33 ;
34
35         .bss
36
37 SndRetAFlag2:           .res    1
38 SndRetAFlag:            .res    1
39 SndPtrLo:               .res    4
40 SndPtrHi:               .res    4
41 SndDelay:               .res    4
42 SndLoopCnt:             .res    4
43 SndLoopPtrLo:           .res    4
44 SndLoopPtrHi:           .res    4
45 SndVolume:              .res    4
46 SndMaxVolume:           .res    4
47 SndNotePlaying:         .res    4
48 SndRetAddr:             .res    8
49 SndActive:              .res    4
50 SndReqStop:             .res    4
51 SndEnvVol:              .res    4
52 SndEnvFrq:              .res    4
53 SndEnvWave:             .res    4
54 SndChannel:             .res    32
55 SndEnvVolCnt:           .res    4
56 SndEnvVolInc:           .res    4
57 SndEnvVolOff:           .res    4
58 SndEnvVolLoop:          .res    4
59 SndEnvVolParts:         .res    4
60 SndEnvVolParts2:        .res    4
61 SndEnvFrqCnt:           .res    4
62 SndEnvFrqInc:           .res    4
63 SndEnvFrqOff:           .res    4
64 SndEnvFrqLoop:          .res    4
65 SndEnvFrqParts:         .res    4
66 SndEnvFrqParts2:        .res    4
67 SndEnvWaveCnt:          .res    4
68 SndEnvWaveOff:          .res    4
69 SndEnvWaveLoop:         .res    4
70 SndEnvWaveParts:        .res    4
71 SndEnvWaveParts2:       .res    4
72
73 MAX_INSTRUMENTS         .set    64
74 SndEnvVolPtrLo:         .res    MAX_INSTRUMENTS
75 SndEnvVolPtrHi:         .res    MAX_INSTRUMENTS
76 SndEnvFrqPtrLo:         .res    MAX_INSTRUMENTS
77 SndEnvFrqPtrHi:         .res    MAX_INSTRUMENTS
78 SndEnvWavePtrLo:        .res    MAX_INSTRUMENTS
79 SndEnvWavePtrHi:        .res    MAX_INSTRUMENTS
80
81         .rodata
82
83 SndOffsets:             .byte   $00,$08,$10,$18
84
85 ;----------------------------------------------------------------------------
86 ; Macros
87 ;
88
89 if_count        .set    0
90 nest_count      .set    0
91
92 .macro  _IFNE
93         if_count        .set    if_count +1
94         nest_count      .set    nest_count +1
95         beq             .ident (.sprintf ("else%04d", if_count))
96         .ident (.sprintf ("push%04d", nest_count)) .set if_count
97 .endmacro
98
99 .macro  _IFEQ
100         if_count        .set    if_count +1
101         nest_count      .set    nest_count +1
102         bne             .ident (.sprintf ("else%04d", if_count))
103         .ident (.sprintf ("push%04d", nest_count)) .set if_count
104 .endmacro
105
106 .macro  _IFMI
107         if_count        .set    if_count +1
108         nest_count      .set    nest_count +1
109         bpl             .ident (.sprintf ("else%04d", if_count))
110         .ident (.sprintf ("push%04d", nest_count)) .set if_count
111 .endmacro
112
113 .macro  _IFPL
114         if_count        .set    if_count +1
115         nest_count      .set    nest_count +1
116         bmi             .ident (.sprintf ("else%04d", if_count))
117         .ident (.sprintf ("push%04d", nest_count)) .set if_count
118 .endmacro
119
120 .macro  _IFGE
121         if_count        .set    if_count +1
122         nest_count      .set    nest_count +1
123         bcc             .ident (.sprintf ("else%04d", if_count))
124         .ident (.sprintf ("push%04d", nest_count)) .set if_count
125 .endmacro
126
127 .macro  _IFCS
128         if_count        .set    if_count +1
129         nest_count      .set    nest_count +1
130         bcc             .ident (.sprintf ("else%04d", if_count))
131         .ident (.sprintf ("push%04d", nest_count)) .set if_count
132 .endmacro
133
134 .macro  _IFCC
135         if_count        .set    if_count +1
136         nest_count      .set    nest_count +1
137         bcs             .ident (.sprintf ("else%04d", if_count))
138         .ident (.sprintf ("push%04d", nest_count)) .set if_count
139 .endmacro
140
141 .macro  _ELSE
142         bra     .ident (.sprintf ("endif%04d", .ident (.sprintf ("push%04d", nest_count))))
143         .ident  (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
144 .endmacro
145
146 .macro  _ENDIF
147         .if .not .defined( .ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))))
148                 .ident  (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
149         .endif
150         .ident  (.sprintf ("endif%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
151         nest_count      .set    nest_count -1
152 .endmacro
153
154         .code
155
156 ;----------------------------------------------------------------------------
157 ; void lynx_snd_init() will initialize the sound engine.
158 ;
159
160 _31250Hz        .set    %101
161
162 _lynx_snd_init:
163         php
164         sei
165         lda     #%10011000|_31250Hz
166         sta     STIMCTLA
167         lda     #129
168         sta     STIMBKUP        ; set up a 240Hz IRQ
169
170         stz     AUD0VOL
171         stz     AUD1VOL
172         stz     AUD2VOL
173         stz     AUD3VOL
174
175         stz     $fd44           ; all channels full volume / no attenuation
176         lda     #$ff
177         stz     MSTEREO
178
179         lda     #0
180         sta     AUD0CTLA
181         sta     AUD1CTLA
182         sta     AUD2CTLA
183         sta     AUD3CTLA
184
185         ldx     #3
186         lda     #0
187 init0:  stz     SndActive,x
188         stz     SndReqStop,x
189         stz     SndEnvVol,x
190         stz     SndEnvFrq,x
191         stz     SndEnvWave,x
192         ldy     SndOffsets,x
193         sta     SndChannel+2,y
194         dex
195         bpl     init0
196         stz     SndRetAFlag
197         stz     SndRetAFlag2
198         stz     SndSema
199         plp
200         rts
201
202 ;----------------------------------------------------------------------------
203 ; lynx_snd_handler is run at every sound interrupt
204 ;
205
206 lynx_snd_handler:
207         lda     INTSET
208         and     #SND_INTERRUPT
209         bne     @L0
210         clc
211         rts
212 @L0:
213         lda     #$ff
214         tsb     SndSema
215         bne     endirq
216         phy
217         ; *NOW* set all values which were "pre-set" in last interrupt
218         jsr     SndSetValues
219         cli
220
221         lda SndRetAFlag   ; reset the return flag, but save it first
222         _IFNE
223                 lda #$0F ; MASK
224                 sta SndRetAFlag2
225                 stz SndRetAFlag
226         _ENDIF
227
228         ldx #3
229 irq0:   phx
230         lda SndActive,x
231         _IFNE
232                 lda SndEnvVol,x
233                 _IFNE
234                         phx
235                         jsr SndChangeVol
236                         plx
237                 _ENDIF
238                 lda SndEnvFrq,x
239                 _IFNE
240                         phx
241                         jsr SndChangeFrq
242                         plx
243                 _ENDIF
244                 lda SndEnvWave,x
245                 _IFNE
246                         phx
247                         jsr SndChangeWave
248                         plx
249                 _ENDIF
250                 jsr SndGetCmd
251         _ENDIF
252         plx
253         dex
254         bpl irq0
255         sei
256         ply
257         stz SndSema
258 endirq:
259         clc
260         rts
261
262 ;----------------------------------------------------------------------------
263 ; A process table with addresses to sound functions
264 ;
265
266 SndCmdsLo:
267         .byte <((SndLoop)-1)
268         .byte <((SndDo)-1)
269         .byte <((SndPause)-1)
270         .byte <((SndNoteOff)-1)
271         .byte <((SndSetInstr)-1)
272         .byte <((SndNewNote2)-1)
273         .byte <((SndCallPattern)-1)
274         .byte <((SndRetToSong)-1)
275         .byte <((SndDefEnvVol)-1)
276         .byte <((SndSetEnvVol)-1)
277         .byte <((SndDefEnvFrq)-1)
278         .byte <((SndSetEnvFrq)-1)
279         .byte <((SndDefEnvWave)-1)
280         .byte <((SndSetEnvWave)-1)
281         .byte <((SndSetStereo)-1)
282         .byte <((SndSetAttenuationOn)-1)
283         .byte <((SndSetChnAttenution)-1)
284         .byte <((SndPlayerFreq)-1)
285         .byte <((SndReturnAll)-1)
286
287 SndCmdsHi:
288         .byte >((SndLoop)-1)
289         .byte >((SndDo)-1)
290         .byte >((SndPause)-1)
291         .byte >((SndNoteOff)-1)
292         .byte >((SndSetInstr)-1)
293         .byte >((SndNewNote2)-1)
294         .byte >((SndCallPattern)-1)
295         .byte >((SndRetToSong)-1)
296         .byte >((SndDefEnvVol)-1)
297         .byte >((SndSetEnvVol)-1)
298         .byte >((SndDefEnvFrq)-1)
299         .byte >((SndSetEnvFrq)-1)
300         .byte >((SndDefEnvWave)-1)
301         .byte >((SndSetEnvWave)-1)
302         .byte >((SndSetStereo)-1)
303         .byte >((SndSetAttenuationOn)-1)
304         .byte >((SndSetChnAttenution)-1)
305         .byte >((SndPlayerFreq)-1)
306         .byte >((SndReturnAll)-1)
307
308 ;----------------------------------------------------------------------------
309 ; Get next sound command from stream
310 ;
311
312 SndGetCmd:
313         lda SndReqStop,x
314         bne SndStop
315
316         lda SndRetAFlag2
317         and SndMask,x
318         _IFNE
319                 eor SndRetAFlag2
320                 sta SndRetAFlag2
321                 lda SndRetAddr,x
322                 sta SndPtrLo,x
323                 lda SndRetAddr+4,x
324                 sta SndPtrHi,x
325                 ;;; force the direct continue return
326         _ELSE
327                 dec SndDelay,x
328                 bne cmd991 ;; check special case
329         _ENDIF
330
331         lda SndPtrLo,x
332         sta SndPtrTmp
333         lda SndPtrHi,x
334         sta SndPtrTmp+1
335 cmd0:   lda (SndPtrTmp)
336         beq SndStop
337         _IFMI
338                 and #$7f
339                 tay
340                 jsr SndCallCmd
341         _ELSE
342                 jsr SndNewNote
343         _ENDIF
344         clc
345         tya
346         and #$7f
347         adc SndPtrTmp
348         sta SndPtrLo,x
349         sta SndPtrTmp
350         lda #0
351         adc SndPtrTmp+1
352         sta SndPtrHi,x
353         sta SndPtrTmp+1
354
355         tya
356         bmi cmd0
357 cmd991:
358         ;; now check if delay is only 1 AND next one is return all.
359         lda #1
360         cmp SndDelay,x
361         bne cmd99
362
363         ;; NOW read ahead ONE
364         lda SndPtrLo,x
365         sta SndPtrTmp
366         lda SndPtrHi,x
367         sta SndPtrTmp+1
368
369         lda (SndPtrTmp)
370         cmp #$92 ;; Return all
371         _IFEQ
372                 sta SndRetAFlag ; just set !=0
373         _ENDIF
374 cmd99:  rts
375
376 ;----------------------------------------------------------------------------
377 ; Call function pointed to by y
378 ;
379
380 SndCallCmd:
381         lda SndCmdsHi,y
382         pha
383         lda SndCmdsLo,y
384         pha
385         ldy #1
386         rts
387
388 ;----------------------------------------------------------------------------
389 ; Stop sound on one channel
390 ;
391
392 SndStop:
393         stz SndReqStop,x
394         stz SndActive,x
395         ldy SndOffsets,x
396         lda #0
397         sta SndChannel,y
398         ina ;lda #1
399         sta SndChannel+2,y
400         tay ;ldy #1
401         rts
402
403
404 ;----------------------------------------------------------------------------
405 ; Send a new note, length, volume triplet
406 ;
407
408 SndNewNote:
409         phx
410         sta SndNotePlaying,x
411         pha
412         ldy #1
413         lda (SndPtrTmp),y
414         sta SndDelay,x
415         ldy SndOffsets,x
416         lda SndVolume,x
417         sta SndChannel,y
418         plx
419         lda SndPrescaler,x
420         sta SndChannel+5,y
421         lda SndReload,x
422         sta SndChannel+4,y
423         lda #$FF   ; = -1
424         sta SndChannel+2,y
425         plx
426         lda SndEnvVol,x
427         _IFNE
428                 jsr SndSetEnvVol1
429         _ENDIF
430         lda SndEnvFrq,x
431         _IFNE
432                 jsr SndSetEnvFrq1
433         _ENDIF
434         lda SndEnvWave,x
435         _IFNE
436                 jsr SndSetEnvWave1
437         _ENDIF
438         lda #$2
439         ldy SndDelay,x
440         _IFNE
441                 ora #$80
442         _ENDIF
443         tay
444         rts
445
446 ;----------------------------------------------------------------------------
447 ; Start a loop with count
448 ;
449
450 SndLoop:
451         lda (SndPtrTmp),y
452         sta SndLoopCnt,x
453         lda SndPtrTmp
454         sta SndLoopPtrLo,x
455         lda SndPtrTmp+1
456         sta SndLoopPtrHi,x
457         ldy #$82
458         rts
459
460 SndDo:
461         dec SndLoopCnt,x
462         _IFNE
463                 lda SndLoopPtrLo,x
464                 sta SndPtrTmp
465                 lda SndLoopPtrHi,x
466                 sta SndPtrTmp+1
467                 ldy #$82
468         _ELSE
469                 ldy #$81
470         _ENDIF
471         rts
472
473 ;----------------------------------------------------------------------------
474 ; Sound volume envelope
475 ;
476
477 SndDefEnvVol:
478         phx
479         lda (SndPtrTmp),y               ; env #
480         tax
481
482         iny
483         lda (SndPtrTmp),y
484         sta SndEnvVolPtrLo,x
485         iny
486         lda (SndPtrTmp),y
487         sta SndEnvVolPtrHi,x            ; Ptr to [cnt,inc]
488
489         ldy #$84
490         plx
491         rts
492
493 SndSetEnvVol:
494         lda (SndPtrTmp),y               ; # env
495
496 SndSetEnvVol1:
497         and #$7f
498         sta SndEnvVol,x                 ; save
499         _IFEQ
500                 ldy #$82
501                 rts
502         _ENDIF
503
504         tay
505
506         lda SndEnvVolPtrLo,y
507         sta SndEnvPtr
508         lda SndEnvVolPtrHi,y
509         sta SndEnvPtr+1
510
511         lda (SndEnvPtr)
512         sta SndTmp
513         asl
514         sta SndEnvVolLoop,x             ; here is the loop-start
515
516         ldy #1
517         lda (SndEnvPtr),y
518         sta SndEnvVolParts,x
519         sec
520         sbc SndTmp
521         sta SndEnvVolParts2,x
522
523         stz SndEnvVolCnt,x
524         lda #2
525         sta SndEnvVolOff,x
526
527         ldy #$82
528         rts
529
530 ;----------------------------------------------------------------------------
531 ; Sound frequency envelope
532 ;
533
534 SndDefEnvFrq:
535         phx
536         lda (SndPtrTmp),y               ; env #
537         tax
538
539         iny
540         lda (SndPtrTmp),y
541         sta SndEnvFrqPtrLo,x
542         iny
543         lda (SndPtrTmp),y
544         sta SndEnvFrqPtrHi,x            ; Ptr to [inc,cnt]
545         plx
546         ldy #$84
547         rts
548
549 SndSetEnvFrq:
550         lda (SndPtrTmp),y               ; # env
551
552 SndSetEnvFrq1:
553         and #$7f
554         sta SndEnvFrq,x                 ; save
555         _IFEQ
556                 ldy #$82
557                 rts
558         _ENDIF
559
560         tay
561
562         lda SndEnvFrqPtrLo,y
563         sta SndEnvPtr
564         lda SndEnvFrqPtrHi,y
565         sta SndEnvPtr+1
566
567         lda (SndEnvPtr)
568         sta SndTmp
569         asl
570         sta SndEnvFrqLoop,x
571
572         ldy #1
573         lda (SndEnvPtr),y
574         sta SndEnvFrqParts,x
575         sec
576         sbc SndTmp
577         sta SndEnvFrqParts2,x
578
579         stz SndEnvFrqCnt,x
580         lda #2
581         sta SndEnvFrqOff,x
582
583         ldy #$82
584         rts
585
586 ;----------------------------------------------------------------------------
587 ; Sound frequency envelope
588 ;
589
590 SndDefEnvWave:
591
592         phx
593         lda (SndPtrTmp),y               ; env #
594         tax
595
596         iny
597         lda (SndPtrTmp),y
598         sta SndEnvWavePtrLo,x
599         iny
600         lda (SndPtrTmp),y
601         sta SndEnvWavePtrHi,x            ; Ptr to [inc,cnt]
602         plx
603         ldy #$84
604         rts
605
606 SndSetEnvWave:
607         lda (SndPtrTmp),y               ; # env
608
609 SndSetEnvWave1:
610         and #$7f
611         sta SndEnvWave,x                 ; save
612         _IFEQ
613                 ldy #$82
614                 rts
615         _ENDIF
616
617         tay
618
619         lda SndEnvWavePtrLo,y
620         sta SndEnvPtr
621         lda SndEnvWavePtrHi,y
622         sta SndEnvPtr+1
623
624         lda (SndEnvPtr)
625         sta SndTmp
626         asl ; *4 -2
627         dea
628         asl
629         sta SndEnvWaveLoop,x
630
631         ldy #1
632         lda (SndEnvPtr),y
633         sta SndEnvWaveParts,x
634         sec
635         sbc SndTmp
636         sta SndEnvWaveParts2,x
637
638         stz SndEnvWaveCnt,x
639         lda #2
640         sta SndEnvWaveOff,x
641
642         ldy #$82
643         rts
644
645 ;----------------------------------------------------------------------------
646 ; Pause sound
647 ;
648
649 SndPause:
650                 lda (SndPtrTmp),y
651                 sta SndDelay,x
652                 iny
653 SndDummy:        rts
654 ;;;* This set the new Player Freq instantanious!!!
655 SndPlayerFreq:
656                 lda (SndPtrTmp),y
657                 sta STIMCTLA
658                 iny
659                 lda (SndPtrTmp),y
660                 sta STIMBKUP
661                 ldy #$83
662                 rts
663
664 SndNoteOff:
665                 ldy SndOffsets,x
666                 stz SndNotePlaying,x
667                 lda SndEnvVol,x
668                 ora #$80
669                 sta SndEnvVol,x
670                 lda SndEnvFrq,x
671                 ora #$80
672                 sta SndEnvFrq,x
673                 lda SndEnvWave,x
674                 ora #$80
675                 sta SndEnvWave,x
676                 lda #0
677                 sta SndChannel,y
678                 sta SndChannel+4,y
679                 sta SndChannel+5,y
680                 dea
681                 sta SndChannel+2,y
682                 ldy #$81
683                 rts
684 SndSetInstr:
685                 phx
686                 lda SndOffsets,x
687                 tax
688                 lda (SndPtrTmp),y
689                 sta SndChannel+3,x
690                 iny
691                 lda (SndPtrTmp),y
692                 sta SndChannel+7,x
693                 iny
694                 lda (SndPtrTmp),y
695                 sta SndChannel+1,x
696                 plx
697                 iny
698                 lda (SndPtrTmp),y
699                 sta SndVolume,x
700                 iny
701                 lda (SndPtrTmp),y
702                 sta SndMaxVolume,x
703
704                 ldy #$86
705                 rts
706 SndCallPattern:
707                 clc
708                 lda SndPtrTmp
709                 adc #3
710                 sta SndRetAddr,x
711                 lda SndPtrTmp+1
712                 adc #0
713                 sta SndRetAddr+4,x
714                 ldy #1
715                 lda (SndPtrTmp),y
716                 pha
717                 iny
718                 lda (SndPtrTmp),y
719                 sta SndPtrTmp+1
720                 pla
721                 sta SndPtrTmp
722                 ldy #$80
723                 rts
724
725 SndRetToSong:
726                 lda SndRetAddr,x
727                 sta SndPtrTmp
728                 lda SndRetAddr+4,x
729                 sta SndPtrTmp+1
730                 ldy #$80
731                 rts
732
733 SndReturnAll:
734                 lda #1
735                 sta SndRetAFlag
736                 sta SndDelay,x
737                 ldy #$0
738                 rts
739 SndNewNote2:
740 ;;; Note,length,volume
741
742                 phx
743                   sta SndNotePlaying,x
744                   ldy #1
745                   lda (SndPtrTmp),y             ; reload
746                   pha
747                   iny
748                   lda (SndPtrTmp),y             ; prescale
749                   pha
750                   iny
751                   lda (SndPtrTmp),y         ; laenge
752                   sta SndDelay,x
753
754                   ldy SndOffsets,x
755                   lda SndVolume,x
756                   sta SndChannel,y
757                   pla
758                   sta SndChannel+5,y
759                   pla
760                   sta SndChannel+4,y
761                   lda #$FF ; = -1
762                   sta SndChannel+2,y
763                 plx
764                 lda SndEnvVol,x
765                 _IFNE
766                   jsr SndSetEnvVol1
767                 _ENDIF
768                 lda SndEnvFrq,x
769                 _IFNE
770                   jsr SndSetEnvFrq1
771                 _ENDIF
772                 lda SndEnvWave,x
773                 _IFNE
774                   jsr SndSetEnvWave1
775                 _ENDIF
776                 ldy #4
777                 rts
778
779 SndSetStereo:
780                 ldy #1
781                 lda (SndPtrTmp),y
782                 sta MSTEREO
783                 ldy #$82
784                 rts
785
786 SndSetAttenuationOn:
787                 ldy #1
788                 lda (SndPtrTmp),y
789                 sta $FD44
790                 ldy #$82
791                 rts
792
793 SndSetChnAttenution:
794                 ldy #1
795                 lda (SndPtrTmp),y
796                 sta $FD40,x
797                 ldy #$82
798                 rts
799
800 SndChangeVol:
801                 tay
802                 _IFMI
803 vol99:               rts
804                 _ENDIF
805                 lda SndNotePlaying,x
806                 beq vol99
807
808                 lda SndEnvVolPtrLo,y
809                 sta SndEnvPtr
810                 lda SndEnvVolPtrHi,y
811                 sta SndEnvPtr+1
812
813                 dec SndEnvVolCnt,x
814                 _IFMI
815                   dec SndEnvVolParts,x
816                   _IFMI
817                     lda SndEnvVolLoop,x
818                     _IFNE
819                       tay
820                       lda SndEnvVolParts2,x
821                       sta SndEnvVolParts,x
822                       bra vol1v
823                     _ELSE
824                       tya
825                       ora #$80
826                       sta SndEnvVol,x
827                     _ENDIF
828                   _ELSE
829                     ldy SndEnvVolOff,x
830 vol1v:                 lda (SndEnvPtr),y
831                     sta SndEnvVolCnt,x
832                     iny
833                     lda (SndEnvPtr),y
834                     sta SndEnvVolInc,x
835                     iny
836                     tya
837                     sta SndEnvVolOff,x
838                   _ENDIF
839                   rts
840                 _ENDIF
841
842                   ldy SndOffsets,x
843                   clc
844                   lda SndEnvVolInc,x
845                   _IFEQ
846                     rts
847                   _ENDIF
848                   _IFPL
849                     adc SndChannel,y
850                     cmp SndMaxVolume,x
851                     _IFCS
852                       lda SndMaxVolume,x
853                       stz SndEnvVolInc,x
854                     _ENDIF
855                     cmp #$80
856                     _IFGE
857                       lda #$7f
858                       stz SndEnvVolInc,x
859                     _ENDIF
860                  _ELSE
861                    adc SndChannel,y
862                    _IFCC
863                      lda #0
864                      sta SndEnvVolInc,x
865                      ;; NEU: switch Tremolo off
866                      sta SndNotePlaying,x
867                    _ENDIF
868                    cmp #$80
869                    _IFGE
870                      lda #0
871                      sta SndEnvVolInc,x
872                      ;; NEU: switch Tremolo off
873                      sta SndNotePlaying,x
874                    _ENDIF
875                  _ENDIF
876                   sta SndChannel,y
877                   lda SndChannel+2,y
878                   ora #1 ;; if already -1 ... no effect
879                   sta SndChannel+2,y
880                 rts
881
882
883 SndChangeFrq:
884                 tay
885                 _IFMI
886 frq99:               rts
887                 _ENDIF
888                 lda SndNotePlaying,x
889                 beq frq99
890
891                 lda SndEnvFrqPtrLo,y
892                 sta SndEnvPtr
893                 lda SndEnvFrqPtrHi,y
894                 sta SndEnvPtr+1
895
896                 dec SndEnvFrqCnt,x
897                 _IFMI
898                   dec SndEnvFrqParts,x
899                   _IFMI
900                     lda SndEnvFrqLoop,x
901                     _IFNE
902                       tay
903                       lda SndEnvFrqParts2,x
904                       sta SndEnvFrqParts,x
905                       bra frq1f
906                     _ELSE
907                       tya
908                       ora #$80
909                       sta SndEnvFrq,x
910                     _ENDIF
911                   _ELSE
912                     ldy SndEnvFrqOff,x
913 frq1f:                 lda (SndEnvPtr),y
914                     sta SndEnvFrqCnt,x
915                     iny
916                     lda (SndEnvPtr),y
917                     eor #$ff
918                     ina
919                     sta SndEnvFrqInc,x
920                     iny
921                     tya
922                     sta SndEnvFrqOff,x
923                   _ENDIF
924                   rts
925                   _ENDIF
926                   ldy SndOffsets,x
927                   clc
928                   lda SndEnvFrqInc,x
929                   _IFEQ
930                     rts
931                   _ENDIF
932
933                   _IFMI
934                     adc SndChannel+4,y
935                     _IFPL
936                       pha
937                       lda SndChannel+5,y
938                       _IFNE
939                         dea
940                         sta SndChannel+5,y
941                         pla
942                         eor #128
943                       _ELSE
944                         pla
945                         pha
946                         clc
947                         adc SndEnvFrqInc,x
948                         pla
949                       _ENDIF
950                     _ELSE
951                       pha
952                       lda SndChannel+5,y
953                       _IFEQ
954                         pla
955                         sta SndChannel+4,y
956                         rts
957                       _ENDIF
958                       pla
959                     _ENDIF
960                   _ELSE
961                     adc SndChannel+4,y
962                     _IFPL
963                       pha
964                       lda SndChannel+5,y
965                       cmp #6
966                       _IFNE
967                         ina
968                         sta SndChannel+5,y
969                         pla
970                         eor #128
971                       _ELSE
972                         lda SndChannel+4,y
973                         _IFMI
974                           pla
975                           rts
976                         _ENDIF
977                         pla
978                       _ENDIF
979                     _ELSE
980                       pha
981                       lda SndChannel+5,y
982                       cmp #6
983                       _IFEQ
984                         lda SndChannel+4,y
985                         _IFPL
986                           pla
987                           rts
988                         _ENDIF
989                       _ENDIF
990                       pla
991                     _ENDIF
992                   _ENDIF
993                   sta SndChannel+4,y
994
995                   ora #1 ;; if already -1 -> no effect
996                 rts
997
998 SndChangeWave:
999                 tay
1000                 ;; Ab hier x Kanal 0-3, y Environment
1001                 _IFMI
1002 wav99:               rts
1003                 _ENDIF
1004                 lda SndNotePlaying,x
1005                 beq wav99
1006
1007
1008                 lda SndEnvWavePtrLo,y
1009                 sta SndEnvPtr
1010                 lda SndEnvWavePtrHi,y
1011                 sta SndEnvPtr+1
1012
1013                 dec SndEnvWaveCnt,x
1014                 _IFMI
1015                   dec SndEnvWaveParts,x
1016                   _IFMI
1017                     lda SndEnvWaveLoop,x
1018                     _IFNE
1019                       tay
1020                       ;; Ab hier x Kanal 0-3, y Offset im Environment
1021                       lda SndEnvWaveParts2,x
1022                       sta SndEnvWaveParts,x
1023                       bra wav1v
1024                     _ELSE
1025                       tya
1026                       ora #$80 ;; beende Env
1027                       sta SndEnvWave,x
1028                     _ENDIF
1029                   _ELSE
1030                     ldy SndEnvWaveOff,x
1031                 ;; Ab hier x Kanal 0-3, y Offset im  Environment
1032 wav1v:                 lda (SndEnvPtr),y
1033                     sta SndEnvWaveCnt,x
1034                   phx
1035                   lda SndOffsets,x
1036                   tax
1037                 ;; Ab hier x Kanal (0-3)*8, y Offset im  Environment
1038
1039                     iny
1040                     lda (SndEnvPtr),y
1041                     sta SndChannel+3,x  ; Shift LO
1042                     iny
1043                     lda (SndEnvPtr),y
1044                     sta SndChannel+7,x   ; Shift HI
1045                     iny
1046                     lda (SndEnvPtr),y
1047                     sta SndChannel+1,x  ; Feedback
1048                     iny
1049                     tya
1050                     ply
1051                 ;; Ab hier x Kanal (0-3)*8,  y Kanal 0-3
1052                     sta SndEnvWaveOff,y
1053                   lda #$FF ; =-1 ;; stop timer to set new values...
1054                   sta SndChannel+2,x
1055                   _ENDIF
1056                 _ENDIF
1057                 rts
1058
1059
1060 SndSetValues:
1061                 ldx #4-1
1062 set0:                ldy SndOffsets,x
1063                   lda SndChannel+2,y
1064                   _IFNE                        ; flag == 0 => don`t set
1065
1066             bit #$80
1067                     _IFNE                       ;
1068                       lda #0
1069                       sta $fd25,y                 ; stop sound timer
1070
1071                       lda SndChannel+3,y
1072                       sta $fd23,y                 ; shifter 1
1073                       ;;lda $fd27,y
1074                       ;;and #$0F
1075                       ;;ora SndChannel+7,y          ; shifter 2
1076                       lda SndChannel+7,y          ; shifter 2
1077                       sta $fd27,y
1078                       lda SndChannel+1,y
1079                       sta $fd21,y                 ; feedback
1080                     _ENDIF
1081
1082                     lda SndChannel,y
1083                     sta $fd20,y                 ; volume
1084                     lda SndChannel+2,y
1085             bit #$80
1086                     _IFNE                       ;
1087                     lda SndChannel+4,y
1088                     sta $fd24,y                 ; reload
1089                     lda SndChannel+5,y
1090                     ora #%00011000 ;;; #%01011000
1091             ;; and #%00111111
1092                     sta $fd25,y                 ; re-enable timer
1093                     _ENDIF
1094
1095                     lda #0
1096                     sta SndChannel+2,y          ; clear flag
1097                 _ENDIF
1098
1099                 dex
1100         _IFPL
1101             jmp set0
1102         _ENDIF
1103         rts
1104
1105 _lynx_snd_play:
1106         sta ptr1
1107         stx ptr1+1
1108         jsr popa
1109         tax
1110         lda ptr1
1111         ldy ptr1+1
1112         php
1113         pha
1114         lda SndActive,x
1115         _IFNE
1116                 dec SndReqStop,x
1117                 lda #1
1118                 sta SndDelay,x
1119 start0:         lda SndActive,x
1120                 bne start0
1121         _ENDIF
1122         bra start1
1123 SndStartSoundx:
1124         php
1125         pha
1126 start1:
1127         sei
1128         pla
1129         sta SndPtrLo,x
1130         tya
1131         sta SndPtrHi,x
1132         lda #1
1133         sta SndDelay,x
1134         stz SndEnvVol,x
1135         stz SndEnvFrq,x
1136         stz SndEnvWave,x
1137         sta SndActive,x
1138         stz SndReqStop,x
1139         plp
1140         rts
1141 SndStartSound2:
1142         pha
1143         lda SndActive,x         ; check default
1144         beq start20                  ; inactive => ok
1145         phx
1146         ldx #3                  ; search free channel
1147 start21:
1148         lda SndActive,x
1149         beq start22                ; found =>
1150         dex
1151         bpl start21
1152         plx                     ; not found
1153         dec SndReqStop,x        ; stop default-channel
1154         lda #1
1155         sta SndDelay,x
1156 start23:
1157         lda SndActive,x
1158         bne start23
1159         bra start20
1160 start22:
1161         pla             ; clear stack
1162 start20:
1163         pla
1164         phx
1165         jsr SndStartSoundx      ; launch new sound
1166         plx
1167         rts
1168
1169 _lynx_snd_stop:
1170         ldx #3
1171         lda SndActive,x
1172         _IFNE
1173 stop0:          dec SndReqStop,x
1174                 lda #1
1175                 sta SndDelay,x
1176 stop1:          lda SndActive,x
1177                 bne stop1
1178         _ENDIF
1179         dex
1180         bpl stop0
1181         rts
1182
1183 _lynx_snd_stop_channel:
1184         lda SndActive,x
1185         _IFNE
1186                 dec SndReqStop,x
1187                 lda #1
1188                 sta SndDelay,x
1189 stopc1:         lda SndActive,x
1190                 bne stopc1
1191         _ENDIF
1192         rts
1193
1194 _lynx_snd_active:
1195         ldx #3
1196         lda #0
1197 act0:   ldy SndActive,x
1198         _IFNE
1199                 ora SndMask,x
1200         _ENDIF
1201         dex
1202         bpl act0
1203         rts
1204
1205 _lynx_snd_pause:
1206         php
1207         sei
1208         lda STIMCTLA
1209         sta SndPauseOff1+1
1210         stz STIMCTLA
1211         lda MSTEREO
1212         sta SndPauseOff2+1
1213         lda #$ff
1214         sta MSTEREO
1215         lda #$18
1216         trb AUD0CTLA
1217         trb AUD1CTLA
1218         trb AUD2CTLA
1219         trb AUD3CTLA
1220         plp
1221         rts
1222
1223 _lynx_snd_continue:
1224         php
1225         sei
1226 SndPauseOff1:
1227         lda #0 ; Selbsmodifizierter Code!!!
1228         sta STIMCTLA
1229 SndPauseOff2:
1230         lda #0 ; Selbsmodifizierter Code!!!
1231         sta MSTEREO
1232
1233         lda #$18
1234         tsb AUD0CTLA
1235         tsb AUD1CTLA
1236         tsb AUD2CTLA
1237         tsb AUD3CTLA
1238
1239         plp
1240         rts
1241
1242         .rodata
1243
1244 SndMask:
1245         .byte 1,2,4,8
1246
1247 SndPrescaler:
1248         .byte $00,$06,$06,$06,$06,$05,$05,$05,$05,$05,$05,$05,$04,$04,$04,$04
1249         .byte $04,$04,$04,$04,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$02,$02
1250         .byte $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$01,$01,$01,$01,$01
1251         .byte $01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$00,$00
1252         .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1253         .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1254         .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1255         .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1256
1257 SndReload:
1258         .byte $00,$9A,$96,$8F,$86,$FA,$E5,$D1,$BE,$AC,$9C,$8D,$00,$E8,$D3,$C0
1259         .byte $AF,$A0,$93,$87,$FA,$E7,$D6,$C6,$B8,$AC,$A1,$96,$8D,$84,$FA,$EB
1260         .byte $DE,$D2,$C7,$BC,$B3,$AA,$A1,$9A,$93,$8C,$86,$00,$F5,$EB,$E1,$D8
1261         .byte $CF,$C7,$C0,$B9,$B2,$AB,$A5,$A0,$9A,$95,$90,$8B,$87,$82,$FD,$F5
1262         .byte $EE,$E7,$E0,$D9,$D3,$CD,$C8,$C2,$BD,$B8,$B3,$AE,$AA,$A5,$A1,$9D
1263         .byte $99,$96,$92,$8F,$8B,$88,$85,$82,$7F,$7C,$79,$77,$74,$72,$6F,$6D
1264         .byte $6B,$69,$67,$64,$63,$61,$5F,$5D,$5B,$59,$58,$56,$55,$53,$51,$50
1265         .byte $4F,$4D,$4C,$4B,$49,$48,$47,$46,$44,$43,$42,$41,$40,$3F,$3E,$3D
1266
1267
1268