diff --git a/engine/common/soundlib/snd_mp3.c b/engine/common/soundlib/snd_mp3.c index a512bee7..9e85d3b9 100644 --- a/engine/common/soundlib/snd_mp3.c +++ b/engine/common/soundlib/snd_mp3.c @@ -12,8 +12,8 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ - #include "soundlib.h" +#if !XASH_PSP #include "libmpg/libmpg.h" /* @@ -117,12 +117,8 @@ stream_t *Stream_OpenMPG( const char *filename ) file_t *file; int ret; wavinfo_t sc; -#if XASH_PSP - // h - hold mode - file = FS_Open( filename, "rbh", false ); -#else + file = FS_Open( filename, "rb", false ); -#endif if( !file ) return NULL; // at this point we have valid stream @@ -190,7 +186,7 @@ int Stream_ReadMPG( stream_t *stream, int needBytes, void *buffer ) // check remaining size if( bytesWritten + stream->pos > needBytes ) - outsize = ( needBytes - bytesWritten ); + outsize = ( needBytes - bytesWritten ); else outsize = stream->pos; // copy raw sample to output buffer @@ -265,3 +261,485 @@ void Stream_FreeMPG( stream_t *stream ) Mem_Free( stream ); } + +#else // XASH_PSP +#include "platform/psp/scemp3/pspmp3.h" + +/* +================================================================= + + PSP MPEG decoding + +================================================================= +*/ +#define MP3_ID3V1_ID "TAG" +#define MP3_ID3V1_ID_SZ 3 +#define MP3_ID3V1_SZ 128 + +#define MP3_ID3V2_ID "ID3" +#define MP3_ID3V2_ID_SZ 3 +#define MP3_ID3V2_SIZE_OFF 6 +#define MP3_ID3V2_SIZE_SZ 4 +#define MP3_ID3V2_HEADER_SZ 10 + +#define MP3_ERRORS_MAX 3 + +#define PCM_WIDTH 2 // always 16-bit PCM +#define PCM_CHANNELS 2 // always 2 + +#define MP3_BUFFER_SIZE ( 128 * 1024 ) +#define PCM_BUFFER_SIZE (( 1152 * PCM_WIDTH * PCM_CHANNELS ) * 2 ) // framesample * width * channels * 2(double buffer) + +typedef struct +{ + int handle; + int cachePos; + int frameCount; + byte *pcmTempPtr; +} mp3_decoder_t; + +/* +================= +Sound_GetID3V2SizeMPG +================= +*/ +__inline int Sound_GetID3V2SizeMPG( const byte *tagSize ) +{ + int size; + byte *sizePtr = (byte*)&size; + + // 7 bit per byte, invert endian + sizePtr[0] = (( tagSize[3] >> 0 ) & 0x7F ) | (( tagSize[2] & 0x01 ) << 7 ); + sizePtr[1] = (( tagSize[2] >> 1 ) & 0x3F ) | (( tagSize[1] & 0x03 ) << 6 ); + sizePtr[2] = (( tagSize[1] >> 2 ) & 0x1F ) | (( tagSize[0] & 0x07 ) << 5 ); + sizePtr[3] = (( tagSize[0] >> 3 ) & 0x0F ); + + return size; +} + +#if 0 +/* +================= +Sound_FindHeadMPG +================= +*/ +fs_offset_t Sound_FindHeadMPG( const byte *buffer, fs_offset_t filesize ) +{ + fs_offset_t result; + + result = 0; + if( filesize >= MP3_ID3V2_HEADER_SZ ) + { + if( !memcmp( buffer, MP3_ID3V2_ID, MP3_ID3V2_ID_SZ )) + result = Sound_GetID3V2SizeMPG( &buffer[MP3_ID3V2_SIZE_OFF] ) + MP3_ID3V2_HEADER_SZ; + } + return result; +} + +/* +================= +Sound_FindTailMPG +================= +*/ +fs_offset_t Sound_FindTailMPG( const byte *buffer, fs_offset_t filesize ) +{ + fs_offset_t result; + + result = filesize; + if( filesize >= MP3_ID3V1_SZ ) + { + if( !memcmp( &buffer[filesize - MP3_ID3V1_SZ], MP3_ID3V1_ID, MP3_ID3V1_ID_SZ )) + result -= MP3_ID3V1_SZ; + } + return result; +} +#endif + +qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesize ) +{ +#if 0 + int status; + int handle; + size_t bytesWrite = 0; + byte out[PCM_BUFFER_SIZE] __attribute__((aligned(64))); + fs_offset_t headOffset; + fs_offset_t tailOffset; + fs_offset_t contentSize; + int frameSample; + uint bps; + int frameLen; + int frameSize; + int frameCount; + + headOffset = Sound_FindHeadMPG( buffer, filesize ); + tailOffset = Sound_FindTailMPG( buffer, filesize ); + contentSize = tailOffset - headOffset; + // TODO: read Xing header + + handle = sceMp3ReserveMp3Handle( NULL ); + if ( handle < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3ReserveMp3Handle returned 0x%08X\n", handle ); + return false; + } + + status = sceMp3LowLevelInit( handle, &buffer[headOffset] ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3LowLevelInit returned 0x%08X\n", status ); + return false; + } + + frameSample = sceMp3GetMaxOutputSample( handle ); + frameSize = (( frameSample / 8 ) * sceMp3GetBitRate( handle ) * 1000 ) / sceMp3GetSamplingRate( handle ); + frameCount = contentSize / frameSize; + + sound.channels = sceMp3GetMp3ChannelNum( handle ); + sound.rate = sceMp3GetSamplingRate( handle ); + sound.width = PCM_WIDTH; // always 16-bit PCM + sound.loopstart = -1; + sound.size = (frameCount * frameSample) * sound.channels * sound.width; // invalid for VBR +/* + status = sceMp3LowLevelDecode(handle, &buffer[headOffset + mp3usedsize], &mp3usedsize, pcm, &pcmoutsize); + if(status < 0) + { + Con_DPrintf( S_ERROR "sceMp3LowLevelDecode returned 0x%08X\n", status); + } + sceMp3ReleaseMp3Handle( handle ); +*/ + return true; +#else + Con_DPrintf( S_ERROR "Sound_LoadMPG unimplemented function!\n"); + return false; +#endif +} + +/* +================= +Stream_FindHeadMPG +================= +*/ +SceOff Stream_FindHeadMPG( file_t *file ) +{ + SceOff result; + byte tagId[MP3_ID3V2_ID_SZ]; + byte tagSize[MP3_ID3V2_SIZE_SZ]; + + result = 0; + + FS_Seek( file, 0, SEEK_SET ); + + if( FS_Read( file, tagId, MP3_ID3V2_ID_SZ) < MP3_ID3V2_ID_SZ ) + { + Con_DPrintf( S_ERROR "Sound_Mp3FindHead: ID3V2 ID read error\n"); + return result; + } + + if( !memcmp( tagId, MP3_ID3V2_ID, MP3_ID3V2_ID_SZ )) + { + FS_Seek( file, MP3_ID3V2_SIZE_OFF, SEEK_SET ); + if( FS_Read( file, tagSize, MP3_ID3V2_SIZE_SZ ) < MP3_ID3V2_SIZE_SZ ) + Con_DPrintf( S_ERROR "Sound_Mp3FindHead: ID3V2 SIZE read error\n"); + else result = Sound_GetID3V2SizeMPG( tagSize ) + MP3_ID3V2_HEADER_SZ; + } + + return result; +} + +/* +================= +Stream_FindTailMPG +================= +*/ +SceOff Stream_FindTailMPG( file_t *file ) +{ + SceOff result; + byte tagId[MP3_ID3V1_ID_SZ]; + + result = FS_FileLength( file ); + + FS_Seek( file, result - MP3_ID3V1_SZ, SEEK_SET ); + + if( FS_Read( file, tagId, MP3_ID3V1_ID_SZ ) < MP3_ID3V1_ID_SZ ) + { + Con_DPrintf( S_ERROR "Sound_Mp3FindTail: ID3V1 ID read error\n"); + return result; + } + + if( !memcmp( tagId, MP3_ID3V1_ID, MP3_ID3V1_ID_SZ )) + result -= MP3_ID3V1_SZ; + + return result; +} + +/* +================= +Stream_FillBufferMPG +================= +*/ +int Stream_FillBufferMPG( file_t *file, mp3_decoder_t *desc ) +{ + int status; + byte *dstPtr; + int dstSize; + int dstPos; + fs_offset_t readSize; + + if( sceMp3CheckStreamDataNeeded( desc->handle ) <= 0 ) + return 0; + + // get Info on the stream (where to fill to, how much to fill, where to fill from) + status = sceMp3GetInfoToAddStreamData( desc->handle, &dstPtr, &dstSize, &dstPos ); + if( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3GetInfoToAddStreamData returned 0x%08X\n", status); + return status; + } + + // seek file to position requested + if( desc->cachePos != dstPos ) + { + FS_Seek( file, dstPos, SEEK_SET ); + desc->cachePos = dstPos; + } + + // read the amount of data + readSize = FS_Read( file, dstPtr, dstSize ); + desc->cachePos += ( int )readSize; + + // notify mp3 library about how much we really wrote to the stream buffer + status = sceMp3NotifyAddStreamData( desc->handle, ( int )readSize ); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceMp3NotifyAddStreamData returned 0x%08X\n", status); + + return status; +} + +/* +================= +Stream_OpenMPG +================= +*/ +stream_t *Stream_OpenMPG( const char *filename ) +{ + stream_t *stream; + mp3_decoder_t *desc; + file_t *file; + int status; + void *bufferBase; + + file = FS_Open( filename, "rbh", false ); // hold mode + if( !file ) return NULL; + + // at this point we have valid stream + stream = Mem_Calloc( host.soundpool, sizeof( stream_t )); + stream->file = file; + stream->pos = 0; + + desc = Mem_Calloc( host.soundpool, sizeof( mp3_decoder_t ) + MP3_BUFFER_SIZE + PCM_BUFFER_SIZE + 63 ); + bufferBase = (void *)(((( uintptr_t )desc + sizeof( mp3_decoder_t )) & (~( 64 - 1 ))) + 64 ); + + // reserve a mp3 handle + SceMp3InitArg mp3Init; + mp3Init.mp3StreamStart = Stream_FindHeadMPG( file ); + mp3Init.mp3StreamEnd = Stream_FindTailMPG( file ); + mp3Init.mp3Buf = bufferBase; + mp3Init.mp3BufSize = MP3_BUFFER_SIZE; + mp3Init.pcmBuf = (void *)(( uintptr_t )bufferBase + MP3_BUFFER_SIZE ); + mp3Init.pcmBufSize = PCM_BUFFER_SIZE; + + desc->cachePos = 0; + desc->pcmTempPtr = mp3Init.pcmBuf; + desc->handle = sceMp3ReserveMp3Handle( &mp3Init ); + if ( desc->handle < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3ReserveMp3Handle returned 0x%08X\n", desc->handle ); + Mem_Free( stream ); + Mem_Free( desc ); + FS_Close( file ); + return NULL; + } + + // Fill the stream buffer with some data so that sceMp3Init has something to work with + if( Stream_FillBufferMPG( file, desc ) != 0 ) + { + Mem_Free( stream ); + Mem_Free( desc ); + FS_Close( file ); + return NULL; + } + + status = sceMp3Init( desc->handle ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3Init returned 0x%08X\n", status ); + Mem_Free( stream ); + Mem_Free( desc ); + FS_Close( file ); + return NULL; + } + + desc->frameCount = sceMp3GetFrameNum( desc->handle ); + + stream->buffsize = 0; // how many samples left from previous frame + stream->channels = PCM_CHANNELS; // always 2 PCM channels + stream->rate = sceMp3GetSamplingRate( desc->handle ); + stream->width = PCM_WIDTH; // always 16 bit PCM + stream->ptr = (void *)desc; + stream->type = WF_MPGDATA; + + return stream; +} + +/* +================= +Stream_ReadMPG + +assume stream is valid +================= +*/ +int Stream_ReadMPG( stream_t *stream, int needBytes, void *buffer ) +{ + // buffer handling + int bytesWritten = 0; + mp3_decoder_t *desc; + int errdec; + + desc = ( mp3_decoder_t* )stream->ptr; + + while(1) + { + byte *data; + int outsize; + + if( !stream->buffsize ) + { + // Check if we need to fill our stream buffer + if( Stream_FillBufferMPG( stream->file, desc ) != 0 ) + return 0; + + for( errdec = 0; errdec < MP3_ERRORS_MAX; errdec++ ) + { + stream->pos = sceMp3Decode( desc->handle, (SceShort16**)&desc->pcmTempPtr ); + if(( int )stream->pos >= 0 ) // decoding successful + { + break; + } + else if( stream->pos == 0x80671402 ) // next frame header + { + if( Stream_FillBufferMPG( stream->file, desc ) != 0 ) + return 0; + } + else break; + } + + if(( int )stream->pos < 0 ) + { + if( stream->pos != 0x80671402 ) + Con_DPrintf( S_ERROR "sceMp3Decode returned 0x%08X\n", stream->pos ); + return 0; // ??? + } + } + + // check remaining size + if( bytesWritten + stream->pos > needBytes ) + outsize = ( needBytes - bytesWritten ); + else outsize = stream->pos; + + // copy raw sample to output buffer + data = (byte *)buffer + bytesWritten; + memcpy( data, &desc->pcmTempPtr[stream->buffsize], outsize ); + bytesWritten += outsize; + stream->pos -= outsize; + stream->buffsize += outsize; + + // continue from this sample on a next call + if( bytesWritten >= needBytes ) + return bytesWritten; + + stream->buffsize = 0; // no bytes remaining + } + + return 0; +} + +/* +================= +Stream_SetPosMPG + +assume stream is valid +================= +*/ +int Stream_SetPosMPG( stream_t *stream, int newpos ) +{ + mp3_decoder_t *desc; + int frame; + int status; + + desc = ( mp3_decoder_t* )stream->ptr; + + // get frame num + frame = newpos / sceMp3GetMaxOutputSample( desc->handle ); // VBR? + + if( frame < 1 || frame >= desc->frameCount - 1 ) + return false; + + status = sceMp3ResetPlayPositionByFrame( desc->handle, frame ); + if( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3ResetPlayPositionByFrame returned 0x%08X\n", status ); + + // failed to seek for some reasons + return false; + } + + // flush any previous data + stream->buffsize = 0; + + return true; +} + +/* +================= +Stream_GetPosMPG + +assume stream is valid +================= +*/ +int Stream_GetPosMPG( stream_t *stream ) +{ + mp3_decoder_t *desc; + + desc = ( mp3_decoder_t * )stream->ptr; + + return sceMp3GetSumDecodedSample( desc->handle ); +} + +/* +================= +Stream_FreeMPG + +assume stream is valid +================= +*/ +void Stream_FreeMPG( stream_t *stream ) +{ + mp3_decoder_t *desc; + + desc = ( mp3_decoder_t * )stream->ptr; + if( desc ) + { + sceMp3ReleaseMp3Handle( desc->handle ); + Mem_Free( desc ); + stream->ptr = NULL; + } + + if( stream->file ) + { + FS_Close( stream->file ); + stream->file = NULL; + } + + Mem_Free( stream ); +} +#endif // XASH_PSP diff --git a/engine/common/soundlib/soundlib.h b/engine/common/soundlib/soundlib.h index 686d50b1..d94bec17 100644 --- a/engine/common/soundlib/soundlib.h +++ b/engine/common/soundlib/soundlib.h @@ -74,7 +74,9 @@ struct stream_s // current stream state void *ptr; // internal decoder state +#if !XASH_PSP char temp[OUTBUF_SIZE]; // mpeg decoder stuff +#endif size_t pos; // actual track position (or actual buffer remains) int buffsize; // cached buffer size }; diff --git a/engine/platform/psp/scemp3/pspmp3.h b/engine/platform/psp/scemp3/pspmp3.h new file mode 100644 index 00000000..cc40773d --- /dev/null +++ b/engine/platform/psp/scemp3/pspmp3.h @@ -0,0 +1,248 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * pspmp3.h - Prototypes for the sceMp3 library + * + * Copyright (c) 2008 David Perry + * Copyright (c) 2008 Alexander Berl + * Copyright (c) 2022 Sergey Galushko + * + */ + +#ifndef __SCELIBMP3_H__ +#define __SCELIBMP3_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SceMp3InitArg { + /** Stream start position */ + SceOff mp3StreamStart; + /** Stream end position */ + SceOff mp3StreamEnd; + /** Pointer to a buffer to contain raw mp3 stream data (+1472 bytes workspace) */ + SceUChar8* mp3Buf; + /** Size of mp3Buf buffer (must be >= 8192) */ + SceInt32 mp3BufSize; + /** Pointer to decoded pcm samples buffer */ + SceUChar8* pcmBuf; + /** Size of pcmBuf buffer (must be >= 9216) */ + SceInt32 pcmBufSize; +} SceMp3InitArg; + +/** + * sceMp3ReserveMp3Handle + * + * @param args - Pointer to SceMp3InitArg structure + * + * @return sceMp3 handle on success, < 0 on error. + */ +SceInt32 sceMp3ReserveMp3Handle(SceMp3InitArg* args); + +/** + * sceMp3ReleaseMp3Handle + * + * @param handle - sceMp3 handle + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3ReleaseMp3Handle(SceInt32 handle); + +/** + * sceMp3InitResource + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3InitResource(); + +/** + * sceMp3TermResource + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3TermResource(); + +/** + * sceMp3Init + * + * @param handle - sceMp3 handle + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3Init(SceInt32 handle); + +/** + * sceMp3Decode + * + * @param handle - sceMp3 handle + * @param dst - Pointer to destination pcm samples buffer + * + * @return 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 + * + * @return 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 + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3NotifyAddStreamData(SceInt32 handle, SceInt32 size); + +/** + * sceMp3CheckStreamDataNeeded + * + * @param handle - sceMp3 handle + * + * @return 1 if more stream data is needed, < 0 on error. + */ +SceInt32 sceMp3CheckStreamDataNeeded(SceInt32 handle); + +/** + * sceMp3SetLoopNum + * + * @param handle - sceMp3 handle + * @param loop - Number of loops + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3SetLoopNum(SceInt32 handle, SceInt32 loop); + +/** + * sceMp3GetLoopNum + * + * @param handle - sceMp3 handle + * + * @return Number of loops + */ +SceInt32 sceMp3GetLoopNum(SceInt32 handle); + +/** + * sceMp3GetSumDecodedSample + * + * @param handle - sceMp3 handle + * + * @return Number of decoded samples + */ +SceInt32 sceMp3GetSumDecodedSample(SceInt32 handle); + +/** + * sceMp3GetMaxOutputSample + * + * @param handle - sceMp3 handle + * + * @return Number of max samples to output + */ +SceInt32 sceMp3GetMaxOutputSample(SceInt32 handle); + +/** + * sceMp3GetSamplingRate + * + * @param handle - sceMp3 handle + * + * @return Sampling rate of the mp3 + */ +SceInt32 sceMp3GetSamplingRate(SceInt32 handle); + +/** + * sceMp3GetBitRate + * + * @param handle - sceMp3 handle + * + * @return Bitrate of the mp3 + */ +SceInt32 sceMp3GetBitRate(SceInt32 handle); + +/** + * sceMp3GetMp3ChannelNum + * + * @param handle - sceMp3 handle + * + * @return Number of channels of the mp3 + */ +SceInt32 sceMp3GetMp3ChannelNum(SceInt32 handle); + +/** + * sceMp3ResetPlayPosition + * + * @param handle - sceMp3 handle + * + * @return < 0 on error + */ +SceInt32 sceMp3ResetPlayPosition(SceInt32 handle); + +/** + * sceMp3GetFrameNum + * + * @param handle - sceMp3 handle + * + * @return < 0 on error + */ +SceInt32 sceMp3GetFrameNum(SceInt32 handle); + +/** + * sceMp3ResetPlayPositionByFrame + * + * @param handle - sceMp3 handle + * @param frame - frame + * + * @return < 0 on error + */ +SceInt32 sceMp3ResetPlayPositionByFrame(SceInt32 handle, SceUInt32 frame); + +/** + * sceMp3GetMPEGVersion + * + * @param handle - sceMp3 handle + * + * @return < 0 on error + */ +SceInt32 sceMp3GetMPEGVersion(SceInt32 handle); + +/** + * sceMp3LowLevelInit + * + * @param handle - sceMp3 handle + * @param src - Pointer to a buffer to contain raw mp3 stream data + * + * @return < 0 on error + */ +SceInt32 sceMp3LowLevelInit(SceInt32 handle, SceUChar8* src); + +/** + * sceMp3LowLevelDecode + * + * @param handle - sceMp3 handle + * @param mp3src - + * @param mp3srcused - + * @param pcmdst - + * @param pcmdstoutsz - + * + * @return < 0 on error + */ +SceInt32 sceMp3LowLevelDecode(SceInt32 handle, SceUChar8* mp3src, SceUInt32* mp3srcused, SceShort16* pcmdst, SceUInt32* pcmdstoutsz); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/platform/psp/scemp3/sceMp3.S b/engine/platform/psp/scemp3/sceMp3.S new file mode 100644 index 00000000..7f5d798e --- /dev/null +++ b/engine/platform/psp/scemp3/sceMp3.S @@ -0,0 +1,29 @@ + .set noreorder + +#include "pspimport.s" + + IMPORT_START "sceMp3",0x00090011 + IMPORT_FUNC "sceMp3",0x07EC321A,sceMp3ReserveMp3Handle + IMPORT_FUNC "sceMp3",0x0DB149F4,sceMp3NotifyAddStreamData + IMPORT_FUNC "sceMp3",0x2A368661,sceMp3ResetPlayPosition + IMPORT_FUNC "sceMp3",0x354D27EA,sceMp3GetSumDecodedSample + IMPORT_FUNC "sceMp3",0x35750070,sceMp3InitResource + IMPORT_FUNC "sceMp3",0x3C2FA058,sceMp3TermResource + IMPORT_FUNC "sceMp3",0x3CEF484F,sceMp3SetLoopNum + IMPORT_FUNC "sceMp3",0x44E07129,sceMp3Init + IMPORT_FUNC "sceMp3",0x732B042A,sceMp3EndEntry + IMPORT_FUNC "sceMp3",0x7F696782,sceMp3GetMp3ChannelNum + IMPORT_FUNC "sceMp3",0x87677E40,sceMp3GetBitRate + IMPORT_FUNC "sceMp3",0x87C263D1,sceMp3GetMaxOutputSample + IMPORT_FUNC "sceMp3",0x8AB81558,sceMp3StartEntry + IMPORT_FUNC "sceMp3",0x8F450998,sceMp3GetSamplingRate + IMPORT_FUNC "sceMp3",0xA703FE0F,sceMp3GetInfoToAddStreamData + IMPORT_FUNC "sceMp3",0xD021C0FB,sceMp3Decode + IMPORT_FUNC "sceMp3",0xD0A56296,sceMp3CheckStreamDataNeeded + IMPORT_FUNC "sceMp3",0xD8F54A51,sceMp3GetLoopNum + IMPORT_FUNC "sceMp3",0xF5478233,sceMp3ReleaseMp3Handle + IMPORT_FUNC "sceMp3",0xAE6D2027,sceMp3GetMPEGVersion + IMPORT_FUNC "sceMp3",0x3548AEC8,sceMp3GetFrameNum + IMPORT_FUNC "sceMp3",0x0840E808,sceMp3ResetPlayPositionByFrame + IMPORT_FUNC "sceMp3",0x1B839B83,sceMp3LowLevelInit + IMPORT_FUNC "sceMp3",0xE3EE2C81,sceMp3LowLevelDecode diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index eba7a9e0..3cea58df 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -15,12 +15,14 @@ GNU General Public License for more details. #include "platform/platform.h" #include "platform/psp/ka/ka.h" +#include "platform/psp/scemp3/pspmp3.h" #include #include #include #include #include #include +#include #include @@ -30,6 +32,8 @@ PSP_MAIN_THREAD_ATTR( PSP_THREAD_ATTR_USER | PSP_THREAD_ATTR_VFPU ); PSP_MAIN_THREAD_STACK_SIZE_KB( 512 ); PSP_HEAP_SIZE_KB( -3 * 1024 ); /* 3 MB for prx modules */ +static qboolean psp_audiolib_init = false; + static int Platform_ExitCallback( int count, int arg, void *common ) { host.crashed = true; @@ -251,10 +255,68 @@ int Platform_UnloadModule( SceUID modid, int *sce_code ) return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); } +int Platform_InitAudioLibs( void ) +{ + int status; + + if( psp_audiolib_init ) + return -1; + + status = sceUtilityLoadModule( PSP_MODULE_AV_AVCODEC ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status ); + return status; + } + + status = sceUtilityLoadModule( PSP_MODULE_AV_MP3 ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceUtilityLoadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status ); + return status; + } + + // init mp3 resources + status = sceMp3InitResource(); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3InitResource returned 0x%08X\n", status ); + return status; + } + + psp_audiolib_init = true; + + return 0; +} + +int Platform_ShutdownAudioLibs( void ) +{ + int status; + + if( !psp_audiolib_init ) + return -1; + + status = sceMp3TermResource(); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceMp3TermResource returned 0x%08X\n", status ); + + status = sceUtilityUnloadModule( PSP_MODULE_AV_MP3 ); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceUtilityUnloadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status ); + + status = sceUtilityUnloadModule( PSP_MODULE_AV_AVCODEC ); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status ); + + psp_audiolib_init = false; + + return 0; +} + void Platform_Init( void ) { - SceUID kamID; - int result; + SceUID kamID; + int result; // disable fpu exceptions (division by zero and etc...) pspSdkDisableFPUExceptions(); @@ -275,13 +337,16 @@ void Platform_Init( void ) Platform_UnloadModule( kamID, &result ); } + Platform_InitAudioLibs(); + // P5 Ram init - P5Ram_Init(); + P5Ram_Init(); } void Platform_Shutdown( void ) { P5Ram_Shutdown(); + Platform_ShutdownAudioLibs(); #if XASH_PROFILING gprof_cleanup(); #endif diff --git a/engine/wscript b/engine/wscript index 18e26531..9a8df89e 100644 --- a/engine/wscript +++ b/engine/wscript @@ -95,9 +95,11 @@ def build(bld): 'common/*.c', 'common/imagelib/*.c', 'common/soundlib/*.c', - 'common/soundlib/libmpg/*.c', 'server/*.c']) + if bld.env.DEST_OS != 'psp': + source += bld.path.ant_glob(['common/soundlib/libmpg/*.c']) + # basic build: dedicated only, no dependencies if bld.env.DEST_OS == 'win32': libs += ['USER32', 'SHELL32', 'GDI32', 'ADVAPI32', 'DBGHELP', 'PSAPI', 'WS2_32' ]