2020-11-14 12:54:58 +00:00
|
|
|
#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"
|
2020-11-15 19:04:09 +00:00
|
|
|
#include <csignal>
|
2020-11-14 12:54:58 +00:00
|
|
|
|
|
|
|
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<AudioStream_s*>( (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<AudioStream_s*>( (void*)user_data);
|
|
|
|
stream->offset = position;
|
|
|
|
printf("mp3dec_seek_callback position: %d\n", (int)position);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
class CMiniMP3 : public IAudioStream
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CMiniMP3();
|
|
|
|
bool Init( IAudioStreamEvent *pHandler );
|
|
|
|
~CMiniMP3();
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
};
|
|
|
|
|
|
|
|
CMiniMP3::CMiniMP3()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CMiniMP3::~CMiniMP3()
|
|
|
|
{
|
2020-11-14 20:17:36 +00:00
|
|
|
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IAudioStream functions
|
|
|
|
int CMiniMP3::Decode( void *pBuffer, unsigned int bufferSize )
|
|
|
|
{
|
2020-11-14 20:17:36 +00:00
|
|
|
size_t readed = mp3dec_ex_read(&mp3d, pBuffer, bufferSize/2);
|
|
|
|
return readed*2;
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CMiniMP3::GetOutputBits()
|
|
|
|
{
|
2020-11-15 19:04:09 +00:00
|
|
|
return 16;
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CMiniMP3::GetOutputRate()
|
|
|
|
{
|
2020-11-14 20:17:36 +00:00
|
|
|
return mp3d.info.hz;
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CMiniMP3::GetOutputChannels()
|
|
|
|
{
|
2020-11-14 20:17:36 +00:00
|
|
|
return mp3d.info.channels;
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int CMiniMP3::GetPosition()
|
|
|
|
{
|
2020-11-15 19:04:09 +00:00
|
|
|
return audio_stream.offset;
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Only supports seeking forward right now
|
|
|
|
void CMiniMP3::SetPosition( unsigned int position )
|
|
|
|
{
|
2020-11-15 19:04:09 +00:00
|
|
|
audio_stream.offset = position;
|
|
|
|
mp3dec_ex_seek(&mp3d, position);
|
2020-11-14 12:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class CVAudio : public IVAudio
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CVAudio()
|
|
|
|
{
|
|
|
|
// Assume the user will be creating multiple miles objects, so
|
|
|
|
// keep miles running while this exists
|
|
|
|
//IncrementRefMiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
~CVAudio()
|
|
|
|
{
|
|
|
|
//DecrementRefMiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|