-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfds.s
272 lines (254 loc) · 5.17 KB
/
fds.s
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
; Takes care of the FDS registers
ft_load_inst_extra_fds:
lda ft_channel_type, x ;;; ;; ; non-FDS instruments do not affect wave
cmp #CHAN_FDS
beq :+
ldy var_Temp
rts
:
tya ;;; ;; ;
clc
adc #$10
sta var_Temp2 ; ;; ;;;
; Load modulation table
jsr ft_reset_modtable
:
lda (var_Temp_Pointer), y
pha
and #$07
sta $4088
pla
lsr a
lsr a
lsr a
sta $4088
iny
cpy var_Temp2 ;;; ;; ;
bcc :-
lda (var_Temp_Pointer), y ; Modulation delay
iny
sta var_ch_ModDelay
lda (var_Temp_Pointer), y ; Modulation depth
iny
sta var_ch_ModInstDepth ;;; ;; ; keep state
lda (var_Temp_Pointer), y ; Modulation freq low
iny
sta var_ch_ModInstRate
lda (var_Temp_Pointer), y ; Modulation freq high
sta var_ch_ModInstRate + 1
iny ;;; ;; ;
lda (var_Temp_Pointer), y ; Load wave index
jsr ft_load_fds_wave
ldy var_Temp
rts ;;; ;; ;
ft_init_fds:
lda #$00
sta $4023
lda #$83
sta $4023
lda #$FF ;;; ;; ;
sta $408A
lda #$80
sta var_ch_FDSVolume
sta var_ch_ModBias ; ;; ;;;
rts
; Update FDS
ft_update_fds:
lda var_PlayerFlags
bne @Play
lda #$80
sta $4080
rts
@Play:
.if .defined(USE_LINEARPITCH) ;;; ;; ;
lda var_SongFlags
and #FLAG_LINEARPITCH
beq :+
jsr ft_load_fds_table
ldx #FDS_OFFSET
jsr ft_linear_fetch_pitch
:
.endif ; ;; ;;;
lda var_ch_Note + FDS_OFFSET
bne :+ ; branch
jmp @KillFDS
:
; Calculate volume
lda var_ch_VolColumn + FDS_OFFSET ; Kill channel if volume column = 0
lsr a
lsr a
lsr a
beq @KillFDS
sta var_Temp2 ; 4 bit vol
lda var_ch_Volume + FDS_OFFSET ; Kill channel if volume = 0
beq @KillFDS
sta var_Temp ; 5 bit vol
ldx #FDS_OFFSET
jsr ft_multiply_volume
sec
sbc var_ch_TremoloResult + FDS_OFFSET
bpl :+
@NoKill:
lda #$00
:
; Load volume
ora #$80
sta var_Temp ;;; ;; ;
lda var_ch_FDSVolume ; check the volume envelope
bmi :+ ; envelope is disabled
lda var_ch_Trigger + FDS_OFFSET
beq :++ ; envelope is enabled in middle of note
: lda var_Temp
sta $4080 ; Volume
: lda var_ch_FDSVolume
bmi :+
sta $4080 ; enable envelope after volume init
: ; ;; ;;;
; Load frequency
lda var_ch_PeriodCalcHi + FDS_OFFSET
and #$F0
beq :+
lda #$FF
sta var_ch_PeriodCalcLo + FDS_OFFSET
lda #$0F
sta var_ch_PeriodCalcHi + FDS_OFFSET
: lda var_ch_PeriodCalcHi + FDS_OFFSET
sta $4083 ; High
lda var_ch_PeriodCalcLo + FDS_OFFSET
sta $4082 ; Low
lda var_ch_Trigger + FDS_OFFSET ;;; ;; ;
beq :+
jsr ft_reset_modtable
;lda #$00
;sta $4085
lda var_ch_ModInstDepth ;;; ;; ;
sta var_ch_ModDepth
lda var_ch_ModRate + 1
bmi :+
lda var_ch_ModInstRate
sta var_ch_ModRate
lda var_ch_ModInstRate + 1
sta var_ch_ModRate + 1 ; ;; ;;;
: jsr ft_check_fds_effects
lda var_ch_ModDelayTick ; Modulation delay
bne @TickDownDelay
; lda var_ch_ModDepth ; Skip if modulation is disabled
; beq @DisableMod
lda var_ch_ModDepth ; Skip if modulation is disabled
ora #$80
sta $4084 ; Store modulation depth
jsr ft_check_fds_fm
@Return:
rts
@TickDownDelay:
dec var_ch_ModDelayTick
@DisableMod:
; Disable modulation
lda #$80
sta $4087
rts
@KillFDS:
lda var_ch_FDSVolume ;;; ;; ; return if volume envelope is enabled
bpl @NoKill ; ;; ;;;
lda #$80
padjmp_h 7
sta $4080 ; Make channel silent
sta $4084
sta $4087
rts
padjmp 6
; Load the waveform, index in A
ft_load_fds_wave:
sta var_Temp16 + 1 ;;; ;; ;
lda #$00
sta var_Temp16
; Multiply by 64
lsr var_Temp16 + 1
ror var_Temp16
lsr var_Temp16 + 1
ror var_Temp16
; Setup a pointer to the specified wave
clc
lda var_Wavetables
adc var_Temp16
sta var_Temp16
lda var_Wavetables + 1
adc var_Temp16 + 1
sta var_Temp16 + 1
; Write wave
lda #$80
sta $4089 ; Enable wave RAM
ldy #$3F ; optimization
: lda (var_Temp16), y ; 5
sta $4040, y ; 5
dey ; 2
bpl :- ; 3 = 15 cycles and 64 iterations = 960 cycles
lda #$00
sta $4089 ; Disable wave RAM
rts
ft_reset_modtable:
lda #$80
sta $4087
sta $4085
rts
ft_check_fds_effects:
lda var_ch_ModEffWritten
and #$01
beq :+
; FDS modulation depth
lda var_ch_ModEffDepth
sta var_ch_ModDepth
: lda var_ch_ModEffWritten
and #$02
beq :+
; FDS modulation rate high
lda var_ch_ModEffRate + 1
sta var_ch_ModRate + 1
: lda var_ch_ModEffWritten
and #$04
beq :+
; FDS modulation rate low
lda var_ch_ModEffRate + 0
sta var_ch_ModRate + 0
:
lda #$00
sta var_ch_ModEffWritten
rts
ft_check_fds_fm:
lda var_ch_ModRate + 1 ;;; ;; ;
bmi @AutoFM
lda var_ch_ModRate ; Modulation freq
sta $4086
lda var_ch_ModRate + 1
sta $4087
rts
@AutoFM:
lda var_ch_ModRate + 1
and #$7F
sta var_Temp
lda var_ch_ModRate + 0
sta AUX
lda var_ch_PeriodCalcHi + FDS_OFFSET
sta var_Temp16 + 1
lda var_ch_PeriodCalcLo + FDS_OFFSET
sta var_Temp16
lda #$00
sta AUX + 1
jsr MUL
lda EXT
beq :+
lda #$FF
sta ACC
sta ACC + 1
: jsr DIV
lda var_ch_ModBias
eor #$80
bpl :+
dec ACC + 1
: clc
adc ACC
sta $4086
lda ACC + 1
adc #$00
sta $4087
rts