comparison Plugins/Input/console/Gb_Oscs.cpp @ 493:c04dff121e1d trunk

[svn] hostile merge, phase 2: reimport based on new plugin code
author nenolod
date Tue, 24 Jan 2006 20:19:01 -0800
parents
children f12d7e208b43
comparison
equal deleted inserted replaced
492:ccb68bad47b2 493:c04dff121e1d
1
2 // Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
3
4 #include "Gb_Apu.h"
5
6 #include <string.h>
7
8 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
9 can redistribute it and/or modify it under the terms of the GNU Lesser
10 General Public License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version. This
12 module is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details. You should have received a copy of the GNU Lesser General
16 Public License along with this module; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
19 #include BLARGG_SOURCE_BEGIN
20
21 // Gb_Osc
22
23 void Gb_Osc::reset()
24 {
25 delay = 0;
26 last_amp = 0;
27 length = 0;
28 output_select = 3;
29 output = outputs [output_select];
30 }
31
32 void Gb_Osc::clock_length()
33 {
34 if ( (regs [4] & len_enabled_mask) && length )
35 length--;
36 }
37
38 // Gb_Env
39
40 void Gb_Env::clock_envelope()
41 {
42 if ( env_delay && !--env_delay )
43 {
44 env_delay = regs [2] & 7;
45 int v = volume - 1 + (regs [2] >> 2 & 2);
46 if ( (unsigned) v < 15 )
47 volume = v;
48 }
49 }
50
51 bool Gb_Env::write_register( int reg, int data )
52 {
53 switch ( reg )
54 {
55 case 1:
56 length = 64 - (regs [1] & 0x3f);
57 break;
58
59 case 2:
60 if ( !(data >> 4) )
61 enabled = false;
62 break;
63
64 case 4:
65 if ( data & trigger )
66 {
67 env_delay = regs [2] & 7;
68 volume = regs [2] >> 4;
69 enabled = true;
70 if ( length == 0 )
71 length = 64;
72 return true;
73 }
74 }
75 return false;
76 }
77
78 // Gb_Square
79
80 void Gb_Square::reset()
81 {
82 phase = 0;
83 sweep_freq = 0;
84 sweep_delay = 0;
85 Gb_Env::reset();
86 }
87
88 void Gb_Square::clock_sweep()
89 {
90 int sweep_period = (regs [0] & period_mask) >> 4;
91 if ( sweep_period && sweep_delay && !--sweep_delay )
92 {
93 sweep_delay = sweep_period;
94 regs [3] = sweep_freq & 0xFF;
95 regs [4] = (regs [4] & ~0x07) | (sweep_freq >> 8 & 0x07);
96
97 int offset = sweep_freq >> (regs [0] & shift_mask);
98 if ( regs [0] & 0x08 )
99 offset = -offset;
100 sweep_freq += offset;
101
102 if ( sweep_freq < 0 )
103 {
104 sweep_freq = 0;
105 }
106 else if ( sweep_freq >= 2048 )
107 {
108 sweep_delay = 0; // don't modify channel frequency any further
109 sweep_freq = 2048; // silence sound immediately
110 }
111 }
112 }
113
114 void Gb_Square::run( gb_time_t time, gb_time_t end_time, int playing )
115 {
116 if ( sweep_freq == 2048 )
117 playing = false;
118
119 static unsigned char const table [4] = { 1, 2, 4, 6 };
120 int const duty = table [regs [1] >> 6];
121 int amp = volume & playing;
122 if ( phase >= duty )
123 amp = -amp;
124
125 int frequency = this->frequency();
126 if ( unsigned (frequency - 1) > 2040 ) // frequency < 1 || frequency > 2041
127 {
128 // really high frequency results in DC at half volume
129 amp = volume >> 1;
130 playing = false;
131 }
132
133 int delta = amp - last_amp;
134 if ( delta )
135 {
136 last_amp = amp;
137 synth->offset( time, delta, output );
138 }
139
140 time += delay;
141 if ( !playing )
142 time = end_time;
143
144 if ( time < end_time )
145 {
146 int const period = (2048 - frequency) * 4;
147 Blip_Buffer* const output = this->output;
148 int phase = this->phase;
149 int delta = amp * 2;
150 do
151 {
152 phase = (phase + 1) & 7;
153 if ( phase == 0 || phase == duty )
154 {
155 delta = -delta;
156 synth->offset_inline( time, delta, output );
157 }
158 time += period;
159 }
160 while ( time < end_time );
161
162 this->phase = phase;
163 last_amp = delta >> 1;
164 }
165 delay = time - end_time;
166 }
167
168 // Gb_Noise
169
170 #include BLARGG_ENABLE_OPTIMIZER
171
172 void Gb_Noise::run( gb_time_t time, gb_time_t end_time, int playing )
173 {
174 int amp = volume & playing;
175 int tap = 13 - (regs [3] & 8);
176 if ( bits >> tap & 2 )
177 amp = -amp;
178
179 int delta = amp - last_amp;
180 if ( delta )
181 {
182 last_amp = amp;
183 synth->offset( time, delta, output );
184 }
185
186 time += delay;
187 if ( !playing )
188 time = end_time;
189
190 if ( time < end_time )
191 {
192 static unsigned char const table [8] = { 8, 16, 32, 48, 64, 80, 96, 112 };
193 int period = table [regs [3] & 7] << (regs [3] >> 4);
194
195 // keep parallel resampled time to eliminate time conversion in the loop
196 Blip_Buffer* const output = this->output;
197 const blip_resampled_time_t resampled_period =
198 output->resampled_duration( period );
199 blip_resampled_time_t resampled_time = output->resampled_time( time );
200 unsigned bits = this->bits;
201 int delta = amp * 2;
202
203 do
204 {
205 unsigned changed = (bits >> tap) + 1;
206 time += period;
207 bits <<= 1;
208 if ( changed & 2 )
209 {
210 delta = -delta;
211 bits |= 1;
212 synth->offset_resampled( resampled_time, delta, output );
213 }
214 resampled_time += resampled_period;
215 }
216 while ( time < end_time );
217
218 this->bits = bits;
219 last_amp = delta >> 1;
220 }
221 delay = time - end_time;
222 }
223
224 // Gb_Wave
225
226 inline void Gb_Wave::write_register( int reg, int data )
227 {
228 switch ( reg )
229 {
230 case 0:
231 if ( !(data & 0x80) )
232 enabled = false;
233 break;
234
235 case 1:
236 length = 256 - regs [1];
237 break;
238
239 case 2:
240 volume = data >> 5 & 3;
241 break;
242
243 case 4:
244 if ( data & trigger & regs [0] )
245 {
246 wave_pos = 0;
247 enabled = true;
248 if ( length == 0 )
249 length = 256;
250 }
251 }
252 }
253
254 void Gb_Wave::run( gb_time_t time, gb_time_t end_time, int playing )
255 {
256 int volume_shift = (volume - 1) & 7; // volume = 0 causes shift = 7
257 int amp = (wave [wave_pos] >> volume_shift & playing) * 2;
258
259 int frequency = this->frequency();
260 if ( unsigned (frequency - 1) > 2044 ) // frequency < 1 || frequency > 2045
261 {
262 amp = 30 >> volume_shift & playing;
263 playing = false;
264 }
265
266 int delta = amp - last_amp;
267 if ( delta )
268 {
269 last_amp = amp;
270 synth->offset( time, delta, output );
271 }
272
273 time += delay;
274 if ( !playing )
275 time = end_time;
276
277 if ( time < end_time )
278 {
279 Blip_Buffer* const output = this->output;
280 int const period = (2048 - frequency) * 2;
281 int wave_pos = (this->wave_pos + 1) & (wave_size - 1);
282
283 do
284 {
285 int amp = (wave [wave_pos] >> volume_shift) * 2;
286 wave_pos = (wave_pos + 1) & (wave_size - 1);
287 int delta = amp - last_amp;
288 if ( delta )
289 {
290 last_amp = amp;
291 synth->offset_inline( time, delta, output );
292 }
293 time += period;
294 }
295 while ( time < end_time );
296
297 this->wave_pos = (wave_pos - 1) & (wave_size - 1);
298 }
299 delay = time - end_time;
300 }
301
302 // Gb_Apu::write_osc
303
304 void Gb_Apu::write_osc( int index, int reg, int data )
305 {
306 reg -= index * 5;
307 Gb_Square* sq = &square2;
308 switch ( index )
309 {
310 case 0:
311 sq = &square1;
312 case 1:
313 if ( sq->write_register( reg, data ) && index == 0 )
314 {
315 square1.sweep_freq = square1.frequency();
316 if ( (regs [0] & sq->period_mask) && (regs [0] & sq->shift_mask) )
317 {
318 square1.sweep_delay = 1; // cause sweep to recalculate now
319 square1.clock_sweep();
320 }
321 }
322 break;
323
324 case 2:
325 wave.write_register( reg, data );
326 break;
327
328 case 3:
329 if ( noise.write_register( reg, data ) )
330 noise.bits = 0x7FFF;
331 }
332 }
333