Version 1 of my PSX SPU library was complete crap. Sorry.
This version (version 2) has has much improved functionality and has actually been tested a bit. It may actually be useful (gasp!). This doesn't mean to say that there are no bugs or even incorrect parts. If you find a bug or something doesn't work (even after reading the doc's and trying to hack it), or if you fix or improve something yourself, please email it to me so that I can make improvements public.
You are free to modify or hack as you wish, but I absolve myself of all responsibility for any damage that may occur as a result of using the SPU library. If however you manage to produce something cool using the library, then you should be a nice global person and include me in your credits.
Talking about credits, these are due to doomed/padua (docs), dodger/creature (docs + code) and silpheed/hitmen (asm MOD source code + modconv.exe). Their infos (derived from many many hours of PSX hacking no doubt) made my life much easier.
Overview of SPU:
If you haven't got the following docs, then get at least one of
them: doomed/padua's spu doc (1st choice) or dodger's spu doc,
which are both available either from the Hitmen or Napalm sites.
These will tell you very useful detail about the SPU.
Silpheed's "equates.inc" is also a great reference for low-level
stuff.
But if you just want to use my SPU library functions without
bothering too much about low-level stuff, you'll still need to know
basic info about the SPU:
The 512kb sound buffer is accessible only to the SPU, so all sample
data must be transferred thru the SPU. Samples are stored in a
special compressed format of 16-byte blocks.
The first 8208 bytes of the sound buffer are used for processing,
so sample data cannot be stored there. Reverb data also uses some
of the sound buffer memory (usually at the top of the memory).
Each voice has the following parameters:
The SPU output can be adjusted for:
How To Use the SPU (very basic):
See the examples. They might make things a little clearer (or
maybe confuse you more :)
How to Use the Library:
This library is for use with mipsgcc (GCC for mips). I use Rob
Withey's PSX library for PSX initialisation and graphics, so my
examples work best with that.
To compile your proggie to use the library, you will need to
#include "libspu.h" in your proggie, and tell the compiler to link
in the library at "link time", ie: add "libspu.o" to the end of your
compile line. See the example C source and .BAT files.
To use the MODplayer functions, #include "hitmud.h" as well.
Check out the code of the example programs for more detail on how
to use the lib.
Some tools you may need are included in the "tools" directory:
-
*** SPU Control Commands
// Reset the SPU
// Initialise SPU to "sane" values - call this first
// Enable the SPU (turn it on)
// Shut down the SPU (??? - what for?)
// set main SPU output volume (values: 0 -> 0x3fff)
// set SPU output reverb depth (values: 0 -> 0x7fff)
// Switch SPU output reverb on
// Switch SPU output reverb off
// Set CD input Volume (values: 0 -> 0x7fff)
// Set external input Volume (values: 0 -> 0x7fff)
// Wait for SPU to become available (not busy)
// Set SPU Noise Rate (0->63) -
*** SPU Voice Control
// Switch a single voice on (trigger voice, "note on")
// Switch a single voice off ("note off")
// Switch multiple voices ON
// Switch multiple voices OFF
// Set a single voice reverb on (for next note on)
// Set multiple voices reverb on (for next note on)
// Set Voice n Volume (values: 0 -> 0x3fff)
// Set Voice n Pitch
// Set Voice n ADSR
// Set Voice n ADSR (raw)
// Set Voice n Repeat Addr
// Get Voice n current ADSR Volume
// Set Voice n wave data offset
// Switch a single voice to Noise mode
// Switch multiple voices to Noise mode
// Switch a single voice to FM mode
// Switch multiple voices to FM -
*** SPU Data Transfer Functions
// Transfer wavetable (sample) data from main memory to sound buffer
// Load Reverb data (reverb "patch") into reverb area -
*** MOD Functions
// initialise HITMOD structure
Another useful tool is Silpheed's MODCONV.EXE, which converts
Protracker MOD files to HIT files.
Jum's SPU Library Reference:
(check against header file libspu.h if you have funnies)
void SPU_Reset(void);
void SPU_Init(void);
void SPU_Enable(void);
void SPU_Quit(void);
void SPU_Volume(PsxUInt16 vol_left, PsxUInt16 vol_right);
// (larger value = deeper, heavier reverb)
void SPU_ReverbDepth(PsxUInt16 left, PsxUInt16 right);
void SPU_ReverbOn(void);
void SPU_ReverbOff(void);
void SPU_CDVol(PsxUInt16 vol_left, PsxUInt16 vol_right);
void SPU_ExternVol(PsxUInt16 vol_left, PsxUInt16 vol_right);
int SPU_Wait(void);
// (frequency of noise when a channel is switched to noise)
void SPU_SetNoiseRate(PsxUInt8 rate);
void SPU_VoiceOn(PsxUInt8 voice);
void SPU_VoiceOff(PsxUInt8 voice);
// (mask is a bitmask, lower 24 bits relevant, lowest bit = voice 0)
// (eg: to switch voices 0, 4 and 7 on, calculate mask = 000000000000000010010001 = 145)
void SPU_VoiceMaskOn(PsxUInt32 mask);
// (using a mask same as above)
void SPU_VoiceMaskOff(PsxUInt32 mask);
// (NB: reverb for this voice is turned off when
// the sample finishes playing)
void SPU_VoiceReverb(PsxUInt8 voice);
// (using a mask as described above)
// NB: switches off after sample finished
void SPU_VoiceReverbMask(PsxUInt32 mask);
void SPU_VoiceVol(PsxUInt8 voice, PsxUInt16 vol_left, PsxUInt16 vol_right);
// (value 0x1000 corresponds to original sample frequency if sampled at 44.1 kHz)
// (value 0x400 corresponds to original sample frequency if sampled at 11.025 kHz)
void SPU_VoicePitch(PsxUInt8 voice, PsxUInt16 pitch);
// NB: linear only at this stage
// (values: 0 < ar < 127 ; 0 < dr < 15 ; 0 < sl < 15 ; 0 < sr < 127 ; 0 < rr < 31 )
void SPU_VoiceADSR(PsxUInt8 voice, PsxUInt8 ar, PsxUInt8 dr, PsxUInt8 sl,
PsxUInt16 sr, PsxUInt8 rr);
// (useful if you know how PSX SPU ADSR works,
// or if you can get the ADSR values somewhere else :)
void SPU_VoiceADSRRaw(PsxUInt8 voice, PsxUInt16 adsr1, PsxUInt16 adsr2);
// (loop start address, set only after sample has started playing)
void SPU_VoiceRepeatAddress(PsxUInt8 voice, PsxUInt16 rep_addr);
// (returns values 0 -> 0xffff) (???)
PsxUInt16 SPU_GetADSRVol(PsxUInt8 voice);
// Specify the start address of the sample for this voice in the SPU sound buffer
void SPU_VoiceSetData(PsxUInt8 voice, PsxUInt32 sb_addr);
void SPU_Voice2Noise(PsxUInt8 voice);
void SPU_Voice2NoiseMask(PsxUInt32 mask);
// (the voice is FM modulated with the previous voice)
void SPU_Voice2FM(PsxUInt8 voice);
void SPU_Voice2FMMask(PsxUInt32 mask);
// (sample data must be in VAG-packed format)
// (sb_addr = destination address in SPU RAM for MOD samples)
void SPU_UploadData(PsxUInt32 *src_addr, PsxUInt32 sb_addr, PsxUInt32 size);
// and set start addr of reverb process buffer in sound buffer
void SPU_LoadReverb(PsxUInt16 *data, PsxUInt16 work_addr);
// (uploads MOD samples, sets up MOD for playing)
// (sb_addr = destination address in SPU RAM for MOD samples)
void InitMOD(HITMUD *m, PsxUInt8 *modaddr, PsxUInt32 sb_addr);