James' PSX SPU lib ver2

This doc updated April 23 2000
  1. Intro
  2. Overview of PSX SPU
  3. How to Use the SPU
  4. How to Use the Library
  5. Library reference - SPU Control
  6. SPU Library reference - Voice Control
  7. SPU Library reference - Data Transfer Functions
  8. SPU Library reference - MOD Functions
  9. Revision History
Intro:

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):

  1. Initialise SPU
  2. Upload reverb data & set up reverb (not absolutely neccessary)
  3. Upload sample data to sound buffer
  4. Set SPU output parameters
  5. Set voice parameters for the voices you want to use
  6. Send the voices "note on" signals

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:

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)

*** SPU Control Commands

// Reset the SPU
void SPU_Reset(void);

// Initialise SPU to "sane" values - call this first
void SPU_Init(void);

// Enable the SPU (turn it on)
void SPU_Enable(void);

// Shut down the SPU (??? - what for?)
void SPU_Quit(void);

// set main SPU output volume (values: 0 -> 0x3fff)
void SPU_Volume(PsxUInt16 vol_left, PsxUInt16 vol_right);

// set SPU output reverb depth (values: 0 -> 0x7fff)
// (larger value = deeper, heavier reverb)
void SPU_ReverbDepth(PsxUInt16 left, PsxUInt16 right);

// Switch SPU output reverb on
void SPU_ReverbOn(void);

// Switch SPU output reverb off
void SPU_ReverbOff(void);

// Set CD input Volume (values: 0 -> 0x7fff)
void SPU_CDVol(PsxUInt16 vol_left, PsxUInt16 vol_right);

// Set external input Volume (values: 0 -> 0x7fff)
void SPU_ExternVol(PsxUInt16 vol_left, PsxUInt16 vol_right);

// Wait for SPU to become available (not busy)
int SPU_Wait(void);

// Set SPU Noise Rate (0->63)
// (frequency of noise when a channel is switched to noise)
void SPU_SetNoiseRate(PsxUInt8 rate);

-

*** SPU Voice Control

// Switch a single voice on (trigger voice, "note on")
void SPU_VoiceOn(PsxUInt8 voice);

// Switch a single voice off ("note off")
void SPU_VoiceOff(PsxUInt8 voice);

// Switch multiple voices ON
// (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);

// Switch multiple voices OFF
// (using a mask same as above)
void SPU_VoiceMaskOff(PsxUInt32 mask);

// Set a single voice reverb on (for next note on)
// (NB: reverb for this voice is turned off when
// the sample finishes playing)
void SPU_VoiceReverb(PsxUInt8 voice);

// Set multiple voices reverb on (for next note on)
// (using a mask as described above)
// NB: switches off after sample finished
void SPU_VoiceReverbMask(PsxUInt32 mask);

// Set Voice n Volume (values: 0 -> 0x3fff)
void SPU_VoiceVol(PsxUInt8 voice, PsxUInt16 vol_left, PsxUInt16 vol_right);

// Set Voice n Pitch
// (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);

// Set Voice n ADSR
// 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);

// Set Voice n ADSR (raw)
// (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);

// Set Voice n Repeat Addr
// (loop start address, set only after sample has started playing)
void SPU_VoiceRepeatAddress(PsxUInt8 voice, PsxUInt16 rep_addr);

// Get Voice n current ADSR Volume
// (returns values 0 -> 0xffff) (???) PsxUInt16 SPU_GetADSRVol(PsxUInt8 voice);

// Set Voice n wave data offset
// Specify the start address of the sample for this voice in the SPU sound buffer
void SPU_VoiceSetData(PsxUInt8 voice, PsxUInt32 sb_addr);

// Switch a single voice to Noise mode
void SPU_Voice2Noise(PsxUInt8 voice);

// Switch multiple voices to Noise mode
void SPU_Voice2NoiseMask(PsxUInt32 mask);

// Switch a single voice to FM mode
// (the voice is FM modulated with the previous voice)
void SPU_Voice2FM(PsxUInt8 voice);

// Switch multiple voices to FM
void SPU_Voice2FMMask(PsxUInt32 mask);

-

*** SPU Data Transfer Functions

// Transfer wavetable (sample) data from main memory to sound buffer
// (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);

// Load Reverb data (reverb "patch") into reverb area
// and set start addr of reverb process buffer in sound buffer
void SPU_LoadReverb(PsxUInt16 *data, PsxUInt16 work_addr);

-

*** MOD Functions

// initialise HITMOD structure
// (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);

// Play next row of mod
// (call every vblank or via timer 50/60 fps)
int PollMOD(HITMUD *m);

In addition to these functions, the MOD struct can be accessed directly for various tasks.

-

Revision History