Mercurial > spc_convert
comparison snes_spc/SPC_DSP.cpp @ 0:e38dacceb958
initial import
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 21 Oct 2011 05:53:11 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:e38dacceb958 |
---|---|
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,0x9C,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 | |
434 // Envelope is never run during KON | |
435 v->env = 0; | |
436 v->hidden_env = 0; | |
437 | |
438 // Disable BRR decoding until last three samples | |
439 v->interp_pos = 0; | |
440 if ( --v->kon_delay & 3 ) | |
441 v->interp_pos = 0x4000; | |
442 | |
443 // Pitch is never added during KON | |
444 m.t_pitch = 0; | |
445 } | |
446 | |
447 // Gaussian interpolation | |
448 { | |
449 int output = interpolate( v ); | |
450 | |
451 // Noise | |
452 if ( m.t_non & v->vbit ) | |
453 output = (int16_t) (m.noise * 2); | |
454 | |
455 // Apply envelope | |
456 m.t_output = (output * v->env) >> 11 & ~1; | |
457 v->t_envx_out = (uint8_t) (v->env >> 4); | |
458 } | |
459 | |
460 // Immediate silence due to end of sample or soft reset | |
461 if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) | |
462 { | |
463 v->env_mode = env_release; | |
464 v->env = 0; | |
465 } | |
466 | |
467 if ( m.every_other_sample ) | |
468 { | |
469 // KOFF | |
470 if ( m.t_koff & v->vbit ) | |
471 v->env_mode = env_release; | |
472 | |
473 // KON | |
474 if ( m.kon & v->vbit ) | |
475 { | |
476 v->kon_delay = 5; | |
477 v->env_mode = env_attack; | |
478 } | |
479 } | |
480 | |
481 // Run envelope for next sample | |
482 if ( !v->kon_delay ) | |
483 run_envelope( v ); | |
484 } | |
485 inline void SPC_DSP::voice_output( voice_t const* v, int ch ) | |
486 { | |
487 // Apply left/right volume | |
488 int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; | |
489 | |
490 // Add to output total | |
491 m.t_main_out [ch] += amp; | |
492 CLAMP16( m.t_main_out [ch] ); | |
493 | |
494 // Optionally add to echo total | |
495 if ( m.t_eon & v->vbit ) | |
496 { | |
497 m.t_echo_out [ch] += amp; | |
498 CLAMP16( m.t_echo_out [ch] ); | |
499 } | |
500 } | |
501 VOICE_CLOCK( V4 ) | |
502 { | |
503 // Decode BRR | |
504 m.t_looped = 0; | |
505 if ( v->interp_pos >= 0x4000 ) | |
506 { | |
507 decode_brr( v ); | |
508 | |
509 if ( (v->brr_offset += 2) >= brr_block_size ) | |
510 { | |
511 // Start decoding next BRR block | |
512 assert( v->brr_offset == brr_block_size ); | |
513 v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; | |
514 if ( m.t_brr_header & 1 ) | |
515 { | |
516 v->brr_addr = m.t_brr_next_addr; | |
517 m.t_looped = v->vbit; | |
518 } | |
519 v->brr_offset = 1; | |
520 } | |
521 } | |
522 | |
523 // Apply pitch | |
524 v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; | |
525 | |
526 // Keep from getting too far ahead (when using pitch modulation) | |
527 if ( v->interp_pos > 0x7FFF ) | |
528 v->interp_pos = 0x7FFF; | |
529 | |
530 // Output left | |
531 voice_output( v, 0 ); | |
532 } | |
533 inline VOICE_CLOCK( V5 ) | |
534 { | |
535 // Output right | |
536 voice_output( v, 1 ); | |
537 | |
538 // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier | |
539 int endx_buf = REG(endx) | m.t_looped; | |
540 | |
541 // Clear bit in ENDX if KON just began | |
542 if ( v->kon_delay == 5 ) | |
543 endx_buf &= ~v->vbit; | |
544 m.endx_buf = (uint8_t) endx_buf; | |
545 } | |
546 inline VOICE_CLOCK( V6 ) | |
547 { | |
548 (void) v; // avoid compiler warning about unused v | |
549 m.outx_buf = (uint8_t) (m.t_output >> 8); | |
550 } | |
551 inline VOICE_CLOCK( V7 ) | |
552 { | |
553 // Update ENDX | |
554 REG(endx) = m.endx_buf; | |
555 | |
556 m.envx_buf = v->t_envx_out; | |
557 } | |
558 inline VOICE_CLOCK( V8 ) | |
559 { | |
560 // Update OUTX | |
561 VREG(v->regs,outx) = m.outx_buf; | |
562 } | |
563 inline VOICE_CLOCK( V9 ) | |
564 { | |
565 // Update ENVX | |
566 VREG(v->regs,envx) = m.envx_buf; | |
567 } | |
568 | |
569 // Most voices do all these in one clock, so make a handy composite | |
570 inline VOICE_CLOCK( V3 ) | |
571 { | |
572 voice_V3a( v ); | |
573 voice_V3b( v ); | |
574 voice_V3c( v ); | |
575 } | |
576 | |
577 // Common combinations of voice steps on different voices. This greatly reduces | |
578 // code size and allows everything to be inlined in these functions. | |
579 VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } | |
580 VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } | |
581 VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } | |
582 | |
583 | |
584 //// Echo | |
585 | |
586 // Current echo buffer pointer for left/right channel | |
587 #define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) | |
588 | |
589 // Sample in echo history buffer, where 0 is the oldest | |
590 #define ECHO_FIR( i ) (m.echo_hist_pos [i]) | |
591 | |
592 // Calculate FIR point for left/right channel | |
593 #define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) | |
594 | |
595 #define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() | |
596 | |
597 inline void SPC_DSP::echo_read( int ch ) | |
598 { | |
599 int s = GET_LE16SA( ECHO_PTR( ch ) ); | |
600 // second copy simplifies wrap-around handling | |
601 ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; | |
602 } | |
603 | |
604 ECHO_CLOCK( 22 ) | |
605 { | |
606 // History | |
607 if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) | |
608 m.echo_hist_pos = m.echo_hist; | |
609 | |
610 m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; | |
611 echo_read( 0 ); | |
612 | |
613 // FIR (using l and r temporaries below helps compiler optimize) | |
614 int l = CALC_FIR( 0, 0 ); | |
615 int r = CALC_FIR( 0, 1 ); | |
616 | |
617 m.t_echo_in [0] = l; | |
618 m.t_echo_in [1] = r; | |
619 } | |
620 ECHO_CLOCK( 23 ) | |
621 { | |
622 int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); | |
623 int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); | |
624 | |
625 m.t_echo_in [0] += l; | |
626 m.t_echo_in [1] += r; | |
627 | |
628 echo_read( 1 ); | |
629 } | |
630 ECHO_CLOCK( 24 ) | |
631 { | |
632 int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); | |
633 int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); | |
634 | |
635 m.t_echo_in [0] += l; | |
636 m.t_echo_in [1] += r; | |
637 } | |
638 ECHO_CLOCK( 25 ) | |
639 { | |
640 int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); | |
641 int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); | |
642 | |
643 l = (int16_t) l; | |
644 r = (int16_t) r; | |
645 | |
646 l += (int16_t) CALC_FIR( 7, 0 ); | |
647 r += (int16_t) CALC_FIR( 7, 1 ); | |
648 | |
649 CLAMP16( l ); | |
650 CLAMP16( r ); | |
651 | |
652 m.t_echo_in [0] = l & ~1; | |
653 m.t_echo_in [1] = r & ~1; | |
654 } | |
655 inline int SPC_DSP::echo_output( int ch ) | |
656 { | |
657 int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + | |
658 (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); | |
659 CLAMP16( out ); | |
660 return out; | |
661 } | |
662 ECHO_CLOCK( 26 ) | |
663 { | |
664 // Left output volumes | |
665 // (save sample for next clock so we can output both together) | |
666 m.t_main_out [0] = echo_output( 0 ); | |
667 | |
668 // Echo feedback | |
669 int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); | |
670 int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); | |
671 | |
672 CLAMP16( l ); | |
673 CLAMP16( r ); | |
674 | |
675 m.t_echo_out [0] = l & ~1; | |
676 m.t_echo_out [1] = r & ~1; | |
677 } | |
678 ECHO_CLOCK( 27 ) | |
679 { | |
680 // Output | |
681 int l = m.t_main_out [0]; | |
682 int r = echo_output( 1 ); | |
683 m.t_main_out [0] = 0; | |
684 m.t_main_out [1] = 0; | |
685 | |
686 // TODO: global muting isn't this simple (turns DAC on and off | |
687 // or something, causing small ~37-sample pulse when first muted) | |
688 if ( REG(flg) & 0x40 ) | |
689 { | |
690 l = 0; | |
691 r = 0; | |
692 } | |
693 | |
694 // Output sample to DAC | |
695 #ifdef SPC_DSP_OUT_HOOK | |
696 SPC_DSP_OUT_HOOK( l, r ); | |
697 #else | |
698 sample_t* out = m.out; | |
699 WRITE_SAMPLES( l, r, out ); | |
700 m.out = out; | |
701 #endif | |
702 } | |
703 ECHO_CLOCK( 28 ) | |
704 { | |
705 m.t_echo_enabled = REG(flg); | |
706 } | |
707 inline void SPC_DSP::echo_write( int ch ) | |
708 { | |
709 if ( !(m.t_echo_enabled & 0x20) ) | |
710 SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); | |
711 m.t_echo_out [ch] = 0; | |
712 } | |
713 ECHO_CLOCK( 29 ) | |
714 { | |
715 m.t_esa = REG(esa); | |
716 | |
717 if ( !m.echo_offset ) | |
718 m.echo_length = (REG(edl) & 0x0F) * 0x800; | |
719 | |
720 m.echo_offset += 4; | |
721 if ( m.echo_offset >= m.echo_length ) | |
722 m.echo_offset = 0; | |
723 | |
724 // Write left echo | |
725 echo_write( 0 ); | |
726 | |
727 m.t_echo_enabled = REG(flg); | |
728 } | |
729 ECHO_CLOCK( 30 ) | |
730 { | |
731 // Write right echo | |
732 echo_write( 1 ); | |
733 } | |
734 | |
735 | |
736 //// Timing | |
737 | |
738 // Execute clock for a particular voice | |
739 #define V( clock, voice ) voice_##clock( &m.voices [voice] ); | |
740 | |
741 /* The most common sequence of clocks uses composite operations | |
742 for efficiency. For example, the following are equivalent to the | |
743 individual steps on the right: | |
744 | |
745 V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) | |
746 V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) | |
747 V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ | |
748 | |
749 // Voice 0 1 2 3 4 5 6 7 | |
750 #define GEN_DSP_TIMING \ | |
751 PHASE( 0) V(V5,0)V(V2,1)\ | |
752 PHASE( 1) V(V6,0)V(V3,1)\ | |
753 PHASE( 2) V(V7_V4_V1,0)\ | |
754 PHASE( 3) V(V8_V5_V2,0)\ | |
755 PHASE( 4) V(V9_V6_V3,0)\ | |
756 PHASE( 5) V(V7_V4_V1,1)\ | |
757 PHASE( 6) V(V8_V5_V2,1)\ | |
758 PHASE( 7) V(V9_V6_V3,1)\ | |
759 PHASE( 8) V(V7_V4_V1,2)\ | |
760 PHASE( 9) V(V8_V5_V2,2)\ | |
761 PHASE(10) V(V9_V6_V3,2)\ | |
762 PHASE(11) V(V7_V4_V1,3)\ | |
763 PHASE(12) V(V8_V5_V2,3)\ | |
764 PHASE(13) V(V9_V6_V3,3)\ | |
765 PHASE(14) V(V7_V4_V1,4)\ | |
766 PHASE(15) V(V8_V5_V2,4)\ | |
767 PHASE(16) V(V9_V6_V3,4)\ | |
768 PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ | |
769 PHASE(18) V(V8_V5_V2,5)\ | |
770 PHASE(19) V(V9_V6_V3,5)\ | |
771 PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ | |
772 PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ | |
773 PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ | |
774 PHASE(23) V(V7,7) echo_23();\ | |
775 PHASE(24) V(V8,7) echo_24();\ | |
776 PHASE(25) V(V3b,0) V(V9,7) echo_25();\ | |
777 PHASE(26) echo_26();\ | |
778 PHASE(27) misc_27(); echo_27();\ | |
779 PHASE(28) misc_28(); echo_28();\ | |
780 PHASE(29) misc_29(); echo_29();\ | |
781 PHASE(30) misc_30();V(V3c,0) echo_30();\ | |
782 PHASE(31) V(V4,0) V(V1,2)\ | |
783 | |
784 #if !SPC_DSP_CUSTOM_RUN | |
785 | |
786 void SPC_DSP::run( int clocks_remain ) | |
787 { | |
788 require( clocks_remain > 0 ); | |
789 | |
790 int const phase = m.phase; | |
791 m.phase = (phase + clocks_remain) & 31; | |
792 switch ( phase ) | |
793 { | |
794 loop: | |
795 | |
796 #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: | |
797 GEN_DSP_TIMING | |
798 #undef PHASE | |
799 | |
800 if ( --clocks_remain ) | |
801 goto loop; | |
802 } | |
803 } | |
804 | |
805 #endif | |
806 | |
807 | |
808 //// Setup | |
809 | |
810 void SPC_DSP::init( void* ram_64k ) | |
811 { | |
812 m.ram = (uint8_t*) ram_64k; | |
813 mute_voices( 0 ); | |
814 disable_surround( false ); | |
815 set_output( 0, 0 ); | |
816 reset(); | |
817 | |
818 #ifndef NDEBUG | |
819 // be sure this sign-extends | |
820 assert( (int16_t) 0x8000 == -0x8000 ); | |
821 | |
822 // be sure right shift preserves sign | |
823 assert( (-1 >> 1) == -1 ); | |
824 | |
825 // check clamp macro | |
826 int i; | |
827 i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); | |
828 i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); | |
829 | |
830 blargg_verify_byte_order(); | |
831 #endif | |
832 } | |
833 | |
834 void SPC_DSP::soft_reset_common() | |
835 { | |
836 require( m.ram ); // init() must have been called already | |
837 | |
838 m.noise = 0x4000; | |
839 m.echo_hist_pos = m.echo_hist; | |
840 m.every_other_sample = 1; | |
841 m.echo_offset = 0; | |
842 m.phase = 0; | |
843 | |
844 init_counter(); | |
845 } | |
846 | |
847 void SPC_DSP::soft_reset() | |
848 { | |
849 REG(flg) = 0xE0; | |
850 soft_reset_common(); | |
851 } | |
852 | |
853 void SPC_DSP::load( uint8_t const regs [register_count] ) | |
854 { | |
855 memcpy( m.regs, regs, sizeof m.regs ); | |
856 memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); | |
857 | |
858 // Internal state | |
859 for ( int i = voice_count; --i >= 0; ) | |
860 { | |
861 voice_t* v = &m.voices [i]; | |
862 v->brr_offset = 1; | |
863 v->vbit = 1 << i; | |
864 v->regs = &m.regs [i * 0x10]; | |
865 } | |
866 m.new_kon = REG(kon); | |
867 m.t_dir = REG(dir); | |
868 m.t_esa = REG(esa); | |
869 | |
870 soft_reset_common(); | |
871 } | |
872 | |
873 void SPC_DSP::reset() { load( initial_regs ); } | |
874 | |
875 | |
876 //// State save/load | |
877 | |
878 #if !SPC_NO_COPY_STATE_FUNCS | |
879 | |
880 void SPC_State_Copier::copy( void* state, size_t size ) | |
881 { | |
882 func( buf, state, size ); | |
883 } | |
884 | |
885 int SPC_State_Copier::copy_int( int state, int size ) | |
886 { | |
887 BOOST::uint8_t s [2]; | |
888 SET_LE16( s, state ); | |
889 func( buf, &s, size ); | |
890 return GET_LE16( s ); | |
891 } | |
892 | |
893 void SPC_State_Copier::skip( int count ) | |
894 { | |
895 if ( count > 0 ) | |
896 { | |
897 char temp [64]; | |
898 memset( temp, 0, sizeof temp ); | |
899 do | |
900 { | |
901 int n = sizeof temp; | |
902 if ( n > count ) | |
903 n = count; | |
904 count -= n; | |
905 func( buf, temp, n ); | |
906 } | |
907 while ( count ); | |
908 } | |
909 } | |
910 | |
911 void SPC_State_Copier::extra() | |
912 { | |
913 int n = 0; | |
914 SPC_State_Copier& copier = *this; | |
915 SPC_COPY( uint8_t, n ); | |
916 skip( n ); | |
917 } | |
918 | |
919 void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) | |
920 { | |
921 SPC_State_Copier copier( io, copy ); | |
922 | |
923 // DSP registers | |
924 copier.copy( m.regs, register_count ); | |
925 | |
926 // Internal state | |
927 | |
928 // Voices | |
929 int i; | |
930 for ( i = 0; i < voice_count; i++ ) | |
931 { | |
932 voice_t* v = &m.voices [i]; | |
933 | |
934 // BRR buffer | |
935 int i; | |
936 for ( i = 0; i < brr_buf_size; i++ ) | |
937 { | |
938 int s = v->buf [i]; | |
939 SPC_COPY( int16_t, s ); | |
940 v->buf [i] = v->buf [i + brr_buf_size] = s; | |
941 } | |
942 | |
943 SPC_COPY( uint16_t, v->interp_pos ); | |
944 SPC_COPY( uint16_t, v->brr_addr ); | |
945 SPC_COPY( uint16_t, v->env ); | |
946 SPC_COPY( int16_t, v->hidden_env ); | |
947 SPC_COPY( uint8_t, v->buf_pos ); | |
948 SPC_COPY( uint8_t, v->brr_offset ); | |
949 SPC_COPY( uint8_t, v->kon_delay ); | |
950 { | |
951 int m = v->env_mode; | |
952 SPC_COPY( uint8_t, m ); | |
953 v->env_mode = (enum env_mode_t) m; | |
954 } | |
955 SPC_COPY( uint8_t, v->t_envx_out ); | |
956 | |
957 copier.extra(); | |
958 } | |
959 | |
960 // Echo history | |
961 for ( i = 0; i < echo_hist_size; i++ ) | |
962 { | |
963 int j; | |
964 for ( j = 0; j < 2; j++ ) | |
965 { | |
966 int s = m.echo_hist_pos [i] [j]; | |
967 SPC_COPY( int16_t, s ); | |
968 m.echo_hist [i] [j] = s; // write back at offset 0 | |
969 } | |
970 } | |
971 m.echo_hist_pos = m.echo_hist; | |
972 memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); | |
973 | |
974 // Misc | |
975 SPC_COPY( uint8_t, m.every_other_sample ); | |
976 SPC_COPY( uint8_t, m.kon ); | |
977 | |
978 SPC_COPY( uint16_t, m.noise ); | |
979 SPC_COPY( uint16_t, m.counter ); | |
980 SPC_COPY( uint16_t, m.echo_offset ); | |
981 SPC_COPY( uint16_t, m.echo_length ); | |
982 SPC_COPY( uint8_t, m.phase ); | |
983 | |
984 SPC_COPY( uint8_t, m.new_kon ); | |
985 SPC_COPY( uint8_t, m.endx_buf ); | |
986 SPC_COPY( uint8_t, m.envx_buf ); | |
987 SPC_COPY( uint8_t, m.outx_buf ); | |
988 | |
989 SPC_COPY( uint8_t, m.t_pmon ); | |
990 SPC_COPY( uint8_t, m.t_non ); | |
991 SPC_COPY( uint8_t, m.t_eon ); | |
992 SPC_COPY( uint8_t, m.t_dir ); | |
993 SPC_COPY( uint8_t, m.t_koff ); | |
994 | |
995 SPC_COPY( uint16_t, m.t_brr_next_addr ); | |
996 SPC_COPY( uint8_t, m.t_adsr0 ); | |
997 SPC_COPY( uint8_t, m.t_brr_header ); | |
998 SPC_COPY( uint8_t, m.t_brr_byte ); | |
999 SPC_COPY( uint8_t, m.t_srcn ); | |
1000 SPC_COPY( uint8_t, m.t_esa ); | |
1001 SPC_COPY( uint8_t, m.t_echo_enabled ); | |
1002 | |
1003 SPC_COPY( int16_t, m.t_main_out [0] ); | |
1004 SPC_COPY( int16_t, m.t_main_out [1] ); | |
1005 SPC_COPY( int16_t, m.t_echo_out [0] ); | |
1006 SPC_COPY( int16_t, m.t_echo_out [1] ); | |
1007 SPC_COPY( int16_t, m.t_echo_in [0] ); | |
1008 SPC_COPY( int16_t, m.t_echo_in [1] ); | |
1009 | |
1010 SPC_COPY( uint16_t, m.t_dir_addr ); | |
1011 SPC_COPY( uint16_t, m.t_pitch ); | |
1012 SPC_COPY( int16_t, m.t_output ); | |
1013 SPC_COPY( uint16_t, m.t_echo_ptr ); | |
1014 SPC_COPY( uint8_t, m.t_looped ); | |
1015 | |
1016 copier.extra(); | |
1017 } | |
1018 #endif |