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