annotate snes_spc.txt @ 9:477c36226481 tip

added old scripts for historical interest.
author Robert McIntyre <rlm@mit.edu>
date Fri, 21 Oct 2011 07:46:18 -0700
parents e38dacceb958
children
rev   line source
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>