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