Code: Select all
#define kAuFramesPerOutputCall (2048)
#define kAuBytesPerOutputCall (kAuFramesPerOutputCall * 4)
int gAuMusicChannel;
int volatile gAuMusicVolume;
SceUID gAuMusicThreadID;
SceBool volatile gAuMusicThreadShouldExit;
SceBool volatile gAuMusicThreadShouldPause;
SceBool volatile gAuMusicThreadIsSleeping;
AuMusic volatile gAuCurrentMusic;
Code: Select all
AuErr AuInitializeMusic()
{
// Reserve hardware channel.
gAuMusicChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL,
kAuFramesPerOutputCall,
PSP_AUDIO_FORMAT_STEREO);
if (gAuMusicChannel < 0)
return kAuErrNoMoreChannels;
gAuMusicVolume = kAuMaximumVolume;
// Start rendering thread.
gAuMusicThreadID = sceKernelCreateThread("Music",
AuMusicRenderingThread,
16,
65536,
0,
NULL);
gAuMusicThreadShouldExit = NO;
gAuMusicThreadShouldPause = NO;
gAuCurrentMusic = NULL;
sceKernelStartThread(gAuMusicThreadID, 0, NULL);
return kAuErrNone;
}
Code: Select all
int AuMusicRenderingThread(SceSize unused1, void *unused2)
{
void *buffer1;
void *buffer2;
void *buffer;
// Allocate rendering buffers.
buffer1 = malloc(kAuBytesPerOutputCall);
buffer2 = malloc(kAuBytesPerOutputCall);
if (! (buffer1 && buffer2))
{
if (buffer1) free(buffer1);
if (buffer2) free(buffer2);
sceKernelExitThread(kAuErrMemory);
return kAuErrMemory;
}
buffer1 = mCachelessPointer(buffer1);
buffer2 = mCachelessPointer(buffer2);
buffer = buffer1;
// Go to sleep and wait for a wakeup call when music needs to be played.
gAuMusicThreadIsSleeping = YES;
sceKernelSleepThread();
gAuMusicThreadIsSleeping = NO;
// Rendering loop.
for (;;)
{
// Check for messages from the main thread.
if (gAuMusicThreadShouldPause)
{
gAuMusicThreadIsSleeping = YES;
sceKernelSleepThread();
gAuMusicThreadIsSleeping = NO;
}
if (gAuMusicThreadShouldExit) break;
// Make sure some music has been set.
if (! gAuCurrentMusic)
{
gAuMusicThreadShouldPause = YES;
continue;
}
// Render music.
long bytesSoFar = 0;
int unused;
while (bytesSoFar < kAuBytesPerOutputCall)
{
long bytes = ov_read(&gAuCurrentMusic->vorbis,
(void *) ((unsigned) buffer + bytesSoFar),
kAuBytesPerOutputCall - bytesSoFar,
&unused);
if (bytes == 0)
{
ov_time_seek(&gAuCurrentMusic->vorbis, gAuCurrentMusic->loopPoint);
continue;
}
if (bytes < 0)
{
gAuCurrentMusic = NULL;
break;
}
bytesSoFar += bytes;
}
if (! gAuCurrentMusic) continue;
// Send rendered music to audio hardware.
sceKernelDelayThread(20 * sceAudioGetChannelRestLen(gAuMusicChannel));
while (sceAudioGetChannelRestLen(gAuMusicChannel) > 0) { }
sceAudioOutput(gAuMusicChannel, gAuMusicVolume, buffer);
// Swap buffers.
buffer = (buffer == buffer1) ? buffer2 : buffer1;
}
// Clean up.
free(buffer1);
free(buffer2);
sceKernelExitThread(kAuErrNone);
return kAuErrNone;
}