2 ; Sound driver for the Atari Lynx.
4 ; Karri Kaksonen and Bjoern Spruck, 11.12.2012
8 .include "zeropage.inc"
10 .export _lynx_snd_init
11 .export _lynx_snd_active
12 .export _lynx_snd_play
13 .export _lynx_snd_stop
14 .export _lynx_snd_stop_channel
15 .export _lynx_snd_pause
16 .export _lynx_snd_continue
17 .interruptor lynx_snd_handler
21 ;----------------------------------------------------------------------------
22 ; ZP variables that go into APPZP
25 .segment "APPZP" : zeropage
32 ;----------------------------------------------------------------------------
48 SndNotePlaying: .res 4
60 SndEnvVolParts: .res 4
61 SndEnvVolParts2: .res 4
66 SndEnvFrqParts: .res 4
67 SndEnvFrqParts2: .res 4
70 SndEnvWaveLoop: .res 4
71 SndEnvWaveParts: .res 4
72 SndEnvWaveParts2: .res 4
74 MAX_INSTRUMENTS .set 64
75 SndEnvVolPtrLo: .res MAX_INSTRUMENTS
76 SndEnvVolPtrHi: .res MAX_INSTRUMENTS
77 SndEnvFrqPtrLo: .res MAX_INSTRUMENTS
78 SndEnvFrqPtrHi: .res MAX_INSTRUMENTS
79 SndEnvWavePtrLo: .res MAX_INSTRUMENTS
80 SndEnvWavePtrHi: .res MAX_INSTRUMENTS
84 SndOffsets: .byte $00,$08,$10,$18
86 ;----------------------------------------------------------------------------
94 if_count .set if_count +1
95 nest_count .set nest_count +1
96 beq .ident (.sprintf ("else%04d", if_count))
97 .ident (.sprintf ("push%04d", nest_count)) .set if_count
101 if_count .set if_count +1
102 nest_count .set nest_count +1
103 bne .ident (.sprintf ("else%04d", if_count))
104 .ident (.sprintf ("push%04d", nest_count)) .set if_count
108 if_count .set if_count +1
109 nest_count .set nest_count +1
110 bpl .ident (.sprintf ("else%04d", if_count))
111 .ident (.sprintf ("push%04d", nest_count)) .set if_count
115 if_count .set if_count +1
116 nest_count .set nest_count +1
117 bmi .ident (.sprintf ("else%04d", if_count))
118 .ident (.sprintf ("push%04d", nest_count)) .set if_count
122 if_count .set if_count +1
123 nest_count .set nest_count +1
124 bcc .ident (.sprintf ("else%04d", if_count))
125 .ident (.sprintf ("push%04d", nest_count)) .set if_count
129 if_count .set if_count +1
130 nest_count .set nest_count +1
131 bcc .ident (.sprintf ("else%04d", if_count))
132 .ident (.sprintf ("push%04d", nest_count)) .set if_count
136 if_count .set if_count +1
137 nest_count .set nest_count +1
138 bcs .ident (.sprintf ("else%04d", if_count))
139 .ident (.sprintf ("push%04d", nest_count)) .set if_count
143 bra .ident (.sprintf ("endif%04d", .ident (.sprintf ("push%04d", nest_count))))
144 .ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
148 .if .not .defined( .ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))))
149 .ident (.sprintf ("else%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
151 .ident (.sprintf ("endif%04d", .ident (.sprintf ("push%04d", nest_count)))) := *
152 nest_count .set nest_count -1
157 ;----------------------------------------------------------------------------
158 ; void lynx_snd_init() will initialize the sound engine.
166 lda #%10011000|_31250Hz
169 sta STIMBKUP ; set up a 240Hz IRQ
176 stz $fd44 ; all channels full volume / no attenuation
188 init0: stz SndActive,x
203 ;----------------------------------------------------------------------------
204 ; lynx_snd_handler is run at every sound interrupt
218 ; *NOW* set all values which were "pre-set" in last interrupt
222 lda SndRetAFlag ; reset the return flag, but save it first
263 ;----------------------------------------------------------------------------
264 ; A process table with addresses to sound functions
270 .byte <((SndPause)-1)
271 .byte <((SndNoteOff)-1)
272 .byte <((SndSetInstr)-1)
273 .byte <((SndNewNote2)-1)
274 .byte <((SndCallPattern)-1)
275 .byte <((SndRetToSong)-1)
276 .byte <((SndDefEnvVol)-1)
277 .byte <((SndSetEnvVol)-1)
278 .byte <((SndDefEnvFrq)-1)
279 .byte <((SndSetEnvFrq)-1)
280 .byte <((SndDefEnvWave)-1)
281 .byte <((SndSetEnvWave)-1)
282 .byte <((SndSetStereo)-1)
283 .byte <((SndSetAttenuationOn)-1)
284 .byte <((SndSetChnAttenution)-1)
285 .byte <((SndPlayerFreq)-1)
286 .byte <((SndReturnAll)-1)
291 .byte >((SndPause)-1)
292 .byte >((SndNoteOff)-1)
293 .byte >((SndSetInstr)-1)
294 .byte >((SndNewNote2)-1)
295 .byte >((SndCallPattern)-1)
296 .byte >((SndRetToSong)-1)
297 .byte >((SndDefEnvVol)-1)
298 .byte >((SndSetEnvVol)-1)
299 .byte >((SndDefEnvFrq)-1)
300 .byte >((SndSetEnvFrq)-1)
301 .byte >((SndDefEnvWave)-1)
302 .byte >((SndSetEnvWave)-1)
303 .byte >((SndSetStereo)-1)
304 .byte >((SndSetAttenuationOn)-1)
305 .byte >((SndSetChnAttenution)-1)
306 .byte >((SndPlayerFreq)-1)
307 .byte >((SndReturnAll)-1)
309 ;----------------------------------------------------------------------------
310 ; Get next sound command from stream
326 ;;; force the direct continue return
329 bne cmd991 ;; check special case
336 cmd0: lda (SndPtrTmp)
359 ;; now check if delay is only 1 AND next one is return all.
364 ;; NOW read ahead ONE
371 cmp #$92 ;; Return all
373 sta SndRetAFlag ; just set !=0
377 ;----------------------------------------------------------------------------
378 ; Call function pointed to by y
389 ;----------------------------------------------------------------------------
390 ; Stop sound on one channel
405 ;----------------------------------------------------------------------------
406 ; Send a new note, length, volume triplet
447 ;----------------------------------------------------------------------------
448 ; Start a loop with count
474 ;----------------------------------------------------------------------------
475 ; Sound volume envelope
480 lda (SndPtrTmp),y ; env #
488 sta SndEnvVolPtrHi,x ; Ptr to [cnt,inc]
495 lda (SndPtrTmp),y ; # env
499 sta SndEnvVol,x ; save
515 sta SndEnvVolLoop,x ; here is the loop-start
522 sta SndEnvVolParts2,x
531 ;----------------------------------------------------------------------------
532 ; Sound frequency envelope
537 lda (SndPtrTmp),y ; env #
545 sta SndEnvFrqPtrHi,x ; Ptr to [inc,cnt]
551 lda (SndPtrTmp),y ; # env
555 sta SndEnvFrq,x ; save
578 sta SndEnvFrqParts2,x
587 ;----------------------------------------------------------------------------
588 ; Sound frequency envelope
594 lda (SndPtrTmp),y ; env #
599 sta SndEnvWavePtrLo,x
602 sta SndEnvWavePtrHi,x ; Ptr to [inc,cnt]
608 lda (SndPtrTmp),y ; # env
612 sta SndEnvWave,x ; save
620 lda SndEnvWavePtrLo,y
622 lda SndEnvWavePtrHi,y
634 sta SndEnvWaveParts,x
637 sta SndEnvWaveParts2,x
646 ;----------------------------------------------------------------------------
655 ;;;* This set the new Player Freq instantanious!!!
741 ;;; Note,length,volume
746 lda (SndPtrTmp),y ; reload
749 lda (SndPtrTmp),y ; prescale
752 lda (SndPtrTmp),y ; laenge
821 lda SndEnvVolParts2,x
831 vol1v: lda (SndEnvPtr),y
866 ;; NEU: switch Tremolo off
873 ;; NEU: switch Tremolo off
879 ora #1 ;; if already -1 ... no effect
904 lda SndEnvFrqParts2,x
914 frq1f: lda (SndEnvPtr),y
996 ora #1 ;; if already -1 -> no effect
1001 ;; Ab hier x Kanal 0-3, y Environment
1005 lda SndNotePlaying,x
1009 lda SndEnvWavePtrLo,y
1011 lda SndEnvWavePtrHi,y
1016 dec SndEnvWaveParts,x
1018 lda SndEnvWaveLoop,x
1021 ;; Ab hier x Kanal 0-3, y Offset im Environment
1022 lda SndEnvWaveParts2,x
1023 sta SndEnvWaveParts,x
1027 ora #$80 ;; beende Env
1032 ;; Ab hier x Kanal 0-3, y Offset im Environment
1033 wav1v: lda (SndEnvPtr),y
1038 ;; Ab hier x Kanal (0-3)*8, y Offset im Environment
1042 sta SndChannel+3,x ; Shift LO
1045 sta SndChannel+7,x ; Shift HI
1048 sta SndChannel+1,x ; Feedback
1052 ;; Ab hier x Kanal (0-3)*8, y Kanal 0-3
1054 lda #$FF ; =-1 ;; stop timer to set new values...
1063 set0: ldy SndOffsets,x
1065 _IFNE ; flag == 0 => don`t set
1070 sta $fd25,y ; stop sound timer
1073 sta $fd23,y ; shifter 1
1076 ;;ora SndChannel+7,y ; shifter 2
1077 lda SndChannel+7,y ; shifter 2
1080 sta $fd21,y ; feedback
1084 sta $fd20,y ; volume
1089 sta $fd24,y ; reload
1091 ora #%00011000 ;;; #%01011000
1093 sta $fd25,y ; re-enable timer
1097 sta SndChannel+2,y ; clear flag
1120 start0: lda SndActive,x
1144 lda SndActive,x ; check default
1145 beq start20 ; inactive => ok
1147 ldx #3 ; search free channel
1150 beq start22 ; found =>
1154 dec SndReqStop,x ; stop default-channel
1166 jsr SndStartSoundx ; launch new sound
1174 stop0: dec SndReqStop,x
1177 stop1: lda SndActive,x
1184 _lynx_snd_stop_channel:
1191 stopc1: lda SndActive,x
1199 act0: ldy SndActive,x
1229 lda #0 ; Selbsmodifizierter Code!!!
1232 lda #0 ; Selbsmodifizierter Code!!!
1250 .byte $00,$06,$06,$06,$06,$05,$05,$05,$05,$05,$05,$05,$04,$04,$04,$04
1251 .byte $04,$04,$04,$04,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$02,$02
1252 .byte $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$01,$01,$01,$01,$01
1253 .byte $01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$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 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1257 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1260 .byte $00,$9A,$96,$8F,$86,$FA,$E5,$D1,$BE,$AC,$9C,$8D,$00,$E8,$D3,$C0
1261 .byte $AF,$A0,$93,$87,$FA,$E7,$D6,$C6,$B8,$AC,$A1,$96,$8D,$84,$FA,$EB
1262 .byte $DE,$D2,$C7,$BC,$B3,$AA,$A1,$9A,$93,$8C,$86,$00,$F5,$EB,$E1,$D8
1263 .byte $CF,$C7,$C0,$B9,$B2,$AB,$A5,$A0,$9A,$95,$90,$8B,$87,$82,$FD,$F5
1264 .byte $EE,$E7,$E0,$D9,$D3,$CD,$C8,$C2,$BD,$B8,$B3,$AE,$AA,$A5,$A1,$9D
1265 .byte $99,$96,$92,$8F,$8B,$88,$85,$82,$7F,$7C,$79,$77,$74,$72,$6F,$6D
1266 .byte $6B,$69,$67,$64,$63,$61,$5F,$5D,$5B,$59,$58,$56,$55,$53,$51,$50
1267 .byte $4F,$4D,$4C,$4B,$49,$48,$47,$46,$44,$43,$42,$41,$40,$3F,$3E,$3D