aboutsummaryrefslogtreecommitdiff
path: root/smelt/glfw_m/sfx_oal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'smelt/glfw_m/sfx_oal.cpp')
-rw-r--r--smelt/glfw_m/sfx_oal.cpp368
1 files changed, 368 insertions, 0 deletions
diff --git a/smelt/glfw_m/sfx_oal.cpp b/smelt/glfw_m/sfx_oal.cpp
new file mode 100644
index 0000000..5b8d135
--- /dev/null
+++ b/smelt/glfw_m/sfx_oal.cpp
@@ -0,0 +1,368 @@
+// -*- C++ -*-
+/*
+ * Simple MultimEdia LiTerator(SMELT)
+ * by Chris Xiong 2015
+ * GFX implementation based on OpenAL
+ *
+ * WARNING: This library is in development and interfaces would be very
+ * unstable.
+ *
+ */
+#include "smelt_internal.hpp"
+
+static const char* SFX_OAL_SRCFN="smelt/glfw/sfx_oal.cpp";
+#ifndef ENABLE_DUMB
+#ifdef ENABLE_OGG_SUPPORT
+struct oggdata{const BYTE *data;DWORD size,pos;};
+static void* readVorbis(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq);
+#endif
+static void* readRiffWv(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq);
+SMSFX SMELT_IMPL::smSFXLoad(const char *path)
+{
+ FILE *pFile;DWORD size,rsize; char *buff;
+ pFile=fopen(path,"rb");
+ if(!pFile)return 0;
+ fseek(pFile,0,SEEK_END);size=ftell(pFile);rewind(pFile);
+ buff=(char*)malloc(sizeof(char)*size);
+ if(!buff)return 0;
+ rsize=fread(buff,1,size,pFile);
+ if(rsize!=size)return 0;
+ SMSFX ret=smSFXLoadFromMemory(buff,size);
+ free(buff);
+ fclose(pFile);
+ return ret;
+}
+SMSFX SMELT_IMPL::smSFXLoadFromMemory(const char *ptr,DWORD size)
+{
+ if(pOpenALDevice&&!mute)
+ {
+#ifdef ENABLE_OGG_SUPPORT
+ bool isOgg=size>4&&ptr[0]=='O'&&ptr[1]=='g'&&ptr[2]=='g'&&ptr[3]=='S';
+#endif
+ void *decompdata=NULL,*decomp=NULL;
+ ALsizei decompsize=0,freq=0;
+ ALenum fmt=AL_FORMAT_STEREO16;
+ decompdata=readRiffWv((const BYTE*)ptr,size,&decompsize,&fmt,&freq);
+#ifdef ENABLE_OGG_SUPPORT
+ if(!decompdata)
+ {
+ if(!isOgg)return 0;
+ else decompdata=readVorbis((const BYTE*)ptr,size,&decompsize,&fmt,&freq);
+ }
+#endif
+ if(!decompdata)return 0;
+ decomp=decompdata;
+ ALuint buff=0;alGenBuffers(1,&buff);
+ alBufferData(buff,fmt,decomp,decompsize,freq);
+ free(decompdata);return(SMSFX)buff;
+ }
+ return 0;
+}
+SMCHN SMELT_IMPL::smSFXPlay(SMSFX fx,int vol,int pan,float pitch,bool loop)
+{
+ if(pOpenALDevice)
+ {
+ ALuint src=getSource();
+ if(src)
+ {
+ if(vol<0)vol=0;if(vol>100)vol=100;
+ if(pan<-100)pan=-100;if(pan>100)pan=100;
+ alSourceStop(src);
+ alSourcei(src,AL_BUFFER,(ALint)fx);
+ alSourcef(src,AL_GAIN,((ALfloat)vol)/100.);
+ alSourcef(src,AL_PITCH,pitch);
+ alSource3f(src,AL_POSITION,((ALfloat)pan)/100.,.0,.0);
+ alSourcei(src,AL_LOOPING,loop?AL_TRUE:AL_FALSE);
+ alSourcePlay(src);
+ }
+ return src;
+ }
+ return 0;
+}
+float SMELT_IMPL::smSFXGetLengthf(SMSFX fx)
+{
+ ALuint buff=(ALuint)fx;
+ ALint freq;
+ DWORD lend=smSFXGetLengthd(fx);
+ alGetBufferi(buff,AL_FREQUENCY,&freq);
+ float ret=lend/(float)freq;
+ return ret;
+}
+DWORD SMELT_IMPL::smSFXGetLengthd(SMSFX fx)
+{
+ if(pOpenALDevice)
+ {
+ ALint size_b,chnc,bit;
+ ALuint buff=(ALuint)fx;
+ alGetBufferi(buff,AL_SIZE,&size_b);
+ alGetBufferi(buff,AL_CHANNELS,&chnc);
+ alGetBufferi(buff,AL_BITS,&bit);
+ DWORD ret=size_b*8/(chnc*bit);
+ return ret;
+ }
+ return -1;
+}
+void SMELT_IMPL::smSFXSetLoopPoint(SMSFX fx,DWORD l,DWORD r)
+{
+ if(pOpenALDevice)
+ {
+ ALint pt[2];pt[0]=l;pt[1]=r;
+ alBufferiv((ALuint)fx,AL_LOOP_POINTS_SOFT,pt);
+ }
+}
+void SMELT_IMPL::smSFXFree(SMSFX fx)
+{
+ if(pOpenALDevice)
+ {
+ ALuint buff=(ALuint)fx;
+ alDeleteBuffers(1,&buff);
+ }
+}
+void SMELT_IMPL::smChannelVol(SMCHN chn,int vol)
+{
+ if(pOpenALDevice)
+ {
+ if(vol<0)vol=0;if(vol>100)vol=100;
+ alSourcef((ALuint)chn,AL_GAIN,((ALfloat)vol)/100.);
+ }
+}
+void SMELT_IMPL::smChannelPan(SMCHN chn,int pan)
+{
+ if(pOpenALDevice)
+ {
+ if(pan<-100)pan=-100;if(pan>100)pan=100;
+ alSource3f((ALuint)chn,AL_POSITION,((ALfloat)pan)/100.,.0,.0);
+ }
+}
+void SMELT_IMPL::smChannelPitch(SMCHN chn,float pitch)
+{
+ if(pOpenALDevice)alSourcef((ALuint)chn,AL_PITCH,pitch);
+}
+void SMELT_IMPL::smChannelPause(SMCHN chn)
+{
+ if(pOpenALDevice)alSourcePause((ALuint)chn);
+}
+void SMELT_IMPL::smChannelResume(SMCHN chn)
+{
+ if(pOpenALDevice)alSourcePlay((ALuint)chn);
+}
+void SMELT_IMPL::smChannelStop(SMCHN chn)
+{
+ if(pOpenALDevice)alSourceStop((ALuint)chn);
+}
+void SMELT_IMPL::smChannelPauseAll()
+{
+ if(pOpenALDevice)
+ {
+ ALCcontext *ctx=alcGetCurrentContext();
+ alcSuspendContext(ctx);
+ }
+}
+void SMELT_IMPL::smChannelResumeAll()
+{
+ if(pOpenALDevice)
+ {
+ ALCcontext *ctx=alcGetCurrentContext();
+ alcProcessContext(ctx);
+ }
+}
+void SMELT_IMPL::smChannelStopAll()
+{
+ if(pOpenALDevice)
+ {
+ for(int i=0;i<scnt;++i)alSourceStop(src[i]);
+ }
+}
+bool SMELT_IMPL::smChannelIsPlaying(SMCHN chn)
+{
+ if(pOpenALDevice)
+ {
+ ALint state=AL_STOPPED;
+ alGetSourceiv((ALuint)chn,AL_SOURCE_STATE,&state);
+ return state==AL_PLAYING;
+ }
+ return false;
+}
+float SMELT_IMPL::smChannelGetPosf(SMCHN chn)
+{
+ if(pOpenALDevice)
+ {
+ ALfloat ret;
+ alGetSourcef((ALuint)chn,AL_SEC_OFFSET,&ret);
+ return (float)ret;
+ }
+ return -1.;
+}
+void SMELT_IMPL::smChannelSetPosf(SMCHN chn,float pos)
+{
+ if(pOpenALDevice)alSourcef((ALuint)chn,AL_SEC_OFFSET,(ALfloat)pos);
+}
+int SMELT_IMPL::smChannelGetPosd(SMCHN chn)
+{
+ if(pOpenALDevice)
+ {
+ ALint ret;
+ alGetSourcei((ALuint)chn,AL_SAMPLE_OFFSET,&ret);
+ return (int)ret;
+ }
+ return -1;
+}
+void SMELT_IMPL::smChannelSetPosd(SMCHN chn,int pos)
+{
+ if(pOpenALDevice)alSourcei((ALuint)chn,AL_SAMPLE_OFFSET,(ALint)pos);
+}
+
+#ifdef ENABLE_OGG_SUPPORT
+static size_t oggRead(void *ptr,size_t size,size_t nmemb,void *ds)
+{
+ oggdata *data=(oggdata*)ds;
+ const DWORD avail=data->size-data->pos;
+ size_t want=nmemb*size;
+ if(want>avail)want=avail-(avail%size);
+ if(want>0)
+ {
+ memcpy(ptr,data->data+data->pos,want);
+ data->pos+=want;
+ }
+ return want/size;
+}
+static int oggSeek(void *ds,ogg_int64_t offset,int whence)
+{
+ oggdata *data=(oggdata*)ds;
+ ogg_int64_t pos=0;
+ switch(whence)
+ {
+ case SEEK_SET:pos=offset;break;
+ case SEEK_CUR:pos=((ogg_int64_t)data->pos)+offset;break;
+ case SEEK_END:pos=((ogg_int64_t)data->size)+offset;break;
+ default: return -1;
+ }
+ if((pos<0)||(pos>((ogg_int64_t)data->size)))return -1;
+ data->pos=(DWORD)pos;
+ return 0;
+}
+static long oggLocate(void *ds)
+{
+ oggdata* data=(oggdata*)ds;
+ return (long)data->pos;
+}
+static int oggClose(void *ds){return 0;}
+
+static ov_callbacks oggrt={oggRead,oggSeek,oggClose,oggLocate};
+static void* readVorbis(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq)
+{
+ oggdata adata={data,size,0};
+ OggVorbis_File vf;
+ memset(&vf,0,sizeof(vf));
+ if(ov_open_callbacks(&adata,&vf,NULL,0,oggrt)==0)
+ {
+ int bs=0;
+ vorbis_info *info=ov_info(&vf,-1);
+ *decomp_size=0;
+ *fmt=(info->channels==1)?AL_FORMAT_MONO16:AL_FORMAT_STEREO16;
+ *freq=info->rate;
+ if(!(info->channels==1||info->channels==2)){ov_clear(&vf);return NULL;}
+ char buf[1024*16];long rc=0;size_t allocated=1024*16;
+ BYTE *ret=(ALubyte*)malloc(allocated);
+ while((rc=ov_read(&vf,buf,sizeof(buf),0,2,1,&bs))!=0)
+ {
+ if(rc>0)
+ {
+ *decomp_size+=rc;
+ if((unsigned)*decomp_size>=allocated)
+ {
+ allocated<<=1;
+ ALubyte *tmp=(ALubyte*)realloc(ret,allocated);
+ if(!tmp){free(ret);ret=NULL;break;}
+ ret=tmp;
+ }
+ memcpy(ret+(*decomp_size-rc),buf,rc);
+ }
+ }
+ ov_clear(&vf);
+ return ret;
+ }
+ return NULL;
+}
+#endif
+static void* readRiffWv(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq)
+{
+ if(data[0x0]!='R'||data[0x1]!='I'||data[0x2]!='F'||data[0x3]!='F')return NULL;
+ if(data[0x8]!='W'||data[0x9]!='A'||data[0xA]!='V'||data[0xB]!='E')return NULL;
+ if(data[0xC]!='f'||data[0xD]!='m'||data[0xE]!='t'||data[0xF]!=' ')return NULL;
+ if(data[0x16]==2)
+ {
+ if(data[0x22]==16)*fmt=AL_FORMAT_STEREO16;
+ else if(data[0x22]==8)*fmt=AL_FORMAT_STEREO8;
+ else return NULL;
+ }
+ else if(data[0x16]==1)
+ {
+ if(data[0x22]==16)*fmt=AL_FORMAT_MONO16;
+ else if(data[0x22]==8)*fmt=AL_FORMAT_MONO8;
+ else return NULL;
+ }else return NULL;
+ *decomp_size=(ALsizei)(data[0x28]|(data[0x29]<<8L)|(data[0x2A]<<16L)|(data[0x2B]<<24L));
+ *freq=(ALsizei)(data[0x18]|(data[0x19]<<8L)|(data[0x1A]<<16L)|(data[0x1B]<<24L));
+ ALubyte *ret=(ALubyte*)malloc(*decomp_size);
+ memcpy(ret,data+44,*decomp_size);
+ return ret;
+}
+ALuint SMELT_IMPL::getSource()
+{
+ for(int i=0;i<scnt;++i)
+ {
+ ALint state=AL_PLAYING;
+ alGetSourceiv(src[i],AL_SOURCE_STATE,&state);
+ if(!(state==AL_PLAYING||state==AL_PAUSED))return src[i];
+ }
+ if(scnt>=SRC_MAX)return 0;
+ ALuint ret=0;
+ alGenSources(1,&ret);if(!ret)return 0;
+ src[scnt++]=ret;return ret;
+}
+bool SMELT_IMPL::initOAL()
+{
+ if(pOpenALDevice)return true;
+ scnt=0;memset(src,0,sizeof(src));
+ smLog("%s:" SLINE ": Initializing OpenAL...\n",SFX_OAL_SRCFN);
+ ALCdevice *dev=alcOpenDevice(NULL);
+ if(!dev)
+ {
+ smLog("%s:" SLINE ": alcOpenDevice() failed.\n",SFX_OAL_SRCFN);
+ return mute=true;
+ }
+ ALint caps[]={ALC_FREQUENCY,44100,0};
+ ALCcontext *ctx=alcCreateContext(dev,caps);
+ if(!ctx)
+ {
+ smLog("%s:" SLINE ": alcCreateContext() failed.\n",SFX_OAL_SRCFN);
+ return mute=true;
+ }
+ alcMakeContextCurrent(ctx);alcProcessContext(ctx);
+ smLog("%s:" SLINE ": Done OpenAL initialization\n",SFX_OAL_SRCFN);
+ smLog("%s:" SLINE ": AL_VENDOR: %s\n",SFX_OAL_SRCFN,(char*)alGetString(AL_VENDOR));
+ smLog("%s:" SLINE ": AL_RENDERER: %s\n",SFX_OAL_SRCFN,(char*)alGetString(AL_RENDERER));
+ smLog("%s:" SLINE ": AL_VERSION: %s\n",SFX_OAL_SRCFN,(char*)alGetString(AL_VERSION));
+ const char* ext=(const char*)alGetString(AL_EXTENSIONS);
+ lpp=strstr(ext,"AL_SOFT_loop_points")!=NULL;
+ if(!lpp)smLog("%s:" SLINE ": Warning: loop points not supported. Please recompile with OpenAL Soft.\n",SFX_OAL_SRCFN);
+ pOpenALDevice=(void*)dev;
+ return true;
+}
+void SMELT_IMPL::finiOAL()
+{
+ if(pOpenALDevice)
+ {
+ for(int i=0;i<scnt;++i)alSourceStop(src[i]);
+ alDeleteSources(scnt,src);scnt=0;memset(src,0,sizeof(src));
+ ALCcontext *ctx=alcGetCurrentContext();
+ ALCdevice *dev=alcGetContextsDevice(ctx);
+ alcMakeContextCurrent(NULL);
+ alcSuspendContext(ctx);alcDestroyContext(ctx);
+ alcCloseDevice(dev);pOpenALDevice=NULL;
+ }
+}
+#else
+#include "sfx_dumb.cpp"
+#endif //ifndef ENABLE_DUMB