PS2 Linux Programming
Audio Application Framework
Introduction
The PlayStation2 contains two sound processing units (SPU) providing a total of 48 polyphonic voices and 2MB of sound memory. Unfortunately, under PS2 Linux most of these resources are not available. PS2 Linux provides access to the sound hardware through a generic Linux soundcard driver which is programmed using the Linux Open Sound System API – see OpenSound. The author would welcome any information on using the SPUs under PS2 Linux in a more effective and realistic manner. Access to the SPU in a native manner would be most advantageous and any information on doing this would be welcome.
Background
Using the soundcard driver it is possible to stream digital audio data into each of the sound processors – see the tutorial on “Using Audio Under PS2 Linux”. This provides two channels, one of which can be used to play music whilst the other plays sound effects. This provides basic sound capability but it adequate for some simple game applications.
All of the sound data must be stored in main memory (not sound memory) and streamed to the SPU by the main CPU. It should be noted that this scheme can have an adverse effect on the performance of an application and as such efforts should be made to minimise the size of the sound samples used.
Two classes are used to manage the sound system. The first one is a class which is associated with the SPU.
class AudioDevice
{
public:
AudioDevice(const int Which);
~AudioDevice();
int Open(const int which);
void Close(void);
void HandleAudio(void);
void SetSoundSample(SoundSample * const Sample);
int GetFragmentSize(void) const;
protected:
int GetFreeFragments(void) const;
SoundSample * m_Current;
int m_AudioFD;
int m_FragmentSize;
unsigned char * m_Silence;
};
This class contains methods to open and close the sound processor, to specify the particular sound sample that is to be currently played and to handle the streaming of the digital audio data to the SPU.
The second class is associated with the sampled sound data to be played.
class SoundSample
{
public:
SoundSample(char * Filename, AudioDevice * const pAD);
~SoundSample();
void Load(char * Filename);
void Reset();
void Play(void);
unsigned char * GetNextFragment();
protected:
AudioDevice * m_pAD;
unsigned char * m_Stream;
long m_Location;
int m_FragSize;
long m_NumFragments;
char m_SampleName[32];
};
Each sound sample has an instance of this class associated with it. The class associates a particular sound sample with one of the Sound Processor units for streaming. The class also has methods to load a sound sample from disk into main memory and to control the playing of the sample.
The Example Code
Use of the audio framework is illustrated with some simple code that plays four different sounds, a frog croak, a shotgun, a machine gun and a rather strange “EEK” noise. The sounds are played by pressing the square, cross, triangle or circle on the controller pad 0. The main program code is repeated below for clarity.
int main(void)
{
AudioDevice DSP0(0), DSP1(1);
SoundSample Gun("auto", &DSP0);
SoundSample Eep("eep", &DSP0);
SoundSample Shotgun("shotgun", &DSP1);
SoundSample Croak("croak", &DSP1);
// Initialise control pad 0
if(!pad_init(PAD_0, PAD_INIT_LOCK | PAD_INIT_ANALOGUE | PAD_INIT_PRESSURE))
{
printf("Failed to initialise control pad\n");
pad_cleanup(PAD_0);
exit(0);
}
while(1)
{
pad_update(PAD_0);
if(pad[0].pressed & PAD_CROSS) Gun.Play();
if(pad[0].pressed & PAD_SQUARE) Shotgun.Play();
if(pad[0].pressed & PAD_TRI) Croak.Play();
if(pad[0].pressed & PAD_CIRCLE) Eep.Play();
DSP0.HandleAudio();
DSP1.HandleAudio();
// Check for exit condition
if((pad[0].buttons & PAD_START)&&(pad[0].buttons & PAD_SELECT)) break;
}
DSP0.Close();
DSP1.Close();
pad_cleanup(PAD_0);
}
Firstly the SPU audio devices are opened for use the each of the sound samples are loaded into main memory and associated with a particular SPU for playback. In the main game loop it can be seen that each sound effect is played with it’s associated SoundSample::Play() method. Within the game loop, the method AudioDevice::HandleAudio() is executed for each open SPU and this controls the streaming of the digital audio data to the SPU. At the end of the program the audio devices are closed with the method AudioDevice::Close(),
In this tutorial, a simple framework has been provided to stream digital audio to SPU devices to facilitate simple audio playback for use within games applications.
(The author would welcome any information on using the SPUs under PS2 Linux in a more effective and realistic manner. Access to the SPU in a native manner would be most advantageous.)
Dr Henry S Fortuna
University of Abertay Dundee