Mercurial > spc_convert
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/snes_spc/SPC_DSP.cpp Fri Oct 21 05:53:11 2011 -0700 1.3 @@ -0,0 +1,1018 @@ 1.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/ 1.5 + 1.6 +#include "SPC_DSP.h" 1.7 + 1.8 +#include "blargg_endian.h" 1.9 +#include <string.h> 1.10 + 1.11 +/* Copyright (C) 2007 Shay Green. This module is free software; you 1.12 +can redistribute it and/or modify it under the terms of the GNU Lesser 1.13 +General Public License as published by the Free Software Foundation; either 1.14 +version 2.1 of the License, or (at your option) any later version. This 1.15 +module is distributed in the hope that it will be useful, but WITHOUT ANY 1.16 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 1.17 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 1.18 +details. You should have received a copy of the GNU Lesser General Public 1.19 +License along with this module; if not, write to the Free Software Foundation, 1.20 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 1.21 + 1.22 +#include "blargg_source.h" 1.23 + 1.24 +#ifdef BLARGG_ENABLE_OPTIMIZER 1.25 + #include BLARGG_ENABLE_OPTIMIZER 1.26 +#endif 1.27 + 1.28 +#if INT_MAX < 0x7FFFFFFF 1.29 + #error "Requires that int type have at least 32 bits" 1.30 +#endif 1.31 + 1.32 +// TODO: add to blargg_endian.h 1.33 +#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) 1.34 +#define GET_LE16A( addr ) GET_LE16( addr ) 1.35 +#define SET_LE16A( addr, data ) SET_LE16( addr, data ) 1.36 + 1.37 +static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = 1.38 +{ 1.39 + 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, 1.40 + 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, 1.41 + 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, 1.42 + 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, 1.43 + 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, 1.44 + 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, 1.45 + 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, 1.46 + 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF 1.47 +}; 1.48 + 1.49 +// if ( io < -32768 ) io = -32768; 1.50 +// if ( io > 32767 ) io = 32767; 1.51 +#define CLAMP16( io )\ 1.52 +{\ 1.53 + if ( (int16_t) io != io )\ 1.54 + io = (io >> 31) ^ 0x7FFF;\ 1.55 +} 1.56 + 1.57 +// Access global DSP register 1.58 +#define REG(n) m.regs [r_##n] 1.59 + 1.60 +// Access voice DSP register 1.61 +#define VREG(r,n) r [v_##n] 1.62 + 1.63 +#define WRITE_SAMPLES( l, r, out ) \ 1.64 +{\ 1.65 + out [0] = l;\ 1.66 + out [1] = r;\ 1.67 + out += 2;\ 1.68 + if ( out >= m.out_end )\ 1.69 + {\ 1.70 + check( out == m.out_end );\ 1.71 + check( m.out_end != &m.extra [extra_size] || \ 1.72 + (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ 1.73 + out = m.extra;\ 1.74 + m.out_end = &m.extra [extra_size];\ 1.75 + }\ 1.76 +}\ 1.77 + 1.78 +void SPC_DSP::set_output( sample_t* out, int size ) 1.79 +{ 1.80 + require( (size & 1) == 0 ); // must be even 1.81 + if ( !out ) 1.82 + { 1.83 + out = m.extra; 1.84 + size = extra_size; 1.85 + } 1.86 + m.out_begin = out; 1.87 + m.out = out; 1.88 + m.out_end = out + size; 1.89 +} 1.90 + 1.91 +// Volume registers and efb are signed! Easy to forget int8_t cast. 1.92 +// Prefixes are to avoid accidental use of locals with same names. 1.93 + 1.94 +// Gaussian interpolation 1.95 + 1.96 +static short const gauss [512] = 1.97 +{ 1.98 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.99 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1.100 + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 1.101 + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 1.102 + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 1.103 + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, 1.104 + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, 1.105 + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 1.106 + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, 1.107 + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, 1.108 + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, 1.109 + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, 1.110 + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, 1.111 + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, 1.112 + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, 1.113 + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, 1.114 + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, 1.115 + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, 1.116 + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, 1.117 + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, 1.118 + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, 1.119 + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, 1.120 + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, 1.121 + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, 1.122 + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, 1.123 +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, 1.124 +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, 1.125 +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, 1.126 +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, 1.127 +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, 1.128 +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, 1.129 +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, 1.130 +}; 1.131 + 1.132 +inline int SPC_DSP::interpolate( voice_t const* v ) 1.133 +{ 1.134 + // Make pointers into gaussian based on fractional position between samples 1.135 + int offset = v->interp_pos >> 4 & 0xFF; 1.136 + short const* fwd = gauss + 255 - offset; 1.137 + short const* rev = gauss + offset; // mirror left half of gaussian 1.138 + 1.139 + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; 1.140 + int out; 1.141 + out = (fwd [ 0] * in [0]) >> 11; 1.142 + out += (fwd [256] * in [1]) >> 11; 1.143 + out += (rev [256] * in [2]) >> 11; 1.144 + out = (int16_t) out; 1.145 + out += (rev [ 0] * in [3]) >> 11; 1.146 + 1.147 + CLAMP16( out ); 1.148 + out &= ~1; 1.149 + return out; 1.150 +} 1.151 + 1.152 + 1.153 +//// Counters 1.154 + 1.155 +int const simple_counter_range = 2048 * 5 * 3; // 30720 1.156 + 1.157 +static unsigned const counter_rates [32] = 1.158 +{ 1.159 + simple_counter_range + 1, // never fires 1.160 + 2048, 1536, 1.161 + 1280, 1024, 768, 1.162 + 640, 512, 384, 1.163 + 320, 256, 192, 1.164 + 160, 128, 96, 1.165 + 80, 64, 48, 1.166 + 40, 32, 24, 1.167 + 20, 16, 12, 1.168 + 10, 8, 6, 1.169 + 5, 4, 3, 1.170 + 2, 1.171 + 1 1.172 +}; 1.173 + 1.174 +static unsigned const counter_offsets [32] = 1.175 +{ 1.176 + 1, 0, 1040, 1.177 + 536, 0, 1040, 1.178 + 536, 0, 1040, 1.179 + 536, 0, 1040, 1.180 + 536, 0, 1040, 1.181 + 536, 0, 1040, 1.182 + 536, 0, 1040, 1.183 + 536, 0, 1040, 1.184 + 536, 0, 1040, 1.185 + 536, 0, 1040, 1.186 + 0, 1.187 + 0 1.188 +}; 1.189 + 1.190 +inline void SPC_DSP::init_counter() 1.191 +{ 1.192 + m.counter = 0; 1.193 +} 1.194 + 1.195 +inline void SPC_DSP::run_counters() 1.196 +{ 1.197 + if ( --m.counter < 0 ) 1.198 + m.counter = simple_counter_range - 1; 1.199 +} 1.200 + 1.201 +inline unsigned SPC_DSP::read_counter( int rate ) 1.202 +{ 1.203 + return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; 1.204 +} 1.205 + 1.206 + 1.207 +//// Envelope 1.208 + 1.209 +inline void SPC_DSP::run_envelope( voice_t* const v ) 1.210 +{ 1.211 + int env = v->env; 1.212 + if ( v->env_mode == env_release ) // 60% 1.213 + { 1.214 + if ( (env -= 0x8) < 0 ) 1.215 + env = 0; 1.216 + v->env = env; 1.217 + } 1.218 + else 1.219 + { 1.220 + int rate; 1.221 + int env_data = VREG(v->regs,adsr1); 1.222 + if ( m.t_adsr0 & 0x80 ) // 99% ADSR 1.223 + { 1.224 + if ( v->env_mode >= env_decay ) // 99% 1.225 + { 1.226 + env--; 1.227 + env -= env >> 8; 1.228 + rate = env_data & 0x1F; 1.229 + if ( v->env_mode == env_decay ) // 1% 1.230 + rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; 1.231 + } 1.232 + else // env_attack 1.233 + { 1.234 + rate = (m.t_adsr0 & 0x0F) * 2 + 1; 1.235 + env += rate < 31 ? 0x20 : 0x400; 1.236 + } 1.237 + } 1.238 + else // GAIN 1.239 + { 1.240 + int mode; 1.241 + env_data = VREG(v->regs,gain); 1.242 + mode = env_data >> 5; 1.243 + if ( mode < 4 ) // direct 1.244 + { 1.245 + env = env_data * 0x10; 1.246 + rate = 31; 1.247 + } 1.248 + else 1.249 + { 1.250 + rate = env_data & 0x1F; 1.251 + if ( mode == 4 ) // 4: linear decrease 1.252 + { 1.253 + env -= 0x20; 1.254 + } 1.255 + else if ( mode < 6 ) // 5: exponential decrease 1.256 + { 1.257 + env--; 1.258 + env -= env >> 8; 1.259 + } 1.260 + else // 6,7: linear increase 1.261 + { 1.262 + env += 0x20; 1.263 + if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) 1.264 + env += 0x8 - 0x20; // 7: two-slope linear increase 1.265 + } 1.266 + } 1.267 + } 1.268 + 1.269 + // Sustain level 1.270 + if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) 1.271 + v->env_mode = env_sustain; 1.272 + 1.273 + v->hidden_env = env; 1.274 + 1.275 + // unsigned cast because linear decrease going negative also triggers this 1.276 + if ( (unsigned) env > 0x7FF ) 1.277 + { 1.278 + env = (env < 0 ? 0 : 0x7FF); 1.279 + if ( v->env_mode == env_attack ) 1.280 + v->env_mode = env_decay; 1.281 + } 1.282 + 1.283 + if ( !read_counter( rate ) ) 1.284 + v->env = env; // nothing else is controlled by the counter 1.285 + } 1.286 +} 1.287 + 1.288 + 1.289 +//// BRR Decoding 1.290 + 1.291 +inline void SPC_DSP::decode_brr( voice_t* v ) 1.292 +{ 1.293 + // Arrange the four input nybbles in 0xABCD order for easy decoding 1.294 + int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; 1.295 + 1.296 + int const header = m.t_brr_header; 1.297 + 1.298 + // Write to next four samples in circular buffer 1.299 + int* pos = &v->buf [v->buf_pos]; 1.300 + int* end; 1.301 + if ( (v->buf_pos += 4) >= brr_buf_size ) 1.302 + v->buf_pos = 0; 1.303 + 1.304 + // Decode four samples 1.305 + for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) 1.306 + { 1.307 + // Extract nybble and sign-extend 1.308 + int s = (int16_t) nybbles >> 12; 1.309 + 1.310 + // Shift sample based on header 1.311 + int const shift = header >> 4; 1.312 + s = (s << shift) >> 1; 1.313 + if ( shift >= 0xD ) // handle invalid range 1.314 + s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) 1.315 + 1.316 + // Apply IIR filter (8 is the most commonly used) 1.317 + int const filter = header & 0x0C; 1.318 + int const p1 = pos [brr_buf_size - 1]; 1.319 + int const p2 = pos [brr_buf_size - 2] >> 1; 1.320 + if ( filter >= 8 ) 1.321 + { 1.322 + s += p1; 1.323 + s -= p2; 1.324 + if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 1.325 + { 1.326 + s += p2 >> 4; 1.327 + s += (p1 * -3) >> 6; 1.328 + } 1.329 + else // s += p1 * 0.8984375 - p2 * 0.40625 1.330 + { 1.331 + s += (p1 * -13) >> 7; 1.332 + s += (p2 * 3) >> 4; 1.333 + } 1.334 + } 1.335 + else if ( filter ) // s += p1 * 0.46875 1.336 + { 1.337 + s += p1 >> 1; 1.338 + s += (-p1) >> 5; 1.339 + } 1.340 + 1.341 + // Adjust and write sample 1.342 + CLAMP16( s ); 1.343 + s = (int16_t) (s * 2); 1.344 + pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around 1.345 + } 1.346 +} 1.347 + 1.348 + 1.349 +//// Misc 1.350 + 1.351 +#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() 1.352 + 1.353 +MISC_CLOCK( 27 ) 1.354 +{ 1.355 + m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON 1.356 +} 1.357 +MISC_CLOCK( 28 ) 1.358 +{ 1.359 + m.t_non = REG(non); 1.360 + m.t_eon = REG(eon); 1.361 + m.t_dir = REG(dir); 1.362 +} 1.363 +MISC_CLOCK( 29 ) 1.364 +{ 1.365 + if ( (m.every_other_sample ^= 1) != 0 ) 1.366 + m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read 1.367 +} 1.368 +MISC_CLOCK( 30 ) 1.369 +{ 1.370 + if ( m.every_other_sample ) 1.371 + { 1.372 + m.kon = m.new_kon; 1.373 + m.t_koff = REG(koff) | m.mute_mask; 1.374 + } 1.375 + 1.376 + run_counters(); 1.377 + 1.378 + // Noise 1.379 + if ( !read_counter( REG(flg) & 0x1F ) ) 1.380 + { 1.381 + int feedback = (m.noise << 13) ^ (m.noise << 14); 1.382 + m.noise = (feedback & 0x4000) ^ (m.noise >> 1); 1.383 + } 1.384 +} 1.385 + 1.386 + 1.387 +//// Voices 1.388 + 1.389 +#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) 1.390 + 1.391 +inline VOICE_CLOCK( V1 ) 1.392 +{ 1.393 + m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; 1.394 + m.t_srcn = VREG(v->regs,srcn); 1.395 +} 1.396 +inline VOICE_CLOCK( V2 ) 1.397 +{ 1.398 + // Read sample pointer (ignored if not needed) 1.399 + uint8_t const* entry = &m.ram [m.t_dir_addr]; 1.400 + if ( !v->kon_delay ) 1.401 + entry += 2; 1.402 + m.t_brr_next_addr = GET_LE16A( entry ); 1.403 + 1.404 + m.t_adsr0 = VREG(v->regs,adsr0); 1.405 + 1.406 + // Read pitch, spread over two clocks 1.407 + m.t_pitch = VREG(v->regs,pitchl); 1.408 +} 1.409 +inline VOICE_CLOCK( V3a ) 1.410 +{ 1.411 + m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; 1.412 +} 1.413 +inline VOICE_CLOCK( V3b ) 1.414 +{ 1.415 + // Read BRR header and byte 1.416 + m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; 1.417 + m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking 1.418 +} 1.419 +VOICE_CLOCK( V3c ) 1.420 +{ 1.421 + // Pitch modulation using previous voice's output 1.422 + if ( m.t_pmon & v->vbit ) 1.423 + m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; 1.424 + 1.425 + if ( v->kon_delay ) 1.426 + { 1.427 + // Get ready to start BRR decoding on next sample 1.428 + if ( v->kon_delay == 5 ) 1.429 + { 1.430 + v->brr_addr = m.t_brr_next_addr; 1.431 + v->brr_offset = 1; 1.432 + v->buf_pos = 0; 1.433 + m.t_brr_header = 0; // header is ignored on this sample 1.434 + m.kon_check = true; 1.435 + } 1.436 + 1.437 + // Envelope is never run during KON 1.438 + v->env = 0; 1.439 + v->hidden_env = 0; 1.440 + 1.441 + // Disable BRR decoding until last three samples 1.442 + v->interp_pos = 0; 1.443 + if ( --v->kon_delay & 3 ) 1.444 + v->interp_pos = 0x4000; 1.445 + 1.446 + // Pitch is never added during KON 1.447 + m.t_pitch = 0; 1.448 + } 1.449 + 1.450 + // Gaussian interpolation 1.451 + { 1.452 + int output = interpolate( v ); 1.453 + 1.454 + // Noise 1.455 + if ( m.t_non & v->vbit ) 1.456 + output = (int16_t) (m.noise * 2); 1.457 + 1.458 + // Apply envelope 1.459 + m.t_output = (output * v->env) >> 11 & ~1; 1.460 + v->t_envx_out = (uint8_t) (v->env >> 4); 1.461 + } 1.462 + 1.463 + // Immediate silence due to end of sample or soft reset 1.464 + if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) 1.465 + { 1.466 + v->env_mode = env_release; 1.467 + v->env = 0; 1.468 + } 1.469 + 1.470 + if ( m.every_other_sample ) 1.471 + { 1.472 + // KOFF 1.473 + if ( m.t_koff & v->vbit ) 1.474 + v->env_mode = env_release; 1.475 + 1.476 + // KON 1.477 + if ( m.kon & v->vbit ) 1.478 + { 1.479 + v->kon_delay = 5; 1.480 + v->env_mode = env_attack; 1.481 + } 1.482 + } 1.483 + 1.484 + // Run envelope for next sample 1.485 + if ( !v->kon_delay ) 1.486 + run_envelope( v ); 1.487 +} 1.488 +inline void SPC_DSP::voice_output( voice_t const* v, int ch ) 1.489 +{ 1.490 + // Apply left/right volume 1.491 + int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; 1.492 + 1.493 + // Add to output total 1.494 + m.t_main_out [ch] += amp; 1.495 + CLAMP16( m.t_main_out [ch] ); 1.496 + 1.497 + // Optionally add to echo total 1.498 + if ( m.t_eon & v->vbit ) 1.499 + { 1.500 + m.t_echo_out [ch] += amp; 1.501 + CLAMP16( m.t_echo_out [ch] ); 1.502 + } 1.503 +} 1.504 +VOICE_CLOCK( V4 ) 1.505 +{ 1.506 + // Decode BRR 1.507 + m.t_looped = 0; 1.508 + if ( v->interp_pos >= 0x4000 ) 1.509 + { 1.510 + decode_brr( v ); 1.511 + 1.512 + if ( (v->brr_offset += 2) >= brr_block_size ) 1.513 + { 1.514 + // Start decoding next BRR block 1.515 + assert( v->brr_offset == brr_block_size ); 1.516 + v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; 1.517 + if ( m.t_brr_header & 1 ) 1.518 + { 1.519 + v->brr_addr = m.t_brr_next_addr; 1.520 + m.t_looped = v->vbit; 1.521 + } 1.522 + v->brr_offset = 1; 1.523 + } 1.524 + } 1.525 + 1.526 + // Apply pitch 1.527 + v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; 1.528 + 1.529 + // Keep from getting too far ahead (when using pitch modulation) 1.530 + if ( v->interp_pos > 0x7FFF ) 1.531 + v->interp_pos = 0x7FFF; 1.532 + 1.533 + // Output left 1.534 + voice_output( v, 0 ); 1.535 +} 1.536 +inline VOICE_CLOCK( V5 ) 1.537 +{ 1.538 + // Output right 1.539 + voice_output( v, 1 ); 1.540 + 1.541 + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier 1.542 + int endx_buf = REG(endx) | m.t_looped; 1.543 + 1.544 + // Clear bit in ENDX if KON just began 1.545 + if ( v->kon_delay == 5 ) 1.546 + endx_buf &= ~v->vbit; 1.547 + m.endx_buf = (uint8_t) endx_buf; 1.548 +} 1.549 +inline VOICE_CLOCK( V6 ) 1.550 +{ 1.551 + (void) v; // avoid compiler warning about unused v 1.552 + m.outx_buf = (uint8_t) (m.t_output >> 8); 1.553 +} 1.554 +inline VOICE_CLOCK( V7 ) 1.555 +{ 1.556 + // Update ENDX 1.557 + REG(endx) = m.endx_buf; 1.558 + 1.559 + m.envx_buf = v->t_envx_out; 1.560 +} 1.561 +inline VOICE_CLOCK( V8 ) 1.562 +{ 1.563 + // Update OUTX 1.564 + VREG(v->regs,outx) = m.outx_buf; 1.565 +} 1.566 +inline VOICE_CLOCK( V9 ) 1.567 +{ 1.568 + // Update ENVX 1.569 + VREG(v->regs,envx) = m.envx_buf; 1.570 +} 1.571 + 1.572 +// Most voices do all these in one clock, so make a handy composite 1.573 +inline VOICE_CLOCK( V3 ) 1.574 +{ 1.575 + voice_V3a( v ); 1.576 + voice_V3b( v ); 1.577 + voice_V3c( v ); 1.578 +} 1.579 + 1.580 +// Common combinations of voice steps on different voices. This greatly reduces 1.581 +// code size and allows everything to be inlined in these functions. 1.582 +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } 1.583 +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } 1.584 +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } 1.585 + 1.586 + 1.587 +//// Echo 1.588 + 1.589 +// Current echo buffer pointer for left/right channel 1.590 +#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) 1.591 + 1.592 +// Sample in echo history buffer, where 0 is the oldest 1.593 +#define ECHO_FIR( i ) (m.echo_hist_pos [i]) 1.594 + 1.595 +// Calculate FIR point for left/right channel 1.596 +#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) 1.597 + 1.598 +#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() 1.599 + 1.600 +inline void SPC_DSP::echo_read( int ch ) 1.601 +{ 1.602 + int s = GET_LE16SA( ECHO_PTR( ch ) ); 1.603 + // second copy simplifies wrap-around handling 1.604 + ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; 1.605 +} 1.606 + 1.607 +ECHO_CLOCK( 22 ) 1.608 +{ 1.609 + // History 1.610 + if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) 1.611 + m.echo_hist_pos = m.echo_hist; 1.612 + 1.613 + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; 1.614 + echo_read( 0 ); 1.615 + 1.616 + // FIR (using l and r temporaries below helps compiler optimize) 1.617 + int l = CALC_FIR( 0, 0 ); 1.618 + int r = CALC_FIR( 0, 1 ); 1.619 + 1.620 + m.t_echo_in [0] = l; 1.621 + m.t_echo_in [1] = r; 1.622 +} 1.623 +ECHO_CLOCK( 23 ) 1.624 +{ 1.625 + int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); 1.626 + int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); 1.627 + 1.628 + m.t_echo_in [0] += l; 1.629 + m.t_echo_in [1] += r; 1.630 + 1.631 + echo_read( 1 ); 1.632 +} 1.633 +ECHO_CLOCK( 24 ) 1.634 +{ 1.635 + int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); 1.636 + int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); 1.637 + 1.638 + m.t_echo_in [0] += l; 1.639 + m.t_echo_in [1] += r; 1.640 +} 1.641 +ECHO_CLOCK( 25 ) 1.642 +{ 1.643 + int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); 1.644 + int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); 1.645 + 1.646 + l = (int16_t) l; 1.647 + r = (int16_t) r; 1.648 + 1.649 + l += (int16_t) CALC_FIR( 7, 0 ); 1.650 + r += (int16_t) CALC_FIR( 7, 1 ); 1.651 + 1.652 + CLAMP16( l ); 1.653 + CLAMP16( r ); 1.654 + 1.655 + m.t_echo_in [0] = l & ~1; 1.656 + m.t_echo_in [1] = r & ~1; 1.657 +} 1.658 +inline int SPC_DSP::echo_output( int ch ) 1.659 +{ 1.660 + int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + 1.661 + (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); 1.662 + CLAMP16( out ); 1.663 + return out; 1.664 +} 1.665 +ECHO_CLOCK( 26 ) 1.666 +{ 1.667 + // Left output volumes 1.668 + // (save sample for next clock so we can output both together) 1.669 + m.t_main_out [0] = echo_output( 0 ); 1.670 + 1.671 + // Echo feedback 1.672 + int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); 1.673 + int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); 1.674 + 1.675 + CLAMP16( l ); 1.676 + CLAMP16( r ); 1.677 + 1.678 + m.t_echo_out [0] = l & ~1; 1.679 + m.t_echo_out [1] = r & ~1; 1.680 +} 1.681 +ECHO_CLOCK( 27 ) 1.682 +{ 1.683 + // Output 1.684 + int l = m.t_main_out [0]; 1.685 + int r = echo_output( 1 ); 1.686 + m.t_main_out [0] = 0; 1.687 + m.t_main_out [1] = 0; 1.688 + 1.689 + // TODO: global muting isn't this simple (turns DAC on and off 1.690 + // or something, causing small ~37-sample pulse when first muted) 1.691 + if ( REG(flg) & 0x40 ) 1.692 + { 1.693 + l = 0; 1.694 + r = 0; 1.695 + } 1.696 + 1.697 + // Output sample to DAC 1.698 + #ifdef SPC_DSP_OUT_HOOK 1.699 + SPC_DSP_OUT_HOOK( l, r ); 1.700 + #else 1.701 + sample_t* out = m.out; 1.702 + WRITE_SAMPLES( l, r, out ); 1.703 + m.out = out; 1.704 + #endif 1.705 +} 1.706 +ECHO_CLOCK( 28 ) 1.707 +{ 1.708 + m.t_echo_enabled = REG(flg); 1.709 +} 1.710 +inline void SPC_DSP::echo_write( int ch ) 1.711 +{ 1.712 + if ( !(m.t_echo_enabled & 0x20) ) 1.713 + SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); 1.714 + m.t_echo_out [ch] = 0; 1.715 +} 1.716 +ECHO_CLOCK( 29 ) 1.717 +{ 1.718 + m.t_esa = REG(esa); 1.719 + 1.720 + if ( !m.echo_offset ) 1.721 + m.echo_length = (REG(edl) & 0x0F) * 0x800; 1.722 + 1.723 + m.echo_offset += 4; 1.724 + if ( m.echo_offset >= m.echo_length ) 1.725 + m.echo_offset = 0; 1.726 + 1.727 + // Write left echo 1.728 + echo_write( 0 ); 1.729 + 1.730 + m.t_echo_enabled = REG(flg); 1.731 +} 1.732 +ECHO_CLOCK( 30 ) 1.733 +{ 1.734 + // Write right echo 1.735 + echo_write( 1 ); 1.736 +} 1.737 + 1.738 + 1.739 +//// Timing 1.740 + 1.741 +// Execute clock for a particular voice 1.742 +#define V( clock, voice ) voice_##clock( &m.voices [voice] ); 1.743 + 1.744 +/* The most common sequence of clocks uses composite operations 1.745 +for efficiency. For example, the following are equivalent to the 1.746 +individual steps on the right: 1.747 + 1.748 +V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) 1.749 +V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) 1.750 +V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ 1.751 + 1.752 +// Voice 0 1 2 3 4 5 6 7 1.753 +#define GEN_DSP_TIMING \ 1.754 +PHASE( 0) V(V5,0)V(V2,1)\ 1.755 +PHASE( 1) V(V6,0)V(V3,1)\ 1.756 +PHASE( 2) V(V7_V4_V1,0)\ 1.757 +PHASE( 3) V(V8_V5_V2,0)\ 1.758 +PHASE( 4) V(V9_V6_V3,0)\ 1.759 +PHASE( 5) V(V7_V4_V1,1)\ 1.760 +PHASE( 6) V(V8_V5_V2,1)\ 1.761 +PHASE( 7) V(V9_V6_V3,1)\ 1.762 +PHASE( 8) V(V7_V4_V1,2)\ 1.763 +PHASE( 9) V(V8_V5_V2,2)\ 1.764 +PHASE(10) V(V9_V6_V3,2)\ 1.765 +PHASE(11) V(V7_V4_V1,3)\ 1.766 +PHASE(12) V(V8_V5_V2,3)\ 1.767 +PHASE(13) V(V9_V6_V3,3)\ 1.768 +PHASE(14) V(V7_V4_V1,4)\ 1.769 +PHASE(15) V(V8_V5_V2,4)\ 1.770 +PHASE(16) V(V9_V6_V3,4)\ 1.771 +PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ 1.772 +PHASE(18) V(V8_V5_V2,5)\ 1.773 +PHASE(19) V(V9_V6_V3,5)\ 1.774 +PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ 1.775 +PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ 1.776 +PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ 1.777 +PHASE(23) V(V7,7) echo_23();\ 1.778 +PHASE(24) V(V8,7) echo_24();\ 1.779 +PHASE(25) V(V3b,0) V(V9,7) echo_25();\ 1.780 +PHASE(26) echo_26();\ 1.781 +PHASE(27) misc_27(); echo_27();\ 1.782 +PHASE(28) misc_28(); echo_28();\ 1.783 +PHASE(29) misc_29(); echo_29();\ 1.784 +PHASE(30) misc_30();V(V3c,0) echo_30();\ 1.785 +PHASE(31) V(V4,0) V(V1,2)\ 1.786 + 1.787 +#if !SPC_DSP_CUSTOM_RUN 1.788 + 1.789 +void SPC_DSP::run( int clocks_remain ) 1.790 +{ 1.791 + require( clocks_remain > 0 ); 1.792 + 1.793 + int const phase = m.phase; 1.794 + m.phase = (phase + clocks_remain) & 31; 1.795 + switch ( phase ) 1.796 + { 1.797 + loop: 1.798 + 1.799 + #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: 1.800 + GEN_DSP_TIMING 1.801 + #undef PHASE 1.802 + 1.803 + if ( --clocks_remain ) 1.804 + goto loop; 1.805 + } 1.806 +} 1.807 + 1.808 +#endif 1.809 + 1.810 + 1.811 +//// Setup 1.812 + 1.813 +void SPC_DSP::init( void* ram_64k ) 1.814 +{ 1.815 + m.ram = (uint8_t*) ram_64k; 1.816 + mute_voices( 0 ); 1.817 + disable_surround( false ); 1.818 + set_output( 0, 0 ); 1.819 + reset(); 1.820 + 1.821 + #ifndef NDEBUG 1.822 + // be sure this sign-extends 1.823 + assert( (int16_t) 0x8000 == -0x8000 ); 1.824 + 1.825 + // be sure right shift preserves sign 1.826 + assert( (-1 >> 1) == -1 ); 1.827 + 1.828 + // check clamp macro 1.829 + int i; 1.830 + i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); 1.831 + i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); 1.832 + 1.833 + blargg_verify_byte_order(); 1.834 + #endif 1.835 +} 1.836 + 1.837 +void SPC_DSP::soft_reset_common() 1.838 +{ 1.839 + require( m.ram ); // init() must have been called already 1.840 + 1.841 + m.noise = 0x4000; 1.842 + m.echo_hist_pos = m.echo_hist; 1.843 + m.every_other_sample = 1; 1.844 + m.echo_offset = 0; 1.845 + m.phase = 0; 1.846 + 1.847 + init_counter(); 1.848 +} 1.849 + 1.850 +void SPC_DSP::soft_reset() 1.851 +{ 1.852 + REG(flg) = 0xE0; 1.853 + soft_reset_common(); 1.854 +} 1.855 + 1.856 +void SPC_DSP::load( uint8_t const regs [register_count] ) 1.857 +{ 1.858 + memcpy( m.regs, regs, sizeof m.regs ); 1.859 + memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); 1.860 + 1.861 + // Internal state 1.862 + for ( int i = voice_count; --i >= 0; ) 1.863 + { 1.864 + voice_t* v = &m.voices [i]; 1.865 + v->brr_offset = 1; 1.866 + v->vbit = 1 << i; 1.867 + v->regs = &m.regs [i * 0x10]; 1.868 + } 1.869 + m.new_kon = REG(kon); 1.870 + m.t_dir = REG(dir); 1.871 + m.t_esa = REG(esa); 1.872 + 1.873 + soft_reset_common(); 1.874 +} 1.875 + 1.876 +void SPC_DSP::reset() { load( initial_regs ); } 1.877 + 1.878 + 1.879 +//// State save/load 1.880 + 1.881 +#if !SPC_NO_COPY_STATE_FUNCS 1.882 + 1.883 +void SPC_State_Copier::copy( void* state, size_t size ) 1.884 +{ 1.885 + func( buf, state, size ); 1.886 +} 1.887 + 1.888 +int SPC_State_Copier::copy_int( int state, int size ) 1.889 +{ 1.890 + BOOST::uint8_t s [2]; 1.891 + SET_LE16( s, state ); 1.892 + func( buf, &s, size ); 1.893 + return GET_LE16( s ); 1.894 +} 1.895 + 1.896 +void SPC_State_Copier::skip( int count ) 1.897 +{ 1.898 + if ( count > 0 ) 1.899 + { 1.900 + char temp [64]; 1.901 + memset( temp, 0, sizeof temp ); 1.902 + do 1.903 + { 1.904 + int n = sizeof temp; 1.905 + if ( n > count ) 1.906 + n = count; 1.907 + count -= n; 1.908 + func( buf, temp, n ); 1.909 + } 1.910 + while ( count ); 1.911 + } 1.912 +} 1.913 + 1.914 +void SPC_State_Copier::extra() 1.915 +{ 1.916 + int n = 0; 1.917 + SPC_State_Copier& copier = *this; 1.918 + SPC_COPY( uint8_t, n ); 1.919 + skip( n ); 1.920 +} 1.921 + 1.922 +void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) 1.923 +{ 1.924 + SPC_State_Copier copier( io, copy ); 1.925 + 1.926 + // DSP registers 1.927 + copier.copy( m.regs, register_count ); 1.928 + 1.929 + // Internal state 1.930 + 1.931 + // Voices 1.932 + int i; 1.933 + for ( i = 0; i < voice_count; i++ ) 1.934 + { 1.935 + voice_t* v = &m.voices [i]; 1.936 + 1.937 + // BRR buffer 1.938 + int i; 1.939 + for ( i = 0; i < brr_buf_size; i++ ) 1.940 + { 1.941 + int s = v->buf [i]; 1.942 + SPC_COPY( int16_t, s ); 1.943 + v->buf [i] = v->buf [i + brr_buf_size] = s; 1.944 + } 1.945 + 1.946 + SPC_COPY( uint16_t, v->interp_pos ); 1.947 + SPC_COPY( uint16_t, v->brr_addr ); 1.948 + SPC_COPY( uint16_t, v->env ); 1.949 + SPC_COPY( int16_t, v->hidden_env ); 1.950 + SPC_COPY( uint8_t, v->buf_pos ); 1.951 + SPC_COPY( uint8_t, v->brr_offset ); 1.952 + SPC_COPY( uint8_t, v->kon_delay ); 1.953 + { 1.954 + int m = v->env_mode; 1.955 + SPC_COPY( uint8_t, m ); 1.956 + v->env_mode = (enum env_mode_t) m; 1.957 + } 1.958 + SPC_COPY( uint8_t, v->t_envx_out ); 1.959 + 1.960 + copier.extra(); 1.961 + } 1.962 + 1.963 + // Echo history 1.964 + for ( i = 0; i < echo_hist_size; i++ ) 1.965 + { 1.966 + int j; 1.967 + for ( j = 0; j < 2; j++ ) 1.968 + { 1.969 + int s = m.echo_hist_pos [i] [j]; 1.970 + SPC_COPY( int16_t, s ); 1.971 + m.echo_hist [i] [j] = s; // write back at offset 0 1.972 + } 1.973 + } 1.974 + m.echo_hist_pos = m.echo_hist; 1.975 + memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); 1.976 + 1.977 + // Misc 1.978 + SPC_COPY( uint8_t, m.every_other_sample ); 1.979 + SPC_COPY( uint8_t, m.kon ); 1.980 + 1.981 + SPC_COPY( uint16_t, m.noise ); 1.982 + SPC_COPY( uint16_t, m.counter ); 1.983 + SPC_COPY( uint16_t, m.echo_offset ); 1.984 + SPC_COPY( uint16_t, m.echo_length ); 1.985 + SPC_COPY( uint8_t, m.phase ); 1.986 + 1.987 + SPC_COPY( uint8_t, m.new_kon ); 1.988 + SPC_COPY( uint8_t, m.endx_buf ); 1.989 + SPC_COPY( uint8_t, m.envx_buf ); 1.990 + SPC_COPY( uint8_t, m.outx_buf ); 1.991 + 1.992 + SPC_COPY( uint8_t, m.t_pmon ); 1.993 + SPC_COPY( uint8_t, m.t_non ); 1.994 + SPC_COPY( uint8_t, m.t_eon ); 1.995 + SPC_COPY( uint8_t, m.t_dir ); 1.996 + SPC_COPY( uint8_t, m.t_koff ); 1.997 + 1.998 + SPC_COPY( uint16_t, m.t_brr_next_addr ); 1.999 + SPC_COPY( uint8_t, m.t_adsr0 ); 1.1000 + SPC_COPY( uint8_t, m.t_brr_header ); 1.1001 + SPC_COPY( uint8_t, m.t_brr_byte ); 1.1002 + SPC_COPY( uint8_t, m.t_srcn ); 1.1003 + SPC_COPY( uint8_t, m.t_esa ); 1.1004 + SPC_COPY( uint8_t, m.t_echo_enabled ); 1.1005 + 1.1006 + SPC_COPY( int16_t, m.t_main_out [0] ); 1.1007 + SPC_COPY( int16_t, m.t_main_out [1] ); 1.1008 + SPC_COPY( int16_t, m.t_echo_out [0] ); 1.1009 + SPC_COPY( int16_t, m.t_echo_out [1] ); 1.1010 + SPC_COPY( int16_t, m.t_echo_in [0] ); 1.1011 + SPC_COPY( int16_t, m.t_echo_in [1] ); 1.1012 + 1.1013 + SPC_COPY( uint16_t, m.t_dir_addr ); 1.1014 + SPC_COPY( uint16_t, m.t_pitch ); 1.1015 + SPC_COPY( int16_t, m.t_output ); 1.1016 + SPC_COPY( uint16_t, m.t_echo_ptr ); 1.1017 + SPC_COPY( uint8_t, m.t_looped ); 1.1018 + 1.1019 + copier.extra(); 1.1020 +} 1.1021 +#endif