/* ActiveGS, Copyright 2004-2016 Olivier Goguel, https://github.com/ogoguel/ActiveGS Based on Kegs, Copyright 2004 Kent Dickey, https://kegs.sourceforge.net This code is covered by the GNU GPL licence */ #include "defc.h" #if defined(DRIVER_IOS) || defined(DRIVER_OSX) # include # import # import # include #else # include "../OpenAL/AL/alc.h" # include "../OpenAL/AL/al.h" #endif #include "sound.h" //extern int g_audio_rate; #define AL_NUM_BUFFERS 8 #define AL_BUFFER_SIZE (SOUND_SHM_SAMP_SIZE*4*2) ALuint source=0, buffers[AL_NUM_BUFFERS]; int sndQueues[AL_NUM_BUFFERS]; const ALenum format = AL_FORMAT_STEREO16; unsigned char *al_tmp_buf[AL_NUM_BUFFERS][AL_BUFFER_SIZE]; ALCdevice *dev=NULL; ALCcontext *ctx=NULL; int nblog = 2000; //#define SNDLOG(STR,VAL) if (nblog){outputInfo(STR,VAL); nblog--;} //#define SNDLOG(STR,VAL) if (nblog){printf(STR,VAL); nblog--;} #define SNDLOG(STR,VAL) // http://www.subfurther.com/blog/?p=602 #if defined(DRIVER_IOS) || defined(DRIVER_OSX) typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq); ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) { static alBufferDataStaticProcPtr proc = NULL; if (proc == NULL) { proc = (alBufferDataStaticProcPtr) alGetProcAddress((const ALCchar*) "alBufferDataStatic"); } if (proc) proc(bid, format, data, size, freq); return; } #endif void resetQueues() { for(int i=0;i 0)) { if(l_DataBuffer == NULL) { printf("*** DataBuffer NULL!!! *** \n"); } // grab a buffer ID from openAL alGenBuffers(1, (ALuint*)&sound.m_BufferId); ALenum l_error = alGetError(); if(l_error != AL_NO_ERROR) { printf("**** OpenAL ERROR buffer%i\n", l_error); return sound; } else { printf("**** OpenAL OK buffer %i\n", sound.m_BufferId); } ALuint f; if (sound.depth==16) { if (sound.nbchannel == 1) f = AL_FORMAT_MONO16; else f = AL_FORMAT_STEREO16; } else { if (sound.nbchannel == 1) f = AL_FORMAT_MONO8; else f = AL_FORMAT_STEREO8; } alBufferData(sound.m_BufferId, f, l_DataBuffer, l_FileSize, sound.frequency); l_error = alGetError(); if(l_error != AL_NO_ERROR) { printf("**** OpenAL ERROR format\n"); return sound; } // create Source alGenSources(1, (ALuint*)&sound.m_SourceId); l_error = alGetError(); if(l_error != AL_NO_ERROR) { printf("**** OpenAL ERROR source\n"); return sound; } alSourcei(sound.m_SourceId, AL_BUFFER, sound.m_BufferId); l_error = alGetError(); if(l_error != AL_NO_ERROR) { printf("**** OpenAL ERROR source buffer\n"); return sound; } // if loop: //alSourcei(m_SourceId, AL_LOOPING, AL_TRUE); alSourcef(sound.m_SourceId, AL_PITCH, 1.0f); //l_error = alGetError(); //ASSERTC(l_error == AL_NO_ERROR,"**** OpenAL ERROR buffer\n"); //if(l_error != AL_NO_ERROR) //{ // CONSOLEMSG("**** OpenAL ERROR properties\n"); // return FAILURE; //} alSourcef(sound.m_SourceId, AL_GAIN, 1.0f); l_error = alGetError(); if(l_error != AL_NO_ERROR) { printf("**** OpenAL ERROR properties\n"); return sound; } } else { return sound; } if (l_DataBuffer) { free(l_DataBuffer); l_DataBuffer = NULL; } //printf("**** OpenAL Resource load SUCCESS\n"); sound.successfullyLoaded = 1; return sound; } int async_release_wav(OASound* _pSound) { if (!_pSound) return 0; if(_pSound->m_SourceId) { alDeleteSources(1, (ALuint*)&_pSound->m_SourceId); _pSound->m_SourceId = 0; } if(_pSound->m_BufferId) { alDeleteBuffers(1, (ALuint*)&_pSound->m_BufferId); _pSound->m_BufferId = 0; } _pSound->successfullyLoaded=0; return 1; } // **************************************************************************** // // **************************************************************************** int async_play_wav(OASound* _pSound, int _Loop, float _Attenuation, float _StartAt ) { if (!_pSound) return 0; if (!_pSound->successfullyLoaded) return 0; if(!_pSound->m_SourceId) return 0; alSourcePlay(_pSound->m_SourceId); int l_error = alGetError(); if(l_error != AL_NO_ERROR) { printf("**** OpenAL ERROR play %i\n", l_error); } return 1; } // **************************************************************************** // // **************************************************************************** int async_stop_wav(OASound* _pSound) { if (!_pSound) return 0; if (!_pSound->successfullyLoaded) return 0; if(!_pSound->m_SourceId) return 0; alSourceStop(_pSound->m_SourceId); return 1; } void x_play_sound(enum_sound _hSound) { async_play_wav(&g_system_sounds[_hSound].sound,0,0,0); } int x_is_sound_playing(enum_sound _hSound) { OASound& sound = g_system_sounds[_hSound].sound; if (sound.m_SourceId==0) return 0; ALint val; alGetSourcei(sound.m_SourceId, AL_SOURCE_STATE, &val); return (val == AL_PLAYING); } #if 1 #pragma push() #pragma pack(1) /* * Struct to hold fmt subchunk data for WAVE files. */ struct WAVE_Format { char subChunkID[4]; int subChunkSize; short audioFormat; short numChannels; int sampleRate; int byteRate; short blockAlign; short bitsPerSample; } __attribute__((packed)); /* * Struct to hold the data of the wave file */ struct WAVE_Data { char subChunkID[4]; //should contain the word data int subChunk2Size; //Stores the size of the data block } __attribute__((packed)); struct RIFF_Header { char chunkID[4]; int chunkSize;//size not including chunkSize or chunkID char format[4]; } __attribute__((packed)); #pragma pop() bool loadWavFile(const char* filename, unsigned char** buffer, unsigned int* size, int* frequency, int* depth,int* nbchannel) { //Local Declarations FILE* soundFile = NULL; WAVE_Format wave_format; RIFF_Header riff_header; WAVE_Data wave_data; unsigned char* data; soundFile = fopen(filename, "rb"); if (!soundFile) { printf("could not open %s\n",filename); return false; } // Read in the first chunk into the struct fread(&riff_header, sizeof(RIFF_Header), 1, soundFile); //check for RIFF and WAVE tag in memeory if ((riff_header.chunkID[0] != 'R' || riff_header.chunkID[1] != 'I' || riff_header.chunkID[2] != 'F' || riff_header.chunkID[3] != 'F') || (riff_header.format[0] != 'W' || riff_header.format[1] != 'A' || riff_header.format[2] != 'V' || riff_header.format[3] != 'E')) { fclose(soundFile); printf ("Invalid RIFF or WAVE Header in %s\n",filename); return false; } //Read in the 2nd chunk for the wave info fread(&wave_format, sizeof(WAVE_Format), 1, soundFile); //check for fmt tag in memory if (wave_format.subChunkID[0] != 'f' || wave_format.subChunkID[1] != 'm' || wave_format.subChunkID[2] != 't' || wave_format.subChunkID[3] != ' ') { fclose(soundFile); printf ("Invalid Wave Format"); return false; } //check for extra parameters; if (wave_format.subChunkSize > 16) fseek(soundFile, sizeof(short), SEEK_CUR); //Read in the the last byte of data before the sound file fread(&wave_data, sizeof(WAVE_Data), 1, soundFile); //check for data tag in memory if (wave_data.subChunkID[0] != 'd' || wave_data.subChunkID[1] != 'a' || wave_data.subChunkID[2] != 't' || wave_data.subChunkID[3] != 'a') { fclose(soundFile); printf ( "Invalid data header"); return false; } //Allocate memory for data data = (unsigned char*)malloc(wave_data.subChunk2Size); // Read in the sound data into the soundData variable if (!fread(data, wave_data.subChunk2Size, 1, soundFile)) { free(data); fclose(soundFile); printf ( "error loading WAVE data into struct!"); return false; } //Now we set the variables that we passed in with the //data from the structs *size = wave_data.subChunk2Size; *frequency = wave_format.sampleRate; *nbchannel = wave_format.numChannels ; *depth = wave_format.bitsPerSample; *buffer = data; fclose(soundFile); return true; } bool x_load_wav(const char* _Path, unsigned char** _outDataBuffer, unsigned int & _outFileSize, OASound & _sound ) { return loadWavFile(_Path,_outDataBuffer,&_outFileSize,&_sound.frequency,&_sound.depth,&_sound.nbchannel); } #endif