SDK Updated with sceMp3 stubs+headers

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

SDK Updated with sceMp3 stubs+headers

Post by Raphael »

After some fiddling, InsertWittyName and me figured out how to use sceMp3 library to playback mp3.

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 &#40;c&#41; 2008 David Perry <[email protected]>
 * Copyright &#40;c&#41; 2008 Alexander Berl <[email protected]>
 *
 * $Id&#58; $
 */

#ifndef __SCELIBMP3_H__
#define __SCELIBMP3_H__

#include <psptypes.h>

#ifdef __cplusplus
extern "C" &#123;
#endif

typedef struct SceMp3InitArg &#123;
	/** 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 &#40;+1472 bytes workspace&#41; */
	SceVoid*	mp3Buf;
	/** Size of mp3Buf buffer &#40;must be >= 8192&#41; */
	SceInt32	mp3BufSize;
	/** Pointer to decoded pcm samples buffer */
	SceVoid*	pcmBuf;
	/** Size of pcmBuf buffer &#40;must be >= 9216&#41; */
	SceInt32	pcmBufSize;
&#125; SceMp3InitArg;

/**
 * sceMp3ReserveMp3Handle
 *
 * @param args - Pointer to SceMp3InitArg structure
 *
 * @returns sceMp3 handle on success, < 0 on error.
 */
SceInt32 sceMp3ReserveMp3Handle&#40;SceMp3InitArg* args&#41;;

/**
 * sceMp3ReleaseMp3Handle
 *
 * @param handle - sceMp3 handle
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3ReleaseMp3Handle&#40;SceInt32 handle&#41;;

/**
 * sceMp3InitResource
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3InitResource&#40;&#41;;

/**
 * sceMp3TermResource
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3TermResource&#40;&#41;;

/**
 * sceMp3Init
 *
 * @param handle - sceMp3 handle
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3Init&#40;SceInt32 handle&#41;;

/**
 * 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&#40;SceInt32 handle, SceShort16** dst&#41;;

/**
 * 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&#40;SceInt32 handle, SceUChar8** dst, SceInt32* towrite, SceInt32* srcpos&#41;;

/**
 * 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&#40;SceInt32 handle, SceInt32 size&#41;;

/**
 * sceMp3CheckStreamDataNeeded
 *
 * @param handle - sceMp3 handle
 *
 * @returns 1 if more stream data is needed, < 0 on error.
 */
SceInt32 sceMp3CheckStreamDataNeeded&#40;SceInt32 handle&#41;;

/**
 * sceMp3SetLoopNum
 *
 * @param handle - sceMp3 handle
 * @param loop - Number of loops
 *
 * @returns 0 if success, < 0 on error.
 */
SceInt32 sceMp3SetLoopNum&#40;SceInt32 handle, SceInt32 loop&#41;;

/**
 * sceMp3GetLoopNum
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of loops
 */
SceInt32 sceMp3GetLoopNum&#40;SceInt32 handle&#41;;

/**
 * sceMp3GetSumDecodedSample
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of decoded samples
 */
SceInt32 sceMp3GetSumDecodedSample&#40;SceInt32 handle&#41;;

/**
 * sceMp3GetMaxOutputSample
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of max samples to output
 */
SceInt32 sceMp3GetMaxOutputSample&#40;SceInt32 handle&#41;;

/**
 * sceMp3GetSamplingRate
 *
 * @param handle - sceMp3 handle
 *
 * @returns Sampling rate of the mp3
 */
SceInt32 sceMp3GetSamplingRate&#40;SceInt32 handle&#41;;

/**
 * sceMp3GetBitRate
 *
 * @param handle - sceMp3 handle
 *
 * @returns Bitrate of the mp3
 */
SceInt32 sceMp3GetBitRate&#40;SceInt32 handle&#41;;

/**
 * sceMp3GetMp3ChannelNum
 *
 * @param handle - sceMp3 handle
 *
 * @returns Number of channels of the mp3
 */
SceInt32 sceMp3GetMp3ChannelNum&#40;SceInt32 handle&#41;;

/**
 * sceMp3ResetPlayPosition
 *
 * @param handle - sceMp3 handle
 *
 * @returns < 0 on error
 */
SceInt32 sceMp3ResetPlayPosition&#40;SceInt32 handle&#41;; 


#ifdef __cplusplus
&#125;
#endif

#endif

Sample:

Code: Select all

/*
 * PSP Software Development Kit - http&#58;//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 &#40;c&#41; 2008 Alexander Berl <[email protected]>
 *
 * $Id&#58; $
 */
#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&#40;"Mp3Test", 0, 0, 1&#41;;
PSP_MAIN_THREAD_ATTR&#40;THREAD_ATTR_USER&#41;;
PSP_HEAP_SIZE_KB&#40;-1024&#41;;

#define MP3FILE "ms0&#58;/MUSIC/Test.mp3"

/* Define printf, just to make typing easier */
#define printf  pspDebugScreenPrintf

static int isrunning = 1;
/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41;
&#123;
    isrunning = 0;

	return 0;
&#125;

/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41;
&#123;
    int cbid;
    cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
    sceKernelRegisterExitCallback&#40;cbid&#41;;
    sceKernelSleepThreadCB&#40;&#41;;

	return 0;
&#125;

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41;
&#123;
    int thid = 0;
    thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, 0, 0&#41;;
    if &#40;thid >= 0&#41;
	sceKernelStartThread&#40;thid, 0, 0&#41;;
    return thid;
&#125;


// Input and Output buffers
char	mp3Buf&#91;16*1024&#93;  __attribute__&#40;&#40;aligned&#40;64&#41;&#41;&#41;;
short	pcmBuf&#91;16*&#40;1152/2&#41;&#93;  __attribute__&#40;&#40;aligned&#40;64&#41;&#41;&#41;;


// Macro to allow formatted input without having to use stdargs.h
#define ERRORMSG&#40;...&#41; &#123; char msg&#91;128&#93;; sprintf&#40;msg,__VA_ARGS__&#41;; error&#40;msg&#41;; &#125;

// Print out an error message and quit after user input
void error&#40; char* msg &#41;
&#123;
	SceCtrlData pad;
	pspDebugScreenClear&#40;&#41;;
	pspDebugScreenSetXY&#40;0, 0&#41;;
	printf&#40;msg&#41;;
	printf&#40;"Press X to quit.\n"&#41;;
	while &#40;isrunning&#41;
	&#123;
		sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
		if &#40;pad.Buttons & PSP_CTRL_CROSS&#41;
			break;
		sceDisplayWaitVblankStart&#40;&#41;;
	&#125;
	sceKernelExitGame&#40;&#41;;
&#125;

int fillStreamBuffer&#40; int fd, int handle &#41;
&#123;
	char* dst;
	int write;
	int pos;
	// Get Info on the stream &#40;where to fill to, how much to fill, where to fill from&#41;
	int status = sceMp3GetInfoToAddStreamData&#40; handle, &dst, &write, &pos&#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3GetInfoToAddStreamData returned 0x%08X\n", status&#41;;
	&#125;

	// Seek file to position requested
	status = sceIoLseek32&#40; fd, pos, SEEK_SET &#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceIoLseek32 returned 0x%08X\n", status&#41;;
	&#125;
	
	// Read the amount of data
	int read = sceIoRead&#40; fd, dst, write &#41;;
	if &#40;read < 0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; Could not read from file - 0x%08X\n", read&#41;;
	&#125;
	
	if &#40;read==0&#41;
	&#123;
		// End of file?
		return 0;
	&#125;
	
	// Notify mp3 library about how much we really wrote to the stream buffer
	status = sceMp3NotifyAddStreamData&#40; handle, read &#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3NotifyAddStreamData returned 0x%08X\n", status&#41;;
	&#125;
	
	return &#40;pos>0&#41;;
&#125;

/* main routine */
int main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
    SceCtrlData pad;

    //init screen and callbacks
    pspDebugScreenInit&#40;&#41;;
    pspDebugScreenClear&#40;&#41;;
    SetupCallbacks&#40;&#41;;
	
    // Setup Pad
    sceCtrlSetSamplingCycle&#40;0&#41;;
    sceCtrlSetSamplingMode&#40;0&#41;;

	// Load modules
	int status = sceUtilityLoadModule&#40;PSP_MODULE_AV_AVCODEC&#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceUtilityLoadModule&#40;PSP_MODULE_AV_AVCODEC&#41; returned 0x%08X\n", status&#41;;
	&#125;
	
	status = sceUtilityLoadModule&#40;PSP_MODULE_AV_MP3&#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceUtilityLoadModule&#40;PSP_MODULE_AV_MP3&#41; returned 0x%08X\n", status&#41;;
	&#125;
	
	// Open the input file
	int fd = sceIoOpen&#40; MP3FILE, PSP_O_RDONLY, 0777 &#41;;
	if &#40;fd<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; Could not open file '%s' - 0x%08X\n", MP3FILE, fd&#41;;
	&#125;
	
	// Init mp3 resources
	status = sceMp3InitResource&#40;&#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3InitResource returned 0x%08X\n", status&#41;;
	&#125;
	
	// Reserve a mp3 handle for our playback
	SceMp3InitArg mp3Init;
	mp3Init.mp3StreamStart = 0;
	mp3Init.mp3StreamEnd = sceIoLseek32&#40; fd, 0, SEEK_END &#41;;
	mp3Init.unk1 = 0;
	mp3Init.unk2 = 0;
	mp3Init.mp3Buf = mp3Buf;
	mp3Init.mp3BufSize = sizeof&#40;mp3Buf&#41;;
	mp3Init.pcmBuf = pcmBuf;
	mp3Init.pcmBufSize = sizeof&#40;pcmBuf&#41;;
	
	int handle = sceMp3ReserveMp3Handle&#40; &mp3Init &#41;;
	if &#40;handle<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3ReserveMp3Handle returned 0x%08X\n", handle&#41;;
	&#125;
	
	// Fill the stream buffer with some data so that sceMp3Init has something to work with
	fillStreamBuffer&#40; fd, handle &#41;;
	
	status = sceMp3Init&#40; handle &#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3Init returned 0x%08X\n", status&#41;;
	&#125;
	
	int channel = -1;
	int samplingRate = sceMp3GetSamplingRate&#40; handle &#41;;
	int numChannels = sceMp3GetMp3ChannelNum&#40; handle &#41;;
	int lastDecoded = 0;
	int volume = PSP_AUDIO_VOLUME_MAX;
	int numPlayed = 0;
	int paused = 0;
	int lastButtons = 0;
	int loop = 0;
	while &#40;isrunning&#41;
	&#123;
		sceDisplayWaitVblankStart&#40;&#41;;
		pspDebugScreenSetXY&#40;0, 0&#41;;
		printf&#40;"PSP Mp3 Sample v1.0 by Raphael\n\n"&#41;;
		printf&#40;"Playing '%s'...\n", MP3FILE&#41;;
		printf&#40;" %i Hz\n", samplingRate&#41;;
		printf&#40;" %i kbit/s\n", sceMp3GetBitRate&#40; handle &#41;&#41;;
		printf&#40;" %s\n", numChannels==2?"Stereo"&#58;"Mono"&#41;;
		printf&#40;" %s\n\n", loop==0?"No loop"&#58;"Loop"&#41;;
		int playTime = samplingRate>0?numPlayed / samplingRate&#58;0;
		printf&#40;" Playtime&#58; %02i&#58;%02i\n", playTime/60, playTime%60 &#41;;
		printf&#40;"\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"&#41;;
		
		if &#40;!paused&#41;
		&#123;
			// Check if we need to fill our stream buffer
			if &#40;sceMp3CheckStreamDataNeeded&#40; handle &#41;>0&#41;
			&#123;
				fillStreamBuffer&#40; fd, handle &#41;;
			&#125;

			// 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 &#40;;retries<1;retries++&#41;
			&#123;
				bytesDecoded = sceMp3Decode&#40; handle, &buf &#41;;
				if &#40;bytesDecoded>0&#41;
					break;
				
				if &#40;sceMp3CheckStreamDataNeeded&#40; handle &#41;<=0&#41;
					break;
				
				if &#40;!fillStreamBuffer&#40; fd, handle &#41;&#41;
				&#123;
					numPlayed = 0;
				&#125;
			&#125;
			if &#40;bytesDecoded<0 && bytesDecoded!=0x80671402&#41;
			&#123;
				ERRORMSG&#40;"ERROR&#58; sceMp3Decode returned 0x%08X\n", bytesDecoded&#41;;
			&#125;
			
			// Nothing more to decode? Must have reached end of input buffer
			if &#40;bytesDecoded==0 || bytesDecoded==0x80671402&#41;
			&#123;
				paused = 1;
				sceMp3ResetPlayPosition&#40; handle &#41;;
				numPlayed = 0;
			&#125;
			else
			&#123;
				// Reserve the Audio channel for our output if not yet done
				if &#40;channel<0 || lastDecoded!=bytesDecoded&#41;
				&#123;
					if &#40;channel>=0&#41;
						sceAudioSRCChRelease&#40;&#41;;
					
					channel = sceAudioSRCChReserve&#40; bytesDecoded/&#40;2*numChannels&#41;, samplingRate, numChannels &#41;;
				&#125;
				// Output the decoded samples and accumulate the number of played samples to get the playtime
				numPlayed += sceAudioSRCOutputBlocking&#40; volume, buf &#41;;
			&#125;
		&#125;
		
		sceCtrlPeekBufferPositive&#40;&pad, 1&#41;;
		
		if &#40;pad.Buttons!=lastButtons&#41;
		&#123;
			if &#40;pad.Buttons & PSP_CTRL_CIRCLE&#41;
			&#123;
				paused ^= 1;
			&#125;
			
			if &#40;pad.Buttons & PSP_CTRL_TRIANGLE&#41;
			&#123;
				// Reset the stream and playback status
				sceMp3ResetPlayPosition&#40; handle &#41;;
				numPlayed = 0;
			&#125;
			
			if &#40;pad.Buttons & PSP_CTRL_CROSS&#41;
			&#123;
				loop = &#40;loop==0?-1&#58;0&#41;;
				status = sceMp3SetLoopNum&#40; handle, loop &#41;;
				if &#40;status<0&#41;
				&#123;
					ERRORMSG&#40;"ERROR&#58; sceMp3SetLoopNum returned 0x%08X\n", status&#41;;
				&#125;
			&#125;
			
			if &#40;pad.Buttons & PSP_CTRL_SQUARE&#41;
			&#123;
				break;
			&#125;
			
			lastButtons = pad.Buttons;
		&#125;
    &#125;
    
    // Cleanup time...
    if &#40;channel>=0&#41;
		sceAudioSRCChRelease&#40;&#41;;
	
	status = sceMp3ReleaseMp3Handle&#40; handle &#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3ReleaseMp3Handle returned 0x%08X\n", status&#41;;
	&#125;
	
	status = sceMp3TermResource&#40;&#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceMp3TermResource returned 0x%08X\n", status&#41;;
	&#125;
	
	status = sceIoClose&#40; fd &#41;;
	if &#40;status<0&#41;
	&#123;
		ERRORMSG&#40;"ERROR&#58; sceIoClose returned 0x%08X\n", status&#41;;
	&#125;
	
    sceKernelExitGame&#40;&#41;;

    return 0;
&#125;
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
KickinAezz
Posts: 328
Joined: Sun Jun 03, 2007 10:05 pm

Post by KickinAezz »

Any advantages over our ME mp3 player?
Intrigued by PSP system Since December 2006.
Use it more for Development than for Gaming.
SilverSpring
Posts: 110
Joined: Tue Feb 27, 2007 9:43 pm
Contact:

Post by SilverSpring »

The libaac have identical function names so maybe the prototypes are the same/similar to libmp3:

Code: Select all

0x6c05813b sceAac_6C05813B &#40;module_start alias&#41;
0x61aa43c9 sceAac_61AA43C9 &#40;module_stop alias&#41;
0xe0c89aca sceAacInit
0x33b8c009 sceAacExit
0x5cffc57c sceAacInitResource
0x23d35cae sceAacTermResource
0x7e4cfee4 sceAacDecode
0x523347d9 sceAacGetLoopNum
0xbbdd6403 sceAacSetLoopNum
0xd7c51541 sceAacCheckStreamDataNeeded
0xac6dcbe3 sceAacNotifyAddStreamData
0x02098c69 sceAacGetInfoToAddStreamData
0x6dc7758a sceAacGetMaxOutputSample
0x506bf66c sceAacGetSumDecodedSample
0xd2da2bba sceAacResetPlayPosition
I haven't looked into it or tested it but libaac was added in 3.95 firmware (libaac.prx) and maybe the usage is similar.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

Is the sce lib hardware accelerated?
SilverSpring
Posts: 110
Joined: Tue Feb 27, 2007 9:43 pm
Contact:

Post by SilverSpring »

Torch wrote:Is the sce lib hardware accelerated?
Yes it's already using Media Engine decoding.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

SilverSpring wrote: Yes it's already using Media Engine decoding.
Speaking of the ME, is the sound equalizer stuff done by the ME or is it software?
Are there any functions which I can use to set custom equalizer settings, because the built in ones sound awful.

I read somewhere that the equalizer stuff was done like an FPGA and that the various presets where actually stored as an FPGA logic and the hardware gets "reprogrammed" with the preset codes when you press then note button.
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

KickinAezz wrote:Any advantages over our ME mp3 player?
Easier interface to getting it to work with streaming. Also you don't have to fill those 'magic' buffers with decoding parameters.
And to say the least, the sample already provides near perfect playback, even though it's single threaded and uses only a small decoding buffer of 16kb. Equal performance and reliability is only achieved with lots of threaded coding and bigger buffers with the previous method.
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

SilverSpring wrote:The libaac have identical function names so maybe the prototypes are the same/similar to libmp3:

Code: Select all

0x6c05813b sceAac_6C05813B &#40;module_start alias&#41;
0x61aa43c9 sceAac_61AA43C9 &#40;module_stop alias&#41;
0xe0c89aca sceAacInit
0x33b8c009 sceAacExit
0x5cffc57c sceAacInitResource
0x23d35cae sceAacTermResource
0x7e4cfee4 sceAacDecode
0x523347d9 sceAacGetLoopNum
0xbbdd6403 sceAacSetLoopNum
0xd7c51541 sceAacCheckStreamDataNeeded
0xac6dcbe3 sceAacNotifyAddStreamData
0x02098c69 sceAacGetInfoToAddStreamData
0x6dc7758a sceAacGetMaxOutputSample
0x506bf66c sceAacGetSumDecodedSample
0xd2da2bba sceAacResetPlayPosition
I haven't looked into it or tested it but libaac was added in 3.95 firmware (libaac.prx) and maybe the usage is similar.
Thanks, that might be worth looking into too :)
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
pspZorba
Posts: 156
Joined: Sat Sep 22, 2007 11:45 am
Location: NY

Post by pspZorba »

Thank you guys

That's what I was waiting for to add music in my dev.
--pspZorba--
NO to K1.5 !
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Don't know when I'd use it, but it's great to have it if I did. Great work!
ne0h
Posts: 386
Joined: Thu Feb 21, 2008 2:15 am

Post by ne0h »

?Raphael, you have posted the header and a sample but there's no library needed?
Insert_witty_name
Posts: 376
Joined: Wed May 10, 2006 11:31 pm

Post by Insert_witty_name »

Update your SDK.

The library, header and sample are all there.
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

SilverSpring wrote:The libaac have identical function names so maybe the prototypes are the same/similar to libmp3:

Code: Select all

0x6c05813b sceAac_6C05813B &#40;module_start alias&#41;
0x61aa43c9 sceAac_61AA43C9 &#40;module_stop alias&#41;
0xe0c89aca sceAacInit
0x33b8c009 sceAacExit
0x5cffc57c sceAacInitResource
0x23d35cae sceAacTermResource
0x7e4cfee4 sceAacDecode
0x523347d9 sceAacGetLoopNum
0xbbdd6403 sceAacSetLoopNum
0xd7c51541 sceAacCheckStreamDataNeeded
0xac6dcbe3 sceAacNotifyAddStreamData
0x02098c69 sceAacGetInfoToAddStreamData
0x6dc7758a sceAacGetMaxOutputSample
0x506bf66c sceAacGetSumDecodedSample
0xd2da2bba sceAacResetPlayPosition
I haven't looked into it or tested it but libaac was added in 3.95 firmware (libaac.prx) and maybe the usage is similar.
Well, since we need some way of loading the libAAC.prx properly in user mode, I fiddled with sceUtilityLoadModule a bit.

I found the following values to load other modules than the ones already known:
#define PSP_MODULE_AV_VAUDIO 0x0305
#define PSP_MODULE_AV_AAC 0x0306
#define PSP_MODULE_AV_G729 0x0307

#define PSP_MODULE_NP_COMMON 0x0400 // sceNpCore, sceNp, sceNpAuth
#define PSP_MODULE_NP_SERVICE 0x0401
#define PSP_MODULE_NP_MATCHING2 0x0402

// scePspNpDrm_driver
#define PSP_MODULE_NP_DRM 0x0500

// sceIrDA_Driver
#define PSP_MODULE_IRDA 0x0600
I'll add those to pspUtility.h and commit it. Looks like AAC decoding is not far :)

PS: Anyone knows what the NP modules might be for (NetPlay maybe)? I guess the PspNpDrm is for the NP9660 UMD driver, no?
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
kralyk
Posts: 114
Joined: Sun Apr 06, 2008 8:18 pm
Location: Czech Republic, central EU

Post by kralyk »

Brilliant, thanks for your work Raphael and InsertWittyName
AlphaDingDong
Posts: 29
Joined: Fri Mar 21, 2008 2:51 pm
Location: The interwebs

Post by AlphaDingDong »

I've been getting error code 0x807F00FD from sceMp3Init wherever I try to use it, including the sample. I can't find the error code listed anywhere.

Any idea what's happening here?
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

AlphaDingDong wrote:I've been getting error code 0x807F00FD from sceMp3Init wherever I try to use it, including the sample. I can't find the error code listed anywhere.

Any idea what's happening here?
Most likely an error code meaning that the header is not a valid mp3header. That's the case when you have an ID3 tag at the start of the mp3. sceMp3 doesn't parse that unfortunately, so you have to do it yourself (and give the proper streamStart/streamEnd address to mp3InitArgs) or strip id3 tags from the mp3s you play.
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
AlphaDingDong
Posts: 29
Joined: Fri Mar 21, 2008 2:51 pm
Location: The interwebs

Post by AlphaDingDong »

That's probably it. Thanks.
wxnlyq
Posts: 4
Joined: Fri Oct 03, 2008 12:35 pm

Post by wxnlyq »

I've been succeed to play a mp3 file using the pspmp3 lib.
But when I try to run it in a separate thread, it failed(PSP is shutdown).

It seem that when sceIoOpen is called, some error occurs.
Why I can't open a file in the thread?

Because the sample code is written to play a single file, but I want to multiple mp3 file at the same time&#65292;How can I do it?

Could somebody give me a help.

Code: Select all

#mp3.h
#include "Mp3.h"
#define printf pspDebugScreenPrintf

void Mp3&#58;&#58;init&#40;&#41; &#123;
	loadModules&#40;&#41;;
&#125;

Mp3&#58;&#58;Mp3&#40;const std&#58;&#58;string& filename, int inBufferSize, int outBufferSize&#41; &#58;
	m_volume&#40;PSP_AUDIO_VOLUME_MAX&#41;, m_paused&#40;true&#41;, m_samplesPlayed&#40;0&#41; &#123;
	load&#40;filename&#41;;
&#125;

Mp3&#58;&#58;~Mp3&#40;&#41; &#123;
	unload&#40;&#41;;
&#125;

bool Mp3&#58;&#58;loadModules&#40;&#41; &#123;
	int loadAvCodec = sceUtilityLoadModule&#40;PSP_MODULE_AV_AVCODEC&#41;;
	if &#40;loadAvCodec < 0&#41; &#123;
		std&#58;&#58;cout << "Failed to load AV_AVCODEC module.\n";
		return false;
	&#125;

	int loadMp3 = sceUtilityLoadModule&#40;PSP_MODULE_AV_MP3&#41;;
	if &#40;loadMp3 < 0&#41; &#123;
		std&#58;&#58;cout << "Failed to load AV_MP3 module.\n";
		return false;
	&#125;

	return true;
&#125;

bool Mp3&#58;&#58;fillBuffers&#40;&#41; &#123;
	SceUChar8* dest;
	SceInt32 length;
	SceInt32 pos;

	int ret = sceMp3GetInfoToAddStreamData&#40;m_mp3Handle, &dest, &length, &pos&#41;;
	if &#40;ret < 0&#41;
		return false;

	if &#40;sceIoLseek32&#40;m_fileHandle, pos, SEEK_SET&#41; < 0&#41; &#123;
		std&#58;&#58;cout << "Seek failed.\n";
		return false;
	&#125;

	int readLength = sceIoRead&#40;m_fileHandle, dest, length&#41;;
	if &#40;readLength < 0&#41;
		return false;

	ret = sceMp3NotifyAddStreamData&#40;m_mp3Handle, readLength&#41;;
	if &#40;ret < 0&#41;
		return false;

	return true;
&#125;

bool Mp3&#58;&#58;load&#40;const std&#58;&#58;string& filename, int inBufferSize, int outBufferSize&#41; &#123;
	printf&#40;"load\n"&#41;;
	try &#123;
		m_inBufferSize = inBufferSize;
		printf&#40;"1\n"&#41;;
		m_inBuffer = new char&#91;m_inBufferSize&#93;;
		if &#40;!m_inBuffer&#41;
			throw std&#58;&#58;runtime_error&#40;"Failed to allocate in buffer."&#41;;

		m_outBufferSize = outBufferSize;
		printf&#40;"2\n"&#41;;
		m_outBuffer = new short&#91;outBufferSize&#93;;
		if &#40;!m_outBuffer&#41;
			throw std&#58;&#58;runtime_error&#40;"Failed to allocate out buffer."&#41;;

		printf&#40;"3&#58;%s\n",filename.c_str&#40;&#41;&#41;;
		m_fileHandle = sceIoOpen&#40;filename.c_str&#40;&#41;, PSP_O_RDONLY, 0777&#41;;
		if &#40;m_fileHandle < 0&#41;
			throw std&#58;&#58;runtime_error&#40;"Failed to open mp3 file."&#41;;

		printf&#40;"4\n"&#41;;
		int ret = sceMp3InitResource&#40;&#41;;
		if &#40;ret < 0&#41;
			throw std&#58;&#58;runtime_error&#40;"Failed to init sceMp3."&#41;;

		SceMp3InitArg initArgs;

		int fileSize = sceIoLseek32&#40;m_fileHandle, 0, SEEK_END&#41;;
		sceIoLseek32&#40;m_fileHandle, 0, SEEK_SET&#41;;

		unsigned char* testbuffer = new unsigned char&#91;7456&#93;;
		sceIoRead&#40;m_fileHandle, testbuffer, 7456&#41;;

		delete testbuffer;

		initArgs.unk1 = 0;
		initArgs.unk2 = 0;
		initArgs.mp3StreamStart = 0;
		initArgs.mp3StreamEnd = fileSize;
		initArgs.mp3BufSize = m_inBufferSize;
		initArgs.mp3Buf = &#40;SceVoid*&#41; m_inBuffer;
		initArgs.pcmBufSize = m_outBufferSize;
		initArgs.pcmBuf = &#40;SceVoid*&#41; m_outBuffer;

		printf&#40;"5\n"&#41;;
		m_mp3Handle = sceMp3ReserveMp3Handle&#40;&initArgs&#41;;
		if &#40;m_mp3Handle < 0&#41;
			throw std&#58;&#58;runtime_error&#40;"Failed to reserve mp3 handle."&#41;;

		// Alright we are all set up, let's fill the first buffer.
		fillBuffers&#40;&#41;;

		// Start this bitch up!
		printf&#40;"6\n"&#41;;
		int start = sceMp3Init&#40;m_mp3Handle&#41;;
		if &#40;start < 0&#41;
			throw std&#58;&#58;runtime_error&#40;"Failed to init sceMp3."&#41;;

		printf&#40;"7\n"&#41;;
		m_numChannels = sceMp3GetMp3ChannelNum&#40;m_mp3Handle&#41;;
		printf&#40;"8\n"&#41;;
		m_samplingRate = sceMp3GetSamplingRate&#40;m_mp3Handle&#41;;
	&#125; catch &#40;std&#58;&#58;exception& e&#41; &#123;
		printf&#40;"exceptiuon&#58;%s\n", e.what&#40;&#41;&#41;;
		std&#58;&#58;cout << "Error&#58; " << e.what&#40;&#41; << "\n";
		return false;
	&#125;

	return true;
&#125;

bool Mp3&#58;&#58;unload&#40;&#41; &#123;
	if &#40;m_channel >= 0&#41;
		sceAudioSRCChRelease&#40;&#41;;

	sceMp3ReleaseMp3Handle&#40;m_mp3Handle&#41;;
	sceMp3TermResource&#40;&#41;;

	sceIoClose&#40;m_fileHandle&#41;;

	delete&#91;&#93; m_inBuffer;
	delete&#91;&#93; m_outBuffer;

	return true;
&#125;

bool Mp3&#58;&#58;update&#40;&#41; &#123;
	if &#40;!m_paused&#41; &#123;
		if &#40;sceMp3CheckStreamDataNeeded&#40;m_mp3Handle&#41; > 0&#41; &#123;
			fillBuffers&#40;&#41;;
		&#125;

		short* tempBuffer;
		int numDecoded = 0;

		while &#40;true&#41; &#123;
			numDecoded = sceMp3Decode&#40;m_mp3Handle, &tempBuffer&#41;;
			if &#40;numDecoded > 0&#41;
				break;

			int ret = sceMp3CheckStreamDataNeeded&#40;m_mp3Handle&#41;;
			if &#40;ret <= 0&#41;
				break;

			fillBuffers&#40;&#41;;
		&#125;

		// Okay, let's see if we can't get something outputted &#58;/
		if &#40;numDecoded == 0 || numDecoded == WeirdSceMp3Error&#41; &#123;
			sceMp3ResetPlayPosition&#40;m_mp3Handle&#41;;
			if &#40;!m_loop&#41;
				m_paused = true;

			m_samplesPlayed = 0;
		&#125; else &#123;
			if &#40;m_channel < 0 || m_lastDecoded != numDecoded&#41; &#123;
				if &#40;m_channel >= 0&#41;
					sceAudioSRCChRelease&#40;&#41;;

				m_channel = sceAudioSRCChReserve&#40;numDecoded / &#40;2 * m_numChannels&#41;, m_samplingRate, m_numChannels&#41;;
			&#125;

			// Output
			m_samplesPlayed += sceAudioSRCOutputBlocking&#40;m_volume, tempBuffer&#41;;
			m_playTime = &#40;m_samplingRate > 0&#41; ? &#40;m_samplesPlayed / m_samplingRate&#41; &#58; 0;
		&#125;
	&#125;

	return true;
&#125;

bool Mp3&#58;&#58;play&#40;&#41; &#123;
	return &#40;m_paused = false&#41;;
&#125;

bool Mp3&#58;&#58;pause&#40;&#41; &#123;
	return &#40;m_paused = true&#41;;
&#125;

bool Mp3&#58;&#58;setLoop&#40;bool loop&#41; &#123;
	sceMp3SetLoopNum&#40;m_mp3Handle, &#40;loop == true&#41; ? -1 &#58; 0&#41;;
	return &#40;m_loop = loop&#41;;
&#125;

int Mp3&#58;&#58;setVolume&#40;int volume&#41; &#123;
	return &#40;m_volume = volume&#41;;
&#125;

int Mp3&#58;&#58;playTime&#40;&#41; const &#123;
	return m_playTime;
&#125;

int Mp3&#58;&#58;playTimeMinutes&#40;&#41; &#123;
	return m_playTime / 60;
&#125;

int Mp3&#58;&#58;playTimeSeconds&#40;&#41; &#123;
	return m_playTime % 60;
&#125;

Code: Select all

#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdebug.h>
#include <pspaudio.h>
#include <pspaudiolib.h>
#include <psppower.h>
#include <pspdisplay.h>
#include "Mp3.h"
#include "Log.h"
#include "MyMp3.h"
PSP_MODULE_INFO&#40;JGEApp_Title, 0, 1, 1&#41;
;PSP_MAIN_THREAD_ATTR&#40;0&#41;;
PSP_HEAP_SIZE_KB&#40;18*1024&#41;;
#define printf pspDebugScreenPrintf
// TWILIGHT ZONE! <do doo do doo>
/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41; &#123;
	sceKernelExitGame&#40;&#41;;
	return 0;
&#125;

/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41; &#123;
	int cbid;

	cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
	sceKernelRegisterExitCallback&#40;cbid&#41;;

	sceKernelSleepThreadCB&#40;&#41;;

	return 0;
&#125;
int MyCallbackThread&#40;SceSize args, void *argp&#41; &#123;
	printf&#40;"init\n"&#41;;
	Mp3&#58;&#58;init&#40;&#41;;
	printf&#40;"new Mp3\n"&#41;;
	Mp3 *mp3 = new Mp3&#40;"music.mp3"&#41;;
	mp3->setLoop&#40;true&#41;;
	printf&#40;"play\n"&#41;;
	mp3->play&#40;&#41;;
	while &#40;1&#41; &#123;
		printf&#40;"CallbackThread1&#58;%d\n", mp3->playTime&#40;&#41;&#41;;
		mp3->update&#40;&#41;;
	&#125;
	delete mp3;
	return 0;
&#125;

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41; &#123;
	int thid = 0;

	thid = sceKernelCreateThread&#40;"update_thread", MyCallbackThread, 0x11, 0xFA0, 0, 0&#41;;
	if &#40;thid >= 0&#41; &#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;

	return thid;
&#125;
// END OF TWILIGHT ZONE! <do doo do do>
int main&#40;&#41; &#123;
	scePowerSetClockFrequency&#40;333, 333, 166&#41;;

	pspDebugScreenInit&#40;&#41;;
	SetupCallbacks&#40;&#41;;

	SceCtrlData pad;

	int thid = 0;

	thid = sceKernelCreateThread&#40;"mythread", CallbackThread, 0x11, 0xFA0, 0, 0&#41;;
	if &#40;thid >= 0&#41; &#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;

//	Mp3&#58;&#58;init&#40;&#41;;
//	Mp3 *mp3 = new Mp3&#40;"music.mp3"&#41;;
//	mp3->setLoop&#40;true&#41;;
//	mp3->play&#40;&#41;;

	while &#40;1&#41; &#123;
		sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
		if &#40;pad.Buttons & PSP_CTRL_CROSS&#41; &#123;
			break;
		&#125;
		sceDisplayWaitVblankStart&#40;&#41;;
//		printf&#40;"CallbackThread1&#58;%d\n", mp3->playTime&#40;&#41;&#41;;
//		mp3->update&#40;&#41;;
	&#125;
//	delete mp3;

&#125;
wxnlyq
Posts: 4
Joined: Fri Oct 03, 2008 12:35 pm

Post by wxnlyq »

In the sample code, sceAudioSRCOutputBlocking is used to send the audio data.
When I try to change the sceAudioSRCChRelease/sceAudioSRCChReserve/sceAudioSRCOutputBlocking to sceAudioChRelease/sceAudioChReserve/sceAudioOutputBlocking, the sound comes to noise.
How can I use sceAudioOutputBlocking to assign a channel to feed the data?
wxnlyq
Posts: 4
Joined: Fri Oct 03, 2008 12:35 pm

Post by wxnlyq »

I set the filepath to be absolute and now it can be run in a thread.
But when MyCallbackThread and MyCallbackThread1 are run at the same time, problem occurs.

1&#12289;Why I can't use a relative path to open a file?
2&#12289;Can't pspmp3 lib be used in multithread?

Code: Select all

#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdebug.h>
#include <pspaudio.h>
#include <pspaudiolib.h>
#include <psppower.h>
#include <pspdisplay.h>
#include "Mp3.h"
#include "Log.h"
#include "MyMp3.h"
PSP_MODULE_INFO&#40;JGEApp_Title, 0, 1, 1&#41;
;PSP_MAIN_THREAD_ATTR&#40;0&#41;;
PSP_HEAP_SIZE_KB&#40;18*1024&#41;;
#define printf pspDebugScreenPrintf
// TWILIGHT ZONE! <do doo do doo>
/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41; &#123;
	sceKernelExitGame&#40;&#41;;
	return 0;
&#125;

/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41; &#123;
	int cbid;

	cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
	sceKernelRegisterExitCallback&#40;cbid&#41;;

	sceKernelSleepThreadCB&#40;&#41;;

	return 0;
&#125;
int MyCallbackThread&#40;SceSize args, void *argp&#41; &#123;
	printf&#40;"1new Mp3\n"&#41;;
	Mp3 *mp3 = new Mp3&#40;"ms0&#58;/08.mp3"&#41;;
	mp3->setLoop&#40;true&#41;;
	printf&#40;"1play\n"&#41;;
	mp3->play&#40;&#41;;
	while &#40;1&#41; &#123;
		printf&#40;"1MyCallbackThread&#58;%d\n", mp3->playTime&#40;&#41;&#41;;
		mp3->update&#40;&#41;;
	&#125;
	delete mp3;
	return 0;
&#125;
int MyCallbackThread1&#40;SceSize args, void *argp&#41; &#123;
	printf&#40;"2new Mp3\n"&#41;;
	Mp3 *mp3 = new Mp3&#40;"ms0&#58;/music.mp3"&#41;;
	mp3->setLoop&#40;true&#41;;
	printf&#40;"2play\n"&#41;;
	mp3->play&#40;&#41;;
	while &#40;1&#41; &#123;
		printf&#40;"2MyCallbackThread&#58;%d\n", mp3->playTime&#40;&#41;&#41;;
		mp3->update&#40;&#41;;
	&#125;
	delete mp3;
	return 0;
&#125;
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41; &#123;
	int thid = 0;

	thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, 0, 0&#41;;
	if &#40;thid >= 0&#41; &#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;

	return thid;
&#125;
// END OF TWILIGHT ZONE! <do doo do do>
int main&#40;&#41; &#123;
	scePowerSetClockFrequency&#40;333, 333, 166&#41;;

	pspDebugScreenInit&#40;&#41;;
	SetupCallbacks&#40;&#41;;

	SceCtrlData pad;

	int thid = 0;

	Mp3&#58;&#58;init&#40;&#41;;
	thid = sceKernelCreateThread&#40;"mythread", MyCallbackThread, 0x11, 0xFA0, 0, 0&#41;;
	if &#40;thid >= 0&#41; &#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;
	thid = sceKernelCreateThread&#40;"mythread1", MyCallbackThread1, 0x11, 0xFA0, 0, 0&#41;;
	if &#40;thid >= 0&#41; &#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;

//	Mp3 *mp3 = new Mp3&#40;"music.mp3"&#41;;
//	mp3->setLoop&#40;true&#41;;
//	mp3->play&#40;&#41;;

	while &#40;1&#41; &#123;
		sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
		if &#40;pad.Buttons & PSP_CTRL_CROSS&#41; &#123;
			break;
		&#125;
		//sceDisplayWaitVblankStart&#40;&#41;;
//		printf&#40;"CallbackThread1&#58;%d\n", mp3->playTime&#40;&#41;&#41;;
//		mp3->update&#40;&#41;;
	&#125;
//	delete mp3;

&#125;
sakya
Posts: 190
Joined: Fri Apr 28, 2006 5:48 pm
Contact:

Post by sakya »

Hi! :)
wxnlyq wrote:1&#12289;Why I can't use a relative path to open a file?
Did you try to change the current dir with sceIoChdir to be sure that the current directory is what you think?

Ciaooo
Sakya
wxnlyq
Posts: 4
Joined: Fri Oct 03, 2008 12:35 pm

Post by wxnlyq »

sakya wrote:Hi! :)
wxnlyq wrote:1&#12289;Why I can't use a relative path to open a file?
Did you try to change the current dir with sceIoChdir to be sure that the current directory is what you think?

Ciaooo
Sakya
music.mp3 is located in the directory where my EBOOT.PBP exits.
In the main, I can use sceIoOpen("music.mp3",...) to open the file,
but in the MyCallbackThread, sceIoOpen("music.mp3",...) fail to find it.

Isn't the current dir different between threads?
theHobbit
Posts: 65
Joined: Sat Sep 30, 2006 5:26 am

Post by theHobbit »

Does anyone have an idea on how to implement a seek function with this library?
homemister
Posts: 25
Joined: Mon Mar 24, 2008 12:16 pm

Post by homemister »

DONE!
Here is the code i used. I uses some of the ID3 functions to get the starting place for the mp3.

Code: Select all

/*
 * PSP Software Development Kit - http&#58;//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 &#40;c&#41; 2008 Alexander Berl <[email protected]>
 *
 * $Id&#58; $
 */
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <stdio.h>
#include <pspaudio.h>
#include <pspmp3.h>
#include <psputility.h>
#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>
#include "../players/id3.h"
#include "../players/player.h"
#include <stdio.h>

#include <string.h>

#include <pspkernel.h>

#include <stdlib.h>
#include <pspiofilemgr.h>

static char mp3Buf&#91;32*1024&#93;  __attribute__&#40;&#40;aligned&#40;64&#41;&#41;&#41;;
static short pcmBuf&#91;32*&#40;1152/2&#41;&#93;  __attribute__&#40;&#40;aligned&#40;64&#41;&#41;&#41;;
//static int fd;
static int playmp3;
static SceUID mp3thread = -1;
static int handle;
static int channel = -1;
static int EOS = 0;
static int paused;
static char *MP3FILE;
static int samplingRate;
static int numChannels;
static int lastDecoded = 0;
static int volume = PSP_AUDIO_VOLUME_MAX;
static int numPlayed = 0;
static int loop = 0;
static short* buf;
static int pos;
static int posreal;
static int endpos;
static int data_starthm;
static int perc;
static SceInt64 res;
static int kbit;
static int size;
static int fillStreamBuffer&#40; int fd, int handle &#41;
&#123;
	char* dst;
	int write;
	// Get Info on the stream &#40;where to fill to, how much to fill, where to fill from&#41;
	sceMp3GetInfoToAddStreamData&#40; handle, &dst, &write, &pos&#41;;
	// Seek file to position requested
	sceIoLseek32Async&#40; fd, posreal, SEEK_SET &#41;;
	sceIoWaitAsync&#40;fd, &res&#41;;
	// Read the amount of data
	sceIoReadAsync&#40; fd, dst, write &#41;;
	sceIoWaitAsync&#40;fd, &res&#41;;
	posreal = posreal + res;
	// Notify mp3 library about how much we really wrote to the stream buffer
	sceMp3NotifyAddStreamData&#40; handle, res &#41;;
	return &#40;pos>0&#41;;
&#125;
int decodeThread2&#40;SceSize args, void *argp&#41;&#123;
	fd = sceIoOpen&#40;MP3FILE, PSP_O_RDONLY, 0777 &#41;;
	sceIoChangeAsyncPriority&#40;fd, 0x10&#41;;

	data_starthm = ID3v2TagSize&#40;MP3FILE&#41;;
	// Init mp3 resources
	sceMp3InitResource&#40;&#41;;
	sceIoLseek32Async&#40;fd, 0, PSP_SEEK_SET&#41;;
	sceIoWaitAsync&#40;fd, &res&#41;;
	sceIoLseek32Async&#40; fd, 0, SEEK_END &#41;;
	sceIoWaitAsync&#40;fd, &res&#41;;
	endpos = res;
	if&#40;data_starthm > &#40;endpos-1000&#41;&#41;&#123;
		data_starthm = 0;
	&#125;
	size = &#40;endpos - data_starthm&#41;;
	posreal = data_starthm;
	// Reserve a mp3 handle for our playback
	SceMp3InitArg mp3Init;
	mp3Init.mp3StreamStart = data_starthm;
	mp3Init.mp3StreamEnd = endpos;
	mp3Init.unk1 = 0;
	mp3Init.unk2 = 0;
	mp3Init.mp3Buf = mp3Buf;
	mp3Init.mp3BufSize = sizeof&#40;mp3Buf&#41;;
	mp3Init.pcmBuf = pcmBuf;
	mp3Init.pcmBufSize = sizeof&#40;pcmBuf&#41;;

	handle = sceMp3ReserveMp3Handle&#40; &mp3Init &#41;;
	
	// Fill the stream buffer with some data so that sceMp3Init has something to work with
	fillStreamBuffer&#40; fd, handle &#41;;
	
	sceMp3Init&#40; handle &#41;;
	numChannels = sceMp3GetMp3ChannelNum&#40; handle &#41;;
	kbit = sceMp3GetBitRate&#40;handle&#41;;
	samplingRate = sceMp3GetSamplingRate&#40;handle&#41;;
	lastDecoded = 0;
	volume = PSP_AUDIO_VOLUME_MAX;
	numPlayed = 0;
	loop = 0;
	while&#40;playmp3&#41;
	&#123;
		while &#40;paused&#41;
		&#123;
			perc = &#40;posreal*100/endpos&#41;;
			if&#40;perc >= 99&#41;&#123;
				EOS = 1;
				paused = 0;
			&#125;
			samplingRate = sceMp3GetSamplingRate&#40;handle&#41;;
			// Check if we need to fill our stream buffer
			if &#40;sceMp3CheckStreamDataNeeded&#40; handle &#41;>0&#41;
			&#123;
				fillStreamBuffer&#40; fd, handle &#41;;
			&#125;
			// Decode some samples
			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 &#40;;retries<1;retries++&#41;
			&#123;
				bytesDecoded = sceMp3Decode&#40; handle, &buf &#41;;
				if &#40;bytesDecoded>0&#41;&#123;
					break;
				&#125;
			
				if &#40;sceMp3CheckStreamDataNeeded&#40; handle &#41;<=0&#41;
					break;
			
				if &#40;!fillStreamBuffer&#40; fd, handle &#41;&#41;
				&#123;
					numPlayed = 0;
				&#125;
			&#125;
			// Reserve the Audio channel for our output if not yet done
			if &#40;channel<0 || lastDecoded!=bytesDecoded&#41;
			&#123;
				if &#40;channel>=0&#41;
					sceAudioSRCChRelease&#40;&#41;;
	
				channel = sceAudioSRCChReserve&#40; bytesDecoded/&#40;2*numChannels&#41;, samplingRate, numChannels &#41;;
			&#125;
			// Output the decoded samples and accumulate the number of played samples to get the playtime
			numPlayed += sceAudioSRCOutputBlocking&#40; volume, buf &#41;;
		&#125;
	sceKernelDelayThread&#40;10000&#41;;
	&#125;
	return 0;
&#125;
/* main routine */
int LoadMp3&#40;char *MP3FILEpath&#41;
&#123;
	playmp3 = 1;
	paused = 0;
	EOS = 0;
	MP3FILE = MP3FILEpath;
	mp3thread = sceKernelCreateThread&#40;"decodeThread2", decodeThread2, 12, 256*1024, PSP_THREAD_ATTR_USER, NULL&#41;;
	sceKernelStartThread&#40;mp3thread, 0, NULL&#41;;
	return data_starthm;
				//sceMp3ResetPlayPosition&#40; handle &#41;;
&#125;
void PlayMp3&#40;&#41;
&#123;
	playmp3 = 1;
	paused = 1;
	EOS = 0;
&#125;
void PauseMp3&#40;&#41;
&#123;
	if&#40;paused == 1&#41;&#123;
		paused = 0;
	&#125;else&#123;
		paused = 1;
	&#125;
&#125;
void LoopMp3&#40;int num&#41;
&#123;
	sceMp3SetLoopNum&#40;handle, num&#41;;
&#125;
void StopMp3&#40;void&#41;
&#123;
	playmp3 = 0;
	paused = 0;
	EOS = 0;
	sceKernelWaitThreadEnd&#40;mp3thread, NULL&#41;;

    	sceKernelDeleteThread&#40;mp3thread&#41;;
	if &#40;channel>=0&#41;
		sceAudioSRCChRelease&#40;&#41;;
	sceMp3ReleaseMp3Handle&#40; handle &#41;;
	sceMp3TermResource&#40;&#41;;
	sceIoClose&#40; fd &#41;;
&#125;
int getPos&#40;void&#41;&#123;

    return posreal;

&#125;


int setPos&#40;int value&#41;&#123;
	posreal = value;

    return posreal;

&#125;
int GetTime&#40;void&#41;&#123;

   int playTime = samplingRate>0?&#40;posreal*8&#41; / &#40;kbit*1024&#41;&#58;0;
   return playTime;

&#125;
short *VisMp3&#40;void&#41; &#123;
	return&#40;buf&#41;;
&#125;
int EOSMp3&#40;void&#41;&#123;

    return EOS;

&#125;
int PercentMp3&#40;void&#41;&#123;

    return perc;

&#125;
void setvolume&#40;int num&#41;&#123;
    volume = 327.68*num;

&#125;
char *Mp3Filename&#40;&#41;&#123;

    return MP3FILE;

&#125;
int rawlength&#40;&#41;&#123;
	return &#40;&#40;size*8&#41; / &#40;kbit*1024&#41;&#41;;
&#125;
static void getMP3TagInfo&#40;char *filename, struct fileInfo *targetInfo&#41;&#123;

    //ID3&#58;

    struct ID3Tag ID3;

    ID3 = ParseID3&#40;filename&#41;;

    strcpy&#40;targetInfo->title, ID3.ID3Title&#41;;

    strcpy&#40;targetInfo->artist, ID3.ID3Artist&#41;;

    strcpy&#40;targetInfo->album, ID3.ID3Album&#41;;

    strcpy&#40;targetInfo->year, ID3.ID3Year&#41;;

    strcpy&#40;targetInfo->genre, ID3.ID3GenreText&#41;;

    strcpy&#40;targetInfo->trackNumber, ID3.ID3TrackText&#41;;

    targetInfo->encapsulatedPictureType = ID3.ID3EncapsulatedPictureType;

    targetInfo->encapsulatedPictureOffset = ID3.ID3EncapsulatedPictureOffset;

    targetInfo->encapsulatedPictureLength = ID3.ID3EncapsulatedPictureLength;

&#125;
struct fileInfo Taginfo2&#40;char *filename&#41;&#123;

    struct fileInfo tempInfo;

    initFileInfo&#40;&tempInfo&#41;;
    getMP3TagInfo&#40;filename, &tempInfo&#41;;

    return tempInfo;

&#125;

struct fileInfo Taginfo&#40;char *filename&#41;&#123;

    struct fileInfo tempInfo;

    initFileInfo&#40;&tempInfo&#41;;
    getMP3TagInfo&#40;filename, &tempInfo&#41;;
    tempInfo.kbit = kbit;
    tempInfo.hz = samplingRate;
	if&#40;numChannels < 2&#41;&#123;
		sprintf&#40;tempInfo.mode,"mono"&#41;;
	&#125;else&#123;
		sprintf&#40;tempInfo.mode,"stereo"&#41;;
	&#125;
	int secs = &#40;size*8&#41; / &#40;kbit*1024&#41;;
	int h = secs / 3600;

	int m = &#40;secs - h * 3600&#41; / 60;

	int s = secs - h * 3600 - m * 60;

	snprintf&#40;tempInfo.strLength, sizeof&#40;tempInfo.strLength&#41;, "%2.2i&#58;%2.2i&#58;%2.2i", h, m, s&#41;;

	return tempInfo;

&#125;
theHobbit
Posts: 65
Joined: Sat Sep 30, 2006 5:26 am

Post by theHobbit »

Thanks, i will give it a try. Do you know if this works with 48k samplerate?

I've been trying to play a song with 48k with no luck :(
willow :--)
Posts: 107
Joined: Sat Jan 13, 2007 11:50 am

Slowness issues ?

Post by willow :--) »

I've tried to use the sample in order to decode some mp3s, and it works fine as long I don't try to do anything else, but the sound becomes choppy whenever my app does an access to the disk, and overall adding mp3 output slows my application, a lot.
I have the following questions:

1) would increasing the sizes of mp3Buf and/or pcmBuf (as defined in Raphael's sample) help ? If so, why, and what would be the drawbacks ?

2) Would putting the mp3 playing routine in a separate thread help ? And if so, why ? (I have close to no knowledge in threads)

3) any other suggestion ?

Basically my main loop looks like this (pseudo code):

Code: Select all

while &#40;1&#41;&#123;
 update sound 
 update data
 render on screen
&#125;
The "update sound" is basically the update method defined in wxnlyq's code a few posts above
Update data does some processing, checks user input, and sometimes loads files on the disk. When this happens, the sound becomes choppy.

(I was using Cooleye's method, in a separate thread until now, but I have weird problems with it and thought it'd be better to use the "latest" method)
willow :--)
Posts: 107
Joined: Sat Jan 13, 2007 11:50 am

Re: Slowness issues ?

Post by willow :--) »

replying to myself:
willow :--) wrote: 1) would increasing the sizes of mp3Buf and/or pcmBuf (as defined in Raphael's sample) help ? If so, why, and what would be the drawbacks ?
No, that didn't help.
2) Would putting the mp3 playing routine in a separate thread help ?
Yes, that did the trick !
Art
Posts: 642
Joined: Wed Nov 09, 2005 8:01 am

Post by Art »

Here is the code i used. I uses some of the ID3 functions to get the starting place for the mp3.
I have a late SDK with this mp3 sample, but where can I find id3.h and player.h ?
Art.
If not actually, then potentially.
Insert_witty_name
Posts: 376
Joined: Wed May 10, 2006 11:31 pm

Post by Insert_witty_name »

It's in Sakya's lightMP3 source code IIRC.
jsharrad
Posts: 100
Joined: Thu Oct 20, 2005 3:06 am

Post by jsharrad »

Surely homemeister wouldn't be using sakya's GPL player code in his non GPL luaplayer? :P
Post Reply