-
Notifications
You must be signed in to change notification settings - Fork 1
/
ayfxplay.asm
291 lines (246 loc) · 6.52 KB
/
ayfxplay.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
;--------------------------------------------------------------;
; ;
;The simplest effects player. ;
; ;
;Plays effects on one AY, without music on the background. ;
; ;
;Priority of channel selection: ;
; If there are free channels, one of them is selected. ;
; If there are no free channels, the longest sounding ;
; is selected. ;
; ;
;The playing procedure uses the registers AF, BC, DE, HL, IY. ;
; ;
; Initialization: ;
; ld hl, Effects Bank Address ;
; call AFXINIT ;
; ;
; Start the effect: ;
; ld a, effect number (0..255) ;
; call AFXPLAY ;
; ;
; In the interrupt handler: ;
; call AFXFRAME ;
; ;
;--------------------------------------------------------------;
; channel descriptors, 4 bytes per channel:
; +0 (2) current address (the channel is free if the high byte =$00)
; +2 (2) sound time
; ...
afxChDesc .fill 3*4
;--------------------------------------------------------------;
; Initializing the effects player. ;
; Turns off all channels, sets variables. ;
; Input: HL = bank address with effects ;
;--------------------------------------------------------------;
INIT_AFX:
inc hl
ld (afxBnkAdr+1),hl ;save the address of the table of offsets
ld (afxBnkAdr2+1),hl ;save the address of the table of offsets
ld hl,afxChDesc ;mark all channels as empty
ld de,$00ff
ld bc,$0300
afxInit0
ld (hl),d
inc hl
ld (hl),d
inc hl
ld (hl),e
inc hl
ld (hl),e
inc hl
djnz afxInit0
ld hl,$cf0f ;initialize AY
ld e,15
afxInit1
dec e
ld c,h
out (c),e
ld c,l
out (c),d
jr nz,afxInit1
ld (afxNseMix+1),de ;reset the player variables
ret
;--------------------------------------------------------------;
; Playing the current frame. ;
; No parameters . ;
;--------------------------------------------------------------;
AFXFRAME:
ld bc,$0300
ld iy,afxChDesc
afxFrame0
push bc
ld a,11
ld h,(iy+1) ;the comparison of the high-order byte of the address to <11
cp h
jr nc,afxFrame7 ;the channel does not play, we skip
ld l,(iy+0)
ld e,(hl) ;we take the value of the information byte
inc hl
sub b ;select the volume register:
ld d,b ;(11-3=8, 11-2=9, 11-1=10)
ld c,$cf ;output the volume value
out (c),a
ld a,e
and $0f
ld c,$0f
out (c),a
bit 5,e ;will change the tone?
jr z,afxFrame1 ;tone does not change
ld a,3 ;select the tone registers:
sub d ;3-3=0, 3-2=1, 3-1=2
add a,a ;0*2=0, 1*2=2, 2*2=4
ld c,$cf ;output the tone values
out (c),a
ld d,(hl)
inc hl
ld c,$0f
out (c),d
inc a
ld c,$cf
out (c),a
ld d,(hl)
inc hl
ld c,$0f
out (c),d
afxFrame1
bit 6,e ;will change the noise?
jr z,afxFrame3 ;noise does not change
ld a,(hl) ;read the meaning of noise
sub $20
jr c,afxFrame2 ;less than $ 20, play on
ld h,a ;otherwise the end of the effect
ld l,a
ld b,$ff
ld c,b ;in BC we record the longest time
jr afxFrame6
afxFrame2
inc hl
ld (afxNseMix+1),a ;keep the noise value
afxFrame3
pop bc ;restore the value of the cycle in B
push bc
inc b ;number of shifts for flags TN
ld a,%01101111 ;mask for flags TN
afxFrame4
rrc e ;shift flags and mask
rrca
djnz afxFrame4
ld d,a
ld bc,afxNseMix+2 ;store the values of the flags
ld a,(bc)
xor e
and d
xor e ;E is masked by D
ld (bc),a
afxFrame5
ld c,(iy+2) ;increase the time counter
ld b,(iy+3)
inc bc
afxFrame6
ld (iy+2),c
ld (iy+3),b
ld (iy+0),l ;save the changed address
ld (iy+1),h
afxFrame7
ld bc,4 ;go to the next channel
add iy,bc
pop bc
djnz afxFrame0
ld hl,$cf0f ;output the value of noise and mixer
afxNseMix
ld de,0 ;+1 (E) = noise, +2 (D) = mixer
ld a,6
ld c,h
out (c),a
ld c,l
out (c),e
inc a
ld c,h
out (c),a
ld c,l
out (c),d
ret
;--------------------------------------------------------------;
; Launch the effect on a free channel. Without ;
; free channels is selected the longest sounding. ;
; Input: A = Effect number 1..255 ;
;--------------------------------------------------------------;
AFXPLAY:
push hl
push bc
push de
dec a ; input matches fx number in ayfxedit
ld de,0 ; in DE the longest time in search
ld h,e
ld l,a
add hl,hl
afxBnkAdr
ld bc,0 ;address of the effect offsets table
add hl,bc
ld c,(hl)
inc hl
ld b,(hl)
add hl,bc ;the effect address is obtained in hl
push hl ;save the effect address on the stack
ld hl,afxChDesc ;empty channel search
ld b,2 ; search 2 channels - force the third
afxPlay0
inc hl
inc hl
ld a,(hl) ;compare the channel time with the largest
inc hl
cp e
jr c,afxPlay1
ld c,a
ld a,(hl)
cp d
jr c,afxPlay1
ld e,c ;remember the longest time
ld d,a
ld (peet),hl
afxPlay1
inc hl
djnz afxPlay0
pop de ;take the effect address from the stack
peet=$+1
ld hl,0
ld (hl),b ;b is 0
dec hl
ld (hl),b
dec hl
ld (hl),d
dec hl
ld (hl),e
pop de
pop bc
pop hl
ret
AFXPLAYON3:
push hl
push bc
push de
dec a
ld h,0
ld l,a
add hl,hl
afxBnkAdr2
ld bc,0 ;address of the effect offsets table
add hl,bc
ld c,(hl)
inc hl
ld b,(hl)
add hl,bc ;the effect address is obtained in hl
ex de,hl
ld hl,afxChDesc+$0b
ld (hl),0 ;b is 0
dec hl
ld (hl),0
dec hl
ld (hl),d
dec hl
ld (hl),e
pop de
pop bc
pop hl
ret