280 lines
5.8 KiB
C++
280 lines
5.8 KiB
C++
#define __MAKE_PLUGIN__
|
|
|
|
#include<hgl/plugin/PlugIn.h>
|
|
#include<hgl/plugin/PlugInInterface.h>
|
|
#include<malloc.h>
|
|
#include<string.h>
|
|
#include<hgl/al/al.h>
|
|
|
|
#include<vorbis/vorbisfile.h>
|
|
|
|
using namespace hgl;
|
|
using namespace openal;
|
|
|
|
struct ogg_fileread
|
|
{
|
|
unsigned char *data;
|
|
size_t pos;
|
|
size_t size;
|
|
};
|
|
|
|
size_t VorbisRead(void *buffer,size_t size,size_t count,void *ptr)
|
|
{
|
|
ogg_fileread *obj=(ogg_fileread *)ptr;
|
|
|
|
size*=count;
|
|
|
|
if(obj->pos+size>obj->size)
|
|
size=obj->size-obj->pos;
|
|
|
|
if(size)
|
|
{
|
|
memcpy(buffer,obj->data+obj->pos,size);
|
|
|
|
obj->pos+=size;
|
|
}
|
|
|
|
return(size);
|
|
}
|
|
|
|
int VorbisSeek(void *ptr,ogg_int64_t offset,int whence)
|
|
{
|
|
ogg_fileread *obj=(ogg_fileread *)ptr;
|
|
|
|
if(whence==SEEK_SET)
|
|
{
|
|
obj->pos=offset;
|
|
}
|
|
else
|
|
if(whence==SEEK_CUR)
|
|
{
|
|
obj->pos+=offset;
|
|
}else
|
|
if(whence==SEEK_END)
|
|
{
|
|
obj->pos=obj->size+offset;
|
|
}
|
|
|
|
if(obj->pos>obj->size)obj->pos=obj->size;
|
|
|
|
return(0);
|
|
}
|
|
|
|
int VorbisClose(void *)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
long VorbisTell(void *ptr)
|
|
{
|
|
return ((ogg_fileread *)ptr)->pos;
|
|
}
|
|
|
|
ALvoid LoadOGG(ALbyte *memory, ALsizei memory_size,ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop)
|
|
{
|
|
int result;
|
|
char * ptr=nullptr;
|
|
|
|
ov_callbacks func;
|
|
OggVorbis_File ogg_stream;
|
|
vorbis_info * info;
|
|
int section;
|
|
|
|
ogg_fileread ogg_memory;
|
|
|
|
func.read_func =VorbisRead;
|
|
func.close_func =VorbisClose;
|
|
func.seek_func =VorbisSeek;
|
|
func.tell_func =VorbisTell;
|
|
|
|
ogg_memory.data=(unsigned char *)memory;
|
|
ogg_memory.pos=0;
|
|
ogg_memory.size=memory_size;
|
|
|
|
*size=0;
|
|
|
|
if(ov_open_callbacks(&ogg_memory,&ogg_stream,NULL,0,func)!=0)
|
|
return;
|
|
|
|
info =ov_info(&ogg_stream,-1);
|
|
|
|
if(info->channels==1)*format=AL_FORMAT_MONO16;
|
|
else *format=AL_FORMAT_STEREO16;
|
|
|
|
const int pcm_total_bytes = ov_pcm_total(&ogg_stream,0)*info->channels*2;
|
|
|
|
int out_size = 0;
|
|
|
|
ptr = new char[pcm_total_bytes];
|
|
|
|
while(true)
|
|
{
|
|
result=ov_read(&ogg_stream,ptr+out_size,pcm_total_bytes-out_size,
|
|
0, // 0: little-endian 1: big_endian
|
|
2, // 1: 8 bit-samples 2: 16 bit-samples
|
|
1, // 0: unsigned 1: signed
|
|
§ion);
|
|
|
|
if(result<=0)break;
|
|
|
|
out_size += result;
|
|
}
|
|
|
|
*freq=info->rate;
|
|
*size=out_size;
|
|
*data=ptr;
|
|
|
|
ov_clear(&ogg_stream);
|
|
}
|
|
|
|
void ClearOGG(ALenum, ALvoid *data, ALsizei, ALsizei)
|
|
{
|
|
if (data)
|
|
delete[] (char *)data;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------
|
|
struct OggStream
|
|
{
|
|
ov_callbacks func;
|
|
|
|
ogg_fileread ogg_memory;
|
|
OggVorbis_File ogg_stream;
|
|
};
|
|
|
|
void *OpenOGG(ALbyte *memory,ALsizei memory_size,ALenum *format,ALsizei *rate,double *total_time)
|
|
{
|
|
vorbis_info *info;
|
|
|
|
OggStream *ptr=new OggStream;
|
|
|
|
ptr->func.read_func =VorbisRead;
|
|
ptr->func.close_func =VorbisClose;
|
|
ptr->func.seek_func =VorbisSeek;
|
|
ptr->func.tell_func =VorbisTell;
|
|
|
|
ptr->ogg_memory.data=(unsigned char *)memory;
|
|
ptr->ogg_memory.pos=0;
|
|
ptr->ogg_memory.size=memory_size;
|
|
|
|
if(ov_open_callbacks(&(ptr->ogg_memory),&(ptr->ogg_stream),NULL,0,ptr->func)!=0)
|
|
return(nullptr);
|
|
|
|
info =ov_info(&(ptr->ogg_stream),-1);
|
|
|
|
if(info->channels==1)*format=AL_FORMAT_MONO16;
|
|
else *format=AL_FORMAT_STEREO16;
|
|
|
|
*rate=info->rate;
|
|
|
|
*total_time=ov_time_total(&(ptr->ogg_stream),-1);
|
|
|
|
return(ptr);
|
|
}
|
|
|
|
void CloseOGG(void *ptr)
|
|
{
|
|
OggStream *obj=(OggStream *)ptr;
|
|
|
|
ov_clear(&(obj->ogg_stream));
|
|
|
|
delete obj;
|
|
}
|
|
|
|
uint ReadOGG(void *ptr,char *data,uint buf_max)
|
|
{
|
|
OggStream *obj=(OggStream *)ptr;
|
|
int section;
|
|
int result;
|
|
uint size=0;
|
|
|
|
while(size<buf_max)
|
|
{
|
|
result=ov_read(&(obj->ogg_stream),data+size,buf_max-size,0,2,1,§ion);
|
|
|
|
if(result>0)size+=result;else
|
|
if(result<0)return(0);else break;
|
|
}
|
|
|
|
if(size==0)return(0);
|
|
|
|
return(size);
|
|
}
|
|
|
|
void RestartOGG(void *ptr)
|
|
{
|
|
OggStream *obj=(OggStream *)ptr;
|
|
|
|
ov_pcm_seek(&(obj->ogg_stream),0);
|
|
}
|
|
//--------------------------------------------------------------------------------------------------
|
|
struct OutInterface
|
|
{
|
|
void (*Load)(ALbyte *,ALsizei,ALenum *,ALvoid **,ALsizei *,ALsizei *,ALboolean *);
|
|
void (*Clear)(ALenum,ALvoid *,ALsizei,ALsizei);
|
|
|
|
void *(*Open)(ALbyte *,ALsizei,ALenum *,ALsizei *,double *);
|
|
void (*Close)(void *);
|
|
uint (*Read)(void *,char *,uint);
|
|
void (*Restart)(void *);
|
|
};
|
|
|
|
static OutInterface out_interface=
|
|
{
|
|
LoadOGG,
|
|
ClearOGG,
|
|
|
|
OpenOGG,
|
|
CloseOGG,
|
|
ReadOGG,
|
|
RestartOGG
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
#if HGL_OS != HGL_OS_Windows
|
|
const u16char plugin_intro[]=U16_TEXT("Vorbis OGG 音频文件解码(使用操作系统内置解码器,2016-09-16)");
|
|
#else
|
|
const u16char plugin_intro[]=U16_TEXT("Vorbis OGG 音频文件解码(LibOGG 1.3.5,LibVorbis 1.3.7,2022-03-31)");
|
|
#endif//
|
|
|
|
HGL_PLUGIN_FUNC uint32 GetPlugInVersion()
|
|
{
|
|
return(2); //版本号
|
|
//根据版本号取得不同的API
|
|
}
|
|
|
|
u16char * GetPlugInIntro()
|
|
{
|
|
return((u16char *)plugin_intro);
|
|
}
|
|
|
|
bool GetPlugInInterface(uint32 ver,void *data)
|
|
{
|
|
if(ver==2)
|
|
{
|
|
memcpy(data,&out_interface,sizeof(OutInterface));
|
|
}
|
|
else
|
|
return(false);
|
|
|
|
return(true);
|
|
}
|
|
|
|
static PlugInInterface pii=
|
|
{
|
|
nullptr,
|
|
|
|
GetPlugInVersion,
|
|
GetPlugInIntro,
|
|
|
|
GetPlugInInterface,
|
|
nullptr,
|
|
|
|
nullptr,
|
|
nullptr
|
|
};
|
|
|
|
HGL_PLUGIN_FUNC PlugInInterface *InitPlugIn()
|
|
{
|
|
return &pii;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------
|