The code has been checked into the SVN repository. Feel free to update your SDK if you feel like trying out the library :)
Header:
Code: Select all
/*
 * PSP Software Development Kit - http://www.pspdev.org
 * -----------------------------------------------------------------------
 * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
 *
 * pspmp3.h - Prototypes for the sceMp3 library
 *
 * Copyright (c) 2008 David Perry <tias_dp@hotmail.com>
 * Copyright (c) 2008 Alexander Berl <raphael@fx-world.org>
 *
 * $Id: $
 */
#ifndef __SCELIBMP3_H__
#define __SCELIBMP3_H__
#include <psptypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct SceMp3InitArg {
	/** Stream start position */
	SceUInt32	mp3StreamStart;
	/** Unknown - set to 0 */
	SceUInt32	unk1;
	/** Stream end position */
	SceUInt32	mp3StreamEnd;
	/** Unknown - set to 0 */
	SceUInt32	unk2;
	/** Pointer to a buffer to contain raw mp3 stream data (+1472 bytes workspace) */
	SceVoid*	mp3Buf;
	/** Size of mp3Buf buffer (must be >= 8192) */
	SceInt32	mp3BufSize;
	/** Pointer to decoded pcm samples buffer */
	SceVoid*	pcmBuf;
	/** Size of pcmBuf buffer (must be >= 9216) */
	SceInt32	pcmBufSize;
} SceMp3InitArg;
/**
 * sceMp3ReserveMp3Handle
 *
 * @param args - Pointer to SceMp3InitArg structure
 *
 * @returns sceMp3 handle on success, < 0 on error.
 */
SceInt32 sceMp3ReserveMp3Handle(SceMp3InitArg* args);
/**
 * sceMp3ReleaseMp3Handle
 *
 * @param handle - sceMp3 handle
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3ReleaseMp3Handle(SceInt32 handle);
/**
 * sceMp3InitResource
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3InitResource();
/**
 * sceMp3TermResource
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3TermResource();
/**
 * sceMp3Init
 *
 * @param handle - sceMp3 handle
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3Init(SceInt32 handle);
/**
 * sceMp3Decode
 *
 * @param handle - sceMp3 handle
 * @param dst - Pointer to destination pcm samples buffer
 *
 * @returns number of bytes in decoded pcm buffer, < 0 on error.
 */
SceInt32 sceMp3Decode(SceInt32 handle, SceShort16** dst);
/**
 * sceMp3GetInfoToAddStreamData
 *
 * @param handle - sceMp3 handle
 * @param dst - Pointer to stream data buffer
 * @param towrite - Space remaining in stream data buffer
 * @param srcpos - Position in source stream to start reading from
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3GetInfoToAddStreamData(SceInt32 handle, SceUChar8** dst, SceInt32* towrite, SceInt32* srcpos);
/**
 * sceMp3NotifyAddStreamData
 *
 * @param handle - sceMp3 handle
 * @param size - number of bytes added to the stream data buffer
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3NotifyAddStreamData(SceInt32 handle, SceInt32 size);
/**
 * sceMp3CheckStreamDataNeeded
 *
 * @param handle - sceMp3 handle
 *
 * @returns 1 if more stream data is needed, < 0 on error.
 */
SceInt32 sceMp3CheckStreamDataNeeded(SceInt32 handle);
/**
 * sceMp3SetLoopNum
 *
 * @param handle - sceMp3 handle
 * @param loop - Number of loops
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3SetLoopNum(SceInt32 handle, SceInt32 loop);
/**
 * sceMp3GetLoopNum
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of loops
 */
SceInt32 sceMp3GetLoopNum(SceInt32 handle);
/**
 * sceMp3GetSumDecodedSample
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of decoded samples
 */
SceInt32 sceMp3GetSumDecodedSample(SceInt32 handle);
/**
 * sceMp3GetMaxOutputSample
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of max samples to output
 */
SceInt32 sceMp3GetMaxOutputSample(SceInt32 handle);
/**
 * sceMp3GetSamplingRate
 *
 * @param handle - sceMp3 handle
 *
 * @returns Sampling rate of the mp3
 */
SceInt32 sceMp3GetSamplingRate(SceInt32 handle);
/**
 * sceMp3GetBitRate
 *
 * @param handle - sceMp3 handle
 *
 * @returns Bitrate of the mp3
 */
SceInt32 sceMp3GetBitRate(SceInt32 handle);
/**
 * sceMp3GetMp3ChannelNum
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of channels of the mp3
 */
SceInt32 sceMp3GetMp3ChannelNum(SceInt32 handle);
/**
 * sceMp3ResetPlayPosition
 *
 * @param handle - sceMp3 handle
 *
 * @returns < 0 on error
 */
SceInt32 sceMp3ResetPlayPosition(SceInt32 handle); 
#ifdef __cplusplus
}
#endif
#endif
Sample:
Code: Select all
/*
 * PSP Software Development Kit - http://www.pspdev.org
 * -----------------------------------------------------------------------
 * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
 *
 * main.c - Sample to demonstrate proper use of the mp3 library
 *
 * Copyright (c) 2008 Alexander Berl <raphael@fx-world.org>
 *
 * $Id: $
 */
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <stdio.h>
#include <pspaudio.h>
#include <pspmp3.h>
#include <psputility.h>
/* Define the module info section */
PSP_MODULE_INFO("Mp3Test", 0, 0, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
PSP_HEAP_SIZE_KB(-1024);
#define MP3FILE "ms0:/MUSIC/Test.mp3"
/* Define printf, just to make typing easier */
#define printf  pspDebugScreenPrintf
static int isrunning = 1;
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
    isrunning = 0;
	return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
    int cbid;
    cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
    sceKernelRegisterExitCallback(cbid);
    sceKernelSleepThreadCB();
	return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
    int thid = 0;
    thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
    if (thid >= 0)
	sceKernelStartThread(thid, 0, 0);
    return thid;
}
// Input and Output buffers
char	mp3Buf[16*1024]  __attribute__((aligned(64)));
short	pcmBuf[16*(1152/2)]  __attribute__((aligned(64)));
// Macro to allow formatted input without having to use stdargs.h
#define ERRORMSG(...) { char msg[128]; sprintf(msg,__VA_ARGS__); error(msg); }
// Print out an error message and quit after user input
void error( char* msg )
{
	SceCtrlData pad;
	pspDebugScreenClear();
	pspDebugScreenSetXY(0, 0);
	printf(msg);
	printf("Press X to quit.\n");
	while (isrunning)
	{
		sceCtrlReadBufferPositive(&pad, 1);
		if (pad.Buttons & PSP_CTRL_CROSS)
			break;
		sceDisplayWaitVblankStart();
	}
	sceKernelExitGame();
}
int fillStreamBuffer( int fd, int handle )
{
	char* dst;
	int write;
	int pos;
	// Get Info on the stream (where to fill to, how much to fill, where to fill from)
	int status = sceMp3GetInfoToAddStreamData( handle, &dst, &write, &pos);
	if (status<0)
	{
		ERRORMSG("ERROR: sceMp3GetInfoToAddStreamData returned 0x%08X\n", status);
	}
	// Seek file to position requested
	status = sceIoLseek32( fd, pos, SEEK_SET );
	if (status<0)
	{
		ERRORMSG("ERROR: sceIoLseek32 returned 0x%08X\n", status);
	}
	
	// Read the amount of data
	int read = sceIoRead( fd, dst, write );
	if (read < 0)
	{
		ERRORMSG("ERROR: Could not read from file - 0x%08X\n", read);
	}
	
	if (read==0)
	{
		// End of file?
		return 0;
	}
	
	// Notify mp3 library about how much we really wrote to the stream buffer
	status = sceMp3NotifyAddStreamData( handle, read );
	if (status<0)
	{
		ERRORMSG("ERROR: sceMp3NotifyAddStreamData returned 0x%08X\n", status);
	}
	
	return (pos>0);
}
/* main routine */
int main(int argc, char *argv[])
{
    SceCtrlData pad;
    //init screen and callbacks
    pspDebugScreenInit();
    pspDebugScreenClear();
    SetupCallbacks();
	
    // Setup Pad
    sceCtrlSetSamplingCycle(0);
    sceCtrlSetSamplingMode(0);
	// Load modules
	int status = sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC);
	if (status<0)
	{
		ERRORMSG("ERROR: sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status);
	}
	
	status = sceUtilityLoadModule(PSP_MODULE_AV_MP3);
	if (status<0)
	{
		ERRORMSG("ERROR: sceUtilityLoadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status);
	}
	
	// Open the input file
	int fd = sceIoOpen( MP3FILE, PSP_O_RDONLY, 0777 );
	if (fd<0)
	{
		ERRORMSG("ERROR: Could not open file '%s' - 0x%08X\n", MP3FILE, fd);
	}
	
	// Init mp3 resources
	status = sceMp3InitResource();
	if (status<0)
	{
		ERRORMSG("ERROR: sceMp3InitResource returned 0x%08X\n", status);
	}
	
	// Reserve a mp3 handle for our playback
	SceMp3InitArg mp3Init;
	mp3Init.mp3StreamStart = 0;
	mp3Init.mp3StreamEnd = sceIoLseek32( fd, 0, SEEK_END );
	mp3Init.unk1 = 0;
	mp3Init.unk2 = 0;
	mp3Init.mp3Buf = mp3Buf;
	mp3Init.mp3BufSize = sizeof(mp3Buf);
	mp3Init.pcmBuf = pcmBuf;
	mp3Init.pcmBufSize = sizeof(pcmBuf);
	
	int handle = sceMp3ReserveMp3Handle( &mp3Init );
	if (handle<0)
	{
		ERRORMSG("ERROR: sceMp3ReserveMp3Handle returned 0x%08X\n", handle);
	}
	
	// Fill the stream buffer with some data so that sceMp3Init has something to work with
	fillStreamBuffer( fd, handle );
	
	status = sceMp3Init( handle );
	if (status<0)
	{
		ERRORMSG("ERROR: sceMp3Init returned 0x%08X\n", status);
	}
	
	int channel = -1;
	int samplingRate = sceMp3GetSamplingRate( handle );
	int numChannels = sceMp3GetMp3ChannelNum( handle );
	int lastDecoded = 0;
	int volume = PSP_AUDIO_VOLUME_MAX;
	int numPlayed = 0;
	int paused = 0;
	int lastButtons = 0;
	int loop = 0;
	while (isrunning)
	{
		sceDisplayWaitVblankStart();
		pspDebugScreenSetXY(0, 0);
		printf("PSP Mp3 Sample v1.0 by Raphael\n\n");
		printf("Playing '%s'...\n", MP3FILE);
		printf(" %i Hz\n", samplingRate);
		printf(" %i kbit/s\n", sceMp3GetBitRate( handle ));
		printf(" %s\n", numChannels==2?"Stereo":"Mono");
		printf(" %s\n\n", loop==0?"No loop":"Loop");
		int playTime = samplingRate>0?numPlayed / samplingRate:0;
		printf(" Playtime: %02i:%02i\n", playTime/60, playTime%60 );
		printf("\n\n\nPress CIRCLE to Pause/Resume playback\nPress TRIANGLE to reset playback\nPress CROSS to switch loop mode\nPress SQUARE to stop playback and quit\n");
		
		if (!paused)
		{
			// Check if we need to fill our stream buffer
			if (sceMp3CheckStreamDataNeeded( handle )>0)
			{
				fillStreamBuffer( fd, handle );
			}
			// Decode some samples
			short* buf;
			int bytesDecoded;
			int retries = 0;
			// We retry in case it's just that we reached the end of the stream and need to loop
			for (;retries<1;retries++)
			{
				bytesDecoded = sceMp3Decode( handle, &buf );
				if (bytesDecoded>0)
					break;
				
				if (sceMp3CheckStreamDataNeeded( handle )<=0)
					break;
				
				if (!fillStreamBuffer( fd, handle ))
				{
					numPlayed = 0;
				}
			}
			if (bytesDecoded<0 && bytesDecoded!=0x80671402)
			{
				ERRORMSG("ERROR: sceMp3Decode returned 0x%08X\n", bytesDecoded);
			}
			
			// Nothing more to decode? Must have reached end of input buffer
			if (bytesDecoded==0 || bytesDecoded==0x80671402)
			{
				paused = 1;
				sceMp3ResetPlayPosition( handle );
				numPlayed = 0;
			}
			else
			{
				// Reserve the Audio channel for our output if not yet done
				if (channel<0 || lastDecoded!=bytesDecoded)
				{
					if (channel>=0)
						sceAudioSRCChRelease();
					
					channel = sceAudioSRCChReserve( bytesDecoded/(2*numChannels), samplingRate, numChannels );
				}
				// Output the decoded samples and accumulate the number of played samples to get the playtime
				numPlayed += sceAudioSRCOutputBlocking( volume, buf );
			}
		}
		
		sceCtrlPeekBufferPositive(&pad, 1);
		
		if (pad.Buttons!=lastButtons)
		{
			if (pad.Buttons & PSP_CTRL_CIRCLE)
			{
				paused ^= 1;
			}
			
			if (pad.Buttons & PSP_CTRL_TRIANGLE)
			{
				// Reset the stream and playback status
				sceMp3ResetPlayPosition( handle );
				numPlayed = 0;
			}
			
			if (pad.Buttons & PSP_CTRL_CROSS)
			{
				loop = (loop==0?-1:0);
				status = sceMp3SetLoopNum( handle, loop );
				if (status<0)
				{
					ERRORMSG("ERROR: sceMp3SetLoopNum returned 0x%08X\n", status);
				}
			}
			
			if (pad.Buttons & PSP_CTRL_SQUARE)
			{
				break;
			}
			
			lastButtons = pad.Buttons;
		}
    }
    
    // Cleanup time...
    if (channel>=0)
		sceAudioSRCChRelease();
	
	status = sceMp3ReleaseMp3Handle( handle );
	if (status<0)
	{
		ERRORMSG("ERROR: sceMp3ReleaseMp3Handle returned 0x%08X\n", status);
	}
	
	status = sceMp3TermResource();
	if (status<0)
	{
		ERRORMSG("ERROR: sceMp3TermResource returned 0x%08X\n", status);
	}
	
	status = sceIoClose( fd );
	if (status<0)
	{
		ERRORMSG("ERROR: sceIoClose returned 0x%08X\n", status);
	}
	
    sceKernelExitGame();
    return 0;
}

