Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/apu/SPC_DSP.cpp
28798 views
1
// snes_spc 0.9.0. http://www.slack.net/~ant/
2
3
#include "SPC_DSP.h"
4
5
#include "blargg_endian.h"
6
#include <string.h>
7
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 */
18
19
#include "blargg_source.h"
20
21
#ifdef BLARGG_ENABLE_OPTIMIZER
22
#include BLARGG_ENABLE_OPTIMIZER
23
#endif
24
25
#if INT_MAX < 0x7FFFFFFF
26
#error "Requires that int type have at least 32 bits"
27
#endif
28
29
// TODO: add to blargg_endian.h
30
#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr ))
31
#define GET_LE16A( addr ) GET_LE16( addr )
32
#define SET_LE16A( addr, data ) SET_LE16( addr, data )
33
34
static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
35
{
36
0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
37
0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
38
0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A,
39
0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF,
40
0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67,
41
0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x00,0x4E,0x7B,0xFF,
42
0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F,
43
0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF
44
};
45
46
// if ( io < -32768 ) io = -32768;
47
// if ( io > 32767 ) io = 32767;
48
#define CLAMP16( io )\
49
{\
50
if ( (int16_t) io != io )\
51
io = (io >> 31) ^ 0x7FFF;\
52
}
53
54
// Access global DSP register
55
#define REG(n) m.regs [r_##n]
56
57
// Access voice DSP register
58
#define VREG(r,n) r [v_##n]
59
60
#define WRITE_SAMPLES( l, r, out ) \
61
{\
62
out [0] = l;\
63
out [1] = r;\
64
out += 2;\
65
if ( out >= m.out_end )\
66
{\
67
check( out == m.out_end );\
68
check( m.out_end != &m.extra [extra_size] || \
69
(m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\
70
out = m.extra;\
71
m.out_end = &m.extra [extra_size];\
72
}\
73
}\
74
75
void SPC_DSP::set_output( sample_t* out, int size )
76
{
77
require( (size & 1) == 0 ); // must be even
78
if ( !out )
79
{
80
out = m.extra;
81
size = extra_size;
82
}
83
m.out_begin = out;
84
m.out = out;
85
m.out_end = out + size;
86
}
87
88
// Volume registers and efb are signed! Easy to forget int8_t cast.
89
// Prefixes are to avoid accidental use of locals with same names.
90
91
// Gaussian interpolation
92
93
static short const gauss [512] =
94
{
95
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
97
2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
98
6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
99
11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
100
18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27,
101
28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40,
102
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
103
58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77,
104
78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102,
105
104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
106
134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
107
171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
108
212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
109
260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
110
314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
111
374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
112
439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
113
508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
114
582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
115
659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
116
737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
117
816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
118
894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
119
969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
120
1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
121
1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
122
1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
123
1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
124
1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
125
1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
126
1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
127
};
128
129
inline int SPC_DSP::interpolate( voice_t const* v )
130
{
131
// Make pointers into gaussian based on fractional position between samples
132
int offset = v->interp_pos >> 4 & 0xFF;
133
short const* fwd = gauss + 255 - offset;
134
short const* rev = gauss + offset; // mirror left half of gaussian
135
136
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
137
int out;
138
out = (fwd [ 0] * in [0]) >> 11;
139
out += (fwd [256] * in [1]) >> 11;
140
out += (rev [256] * in [2]) >> 11;
141
out = (int16_t) out;
142
out += (rev [ 0] * in [3]) >> 11;
143
144
CLAMP16( out );
145
out &= ~1;
146
return out;
147
}
148
149
150
//// Counters
151
152
int const simple_counter_range = 2048 * 5 * 3; // 30720
153
154
static unsigned const counter_rates [32] =
155
{
156
simple_counter_range + 1, // never fires
157
2048, 1536,
158
1280, 1024, 768,
159
640, 512, 384,
160
320, 256, 192,
161
160, 128, 96,
162
80, 64, 48,
163
40, 32, 24,
164
20, 16, 12,
165
10, 8, 6,
166
5, 4, 3,
167
2,
168
1
169
};
170
171
static unsigned const counter_offsets [32] =
172
{
173
1, 0, 1040,
174
536, 0, 1040,
175
536, 0, 1040,
176
536, 0, 1040,
177
536, 0, 1040,
178
536, 0, 1040,
179
536, 0, 1040,
180
536, 0, 1040,
181
536, 0, 1040,
182
536, 0, 1040,
183
0,
184
0
185
};
186
187
inline void SPC_DSP::init_counter()
188
{
189
m.counter = 0;
190
}
191
192
inline void SPC_DSP::run_counters()
193
{
194
if ( --m.counter < 0 )
195
m.counter = simple_counter_range - 1;
196
}
197
198
inline unsigned SPC_DSP::read_counter( int rate )
199
{
200
return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate];
201
}
202
203
204
//// Envelope
205
206
inline void SPC_DSP::run_envelope( voice_t* const v )
207
{
208
int env = v->env;
209
if ( v->env_mode == env_release ) // 60%
210
{
211
if ( (env -= 0x8) < 0 )
212
env = 0;
213
v->env = env;
214
}
215
else
216
{
217
int rate;
218
int env_data = VREG(v->regs,adsr1);
219
if ( m.t_adsr0 & 0x80 ) // 99% ADSR
220
{
221
if ( v->env_mode >= env_decay ) // 99%
222
{
223
env--;
224
env -= env >> 8;
225
rate = env_data & 0x1F;
226
if ( v->env_mode == env_decay ) // 1%
227
rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10;
228
}
229
else // env_attack
230
{
231
rate = (m.t_adsr0 & 0x0F) * 2 + 1;
232
env += rate < 31 ? 0x20 : 0x400;
233
}
234
}
235
else // GAIN
236
{
237
int mode;
238
env_data = VREG(v->regs,gain);
239
mode = env_data >> 5;
240
if ( mode < 4 ) // direct
241
{
242
env = env_data * 0x10;
243
rate = 31;
244
}
245
else
246
{
247
rate = env_data & 0x1F;
248
if ( mode == 4 ) // 4: linear decrease
249
{
250
env -= 0x20;
251
}
252
else if ( mode < 6 ) // 5: exponential decrease
253
{
254
env--;
255
env -= env >> 8;
256
}
257
else // 6,7: linear increase
258
{
259
env += 0x20;
260
if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
261
env += 0x8 - 0x20; // 7: two-slope linear increase
262
}
263
}
264
}
265
266
// Sustain level
267
if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
268
v->env_mode = env_sustain;
269
270
v->hidden_env = env;
271
272
// unsigned cast because linear decrease going negative also triggers this
273
if ( (unsigned) env > 0x7FF )
274
{
275
env = (env < 0 ? 0 : 0x7FF);
276
if ( v->env_mode == env_attack )
277
v->env_mode = env_decay;
278
}
279
280
if ( !read_counter( rate ) )
281
v->env = env; // nothing else is controlled by the counter
282
}
283
}
284
285
286
//// BRR Decoding
287
288
inline void SPC_DSP::decode_brr( voice_t* v )
289
{
290
// Arrange the four input nybbles in 0xABCD order for easy decoding
291
int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
292
293
int const header = m.t_brr_header;
294
295
// Write to next four samples in circular buffer
296
int* pos = &v->buf [v->buf_pos];
297
int* end;
298
if ( (v->buf_pos += 4) >= brr_buf_size )
299
v->buf_pos = 0;
300
301
// Decode four samples
302
for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
303
{
304
// Extract nybble and sign-extend
305
int s = (int16_t) nybbles >> 12;
306
307
// Shift sample based on header
308
int const shift = header >> 4;
309
s = (s << shift) >> 1;
310
if ( shift >= 0xD ) // handle invalid range
311
s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0)
312
313
// Apply IIR filter (8 is the most commonly used)
314
int const filter = header & 0x0C;
315
int const p1 = pos [brr_buf_size - 1];
316
int const p2 = pos [brr_buf_size - 2] >> 1;
317
if ( filter >= 8 )
318
{
319
s += p1;
320
s -= p2;
321
if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
322
{
323
s += p2 >> 4;
324
s += (p1 * -3) >> 6;
325
}
326
else // s += p1 * 0.8984375 - p2 * 0.40625
327
{
328
s += (p1 * -13) >> 7;
329
s += (p2 * 3) >> 4;
330
}
331
}
332
else if ( filter ) // s += p1 * 0.46875
333
{
334
s += p1 >> 1;
335
s += (-p1) >> 5;
336
}
337
338
// Adjust and write sample
339
CLAMP16( s );
340
s = (int16_t) (s * 2);
341
pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
342
}
343
}
344
345
346
//// Misc
347
348
#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n()
349
350
MISC_CLOCK( 27 )
351
{
352
m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON
353
}
354
MISC_CLOCK( 28 )
355
{
356
m.t_non = REG(non);
357
m.t_eon = REG(eon);
358
m.t_dir = REG(dir);
359
}
360
MISC_CLOCK( 29 )
361
{
362
if ( (m.every_other_sample ^= 1) != 0 )
363
m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read
364
}
365
MISC_CLOCK( 30 )
366
{
367
if ( m.every_other_sample )
368
{
369
m.kon = m.new_kon;
370
m.t_koff = REG(koff) | m.mute_mask;
371
}
372
373
run_counters();
374
375
// Noise
376
if ( !read_counter( REG(flg) & 0x1F ) )
377
{
378
int feedback = (m.noise << 13) ^ (m.noise << 14);
379
m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
380
}
381
}
382
383
384
//// Voices
385
386
#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v )
387
388
inline VOICE_CLOCK( V1 )
389
{
390
m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;
391
m.t_srcn = VREG(v->regs,srcn);
392
}
393
inline VOICE_CLOCK( V2 )
394
{
395
// Read sample pointer (ignored if not needed)
396
uint8_t const* entry = &m.ram [m.t_dir_addr];
397
if ( !v->kon_delay )
398
entry += 2;
399
m.t_brr_next_addr = GET_LE16A( entry );
400
401
m.t_adsr0 = VREG(v->regs,adsr0);
402
403
// Read pitch, spread over two clocks
404
m.t_pitch = VREG(v->regs,pitchl);
405
}
406
inline VOICE_CLOCK( V3a )
407
{
408
m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8;
409
}
410
inline VOICE_CLOCK( V3b )
411
{
412
// Read BRR header and byte
413
m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF];
414
m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking
415
}
416
VOICE_CLOCK( V3c )
417
{
418
// Pitch modulation using previous voice's output
419
if ( m.t_pmon & v->vbit )
420
m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10;
421
422
if ( v->kon_delay )
423
{
424
// Get ready to start BRR decoding on next sample
425
if ( v->kon_delay == 5 )
426
{
427
v->brr_addr = m.t_brr_next_addr;
428
v->brr_offset = 1;
429
v->buf_pos = 0;
430
m.t_brr_header = 0; // header is ignored on this sample
431
m.kon_check = true;
432
433
if (take_spc_snapshot)
434
{
435
take_spc_snapshot = 0;
436
if (spc_snapshot_callback)
437
spc_snapshot_callback();
438
}
439
}
440
441
// Envelope is never run during KON
442
v->env = 0;
443
v->hidden_env = 0;
444
445
// Disable BRR decoding until last three samples
446
v->interp_pos = 0;
447
if ( --v->kon_delay & 3 )
448
v->interp_pos = 0x4000;
449
450
// Pitch is never added during KON
451
m.t_pitch = 0;
452
}
453
454
// Gaussian interpolation
455
{
456
int output = interpolate( v );
457
458
// Noise
459
if ( m.t_non & v->vbit )
460
output = (int16_t) (m.noise * 2);
461
462
// Apply envelope
463
m.t_output = (output * v->env) >> 11 & ~1;
464
v->t_envx_out = (uint8_t) (v->env >> 4);
465
}
466
467
// Immediate silence due to end of sample or soft reset
468
if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 )
469
{
470
v->env_mode = env_release;
471
v->env = 0;
472
}
473
474
if ( m.every_other_sample )
475
{
476
// KOFF
477
if ( m.t_koff & v->vbit )
478
v->env_mode = env_release;
479
480
// KON
481
if ( m.kon & v->vbit )
482
{
483
v->kon_delay = 5;
484
v->env_mode = env_attack;
485
}
486
}
487
488
// Run envelope for next sample
489
if ( !v->kon_delay )
490
run_envelope( v );
491
}
492
493
inline void SPC_DSP::voice_output( voice_t const* v, int ch )
494
{
495
// Apply left/right volume
496
int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7;
497
amp *= ((stereo_switch & (1 << (v->voice_number + ch * voice_count))) ? 1 : 0);
498
499
// Add to output total
500
m.t_main_out [ch] += amp;
501
CLAMP16( m.t_main_out [ch] );
502
503
// Optionally add to echo total
504
if ( m.t_eon & v->vbit )
505
{
506
m.t_echo_out [ch] += amp;
507
CLAMP16( m.t_echo_out [ch] );
508
}
509
}
510
VOICE_CLOCK( V4 )
511
{
512
// Decode BRR
513
m.t_looped = 0;
514
if ( v->interp_pos >= 0x4000 )
515
{
516
decode_brr( v );
517
518
if ( (v->brr_offset += 2) >= brr_block_size )
519
{
520
// Start decoding next BRR block
521
assert( v->brr_offset == brr_block_size );
522
v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
523
if ( m.t_brr_header & 1 )
524
{
525
v->brr_addr = m.t_brr_next_addr;
526
m.t_looped = v->vbit;
527
}
528
v->brr_offset = 1;
529
}
530
}
531
532
// Apply pitch
533
v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
534
535
// Keep from getting too far ahead (when using pitch modulation)
536
if ( v->interp_pos > 0x7FFF )
537
v->interp_pos = 0x7FFF;
538
539
// Output left
540
voice_output( v, 0 );
541
}
542
inline VOICE_CLOCK( V5 )
543
{
544
// Output right
545
voice_output( v, 1 );
546
547
// ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
548
int endx_buf = REG(endx) | m.t_looped;
549
550
// Clear bit in ENDX if KON just began
551
if ( v->kon_delay == 5 )
552
endx_buf &= ~v->vbit;
553
m.endx_buf = (uint8_t) endx_buf;
554
}
555
inline VOICE_CLOCK( V6 )
556
{
557
(void) v; // avoid compiler warning about unused v
558
m.outx_buf = (uint8_t) (m.t_output >> 8);
559
}
560
inline VOICE_CLOCK( V7 )
561
{
562
// Update ENDX
563
REG(endx) = m.endx_buf;
564
565
m.envx_buf = v->t_envx_out;
566
}
567
inline VOICE_CLOCK( V8 )
568
{
569
// Update OUTX
570
VREG(v->regs,outx) = m.outx_buf;
571
}
572
inline VOICE_CLOCK( V9 )
573
{
574
// Update ENVX
575
VREG(v->regs,envx) = m.envx_buf;
576
}
577
578
// Most voices do all these in one clock, so make a handy composite
579
inline VOICE_CLOCK( V3 )
580
{
581
voice_V3a( v );
582
voice_V3b( v );
583
voice_V3c( v );
584
}
585
586
// Common combinations of voice steps on different voices. This greatly reduces
587
// code size and allows everything to be inlined in these functions.
588
VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); }
589
VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); }
590
VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
591
592
593
//// Echo
594
595
// Current echo buffer pointer for left/right channel
596
#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2])
597
598
// Sample in echo history buffer, where 0 is the oldest
599
#define ECHO_FIR( i ) (m.echo_hist_pos [i])
600
601
// Calculate FIR point for left/right channel
602
#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6)
603
604
#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n()
605
606
inline void SPC_DSP::echo_read( int ch )
607
{
608
int s;
609
if ( m.t_echo_ptr >= 0xffc0 && rom_enabled )
610
s = GET_LE16SA( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0] );
611
else
612
s = GET_LE16SA( ECHO_PTR( ch ) );
613
// second copy simplifies wrap-around handling
614
ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1;
615
}
616
617
ECHO_CLOCK( 22 )
618
{
619
// History
620
if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] )
621
m.echo_hist_pos = m.echo_hist;
622
623
m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF;
624
echo_read( 0 );
625
626
// FIR (using l and r temporaries below helps compiler optimize)
627
int l = CALC_FIR( 0, 0 );
628
int r = CALC_FIR( 0, 1 );
629
630
m.t_echo_in [0] = l;
631
m.t_echo_in [1] = r;
632
}
633
ECHO_CLOCK( 23 )
634
{
635
int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 );
636
int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 );
637
638
m.t_echo_in [0] += l;
639
m.t_echo_in [1] += r;
640
641
echo_read( 1 );
642
}
643
ECHO_CLOCK( 24 )
644
{
645
int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 );
646
int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 );
647
648
m.t_echo_in [0] += l;
649
m.t_echo_in [1] += r;
650
}
651
ECHO_CLOCK( 25 )
652
{
653
int l = m.t_echo_in [0] + CALC_FIR( 6, 0 );
654
int r = m.t_echo_in [1] + CALC_FIR( 6, 1 );
655
656
l = (int16_t) l;
657
r = (int16_t) r;
658
659
l += (int16_t) CALC_FIR( 7, 0 );
660
r += (int16_t) CALC_FIR( 7, 1 );
661
662
CLAMP16( l );
663
CLAMP16( r );
664
665
m.t_echo_in [0] = l & ~1;
666
m.t_echo_in [1] = r & ~1;
667
}
668
inline int SPC_DSP::echo_output( int ch )
669
{
670
int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) +
671
(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
672
CLAMP16( out );
673
return out;
674
}
675
ECHO_CLOCK( 26 )
676
{
677
// Left output volumes
678
// (save sample for next clock so we can output both together)
679
m.t_main_out [0] = echo_output( 0 );
680
681
// Echo feedback
682
int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7);
683
int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7);
684
685
CLAMP16( l );
686
CLAMP16( r );
687
688
m.t_echo_out [0] = l & ~1;
689
m.t_echo_out [1] = r & ~1;
690
}
691
ECHO_CLOCK( 27 )
692
{
693
// Output
694
int l = m.t_main_out [0];
695
int r = echo_output( 1 );
696
m.t_main_out [0] = 0;
697
m.t_main_out [1] = 0;
698
699
// TODO: global muting isn't this simple (turns DAC on and off
700
// or something, causing small ~37-sample pulse when first muted)
701
if ( REG(flg) & 0x40 )
702
{
703
l = 0;
704
r = 0;
705
}
706
707
// Output sample to DAC
708
#ifdef SPC_DSP_OUT_HOOK
709
SPC_DSP_OUT_HOOK( l, r );
710
#else
711
sample_t* out = m.out;
712
WRITE_SAMPLES( l, r, out );
713
m.out = out;
714
#endif
715
}
716
ECHO_CLOCK( 28 )
717
{
718
m.t_echo_enabled = REG(flg);
719
}
720
inline void SPC_DSP::echo_write( int ch )
721
{
722
if ( !(m.t_echo_enabled & 0x20) )
723
{
724
if ( m.t_echo_ptr >= 0xffc0 && rom_enabled )
725
SET_LE16A( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0], m.t_echo_out [ch] );
726
else
727
SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] );
728
}
729
730
m.t_echo_out [ch] = 0;
731
}
732
ECHO_CLOCK( 29 )
733
{
734
m.t_esa = REG(esa);
735
736
if ( !m.echo_offset )
737
m.echo_length = (REG(edl) & 0x0F) * 0x800;
738
739
m.echo_offset += 4;
740
if ( m.echo_offset >= m.echo_length )
741
m.echo_offset = 0;
742
743
// Write left echo
744
echo_write( 0 );
745
746
m.t_echo_enabled = REG(flg);
747
}
748
ECHO_CLOCK( 30 )
749
{
750
// Write right echo
751
echo_write( 1 );
752
}
753
754
755
//// Timing
756
757
// Execute clock for a particular voice
758
#define V( clock, voice ) voice_##clock( &m.voices [voice] );
759
760
/* The most common sequence of clocks uses composite operations
761
for efficiency. For example, the following are equivalent to the
762
individual steps on the right:
763
764
V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5)
765
V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4)
766
V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */
767
768
// Voice 0 1 2 3 4 5 6 7
769
#define GEN_DSP_TIMING \
770
PHASE( 0) V(V5,0)V(V2,1)\
771
PHASE( 1) V(V6,0)V(V3,1)\
772
PHASE( 2) V(V7_V4_V1,0)\
773
PHASE( 3) V(V8_V5_V2,0)\
774
PHASE( 4) V(V9_V6_V3,0)\
775
PHASE( 5) V(V7_V4_V1,1)\
776
PHASE( 6) V(V8_V5_V2,1)\
777
PHASE( 7) V(V9_V6_V3,1)\
778
PHASE( 8) V(V7_V4_V1,2)\
779
PHASE( 9) V(V8_V5_V2,2)\
780
PHASE(10) V(V9_V6_V3,2)\
781
PHASE(11) V(V7_V4_V1,3)\
782
PHASE(12) V(V8_V5_V2,3)\
783
PHASE(13) V(V9_V6_V3,3)\
784
PHASE(14) V(V7_V4_V1,4)\
785
PHASE(15) V(V8_V5_V2,4)\
786
PHASE(16) V(V9_V6_V3,4)\
787
PHASE(17) V(V1,0) V(V7,5)V(V4,6)\
788
PHASE(18) V(V8_V5_V2,5)\
789
PHASE(19) V(V9_V6_V3,5)\
790
PHASE(20) V(V1,1) V(V7,6)V(V4,7)\
791
PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\
792
PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\
793
PHASE(23) V(V7,7) echo_23();\
794
PHASE(24) V(V8,7) echo_24();\
795
PHASE(25) V(V3b,0) V(V9,7) echo_25();\
796
PHASE(26) echo_26();\
797
PHASE(27) misc_27(); echo_27();\
798
PHASE(28) misc_28(); echo_28();\
799
PHASE(29) misc_29(); echo_29();\
800
PHASE(30) misc_30();V(V3c,0) echo_30();\
801
PHASE(31) V(V4,0) V(V1,2)\
802
803
#if !SPC_DSP_CUSTOM_RUN
804
805
void SPC_DSP::run( int clocks_remain )
806
{
807
require( clocks_remain > 0 );
808
809
int const phase = m.phase;
810
m.phase = (phase + clocks_remain) & 31;
811
switch ( phase )
812
{
813
loop:
814
815
#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
816
GEN_DSP_TIMING
817
#undef PHASE
818
819
if ( --clocks_remain )
820
goto loop;
821
}
822
}
823
824
#endif
825
826
827
//// Setup
828
829
void SPC_DSP::init( void* ram_64k )
830
{
831
m.ram = (uint8_t*) ram_64k;
832
mute_voices( 0 );
833
disable_surround( false );
834
set_output( 0, 0 );
835
reset();
836
837
stereo_switch = 0xffff;
838
take_spc_snapshot = 0;
839
spc_snapshot_callback = 0;
840
841
#ifndef NDEBUG
842
// be sure this sign-extends
843
assert( (int16_t) 0x8000 == -0x8000 );
844
845
// be sure right shift preserves sign
846
assert( (-1 >> 1) == -1 );
847
848
// check clamp macro
849
int i;
850
i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
851
i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
852
853
blargg_verify_byte_order();
854
#endif
855
}
856
857
void SPC_DSP::soft_reset_common()
858
{
859
require( m.ram ); // init() must have been called already
860
861
m.noise = 0x4000;
862
m.echo_hist_pos = m.echo_hist;
863
m.every_other_sample = 1;
864
m.echo_offset = 0;
865
m.phase = 0;
866
867
init_counter();
868
869
for (int i = 0; i < voice_count; i++)
870
m.voices[i].voice_number = i;
871
}
872
873
void SPC_DSP::soft_reset()
874
{
875
REG(flg) = 0xE0;
876
soft_reset_common();
877
}
878
879
void SPC_DSP::load( uint8_t const regs [register_count] )
880
{
881
memcpy( m.regs, regs, sizeof m.regs );
882
memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count );
883
884
// Internal state
885
for ( int i = voice_count; --i >= 0; )
886
{
887
voice_t* v = &m.voices [i];
888
v->brr_offset = 1;
889
v->vbit = 1 << i;
890
v->regs = &m.regs [i * 0x10];
891
}
892
m.new_kon = REG(kon);
893
m.t_dir = REG(dir);
894
m.t_esa = REG(esa);
895
896
soft_reset_common();
897
}
898
899
void SPC_DSP::reset() { load( initial_regs ); }
900
901
902
//// State save/load
903
904
#if !SPC_NO_COPY_STATE_FUNCS
905
906
void SPC_State_Copier::copy( void* state, size_t size )
907
{
908
func( buf, state, size );
909
}
910
911
int SPC_State_Copier::copy_int( int state, int size )
912
{
913
BOOST::uint8_t s [2];
914
SET_LE16( s, state );
915
func( buf, &s, size );
916
return GET_LE16( s );
917
}
918
919
void SPC_State_Copier::skip( int count )
920
{
921
if ( count > 0 )
922
{
923
char temp [64];
924
memset( temp, 0, sizeof temp );
925
do
926
{
927
int n = sizeof temp;
928
if ( n > count )
929
n = count;
930
count -= n;
931
func( buf, temp, n );
932
}
933
while ( count );
934
}
935
}
936
937
void SPC_State_Copier::extra()
938
{
939
int n = 0;
940
SPC_State_Copier& copier = *this;
941
SPC_COPY( uint8_t, n );
942
skip( n );
943
}
944
945
void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy )
946
{
947
SPC_State_Copier copier( io, copy );
948
949
// DSP registers
950
copier.copy( m.regs, register_count );
951
952
// Internal state
953
954
// Voices
955
int i;
956
for ( i = 0; i < voice_count; i++ )
957
{
958
voice_t* v = &m.voices [i];
959
960
// BRR buffer
961
int i;
962
for ( i = 0; i < brr_buf_size; i++ )
963
{
964
int s = v->buf [i];
965
SPC_COPY( int16_t, s );
966
v->buf [i] = v->buf [i + brr_buf_size] = s;
967
}
968
969
SPC_COPY( uint16_t, v->interp_pos );
970
SPC_COPY( uint16_t, v->brr_addr );
971
SPC_COPY( uint16_t, v->env );
972
SPC_COPY( int16_t, v->hidden_env );
973
SPC_COPY( uint8_t, v->buf_pos );
974
SPC_COPY( uint8_t, v->brr_offset );
975
SPC_COPY( uint8_t, v->kon_delay );
976
{
977
int m = v->env_mode;
978
SPC_COPY( uint8_t, m );
979
v->env_mode = (enum env_mode_t) m;
980
}
981
SPC_COPY( uint8_t, v->t_envx_out );
982
983
copier.extra();
984
}
985
986
// Echo history
987
for ( i = 0; i < echo_hist_size; i++ )
988
{
989
int j;
990
for ( j = 0; j < 2; j++ )
991
{
992
int s = m.echo_hist_pos [i] [j];
993
SPC_COPY( int16_t, s );
994
m.echo_hist [i] [j] = s; // write back at offset 0
995
}
996
}
997
m.echo_hist_pos = m.echo_hist;
998
memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] );
999
1000
// Misc
1001
SPC_COPY( uint8_t, m.every_other_sample );
1002
SPC_COPY( uint8_t, m.kon );
1003
1004
SPC_COPY( uint16_t, m.noise );
1005
SPC_COPY( uint16_t, m.counter );
1006
SPC_COPY( uint16_t, m.echo_offset );
1007
SPC_COPY( uint16_t, m.echo_length );
1008
SPC_COPY( uint8_t, m.phase );
1009
1010
SPC_COPY( uint8_t, m.new_kon );
1011
SPC_COPY( uint8_t, m.endx_buf );
1012
SPC_COPY( uint8_t, m.envx_buf );
1013
SPC_COPY( uint8_t, m.outx_buf );
1014
1015
SPC_COPY( uint8_t, m.t_pmon );
1016
SPC_COPY( uint8_t, m.t_non );
1017
SPC_COPY( uint8_t, m.t_eon );
1018
SPC_COPY( uint8_t, m.t_dir );
1019
SPC_COPY( uint8_t, m.t_koff );
1020
1021
SPC_COPY( uint16_t, m.t_brr_next_addr );
1022
SPC_COPY( uint8_t, m.t_adsr0 );
1023
SPC_COPY( uint8_t, m.t_brr_header );
1024
SPC_COPY( uint8_t, m.t_brr_byte );
1025
SPC_COPY( uint8_t, m.t_srcn );
1026
SPC_COPY( uint8_t, m.t_esa );
1027
SPC_COPY( uint8_t, m.t_echo_enabled );
1028
1029
SPC_COPY( int16_t, m.t_main_out [0] );
1030
SPC_COPY( int16_t, m.t_main_out [1] );
1031
SPC_COPY( int16_t, m.t_echo_out [0] );
1032
SPC_COPY( int16_t, m.t_echo_out [1] );
1033
SPC_COPY( int16_t, m.t_echo_in [0] );
1034
SPC_COPY( int16_t, m.t_echo_in [1] );
1035
1036
SPC_COPY( uint16_t, m.t_dir_addr );
1037
SPC_COPY( uint16_t, m.t_pitch );
1038
SPC_COPY( int16_t, m.t_output );
1039
SPC_COPY( uint16_t, m.t_echo_ptr );
1040
SPC_COPY( uint8_t, m.t_looped );
1041
1042
copier.extra();
1043
}
1044
#endif
1045
1046
1047
//// Snes9x Accessor
1048
1049
void SPC_DSP::set_spc_snapshot_callback( void (*callback) (void) )
1050
{
1051
spc_snapshot_callback = callback;
1052
}
1053
1054
void SPC_DSP::dump_spc_snapshot( void )
1055
{
1056
take_spc_snapshot = 1;
1057
}
1058
1059
void SPC_DSP::set_stereo_switch( int value )
1060
{
1061
stereo_switch = value;
1062
}
1063
1064
SPC_DSP::uint8_t SPC_DSP::reg_value( int ch, int addr )
1065
{
1066
return m.voices[ch].regs[addr];
1067
}
1068
1069
int SPC_DSP::envx_value( int ch )
1070
{
1071
return m.voices[ch].env;
1072
}
1073
1074