Add tools/ and manual/, move sources to src/
[dpadhero2.git] / src / sound / envelope.asm
blob5d4d25c6978efba3e967d1bc5c7add7f55769f79
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 ; Real-time volume envelope processing.
23 ; Only useful for channels 0, 1 and 3.
24 ; Volume envelope format:
25 ; Byte 0: Start volume (0..15)
26 ; Series of 4-byte tuples: 8x8 fixed-point step, hold length, end volume
27 ; Until integer part of step = $FF
28 ; If next byte is also $FF, it's really the end
29 ; Otherwise the envelope is looped from that value
31 .include "mixer.h"
33 .dataseg zeropage
35 ; private variables
36 env .ptr
38 .codeseg
40 ; exported API
41 .public envelope_tick
43 ; external symbols
44 .extrn mixer:mixer_state
46 ; Copies current volume envelope data pointer to local pointer.
47 ; Params: X = channel number
48 .macro set_env_ptr
49 lda mixer.envelopes.ptr.lo,x
50 sta env.lo
51 lda mixer.envelopes.ptr.hi,x
52 sta env.hi ; set pointer to envelope
53 .endm
55 ; Fetches next byte from volume envelope data.
56 ; Params: Y = envelope data offset (auto-incremented)
57 .macro fetch_env_byte
58 lda [env],y
59 iny
60 .endm
62 ; Does one tick of envelope processing.
63 ; Params: X = channel number
65 .proc envelope_tick
66 lda mixer.envelopes.phase,x
67 bmi @@init ; phase = $80
68 asl
69 bmi @@process ; phase = $40
70 asl
71 bmi @@sustain ; phase = $20
72 rts
74 ; Initialize envelope
75 @@init:
76 lsr mixer.envelopes.phase,x ; phase = update envelope
77 lda #0
78 sta mixer.envelopes.pos,x ; reset envelope position
79 tay
80 set_env_ptr
81 @@init_vol:
82 fetch_env_byte
83 sta mixer.envelopes.vol.int,x ; 1st byte = start volume
84 ; Initialize envelope point
85 @@point_init:
86 fetch_env_byte
87 cmp #$FF ; $FF = end of envelope reached
88 beq @@env_end
89 ; Point OK, set 4-tuple
90 sta mixer.envelopes.step.int,x
91 fetch_env_byte
92 sta mixer.envelopes.step.frac,x
93 fetch_env_byte
94 sta mixer.envelopes.hold,x
95 fetch_env_byte
96 sta mixer.envelopes.dest,x
97 lda #$00
98 sta mixer.envelopes.vol.frac,x
99 tya
100 sta mixer.envelopes.pos,x
102 ; End of envelope reached (step.int = FF)
103 @@env_end:
104 fetch_env_byte ; if FF, definitely end... otherwise loop
105 cmp #$FF
106 beq @@env_stop
107 tay ; loop the envelope
108 jmp @@init_vol
109 ; No more envelope processing
110 @@env_stop:
111 lda #$00
112 sta mixer.envelopes.phase,x
113 - rts
115 ; Sustain volume until hold == 0.
116 @@sustain:
117 ldy mixer.envelopes.hold,x
119 beq - ; sustain forever if length = $FF
120 dec mixer.envelopes.hold,x
121 bne -
122 asl mixer.envelopes.phase,x ; back to phase = process
123 jmp @@next_point
125 ; Update volume according to step
126 @@process:
127 ; fractional part
128 lda mixer.envelopes.vol.frac,x
130 adc mixer.envelopes.step.frac,x
131 sta mixer.envelopes.vol.frac,x
133 ; integer part
134 lda mixer.envelopes.vol.int,x
135 cmp mixer.envelopes.dest,x
136 bcs @@sub_volume
137 ; CurrentVol < DestVol ==> CurrentVol += StepHi
139 adc mixer.envelopes.step.int,x
140 cmp mixer.envelopes.dest,x
141 bcs @@reached_dest
142 sta mixer.envelopes.vol.int,x
144 ; CurrentVol > DestVol ==> CurrentVol -= StepHi
145 @@sub_volume:
148 eor #$01 ; toggle carry
150 sbc mixer.envelopes.step.int,x
151 bmi @@reached_dest
152 cmp mixer.envelopes.dest,x
153 beq @@reached_dest
154 bcc @@reached_dest
155 sta mixer.envelopes.vol.int,x
157 ; Reached point's destination volume
158 @@reached_dest:
159 lda mixer.envelopes.dest,x
160 sta mixer.envelopes.vol.int,x
161 lda mixer.envelopes.hold,x
162 beq @@next_point
163 lsr mixer.envelopes.phase,x ; phase = sustain
165 ; Start the next envelope point
166 @@next_point:
167 set_env_ptr
168 ldy mixer.envelopes.pos,x
169 jmp @@point_init
170 .endp
172 .end