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