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