1 // Nes_Snd_Emu $vers. http://www.slack.net/~ant/
2 
3 #include "Nes_Apu.h"
4 
5 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6 can redistribute it and/or modify it under the terms of the GNU Lesser
7 General Public License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version. This
9 module is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 details. You should have received a copy of the GNU Lesser General Public
13 License along with this module; if not, write to the Free Software Foundation,
14 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "blargg_source.h"
17 
18 // Nes_Osc
19 
clock_length(int halt_mask)20 void Nes_Osc::clock_length( int halt_mask )
21 {
22 	if ( length_counter && !(regs [0] & halt_mask) )
23 		length_counter--;
24 }
25 
clock_envelope()26 void Nes_Envelope::clock_envelope()
27 {
28 	int period = regs [0] & 15;
29 	if ( reg_written [3] )
30 	{
31 		reg_written [3] = false;
32 		env_delay = period;
33 		envelope = 15;
34 	}
35 	else if ( --env_delay < 0 )
36 	{
37 		env_delay = period;
38 		if ( envelope | (regs [0] & 0x20) )
39 			envelope = (envelope - 1) & 15;
40 	}
41 }
42 
volume() const43 int Nes_Envelope::volume() const
44 {
45 	return length_counter == 0 ? 0 : (regs [0] & 0x10) ? (regs [0] & 15) : envelope;
46 }
47 
48 // Nes_Square
49 
clock_sweep(int negative_adjust)50 void Nes_Square::clock_sweep( int negative_adjust )
51 {
52 	int sweep = regs [1];
53 
54 	if ( --sweep_delay < 0 )
55 	{
56 		reg_written [1] = true;
57 
58 		int period = this->period();
59 		int shift = sweep & shift_mask;
60 		if ( shift && (sweep & 0x80) && period >= 8 )
61 		{
62 			int offset = period >> shift;
63 
64 			if ( sweep & negate_flag )
65 				offset = negative_adjust - offset;
66 
67 			if ( period + offset < 0x800 )
68 			{
69 				period += offset;
70 				// rewrite period
71 				regs [2] = period & 0xFF;
72 				regs [3] = (regs [3] & ~7) | ((period >> 8) & 7);
73 			}
74 		}
75 	}
76 
77 	if ( reg_written [1] )
78 	{
79 		reg_written [1] = false;
80 		sweep_delay = (sweep >> 4) & 7;
81 	}
82 }
83 
84 // TODO: clean up
maintain_phase(nes_time_t time,nes_time_t end_time,nes_time_t timer_period)85 inline Nes_Square::nes_time_t Nes_Square::maintain_phase( nes_time_t time, nes_time_t end_time,
86 		nes_time_t timer_period )
87 {
88 	nes_time_t remain = end_time - time;
89 	if ( remain > 0 )
90 	{
91 		int count = (remain + timer_period - 1) / timer_period;
92 		phase = (phase + count) & (phase_range - 1);
93 		time += count * timer_period;
94 	}
95 	return time;
96 }
97 
run(nes_time_t time,nes_time_t end_time)98 void Nes_Square::run( nes_time_t time, nes_time_t end_time )
99 {
100 	const int period = this->period();
101 	const int timer_period = (period + 1) * 2;
102 
103 	if ( !output )
104 	{
105 		delay = maintain_phase( time + delay, end_time, timer_period ) - end_time;
106 		return;
107 	}
108 
109 	int offset = period >> (regs [1] & shift_mask);
110 	if ( regs [1] & negate_flag )
111 		offset = 0;
112 
113 	const int volume = this->volume();
114 	if ( volume == 0 || period < 8 || (period + offset) >= 0x800 )
115 	{
116 		if ( last_amp )
117 		{
118 			output->set_modified();
119 			synth.offset( time, -last_amp, output );
120 			last_amp = 0;
121 		}
122 
123 		time += delay;
124 		time = maintain_phase( time, end_time, timer_period );
125 	}
126 	else
127 	{
128 		// handle duty select
129 		int duty_select = (regs [0] >> 6) & 3;
130 		int duty = 1 << duty_select; // 1, 2, 4, 2
131 		int amp = 0;
132 		if ( duty_select == 3 )
133 		{
134 			duty = 2; // negated 25%
135 			amp = volume;
136 		}
137 		if ( phase < duty )
138 			amp ^= volume;
139 
140 		output->set_modified();
141 		{
142 			int delta = update_amp( amp );
143 			if ( delta )
144 				synth.offset( time, delta, output );
145 		}
146 
147 		time += delay;
148 		if ( time < end_time )
149 		{
150 			Blip_Buffer* const output = this->output;
151 			const Synth& synth = this->synth;
152 			int delta = amp * 2 - volume;
153 			int phase = this->phase;
154 
155 			do
156 			{
157 				phase = (phase + 1) & (phase_range - 1);
158 				if ( phase == 0 || phase == duty )
159 				{
160 					delta = -delta;
161 					synth.offset_inline( time, delta, output );
162 				}
163 				time += timer_period;
164 			}
165 			while ( time < end_time );
166 
167 			last_amp = (delta + volume) >> 1;
168 			this->phase = phase;
169 		}
170 	}
171 
172 	delay = time - end_time;
173 }
174 
175 // Nes_Triangle
176 
clock_linear_counter()177 void Nes_Triangle::clock_linear_counter()
178 {
179 	if ( reg_written [3] )
180 		linear_counter = regs [0] & 0x7F;
181 	else if ( linear_counter )
182 		linear_counter--;
183 
184 	if ( !(regs [0] & 0x80) )
185 		reg_written [3] = false;
186 }
187 
calc_amp() const188 inline int Nes_Triangle::calc_amp() const
189 {
190 	int amp = phase_range - phase;
191 	if ( amp < 0 )
192 		amp = phase - (phase_range + 1);
193 	return amp;
194 }
195 
196 // TODO: clean up
maintain_phase(nes_time_t time,nes_time_t end_time,nes_time_t timer_period)197 inline Nes_Square::nes_time_t Nes_Triangle::maintain_phase( nes_time_t time, nes_time_t end_time,
198 		nes_time_t timer_period )
199 {
200 	nes_time_t remain = end_time - time;
201 	if ( remain > 0 )
202 	{
203 		int count = (remain + timer_period - 1) / timer_period;
204 		phase = ((unsigned) phase + 1 - count) & (phase_range * 2 - 1);
205 		phase++;
206 		time += count * timer_period;
207 	}
208 	return time;
209 }
210 
run(nes_time_t time,nes_time_t end_time)211 void Nes_Triangle::run( nes_time_t time, nes_time_t end_time )
212 {
213 	const int timer_period = period() + 1;
214 	if ( !output )
215 	{
216 		time += delay;
217 		delay = 0;
218 		if ( length_counter && linear_counter && timer_period >= 3 )
219 			delay = maintain_phase( time, end_time, timer_period ) - end_time;
220 		return;
221 	}
222 
223 	// to do: track phase when period < 3
224 	// to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks.
225 
226 	int delta = update_amp( calc_amp() );
227 	if ( delta )
228 	{
229 		output->set_modified();
230 		synth.offset( time, delta, output );
231 	}
232 
233 	time += delay;
234 	if ( length_counter == 0 || linear_counter == 0 || timer_period < 3 )
235 	{
236 		time = end_time;
237 	}
238 	else if ( time < end_time )
239 	{
240 		Blip_Buffer* const output = this->output;
241 
242 		int phase = this->phase;
243 		int volume = 1;
244 		if ( phase > phase_range )
245 		{
246 			phase -= phase_range;
247 			volume = -volume;
248 		}
249 		output->set_modified();
250 
251 		do
252 		{
253 			if ( --phase == 0 )
254 			{
255 				phase = phase_range;
256 				volume = -volume;
257 			}
258 			else
259 			{
260 				synth.offset_inline( time, volume, output );
261 			}
262 
263 			time += timer_period;
264 		}
265 		while ( time < end_time );
266 
267 		if ( volume < 0 )
268 			phase += phase_range;
269 		this->phase = phase;
270 		last_amp = calc_amp();
271  	}
272 	delay = time - end_time;
273 }
274 
275 // Nes_Dmc
276 
reset()277 void Nes_Dmc::reset()
278 {
279 	address = 0;
280 	dac = 0;
281 	buf = 0;
282 	bits_remain = 1;
283 	bits = 0;
284 	buf_full = false;
285 	silence = true;
286 	next_irq = Nes_Apu::no_irq;
287 	irq_flag = false;
288 	irq_enabled = false;
289 
290 	Nes_Osc::reset();
291 	period = 0x1AC;
292 }
293 
recalc_irq()294 void Nes_Dmc::recalc_irq()
295 {
296 	nes_time_t irq = Nes_Apu::no_irq;
297 	if ( irq_enabled && length_counter )
298 		irq = apu->last_dmc_time + delay +
299 				((length_counter - 1) * 8 + bits_remain - 1) * nes_time_t (period) + 1;
300 	if ( irq != next_irq )
301 	{
302 		next_irq = irq;
303 		apu->irq_changed();
304 	}
305 }
306 
count_reads(nes_time_t time,nes_time_t * last_read) const307 int Nes_Dmc::count_reads( nes_time_t time, nes_time_t* last_read ) const
308 {
309 	if ( last_read )
310 		*last_read = time;
311 
312 	if ( length_counter == 0 )
313 		return 0; // not reading
314 
315 	nes_time_t first_read = next_read_time();
316 	nes_time_t avail = time - first_read;
317 	if ( avail <= 0 )
318 		return 0;
319 
320 	int count = (avail - 1) / (period * 8) + 1;
321 	if ( !(regs [0] & loop_flag) && count > length_counter )
322 		count = length_counter;
323 
324 	if ( last_read )
325 	{
326 		*last_read = first_read + (count - 1) * (period * 8) + 1;
327 		check( *last_read <= time );
328 		check( count == count_reads( *last_read, NULL ) );
329 		check( count - 1 == count_reads( *last_read - 1, NULL ) );
330 	}
331 
332 	return count;
333 }
334 
335 static short const dmc_period_table [2] [16] = {
336 	{428, 380, 340, 320, 286, 254, 226, 214, // NTSC
337 	190, 160, 142, 128, 106,  84,  72,  54},
338 
339 	{398, 354, 316, 298, 276, 236, 210, 198, // PAL
340 	176, 148, 132, 118,  98,  78,  66,  50}
341 };
342 
reload_sample()343 inline void Nes_Dmc::reload_sample()
344 {
345 	address = 0x4000 + regs [2] * 0x40;
346 	length_counter = regs [3] * 0x10 + 1;
347 }
348 
349 static int const dmc_table [128] =
350 {
351    0,  24,  48,  71,  94, 118, 141, 163, 186, 209, 231, 253, 275, 297, 319, 340,
352  361, 383, 404, 425, 445, 466, 486, 507, 527, 547, 567, 587, 606, 626, 645, 664,
353  683, 702, 721, 740, 758, 777, 795, 813, 832, 850, 867, 885, 903, 920, 938, 955,
354  972, 989,1006,1023,1040,1056,1073,1089,1105,1122,1138,1154,1170,1185,1201,1217,
355 1232,1248,1263,1278,1293,1308,1323,1338,1353,1368,1382,1397,1411,1425,1440,1454,
356 1468,1482,1496,1510,1523,1537,1551,1564,1578,1591,1604,1618,1631,1644,1657,1670,
357 1683,1695,1708,1721,1733,1746,1758,1771,1783,1795,1807,1819,1831,1843,1855,1867,
358 1879,1890,1902,1914,1925,1937,1948,1959,1971,1982,1993,2004,2015,2026,2037,2048,
359 };
360 
update_amp_nonlinear(int in)361 inline int Nes_Dmc::update_amp_nonlinear( int in )
362 {
363 	if ( !nonlinear )
364 		in = dmc_table [in];
365 	int delta = in - last_amp;
366 	last_amp = in;
367 	return delta;
368 }
369 
write_register(int addr,int data)370 void Nes_Dmc::write_register( int addr, int data )
371 {
372 	if ( addr == 0 )
373 	{
374 		period = dmc_period_table [pal_mode] [data & 15];
375 		irq_enabled = (data & 0xC0) == 0x80; // enabled only if loop disabled
376 		irq_flag &= irq_enabled;
377 		recalc_irq();
378 	}
379 	else if ( addr == 1 )
380 	{
381 		dac = data & 0x7F;
382 	}
383 }
384 
start()385 void Nes_Dmc::start()
386 {
387 	reload_sample();
388 	fill_buffer();
389 	recalc_irq();
390 }
391 
fill_buffer()392 void Nes_Dmc::fill_buffer()
393 {
394 	if ( !buf_full && length_counter )
395 	{
396 		require( apu->dmc_reader.f ); // dmc_reader must be set
397 		buf = apu->dmc_reader.f( apu->dmc_reader.data, 0x8000u + address );
398 		address = (address + 1) & 0x7FFF;
399 		buf_full = true;
400 		if ( --length_counter == 0 )
401 		{
402 			if ( regs [0] & loop_flag )
403 			{
404 				reload_sample();
405 			}
406 			else
407 			{
408 				apu->osc_enables &= ~0x10;
409 				irq_flag = irq_enabled;
410 				next_irq = Nes_Apu::no_irq;
411 				apu->irq_changed();
412 			}
413 		}
414 	}
415 }
416 
run(nes_time_t time,nes_time_t end_time)417 void Nes_Dmc::run( nes_time_t time, nes_time_t end_time )
418 {
419 	int delta = update_amp_nonlinear( dac );
420 	if ( !output )
421 	{
422 		silence = true;
423 	}
424 	else if ( delta )
425 	{
426 		output->set_modified();
427 		synth.offset( time, delta, output );
428 	}
429 
430 	time += delay;
431 	if ( time < end_time )
432 	{
433 		int bits_remain = this->bits_remain;
434 		if ( silence && !buf_full )
435 		{
436 			int count = (end_time - time + period - 1) / period;
437 			bits_remain = (bits_remain - 1 + 8 - (count % 8)) % 8 + 1;
438 			time += count * period;
439 		}
440 		else
441 		{
442 			Blip_Buffer* const output = this->output;
443 			const int period = this->period;
444 			int bits = this->bits;
445 			int dac = this->dac;
446 			if ( output )
447 				output->set_modified();
448 
449 			do
450 			{
451 				if ( !silence )
452 				{
453 					int step = (bits & 1) * 4 - 2;
454 					bits >>= 1;
455 					if ( unsigned (dac + step) <= 0x7F )
456 					{
457 						dac += step;
458 						synth.offset_inline( time, update_amp_nonlinear( dac ), output );
459 					}
460 				}
461 
462 				time += period;
463 
464 				if ( --bits_remain == 0 )
465 				{
466 					bits_remain = 8;
467 					if ( !buf_full )
468 					{
469 						silence = true;
470 					}
471 					else
472 					{
473 						silence = false;
474 						bits = buf;
475 						buf_full = false;
476 						if ( !output )
477 							silence = true;
478 						fill_buffer();
479 					}
480 				}
481 			}
482 			while ( time < end_time );
483 
484 			this->dac = dac;
485 			this->bits = bits;
486 		}
487 		this->bits_remain = bits_remain;
488 	}
489 	delay = time - end_time;
490 }
491 
492 // Nes_Noise
493 
494 static short const noise_period_table [16] = {
495 	0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0,
496 	0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4
497 };
498 
run(nes_time_t time,nes_time_t end_time)499 void Nes_Noise::run( nes_time_t time, nes_time_t end_time )
500 {
501 	int period = noise_period_table [regs [2] & 15];
502 
503 	if ( !output )
504 	{
505 		// TODO: clean up
506 		time += delay;
507 		delay = time + (end_time - time + period - 1) / period * period - end_time;
508 		return;
509 	}
510 
511 
512 	const int volume = this->volume();
513 	int amp = (noise & 1) ? volume : 0;
514 	{
515 		int delta = update_amp( amp );
516 		if ( delta )
517 		{
518 			output->set_modified();
519 			synth.offset( time, delta, output );
520 		}
521 	}
522 
523 	time += delay;
524 	if ( time < end_time )
525 	{
526 		const int mode_flag = 0x80;
527 
528 		if ( !volume )
529 		{
530 			// round to next multiple of period
531 			time += (end_time - time + period - 1) / period * period;
532 
533 			// approximate noise cycling while muted, by shuffling up noise register
534 			// to do: precise muted noise cycling?
535 			if ( !(regs [2] & mode_flag) )
536 			{
537 				int feedback = (noise << 13) ^ (noise << 14);
538 				noise = (feedback & 0x4000) | (noise >> 1);
539 			}
540 		}
541 		else
542 		{
543 			Blip_Buffer* const output = this->output;
544 
545 			// using resampled time avoids conversion in synth.offset()
546 			blip_resampled_time_t rperiod = output->resampled_duration( period );
547 			blip_resampled_time_t rtime = output->resampled_time( time );
548 
549 			int noise = this->noise;
550 			int delta = amp * 2 - volume;
551 			const int tap = (regs [2] & mode_flag ? 8 : 13);
552 			output->set_modified();
553 
554 			do
555 			{
556 				int feedback = (noise << tap) ^ (noise << 14);
557 				time += period;
558 
559 				if ( (noise + 1) & 2 )
560 				{
561 					// bits 0 and 1 of noise differ
562 					delta = -delta;
563 					synth.offset_resampled( rtime, delta, output );
564 				}
565 
566 				rtime += rperiod;
567 				noise = (feedback & 0x4000) | (noise >> 1);
568 			}
569 			while ( time < end_time );
570 
571 			last_amp = (delta + volume) >> 1;
572 			this->noise = noise;
573 		}
574 	}
575 
576 	delay = time - end_time;
577 }
578 
579