Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Sound/al_audio.cpp')
-rw-r--r--Source/Sound/al_audio.cpp1610
1 files changed, 1610 insertions, 0 deletions
diff --git a/Source/Sound/al_audio.cpp b/Source/Sound/al_audio.cpp
new file mode 100644
index 00000000..f494994d
--- /dev/null
+++ b/Source/Sound/al_audio.cpp
@@ -0,0 +1,1610 @@
+//-----------------------------------------------------------------------------
+// Name: al_audio.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "al_audio.h"
+
+#include <Sound/soundlogging.h>
+#include <Sound/Loader/ogg_loader.h>
+
+#include <Internal/error.h>
+#include <Internal/timer.h>
+#include <Internal/common.h>
+#include <Internal/filesystem.h>
+
+#include <Compat/fileio.h>
+#include <Memory/allocation.h>
+#include <Math/vec3math.h>
+#include <Threading/sdl_wrapper.h>
+#include <Utility/strings.h>
+
+#ifdef WIN32
+#define NOMINMAX
+#include <windows.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
+#include <memory.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdint>
+#include <cmath>
+#include <cerrno>
+
+
+/*******************************************************************
+ staticEmitter class - internal class for playing sounds.
+*******************************************************************/
+class StaticEmitter : public AudioEmitter {
+public:
+ StaticEmitter(bool loop, const vec3 &position, float volume, float pitch_mul = 1.0f, uint8_t flags = 0, float _max_distance = 100.0f, unsigned char _priority = _default_priority) :
+ m_looping(loop),
+ m_position(position),
+ m_velocity(0.0f),
+ m_volume(volume),
+ m_pitch_mul(pitch_mul),
+ m_volume_mult(1.0),
+ m_max_distance(_max_distance),
+ m_occlusion_position(position),
+ m_priority(_priority)
+ {flags_ = flags;}
+
+ ~StaticEmitter()
+ {}
+
+ virtual bool KeepPlaying() {
+ return m_looping?false:true;
+ }
+
+ virtual bool GetPosition(vec3 &p) {
+ p = m_position;
+ return ((flags_ & SoundFlags::kRelative) != 0);
+ }
+
+ virtual const vec3 GetPosition() {
+ return m_position;
+ }
+
+ virtual const vec3 GetOcclusionPosition() {
+ return m_occlusion_position;
+ }
+
+ virtual float GetMaxDistance() {
+ return m_max_distance;
+ }
+
+ virtual void GetDirection(vec3 &p) {
+ p.x() = 0.0f; p.y() = 0.0f; p.z() = 0.0f;
+ return;
+ }
+
+ virtual const vec3& GetVelocity() {
+ return m_velocity;
+ }
+
+ virtual float GetVolume() {
+ return m_volume * m_volume_mult;
+ }
+
+ virtual float GetPitchMultiplier() {
+ return m_pitch_mul;
+ }
+
+ virtual void SetPitchMultiplier(float mul) {
+ m_pitch_mul = mul;
+ }
+
+ virtual void SetVolume(float mul) {
+ if( mul > 1.0f )
+ mul = 1.0f;
+ if( mul < 0.0f )
+ mul = 0.0f;
+
+ m_volume = mul;
+ }
+
+ virtual void SetVolumeMult(float mul) {
+ m_volume_mult = mul;
+ }
+
+ virtual void SetPosition(const vec3 &pos) {
+ m_position = pos;
+ }
+
+ virtual void SetOcclusionPosition(const vec3 &pos) {
+ m_occlusion_position = pos;
+ }
+
+ virtual void SetVelocity(const vec3 &vel) {
+ m_velocity = vel;
+ }
+
+ virtual void Unsubscribe() {
+ // should call the audioEmitter destructor, all should be cleaned.
+ delete this;
+ }
+
+ virtual unsigned char GetPriority() {
+ return m_priority;
+ }
+
+private:
+ bool m_looping;
+ vec3 m_position;
+ vec3 m_velocity;
+ float m_volume;
+ float m_pitch_mul;
+ float m_volume_mult;
+ float m_max_distance;
+ vec3 m_occlusion_position;
+ unsigned char m_priority;
+};
+
+void AudioEmitter::link(alAudio &a)
+{
+ m_audio = &a;
+}
+
+void AudioEmitter::Unsubscribe()
+{
+ if (m_audio)
+ {
+ m_audio->unsubscribe(*this);
+ m_audio = NULL;
+ }
+}
+
+AudioEmitter::~AudioEmitter()
+{
+ if (m_audio)
+ {
+ m_audio->unsubscribe(*this);
+ m_audio = NULL;
+ }
+}
+
+uint8_t AudioEmitter::flags() {
+ return flags_;
+}
+
+int AudioEmitter::uid_counter = 1;
+
+
+/*******************************************************************
+ audioStreamer class - base interface for stream subscribers
+*******************************************************************/
+audioStreamer::audioStreamer()
+{
+}
+
+audioStreamer::~audioStreamer()
+{
+}
+
+alAudio::alAudio(const char* preferred_device, float volume, float reference_distance) :
+ m_device(NULL),
+ m_context(NULL),
+ priority_levels(0),
+ m_handle_ctr(0),
+ m_reference_distance(reference_distance),
+ m_gain(volume),
+ m_pitch(1.0f)
+{
+ //Sending NULL to alcOpenDevice will result in fallback to default.
+ const char* open_device_name = NULL;
+
+ if( preferred_device == NULL ) {
+ preferred_device = "";
+ }
+
+ this->preferred_device = std::string(preferred_device);
+
+ if( alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE ) {
+ LOGI << "ALC_ENUMERATION_EXT is available" << std::endl;
+
+ const char* device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+
+ size_t cur_d_start = 0;
+ if( strlen(preferred_device) > 0 ) {
+ LOGI << "Trying to open preferred device: " << preferred_device << std::endl;
+ }
+
+ LOGI << "=== Available sound devices ===" << std::endl;
+ while( device_list ) {
+ if( device_list[cur_d_start] == '\0' ) {
+ device_list = NULL;
+ } else {
+ LOGI << &device_list[cur_d_start] << std::endl;
+ available_device_list.push_back(std::string(&device_list[cur_d_start]));
+ if(strmtch(preferred_device, &device_list[cur_d_start])) {
+ open_device_name = &device_list[cur_d_start];
+ }
+ cur_d_start += strlen(&device_list[cur_d_start]) + 1;
+ }
+ }
+ LOGI << "=== ===" << std::endl;
+
+ if( open_device_name == NULL ) {
+ open_device_name = alcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER );
+ LOGI << "Opening default audio device: " << open_device_name << "." << std::endl;
+ } else {
+ LOGI << "Opening preferred audio device: " << open_device_name << "." << std::endl;
+ }
+
+ used_device = std::string(open_device_name);
+ } else {
+ LOGI << "ALC_ENUMERATION_EXT is not available, will open default device." << std::endl;
+ }
+
+ m_device = alcOpenDevice( open_device_name );
+
+ if( m_device )
+ {
+ const char* actual_device = alcGetString(m_device,ALC_DEVICE_SPECIFIER);
+
+ if( actual_device ) {
+ LOGI << "Opened and using audio device: " << actual_device << std::endl;
+ }
+
+ m_context = alcCreateContext( m_device, NULL );
+
+ if( m_context )
+ {
+ alcMakeContextCurrent( m_context );
+ alGetError(); // Clear Error Code
+
+ reset_listener();
+
+ const unsigned long _ideal_max_sources = 32;
+
+ for( unsigned i = 0; i < _ideal_max_sources; i++ )
+ {
+ rc_alAudioSource as;
+ as->Allocate();
+
+ if( as->IsValid() )
+ {
+ m_sources.push_back(as);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ LOGI << "We have " << m_sources.size() << " audio sources available." << std::endl;
+ }
+ else
+ {
+ LOGF << "Failed to load audio context, this means no sound, and probably crashing." << alcErrString(alcGetError(m_device)) << std::endl;
+ }
+ }
+ else
+ {
+ LOGF << "Failed to load audio device, this means no sound, and probably crashing." << std::endl;
+ }
+}
+
+void alAudio::Dispose() {
+
+ m_sources.clear();
+
+ m_buffers.clear();
+
+ // unsubscribe to all the audioEmitters,
+ // this will also allow the staticEmitters that are still running to be deleted
+ streamer_subscribers::iterator ssi;
+ for (ssi = m_streamers.begin(); ssi != m_streamers.end(); ++ssi)
+ {
+ if (!ssi->second->get_discard())
+ ssi->second->get_audioEmitter()->Unsubscribe();
+ }
+
+ for (ssi = m_streamers.begin(); ssi != m_streamers.end(); ++ssi)
+ {
+ delete ssi->second;
+ }
+
+ alcDestroyContext( m_context );
+
+ ALCenum err = alcGetError( m_device );
+ m_context = NULL;
+ if( err == ALC_NO_ERROR )
+ {
+ if( alcCloseDevice( m_device ) == false )
+ {
+ LOGE << "Unable to shut down alc device: \"" << alcErrString(err) << "\"" << std::endl;
+ }
+
+ m_device = NULL;
+ }
+ else
+ {
+ LOGE << "Error shutting down alc context: \"" << alcErrString(err) << "\"" << std::endl;
+ }
+}
+
+void alAudio::reset_listener()
+{
+ listener_pos = vec3(0.0f);
+ ALfloat listenerPos[]={0.0f,0.0f,0.0f};
+ ALfloat listenerVel[]={0.0f,0.0f,0.0f};
+ ALfloat listenerOri[]={0.0f,0.0f,-1.0f,0.0f,1.0f,0.0f}; // at, then up
+ // Set Listener attributes
+ alListenerfv(AL_POSITION,listenerPos);
+ alListenerfv(AL_VELOCITY,listenerVel);
+ alListenerfv(AL_ORIENTATION,listenerOri);
+}
+
+void alAudio::set_listener_position(vec3 &position)
+{
+ listener_pos = position;
+ alListener3f(AL_POSITION, position.x(), position.y(), position.z());
+}
+
+void alAudio::set_listener_orientation(vec3 &facing, vec3 &up)
+{
+ ALfloat listenerOri[6];
+ listenerOri[0] = facing.x();
+ listenerOri[1] = facing.y();
+ listenerOri[2] = facing.z();
+ listenerOri[3] = up.x();
+ listenerOri[4] = up.y();
+ listenerOri[5] = up.z();
+
+ alListenerfv(AL_ORIENTATION, listenerOri);
+}
+
+void alAudio::set_listener_velocity(vec3 &velocity)
+{
+ alListener3f(AL_VELOCITY, velocity.x(), velocity.y(), velocity.z());
+}
+
+void alAudio::update(float timestep)
+{
+
+ update_subscribers(timestep);
+
+ //Disabling because this system is now runnign in separate thread and needs to be fully contained.
+ //TODO: This rendering has to be moved to an external site.
+ /*
+ if( config["visible_sound_spheres"].toBool() )
+ {
+ static_handles::iterator iter = m_handles.begin();
+ for(; iter != m_handles.end(); ++iter){
+ DebugDraw::Instance()->AddWireSphere(iter->second->GetPosition(),
+ iter->second->GetMaxDistance()*0.4f, vec4(1.0f), _delete_on_update);
+ }
+ }
+ */
+
+}
+
+void alAudio::subscribe(audioStreamer &streamer)
+{
+ rc_alAudioSource source;
+
+ if (m_sources.empty())
+ {
+ //printf("Implement sound prioritization");
+ source = find_free_source();
+ }
+ else
+ {
+ source = m_sources.front();
+ m_sources.pop_front();
+ }
+
+ if( source->IsValid() )
+ {
+ streamer.link(*this);
+
+ // set current values in source
+ source->Sourcef(AL_REFERENCE_DISTANCE, m_reference_distance);
+ source->Sourcef(AL_GAIN, m_gain * streamer.GetVolume());
+ source->Sourcef(AL_PITCH, m_pitch * streamer.GetPitchMultiplier());
+ source->Sourcef(AL_MIN_GAIN, 0.0f);
+ source->Sourcef(AL_MAX_GAIN, 1.0f);
+
+ streamerLink *link = new streamerLink(source, streamer);
+ m_streamers.insert(streamer_subscribers::value_type(&streamer, link));
+ }
+}
+
+void alAudio::unsubscribe(AudioEmitter &streamer)
+{
+ const unsigned long &handle = streamer.handle;
+ m_handles.erase(handle);
+ //printf("Erasing %u from handles\n", handle);
+
+ streamer_subscribers::iterator it = m_streamers.find(&streamer);
+
+ if (it != m_streamers.end())
+ {
+ it->second->signal_discard();
+ }
+}
+
+
+void alAudio::update_subscribers(float timestep) {
+ unsigned int current_tick = SDL_TS_GetTicks();
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end()) {
+ if (it->second->get_discard()){
+ ++it;
+ continue;
+ }
+
+ // set current values in source
+ it->second->get_source()->Sourcef(AL_REFERENCE_DISTANCE, m_reference_distance);
+ it->second->get_source()->Sourcef(AL_GAIN, m_gain * it->second->get_audioEmitter()->GetVolume());
+ it->second->get_source()->Sourcef(AL_PITCH, m_pitch * it->second->get_audioEmitter()->GetPitchMultiplier());
+ const vec3 &vel = it->second->get_audioEmitter()->GetVelocity();
+ it->second->get_source()->Source3f(AL_VELOCITY, vel[0], vel[1], vel[2]);
+ //alSourcef(it->second->get_source(), AL_MIN_GAIN, 0.0f);
+ //alSourcef(it->second->get_source(), AL_MAX_GAIN, 1.0f);
+
+ it->second->update(timestep,current_tick);
+
+ ++it;
+ }
+
+ // sweep and remove discarded members
+ it = m_streamers.begin();
+ while(it != m_streamers.end())
+ {
+ if (it->second->get_discard())
+ {
+ it->second->get_source()->Stop();
+ m_sources.push_front(it->second->get_source());
+
+ delete it->second;
+ // verify
+ m_streamers.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+bool alAudio::load(const std::string& rel_path, const FilterInfo &filter_info) {
+ // prexisting file found, don't reload
+ if (m_buffers.end() != m_buffers.find(std::pair<std::string, std::string>(rel_path, filter_info.path))) {
+ return true;
+ }
+
+ if (rel_path[rel_path.length() - 1] == 'g' || rel_path[rel_path.length() - 1] == 'G')
+ return load_ogg(rel_path, filter_info);
+ else
+ return load_wav(rel_path, filter_info);
+}
+
+bool alAudio::load_ogg(const std::string& rel_path, const FilterInfo &filter_info)
+{
+ bool retval = true;
+
+ Path abs_path = FindFilePath( rel_path.c_str(), kAnyPath );
+
+ oggLoader ol(abs_path);
+
+ char *data = new char[ol.get_sample_count() * 2];
+
+ int max_size = ol.get_sample_count() * 2;
+ int size = 0;
+ int result = 0;
+ while(size < max_size)
+ {
+ result = ol.stream_buffer_int16(data + size, max_size);
+ if (result <= 0) {
+ delete [] data;
+ return false;
+ }
+
+ size += result;
+ }
+
+ ALenum format;
+
+ if(ol.get_channels() == 1)
+ format = AL_FORMAT_MONO16;
+ else
+ format = AL_FORMAT_STEREO16;
+
+ if (format != AL_FORMAT_MONO16)
+ {
+ LOGW << "Stereo format handed to a mono reader" << std::endl;
+ retval = false;
+ }
+
+ if (retval)
+ {
+ rc_alAudioBuffer buffer;
+ buffer->Allocate();
+
+ // Copy ogg data into AL Buffer
+ buffer->BufferData( format, data, ol.get_sample_count() * 2, ol.get_sample_rate());
+
+ if (AL_NO_ERROR == alGetError())
+ {
+ m_buffers.insert(buffer_map::value_type(
+ std::pair<std::string, std::string>(rel_path, filter_info.path),
+ buffer));
+ }
+ else
+ {
+ LOGE << "Failed to buffer data" << std::endl;
+ retval = false;
+ }
+ }
+
+ delete [] data;
+
+ return retval;
+}
+
+void LowPassFilter(ALenum format, ALvoid* data, ALsizei size) {
+ unsigned bytes_per_channel_sample = 1;
+ if(format == AL_FORMAT_MONO16 || format == AL_FORMAT_STEREO16){
+ bytes_per_channel_sample = 2;
+ }
+
+ unsigned channels = 1;
+ if(format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16){
+ channels = 2;
+ }
+
+ if(bytes_per_channel_sample == 2 && channels == 1){
+ int16_t* data_dbyte = (int16_t*)data;
+ for(int i=0; i<size/2-3; i++){
+ data_dbyte[i] = data_dbyte[i]/4 + data_dbyte[i+1]/4 + data_dbyte[i+2]/4 + data_dbyte[i+3]/4;
+ }
+ }
+
+ if(bytes_per_channel_sample == 2 && channels == 2){
+ int16_t* data_dbyte = (int16_t*)data;
+ for(int i=0; i<size/2-6; i++){
+ data_dbyte[i] = data_dbyte[i]/4 + data_dbyte[i+2]/4 + data_dbyte[i+4]/4 + data_dbyte[i+6]/4;
+ }
+ }
+}
+
+bool ParseWAV(const char* file_data, ALenum &format, ALvoid* &data, ALsizei &size, ALsizei &freq)
+{
+ const char* data_index = &file_data[0];
+ char xbuffer[5];
+ xbuffer[4] = '\0';
+ memcpy(xbuffer, data_index, 4);
+ data_index += 4;
+ if(strcmp(xbuffer, "RIFF") != 0){
+ LOGE << "WAV file has invalid header" << std::endl;
+ return false;
+ }
+ data_index += 4;
+ memcpy(xbuffer, data_index, 4);
+ data_index += 4;
+ if(strcmp(xbuffer, "WAVE") != 0){
+ LOGE << "WAV file has invalid header" << std::endl;
+ return false;
+ }
+ bool found_format_chunk = false;
+ do {
+ memcpy(xbuffer, data_index, 4);
+ data_index += 4;
+ if(strcmp(xbuffer, "fmt ") == 0){
+ found_format_chunk = true;
+ } else {
+ int32_t chunk_size = *((int32_t*)data_index);
+ data_index += 4 + chunk_size;
+ }
+ } while(!found_format_chunk);
+
+ data_index += 4;
+ int16_t audioFormat = *((int16_t*)data_index);
+ data_index += 2;
+ int16_t channels = *((int16_t*)data_index);
+ data_index += 2;
+ int32_t sampleRate = *((int32_t*)data_index);
+ data_index += 4;
+ //int32_t byteRate = *((int32_t*)data_index);
+ data_index += 6;
+ int16_t bitsPerSample = *((int16_t*)data_index);
+ data_index += 2;
+
+ if (audioFormat != 1) {
+ // Note: This early exit was added because the original code assumed there'd be a 16bit int here.
+ // In the case of an example 32 bit float file, audioFormat == 3, this was a "fact" chunk instead,
+ // and it would convert "fa" to an int16, and then skip 24+kb and hit an access violation
+ LOGE << "WAV file has unsupported non-PCM format" << std::endl;
+ return false;
+ }
+
+ bool found_data_chunk = false;
+ do {
+ memcpy(xbuffer, data_index, 4);
+ data_index += 4;
+ if(strcmp(xbuffer, "data") == 0){
+ found_data_chunk = true;
+ } else {
+ int32_t chunk_size = *((int32_t*)data_index);
+ data_index += 4 + chunk_size;
+ }
+ } while(!found_data_chunk);
+
+ int32_t dataChunkSize = *((int32_t*)data_index);
+ data_index += 4;
+
+ if(channels == 1 && bitsPerSample == 8){
+ format = AL_FORMAT_MONO8;
+ } else if(channels == 2 && bitsPerSample == 8){
+ format = AL_FORMAT_STEREO8;
+ } else if(channels == 1 && bitsPerSample == 16){
+ format = AL_FORMAT_MONO16;
+ } else if(channels == 2 && bitsPerSample == 16){
+ format = AL_FORMAT_STEREO16;
+ } else {
+ LOGE << "WAV file has unknown format" << std::endl;
+ return false;
+ }
+
+ freq = sampleRate;
+ data = OG_MALLOC(dataChunkSize);
+ size = dataChunkSize;
+ memcpy(data, data_index, dataChunkSize);
+
+ return true;
+}
+
+bool GenerateEmptyData(ALenum &format, ALvoid* &data, ALsizei &size, ALsizei &freq) {
+ freq = 44100;
+ format = AL_FORMAT_MONO8;
+ size = freq*5;
+ data = OG_MALLOC(size);
+ memset(data, 0, size);
+ return true;
+}
+
+bool LoadWAVFromFile(const char* file_path, ALenum &format, ALvoid* &data, ALsizei &size, ALsizei &freq) {
+ FILE* file = my_fopen(file_path, "rb");
+ if(!file){
+ LOGE << "Could not open WAV file (fopen): " << file_path << " " << strerror(errno) << std::endl;
+ return false;
+ }
+
+ fseek (file, 0, SEEK_END);
+ int file_size = ftell(file);
+ rewind (file);
+
+ void* mem = OG_MALLOC(file_size);
+ if(!mem){
+ LOGE << "Could not allocate memory for file: " << file_path << std::endl;
+ fclose(file);
+ return false;
+ }
+ fread(mem, 1, file_size, file);
+ fclose(file);
+
+ bool ret = ParseWAV((char*)mem, format, data, size, freq);
+
+ OG_FREE(mem);
+ return ret;
+}
+
+bool alAudio::load_wav(const std::string& rel_path, const FilterInfo &filter_info) {
+ bool retval = true;
+
+ ALint error;
+ ALsizei size,freq;
+ ALenum format;
+ ALvoid *data = NULL;
+
+ char abs_path[kPathSize];
+ if(FindFilePath(rel_path.c_str(), abs_path, kPathSize, kModPaths|kDataPaths) == -1){
+ LOGE << "Could not find sound file: " << rel_path.c_str() << ". Generating empty placeholder." << std::endl;
+ GenerateEmptyData(format,data,size,freq);
+ } else {
+ if( LoadWAVFromFile(abs_path,format,data,size,freq) == false ) {
+ LOGE << "Failed loading data, generating empty placeholder for " << rel_path.c_str() << std::endl;
+ GenerateEmptyData(format,data,size,freq);
+ }
+ }
+
+ if (data == NULL) {
+ retval = false;
+ } else {
+ rc_alAudioBuffer buffer;
+ buffer->Allocate();
+
+ //LowPassFilter(format, data, size);
+
+ AudioBufferData abd;
+ abd.bytes_per_channel_sample = 1;
+ if(format == AL_FORMAT_MONO16 || format == AL_FORMAT_STEREO16){
+ abd.bytes_per_channel_sample = 2;
+ }
+ abd.channels = 1;
+ if(format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16){
+ abd.channels = 2;
+ }
+ abd.num_bytes = size;
+ abd.data = (void*)data;
+
+ if(!filter_info.path.empty()){
+ if(filter_info.type == _simple_filter) {
+ SimpleFIRFilter filter;
+ if( filter.Load(filter_info.path) ) {
+ filter.Apply(abd);
+ } else {
+ LOGE << "Failed loading fir filter: " << filter_info.path << " will not apply to sound of " << rel_path << std::endl;
+ }
+ buffer->BufferData(format,data,size,freq);
+ } else if(filter_info.type == _convolution_filter) {
+ LOGE << "Game does not currently support _convolution_filter for audio, and the developer never expected it to be used, it was disabled because underlying library was removed after being deemed not in use." << std::endl;
+
+ buffer->BufferData(format,data,size,freq);
+ /*
+ FFTConvolutionFilter filter;
+ std::vector<int16_t> filtered;
+ if( filter.Load(filter_info.path) ) {
+ filter.Apply(abd, &filtered);
+ } else {
+ LOGE << "Failed loading FFTConvolution filter: " << filter_info.path << " will not apply to sound of " << rel_path << std::endl;
+ }
+ if(!filtered.empty()){
+ buffer->BufferData(format,&filtered[0],filtered.size()*2,freq);
+ } else {
+ buffer->BufferData(format,data,size,freq);
+ }
+ */
+ }
+ } else {
+ buffer->BufferData(format,data,size,freq);
+ }
+
+ if ((error = alGetError()) == AL_NO_ERROR) {
+ m_buffers.insert(buffer_map::value_type(
+ std::pair<std::string, std::string>(rel_path, filter_info.path),
+ buffer));
+ } else {
+ LOGE << "Failed to buffer data: \"" << alErrString(error) << "\"" << std::endl;
+ retval = false;
+ }
+ }
+
+ OG_FREE(data);
+
+ return retval;
+}
+
+void alAudio::set_volume(float volume)
+{
+ m_gain = volume;
+
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end())
+ {
+ if (!it->second->get_discard())
+ {
+ it->second->get_source()->Sourcef(AL_GAIN, m_gain * it->second->get_audioEmitter()->GetVolume());
+ }
+ ++it;
+ }
+}
+
+void alAudio::set_master_volume( float volume )
+{
+ if( volume > 1.0f )
+ volume = 1.0f;
+ if( volume < 0.0f )
+ volume = 0.0f;
+
+ alListenerf(AL_GAIN, volume);
+}
+
+void alAudio::set_pitch(float pitch)
+{
+ m_pitch = pitch;
+
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end())
+ {
+ if (!it->second->get_discard())
+ {
+ it->second->get_source()->Sourcef(AL_PITCH, m_pitch * it->second->get_audioEmitter()->GetPitchMultiplier());
+ }
+ ++it;
+ }
+}
+
+void alAudio::set_reference_distance(float distance)
+{
+ m_reference_distance = distance;
+
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end())
+ {
+ if (!it->second->get_discard())
+ {
+ it->second->get_source()->Sourcef( AL_REFERENCE_DISTANCE, m_reference_distance);
+ }
+ ++it;
+ }
+}
+
+void alAudio::set_distance_model(ALenum model)
+{
+ alDistanceModel(model);
+}
+
+void alAudio::play(const unsigned long& handle, const SoundPlayInfo& spi, AudioEmitter *owner )
+{
+ set_sound(handle,spi, owner);
+}
+
+std::vector<AudioEmitter*> alAudio::GetActiveSounds() {
+ std::vector<AudioEmitter*> active_sounds(m_handles.size());
+ alAudio::static_handles::iterator iter;
+ unsigned i=0;
+ for(iter = m_handles.begin(); iter != m_handles.end(); ++iter){
+ active_sounds[i] = iter->second;
+ ++i;
+ }
+ return active_sounds;
+}
+
+float GetRolloffFromMaxDistance(float max_distance){
+ static const float inv_threshold_vol = 100.0f;
+ return (inv_threshold_vol - 1.0f) / (1+max_distance);
+}
+
+int alAudio::set_sound(const unsigned long& handle, const SoundPlayInfo& spi, AudioEmitter *owner)
+{
+ if(!spi.looping && !(spi.flags & SoundFlags::kRelative) && distance_squared(spi.position, listener_pos) >
+ spi.max_distance * spi.max_distance)
+ {
+ return -1;
+ }
+ const char *rel_path = spi.path.c_str();
+
+ buffer_map::iterator it = m_buffers.find(
+ std::pair<std::string, std::string>(rel_path, spi.filter_info.path));
+
+ // if buffer isn't found, need to load.
+ if (m_buffers.end() == it) {
+ size_t str_size = strlen(rel_path);
+ char *buffer = new char [str_size + 1];
+ ::memset(buffer, 0, str_size + 1);
+ ::memcpy(buffer, rel_path, str_size);
+
+ if (load(buffer, spi.filter_info)) {
+ it = m_buffers.find(
+ std::pair<std::string, std::string>(
+ rel_path, spi.filter_info.path)); // this can be made faster.
+ } else {
+ it = m_buffers.end();
+ }
+
+ ALenum err = alGetError();
+
+ if( err != AL_NO_ERROR )
+ {
+ LOGE << alErrString(err) << std::endl;
+ }
+
+ delete [] buffer;
+ }
+
+ if (m_buffers.end() != it) {
+ //need to manage this better than dropping out.
+ rc_alAudioSource source;
+
+ if (m_sources.empty())
+ {
+ //printf("Implement sound prioritization");
+ source = find_free_source();
+ }
+ else
+ {
+ source = m_sources.front();
+ m_sources.pop_front();
+ }
+
+ if( source->IsValid() )
+ {
+ priority_levels = max(priority_levels, spi.priority);
+
+ AudioEmitter *emitter = NULL;
+ if (owner == NULL)
+ {
+ //printf("Creating %u %s\n",handle, spi.path.c_str());
+ // this is not a leak due to the unsubscribe deleting the object.
+ //staticEmitter *emitter = new staticEmitter(looping, position);
+ emitter = new StaticEmitter(spi.looping, spi.position, spi.volume, spi.pitch, spi.flags, spi.max_distance, spi.priority);
+ emitter->handle = handle;
+ m_handles.insert(static_handles::value_type(handle, emitter));
+ }
+ else
+ {
+ emitter = owner;
+ }
+ CheckALError(__LINE__, __FILE__);
+ emitter->display_name = spi.path.substr(spi.path.rfind('/')+1);
+ emitter->SetOcclusionPosition(spi.occlusion_position);
+ emitter->SetVolumeMult(spi.volume_mult);
+
+ // set current values in source
+ source->Sourcef(AL_REFERENCE_DISTANCE, m_reference_distance);
+ //alSourcef(source, AL_ROLLOFF_FACTOR, GetRolloffFromMaxDistance(spi.max_distance));
+ source->Sourcef(AL_GAIN, m_gain * emitter->GetVolume());
+ source->Sourcef(AL_PITCH, m_pitch * emitter->GetPitchMultiplier());
+ source->Sourcef(AL_MIN_GAIN, 0.0f);
+ source->Sourcef(AL_MAX_GAIN, spi.max_gain);
+ CheckALError(__LINE__, __FILE__);
+
+ vec3 p;
+ source->Sourcei (AL_SOURCE_RELATIVE, emitter->GetPosition(p)?AL_TRUE:AL_FALSE);
+ source->Source3f(AL_POSITION, p.x(), p.y(), p.z());
+ emitter->GetDirection(p);
+ source->Source3f(AL_DIRECTION, p.x(), p.y(), p.z());
+ p = emitter->GetVelocity();
+ source->Source3f(AL_VELOCITY, p.x(), p.y(), p.z());
+
+ emitter->link(*this);
+ staticLink *link = new staticLink(source, *emitter, it->second, spi);
+ m_streamers.insert(streamer_subscribers::value_type(emitter, link));
+
+ CheckALError(__LINE__, __FILE__);
+ }
+ }
+ else
+ {
+ LOGE << "Unable to load sound file: " << rel_path << std::endl;
+ }
+
+ return handle;
+}
+
+rc_alAudioSource alAudio::find_free_source()
+{
+ int i = priority_levels;
+ do {
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end())
+ {
+ if (it->second->get_discard() || (it->second->get_audioEmitter()->GetPriority() == i))
+ {
+ rc_alAudioSource source = it->second->get_source();
+ source->Stop();
+
+ // nuke handles.
+ static_handles::iterator it_handle = m_handles.begin();
+ while(it_handle != m_handles.end())
+ {
+ if (it->second->get_audioEmitter() == it_handle->second) {
+ /*it_handle = */m_handles.erase(it_handle++);
+ } else {
+ ++it_handle;
+ }
+ }
+
+ delete it->second;
+ m_streamers.erase(it++);
+
+ return source;
+ }
+ ++it;
+ }
+ --i;
+ } while (i >= 0);
+
+ return rc_alAudioSource();
+}
+
+std::string GetALErrorString(ALenum err)
+{
+ switch(err)
+ {
+ case AL_NO_ERROR:
+ return std::string("AL_NO_ERROR");
+ break;
+
+ case AL_INVALID_NAME:
+ return std::string("AL_INVALID_NAME");
+ break;
+
+ case AL_INVALID_ENUM:
+ return std::string("AL_INVALID_ENUM");
+ break;
+
+ case AL_INVALID_VALUE:
+ return std::string("AL_INVALID_VALUE");
+ break;
+
+ case AL_INVALID_OPERATION:
+ return std::string("AL_INVALID_OPERATION");
+ break;
+
+ case AL_OUT_OF_MEMORY:
+ return std::string("AL_OUT_OF_MEMORY");
+ break;
+ };
+
+ return std::string("Unknown OpenAL error");
+}
+
+void CheckALError(int line, const char* file){
+ ALenum err;
+ err = alGetError();
+ if (err != AL_NO_ERROR) {
+ char error_msg[1024];
+ int i = 0;
+ int last_slash = 0;
+ while(file[i] != '\0') {
+ if(file[i] == '\\' || file[i] == '/') last_slash = i+1;
+ i++;
+ }
+ FormatString(error_msg, 1024, "On line %d of %s: \n%s", line, &file[last_slash], GetALErrorString(err).c_str());
+ DisplayError("OpenAL error", error_msg);
+ }
+}
+
+alAudio::streamerLink::streamerLink(rc_alAudioSource source, audioStreamer &streamer) :
+ basicLink(source), m_streamer(&streamer)
+{
+ unsigned long i = 0;
+ for (i = 0; i < streamer.required_buffers(); ++i)
+ {
+ rc_alAudioBuffer buf;
+ buf->Allocate();
+ m_buffers.push_back(buf);
+ }
+
+ for (i = 0; i < m_buffers.size(); ++i)
+ {
+ update(m_buffers[i]);
+ }
+
+
+ CheckALError(__LINE__, __FILE__);
+ m_source->QueueBuffers( std::vector<rc_alAudioBuffer>(m_buffers.begin(),m_buffers.begin() + streamer.required_buffers()));
+ CheckALError(__LINE__, __FILE__);
+ m_source->Play();
+ CheckALError(__LINE__, __FILE__);
+}
+
+alAudio::streamerLink::~streamerLink()
+{
+ // may not be a safe assumption in the future
+ m_source->Stop();
+}
+
+void alAudio::streamerLink::update(rc_alAudioBuffer buffer)
+{
+ m_streamer->update(buffer);
+ update_position();
+}
+
+void alAudio::streamerLink::update(float timestep, unsigned int current_tick)
+{
+ update_position();
+
+ std::vector<rc_alAudioBuffer> buffers = m_source->DequeueBuffers();
+
+ for( unsigned i = 0; i < buffers.size(); i++ )
+ {
+ m_streamer->update(buffers[i]);
+ }
+
+ m_source->QueueBuffers(buffers);
+
+ // check if playback stopped due to buffer timeout...
+ ALint state = m_source->GetSourcei(AL_SOURCE_STATE);
+
+ if (AL_STOPPED == state)
+ {
+ if (m_streamer->KeepPlaying())
+ {
+ m_source->Play();
+ }
+ else
+ {
+ m_streamer->Unsubscribe();
+ }
+ }
+}
+
+void alAudio::streamerLink::update_position()
+{
+ vec3 p;
+
+ m_source->Sourcei (AL_SOURCE_RELATIVE, m_streamer->GetPosition(p)?AL_TRUE:AL_FALSE);
+ m_source->Source3f(AL_POSITION, p.x(), p.y(), p.z());
+
+ m_streamer->GetDirection(p);
+ m_source->Source3f(AL_DIRECTION, p.x(), p.y(), p.z());
+ p = m_streamer->GetVelocity();
+ m_source->Source3f(AL_VELOCITY, p.x(), p.y(), p.z());
+}
+
+void alAudio::streamerLink::stop()
+{
+ m_streamer->Stop();
+ m_source->Stop();
+
+ std::vector<rc_alAudioBuffer> buffers = m_source->DequeueBuffers();
+
+ for( unsigned i = 0; i < buffers.size(); i++ )
+ {
+ m_streamer->update(buffers[i]);
+ }
+
+ m_source->QueueBuffers(buffers);
+
+ m_source->Play();
+}
+
+
+alAudio::staticLink::staticLink( rc_alAudioSource source, AudioEmitter &emitter, rc_alAudioBuffer buffer, const SoundPlayInfo &_spi) :
+ basicLink(source),
+ m_buffer(buffer),
+ m_emitter(&emitter),
+ played(false),
+ play_on_tick(_spi.play_past_tick)
+{
+ spi = _spi;
+ source->SetBuffer( m_buffer);
+ source->Sourcei(AL_LOOPING, spi.looping?AL_TRUE:AL_FALSE);
+ m_source->Stop();
+}
+
+alAudio::staticLink::~staticLink() {
+}
+
+void alAudio::staticLink::update(float timestep, unsigned int current_tick) {
+ update_position();
+
+ vec3 p;
+ m_emitter->GetPosition(p);
+
+ /*
+ TODO: Move to external routine, calling it from here would break the thread boundery
+ if( config["visible_sound_spheres"].toBool() )
+ {
+ DebugDraw::Instance()->AddLine(p, p+vec3(0.0f,1.0f,0.0f), 0.1f, vec4(1.0f), _delete_on_draw);
+ }
+ */
+
+ if( current_tick >= play_on_tick && played == false) {
+ m_source->Play();
+ played = true;
+ }
+
+ ALint state = m_source->GetSourcei(AL_SOURCE_STATE);
+ if (played == true && AL_STOPPED == state )
+ {
+ m_emitter->Unsubscribe();
+ }
+ // Do not put any code after this spot, unsubscribe WILL destroy this object.
+}
+
+void alAudio::staticLink::update_position() {
+ vec3 p;
+
+ m_source->Sourcei (AL_SOURCE_RELATIVE, m_emitter->GetPosition(p)?AL_TRUE:AL_FALSE);
+ m_source->Source3f(AL_POSITION, p.x(), p.y(), p.z());
+
+ m_emitter->GetDirection(p);
+ m_source->Source3f(AL_DIRECTION, p.x(), p.y(), p.z());
+ p = m_emitter->GetVelocity();
+ m_source->Source3f(AL_VELOCITY, p.x(), p.y(), p.z());
+}
+
+void alAudio::staticLink::stop() {
+ m_emitter->Unsubscribe();
+ // Do not put any code after this spot, unsubscribe WILL destroy this object.
+}
+
+unsigned long alAudio::get_next_handle() {
+ return ++m_handle_ctr;
+}
+
+unsigned long alAudio::get_invalid_handle() {
+ return 0;
+}
+
+std::string alAudio::GetPreferredDevice() {
+ return preferred_device;
+}
+
+std::string alAudio::GetUsedDevice() {
+ return used_device;
+}
+
+std::vector<std::string> alAudio::GetAvailableDevices() {
+ return available_device_list;
+}
+
+void alAudio::change_pitch(unsigned long handle, float pitch) {
+ static_handles::iterator it = m_handles.find(handle);
+
+ if (it != m_handles.end()) {
+ it->second->SetPitchMultiplier(pitch);
+ }
+}
+
+void alAudio::change_volume(unsigned long handle, float volume) {
+ static_handles::iterator it = m_handles.find(handle);
+
+ if (it != m_handles.end()) {
+ it->second->SetVolume(volume);
+ }
+}
+
+void alAudio::SetPosition(const unsigned long &handle, const vec3 &new_pos) {
+ static_handles::iterator it = m_handles.find(handle);
+
+ if (it != m_handles.end()) {
+ it->second->SetPosition(new_pos);
+ }
+}
+
+void alAudio::TranslatePosition(const unsigned long &handle, const vec3 &new_pos) {
+ static_handles::iterator it = m_handles.find(handle);
+
+ if (it != m_handles.end()) {
+ it->second->SetPosition(it->second->GetPosition()+new_pos);
+ }
+}
+
+void alAudio::SetOcclusionPosition(const unsigned long &handle, const vec3 &new_pos) {
+ static_handles::iterator it = m_handles.find(handle);
+
+ if (it != m_handles.end()) {
+ it->second->SetOcclusionPosition(new_pos);
+ }
+}
+
+void alAudio::SetVelocity(const unsigned long &handle, const vec3 &new_vel) {
+ static_handles::iterator it = m_handles.find(handle);
+
+ if (it != m_handles.end()) {
+ it->second->SetVelocity(new_vel);
+ }
+}
+
+bool alAudio::IsHandleValid(const unsigned long &handle) {
+ static_handles::iterator it = m_handles.find(handle);
+ if (it != m_handles.end()) {
+ return true;
+ }
+ return false;
+}
+
+const vec3 alAudio::GetPosition( const unsigned long &handle ) {
+ static_handles::iterator it = m_handles.find(handle);
+ if (it != m_handles.end()) {
+ return(it->second->GetPosition());
+ }
+ return vec3(0.0f);
+}
+
+void alAudio::SetPitch( const unsigned long &handle, float pitch ) {
+ static_handles::iterator it = m_handles.find(handle);
+ if (it != m_handles.end()) {
+ it->second->SetPitchMultiplier(pitch);
+ }
+}
+
+void alAudio::SetVolume( const unsigned long &handle, float volume ) {
+ static_handles::iterator it = m_handles.find(handle);
+ if (it != m_handles.end()) {
+ it->second->SetVolume(volume);
+ }
+}
+
+void alAudio::Stop( const unsigned long & handle ) {
+ static_handles::iterator it = m_handles.find(handle);
+ if (it != m_handles.end()) {
+ //printf("Stopping %u\n",handle);
+ it->second->Unsubscribe();
+ }
+}
+
+void alAudio::StopAll() {
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end()) {
+ if (it->second->get_discard()){
+ ++it;
+ continue;
+ }
+
+ it->second->stop();
+
+ ++it;
+ }
+}
+
+void alAudio::StopAllTransient()
+{
+ streamer_subscribers::iterator it = m_streamers.begin();
+ while(it != m_streamers.end()) {
+ if (it->second->get_discard()){
+ ++it;
+ continue;
+ }
+
+ if( it->second->is_transient() )
+ {
+ it->second->stop();
+ }
+
+ ++it;
+ }
+}
+
+bool SimpleFIRFilter::Load( const std::string &path )
+{
+ ALsizei size,freq;
+ ALenum format;
+ ALvoid *data = NULL;
+
+ char abs_path[kPathSize];
+ FindFilePath(path.c_str(), abs_path, kPathSize, kDataPaths | kModPaths);
+
+ if( LoadWAVFromFile(abs_path, format, data, size, freq) ) {
+ if( data ) {
+ unsigned bytes_per_channel_sample = 1;
+ if(format == AL_FORMAT_MONO16 || format == AL_FORMAT_STEREO16){
+ bytes_per_channel_sample = 2;
+ }
+
+ unsigned channels = 1;
+ if(format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16){
+ channels = 2;
+ }
+
+ if(bytes_per_channel_sample == 2 && channels == 1){
+ int16_t* data_dbyte = (int16_t*)data;
+ filter.resize(size/2);
+ for(int i=0; i<size/2; i++){
+ filter[i] = data_dbyte[i] / 32767.0f;
+ }
+ } else {
+ OG_FREE(data);
+ data = NULL;
+ LOGE << "Filter is not 16-bit mono: " << path.c_str() << std::endl;
+ return false;
+ }
+ } else {
+ LOGE << "Unable to load fir filter from " << path << std::endl;
+ return false;
+ }
+ } else {
+ LOGE << "Unable to load wav file for FIR filter" << std::endl;
+ return false;
+ }
+
+ OG_FREE( data );
+ return true;
+}
+
+void SimpleFIRFilter::Apply( AudioBufferData &abd, std::vector<int16_t> *output_new)
+{
+ unsigned filter_mid = unsigned(((float)filter.size())*0.5f);
+ unsigned filter_size = filter.size();
+ unsigned filter_tip = filter_size - filter_mid;
+
+ if(abd.bytes_per_channel_sample == 2){
+ for(unsigned k=0; k<abd.channels; ++k){
+ int16_t* data_dbyte = (int16_t*)abd.data;
+ unsigned end = abd.num_bytes/2/abd.channels;
+
+ std::vector<int16_t> temp(filter_size);
+ for(unsigned i=0; i<filter_mid; ++i){
+ temp[i] = 0;
+ }
+ unsigned next_step = min(filter_size,end+filter_mid);
+ for(unsigned i=filter_mid; i<next_step; ++i){
+ temp[i] = data_dbyte[(i-filter_mid)*abd.channels+k];
+ }
+ for(unsigned i=end+filter_mid; i<filter_size; ++i){
+ temp[i] = 0;
+ }
+
+ unsigned offset = 0;
+ float total;
+ for(unsigned i=0; i<end; i++){
+ total = 0.0f;
+ for(unsigned j=0; j<filter.size(); ++j){
+ total += (float)temp[(j+offset)%filter_size] * filter[j];
+ }
+ data_dbyte[i*abd.channels+k] = (int16_t)total;
+ if(i+filter_tip < end){
+ temp[offset] = data_dbyte[(i+filter_tip)*abd.channels+k];
+ } else {
+ temp[offset] = 0;
+ }
+ ++offset;
+ offset = offset%filter_size;
+ }
+ }
+ }
+}
+
+/*
+bool FFTConvolutionFilter::Load( const std::string &path )
+{
+ ALsizei size,freq;
+ ALenum format;
+ ALvoid *data = NULL;
+
+ char abs_path[kPathSize];
+ FindFilePath(path.c_str(), abs_path, kPathSize, kDataPaths | kModPaths);
+
+ if( LoadWAVFromFile(abs_path, format, data, size, freq) ) {
+ if( data )
+ {
+ unsigned bytes_per_channel_sample = 1;
+ if(format == AL_FORMAT_MONO16 || format == AL_FORMAT_STEREO16){
+ bytes_per_channel_sample = 2;
+ }
+
+ unsigned channels = 1;
+ if(format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16){
+ channels = 2;
+ }
+
+ if(bytes_per_channel_sample == 2 && channels == 1){
+ int16_t* data_dbyte = (int16_t*)data;
+ filter.resize(size/2);
+ for(int i=0; i<size/2; i++){
+ filter[i] = data_dbyte[i];// / 32767.0f;
+ }
+ } else {
+ LOGE << "Filter is not 16-bit mono: " << path.c_str() << std::endl;
+ OG_FREE(data);
+ data = NULL;
+ return false;
+ }
+ } else {
+ LOGE << "Unable to load convolution filter from " << path << std::endl;
+ return false;
+ }
+ } else {
+ LOGE << "Unable to load wav file for FFTConvolution filter" << std::endl;
+ return false;
+ }
+
+ OG_FREE(data);
+ return true;
+}
+
+void FFTConvolutionFilter::Apply( AudioBufferData &abd, std::vector<int16_t> *output_new)
+{
+ if(abd.channels > 1){
+ return;
+ }
+ int16_t* samples = (int16_t*)abd.data;
+ int length1 = abd.num_bytes/abd.bytes_per_channel_sample;
+ int length2 = filter.size();
+
+ float gain = 0.2f;
+
+ int i;
+ float *in;
+ float *in2;
+ int n;
+ int nc;
+ fftwf_complex *out1;
+ fftwf_complex *out2;
+ fftwf_plan plan_backward;
+ fftwf_plan plan_forward;
+
+ int long_length = length1+length2-1;
+
+ n = long_length;
+ nc = ( n / 2 ) + 1;
+ in = (float*)fftwf_malloc ( sizeof ( float ) * n );
+ for ( i = 0; i < length1; i++ )
+ {
+ in[i] = samples[i];
+ }
+ for ( i = length1; i < n; i++ )
+ {
+ in[i] = 0;
+ }
+ out1 = (fftwf_complex*)fftwf_malloc ( sizeof ( fftwf_complex ) * nc );
+ plan_forward = fftwf_plan_dft_r2c_1d ( n, in, out1, FFTW_ESTIMATE );
+ fftwf_execute ( plan_forward );
+ fftwf_destroy_plan ( plan_forward );
+ fftwf_free ( in );
+
+ in = (float*)fftwf_malloc ( sizeof ( float ) * n );
+ for ( i = 0; i < length2; i++ )
+ {
+ in[i] = filter[i];
+ }
+ for ( i = length2; i < n; i++ )
+ {
+ in[i] = 0;
+ }
+ out2 = (fftwf_complex*)fftwf_malloc ( sizeof ( fftwf_complex ) * nc );
+ plan_forward = fftwf_plan_dft_r2c_1d ( n, in, out2, FFTW_ESTIMATE );
+ fftwf_execute ( plan_forward );
+ fftwf_destroy_plan ( plan_forward );
+ fftwf_free ( in );
+
+ float new_r;
+ float new_i;
+ float scale = 1/(float)n*gain;
+ for (i = 0;i<nc;i++){
+ new_r = (out1[i][0]*out2[i][0] - out1[i][1]*out2[i][1])*scale;
+ new_i = (out1[i][1]*out2[i][0] + out1[i][0]*out2[i][1])*scale;
+
+ out1[i][0] = new_r;
+ out1[i][1] = new_i;
+ }
+
+
+ //Set up an array to hold the backtransformed data IN2,
+ //get a "plan", and execute the plan to backtransform the OUT
+ //FFT coefficients to IN2.
+
+
+ in2 = (float*)fftwf_malloc ( sizeof ( float ) * n );
+ plan_backward = fftwf_plan_dft_c2r_1d ( n, out1, in2, FFTW_ESTIMATE );
+ fftwf_execute ( plan_backward );
+
+ for (i = 0; i < length1; i++ )
+ {
+ samples[i] = (int16_t)(in2[i]/n);
+ }
+
+ if(output_new){
+ std::vector<int16_t> &output = (*output_new);
+ output.resize(long_length);
+ for (i = 0; i < long_length; i++ )
+ {
+ output[i] = (int16_t)(in2[i]/n);
+ }
+ }
+
+ fftwf_destroy_plan ( plan_backward );
+ fftwf_free ( in2 );
+ fftwf_free ( out1 );
+ fftwf_free ( out2 );
+
+ return;
+}
+*/
+
+void alAudio::SetVolumeMult( const unsigned long &handle, float volume )
+{
+ static_handles::iterator it = m_handles.find(handle);
+ if (it != m_handles.end())
+ {
+ it->second->SetVolumeMult(volume);
+ }
+}