Fixed bug that caused HRTF audio spatialized sounds to come from the incorrect directions.
This commit is contained in:
@@ -69,6 +69,8 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context)
|
|||||||
|
|
||||||
m_workspace_data = NULL;
|
m_workspace_data = NULL;
|
||||||
m_reverb_sequence = 0;
|
m_reverb_sequence = 0;
|
||||||
|
|
||||||
|
m_hrtf_data = NULL;
|
||||||
|
|
||||||
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
||||||
m_reverb_impulse_responses[i] = NULL;
|
m_reverb_impulse_responses[i] = NULL;
|
||||||
@@ -680,6 +682,53 @@ void KRAudioManager::initHRTF()
|
|||||||
m_hrtf_sample_locations.push_back(KRVector2(80.0f,150.0f));
|
m_hrtf_sample_locations.push_back(KRVector2(80.0f,150.0f));
|
||||||
m_hrtf_sample_locations.push_back(KRVector2(80.0f,180.0f));
|
m_hrtf_sample_locations.push_back(KRVector2(80.0f,180.0f));
|
||||||
m_hrtf_sample_locations.push_back(KRVector2(90.0f,000.0f));
|
m_hrtf_sample_locations.push_back(KRVector2(90.0f,000.0f));
|
||||||
|
|
||||||
|
if(m_hrtf_data) {
|
||||||
|
delete m_hrtf_data;
|
||||||
|
}
|
||||||
|
m_hrtf_data = (float *)malloc(m_hrtf_sample_locations.size() * sizeof(float) * 128 * 4 * 2);
|
||||||
|
|
||||||
|
for(int channel=0; channel < 2; channel++) {
|
||||||
|
m_hrtf_spectral[channel].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int sample_index=0;
|
||||||
|
for(std::vector<KRVector2>::iterator itr=m_hrtf_sample_locations.begin(); itr != m_hrtf_sample_locations.end(); itr++) {
|
||||||
|
KRVector2 pos = *itr;
|
||||||
|
KRAudioSample *sample = getHRTFSample(pos);
|
||||||
|
for(int channel=0; channel < 2; channel++) {
|
||||||
|
DSPSplitComplex spectral;
|
||||||
|
spectral.realp = m_hrtf_data + sample_index * 1024 + channel * 512;
|
||||||
|
spectral.imagp = m_hrtf_data + sample_index * 1024 + channel * 512 + 256;
|
||||||
|
sample->sample(0, 128, channel, spectral.realp, 1.0f);
|
||||||
|
memset(spectral.realp + 128, 0, sizeof(float) * 128);
|
||||||
|
memset(spectral.imagp, 0, sizeof(float) * 256);
|
||||||
|
vDSP_fft_zip(m_fft_setup, &spectral, 1, 8, kFFTDirection_Forward);
|
||||||
|
m_hrtf_spectral[channel][pos] = spectral;
|
||||||
|
}
|
||||||
|
sample_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
KRAudioSample *KRAudioManager::getHRTFSample(const KRVector2 &hrtf_dir)
|
||||||
|
{
|
||||||
|
//hrtf_kemar_H-10e000a.wav
|
||||||
|
char szName[64];
|
||||||
|
sprintf(szName, "hrtf_kemar_H%de%03da", int(hrtf_dir.x), abs(int(hrtf_dir.y)));
|
||||||
|
|
||||||
|
return get(szName);
|
||||||
|
}
|
||||||
|
|
||||||
|
DSPSplitComplex KRAudioManager::getHRTFSpectral(const KRVector2 &hrtf_dir, const int channel)
|
||||||
|
{
|
||||||
|
KRVector2 dir = hrtf_dir;
|
||||||
|
int sample_channel = channel;
|
||||||
|
if(dir.y < 0) {
|
||||||
|
dir.y = -dir.y;
|
||||||
|
sample_channel = (channel + 1) % 2;
|
||||||
|
}
|
||||||
|
return m_hrtf_spectral[sample_channel][dir];
|
||||||
}
|
}
|
||||||
|
|
||||||
void KRAudioManager::getHRTFMix(const KRVector2 &dir, KRVector2 &dir1, KRVector2 &dir2, KRVector2 &dir3, KRVector2 &dir4, float &mix1, float &mix2, float &mix3, float &mix4)
|
void KRAudioManager::getHRTFMix(const KRVector2 &dir, KRVector2 &dir1, KRVector2 &dir2, KRVector2 &dir3, KRVector2 &dir4, float &mix1, float &mix2, float &mix3, float &mix4)
|
||||||
@@ -799,21 +848,10 @@ void KRAudioManager::getHRTFMix(const KRVector2 &dir, KRVector2 &dir1, KRVector2
|
|||||||
mix4 = azim_blend2 * elev_blend;
|
mix4 = azim_blend2 * elev_blend;
|
||||||
}
|
}
|
||||||
|
|
||||||
KRAudioSample *KRAudioManager::getHRTFSample(const KRVector2 &hrtf_dir, bool &swap)
|
|
||||||
{
|
|
||||||
//hrtf_kemar_H-10e000a.wav
|
|
||||||
swap = hrtf_dir.y < 0;
|
|
||||||
|
|
||||||
char szName[64];
|
|
||||||
sprintf(szName, "hrtf_kemar_H%de%03da", int(hrtf_dir.x), abs(int(hrtf_dir.y)));
|
|
||||||
|
|
||||||
return get(szName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KRAudioManager::initSiren()
|
void KRAudioManager::initSiren()
|
||||||
{
|
{
|
||||||
if(m_auGraph == NULL) {
|
if(m_auGraph == NULL) {
|
||||||
initHRTF();
|
|
||||||
m_output_sample = KRENGINE_AUDIO_BLOCK_LENGTH;
|
m_output_sample = KRENGINE_AUDIO_BLOCK_LENGTH;
|
||||||
|
|
||||||
// initialize double-buffer for reverb input
|
// initialize double-buffer for reverb input
|
||||||
@@ -946,6 +984,11 @@ void KRAudioManager::initSiren()
|
|||||||
|
|
||||||
OSDEBUG(AUGraphInitialize(m_auGraph));
|
OSDEBUG(AUGraphInitialize(m_auGraph));
|
||||||
|
|
||||||
|
// ----====---- Initialize HRTF Engine ----====----
|
||||||
|
|
||||||
|
initHRTF();
|
||||||
|
|
||||||
|
// ----====---- Start the audio system ----====----
|
||||||
OSDEBUG(AUGraphStart(m_auGraph));
|
OSDEBUG(AUGraphStart(m_auGraph));
|
||||||
|
|
||||||
// CAShow(m_auGraph);
|
// CAShow(m_auGraph);
|
||||||
@@ -976,7 +1019,12 @@ void KRAudioManager::cleanupSiren()
|
|||||||
free(m_workspace_data);
|
free(m_workspace_data);
|
||||||
m_workspace_data = NULL;
|
m_workspace_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_hrtf_data) {
|
||||||
|
free(m_hrtf_data);
|
||||||
|
m_hrtf_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
||||||
m_reverb_impulse_responses[i] = NULL;
|
m_reverb_impulse_responses[i] = NULL;
|
||||||
m_reverb_impulse_responses_weight[i] = 0.0f;
|
m_reverb_impulse_responses_weight[i] = 0.0f;
|
||||||
@@ -1262,21 +1310,26 @@ void KRAudioManager::renderHRTF()
|
|||||||
int fft_size = 256;
|
int fft_size = 256;
|
||||||
int fft_size_log2 = 8;
|
int fft_size_log2 = 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KRVector3 listener_right = KRVector3::Cross(m_listener_forward, m_listener_up);
|
KRVector3 listener_right = KRVector3::Cross(m_listener_forward, m_listener_up);
|
||||||
|
|
||||||
KRMat4 inv_listener_mat = KRMat4::Invert(KRMat4(listener_right, m_listener_up, m_listener_forward, m_listener_position));
|
|
||||||
|
|
||||||
for(std::set<KRAudioSource *>::iterator itr=m_activeAudioSources.begin(); itr != m_activeAudioSources.end(); itr++) {
|
for(std::set<KRAudioSource *>::iterator itr=m_activeAudioSources.begin(); itr != m_activeAudioSources.end(); itr++) {
|
||||||
KRAudioSource *source = *itr;
|
KRAudioSource *source = *itr;
|
||||||
KRAudioSample *source_sample = source->getAudioSample();
|
KRAudioSample *source_sample = source->getAudioSample();
|
||||||
if(source_sample) {
|
if(source_sample) {
|
||||||
KRVector3 source_world_position = source->getWorldTranslation();
|
KRVector3 source_world_position = source->getWorldTranslation();
|
||||||
KRVector3 source_listener_space = KRMat4::Dot(inv_listener_mat, source_world_position);
|
KRVector3 diff = source_world_position - m_listener_position;
|
||||||
KRVector3 source_dir = KRVector3::Normalize(source_listener_space);
|
float distance = diff.magnitude();
|
||||||
float distance = source_listener_space.magnitude();
|
|
||||||
float gain = source->getGain() * m_global_gain / pow(KRMAX(distance / source->getReferenceDistance(), 1.0f), source->getRolloffFactor());
|
float gain = source->getGain() * m_global_gain / pow(KRMAX(distance / source->getReferenceDistance(), 1.0f), source->getRolloffFactor());
|
||||||
|
KRVector3 source_listener_space = KRVector3(
|
||||||
|
KRVector3::Dot(listener_right, diff),
|
||||||
|
KRVector3::Dot(m_listener_up, diff),
|
||||||
|
KRVector3::Dot(m_listener_forward, diff)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
KRVector3 source_dir = KRVector3::Normalize(source_listener_space);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(source->getEnableOcclusion() && false) {
|
if(source->getEnableOcclusion() && false) {
|
||||||
KRHitInfo hitinfo;
|
KRHitInfo hitinfo;
|
||||||
@@ -1285,35 +1338,26 @@ void KRAudioManager::renderHRTF()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KRVector2 source_dir2 = KRVector2::Normalize(KRVector2(source_dir.x, source_dir.z));
|
||||||
float azimuth = atan2(source_dir.x, source_dir.z);
|
float azimuth = -atan2(source_dir2.x, -source_dir2.y);
|
||||||
float elevation = atan( source_dir.y / sqrt(source_dir.x * source_dir.x + source_dir.z * source_dir.z));
|
float elevation = atan( source_dir.y / sqrt(source_dir.x * source_dir.x + source_dir.z * source_dir.z));
|
||||||
|
|
||||||
float mix[4];
|
float mix[4];
|
||||||
KRVector2 dir[4];
|
KRVector2 dir[4];
|
||||||
bool swap[4];
|
|
||||||
KRAudioSample *sample[4];
|
|
||||||
|
|
||||||
getHRTFMix(KRVector2(elevation, azimuth), dir[0], dir[1], dir[2], dir[3], mix[0], mix[1], mix[2], mix[3]);
|
getHRTFMix(KRVector2(elevation, azimuth), dir[0], dir[1], dir[2], dir[3], mix[0], mix[1], mix[2], mix[3]);
|
||||||
|
|
||||||
for(int i=0; i < 4; i++) {
|
|
||||||
sample[i] = getHRTFSample(dir[i], swap[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int channel=0; channel<impulse_response_channels; channel++) {
|
for(int channel=0; channel<impulse_response_channels; channel++) {
|
||||||
|
|
||||||
memset(hrtf_accum->realp, 0, sizeof(float) * fft_size);
|
memset(hrtf_accum->realp, 0, sizeof(float) * fft_size);
|
||||||
memset(hrtf_accum->imagp, 0, sizeof(float) * fft_size);
|
memset(hrtf_accum->imagp, 0, sizeof(float) * fft_size);
|
||||||
|
|
||||||
for(int i=0; i < 4; i++) {
|
for(int i=0; i < 4; i++) {
|
||||||
if(sample[i] != NULL && mix[i] > 0.0f) {
|
if(mix[i] > 0.0f) {
|
||||||
|
DSPSplitComplex hrtf_impulse_sample = getHRTFSpectral(dir[i], channel);
|
||||||
sample[i]->sample(0, hrtf_frames, (channel + (swap[i] ? 1 : 0)) % 2, hrtf_impulse->realp, 1.0f);
|
vDSP_vsmul(hrtf_impulse_sample.realp, 1, mix+i, hrtf_impulse->realp, 1, fft_size);
|
||||||
memset(hrtf_impulse->realp + hrtf_frames, 0, sizeof(float) * hrtf_frames);
|
vDSP_vsmul(hrtf_impulse_sample.imagp, 1, mix+i, hrtf_impulse->imagp, 1, fft_size);
|
||||||
memset(hrtf_impulse->imagp, 0, sizeof(float) * fft_size);
|
|
||||||
vDSP_fft_zip(m_fft_setup, hrtf_impulse, 1, fft_size_log2, kFFTDirection_Forward);
|
|
||||||
vDSP_vsmul(hrtf_impulse->realp, 1, mix+i, hrtf_impulse->realp, 1, fft_size);
|
|
||||||
vDSP_vsmul(hrtf_impulse->imagp, 1, mix+i, hrtf_impulse->imagp, 1, fft_size);
|
|
||||||
vDSP_zvadd(hrtf_impulse, 1, hrtf_accum, 1, hrtf_accum, 1, fft_size);
|
vDSP_zvadd(hrtf_impulse, 1, hrtf_accum, 1, hrtf_accum, 1, fft_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,8 @@ private:
|
|||||||
float *m_workspace_data;
|
float *m_workspace_data;
|
||||||
DSPSplitComplex m_workspace[3];
|
DSPSplitComplex m_workspace[3];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float *getBlockAddress(int block_offset);
|
float *getBlockAddress(int block_offset);
|
||||||
void renderBlock();
|
void renderBlock();
|
||||||
void renderReverb();
|
void renderReverb();
|
||||||
@@ -158,9 +160,12 @@ private:
|
|||||||
void renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log2);
|
void renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log2);
|
||||||
|
|
||||||
std::vector<KRVector2> m_hrtf_sample_locations;
|
std::vector<KRVector2> m_hrtf_sample_locations;
|
||||||
|
float *m_hrtf_data;
|
||||||
|
map<KRVector2, DSPSplitComplex> m_hrtf_spectral[2];
|
||||||
|
|
||||||
void getHRTFMix(const KRVector2 &dir, KRVector2 &hrtf1, KRVector2 &hrtf2, KRVector2 &hrtf3, KRVector2 &hrtf4, float &mix1, float &mix2, float &mix3, float &mix4);
|
void getHRTFMix(const KRVector2 &dir, KRVector2 &hrtf1, KRVector2 &hrtf2, KRVector2 &hrtf3, KRVector2 &hrtf4, float &mix1, float &mix2, float &mix3, float &mix4);
|
||||||
KRAudioSample *getHRTFSample(const KRVector2 &hrtf_dir, bool &swap);
|
KRAudioSample *getHRTFSample(const KRVector2 &hrtf_dir);
|
||||||
|
DSPSplitComplex getHRTFSpectral(const KRVector2 &hrtf_dir, const int channel);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(KRAUDIO_MANAGER_H) */
|
#endif /* defined(KRAUDIO_MANAGER_H) */
|
||||||
|
|||||||
@@ -120,6 +120,34 @@ bool KRVector2::operator !=(const KRVector2& b) const {
|
|||||||
return x != b.x || y != b.y;
|
return x != b.x || y != b.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool KRVector2::operator >(const KRVector2& b) const
|
||||||
|
{
|
||||||
|
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
|
||||||
|
if(x > b.x) {
|
||||||
|
return true;
|
||||||
|
} else if(x < b.x) {
|
||||||
|
return false;
|
||||||
|
} else if(y > b.y) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KRVector2::operator <(const KRVector2& b) const
|
||||||
|
{
|
||||||
|
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
|
||||||
|
if(x < b.x) {
|
||||||
|
return true;
|
||||||
|
} else if(x > b.x) {
|
||||||
|
return false;
|
||||||
|
} else if(y < b.y) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float& KRVector2::operator[] (unsigned i) {
|
float& KRVector2::operator[] (unsigned i) {
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ public:
|
|||||||
KRVector2& operator *=(const float v);
|
KRVector2& operator *=(const float v);
|
||||||
KRVector2& operator /=(const float v);
|
KRVector2& operator /=(const float v);
|
||||||
|
|
||||||
|
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
|
||||||
|
bool operator >(const KRVector2& b) const;
|
||||||
|
bool operator <(const KRVector2& b) const;
|
||||||
|
|
||||||
bool operator ==(const KRVector2& b) const;
|
bool operator ==(const KRVector2& b) const;
|
||||||
bool operator !=(const KRVector2& b) const;
|
bool operator !=(const KRVector2& b) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user