rlm@0: /* SNES SPC-700 APU emulator C interface (also usable from C++) */ rlm@0: rlm@0: /* snes_spc 0.9.0 */ rlm@0: #ifndef SPC_H rlm@0: #define SPC_H rlm@0: rlm@0: #include rlm@0: rlm@0: #ifdef __cplusplus rlm@0: extern "C" { rlm@0: #endif rlm@0: rlm@0: /* Error string return. NULL if success, otherwise error message. */ rlm@0: typedef const char* spc_err_t; rlm@0: rlm@0: typedef struct SNES_SPC SNES_SPC; rlm@0: rlm@0: /* Creates new SPC emulator. NULL if out of memory. */ rlm@0: SNES_SPC* spc_new( void ); rlm@0: rlm@0: /* Frees SPC emulator */ rlm@0: void spc_delete( SNES_SPC* ); rlm@0: rlm@0: /* Sample pairs generated per second */ rlm@0: enum { spc_sample_rate = 32000 }; rlm@0: rlm@0: rlm@0: /**** Emulator use ****/ rlm@0: rlm@0: /* Sets IPL ROM data. Library does not include ROM data. Most SPC music files rlm@0: don't need ROM, but a full emulator must provide this. */ rlm@0: enum { spc_rom_size = 0x40 }; rlm@0: void spc_init_rom( SNES_SPC*, unsigned char const rom [spc_rom_size] ); rlm@0: rlm@0: /* Sets destination for output samples */ rlm@0: typedef short spc_sample_t; rlm@0: void spc_set_output( SNES_SPC*, spc_sample_t* out, int out_size ); rlm@0: rlm@0: /* Number of samples written to output since last set */ rlm@0: int spc_sample_count( SNES_SPC const* ); rlm@0: rlm@0: /* Resets SPC to power-on state. This resets your output buffer, so you must rlm@0: call spc_set_output() after this. */ rlm@0: void spc_reset( SNES_SPC* ); rlm@0: rlm@0: /* Emulates pressing reset switch on SNES. This resets your output buffer, so rlm@0: you must call spc_set_output() after this. */ rlm@0: void spc_soft_reset( SNES_SPC* ); rlm@0: rlm@0: /* 1024000 SPC clocks per second, sample pair every 32 clocks */ rlm@0: typedef int spc_time_t; rlm@0: enum { spc_clock_rate = 1024000 }; rlm@0: enum { spc_clocks_per_sample = 32 }; rlm@0: rlm@0: /* Reads/writes port at specified time */ rlm@0: enum { spc_port_count = 4 }; rlm@0: int spc_read_port ( SNES_SPC*, spc_time_t, int port ); rlm@0: void spc_write_port( SNES_SPC*, spc_time_t, int port, int data ); rlm@0: rlm@0: /* Runs SPC to end_time and starts a new time frame at 0 */ rlm@0: void spc_end_frame( SNES_SPC*, spc_time_t end_time ); rlm@0: rlm@0: rlm@0: /**** Sound control ****/ rlm@0: rlm@0: /*Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ rlm@0: enum { spc_voice_count = 8 }; rlm@0: void spc_mute_voices( SNES_SPC*, int mask ); rlm@0: rlm@0: /* If true, prevents channels and global volumes from being phase-negated. rlm@0: Only supported by fast DSP; has no effect on accurate DSP. */ rlm@0: void spc_disable_surround( SNES_SPC*, int disable ); rlm@0: rlm@0: /* Sets tempo, where spc_tempo_unit = normal, spc_tempo_unit / 2 = half speed, etc. */ rlm@0: enum { spc_tempo_unit = 0x100 }; rlm@0: void spc_set_tempo( SNES_SPC*, int ); rlm@0: rlm@0: rlm@0: /**** SPC music playback *****/ rlm@0: rlm@0: /* Loads SPC data into emulator. Returns NULL on success, otherwise error string. */ rlm@0: spc_err_t spc_load_spc( SNES_SPC*, void const* spc_in, long size ); rlm@0: rlm@0: /* Clears echo region. Useful after loading an SPC as many have garbage in echo. */ rlm@0: void spc_clear_echo( SNES_SPC* ); rlm@0: rlm@0: /* Plays for count samples and write samples to out. Discards samples if out rlm@0: is NULL. Count must be a multiple of 2 since output is stereo. */ rlm@0: spc_err_t spc_play( SNES_SPC*, int count, short* out ); rlm@0: rlm@0: /* Skips count samples. Several times faster than spc_play(). */ rlm@0: spc_err_t spc_skip( SNES_SPC*, int count ); rlm@0: rlm@0: rlm@0: /**** State save/load (only available with accurate DSP) ****/ rlm@0: rlm@0: /* Saves/loads exact emulator state */ rlm@0: enum { spc_state_size = 67 * 1024L }; /* maximum space needed when saving */ rlm@0: typedef void (*spc_copy_func_t)( unsigned char** io, void* state, size_t ); rlm@0: void spc_copy_state( SNES_SPC*, unsigned char** io, spc_copy_func_t ); rlm@0: rlm@0: /* Writes minimal SPC file header to spc_out */ rlm@0: void spc_init_header( void* spc_out ); rlm@0: rlm@0: /* Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. rlm@0: Does not set up SPC header; use spc_init_header() for that. */ rlm@0: enum { spc_file_size = 0x10200 }; /* spc_out must have this many bytes allocated */ rlm@0: void spc_save_spc( SNES_SPC*, void* spc_out ); rlm@0: rlm@0: /* Returns non-zero if new key-on events occurred since last check. Useful for rlm@0: trimming silence while saving an SPC. */ rlm@0: int spc_check_kon( SNES_SPC* ); rlm@0: rlm@0: rlm@0: /**** SPC_Filter ****/ rlm@0: rlm@0: typedef struct SPC_Filter SPC_Filter; rlm@0: rlm@0: /* Creates new filter. NULL if out of memory. */ rlm@0: SPC_Filter* spc_filter_new( void ); rlm@0: rlm@0: /* Frees filter */ rlm@0: void spc_filter_delete( SPC_Filter* ); rlm@0: rlm@0: /* Filters count samples of stereo sound in place. Count must be a multiple of 2. */ rlm@0: void spc_filter_run( SPC_Filter*, spc_sample_t* io, int count ); rlm@0: rlm@0: /* Clears filter to silence */ rlm@0: void spc_filter_clear( SPC_Filter* ); rlm@0: rlm@0: /* Sets gain (volume), where spc_filter_gain_unit is normal. Gains greater than rlm@0: spc_filter_gain_unit are fine, since output is clamped to 16-bit sample range. */ rlm@0: enum { spc_filter_gain_unit = 0x100 }; rlm@0: void spc_filter_set_gain( SPC_Filter*, int gain ); rlm@0: rlm@0: /* Sets amount of bass (logarithmic scale) */ rlm@0: enum { spc_filter_bass_none = 0 }; rlm@0: enum { spc_filter_bass_norm = 8 }; /* normal amount */ rlm@0: enum { spc_filter_bass_max = 31 }; rlm@0: void spc_filter_set_bass( SPC_Filter*, int bass ); rlm@0: rlm@0: rlm@0: #ifdef __cplusplus rlm@0: } rlm@0: #endif rlm@0: rlm@0: #endif