Mercurial > spc_convert
view snes_spc.txt @ 0:e38dacceb958
initial import
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 21 Oct 2011 05:53:11 -0700 |
parents | |
children |
line wrap: on
line source
1 snes_spc 0.9.0: SNES SPC-700 APU Emulator2 -----------------------------------------3 Author : Shay Green <gblargg@gmail.com>4 Website: http://www.slack.net/~ant/5 Forum : http://groups.google.com/group/blargg-sound-libs6 License: GNU Lesser General Public License (LGPL)9 Contents10 --------11 * C and C++ Interfaces12 * Overview13 * Full SPC Emulation14 * DSP Emulation15 * SPC Music Playback16 * State Copying17 * Library Compilation18 * Error handling19 * Solving Problems20 * Accurate S-DSP Limitations21 * Fast S-DSP Limitations22 * S-SMP Limitations23 * To Do24 * Thanks27 C and C++ Interfaces28 --------------------29 The library includes a C interface in spc.h and dsp.h, which can be used30 from C and C++. This C interface is referred to in the following31 documentation. If you're building this as a shared library (rather than32 linking statically), you should use the C interface since it will change33 less in future versions.35 The native C++ interface is in the header files SNES_SPC.h, SPC_DSP.h,36 and SPC_Filter.h, and the two interfaces can be freely mixed in C++37 code. Conversion between the two interfaces generally follows a pattern:39 C interface C++ interface40 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -41 SNES_SPC* spc; SNES_SPC* spc;43 spc = spc_new(); spc = new SNES_SPC;45 spc_play( spc, count, buf ); spc->play( count, buf );47 spc_sample_rate SNES_SPC::sample_rate49 spc_delete( spc ); delete spc;52 Overview53 --------54 There are three main roles for this library:55 * Full SPC emulation in a SNES emulator56 * DSP emulation in a SNES emulator (where you emulate the SMP CPU)57 * SPC playback in an SPC music file player59 Each of these uses are described separately below.62 Full SPC Emulation63 ------------------64 See spc.h for full function reference (SNES_SPC.h if using C++).66 * Create SPC emulator with spc_new() and check for NULL.68 * Call spc_init_rom() with a pointer to the 64-byte IPL ROM dump (not69 included with library).71 * When your emulated SNES is powered on, call spc_reset(). When the72 reset switch is pressed, call spc_soft_reset().74 * Call spc_set_output() with your output buffer, then do emulation.76 * When the SNES CPU accesses APU ports, call spc_read_port() and77 spc_write_port().79 * When your emulator's timebase is going back to 0, call80 spc_end_frame(), usually at the end of a video frame or scanline.82 * Periodically play samples from your buffer. Use spc_sample_count() to83 find out how many samples have been written, then spc_set_output() after84 you've made more space in your buffer.86 * Save/load full emulator state with spc_copy_state().88 * You can save as an SPC music file with spc_save_spc().90 * When done, use spc_delete() to free memory.93 DSP Emulation94 -------------95 See dsp.h for full function reference (SPC_DSP.h if using C++).97 * Create DSP emulator with spc_dsp_new() and check for NULL.99 * Let the DSP know where your 64K RAM is with spc_dsp_init().101 * When your emulated SNES is powered on, call spc_dsp_reset(). When the102 reset switch is pressed, call spc_dsp_soft_reset().104 * Call spc_dsp_set_output() with your output buffer, then do emulation.106 * Use spc_dsp_run() to run DSP for specified number of clocks (1024000107 per second). Every 32 clocks a pair of samples is added to your output108 buffer.110 * Use spc_dsp_read() and spc_dsp_write() to handle DSP reads/writes from111 the S-SMP. Before calling these always catch the DSP up to present time112 with spc_dsp_run().114 * Periodically play samples from your buffer. Use spc_dsp_sample_count()115 to find out how many samples have been written, then116 spc_dsp_set_output() after you've made more space in your buffer.118 * Use spc_dsp_copy_state() to save/load full DSP state.120 * When done, use spc_delete() to free memory.123 SPC Music Playback124 ------------------125 See spc.h for full function reference (SNES_SPC.h if using C++).127 * Create SPC emulator with spc_new() and check for NULL.129 * Load SPC with spc_load_spc() and check for error.131 * Optionally cear echo buffer with spc_clear_echo(). Many SPCs have132 garbage in echo buffer, which causes noise at the beginning.134 * Generate samples as needed with spc_play().136 * When done, use spc_delete() to free memory.138 * For a more complete game music playback library, use Game_Music_Emu141 State Copying142 -------------143 The SPC and DSP modules include state save/load functions. They take a144 pointer to a pointer to a buffer to store state, and a copy function.145 This copy function can either copy data to the buffer or from it,146 allowing state save and restore with the same library function. The147 internal save state format allows for future expansion without making148 previous save states unusable.150 The SPC save state format puts the most important parts first to make it151 easier to manually examine. It's organized as follows:153 Offset Size Data154 - - - - - - - - - - - - - - - - - -155 0 $10000 SPC RAM156 $10000 $10 SMP $F0-$FF registers157 $10010 4 SMP $F4-$F8 output registers158 $10014 2 PC159 $10016 1 A160 $10017 1 X161 $10018 1 Y162 $10019 1 PSW163 $1001A 1 SP164 $1001B 5 internal165 $10020 $80 DSP registers166 $100A0 ... internal169 Library Compilation170 -------------------171 While this library is in C++, it has been written to easily link in a C172 program *without* needing the standard C++ library. It doesn't use173 exception handling or run-time type information (RTTI), so you can174 disable these in your C++ compiler to increase efficiency.176 If you're building a shared library (DLL), I recommend only exporting177 the C interfaces in spc.h and dsp.h, as the C++ interfaces expose178 implementation details that will break link compatibility across179 versions.181 If you're using C and compiling with GCC, I recommend the following182 command-line options when compiling the library source, otherwise GCC183 will insert calls to the standard C++ library and require that it be184 linked in:186 -fno-rtti -fno-exceptions188 For maximum optimization, see the NDEBUG and BLARGG_NONPORTABLE options189 in blargg_config. If using GCC, you can enable these by adding the190 following command-line options when you invoke gcc. If you encounter191 problems, try without -DBLARGG_NONPORTABLE; if that works, contact me so192 I can figure out why BLARGG_NONPORTABLE was causing it to fail.194 -O3 -DNDEBUG -DBLARGG_NONPORTABLE -fno-rtti -fno-exceptions198 Error handling199 --------------200 Functions which can fail have a return type of spc_err_t (blargg_err_t201 in the C++ interfaces), which is a pointer to an error string (const202 char*). If a function is successful it returns NULL. Errors that you can203 easily avoid are checked with debug assertions; spc_err_t return values204 are only used for genuine run-time errors that can't be easily predicted205 in advance (out of memory, I/O errors, incompatible file data). Your206 code should check all error values.208 To improve usability for C programmers, C++ programmers unfamiliar with209 exceptions, and compatibility with older C++ compilers, the library does210 *not* throw any C++ exceptions and uses malloc() instead of the standard211 operator new. This means that you *must* check for NULL when creating a212 library object with the new operator.215 Solving Problems216 ----------------217 If you're having problems, try the following:219 * If you're getting garbled sound, try this simple siren generator in220 place of your call to play(). This will quickly tell whether the problem221 is in the library or in your code.223 static void play_siren( long count, short* out )224 {225 static double a, a2;226 while ( count-- )227 *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) );228 }230 * Enable debugging support in your environment. This enables assertions231 and other run-time checks.233 * Turn the compiler's optimizer is off. Sometimes an optimizer generates234 bad code.236 * If multiple threads are being used, ensure that only one at a time is237 accessing a given set of objects from the library. This library is not238 in general thread-safe, though independent objects can be used in239 separate threads.241 * If all else fails, see if the demos work.244 Accurate S-DSP Limitations245 --------------------------246 * Power-up and soft reset behavior might have slight inaccuracies.248 * Muting (FLG bit 6) behavior when toggling bit very rapidly is not249 emulated properly.251 * No other known inaccuracies. Has passed 100+ strenuous tests.254 Fast S-DSP Limitations255 ----------------------256 * Uses faster sample calculations except in cases where exact value is257 actually important (BRR decoding, and gaussian interpolation combined258 with pitch modulation).260 * Stops decoding BRR data when a voice's envelope has released to261 silence.263 * Emulates 32 clocks at a time, so DSP register and memory accesses are264 all done in a bunch rather than spread out. Even though, some clever265 code makes register accesses separated by 40 or so clocks occur with266 cycle-accurate timing.269 S-SMP Limitations270 -----------------271 * Opcode fetches and indirect pointers are always read directly from272 memory, even for the $F0-$FF region, and the DSP is not caught up for273 these fetches.275 * Attempts to perversely execute data in registers or an area being276 modified by echo will not be emulated properly.278 * Has not been thoroughly tested.280 * Test register ($F0) is not implemented.282 * Echo buffer can overwrite IPL ROM area, and does not correctly update283 extra RAM there.286 To Do287 -----288 * I'd like feedback on the interface and any ways to improve it. In289 particular, the differing features between the accurate and fast DSP290 emulators might make it harder to cleanly switch between them without291 modifying source code.293 * Finish thorough tests on SMP memory access times.295 * Finish thorough tests on SMP instruction behavior (flags, registers).297 * Finish thorough tests on SMP timers.299 * Finish power-up and reset behavior testing.301 * Come up with best starting conditions to play an SPC and implement in302 hardware SNES SPC player for verification.305 Thanks306 ------307 Thanks to Anti-Resonance's SPC2ROM and help getting SPCs playing on my308 SNES in the first place, then Brad Martin's openspc and Chris Moeller's309 openspc++ C++ adaptation, giving me a good SPC emulator to start with310 several years ago. Thanks to Richard Bannister, Mahendra Tallur, Shazz,311 nenolod, theHobbit, Johan Samuelsson, nes6502, and Micket for helping312 test my Game_Music_Emu library. Thanks to hcs for help in converting to313 C for the Rockbox port. Thanks to byuu (bsnes author) and pagefault and314 Nach (zsnes team) for testing and using my new rewritten DSP in their315 emulators. Thanks to anomie for his good SNES documentation and316 discussions with me to keep it up to date with my latest findings.317 --318 Shay Green <gblargg@gmail.com>