package jass.generators; import jass.engine.*; import java.util.*; import java.io.File; /** Spatial Mixer UG. @author Reynald Hoskinson (reynald@cs.ubc.ca) */ public class SpatialMixer extends InOut { static final boolean DEBUG = true; static final int windowLength = 256; protected float[] tmp_bufL; // scratchpad protected float[] tmp_bufR; // scratchpad protected float[] tmp_out; // intermediate output protected HRTF hrtf; protected PositionData [] positions; /** set filename to obtain hrir info for 1 subject @param filename filename of subject's hrir data */ public void startHRTF() { hrtf.startSpatial(); } public void stopHRTF() { hrtf.stopSpatial(); } public void changeHRTF(File filename) { hrtf.fillHRTF(filename); } /** set position of source @param inputNo buffer number to set position of @param p Position data gives the 3D coordinate of the sound source */ public void setPosition(int inputNo, PositionData p) { if (inputNo > positions.length) { System.out.println("SpatialMixer warning: inputNo exceeds number of sources"); } else { positions[inputNo] = p; } } /** Create stereo Spatialized mixer @param bufferSize Buffer size used for real-time rendering. For stereo must be 2X input buffersize @param n no inputs @param hrtf_data hrtf file. */ public SpatialMixer(int bufferSize,int n, String hrtf_data) { super(bufferSize); hrtf = new HRTF(windowLength, hrtf_data); // one channel each int bufsz = bufferSize/2; tmp_bufL = new float[bufsz]; tmp_bufR = new float[bufsz]; tmp_out = new float[bufferSize]; positions = new PositionData[n]; } /** Create. For superclasses @param bufferSize Buffer size used for real-time rendering. */ public SpatialMixer(int bufferSize) { super(bufferSize); } /** Compute the next buffer and store in member float[] buf. Note if stereo then output buf[] is twice as big as input buffers --> this means that each source is a mono stream. will sourceContainer.size() always == n in Mixer constructor? */ protected void computeBuffer() { int bufsz = getBufferSize(); // will this return the right thing? ie. 1 channel worth int nsrc = sourceContainer.size(); int inbufsz = bufsz/2; /* if (DEBUG) { System.out.println("bufsz: " + bufsz); System.out.println("nsrc: " + nsrc); System.out.println("inbufsz: " + inbufsz); } */ for(int k=0;k<bufsz;k++) { //can't overwrite buf[] yet as one of the srcBuffers may be pointing to it! tmp_out[k] = 0; } for(int i=0;i<nsrc;i++) { float[] tmpsrc = srcBuffers[i]; // System.out.println("tmpsrc.length: " + tmpsrc.length); // tmpsrc.length 256 // inbufsz: 256 // nsrc 1 // bufsz 512 // System.out.println("tmpsrc.length: " + tmpsrc.length); // for each source, do spatailize. /* q1. I guess this is where they are mixed too? q2. are buffer overruns handled elsewhere? q3. should I keep srcBuffers unchanged? */ hrtf.setLocation(positions[i]); hrtf.process(tmpsrc, tmp_bufL, tmp_bufR); // add this source to the output buffers. // interleaved int iout = 0; for(int k=0;k<inbufsz;k++) { tmp_out[iout++] += tmp_bufL[k]; tmp_out[iout++] += tmp_bufR[k]; } } // now move to real output buf. for(int k=0;k<bufsz;k++) { buf[k] = tmp_out[k]; } } }