1 | |
2 | // Nes_Snd_Emu 0.1.7. http://www.slack.net/~ant/libs/ |
3 | |
4 | #include "Nes_Vrc6.h" |
5 | |
6 | /* Copyright (C) 2003-2005 Shay Green. This module is free software; you |
7 | can redistribute it and/or modify it under the terms of the GNU Lesser |
8 | General Public License as published by the Free Software Foundation; either |
9 | version 2.1 of the License, or (at your option) any later version. This |
10 | module is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
13 | more details. You should have received a copy of the GNU Lesser General |
14 | Public License along with this module; if not, write to the Free Software |
15 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
16 | |
17 | #include BLARGG_SOURCE_BEGIN |
18 | |
19 | Nes_Vrc6::Nes_Vrc6() |
20 | { |
21 | output( NULL ); |
22 | volume( 1.0 ); |
23 | reset(); |
24 | } |
25 | |
26 | Nes_Vrc6::~Nes_Vrc6() |
27 | { |
28 | } |
29 | |
30 | void Nes_Vrc6::reset() |
31 | { |
32 | last_time = 0; |
33 | for ( int i = 0; i < osc_count; i++ ) |
34 | { |
35 | Vrc6_Osc& osc = oscs [i]; |
36 | for ( int j = 0; j < reg_count; j++ ) |
37 | osc.regs [j] = 0; |
38 | osc.delay = 0; |
39 | osc.last_amp = 0; |
40 | osc.phase = 1; |
41 | osc.amp = 0; |
42 | } |
43 | } |
44 | |
45 | void Nes_Vrc6::volume( double v ) |
46 | { |
47 | v *= 0.0967 * 2; |
48 | saw_synth.volume( v ); |
49 | square_synth.volume( v * 0.5 ); |
50 | } |
51 | |
52 | void Nes_Vrc6::treble_eq( blip_eq_t const& eq ) |
53 | { |
54 | saw_synth.treble_eq( eq ); |
55 | square_synth.treble_eq( eq ); |
56 | } |
57 | |
58 | void Nes_Vrc6::output( Blip_Buffer* buf ) |
59 | { |
60 | for ( int i = 0; i < osc_count; i++ ) |
61 | osc_output( i, buf ); |
62 | } |
63 | |
64 | void Nes_Vrc6::run_until( cpu_time_t time ) |
65 | { |
66 | require( time >= last_time ); |
67 | run_square( oscs [0], time ); |
68 | run_square( oscs [1], time ); |
69 | run_saw( time ); |
70 | last_time = time; |
71 | } |
72 | |
73 | void Nes_Vrc6::write_osc( cpu_time_t time, int osc_index, int reg, int data ) |
74 | { |
75 | require( (unsigned) osc_index < osc_count ); |
76 | require( (unsigned) reg < reg_count ); |
77 | |
78 | run_until( time ); |
79 | oscs [osc_index].regs [reg] = data; |
80 | } |
81 | |
82 | void Nes_Vrc6::end_frame( cpu_time_t time ) |
83 | { |
84 | if ( time > last_time ) |
85 | run_until( time ); |
86 | last_time -= time; |
87 | assert( last_time >= 0 ); |
88 | } |
89 | |
90 | void Nes_Vrc6::save_snapshot( vrc6_snapshot_t* out ) const |
91 | { |
92 | out->saw_amp = oscs [2].amp; |
93 | for ( int i = 0; i < osc_count; i++ ) |
94 | { |
95 | Vrc6_Osc const& osc = oscs [i]; |
96 | for ( int r = 0; r < reg_count; r++ ) |
97 | out->regs [i] [r] = osc.regs [r]; |
98 | |
99 | out->delays [i] = osc.delay; |
100 | out->phases [i] = osc.phase; |
101 | } |
102 | } |
103 | |
104 | void Nes_Vrc6::load_snapshot( vrc6_snapshot_t const& in ) |
105 | { |
106 | reset(); |
107 | oscs [2].amp = in.saw_amp; |
108 | for ( int i = 0; i < osc_count; i++ ) |
109 | { |
110 | Vrc6_Osc& osc = oscs [i]; |
111 | for ( int r = 0; r < reg_count; r++ ) |
112 | osc.regs [r] = in.regs [i] [r]; |
113 | |
114 | osc.delay = in.delays [i]; |
115 | osc.phase = in.phases [i]; |
116 | } |
117 | if ( !oscs [2].phase ) |
118 | oscs [2].phase = 1; |
119 | } |
120 | |
121 | #include BLARGG_ENABLE_OPTIMIZER |
122 | |
123 | void Nes_Vrc6::run_square( Vrc6_Osc& osc, cpu_time_t end_time ) |
124 | { |
125 | Blip_Buffer* output = osc.output; |
126 | if ( !output ) |
127 | return; |
128 | |
129 | int volume = osc.regs [0] & 15; |
130 | if ( !(osc.regs [2] & 0x80) ) |
131 | volume = 0; |
132 | |
133 | int gate = osc.regs [0] & 0x80; |
134 | int duty = ((osc.regs [0] >> 4) & 7) + 1; |
135 | int delta = ((gate || osc.phase < duty) ? volume : 0) - osc.last_amp; |
136 | cpu_time_t time = last_time; |
137 | if ( delta ) |
138 | { |
139 | osc.last_amp += delta; |
140 | square_synth.offset( time, delta, output ); |
141 | } |
142 | |
143 | time += osc.delay; |
144 | osc.delay = 0; |
145 | int period = osc.period(); |
146 | if ( volume && !gate && period > 4 ) |
147 | { |
148 | if ( time < end_time ) |
149 | { |
150 | int phase = osc.phase; |
151 | |
152 | do |
153 | { |
154 | phase++; |
155 | if ( phase == 16 ) |
156 | { |
157 | phase = 0; |
158 | osc.last_amp = volume; |
159 | square_synth.offset( time, volume, output ); |
160 | } |
161 | if ( phase == duty ) |
162 | { |
163 | osc.last_amp = 0; |
164 | square_synth.offset( time, -volume, output ); |
165 | } |
166 | time += period; |
167 | } |
168 | while ( time < end_time ); |
169 | |
170 | osc.phase = phase; |
171 | } |
172 | osc.delay = time - end_time; |
173 | } |
174 | } |
175 | |
176 | void Nes_Vrc6::run_saw( cpu_time_t end_time ) |
177 | { |
178 | Vrc6_Osc& osc = oscs [2]; |
179 | Blip_Buffer* output = osc.output; |
180 | if ( !output ) |
181 | return; |
182 | |
183 | int amp = osc.amp; |
184 | int amp_step = osc.regs [0] & 0x3F; |
185 | cpu_time_t time = last_time; |
186 | int last_amp = osc.last_amp; |
187 | if ( !(osc.regs [2] & 0x80) || !(amp_step | amp) ) |
188 | { |
189 | osc.delay = 0; |
190 | int delta = (amp >> 3) - last_amp; |
191 | last_amp = amp >> 3; |
192 | saw_synth.offset( time, delta, output ); |
193 | } |
194 | else |
195 | { |
196 | time += osc.delay; |
197 | if ( time < end_time ) |
198 | { |
199 | int period = osc.period() * 2; |
200 | int phase = osc.phase; |
201 | |
202 | do |
203 | { |
204 | if ( --phase == 0 ) |
205 | { |
206 | phase = 7; |
207 | amp = 0; |
208 | } |
209 | |
210 | int delta = (amp >> 3) - last_amp; |
211 | if ( delta ) |
212 | { |
213 | last_amp = amp >> 3; |
214 | saw_synth.offset( time, delta, output ); |
215 | } |
216 | |
217 | time += period; |
218 | amp = (amp + amp_step) & 0xFF; |
219 | } |
220 | while ( time < end_time ); |
221 | |
222 | osc.phase = phase; |
223 | osc.amp = amp; |
224 | } |
225 | |
226 | osc.delay = time - end_time; |
227 | } |
228 | |
229 | osc.last_amp = last_amp; |
230 | } |
231 | |
232 | |