view fast_dsp/SPC_DSP.cpp @ 0:e38dacceb958

initial import
author Robert McIntyre <rlm@mit.edu>
date Fri, 21 Oct 2011 05:53:11 -0700
parents
children
line wrap: on
line source
1 // snes_spc 0.9.0. http://www.slack.net/~ant/
3 #include "SPC_DSP.h"
5 #include "blargg_endian.h"
6 #include <string.h>
8 /* Copyright (C) 2007 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 more
15 details. You should have received a copy of the GNU Lesser General Public
16 License along with this module; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
19 #include "blargg_source.h"
21 #ifdef BLARGG_ENABLE_OPTIMIZER
22 #include BLARGG_ENABLE_OPTIMIZER
23 #endif
25 #if INT_MAX < 0x7FFFFFFF
26 #error "Requires that int type have at least 32 bits"
27 #endif
30 // TODO: add to blargg_endian.h
31 #define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr ))
32 #define GET_LE16A( addr ) GET_LE16( addr )
33 #define SET_LE16A( addr, data ) SET_LE16( addr, data )
35 static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
36 {
37 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
38 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
39 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A,
40 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF,
41 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67,
42 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF,
43 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F,
44 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF
45 };
47 // if ( io < -32768 ) io = -32768;
48 // if ( io > 32767 ) io = 32767;
49 #define CLAMP16( io )\
50 {\
51 if ( (int16_t) io != io )\
52 io = (io >> 31) ^ 0x7FFF;\
53 }
55 // Access global DSP register
56 #define REG(n) m.regs [r_##n]
58 // Access voice DSP register
59 #define VREG(r,n) r [v_##n]
61 #define WRITE_SAMPLES( l, r, out ) \
62 {\
63 out [0] = l;\
64 out [1] = r;\
65 out += 2;\
66 if ( out >= m.out_end )\
67 {\
68 check( out == m.out_end );\
69 check( m.out_end != &m.extra [extra_size] || \
70 (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\
71 out = m.extra;\
72 m.out_end = &m.extra [extra_size];\
73 }\
74 }\
76 void SPC_DSP::set_output( sample_t* out, int size )
77 {
78 require( (size & 1) == 0 ); // must be even
79 if ( !out )
80 {
81 out = m.extra;
82 size = extra_size;
83 }
84 m.out_begin = out;
85 m.out = out;
86 m.out_end = out + size;
87 }
89 // Volume registers and efb are signed! Easy to forget int8_t cast.
90 // Prefixes are to avoid accidental use of locals with same names.
92 // Interleved gauss table (to improve cache coherency)
93 // interleved_gauss [i] = gauss [(i & 1) * 256 + 255 - (i >> 1 & 0xFF)]
94 static short const interleved_gauss [512] =
95 {
96 370,1305, 366,1305, 362,1304, 358,1304, 354,1304, 351,1304, 347,1304, 343,1303,
97 339,1303, 336,1303, 332,1302, 328,1302, 325,1301, 321,1300, 318,1300, 314,1299,
98 311,1298, 307,1297, 304,1297, 300,1296, 297,1295, 293,1294, 290,1293, 286,1292,
99 283,1291, 280,1290, 276,1288, 273,1287, 270,1286, 267,1284, 263,1283, 260,1282,
100 257,1280, 254,1279, 251,1277, 248,1275, 245,1274, 242,1272, 239,1270, 236,1269,
101 233,1267, 230,1265, 227,1263, 224,1261, 221,1259, 218,1257, 215,1255, 212,1253,
102 210,1251, 207,1248, 204,1246, 201,1244, 199,1241, 196,1239, 193,1237, 191,1234,
103 188,1232, 186,1229, 183,1227, 180,1224, 178,1221, 175,1219, 173,1216, 171,1213,
104 168,1210, 166,1207, 163,1205, 161,1202, 159,1199, 156,1196, 154,1193, 152,1190,
105 150,1186, 147,1183, 145,1180, 143,1177, 141,1174, 139,1170, 137,1167, 134,1164,
106 132,1160, 130,1157, 128,1153, 126,1150, 124,1146, 122,1143, 120,1139, 118,1136,
107 117,1132, 115,1128, 113,1125, 111,1121, 109,1117, 107,1113, 106,1109, 104,1106,
108 102,1102, 100,1098, 99,1094, 97,1090, 95,1086, 94,1082, 92,1078, 90,1074,
109 89,1070, 87,1066, 86,1061, 84,1057, 83,1053, 81,1049, 80,1045, 78,1040,
110 77,1036, 76,1032, 74,1027, 73,1023, 71,1019, 70,1014, 69,1010, 67,1005,
111 66,1001, 65, 997, 64, 992, 62, 988, 61, 983, 60, 978, 59, 974, 58, 969,
112 56, 965, 55, 960, 54, 955, 53, 951, 52, 946, 51, 941, 50, 937, 49, 932,
113 48, 927, 47, 923, 46, 918, 45, 913, 44, 908, 43, 904, 42, 899, 41, 894,
114 40, 889, 39, 884, 38, 880, 37, 875, 36, 870, 36, 865, 35, 860, 34, 855,
115 33, 851, 32, 846, 32, 841, 31, 836, 30, 831, 29, 826, 29, 821, 28, 816,
116 27, 811, 27, 806, 26, 802, 25, 797, 24, 792, 24, 787, 23, 782, 23, 777,
117 22, 772, 21, 767, 21, 762, 20, 757, 20, 752, 19, 747, 19, 742, 18, 737,
118 17, 732, 17, 728, 16, 723, 16, 718, 15, 713, 15, 708, 15, 703, 14, 698,
119 14, 693, 13, 688, 13, 683, 12, 678, 12, 674, 11, 669, 11, 664, 11, 659,
120 10, 654, 10, 649, 10, 644, 9, 640, 9, 635, 9, 630, 8, 625, 8, 620,
121 8, 615, 7, 611, 7, 606, 7, 601, 6, 596, 6, 592, 6, 587, 6, 582,
122 5, 577, 5, 573, 5, 568, 5, 563, 4, 559, 4, 554, 4, 550, 4, 545,
123 4, 540, 3, 536, 3, 531, 3, 527, 3, 522, 3, 517, 2, 513, 2, 508,
124 2, 504, 2, 499, 2, 495, 2, 491, 2, 486, 1, 482, 1, 477, 1, 473,
125 1, 469, 1, 464, 1, 460, 1, 456, 1, 451, 1, 447, 1, 443, 1, 439,
126 0, 434, 0, 430, 0, 426, 0, 422, 0, 418, 0, 414, 0, 410, 0, 405,
127 0, 401, 0, 397, 0, 393, 0, 389, 0, 385, 0, 381, 0, 378, 0, 374,
128 };
131 //// Counters
133 #define RATE( rate, div )\
134 (rate >= div ? rate / div * 8 - 1 : rate - 1)
136 static unsigned const counter_mask [32] =
137 {
138 RATE( 2,2), RATE(2048,4), RATE(1536,3),
139 RATE(1280,5), RATE(1024,4), RATE( 768,3),
140 RATE( 640,5), RATE( 512,4), RATE( 384,3),
141 RATE( 320,5), RATE( 256,4), RATE( 192,3),
142 RATE( 160,5), RATE( 128,4), RATE( 96,3),
143 RATE( 80,5), RATE( 64,4), RATE( 48,3),
144 RATE( 40,5), RATE( 32,4), RATE( 24,3),
145 RATE( 20,5), RATE( 16,4), RATE( 12,3),
146 RATE( 10,5), RATE( 8,4), RATE( 6,3),
147 RATE( 5,5), RATE( 4,4), RATE( 3,3),
148 RATE( 2,4),
149 RATE( 1,4)
150 };
151 #undef RATE
153 inline void SPC_DSP::init_counter()
154 {
155 // counters start out with this synchronization
156 m.counters [0] = 1;
157 m.counters [1] = 0;
158 m.counters [2] = -0x20u;
159 m.counters [3] = 0x0B;
161 int n = 2;
162 for ( int i = 1; i < 32; i++ )
163 {
164 m.counter_select [i] = &m.counters [n];
165 if ( !--n )
166 n = 3;
167 }
168 m.counter_select [ 0] = &m.counters [0];
169 m.counter_select [30] = &m.counters [2];
170 }
172 inline void SPC_DSP::run_counter( int i )
173 {
174 int n = m.counters [i];
175 if ( !(n-- & 7) )
176 n -= 6 - i;
177 m.counters [i] = n;
178 }
180 #define READ_COUNTER( rate )\
181 (*m.counter_select [rate] & counter_mask [rate])
184 //// Emulation
186 void SPC_DSP::run( int clock_count )
187 {
188 int new_phase = m.phase + clock_count;
189 int count = new_phase >> 5;
190 m.phase = new_phase & 31;
191 if ( !count )
192 return;
194 uint8_t* const ram = m.ram;
195 uint8_t const* const dir = &ram [REG(dir) * 0x100];
196 int const slow_gaussian = (REG(pmon) >> 1) | REG(non);
197 int const noise_rate = REG(flg) & 0x1F;
199 // Global volume
200 int mvoll = (int8_t) REG(mvoll);
201 int mvolr = (int8_t) REG(mvolr);
202 if ( mvoll * mvolr < m.surround_threshold )
203 mvoll = -mvoll; // eliminate surround
205 do
206 {
207 // KON/KOFF reading
208 if ( (m.every_other_sample ^= 1) != 0 )
209 {
210 m.new_kon &= ~m.kon;
211 m.kon = m.new_kon;
212 m.t_koff = REG(koff);
213 }
215 run_counter( 1 );
216 run_counter( 2 );
217 run_counter( 3 );
219 // Noise
220 if ( !READ_COUNTER( noise_rate ) )
221 {
222 int feedback = (m.noise << 13) ^ (m.noise << 14);
223 m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
224 }
226 // Voices
227 int pmon_input = 0;
228 int main_out_l = 0;
229 int main_out_r = 0;
230 int echo_out_l = 0;
231 int echo_out_r = 0;
232 voice_t* v = m.voices;
233 uint8_t* v_regs = m.regs;
234 int vbit = 1;
235 do
236 {
237 #define SAMPLE_PTR(i) GET_LE16A( &dir [VREG(v_regs,srcn) * 4 + i * 2] )
239 int brr_header = ram [v->brr_addr];
240 int kon_delay = v->kon_delay;
242 // Pitch
243 int pitch = GET_LE16A( &VREG(v_regs,pitchl) ) & 0x3FFF;
244 if ( REG(pmon) & vbit )
245 pitch += ((pmon_input >> 5) * pitch) >> 10;
247 // KON phases
248 if ( --kon_delay >= 0 )
249 {
250 v->kon_delay = kon_delay;
252 // Get ready to start BRR decoding on next sample
253 if ( kon_delay == 4 )
254 {
255 v->brr_addr = SAMPLE_PTR( 0 );
256 v->brr_offset = 1;
257 v->buf_pos = v->buf;
258 brr_header = 0; // header is ignored on this sample
259 }
261 // Envelope is never run during KON
262 v->env = 0;
263 v->hidden_env = 0;
265 // Disable BRR decoding until last three samples
266 v->interp_pos = (kon_delay & 3 ? 0x4000 : 0);
268 // Pitch is never added during KON
269 pitch = 0;
270 }
272 int env = v->env;
274 // Gaussian interpolation
275 {
276 int output = 0;
277 VREG(v_regs,envx) = (uint8_t) (env >> 4);
278 if ( env )
279 {
280 // Make pointers into gaussian based on fractional position between samples
281 int offset = (unsigned) v->interp_pos >> 3 & 0x1FE;
282 short const* fwd = interleved_gauss + offset;
283 short const* rev = interleved_gauss + 510 - offset; // mirror left half of gaussian
285 int const* in = &v->buf_pos [(unsigned) v->interp_pos >> 12];
287 if ( !(slow_gaussian & vbit) ) // 99%
288 {
289 // Faster approximation when exact sample value isn't necessary for pitch mod
290 output = (fwd [0] * in [0] +
291 fwd [1] * in [1] +
292 rev [1] * in [2] +
293 rev [0] * in [3]) >> 11;
294 output = (output * env) >> 11;
295 }
296 else
297 {
298 output = (int16_t) (m.noise * 2);
299 if ( !(REG(non) & vbit) )
300 {
301 output = (fwd [0] * in [0]) >> 11;
302 output += (fwd [1] * in [1]) >> 11;
303 output += (rev [1] * in [2]) >> 11;
304 output = (int16_t) output;
305 output += (rev [0] * in [3]) >> 11;
307 CLAMP16( output );
308 output &= ~1;
309 }
310 output = (output * env) >> 11 & ~1;
311 }
313 // Output
314 int l = output * v->volume [0];
315 int r = output * v->volume [1];
317 main_out_l += l;
318 main_out_r += r;
320 if ( REG(eon) & vbit )
321 {
322 echo_out_l += l;
323 echo_out_r += r;
324 }
325 }
327 pmon_input = output;
328 VREG(v_regs,outx) = (uint8_t) (output >> 8);
329 }
331 // Soft reset or end of sample
332 if ( REG(flg) & 0x80 || (brr_header & 3) == 1 )
333 {
334 v->env_mode = env_release;
335 env = 0;
336 }
338 if ( m.every_other_sample )
339 {
340 // KOFF
341 if ( m.t_koff & vbit )
342 v->env_mode = env_release;
344 // KON
345 if ( m.kon & vbit )
346 {
347 v->kon_delay = 5;
348 v->env_mode = env_attack;
349 REG(endx) &= ~vbit;
350 }
351 }
353 // Envelope
354 if ( !v->kon_delay )
355 {
356 if ( v->env_mode == env_release ) // 97%
357 {
358 env -= 0x8;
359 v->env = env;
360 if ( env <= 0 )
361 {
362 v->env = 0;
363 goto skip_brr; // no BRR decoding for you!
364 }
365 }
366 else // 3%
367 {
368 int rate;
369 int const adsr0 = VREG(v_regs,adsr0);
370 int env_data = VREG(v_regs,adsr1);
371 if ( adsr0 >= 0x80 ) // 97% ADSR
372 {
373 if ( v->env_mode > env_decay ) // 89%
374 {
375 env--;
376 env -= env >> 8;
377 rate = env_data & 0x1F;
379 // optimized handling
380 v->hidden_env = env;
381 if ( READ_COUNTER( rate ) )
382 goto exit_env;
383 v->env = env;
384 goto exit_env;
385 }
386 else if ( v->env_mode == env_decay )
387 {
388 env--;
389 env -= env >> 8;
390 rate = (adsr0 >> 3 & 0x0E) + 0x10;
391 }
392 else // env_attack
393 {
394 rate = (adsr0 & 0x0F) * 2 + 1;
395 env += rate < 31 ? 0x20 : 0x400;
396 }
397 }
398 else // GAIN
399 {
400 int mode;
401 env_data = VREG(v_regs,gain);
402 mode = env_data >> 5;
403 if ( mode < 4 ) // direct
404 {
405 env = env_data * 0x10;
406 rate = 31;
407 }
408 else
409 {
410 rate = env_data & 0x1F;
411 if ( mode == 4 ) // 4: linear decrease
412 {
413 env -= 0x20;
414 }
415 else if ( mode < 6 ) // 5: exponential decrease
416 {
417 env--;
418 env -= env >> 8;
419 }
420 else // 6,7: linear increase
421 {
422 env += 0x20;
423 if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
424 env += 0x8 - 0x20; // 7: two-slope linear increase
425 }
426 }
427 }
429 // Sustain level
430 if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
431 v->env_mode = env_sustain;
433 v->hidden_env = env;
435 // unsigned cast because linear decrease going negative also triggers this
436 if ( (unsigned) env > 0x7FF )
437 {
438 env = (env < 0 ? 0 : 0x7FF);
439 if ( v->env_mode == env_attack )
440 v->env_mode = env_decay;
441 }
443 if ( !READ_COUNTER( rate ) )
444 v->env = env; // nothing else is controlled by the counter
445 }
446 }
447 exit_env:
449 {
450 // Apply pitch
451 int old_pos = v->interp_pos;
452 int interp_pos = (old_pos & 0x3FFF) + pitch;
453 if ( interp_pos > 0x7FFF )
454 interp_pos = 0x7FFF;
455 v->interp_pos = interp_pos;
457 // BRR decode if necessary
458 if ( old_pos >= 0x4000 )
459 {
460 // Arrange the four input nybbles in 0xABCD order for easy decoding
461 int nybbles = ram [(v->brr_addr + v->brr_offset) & 0xFFFF] * 0x100 +
462 ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
464 // Advance read position
465 int const brr_block_size = 9;
466 int brr_offset = v->brr_offset;
467 if ( (brr_offset += 2) >= brr_block_size )
468 {
469 // Next BRR block
470 int brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
471 assert( brr_offset == brr_block_size );
472 if ( brr_header & 1 )
473 {
474 brr_addr = SAMPLE_PTR( 1 );
475 if ( !v->kon_delay )
476 REG(endx) |= vbit;
477 }
478 v->brr_addr = brr_addr;
479 brr_offset = 1;
480 }
481 v->brr_offset = brr_offset;
483 // Decode
485 // 0: >>1 1: <<0 2: <<1 ... 12: <<11 13-15: >>4 <<11
486 static unsigned char const shifts [16 * 2] = {
487 13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16,
488 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11
489 };
490 int const scale = brr_header >> 4;
491 int const right_shift = shifts [scale];
492 int const left_shift = shifts [scale + 16];
494 // Write to next four samples in circular buffer
495 int* pos = v->buf_pos;
496 int* end;
498 // Decode four samples
499 for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
500 {
501 // Extract upper nybble and scale appropriately
502 int s = ((int16_t) nybbles >> right_shift) << left_shift;
504 // Apply IIR filter (8 is the most commonly used)
505 int const filter = brr_header & 0x0C;
506 int const p1 = pos [brr_buf_size - 1];
507 int const p2 = pos [brr_buf_size - 2] >> 1;
508 if ( filter >= 8 )
509 {
510 s += p1;
511 s -= p2;
512 if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
513 {
514 s += p2 >> 4;
515 s += (p1 * -3) >> 6;
516 }
517 else // s += p1 * 0.8984375 - p2 * 0.40625
518 {
519 s += (p1 * -13) >> 7;
520 s += (p2 * 3) >> 4;
521 }
522 }
523 else if ( filter ) // s += p1 * 0.46875
524 {
525 s += p1 >> 1;
526 s += (-p1) >> 5;
527 }
529 // Adjust and write sample
530 CLAMP16( s );
531 s = (int16_t) (s * 2);
532 pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
533 }
535 if ( pos >= &v->buf [brr_buf_size] )
536 pos = v->buf;
537 v->buf_pos = pos;
538 }
539 }
540 skip_brr:
541 // Next voice
542 vbit <<= 1;
543 v_regs += 0x10;
544 v++;
545 }
546 while ( vbit < 0x100 );
548 // Echo position
549 int echo_offset = m.echo_offset;
550 uint8_t* const echo_ptr = &ram [(REG(esa) * 0x100 + echo_offset) & 0xFFFF];
551 if ( !echo_offset )
552 m.echo_length = (REG(edl) & 0x0F) * 0x800;
553 echo_offset += 4;
554 if ( echo_offset >= m.echo_length )
555 echo_offset = 0;
556 m.echo_offset = echo_offset;
558 // FIR
559 int echo_in_l = GET_LE16SA( echo_ptr + 0 );
560 int echo_in_r = GET_LE16SA( echo_ptr + 2 );
562 int (*echo_hist_pos) [2] = m.echo_hist_pos;
563 if ( ++echo_hist_pos >= &m.echo_hist [echo_hist_size] )
564 echo_hist_pos = m.echo_hist;
565 m.echo_hist_pos = echo_hist_pos;
567 echo_hist_pos [0] [0] = echo_hist_pos [8] [0] = echo_in_l;
568 echo_hist_pos [0] [1] = echo_hist_pos [8] [1] = echo_in_r;
570 #define CALC_FIR_( i, in ) ((in) * (int8_t) REG(fir + i * 0x10))
571 echo_in_l = CALC_FIR_( 7, echo_in_l );
572 echo_in_r = CALC_FIR_( 7, echo_in_r );
574 #define CALC_FIR( i, ch ) CALC_FIR_( i, echo_hist_pos [i + 1] [ch] )
575 #define DO_FIR( i )\
576 echo_in_l += CALC_FIR( i, 0 );\
577 echo_in_r += CALC_FIR( i, 1 );
578 DO_FIR( 0 );
579 DO_FIR( 1 );
580 DO_FIR( 2 );
581 #if defined (__MWERKS__) && __MWERKS__ < 0x3200
582 __eieio(); // keeps compiler from stupidly "caching" things in memory
583 #endif
584 DO_FIR( 3 );
585 DO_FIR( 4 );
586 DO_FIR( 5 );
587 DO_FIR( 6 );
589 // Echo out
590 if ( !(REG(flg) & 0x20) )
591 {
592 int l = (echo_out_l >> 7) + ((echo_in_l * (int8_t) REG(efb)) >> 14);
593 int r = (echo_out_r >> 7) + ((echo_in_r * (int8_t) REG(efb)) >> 14);
595 // just to help pass more validation tests
596 #if SPC_MORE_ACCURACY
597 l &= ~1;
598 r &= ~1;
599 #endif
601 CLAMP16( l );
602 CLAMP16( r );
604 SET_LE16A( echo_ptr + 0, l );
605 SET_LE16A( echo_ptr + 2, r );
606 }
608 // Sound out
609 int l = (main_out_l * mvoll + echo_in_l * (int8_t) REG(evoll)) >> 14;
610 int r = (main_out_r * mvolr + echo_in_r * (int8_t) REG(evolr)) >> 14;
612 CLAMP16( l );
613 CLAMP16( r );
615 if ( (REG(flg) & 0x40) )
616 {
617 l = 0;
618 r = 0;
619 }
621 sample_t* out = m.out;
622 WRITE_SAMPLES( l, r, out );
623 m.out = out;
624 }
625 while ( --count );
626 }
629 //// Setup
631 void SPC_DSP::mute_voices( int mask )
632 {
633 m.mute_mask = mask;
634 for ( int i = 0; i < voice_count; i++ )
635 {
636 m.voices [i].enabled = (mask >> i & 1) - 1;
637 update_voice_vol( i * 0x10 );
638 }
639 }
641 void SPC_DSP::init( void* ram_64k )
642 {
643 m.ram = (uint8_t*) ram_64k;
644 mute_voices( 0 );
645 disable_surround( false );
646 set_output( 0, 0 );
647 reset();
649 #ifndef NDEBUG
650 // be sure this sign-extends
651 assert( (int16_t) 0x8000 == -0x8000 );
653 // be sure right shift preserves sign
654 assert( (-1 >> 1) == -1 );
656 // check clamp macro
657 int i;
658 i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
659 i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
661 blargg_verify_byte_order();
662 #endif
663 }
665 void SPC_DSP::soft_reset_common()
666 {
667 require( m.ram ); // init() must have been called already
669 m.noise = 0x4000;
670 m.echo_hist_pos = m.echo_hist;
671 m.every_other_sample = 1;
672 m.echo_offset = 0;
673 m.phase = 0;
675 init_counter();
676 }
678 void SPC_DSP::soft_reset()
679 {
680 REG(flg) = 0xE0;
681 soft_reset_common();
682 }
684 void SPC_DSP::load( uint8_t const regs [register_count] )
685 {
686 memcpy( m.regs, regs, sizeof m.regs );
687 memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count );
689 // Internal state
690 int i;
691 for ( i = voice_count; --i >= 0; )
692 {
693 voice_t& v = m.voices [i];
694 v.brr_offset = 1;
695 v.buf_pos = v.buf;
696 }
697 m.new_kon = REG(kon);
699 mute_voices( m.mute_mask );
700 soft_reset_common();
701 }
703 void SPC_DSP::reset() { load( initial_regs ); }