Say hello to D-Pad Hero 2 repository
[dpadhero2.git] / sound / effect.asm
blobd9fbc4148af2ec69ecd316c494d8cc9af2a1b477
2 ; Copyright (C) 2004, 2005 Kent Hansen.
4 ; This file is part of Neotoxin.
6 ; Neotoxin is free software; you can redistribute it and/or modify
7 ; it under the terms of the GNU General Public License as published by
8 ; the Free Software Foundation; either version 2 of the License, or
9 ; (at your option) any later version.
11 ; Neotoxin is distributed in the hope that it will be useful,
12 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ; GNU General Public License for more details.
16 ; You should have received a copy of the GNU General Public License
17 ; along with this program; if not, write to the Free Software
18 ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ; Description:
22 ; MOD-style music effect generators.
23 ; Each effect modifies the period in a certain way.
24 ; - Slide up/down
25 ; - Portamento
26 ; - Vibrato
27 ; - Arpeggio
29 .include "mixer.h"
30 .include "track.h"
31 .include <common/tablecall.h>
33 .dataseg
35 temp .int16
36 value .byte
38 .codeseg
40 ; exported API
41 .public effect_tick
43 ; external symbols
44 .extrn period_table_lo:byte
45 .extrn period_table_hi:byte
46 .extrn mixer:mixer_state
47 .extrn tracks:track_state
48 .extrn table_call:proc
50 ; Do one tick of effect.
51 ; Params: X = channel number
53 .proc effect_tick
54 lda mixer.tonals.effect.kind,x
55 jsr table_call
56 TC_SLOT null_tick
57 TC_SLOT slide_up_tick
58 TC_SLOT slide_down_tick
59 TC_SLOT portamento_tick
60 TC_SLOT vibrato_tick
61 TC_SLOT arpeggio_tick
62 TC_SLOT volume_slide_tick
63 TC_SLOT tremolo_tick
64 TC_SLOT cut_tick
65 TC_SLOT pulsemod_tick
66 .endp
68 ; Command 0 is no effect.
70 .proc null_tick
71 rts
72 .endp
74 ;-------------------------[ Vibrato implementation ]--------------------------
76 .proc vibrato_tick
77 ; check vibrato delay
78 lda mixer.tonals.effect.vibrato.counter,x
79 beq @@counter_ended
80 dec mixer.tonals.effect.vibrato.counter,x
81 rts
83 @@counter_ended:
84 ; reset channel frequency
85 lda mixer.tonals.period_index,x
86 jsr set_period
88 ; get sine value
89 lda mixer.tonals.effect.vibrato.pos,x
90 and #$1F
91 tay
92 lda vibrato_table,y
93 sta value
95 ; *** convert sine value to real delta freq, according to vibrato depth ***
97 lda #$00
98 sta temp.lo
99 sta temp.hi
100 lda mixer.tonals.effect.vibrato.param,x
101 and #$0F ; VibratoDepth in lower 4 bits
104 ; this loop performs SineValue*VibratoDepth
105 - lda temp.lo
106 adc value
107 sta temp.lo
108 bcc +
109 inc temp.hi
111 + dey
112 bne -
114 ; this stores the result of (SineValue*VibratoDepth)/128 in temp.hi
115 asl temp.lo
116 rol temp.hi
118 lda mixer.tonals.effect.vibrato.pos,x
119 and #$3F
120 cmp #$20
121 bcc @@vib_add
123 lda mixer.tonals.period.lo,x
125 sbc temp.hi
126 sta mixer.tonals.period.lo,x
127 bcs @@vib_done
128 dec mixer.tonals.period.hi,x
129 bcc @@vib_done
131 @@vib_add:
132 lda mixer.tonals.period.lo,x
134 adc temp.hi
135 sta mixer.tonals.period.lo,x
136 bcc @@vib_done
137 inc mixer.tonals.period.hi,x
139 @@vib_done:
140 ; increment vibrato pos
141 lda mixer.tonals.effect.vibrato.param,x
147 adc mixer.tonals.effect.vibrato.pos,x ; add VibratoSpeed to VibratoPos
148 sta mixer.tonals.effect.vibrato.pos,x
150 .endp
152 ; ProTracker sine table used for vibrato
154 vibrato_table:
155 .db $00,$18,$31,$4A,$61,$78,$8D,$A1
156 .db $B4,$C5,$D4,$E0,$EB,$F4,$FA,$FD
157 .db $FF,$FD,$FA,$F4,$EB,$E0,$D4,$C5
158 .db $B4,$A1,$8D,$78,$61,$4A,$31,$18
160 ;----------------------[ Slide to note implementation ]-----------------------
162 .proc portamento_tick
163 lda mixer.tonals.effect.portamento.ctrl,x
164 bpl @@portamento_exit
166 bcc @@portamento_down
168 jsr slide_up_tick
169 ; check if slide frequency has been reached
170 lda mixer.tonals.period.lo,x
171 cmp mixer.tonals.effect.portamento.target.lo,x
172 lda mixer.tonals.period.hi,x
173 sbc mixer.tonals.effect.portamento.target.hi,x
174 bpl @@portamento_exit
176 @@portamento_done:
177 ; set final period
178 lda mixer.tonals.effect.portamento.target.lo,x
179 sta mixer.tonals.period.lo,x
180 lda mixer.tonals.effect.portamento.target.hi,x
181 sta mixer.tonals.period.hi,x
182 ; halt
183 lda #$00
184 sta mixer.tonals.effect.portamento.ctrl,x
187 @@portamento_down:
188 jsr slide_down_tick
189 ; check if slide frequency has been reached
190 lda mixer.tonals.period.lo,x
191 cmp mixer.tonals.effect.portamento.target.lo,x
192 lda mixer.tonals.period.hi,x
193 sbc mixer.tonals.effect.portamento.target.hi,x
194 bpl @@portamento_done
196 @@portamento_exit:
198 .endp
200 ;-----------------------[ Slide down implementation ]-------------------------
202 .proc slide_down_tick
203 ; slide down by adding slide amount to channel frequency
204 lda mixer.tonals.period.lo,x
206 adc mixer.tonals.effect.slide.amount,x
207 sta mixer.tonals.period.lo,x
208 bcc +
209 inc mixer.tonals.period.hi,x
210 + rts
211 .endp
213 ;------------------------[ Slide up implementation ]--------------------------
215 .proc slide_up_tick
216 ; slide up by subtracting slide amount from channel frequency
217 lda mixer.tonals.period.lo,x
219 sbc mixer.tonals.effect.slide.amount,x
220 sta mixer.tonals.period.lo,x
221 bcs +
222 dec mixer.tonals.period.hi,x
223 + rts
224 .endp
226 ;------------------------[ Arpeggio implementation ]--------------------------
228 .proc arpeggio_tick
229 lda mixer.tonals.effect.arpeggio.pos,x
232 - cmp #$03
233 bcc +
234 sbc #$03
235 bpl -
237 ; A = Tick % 3
238 + cmp #$01
239 beq @@add_note1
240 bcs @@add_note2
241 lda mixer.tonals.period_index,x
242 bpl set_period
244 @@add_note1:
245 lda mixer.tonals.effect.arpeggio.param,x
251 adc mixer.tonals.period_index,x
252 bpl set_period
254 @@add_note2:
255 lda mixer.tonals.effect.arpeggio.param,x
256 and #$0F
258 adc mixer.tonals.period_index,x
260 set_period:
262 lda period_table_lo,y
263 sta mixer.tonals.period.lo,x
264 lda period_table_hi,y
265 sta mixer.tonals.period.hi,x
267 inc mixer.tonals.effect.arpeggio.pos,x
268 lda mixer.tonals.effect.arpeggio.pos,x
269 cmp #6
270 bcc +
271 lda #0
272 sta mixer.tonals.effect.arpeggio.pos,x
273 + rts
274 .endp
276 ;------------------------[ Volume slide implementation ]--------------------------
278 .proc volume_slide_tick
279 lda mixer.tonals.effect.slide.amount,x
280 and #$F0
281 bne +
282 ; slide down
283 lda mixer.envelopes.master,x
285 sbc mixer.tonals.effect.slide.amount,x
286 bcs ++
287 lda #0
288 ++ sta mixer.envelopes.master,x
290 ; slide up
291 + lda mixer.tonals.effect.slide.amount,x
297 adc mixer.envelopes.master,x
298 bcc ++
299 lda #$FF
300 ++ sta mixer.envelopes.master,x
302 .endp
304 ;------------------------[ Tremolo implementation ]--------------------------
306 .proc tremolo_tick
307 ; get sine value
308 lda mixer.tonals.effect.tremolo.pos,x
309 and #$1F
311 lda vibrato_table,y
312 sta value
314 lda #0
315 sta temp.lo
316 sta temp.hi
317 lda mixer.tonals.effect.tremolo.param,x
318 and #$0F ; TremoloDepth in lower 4 bits
321 ; this loop performs SineValue*TremoloDepth
322 - lda temp.lo
323 adc value
324 sta temp.lo
325 bcc +
326 inc temp.hi
328 + dey
329 bne -
331 ; compute (SineValue*TremoloDepth)/16
332 lsr temp.hi
333 ror temp.lo
334 lsr temp.hi
335 ror temp.lo
336 lsr temp.hi
337 ror temp.lo
338 lsr temp.hi
339 ror temp.lo
341 lda mixer.tonals.effect.tremolo.pos,x
342 and #$3F
343 cmp #$20
344 bcc @@inc_vol
346 lda #$F0
348 sbc temp.lo
349 bcs +
350 lda #0
351 + sta mixer.envelopes.master,x
352 jmp @@inc_pos
354 @@inc_vol:
355 lda #$F0
357 adc temp.lo
358 bcc +
359 lda #$FF
360 + sta mixer.envelopes.master,x
362 @@inc_pos:
363 lda mixer.tonals.effect.tremolo.param,x ; speed in upper 4 bits
369 adc mixer.tonals.effect.tremolo.pos,x
370 sta mixer.tonals.effect.tremolo.pos,x
372 .endp
374 ; ------ Cut note
375 ; Reusing the vibrato struct because I'm lazy...
376 .proc cut_tick
377 lda mixer.tonals.effect.vibrato.pos,x
378 cmp mixer.tonals.effect.vibrato.param,x
379 beq @@cut
380 bcs +
381 inc mixer.tonals.effect.vibrato.pos,x
382 + rts
383 @@cut:
384 lda #0
385 sta mixer.tonals.period.lo,x
386 sta mixer.tonals.period.hi,x
388 .endp
390 ; ------ Pulse width (duty cycle) modulation
391 ; NB: can only be used on channels 0 and 1
392 ; Reusing the vibrato struct because I'm lazy...
393 .proc pulsemod_tick
394 lda tracks.tick,x
395 bne +
396 lda #1
397 sta mixer.tonals.square.counter,x
398 lda mixer.tonals.effect.vibrato.param,x ; new duty cycle in lower 2 bits
403 sta mixer.tonals.square.duty_ctrl,x
404 + rts
405 .endp
407 .end