rlm@0
|
1 snes_spc 0.9.0: SNES SPC-700 APU Emulator
|
rlm@0
|
2 -----------------------------------------
|
rlm@0
|
3 Author : Shay Green <gblargg@gmail.com>
|
rlm@0
|
4 Website: http://www.slack.net/~ant/
|
rlm@0
|
5 Forum : http://groups.google.com/group/blargg-sound-libs
|
rlm@0
|
6 License: GNU Lesser General Public License (LGPL)
|
rlm@0
|
7
|
rlm@0
|
8
|
rlm@0
|
9 Contents
|
rlm@0
|
10 --------
|
rlm@0
|
11 * C and C++ Interfaces
|
rlm@0
|
12 * Overview
|
rlm@0
|
13 * Full SPC Emulation
|
rlm@0
|
14 * DSP Emulation
|
rlm@0
|
15 * SPC Music Playback
|
rlm@0
|
16 * State Copying
|
rlm@0
|
17 * Library Compilation
|
rlm@0
|
18 * Error handling
|
rlm@0
|
19 * Solving Problems
|
rlm@0
|
20 * Accurate S-DSP Limitations
|
rlm@0
|
21 * Fast S-DSP Limitations
|
rlm@0
|
22 * S-SMP Limitations
|
rlm@0
|
23 * To Do
|
rlm@0
|
24 * Thanks
|
rlm@0
|
25
|
rlm@0
|
26
|
rlm@0
|
27 C and C++ Interfaces
|
rlm@0
|
28 --------------------
|
rlm@0
|
29 The library includes a C interface in spc.h and dsp.h, which can be used
|
rlm@0
|
30 from C and C++. This C interface is referred to in the following
|
rlm@0
|
31 documentation. If you're building this as a shared library (rather than
|
rlm@0
|
32 linking statically), you should use the C interface since it will change
|
rlm@0
|
33 less in future versions.
|
rlm@0
|
34
|
rlm@0
|
35 The native C++ interface is in the header files SNES_SPC.h, SPC_DSP.h,
|
rlm@0
|
36 and SPC_Filter.h, and the two interfaces can be freely mixed in C++
|
rlm@0
|
37 code. Conversion between the two interfaces generally follows a pattern:
|
rlm@0
|
38
|
rlm@0
|
39 C interface C++ interface
|
rlm@0
|
40 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
rlm@0
|
41 SNES_SPC* spc; SNES_SPC* spc;
|
rlm@0
|
42
|
rlm@0
|
43 spc = spc_new(); spc = new SNES_SPC;
|
rlm@0
|
44
|
rlm@0
|
45 spc_play( spc, count, buf ); spc->play( count, buf );
|
rlm@0
|
46
|
rlm@0
|
47 spc_sample_rate SNES_SPC::sample_rate
|
rlm@0
|
48
|
rlm@0
|
49 spc_delete( spc ); delete spc;
|
rlm@0
|
50
|
rlm@0
|
51
|
rlm@0
|
52 Overview
|
rlm@0
|
53 --------
|
rlm@0
|
54 There are three main roles for this library:
|
rlm@0
|
55 * Full SPC emulation in a SNES emulator
|
rlm@0
|
56 * DSP emulation in a SNES emulator (where you emulate the SMP CPU)
|
rlm@0
|
57 * SPC playback in an SPC music file player
|
rlm@0
|
58
|
rlm@0
|
59 Each of these uses are described separately below.
|
rlm@0
|
60
|
rlm@0
|
61
|
rlm@0
|
62 Full SPC Emulation
|
rlm@0
|
63 ------------------
|
rlm@0
|
64 See spc.h for full function reference (SNES_SPC.h if using C++).
|
rlm@0
|
65
|
rlm@0
|
66 * Create SPC emulator with spc_new() and check for NULL.
|
rlm@0
|
67
|
rlm@0
|
68 * Call spc_init_rom() with a pointer to the 64-byte IPL ROM dump (not
|
rlm@0
|
69 included with library).
|
rlm@0
|
70
|
rlm@0
|
71 * When your emulated SNES is powered on, call spc_reset(). When the
|
rlm@0
|
72 reset switch is pressed, call spc_soft_reset().
|
rlm@0
|
73
|
rlm@0
|
74 * Call spc_set_output() with your output buffer, then do emulation.
|
rlm@0
|
75
|
rlm@0
|
76 * When the SNES CPU accesses APU ports, call spc_read_port() and
|
rlm@0
|
77 spc_write_port().
|
rlm@0
|
78
|
rlm@0
|
79 * When your emulator's timebase is going back to 0, call
|
rlm@0
|
80 spc_end_frame(), usually at the end of a video frame or scanline.
|
rlm@0
|
81
|
rlm@0
|
82 * Periodically play samples from your buffer. Use spc_sample_count() to
|
rlm@0
|
83 find out how many samples have been written, then spc_set_output() after
|
rlm@0
|
84 you've made more space in your buffer.
|
rlm@0
|
85
|
rlm@0
|
86 * Save/load full emulator state with spc_copy_state().
|
rlm@0
|
87
|
rlm@0
|
88 * You can save as an SPC music file with spc_save_spc().
|
rlm@0
|
89
|
rlm@0
|
90 * When done, use spc_delete() to free memory.
|
rlm@0
|
91
|
rlm@0
|
92
|
rlm@0
|
93 DSP Emulation
|
rlm@0
|
94 -------------
|
rlm@0
|
95 See dsp.h for full function reference (SPC_DSP.h if using C++).
|
rlm@0
|
96
|
rlm@0
|
97 * Create DSP emulator with spc_dsp_new() and check for NULL.
|
rlm@0
|
98
|
rlm@0
|
99 * Let the DSP know where your 64K RAM is with spc_dsp_init().
|
rlm@0
|
100
|
rlm@0
|
101 * When your emulated SNES is powered on, call spc_dsp_reset(). When the
|
rlm@0
|
102 reset switch is pressed, call spc_dsp_soft_reset().
|
rlm@0
|
103
|
rlm@0
|
104 * Call spc_dsp_set_output() with your output buffer, then do emulation.
|
rlm@0
|
105
|
rlm@0
|
106 * Use spc_dsp_run() to run DSP for specified number of clocks (1024000
|
rlm@0
|
107 per second). Every 32 clocks a pair of samples is added to your output
|
rlm@0
|
108 buffer.
|
rlm@0
|
109
|
rlm@0
|
110 * Use spc_dsp_read() and spc_dsp_write() to handle DSP reads/writes from
|
rlm@0
|
111 the S-SMP. Before calling these always catch the DSP up to present time
|
rlm@0
|
112 with spc_dsp_run().
|
rlm@0
|
113
|
rlm@0
|
114 * Periodically play samples from your buffer. Use spc_dsp_sample_count()
|
rlm@0
|
115 to find out how many samples have been written, then
|
rlm@0
|
116 spc_dsp_set_output() after you've made more space in your buffer.
|
rlm@0
|
117
|
rlm@0
|
118 * Use spc_dsp_copy_state() to save/load full DSP state.
|
rlm@0
|
119
|
rlm@0
|
120 * When done, use spc_delete() to free memory.
|
rlm@0
|
121
|
rlm@0
|
122
|
rlm@0
|
123 SPC Music Playback
|
rlm@0
|
124 ------------------
|
rlm@0
|
125 See spc.h for full function reference (SNES_SPC.h if using C++).
|
rlm@0
|
126
|
rlm@0
|
127 * Create SPC emulator with spc_new() and check for NULL.
|
rlm@0
|
128
|
rlm@0
|
129 * Load SPC with spc_load_spc() and check for error.
|
rlm@0
|
130
|
rlm@0
|
131 * Optionally cear echo buffer with spc_clear_echo(). Many SPCs have
|
rlm@0
|
132 garbage in echo buffer, which causes noise at the beginning.
|
rlm@0
|
133
|
rlm@0
|
134 * Generate samples as needed with spc_play().
|
rlm@0
|
135
|
rlm@0
|
136 * When done, use spc_delete() to free memory.
|
rlm@0
|
137
|
rlm@0
|
138 * For a more complete game music playback library, use Game_Music_Emu
|
rlm@0
|
139
|
rlm@0
|
140
|
rlm@0
|
141 State Copying
|
rlm@0
|
142 -------------
|
rlm@0
|
143 The SPC and DSP modules include state save/load functions. They take a
|
rlm@0
|
144 pointer to a pointer to a buffer to store state, and a copy function.
|
rlm@0
|
145 This copy function can either copy data to the buffer or from it,
|
rlm@0
|
146 allowing state save and restore with the same library function. The
|
rlm@0
|
147 internal save state format allows for future expansion without making
|
rlm@0
|
148 previous save states unusable.
|
rlm@0
|
149
|
rlm@0
|
150 The SPC save state format puts the most important parts first to make it
|
rlm@0
|
151 easier to manually examine. It's organized as follows:
|
rlm@0
|
152
|
rlm@0
|
153 Offset Size Data
|
rlm@0
|
154 - - - - - - - - - - - - - - - - - -
|
rlm@0
|
155 0 $10000 SPC RAM
|
rlm@0
|
156 $10000 $10 SMP $F0-$FF registers
|
rlm@0
|
157 $10010 4 SMP $F4-$F8 output registers
|
rlm@0
|
158 $10014 2 PC
|
rlm@0
|
159 $10016 1 A
|
rlm@0
|
160 $10017 1 X
|
rlm@0
|
161 $10018 1 Y
|
rlm@0
|
162 $10019 1 PSW
|
rlm@0
|
163 $1001A 1 SP
|
rlm@0
|
164 $1001B 5 internal
|
rlm@0
|
165 $10020 $80 DSP registers
|
rlm@0
|
166 $100A0 ... internal
|
rlm@0
|
167
|
rlm@0
|
168
|
rlm@0
|
169 Library Compilation
|
rlm@0
|
170 -------------------
|
rlm@0
|
171 While this library is in C++, it has been written to easily link in a C
|
rlm@0
|
172 program *without* needing the standard C++ library. It doesn't use
|
rlm@0
|
173 exception handling or run-time type information (RTTI), so you can
|
rlm@0
|
174 disable these in your C++ compiler to increase efficiency.
|
rlm@0
|
175
|
rlm@0
|
176 If you're building a shared library (DLL), I recommend only exporting
|
rlm@0
|
177 the C interfaces in spc.h and dsp.h, as the C++ interfaces expose
|
rlm@0
|
178 implementation details that will break link compatibility across
|
rlm@0
|
179 versions.
|
rlm@0
|
180
|
rlm@0
|
181 If you're using C and compiling with GCC, I recommend the following
|
rlm@0
|
182 command-line options when compiling the library source, otherwise GCC
|
rlm@0
|
183 will insert calls to the standard C++ library and require that it be
|
rlm@0
|
184 linked in:
|
rlm@0
|
185
|
rlm@0
|
186 -fno-rtti -fno-exceptions
|
rlm@0
|
187
|
rlm@0
|
188 For maximum optimization, see the NDEBUG and BLARGG_NONPORTABLE options
|
rlm@0
|
189 in blargg_config. If using GCC, you can enable these by adding the
|
rlm@0
|
190 following command-line options when you invoke gcc. If you encounter
|
rlm@0
|
191 problems, try without -DBLARGG_NONPORTABLE; if that works, contact me so
|
rlm@0
|
192 I can figure out why BLARGG_NONPORTABLE was causing it to fail.
|
rlm@0
|
193
|
rlm@0
|
194 -O3 -DNDEBUG -DBLARGG_NONPORTABLE -fno-rtti -fno-exceptions
|
rlm@0
|
195
|
rlm@0
|
196
|
rlm@0
|
197
|
rlm@0
|
198 Error handling
|
rlm@0
|
199 --------------
|
rlm@0
|
200 Functions which can fail have a return type of spc_err_t (blargg_err_t
|
rlm@0
|
201 in the C++ interfaces), which is a pointer to an error string (const
|
rlm@0
|
202 char*). If a function is successful it returns NULL. Errors that you can
|
rlm@0
|
203 easily avoid are checked with debug assertions; spc_err_t return values
|
rlm@0
|
204 are only used for genuine run-time errors that can't be easily predicted
|
rlm@0
|
205 in advance (out of memory, I/O errors, incompatible file data). Your
|
rlm@0
|
206 code should check all error values.
|
rlm@0
|
207
|
rlm@0
|
208 To improve usability for C programmers, C++ programmers unfamiliar with
|
rlm@0
|
209 exceptions, and compatibility with older C++ compilers, the library does
|
rlm@0
|
210 *not* throw any C++ exceptions and uses malloc() instead of the standard
|
rlm@0
|
211 operator new. This means that you *must* check for NULL when creating a
|
rlm@0
|
212 library object with the new operator.
|
rlm@0
|
213
|
rlm@0
|
214
|
rlm@0
|
215 Solving Problems
|
rlm@0
|
216 ----------------
|
rlm@0
|
217 If you're having problems, try the following:
|
rlm@0
|
218
|
rlm@0
|
219 * If you're getting garbled sound, try this simple siren generator in
|
rlm@0
|
220 place of your call to play(). This will quickly tell whether the problem
|
rlm@0
|
221 is in the library or in your code.
|
rlm@0
|
222
|
rlm@0
|
223 static void play_siren( long count, short* out )
|
rlm@0
|
224 {
|
rlm@0
|
225 static double a, a2;
|
rlm@0
|
226 while ( count-- )
|
rlm@0
|
227 *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) );
|
rlm@0
|
228 }
|
rlm@0
|
229
|
rlm@0
|
230 * Enable debugging support in your environment. This enables assertions
|
rlm@0
|
231 and other run-time checks.
|
rlm@0
|
232
|
rlm@0
|
233 * Turn the compiler's optimizer is off. Sometimes an optimizer generates
|
rlm@0
|
234 bad code.
|
rlm@0
|
235
|
rlm@0
|
236 * If multiple threads are being used, ensure that only one at a time is
|
rlm@0
|
237 accessing a given set of objects from the library. This library is not
|
rlm@0
|
238 in general thread-safe, though independent objects can be used in
|
rlm@0
|
239 separate threads.
|
rlm@0
|
240
|
rlm@0
|
241 * If all else fails, see if the demos work.
|
rlm@0
|
242
|
rlm@0
|
243
|
rlm@0
|
244 Accurate S-DSP Limitations
|
rlm@0
|
245 --------------------------
|
rlm@0
|
246 * Power-up and soft reset behavior might have slight inaccuracies.
|
rlm@0
|
247
|
rlm@0
|
248 * Muting (FLG bit 6) behavior when toggling bit very rapidly is not
|
rlm@0
|
249 emulated properly.
|
rlm@0
|
250
|
rlm@0
|
251 * No other known inaccuracies. Has passed 100+ strenuous tests.
|
rlm@0
|
252
|
rlm@0
|
253
|
rlm@0
|
254 Fast S-DSP Limitations
|
rlm@0
|
255 ----------------------
|
rlm@0
|
256 * Uses faster sample calculations except in cases where exact value is
|
rlm@0
|
257 actually important (BRR decoding, and gaussian interpolation combined
|
rlm@0
|
258 with pitch modulation).
|
rlm@0
|
259
|
rlm@0
|
260 * Stops decoding BRR data when a voice's envelope has released to
|
rlm@0
|
261 silence.
|
rlm@0
|
262
|
rlm@0
|
263 * Emulates 32 clocks at a time, so DSP register and memory accesses are
|
rlm@0
|
264 all done in a bunch rather than spread out. Even though, some clever
|
rlm@0
|
265 code makes register accesses separated by 40 or so clocks occur with
|
rlm@0
|
266 cycle-accurate timing.
|
rlm@0
|
267
|
rlm@0
|
268
|
rlm@0
|
269 S-SMP Limitations
|
rlm@0
|
270 -----------------
|
rlm@0
|
271 * Opcode fetches and indirect pointers are always read directly from
|
rlm@0
|
272 memory, even for the $F0-$FF region, and the DSP is not caught up for
|
rlm@0
|
273 these fetches.
|
rlm@0
|
274
|
rlm@0
|
275 * Attempts to perversely execute data in registers or an area being
|
rlm@0
|
276 modified by echo will not be emulated properly.
|
rlm@0
|
277
|
rlm@0
|
278 * Has not been thoroughly tested.
|
rlm@0
|
279
|
rlm@0
|
280 * Test register ($F0) is not implemented.
|
rlm@0
|
281
|
rlm@0
|
282 * Echo buffer can overwrite IPL ROM area, and does not correctly update
|
rlm@0
|
283 extra RAM there.
|
rlm@0
|
284
|
rlm@0
|
285
|
rlm@0
|
286 To Do
|
rlm@0
|
287 -----
|
rlm@0
|
288 * I'd like feedback on the interface and any ways to improve it. In
|
rlm@0
|
289 particular, the differing features between the accurate and fast DSP
|
rlm@0
|
290 emulators might make it harder to cleanly switch between them without
|
rlm@0
|
291 modifying source code.
|
rlm@0
|
292
|
rlm@0
|
293 * Finish thorough tests on SMP memory access times.
|
rlm@0
|
294
|
rlm@0
|
295 * Finish thorough tests on SMP instruction behavior (flags, registers).
|
rlm@0
|
296
|
rlm@0
|
297 * Finish thorough tests on SMP timers.
|
rlm@0
|
298
|
rlm@0
|
299 * Finish power-up and reset behavior testing.
|
rlm@0
|
300
|
rlm@0
|
301 * Come up with best starting conditions to play an SPC and implement in
|
rlm@0
|
302 hardware SNES SPC player for verification.
|
rlm@0
|
303
|
rlm@0
|
304
|
rlm@0
|
305 Thanks
|
rlm@0
|
306 ------
|
rlm@0
|
307 Thanks to Anti-Resonance's SPC2ROM and help getting SPCs playing on my
|
rlm@0
|
308 SNES in the first place, then Brad Martin's openspc and Chris Moeller's
|
rlm@0
|
309 openspc++ C++ adaptation, giving me a good SPC emulator to start with
|
rlm@0
|
310 several years ago. Thanks to Richard Bannister, Mahendra Tallur, Shazz,
|
rlm@0
|
311 nenolod, theHobbit, Johan Samuelsson, nes6502, and Micket for helping
|
rlm@0
|
312 test my Game_Music_Emu library. Thanks to hcs for help in converting to
|
rlm@0
|
313 C for the Rockbox port. Thanks to byuu (bsnes author) and pagefault and
|
rlm@0
|
314 Nach (zsnes team) for testing and using my new rewritten DSP in their
|
rlm@0
|
315 emulators. Thanks to anomie for his good SNES documentation and
|
rlm@0
|
316 discussions with me to keep it up to date with my latest findings.
|
rlm@0
|
317 --
|
rlm@0
|
318 Shay Green <gblargg@gmail.com>
|