// class file for HRIR data
// organized in terms of azimuth (naz) elevation (nel) time (nt)
// right now as a 25x50x200 data structure, as organized in CIPIC
/*
% two arrays: hrir_l and hrir
% indices naz, nel, nt (azimuth, elevation, time)
% (25x50x200) 3 dimensional array
% in matlab, azimuth angle corresponding to nax is the naz'th element
% of the vector
% azimuths = [-80 -65 -55 -45:5:45 55 65 80]
% elevations range from -45 to +230.625 in steps of 5.625
% this angular increment divides the full circle into 64 equal parts,
% but only 50 values are used
% elevation angle corresponding to nel is the nel-th element of the
% vector elevations = -45 + 5.625*(0:49)
% temporal
@author Reynald Hoskinson (reynald@cs.ubc.ca)
*/
package jass.generators;
import java.io.*;
/**
class for using CIPIC-type HRIR files
*/
public class HRIR {
static final boolean DEBUG = true;
// stores original hrir data
float [][][] hrir_l;
float [][][] hrir_r;
// buffer to read samples from file/stream to process
byte [] samples;
// buffers for the separated right/left channels of original sample
// imaginary ones needed for FFT
double [] channelL;
double [] channelL_img;
double [] channelR;
double [] channelR_img;
// separate buffer for the FFT'd version of the hrir at a particular
// location
double [] fftdHrirL;
double [] fftdHrirR;
int windowLength; // FFT window length used
// formula used to interplolate/choose
// between HRIR points.
CIPIC_HRTF ucdpulse;
RectPolar rp;
FFT fft;
float headRadius = 0.3f; // meters
/*
takes the window size in samples
and the filename of the HRTF data
*/
public HRIR (int windowlength, String filename) {
windowLength = windowlength;
if (DEBUG) {
System.out.println("windowlength: " + windowLength);
}
// this is dependent on window size.
// figure out the formula later!
fft = new FFT(8);
hrir_l = new float[25][50][200];
hrir_r = new float[25][50][200];
channelL = new double[windowLength];
channelR = new double[windowLength];
channelL_img = new double[windowLength];
channelR_img = new double[windowLength];
rp = new RectPolar(headRadius, windowLength);
fftdHrirL = new double[windowLength];
fftdHrirR = new double[windowLength];
ucdpulse = new CIPIC_HRTF();
// zero imaginary portion
for(int i = 0; i < channelL_img.length; i++) {
channelL_img[0] = 0.0;
channelR_img[0] = 0.0;
}
loadHRIRFromCIPIC(filename);
}
// sets a value of the HRIR.
// r true: right. r false: left
public void set(int naz, int nel, int nt, float val, boolean r) {
if (r) {
hrir_r[naz][nel][nt] = val;
}
else {
hrir_l[naz][nel][nt] = val;
}
}
// gets an array of the HRIR for specific azimuth index, elevation index
public float[] getNL(int naz, int nel, boolean r) {
if (r) {
return hrir_r[naz][nel];
}
else {
return hrir_r[naz][nel];
}
}
/*
* save HRIR data to file
*/
public void saveToHRTF(String filename) {
int init = 200; // original CIPIC
fftdHrirL = new double[windowLength];
fftdHrirR = new double[windowLength];
String thisLine;
try {
File file = new File(filename);
file.createNewFile();
Writer out = new FileWriter(file);
PrintWriter pw = new PrintWriter(out);
double theta;
for (int az = 0; az < 25; az ++) {
for (int el = 0; el < 50; el++) {
for (int i =0; i < fftdHrirL.length; i++) {
if (i < init) {
fftdHrirL[i] = hrir_l[az][el][i];
fftdHrirR[i] = hrir_r[az][el][i];
channelL_img[i] = 0.0;
channelR_img[i] = 0.0;
}
else {
fftdHrirR[i] = 0.0;
fftdHrirL[i] = 0.0;
channelL_img[i] = 0.0;
channelR_img[i] = 0.0;
}
}
// fft hrir signal
fft.doFFT(fftdHrirL, channelL_img, false);
fft.doFFT(fftdHrirR, channelR_img, false);
rp.constructHRTF(fftdHrirL, channelL_img);
rp.constructHRTF(fftdHrirR, channelR_img);
// write real part to file
for (int i =0; i < fftdHrirL.length; i++) {
pw.print(fftdHrirL[i] + " ");
}
pw.println();
// imaginary
for (int i =0; i < fftdHrirL.length; i++) {
pw.print(channelL_img[i] + " ");
}
pw.println();
// right side
for (int i =0; i < fftdHrirR.length; i++) {
pw.print(fftdHrirR[i] + " ");
}
pw.println();
for (int i =0; i < channelR_img.length; i++) {
pw.print(channelR_img[i] + " ");
}
pw.println();
}
}
pw.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
/*
* loads HRIR data from file
*/
public void loadHRIRFromCIPIC(String filename) {
try {
String thisLine;
File file = new File(filename);
Reader in = new FileReader(filename);
BufferedReader bf = new BufferedReader(in);
String delimiter = " ";
for (int i = 0; i < 25; i ++) {
for (int j = 0; j < 50; j++) {
thisLine = bf.readLine();
java.util.StringTokenizer st =
new java.util.StringTokenizer(thisLine, delimiter);
for (int k = 0; k < 200; k++ ) {
hrir_l[i][j][k] = Float.valueOf(st.nextToken()).floatValue();
}
}
}
if (DEBUG) {
System.out.println("finished hrir_l");
}
// ignore blank line in middle
bf.readLine();
for (int i = 0; i < 25; i ++) {
for (int j = 0; j < 50; j++) {
thisLine = bf.readLine();
java.util.StringTokenizer st =
new java.util.StringTokenizer(thisLine, delimiter);
for (int k = 0; k < 200; k++ ) {
hrir_r[i][j][k] = Float.valueOf(st.nextToken()).floatValue();
}
}
}
if (DEBUG) {
System.out.println("finished hrir_r ");
}
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
if (args.length < 2) {
System.out.println ("usage: java HRIR <original HRIR file> <outputfile>");
}
else {HRIR hrir = new HRIR(256, args[0]);
hrir.saveToHRTF(args[1]);
}
}
}