1 | // Highly accurate SNES SPC-700 DSP emulator |
2 | |
3 | // snes_spc 0.9.0 |
4 | #ifndef SPC_DSP_H |
5 | #define SPC_DSP_H |
6 | |
7 | #include "blargg_common.h" |
8 | |
9 | extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } |
10 | |
11 | class SPC_DSP { |
12 | public: |
13 | typedef BOOST::uint8_t uint8_t; |
14 | |
15 | // Setup |
16 | |
17 | // Initializes DSP and has it use the 64K RAM provided |
18 | void init( void* ram_64k ); |
19 | |
20 | // Sets destination for output samples. If out is NULL or out_size is 0, |
21 | // doesn't generate any. |
22 | typedef short sample_t; |
23 | void set_output( sample_t* out, int out_size ); |
24 | |
25 | void set_output( Resampler* resampler ); |
26 | |
27 | // Number of samples written to output since it was last set, always |
28 | // a multiple of 2. Undefined if more samples were generated than |
29 | // output buffer could hold. |
30 | int sample_count() const; |
31 | |
32 | // Emulation |
33 | |
34 | // Resets DSP to power-on state |
35 | void reset(); |
36 | |
37 | // Emulates pressing reset switch on SNES |
38 | void soft_reset(); |
39 | |
40 | // Reads/writes DSP registers. For accuracy, you must first call run() |
41 | // to catch the DSP up to present. |
42 | int read ( int addr ) const; |
43 | void write( int addr, int data ); |
44 | |
45 | // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks |
46 | // a pair of samples is be generated. |
47 | void run( int clock_count ); |
48 | |
49 | // Sound control |
50 | |
51 | // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). |
52 | // Reduces emulation accuracy. |
53 | enum { voice_count = 8 }; |
54 | void mute_voices( int mask ); |
55 | |
56 | // State |
57 | |
58 | // Resets DSP and uses supplied values to initialize registers |
59 | enum { register_count = 128 }; |
60 | void load( uint8_t const regs [register_count] ); |
61 | |
62 | // Saves/loads exact emulator state |
63 | enum { state_size = 640 }; // maximum space needed when saving |
64 | typedef dsp_copy_func_t copy_func_t; |
65 | void copy_state( unsigned char** io, copy_func_t ); |
66 | |
67 | // Returns non-zero if new key-on events occurred since last call |
68 | bool check_kon(); |
69 | |
70 | // Snes9x Accessor |
71 | |
72 | int stereo_switch; |
73 | int take_spc_snapshot; |
74 | void (*spc_snapshot_callback) (void); |
75 | |
76 | void set_spc_snapshot_callback( void (*callback) (void) ); |
77 | void dump_spc_snapshot( void ); |
78 | void set_stereo_switch( int ); |
79 | uint8_t reg_value( int, int ); |
80 | int envx_value( int ); |
81 | |
82 | // DSP register addresses |
83 | |
84 | // Global registers |
85 | enum { |
86 | r_mvoll = 0x0C, r_mvolr = 0x1C, |
87 | r_evoll = 0x2C, r_evolr = 0x3C, |
88 | r_kon = 0x4C, r_koff = 0x5C, |
89 | r_flg = 0x6C, r_endx = 0x7C, |
90 | r_efb = 0x0D, r_pmon = 0x2D, |
91 | r_non = 0x3D, r_eon = 0x4D, |
92 | r_dir = 0x5D, r_esa = 0x6D, |
93 | r_edl = 0x7D, |
94 | r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F |
95 | }; |
96 | |
97 | // Voice registers |
98 | enum { |
99 | v_voll = 0x00, v_volr = 0x01, |
100 | v_pitchl = 0x02, v_pitchh = 0x03, |
101 | v_srcn = 0x04, v_adsr0 = 0x05, |
102 | v_adsr1 = 0x06, v_gain = 0x07, |
103 | v_envx = 0x08, v_outx = 0x09 |
104 | }; |
105 | |
106 | public: |
107 | enum { = 16 }; |
108 | sample_t* () { return m.extra; } |
109 | sample_t const* out_pos() const { return m.out; } |
110 | void disable_surround( bool ) { } // not supported |
111 | public: |
112 | BLARGG_DISABLE_NOTHROW |
113 | |
114 | typedef BOOST::int8_t int8_t; |
115 | typedef BOOST::int16_t int16_t; |
116 | |
117 | enum { echo_hist_size = 8 }; |
118 | |
119 | enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; |
120 | enum { brr_buf_size = 12 }; |
121 | struct voice_t |
122 | { |
123 | int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) |
124 | int buf_pos; // place in buffer where next samples will be decoded |
125 | int interp_pos; // relative fractional position in sample (0x1000 = 1.0) |
126 | int brr_addr; // address of current BRR block |
127 | int brr_offset; // current decoding offset in BRR block |
128 | uint8_t* regs; // pointer to voice's DSP registers |
129 | int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. |
130 | int kon_delay; // KON delay/current setup phase |
131 | env_mode_t env_mode; |
132 | int env; // current envelope level |
133 | int hidden_env; // used by GAIN mode 7, very obscure quirk |
134 | uint8_t t_envx_out; |
135 | int voice_number; |
136 | }; |
137 | private: |
138 | enum { brr_block_size = 9 }; |
139 | |
140 | Resampler *resampler; |
141 | |
142 | struct state_t |
143 | { |
144 | uint8_t regs [register_count]; |
145 | |
146 | // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) |
147 | int echo_hist [echo_hist_size * 2] [2]; |
148 | int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] |
149 | |
150 | int every_other_sample; // toggles every sample |
151 | int kon; // KON value when last checked |
152 | int noise; |
153 | int counter; |
154 | int echo_offset; // offset from ESA in echo buffer |
155 | int echo_length; // number of bytes that echo_offset will stop at |
156 | int phase; // next clock cycle to run (0-31) |
157 | bool kon_check; // set when a new KON occurs |
158 | |
159 | // Hidden registers also written to when main register is written to |
160 | int new_kon; |
161 | uint8_t endx_buf; |
162 | uint8_t envx_buf; |
163 | uint8_t outx_buf; |
164 | |
165 | // Temporary state between clocks |
166 | |
167 | // read once per sample |
168 | int t_pmon; |
169 | int t_non; |
170 | int t_eon; |
171 | int t_dir; |
172 | int t_koff; |
173 | |
174 | // read a few clocks ahead then used |
175 | int t_brr_next_addr; |
176 | int t_adsr0; |
177 | int ; |
178 | int t_brr_byte; |
179 | int t_srcn; |
180 | int t_esa; |
181 | int t_echo_enabled; |
182 | |
183 | // internal state that is recalculated every sample |
184 | int t_dir_addr; |
185 | int t_pitch; |
186 | int t_output; |
187 | int t_looped; |
188 | int t_echo_ptr; |
189 | |
190 | // left/right sums |
191 | int t_main_out [2]; |
192 | int t_echo_out [2]; |
193 | int t_echo_in [2]; |
194 | |
195 | voice_t voices [voice_count]; |
196 | |
197 | // non-emulation state |
198 | uint8_t* ram; // 64K shared RAM between DSP and SMP |
199 | int mute_mask; |
200 | |
201 | sample_t* out; |
202 | sample_t* out_end; |
203 | sample_t* out_begin; |
204 | sample_t [extra_size]; |
205 | |
206 | uint8_t separate_echo_buffer [0x10000]; |
207 | }; |
208 | state_t m; |
209 | |
210 | void init_counter(); |
211 | void run_counters(); |
212 | unsigned read_counter( int rate ); |
213 | |
214 | int interpolate( voice_t const* v ); |
215 | void run_envelope( voice_t* const v ); |
216 | void decode_brr( voice_t* v ); |
217 | |
218 | void misc_27(); |
219 | void misc_28(); |
220 | void misc_29(); |
221 | void misc_30(); |
222 | |
223 | void voice_output( voice_t const* v, int ch ); |
224 | void voice_V1( voice_t* const ); |
225 | void voice_V2( voice_t* const ); |
226 | void voice_V3( voice_t* const ); |
227 | void voice_V3a( voice_t* const ); |
228 | void voice_V3b( voice_t* const ); |
229 | void voice_V3c( voice_t* const ); |
230 | void voice_V4( voice_t* const ); |
231 | void voice_V5( voice_t* const ); |
232 | void voice_V6( voice_t* const ); |
233 | void voice_V7( voice_t* const ); |
234 | void voice_V8( voice_t* const ); |
235 | void voice_V9( voice_t* const ); |
236 | void voice_V7_V4_V1( voice_t* const ); |
237 | void voice_V8_V5_V2( voice_t* const ); |
238 | void voice_V9_V6_V3( voice_t* const ); |
239 | |
240 | void echo_read( int ch ); |
241 | int echo_output( int ch ); |
242 | void echo_write( int ch ); |
243 | void echo_22(); |
244 | void echo_23(); |
245 | void echo_24(); |
246 | void echo_25(); |
247 | void echo_26(); |
248 | void echo_27(); |
249 | void echo_28(); |
250 | void echo_29(); |
251 | void echo_30(); |
252 | |
253 | void soft_reset_common(); |
254 | }; |
255 | |
256 | #include <assert.h> |
257 | |
258 | inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } |
259 | |
260 | inline int SPC_DSP::read( int addr ) const |
261 | { |
262 | assert( (unsigned) addr < register_count ); |
263 | return m.regs [addr]; |
264 | } |
265 | |
266 | inline void SPC_DSP::write( int addr, int data ) |
267 | { |
268 | assert( (unsigned) addr < register_count ); |
269 | |
270 | m.regs [addr] = (uint8_t) data; |
271 | switch ( addr & 0x0F ) |
272 | { |
273 | case v_envx: |
274 | m.envx_buf = (uint8_t) data; |
275 | break; |
276 | |
277 | case v_outx: |
278 | m.outx_buf = (uint8_t) data; |
279 | break; |
280 | |
281 | case 0x0C: |
282 | if ( addr == r_kon ) |
283 | m.new_kon = (uint8_t) data; |
284 | |
285 | if ( addr == r_endx ) // always cleared, regardless of data written |
286 | { |
287 | m.endx_buf = 0; |
288 | m.regs [r_endx] = 0; |
289 | } |
290 | break; |
291 | } |
292 | } |
293 | |
294 | inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } |
295 | |
296 | inline bool SPC_DSP::check_kon() |
297 | { |
298 | bool old = m.kon_check; |
299 | m.kon_check = 0; |
300 | return old; |
301 | } |
302 | |
303 | #if !SPC_NO_COPY_STATE_FUNCS |
304 | |
305 | class SPC_State_Copier { |
306 | SPC_DSP::copy_func_t func; |
307 | unsigned char** buf; |
308 | public: |
309 | SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } |
310 | void copy( void* state, size_t size ); |
311 | int copy_int( int state, int size ); |
312 | void skip( int count ); |
313 | void (); |
314 | }; |
315 | |
316 | #define SPC_COPY( type, state )\ |
317 | {\ |
318 | state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ |
319 | assert( (BOOST::type) state == state );\ |
320 | } |
321 | |
322 | #endif |
323 | |
324 | #endif |
325 | |