void Hrtf::get_kemar_data(kemar_ptr & kemar_data, int & elev_n, const v3f &pos) { kemar_data = 0; elev_n = 0; if (pos.is0()) return; #ifdef _WINDOWS float len = (float)_hypot(pos.x, pos.y); #else float len = (float)hypot(pos.x, pos.y); #endif int elev_gr = (int)(180 * atan2f(pos.z, len) / (float)M_PI); //LOG_DEBUG(("elev = %d (%g %g %g)", elev_gr, pos.x, pos.y, pos.z)); for(size_t i = 0; i < KemarElevationCount; ++i) { const kemar_elevation_data &elev = ::kemar_data[i]; if (elev_gr < elev.elevation + KemarElevationStep / 2) { //LOG_DEBUG(("used elevation %d", elev.elevation)); kemar_data = elev.data; elev_n = elev.samples; break; } } }
unsigned Hrtf::process( unsigned sample_rate, clunk::Buffer &dst_buf, unsigned dst_ch, const clunk::Buffer &src_buf, unsigned src_ch, const v3f &delta_position, float fx_volume) { s16 * const dst = static_cast<s16*>(dst_buf.get_ptr()); const unsigned dst_n = (unsigned)dst_buf.get_size() / dst_ch / 2; const s16 * const src = static_cast<const s16 *>(src_buf.get_ptr()); const unsigned src_n = (unsigned)src_buf.get_size() / src_ch / 2; assert(dst_n <= src_n); kemar_ptr kemar_data; int angles; get_kemar_data(kemar_data, angles, delta_position); if (delta_position.is0() || kemar_data == NULL) { //2d stereo sound! if (src_ch == dst_ch) { memcpy(dst_buf.get_ptr(), src_buf.get_ptr(), dst_buf.get_size()); return dst_n; } else throw_ex(("unsupported sample conversion")); } assert(dst_ch == 2); //LOG_DEBUG(("data: %p, angles: %d", (void *) kemar_data, angles)); float t_idt, angle_gr, left_to_right_amp; idt_iit(delta_position, t_idt, angle_gr, left_to_right_amp); const int kemar_sector_size = 360 / angles; const int kemar_idx[2] = { ((360 - (int)angle_gr + kemar_sector_size / 2) / kemar_sector_size) % angles, ((int)angle_gr + kemar_sector_size / 2) / kemar_sector_size }; float amp[2] = { left_to_right_amp > 1? 1: 1 / left_to_right_amp, left_to_right_amp > 1? left_to_right_amp: 1 }; //LOG_DEBUG(("%g (of %d)-> left: %d, right: %d", angle_gr, angles, kemar_idx_left, kemar_idx_right)); int idt_offset = (int)(t_idt * sample_rate); int window = 0; while(sample3d[0].get_size() < dst_n * 2 || sample3d[1].get_size() < dst_n * 2) { size_t offset = window * WINDOW_SIZE / 2; assert(offset + WINDOW_SIZE / 2 <= src_n); for(unsigned c = 0; c < dst_ch; ++c) { sample3d[c].reserve(WINDOW_SIZE); s16 *dst = static_cast<s16 *>(static_cast<void *>((static_cast<u8 *>(sample3d[c].get_ptr()) + sample3d[c].get_size() - WINDOW_SIZE))); hrtf(c, dst, src + offset * src_ch, src_ch, src_n - offset, idt_offset, kemar_data, kemar_idx[c], amp[c]); } ++window; } assert(sample3d[0].get_size() >= dst_n * 2 && sample3d[1].get_size() >= dst_n * 2); //LOG_DEBUG(("angle: %g", angle_gr)); //LOG_DEBUG(("idt offset %d samples", idt_offset)); s16 * src_3d[2] = { static_cast<s16 *>(sample3d[0].get_ptr()), static_cast<s16 *>(sample3d[1].get_ptr()) }; //LOG_DEBUG(("size1: %u, %u, needed: %u\n%s", (unsigned)sample3d[0].get_size(), (unsigned)sample3d[1].get_size(), dst_n, sample3d[0].dump().c_str())); for(unsigned i = 0; i < dst_n; ++i) { for(unsigned c = 0; c < dst_ch; ++c) { dst[i * dst_ch + c] = src_3d[c][i]; } } skip(dst_n); return window * WINDOW_SIZE / 2; }