#include "interface.h" #define MINIMP3_IMPLEMENTATION #include "minimp3_ex.h" #include "vaudio/ivaudio.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" struct AudioStream_s { IAudioStreamEvent *stream_event; int offset; unsigned int decode_size; }; size_t mp3dec_read_callback(void *buf, size_t size, void *user_data) { AudioStream_s *stream = static_cast( (void*)user_data); int ret_size = stream->stream_event->StreamRequestData( buf, size, stream->offset ); // printf("mp3dec_read_callback size: %d, ret_size: %d\n", (int)size, ret_size); stream->offset += ret_size; return ret_size; } int mp3dec_seek_callback(uint64_t position, void *user_data) { struct AudioStream_s *stream = static_cast( (void*)user_data); stream->offset = position; // printf("mp3dec_seek_callback position: %d\n", (int)position); return 0; } class CMiniMP3 : public IAudioStream { public: bool Init( IAudioStreamEvent *pHandler ); // IAudioStream functions virtual int Decode( void *pBuffer, unsigned int bufferSize ); virtual int GetOutputBits(); virtual int GetOutputRate(); virtual int GetOutputChannels(); virtual unsigned int GetPosition(); virtual void SetPosition( unsigned int position ); private: short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME]; mp3dec_ex_t mp3d; mp3dec_io_t mp3io; struct AudioStream_s audio_stream; }; bool CMiniMP3::Init( IAudioStreamEvent *pHandler ) { // printf("CMiniMP3::Init\n"); audio_stream.stream_event = pHandler; audio_stream.offset = 0; audio_stream.decode_size = 0; mp3io.read = &mp3dec_read_callback; mp3io.read_data = &audio_stream; mp3io.seek = &mp3dec_seek_callback; mp3io.seek_data = &audio_stream; if( mp3dec_ex_open_cb(&mp3d, &mp3io, MP3D_SEEK_TO_SAMPLE) ) { // printf("mp3dec_ex_open_cb failed\n"); return false; } if ( mp3dec_ex_seek(&mp3d, 0) ) { // printf("mp3dec_ex_seek failed\n"); return false; } return true; } // IAudioStream functions int CMiniMP3::Decode( void *pBuffer, unsigned int bufferSize ) { size_t readed = mp3dec_ex_read(&mp3d, (mp3d_sample_t*)pBuffer, bufferSize/2); return readed*2; } int CMiniMP3::GetOutputBits() { return 16; } int CMiniMP3::GetOutputRate() { return mp3d.info.hz; } int CMiniMP3::GetOutputChannels() { return mp3d.info.channels; } unsigned int CMiniMP3::GetPosition() { return audio_stream.offset; } void CMiniMP3::SetPosition( unsigned int position ) { audio_stream.offset = position; mp3dec_ex_seek(&mp3d, position); } class CVAudio : public IVAudio { public: IAudioStream *CreateMP3StreamDecoder( IAudioStreamEvent *pEventHandler ) { CMiniMP3 *pMP3 = new CMiniMP3; if ( !pMP3->Init( pEventHandler ) ) { delete pMP3; return NULL; } return pMP3; } void DestroyMP3StreamDecoder( IAudioStream *pDecoder ) { delete pDecoder; } }; EXPOSE_INTERFACE( CVAudio, IVAudio, VAUDIO_INTERFACE_VERSION );