From 3bd383baf6a17e734329e1fc677c7e86283db772 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Mon, 26 Oct 2015 22:52:36 +0800 Subject: Added support for relative line numbers. Added instructions for, brk and cont. (They are still untested...) Parser code cleanup. Removed garbage output to stderr. Reorganize the repository structure. Updated BLR2 code move it into archive. Added BLR1 files. --- archive/hgewin/sound.cpp | 531 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 531 insertions(+) create mode 100644 archive/hgewin/sound.cpp (limited to 'archive/hgewin/sound.cpp') diff --git a/archive/hgewin/sound.cpp b/archive/hgewin/sound.cpp new file mode 100644 index 0000000..9024652 --- /dev/null +++ b/archive/hgewin/sound.cpp @@ -0,0 +1,531 @@ +/* +** Haaf's Game Engine 1.8 +** Copyright (C) 2003-2007, Relish Games +** hge.relishgames.com +** +** Core functions implementation: audio routines +*/ + + +// This is just enough to get Hammerfight working without using libBA$$. +// If you want a full HGE audio implementation, you should either use the +// code in sound_libbass.cpp (and maybe pay for a BA$$ licen$e), or improve +// this code. +// Well, this code is now improved by Chris Xiong, adding several new interfaces. +// (Such as seeking in sample...) +// Channel functions are fully supported now. However music and streaming are +// still not supported. Some APIs changed for OpenAL is different from BA$$. + +#include "hge_impl.h" + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "ogg/ogg.h" +#include "vorbis/vorbisfile.h" +static const char* SOUND_SRC_FN="hge/sound.cpp"; +struct oggcbdata +{ + const BYTE *data; + DWORD size; + DWORD pos; +}; + +static size_t oggcb_read(void *ptr, size_t size, size_t nmemb, void *datasource) +{ + oggcbdata *data = (oggcbdata *) datasource; + 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 oggcb_seek(void *datasource, ogg_int64_t offset, int whence) +{ + oggcbdata *data = (oggcbdata *) datasource; + 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 int oggcb_close(void *datasource) +{ + return 0; +} + +static long oggcb_tell(void *datasource) +{ + oggcbdata *data = (oggcbdata *) datasource; + return (long) data->pos; +} + +static ov_callbacks oggcb = { oggcb_read, oggcb_seek, oggcb_close, oggcb_tell }; + +static void *decompress_vorbis(const BYTE *data, const DWORD size, ALsizei *decompressed_size, ALenum *fmt, ALsizei *freq) +{ +#ifdef __POWERPC__ + const int bigendian = 1; +#else + const int bigendian = 0; +#endif + + oggcbdata cbdata = { data, size, 0 }; + OggVorbis_File vf; + memset(&vf, '\0', sizeof (vf)); + if (ov_open_callbacks(&cbdata, &vf, NULL, 0, oggcb) == 0) + { + int bitstream = 0; + vorbis_info *info = ov_info(&vf, -1); + + *decompressed_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 = 64 * 1024; + BYTE *retval = (ALubyte *) malloc(allocated); + while ( (rc = ov_read(&vf, buf, sizeof (buf), bigendian, 2, 1, &bitstream)) != 0 ) + { + if (rc > 0) + { + *decompressed_size += rc; + if ((unsigned)*decompressed_size >= allocated) + { + allocated *= 2; + ALubyte *tmp = (ALubyte *) realloc(retval, allocated); + if (tmp == NULL) + { + free(retval); + retval = NULL; + break; + } + retval = tmp; + } + memcpy(retval + (*decompressed_size - rc), buf, rc); + } + } + ov_clear(&vf); + return retval; + } + + return NULL; +} + +#define MAX_SIDS 128 +static int sidcount = 0; +static ALuint sids[MAX_SIDS]; + +static ALuint get_source() +{ + for (int i = 0; i < sidcount; i++) + { + ALint state = AL_PLAYING; + alGetSourceiv(sids[i], AL_SOURCE_STATE, &state); + if ((state != AL_PLAYING) && (state != AL_PAUSED)) + return sids[i]; + } + if (sidcount >= MAX_SIDS) + return 0; + + ALuint sid = 0; + alGenSources(1, &sid); + if (sid == 0) + return 0; + sids[sidcount++] = sid; + return sid; +} + + +HEFFECT CALL HGE_Impl::Effect_Load(const char *filename, DWORD size) +{ + DWORD _size; + void *data; + + if(hOpenAL) + { + if(bSilent) return 1; + + if(size) { data=(void *)filename; _size=size; } + else + { + data=Resource_Load(filename, &_size); + if(!data) return 0; + } + + const BYTE *magic = (const BYTE *) data; + const bool isOgg = ( (_size > 4) && + (magic[0] == 'O') && (magic[1] == 'g') && + (magic[2] == 'g') && (magic[3] == 'S') ); + if (!isOgg) + { + if(!size) Resource_Free(data); + return 0; + } + void *allocation_decompressed = NULL; + void *decompressed = NULL; + ALsizei decompressed_size = 0; + ALsizei freq = 0; + ALenum fmt = AL_FORMAT_STEREO16; + if (isOgg) + { + /*if (alIsExtensionPresent((const ALchar *) "AL_EXT_vorbis"))//useless + { + fmt = alGetEnumValue((const ALchar *) "AL_FORMAT_VORBIS_EXT"); + decompressed = data; + decompressed_size = _size; + } + else + {*/ + allocation_decompressed = decompress_vorbis((const BYTE *) data, _size, &decompressed_size, &fmt, &freq); + decompressed = allocation_decompressed; + //} + } + + ALuint bid = 0; + alGenBuffers(1, &bid); + alBufferData(bid, fmt, decompressed, decompressed_size, freq); + free(allocation_decompressed); // not delete[] ! + if(!size) Resource_Free(data); + return (HEFFECT) bid; + } + else return 0; +} + +HCHANNEL CALL HGE_Impl::Effect_Play(HEFFECT eff) +{ + return Effect_PlayEx(eff, 1.0f, 0, 1.0f, false); +} + +HCHANNEL CALL HGE_Impl::Effect_PlayEx(HEFFECT eff, float volume, float pan, float pitch, bool loop) +{ + if(hOpenAL) + { + const ALuint sid = get_source(); // find an unused sid, or generate a new one. + if (sid != 0) + { + if (volume < 0) volume = 0; else if (volume > 1.0) volume = 1.0; + if (pan < -1.0) pan = -1.0; else if (pan > 1.0) pan = 1.0; + alSourceStop(sid); + alSourcei(sid, AL_BUFFER, (ALint) eff); + alSourcef(sid, AL_GAIN, volume); + alSourcef(sid, AL_PITCH, pitch); + alSource3f(sid, AL_POSITION, pan, 0.0f, 0.0f); + alSourcei(sid, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + alSourcePlay(sid); + } + return sid; + } + else return 0; +} + +void CALL HGE_Impl::Effect_Free(HEFFECT eff) +{ + if(hOpenAL) + { + ALuint bid = (ALuint) eff; + alDeleteBuffers(1, &bid); + } +} +//Castrate!! +HMUSIC CALL HGE_Impl::Music_Load(const char *filename, DWORD size){return 0;} + +HCHANNEL CALL HGE_Impl::Music_Play(HMUSIC mus, bool loop, int volume, int order, int row){return 0;} + +void CALL HGE_Impl::Music_Free(HMUSIC mus){} + +void CALL HGE_Impl::Music_SetAmplification(HMUSIC music, int ampl){} + +int CALL HGE_Impl::Music_GetAmplification(HMUSIC music){return -1;} + +int CALL HGE_Impl::Music_GetLength(HMUSIC music){return -1;} + +void CALL HGE_Impl::Music_SetPos(HMUSIC music, int order, int row){} + +bool CALL HGE_Impl::Music_GetPos(HMUSIC music, int *order, int *row){return false;} + +void CALL HGE_Impl::Music_SetInstrVolume(HMUSIC music, int instr, int volume){} + +int CALL HGE_Impl::Music_GetInstrVolume(HMUSIC music, int instr){return -1;} + +void CALL HGE_Impl::Music_SetChannelVolume(HMUSIC music, int channel, int volume){} + +int CALL HGE_Impl::Music_GetChannelVolume(HMUSIC music, int channel){return -1;} + +HSTREAM CALL HGE_Impl::Stream_Load(const char *filename, DWORD size){return 0;} + +void CALL HGE_Impl::Stream_Free(HSTREAM stream){} + +HCHANNEL CALL HGE_Impl::Stream_Play(HSTREAM stream, bool loop, int volume){return 0;} + +void CALL HGE_Impl::Channel_SetPanning(HCHANNEL chn, float pan) +{ + if(pan>1.0)pan=1.0; + if(pan<-1.0)pan=-1.0; + if(hOpenAL) + { + alSource3f((ALuint) chn, AL_POSITION, pan, 0.0f, 0.0f); + } +} + +void CALL HGE_Impl::Channel_SetVolume(HCHANNEL chn, float volume) +{ + if(hOpenAL) + { + if (volume < 0) volume = 0; else if (volume > 1.0f) volume = 1.0f; + alSourcef((ALuint) chn, AL_GAIN, volume); + } +} + +void CALL HGE_Impl::Channel_SetPitch(HCHANNEL chn, float pitch) +{ + if(hOpenAL) + { + alSourcef((ALuint) chn, AL_PITCH, pitch); + } +} + +void CALL HGE_Impl::Channel_Pause(HCHANNEL chn) +{ + if(hOpenAL) + { + alSourcePause((ALuint) chn); + } +} + +void CALL HGE_Impl::Channel_Resume(HCHANNEL chn) +{ + if(hOpenAL) + { + alSourcePlay((ALuint) chn); + } +} + +void CALL HGE_Impl::Channel_Stop(HCHANNEL chn) +{ + if(hOpenAL) + { + alSourceStop((ALuint) chn); + } +} + +void CALL HGE_Impl::Channel_PauseAll() +{ + if(hOpenAL) + { + ALCcontext *ctx = alcGetCurrentContext(); + alcSuspendContext(ctx); + } +} + +void CALL HGE_Impl::Channel_ResumeAll() +{ + if(hOpenAL) + { + ALCcontext *ctx = alcGetCurrentContext(); + alcProcessContext(ctx); + } +} + +void CALL HGE_Impl::Channel_StopAll() +{ + if(hOpenAL) + { + for (int i = 0; i < sidcount; i++) + alSourceStop(sids[i]); + } +} + +bool CALL HGE_Impl::Channel_IsPlaying(HCHANNEL chn) +{ + if(hOpenAL) + { + ALint state = AL_STOPPED; + alGetSourceiv((ALuint) chn, AL_SOURCE_STATE, &state); + return state == AL_PLAYING; + } + else return false; +} +//The following features are ported to OpenAL by Chris +float CALL HGE_Impl::Channel_GetLength(HCHANNEL chn) +//WARNING!!:In OpenAL We pass HEFFECT insteat HCHANNEL in! +//This should be fixed. +{ + //Well, you developers should know this "by heart". + if (hOpenAL) + { + ALint sizeInBytes; + ALint channels; + ALint bits; + ALuint bufferID=chn; + alGetBufferi(bufferID, AL_SIZE, &sizeInBytes); + alGetBufferi(bufferID, AL_CHANNELS, &channels); + alGetBufferi(bufferID, AL_BITS, &bits); + int lengthInSamples = sizeInBytes * 8 / (channels * bits); + ALint frequency; + alGetBufferi(bufferID, AL_FREQUENCY, &frequency); + float durationInSeconds = (float)lengthInSamples / (float)frequency; + return durationInSeconds; + } + return -1; +} + +float CALL HGE_Impl::Channel_GetPos(HCHANNEL chn) +{ + if (hOpenAL) + { + ALfloat res; + alGetSourcef((ALuint)chn,AL_SEC_OFFSET,&res); + return (float)res; + } + else return -1.0f; +} + +void CALL HGE_Impl::Channel_SetPos(HCHANNEL chn, float fSeconds) +{ + if (hOpenAL) + { + alSourcef((ALuint)chn,AL_SEC_OFFSET,(ALfloat)fSeconds); + } +} + +int CALL HGE_Impl::Channel_GetPos_BySample(HCHANNEL chn) +{ + if (hOpenAL) + { + ALint res; + alGetSourcei((ALuint)chn,AL_SAMPLE_OFFSET,&res); + return (int)res; + } + else return -1; +} + +void CALL HGE_Impl::Channel_SetPos_BySample(HCHANNEL chn, int iSample) +{ + if (hOpenAL) + { + alSourcei((ALuint)chn,AL_SAMPLE_OFFSET,(ALint)iSample); + } +} + +void CALL HGE_Impl::Channel_SlideTo(HCHANNEL channel, float time, int volume, int pan, float pitch){} + +bool CALL HGE_Impl::Channel_IsSliding(HCHANNEL channel){return false;} + + +//////// Implementation //////// + + +bool HGE_Impl::_SoundInit() +{ + if(!bUseSound || hOpenAL) return true; + + bSilent=false; + + sidcount = 0; + memset(sids, '\0', sizeof (sids)); + + System_Log("%s: Starting OpenAL init",SOUND_SRC_FN); + + ALCdevice *dev = alcOpenDevice(NULL); + if (!dev) + { + System_Log("%s: alcOpenDevice(NULL) failed, using no sound",SOUND_SRC_FN); + bSilent=true; + return true; + } + + ALint caps[] = { ALC_FREQUENCY, nSampleRate, 0 }; + ALCcontext *ctx = alcCreateContext(dev, caps); + if (!ctx) + { + alcCloseDevice(dev); + System_Log("%s: alcCreateContext(NULL) failed, using no sound",SOUND_SRC_FN); + bSilent=true; + return true; + } + + alcMakeContextCurrent(ctx); + alcProcessContext(ctx); + + System_Log("%s: OpenAL initialized successfully.",SOUND_SRC_FN); + System_Log("%s: AL_VENDOR: %s",SOUND_SRC_FN, (char *) alGetString(AL_VENDOR)); + System_Log("%s: AL_RENDERER: %s",SOUND_SRC_FN, (char *) alGetString(AL_RENDERER)); + System_Log("%s: AL_VERSION: %s",SOUND_SRC_FN,(char *) alGetString(AL_VERSION)); + System_Log("%s: AL_EXTENSIONS: %s",SOUND_SRC_FN,(char *) alGetString(AL_EXTENSIONS)); + + hOpenAL = (void *) 0x1; // something non-NULL (!!! FIXME: this should eventually be a library handle). + + _SetFXVolume(nFXVolume); + //_SetMusVolume(nMusVolume); + //_SetStreamVolume(nStreamVolume); + + return true; +} + +void HGE_Impl::_SoundDone() +{ + CStreamList *stmItem=streams, *stmNext; + + if(hOpenAL) + { + for (int i = 0; i < sidcount; i++) + alSourceStop(sids[i]); + alDeleteSources(sidcount, sids); + sidcount = 0; + memset(sids, '\0', sizeof (sids)); + + ALCcontext *ctx = alcGetCurrentContext(); + ALCdevice *dev = alcGetContextsDevice(ctx); + alcMakeContextCurrent(NULL); + alcSuspendContext(ctx); + alcDestroyContext(ctx); + alcCloseDevice(dev); + + hOpenAL=0; + + while(stmItem) + { + stmNext=stmItem->next; + Resource_Free(stmItem->data); + delete stmItem; + stmItem=stmNext; + } + streams=0; + } +} + +void HGE_Impl::_SetMusVolume(int vol){} + +void HGE_Impl::_SetStreamVolume(int vol){} + +void HGE_Impl::_SetFXVolume(int vol) +{ + if(hOpenAL) + { + alListenerf(AL_GAIN, ((ALfloat) vol) / 100.0f); + } +} -- cgit v1.2.3